Merge branch 'master' of gnunet.org:gnunet
authortg(x) <*@tg-x.net>
Wed, 22 Mar 2017 09:08:01 +0000 (10:08 +0100)
committertg(x) <*@tg-x.net>
Wed, 22 Mar 2017 09:08:01 +0000 (10:08 +0100)
380 files changed:
AUTHORS
README
configure.ac
contrib/.gitignore
doc/gnunet-c-tutorial.pdf
doc/gnunet-c-tutorial.tex
doc/man/gnunet-cadet.1
doc/testbed_test.c
po/POTFILES.in
src/arm/arm_api.c
src/arm/gnunet-arm.c
src/arm/gnunet-service-arm.c
src/ats-tests/gnunet-ats-sim.c
src/ats-tests/gnunet-solver-eval.c
src/ats-tool/gnunet-ats.c
src/ats/ats_api_scheduling.c
src/ats/gnunet-ats-solver-eval.c
src/ats/gnunet-service-ats_addresses.c
src/ats/gnunet-service-ats_performance.c
src/ats/perf_ats_solver.c
src/auction/gnunet-auction-create.c
src/block/bg_bf.c
src/cadet/Makefile.am
src/cadet/TODO
src/cadet/cadet.conf.in
src/cadet/cadet.h
src/cadet/cadet_api.c
src/cadet/cadet_api_new.c [deleted file]
src/cadet/cadet_common.c [deleted file]
src/cadet/cadet_path.c [deleted file]
src/cadet/cadet_path.h [deleted file]
src/cadet/cadet_protocol.h
src/cadet/cadet_test_lib.c
src/cadet/cadet_test_lib.h
src/cadet/cadet_test_lib_new.c [deleted file]
src/cadet/cadet_test_lib_new.h [deleted file]
src/cadet/gnunet-cadet.c
src/cadet/gnunet-service-cadet-new.c [deleted file]
src/cadet/gnunet-service-cadet-new.h [deleted file]
src/cadet/gnunet-service-cadet-new_channel.c [deleted file]
src/cadet/gnunet-service-cadet-new_channel.h [deleted file]
src/cadet/gnunet-service-cadet-new_connection.c [deleted file]
src/cadet/gnunet-service-cadet-new_connection.h [deleted file]
src/cadet/gnunet-service-cadet-new_core.c [deleted file]
src/cadet/gnunet-service-cadet-new_core.h [deleted file]
src/cadet/gnunet-service-cadet-new_dht.c [deleted file]
src/cadet/gnunet-service-cadet-new_dht.h [deleted file]
src/cadet/gnunet-service-cadet-new_hello.c [deleted file]
src/cadet/gnunet-service-cadet-new_hello.h [deleted file]
src/cadet/gnunet-service-cadet-new_paths.c [deleted file]
src/cadet/gnunet-service-cadet-new_paths.h [deleted file]
src/cadet/gnunet-service-cadet-new_peer.c [deleted file]
src/cadet/gnunet-service-cadet-new_peer.h [deleted file]
src/cadet/gnunet-service-cadet-new_tunnels.c [deleted file]
src/cadet/gnunet-service-cadet-new_tunnels.h [deleted file]
src/cadet/gnunet-service-cadet.c
src/cadet/gnunet-service-cadet.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_channel.c
src/cadet/gnunet-service-cadet_channel.h
src/cadet/gnunet-service-cadet_connection.c
src/cadet/gnunet-service-cadet_connection.h
src/cadet/gnunet-service-cadet_core.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_core.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_dht.c
src/cadet/gnunet-service-cadet_dht.h
src/cadet/gnunet-service-cadet_hello.c
src/cadet/gnunet-service-cadet_hello.h
src/cadet/gnunet-service-cadet_local.c [deleted file]
src/cadet/gnunet-service-cadet_local.h [deleted file]
src/cadet/gnunet-service-cadet_paths.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_paths.h [new file with mode: 0644]
src/cadet/gnunet-service-cadet_peer.c
src/cadet/gnunet-service-cadet_peer.h
src/cadet/gnunet-service-cadet_tunnel.c [deleted file]
src/cadet/gnunet-service-cadet_tunnel.h [deleted file]
src/cadet/gnunet-service-cadet_tunnels.c [new file with mode: 0644]
src/cadet/gnunet-service-cadet_tunnels.h [new file with mode: 0644]
src/cadet/test_cadet.c
src/cadet/test_cadet_local.c [deleted file]
src/cadet/test_cadet_local_mq.c
src/cadet/test_cadet_new.c [deleted file]
src/cadet/test_cadet_single.c [deleted file]
src/consensus/Makefile.am
src/consensus/consensus_protocol.h
src/consensus/gnunet-consensus-profiler.c
src/consensus/gnunet-service-consensus.c
src/consensus/test_consensus.conf
src/conversation/Makefile.am
src/conversation/gnunet-conversation.c
src/conversation/gnunet-helper-audio-playback.c
src/conversation/gnunet-service-conversation.c
src/conversation/microphone.c
src/core/core_api.c
src/core/gnunet-core.c
src/core/gnunet-service-core.c
src/core/gnunet-service-core_kx.c
src/datacache/Makefile.am
src/datacache/plugin_datacache_sqlite.c
src/datastore/Makefile.am
src/datastore/datastore.h
src/datastore/datastore_api.c
src/datastore/gnunet-datastore.c
src/datastore/gnunet-service-datastore.c
src/datastore/plugin_datastore_heap.c
src/datastore/plugin_datastore_mysql.c
src/datastore/plugin_datastore_postgres.c
src/datastore/plugin_datastore_sqlite.c
src/datastore/plugin_datastore_template.c
src/datastore/test_datastore_api.c
src/datastore/test_datastore_api_management.c
src/datastore/test_plugin_datastore.c
src/dht/dht_api.c
src/dht/gnunet-dht-get.c
src/dht/gnunet-dht-monitor.c
src/dht/gnunet-dht-put.c
src/dht/gnunet-service-dht_clients.c
src/dht/gnunet-service-dht_datacache.c
src/dht/gnunet-service-dht_neighbours.c
src/dht/gnunet_dht_profiler.c
src/dns/Makefile.am
src/dns/dns_api.c
src/dns/gnunet-dns-monitor.c
src/dns/gnunet-dns-redirector.c
src/dns/gnunet-helper-dns.c
src/dns/gnunet-service-dns.c
src/dv/dv_api.c
src/dv/gnunet-dv.c
src/dv/gnunet-service-dv.c
src/exit/Makefile.am
src/exit/gnunet-daemon-exit.c
src/exit/gnunet-helper-exit-windows.c
src/exit/gnunet-helper-exit.c
src/fs/Makefile.am
src/fs/fs_api.h
src/fs/fs_directory.c
src/fs/fs_dirmetascan.c
src/fs/fs_download.c
src/fs/fs_getopt.c
src/fs/fs_publish.c
src/fs/fs_search.c
src/fs/fs_tree.c
src/fs/fs_unindex.c
src/fs/fs_uri.c
src/fs/gnunet-auto-share.c
src/fs/gnunet-download.c
src/fs/gnunet-fs-profiler.c
src/fs/gnunet-fs.c
src/fs/gnunet-helper-fs-publish.c
src/fs/gnunet-publish.c
src/fs/gnunet-search.c
src/fs/gnunet-service-fs.c
src/fs/gnunet-service-fs_cadet_client.c
src/fs/gnunet-service-fs_cadet_server.c
src/fs/gnunet-service-fs_cp.c
src/fs/gnunet-service-fs_indexing.c
src/fs/gnunet-service-fs_lc.c [deleted file]
src/fs/gnunet-service-fs_lc.h [deleted file]
src/fs/gnunet-service-fs_pr.c
src/fs/gnunet-service-fs_put.c
src/fs/gnunet-unindex.c
src/gns/gns_api.c
src/gns/gnunet-bcd.c
src/gns/gnunet-dns2gns.c
src/gns/gnunet-gns-proxy.c
src/gns/gnunet-gns.c
src/gns/plugin_gnsrecord_gns.c
src/hello/hello.c
src/hostlist/gnunet-daemon-hostlist.c
src/hostlist/gnunet-daemon-hostlist_client.c
src/hostlist/gnunet-daemon-hostlist_server.c
src/identity-provider/gnunet-identity-token.c
src/identity-provider/identity_provider_api.c
src/identity/gnunet-identity.c
src/identity/identity_api.c
src/include/Makefile.am
src/include/gnunet_arm_service.h
src/include/gnunet_bandwidth_lib.h
src/include/gnunet_cadet_service.h
src/include/gnunet_configuration_lib.h
src/include/gnunet_connection_lib.h [deleted file]
src/include/gnunet_constants.h
src/include/gnunet_core_service.h
src/include/gnunet_datastore_plugin.h
src/include/gnunet_datastore_service.h
src/include/gnunet_fs_service.h
src/include/gnunet_getopt_lib.h
src/include/gnunet_helper_lib.h
src/include/gnunet_json_lib.h
src/include/gnunet_mq_lib.h
src/include/gnunet_multicast_service.h
src/include/gnunet_peerstore_service.h
src/include/gnunet_server_lib.h [deleted file]
src/include/gnunet_service_lib.h
src/include/gnunet_sq_lib.h
src/include/gnunet_util_lib.h
src/include/platform.h
src/integration-tests/confs/test_defaults.conf
src/json/json.c
src/multicast/.gitignore
src/multicast/Makefile.am
src/multicast/gnunet-service-multicast.c
src/multicast/test_multicast.conf
src/multicast/test_multicast_2peers.c [new file with mode: 0644]
src/multicast/test_multicast_multipeer.c
src/namecache/Makefile.am
src/namecache/gnunet-namecache.c
src/namecache/plugin_namecache_sqlite.c
src/namestore/Makefile.am
src/namestore/gnunet-namestore.c
src/namestore/gnunet-service-namestore.c
src/namestore/plugin_namestore_sqlite.c
src/nat-auto/Makefile.am
src/nat-auto/gnunet-nat-auto.c
src/nat-auto/gnunet-nat-server.c
src/nat-auto/nat_auto_api.c
src/nat/gnunet-nat.c
src/nat/gnunet-service-nat.c
src/nat/gnunet-service-nat_externalip.c
src/nat/gnunet-service-nat_helper.c
src/nat/nat_api.c
src/nat/nat_stun.h
src/nse/gnunet-nse-profiler.c
src/peerinfo-tool/gnunet-peerinfo.c
src/peerinfo/gnunet-service-peerinfo.c
src/peerstore/Makefile.am
src/peerstore/gnunet-service-peerstore.c
src/peerstore/peerstore.h
src/peerstore/peerstore_api.c
src/peerstore/peerstore_common.c
src/peerstore/peerstore_common.h
src/peerstore/plugin_peerstore_flat.c
src/peerstore/plugin_peerstore_sqlite.c
src/peerstore/test_peerstore_api_iterate.c
src/peerstore/test_peerstore_api_store.c
src/peerstore/test_plugin_peerstore.c
src/pq/pq.c
src/psyc/.gitignore
src/psyc/psyc_api.c
src/psycstore/.gitignore
src/psycstore/gnunet-service-psycstore.c
src/psycstore/psycstore_api.c
src/psycutil/.gitignore [new file with mode: 0644]
src/pt/Makefile.am
src/pt/gnunet-daemon-pt.c
src/regex/gnunet-regex-profiler.c
src/regex/gnunet-regex-simulation-profiler.c
src/regex/gnunet-service-regex.c
src/regex/regex_api_announce.c
src/regex/regex_api_search.c
src/rest/gnunet-rest-server.c
src/revocation/gnunet-revocation.c
src/revocation/test_revocation.c
src/rps/Makefile.am
src/rps/gnunet-rps.c
src/rps/gnunet-service-rps.c
src/rps/gnunet-service-rps_peers.c
src/rps/gnunet-service-rps_peers.h
src/rps/rps_api.c
src/rps/test_rps.c
src/rps/test_service_rps_peers.c
src/scalarproduct/Makefile.am
src/scalarproduct/gnunet-scalarproduct.c
src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c
src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c
src/scalarproduct/gnunet-service-scalarproduct_alice.c
src/scalarproduct/gnunet-service-scalarproduct_bob.c
src/scalarproduct/scalarproduct_api.c
src/secretsharing/Makefile.am
src/secretsharing/gnunet-secretsharing-profiler.c
src/secretsharing/gnunet-service-secretsharing.c
src/set/Makefile.am
src/set/gnunet-service-set.c
src/set/gnunet-service-set.h
src/set/gnunet-service-set_intersection.c
src/set/gnunet-service-set_intersection.h [new file with mode: 0644]
src/set/gnunet-service-set_union.c
src/set/gnunet-service-set_union.h [new file with mode: 0644]
src/set/gnunet-set-ibf-profiler.c
src/set/gnunet-set-profiler.c
src/set/set_api.c
src/set/test_set_api.c
src/set/test_set_union_copy.c
src/social/.gitignore
src/social/gnunet-social.c
src/social/social_api.c
src/sq/Makefile.am
src/sq/sq.c
src/sq/sq_query_helper.c
src/sq/sq_result_helper.c
src/sq/test_sq.c
src/statistics/gnunet-service-statistics.c
src/statistics/gnunet-statistics.c
src/statistics/statistics_api.c
src/testbed-logger/gnunet-service-testbed-logger.c
src/testbed-logger/test_testbed_logger_api.c
src/testbed-logger/testbed_logger_api.c
src/testbed/Makefile.am
src/testbed/generate-underlay-topology.c
src/testbed/gnunet-helper-testbed.c
src/testbed/gnunet-service-testbed_barriers.c
src/testbed/gnunet-service-testbed_oc.c
src/testbed/gnunet-service-testbed_peers.c
src/testbed/gnunet-testbed-profiler.c
src/testbed/test_gnunet_helper_testbed.c
src/testbed/testbed_api_hosts.c
src/testbed/testbed_api_peers.c
src/testbed/testbed_api_topology.c
src/testing/gnunet-testing.c
src/testing/list-keys.c
src/testing/testing.c
src/topology/friends.c
src/topology/gnunet-daemon-topology.c
src/transport/Makefile.am
src/transport/gnunet-helper-transport-wlan-dummy.c
src/transport/gnunet-service-transport_validation.c
src/transport/gnunet-transport-certificate-creation.c
src/transport/gnunet-transport-profiler.c
src/transport/gnunet-transport.c
src/transport/plugin_transport_http_client.c
src/transport/plugin_transport_http_server.c
src/transport/plugin_transport_tcp.c
src/transport/plugin_transport_udp.c
src/transport/plugin_transport_udp.h
src/transport/plugin_transport_udp_broadcasting.c
src/transport/plugin_transport_wlan.c
src/transport/tcp_connection_legacy.c [new file with mode: 0644]
src/transport/tcp_server_legacy.c [new file with mode: 0644]
src/transport/tcp_server_mst_legacy.c [new file with mode: 0644]
src/transport/tcp_service_legacy.c [new file with mode: 0644]
src/transport/test_plugin_transport.c
src/transport/test_transport_api_reliability.c
src/transport/transport-testing-loggers.c
src/transport/transport-testing-main.c
src/transport/transport-testing.c
src/transport/transport_api_address_to_string.c
src/transport/transport_api_core.c
src/util/Makefile.am
src/util/bandwidth.c
src/util/client.c
src/util/connection.c [deleted file]
src/util/disk.c
src/util/getopt.c
src/util/getopt_helpers.c
src/util/gnunet-config.c
src/util/gnunet-ecc.c
src/util/gnunet-resolver.c
src/util/gnunet-scrypt.c
src/util/helper.c
src/util/mq.c
src/util/mst.c
src/util/resolver_api.c
src/util/server.c [deleted file]
src/util/server_mst.c [deleted file]
src/util/server_nc.c [deleted file]
src/util/server_tc.c [deleted file]
src/util/service.c
src/util/service_new.c [deleted file]
src/util/socks.c
src/util/test_client.c
src/util/test_common_allocation.c
src/util/test_connection.c [deleted file]
src/util/test_connection_addressing.c [deleted file]
src/util/test_connection_receive_cancel.c [deleted file]
src/util/test_connection_timeout.c [deleted file]
src/util/test_connection_timeout_no_connect.c [deleted file]
src/util/test_connection_transmit_cancel.c [deleted file]
src/util/test_getopt.c
src/util/test_program.c
src/util/test_server.c [deleted file]
src/util/test_server_disconnect.c [deleted file]
src/util/test_server_mst_interrupt.c [deleted file]
src/util/test_server_with_client.c [deleted file]
src/util/test_server_with_client_unix.c [deleted file]
src/util/test_service.c
src/util/util.conf
src/vpn/Makefile.am
src/vpn/gnunet-helper-vpn-windows.c
src/vpn/gnunet-helper-vpn.c
src/vpn/gnunet-service-vpn.c
src/vpn/gnunet-vpn.c

diff --git a/AUTHORS b/AUTHORS
index aedc5dffb10e071ac4f9b0e6e25730f85152497c..d5bf155432f466b7d2e250eb9f628f0e5cd26563 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -18,6 +18,7 @@ Fabian Oehlmann
 Florian Dold <florian.dold@gmail.com>
 Gabor X Toth <tg-x.net>
 LRN <lrn1986@gmail.com>
+Marcello Stanisci <marcello.stanisci@inria.fr>
 Martin Schanzenbach <mschanzenbach@posteo.de>
 Matthias Wachs <wachs@net.in.tum.de>
 Maximilian Szengel <gnunet@maxsz.de>
diff --git a/README b/README
index a72d8b3b828d91e41dc9b8f90f5fd0ac8fb5aafa..7f73525e890912d253be3b901b842d870e3b86df 100644 (file)
--- a/README
+++ b/README
@@ -13,7 +13,7 @@ worldwide group of independent free software developers.  GNUnet is a
 GNU package (http://www.gnu.org/).
 
 This is an ALPHA release.  There are known and significant bugs as
-well as many missing features in this release.  
+well as many missing features in this release.
 
 Additional documentation about GNUnet can be found at
 https://gnunet.org/.
@@ -42,7 +42,7 @@ These are the direct dependencies for running GNUnet:
 - libltdl       >= 2.2 (part of GNU libtool)
 - sqlite        >= 3.8 (default database, required)
 - mysql         >= 5.1 (alternative to sqlite)
-- postgres      >= 8.3 (alternative to sqlite)
+- postgres      >= 9.6 (alternative to sqlite)
 - libopus       >= 1.0.1 (optional for experimental conversation tool)
 - libpulse      >= 2.0 (optional for experimental conversation tool)
 - libogg        >= 1.3.0 (optional for experimental conversation tool)
index 9fa6201282245d990a66053b88a15f2e9c42f561..273301f1b69874ead1e4c0c33c99f8475295480b 100644 (file)
@@ -818,7 +818,7 @@ CPPFLAGS=$SAVE_CPPFLAGS
 postgres=false
 # even running the check for postgres breaks emscripten ...
 if test "$taler_only" != yes; then
-  AX_LIB_POSTGRESQL([])
+  AX_LIB_POSTGRESQL([9.6])
   if test "$found_postgresql" = "yes"; then
     CPPFLAGS="$CPPFLAGS $POSTGRESQL_CPPFLAGS"
     AC_CHECK_HEADERS([libpq-fe.h],
index a6c776023743496533ad45209c4d626d6572c621..304706d7eef17955f15363a85d853db53b6dfac2 100644 (file)
@@ -6,3 +6,4 @@ timeout_watchdog
 gnunet_pyexpect.py
 gnunet_pyexpect.pyc
 pydiffer.pyc
+test_gnunet_prefix
index f0dfe58b3f271e845300189b9b035ab0f1136758..115ed77028e81781b190a75710d5c929871bf4ea 100644 (file)
Binary files a/doc/gnunet-c-tutorial.pdf and b/doc/gnunet-c-tutorial.pdf differ
index 069c1838fe272058445730f43e5c43d65c32d928..0f82a2e4b7924d6abad1061b48f1db038c500d1c 100644 (file)
@@ -1,12 +1,13 @@
 \documentclass[10pt]{article}
 \usepackage[ansinew]{inputenc}
 \usepackage{makeidx,amsmath,amssymb,exscale,multicol,epsfig,graphics,verbatim,ulem}
-\usepackage{epsfig,geometry,url,listings, subcaption}
+\usepackage{epsfig,geometry,url,listings,subcaption}
 \usepackage{boxedminipage}
 \usepackage[T1]{fontenc}%required
 \usepackage{textcomp}
 \geometry{headsep=3ex,hscale=0.9}
 \usepackage{hyperref}
+\usepackage{color}
 \hypersetup{pdftitle={GNUnet C Tutorial},
   pdfsubject={GNUnet},
   pdfauthor={Christian Grothoff <christian@grothoff.org>},
@@ -28,6 +29,26 @@ literate={*}{{\char42}}1
 
 \begin{document}
 
+\lstset{ %
+language=C,                     % choose the language of the code
+basicstyle=\footnotesize,       % the size of the fonts that are used for the code
+numbers=left,                   % where to put the line-numbers
+numberstyle=\footnotesize,      % the size of the fonts that are used for the line-numbers
+stepnumber=1,                   % the step between two line-numbers. If it is 1 each line will be numbered
+numbersep=5pt,                  % how far the line-numbers are from the code
+backgroundcolor=\color{white},  % choose the background color. You must add \usepackage{color}
+showspaces=false,               % show spaces adding particular underscores
+showstringspaces=false,         % underline spaces within strings
+showtabs=false,                 % show tabs within strings adding particular underscores
+frame=single,           % adds a frame around the code
+tabsize=2,          % sets default tabsize to 2 spaces
+captionpos=b,           % sets the caption-position to bottom
+breaklines=true,        % sets automatic line breaking
+breakatwhitespace=false,    % sets if automatic breaks should only happen at whitespace
+escapeinside={\%*}{*)}          % if you want to add a comment within your code
+}
+
+
 \begin{center}
 \large {A Tutorial for GNUnet 0.10.x (C version)}
 
@@ -68,20 +89,25 @@ You should also download the signature file and verify the integrity of the tarb
 \url{ftp://ftp.gnu.org/gnu/gnunet/gnunet-0.10.x.tar.gz.sig}
 \end{center}
 To verify the signature you should first import the GPG key used to sign the tarball
+\lstset{language=bash}
 \begin{lstlisting}
 $ gpg --keyserver keys.gnupg.net --recv-keys 48426C7E
 \end{lstlisting}
 And use this key to verify the tarball's signature
+\lstset{language=bash}
 \begin{lstlisting}
 $ gpg --verify gnunet-0.10.x.tar.gz.sig gnunet-0.10.x.tar.gz
 \end{lstlisting}
 After successfully verifying the integrity you can extract the tarball using
+\lstset{language=bash}
 \begin{lstlisting}
 $ tar xvzf gnunet-0.10.x.tar.gz
 $ mv gnunet-0.10.x gnunet              # we will use the directory "gnunet" in the remainder of this document
 $ cd gnunet
 \end{lstlisting}
 
+However, please note that stable versions can be very outdated, as a developer
+you are strongly encouraged to use the version from \url{https://gnunet.org/git/}.
 
 \subsection{Installing Build Tool Chain and Dependencies}
 
@@ -116,15 +142,15 @@ The remainder of this tutorial assumes that you have Git Master checked out.
 \subsection{Compiling and Installing GNUnet}
 
 First, you need to install at least {\tt libgnupgerror} version
-1.12\footnote{\url{ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.12.tar.bz2}}
+1.27\footnote{\url{ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.27.tar.bz2}}
 and {\tt libgcrypt} version
-1.6\footnote{\url{ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.6.0.tar.bz2}}.
+1.7.6\footnote{\url{ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.7.6.tar.bz2}}.
 
 \lstset{language=bash}
 \begin{lstlisting}
-$ wget ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.12.tar.bz2
-$ tar xf libgpg-error-1.12.tar.bz2
-$ cd libgpg-error-1.12
+$ wget ftp://ftp.gnupg.org/gcrypt/libgpg-error/libgpg-error-1.27.tar.bz2
+$ tar xf libgpg-error-1.27.tar.bz2
+$ cd libgpg-error-1.27
 $ ./configure
 $ sudo make install
 $ cd ..
@@ -132,9 +158,9 @@ $ cd ..
 
 \lstset{language=bash}
 \begin{lstlisting}
-$ wget ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.6.0.tar.bz2
-$ tar xf libgcrypt-1.6.0.tar.bz2
-$ cd libgcrypt-1.6.0
+$ wget ftp://ftp.gnupg.org/gcrypt/libgcrypt/libgcrypt-1.7.6.tar.bz2
+$ tar xf libgcrypt-1.7.6.tar.bz2
+$ cd libgcrypt-1.7.6
 $ ./configure
 $ sudo make install
 $ cd ..
@@ -176,12 +202,14 @@ $ touch ~/.config/gnunet.conf
 You should check your installation to ensure that installing GNUnet
 was successful up to this point. You should be able to access GNUnet's
 binaries and run GNUnet's self check.
+\lstset{language=bash}
 \begin{lstlisting}
 $ which gnunet-arm
 \end{lstlisting}
 should return \lstinline|$PREFIX/bin/gnunet-arm|. It should be
 located in your GNUnet installation and the output should not be
 empty. If you see an output like:
+\lstset{language=bash}
 \begin{lstlisting}
 $ which gnunet-arm
 $
@@ -189,29 +217,20 @@ $
 check your {\tt PATH} variable to ensure GNUnet's {\tt bin} directory is included.
 
 GNUnet provides tests for all of its subcomponents. Run
+\lstset{language=bash}
 \begin{lstlisting}
 $ make check
 \end{lstlisting}
 to execute tests for all components. {\tt make check} traverses all subdirectories in {\tt src}.
 For every subdirectory you should get a message like this:
 
-\begin{lstlisting}
+\begin{verbatim}
 make[2]: Entering directory `/home/$USER/gnunet/contrib'
 PASS: test_gnunet_prefix
 =============
 1 test passed
 =============
-\end{lstlisting}
-
-If you see a message like this:
-
-\begin{lstlisting}
-Mar 12 16:57:56-642482 resolver-api-19449 ERROR Must specify `HOSTNAME' for `resolver' in configuration!
-Mar 12 16:57:56-642573 test_program-19449 ERROR Assertion failed at resolver_api.c:204.
-/bin/bash: line 5: 19449 Aborted                 (core dumped) ${dir}$tst
-FAIL: test_program
-\end{lstlisting}
-double check the steps performed in ~\ref{sub:install}
+\end{verbatim}
 
 
 \section{Background: GNUnet Architecture}
@@ -262,6 +281,7 @@ First of all we need to configure your peer. Each peer is started with a configu
 
 Since we want to start additional peers later, we need
 some modifications from the default configuration. We need to create a separate service home and a file containing our modifications for this peer:
+\lstset{language=bash}
 \begin{lstlisting}
 $ mkdir ~/gnunet1/
 $ touch peer1.conf
@@ -271,12 +291,12 @@ Now add the following lines to peer1.conf to use this directory. For
 simplified usage we want to prevent the peer to connect to the GNUnet
 network since this could lead to confusing output. This modifications
 will replace the default settings:
-\begin{lstlisting}
+\begin{verbatim}
 [PATHS]
 GNUNET_HOME = ~/gnunet1/               # Use this directory to store GNUnet data
 [hostlist]
 SERVERS =                              # prevent bootstrapping
-\end{lstlisting}
+\end{verbatim}
 
 
 \subsection{Start a peer}
@@ -322,6 +342,7 @@ $ cd ~/gnunet/src/dht;
 $ ./gnunet-dht-monitor -c ~/peer1.conf -k KEY
 \end{lstlisting}
 Now open a separate terminal and change again to the \lstinline|gnunet/src/dht| directory:
+\lstset{language=bash}
 \begin{lstlisting}
 $ cd ~/gnunet/src/dht
 $ ./gnunet-dht-put -c ~/peer1.conf -k KEY -d VALUE             # put VALUE under KEY in the DHT
@@ -334,6 +355,11 @@ $ gnunet-statistics -c ~/peer1.conf -s dht # print statistics about DHT service
 
 \subsection{Starting Two Peers by Hand}
 
+This section describes how to start two peers on the same machine by hand.
+The process is rather painful, but the description is somewhat instructive.
+In practice, you might prefer the automated method described in
+Section~\ref{sec:testbed}.
+
 \subsubsection{Setup a second peer}
 We will now start a second peer on your machine.
 For the second peer, you will need to manually create a modified
@@ -348,13 +374,14 @@ To configure the second peer, use the files {\tt
 configuration file:
 %
 \lstset{language=bash}
+\lstset{language=bash}
 \begin{lstlisting}
 $ cat $PREFIX/share/gnunet/config.d/*.conf > peer2.conf
 \end{lstlisting}
 Now you have to edit {\tt peer2.conf} and change:
 \begin{itemize}
   \itemsep0em
-  \item{\texttt{SERVICEHOME} under \texttt{PATHS}}
+  \item{\texttt{GNUNET\_TEST\_HOME} under \texttt{PATHS}}
   \item{Every (uncommented) value for ``\texttt{PORT}'' (add 10000) in any
         section (the option may be commented out if \texttt{PORT} is
         prefixed by "\#", in this case, UNIX domain sockets are used
@@ -399,10 +426,10 @@ If you want the two peers to connect, you have multiple options:
 To setup peer 1 as bootstrapping server change the configuration of
 the first one to be a hostlist server by adding the following lines to
 \texttt{peer1.conf} to enable bootstrapping server:
- \begin{lstlisting}
+ \begin{verbatim}
 [hostlist]
 OPTIONS = -p
-\end{lstlisting}
+\end{verbatim}
 
 Then change {\tt peer2.conf} and replace the ``\texttt{SERVERS}'' line in the ``\texttt{[hostlist]}'' section with
 ``\texttt{http://localhost:8080/}''.  Restart both peers using:
@@ -432,12 +459,13 @@ If you want to use the \texttt{peerinfo} tool to connect your peers, you should:
 
 Check that they are connected using {\tt gnunet-core -c peer1.conf}, which should give you the other peer's
 peer identity:
+\lstset{language=bash}
 \begin{lstlisting}
 $ gnunet-core -c peer1.conf
 Peer `9TVUCS8P5A7ILLBGO6 [...shortened...] 1KNBJ4NGCHP3JPVULDG'
 \end{lstlisting}
 
-\subsection{Starting Peers Using the Testbed Service}
+\subsection{Starting Peers Using the Testbed Service} \label{sec:testbed}
 
 GNUnet's testbed service is used for testing scenarios where a number of peers
 are to be started.  The testbed can manage peers on a single host or on multiple
@@ -463,7 +491,8 @@ found in the testbed default configuration file \texttt{src/testbed/testbed.conf
 
 With the testbed API, a sample test case can be structured as follows:
 % <lynX> Is there a way to pick a more readable font for this include?
-\lstinputlisting[language=C]{testbed_test.c}
+\lstset{language=C}
+\lstinputlisting{testbed_test.c}
 The source code for the above listing can be found at
 \url{https://gnunet.org/git/gnunet.git/tree/doc/testbed_test.c}
 or in the {\tt doc/} folder of your repository check-out.
@@ -473,6 +502,8 @@ After installing GNUnet, the above source code can be compiled as:
 $ export CPPFLAGS="-I/path/to/gnunet/headers"
 $ export LDFLAGS="-L/path/to/gnunet/libraries"
 $ gcc $CPPFLAGS $LDFLAGS -o testbed-test testbed_test.c  -lgnunettestbed -lgnunetdht -lgnunetutil
+$ touch template.conf # Generate (empty) configuration
+$ ./testbed-test  # run it (press CTRL-C to stop)
 \end{lstlisting}
 The \texttt{CPPFLAGS} and \texttt{LDFLAGS} are necessary if GNUnet is installed
 into a different directory other than \texttt{/usr/local}.
@@ -593,7 +624,7 @@ command-line options, setup the scheduler and then invoke the {\tt
 to the parsed configuration (and the configuration file name that was
 used, which is typically not needed):
 
-\lstset{language=c}
+\lstset{language=C}
 \begin{lstlisting}
 #include <gnunet/platform.h>
 #include <gnunet/gnunet_util_lib.h>
@@ -606,7 +637,7 @@ run (void *cls,
      const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
-  /* main code here */
+  // main code here
   ret = 0;
 }
 
@@ -632,6 +663,7 @@ expanding the {\tt options} array.  For example, the following would
 add a string-option and a binary flag (defaulting to {\tt NULL} and
 {\tt GNUNET\_NO} respectively):
 
+\lstset{language=C}
 \begin{lstlisting}
 static char *string_option;
 static int a_flag;
@@ -696,7 +728,7 @@ file).
 Before a client library can implement the application-specific protocol
 with the service, a connection must be created:
 
-\lstset{language=c}
+\lstset{language=C}
 \begin{lstlisting}
   struct GNUNET_MQ_MessageHandlers handlers[] = {
     // ...
@@ -723,36 +755,26 @@ In GNUnet, messages are always sent beginning with a {\tt struct GNUNET\_Message
 in big endian format. This header defines the size and the type of the
 message, the payload follows after this header.
 
-\lstset{language=c}
+\lstset{language=C}
 \begin{lstlisting}
 struct GNUNET_MessageHeader
 {
-
-  /**
-   * The length of the struct (in bytes, including the length field itself),
-   * in big-endian format.
-   */
   uint16_t size GNUNET_PACKED;
-
-  /**
-   * The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
-   */
   uint16_t type GNUNET_PACKED;
-
 };
 \end{lstlisting}
 
 Existing message types are defined in {\tt gnunet\_protocols.h}\\
 A common way to create a message is with an envelope:
 
-\lstset{language=c}
+\lstset{language=C}
 \begin{lstlisting}
 struct GNUNET_MQ_Envelope *env;
 struct GNUNET_MessageHeader *msg;
 
 env = GNUNET_MQ_msg_extra (msg, payload_size, GNUNET_MY_MESSAGE_TYPE);
 memcpy (&msg[1], &payload, payload_size);
-/* Send message via message queue 'mq': */
+// Send message via message queue 'mq'
 GNUNET_mq_send (mq, env);
 \end{lstlisting}
 
@@ -785,38 +807,19 @@ and {\tt handle\_} are mandatory.
 
 \lstset{language=c}
 \begin{lstlisting}
-/**
- * Function called with MyMessage messages from service.
- *
- * @param cls closure
- * @param msg message received
- */
 static void
 handle_fix (void *cls, const struct MyMessage *msg)
 {
   // process 'msg'
 }
 
-/**
- * Function called with MyVarMessage messages from service.
- *
- * @param cls closure
- * @param msg message received
- * @return #GNUNET_OK if @a msg is well-formed
- */
 static int
 check_var (void *cls, const struct MyVarMessage *msg)
 {
   // check 'msg' is well-formed
-  return GNUNET_OK; /* suppose yes */
+  return GNUNET_OK;
 }
 
-/**
- * Function called with MyMessage messages from service.
- *
- * @param cls closure
- * @param msg message received
- */
 static void
 handle_var (void *cls, const struct MyVarMessage *msg)
 {
@@ -900,13 +903,6 @@ like this:
 
 \lstset{language=c}
 \begin{lstlisting}
-/**
- * Launch service.
- *
- * @param cls closure
- * @param c configuration to use
- * @param service the initialized service
- */
 static void
 run (void *cls,
      const struct GNUNET_CONFIGURATION_Handle *c,
@@ -914,14 +910,6 @@ run (void *cls,
 {
 }
 
-/**
- * Callback called when a client connects to the service.
- *
- * @param cls closure for the service
- * @param c the new client that connected to the service
- * @param mq the message queue used to send messages to the client
- * @return @a c
- */
 static void *
 client_connect_cb (void *cls,
                   struct GNUNET_SERVICE_Client *c,
@@ -930,13 +918,6 @@ client_connect_cb (void *cls,
   return c;
 }
 
-/**
- * Callback called when a client disconnected from the service
- *
- * @param cls closure for the service
- * @param c the client that disconnected
- * @param internal_cls should be equal to @a c
- */
 static void
 client_disconnect_cb (void *cls,
                      struct GNUNET_SERVICE_Client *c,
@@ -988,11 +969,7 @@ GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
                      GNUNET_CORE_StartupCallback init,
                      GNUNET_CORE_ConnectEventHandler connects,
                      GNUNET_CORE_DisconnectEventHandler disconnects,
-                     GNUNET_CORE_MessageCallback inbound_notify,
-                     int inbound_hdr_only,
-                     GNUNET_CORE_MessageCallback outbound_notify,
-                     int outbound_hdr_only,
-                     const struct GNUNET_CORE_MessageHandler *handlers);
+                     const struct GNUNET_MQ_MessageHandler *handlers);
 \end{lstlisting}
 
 \subsection{New P2P connections}
@@ -1003,45 +980,33 @@ which communicates the identity of the new peer to the service:
 
 \lstset{language=C}
 \begin{lstlisting}
-void
+void *
 connects (void *cls,
-         const struct GNUNET_PeerIdentity * peer)
+          const struct GNUNET_PeerIdentity *peer,
+          struct GNUNET_MQ_Handle *mq)
 {
-    /* Save identity for later use */
-    /* Optional: start sending messages to peer */
+  return mq;
 }
 \end{lstlisting}
 
+Note that whatever you return from {\tt connects} is given as the
+{\it cls} argument to the message handlers for messages from
+the respective peer.
+
 \exercise{Create a service that connects to the \texttt{CORE}.  Then
 start (and connect) two peers and print a message once your connect
 callback is invoked.}
 
 \subsection{Receiving P2P Messages}
 
-To receive messages from \texttt{CORE}, services register a set of handlers
-(parameter {\tt *handlers} in the \lstinline|GNUNET_CORE_connect| call that are called by \texttt{CORE}
-when a suitable message arrives.
+To receive messages from \texttt{CORE}, you pass the desired
+{\em handlers} to the {\tt GNUNET\_CORE\_connect()} function,
+just as we showed for services.
 
-\lstset{language=c}
-\begin{lstlisting}
-static int
-callback_function_for_type_one(void *cls,
-                               const struct GNUNET_PeerIdentity *peer,
-                               const struct GNUNET_MessageHeader *message)
-{
-    /* Do stuff */
-    return GNUNET_OK; /* or GNUNET_SYSERR to close the connection */
-}
-
-/**
- * Functions to handle messages from core
- */
-static struct GNUNET_CORE_MessageHandler core_handlers[] = {
-  {&callback_function_for_type_one, GNUNET_MESSAGE_TYPE_MYSERVICE_TYPE_ONE, 0},
-  /* more handlers*/
-  {NULL, 0, 0}
-};
-\end{lstlisting}
+It is your responsibility to process messages fast enough or
+to implement flow control. If an application does not process
+CORE messages fast enough, CORE will randomly drop messages
+to not keep a very long queue in memory.
 
 \exercise{Start one peer with a new service that has a message
 handler and start a second peer that only has your ``old'' service
@@ -1051,29 +1016,13 @@ the two peers are connected?  Why?}
 
 \subsection{Sending P2P Messages}
 
-In response to events (connect, disconnect, inbound messages,
-timing, etc.) services can then use this API to transmit messages:
+You can transmit messages to other peers using the {\it mq} you were
+given during the {\tt connect} callback.  Note that the {\it mq}
+automatically is released upon {\tt disconnect} and that you must
+not use it afterwards.
 
-\lstset{language=C}
-\begin{lstlisting}
-typedef size_t
-(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
-                                          size_t size,
-                                          void *buf)
-{
-    /* Fill "*buf" with up to "size" bytes, must start with GNUNET_MessageHeader */
-    return n; /* Total size of the message put in "*buf" */
-}
-
-struct GNUNET_CORE_TransmitHandle *
-GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle,
-                                   int cork, uint32_t priority,
-                                   struct GNUNET_TIME_Relative maxdelay,
-                                   const struct GNUNET_PeerIdentity *target,
-                                   size_t notify_size,
-                                   GNUNET_CONNECTION_TransmitReadyNotify notify,
-                                   void *notify_cls);
-\end{lstlisting}
+It is your responsibility to not over-fill the message queue, GNUnet
+will send the messages roughly in the order given as soon as possible.
 
 \exercise{Write a service that upon connect sends messages as
 fast as possible to the other peer (the other peer should run a
@@ -1258,22 +1207,21 @@ and other unfavorable events, just make several PUT requests!
 
 \lstset{language=C}
 \begin{lstlisting}
-void
+static void
 message_sent_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-    /* Request has left local node */
+  // Request has left local node
 }
 
 struct GNUNET_DHT_PutHandle *
 GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
                 const struct GNUNET_HashCode *key,
                 uint32_t desired_replication_level,
-                enum GNUNET_DHT_RouteOption options, /* Route options, see next call */
+                enum GNUNET_DHT_RouteOption options,
                 enum GNUNET_BLOCK_Type type, size_t size, const void *data,
-                struct GNUNET_TIME_Absolute exp, /* When does the data expire? */
-                struct GNUNET_TIME_Relative timeout,  /* How long to try to send the request */
-                GNUNET_DHT_PutContinuation cont,
-                void *cont_cls)
+                struct GNUNET_TIME_Absolute exp,
+                struct GNUNET_TIME_Relative timeout,
+                GNUNET_DHT_PutContinuation cont, void *cont_cls)
 \end{lstlisting}
 
 \exercise{Store a value in the DHT periodically to make sure it is available
@@ -1305,9 +1253,8 @@ get_result_iterator (void *cls, struct GNUNET_TIME_Absolute expiration,
                      unsigned int put_path_length,
                      enum GNUNET_BLOCK_Type type, size_t size, const void *data)
 {
-    /* Do stuff with the data and/or route */
-    /* Optionally: */
-    GNUNET_DHT_get_stop (get_handle);
+  // Optionally:
+  GNUNET_DHT_get_stop (get_handle);
 }
 
 get_handle =
@@ -1315,9 +1262,9 @@ get_handle =
                             block_type,
                             &key,
                             replication,
-                            GNUNET_DHT_RO_NONE, /* Route options */
-                            NULL, /* xquery: not used here */
-                            0, /* xquery size */
+                            GNUNET_DHT_RO_NONE,
+                            NULL,
+                            0,
                             &get_result_iterator,
                             cls)
 \end{lstlisting}
@@ -1356,13 +1303,13 @@ static enum GNUNET_BLOCK_EvaluationResult
 block_plugin_SERVICE_evaluate (void *cls,
                               enum GNUNET_BLOCK_Type type,
                               struct GNUNET_BlockGroup *bg,
-                             const GNUNET_HashCode *query,
-                             const void *xquery,
-                             size_t xquery_size,
-                             const void *reply_block,
-                             size_t reply_block_size)
+                              const GNUNET_HashCode *query,
+                              const void *xquery,
+                              size_t xquery_size,
+                              const void *reply_block,
+                              size_t reply_block_size)
 {
-  /* Verify type, block and bg */
+  // Verify type, block and bg
 }
 \end{lstlisting}
 
@@ -1385,10 +1332,10 @@ just fine with such blocks).
 \begin{lstlisting}
 static int
 block_plugin_SERVICE_get_key (void *cls, enum GNUNET_BLOCK_Type type,
-                              const void *block, size_t block_size,
-                              struct GNUNET_HashCode *key)
+                             const void *block, size_t block_size,
+                             struct GNUNET_HashCode *key)
 {
-    /* Store the key in the key argument, return GNUNET_OK on success. */
+  // Store the key in the key argument, return GNUNET_OK on success.
 }
 \end{lstlisting}
 
@@ -1407,8 +1354,8 @@ libgnunet_plugin_block_SERVICE_init (void *cls)
 {
   static enum GNUNET_BLOCK_Type types[] =
   {
-    GNUNET_BLOCK_TYPE_SERVICE_BLOCKYPE, /* list of blocks we care about, from gnunet_block_lib.h */
-    GNUNET_BLOCK_TYPE_ANY       /* end of list */
+    GNUNET_BLOCK_TYPE_SERVICE_BLOCKYPE,
+    GNUNET_BLOCK_TYPE_ANY
   };
   struct GNUNET_BLOCK_PluginFunctions *api;
 
@@ -1483,7 +1430,7 @@ to allow for filtering of messages. When an event happens, the appropiate callba
 is called with all the information about the event.
 \lstset{language=C}
 \begin{lstlisting}
-void
+static void
 get_callback (void *cls,
               enum GNUNET_DHT_RouteOption options,
               enum GNUNET_BLOCK_Type type,
@@ -1495,7 +1442,8 @@ get_callback (void *cls,
 {
 }
 
-void
+
+static void
 get_resp_callback (void *cls,
                    enum GNUNET_BLOCK_Type type,
                    const struct GNUNET_PeerIdentity *get_path,
@@ -1509,7 +1457,8 @@ get_resp_callback (void *cls,
 {
 }
 
-void
+
+static void
 put_callback (void *cls,
               enum GNUNET_DHT_RouteOption options,
               enum GNUNET_BLOCK_Type type,
@@ -1524,13 +1473,14 @@ put_callback (void *cls,
 {
 }
 
+
 monitor_handle = GNUNET_DHT_monitor_start (dht_handle,
-                                           block_type, /* GNUNET_BLOCK_TYPE_ANY for all */
-                                           key, /* NULL for all */
-                                           &get_callback,
-                                           &get_resp_callback,
-                                           &put_callback,
-                                           cls);
+                                          block_type,
+                                          key,
+                                          &get_callback,
+                                          &get_resp_callback,
+                                          &put_callback,
+                                          cls);
 \end{lstlisting}
 
 
index 867a59f65a1c822e5339f0a77de2a1c21709c84d..d95cf851c450af0e0f3fcabdf362213644ca09e4 100644 (file)
@@ -1,17 +1,52 @@
 .TH GNUNET\-CADET 1 "May 3, 2016" "GNUnet"
 
 .SH NAME
-gnunet\-cadet \- Print information about CADET tunnels and peers
+gnunet\-cadet \- Create or obtain information about CADET tunnels and peers
 
 .SH SYNOPSIS
 .B gnunet\-cadet
 .RI [ options ]
+.I [ \fIPEER_ID SHARED_SECRET\fR ]
 .br
 
 .SH DESCRIPTION
 \fBgnunet\-cadet\fP prints information about CADET tunnels and peers.
+It can also be used for command-line based CADET tunnels using the
+\fI-o SHARED_SECRET\fR option to open a port on a receiving PEER_ID
+and using "\fBgnunet\-cadet\fP \fIPEER_ID SHARED_SECRET\fR" to
+establish one circuit to that peer from any other peer. The receiving
+process will only accept one incoming circuit, but several commands
+using the same \fI-o\fR can be issued to satisfy multiple requests.
+For one-to-many communication \fBgnunet\-social\fP may be better
+suited, however.
 
-.SH OPTIONS
+.SH SPECIFIC OPTIONS
+.B
+.IP "\-C CONNECTION_ID,  \-\-connection=CONNECTION_ID"
+Provide information about a particular connection.
+.B
+.IP "\-d,  \-\-dump"
+Dump debug information to STDERR.
+.B
+.IP "\-e,  \-\-echo"
+Activate echo mode.
+.B
+.IP "\-o SHARED_SECRET,  \-\-open-port=SHARED_SECRET"
+Listen for connections using a shared secret among sender and recipient.
+.B
+.IP "\-p PEER_ID,  \-\-peer=PEER_ID"
+Provide information about a patricular peer.
+.B
+.IP "\-P,  \-\-peers"
+Provide information about all peers.
+.B
+.IP "\-t TUNNEL_ID,  \-\-tunnel=TUNNEL_ID"
+Provide information about a patricular tunnel.
+.B
+.IP "\-T,  \-\-tunnels"
+Provide information about all tunnels.
+
+.SH STANDARD OPTIONS
 .B
 .IP "\-c FILENAME,  \-\-config=FILENAME"
 Use the configuration file FILENAME.
@@ -19,17 +54,11 @@ Use the configuration file FILENAME.
 .IP "\-h, \-\-help"
 Print short help on options.
 .B
-.IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL"
-Use LOGLEVEL for logging.  Valid values are DEBUG, INFO, WARNING and ERROR.
-.B
 .IP "\-l LOGFILE, \-\-logfile=LOGFILE"
 Configure logging to write logs to LOGFILE.
 .B
-.IP "\-m, \-\-monitor"
-Provide information about all tunnels (continuously) NOT IMPLEMENTED.
-.B
-.IP "\-t OWNER\_ID:TUNNEL\_ID, \-\-tunnel=OWNER\_ID:TUNNEL\_ID"
-Provide information about a particular tunnel.
+.IP "\-L LOGLEVEL, \-\-loglevel=LOGLEVEL"
+Use LOGLEVEL for logging.  Valid values are DEBUG, INFO, WARNING and ERROR.
 .B
 .IP "\-v, \-\-version"
 Print GNUnet version number.
index 0ef0980af0a5fa89d651338b292eb5a603a30657..1696234b0535231aa58698526759b133037a078a 100644 (file)
@@ -4,65 +4,35 @@
 #include <gnunet/gnunet_testbed_service.h>
 #include <gnunet/gnunet_dht_service.h>
 
-/* Number of peers we want to start */
 #define NUM_PEERS 20
 
 static struct GNUNET_TESTBED_Operation *dht_op;
 
 static struct GNUNET_DHT_Handle *dht_handle;
 
-static struct GNUNET_SCHEDULER_Task * shutdown_tid;
 
-
-/**
- * Closure to 'dht_ca' and 'dht_da' DHT adapters.
- */
 struct MyContext
 {
-  /**
-   * Argument we pass to GNUNET_DHT_connect.
-   */
   int ht_len;
 } ctxt;
 
 
-/**
- * Global result for testcase.
- */
 static int result;
 
 
-/**
- * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
- * Cleans up.
- */
 static void
 shutdown_task (void *cls)
 {
-  shutdown_tid = NULL;
   if (NULL != dht_op)
   {
-    GNUNET_TESTBED_operation_done (dht_op); /* indirectly calls the dht_da() for closing
-                                               down the connection to the DHT */
+    GNUNET_TESTBED_operation_done (dht_op);
     dht_op = NULL;
     dht_handle = NULL;
   }
   result = GNUNET_OK;
-  GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
 }
 
 
-/**
- * This is where the test logic should be, at least that
- * part of it that uses the DHT of peer "0".
- *
- * @param cls closure, for the example: NULL
- * @param op should be equal to "dht_op"
- * @param ca_result result of the connect operation, the
- *        connection to the DHT service
- * @param emsg error message, if testbed somehow failed to
- *        connect to the DHT.
- */
 static void
 service_connect_comp (void *cls,
                       struct GNUNET_TESTBED_Operation *op,
@@ -71,72 +41,31 @@ service_connect_comp (void *cls,
 {
   GNUNET_assert (op == dht_op);
   dht_handle = ca_result;
-  /* Service to DHT successful; here we'd usually do something
-     with the DHT (ok, if successful) */
-
-  /* for now, just indiscriminately terminate after 10s */
-  GNUNET_SCHEDULER_cancel (shutdown_tid);
-  shutdown_tid = GNUNET_SCHEDULER_add_delayed
-      (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
-       &shutdown_task, NULL);
+  // Do work here...
+  GNUNET_SCHEDULER_shutdown ();
 }
 
 
-/**
- * Testbed has provided us with the configuration to access one
- * of the peers and it is time to do "some" connect operation to
- * "some" subsystem of the peer.  For this example, we connect
- * to the DHT subsystem.  Testbed doesn't know which subsystem,
- * so we need these adapters to do the actual connecting (and
- * possibly pass additional options to the subsystem connect
- * function, such as the "ht_len" argument for the DHT).
- *
- * @param cls closure
- * @param cfg peer configuration (here: peer[0]
- * @return NULL on error, otherwise some handle to access the
- *         subsystem
- */
 static void *
 dht_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   struct MyContext *ctxt = cls;
 
-  /* Use the provided configuration to connect to service */
   dht_handle = GNUNET_DHT_connect (cfg, ctxt->ht_len);
   return dht_handle;
 }
 
 
-/**
- * Dual of 'dht_ca' to perform the 'disconnect'/cleanup operation
- * once we no longer need to access this subsystem.
- *
- * @param cls closure
- * @param op_result whatever we returned from 'dht_ca'
- */
 static void
 dht_da (void *cls, void *op_result)
 {
   struct MyContext *ctxt = cls;
 
-  /* Disconnect from DHT service */
   GNUNET_DHT_disconnect ((struct GNUNET_DHT_Handle *) op_result);
   dht_handle = NULL;
 }
 
 
-/**
- * Main function inovked from TESTBED once all of the
- * peers are up and running.  This one then connects
- * just to the DHT service of peer 0.
- *
- * @param cls closure
- * @param h the run handle
- * @param peers started peers for the test
- * @param num_peers size of the 'peers' array
- * @param links_succeeded number of links between peers that were created
- * @param links_failed number of links testbed was unable to establish
- */
 static void
 test_master (void *cls,
              struct GNUNET_TESTBED_RunHandle *h,
@@ -145,27 +74,12 @@ test_master (void *cls,
              unsigned int links_succeeded,
              unsigned int links_failed)
 {
-  /* Testbed is ready with peers running and connected in a pre-defined overlay
-     topology  */
-
-  /* do something */
   ctxt.ht_len = 10;
-
-  /* connect to a peers service */
   dht_op = GNUNET_TESTBED_service_connect
-      (NULL,                    /* Closure for operation */
-       peers[0],                /* The peer whose service to connect to */
-       "dht",                   /* The name of the service */
-       service_connect_comp,    /* callback to call after a handle to service
-                                   is opened */
-       NULL,                    /* closure for the above callback */
-       dht_ca,                  /* callback to call with peer's configuration;
-                                   this should open the needed service connection */
-       dht_da,                  /* callback to be called when closing the
-                                   opened service connection */
-       &ctxt);                  /* closure for the above two callbacks */
-  shutdown_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                               &shutdown_task, NULL);
+      (NULL, peers[0], "dht",
+       &service_connect_comp, NULL,
+       &dht_ca, &dht_da, &ctxt);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
 }
 
 
@@ -176,15 +90,9 @@ main (int argc, char **argv)
 
   result = GNUNET_SYSERR;
   ret = GNUNET_TESTBED_test_run
-      ("awesome-test",  /* test case name */
-       "template.conf", /* template configuration */
-       NUM_PEERS,       /* number of peers to start */
-       0LL, /* Event mask - set to 0 for no event notifications */
-       NULL, /* Controller event callback */
-       NULL, /* Closure for controller event callback */
-       &test_master, /* continuation callback to be called when testbed setup is
-                        complete */
-       NULL); /* Closure for the test_master callback */
+      ("awesome-test", "template.conf",
+       NUM_PEERS, 0LL,
+       NULL, NULL, &test_master, NULL);
   if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
     return 1;
   return 0;
index 6c156336b18337c89e4539cfec9752758a4b0f00..c73881fefd42cee3c446a04534e5a384deb8948b 100644 (file)
@@ -37,31 +37,19 @@ src/block/block.c
 src/block/plugin_block_template.c
 src/block/plugin_block_test.c
 src/cadet/cadet_api.c
-src/cadet/cadet_api_new.c
-src/cadet/cadet_common.c
-src/cadet/cadet_path.c
 src/cadet/cadet_test_lib.c
-src/cadet/cadet_test_lib_new.c
 src/cadet/desirability_table.c
 src/cadet/gnunet-cadet.c
 src/cadet/gnunet-cadet-profiler.c
 src/cadet/gnunet-service-cadet.c
 src/cadet/gnunet-service-cadet_channel.c
 src/cadet/gnunet-service-cadet_connection.c
+src/cadet/gnunet-service-cadet_core.c
 src/cadet/gnunet-service-cadet_dht.c
 src/cadet/gnunet-service-cadet_hello.c
-src/cadet/gnunet-service-cadet_local.c
-src/cadet/gnunet-service-cadet-new.c
-src/cadet/gnunet-service-cadet-new_channel.c
-src/cadet/gnunet-service-cadet-new_connection.c
-src/cadet/gnunet-service-cadet-new_core.c
-src/cadet/gnunet-service-cadet-new_dht.c
-src/cadet/gnunet-service-cadet-new_hello.c
-src/cadet/gnunet-service-cadet-new_paths.c
-src/cadet/gnunet-service-cadet-new_peer.c
-src/cadet/gnunet-service-cadet-new_tunnels.c
+src/cadet/gnunet-service-cadet_paths.c
 src/cadet/gnunet-service-cadet_peer.c
-src/cadet/gnunet-service-cadet_tunnel.c
+src/cadet/gnunet-service-cadet_tunnels.c
 src/consensus/consensus_api.c
 src/consensus/gnunet-consensus-profiler.c
 src/consensus/gnunet-service-consensus.c
@@ -165,7 +153,6 @@ src/fs/gnunet-service-fs_cadet_client.c
 src/fs/gnunet-service-fs_cadet_server.c
 src/fs/gnunet-service-fs_cp.c
 src/fs/gnunet-service-fs_indexing.c
-src/fs/gnunet-service-fs_lc.c
 src/fs/gnunet-service-fs_pe.c
 src/fs/gnunet-service-fs_pr.c
 src/fs/gnunet-service-fs_push.c
@@ -311,6 +298,7 @@ src/rest/gnunet-rest-server.c
 src/rest/rest.c
 src/revocation/gnunet-revocation.c
 src/revocation/gnunet-service-revocation.c
+src/revocation/plugin_block_revocation.c
 src/revocation/revocation_api.c
 src/rps/gnunet-rps.c
 src/rps/gnunet-service-rps.c
@@ -339,6 +327,7 @@ src/set/gnunet-set-ibf-profiler.c
 src/set/gnunet-set-profiler.c
 src/set/ibf.c
 src/set/ibf_sim.c
+src/set/plugin_block_set_test.c
 src/set/set_api.c
 src/social/gnunet-service-social.c
 src/social/gnunet-social.c
@@ -413,6 +402,10 @@ src/transport/plugin_transport_udp_broadcasting.c
 src/transport/plugin_transport_udp.c
 src/transport/plugin_transport_unix.c
 src/transport/plugin_transport_wlan.c
+src/transport/tcp_connection_legacy.c
+src/transport/tcp_server_legacy.c
+src/transport/tcp_server_mst_legacy.c
+src/transport/tcp_service_legacy.c
 src/transport/transport_api_address_to_string.c
 src/transport/transport_api_blacklist.c
 src/transport/transport_api_core.c
@@ -436,7 +429,6 @@ src/util/common_endian.c
 src/util/common_logging.c
 src/util/configuration.c
 src/util/configuration_loader.c
-src/util/connection.c
 src/util/container_bloomfilter.c
 src/util/container_heap.c
 src/util/container_meta_data.c
@@ -483,11 +475,9 @@ src/util/plugin.c
 src/util/program.c
 src/util/resolver_api.c
 src/util/scheduler.c
-src/util/server.c
 src/util/server_mst.c
 src/util/server_nc.c
 src/util/server_tc.c
-src/util/service.c
 src/util/service_new.c
 src/util/signal.c
 src/util/socks.c
index a613438334fad05bfbe480f98098b2d467362cac..56af544b162b99a9e45ba9af803107f7d3cc63fc 100644 (file)
@@ -753,7 +753,7 @@ change_service (struct GNUNET_ARM_Handle *h,
 
   slen = strlen (service_name) + 1;
   if (slen + sizeof (struct GNUNET_ARM_Message) >=
-      GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return NULL;
index 65a6463cfbb9be879761e27c0237b65dc67ffc93..78c78738a1d5d3b2c65dc713bf70acff159b59fa 100644 (file)
@@ -121,12 +121,12 @@ static struct GNUNET_SCHEDULER_Task *timeout_task;
 /**
  * Do we want to give our stdout to gnunet-service-arm?
  */
-static unsigned int no_stdout;
+static int no_stdout;
 
 /**
  * Do we want to give our stderr to gnunet-service-arm?
  */
-static unsigned int no_stderr;
+static int no_stderr;
 
 /**
  * Handle for the task running the #action_loop().
@@ -220,14 +220,8 @@ req_string (enum GNUNET_ARM_RequestStatus rs)
   {
   case GNUNET_ARM_REQUEST_SENT_OK:
     return _("Message was sent successfully");
-  case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
-    return _("Misconfiguration (can not connect to the ARM service)");
   case GNUNET_ARM_REQUEST_DISCONNECTED:
     return _("We disconnected from ARM before we could send a request");
-  case GNUNET_ARM_REQUEST_BUSY:
-    return _("ARM API is busy");
-  case GNUNET_ARM_REQUEST_TIMEOUT:
-    return _("Request timed out");
   }
   return _("Unknown request status");
 }
@@ -245,27 +239,27 @@ ret_string (enum GNUNET_ARM_Result result)
   switch (result)
   {
   case GNUNET_ARM_RESULT_STOPPED:
-    return _("%s is stopped");
+    return _("is stopped");
   case GNUNET_ARM_RESULT_STARTING:
-    return _("%s is starting");
+    return _("is starting");
   case GNUNET_ARM_RESULT_STOPPING:
-    return _("%s is stopping");
+    return _("is stopping");
   case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
-    return _("%s is starting already");
+    return _("is starting already");
   case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
-    return _("%s is stopping already");
+    return _("is stopping already");
   case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
-    return _("%s is started already");
+    return _("is started already");
   case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
-    return _("%s is stopped already");
+    return _("is stopped already");
   case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
-    return _("%s service is not known to ARM");
+    return _("service is not known to ARM");
   case GNUNET_ARM_RESULT_START_FAILED:
-    return _("%s service failed to start");
+    return _("service failed to start");
   case GNUNET_ARM_RESULT_IN_SHUTDOWN:
-    return _("%s service cannot be started because ARM is shutting down");
+    return _("service cannot be manipulated because ARM is shutting down");
   }
-  return _("%.s Unknown result code.");
+  return _("Unknown result code.");
 }
 
 
@@ -378,10 +372,9 @@ stop_callback (void *cls,
       (GNUNET_ARM_RESULT_STOPPED != result) &&
       (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
   {
-    GNUNET_asprintf (&msg, "%s",
-                    _("Failed to stop the ARM service: %s\n"));
-    FPRINTF (stdout, msg, ret_string (result));
-    GNUNET_free (msg);
+    FPRINTF (stdout,
+             _("Failed to stop the ARM service: %s\n"),
+             ret_string (result));
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
@@ -476,11 +469,10 @@ term_callback (void *cls,
   if ((GNUNET_ARM_RESULT_STOPPED != result) &&
       (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY != result))
   {
-    GNUNET_asprintf (&msg,
-                    _("Failed to kill the `%s' service: %s\n"),
-                     term, ret_string (result));
-    FPRINTF (stdout, "%s", msg);
-    GNUNET_free (msg);
+    FPRINTF (stdout,
+             _("Failed to kill the `%s' service: %s\n"),
+             term,
+             ret_string (result));
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
@@ -770,35 +762,70 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'e', "end", NULL, gettext_noop ("stop all GNUnet services"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &end},
-    {'i', "init", "SERVICE", gettext_noop ("start a particular service"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &init},
-    {'k', "kill", "SERVICE", gettext_noop ("stop a particular service"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &term},
-    {'s', "start", NULL, gettext_noop ("start all GNUnet default services"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &start},
-    {'r', "restart", NULL,
-     gettext_noop ("stop and start all GNUnet default services"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &restart},
-    {'d', "delete", NULL,
-     gettext_noop ("delete config file and directory on exit"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &delete},
-    {'m', "monitor", NULL,
-     gettext_noop ("monitor ARM activities"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &monitor},
-    {'q', "quiet", NULL, gettext_noop ("don't print status messages"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &quiet},
-    {'T', "timeout", "DELAY",
-     gettext_noop ("exit with error status if operation does not finish after DELAY"),
-     GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &timeout},
-    {'I', "info", NULL, gettext_noop ("list currently running services"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &list},
-    {'O', "no-stdout", NULL, gettext_noop ("don't let gnunet-service-arm inherit standard output"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &no_stdout},
-    {'E', "no-stderr", NULL, gettext_noop ("don't let gnunet-service-arm inherit standard error"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &no_stderr},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('e',
+                                  "end",
+                                  gettext_noop ("stop all GNUnet services"),
+                                  &end),
+
+    GNUNET_GETOPT_OPTION_STRING ('i',
+                                 "init",
+                                 "SERVICE",
+                                 gettext_noop ("start a particular service"),
+                                 &init),
+
+    GNUNET_GETOPT_OPTION_STRING ('k',
+                                 "kill",
+                                 "SERVICE",
+                                 gettext_noop ("stop a particular service"),
+                                 &term),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('s',
+                                  "start",
+                                  gettext_noop ("start all GNUnet default services"),
+                                  &start),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('r',
+                                  "restart",
+                                  gettext_noop ("stop and start all GNUnet default services"),
+                                  &restart),
+    GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                  "delete",
+                                  gettext_noop ("delete config file and directory on exit"),
+                                  &delete),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('m',
+                                  "monitor",
+                                  gettext_noop ("monitor ARM activities"),
+                                  &monitor),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('q',
+                                  "quiet",
+                                  gettext_noop ("don't print status messages"),
+                                  &quiet),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('T',
+                                            "timeout",
+                                            "DELAY",
+                                            gettext_noop ("exit with error status if operation does not finish after DELAY"),
+                                            &timeout),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('I',
+                                  "info",
+                                  gettext_noop ("list currently running services"),
+                                  &list), 
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('O',
+                                  "no-stdout",
+                                  gettext_noop ("don't let gnunet-service-arm inherit standard output"),
+                                  &no_stdout),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('E',
+                                  "no-stderr",
+                                  gettext_noop ("don't let gnunet-service-arm inherit standard error"),
+                                  &no_stderr),
+
     GNUNET_GETOPT_OPTION_END
   };
 
index 4f3e964e3183e957f28fe5911ebf17153954afdd..19088c5cb7ec57bd526ead12252651986169bba1 100644 (file)
@@ -812,6 +812,7 @@ start_process (struct ServiceList *sl,
                        "%s %s",
                        fin_options,
                        optpos);
+      GNUNET_free (fin_options);
       GNUNET_free (optpos);
     }
     else
@@ -2224,7 +2225,7 @@ main (int argc,
   shc_chld =
     GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD,
                                    &sighandler_child_death);
-  ret = GNUNET_SERVICE_ruN_ (argc,
+  ret = GNUNET_SERVICE_run_ (argc,
                              argv,
                              "arm",
                              GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN,
index 56f8f2223e6a0633b51fd6e2be96024a1475c18a..0f32df51108285600f7112fa688d04109cb06fb8 100644 (file)
@@ -81,15 +81,19 @@ evaluate (struct GNUNET_TIME_Relative duration_total)
 
 
   duration = (duration_total.rel_value_us / (1000 * 1000));
+  if (0 == duration)
+    duration = 1;
   for (c_m = 0; c_m < e->num_masters; c_m++)
   {
     mp = &masters_p[c_m];
     fprintf (stderr,
-        _("Master [%u]: sent: %u KiB in %u sec. = %u KiB/s, received: %u KiB in %u sec. = %u KiB/s\n"),
-        mp->no, mp->total_bytes_sent / 1024, duration,
-        (mp->total_bytes_sent / 1024) / duration,
-        mp->total_bytes_received / 1024, duration,
-        (mp->total_bytes_received / 1024) / duration);
+             _("Master [%u]: sent: %u KiB in %u sec. = %u KiB/s, received: %u KiB in %u sec. = %u KiB/s\n"),
+             mp->no, mp->total_bytes_sent / 1024,
+             duration,
+             (mp->total_bytes_sent / 1024) / duration,
+             mp->total_bytes_received / 1024,
+             duration,
+             (mp->total_bytes_received / 1024) / duration);
 
     for (c_s = 0; c_s < e->num_slaves; c_s++)
     {
index 0e49a3a323976b6b76b9795bcccf13754fda69ad..1bb7fdee7587415860780e5b46f30d0b1659ed3e 100644 (file)
@@ -331,12 +331,14 @@ load_episode (struct Experiment *e,
             o->pref_type = GNUNET_ATS_PREFERENCE_LATENCY;
           else
           {
-              fprintf (stderr, "Invalid preference in operation %u `%s' in episode %u\n",
-                  op_counter, op, cur->id);
+              fprintf (stderr,
+                       "Invalid preference in operation %u `%s' in episode %u\n",
+                       op_counter,
+                       op,
+                       cur->id);
               GNUNET_free (type);
               GNUNET_free (op_name);
               GNUNET_free (op);
-              GNUNET_free (pref);
               GNUNET_free (sec_name);
               GNUNET_free_non_null (pref);
               GNUNET_free (o);
@@ -929,22 +931,35 @@ main (int argc, char *argv[])
   opt_log = GNUNET_NO;
   opt_plot = GNUNET_NO;
 
-  static struct GNUNET_GETOPT_CommandLineOption options[] =
-  {
-    { 's', "solver", NULL,
-        gettext_noop ("solver to use"),
-        1, &GNUNET_GETOPT_set_string, &opt_solver},
-    {  'e', "experiment", NULL,
-      gettext_noop ("experiment to use"),
-      1, &GNUNET_GETOPT_set_string, &opt_exp_file},
-    {  'e', "experiment", NULL,
-      gettext_noop ("experiment to use"),
-      1, &GNUNET_GETOPT_set_one, &opt_verbose},
+  struct GNUNET_GETOPT_CommandLineOption options[] =
+  {
+    GNUNET_GETOPT_OPTION_STRING ('s',
+                                 "solver",
+                                 NULL,
+                                 gettext_noop ("solver to use"),
+                                 &opt_solver),
+
+    GNUNET_GETOPT_OPTION_STRING ('e',
+                                 "experiment",
+                                 NULL,
+                                 gettext_noop ("experiment to use"),
+                                 &opt_exp_file),
+    GNUNET_GETOPT_OPTION_SET_ONE ('e',
+                                  "experiment",
+                                  gettext_noop ("experiment to use"),
+                                  &opt_verbose),
     GNUNET_GETOPT_OPTION_END
   };
 
-  GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
+  if (GNUNET_OK !=
+      GNUNET_PROGRAM_run (argc,
+                          argv, argv[0],
+                          NULL,
+                          options,
+                          &run, argv[0]))
+    return 1;
 
   return 0;
 }
-/* end of file ats-testing-experiment.c*/
+/* end of file gnunet-solver-eval.c*/
index 5fc1d6e92e93181b706523d1934cb50c596ae8e1..f645ba56d45acb5f8323f773dd8c5f2978f081b4 100644 (file)
@@ -944,34 +944,62 @@ main (int argc,
   stat_receive_done = GNUNET_NO;
   opt_type_str = NULL;
 
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    { 'u', "used", NULL,
-      gettext_noop ("get list of active addresses currently used"), 0,
-      &GNUNET_GETOPT_set_one, &opt_list_used },
-    { 'a', "all", NULL, gettext_noop ("get list of all active addresses"), 0,
-      &GNUNET_GETOPT_set_one, &opt_list_all },
-    { 'C', "connect", "PEER",
-      gettext_noop ("connect to PEER"), 1,
-      &GNUNET_GETOPT_set_string, &cpid_str },
-    { 'n', "numeric", NULL,
-      gettext_noop ("do not resolve IP addresses to hostnames"), 0,
-      &GNUNET_GETOPT_set_one, &opt_resolve_addresses_numeric },
-    { 'm', "monitor", NULL, gettext_noop ("monitor mode"), 0,
-      &GNUNET_GETOPT_set_one, &opt_monitor },
-    { 'p', "preference", NULL, gettext_noop ("set preference for the given peer"),
-      0, &GNUNET_GETOPT_set_one, &opt_set_pref },
-    { 'q', "quotas", NULL, gettext_noop ("print all configured quotas"), 0,
-      &GNUNET_GETOPT_set_one, &opt_print_quotas },
-    { 'i', "id", "TYPE", gettext_noop ("peer id"), 1, &GNUNET_GETOPT_set_string,
-      &opt_pid_str },
-    { 't', "type", "TYPE",
-      gettext_noop ("preference type to set: latency | bandwidth"), 1,
-      &GNUNET_GETOPT_set_string, &opt_type_str },
-    { 'k', "value", "VALUE", gettext_noop ("preference value"), 1,
-      &GNUNET_GETOPT_set_uint, &opt_pref_value },
-    { 'V', "verbose", NULL,
-      gettext_noop ("verbose output (include ATS address properties)"), 0,
-      &GNUNET_GETOPT_set_one, &opt_verbose },
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('u',
+                                  "used",
+                                  gettext_noop ("get list of active addresses currently used"),
+                                  &opt_list_used),
+    GNUNET_GETOPT_OPTION_SET_ONE ('a',
+                                  "all",
+                                  gettext_noop ("get list of all active addresses"),
+                                  &opt_list_all),
+
+    GNUNET_GETOPT_OPTION_STRING ('C',
+                                 "connect",
+                                 NULL,
+                                 gettext_noop ("connect to PEER"),
+                                 &cpid_str),
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "numeric",
+                                  gettext_noop ("do not resolve IP addresses to hostnames"),
+                                  &opt_resolve_addresses_numeric),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('m',
+                                  "monitor",
+                                  gettext_noop ("monitor mode"),
+                                  &opt_monitor),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('p',
+                                  "preference",
+                                  gettext_noop ("set preference for the given peer"),
+                                  &opt_set_pref),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('q', 
+                                  "quotas",
+                                  gettext_noop ("print all configured quotas"),
+                                  &opt_print_quotas),
+    GNUNET_GETOPT_OPTION_STRING ('i',
+                                 "id",
+                                 "TYPE",
+                                 gettext_noop ("peer id"),
+                                 &opt_pid_str),
+
+    GNUNET_GETOPT_OPTION_STRING ('t',
+                                 "type",
+                                 "TYPE",
+                                 gettext_noop ("preference type to set: latency | bandwidth"),
+                                 &opt_type_str),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('k',
+                                   "value",
+                                   "VALUE",
+                                   gettext_noop ("preference value"),
+                                   &opt_pref_value),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('V',
+                                  "verbose",
+                                  gettext_noop ("verbose output (include ATS address properties)"),
+                                  &opt_verbose),
     GNUNET_GETOPT_OPTION_END
   };
 
index faeeb60817e05f9a373342aab8560faf21bd46c6..81ae01b6ad5cb6c700d56a0c41d4946da2f8efb1 100644 (file)
@@ -657,9 +657,9 @@ GNUNET_ATS_address_add (struct GNUNET_ATS_SchedulingHandle *sh,
   GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != prop->scope);
   namelen = strlen (address->transport_name) + 1;
   msize = address->address_length + namelen;
-  if ((msize + sizeof (struct AddressUpdateMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
-      (address->address_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
-      (namelen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) )
+  if ((msize + sizeof (struct AddressUpdateMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
+      (address->address_length >= GNUNET_MAX_MESSAGE_SIZE) ||
+      (namelen >= GNUNET_MAX_MESSAGE_SIZE) )
   {
     /* address too large for us, this should not happen */
     GNUNET_break (0);
index e2e68562c8505f76857d3fc4015d7f151fa3e9d9..597285f5ed4c7361729f5b09b265312cee0f537a 100644 (file)
@@ -3289,24 +3289,33 @@ main (int argc, char *argv[])
 
   static struct GNUNET_GETOPT_CommandLineOption options[] =
   {
-    { 's', "solver", NULL,
-        gettext_noop ("solver to use"),
-        1, &GNUNET_GETOPT_set_string, &opt_solver},
-    {  'e', "experiment", NULL,
-      gettext_noop ("experiment to use"),
-      1, &GNUNET_GETOPT_set_string, &opt_exp_file},
-    {  'V', "verbose", NULL,
-      gettext_noop ("be verbose"),
-      0, &GNUNET_GETOPT_set_one, &opt_verbose},
-    {  'p', "print", NULL,
-      gettext_noop ("print logging"),
-      0, &GNUNET_GETOPT_set_one, &opt_print},
-    {  'f', "file", NULL,
-        gettext_noop ("save logging to disk"),
-        0, &GNUNET_GETOPT_set_one, &opt_save},
-    {  'd', "dn", NULL,
-        gettext_noop ("disable normalization"),
-        0, &GNUNET_GETOPT_set_one, &opt_disable_normalization},
+    GNUNET_GETOPT_OPTION_STRING ('s',
+                                 "solver",
+                                 gettext_noop ("solver to use"),
+                                 &opt_solver),
+
+    GNUNET_GETOPT_OPTION_STRING ('e',
+                                 "experiment"
+                                 gettext_noop ("experiment to use"),
+                                 &opt_exp_file),
+
+    GNUNET_GETOPT_OPTION_VERBOSE (&opt_verbose),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('p', 
+                                  "print",
+                                  gettext_noop ("print logging"),
+                                  &opt_print),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('f',
+                                  "file",
+                                  gettext_noop ("save logging to disk"),
+                                  &opt_save),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('d', 
+                                  "dn",
+                                  gettext_noop ("disable normalization"),
+                                  &opt_disable_normalization),
+
     GNUNET_GETOPT_OPTION_END
   };
 
index 1a4a332066d2c4923a89f9b4546eb3faf3816f90..ba34cbacb122451786fa03c7bd81c014171a3b26 100644 (file)
@@ -571,7 +571,7 @@ transmit_req_addr (struct AddressIteration *ai,
   msize = plugin_addr_len + plugin_name_length;
 
   GNUNET_assert (sizeof (struct PeerInformationMessage) + msize
-                < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+                < GNUNET_MAX_MESSAGE_SIZE);
   env = GNUNET_MQ_msg_extra (msg,
                             msize,
                             GNUNET_MESSAGE_TYPE_ATS_ADDRESSLIST_RESPONSE);
index 5252a71bc18818a2a31771c302b6915e40844f1c..07ddf05316ea7a25bb9ca770407608f542e38d25 100644 (file)
@@ -85,7 +85,7 @@ notify_client (struct GNUNET_SERVICE_Client *client,
 
   if (NULL != prop)
     GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != prop->scope);
-  GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+  GNUNET_assert (msize < GNUNET_MAX_MESSAGE_SIZE);
   msg = (struct PeerInformationMessage *) buf;
   msg->header.size = htons (msize);
   msg->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_PEER_INFORMATION);
index f05668e9bc49d3ddd64d9f4cb1bfff38b3e89db0..855899b3627640514db76650a98ed623477f4cea 100644 (file)
@@ -1404,27 +1404,42 @@ main (int argc, char *argv[])
   ph.total_iterations = 1;
 
   static struct GNUNET_GETOPT_CommandLineOption options[] = {
-      { 'a', "addresses", NULL,
-          gettext_noop ("addresses to use"),
-          1, &GNUNET_GETOPT_set_uint, &ph.N_address },
-      { 's', "start", NULL,
-          gettext_noop ("start with peer"),
-          1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
-      { 'e', "end", NULL,
-          gettext_noop ("end with peer"),
-          1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
-      { 'i', "iterations", NULL,
-          gettext_noop ("number of iterations used for averaging (default: 1)"),
-          1, &GNUNET_GETOPT_set_uint, &ph.total_iterations },
-      { 'p', "percentage", NULL,
-          gettext_noop ("update a fix percentage of addresses"),
-          1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
-      { 'd', "data", NULL,
-          gettext_noop ("create data file"),
-          0, &GNUNET_GETOPT_set_one, &ph.create_datafile},
-      { 'u', "update", NULL,
-          gettext_noop ("measure updates"),
-          0, &GNUNET_GETOPT_set_one, &ph.measure_updates},
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('a',
+                                     "addresses",
+                                     gettext_noop ("addresses to use"),
+                                     &ph.N_address),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('s',
+                                     "start",
+                                     gettext_noop ("start with peer"),
+                                     &ph.N_peers_start),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('e',
+                                     "end",
+                                     gettext_noop ("end with peer"),
+                                     &ph.N_peers_end),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('i',
+                                     "iterations",
+                                     gettext_noop ("number of iterations used for averaging (default: 1)"),
+                                     &ph.total_iterations),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('p',
+                                     "percentage",
+                                     gettext_noop ("update a fix percentage of addresses"),
+                                     &ph.opt_update_percent),
+
+      GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                    "data",
+                                    gettext_noop ("create data file"),
+                                    &ph.create_datafile),
+
+      GNUNET_GETOPT_OPTION_SET_ONE ('u',
+                                    "update",
+                                    gettext_noop ("measure updates"),
+                                    &ph.measure_updates),
+
       GNUNET_GETOPT_OPTION_END
   };
 
index a4c0295725baba30d5e2ae6e3a69c0eec4a0a313..e6fcab097f48c74606a6617d47482a2c75cb871b 100644 (file)
@@ -155,30 +155,49 @@ fail:
 int
 main (int argc, char *const *argv)
 {
-       static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-               {'d', "description", "FILE",
-                       gettext_noop ("description of the item to be sold"),
-                       1, &GNUNET_GETOPT_set_filename, &fndesc},
-               {'p', "pricemap", "FILE",
-                       gettext_noop ("mapping of possible prices"),
-                       1, &GNUNET_GETOPT_set_filename, &fnprices},
-               {'r', "roundtime", "DURATION",
-                       gettext_noop ("max duration per round"),
-                       1, &GNUNET_GETOPT_set_relative_time, &dround},
-               {'s', "regtime", "DURATION",
-                       gettext_noop ("duration until auction starts"),
-                       1, &GNUNET_GETOPT_set_relative_time, &dstart},
-               {'m', "m", "NUMBER",
-                       gettext_noop ("number of items to sell\n"
-                                     "0 for first price auction\n"
-                                     ">0 for vickrey/M+1st price auction"),
-                       1, &GNUNET_GETOPT_set_uint, &m},
-               {'u', "public", NULL,
-                       gettext_noop ("public auction outcome"),
-                       0, &GNUNET_GETOPT_set_one, &outcome},
-               {'i', "interactive", NULL,
-                       gettext_noop ("keep running in foreground until auction completes"),
-                       0, &GNUNET_GETOPT_set_one, &interactive},
+       struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+                GNUNET_GETOPT_OPTION_FILENAME ('d',
+                                               "description",
+                                               "FILE",
+                                               gettext_noop ("description of the item to be sold"),
+                                               &fndesc),
+
+                GNUNET_GETOPT_OPTION_FILENAME ('p',
+                                               "pricemap",
+                                               "FILE",
+                                               gettext_noop ("mapping of possible prices"),
+                                               &fnprices),
+
+                GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('r',
+                                                        "roundtime",
+                                                        "DURATION",
+                                                        gettext_noop ("max duration per round"),
+                                                        &dround),
+
+                GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('s',
+                                                        "regtime",
+                                                        "DURATION",
+                                                        gettext_noop ("duration until auction starts"),
+                                                        &dstart),
+                GNUNET_GETOPT_OPTION_SET_UINT ('m',
+                                               "m",
+                                               "NUMBER",
+                                               gettext_noop ("number of items to sell\n"
+                                                             "0 for first price auction\n"
+                                                            ">0 for vickrey/M+1st price auction"),
+                                               &m), 
+
+                GNUNET_GETOPT_OPTION_SET_ONE ('u',
+                                              "public",
+                                              gettext_noop ("public auction outcome"),
+                                              &outcome),
+
+                GNUNET_GETOPT_OPTION_SET_ONE ('i',
+                                              "interactive",
+                                              gettext_noop ("keep running in foreground until auction completes"),
+                                              &interactive),
+
                GNUNET_GETOPT_OPTION_END
        };
        if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
index 1a17ec84e46543382f2d155ef1806d42449c09b9..3e7d38892dc209d7b25fa697147b9236d3e27401 100644 (file)
@@ -77,6 +77,7 @@ bf_group_serialize_cb (struct GNUNET_BLOCK_Group *bg,
                                                  raw,
                                                  gi->bf_size))
   {
+    GNUNET_free (raw);
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
index b52079b2e1dcc1d95107d89083a263c874538eb8..ce30ebe46a3e98bc9b7ae4cda0b1e54d0cfaebc5 100644 (file)
@@ -23,84 +23,48 @@ AM_CLFAGS = -g
 
 libexec_PROGRAMS = \
  gnunet-service-cadet \
- gnunet-service-cadet-new \
  $(EXP_LIBEXEC)
 
 bin_PROGRAMS = \
  gnunet-cadet
 
 lib_LTLIBRARIES = \
-  libgnunetcadetnew.la \
   libgnunetcadet.la \
   $(EXP_LIB)
 
 libgnunetcadet_la_SOURCES = \
-  cadet_api.c cadet_common.c
+  cadet_api.c
 libgnunetcadet_la_LIBADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(XLIB) \
   $(LTLIBINTL)
 libgnunetcadet_la_LDFLAGS = \
   $(GN_LIB_LDFLAGS) $(WINFLAGS) \
-  -version-info 5:0:0
-
-
-libgnunetcadetnew_la_SOURCES = \
-  cadet_api_new.c
-libgnunetcadetnew_la_LIBADD = \
-  $(top_builddir)/src/util/libgnunetutil.la \
-  $(XLIB) \
-  $(LTLIBINTL)
-libgnunetcadetnew_la_LDFLAGS = \
-  $(GN_LIB_LDFLAGS) $(WINFLAGS) \
-  -version-info 6:0:0
+  -version-info 7:0:0
 
 gnunet_cadet_SOURCES = \
   gnunet-cadet.c
 gnunet_cadet_LDADD = \
-  libgnunetcadetnew.la \
+  libgnunetcadet.la \
   $(top_builddir)/src/util/libgnunetutil.la
 
-gnunet_service_cadet_new_SOURCES = \
- gnunet-service-cadet-new.c gnunet-service-cadet-new.h \
- gnunet-service-cadet-new_channel.c gnunet-service-cadet-new_channel.h \
- gnunet-service-cadet-new_connection.c gnunet-service-cadet-new_connection.h \
- gnunet-service-cadet-new_core.c gnunet-service-cadet-new_core.h \
- gnunet-service-cadet-new_dht.c gnunet-service-cadet-new_dht.h \
- gnunet-service-cadet-new_hello.c gnunet-service-cadet-new_hello.h \
- gnunet-service-cadet-new_tunnels.c gnunet-service-cadet-new_tunnels.h \
- gnunet-service-cadet-new_paths.c gnunet-service-cadet-new_paths.h \
- gnunet-service-cadet-new_peer.c gnunet-service-cadet-new_peer.h
-gnunet_service_cadet_new_LDADD = \
-  $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/ats/libgnunetats.la \
-  $(top_builddir)/src/core/libgnunetcore.la \
-  $(top_builddir)/src/dht/libgnunetdht.la \
-  $(top_builddir)/src/statistics/libgnunetstatistics.la \
-  $(top_builddir)/src/transport/libgnunettransport.la \
-  $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
-  $(top_builddir)/src/hello/libgnunethello.la \
-  $(top_builddir)/src/block/libgnunetblock.la
-
 gnunet_service_cadet_SOURCES = \
- gnunet-service-cadet_tunnel.c gnunet-service-cadet_tunnel.h \
- gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
+ gnunet-service-cadet.c gnunet-service-cadet.h \
  gnunet-service-cadet_channel.c gnunet-service-cadet_channel.h \
- gnunet-service-cadet_local.c gnunet-service-cadet_local.h \
- gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h \
+ gnunet-service-cadet_connection.c gnunet-service-cadet_connection.h \
+ gnunet-service-cadet_core.c gnunet-service-cadet_core.h \
  gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \
  gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \
- cadet_path.c cadet_path.h \
- cadet_common.c \
- gnunet-service-cadet.c
-gnunet_service_cadet_CFLAGS = $(AM_CFLAGS)
+ gnunet-service-cadet_tunnels.c gnunet-service-cadet_tunnels.h \
+ gnunet-service-cadet_paths.c gnunet-service-cadet_paths.h \
+ gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h
 gnunet_service_cadet_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/transport/libgnunettransport.la \
-  $(top_builddir)/src/core/libgnunetcore.la \
   $(top_builddir)/src/ats/libgnunetats.la \
+  $(top_builddir)/src/core/libgnunetcore.la \
   $(top_builddir)/src/dht/libgnunetdht.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/transport/libgnunettransport.la \
   $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
   $(top_builddir)/src/hello/libgnunethello.la \
   $(top_builddir)/src/block/libgnunetblock.la
@@ -110,39 +74,14 @@ endif
 
 
 if HAVE_TESTING
- noinst_LTLIBRARIES = libgnunetcadettest.la libgnunetcadettestnew.la $(noinst_LIB_EXP)
- noinst_PROGRAMS = gnunet-cadet-profiler
+ noinst_LTLIBRARIES = libgnunetcadettest.la $(noinst_LIB_EXP)
+# noinst_PROGRAMS = gnunet-cadet-profiler
 endif
 
-libgnunetcadettest_la_SOURCES = \
-  cadet_test_lib.c cadet_test_lib.h
-libgnunetcadettest_la_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/testbed/libgnunettestbed.la \
- libgnunetcadet.la
-
 if HAVE_TESTING
 check_PROGRAMS = \
   test_cadet_local_mq \
-  test_cadet_2_forward_new \
-  test_cadet_2_forward_new \
-  test_cadet_2_signal_new \
-  test_cadet_2_keepalive_new \
-  test_cadet_2_speed_new \
-  test_cadet_2_speed_ack_new \
-  test_cadet_2_speed_backwards_new \
-  test_cadet_2_speed_reliable_new \
-  test_cadet_2_speed_reliable_backwards_new \
-  test_cadet_5_forward_new \
-  test_cadet_5_signal_new \
-  test_cadet_5_keepalive_new \
-  test_cadet_5_speed_new \
-  test_cadet_5_speed_ack_new \
-  test_cadet_5_speed_reliable_new \
-  test_cadet_5_speed_reliable_backwards_new \
-  test_cadet_5_speed_backwards_new \
-  test_cadet_single \
-  test_cadet_local \
+  test_cadet_2_forward \
   test_cadet_2_forward \
   test_cadet_2_signal \
   test_cadet_2_keepalive \
@@ -161,41 +100,39 @@ check_PROGRAMS = \
   test_cadet_5_speed_backwards
 endif
 
+
+#gnunet_cadet_profiler_SOURCES = \
+#  gnunet-cadet-profiler.c
+#gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
+
+
+test_cadet_local_mq_SOURCES = \
+  test_cadet_local_mq.c
+test_cadet_local_mq_LDADD = \
+  libgnunetcadet.la \
+  $(top_builddir)/src/testing/libgnunettesting.la \
+  $(top_builddir)/src/util/libgnunetutil.la
+
+
+libgnunetcadettest_la_SOURCES = \
+  cadet_test_lib.c cadet_test_lib.h
+libgnunetcadettest_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/testbed/libgnunettestbed.la \
+ libgnunetcadet.la
+
 ld_cadet_test_lib = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/testing/libgnunettesting.la \
-  libgnunetcadettest.la \
   libgnunetcadet.la \
+  libgnunetcadettest.la \
   $(top_builddir)/src/testbed/libgnunettestbed.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la
-
 dep_cadet_test_lib = \
   libgnunetcadet.la \
   libgnunetcadettest.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la
 
-
-gnunet_cadet_profiler_SOURCES = \
-  gnunet-cadet-profiler.c
-gnunet_cadet_profiler_LDADD = $(ld_cadet_test_lib)
-
-
-test_cadet_single_SOURCES = \
-  test_cadet_single.c
-test_cadet_single_LDADD = $(ld_cadet_test_lib)
-
-test_cadet_local_SOURCES = \
-  test_cadet_local.c
-test_cadet_local_LDADD = $(ld_cadet_test_lib)
-
-
-test_cadet_local_mq_SOURCES = \
-  test_cadet_local_mq.c
-test_cadet_local_mq_LDADD = \
-  libgnunetcadetnew.la \
-  $(top_builddir)/src/testing/libgnunettesting.la \
-  $(top_builddir)/src/util/libgnunetutil.la
-
 test_cadet_2_forward_SOURCES = \
   test_cadet.c
 test_cadet_2_forward_LDADD = $(ld_cadet_test_lib)
@@ -228,7 +165,6 @@ test_cadet_2_speed_reliable_backwards_SOURCES = \
   test_cadet.c
 test_cadet_2_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
 
-
 test_cadet_5_forward_SOURCES = \
   test_cadet.c
 test_cadet_5_forward_LDADD = $(ld_cadet_test_lib)
@@ -262,92 +198,6 @@ test_cadet_5_speed_reliable_backwards_SOURCES = \
 test_cadet_5_speed_reliable_backwards_LDADD = $(ld_cadet_test_lib)
 
 
-# NEW TESTS
-libgnunetcadettestnew_la_SOURCES = \
-  cadet_test_lib_new.c cadet_test_lib_new.h
-libgnunetcadettestnew_la_LIBADD = \
- $(top_builddir)/src/util/libgnunetutil.la \
- $(top_builddir)/src/testbed/libgnunettestbed.la \
- libgnunetcadetnew.la
-
-ld_cadet_test_lib_new = \
-  $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/testing/libgnunettesting.la \
-  libgnunetcadetnew.la \
-  libgnunetcadettestnew.la \
-  $(top_builddir)/src/testbed/libgnunettestbed.la \
-  $(top_builddir)/src/statistics/libgnunetstatistics.la
-dep_cadet_test_lib_new = \
-  libgnunetcadetnew.la \
-  libgnunetcadettestnew.la \
-  $(top_builddir)/src/statistics/libgnunetstatistics.la
-
-test_cadet_2_forward_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_2_forward_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_signal_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_2_signal_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_keepalive_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_2_keepalive_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_2_speed_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_ack_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_2_speed_ack_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_backwards_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_2_speed_backwards_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_reliable_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_2_speed_reliable_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_2_speed_reliable_backwards_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_2_speed_reliable_backwards_new_LDADD = $(ld_cadet_test_lib_new)
-
-
-test_cadet_5_forward_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_5_forward_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_signal_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_5_signal_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_keepalive_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_5_keepalive_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_5_speed_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_ack_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_5_speed_ack_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_backwards_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_5_speed_backwards_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_reliable_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_5_speed_reliable_new_LDADD = $(ld_cadet_test_lib_new)
-
-test_cadet_5_speed_reliable_backwards_new_SOURCES = \
-  test_cadet_new.c
-test_cadet_5_speed_reliable_backwards_new_LDADD = $(ld_cadet_test_lib_new)
-
-
 if ENABLE_TEST_RUN
 AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
 TESTS = \
index 820efab7a60eb2846548fda764ec709367959f95..06567b0ad74f0cb39139de4b14df84d6a00c4ee3 100644 (file)
@@ -1,6 +1,10 @@
-- URGENT: Congestion/flow control (CHANNEL):
-  + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
-   (and figure out how/where to use this!)
+- URGENT:
+  + if 'client-not-ready', we do not ACK at all, and sender keeps
+    retransmitting again and again; would be good to do flow-control notification instead
+    of not ACKing that we got the data but are simply not ready for more!
+  + Congestion/flow control (CHANNEL):
+    estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
+    (and figure out how/where to use this!)
 
 - HIGH: revisit handling of 'unbuffered' traffic! (CHANNEL/TUNNEL)
         (need to push down through tunnel into connection selection);
index 86ba2e535d0a2b6e839c2ccd52a8a4b027822930..d50e168f0938b8f3bd7a8699cdd34ed3fc2e4a08 100644 (file)
@@ -3,7 +3,7 @@ FORCESTART = YES
 AUTOSTART = @AUTOSTART@
 @JAVAPORT@PORT = 2096
 HOSTNAME = localhost
-BINARY = gnunet-service-cadet-new
+BINARY = gnunet-service-cadet
 # PREFIX = valgrind --leak-check=yes
 ACCEPT_FROM = 127.0.0.1;
 ACCEPT_FROM6 = ::1;
index 451d1f354363f18627781e57b95a1879dac995b0..99f9f265310d43645caf768b1a488953e75b1d02 100644 (file)
@@ -59,7 +59,7 @@ extern "C"
 #include "gnunet_core_service.h"
 #include "gnunet_cadet_service.h"
 #include "gnunet_protocols.h"
-#include <gnunet_cadet_service.h>
+#include "gnunet_cadet_service.h"
 
 /******************************************************************************/
 /**************************       CONSTANTS      ******************************/
index 7b9ac62b388c7aae0d103764363308007d71c0ff..decf473a9c11679bf0811eabcfb907e042ac5613 100644 (file)
@@ -21,8 +21,8 @@
  * @file cadet/cadet_api.c
  * @brief cadet api: client implementation of cadet service
  * @author Bartlomiej Polot
+ * @author Christian Grothoff
  */
-
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_constants.h"
 
 #define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__)
 
-/******************************************************************************/
-/************************      DATA STRUCTURES     ****************************/
-/******************************************************************************/
-
 /**
- * Transmission queue to the service
- *
- * @deprecated
+ * Ugly legacy hack.
  */
-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;
-
-  /**
-   * Request data task.
-   */
-  struct GNUNET_SCHEDULER_Task *request_data_task;
-
-  /**
-   * 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;
-
-  /**
-   * Size of the payload.
-   */
-  size_t size;
-};
-
-
 union CadetInfoCB
 {
 
@@ -119,69 +71,19 @@ union CadetInfoCB
 struct GNUNET_CADET_Handle
 {
   /**
-   * Flag to indicate old or MQ API.
-   */
-  int mq_api;
-
-  /**
-   * Message queue (if available).
+   * Message queue.
    */
   struct GNUNET_MQ_Handle *mq;
 
-  /**
-   * Set of handlers used for processing incoming messages in the channels
-   *
-   * @deprecated
-   */
-  const struct GNUNET_CADET_MessageHandler *message_handlers;
-
-  /**
-   * Number of handlers in the handlers array.
-   *
-   * @deprecated
-   */
-  unsigned int n_handlers;
-
   /**
    * Ports open.
    */
   struct GNUNET_CONTAINER_MultiHashMap *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 disconnection
-   */
-  GNUNET_CADET_ChannelEndHandler *cleaner;
-
-  /**
-   * Closure for all the handlers given by the client
-   *
-   * @deprecated
-   */
-  void *cls;
-
-  /**
-   * Messages to send to the service, head.
-   *
-   * @deprecated
-   */
-  struct GNUNET_CADET_TransmitHandle *th_head;
-
-  /**
-   * Messages to send to the service, tail.
-   *
-   * @deprecated
+   * Channels open.
    */
-  struct GNUNET_CADET_TransmitHandle *th_tail;
+  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
 
   /**
    * child of the next channel to create (to avoid reusing IDs often)
@@ -193,15 +95,10 @@ struct GNUNET_CADET_Handle
    */
   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.
    */
-  struct GNUNET_SCHEDULER_Task * reconnect_task;
+  struct GNUNET_SCHEDULER_Task *reconnect_task;
 
   /**
    * Callback for an info task (only one active at a time).
@@ -212,23 +109,12 @@ struct GNUNET_CADET_Handle
    * 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
+   * Time to the next reconnect in case one reconnect fails
    */
-  GNUNET_PEER_Id id;
+  struct GNUNET_TIME_Relative reconnect_time;
 
-  /**
-   * Channel this peer belongs to
-   */
-  struct GNUNET_CADET_Channel *t;
 };
 
 
@@ -237,56 +123,30 @@ struct GNUNET_CADET_Peer
  */
 struct GNUNET_CADET_Channel
 {
-  /**
-   * DLL next
-   */
-  struct GNUNET_CADET_Channel *next;
 
   /**
-   * DLL prev
+   * Other end of the channel.
    */
-  struct GNUNET_CADET_Channel *prev;
+  struct GNUNET_PeerIdentity peer;
 
   /**
    * Handle to the cadet this channel belongs to
    */
   struct GNUNET_CADET_Handle *cadet;
 
-  /**
-   * Local ID of the channel
-   */
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
   /**
    * Channel's port, if incoming.
    */
   struct GNUNET_CADET_Port *incoming_port;
 
   /**
-   * Other end of the channel.
-   */
-  GNUNET_PEER_Id peer;
-
-  /**
-   * Any data the caller wants to put in here
+   * Any data the caller wants to put in here, used for the
+   * various callbacks (@e disconnects, @e window_changes, handlers).
    */
   void *ctx;
 
   /**
-   * Channel options: reliability, etc.
-   */
-  enum GNUNET_CADET_ChannelOption options;
-
-  /**
-   * Are we allowed to send to the service?
-   *
-   * @deprecated?
-   */
-  unsigned int allow_send;
-
-  /*****************************    MQ     ************************************/
-  /**
-   * Message Queue for the channel.
+   * Message Queue for the channel (which we are implementing).
    */
   struct GNUNET_MQ_Handle *mq;
 
@@ -296,7 +156,9 @@ struct GNUNET_CADET_Channel
   struct GNUNET_SCHEDULER_Task *mq_cont;
 
   /**
-   * Pending envelope in case we don't have an ACK from the service.
+   * Pending envelope with a message to be transmitted to the
+   * service as soon as we are allowed to.  Should only be
+   * non-NULL if @e allow_send is 0.
    */
   struct GNUNET_MQ_Envelope *pending_env;
 
@@ -310,6 +172,21 @@ struct GNUNET_CADET_Channel
    */
   GNUNET_CADET_DisconnectEventHandler disconnects;
 
+  /**
+   * Local ID of the channel, #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI bit is set if outbound.
+   */
+  struct GNUNET_CADET_ClientChannelNumber ccn;
+
+  /**
+   * Channel options: reliability, etc.
+   */
+  enum GNUNET_CADET_ChannelOption options;
+
+  /**
+   * How many messages are we allowed to send to the service right now?
+   */
+  unsigned int allow_send;
+
 };
 
 
@@ -318,35 +195,22 @@ struct GNUNET_CADET_Channel
  */
 struct GNUNET_CADET_Port
 {
-  /**
-   * Handle to the CADET session this port belongs to.
-   */
-  struct GNUNET_CADET_Handle *cadet;
 
   /**
-   * Port ID.
-   *
-   * @deprecated
+   * Port "number"
    */
-  struct GNUNET_HashCode *hash;
+  struct GNUNET_HashCode id;
 
   /**
-   * Callback handler for incoming channels on this port.
+   * Handle to the CADET session this port belongs to.
    */
-  GNUNET_CADET_InboundChannelNotificationHandler *handler;
+  struct GNUNET_CADET_Handle *cadet;
 
   /**
    * Closure for @a handler.
    */
   void *cls;
 
-  /*****************************    MQ     ************************************/
-
-  /**
-   * Port "number"
-   */
-  struct GNUNET_HashCode id;
-
   /**
    * Handler for incoming channels on this port
    */
@@ -355,7 +219,7 @@ struct GNUNET_CADET_Port
   /**
    * Closure for @ref connects
    */
-  void * connects_cls;
+  void *connects_cls;
 
   /**
    * Window size change handler.
@@ -363,106 +227,30 @@ struct GNUNET_CADET_Port
   GNUNET_CADET_WindowSizeEventHandler window_changes;
 
   /**
-   * Handler called when an incoming channel is destroyed..
+   * Handler called when an incoming channel is destroyed.
    */
   GNUNET_CADET_DisconnectEventHandler disconnects;
 
   /**
    * Payload handlers for incoming channels.
    */
-  const struct GNUNET_MQ_MessageHandler *handlers;
+  struct GNUNET_MQ_MessageHandler *handlers;
 };
 
 
-/**
- * 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;
-};
-
-
-
-/******************************************************************************/
-/*********************      FUNCTION DECLARATIONS     *************************/
-/******************************************************************************/
-
-/**
- * Reconnect to the service, retransmit all infomation to try to restore the
- * original state.
- *
- * @param h Handle to the CADET service.
- */
-static void
-schedule_reconnect (struct GNUNET_CADET_Handle *h);
-
-
-/**
- * Reconnect callback: tries to reconnect again after a failer previous
- * reconnection.
- *
- * @param cls Closure (cadet handle).
- */
-static void
-reconnect_cbk (void *cls);
-
-
-/**
- * Reconnect to the service, retransmit all infomation to try to restore the
- * original state.
- *
- * @param h handle to the cadet
- */
-static void
-reconnect (struct GNUNET_CADET_Handle *h);
-
-
-/******************************************************************************/
-/***********************     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;
-}
-
-
 /**
  * Find the Port struct for a hash.
  *
  * @param h CADET handle.
  * @param hash HashCode for the port number.
- *
  * @return The port handle if known, NULL otherwise.
  */
 static struct GNUNET_CADET_Port *
 find_port (const struct GNUNET_CADET_Handle *h,
           const struct GNUNET_HashCode *hash)
 {
-  struct GNUNET_CADET_Port *p;
-
-  p = GNUNET_CONTAINER_multihashmap_get (h->ports, hash);
-
-  return p;
+  return GNUNET_CONTAINER_multihashmap_get (h->ports,
+                                            hash);
 }
 
 
@@ -474,15 +262,11 @@ find_port (const struct GNUNET_CADET_Handle *h,
  * @return handle to the required channel or NULL if not found
  */
 static struct GNUNET_CADET_Channel *
-retrieve_channel (struct GNUNET_CADET_Handle *h,
-                  struct GNUNET_CADET_ClientChannelNumber ccn)
+find_channel (struct GNUNET_CADET_Handle *h,
+              struct GNUNET_CADET_ClientChannelNumber ccn)
 {
-  struct GNUNET_CADET_Channel *ch;
-
-  for (ch = h->channels_head; NULL != ch; ch = ch->next)
-    if (ch->ccn.channel_of_client == ccn.channel_of_client)
-      return ch;
-  return NULL;
+  return GNUNET_CONTAINER_multihashmap32_get (h->channels,
+                                              ntohl (ccn.channel_of_client));
 }
 
 
@@ -490,38 +274,37 @@ retrieve_channel (struct GNUNET_CADET_Handle *h,
  * Create a new channel and insert it in the channel list of the cadet handle
  *
  * @param h Cadet handle
- * @param ccn Desired ccn of the channel, 0 to assign one automatically.
- *
+ * @param ccnp pointer to desired ccn of the channel, NULL to assign one automatically.
  * @return Handle to the created channel.
  */
 static struct GNUNET_CADET_Channel *
 create_channel (struct GNUNET_CADET_Handle *h,
-                struct GNUNET_CADET_ClientChannelNumber ccn)
+                const struct GNUNET_CADET_ClientChannelNumber *ccnp)
 {
   struct GNUNET_CADET_Channel *ch;
+  struct GNUNET_CADET_ClientChannelNumber ccn;
 
   ch = GNUNET_new (struct GNUNET_CADET_Channel);
-  GNUNET_CONTAINER_DLL_insert (h->channels_head,
-                               h->channels_tail,
-                               ch);
   ch->cadet = h;
-  if (0 == ccn.channel_of_client)
+  if (NULL == ccnp)
   {
-    ch->ccn = h->next_ccn;
-    while (NULL != retrieve_channel (h,
-                                     h->next_ccn))
-    {
+    while (NULL !=
+           find_channel (h,
+                         h->next_ccn))
       h->next_ccn.channel_of_client
-        = htonl (1 + ntohl (h->next_ccn.channel_of_client));
-      if (0 == ntohl (h->next_ccn.channel_of_client))
-        h->next_ccn.channel_of_client
-          = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-    }
+        = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI | (1 + ntohl (h->next_ccn.channel_of_client)));
+    ccn = h->next_ccn;
   }
   else
   {
-    ch->ccn = ccn;
+    ccn = *ccnp;
   }
+  ch->ccn = ccn;
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap32_put (h->channels,
+                                                      ntohl (ch->ccn.channel_of_client),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   return ch;
 }
 
@@ -535,114 +318,106 @@ create_channel (struct GNUNET_CADET_Handle *h,
  *
  * @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)
 {
-  struct GNUNET_CADET_Handle *h;
-  struct GNUNET_CADET_TransmitHandle *th;
-  struct GNUNET_CADET_TransmitHandle *next;
+  struct GNUNET_CADET_Handle *h = ch->cadet;
 
-  if (NULL == ch)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  h = ch->cadet;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " destroy_channel %X of %p\n",
+       "Destroying channel %X of %p\n",
        ch->ccn,
        h);
-
-  GNUNET_CONTAINER_DLL_remove (h->channels_head,
-                               h->channels_tail,
-                               ch);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (h->channels,
+                                                         ntohl (ch->ccn.channel_of_client),
+                                                         ch));
   if (NULL != ch->mq_cont)
   {
     GNUNET_SCHEDULER_cancel (ch->mq_cont);
     ch->mq_cont = NULL;
   }
   /* signal channel destruction */
-  if (0 != ch->peer)
-  {
-    if (NULL != h->cleaner)
-    {
-      /** @a deprecated  */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-          " calling cleaner\n");
-      h->cleaner (h->cls, ch, ch->ctx);
-    }
-    else if (NULL != ch->disconnects)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-          " calling disconnect handler\n");
-      ch->disconnects (ch->ctx, ch);
-    }
-    else
-    {
-      /* Application won't be aware of the channel destruction and use
-       * a pointer to free'd memory.
-       */
-      GNUNET_assert (0);
-    }
-  }
-
-  /* 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_CADET_notify_transmit_ready_cancel (th);
-  }
-
-  if (0 != ch->peer)
-    GNUNET_PEER_change_rc (ch->peer, -1);
+  if (NULL != ch->disconnects)
+    ch->disconnects (ch->ctx,
+                     ch);
+  if (NULL != ch->pending_env)
+    GNUNET_MQ_discard (ch->pending_env);
+  GNUNET_MQ_destroy (ch->mq);
   GNUNET_free (ch);
 }
 
 
 /**
- * Add a transmit handle to the transmission queue and set the
- * timeout if needed.
+ * Reconnect to the service, retransmit all infomation to try to restore the
+ * original state.
+ *
+ * @param h handle to the cadet
+ */
+static void
+reconnect (struct GNUNET_CADET_Handle *h);
+
+
+/**
+ * Reconnect callback: tries to reconnect again after a failer previous
+ * reconnecttion
  *
- * @param h cadet handle with the queue head and tail
- * @param th handle to the packet to be transmitted
+ * @param cls closure (cadet handle)
  */
 static void
-add_to_queue (struct GNUNET_CADET_Handle *h,
-              struct GNUNET_CADET_TransmitHandle *th)
+reconnect_cbk (void *cls)
 {
-  GNUNET_CONTAINER_DLL_insert_tail (h->th_head,
-                                    h->th_tail,
-                                    th);
+  struct GNUNET_CADET_Handle *h = cls;
+
+  h->reconnect_task = NULL;
+  reconnect (h);
 }
 
 
 /**
- * Remove a transmit handle from the transmission queue, if present.
+ * Function called during #reconnect() to destroy
+ * all channels that are still open.
  *
- * Safe to call even if not queued.
+ * @param cls the `struct GNUNET_CADET_Handle`
+ * @param cid chanenl ID
+ * @param value a `struct GNUNET_CADET_Channel` to destroy
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+destroy_channel_on_reconnect_cb (void *cls,
+                                 uint32_t cid,
+                                 void *value)
+{
+  /* struct GNUNET_CADET_Handle *handle = cls; */
+  struct GNUNET_CADET_Channel *ch = value;
+
+  destroy_channel (ch);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Reconnect to the service, retransmit all infomation to try to restore the
+ * original state.
+ *
+ * @param h handle to the cadet
  *
- * @param th handle to the packet to be unqueued.
+ * @return #GNUNET_YES in case of sucess, #GNUNET_NO otherwise (service down...)
  */
 static void
-remove_from_queue (struct GNUNET_CADET_TransmitHandle *th)
+schedule_reconnect (struct GNUNET_CADET_Handle *h)
 {
-  struct GNUNET_CADET_Handle *h = th->channel->cadet;
-
-  /* It might or might not have been queued (rarely not), but check anyway. */
-  if (NULL != th->next || h->th_tail == th)
-  {
-    GNUNET_CONTAINER_DLL_remove (h->th_head, h->th_tail, th);
-  }
+  if (NULL != h->reconnect_task)
+    return;
+  GNUNET_CONTAINER_multihashmap32_iterate (h->channels,
+                                           &destroy_channel_on_reconnect_cb,
+                                           h);
+  h->reconnect_task
+    = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
+                                    &reconnect_cbk,
+                                    h);
+  h->reconnect_time
+    = GNUNET_TIME_STD_BACKOFF (h->reconnect_time);
 }
 
 
@@ -655,29 +430,44 @@ static void
 notify_window_size (struct GNUNET_CADET_Channel *ch)
 {
   if (NULL != ch->window_changes)
-  {
-    ch->window_changes (ch->ctx, ch, ch->allow_send);
-  }
+    ch->window_changes (ch->ctx,
+                        ch, /* FIXME: remove 'ch'? */
+                        ch->allow_send);
 }
 
-/******************************************************************************/
-/***********************      MQ API CALLBACKS     ****************************/
-/******************************************************************************/
 
 /**
- * Allow the MQ implementation to send the next message.
+ * Transmit the next message from our queue.
  *
  * @param cls Closure (channel whose mq to activate).
  */
 static void
-cadet_mq_send_continue (void *cls)
+cadet_mq_send_now (void *cls)
 {
   struct GNUNET_CADET_Channel *ch = cls;
+  struct GNUNET_MQ_Envelope *env = ch->pending_env;
 
   ch->mq_cont = NULL;
+  if (0 == ch->allow_send)
+  {
+    /* how did we get here? */
+    GNUNET_break (0);
+    return;
+  }
+  if (NULL == env)
+  {
+    /* how did we get here? */
+    GNUNET_break (0);
+    return;
+  }
+  ch->allow_send--;
+  ch->pending_env = NULL;
+  GNUNET_MQ_send (ch->cadet->mq,
+                  env);
   GNUNET_MQ_impl_send_continue (ch->mq);
 }
 
+
 /**
  * Implement sending functionality of a message queue for
  * us sending messages to a peer.
@@ -701,7 +491,6 @@ cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq,
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_CADET_LocalData *cadet_msg;
 
-
   if (NULL == h->mq)
   {
     /* We're currently reconnecting, pretend this worked */
@@ -717,26 +506,16 @@ cadet_mq_send_impl (struct GNUNET_MQ_Handle *mq,
     GNUNET_MQ_impl_send_continue (mq);
     return;
   }
-
   env = GNUNET_MQ_msg_nested_mh (cadet_msg,
                                  GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
                                  msg);
   cadet_msg->ccn = ch->ccn;
-
+  GNUNET_assert (NULL == ch->pending_env);
+  ch->pending_env = env;
   if (0 < ch->allow_send)
-  {
-    /* Service has allowed this message, just send it and continue accepting */
-    GNUNET_MQ_send (h->mq, env);
-    ch->allow_send--;
-    ch->mq_cont = GNUNET_SCHEDULER_add_now (&cadet_mq_send_continue, ch);
-    // notify_window_size (ch); /* FIXME add "verbose" setting? */
-  }
-  else
-  {
-    /* Service has NOT allowed this message, queue it and wait for an ACK */
-    GNUNET_assert (NULL == ch->pending_env);
-    ch->pending_env = env;
-  }
+    ch->mq_cont
+      = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
+                                  ch);
 }
 
 
@@ -763,14 +542,25 @@ cadet_mq_destroy_impl (struct GNUNET_MQ_Handle *mq,
  * the CADET service.  We should just complain about it but otherwise
  * continue processing.
  *
- * @param cls closure
+ * @param cls closure with our `struct GNUNET_CADET_Channel`
  * @param error error code
  */
 static void
 cadet_mq_error_handler (void *cls,
                         enum GNUNET_MQ_Error error)
 {
-  GNUNET_break_op (0);
+  struct GNUNET_CADET_Channel *ch = cls;
+
+  GNUNET_break (0);
+  if (GNUNET_MQ_ERROR_NO_MATCH == error)
+  {
+    /* Got a message we did not understand, still try to continue! */
+    GNUNET_CADET_receive_done (ch);
+  }
+  else
+  {
+    schedule_reconnect (ch->cadet);
+  }
 }
 
 
@@ -781,65 +571,20 @@ cadet_mq_error_handler (void *cls,
  * @param mq message queue
  * @param impl_state state specific to the implementation
  */
-
 static void
 cadet_mq_cancel_impl (struct GNUNET_MQ_Handle *mq,
                      void *impl_state)
 {
   struct GNUNET_CADET_Channel *ch = impl_state;
 
-  LOG (GNUNET_ERROR_TYPE_WARNING,
-       "Cannot cancel mq message on channel %X of %p\n",
-       ch->ccn.channel_of_client, ch->cadet);
-
-  GNUNET_break (0);
-}
-
-
-/******************************************************************************/
-/***********************      RECEIVE HANDLERS     ****************************/
-/******************************************************************************/
-
-
-/**
- * Call the @a notify callback given to #GNUNET_CADET_notify_transmit_ready to
- * request the data to send over MQ. Since MQ manages the queue, this function
- * is scheduled immediatly after a transmit ready notification.
- *
- * @param cls Closure (transmit handle).
- */
-static void
-request_data (void *cls)
-{
-  struct GNUNET_CADET_TransmitHandle *th = cls;
-  struct GNUNET_CADET_LocalData *msg;
-  struct GNUNET_MQ_Envelope *env;
-  size_t osize;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Requesting Data: %u bytes (allow send is %u)\n",
-       th->size,
-       th->channel->allow_send);
-
-  GNUNET_assert (0 < th->channel->allow_send);
-  th->channel->allow_send--;
-  /* NOTE: we may be allowed to send another packet immediately,
-     albeit the current logic waits for the ACK. */
-  th->request_data_task = NULL;
-  remove_from_queue (th);
-
-  env = GNUNET_MQ_msg_extra (msg,
-                             th->size,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
-  msg->ccn = th->channel->ccn;
-  osize = th->notify (th->notify_cls,
-                      th->size,
-                      &msg[1]);
-  GNUNET_assert (osize == th->size);
-
-  GNUNET_MQ_send (th->channel->cadet->mq,
-                  env);
-  GNUNET_free (th);
+  GNUNET_assert (NULL != ch->pending_env);
+  GNUNET_MQ_discard (ch->pending_env);
+  ch->pending_env = NULL;
+  if (NULL != ch->mq_cont)
+  {
+    GNUNET_SCHEDULER_cancel (ch->mq_cont);
+    ch->mq_cont = NULL;
+  }
 }
 
 
@@ -866,7 +611,8 @@ handle_channel_created (void *cls,
     GNUNET_break (0);
     return;
   }
-  port = find_port (h, port_number);
+  port = find_port (h,
+                    port_number);
   if (NULL == port)
   {
     /* We could have closed the port but the service didn't know about it yet
@@ -875,7 +621,6 @@ handle_channel_created (void *cls,
     struct GNUNET_CADET_LocalChannelDestroyMessage *d_msg;
     struct GNUNET_MQ_Envelope *env;
 
-    GNUNET_break (0);
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "No handler for incoming channel %X (on port %s, recently closed?)\n",
          ntohl (ccn.channel_of_client),
@@ -889,10 +634,9 @@ handle_channel_created (void *cls,
   }
 
   ch = create_channel (h,
-                       ccn);
-  ch->peer = GNUNET_PEER_intern (&msg->peer);
+                       &ccn);
+  ch->peer = msg->peer;
   ch->cadet = h;
-  ch->ccn = ccn;
   ch->incoming_port = port;
   ch->options = ntohl (msg->opt);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -901,34 +645,21 @@ handle_channel_created (void *cls,
        GNUNET_h2s (port_number),
        ch);
 
-  if (NULL != port->handler)
-  {
-    /** @deprecated */
-    /* Old style API */
-    ch->ctx = port->handler (port->cls,
-                             ch,
-                             &msg->peer,
-                             port->hash,
-                             ch->options);
-  }
-  else
-  {
-    /* MQ API */
-    GNUNET_assert (NULL != port->connects);
-    ch->window_changes = port->window_changes;
-    ch->disconnects = port->disconnects;
-    ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
-                                            &cadet_mq_destroy_impl,
-                                            &cadet_mq_cancel_impl,
-                                            ch,
-                                            port->handlers,
-                                            &cadet_mq_error_handler,
-                                            ch);
-    ch->ctx = port->connects (port->cls,
-                              ch,
-                              &msg->peer);
-    GNUNET_MQ_set_handlers_closure (ch->mq, ch->ctx);
-  }
+  GNUNET_assert (NULL != port->connects);
+  ch->window_changes = port->window_changes;
+  ch->disconnects = port->disconnects;
+  ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
+                                          &cadet_mq_destroy_impl,
+                                          &cadet_mq_cancel_impl,
+                                          ch,
+                                          port->handlers,
+                                          &cadet_mq_error_handler,
+                                          ch);
+  ch->ctx = port->connects (port->cls,
+                            ch,
+                            &msg->peer);
+  GNUNET_MQ_set_handlers_closure (ch->mq,
+                                  ch->ctx);
 }
 
 
@@ -944,22 +675,19 @@ handle_channel_destroy (void *cls,
 {
   struct GNUNET_CADET_Handle *h = cls;
   struct GNUNET_CADET_Channel *ch;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  ccn = msg->ccn;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Channel %X Destroy from service\n",
-       ntohl (ccn.channel_of_client));
-  ch = retrieve_channel (h,
-                         ccn);
 
+  ch = find_channel (h,
+                     msg->ccn);
   if (NULL == ch)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "channel %X unknown\n",
-         ntohl (ccn.channel_of_client));
+         "Received channel destroy for unknown channel %X from CADET service (recently close?)\n",
+         ntohl (msg->ccn.channel_of_client));
     return;
   }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received channel destroy for channel %X from CADET service\n",
+       ntohl (msg->ccn.channel_of_client));
   destroy_channel (ch);
 }
 
@@ -976,25 +704,14 @@ static int
 check_local_data (void *cls,
                   const struct GNUNET_CADET_LocalData *message)
 {
-  struct GNUNET_CADET_Handle *h = cls;
-  struct GNUNET_CADET_Channel *ch;
   uint16_t size;
 
   size = ntohs (message->header.size);
   if (sizeof (*message) + sizeof (struct GNUNET_MessageHeader) > size)
   {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-
-  ch = retrieve_channel (h,
-                         message->ccn);
-  if (NULL == ch)
-  {
-    GNUNET_break_op (0);
+    GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-
   return GNUNET_OK;
 }
 
@@ -1011,62 +728,31 @@ handle_local_data (void *cls,
 {
   struct GNUNET_CADET_Handle *h = cls;
   const struct GNUNET_MessageHeader *payload;
-  const struct GNUNET_CADET_MessageHandler *handler;
   struct GNUNET_CADET_Channel *ch;
   uint16_t type;
   int fwd;
 
-  ch = retrieve_channel (h,
-                         message->ccn);
+  ch = find_channel (h,
+                     message->ccn);
   if (NULL == ch)
   {
-    GNUNET_break_op (0);
-    reconnect (h);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Unknown channel %X for incoming data (recently closed?)\n",
+         ntohl (message->ccn.channel_of_client));
     return;
   }
 
-  payload = (struct GNUNET_MessageHeader *) &message[1];
+  payload = (const struct GNUNET_MessageHeader *) &message[1];
   type = ntohs (payload->type);
   fwd = ntohl (ch->ccn.channel_of_client) <= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got a %s data on channel %s [%X] of type %s (%u)\n",
-       GC_f2s (fwd),
-       GNUNET_i2s (GNUNET_PEER_resolve2 (ch->peer)),
+       "Got a %s data on channel %s [%X] of type %u\n",
+       fwd ? "FWD" : "BWD",
+       GNUNET_i2s (&ch->peer),
        ntohl (message->ccn.channel_of_client),
-       GC_m2s (type),
        type);
-  if (NULL != ch->mq)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "injecting msg %s into mq %p\n",
-         GC_m2s (ntohs (payload->type)),
-         ch->mq);
-    GNUNET_MQ_inject_message (ch->mq, payload);
-    return;
-  }
-  /** @a deprecated */
-  for (unsigned i=0;i<h->n_handlers;i++)
-  {
-    handler = &h->message_handlers[i];
-    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;
-      }
-      return;
-    }
-  }
-  /* Other peer sent message we do not comprehend. */
-  GNUNET_break_op (0);
-  GNUNET_CADET_receive_done (ch);
+  GNUNET_MQ_inject_message (ch->mq,
+                            payload);
 }
 
 
@@ -1083,55 +769,34 @@ handle_local_ack (void *cls,
 {
   struct GNUNET_CADET_Handle *h = cls;
   struct GNUNET_CADET_Channel *ch;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-  struct GNUNET_CADET_TransmitHandle *th;
 
-  ccn = message->ccn;
-  ch = retrieve_channel (h, ccn);
+  ch = find_channel (h,
+                     message->ccn);
   if (NULL == ch)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "ACK on unknown channel %X\n",
-         ntohl (ccn.channel_of_client));
+         ntohl (message->ccn.channel_of_client));
     return;
   }
   ch->allow_send++;
-  if (NULL != ch->mq)
+  if (NULL == ch->pending_env)
   {
-    if (NULL == ch->pending_env)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got an ACK on mq channel %X, allow send now %u!\n",
-           ntohl (ch->ccn.channel_of_client),
-           ch->allow_send);
-      notify_window_size (ch);
-    }
-    else
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got an ACK on mq channel %X, sending pending message!\n",
-           ntohl (ch->ccn.channel_of_client));
-      GNUNET_MQ_send (h->mq, ch->pending_env);
-      ch->allow_send--;
-      ch->pending_env = NULL;
-      ch->mq_cont = GNUNET_SCHEDULER_add_now (&cadet_mq_send_continue, ch);
-    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got an ACK on mq channel %X, allow send now %u!\n",
+         ntohl (ch->ccn.channel_of_client),
+         ch->allow_send);
+    notify_window_size (ch);
     return;
   }
-
-  /** @deprecated */
-  /* Old style API */
-  for (th = h->th_head; NULL != th; th = th->next)
-  {
-    if ( (th->channel == ch) &&
-         (NULL == th->request_data_task) )
-    {
-      th->request_data_task
-        = GNUNET_SCHEDULER_add_now (&request_data,
-                                    th);
-      break;
-    }
-  }
+  if (NULL != ch->mq_cont)
+    return; /* already working on it! */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got an ACK on mq channel %X, sending pending message!\n",
+       ntohl (ch->ccn.channel_of_client));
+  ch->mq_cont
+    = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
+                                ch);
 }
 
 
@@ -1149,134 +814,15 @@ handle_mq_error (void *cls,
 {
   struct GNUNET_CADET_Handle *h = cls;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MQ ERROR: %u\n", error);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "MQ ERROR: %u\n",
+              error);
   GNUNET_MQ_destroy (h->mq);
   h->mq = NULL;
   reconnect (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);
-// }
-
-
-
-/**
- * Check that message received from CADET service is well-formed.
- *
- * @param cls the `struct GNUNET_CADET_Handle`
- * @param message the message we got
- * @return #GNUNET_OK if the message is well-formed,
- *         #GNUNET_SYSERR otherwise
- */
-static int
-check_get_peers (void *cls,
-                 const struct GNUNET_CADET_LocalInfoPeer *message)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-  uint16_t size;
-
-  if (NULL == h->info_cb.peers_cb)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "  no handler for peesr monitor message!\n");
-    return GNUNET_SYSERR;
-  }
-
-  size = ntohs (message->header.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 GNUNET_SYSERR;
-  }
-
-  return GNUNET_OK;
-}
-
-
 /**
  * Process a local reply about info on all tunnels, pass info to the user.
  *
@@ -1288,9 +834,13 @@ handle_get_peers (void *cls,
                   const struct GNUNET_CADET_LocalInfoPeer *msg)
 {
   struct GNUNET_CADET_Handle *h = cls;
-  h->info_cb.peers_cb (h->info_cls, &msg->destination,
+
+  if (NULL == h->info_cb.peers_cb)
+    return;
+  h->info_cb.peers_cb (h->info_cls,
+                       &msg->destination,
                        (int) ntohs (msg->tunnel),
-                       (unsigned int ) ntohs (msg->paths),
+                       (unsigned int) ntohs (msg->paths),
                        0);
 }
 
@@ -1307,62 +857,39 @@ static int
 check_get_peer (void *cls,
                 const struct GNUNET_CADET_LocalInfoPeer *message)
 {
-  struct GNUNET_CADET_Handle *h = cls;
-  const size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPeer);
-  struct GNUNET_PeerIdentity *paths_array;
+  size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPeer);
+  const struct GNUNET_PeerIdentity *paths_array;
   size_t esize;
   unsigned int epaths;
   unsigned int paths;
   unsigned int peers;
 
-  if (NULL == h->info_cb.peer_cb)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "  no handler for peer monitor message!\n");
-    goto clean_cls;
-  }
-
-  /* Verify message sanity */
   esize = ntohs (message->header.size);
   if (esize < msize)
   {
-    GNUNET_break_op (0);
-    h->info_cb.peer_cb (h->info_cls, NULL, 0, 0, 0, NULL);
-    goto clean_cls;
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
   if (0 != ((esize - msize) % sizeof (struct GNUNET_PeerIdentity)))
   {
-    GNUNET_break_op (0);
-    h->info_cb.peer_cb (h->info_cls, NULL, 0, 0, 0, NULL);
-    goto clean_cls;
-
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
   peers = (esize - msize) / sizeof (struct GNUNET_PeerIdentity);
-  epaths = (unsigned int) ntohs (message->paths);
-  paths_array = (struct GNUNET_PeerIdentity *) &message[1];
+  epaths = ntohs (message->paths);
+  paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
   paths = 0;
-  for (int i = 0; i < peers; i++)
-  {
-    if (0 == memcmp (&paths_array[i], &message->destination,
+  for (unsigned int i = 0; i < peers; i++)
+    if (0 == memcmp (&paths_array[i],
+                     &message->destination,
                      sizeof (struct GNUNET_PeerIdentity)))
-    {
       paths++;
-    }
-  }
   if (paths != epaths)
   {
-    GNUNET_break_op (0);
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "p:%u, e: %u\n", paths, epaths);
-    h->info_cb.peer_cb (h->info_cls, NULL, 0, 0, 0, NULL);
-    goto clean_cls;
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
-
   return GNUNET_OK;
-
-clean_cls:
-  h->info_cb.peer_cb = NULL;
-  h->info_cls = NULL;
-  return GNUNET_SYSERR;
 }
 
 
@@ -1377,22 +904,26 @@ handle_get_peer (void *cls,
                  const struct GNUNET_CADET_LocalInfoPeer *message)
 {
   struct GNUNET_CADET_Handle *h = cls;
-  struct GNUNET_PeerIdentity *paths_array;
+  const struct GNUNET_PeerIdentity *paths_array;
   unsigned int paths;
   unsigned int path_length;
   int neighbor;
   unsigned int peers;
 
-  paths = (unsigned int) ntohs (message->paths);
-  paths_array = (struct GNUNET_PeerIdentity *) &message[1];
+  if (NULL == h->info_cb.peer_cb)
+    return;
+  paths = ntohs (message->paths);
+  paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
   peers = (ntohs (message->header.size) - sizeof (*message))
           / sizeof (struct GNUNET_PeerIdentity);
   path_length = 0;
   neighbor = GNUNET_NO;
 
-  for (int i = 0; i < peers; i++)
+  for (unsigned int i = 0; i < peers; i++)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&paths_array[i]));
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                " %s\n",
+                GNUNET_i2s (&paths_array[i]));
     path_length++;
     if (0 == memcmp (&paths_array[i], &message->destination,
                      sizeof (struct GNUNET_PeerIdentity)))
@@ -1404,7 +935,7 @@ handle_get_peer (void *cls,
   }
 
   /* Call Callback with tunnel info. */
-  paths_array = (struct GNUNET_PeerIdentity *) &message[1];
+  paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
   h->info_cb.peer_cb (h->info_cls,
                       &message->destination,
                       (int) ntohs (message->tunnel),
@@ -1414,40 +945,6 @@ handle_get_peer (void *cls,
 }
 
 
-/**
- * Check that message received from CADET service is well-formed.
- *
- * @param cls the `struct GNUNET_CADET_Handle`
- * @param msg the message we got
- * @return #GNUNET_OK if the message is well-formed,
- *         #GNUNET_SYSERR otherwise
- */
-static int
-check_get_tunnels (void *cls,
-                   const struct GNUNET_CADET_LocalInfoTunnel *msg)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-  uint16_t size;
-
-  if (NULL == h->info_cb.tunnels_cb)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "  no handler for tunnels monitor message!\n");
-    return GNUNET_SYSERR;
-  }
-
-  size = ntohs (msg->header.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 GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
 /**
  * Process a local reply about info on all tunnels, pass info to the user.
  *
@@ -1460,6 +957,8 @@ handle_get_tunnels (void *cls,
 {
   struct GNUNET_CADET_Handle *h = cls;
 
+  if (NULL == h->info_cb.tunnels_cb)
+    return;
   h->info_cb.tunnels_cb (h->info_cls,
                          &msg->destination,
                          ntohl (msg->channels),
@@ -1482,28 +981,18 @@ static int
 check_get_tunnel (void *cls,
                   const struct GNUNET_CADET_LocalInfoTunnel *msg)
 {
-  struct GNUNET_CADET_Handle *h = cls;
   unsigned int ch_n;
   unsigned int c_n;
   size_t esize;
   size_t msize;
 
-  if (NULL == h->info_cb.tunnel_cb)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "  no handler for tunnel monitor message!\n");
-    goto clean_cls;
-  }
-
   /* Verify message sanity */
   msize = ntohs (msg->header.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;
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
   ch_n = ntohl (msg->channels);
   c_n = ntohl (msg->connections);
@@ -1518,17 +1007,9 @@ check_get_tunnel (void *cls,
                 (unsigned int) esize,
                 ch_n,
                 c_n);
-    h->info_cb.tunnel_cb (h->info_cls,
-                          NULL, 0, 0, NULL, NULL, 0, 0);
-    goto clean_cls;
+    return GNUNET_SYSERR;
   }
-
   return GNUNET_OK;
-
-clean_cls:
-  h->info_cb.tunnel_cb = NULL;
-  h->info_cls = NULL;
-  return GNUNET_SYSERR;
 }
 
 
@@ -1548,6 +1029,9 @@ handle_get_tunnel (void *cls,
   const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns;
   const struct GNUNET_CADET_ChannelTunnelNumber *chns;
 
+  if (NULL == h->info_cb.tunnel_cb)
+    return;
+
   ch_n = ntohl (msg->channels);
   c_n = ntohl (msg->connections);
 
@@ -1591,44 +1075,25 @@ reconnect (struct GNUNET_CADET_Handle *h)
                              GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
                              struct GNUNET_CADET_LocalAck,
                              h),
-    GNUNET_MQ_hd_var_size (get_peers,
-                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
-                           struct GNUNET_CADET_LocalInfoPeer,
-                           h),
+    GNUNET_MQ_hd_fixed_size (get_peers,
+                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
+                             struct GNUNET_CADET_LocalInfoPeer,
+                             h),
     GNUNET_MQ_hd_var_size (get_peer,
                            GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
                            struct GNUNET_CADET_LocalInfoPeer,
                            h),
-    GNUNET_MQ_hd_var_size (get_tunnels,
-                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
-                           struct GNUNET_CADET_LocalInfoTunnel,
-                           h),
+    GNUNET_MQ_hd_fixed_size (get_tunnels,
+                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
+                             struct GNUNET_CADET_LocalInfoTunnel,
+                             h),
     GNUNET_MQ_hd_var_size (get_tunnel,
                            GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
                            struct GNUNET_CADET_LocalInfoTunnel,
                            h),
-// FIXME
-//   GNUNET_MQ_hd_fixed_Y       size (channel_destroyed,
-//                        GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED,
-//                        struct GNUNET_CADET_ChannelDestroyMessage);
     GNUNET_MQ_handler_end ()
   };
-  struct GNUNET_CADET_Channel *ch;
-
-  while (NULL != (ch = h->channels_head))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Destroying channel due to a reconnect\n");
-    destroy_channel (ch);
-  }
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CADET\n");
-
-  if (NULL != h->mq)
-  {
-    GNUNET_MQ_destroy (h->mq);
-    h->mq = NULL;
-  }
   h->mq = GNUNET_CLIENT_connect (h->cfg,
                                  "cadet",
                                  handlers,
@@ -1639,85 +1104,60 @@ reconnect (struct GNUNET_CADET_Handle *h)
     schedule_reconnect (h);
     return;
   }
-  else
-  {
-    h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
-  }
-}
-
-/**
- * Reconnect callback: tries to reconnect again after a failer previous
- * reconnecttion
- *
- * @param cls closure (cadet handle)
- */
-static void
-reconnect_cbk (void *cls)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-
-  h->reconnect_task = NULL;
-  reconnect (h);
+  h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
 }
 
 
 /**
- * Reconnect to the service, retransmit all infomation to try to restore the
- * original state.
- *
- * @param h handle to the cadet
+ * Function called during #GNUNET_CADET_disconnect() to destroy
+ * all channels that are still open.
  *
- * @return #GNUNET_YES in case of sucess, #GNUNET_NO otherwise (service down...)
+ * @param cls the `struct GNUNET_CADET_Handle`
+ * @param cid chanenl ID
+ * @param value a `struct GNUNET_CADET_Channel` to destroy
+ * @return #GNUNET_OK (continue to iterate)
  */
-static void
-schedule_reconnect (struct GNUNET_CADET_Handle *h)
-{
-  if (NULL == h->reconnect_task)
-  {
-    h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
-                                                      &reconnect_cbk, h);
-    h->reconnect_time = GNUNET_TIME_STD_BACKOFF (h->reconnect_time);
-  }
-}
-
-
-/******************************************************************************/
-/**********************      API CALL DEFINITIONS     *************************/
-/******************************************************************************/
-
-struct GNUNET_CADET_Handle *
-GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                      void *cls,
-                      GNUNET_CADET_ChannelEndHandler cleaner,
-                      const struct GNUNET_CADET_MessageHandler *handlers)
+static int
+destroy_channel_cb (void *cls,
+                    uint32_t cid,
+                    void *value)
 {
-  struct GNUNET_CADET_Handle *h;
+  /* struct GNUNET_CADET_Handle *handle = cls; */
+  struct GNUNET_CADET_Channel *ch = value;
 
-  h = GNUNET_new (struct GNUNET_CADET_Handle);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "GNUNET_CADET_connect() %p\n",
-       h);
-  h->cfg = cfg;
-  h->cleaner = cleaner;
-  h->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_YES);
-  reconnect (h);
-  if (h->mq == NULL)
+  if (ntohl (ch->ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
   {
     GNUNET_break (0);
-    GNUNET_CADET_disconnect (h);
-    return NULL;
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "channel %X not destroyed\n",
+         ntohl (ch->ccn.channel_of_client));
   }
-  h->cls = cls;
-  h->message_handlers = handlers;
-  h->next_ccn.channel_of_client = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-  h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
-  h->reconnect_task = NULL;
+  destroy_channel (ch);
+  return GNUNET_OK;
+}
 
-  /* count handlers */
-  for (h->n_handlers = 0;
-       handlers && handlers[h->n_handlers].type;
-       h->n_handlers++) ;
-  return h;
+
+/**
+ * Function called during #GNUNET_CADET_disconnect() to destroy
+ * all ports that are still open.
+ *
+ * @param cls the `struct GNUNET_CADET_Handle`
+ * @param id port ID
+ * @param value a `struct GNUNET_CADET_Channel` to destroy
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+destroy_port_cb (void *cls,
+                 const struct GNUNET_HashCode *id,
+                 void *value)
+{
+  /* struct GNUNET_CADET_Handle *handle = cls; */
+  struct GNUNET_CADET_Port *port = value;
+
+  /* This is a warning, the app should have cleanly closed all open ports */
+  GNUNET_break (0);
+  GNUNET_CADET_close_port (port);
+  return GNUNET_OK;
 }
 
 
@@ -1732,57 +1172,16 @@ GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
 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 (ntohl (ch->ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-    {
-      GNUNET_break (0);
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "channel %X not destroyed\n",
-           ntohl (ch->ccn.channel_of_client));
-    }
-    destroy_channel (ch);
-    ch = aux;
-  }
-  while (NULL != (th = handle->th_head))
-  {
-    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_CHANNEL_OPEN:
-      case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
-      case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN:
-      case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE:
-      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 unsent msg %s\n",
-             GC_m2s (ntohs(msg->type)));
-    }
-
-    GNUNET_CADET_notify_transmit_ready_cancel (th);
-  }
-
+  GNUNET_CONTAINER_multihashmap_iterate (handle->ports,
+                                         &destroy_port_cb,
+                                         handle);
+  GNUNET_CONTAINER_multihashmap_destroy (handle->ports);
+  handle->ports = NULL;
+  GNUNET_CONTAINER_multihashmap32_iterate (handle->channels,
+                                           &destroy_channel_cb,
+                                           handle);
+  GNUNET_CONTAINER_multihashmap32_destroy (handle->channels);
+  handle->channels = NULL;
   if (NULL != handle->mq)
   {
     GNUNET_MQ_destroy (handle->mq);
@@ -1790,58 +1189,15 @@ GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle)
   }
   if (NULL != handle->reconnect_task)
   {
-    GNUNET_SCHEDULER_cancel(handle->reconnect_task);
+    GNUNET_SCHEDULER_cancel (handle->reconnect_task);
     handle->reconnect_task = NULL;
   }
-
-  GNUNET_CONTAINER_multihashmap_destroy (handle->ports);
-  handle->ports = NULL;
   GNUNET_free (handle);
 }
 
 
 /**
- * Open a port to receive incomming channels.
- *
- * @param h CADET handle.
- * @param port Hash representing the port number.
- * @param new_channel Function called when an channel is received.
- * @param new_channel_cls Closure for @a new_channel.
- * @return Port handle.
- */
-struct GNUNET_CADET_Port *
-GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
-                       const struct GNUNET_HashCode *port,
-                       GNUNET_CADET_InboundChannelNotificationHandler
-                           new_channel,
-                       void *new_channel_cls)
-{
-  struct GNUNET_CADET_PortMessage *msg;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_Port *p;
-
-  GNUNET_assert (NULL != new_channel);
-  p = GNUNET_new (struct GNUNET_CADET_Port);
-  p->cadet = h;
-  p->hash = GNUNET_new (struct GNUNET_HashCode);
-  *p->hash = *port;
-  p->handler = new_channel;
-  p->cls = new_channel_cls;
-  GNUNET_assert (GNUNET_OK ==
-                GNUNET_CONTAINER_multihashmap_put (h->ports,
-                                                   p->hash,
-                                                   p,
-                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-
-  env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN);
-  msg->port = *p->hash;
-  GNUNET_MQ_send (h->mq, env);
-
-  return p;
-}
-
-/**
- * Close a port opened with @a GNUNET_CADET_open_port.
+ * Close a port opened with @a GNUNET_CADET_open_port().
  * The @a new_channel callback will no longer be called.
  *
  * @param p Port handle.
@@ -1851,111 +1207,45 @@ GNUNET_CADET_close_port (struct GNUNET_CADET_Port *p)
 {
   struct GNUNET_CADET_PortMessage *msg;
   struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_HashCode *id;
-
-  env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE);
 
-  id = NULL != p->hash ? p->hash : &p->id;
-  msg->port = *id;
-  GNUNET_MQ_send (p->cadet->mq, env);
-  GNUNET_CONTAINER_multihashmap_remove (p->cadet->ports, id, p);
-  GNUNET_free_non_null (p->hash);
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE);
+  msg->port = p->id;
+  GNUNET_MQ_send (p->cadet->mq,
+                  env);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (p->cadet->ports,
+                                                       &p->id,
+                                                       p));
+  GNUNET_free_non_null (p->handlers);
   GNUNET_free (p);
 }
 
 
 /**
- * Create a new channel towards a remote peer.
+ * Destroy an existing channel.
  *
- * 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.
+ * The existing end callback for the channel will be called immediately.
+ * Any pending outgoing messages will be sent but no incoming messages will be
+ * accepted and no data callbacks will be called.
  *
- * @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 hash (port number).
- * @param options CadetOption flag field, with all desired option bits set to 1.
- * @return handle to the channel
+ * @param channel Channel handle, becomes invalid after this call.
  */
-struct GNUNET_CADET_Channel *
-GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
-                            void *channel_ctx,
-                            const struct GNUNET_PeerIdentity *peer,
-                            const struct GNUNET_HashCode *port,
-                            enum GNUNET_CADET_ChannelOption options)
-{
-  struct GNUNET_CADET_LocalChannelCreateMessage *msg;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_Channel *ch;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  ccn.channel_of_client = htonl (0);
-  ch = create_channel (h, ccn);
-  ch->ctx = channel_ctx;
-  ch->peer = GNUNET_PEER_intern (peer);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Creating new channel to %s:%u at %p number %X\n",
-       GNUNET_i2s (peer),
-       port,
-       ch,
-       ntohl (ch->ccn.channel_of_client));
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
-  msg->ccn = ch->ccn;
-  msg->port = *port;
-  msg->peer = *peer;
-  msg->opt = htonl (options);
-  GNUNET_MQ_send (h->mq,
-                  env);
-  return ch;
-}
-
-
 void
 GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
 {
-  struct GNUNET_CADET_Handle *h;
+  struct GNUNET_CADET_Handle *h = channel->cadet;
   struct GNUNET_CADET_LocalChannelDestroyMessage *msg;
   struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_TransmitHandle *th;
-  struct GNUNET_CADET_TransmitHandle *next;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying channel\n");
-  h = channel->cadet;
-  for  (th = h->th_head; th != NULL; th = next)
+  if (NULL != h->mq)
   {
-    next = th->next;
-    if (th->channel == channel)
-    {
-      GNUNET_break (0);
-      if (GNUNET_YES == th_is_payload (th))
-      {
-        /* applications should cancel before destroying channel */
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             "Channel destroyed without cancelling transmission requests\n");
-        th->notify (th->notify_cls, 0, NULL);
-      }
-      else
-      {
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             "no meta-traffic should be queued\n");
-      }
-      GNUNET_CONTAINER_DLL_remove (h->th_head,
-                                   h->th_tail,
-                                   th);
-      GNUNET_CADET_notify_transmit_ready_cancel (th);
-    }
+    env = GNUNET_MQ_msg (msg,
+                         GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
+    msg->ccn = channel->ccn;
+    GNUNET_MQ_send (h->mq,
+                    env);
   }
-
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
-  msg->ccn = channel->ccn;
-  GNUNET_MQ_send (h->mq,
-                  env);
-
   destroy_channel (channel);
 }
 
@@ -1971,10 +1261,10 @@ GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
  */
 const union GNUNET_CADET_ChannelInfo *
 GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
-                              enum GNUNET_CADET_ChannelOption option, ...)
+                               enum GNUNET_CADET_ChannelOption option,
+                               ...)
 {
   static int bool_flag;
-  const union GNUNET_CADET_ChannelInfo *ret;
 
   switch (option)
   {
@@ -1985,74 +1275,15 @@ GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
         bool_flag = GNUNET_YES;
       else
         bool_flag = GNUNET_NO;
-      ret = (const union GNUNET_CADET_ChannelInfo *) &bool_flag;
+      return (const union GNUNET_CADET_ChannelInfo *) &bool_flag;
       break;
     case GNUNET_CADET_OPTION_PEER:
-      ret = (const union GNUNET_CADET_ChannelInfo *) GNUNET_PEER_resolve2 (channel->peer);
+      return (const union GNUNET_CADET_ChannelInfo *) &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);
-  GNUNET_assert (NULL != notify);
-  GNUNET_assert (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE >= notify_size);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "CADET NOTIFY TRANSMIT READY on channel %X allow_send is %u to %s with %u bytes\n",
-       ntohl (channel->ccn.channel_of_client),
-       channel->allow_send,
-       (ntohl (channel->ccn.channel_of_client) >=
-        GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-       ? "origin"
-       : "destination",
-       (unsigned int) notify_size);
-  if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us != maxdelay.rel_value_us)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "CADET transmit ready timeout is deprected (has no effect)\n");
-  }
-
-  th = GNUNET_new (struct GNUNET_CADET_TransmitHandle);
-  th->channel = channel;
-  th->size = notify_size;
-  th->notify = notify;
-  th->notify_cls = notify_cls;
-  if (0 != channel->allow_send)
-    th->request_data_task
-      = GNUNET_SCHEDULER_add_now (&request_data,
-                                  th);
-  else
-    add_to_queue (channel->cadet,
-                  th);
-  return th;
-}
-
-
-void
-GNUNET_CADET_notify_transmit_ready_cancel (struct GNUNET_CADET_TransmitHandle *th)
-{
-  if (NULL != th->request_data_task)
-  {
-    GNUNET_SCHEDULER_cancel (th->request_data_task);
-    th->request_data_task = NULL;
-  }
-  remove_from_queue (th);
-  GNUNET_free (th);
 }
 
 
@@ -2078,18 +1309,23 @@ GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel)
 }
 
 
+/**
+ * Send message of @a type to CADET service of @a h
+ *
+ * @param h handle to CADET service
+ * @param type message type of trivial information request to send
+ */
 static void
-send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type)
+send_info_request (struct GNUNET_CADET_Handle *h,
+                   uint16_t type)
 {
   struct GNUNET_MessageHeader *msg;
   struct GNUNET_MQ_Envelope *env;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " Sending %s monitor message to service\n",
-       GC_m2s(type));
-
-  env = GNUNET_MQ_msg (msg, type);
-  GNUNET_MQ_send (h->mq, env);
+  env = GNUNET_MQ_msg (msg,
+                       type);
+  GNUNET_MQ_send (h->mq,
+                  env);
 }
 
 
@@ -2103,8 +1339,8 @@ send_info_request (struct GNUNET_CADET_Handle *h, uint16_t type)
 void
 GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "requesting dump\n");
-  send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP);
+  send_info_request (h,
+                     GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP);
 }
 
 
@@ -2113,13 +1349,11 @@ GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h)
  * 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
@@ -2132,7 +1366,8 @@ GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h,
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+  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;
@@ -2145,15 +1380,13 @@ GNUNET_CADET_get_peers (struct GNUNET_CADET_Handle *h,
  * WARNING: unstable API, likely to change in the future!
  *
  * @param h Cadet handle.
- *
- * @return Closure given to GNUNET_CADET_get_peers.
+ * @return Closure given to GNUNET_CADET_get_peers().
  */
 void *
 GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h)
 {
-  void *cls;
+  void *cls = h->info_cls;
 
-  cls = h->info_cls;
   h->info_cb.peers_cb = NULL;
   h->info_cls = NULL;
   return cls;
@@ -2171,7 +1404,6 @@ GNUNET_CADET_get_peers_cancel (struct GNUNET_CADET_Handle *h)
  * @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
@@ -2188,11 +1420,11 @@ GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h,
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-
-  env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
   msg->peer = *id;
-  GNUNET_MQ_send (h->mq, env);
-
+  GNUNET_MQ_send (h->mq,
+                  env);
   h->info_cb.peer_cb = callback;
   h->info_cls = callback_cls;
   return GNUNET_OK;
@@ -2209,7 +1441,6 @@ GNUNET_CADET_get_peer (struct GNUNET_CADET_Handle *h,
  * @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
@@ -2222,7 +1453,8 @@ GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h,
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  send_info_request (h, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+  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;
@@ -2233,23 +1465,19 @@ GNUNET_CADET_get_tunnels (struct GNUNET_CADET_Handle *h,
  * Cancel a monitor request. The monitor callback will not be called.
  *
  * @param h Cadet handle.
- *
- * @return Closure given to GNUNET_CADET_get_tunnels.
+ * @return Closure given to GNUNET_CADET_get_tunnels().
  */
 void *
 GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h)
 {
-  void *cls;
+  void *cls = h->info_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.
@@ -2261,7 +1489,6 @@ GNUNET_CADET_get_tunnels_cancel (struct GNUNET_CADET_Handle *h)
  * @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
@@ -2278,169 +1505,17 @@ GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-
-  env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
   msg->peer = *id;
-  GNUNET_MQ_send (h->mq, env);
-
+  GNUNET_MQ_send (h->mq,
+                  env);
   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;
-  struct GNUNET_MQ_Envelope *env;
-
-  if (NULL != h->info_cb.channel_cb)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-
-  env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL);
-  msg->peer = *initiator;
-  msg->ccn.channel_of_client = htonl (channel_number);
-  GNUNET_MQ_send (h->mq, env);
-
-  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);
-  GNUNET_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_old (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_old (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_old,
-                                      &cadet_mq_destroy_impl_old,
-                                      NULL, /* FIXME: cancel impl. */
-                                      state,
-                                      NULL, /* no msg handlers */
-                                      NULL, /* no err handlers */
-                                      NULL); /* no handler cls */
-  return mq;
-}
-
-
 /**
  * Transitional function to convert an unsigned int port to a hash value.
  * WARNING: local static value returned, NOT reentrant!
@@ -2456,19 +1531,14 @@ GC_u2h (uint32_t port)
   static struct GNUNET_HashCode hash;
 
   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "This is a transitional function, "
-              "use proper crypto hashes as CADET ports\n");
-  GNUNET_CRYPTO_hash (&port, sizeof (port), &hash);
-
+              "This is a transitional function, use proper crypto hashes as CADET ports\n");
+  GNUNET_CRYPTO_hash (&port,
+                      sizeof (port),
+                      &hash);
   return &hash;
 }
 
 
-
-/******************************************************************************/
-/******************************* MQ-BASED API *********************************/
-/******************************************************************************/
-
 /**
  * Connect to the MQ-based cadet service.
  *
@@ -2477,16 +1547,17 @@ GC_u2h (uint32_t port)
  * @return Handle to the cadet service NULL on error.
  */
 struct GNUNET_CADET_Handle *
-GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg)
+GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   struct GNUNET_CADET_Handle *h;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "GNUNET_CADET_connecT()\n");
+       "GNUNET_CADET_connect()\n");
   h = GNUNET_new (struct GNUNET_CADET_Handle);
   h->cfg = cfg;
-  h->mq_api = GNUNET_YES;
-  h->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_YES);
+  h->ports = GNUNET_CONTAINER_multihashmap_create (4,
+                                                   GNUNET_YES);
+  h->channels = GNUNET_CONTAINER_multihashmap32_create (4);
   reconnect (h);
   if (NULL == h->mq)
   {
@@ -2512,11 +1583,10 @@ GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg)
  * @param window_changes Function called when the transmit window size changes.
  * @param disconnects Function called when a channel is disconnected.
  * @param handlers Callbacks for messages we care about, NULL-terminated.
- *
  * @return Port handle.
  */
 struct GNUNET_CADET_Port *
-GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
+GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
                         const struct GNUNET_HashCode *port,
                         GNUNET_CADET_ConnectEventHandler connects,
                         void * connects_cls,
@@ -2538,16 +1608,7 @@ GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
   p->cls = connects_cls;
   p->window_changes = window_changes;
   p->disconnects = disconnects;
-  if (NULL != handlers)
-  {
-    unsigned int i;
-    for (i=0;NULL != handlers[i].cb; i++) ;
-    p->handlers = GNUNET_new_array (i + 1,
-                                    struct GNUNET_MQ_MessageHandler);
-    GNUNET_memcpy ((struct GNUNET_MQ_MessageHandler *) p->handlers,
-                   handlers,
-                   i * sizeof (struct GNUNET_MQ_MessageHandler));
-  }
+  p->handlers = GNUNET_MQ_copy_handlers (handlers);
 
   GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONTAINER_multihashmap_put (h->ports,
@@ -2555,10 +1616,11 @@ GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
                                                    p,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
 
-  env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN);
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN);
   msg->port = p->id;
-  GNUNET_MQ_send (h->mq, env);
-
+  GNUNET_MQ_send (h->mq,
+                  env);
   return p;
 }
 
@@ -2580,11 +1642,10 @@ GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
  * @param window_changes Function called when the transmit window size changes.
  * @param disconnects Function called when the channel is disconnected.
  * @param handlers Callbacks for messages we care about, NULL-terminated.
- *
  * @return Handle to the channel.
  */
 struct GNUNET_CADET_Channel *
-GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h,
+GNUNET_CADET_channel_create (struct GNUNET_CADET_Handle *h,
                              void *channel_cls,
                              const struct GNUNET_PeerIdentity *destination,
                              const struct GNUNET_HashCode *port,
@@ -2594,17 +1655,14 @@ GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h,
                              const struct GNUNET_MQ_MessageHandler *handlers)
 {
   struct GNUNET_CADET_Channel *ch;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
   struct GNUNET_CADET_LocalChannelCreateMessage *msg;
   struct GNUNET_MQ_Envelope *env;
 
   GNUNET_assert (NULL != disconnects);
-
-  /* Save parameters */
-  ccn.channel_of_client = htonl (0);
-  ch = create_channel (h, ccn);
+  ch = create_channel (h,
+                       NULL);
   ch->ctx = channel_cls;
-  ch->peer = GNUNET_PEER_intern (destination);
+  ch->peer = *destination;
   ch->options = options;
   ch->window_changes = window_changes;
   ch->disconnects = disconnects;
@@ -2628,7 +1686,6 @@ GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h,
   msg->opt = htonl (options);
   GNUNET_MQ_send (h->mq,
                   env);
-
   return ch;
 }
 
@@ -2645,3 +1702,5 @@ GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel)
 {
   return channel->mq;
 }
+
+/* end of cadet_api.c */
diff --git a/src/cadet/cadet_api_new.c b/src/cadet/cadet_api_new.c
deleted file mode 100644 (file)
index a62de0a..0000000
+++ /dev/null
@@ -1,1720 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/cadet_api.c
- * @brief cadet api: client implementation of cadet service
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_constants.h"
-#include "gnunet_cadet_service.h"
-#include "cadet.h"
-#include "cadet_protocol.h"
-
-#define LOG(kind,...) GNUNET_log_from (kind, "cadet-api",__VA_ARGS__)
-
-/**
- * Ugly legacy hack.
- */
-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
-{
-  /**
-   * Message queue.
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * Ports open.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap *ports;
-
-  /**
-   * Channels open.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
-
-  /**
-   * child of the next channel to create (to avoid reusing IDs often)
-   */
-  struct GNUNET_CADET_ClientChannelNumber next_ccn;
-
-  /**
-   * Configuration given by the client, in case of reconnection
-   */
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-  /**
-   * Task for trying to reconnect.
-   */
-  struct GNUNET_SCHEDULER_Task *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;
-
-  /**
-   * Time to the next reconnect in case one reconnect fails
-   */
-  struct GNUNET_TIME_Relative reconnect_time;
-
-};
-
-
-/**
- * Opaque handle to a channel.
- */
-struct GNUNET_CADET_Channel
-{
-
-  /**
-   * Other end of the channel.
-   */
-  struct GNUNET_PeerIdentity peer;
-
-  /**
-   * Handle to the cadet this channel belongs to
-   */
-  struct GNUNET_CADET_Handle *cadet;
-
-  /**
-   * Channel's port, if incoming.
-   */
-  struct GNUNET_CADET_Port *incoming_port;
-
-  /**
-   * Any data the caller wants to put in here, used for the
-   * various callbacks (@e disconnects, @e window_changes, handlers).
-   */
-  void *ctx;
-
-  /**
-   * Message Queue for the channel (which we are implementing).
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * Task to allow mq to send more traffic.
-   */
-  struct GNUNET_SCHEDULER_Task *mq_cont;
-
-  /**
-   * Pending envelope with a message to be transmitted to the
-   * service as soon as we are allowed to.  Should only be
-   * non-NULL if @e allow_send is 0.
-   */
-  struct GNUNET_MQ_Envelope *pending_env;
-
-  /**
-   * Window change handler.
-   */
-  GNUNET_CADET_WindowSizeEventHandler window_changes;
-
-  /**
-   * Disconnect handler.
-   */
-  GNUNET_CADET_DisconnectEventHandler disconnects;
-
-  /**
-   * Local ID of the channel, #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI bit is set if outbound.
-   */
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  /**
-   * Channel options: reliability, etc.
-   */
-  enum GNUNET_CADET_ChannelOption options;
-
-  /**
-   * How many messages are we allowed to send to the service right now?
-   */
-  unsigned int allow_send;
-
-};
-
-
-/**
- * Opaque handle to a port.
- */
-struct GNUNET_CADET_Port
-{
-
-  /**
-   * Port "number"
-   */
-  struct GNUNET_HashCode id;
-
-  /**
-   * Handle to the CADET session this port belongs to.
-   */
-  struct GNUNET_CADET_Handle *cadet;
-
-  /**
-   * Callback handler for incoming channels on this port.
-   */
-  GNUNET_CADET_InboundChannelNotificationHandler *handler;
-
-  /**
-   * Closure for @a handler.
-   */
-  void *cls;
-
-  /**
-   * Handler for incoming channels on this port
-   */
-  GNUNET_CADET_ConnectEventHandler connects;
-
-  /**
-   * Closure for @ref connects
-   */
-  void *connects_cls;
-
-  /**
-   * Window size change handler.
-   */
-  GNUNET_CADET_WindowSizeEventHandler window_changes;
-
-  /**
-   * Handler called when an incoming channel is destroyed.
-   */
-  GNUNET_CADET_DisconnectEventHandler disconnects;
-
-  /**
-   * Payload handlers for incoming channels.
-   */
-  struct GNUNET_MQ_MessageHandler *handlers;
-};
-
-
-/**
- * Find the Port struct for a hash.
- *
- * @param h CADET handle.
- * @param hash HashCode for the port number.
- * @return The port handle if known, NULL otherwise.
- */
-static struct GNUNET_CADET_Port *
-find_port (const struct GNUNET_CADET_Handle *h,
-          const struct GNUNET_HashCode *hash)
-{
-  return GNUNET_CONTAINER_multihashmap_get (h->ports,
-                                            hash);
-}
-
-
-/**
- * Get the channel handler for the channel specified by id from the given handle
- *
- * @param h Cadet handle
- * @param ccn ID of the wanted channel
- * @return handle to the required channel or NULL if not found
- */
-static struct GNUNET_CADET_Channel *
-find_channel (struct GNUNET_CADET_Handle *h,
-              struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  return GNUNET_CONTAINER_multihashmap32_get (h->channels,
-                                              ntohl (ccn.channel_of_client));
-}
-
-
-/**
- * Create a new channel and insert it in the channel list of the cadet handle
- *
- * @param h Cadet handle
- * @param ccnp pointer to desired ccn of the channel, NULL to assign one automatically.
- * @return Handle to the created channel.
- */
-static struct GNUNET_CADET_Channel *
-create_channel (struct GNUNET_CADET_Handle *h,
-                const struct GNUNET_CADET_ClientChannelNumber *ccnp)
-{
-  struct GNUNET_CADET_Channel *ch;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  ch = GNUNET_new (struct GNUNET_CADET_Channel);
-  ch->cadet = h;
-  if (NULL == ccnp)
-  {
-    while (NULL !=
-           find_channel (h,
-                         h->next_ccn))
-      h->next_ccn.channel_of_client
-        = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI | (1 + ntohl (h->next_ccn.channel_of_client)));
-    ccn = h->next_ccn;
-  }
-  else
-  {
-    ccn = *ccnp;
-  }
-  ch->ccn = ccn;
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multihashmap32_put (h->channels,
-                                                      ntohl (ch->ccn.channel_of_client),
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  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.
- */
-static void
-destroy_channel (struct GNUNET_CADET_Channel *ch)
-{
-  struct GNUNET_CADET_Handle *h = ch->cadet;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying channel %X of %p\n",
-       ch->ccn,
-       h);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (h->channels,
-                                                         ntohl (ch->ccn.channel_of_client),
-                                                         ch));
-  if (NULL != ch->mq_cont)
-  {
-    GNUNET_SCHEDULER_cancel (ch->mq_cont);
-    ch->mq_cont = NULL;
-  }
-  /* signal channel destruction */
-  if (NULL != ch->disconnects)
-    ch->disconnects (ch->ctx,
-                     ch);
-  if (NULL != ch->pending_env)
-    GNUNET_MQ_discard (ch->pending_env);
-  GNUNET_MQ_destroy (ch->mq);
-  GNUNET_free (ch);
-}
-
-
-/**
- * Reconnect to the service, retransmit all infomation to try to restore the
- * original state.
- *
- * @param h handle to the cadet
- */
-static void
-reconnect (struct GNUNET_CADET_Handle *h);
-
-
-/**
- * Reconnect callback: tries to reconnect again after a failer previous
- * reconnecttion
- *
- * @param cls closure (cadet handle)
- */
-static void
-reconnect_cbk (void *cls)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-
-  h->reconnect_task = NULL;
-  reconnect (h);
-}
-
-
-/**
- * Function called during #reconnect() to destroy
- * all channels that are still open.
- *
- * @param cls the `struct GNUNET_CADET_Handle`
- * @param cid chanenl ID
- * @param value a `struct GNUNET_CADET_Channel` to destroy
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-destroy_channel_on_reconnect_cb (void *cls,
-                                 uint32_t cid,
-                                 void *value)
-{
-  /* struct GNUNET_CADET_Handle *handle = cls; */
-  struct GNUNET_CADET_Channel *ch = value;
-
-  destroy_channel (ch);
-  return GNUNET_OK;
-}
-
-
-/**
- * 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
-schedule_reconnect (struct GNUNET_CADET_Handle *h)
-{
-  if (NULL != h->reconnect_task)
-    return;
-  GNUNET_CONTAINER_multihashmap32_iterate (h->channels,
-                                           &destroy_channel_on_reconnect_cb,
-                                           h);
-  h->reconnect_task
-    = GNUNET_SCHEDULER_add_delayed (h->reconnect_time,
-                                    &reconnect_cbk,
-                                    h);
-  h->reconnect_time
-    = GNUNET_TIME_STD_BACKOFF (h->reconnect_time);
-}
-
-
-/**
- * Notify the application about a change in the window size (if needed).
- *
- * @param ch Channel to notify about.
- */
-static void
-notify_window_size (struct GNUNET_CADET_Channel *ch)
-{
-  if (NULL != ch->window_changes)
-    ch->window_changes (ch->ctx,
-                        ch, /* FIXME: remove 'ch'? */
-                        ch->allow_send);
-}
-
-
-/**
- * Transmit the next message from our queue.
- *
- * @param cls Closure (channel whose mq to activate).
- */
-static void
-cadet_mq_send_now (void *cls)
-{
-  struct GNUNET_CADET_Channel *ch = cls;
-  struct GNUNET_MQ_Envelope *env = ch->pending_env;
-
-  ch->mq_cont = NULL;
-  if (0 == ch->allow_send)
-  {
-    /* how did we get here? */
-    GNUNET_break (0);
-    return;
-  }
-  if (NULL == env)
-  {
-    /* how did we get here? */
-    GNUNET_break (0);
-    return;
-  }
-  ch->allow_send--;
-  ch->pending_env = NULL;
-  GNUNET_MQ_send (ch->cadet->mq,
-                  env);
-  GNUNET_MQ_impl_send_continue (ch->mq);
-}
-
-
-/**
- * Implement sending functionality of a message queue for
- * us sending messages to a peer.
- *
- * Encapsulates the payload message in a #GNUNET_CADET_LocalData message
- * in order to label the message with the channel ID and send the
- * encapsulated message to the service.
- *
- * @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 GNUNET_CADET_Channel *ch = impl_state;
-  struct GNUNET_CADET_Handle *h = ch->cadet;
-  uint16_t msize;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalData *cadet_msg;
-
-  if (NULL == h->mq)
-  {
-    /* We're currently reconnecting, pretend this worked */
-    GNUNET_MQ_impl_send_continue (mq);
-    return;
-  }
-
-  /* check message size for sanity */
-  msize = ntohs (msg->size);
-  if (msize > GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE)
-  {
-    GNUNET_break (0);
-    GNUNET_MQ_impl_send_continue (mq);
-    return;
-  }
-  env = GNUNET_MQ_msg_nested_mh (cadet_msg,
-                                 GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
-                                 msg);
-  cadet_msg->ccn = ch->ccn;
-  GNUNET_assert (NULL == ch->pending_env);
-  ch->pending_env = env;
-  if (0 < ch->allow_send)
-    ch->mq_cont
-      = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
-                                  ch);
-}
-
-
-/**
- * Handle destruction of a message queue.  Implementations must not
- * free @a mq, but should take care of @a 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 GNUNET_CADET_Channel *ch = impl_state;
-
-  GNUNET_assert (mq == ch->mq);
-  ch->mq = NULL;
-}
-
-
-/**
- * We had an error processing a message we forwarded from a peer to
- * the CADET service.  We should just complain about it but otherwise
- * continue processing.
- *
- * @param cls closure with our `struct GNUNET_CADET_Channel`
- * @param error error code
- */
-static void
-cadet_mq_error_handler (void *cls,
-                        enum GNUNET_MQ_Error error)
-{
-  struct GNUNET_CADET_Channel *ch = cls;
-
-  GNUNET_break (0);
-  if (GNUNET_MQ_ERROR_NO_MATCH == error)
-  {
-    /* Got a message we did not understand, still try to continue! */
-    GNUNET_CADET_receive_done (ch);
-  }
-  else
-  {
-    schedule_reconnect (ch->cadet);
-  }
-}
-
-
-/**
- * Implementation function that cancels the currently sent message.
- * Should basically undo whatever #mq_send_impl() did.
- *
- * @param mq message queue
- * @param impl_state state specific to the implementation
- */
-static void
-cadet_mq_cancel_impl (struct GNUNET_MQ_Handle *mq,
-                     void *impl_state)
-{
-  struct GNUNET_CADET_Channel *ch = impl_state;
-
-  GNUNET_assert (NULL != ch->pending_env);
-  GNUNET_MQ_discard (ch->pending_env);
-  ch->pending_env = NULL;
-  if (NULL != ch->mq_cont)
-  {
-    GNUNET_SCHEDULER_cancel (ch->mq_cont);
-    ch->mq_cont = NULL;
-  }
-}
-
-
-/**
- * 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
-handle_channel_created (void *cls,
-                        const struct GNUNET_CADET_LocalChannelCreateMessage *msg)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-  struct GNUNET_CADET_Channel *ch;
-  struct GNUNET_CADET_Port *port;
-  const struct GNUNET_HashCode *port_number;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  ccn = msg->ccn;
-  port_number = &msg->port;
-  if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  port = find_port (h,
-                    port_number);
-  if (NULL == port)
-  {
-    /* We could have closed the port but the service didn't know about it yet
-     * This is not an error.
-     */
-    struct GNUNET_CADET_LocalChannelDestroyMessage *d_msg;
-    struct GNUNET_MQ_Envelope *env;
-
-    GNUNET_break (0);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "No handler for incoming channel %X (on port %s, recently closed?)\n",
-         ntohl (ccn.channel_of_client),
-         GNUNET_h2s (port_number));
-    env = GNUNET_MQ_msg (d_msg,
-                         GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
-    d_msg->ccn = msg->ccn;
-    GNUNET_MQ_send (h->mq,
-                    env);
-    return;
-  }
-
-  ch = create_channel (h,
-                       &ccn);
-  ch->peer = msg->peer;
-  ch->cadet = h;
-  ch->incoming_port = port;
-  ch->options = ntohl (msg->opt);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Creating incoming channel %X [%s] %p\n",
-       ntohl (ccn.channel_of_client),
-       GNUNET_h2s (port_number),
-       ch);
-
-  GNUNET_assert (NULL != port->connects);
-  ch->window_changes = port->window_changes;
-  ch->disconnects = port->disconnects;
-  ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
-                                          &cadet_mq_destroy_impl,
-                                          &cadet_mq_cancel_impl,
-                                          ch,
-                                          port->handlers,
-                                          &cadet_mq_error_handler,
-                                          ch);
-  ch->ctx = port->connects (port->cls,
-                            ch,
-                            &msg->peer);
-  GNUNET_MQ_set_handlers_closure (ch->mq,
-                                  ch->ctx);
-}
-
-
-/**
- * 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
-handle_channel_destroy (void *cls,
-                        const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-  struct GNUNET_CADET_Channel *ch;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received channel destroy for channel %X from CADET service\n",
-       ntohl (msg->ccn.channel_of_client));
-  ch = find_channel (h,
-                     msg->ccn);
-  if (NULL == ch)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  destroy_channel (ch);
-}
-
-
-/**
- * Check that message received from CADET service is well-formed.
- *
- * @param cls the `struct GNUNET_CADET_Handle`
- * @param message the message we got
- * @return #GNUNET_OK if the message is well-formed,
- *         #GNUNET_SYSERR otherwise
- */
-static int
-check_local_data (void *cls,
-                  const struct GNUNET_CADET_LocalData *message)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-  struct GNUNET_CADET_Channel *ch;
-  uint16_t size;
-
-  size = ntohs (message->header.size);
-  if (sizeof (*message) + sizeof (struct GNUNET_MessageHeader) > size)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-
-  ch = find_channel (h,
-                     message->ccn);
-  if (NULL == ch)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Process the incoming data packets, call appropriate handlers.
- *
- * @param h       The cadet handle
- * @param message A message encapsulating the data
- */
-static void
-handle_local_data (void *cls,
-                   const struct GNUNET_CADET_LocalData *message)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-  const struct GNUNET_MessageHeader *payload;
-  struct GNUNET_CADET_Channel *ch;
-  uint16_t type;
-  int fwd;
-
-  ch = find_channel (h,
-                     message->ccn);
-  if (NULL == ch)
-  {
-    GNUNET_break (0);
-    reconnect (h);
-    return;
-  }
-
-  payload = (const struct GNUNET_MessageHeader *) &message[1];
-  type = ntohs (payload->type);
-  fwd = ntohl (ch->ccn.channel_of_client) <= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got a %s data on channel %s [%X] of type %u\n",
-       fwd ? "FWD" : "BWD",
-       GNUNET_i2s (&ch->peer),
-       ntohl (message->ccn.channel_of_client),
-       type);
-  GNUNET_MQ_inject_message (ch->mq,
-                            payload);
-}
-
-
-/**
- * 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
-handle_local_ack (void *cls,
-                  const struct GNUNET_CADET_LocalAck *message)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-  struct GNUNET_CADET_Channel *ch;
-
-  ch = find_channel (h,
-                     message->ccn);
-  if (NULL == ch)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "ACK on unknown channel %X\n",
-         ntohl (message->ccn.channel_of_client));
-    return;
-  }
-  ch->allow_send++;
-  if (NULL == ch->pending_env)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got an ACK on mq channel %X, allow send now %u!\n",
-         ntohl (ch->ccn.channel_of_client),
-         ch->allow_send);
-    notify_window_size (ch);
-    return;
-  }
-  if (NULL != ch->mq_cont)
-    return; /* already working on it! */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got an ACK on mq channel %X, sending pending message!\n",
-       ntohl (ch->ccn.channel_of_client));
-  ch->mq_cont
-    = GNUNET_SCHEDULER_add_now (&cadet_mq_send_now,
-                                ch);
-}
-
-
-/**
- * Generic error handler, called with the appropriate error code and
- * the same closure specified at the creation of the message queue.
- * Not every message queue implementation supports an error handler.
- *
- * @param cls closure, a `struct GNUNET_CORE_Handle *`
- * @param error error code
- */
-static void
-handle_mq_error (void *cls,
-                 enum GNUNET_MQ_Error error)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "MQ ERROR: %u\n",
-              error);
-  GNUNET_MQ_destroy (h->mq);
-  h->mq = NULL;
-  reconnect (h);
-}
-
-
-/**
- * Process a local reply about info on all tunnels, pass info to the user.
- *
- * @param cls Closure (Cadet handle).
- * @param msg Message itself.
- */
-static void
-handle_get_peers (void *cls,
-                  const struct GNUNET_CADET_LocalInfoPeer *msg)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-
-  if (NULL == h->info_cb.peers_cb)
-    return;
-  h->info_cb.peers_cb (h->info_cls,
-                       &msg->destination,
-                       (int) ntohs (msg->tunnel),
-                       (unsigned int) ntohs (msg->paths),
-                       0);
-}
-
-
-/**
- * Check that message received from CADET service is well-formed.
- *
- * @param cls the `struct GNUNET_CADET_Handle`
- * @param message the message we got
- * @return #GNUNET_OK if the message is well-formed,
- *         #GNUNET_SYSERR otherwise
- */
-static int
-check_get_peer (void *cls,
-                const struct GNUNET_CADET_LocalInfoPeer *message)
-{
-  size_t msize = sizeof (struct GNUNET_CADET_LocalInfoPeer);
-  const struct GNUNET_PeerIdentity *paths_array;
-  size_t esize;
-  unsigned int epaths;
-  unsigned int paths;
-  unsigned int peers;
-
-  esize = ntohs (message->header.size);
-  if (esize < msize)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  if (0 != ((esize - msize) % sizeof (struct GNUNET_PeerIdentity)))
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  peers = (esize - msize) / sizeof (struct GNUNET_PeerIdentity);
-  epaths = ntohs (message->paths);
-  paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
-  paths = 0;
-  for (unsigned int i = 0; i < peers; i++)
-    if (0 == memcmp (&paths_array[i],
-                     &message->destination,
-                     sizeof (struct GNUNET_PeerIdentity)))
-      paths++;
-  if (paths != epaths)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Process a local peer info reply, pass info to the user.
- *
- * @param cls Closure (Cadet handle).
- * @param message Message itself.
- */
-static void
-handle_get_peer (void *cls,
-                 const struct GNUNET_CADET_LocalInfoPeer *message)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-  const struct GNUNET_PeerIdentity *paths_array;
-  unsigned int paths;
-  unsigned int path_length;
-  int neighbor;
-  unsigned int peers;
-
-  if (NULL == h->info_cb.peer_cb)
-    return;
-  paths = ntohs (message->paths);
-  paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
-  peers = (ntohs (message->header.size) - sizeof (*message))
-          / sizeof (struct GNUNET_PeerIdentity);
-  path_length = 0;
-  neighbor = GNUNET_NO;
-
-  for (unsigned int i = 0; i < peers; i++)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                " %s\n",
-                GNUNET_i2s (&paths_array[i]));
-    path_length++;
-    if (0 == memcmp (&paths_array[i], &message->destination,
-                     sizeof (struct GNUNET_PeerIdentity)))
-    {
-      if (1 == path_length)
-        neighbor = GNUNET_YES;
-      path_length = 0;
-    }
-  }
-
-  /* Call Callback with tunnel info. */
-  paths_array = (const struct GNUNET_PeerIdentity *) &message[1];
-  h->info_cb.peer_cb (h->info_cls,
-                      &message->destination,
-                      (int) ntohs (message->tunnel),
-                      neighbor,
-                      paths,
-                      paths_array);
-}
-
-
-/**
- * Process a local reply about info on all tunnels, pass info to the user.
- *
- * @param cls Closure (Cadet handle).
- * @param message Message itself.
- */
-static void
-handle_get_tunnels (void *cls,
-                    const struct GNUNET_CADET_LocalInfoTunnel *msg)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-
-  if (NULL == h->info_cb.tunnels_cb)
-    return;
-  h->info_cb.tunnels_cb (h->info_cls,
-                         &msg->destination,
-                         ntohl (msg->channels),
-                         ntohl (msg->connections),
-                         ntohs (msg->estate),
-                         ntohs (msg->cstate));
-
-}
-
-
-/**
- * Check that message received from CADET service is well-formed.
- *
- * @param cls the `struct GNUNET_CADET_Handle`
- * @param msg the message we got
- * @return #GNUNET_OK if the message is well-formed,
- *         #GNUNET_SYSERR otherwise
- */
-static int
-check_get_tunnel (void *cls,
-                  const struct GNUNET_CADET_LocalInfoTunnel *msg)
-{
-  unsigned int ch_n;
-  unsigned int c_n;
-  size_t esize;
-  size_t msize;
-
-  /* Verify message sanity */
-  msize = ntohs (msg->header.size);
-  esize = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
-  if (esize > msize)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  ch_n = ntohl (msg->channels);
-  c_n = ntohl (msg->connections);
-  esize += ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber);
-  esize += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier);
-  if (msize != esize)
-  {
-    GNUNET_break_op (0);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "m:%u, e: %u (%u ch, %u conn)\n",
-                (unsigned int) msize,
-                (unsigned int) esize,
-                ch_n,
-                c_n);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Process a local tunnel info reply, pass info to the user.
- *
- * @param cls Closure (Cadet handle).
- * @param msg Message itself.
- */
-static void
-handle_get_tunnel (void *cls,
-                   const struct GNUNET_CADET_LocalInfoTunnel *msg)
-{
-  struct GNUNET_CADET_Handle *h = cls;
-  unsigned int ch_n;
-  unsigned int c_n;
-  const struct GNUNET_CADET_ConnectionTunnelIdentifier *conns;
-  const struct GNUNET_CADET_ChannelTunnelNumber *chns;
-
-  if (NULL == h->info_cb.tunnel_cb)
-    return;
-
-  ch_n = ntohl (msg->channels);
-  c_n = ntohl (msg->connections);
-
-  /* Call Callback with tunnel info. */
-  conns = (const struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
-  chns = (const struct GNUNET_CADET_ChannelTunnelNumber *) &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));
-}
-
-
-/**
- * Reconnect to the service, retransmit all infomation to try to restore the
- * original state.
- *
- * @param h handle to the cadet
- */
-static void
-reconnect (struct GNUNET_CADET_Handle *h)
-{
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_fixed_size (channel_created,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
-                             struct GNUNET_CADET_LocalChannelCreateMessage,
-                             h),
-    GNUNET_MQ_hd_fixed_size (channel_destroy,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
-                             struct GNUNET_CADET_LocalChannelDestroyMessage,
-                             h),
-    GNUNET_MQ_hd_var_size (local_data,
-                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
-                           struct GNUNET_CADET_LocalData,
-                           h),
-    GNUNET_MQ_hd_fixed_size (local_ack,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
-                             struct GNUNET_CADET_LocalAck,
-                             h),
-    GNUNET_MQ_hd_fixed_size (get_peers,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
-                             struct GNUNET_CADET_LocalInfoPeer,
-                             h),
-    GNUNET_MQ_hd_var_size (get_peer,
-                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
-                           struct GNUNET_CADET_LocalInfoPeer,
-                           h),
-    GNUNET_MQ_hd_fixed_size (get_tunnels,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
-                             struct GNUNET_CADET_LocalInfoTunnel,
-                             h),
-    GNUNET_MQ_hd_var_size (get_tunnel,
-                           GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
-                           struct GNUNET_CADET_LocalInfoTunnel,
-                           h),
-    GNUNET_MQ_handler_end ()
-  };
-
-  h->mq = GNUNET_CLIENT_connect (h->cfg,
-                                 "cadet",
-                                 handlers,
-                                 &handle_mq_error,
-                                 h);
-  if (NULL == h->mq)
-  {
-    schedule_reconnect (h);
-    return;
-  }
-  h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
-}
-
-
-/**
- * Function called during #GNUNET_CADET_disconnect() to destroy
- * all channels that are still open.
- *
- * @param cls the `struct GNUNET_CADET_Handle`
- * @param cid chanenl ID
- * @param value a `struct GNUNET_CADET_Channel` to destroy
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-destroy_channel_cb (void *cls,
-                    uint32_t cid,
-                    void *value)
-{
-  /* struct GNUNET_CADET_Handle *handle = cls; */
-  struct GNUNET_CADET_Channel *ch = value;
-
-  if (ntohl (ch->ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-  {
-    GNUNET_break (0);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "channel %X not destroyed\n",
-         ntohl (ch->ccn.channel_of_client));
-  }
-  destroy_channel (ch);
-  return GNUNET_OK;
-}
-
-
-/**
- * Function called during #GNUNET_CADET_disconnect() to destroy
- * all ports that are still open.
- *
- * @param cls the `struct GNUNET_CADET_Handle`
- * @param id port ID
- * @param value a `struct GNUNET_CADET_Channel` to destroy
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-destroy_port_cb (void *cls,
-                 const struct GNUNET_HashCode *id,
-                 void *value)
-{
-  /* struct GNUNET_CADET_Handle *handle = cls; */
-  struct GNUNET_CADET_Port *port = value;
-
-  /* This is a warning, the app should have cleanly closed all open ports */
-  GNUNET_break (0);
-  GNUNET_CADET_close_port (port);
-  return GNUNET_OK;
-}
-
-
-/**
- * Disconnect from the cadet service. All channels will be destroyed. All channel
- * disconnect callbacks will be called on any still connected peers, notifying
- * about their disconnection. The registered inbound channel cleaner will be
- * called should any inbound channels still exist.
- *
- * @param handle connection to cadet to disconnect
- */
-void
-GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle)
-{
-  GNUNET_CONTAINER_multihashmap_iterate (handle->ports,
-                                         &destroy_port_cb,
-                                         handle);
-  GNUNET_CONTAINER_multihashmap_destroy (handle->ports);
-  handle->ports = NULL;
-  GNUNET_CONTAINER_multihashmap32_iterate (handle->channels,
-                                           &destroy_channel_cb,
-                                           handle);
-  GNUNET_CONTAINER_multihashmap32_destroy (handle->channels);
-  handle->channels = NULL;
-  if (NULL != handle->mq)
-  {
-    GNUNET_MQ_destroy (handle->mq);
-    handle->mq = NULL;
-  }
-  if (NULL != handle->reconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (handle->reconnect_task);
-    handle->reconnect_task = NULL;
-  }
-  GNUNET_free (handle);
-}
-
-
-/**
- * Close a port opened with @a GNUNET_CADET_open_port().
- * The @a new_channel callback will no longer be called.
- *
- * @param p Port handle.
- */
-void
-GNUNET_CADET_close_port (struct GNUNET_CADET_Port *p)
-{
-  struct GNUNET_CADET_PortMessage *msg;
-  struct GNUNET_MQ_Envelope *env;
-
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE);
-  msg->port = p->id;
-  GNUNET_MQ_send (p->cadet->mq,
-                  env);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (p->cadet->ports,
-                                                       &p->id,
-                                                       p));
-  GNUNET_free_non_null (p->handlers);
-  GNUNET_free (p);
-}
-
-
-/**
- * Destroy an existing channel.
- *
- * The existing end callback for the channel will be called immediately.
- * Any pending outgoing messages will be sent but no incoming messages will be
- * accepted and no data callbacks will be called.
- *
- * @param channel Channel handle, becomes invalid after this call.
- */
-void
-GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel)
-{
-  struct GNUNET_CADET_Handle *h = channel->cadet;
-  struct GNUNET_CADET_LocalChannelDestroyMessage *msg;
-  struct GNUNET_MQ_Envelope *env;
-
-  if (NULL != h->mq)
-  {
-    env = GNUNET_MQ_msg (msg,
-                         GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
-    msg->ccn = channel->ccn;
-    GNUNET_MQ_send (h->mq,
-                    env);
-  }
-  destroy_channel (channel);
-}
-
-
-/**
- * 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;
-
-  switch (option)
-  {
-    case GNUNET_CADET_OPTION_NOBUFFER:
-    case GNUNET_CADET_OPTION_RELIABLE:
-    case GNUNET_CADET_OPTION_OUT_OF_ORDER:
-      if (0 != (option & channel->options))
-        bool_flag = GNUNET_YES;
-      else
-        bool_flag = GNUNET_NO;
-      return (const union GNUNET_CADET_ChannelInfo *) &bool_flag;
-      break;
-    case GNUNET_CADET_OPTION_PEER:
-      return (const union GNUNET_CADET_ChannelInfo *) &channel->peer;
-      break;
-    default:
-      GNUNET_break (0);
-      return NULL;
-  }
-}
-
-
-/**
- * Send an ack on the channel to confirm the processing of a message.
- *
- * @param ch Channel on which to send the ACK.
- */
-void
-GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel)
-{
-  struct GNUNET_CADET_LocalAck *msg;
-  struct GNUNET_MQ_Envelope *env;
-
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending ACK on channel %X\n",
-       ntohl (channel->ccn.channel_of_client));
-  msg->ccn = channel->ccn;
-  GNUNET_MQ_send (channel->cadet->mq,
-                  env);
-}
-
-
-/**
- * Send message of @a type to CADET service of @a h
- *
- * @param h handle to CADET service
- * @param type message type of trivial information request to send
- */
-static void
-send_info_request (struct GNUNET_CADET_Handle *h,
-                   uint16_t type)
-{
-  struct GNUNET_MessageHeader *msg;
-  struct GNUNET_MQ_Envelope *env;
-
-  env = GNUNET_MQ_msg (msg,
-                       type);
-  GNUNET_MQ_send (h->mq,
-                  env);
-}
-
-
-/**
- * Request a debug dump on the service's STDERR.
- *
- * WARNING: unstable API, likely to change in the future!
- *
- * @param h cadet handle
- */
-void
-GNUNET_CADET_request_dump (struct GNUNET_CADET_Handle *h)
-{
-  send_info_request (h,
-                     GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP);
-}
-
-
-/**
- * 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 = 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;
-  struct GNUNET_MQ_Envelope *env;
-
-  if (NULL != h->info_cb.peer_cb)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
-  msg->peer = *id;
-  GNUNET_MQ_send (h->mq,
-                  env);
-  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_cls;
-
-  h->info_cb.tunnels_cb = NULL;
-  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;
-  struct GNUNET_MQ_Envelope *env;
-
-  if (NULL != h->info_cb.tunnel_cb)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
-  msg->peer = *id;
-  GNUNET_MQ_send (h->mq,
-                  env);
-  h->info_cb.tunnel_cb = callback;
-  h->info_cls = callback_cls;
-  return GNUNET_OK;
-}
-
-
-/**
- * Transitional function to convert an unsigned int port to a hash value.
- * WARNING: local static value returned, NOT reentrant!
- * WARNING: do not use this function for new code!
- *
- * @param port Numerical port (unsigned int format).
- *
- * @return A GNUNET_HashCode usable for the new CADET API.
- */
-const struct GNUNET_HashCode *
-GC_u2h (uint32_t port)
-{
-  static struct GNUNET_HashCode hash;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-              "This is a transitional function, use proper crypto hashes as CADET ports\n");
-  GNUNET_CRYPTO_hash (&port,
-                      sizeof (port),
-                      &hash);
-  return &hash;
-}
-
-
-/**
- * Connect to the MQ-based cadet service.
- *
- * @param cfg Configuration to use.
- *
- * @return Handle to the cadet service NULL on error.
- */
-struct GNUNET_CADET_Handle *
-GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-  struct GNUNET_CADET_Handle *h;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "GNUNET_CADET_connecT()\n");
-  h = GNUNET_new (struct GNUNET_CADET_Handle);
-  h->cfg = cfg;
-  h->ports = GNUNET_CONTAINER_multihashmap_create (4,
-                                                   GNUNET_YES);
-  h->channels = GNUNET_CONTAINER_multihashmap32_create (4);
-  reconnect (h);
-  if (NULL == h->mq)
-  {
-    GNUNET_break (0);
-    GNUNET_CADET_disconnect (h);
-    return NULL;
-  }
-  h->next_ccn.channel_of_client = htonl (GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-  h->reconnect_time = GNUNET_TIME_UNIT_MILLISECONDS;
-  h->reconnect_task = NULL;
-
-  return h;
-}
-
-
-/**
- * Open a port to receive incomming MQ-based channels.
- *
- * @param h CADET handle.
- * @param port Hash identifying the port.
- * @param connects Function called when an incoming channel is connected.
- * @param connects_cls Closure for the @a connects handler.
- * @param window_changes Function called when the transmit window size changes.
- * @param disconnects Function called when a channel is disconnected.
- * @param handlers Callbacks for messages we care about, NULL-terminated.
- * @return Port handle.
- */
-struct GNUNET_CADET_Port *
-GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
-                        const struct GNUNET_HashCode *port,
-                        GNUNET_CADET_ConnectEventHandler connects,
-                        void * connects_cls,
-                        GNUNET_CADET_WindowSizeEventHandler window_changes,
-                        GNUNET_CADET_DisconnectEventHandler disconnects,
-                        const struct GNUNET_MQ_MessageHandler *handlers)
-{
-  struct GNUNET_CADET_PortMessage *msg;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_Port *p;
-
-  GNUNET_assert (NULL != connects);
-  GNUNET_assert (NULL != disconnects);
-
-  p = GNUNET_new (struct GNUNET_CADET_Port);
-  p->cadet = h;
-  p->id = *port;
-  p->connects = connects;
-  p->cls = connects_cls;
-  p->window_changes = window_changes;
-  p->disconnects = disconnects;
-  p->handlers = GNUNET_MQ_copy_handlers (handlers);
-
-  GNUNET_assert (GNUNET_OK ==
-                GNUNET_CONTAINER_multihashmap_put (h->ports,
-                                                   &p->id,
-                                                   p,
-                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN);
-  msg->port = p->id;
-  GNUNET_MQ_send (h->mq,
-                  env);
-  return p;
-}
-
-
-/**
- * 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_cls Closure for the channel. It's given to:
- *                    - The disconnect handler @a disconnects
- *                    - Each message type callback in @a handlers
- * @param destination Peer identity the channel should go to.
- * @param port Identification of the destination port.
- * @param options CadetOption flag field, with all desired option bits set to 1.
- * @param window_changes Function called when the transmit window size changes.
- * @param disconnects Function called when the channel is disconnected.
- * @param handlers Callbacks for messages we care about, NULL-terminated.
- * @return Handle to the channel.
- */
-struct GNUNET_CADET_Channel *
-GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h,
-                             void *channel_cls,
-                             const struct GNUNET_PeerIdentity *destination,
-                             const struct GNUNET_HashCode *port,
-                             enum GNUNET_CADET_ChannelOption options,
-                             GNUNET_CADET_WindowSizeEventHandler window_changes,
-                             GNUNET_CADET_DisconnectEventHandler disconnects,
-                             const struct GNUNET_MQ_MessageHandler *handlers)
-{
-  struct GNUNET_CADET_Channel *ch;
-  struct GNUNET_CADET_LocalChannelCreateMessage *msg;
-  struct GNUNET_MQ_Envelope *env;
-
-  GNUNET_assert (NULL != disconnects);
-  ch = create_channel (h,
-                       NULL);
-  ch->ctx = channel_cls;
-  ch->peer = *destination;
-  ch->options = options;
-  ch->window_changes = window_changes;
-  ch->disconnects = disconnects;
-
-  /* Create MQ for channel */
-  ch->mq = GNUNET_MQ_queue_for_callbacks (&cadet_mq_send_impl,
-                                          &cadet_mq_destroy_impl,
-                                          &cadet_mq_cancel_impl,
-                                          ch,
-                                          handlers,
-                                          &cadet_mq_error_handler,
-                                          ch);
-  GNUNET_MQ_set_handlers_closure (ch->mq, channel_cls);
-
-  /* Request channel creation to service */
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
-  msg->ccn = ch->ccn;
-  msg->port = *port;
-  msg->peer = *destination;
-  msg->opt = htonl (options);
-  GNUNET_MQ_send (h->mq,
-                  env);
-  return ch;
-}
-
-
-/**
- * Obtain the message queue for a connected peer.
- *
- * @param channel The channel handle from which to get the MQ.
- *
- * @return NULL if @a channel is not yet connected.
- */
-struct GNUNET_MQ_Handle *
-GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel)
-{
-  return channel->mq;
-}
-
-/* end of cadet_api.c */
diff --git a/src/cadet/cadet_common.c b/src/cadet/cadet_common.c
deleted file mode 100644 (file)
index 95a3144..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2012 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/cadet_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 *
-GC_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 "\???";
-  }
-}
-
-
-/**
- * Test if @a bigger is larger than @a smaller.
- * Considers the case that @a bigger just overflowed
- * and is thus tiny while @a smaller is still below
- * `UINT32_MAX`.
- */
-int
-GC_is_pid_bigger (uint32_t bigger,
-                 uint32_t smaller)
-{
-    return (PID_OVERFLOW (smaller, bigger) ||
-            ( (bigger > smaller) &&
-             (! PID_OVERFLOW (bigger, smaller))) );
-}
-
-
-uint32_t
-GC_max_pid (uint32_t a, uint32_t b)
-{
-  if (GC_is_pid_bigger(a, b))
-    return a;
-  return b;
-}
-
-
-uint32_t
-GC_min_pid (uint32_t a, uint32_t b)
-{
-  if (GC_is_pid_bigger(a, b))
-    return b;
-  return a;
-}
-
-
-/**
- * Allocate a string with a hexdump of any binary data.
- *
- * @param bin Arbitrary binary data.
- * @param len Length of @a bin in bytes.
- * @param output Where to write the output (if *output be NULL it's allocated).
- *
- * @return The size of the output.
- */
-size_t
-GC_bin2s (void *bin, unsigned int len, char **output)
-{
-  char *data = bin;
-  char *buf;
-  unsigned int s_len;
-  unsigned int i;
-
-  s_len = 2 * len + 1;
-  if (NULL == *output)
-    *output = GNUNET_malloc (s_len);
-  buf = *output;
-
-  for (i = 0; i < len; i++)
-  {
-    SPRINTF (&buf[2 * i], "%2X", data[i]);
-  }
-  buf[s_len - 1] = '\0';
-
-  return s_len;
-}
-
-
-#if !defined(GNUNET_CULL_LOGGING)
-const char *
-GC_m2s (uint16_t m)
-{
-  static char buf[2][16];
-  static int idx;
-  const char *s;
-
-  idx = (idx + 1) % 2;
-  switch (m)
-  {
-    /**
-     * Used to mark the "payload" of a non-payload message.
-     */
-    case 0:
-      s = "retransmit";
-      break;
-
-      /**
-       * Request the creation of a path
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
-      s = "CONN_CREAT";
-      break;
-
-      /**
-       * Request the modification of an existing path
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK:
-      s = "CONN_ACK";
-      break;
-
-      /**
-       * Notify that a connection of a path is no longer valid
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
-      s = "CONN_BRKN";
-      break;
-
-      /**
-       * At some point, the route will spontaneously change
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_PATH_CHANGED_UNIMPLEMENTED:
-      s = "PATH_CHNGD";
-      break;
-
-      /**
-       * Transport payload data.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
-      s = "DATA";
-      break;
-
-    /**
-     * Confirm receipt of payload data.
-     */
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
-      s = "DATA_ACK";
-      break;
-
-      /**
-       * Key exchange message.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
-      s = "KX";
-      break;
-
-      /**
-       * Encrypted.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED:
-      s = "ENCRYPTED";
-      break;
-
-      /**
-       * Request the destuction of a path
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
-      s = "CONN_DSTRY";
-      break;
-
-      /**
-       * ACK for a data packet.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK:
-      s = "ACK";
-      break;
-
-      /**
-       * POLL for ACK.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL:
-      s = "POLL";
-      break;
-
-      /**
-       * Announce origin is still alive.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE:
-      s = "KEEPALIVE";
-      break;
-
-      /**
-       * Open port
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN:
-      s = "OPEN_PORT";
-      break;
-
-      /**
-       * Close port
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE:
-      s = "CLOSE_PORT";
-      break;
-
-      /**
-       * Ask the cadet service to create a new tunnel
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
-      s = "CHAN_CREAT";
-      break;
-
-      /**
-       * Ask the cadet service to destroy a tunnel
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
-      s = "CHAN_DSTRY";
-      break;
-
-      /**
-       * Confirm the creation of a channel.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
-      s = "CHAN_ACK";
-      break;
-
-      /**
-       * Confirm the creation of a channel.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
-      s = "CHAN_NACK";
-      break;
-
-      /**
-       * Local payload traffic
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA:
-      s = "LOC_DATA";
-      break;
-
-      /**
-       * Local ACK for data.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK:
-      s = "LOC_ACK";
-      break;
-
-      /**
-       * Local monitoring of channels.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNELS:
-      s = "INFO_CHANS";
-      break;
-
-      /**
-       * Local monitoring of a channel.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CHANNEL:
-      s = "INFO_CHAN";
-      break;
-
-      /**
-       * Local monitoring of service.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS:
-      s = "INFO_TUNS";
-      break;
-
-      /**
-       * Local monitoring of service.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL:
-      s = "INFO_TUN";
-      break;
-
-      /**
-       * Local information about all connections of service.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTIONS:
-      s = "INFO_CONNS";
-      break;
-
-      /**
-       * Local information of service about a specific connection.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_CONNECTION:
-      s = "INFO_CONN";
-      break;
-
-      /**
-       * Local information about all peers known to the service.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS:
-      s = "INFO_PEERS";
-      break;
-
-      /**
-       * Local information of service about a specific peer.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER:
-      s = "INFO_PEER";
-      break;
-
-      /**
-       * Traffic (net-cat style) used by the Command Line Interface.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_CLI:
-      s = "CLI";
-      break;
-
-      /**
-       * Debug request.
-       */
-    case GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP:
-      s = "INFO_DUMP";
-      break;
-
-      /**
-       * Used to mark the "payload" of a non-payload message.
-       */
-    case UINT16_MAX:
-      s = "      N/A";
-      break;
-
-
-    default:
-      SPRINTF (buf[idx], "{UNK: %5u}", m);
-      return buf[idx];
-  }
-  SPRINTF (buf[idx], "{%10s}", s);
-  return buf[idx];
-}
-#else
-const char *
-GC_m2s (uint16_t m)
-{
-  return "";
-}
-#endif
diff --git a/src/cadet/cadet_path.c b/src/cadet/cadet_path.c
deleted file mode 100644 (file)
index 79a4988..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001 - 2013 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/cadet_path.c
- * @brief Path handling functions
- * @author Bartlomiej Polot
- */
-
-#include "cadet.h"
-#include "cadet_path.h"
-#include "gnunet-service-cadet_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-pth",__VA_ARGS__)
-
-
-/**
- * @brief Destroy a path after some time has past.
- * Removes the path from the peer (must not be used for direct paths).
- *
- * @param cls Closure (path to destroy).
- */
-static void
-path_destroy_delayed (void *cls)
-{
-  struct CadetPeerPath *path = cls;
-  struct CadetPeer *peer;
-
-  path->path_delete = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroy delayed %p (%u)\n",
-       path,
-       path->length);
-  GNUNET_assert (2 < path->length);
-  peer = GCP_get_short (path->peers[path->length - 1],
-                       GNUNET_NO);
-  GNUNET_assert (NULL != peer);
-  GCP_remove_path (peer, path);
-}
-
-
-/**
- * Create a new path
- *
- * @param length How many hops will the path have.
- * @return A newly allocated path with a peer array of the specified length.
- */
-struct CadetPeerPath *
-path_new (unsigned int length)
-{
-  struct CadetPeerPath *p;
-
-  p = GNUNET_new (struct CadetPeerPath);
-  if (length > 0)
-  {
-    p->length = length;
-    p->peers = GNUNET_malloc (length * sizeof (GNUNET_PEER_Id));
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "New path %p (%u)\n", p, p->length);
-  return p;
-}
-
-
-/**
- * Invert the path
- *
- * @param path the path to invert
- */
-void
-path_invert (struct CadetPeerPath *path)
-{
-  GNUNET_PEER_Id aux;
-  unsigned int i;
-
-  for (i = 0; i < path->length / 2; i++)
-  {
-    aux = path->peers[i];
-    path->peers[i] = path->peers[path->length - i - 1];
-    path->peers[path->length - i - 1] = aux;
-  }
-}
-
-
-/**
- * Duplicate a path, incrementing short peer's rc.
- *
- * @param path The path to duplicate.
- */
-struct CadetPeerPath *
-path_duplicate (const struct CadetPeerPath *path)
-{
-  struct CadetPeerPath *aux;
-  unsigned int i;
-
-  aux = path_new (path->length);
-  GNUNET_memcpy (aux->peers,
-         path->peers,
-         path->length * sizeof (GNUNET_PEER_Id));
-  for (i = 0; i < aux->length; i++)
-    GNUNET_PEER_change_rc (aux->peers[i], 1);
-  return aux;
-}
-
-
-/**
- * Get the length of a path.
- *
- * @param path The path to measure, with the local peer at any point of it.
- *
- * @return Number of hops to reach destination.
- *         UINT_MAX in case the peer is not in the path.
- */
-unsigned int
-path_get_length (struct CadetPeerPath *path)
-{
-  if (NULL == path)
-    return UINT_MAX;
-  return path->length;
-}
-
-
-
-/**
- * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop.
- *
- * Never invalidates a two-hop (direct) path, only a core handler can do that.
- *
- * Rationale: DHT_get sometimes returns bad cached results, for instance,
- * on a locally cached result where the PUT followed a path that is no longer
- * current. The path must remain "known and marked as invalid" for a while.
- *
- * @param p Path to invalidate.
- */
-void
-path_invalidate (struct CadetPeerPath *p)
-{
-  if (NULL != p->path_delete)
-    return;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Invalidating path %p (%u)\n",
-       p,
-       p->length);
-  p->path_delete
-    = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                   &path_destroy_delayed, p);
-}
-
-
-/**
- * Builds a path from a PeerIdentity array.
- *
- * @param peers PeerIdentity array.
- * @param size Size of the @c peers array.
- * @param myid ID of local peer, to find @c own_pos.
- * @param own_pos Output parameter: own position in the path.
- *
- * @return Fixed and shortened path.
- */
-struct CadetPeerPath *
-path_build_from_peer_ids (struct GNUNET_PeerIdentity *peers,
-                          unsigned int size,
-                          GNUNET_PEER_Id myid,
-                          unsigned int *own_pos)
-{
-  struct CadetPeerPath *path;
-  GNUNET_PEER_Id shortid;
-  unsigned int i;
-  unsigned int j;
-  unsigned int offset;
-
-  /* Create path */
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  Creating path...\n");
-  path = path_new (size);
-  *own_pos = 0;
-  offset = 0;
-  for (i = 0; i < size; i++)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  - %u: taking %s\n",
-         i, GNUNET_i2s (&peers[i]));
-    shortid = GNUNET_PEER_intern (&peers[i]);
-
-    /* Check for loops / duplicates */
-    for (j = 0; j < i - offset; j++)
-    {
-      if (path->peers[j] == shortid)
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "    already exists at pos %u\n", j);
-        offset = i - j;
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "    offset now %u\n", offset);
-        GNUNET_PEER_change_rc (shortid, -1);
-      }
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "    storing at %u\n", i - offset);
-    path->peers[i - offset] = shortid;
-    if (path->peers[i - offset] == myid)
-      *own_pos = i - offset;
-  }
-  path->length -= offset;
-
-  if (path->peers[*own_pos] != myid)
-  {
-    /* create path: self not found in path through self */
-    GNUNET_break_op (0);
-    path_destroy (path);
-    return NULL;
-  }
-
-  return path;
-}
-
-
-/**
- * Test if two paths are equivalent (equal or revese of each other).
- *
- * @param p1 First path
- * @param p2 Second path
- *
- * @return #GNUNET_YES if both paths are equivalent
- *         #GNUNET_NO otherwise
- */
-int
-path_equivalent (const struct CadetPeerPath *p1,
-                 const struct CadetPeerPath *p2)
-{
-  unsigned int i;
-  unsigned int l;
-  unsigned int half;
-
-  if (NULL == p1 || NULL == p2)
-    return GNUNET_NO;
-
-  if (p1->length != p2->length)
-    return GNUNET_NO;
-
-  l = p1->length;
-  if (0 == memcmp (p1->peers, p2->peers, sizeof (p1->peers[0]) * l))
-    return GNUNET_YES;
-
-  half = l / 2;
-  l = l - 1;
-  for (i = 0; i <= half; i++)
-    if (p1->peers[i] != p2->peers[l - i])
-      return GNUNET_NO;
-
-  return GNUNET_YES;
-}
-
-
-/**
- * Test if a path is valid (or at least not known to be invalid).
- *
- * @param path Path to test.
- *
- * @return #GNUNET_YES If the path is valid or unknown,
- *         #GNUNET_NO If the path is known to be invalid.
- */
-int
-path_is_valid (const struct CadetPeerPath *path)
-{
-  return (NULL == path->path_delete);
-}
-
-
-/**
- * Destroy the path and free any allocated resources linked to it
- *
- * @param p the path to destroy
- *
- * @return #GNUNET_OK on success
- */
-int
-path_destroy (struct CadetPeerPath *p)
-{
-  if (NULL == p)
-    return GNUNET_OK;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "destroying path %p (%u)\n",
-       p,
-       p->length);
-  GNUNET_PEER_decrement_rcs (p->peers, p->length);
-  GNUNET_free_non_null (p->peers);
-  if (NULL != p->path_delete)
-    GNUNET_SCHEDULER_cancel (p->path_delete);
-  GNUNET_free (p);
-  return GNUNET_OK;
-}
-
-
-/**
- * Compare two paths.
- *
- * @param p1 First path.
- * @param p2 Second path.
- *
- * @return > 0 if p1 is longer, or the first differing PEER_Id is higher on p1.
- *         < 0 if p2 is longer, or the first differing PEER_Id is higher on p2.
- *         0 if they are identical.
- */
-int
-path_cmp (const struct CadetPeerPath *p1,
-         const struct CadetPeerPath *p2)
-{
-  if (p1->length > p2->length)
-    return 1;
-
-  if (p1->length < p2->length)
-    return -1;
-
-  return memcmp (p1->peers,
-                p2->peers,
-                sizeof (GNUNET_PEER_Id) * p1->length);
-}
-
-
-char *
-path_2s (struct CadetPeerPath *p)
-{
-  char *s;
-  char *old;
-  unsigned int i;
-
-  old = GNUNET_strdup ("");
-  for (i = 0; i < p->length; i++)
-  {
-    GNUNET_asprintf (&s, "%s %s",
-                     old, GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
-    GNUNET_free_non_null (old);
-    old = s;
-  }
-  return old;
-}
-
-
-void
-path_debug (struct CadetPeerPath *p)
-{
-  unsigned int i;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "PATH:\n");
-  for (i = 0; i < p->length; i++)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  %s\n",
-                GNUNET_i2s (GNUNET_PEER_resolve2 (p->peers[i])));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "END\n");
-}
diff --git a/src/cadet/cadet_path.h b/src/cadet/cadet_path.h
deleted file mode 100644 (file)
index bb68eec..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001 - 2013 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/cadet_path.h
- * @brief Path handling functions
- * @author Bartlomiej Polot
- */
-
-#ifndef CADET_PATH_H_
-#define CADET_PATH_H_
-
-#ifdef __cplusplus
-extern "C"
-{
-  #if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-
-/******************************************************************************/
-/************************      DATA STRUCTURES     ****************************/
-/******************************************************************************/
-
-/**
- * Information regarding a possible path to reach a single peer
- */
-struct CadetPeerPath
-{
-
-    /**
-     * Linked list
-     */
-  struct CadetPeerPath *next;
-  struct CadetPeerPath *prev;
-
-    /**
-     * List of all the peers that form the path from origin to target.
-     */
-  GNUNET_PEER_Id *peers;
-
-    /**
-     * Number of peers (hops) in the path
-     */
-  unsigned int length;
-
-    /**
-     * User defined data store.
-     */
-  struct CadetConnection *c;
-
-    /**
-     * Path's score, how reliable is the path.
-     */
-//   int score;
-
-  /**
-   * Task to delete the path.
-   * We tried it, it didn't work, don't try again in a while.
-   */
-  struct GNUNET_SCHEDULER_Task * path_delete;
-
-};
-
-/******************************************************************************/
-/*************************        FUNCTIONS       *****************************/
-/******************************************************************************/
-
-/**
- * Create a new path.
- *
- * @param length How many hops will the path have.
- *
- * @return A newly allocated path with a peer array of the specified length.
- */
-struct CadetPeerPath *
-path_new (unsigned int length);
-
-
-/**
- * Invert the path.
- *
- * @param path The path to invert.
- */
-void
-path_invert (struct CadetPeerPath *path);
-
-
-/**
- * Duplicate a path, incrementing short peer's rc.
- *
- * @param path The path to duplicate.
- */
-struct CadetPeerPath *
-path_duplicate (const struct CadetPeerPath *path);
-
-
-/**
- * Get the length of a path.
- *
- * @param path The path to measure, with the local peer at any point of it.
- *
- * @return Number of hops to reach destination.
- *         UINT_MAX in case the peer is not in the path.
- */
-unsigned int
-path_get_length (struct CadetPeerPath *path);
-
-/**
- * Mark path as invalid: keep it aroud for a while to avoid trying it in a loop.
- *
- * DHT_get sometimes returns bad cached results, for instance, on a locally
- * cached result where the PUT followed a path that is no longer current.
- *
- * @param p Path to invalidate.
- */
-void
-path_invalidate (struct CadetPeerPath *p);
-
-/**
- * Test if two paths are equivalent (equal or revese of each other).
- *
- * @param p1 First path
- * @param p2 Second path
- *
- * @return GNUNET_YES if both paths are equivalent
- *         GNUNET_NO otherwise
- */
-int
-path_equivalent (const struct CadetPeerPath *p1,
-                 const struct CadetPeerPath *p2);
-
-/**
- * Test if a path is valid (or at least not known to be invalid).
- *
- * @param path Path to test.
- *
- * @return #GNUNET_YES If the path is valid or unknown,
- *         #GNUNET_NO If the path is known to be invalid.
- */
-int
-path_is_valid (const struct CadetPeerPath *path);
-
-/**
- * Destroy the path and free any allocated resources linked to it
- *
- * @param p the path to destroy
- *
- * @return GNUNET_OK on success
- */
-int
-path_destroy (struct CadetPeerPath *p);
-
-/**
- * Compare two paths.
- *
- * @param p1 First path.
- * @param p2 Second path.
- *
- * @return > 0 if p1 is longer, or the first differing PEER_Id is higher on p1.
- *         < 0 if p2 is longer, or the first differing PEER_Id is higher on p2.
- *         0 if they are identical.
- */
-int
-path_cmp (const struct CadetPeerPath *p1, const struct CadetPeerPath *p2);
-
-/**
- * Builds a path from a PeerIdentity array.
- *
- * @param peers PeerIdentity array.
- * @param size Size of the @c peers array.
- * @param myid ID of local peer, to find @c own_pos.
- * @param own_pos Output parameter: own position in the path.
- *
- * @return Fixed and shortened path.
- */
-struct CadetPeerPath *
-path_build_from_peer_ids (struct GNUNET_PeerIdentity *peers,
-                          unsigned int size,
-                          GNUNET_PEER_Id myid,
-                          unsigned int *own_pos);
-
-/**
- * Path -> allocated one line string. Caller must free.
- *
- * @param p Path.
- */
-char *
-path_2s (struct CadetPeerPath *p);
-
-/**
- * Print info about the path for debug.
- *
- * @param p Path to debug.
- */
-void
-path_debug (struct CadetPeerPath *p);
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-  #endif
-  #ifdef __cplusplus
-}
-#endif
-
-
-/* ifndef CADET_PATH_H */
-#endif
index d2426addbd67cad26531acdea192034093c3f244..560c186cd5a555fed27b2c4e61025704069dac91 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2001 - 2011 GNUnet e.V.
+     Copyright (C) 2007 - 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 */
 
 /**
- * @author Bartlomiej Polot
  * @file cadet/cadet_protocol.h
+ * @brief P2P messages used by CADET
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
  */
 
 #ifndef CADET_PROTOCOL_H_
@@ -298,17 +300,10 @@ struct GNUNET_CADET_TunnelEncryptedMessage
    */
   struct GNUNET_MessageHeader header;
 
-#if NEW_CADET
   /**
    * Reserved, for alignment.
    */
   uint32_t reserved GNUNET_PACKED;
-#else
-  /**
-   * Maximum packet ID authorized.
-   */
-  struct CadetEncryptedMessageIdentifier cemi;
-#endif
 
   /**
    * ID of the connection.
@@ -322,89 +317,18 @@ struct GNUNET_CADET_TunnelEncryptedMessage
    */
   struct GNUNET_ShortHashCode hmac;
 
-  #if NEW_CADET
   /**
    * Axolotl-header that specifies which keys to use in which ratchet
    * to decrypt the body that follows.
    */
   struct GNUNET_CADET_AxHeader ax_header;
-#else
-  /**
-   * Number of messages sent with the current ratchet key.
-   */
-  uint32_t Ns GNUNET_PACKED;
-
-  /**
-   * Number of messages sent with the previous ratchet key.
-   */
-  uint32_t PNs GNUNET_PACKED;
 
-  /**
-   * Current ratchet key.
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey DHRs;
-#endif
   /**
    * Encrypted content follows.
    */
 };
 
 
-#ifndef NEW_CADET
-
-/**
- * Message to query a peer about its Flow Control status regarding a tunnel.
- *
- * It is NOT yet clear if we need this.
- */
-struct GNUNET_CADET_ConnectionHopByHopPollMessage
-{
-  /**
-   * Type: #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * Last packet sent.
-   */
-  struct CadetEncryptedMessageIdentifier cemi;
-
-  /**
-   * ID of the connection.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
-};
-
-
-/**
- * Message to acknowledge cadet encrypted traffic, used for
- * flow-control on a hop-by-hop basis on the connection-level. Note
- * that we do use the @e cemi from the tunnel layer as the connection
- * layer's header is included/shared with the tunnel layer messages,
- * and we only do flow control for the payload.
- */
-struct GNUNET_CADET_ConnectionEncryptedAckMessage
-{
-  /**
-   * Type: #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * Maximum packet ID authorized.
-   */
-  struct CadetEncryptedMessageIdentifier cemi_max;
-
-  /**
-   * ID of the connection.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-};
-
-#endif
-
-
 /******************************************************************************/
 /*******************************   CHANNEL  ***********************************/
 /******************************************************************************/
@@ -450,82 +374,18 @@ struct GNUNET_CADET_ChannelManageMessage
    */
   struct GNUNET_MessageHeader header;
 
-#ifdef NEW_CADET
   /**
    * For alignment.
    */
   uint32_t reserved GNUNET_PACKED;
-#endif
-
-  /**
-   * ID of the channel
-   */
-  struct GNUNET_CADET_ChannelTunnelNumber ctn;
-};
-
-
-#ifndef NEW_CADET
-
-/**
- * Message for cadet data traffic.
- */
-struct GNUNET_CADET_ChannelAppDataMessage
-{
-  /**
-   * Type: #GNUNET_MESSAGE_TYPE_CADET_UNICAST,
-   *       #GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * Unique ID of the payload message
-   */
-  /* NEW: struct ChannelMessageIdentifier */
-  uint32_t mid GNUNET_PACKED;
 
   /**
    * ID of the channel
    */
   struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
-  /**
-   * Payload follows
-   */
 };
 
 
-/**
- * Message to acknowledge end-to-end data.
- */
-struct GNUNET_CADET_ChannelDataAckMessage
-{
-  /**
-   * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK
-   */
-  struct GNUNET_MessageHeader header;
-
-  /**
-   * ID of the channel
-   */
-  struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
-  /**
-   * Bitfield of already-received messages past @e mid.
-   * pid +  1 @ LSB
-   * pid + 64 @ MSB
-   */
-  uint64_t futures GNUNET_PACKED;
-
-  /**
-   * Last message ID received.
-   */
-  /* NEW: struct ChannelMessageIdentifier */
-  uint32_t mid GNUNET_PACKED;
-};
-
-#else
-
-
 /**
  * Number used to uniquely identify messages in a CADET Channel.
  */
@@ -595,8 +455,6 @@ struct GNUNET_CADET_ChannelDataAckMessage
 };
 
 
-#endif
-
 GNUNET_NETWORK_STRUCT_END
 
 #if 0                           /* keep Emacsens' auto-indent happy */
index 9a70dad4937b9eef60d488940985aa3c783c3be9..1df6bff0dfdee7655318d3ed36e68c6a6f203653 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2012 GNUnet e.V.
+     Copyright (C) 2012, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -27,6 +27,7 @@
 #include "cadet_test_lib.h"
 #include "gnunet_cadet_service.h"
 
+
 /**
  * Test context for a CADET Test.
  */
@@ -40,13 +41,18 @@ struct GNUNET_CADET_TEST_Context
   /**
    * Array of handles to the CADET for each peer.
    */
-  struct GNUNET_CADET_Handle **cadetes;
+  struct GNUNET_CADET_Handle **cadets;
 
   /**
    * Operation associated with the connection to the CADET.
    */
   struct GNUNET_TESTBED_Operation **ops;
 
+  /**
+   * Number of peers running, size of the arrays above.
+   */
+  unsigned int num_peers;
+
   /**
    * Main function of the test to run once all CADETs are available.
    */
@@ -58,30 +64,35 @@ struct GNUNET_CADET_TEST_Context
   void *app_main_cls;
 
   /**
-   * Number of peers running, size of the arrays above.
+   * Handler for incoming tunnels.
    */
-  unsigned int num_peers;
+  GNUNET_CADET_ConnectEventHandler connects;
 
   /**
-   * Handler for incoming tunnels.
+   * Function called when the transmit window size changes.
    */
-  GNUNET_CADET_InboundChannelNotificationHandler *new_channel;
+  GNUNET_CADET_WindowSizeEventHandler window_changes;
 
   /**
    * Cleaner for destroyed incoming tunnels.
    */
-  GNUNET_CADET_ChannelEndHandler *cleaner;
+  GNUNET_CADET_DisconnectEventHandler disconnects;
 
   /**
    * Message handlers.
    */
-  struct GNUNET_CADET_MessageHandler* handlers;
+  struct GNUNET_MQ_MessageHandler *handlers;
 
   /**
    * Application ports.
    */
   const struct GNUNET_HashCode **ports;
 
+  /**
+   * Number of ports in #ports.
+   */
+  unsigned int port_count;
+
 };
 
 
@@ -94,6 +105,11 @@ struct GNUNET_CADET_TEST_AdapterContext
    * Peer number for the particular peer.
    */
   unsigned int peer;
+
+  /**
+   * Port handlers for open ports.
+   */
+  struct GNUNET_CADET_Port **ports;
  
   /**
    * General context.
@@ -114,26 +130,28 @@ struct GNUNET_CADET_TEST_AdapterContext
  */
 static void *
 cadet_connect_adapter (void *cls,
-                      const struct GNUNET_CONFIGURATION_Handle *cfg)
+                       const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
   struct GNUNET_CADET_TEST_Context *ctx = actx->ctx;
   struct GNUNET_CADET_Handle *h;
+  unsigned int i;
 
-  h = GNUNET_CADET_connect (cfg,
-                           (void *) (long) actx->peer,
-                           ctx->cleaner,
-                           ctx->handlers);
+  h = GNUNET_CADET_connect (cfg);
   if (NULL == ctx->ports)
     return h;
 
-  for (int i = 0; NULL != ctx->ports[i]; i++)
+  actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *);
+  for (i = 0; i < ctx->port_count; i++)
   {
-    (void ) GNUNET_CADET_open_port (h, ctx->ports[i],
-                                    ctx->new_channel,
-                                    (void *) (long) actx->peer);
+    actx->ports[i] = GNUNET_CADET_open_port (h,
+                                             ctx->ports[i],
+                                             ctx->connects,
+                                             (void *) (long) actx->peer,
+                                             ctx->window_changes,
+                                             ctx->disconnects,
+                                             ctx->handlers);
   }
-
   return h;
 }
 
@@ -152,6 +170,15 @@ cadet_disconnect_adapter (void *cls,
   struct GNUNET_CADET_Handle *cadet = op_result;
   struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
 
+  if (NULL != actx->ports)
+  {
+    for (int i = 0; i < actx->ctx->port_count; i++)
+    {
+      GNUNET_CADET_close_port (actx->ports[i]);
+      actx->ports[i] = NULL;
+    }
+    GNUNET_free (actx->ports);
+  }
   GNUNET_free (actx);
   GNUNET_CADET_disconnect (cadet);
 }
@@ -186,18 +213,18 @@ cadet_connect_cb (void *cls,
   for (i = 0; i < ctx->num_peers; i++)
     if (op == ctx->ops[i])
     {
-      ctx->cadetes[i] = ca_result;
+      ctx->cadets[i] = ca_result;
       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i);
     }
   for (i = 0; i < ctx->num_peers; i++)
-    if (NULL == ctx->cadetes[i])
+    if (NULL == ctx->cadets[i])
       return; /* still some CADET connections missing */
   /* all CADET connections ready! */
   ctx->app_main (ctx->app_main_cls,
                  ctx,
                  ctx->num_peers,
                  ctx->peers,
-                 ctx->cadetes);
+                 ctx->cadets);
 }
 
 
@@ -213,7 +240,7 @@ GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
     ctx->ops[i] = NULL;
   }
   GNUNET_free (ctx->ops);
-  GNUNET_free (ctx->cadetes);
+  GNUNET_free (ctx->cadets);
   GNUNET_free (ctx);
   GNUNET_SCHEDULER_shutdown ();
 }
@@ -243,12 +270,23 @@ cadet_test_run (void *cls,
   struct GNUNET_CADET_TEST_Context *ctx = cls;
   unsigned int i;
 
+  if (0 != links_failed)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n",
+                links_failed);
+    exit (2);
+  }
+
   if  (num_peers != ctx->num_peers)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n",
                 num_peers, ctx->num_peers);
     exit (1);
   }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Testbed up, %u peers and %u links\n",
+              num_peers, links_succeeded);
   ctx->peers = peers;
   for (i = 0; i < num_peers; i++)
   {
@@ -270,31 +308,52 @@ cadet_test_run (void *cls,
 }
 
 
+/**
+ * Run a test using the given name, configuration file and number of peers.
+ * All cadet callbacks will receive the peer number (long) as the closure.
+ *
+ * @param testname Name of the test (for logging).
+ * @param cfgfile Name of the configuration file.
+ * @param num_peers Number of peers to start.
+ * @param tmain Main function to run once the testbed is ready.
+ * @param tmain_cls Closure for @a tmain.
+ * @param connects Handler for incoming channels.
+ * @param window_changes Handler for the window size change notification.
+ * @param disconnects Cleaner for destroyed incoming channels.
+ * @param handlers Message handlers.
+ * @param ports Ports the peers offer, NULL-terminated.
+ */
 void
-GNUNET_CADET_TEST_run (const char *testname,
-                      const char *cfgname,
-                      unsigned int num_peers,
-                      GNUNET_CADET_TEST_AppMain tmain,
-                      void *tmain_cls,
-                      GNUNET_CADET_InboundChannelNotificationHandler new_channel,
-                      GNUNET_CADET_ChannelEndHandler cleaner,
-                      struct GNUNET_CADET_MessageHandler* handlers,
-                      const struct GNUNET_HashCode **ports)
+GNUNET_CADET_TEST_ruN (const char *testname,
+                       const char *cfgfile,
+                       unsigned int num_peers,
+                       GNUNET_CADET_TEST_AppMain tmain,
+                       void *tmain_cls,
+                       GNUNET_CADET_ConnectEventHandler connects,
+                       GNUNET_CADET_WindowSizeEventHandler window_changes,
+                       GNUNET_CADET_DisconnectEventHandler disconnects,
+                       struct GNUNET_MQ_MessageHandler *handlers,
+                       const struct GNUNET_HashCode **ports)
 {
   struct GNUNET_CADET_TEST_Context *ctx;
 
   ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
   ctx->num_peers = num_peers;
-  ctx->ops = GNUNET_malloc (num_peers * sizeof (struct GNUNET_TESTBED_Operation *));
-  ctx->cadetes = GNUNET_malloc (num_peers * sizeof (struct GNUNET_CADET_Handle *));
+  ctx->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *);
+  ctx->cadets = GNUNET_new_array (num_peers, struct GNUNET_CADET_Handle *);
   ctx->app_main = tmain;
   ctx->app_main_cls = tmain_cls;
-  ctx->new_channel = new_channel;
-  ctx->cleaner = cleaner;
-  ctx->handlers = handlers;
+  ctx->connects = connects;
+  ctx->window_changes = window_changes;
+  ctx->disconnects = disconnects;
+  ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
   ctx->ports = ports;
+  ctx->port_count = 0;
+  while (NULL != ctx->ports[ctx->port_count])
+    ctx->port_count++;
+
   GNUNET_TESTBED_test_run (testname,
-                           cfgname,
+                           cfgfile,
                            num_peers,
                            0LL, NULL, NULL,
                            &cadet_test_run, ctx);
index 464977d42d1245ad6308bf528500a8fb952dc7d5..4b3a6b18ddab98b960a4c4eaaf67b727df6bf41b 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2012 GNUnet e.V.
+     Copyright (C) 2012,2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -49,41 +49,41 @@ struct GNUNET_CADET_TEST_Context;
  * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
  * @param num_peers Number of peers that are running.
  * @param peers Array of peers.
- * @param cadetes Handle to each of the CADETs of the peers.
+ * @param cadets Handle to each of the CADETs of the peers.
  */
 typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls,
                                           struct GNUNET_CADET_TEST_Context *ctx,
                                           unsigned int num_peers,
                                           struct GNUNET_TESTBED_Peer **peers,
-                                          struct GNUNET_CADET_Handle **cadetes);
+                                          struct GNUNET_CADET_Handle **cadets);
 
 
 /**
- * Run a test using the given name, configuration file and number of
- * peers.
- * All cadet callbacks will receive the peer number as the closure.
+ * Run a test using the given name, configuration file and number of peers.
+ * All cadet callbacks will receive the peer number (long) as the closure.
  *
  * @param testname Name of the test (for logging).
- * @param cfgname Name of the configuration file.
+ * @param cfgfile Name of the configuration file.
  * @param num_peers Number of peers to start.
  * @param tmain Main function to run once the testbed is ready.
- * @param tmain_cls Closure for 'tmain'.
- * @param new_channel Handler for incoming tunnels.
- * @param cleaner Cleaner for destroyed incoming tunnels.
+ * @param tmain_cls Closure for @a tmain.
+ * @param connects Handler for incoming channels.
+ * @param window_changes Handler for the window size change notification.
+ * @param disconnects Cleaner for destroyed incoming channels.
  * @param handlers Message handlers.
  * @param ports Ports the peers offer, NULL-terminated.
  */
 void
-GNUNET_CADET_TEST_run (const char *testname,
-                      const char *cfgname,
-                      unsigned int num_peers,
-                      GNUNET_CADET_TEST_AppMain tmain,
-                      void *tmain_cls,
-                      GNUNET_CADET_InboundChannelNotificationHandler new_channel,
-                      GNUNET_CADET_ChannelEndHandler cleaner,
-                      struct GNUNET_CADET_MessageHandler* handlers,
-                      const struct GNUNET_HashCode **ports);
-
+GNUNET_CADET_TEST_ruN (const char *testname,
+                       const char *cfgfile,
+                       unsigned int num_peers,
+                       GNUNET_CADET_TEST_AppMain tmain,
+                       void *tmain_cls,
+                       GNUNET_CADET_ConnectEventHandler connects,
+                       GNUNET_CADET_WindowSizeEventHandler window_changes,
+                       GNUNET_CADET_DisconnectEventHandler disconnects,
+                       struct GNUNET_MQ_MessageHandler *handlers,
+                       const struct GNUNET_HashCode **ports);
 
 /**
  * Clean up the testbed.
diff --git a/src/cadet/cadet_test_lib_new.c b/src/cadet/cadet_test_lib_new.c
deleted file mode 100644 (file)
index c3a1540..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2012, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/cadet_test_lib.c
- * @author Bartlomiej Polot
- * @brief library for writing CADET tests
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet_test_lib_new.h"
-#include "gnunet_cadet_service.h"
-
-
-/**
- * Test context for a CADET Test.
- */
-struct GNUNET_CADET_TEST_Context
-{
-  /**
-   * Array of running peers.
-   */
-  struct GNUNET_TESTBED_Peer **peers;
-
-  /**
-   * Array of handles to the CADET for each peer.
-   */
-  struct GNUNET_CADET_Handle **cadets;
-
-  /**
-   * Operation associated with the connection to the CADET.
-   */
-  struct GNUNET_TESTBED_Operation **ops;
-
-  /**
-   * Number of peers running, size of the arrays above.
-   */
-  unsigned int num_peers;
-
-  /**
-   * Main function of the test to run once all CADETs are available.
-   */
-  GNUNET_CADET_TEST_AppMain app_main;
-
-  /**
-   * Closure for 'app_main'.
-   */
-  void *app_main_cls;
-
-  /**
-   * Handler for incoming tunnels.
-   */
-  GNUNET_CADET_ConnectEventHandler connects;
-
-  /**
-   * Function called when the transmit window size changes.
-   */
-  GNUNET_CADET_WindowSizeEventHandler window_changes;
-
-  /**
-   * Cleaner for destroyed incoming tunnels.
-   */
-  GNUNET_CADET_DisconnectEventHandler disconnects;
-
-  /**
-   * Message handlers.
-   */
-  struct GNUNET_MQ_MessageHandler *handlers;
-
-  /**
-   * Application ports.
-   */
-  const struct GNUNET_HashCode **ports;
-
-  /**
-   * Number of ports in #ports.
-   */
-  unsigned int port_count;
-
-};
-
-
-/**
- * Context for a cadet adapter callback.
- */
-struct GNUNET_CADET_TEST_AdapterContext
-{
-  /**
-   * Peer number for the particular peer.
-   */
-  unsigned int peer;
-
-  /**
-   * Port handlers for open ports.
-   */
-  struct GNUNET_CADET_Port **ports;
-  /**
-   * General context.
-   */
-  struct GNUNET_CADET_TEST_Context *ctx;
-};
-
-
-/**
- * Adapter function called to establish a connection to
- * the CADET service.
- *
- * @param cls closure
- * @param cfg configuration of the peer to connect to; will be available until
- *          GNUNET_TESTBED_operation_done() is called on the operation returned
- *          from GNUNET_TESTBED_service_connect()
- * @return service handle to return in 'op_result', NULL on error
- */
-static void *
-cadet_connect_adapter (void *cls,
-                       const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
-  struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
-  struct GNUNET_CADET_TEST_Context *ctx = actx->ctx;
-  struct GNUNET_CADET_Handle *h;
-  unsigned int i;
-
-  h = GNUNET_CADET_connecT (cfg);
-  if (NULL == ctx->ports)
-    return h;
-
-  actx->ports = GNUNET_new_array (ctx->port_count, struct GNUNET_CADET_Port *);
-  for (i = 0; i < ctx->port_count; i++)
-  {
-    actx->ports[i] = GNUNET_CADET_open_porT (h,
-                                             ctx->ports[i],
-                                             ctx->connects,
-                                             (void *) (long) actx->peer,
-                                             ctx->window_changes,
-                                             ctx->disconnects,
-                                             ctx->handlers);
-  }
-  return h;
-}
-
-
-/**
- * Adapter function called to destroy a connection to
- * the CADET service.
- *
- * @param cls closure
- * @param op_result service handle returned from the connect adapter
- */
-static void
-cadet_disconnect_adapter (void *cls,
-                         void *op_result)
-{
-  struct GNUNET_CADET_Handle *cadet = op_result;
-  struct GNUNET_CADET_TEST_AdapterContext *actx = cls;
-
-  if (NULL != actx->ports)
-  {
-    for (int i = 0; i < actx->ctx->port_count; i++)
-    {
-      GNUNET_CADET_close_port (actx->ports[i]);
-      actx->ports[i] = NULL;
-    }
-    GNUNET_free (actx->ports);
-  }
-  GNUNET_free (actx);
-  GNUNET_CADET_disconnect (cadet);
-}
-
-
-/**
- * Callback to be called when a service connect operation is completed.
- *
- * @param cls The callback closure from functions generating an operation.
- * @param op The operation that has been finished.
- * @param ca_result The service handle returned from
- *                  GNUNET_TESTBED_ConnectAdapter() (cadet handle).
- * @param emsg Error message in case the operation has failed.
- *             NULL if operation has executed successfully.
- */
-static void
-cadet_connect_cb (void *cls,
-                 struct GNUNET_TESTBED_Operation *op,
-                 void *ca_result,
-                 const char *emsg)
-{
-  struct GNUNET_CADET_TEST_Context *ctx = cls;
-  unsigned int i;
-
-  if (NULL != emsg)
-  {
-    fprintf (stderr, "Failed to connect to CADET service: %s\n",
-             emsg);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  for (i = 0; i < ctx->num_peers; i++)
-    if (op == ctx->ops[i])
-    {
-      ctx->cadets[i] = ca_result;
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, "...cadet %u connected\n", i);
-    }
-  for (i = 0; i < ctx->num_peers; i++)
-    if (NULL == ctx->cadets[i])
-      return; /* still some CADET connections missing */
-  /* all CADET connections ready! */
-  ctx->app_main (ctx->app_main_cls,
-                 ctx,
-                 ctx->num_peers,
-                 ctx->peers,
-                 ctx->cadets);
-}
-
-
-void
-GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx)
-{
-  unsigned int i;
-
-  for (i = 0; i < ctx->num_peers; i++)
-  {
-    GNUNET_assert (NULL != ctx->ops[i]);
-    GNUNET_TESTBED_operation_done (ctx->ops[i]);
-    ctx->ops[i] = NULL;
-  }
-  GNUNET_free (ctx->ops);
-  GNUNET_free (ctx->cadets);
-  GNUNET_free (ctx);
-  GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Callback run when the testbed is ready (peers running and connected to
- * each other)
- *
- * @param cls Closure (context).
- * @param h the run handle
- * @param num_peers Number of peers that are running.
- * @param peers Handles to each one of the @c num_peers peers.
- * @param links_succeeded the number of overlay link connection attempts that
- *          succeeded
- * @param links_failed the number of overlay link connection attempts that
- *          failed
- */
-static void
-cadet_test_run (void *cls,
-               struct GNUNET_TESTBED_RunHandle *h,
-               unsigned int num_peers,
-               struct GNUNET_TESTBED_Peer **peers,
-               unsigned int links_succeeded,
-               unsigned int links_failed)
-{
-  struct GNUNET_CADET_TEST_Context *ctx = cls;
-  unsigned int i;
-
-  if (0 != links_failed)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Some links failed (%u), ending\n",
-                links_failed);
-    exit (2);
-  }
-
-  if  (num_peers != ctx->num_peers)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers started %u/%u, ending\n",
-                num_peers, ctx->num_peers);
-    exit (1);
-  }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Testbed up, %u peers and %u links\n",
-              num_peers, links_succeeded);
-  ctx->peers = peers;
-  for (i = 0; i < num_peers; i++)
-  {
-    struct GNUNET_CADET_TEST_AdapterContext *newctx;
-    newctx = GNUNET_new (struct GNUNET_CADET_TEST_AdapterContext);
-    newctx->peer = i;
-    newctx->ctx = ctx;
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to cadet %u\n", i);
-    ctx->ops[i] = GNUNET_TESTBED_service_connect (ctx,
-                                                  peers[i],
-                                                  "cadet",
-                                                  &cadet_connect_cb,
-                                                  ctx,
-                                                  &cadet_connect_adapter,
-                                                  &cadet_disconnect_adapter,
-                                                  newctx);
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "op handle %p\n", ctx->ops[i]);
-  }
-}
-
-
-/**
- * Run a test using the given name, configuration file and number of peers.
- * All cadet callbacks will receive the peer number (long) as the closure.
- *
- * @param testname Name of the test (for logging).
- * @param cfgfile Name of the configuration file.
- * @param num_peers Number of peers to start.
- * @param tmain Main function to run once the testbed is ready.
- * @param tmain_cls Closure for @a tmain.
- * @param connects Handler for incoming channels.
- * @param window_changes Handler for the window size change notification.
- * @param disconnects Cleaner for destroyed incoming channels.
- * @param handlers Message handlers.
- * @param ports Ports the peers offer, NULL-terminated.
- */
-void
-GNUNET_CADET_TEST_ruN (const char *testname,
-                       const char *cfgfile,
-                       unsigned int num_peers,
-                       GNUNET_CADET_TEST_AppMain tmain,
-                       void *tmain_cls,
-                       GNUNET_CADET_ConnectEventHandler connects,
-                       GNUNET_CADET_WindowSizeEventHandler window_changes,
-                       GNUNET_CADET_DisconnectEventHandler disconnects,
-                       struct GNUNET_MQ_MessageHandler *handlers,
-                       const struct GNUNET_HashCode **ports)
-{
-  struct GNUNET_CADET_TEST_Context *ctx;
-
-  ctx = GNUNET_new (struct GNUNET_CADET_TEST_Context);
-  ctx->num_peers = num_peers;
-  ctx->ops = GNUNET_new_array (num_peers, struct GNUNET_TESTBED_Operation *);
-  ctx->cadets = GNUNET_new_array (num_peers, struct GNUNET_CADET_Handle *);
-  ctx->app_main = tmain;
-  ctx->app_main_cls = tmain_cls;
-  ctx->connects = connects;
-  ctx->window_changes = window_changes;
-  ctx->disconnects = disconnects;
-  ctx->handlers = GNUNET_MQ_copy_handlers (handlers);
-  ctx->ports = ports;
-  ctx->port_count = 0;
-  while (NULL != ctx->ports[ctx->port_count])
-    ctx->port_count++;
-
-  GNUNET_TESTBED_test_run (testname,
-                           cfgfile,
-                           num_peers,
-                           0LL, NULL, NULL,
-                           &cadet_test_run, ctx);
-}
-
-/* end of cadet_test_lib.c */
diff --git a/src/cadet/cadet_test_lib_new.h b/src/cadet/cadet_test_lib_new.h
deleted file mode 100644 (file)
index 4b3a6b1..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2012,2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/cadet_test_lib.h
- * @author Bartlomiej Polot
- * @brief library for writing CADET tests
- */
-#ifndef CADET_TEST_LIB_H
-#define CADET_TEST_LIB_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "gnunet_testbed_service.h"
-#include "gnunet_cadet_service.h"
-
-/**
- * Test context for a CADET Test.
- */
-struct GNUNET_CADET_TEST_Context;
-
-
-/**
- * Main function of a CADET test.
- *
- * @param cls Closure.
- * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
- * @param num_peers Number of peers that are running.
- * @param peers Array of peers.
- * @param cadets Handle to each of the CADETs of the peers.
- */
-typedef void (*GNUNET_CADET_TEST_AppMain) (void *cls,
-                                          struct GNUNET_CADET_TEST_Context *ctx,
-                                          unsigned int num_peers,
-                                          struct GNUNET_TESTBED_Peer **peers,
-                                          struct GNUNET_CADET_Handle **cadets);
-
-
-/**
- * Run a test using the given name, configuration file and number of peers.
- * All cadet callbacks will receive the peer number (long) as the closure.
- *
- * @param testname Name of the test (for logging).
- * @param cfgfile Name of the configuration file.
- * @param num_peers Number of peers to start.
- * @param tmain Main function to run once the testbed is ready.
- * @param tmain_cls Closure for @a tmain.
- * @param connects Handler for incoming channels.
- * @param window_changes Handler for the window size change notification.
- * @param disconnects Cleaner for destroyed incoming channels.
- * @param handlers Message handlers.
- * @param ports Ports the peers offer, NULL-terminated.
- */
-void
-GNUNET_CADET_TEST_ruN (const char *testname,
-                       const char *cfgfile,
-                       unsigned int num_peers,
-                       GNUNET_CADET_TEST_AppMain tmain,
-                       void *tmain_cls,
-                       GNUNET_CADET_ConnectEventHandler connects,
-                       GNUNET_CADET_WindowSizeEventHandler window_changes,
-                       GNUNET_CADET_DisconnectEventHandler disconnects,
-                       struct GNUNET_MQ_MessageHandler *handlers,
-                       const struct GNUNET_HashCode **ports);
-
-/**
- * Clean up the testbed.
- *
- * @param ctx handle for the testbed
- */
-void
-GNUNET_CADET_TEST_cleanup (struct GNUNET_CADET_TEST_Context *ctx);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-
-/* ifndef CADET_TEST_LIB_H */
-#endif
index c194a5bc1c33c690b418cd36fcf20d6b9dec94cc..57eeac7355094581082dcc81c1a46a1c4c0e5b78 100644 (file)
@@ -772,15 +772,15 @@ run (void *cls,
        && target_id != NULL)
   {
     FPRINTF (stderr,
-             _("You must NOT give a TARGET "
-               "when using 'request all' options\n"));
+             _("Extra arguments are not applicable "
+               "in combination with this option.\n"));
     return;
   }
 
   if (GNUNET_YES == dump)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "requesting debug dump\n");
+                "Requesting debug dump\n");
     job = GNUNET_SCHEDULER_add_now (&request_dump,
                                     NULL);
   }
@@ -829,7 +829,7 @@ run (void *cls,
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Connecting to CADET service\n");
-  mh = GNUNET_CADET_connecT (cfg);
+  mh = GNUNET_CADET_connect (cfg);
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
                                  NULL);
   if (NULL == mh)
@@ -844,7 +844,7 @@ run (void *cls,
     GNUNET_CRYPTO_hash (listen_port,
                         strlen (listen_port),
                         &porthash);
-    lp = GNUNET_CADET_open_porT (mh,
+    lp = GNUNET_CADET_open_port (mh,
                                  &porthash,
                                  &channel_incoming,
                                  NULL,
@@ -876,7 +876,7 @@ run (void *cls,
     GNUNET_CRYPTO_hash (target_port,
                         strlen(target_port),
                         &porthash);
-    ch = GNUNET_CADET_channel_creatE (mh,
+    ch = GNUNET_CADET_channel_create (mh,
                                       NULL,
                                       &pid,
                                       &porthash,
@@ -919,32 +919,55 @@ 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[] = {
-    {'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},
-    {'d', "dump", NULL,
-     gettext_noop ("dump debug information to STDERR"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &dump},
-    {'o', "open-port", "PORT",
-     gettext_noop ("port to listen to"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &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},
+  const char helpstr[] = "Create tunnels and retrieve info about CADET's status.";
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    /* I would use the terminology 'circuit' here...  --lynX */
+    GNUNET_GETOPT_OPTION_STRING ('C',
+                                 "connection",
+                                 "CONNECTION_ID",
+                                 gettext_noop ("Provide information about a particular connection"),
+                                 &conn_id),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('e',
+                                  "echo",
+                                  gettext_noop ("Activate echo mode"),
+                                  &echo), 
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                  "dump",
+                                  gettext_noop ("Dump debug information to STDERR"),
+                                  &dump),
+
+    GNUNET_GETOPT_OPTION_STRING ('o',
+                                 "open-port",
+                                 "SHARED_SECRET",
+                                 gettext_noop ("Listen for connections using a shared secret among sender and recipient"),
+                                 &listen_port),
+
+
+    GNUNET_GETOPT_OPTION_STRING ('p',
+                                 "peer",
+                                 "PEER_ID",
+                                 gettext_noop ("Provide information about a patricular peer"),
+                                 &peer_id),
+
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('P',
+                                  "peers",
+                                  gettext_noop ("Provide information about all peers"),
+                                  &request_peers),
+
+    GNUNET_GETOPT_OPTION_STRING ('t',
+                                 "tunnel",
+                                 "TUNNEL_ID",
+                                 gettext_noop ("Provide information about a particular tunnel"),
+                                 &tunnel_id),
+
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('T',
+                                  "tunnels",
+                                  gettext_noop ("Provide information about all tunnels"),
+                                  &request_tunnels),
 
     GNUNET_GETOPT_OPTION_END
   };
@@ -955,7 +978,7 @@ main (int argc,
     return 2;
 
   res = GNUNET_PROGRAM_run (argc, argv,
-                            "gnunet-cadet (OPTIONS | TARGET PORT)",
+                            "gnunet-cadet (OPTIONS | PEER_ID SHARED_SECRET)",
                             gettext_noop (helpstr),
                             options, &run, NULL);
 
diff --git a/src/cadet/gnunet-service-cadet-new.c b/src/cadet/gnunet-service-cadet-new.c
deleted file mode 100644 (file)
index de85db5..0000000
+++ /dev/null
@@ -1,1490 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2013, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new.c
- * @brief GNUnet CADET service with encryption
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * Dictionary:
- * - peer: other cadet instance. If there is direct connection it's a neighbor.
- * - path: series of directly connected peer from one peer to another.
- * - connection: path which is being used in a tunnel.
- * - tunnel: encrypted connection to a peer, neighbor or not.
- * - channel: logical link between two clients, on the same or different peers.
- *            have properties like reliability.
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_channel.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_core.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_hello.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
-
-
-/**
- * Struct containing information about a client of the service
- */
-struct CadetClient
-{
-  /**
-   * Linked list next
-   */
-  struct CadetClient *next;
-
-  /**
-   * Linked list prev
-   */
-  struct CadetClient *prev;
-
-  /**
-   * Tunnels that belong to this client, indexed by local id,
-   * value is a `struct CadetChannel`.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
-
-  /**
-   * Handle to communicate with the client
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * Client handle.
-   */
-  struct GNUNET_SERVICE_Client *client;
-
-  /**
-   * Ports that this client has declared interest in.
-   * Indexed by port, contains *Client.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap *ports;
-
-  /**
-   * Channel ID to use for the next incoming channel for this client.
-   * Wraps around (in theory).
-   */
-  struct GNUNET_CADET_ClientChannelNumber next_ccn;
-
-  /**
-   * ID of the client, mainly for debug messages. Purely internal to this file.
-   */
-  unsigned int id;
-};
-
-/******************************************************************************/
-/***********************      GLOBAL VARIABLES     ****************************/
-/******************************************************************************/
-
-/****************************** Global variables ******************************/
-
-/**
- * Handle to our configuration.
- */
-const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Handle to the statistics service.
- */
-struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Handle to communicate with ATS.
- */
-struct GNUNET_ATS_ConnectivityHandle *ats_ch;
-
-/**
- * Local peer own ID.
- */
-struct GNUNET_PeerIdentity my_full_id;
-
-/**
- * Own private key.
- */
-struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
-
-/**
- * Signal that shutdown is happening: prevent recovery measures.
- */
-int shutting_down;
-
-/**
- * DLL with all the clients, head.
- */
-static struct CadetClient *clients_head;
-
-/**
- * DLL with all the clients, tail.
- */
-static struct CadetClient *clients_tail;
-
-/**
- * Next ID to assign to a client.
- */
-static unsigned int next_client_id;
-
-/**
- * All ports clients of this peer have opened.
- */
-struct GNUNET_CONTAINER_MultiHashMap *open_ports;
-
-/**
- * Map from ports to channels where the ports were closed at the
- * time we got the inbound connection.
- * Indexed by port, contains `struct CadetChannel`.
- */
-struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
-
-/**
- * Map from PIDs to `struct CadetPeer` entries.
- */
-struct GNUNET_CONTAINER_MultiPeerMap *peers;
-
-/**
- * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
- * hash codes to `struct CadetConnection` objects.
- */
-struct GNUNET_CONTAINER_MultiShortmap *connections;
-
-/**
- * How many messages are needed to trigger an AXOLOTL ratchet advance.
- */
-unsigned long long ratchet_messages;
-
-/**
- * How long until we trigger a ratched advance due to time.
- */
-struct GNUNET_TIME_Relative ratchet_time;
-
-/**
- * How frequently do we send KEEPALIVE messages on idle connections?
- */
-struct GNUNET_TIME_Relative keepalive_period;
-
-/**
- * Set to non-zero values to create random drops to test retransmissions.
- */
-unsigned long long drop_percent;
-
-
-/**
- * Send a message to a client.
- *
- * @param c client to get the message
- * @param env envelope with the message
- */
-void
-GSC_send_to_client (struct CadetClient *c,
-                    struct GNUNET_MQ_Envelope *env)
-{
-  GNUNET_MQ_send (c->mq,
-                  env);
-}
-
-
-/**
- * Return identifier for a client as a string.
- *
- * @param c client to identify
- * @return string for debugging
- */
-const char *
-GSC_2s (struct CadetClient *c)
-{
-  static char buf[32];
-
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "Client(%u)",
-                   c->id);
-  return buf;
-}
-
-
-/**
- * Lookup channel of client @a c by @a ccn.
- *
- * @param c client to look in
- * @param ccn channel ID to look up
- * @return NULL if no such channel exists
- */
-static struct CadetChannel *
-lookup_channel (struct CadetClient *c,
-                struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  return GNUNET_CONTAINER_multihashmap32_get (c->channels,
-                                              ntohl (ccn.channel_of_client));
-}
-
-
-/**
- * Obtain the next LID to use for incoming connections to
- * the given client.
- *
- * @param c client handle
- */
-static struct GNUNET_CADET_ClientChannelNumber
-client_get_next_ccn (struct CadetClient *c)
-{
-  struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
-
-  /* increment until we have a free one... */
-  while (NULL !=
-         lookup_channel (c,
-                         ccn))
-  {
-    ccn.channel_of_client
-      = htonl (1 + (ntohl (ccn.channel_of_client)));
-    if (ntohl (ccn.channel_of_client) >=
-        GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-      ccn.channel_of_client = htonl (0);
-  }
-  c->next_ccn.channel_of_client
-    = htonl (1 + (ntohl (ccn.channel_of_client)));
-  return ccn;
-}
-
-
-/**
- * Bind incoming channel to this client, and notify client about
- * incoming connection.  Caller is responsible for notifying the other
- * peer about our acceptance of the channel.
- *
- * @param c client to bind to
- * @param ch channel to be bound
- * @param dest peer that establishes the connection
- * @param port port number
- * @param options options
- * @return local channel number assigned to the new client
- */
-struct GNUNET_CADET_ClientChannelNumber
-GSC_bind (struct CadetClient *c,
-          struct CadetChannel *ch,
-          struct CadetPeer *dest,
-          const struct GNUNET_HashCode *port,
-          uint32_t options)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalChannelCreateMessage *cm;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  ccn = client_get_next_ccn (c);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
-                                                      ntohl (ccn.channel_of_client),
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
-       GCCH_2s (ch),
-       GCP_2s (dest),
-       GNUNET_h2s (port),
-       (uint32_t) ntohl (options),
-       (uint32_t) ntohl (ccn.channel_of_client));
-  /* notify local client about incoming connection! */
-  env = GNUNET_MQ_msg (cm,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
-  cm->ccn = ccn;
-  cm->port = *port;
-  cm->opt = htonl (options);
-  cm->peer = *GCP_get_id (dest);
-  GSC_send_to_client (c,
-                      env);
-  return ccn;
-}
-
-
-/**
- * Callback invoked on all peers to destroy all tunnels
- * that may still exist.
- *
- * @param cls NULL
- * @param pid identify of a peer
- * @param value a `struct CadetPeer` that may still have a tunnel
- * @return #GNUNET_OK (iterate over all entries)
- */
-static int
-destroy_tunnels_now (void *cls,
-                     const struct GNUNET_PeerIdentity *pid,
-                     void *value)
-{
-  struct CadetPeer *cp = value;
-  struct CadetTunnel *t = GCP_get_tunnel (cp,
-                                          GNUNET_NO);
-
-  if (NULL != t)
-    GCT_destroy_tunnel_now (t);
-  return GNUNET_OK;
-}
-
-
-/**
- * Callback invoked on all peers to destroy all tunnels
- * that may still exist.
- *
- * @param cls NULL
- * @param pid identify of a peer
- * @param value a `struct CadetPeer` that may still have a tunnel
- * @return #GNUNET_OK (iterate over all entries)
- */
-static int
-destroy_paths_now (void *cls,
-                   const struct GNUNET_PeerIdentity *pid,
-                   void *value)
-{
-  struct CadetPeer *cp = value;
-
-  GCP_drop_owned_paths (cp);
-  return GNUNET_OK;
-}
-
-
-/**
- * Shutdown everything once the clients have disconnected.
- */
-static void
-shutdown_rest ()
-{
-  if (NULL != stats)
-  {
-    GNUNET_STATISTICS_destroy (stats,
-                               GNUNET_NO);
-    stats = NULL;
-  }
-  if (NULL != open_ports)
-  {
-    GNUNET_CONTAINER_multihashmap_destroy (open_ports);
-    open_ports = NULL;
-  }
-  if (NULL != loose_channels)
-  {
-    GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
-    loose_channels = NULL;
-  }
-  /* Destroy tunnels.  Note that all channels must be destroyed first! */
-  GCP_iterate_all (&destroy_tunnels_now,
-                   NULL);
-  /* All tunnels, channels, connections and CORE must be down before this point. */
-  GCP_iterate_all (&destroy_paths_now,
-                   NULL);
-  /* All paths, tunnels, channels, connections and CORE must be down before this point. */
-  GCP_destroy_all_peers ();
-  if (NULL != peers)
-  {
-    GNUNET_CONTAINER_multipeermap_destroy (peers);
-    peers = NULL;
-  }
-  if (NULL != connections)
-  {
-    GNUNET_CONTAINER_multishortmap_destroy (connections);
-    connections = NULL;
-  }
-  if (NULL != ats_ch)
-  {
-    GNUNET_ATS_connectivity_done (ats_ch);
-    ats_ch = NULL;
-  }
-  GCD_shutdown ();
-  GCH_shutdown ();
-  GNUNET_free_non_null (my_private_key);
-  my_private_key = NULL;
-}
-
-
-/**
- * Task run during shutdown.
- *
- * @param cls unused
- */
-static void
-shutdown_task (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Shutting down\n");
-  shutting_down = GNUNET_YES;
-  GCO_shutdown ();
-  if (NULL == clients_head)
-    shutdown_rest ();
-}
-
-
-/**
- * We had a remote connection @a value to port @a port before
- * client @a cls opened port @a port.  Bind them now.
- *
- * @param cls the `struct CadetClient`
- * @param port the port
- * @param value the `struct CadetChannel`
- * @return #GNUNET_YES (iterate over all such channels)
- */
-static int
-bind_loose_channel (void *cls,
-                    const struct GNUNET_HashCode *port,
-                    void *value)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch = value;
-
-  GCCH_bind (ch,
-             c);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
-                                                       port,
-                                                       value));
-  return GNUNET_YES;
-}
-
-
-/**
- * Handle port open request.  Creates a mapping from the
- * port to the respective client and checks whether we have
- * loose channels trying to bind to the port.  If so, those
- * are bound.
- *
- * @param cls Identification of the client.
- * @param pmsg The actual message.
- */
-static void
-handle_port_open (void *cls,
-                  const struct GNUNET_CADET_PortMessage *pmsg)
-{
-  struct CadetClient *c = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Open port %s requested by %s\n",
-       GNUNET_h2s (&pmsg->port),
-       GSC_2s (c));
-  if (NULL == c->ports)
-    c->ports = GNUNET_CONTAINER_multihashmap_create (4,
-                                                      GNUNET_NO);
-  if (GNUNET_OK !=
-      GNUNET_CONTAINER_multihashmap_put (c->ports,
-                                         &pmsg->port,
-                                         c,
-                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
-                                            &pmsg->port,
-                                            c,
-                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-  GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
-                                              &pmsg->port,
-                                              &bind_loose_channel,
-                                              c);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for port close requests.  Marks this port as closed
- * (unless of course we have another client with the same port
- * open).  Note that existing channels accepted on the port are
- * not affected.
- *
- * @param cls Identification of the client.
- * @param pmsg The actual message.
- */
-static void
-handle_port_close (void *cls,
-                   const struct GNUNET_CADET_PortMessage *pmsg)
-{
-  struct CadetClient *c = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Closing port %s as requested by %s\n",
-       GNUNET_h2s (&pmsg->port),
-       GSC_2s (c));
-  if (GNUNET_YES !=
-      GNUNET_CONTAINER_multihashmap_remove (c->ports,
-                                            &pmsg->port,
-                                            c))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (open_ports,
-                                                       &pmsg->port,
-                                                       c));
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for requests for us creating a new channel to another peer and port.
- *
- * @param cls Identification of the client.
- * @param tcm The actual message.
- */
-static void
-handle_channel_create (void *cls,
-                       const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch;
-
-  if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-  {
-    /* Channel ID not in allowed range. */
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  ch = lookup_channel (c,
-                       tcm->ccn);
-  if (NULL != ch)
-  {
-    /* Channel ID already in use. Not allowed. */
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "New channel to %s at port %s requested by %s\n",
-       GNUNET_i2s (&tcm->peer),
-       GNUNET_h2s (&tcm->port),
-       GSC_2s (c));
-
-  /* Create channel */
-  ch = GCCH_channel_local_new (c,
-                               tcm->ccn,
-                               GCP_get (&tcm->peer,
-                                        GNUNET_YES),
-                               &tcm->port,
-                               ntohl (tcm->opt));
-  if (NULL == ch)
-  {
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
-                                                      ntohl (tcm->ccn.channel_of_client),
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for requests of destroying an existing channel.
- *
- * @param cls client identification of the client
- * @param msg the actual message
- */
-static void
-handle_channel_destroy (void *cls,
-                        const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (c,
-                       msg->ccn);
-  if (NULL == ch)
-  {
-    /* Client attempted to destroy unknown channel.
-       Can happen if the other side went down at the same time.*/
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "%s tried to destroy unknown channel %X\n",
-         GSC_2s(c),
-         (uint32_t) ntohl (msg->ccn.channel_of_client));
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s is destroying %s\n",
-       GSC_2s(c),
-       GCCH_2s (ch));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
-                                                         ntohl (msg->ccn.channel_of_client),
-                                                         ch));
-  GCCH_channel_local_destroy (ch,
-                              c,
-                              msg->ccn);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Check for client traffic data message is well-formed.
- *
- * @param cls identification of the client
- * @param msg the actual message
- * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
- */
-static int
-check_local_data (void *cls,
-                  const struct GNUNET_CADET_LocalData *msg)
-{
-  size_t payload_size;
-  size_t payload_claimed_size;
-  const char *buf;
-  struct GNUNET_MessageHeader pa;
-
-  /* FIXME: what is the format we shall allow for @a msg?
-     ONE payload item or multiple? Seems current cadet_api
-     at least in theory allows more than one. Next-gen
-     cadet_api will likely no more, so we could then
-     simplify this mess again. */
-  /* Sanity check for message size */
-  payload_size = ntohs (msg->header.size) - sizeof (*msg);
-  buf = (const char *) &msg[1];
-  while (payload_size >= sizeof (struct GNUNET_MessageHeader))
-  {
-    /* need to memcpy() for alignment */
-    GNUNET_memcpy (&pa,
-                   buf,
-                   sizeof (pa));
-    payload_claimed_size = ntohs (pa.size);
-    if ( (payload_size < payload_claimed_size) ||
-         (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
-         (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
-    {
-      GNUNET_break (0);
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Local data of %u total size had sub-message %u at %u with %u bytes\n",
-           ntohs (msg->header.size),
-           ntohs (pa.type),
-           (unsigned int) (buf - (const char *) &msg[1]),
-           (unsigned int) payload_claimed_size);
-      return GNUNET_SYSERR;
-    }
-    payload_size -= payload_claimed_size;
-    buf += payload_claimed_size;
-  }
-  if (0 != payload_size)
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Handler for client payload traffic to be send on a channel to
- * another peer.
- *
- * @param cls identification of the client
- * @param msg the actual message
- */
-static void
-handle_local_data (void *cls,
-                   const struct GNUNET_CADET_LocalData *msg)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch;
-  size_t payload_size;
-  const char *buf;
-
-  ch = lookup_channel (c,
-                       msg->ccn);
-  if (NULL == ch)
-  {
-    /* Channel does not exist (anymore) */
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
-         (unsigned int) ntohl (msg->ccn.channel_of_client));
-    GNUNET_SERVICE_client_continue (c->client);
-    return;
-  }
-  payload_size = ntohs (msg->header.size) - sizeof (*msg);
-  buf = (const char *) &msg[1];
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received %u bytes payload from %s for %s\n",
-       (unsigned int) payload_size,
-       GSC_2s (c),
-       GCCH_2s (ch));
-  if (GNUNET_OK !=
-      GCCH_handle_local_data (ch,
-                              msg->ccn,
-                              buf,
-                              payload_size))
-  {
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Handler for client's ACKs for payload traffic.
- *
- * @param cls identification of the client.
- * @param msg The actual message.
- */
-static void
-handle_local_ack (void *cls,
-                  const struct GNUNET_CADET_LocalAck *msg)
-{
-  struct CadetClient *c = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (c,
-                       msg->ccn);
-  if (NULL == ch)
-  {
-    /* Channel does not exist! */
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (c->client);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got a local ACK from %s for %s\n",
-       GSC_2s(c),
-       GCCH_2s (ch));
-  GCCH_handle_local_ack (ch,
-                         msg->ccn);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all peers to send a monitoring client info about each peer.
- *
- * @param cls Closure ().
- * @param peer Peer ID (tunnel remote peer).
- * @param value Peer info.
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-get_all_peers_iterator (void *cls,
-                        const struct GNUNET_PeerIdentity *peer,
-                        void *value)
-{
-  struct CadetClient *c = cls;
-  struct CadetPeer *p = value;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalInfoPeer *msg;
-
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
-  msg->destination = *peer;
-  msg->paths = htons (GCP_count_paths (p));
-  msg->tunnel = htons (NULL != GCP_get_tunnel (p,
-                                               GNUNET_NO));
-  GNUNET_MQ_send (c->mq,
-                  env);
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO PEERS request.
- *
- * @param cls Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_get_peers (void *cls,
-                  const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c = cls;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *reply;
-
-  GCP_iterate_all (&get_all_peers_iterator,
-                   c);
-  env = GNUNET_MQ_msg (reply,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
-  GNUNET_MQ_send (c->mq,
-                  env);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all paths of a peer to build an InfoPeer message.
- * Message contains blocks of peers, first not included.
- *
- * @param cls message queue for transmission
- * @param path Path itself
- * @param off offset of the peer on @a path
- * @return #GNUNET_YES if should keep iterating.
- *         #GNUNET_NO otherwise.
- */
-static int
-path_info_iterator (void *cls,
-                    struct CadetPeerPath *path,
-                    unsigned int off)
-{
-  struct GNUNET_MQ_Handle *mq = cls;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *resp;
-  struct GNUNET_PeerIdentity *id;
-  uint16_t path_size;
-  unsigned int i;
-  unsigned int path_length;
-
-  path_length = GCPP_get_length (path);
-  path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
-  if (sizeof (*resp) + path_size > UINT16_MAX)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Path of %u entries is too long for info message\n",
-         path_length);
-    return GNUNET_YES;
-  }
-  env = GNUNET_MQ_msg_extra (resp,
-                             path_size,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
-  id = (struct GNUNET_PeerIdentity *) &resp[1];
-
-  /* Don't copy first peer.  First peer is always the local one.  Last
-   * peer is always the destination (leave as 0, EOL).
-   */
-  for (i = 0; i < off; i++)
-    id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
-                                                  i + 1));
-  GNUNET_MQ_send (mq,
-                  env);
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's SHOW_PEER request.
- *
- * @param cls Identification of the client.
- * @param msg The actual message.
- */
-static void
-handle_show_peer (void *cls,
-                  const struct GNUNET_CADET_LocalInfo *msg)
-{
-  struct CadetClient *c = cls;
-  struct CadetPeer *p;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *resp;
-
-  p = GCP_get (&msg->peer,
-               GNUNET_NO);
-  if (NULL != p)
-    GCP_iterate_paths (p,
-                       &path_info_iterator,
-                       c->mq);
-  /* Send message with 0/0 to indicate the end */
-  env = GNUNET_MQ_msg (resp,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
-  GNUNET_MQ_send (c->mq,
-                  env);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all tunnels to send a monitoring client info about each tunnel.
- *
- * @param cls Closure ().
- * @param peer Peer ID (tunnel remote peer).
- * @param value a `struct CadetPeer`
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-get_all_tunnels_iterator (void *cls,
-                          const struct GNUNET_PeerIdentity *peer,
-                          void *value)
-{
-  struct CadetClient *c = cls;
-  struct CadetPeer *p = value;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalInfoTunnel *msg;
-  struct CadetTunnel *t;
-
-  t = GCP_get_tunnel (p,
-                      GNUNET_NO);
-  if (NULL == t)
-    return GNUNET_YES;
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
-  msg->destination = *peer;
-  msg->channels = htonl (GCT_count_channels (t));
-  msg->connections = htonl (GCT_count_any_connections (t));
-  msg->cstate = htons (0);
-  msg->estate = htons ((uint16_t) GCT_get_estate (t));
-  GNUNET_MQ_send (c->mq,
-                  env);
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
- *
- * @param cls client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_info_tunnels (void *cls,
-                     const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c = cls;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *reply;
-
-  GCP_iterate_all (&get_all_tunnels_iterator,
-                   c);
-  env = GNUNET_MQ_msg (reply,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
-  GNUNET_MQ_send (c->mq,
-                  env);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Update the message with information about the connection.
- *
- * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
- * @param ct a connection about which we should store information in @a cls
- */
-static void
-iter_connection (void *cls,
-                 struct CadetTConnection *ct)
-{
-  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
-  struct CadetConnection *cc = ct->cc;
-  struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
-
-  h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
-  h[msg->connections++] = *(GCC_get_id (cc));
-}
-
-
-/**
- * Update the message with information about the channel.
- *
- * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
- * @param ch a channel about which we should store information in @a cls
- */
-static void
-iter_channel (void *cls,
-              struct CadetChannel *ch)
-{
-  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
-  struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
-  struct GNUNET_CADET_ChannelTunnelNumber *chn
-    = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
-
-  chn[msg->channels++] = GCCH_get_id (ch);
-}
-
-
-/**
- * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
- *
- * @param cls Identification of the client.
- * @param msg The actual message.
- */
-static void
-handle_info_tunnel (void *cls,
-                    const struct GNUNET_CADET_LocalInfo *msg)
-{
-  struct CadetClient *c = cls;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalInfoTunnel *resp;
-  struct CadetTunnel *t;
-  struct CadetPeer *p;
-  unsigned int ch_n;
-  unsigned int c_n;
-
-  p = GCP_get (&msg->peer,
-               GNUNET_NO);
-  t = GCP_get_tunnel (p,
-                      GNUNET_NO);
-  if (NULL == t)
-  {
-    /* We don't know the tunnel */
-    struct GNUNET_MQ_Envelope *env;
-    struct GNUNET_CADET_LocalInfoTunnel *warn;
-
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         "Tunnel to %s unknown\n",
-         GNUNET_i2s_full (&msg->peer));
-    env = GNUNET_MQ_msg (warn,
-                         GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
-    warn->destination = msg->peer;
-    GNUNET_MQ_send (c->mq,
-                    env);
-    GNUNET_SERVICE_client_continue (c->client);
-    return;
-  }
-
-  /* Initialize context */
-  ch_n = GCT_count_channels (t);
-  c_n = GCT_count_any_connections (t);
-  env = GNUNET_MQ_msg_extra (resp,
-                             c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
-                             ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
-  resp->destination = msg->peer;
-  /* Do not reorder! #iter_channel needs counters in HBO! */
-  GCT_iterate_connections (t,
-                           &iter_connection,
-                           resp);
-  GCT_iterate_channels (t,
-                        &iter_channel,
-                        resp);
-  resp->connections = htonl (resp->connections);
-  resp->channels = htonl (resp->channels);
-  resp->cstate = htons (0);
-  resp->estate = htons (GCT_get_estate (t));
-  GNUNET_MQ_send (c->mq,
-                  env);
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-/**
- * Iterator over all peers to dump info for each peer.
- *
- * @param cls Closure (unused).
- * @param peer Peer ID (tunnel remote peer).
- * @param value Peer info.
- *
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-show_peer_iterator (void *cls,
-                    const struct GNUNET_PeerIdentity *peer,
-                    void *value)
-{
-  struct CadetPeer *p = value;
-  struct CadetTunnel *t;
-
-  t = GCP_get_tunnel (p,
-                      GNUNET_NO);
-  if (NULL != t)
-    GCT_debug (t,
-               GNUNET_ERROR_TYPE_ERROR);
-  LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO_DUMP request.
- *
- * @param cls Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_info_dump (void *cls,
-                  const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c = cls;
-
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Received dump info request from client %u\n",
-       c->id);
-
-  LOG (GNUNET_ERROR_TYPE_ERROR,
-       "*************************** DUMP START ***************************\n");
-  for (struct CadetClient *ci = clients_head;
-       NULL != ci;
-       ci = ci->next)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
-         ci->id,
-         ci,
-         ci->client,
-         (NULL != c->ports)
-         ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
-         : 0,
-         GNUNET_CONTAINER_multihashmap32_size (ci->channels));
-  }
-  LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
-  GCP_iterate_all (&show_peer_iterator,
-                   NULL);
-
-  LOG (GNUNET_ERROR_TYPE_ERROR,
-       "**************************** DUMP END ****************************\n");
-
-  GNUNET_SERVICE_client_continue (c->client);
-}
-
-
-
-/**
- * Callback called when a client connects to the service.
- *
- * @param cls closure for the service
- * @param client the new client that connected to the service
- * @param mq the message queue used to send messages to the client
- * @return @a c
- */
-static void *
-client_connect_cb (void *cls,
-                  struct GNUNET_SERVICE_Client *client,
-                  struct GNUNET_MQ_Handle *mq)
-{
-  struct CadetClient *c;
-
-  c = GNUNET_new (struct CadetClient);
-  c->client = client;
-  c->mq = mq;
-  c->id = next_client_id++; /* overflow not important: just for debug */
-  c->channels
-    = GNUNET_CONTAINER_multihashmap32_create (32);
-  GNUNET_CONTAINER_DLL_insert (clients_head,
-                               clients_tail,
-                               c);
-  GNUNET_STATISTICS_update (stats,
-                            "# clients",
-                            +1,
-                            GNUNET_NO);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s connected\n",
-       GSC_2s (c));
-  return c;
-}
-
-
-/**
- * A channel was destroyed by the other peer. Tell our client.
- *
- * @param c client that lost a channel
- * @param ccn channel identification number for the client
- * @param ch the channel object
- */
-void
-GSC_handle_remote_channel_destroy (struct CadetClient *c,
-                                   struct GNUNET_CADET_ClientChannelNumber ccn,
-                                   struct CadetChannel *ch)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
-
-  env = GNUNET_MQ_msg (tdm,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
-  tdm->ccn = ccn;
-  GSC_send_to_client (c,
-                      env);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
-                                                         ntohl (ccn.channel_of_client),
-                                                         ch));
-}
-
-
-/**
- * A client that created a loose channel that was not bound to a port
- * disconnected, drop it from the #loose_channels list.
- *
- * @param port the port the channel was trying to bind to
- * @param ch the channel that was lost
- */
-void
-GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
-                        struct CadetChannel *ch)
-{
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
-                                                       port,
-                                                       ch));
-}
-
-
-/**
- * Iterator for deleting each channel whose client endpoint disconnected.
- *
- * @param cls Closure (client that has disconnected).
- * @param key The local channel id in host byte order
- * @param value The value stored at the key (channel to destroy).
- * @return #GNUNET_OK, keep iterating.
- */
-static int
-channel_destroy_iterator (void *cls,
-                          uint32_t key,
-                          void *value)
-{
-  struct CadetClient *c = cls;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-  struct CadetChannel *ch = value;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying %s, due to %s disconnecting.\n",
-       GCCH_2s (ch),
-       GSC_2s (c));
-  ccn.channel_of_client = htonl (key);
-  GCCH_channel_local_destroy (ch,
-                              c,
-                              ccn);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
-                                                         key,
-                                                         ch));
-  return GNUNET_OK;
-}
-
-
-/**
- * Remove client's ports from the global hashmap on disconnect.
- *
- * @param cls Closure (unused).
- * @param key the port.
- * @param value the `struct CadetClient` to remove
- * @return #GNUNET_OK, keep iterating.
- */
-static int
-client_release_ports (void *cls,
-                      const struct GNUNET_HashCode *key,
-                      void *value)
-{
-  struct CadetClient *c = value;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Closing port %s due to %s disconnect.\n",
-       GNUNET_h2s (key),
-       GSC_2s (c));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (open_ports,
-                                                       key,
-                                                       value));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (c->ports,
-                                                       key,
-                                                       value));
-  return GNUNET_OK;
-}
-
-
-/**
- * Callback called when a client disconnected from the service
- *
- * @param cls closure for the service
- * @param client the client that disconnected
- * @param internal_cls should be equal to @a c
- */
-static void
-client_disconnect_cb (void *cls,
-                     struct GNUNET_SERVICE_Client *client,
-                     void *internal_cls)
-{
-  struct CadetClient *c = internal_cls;
-
-  GNUNET_assert (c->client == client);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s is disconnecting.\n",
-       GSC_2s (c));
-  if (NULL != c->channels)
-  {
-    GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
-                                             &channel_destroy_iterator,
-                                             c);
-    GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
-    GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
-  }
-  if (NULL != c->ports)
-  {
-    GNUNET_CONTAINER_multihashmap_iterate (c->ports,
-                                           &client_release_ports,
-                                           c);
-    GNUNET_CONTAINER_multihashmap_destroy (c->ports);
-  }
-  GNUNET_CONTAINER_DLL_remove (clients_head,
-                               clients_tail,
-                               c);
-  GNUNET_STATISTICS_update (stats,
-                            "# clients",
-                            -1,
-                            GNUNET_NO);
-  GNUNET_free (c);
-  if ( (NULL == clients_head) &&
-       (GNUNET_YES == shutting_down) )
-    shutdown_rest ();
-}
-
-
-/**
- * Setup CADET internals.
- *
- * @param cls closure
- * @param server the initialized server
- * @param c configuration to use
- */
-static void
-run (void *cls,
-     const struct GNUNET_CONFIGURATION_Handle *c,
-     struct GNUNET_SERVICE_Handle *service)
-{
-  cfg = c;
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "RATCHET_MESSAGES",
-                                             &ratchet_messages))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET",
-                               "RATCHET_MESSAGES",
-                               "needs to be a number");
-    ratchet_messages = 64;
-  }
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c,
-                                           "CADET",
-                                           "RATCHET_TIME",
-                                           &ratchet_time))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET",
-                               "RATCHET_TIME",
-                               "need delay value");
-    ratchet_time = GNUNET_TIME_UNIT_HOURS;
-  }
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c,
-                                           "CADET",
-                                           "REFRESH_CONNECTION_TIME",
-                                           &keepalive_period))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET",
-                               "REFRESH_CONNECTION_TIME",
-                               "need delay value");
-    keepalive_period = GNUNET_TIME_UNIT_MINUTES;
-  }
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "DROP_PERCENT",
-                                             &drop_percent))
-  {
-    drop_percent = 0;
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
-    LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
-    LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
-    LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
-    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
-  }
-  my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
-  if (NULL == my_private_key)
-  {
-    GNUNET_break (0);
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
-                                      &my_full_id.public_key);
-  stats = GNUNET_STATISTICS_create ("cadet",
-                                    c);
-  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
-                                NULL);
-  ats_ch = GNUNET_ATS_connectivity_init (c);
-  /* FIXME: optimize code to allow GNUNET_YES here! */
-  open_ports = GNUNET_CONTAINER_multihashmap_create (16,
-                                                     GNUNET_NO);
-  loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
-                                                         GNUNET_NO);
-  peers = GNUNET_CONTAINER_multipeermap_create (16,
-                                                GNUNET_YES);
-  connections = GNUNET_CONTAINER_multishortmap_create (256,
-                                                       GNUNET_YES);
-  GCH_init (c);
-  GCD_init (c);
-  GCO_init (c);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "CADET started for peer %s\n",
-              GNUNET_i2s (&my_full_id));
-
-}
-
-
-/**
- * Define "main" method using service macro.
- */
-GNUNET_SERVICE_MAIN
-("cadet",
- GNUNET_SERVICE_OPTION_NONE,
- &run,
- &client_connect_cb,
- &client_disconnect_cb,
- NULL,
- GNUNET_MQ_hd_fixed_size (port_open,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
-                          struct GNUNET_CADET_PortMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (port_close,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
-                          struct GNUNET_CADET_PortMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (channel_create,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
-                          struct GNUNET_CADET_LocalChannelCreateMessage,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (channel_destroy,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
-                          struct GNUNET_CADET_LocalChannelDestroyMessage,
-                          NULL),
- GNUNET_MQ_hd_var_size (local_data,
-                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
-                        struct GNUNET_CADET_LocalData,
-                        NULL),
- GNUNET_MQ_hd_fixed_size (local_ack,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
-                          struct GNUNET_CADET_LocalAck,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (get_peers,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
-                          struct GNUNET_MessageHeader,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (show_peer,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
-                          struct GNUNET_CADET_LocalInfo,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (info_tunnels,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
-                          struct GNUNET_MessageHeader,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (info_tunnel,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
-                          struct GNUNET_CADET_LocalInfo,
-                          NULL),
- GNUNET_MQ_hd_fixed_size (info_dump,
-                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
-                          struct GNUNET_MessageHeader,
-                          NULL),
- GNUNET_MQ_handler_end ());
-
-/* end of gnunet-service-cadet-new.c */
diff --git a/src/cadet/gnunet-service-cadet-new.h b/src/cadet/gnunet-service-cadet-new.h
deleted file mode 100644 (file)
index bee5c67..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new.h
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_H
-#define GNUNET_SERVICE_CADET_H
-
-#include "gnunet_util_lib.h"
-#define NEW_CADET 1
-#include "cadet_protocol.h"
-
-/**
- * A client to the CADET service.  Each client gets a unique handle.
- */
-struct CadetClient;
-
-/**
- * A peer in the GNUnet network.  Each peer we care about must have one globally
- * unique such handle within this process.
- */
-struct CadetPeer;
-
-/**
- * Tunnel from us to another peer.  There can only be at most one
- * tunnel per peer.
- */
-struct CadetTunnel;
-
-/**
- * Entry in the message queue of a `struct CadetTunnel`.
- */
-struct CadetTunnelQueueEntry;
-
-/**
- * A path of peer in the GNUnet network.  There must only be at most
- * once such path.  Paths may share disjoint prefixes, but must all
- * end at a unique suffix.  Paths must also not be proper subsets of
- * other existing paths.
- */
-struct CadetPeerPath;
-
-/**
- * Entry in a peer path.
- */
-struct CadetPeerPathEntry
-{
-  /**
-   * DLL of paths where the same @e peer is at the same offset.
-   */
-  struct CadetPeerPathEntry *next;
-
-  /**
-   * DLL of paths where the same @e peer is at the same offset.
-   */
-  struct CadetPeerPathEntry *prev;
-
-  /**
-   * The peer at this offset of the path.
-   */
-  struct CadetPeer *peer;
-
-  /**
-   * Path this entry belongs to.
-   */
-  struct CadetPeerPath *path;
-
-  /**
-   * Connection using this path, or NULL for none.
-   */
-  struct CadetConnection *cc;
-
-  /**
-   * Path's historic score up to this point.  Basically, how often did
-   * we succeed or fail to use the path up to this entry in a
-   * connection.  Positive values indicate good experiences, negative
-   * values bad experiences.  Code updating the score must guard
-   * against overflows.
-   */
-  int score;
-
-};
-
-/**
- * Entry in list of connections used by tunnel, with metadata.
- */
-struct CadetTConnection
-{
-  /**
-   * Next in DLL.
-   */
-  struct CadetTConnection *next;
-
-  /**
-   * Prev in DLL.
-   */
-  struct CadetTConnection *prev;
-
-  /**
-   * Connection handle.
-   */
-  struct CadetConnection *cc;
-
-  /**
-   * Tunnel this connection belongs to.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Creation time, to keep oldest connection alive.
-   */
-  struct GNUNET_TIME_Absolute created;
-
-  /**
-   * Connection throughput, to keep fastest connection alive.
-   */
-  uint32_t throughput;
-
-  /**
-   * Is the connection currently ready for transmission?
-   */
-  int is_ready;
-};
-
-
-/**
- * Active path through the network (used by a tunnel).  There may
- * be at most one connection per path.
- */
-struct CadetConnection;
-
-/**
- * Description of a segment of a `struct CadetConnection` at the
- * intermediate peers.  Routes are basically entries in a peer's
- * routing table for forwarding traffic.  At both endpoints, the
- * routes are terminated by a `struct CadetConnection`, which knows
- * the complete `struct CadetPath` that is formed by the individual
- * routes.
- */
-struct CadetRoute;
-
-/**
- * Logical end-to-end conenction between clients.  There can be
- * any number of channels between clients.
- */
-struct CadetChannel;
-
-/**
- * Handle to our configuration.
- */
-extern const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Handle to communicate with ATS.
- */
-extern struct GNUNET_ATS_ConnectivityHandle *ats_ch;
-
-/**
- * Local peer own ID.
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-/**
- * Own private key.
- */
-extern struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
-
-/**
- * All ports clients of this peer have opened.
- */
-extern struct GNUNET_CONTAINER_MultiHashMap *open_ports;
-
-/**
- * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
- * hash codes to `struct CadetConnection` objects.
- */
-extern struct GNUNET_CONTAINER_MultiShortmap *connections;
-
-/**
- * Map from ports to channels where the ports were closed at the
- * time we got the inbound connection.
- * Indexed by port, contains `struct CadetChannel`.
- */
-extern struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
-
-/**
- * Map from PIDs to `struct CadetPeer` entries.
- */
-extern struct GNUNET_CONTAINER_MultiPeerMap *peers;
-
-/**
- * How many messages are needed to trigger an AXOLOTL ratchet advance.
- */
-extern unsigned long long ratchet_messages;
-
-/**
- * How long until we trigger a ratched advance due to time.
- */
-extern struct GNUNET_TIME_Relative ratchet_time;
-
-/**
- * How frequently do we send KEEPALIVE messages on idle connections?
- */
-extern struct GNUNET_TIME_Relative keepalive_period;
-
-/**
- * Signal that shutdown is happening: prevent recovery measures.
- */
-extern int shutting_down;
-
-/**
- * Set to non-zero values to create random drops to test retransmissions.
- */
-extern unsigned long long drop_percent;
-
-
-/**
- * Send a message to a client.
- *
- * @param c client to get the message
- * @param env envelope with the message
- */
-void
-GSC_send_to_client (struct CadetClient *c,
-                    struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * A channel was destroyed by the other peer. Tell our client.
- *
- * @param c client that lost a channel
- * @param ccn channel identification number for the client
- * @param ch the channel object
- */
-void
-GSC_handle_remote_channel_destroy (struct CadetClient *c,
-                                   struct GNUNET_CADET_ClientChannelNumber ccn,
-                                   struct CadetChannel *ch);
-
-/**
- * A client that created a loose channel that was not bound to a port
- * disconnected, drop it from the #loose_channels list.
- *
- * @param port the port the channel was trying to bind to
- * @param ch the channel that was lost
- */
-void
-GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
-                        struct CadetChannel *ch);
-
-
-/**
- * Bind incoming channel to this client, and notify client
- * about incoming connection.
- *
- * @param c client to bind to
- * @param ch channel to be bound
- * @param dest peer that establishes the connection
- * @param port port number
- * @param options options
- * @return local channel number assigned to the new client
- */
-struct GNUNET_CADET_ClientChannelNumber
-GSC_bind (struct CadetClient *c,
-          struct CadetChannel *ch,
-          struct CadetPeer *dest,
-          const struct GNUNET_HashCode *port,
-          uint32_t options);
-
-
-/**
- * Return identifier for a client as a string.
- *
- * @param c client to identify
- * @return string for debugging
- */
-const char *
-GSC_2s (struct CadetClient *c);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c
deleted file mode 100644 (file)
index 8769601..0000000
+++ /dev/null
@@ -1,2037 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_channel.c
- * @brief logical links between CADET clients
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * TODO:
- * - Congestion/flow control:
- *   + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
- *     (and figure out how/where to use this!)
- *   + figure out flow control without ACKs (unreliable traffic!)
- * - revisit handling of 'unbuffered' traffic!
- *   (need to push down through tunnel into connection selection)
- * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe
- *   reserve more bits in 'options' to allow for buffer size control?
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_channel.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-#define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__)
-
-/**
- * How long do we initially wait before retransmitting?
- */
-#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
-
-/**
- * How long do we wait before dropping state about incoming
- * connection to closed port?
- */
-#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
-
-/**
- * How long do we wait at least before retransmitting ever?
- */
-#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
-
-/**
- * Maximum message ID into the future we accept for out-of-order messages.
- * If the message is more than this into the future, we drop it.  This is
- * important both to detect values that are actually in the past, as well
- * as to limit adversarially triggerable memory consumption.
- *
- * Note that right now we have "max_pending_messages = 4" hard-coded in
- * the logic below, so a value of 4 would suffice here. But we plan to
- * allow larger windows in the future...
- */
-#define MAX_OUT_OF_ORDER_DISTANCE 1024
-
-
-/**
- * All the states a channel can be in.
- */
-enum CadetChannelState
-{
-  /**
-   * Uninitialized status, should never appear in operation.
-   */
-  CADET_CHANNEL_NEW,
-
-  /**
-   * Channel is to a port that is not open, we're waiting for the
-   * port to be opened.
-   */
-  CADET_CHANNEL_LOOSE,
-
-  /**
-   * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
-   */
-  CADET_CHANNEL_OPEN_SENT,
-
-  /**
-   * Connection confirmed, ready to carry traffic.
-   */
-  CADET_CHANNEL_READY
-};
-
-
-/**
- * Info needed to retry a message in case it gets lost.
- * Note that we DO use this structure also for unreliable
- * messages.
- */
-struct CadetReliableMessage
-{
-  /**
-   * Double linked list, FIFO style
-   */
-  struct CadetReliableMessage *next;
-
-  /**
-   * Double linked list, FIFO style
-   */
-  struct CadetReliableMessage *prev;
-
-  /**
-   * Which channel is this message in?
-   */
-  struct CadetChannel *ch;
-
-  /**
-   * Entry in the tunnels queue for this message, NULL if it has left
-   * the tunnel.  Used to cancel transmission in case we receive an
-   * ACK in time.
-   */
-  struct CadetTunnelQueueEntry *qe;
-
-  /**
-   * Data message we are trying to send.
-   */
-  struct GNUNET_CADET_ChannelAppDataMessage *data_message;
-
-  /**
-   * How soon should we retry if we fail to get an ACK?
-   * Messages in the queue are sorted by this value.
-   */
-  struct GNUNET_TIME_Absolute next_retry;
-
-  /**
-   * How long do we wait for an ACK after transmission?
-   * Use for the back-off calculation.
-   */
-  struct GNUNET_TIME_Relative retry_delay;
-
-  /**
-   * Time when we first successfully transmitted the message
-   * (that is, set @e num_transmissions to 1).
-   */
-  struct GNUNET_TIME_Absolute first_transmission_time;
-
-  /**
-   * Identifier of the connection that this message took when it
-   * was first transmitted.  Only useful if @e num_transmissions is 1.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken;
-
-  /**
-   * How often was this message transmitted?  #GNUNET_SYSERR if there
-   * was an error transmitting the message, #GNUNET_NO if it was not
-   * yet transmitted ever, otherwise the number of (re) transmissions.
-   */
-  int num_transmissions;
-
-};
-
-
-/**
- * List of received out-of-order data messages.
- */
-struct CadetOutOfOrderMessage
-{
-  /**
-   * Double linked list, FIFO style
-   */
-  struct CadetOutOfOrderMessage *next;
-
-  /**
-   * Double linked list, FIFO style
-   */
-  struct CadetOutOfOrderMessage *prev;
-
-  /**
-   * ID of the message (messages up to this point needed
-   * before we give this one to the client).
-   */
-  struct ChannelMessageIdentifier mid;
-
-  /**
-   * The envelope with the payload of the out-of-order message
-   */
-  struct GNUNET_MQ_Envelope *env;
-
-};
-
-
-/**
- * Client endpoint of a `struct CadetChannel`.  A channel may be a
- * loopback channel, in which case it has two of these endpoints.
- * Note that flow control also is required in both directions.
- */
-struct CadetChannelClient
-{
-  /**
-   * Client handle.  Not by itself sufficient to designate
-   * the client endpoint, as the same client handle may
-   * be used for both the owner and the destination, and
-   * we thus also need the channel ID to identify the client.
-   */
-  struct CadetClient *c;
-
-  /**
-   * Head of DLL of messages received out of order or while client was unready.
-   */
-  struct CadetOutOfOrderMessage *head_recv;
-
-  /**
-   * Tail DLL of messages received out of order or while client was unready.
-   */
-  struct CadetOutOfOrderMessage *tail_recv;
-
-  /**
-   * Local tunnel number for this client.
-   * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
-   *  otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-   */
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  /**
-   * Number of entries currently in @a head_recv DLL.
-   */
-  unsigned int num_recv;
-
-  /**
-   * Can we send data to the client?
-   */
-  int client_ready;
-
-};
-
-
-/**
- * Struct containing all information regarding a channel to a remote client.
- */
-struct CadetChannel
-{
-  /**
-   * Tunnel this channel is in.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Client owner of the tunnel, if any.
-   * (Used if this channel represends the initiating end of the tunnel.)
-   */
-  struct CadetChannelClient *owner;
-
-  /**
-   * Client destination of the tunnel, if any.
-   * (Used if this channel represents the listening end of the tunnel.)
-   */
-  struct CadetChannelClient *dest;
-
-  /**
-   * Last entry in the tunnel's queue relating to control messages
-   * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
-   * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK).  Used to cancel
-   * transmission in case we receive updated information.
-   */
-  struct CadetTunnelQueueEntry *last_control_qe;
-
-  /**
-   * Head of DLL of messages sent and not yet ACK'd.
-   */
-  struct CadetReliableMessage *head_sent;
-
-  /**
-   * Tail of DLL of messages sent and not yet ACK'd.
-   */
-  struct CadetReliableMessage *tail_sent;
-
-  /**
-   * Task to resend/poll in case no ACK is received.
-   */
-  struct GNUNET_SCHEDULER_Task *retry_control_task;
-
-  /**
-   * Task to resend/poll in case no ACK is received.
-   */
-  struct GNUNET_SCHEDULER_Task *retry_data_task;
-
-  /**
-   * Last time the channel was used
-   */
-  struct GNUNET_TIME_Absolute timestamp;
-
-  /**
-   * Destination port of the channel.
-   */
-  struct GNUNET_HashCode port;
-
-  /**
-   * Counter for exponential backoff.
-   */
-  struct GNUNET_TIME_Relative retry_time;
-
-  /**
-   * Bitfield of already-received messages past @e mid_recv.
-   */
-  uint64_t mid_futures;
-
-  /**
-   * Next MID expected for incoming traffic.
-   */
-  struct ChannelMessageIdentifier mid_recv;
-
-  /**
-   * Next MID to use for outgoing traffic.
-   */
-  struct ChannelMessageIdentifier mid_send;
-
-  /**
-   * Total (reliable) messages pending ACK for this channel.
-   */
-  unsigned int pending_messages;
-
-  /**
-   * Maximum (reliable) messages pending ACK for this channel
-   * before we throttle the client.
-   */
-  unsigned int max_pending_messages;
-
-  /**
-   * Number identifying this channel in its tunnel.
-   */
-  struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
-  /**
-   * Channel state.
-   */
-  enum CadetChannelState state;
-
-  /**
-   * Count how many ACKs we skipped, used to prevent long
-   * sequences of ACK skipping.
-   */
-  unsigned int skip_ack_series;
-
-  /**
-   * Is the tunnel bufferless (minimum latency)?
-   */
-  int nobuffer;
-
-  /**
-   * Is the tunnel reliable?
-   */
-  int reliable;
-
-  /**
-   * Is the tunnel out-of-order?
-   */
-  int out_of_order;
-
-  /**
-   * Is this channel a loopback channel, where the destination is us again?
-   */
-  int is_loopback;
-
-  /**
-   * Flag to signal the destruction of the channel.  If this is set to
-   * #GNUNET_YES the channel will be destroyed once the queue is
-   * empty.
-   */
-  int destroy;
-
-};
-
-
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GCCH_2s (const struct CadetChannel *ch)
-{
-  static char buf[128];
-
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "Channel %s:%s ctn:%X(%X/%X)",
-                   (GNUNET_YES == ch->is_loopback)
-                   ? "loopback"
-                   : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
-                   GNUNET_h2s (&ch->port),
-                   ch->ctn,
-                   (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
-                   (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
-  return buf;
-}
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_get_id (const struct CadetChannel *ch)
-{
-  return ch->ctn;
-}
-
-
-/**
- * Release memory associated with @a ccc
- *
- * @param ccc data structure to clean up
- */
-static void
-free_channel_client (struct CadetChannelClient *ccc)
-{
-  struct CadetOutOfOrderMessage *com;
-
-  while (NULL != (com = ccc->head_recv))
-  {
-    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                                 ccc->tail_recv,
-                                 com);
-    ccc->num_recv--;
-    GNUNET_MQ_discard (com->env);
-    GNUNET_free (com);
-  }
-  GNUNET_free (ccc);
-}
-
-
-/**
- * Destroy the given channel.
- *
- * @param ch channel to destroy
- */
-static void
-channel_destroy (struct CadetChannel *ch)
-{
-  struct CadetReliableMessage *crm;
-
-  while (NULL != (crm = ch->head_sent))
-  {
-    GNUNET_assert (ch == crm->ch);
-    if (NULL != crm->qe)
-    {
-      GCT_send_cancel (crm->qe);
-      crm->qe = NULL;
-    }
-    GNUNET_CONTAINER_DLL_remove (ch->head_sent,
-                                 ch->tail_sent,
-                                 crm);
-    GNUNET_free (crm->data_message);
-    GNUNET_free (crm);
-  }
-  if (NULL != ch->owner)
-  {
-    free_channel_client (ch->owner);
-    ch->owner = NULL;
-  }
-  if (NULL != ch->dest)
-  {
-    free_channel_client (ch->dest);
-    ch->dest = NULL;
-  }
-  if (NULL != ch->last_control_qe)
-  {
-    GCT_send_cancel (ch->last_control_qe);
-    ch->last_control_qe = NULL;
-  }
-  if (NULL != ch->retry_data_task)
-  {
-    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
-    ch->retry_data_task = NULL;
-  }
-  if (NULL != ch->retry_control_task)
-  {
-    GNUNET_SCHEDULER_cancel (ch->retry_control_task);
-    ch->retry_control_task = NULL;
-  }
-  if (GNUNET_NO == ch->is_loopback)
-  {
-    GCT_remove_channel (ch->t,
-                        ch,
-                        ch->ctn);
-    ch->t = NULL;
-  }
-  GNUNET_free (ch);
-}
-
-
-/**
- * Send a channel create message.
- *
- * @param cls Channel for which to send.
- */
-static void
-send_channel_open (void *cls);
-
-
-/**
- * Function called once the tunnel confirms that we sent the
- * create message.  Delays for a bit until we retry.
- *
- * @param cls our `struct CadetChannel`.
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-channel_open_sent_cb (void *cls,
-                      const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetChannel *ch = cls;
-
-  GNUNET_assert (NULL != ch->last_control_qe);
-  ch->last_control_qe = NULL;
-  ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
-       GCCH_2s (ch),
-       GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
-                                               GNUNET_YES));
-  ch->retry_control_task
-    = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
-                                    &send_channel_open,
-                                    ch);
-}
-
-
-/**
- * Send a channel open message.
- *
- * @param cls Channel for which to send.
- */
-static void
-send_channel_open (void *cls)
-{
-  struct CadetChannel *ch = cls;
-  struct GNUNET_CADET_ChannelOpenMessage msgcc;
-  uint32_t options;
-
-  ch->retry_control_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CHANNEL_OPEN message for %s\n",
-       GCCH_2s (ch));
-  options = 0;
-  if (ch->nobuffer)
-    options |= GNUNET_CADET_OPTION_NOBUFFER;
-  if (ch->reliable)
-    options |= GNUNET_CADET_OPTION_RELIABLE;
-  if (ch->out_of_order)
-    options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
-  msgcc.header.size = htons (sizeof (msgcc));
-  msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
-  msgcc.opt = htonl (options);
-  msgcc.port = ch->port;
-  msgcc.ctn = ch->ctn;
-  ch->state = CADET_CHANNEL_OPEN_SENT;
-  if (NULL != ch->last_control_qe)
-    GCT_send_cancel (ch->last_control_qe);
-  ch->last_control_qe = GCT_send (ch->t,
-                                  &msgcc.header,
-                                  &channel_open_sent_cb,
-                                  ch);
-  GNUNET_assert (NULL == ch->retry_control_task);
-}
-
-
-/**
- * Function called once and only once after a channel was bound
- * to its tunnel via #GCT_add_channel() is ready for transmission.
- * Note that this is only the case for channels that this peer
- * initiates, as for incoming channels we assume that they are
- * ready for transmission immediately upon receiving the open
- * message.  Used to bootstrap the #GCT_send() process.
- *
- * @param ch the channel for which the tunnel is now ready
- */
-void
-GCCH_tunnel_up (struct CadetChannel *ch)
-{
-  GNUNET_assert (NULL == ch->retry_control_task);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Tunnel up, sending CHANNEL_OPEN on %s now\n",
-       GCCH_2s (ch));
-  ch->retry_control_task
-    = GNUNET_SCHEDULER_add_now (&send_channel_open,
-                                ch);
-}
-
-
-/**
- * Create a new channel.
- *
- * @param owner local client owning the channel
- * @param ccn local number of this channel at the @a owner
- * @param destination peer to which we should build the channel
- * @param port desired port at @a destination
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_local_new (struct CadetClient *owner,
-                        struct GNUNET_CADET_ClientChannelNumber ccn,
-                        struct CadetPeer *destination,
-                        const struct GNUNET_HashCode *port,
-                        uint32_t options)
-{
-  struct CadetChannel *ch;
-  struct CadetChannelClient *ccco;
-
-  ccco = GNUNET_new (struct CadetChannelClient);
-  ccco->c = owner;
-  ccco->ccn = ccn;
-  ccco->client_ready = GNUNET_YES;
-
-  ch = GNUNET_new (struct CadetChannel);
-  ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
-  ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
-  ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
-  ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
-  ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
-  ch->owner = ccco;
-  ch->port = *port;
-  if (0 == memcmp (&my_full_id,
-                   GCP_get_id (destination),
-                   sizeof (struct GNUNET_PeerIdentity)))
-  {
-    struct CadetClient *c;
-
-    ch->is_loopback = GNUNET_YES;
-    c = GNUNET_CONTAINER_multihashmap_get (open_ports,
-                                           port);
-    if (NULL == c)
-    {
-      /* port closed, wait for it to possibly open */
-      ch->state = CADET_CHANNEL_LOOSE;
-      (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
-                                                port,
-                                                ch,
-                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Created loose incoming loopback channel to port %s\n",
-           GNUNET_h2s (&ch->port));
-    }
-    else
-    {
-      GCCH_bind (ch,
-                 c);
-    }
-  }
-  else
-  {
-    ch->t = GCP_get_tunnel (destination,
-                            GNUNET_YES);
-    ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
-    ch->ctn = GCT_add_channel (ch->t,
-                               ch);
-  }
-  GNUNET_STATISTICS_update (stats,
-                            "# channels",
-                            1,
-                            GNUNET_NO);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Created channel to port %s at peer %s for %s using %s\n",
-       GNUNET_h2s (port),
-       GCP_2s (destination),
-       GSC_2s (owner),
-       (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
-  return ch;
-}
-
-
-/**
- * We had an incoming channel to a port that is closed.
- * It has not been opened for a while, drop it.
- *
- * @param cls the channel to drop
- */
-static void
-timeout_closed_cb (void *cls)
-{
-  struct CadetChannel *ch = cls;
-
-  ch->retry_control_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Closing incoming channel to port %s from peer %s due to timeout\n",
-       GNUNET_h2s (&ch->port),
-       GCP_2s (GCT_get_destination (ch->t)));
-  channel_destroy (ch);
-}
-
-
-/**
- * Create a new channel based on a request coming in over the network.
- *
- * @param t tunnel to the remote peer
- * @param ctn identifier of this channel in the tunnel
- * @param port desired local port
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_incoming_new (struct CadetTunnel *t,
-                           struct GNUNET_CADET_ChannelTunnelNumber ctn,
-                           const struct GNUNET_HashCode *port,
-                           uint32_t options)
-{
-  struct CadetChannel *ch;
-  struct CadetClient *c;
-
-  ch = GNUNET_new (struct CadetChannel);
-  ch->port = *port;
-  ch->t = t;
-  ch->ctn = ctn;
-  ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
-  ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
-  ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
-  ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
-  ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
-  GNUNET_STATISTICS_update (stats,
-                            "# channels",
-                            1,
-                            GNUNET_NO);
-
-  c = GNUNET_CONTAINER_multihashmap_get (open_ports,
-                                         port);
-  if (NULL == c)
-  {
-    /* port closed, wait for it to possibly open */
-    ch->state = CADET_CHANNEL_LOOSE;
-    (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
-                                              port,
-                                              ch,
-                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-    GNUNET_assert (NULL == ch->retry_control_task);
-    ch->retry_control_task
-      = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
-                                      &timeout_closed_cb,
-                                      ch);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Created loose incoming channel to port %s from peer %s\n",
-         GNUNET_h2s (&ch->port),
-         GCP_2s (GCT_get_destination (ch->t)));
-  }
-  else
-  {
-    GCCH_bind (ch,
-               c);
-  }
-  GNUNET_STATISTICS_update (stats,
-                            "# channels",
-                            1,
-                            GNUNET_NO);
-  return ch;
-}
-
-
-/**
- * Function called once the tunnel confirms that we sent the
- * ACK message.  Just remembers it was sent, we do not expect
- * ACKs for ACKs ;-).
- *
- * @param cls our `struct CadetChannel`.
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-send_ack_cb (void *cls,
-             const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetChannel *ch = cls;
-
-  GNUNET_assert (NULL != ch->last_control_qe);
-  ch->last_control_qe = NULL;
-}
-
-
-/**
- * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
- *
- * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
- */
-static void
-send_channel_data_ack (struct CadetChannel *ch)
-{
-  struct GNUNET_CADET_ChannelDataAckMessage msg;
-
-  if (GNUNET_NO == ch->reliable)
-    return; /* no ACKs */
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
-  msg.header.size = htons (sizeof (msg));
-  msg.ctn = ch->ctn;
-  msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
-  msg.futures = GNUNET_htonll (ch->mid_futures);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending DATA_ACK %u:%llX via %s\n",
-       (unsigned int) ntohl (msg.mid.mid),
-       (unsigned long long) ch->mid_futures,
-       GCCH_2s (ch));
-  if (NULL != ch->last_control_qe)
-    GCT_send_cancel (ch->last_control_qe);
-  ch->last_control_qe = GCT_send (ch->t,
-                                  &msg.header,
-                                  &send_ack_cb,
-                                  ch);
-}
-
-
-/**
- * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
- * connection is up.
- *
- * @param cls the `struct CadetChannel`
- */
-static void
-send_open_ack (void *cls)
-{
-  struct CadetChannel *ch = cls;
-  struct GNUNET_CADET_ChannelManageMessage msg;
-
-  ch->retry_control_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CHANNEL_OPEN_ACK on %s\n",
-       GCCH_2s (ch));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
-  msg.header.size = htons (sizeof (msg));
-  msg.reserved = htonl (0);
-  msg.ctn = ch->ctn;
-  if (NULL != ch->last_control_qe)
-    GCT_send_cancel (ch->last_control_qe);
-  ch->last_control_qe = GCT_send (ch->t,
-                                  &msg.header,
-                                  &send_ack_cb,
-                                  ch);
-}
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
- * this channel.  If the binding was successful, (re)transmit the
- * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
- *
- * @param ch channel that got the duplicate open
- * @param cti identifier of the connection that delivered the message
- */
-void
-GCCH_handle_duplicate_open (struct CadetChannel *ch,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
-{
-  if (NULL == ch->dest)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
-         GCCH_2s (ch));
-    return;
-  }
-  if (NULL != ch->retry_control_task)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
-         GCCH_2s (ch));
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Retransmitting CHANNEL_OPEN_ACK on %s\n",
-       GCCH_2s (ch));
-  ch->retry_control_task
-    = GNUNET_SCHEDULER_add_now (&send_open_ack,
-                                ch);
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
- *
- * @param ch channel the ack is for
- * @param to_owner #GNUNET_YES to send to owner,
- *                 #GNUNET_NO to send to dest
- */
-static void
-send_ack_to_client (struct CadetChannel *ch,
-                    int to_owner)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalAck *ack;
-  struct CadetChannelClient *ccc;
-
-  ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
-  if (NULL == ccc)
-  {
-    /* This can happen if we are just getting ACKs after
-       our local client already disconnected. */
-    GNUNET_assert (GNUNET_YES == ch->destroy);
-    return;
-  }
-  env = GNUNET_MQ_msg (ack,
-                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
-  ack->ccn = ccc->ccn;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
-       GSC_2s (ccc->c),
-       (GNUNET_YES == to_owner) ? "owner" : "dest",
-       ntohl (ack->ccn.channel_of_client),
-       ch->pending_messages,
-       ch->max_pending_messages);
-  GSC_send_to_client (ccc->c,
-                      env);
-}
-
-
-/**
- * A client is bound to the port that we have a channel
- * open to.  Send the acknowledgement for the connection
- * request and establish the link with the client.
- *
- * @param ch open incoming channel
- * @param c client listening on the respective port
- */
-void
-GCCH_bind (struct CadetChannel *ch,
-           struct CadetClient *c)
-{
-  uint32_t options;
-  struct CadetChannelClient *cccd;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Binding %s from %s to port %s of %s\n",
-       GCCH_2s (ch),
-       GCT_2s (ch->t),
-       GNUNET_h2s (&ch->port),
-       GSC_2s (c));
-  if (NULL != ch->retry_control_task)
-  {
-    /* there might be a timeout task here */
-    GNUNET_SCHEDULER_cancel (ch->retry_control_task);
-    ch->retry_control_task = NULL;
-  }
-  options = 0;
-  if (ch->nobuffer)
-    options |= GNUNET_CADET_OPTION_NOBUFFER;
-  if (ch->reliable)
-    options |= GNUNET_CADET_OPTION_RELIABLE;
-  if (ch->out_of_order)
-    options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
-  cccd = GNUNET_new (struct CadetChannelClient);
-  GNUNET_assert (NULL == ch->dest);
-  ch->dest = cccd;
-  cccd->c = c;
-  cccd->client_ready = GNUNET_YES;
-  cccd->ccn = GSC_bind (c,
-                        ch,
-                        (GNUNET_YES == ch->is_loopback)
-                        ? GCP_get (&my_full_id,
-                                   GNUNET_YES)
-                        : GCT_get_destination (ch->t),
-                        &ch->port,
-                        options);
-  GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
-                 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-  ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
-  if (GNUNET_YES == ch->is_loopback)
-  {
-    ch->state = CADET_CHANNEL_OPEN_SENT;
-    GCCH_handle_channel_open_ack (ch,
-                                  NULL);
-  }
-  else
-  {
-    /* notify other peer that we accepted the connection */
-    ch->state = CADET_CHANNEL_READY;
-    ch->retry_control_task
-      = GNUNET_SCHEDULER_add_now (&send_open_ack,
-                                  ch);
-  }
-  /* give client it's initial supply of ACKs */
-  GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
-                 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-  for (unsigned int i=0;i<ch->max_pending_messages;i++)
-    send_ack_to_client (ch,
-                        GNUNET_NO);
-}
-
-
-/**
- * One of our clients has disconnected, tell the other one that we
- * are finished. Done asynchronously to avoid concurrent modification
- * issues if this is the same client.
- *
- * @param cls the `struct CadetChannel` where one of the ends is now dead
- */
-static void
-signal_remote_destroy_cb (void *cls)
-{
-  struct CadetChannel *ch = cls;
-  struct CadetChannelClient *ccc;
-
-  /* Find which end is left... */
-  ch->retry_control_task = NULL;
-  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
-  GSC_handle_remote_channel_destroy (ccc->c,
-                                     ccc->ccn,
-                                     ch);
-  channel_destroy (ch);
-}
-
-
-/**
- * Destroy locally created channel.  Called by the local client, so no
- * need to tell the client.
- *
- * @param ch channel to destroy
- * @param c client that caused the destruction
- * @param ccn client number of the client @a c
- */
-void
-GCCH_channel_local_destroy (struct CadetChannel *ch,
-                            struct CadetClient *c,
-                            struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s asks for destruction of %s\n",
-       GSC_2s (c),
-       GCCH_2s (ch));
-  GNUNET_assert (NULL != c);
-  if ( (NULL != ch->owner) &&
-       (c == ch->owner->c) &&
-       (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
-  {
-    free_channel_client (ch->owner);
-    ch->owner = NULL;
-  }
-  else if ( (NULL != ch->dest) &&
-            (c == ch->dest->c) &&
-            (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
-  {
-    free_channel_client (ch->dest);
-    ch->dest = NULL;
-  }
-  else
-  {
-    GNUNET_assert (0);
-  }
-
-  if (GNUNET_YES == ch->destroy)
-  {
-    /* other end already destroyed, with the local client gone, no need
-       to finish transmissions, just destroy immediately. */
-    channel_destroy (ch);
-    return;
-  }
-  if ( (NULL != ch->head_sent) &&
-       ( (NULL != ch->owner) ||
-         (NULL != ch->dest) ) )
-  {
-    /* Wait for other end to destroy us as well,
-       and otherwise allow send queue to be transmitted first */
-    ch->destroy = GNUNET_YES;
-    return;
-  }
-  if ( (GNUNET_YES == ch->is_loopback) &&
-       ( (NULL != ch->owner) ||
-         (NULL != ch->dest) ) )
-  {
-    if (NULL != ch->retry_control_task)
-      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
-    ch->retry_control_task
-      = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
-                                  ch);
-    return;
-  }
-  if (GNUNET_NO == ch->is_loopback)
-  {
-    /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
-    switch (ch->state)
-    {
-    case CADET_CHANNEL_NEW:
-      /* We gave up on a channel that we created as a client to a remote
-         target, but that never went anywhere. Nothing to do here. */
-      break;
-    case CADET_CHANNEL_LOOSE:
-      GSC_drop_loose_channel (&ch->port,
-                              ch);
-      break;
-    default:
-      GCT_send_channel_destroy (ch->t,
-                                ch->ctn);
-    }
-  }
-  /* Nothing left to do, just finish destruction */
-  channel_destroy (ch);
-}
-
-
-/**
- * We got an acknowledgement for the creation of the channel
- * (the port is open on the other side). Begin transmissions.
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message
- */
-void
-GCCH_handle_channel_open_ack (struct CadetChannel *ch,
-                              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
-{
-  switch (ch->state)
-  {
-  case CADET_CHANNEL_NEW:
-    /* this should be impossible */
-    GNUNET_break (0);
-    break;
-  case CADET_CHANNEL_LOOSE:
-    /* This makes no sense. */
-    GNUNET_break_op (0);
-    break;
-  case CADET_CHANNEL_OPEN_SENT:
-    if (NULL == ch->owner)
-    {
-      /* We're not the owner, wrong direction! */
-      GNUNET_break_op (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
-         GCCH_2s (ch));
-    if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
-    {
-      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
-      ch->retry_control_task = NULL;
-    }
-    ch->state = CADET_CHANNEL_READY;
-    /* On first connect, send client as many ACKs as we allow messages
-       to be buffered! */
-    for (unsigned int i=0;i<ch->max_pending_messages;i++)
-      send_ack_to_client (ch,
-                          GNUNET_YES);
-    break;
-  case CADET_CHANNEL_READY:
-    /* duplicate ACK, maybe we retried the CREATE. Ignore. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received duplicate channel OPEN_ACK for %s\n",
-         GCCH_2s (ch));
-    GNUNET_STATISTICS_update (stats,
-                              "# duplicate CREATE_ACKs",
-                              1,
-                              GNUNET_NO);
-    break;
-  }
-}
-
-
-/**
- * Test if element @a e1 comes before element @a e2.
- *
- * @param cls closure, to a flag where we indicate duplicate packets
- * @param m1 a message of to sort
- * @param m2 another message to sort
- * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
- */
-static int
-is_before (void *cls,
-           struct CadetOutOfOrderMessage *m1,
-           struct CadetOutOfOrderMessage *m2)
-{
-  int *duplicate = cls;
-  uint32_t v1 = ntohl (m1->mid.mid);
-  uint32_t v2 = ntohl (m2->mid.mid);
-  uint32_t delta;
-
-  delta = v2 - v1;
-  if (0 == delta)
-    *duplicate = GNUNET_YES;
-  if (delta > (uint32_t) INT_MAX)
-  {
-    /* in overflow range, we can safely assume we wrapped around */
-    return GNUNET_NO;
-  }
-  else
-  {
-    /* result is small, thus v2 > v1, thus m1 < m2 */
-    return GNUNET_YES;
-  }
-}
-
-
-/**
- * We got payload data for a channel.  Pass it on to the client
- * and send an ACK to the other end (once flow control allows it!)
- *
- * @param ch channel that got data
- * @param cti identifier of the connection that delivered the message
- * @param msg message that was received
- */
-void
-GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
-                                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                                    const struct GNUNET_CADET_ChannelAppDataMessage *msg)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_LocalData *ld;
-  struct CadetChannelClient *ccc;
-  size_t payload_size;
-  struct CadetOutOfOrderMessage *com;
-  int duplicate;
-  uint32_t mid_min;
-  uint32_t mid_max;
-  uint32_t mid_msg;
-  uint32_t delta;
-
-  GNUNET_assert (GNUNET_NO == ch->is_loopback);
-  if ( (GNUNET_YES == ch->destroy) &&
-       (NULL == ch->owner) &&
-       (NULL == ch->dest) )
-  {
-    /* This client is gone, but we still have messages to send to
-       the other end (which is why @a ch is not yet dead).  However,
-       we cannot pass messages to our client anymore. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Dropping incoming payload on %s as this end is already closed\n",
-         GCCH_2s (ch));
-    /* send back DESTROY notification to stop further retransmissions! */
-    GCT_send_channel_destroy (ch->t,
-                              ch->ctn);
-    return;
-  }
-  payload_size = ntohs (msg->header.size) - sizeof (*msg);
-  env = GNUNET_MQ_msg_extra (ld,
-                             payload_size,
-                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
-  ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
-  GNUNET_memcpy (&ld[1],
-                 &msg[1],
-                 payload_size);
-  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
-  if ( (GNUNET_YES == ccc->client_ready) &&
-       ( (GNUNET_YES == ch->out_of_order) ||
-         (msg->mid.mid == ch->mid_recv.mid) ) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Giving %u bytes of payload with MID %u from %s to client %s\n",
-         (unsigned int) payload_size,
-         ntohl (msg->mid.mid),
-         GCCH_2s (ch),
-         GSC_2s (ccc->c));
-    ccc->client_ready = GNUNET_NO;
-    GSC_send_to_client (ccc->c,
-                        env);
-    ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
-    ch->mid_futures >>= 1;
-    send_channel_data_ack (ch);
-    return;
-  }
-
-  if (GNUNET_YES == ch->reliable)
-  {
-    /* check if message ought to be dropped because it is ancient/too distant/duplicate */
-    mid_min = ntohl (ch->mid_recv.mid);
-    mid_max = mid_min + ch->max_pending_messages;
-    mid_msg = ntohl (msg->mid.mid);
-    if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
-         ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) )
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "%s at %u drops ancient or far-future message %u\n",
-           GCCH_2s (ch),
-           (unsigned int) mid_min,
-           ntohl (msg->mid.mid));
-
-      GNUNET_STATISTICS_update (stats,
-                                "# duplicate DATA (ancient or future)",
-                                1,
-                                GNUNET_NO);
-      GNUNET_MQ_discard (env);
-      send_channel_data_ack (ch);
-      return;
-    }
-    /* mark bit for future ACKs */
-    delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
-    if (delta < 64)
-    {
-      if (0 != (ch->mid_futures & (1LLU << delta)))
-      {
-        /* Duplicate within the queue, drop also */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
-             (unsigned int) payload_size,
-             GCCH_2s (ch),
-             ntohl (msg->mid.mid));
-        GNUNET_STATISTICS_update (stats,
-                                  "# duplicate DATA",
-                                  1,
-                                  GNUNET_NO);
-        GNUNET_MQ_discard (env);
-        send_channel_data_ack (ch);
-        return;
-      }
-      ch->mid_futures |= (1LLU << delta);
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Marked bit %llX for mid %u (base: %u); now: %llX\n",
-           (1LLU << delta),
-           mid_msg,
-           mid_min,
-           ch->mid_futures);
-    }
-  }
-  else /* ! ch->reliable */
-  {
-    /* Channel is unreliable, so we do not ACK. But we also cannot
-       allow buffering everything, so check if we have space... */
-    if (ccc->num_recv >= ch->max_pending_messages)
-    {
-      struct CadetOutOfOrderMessage *drop;
-
-      /* Yep, need to drop. Drop the oldest message in
-         the buffer. */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Queue full due slow client on %s, dropping oldest message\n",
-           GCCH_2s (ch));
-      GNUNET_STATISTICS_update (stats,
-                                "# messages dropped due to slow client",
-                                1,
-                                GNUNET_NO);
-      drop = ccc->head_recv;
-      GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                                   ccc->tail_recv,
-                                   drop);
-      ccc->num_recv--;
-      GNUNET_MQ_discard (drop->env);
-      GNUNET_free (drop);
-    }
-  }
-
-  /* Insert message into sorted out-of-order queue */
-  com = GNUNET_new (struct CadetOutOfOrderMessage);
-  com->mid = msg->mid;
-  com->env = env;
-  duplicate = GNUNET_NO;
-  GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
-                                      is_before,
-                                      &duplicate,
-                                      ccc->head_recv,
-                                      ccc->tail_recv,
-                                      com);
-  ccc->num_recv++;
-  if (GNUNET_YES == duplicate)
-  {
-    /* Duplicate within the queue, drop also (this is not covered by
-       the case above if "delta" >= 64, which could be the case if
-       max_pending_messages is also >= 64 or if our client is unready
-       and we are seeing retransmissions of the message our client is
-       blocked on. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
-         (unsigned int) payload_size,
-         GCCH_2s (ch),
-         ntohl (msg->mid.mid));
-    GNUNET_STATISTICS_update (stats,
-                              "# duplicate DATA",
-                              1,
-                              GNUNET_NO);
-    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                                 ccc->tail_recv,
-                                 com);
-    ccc->num_recv--;
-    GNUNET_MQ_discard (com->env);
-    GNUNET_free (com);
-    send_channel_data_ack (ch);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
-       (GNUNET_YES == ccc->client_ready)
-       ? "out-of-order"
-       : "client-not-ready",
-       (unsigned int) payload_size,
-       GCCH_2s (ch),
-       ntohl (ccc->ccn.channel_of_client),
-       ccc,
-       ntohl (msg->mid.mid),
-       ntohl (ch->mid_recv.mid));
-  /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
-     the sender may already be transmitting the previous one.  Needs
-     experimental evaluation to see if/when this ACK helps or
-     hurts. (We might even want another option.) */
-  send_channel_data_ack (ch);
-}
-
-
-/**
- * Function called once the tunnel has sent one of our messages.
- * If the message is unreliable, simply frees the `crm`. If the
- * message was reliable, calculate retransmission time and
- * wait for ACK (or retransmit).
- *
- * @param cls the `struct CadetReliableMessage` that was sent
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-data_sent_cb (void *cls,
-              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * We need to retry a transmission, the last one took too long to
- * be acknowledged.
- *
- * @param cls the `struct CadetChannel` where we need to retransmit
- */
-static void
-retry_transmission (void *cls)
-{
-  struct CadetChannel *ch = cls;
-  struct CadetReliableMessage *crm = ch->head_sent;
-
-  ch->retry_data_task = NULL;
-  GNUNET_assert (NULL == crm->qe);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Retrying transmission on %s of message %u\n",
-       GCCH_2s (ch),
-       (unsigned int) ntohl (crm->data_message->mid.mid));
-  crm->qe = GCT_send (ch->t,
-                      &crm->data_message->header,
-                      &data_sent_cb,
-                      crm);
-  GNUNET_assert (NULL == ch->retry_data_task);
-}
-
-
-/**
- * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
- * the queue and tell our client that it can send more.
- *
- * @param ch the channel that got the PLAINTEXT_DATA_ACK
- * @param cti identifier of the connection that delivered the message
- * @param crm the message that got acknowledged
- */
-static void
-handle_matching_ack (struct CadetChannel *ch,
-                     const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                     struct CadetReliableMessage *crm)
-{
-  GNUNET_CONTAINER_DLL_remove (ch->head_sent,
-                               ch->tail_sent,
-                               crm);
-  ch->pending_messages--;
-  GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
-       GCCH_2s (ch),
-       (unsigned int) ntohl (crm->data_message->mid.mid),
-       ch->pending_messages);
-  if (NULL != crm->qe)
-  {
-    GCT_send_cancel (crm->qe);
-    crm->qe = NULL;
-  }
-  if ( (1 == crm->num_transmissions) &&
-       (NULL != cti) )
-  {
-    GCC_ack_observed (cti);
-    if (0 == memcmp (cti,
-                     &crm->connection_taken,
-                     sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
-    {
-      GCC_latency_observed (cti,
-                            GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
-    }
-  }
-  GNUNET_free (crm->data_message);
-  GNUNET_free (crm);
-  send_ack_to_client (ch,
-                      (NULL == ch->owner)
-                      ? GNUNET_NO
-                      : GNUNET_YES);
-}
-
-
-/**
- * We got an acknowledgement for payload data for a channel.
- * Possibly resume transmissions.
- *
- * @param ch channel that got the ack
- * @param cti identifier of the connection that delivered the message
- * @param ack details about what was received
- */
-void
-GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
-                                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                                        const struct GNUNET_CADET_ChannelDataAckMessage *ack)
-{
-  struct CadetReliableMessage *crm;
-  struct CadetReliableMessage *crmn;
-  int found;
-  uint32_t mid_base;
-  uint64_t mid_mask;
-  unsigned int delta;
-
-  GNUNET_break (GNUNET_NO == ch->is_loopback);
-  if (GNUNET_NO == ch->reliable)
-  {
-    /* not expecting ACKs on unreliable channel, odd */
-    GNUNET_break_op (0);
-    return;
-  }
-  /* mid_base is the MID of the next message that the
-     other peer expects (i.e. that is missing!), everything
-     LOWER (but excluding mid_base itself) was received. */
-  mid_base = ntohl (ack->mid.mid);
-  mid_mask = GNUNET_htonll (ack->futures);
-  found = GNUNET_NO;
-  for (crm = ch->head_sent;
-        NULL != crm;
-       crm = crmn)
-  {
-    crmn = crm->next;
-    delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
-    if (delta >= UINT_MAX - ch->max_pending_messages)
-    {
-      /* overflow, means crm was a bit in the past, so this ACK counts for it. */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got DATA_ACK with base %u satisfying past message %u on %s\n",
-           (unsigned int) mid_base,
-           ntohl (crm->data_message->mid.mid),
-           GCCH_2s (ch));
-      handle_matching_ack (ch,
-                           cti,
-                           crm);
-      found = GNUNET_YES;
-      continue;
-    }
-    delta--;
-    if (delta >= 64)
-      continue;
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Testing bit %llX for mid %u (base: %u)\n",
-         (1LLU << delta),
-         ntohl (crm->data_message->mid.mid),
-         mid_base);
-    if (0 != (mid_mask & (1LLU << delta)))
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got DATA_ACK with mask for %u on %s\n",
-           ntohl (crm->data_message->mid.mid),
-           GCCH_2s (ch));
-      handle_matching_ack (ch,
-                           cti,
-                           crm);
-      found = GNUNET_YES;
-    }
-  }
-  if (GNUNET_NO == found)
-  {
-    /* ACK for message we already dropped, might have been a
-       duplicate ACK? Ignore. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Duplicate DATA_ACK on %s, ignoring\n",
-         GCCH_2s (ch));
-    GNUNET_STATISTICS_update (stats,
-                              "# duplicate DATA_ACKs",
-                              1,
-                              GNUNET_NO);
-    return;
-  }
-  if (NULL != ch->retry_data_task)
-  {
-    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
-    ch->retry_data_task = NULL;
-  }
-  if ( (NULL != ch->head_sent) &&
-       (NULL == ch->head_sent->qe) )
-    ch->retry_data_task
-      = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
-                                 &retry_transmission,
-                                 ch);
-}
-
-
-/**
- * Destroy channel, based on the other peer closing the
- * connection.  Also needs to remove this channel from
- * the tunnel.
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message,
- *            NULL if we are simulating receiving a destroy due to shutdown
- */
-void
-GCCH_handle_remote_destroy (struct CadetChannel *ch,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
-{
-  struct CadetChannelClient *ccc;
-
-  GNUNET_assert (GNUNET_NO == ch->is_loopback);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received remote channel DESTROY for %s\n",
-       GCCH_2s (ch));
-  if (GNUNET_YES == ch->destroy)
-  {
-    /* Local client already gone, this is instant-death. */
-    channel_destroy (ch);
-    return;
-  }
-  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
-  if ( (NULL != ccc) &&
-       (NULL != ccc->head_recv) )
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Lost end of transmission due to remote shutdown on %s\n",
-         GCCH_2s (ch));
-    /* FIXME: change API to notify client about truncated transmission! */
-  }
-  ch->destroy = GNUNET_YES;
-  if (NULL != ccc)
-    GSC_handle_remote_channel_destroy (ccc->c,
-                                       ccc->ccn,
-                                       ch);
-  channel_destroy (ch);
-}
-
-
-/**
- * Test if element @a e1 comes before element @a e2.
- *
- * @param cls closure, to a flag where we indicate duplicate packets
- * @param crm1 an element of to sort
- * @param crm2 another element to sort
- * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
- */
-static int
-cmp_crm_by_next_retry (void *cls,
-                       struct CadetReliableMessage *crm1,
-                       struct CadetReliableMessage *crm2)
-{
-  if (crm1->next_retry.abs_value_us <
-      crm2->next_retry.abs_value_us)
-    return GNUNET_YES;
-  return GNUNET_NO;
-}
-
-
-/**
- * Function called once the tunnel has sent one of our messages.
- * If the message is unreliable, simply frees the `crm`. If the
- * message was reliable, calculate retransmission time and
- * wait for ACK (or retransmit).
- *
- * @param cls the `struct CadetReliableMessage` that was sent
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-data_sent_cb (void *cls,
-              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetReliableMessage *crm = cls;
-  struct CadetChannel *ch = crm->ch;
-
-  GNUNET_assert (GNUNET_NO == ch->is_loopback);
-  GNUNET_assert (NULL != crm->qe);
-  crm->qe = NULL;
-  GNUNET_CONTAINER_DLL_remove (ch->head_sent,
-                               ch->tail_sent,
-                               crm);
-  if (GNUNET_NO == ch->reliable)
-  {
-    GNUNET_free (crm->data_message);
-    GNUNET_free (crm);
-    ch->pending_messages--;
-    send_ack_to_client (ch,
-                        (NULL == ch->owner)
-                        ? GNUNET_NO
-                        : GNUNET_YES);
-    return;
-  }
-  if (NULL == cid)
-  {
-    /* There was an error sending. */
-    crm->num_transmissions = GNUNET_SYSERR;
-  }
-  else if (GNUNET_SYSERR != crm->num_transmissions)
-  {
-    /* Increment transmission counter, and possibly store @a cid
-       if this was the first transmission. */
-    crm->num_transmissions++;
-    if (1 == crm->num_transmissions)
-    {
-      crm->first_transmission_time = GNUNET_TIME_absolute_get ();
-      crm->connection_taken = *cid;
-      GCC_ack_expected (cid);
-    }
-  }
-  if ( (0 == crm->retry_delay.rel_value_us) &&
-       (NULL != cid) )
-  {
-    struct CadetConnection *cc = GCC_lookup (cid);
-
-    if (NULL != cc)
-      crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
-    else
-      crm->retry_delay = ch->retry_time;
-  }
-  crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
-  crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
-                                               MIN_RTT_DELAY);
-  crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
-
-  GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
-                                      cmp_crm_by_next_retry,
-                                      NULL,
-                                      ch->head_sent,
-                                      ch->tail_sent,
-                                      crm);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Message %u sent, next transmission on %s in %s\n",
-       (unsigned int) ntohl (crm->data_message->mid.mid),
-       GCCH_2s (ch),
-       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
-                                               GNUNET_YES));
-  if (NULL == ch->head_sent->qe)
-  {
-    if (NULL != ch->retry_data_task)
-      GNUNET_SCHEDULER_cancel (ch->retry_data_task);
-    ch->retry_data_task
-      = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
-                                 &retry_transmission,
-                                 ch);
-  }
-}
-
-
-/**
- * Handle data given by a client.
- *
- * Check whether the client is allowed to send in this tunnel, save if
- * channel is reliable and send an ACK to the client if there is still
- * buffer space in the tunnel.
- *
- * @param ch Channel.
- * @param sender_ccn ccn of the sender
- * @param buf payload to transmit.
- * @param buf_len number of bytes in @a buf
- * @return #GNUNET_OK if everything goes well,
- *         #GNUNET_SYSERR in case of an error.
- */
-int
-GCCH_handle_local_data (struct CadetChannel *ch,
-                        struct GNUNET_CADET_ClientChannelNumber sender_ccn,
-                        const char *buf,
-                        size_t buf_len)
-{
-  struct CadetReliableMessage *crm;
-
-  if (ch->pending_messages > ch->max_pending_messages)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  if (GNUNET_YES == ch->destroy)
-  {
-    /* we are going down, drop messages */
-    return GNUNET_OK;
-  }
-  ch->pending_messages++;
-
-  if (GNUNET_YES == ch->is_loopback)
-  {
-    struct CadetChannelClient *receiver;
-    struct GNUNET_MQ_Envelope *env;
-    struct GNUNET_CADET_LocalData *ld;
-    int ack_to_owner;
-
-    env = GNUNET_MQ_msg_extra (ld,
-                               buf_len,
-                               GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
-    if ( (NULL != ch->owner) &&
-         (sender_ccn.channel_of_client ==
-          ch->owner->ccn.channel_of_client) )
-    {
-      receiver = ch->dest;
-      ack_to_owner = GNUNET_YES;
-    }
-    else if ( (NULL != ch->dest) &&
-              (sender_ccn.channel_of_client ==
-               ch->dest->ccn.channel_of_client) )
-    {
-      receiver = ch->owner;
-      ack_to_owner = GNUNET_NO;
-    }
-    else
-    {
-      GNUNET_break (0);
-      return GNUNET_SYSERR;
-    }
-    ld->ccn = receiver->ccn;
-    GNUNET_memcpy (&ld[1],
-                   buf,
-                   buf_len);
-    if (GNUNET_YES == receiver->client_ready)
-    {
-      ch->pending_messages--;
-      GSC_send_to_client (receiver->c,
-                          env);
-      send_ack_to_client (ch,
-                          ack_to_owner);
-    }
-    else
-    {
-      struct CadetOutOfOrderMessage *oom;
-
-      oom = GNUNET_new (struct CadetOutOfOrderMessage);
-      oom->env = env;
-      GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
-                                        receiver->tail_recv,
-                                        oom);
-      receiver->num_recv++;
-    }
-    return GNUNET_OK;
-  }
-
-  /* Everything is correct, send the message. */
-  crm = GNUNET_malloc (sizeof (*crm));
-  crm->ch = ch;
-  crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
-                                     + buf_len);
-  crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
-  crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
-  ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
-  crm->data_message->mid = ch->mid_send;
-  crm->data_message->ctn = ch->ctn;
-  GNUNET_memcpy (&crm->data_message[1],
-                 buf,
-                 buf_len);
-  GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
-                                    ch->tail_sent,
-                                    crm);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending message %u from local client to %s with %u bytes\n",
-       ntohl (crm->data_message->mid.mid),
-       GCCH_2s (ch),
-       buf_len);
-  if (NULL != ch->retry_data_task)
-  {
-    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
-    ch->retry_data_task = NULL;
-  }
-  crm->qe = GCT_send (ch->t,
-                      &crm->data_message->header,
-                      &data_sent_cb,
-                      crm);
-  GNUNET_assert (NULL == ch->retry_data_task);
-  return GNUNET_OK;
-}
-
-
-/**
- * Handle ACK from client on local channel.  Means the client is ready
- * for more data, see if we have any for it.
- *
- * @param ch channel to destroy
- * @param client_ccn ccn of the client sending the ack
- */
-void
-GCCH_handle_local_ack (struct CadetChannel *ch,
-                       struct GNUNET_CADET_ClientChannelNumber client_ccn)
-{
-  struct CadetChannelClient *ccc;
-  struct CadetOutOfOrderMessage *com;
-
-  if ( (NULL != ch->owner) &&
-       (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
-    ccc = ch->owner;
-  else if ( (NULL != ch->dest) &&
-            (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
-    ccc = ch->dest;
-  else
-    GNUNET_assert (0);
-  ccc->client_ready = GNUNET_YES;
-  com = ccc->head_recv;
-  if (NULL == com)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
-         GSC_2s (ccc->c),
-         ntohl (client_ccn.channel_of_client),
-         GCCH_2s (ch),
-         ntohl (ccc->ccn.channel_of_client),
-         ccc);
-    return; /* none pending */
-  }
-  if (GNUNET_YES == ch->is_loopback)
-  {
-    int to_owner;
-
-    /* Messages are always in-order, just send */
-    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                                 ccc->tail_recv,
-                                 com);
-    ccc->num_recv--;
-    GSC_send_to_client (ccc->c,
-                        com->env);
-    /* Notify sender that we can receive more */
-    if (ccc->ccn.channel_of_client ==
-        ch->owner->ccn.channel_of_client)
-    {
-      to_owner = GNUNET_NO;
-    }
-    else
-    {
-      GNUNET_assert (ccc->ccn.channel_of_client ==
-                     ch->dest->ccn.channel_of_client);
-      to_owner = GNUNET_YES;
-    }
-    send_ack_to_client (ch,
-                        to_owner);
-    GNUNET_free (com);
-    return;
-  }
-
-  if ( (com->mid.mid != ch->mid_recv.mid) &&
-       (GNUNET_NO == ch->out_of_order) &&
-       (GNUNET_YES == ch->reliable) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
-         GSC_2s (ccc->c),
-         ntohl (ccc->ccn.channel_of_client),
-         ntohl (com->mid.mid),
-         ntohl (ch->mid_recv.mid));
-    return; /* missing next one in-order */
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
-       ntohl (com->mid.mid),
-       GSC_2s (ccc->c),
-       ntohl (ccc->ccn.channel_of_client),
-       GCCH_2s (ch));
-
-  /* all good, pass next message to client */
-  GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
-                               ccc->tail_recv,
-                               com);
-  ccc->num_recv--;
-  /* FIXME: if unreliable, this is not aggressive
-     enough, as it would be OK to have lost some! */
-
-  ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
-  ch->mid_futures >>= 1; /* equivalent to division by 2 */
-  ccc->client_ready = GNUNET_NO;
-  GSC_send_to_client (ccc->c,
-                      com->env);
-  GNUNET_free (com);
-  send_channel_data_ack (ch);
-  if (NULL != ccc->head_recv)
-    return;
-  if (GNUNET_NO == ch->destroy)
-    return;
-  GCT_send_channel_destroy (ch->t,
-                            ch->ctn);
-  channel_destroy (ch);
-}
-
-
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
-
-
-/**
- * Log channel info.
- *
- * @param ch Channel.
- * @param level Debug level to use.
- */
-void
-GCCH_debug (struct CadetChannel *ch,
-            enum GNUNET_ErrorType level)
-{
-  int do_log;
-
-  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
-                                       "cadet-chn",
-                                       __FILE__, __FUNCTION__, __LINE__);
-  if (0 == do_log)
-    return;
-
-  if (NULL == ch)
-  {
-    LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
-    return;
-  }
-  LOG2 (level,
-        "CHN %s:%X (%p)\n",
-        GCT_2s (ch->t),
-        ch->ctn,
-        ch);
-  if (NULL != ch->owner)
-  {
-    LOG2 (level,
-          "CHN origin %s ready %s local-id: %u\n",
-          GSC_2s (ch->owner->c),
-          ch->owner->client_ready ? "YES" : "NO",
-          ntohl (ch->owner->ccn.channel_of_client));
-  }
-  if (NULL != ch->dest)
-  {
-    LOG2 (level,
-          "CHN destination %s ready %s local-id: %u\n",
-          GSC_2s (ch->dest->c),
-          ch->dest->client_ready ? "YES" : "NO",
-          ntohl (ch->dest->ccn.channel_of_client));
-  }
-  LOG2 (level,
-        "CHN  Message IDs recv: %d (%LLX), send: %d\n",
-        ntohl (ch->mid_recv.mid),
-        (unsigned long long) ch->mid_futures,
-        ntohl (ch->mid_send.mid));
-}
-
-
-
-/* end of gnunet-service-cadet-new_channel.c */
diff --git a/src/cadet/gnunet-service-cadet-new_channel.h b/src/cadet/gnunet-service-cadet-new_channel.h
deleted file mode 100644 (file)
index 5167305..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_channel.h
- * @brief GNUnet CADET service with encryption
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
-#define GNUNET_SERVICE_CADET_CHANNEL_H
-
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "cadet_protocol.h"
-
-
-/**
- * A channel is a bidirectional connection between two CADET
- * clients.  Communiation can be reliable, unreliable, in-order
- * or out-of-order.  One client is the "local" client, this
- * one initiated the connection.   The other client is the
- * "incoming" client, this one listened on a port to accept
- * the connection from the "local" client.
- */
-struct CadetChannel;
-
-
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GCCH_2s (const struct CadetChannel *ch);
-
-
-/**
- * Log channel info.
- *
- * @param ch Channel.
- * @param level Debug level to use.
- */
-void
-GCCH_debug (struct CadetChannel *ch,
-            enum GNUNET_ErrorType level);
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_get_id (const struct CadetChannel *ch);
-
-
-/**
- * Create a new channel.
- *
- * @param owner local client owning the channel
- * @param owner_id local chid of this channel at the @a owner
- * @param destination peer to which we should build the channel
- * @param port desired port at @a destination
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_local_new (struct CadetClient *owner,
-                        struct GNUNET_CADET_ClientChannelNumber owner_id,
-                        struct CadetPeer *destination,
-                        const struct GNUNET_HashCode *port,
-                        uint32_t options);
-
-
-/**
- * A client is bound to the port that we have a channel
- * open to.  Send the acknowledgement for the connection
- * request and establish the link with the client.
- *
- * @param ch open incoming channel
- * @param c client listening on the respective port
- */
-void
-GCCH_bind (struct CadetChannel *ch,
-           struct CadetClient *c);
-
-
-/**
- * Destroy locally created channel.  Called by the
- * local client, so no need to tell the client.
- *
- * @param ch channel to destroy
- * @param c client that caused the destruction
- * @param ccn client number of the client @a c
- */
-void
-GCCH_channel_local_destroy (struct CadetChannel *ch,
-                            struct CadetClient *c,
-                            struct GNUNET_CADET_ClientChannelNumber ccn);
-
-
-/**
- * Function called once and only once after a channel was bound
- * to its tunnel via #GCT_add_channel() is ready for transmission.
- * Note that this is only the case for channels that this peer
- * initiates, as for incoming channels we assume that they are
- * ready for transmission immediately upon receiving the open
- * message.  Used to bootstrap the #GCT_send() process.
- *
- * @param ch the channel for which the tunnel is now ready
- */
-void
-GCCH_tunnel_up (struct CadetChannel *ch);
-
-
-/**
- * Create a new channel based on a request coming in over the network.
- *
- * @param t tunnel to the remote peer
- * @param chid identifier of this channel in the tunnel
- * @param origin peer to who initiated the channel
- * @param port desired local port
- * @param options options for the channel
- * @return handle to the new channel
- */
-struct CadetChannel *
-GCCH_channel_incoming_new (struct CadetTunnel *t,
-                           struct GNUNET_CADET_ChannelTunnelNumber chid,
-                           const struct GNUNET_HashCode *port,
-                           uint32_t options);
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
- * this channel.  If the binding was successful, (re)transmit the
- * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
- *
- * @param ch channel that got the duplicate open
- * @param cti identifier of the connection that delivered the message
- */
-void
-GCCH_handle_duplicate_open (struct CadetChannel *ch,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-
-
-
-/**
- * We got payload data for a channel.  Pass it on to the client.
- *
- * @param ch channel that got data
- * @param cti identifier of the connection that delivered the message
- * @param msg message that was received
- */
-void
-GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
-                                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                                    const struct GNUNET_CADET_ChannelAppDataMessage *msg);
-
-
-/**
- * We got an acknowledgement for payload data for a channel.
- * Possibly resume transmissions.
- *
- * @param ch channel that got the ack
- * @param cti identifier of the connection that delivered the message
- * @param ack details about what was received
- */
-void
-GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
-                                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                                        const struct GNUNET_CADET_ChannelDataAckMessage *ack);
-
-
-/**
- * We got an acknowledgement for the creation of the channel
- * (the port is open on the other side). Begin transmissions.
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message,
- *        NULL if the ACK was inferred because we got payload or are on loopback
- */
-void
-GCCH_handle_channel_open_ack (struct CadetChannel *ch,
-                              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-
-
-/**
- * Destroy channel, based on the other peer closing the
- * connection.  Also needs to remove this channel from
- * the tunnel.
- *
- * FIXME: need to make it possible to defer destruction until we have
- * received all messages up to the destroy, and right now the destroy
- * message (and this API) fails to give is the information we need!
- *
- * FIXME: also need to know if the other peer got a destroy from
- * us before!
- *
- * @param ch channel to destroy
- * @param cti identifier of the connection that delivered the message,
- *            NULL during shutdown
- */
-void
-GCCH_handle_remote_destroy (struct CadetChannel *ch,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
-
-
-/**
- * Handle data given by a client.
- *
- * Check whether the client is allowed to send in this tunnel, save if
- * channel is reliable and send an ACK to the client if there is still
- * buffer space in the tunnel.
- *
- * @param ch Channel.
- * @param sender_ccn ccn of the sender
- * @param buf payload to transmit.
- * @param buf_len number of bytes in @a buf
- * @return #GNUNET_OK if everything goes well,
- *         #GNUNET_SYSERR in case of an error.
- */
-int
-GCCH_handle_local_data (struct CadetChannel *ch,
-                        struct GNUNET_CADET_ClientChannelNumber sender_ccn,
-                        const char *buf,
-                        size_t buf_len);
-
-
-/**
- * Handle ACK from client on local channel.
- *
- * @param ch channel to destroy
- * @param client_ccn ccn of the client sending the ack
- */
-void
-GCCH_handle_local_ack (struct CadetChannel *ch,
-                       struct GNUNET_CADET_ClientChannelNumber client_ccn);
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_connection.c b/src/cadet/gnunet-service-cadet-new_connection.c
deleted file mode 100644 (file)
index 6976e66..0000000
+++ /dev/null
@@ -1,1093 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_connection.c
- * @brief management of CORE-level end-to-end connections; establishes
- *        end-to-end routes and transmits messages along the route
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_channel.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_paths.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet_cadet_service.h"
-#include "gnunet_statistics_service.h"
-#include "cadet_protocol.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__)
-
-
-/**
- * All the states a connection can be in.
- */
-enum CadetConnectionState
-{
-  /**
-   * Uninitialized status, we have not yet even gotten the message queue.
-   */
-  CADET_CONNECTION_NEW,
-
-  /**
-   * Connection create message in queue, awaiting transmission by CORE.
-   */
-  CADET_CONNECTION_SENDING_CREATE,
-
-  /**
-   * Connection create message sent, waiting for ACK.
-   */
-  CADET_CONNECTION_SENT,
-
-  /**
-   * We are an inbound connection, and received a CREATE. Need to
-   * send an CREATE_ACK back.
-   */
-  CADET_CONNECTION_CREATE_RECEIVED,
-
-  /**
-   * Connection confirmed, ready to carry traffic.
-   */
-  CADET_CONNECTION_READY
-
-};
-
-
-/**
- * Low-level connection to a destination.
- */
-struct CadetConnection
-{
-
-  /**
-   * ID of the connection.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
-  /**
-   * To which peer does this connection go?
-   */
-  struct CadetPeer *destination;
-
-  /**
-   * Which tunnel is using this connection?
-   */
-  struct CadetTConnection *ct;
-
-  /**
-   * Path we are using to our destination.
-   */
-  struct CadetPeerPath *path;
-
-  /**
-   * Pending message, NULL if we are ready to transmit.
-   */
-  struct GNUNET_MQ_Envelope *env;
-
-  /**
-   * Handle for calling #GCP_request_mq_cancel() once we are finished.
-   */
-  struct GCP_MessageQueueManager *mq_man;
-
-  /**
-   * Task for connection maintenance.
-   */
-  struct GNUNET_SCHEDULER_Task *task;
-
-  /**
-   * Queue entry for keepalive messages.
-   */
-  struct CadetTunnelQueueEntry *keepalive_qe;
-
-  /**
-   * Function to call once we are ready to transmit.
-   */
-  GCC_ReadyCallback ready_cb;
-
-  /**
-   * Closure for @e ready_cb.
-   */
-  void *ready_cb_cls;
-
-  /**
-   * How long do we wait before we try again with a CREATE message?
-   */
-  struct GNUNET_TIME_Relative retry_delay;
-
-  /**
-   * Performance metrics for this connection.
-   */
-  struct CadetConnectionMetrics metrics;
-
-  /**
-   * State of the connection.
-   */
-  enum CadetConnectionState state;
-
-  /**
-   * Options for the route, control buffering.
-   */
-  enum GNUNET_CADET_ChannelOption options;
-
-  /**
-   * How many latency observations did we make for this connection?
-   */
-  unsigned int latency_datapoints;
-
-  /**
-   * Offset of our @e destination in @e path.
-   */
-  unsigned int off;
-
-  /**
-   * Are we ready to transmit via @e mq_man right now?
-   */
-  int mqm_ready;
-
-};
-
-
-/**
- * Lookup a connection by its identifier.
- *
- * @param cid identifier to resolve
- * @return NULL if connection was not found
- */
-struct CadetConnection *
-GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  return GNUNET_CONTAINER_multishortmap_get (connections,
-                                             &cid->connection_of_tunnel);
-}
-
-
-/**
- * Update the connection state. Also triggers the necessary
- * MQM notifications.
- *
- * @param cc connection to update the state for
- * @param new_state new state for @a cc
- * @param new_mqm_ready new `mqm_ready` state for @a cc
- */
-static void
-update_state (struct CadetConnection *cc,
-              enum CadetConnectionState new_state,
-              int new_mqm_ready)
-{
-  int old_ready;
-  int new_ready;
-
-  if ( (new_state == cc->state) &&
-       (new_mqm_ready == cc->mqm_ready) )
-    return; /* no change, nothing to do */
-  old_ready = ( (CADET_CONNECTION_READY == cc->state) &&
-                (GNUNET_YES == cc->mqm_ready) );
-  new_ready = ( (CADET_CONNECTION_READY == new_state) &&
-                (GNUNET_YES == new_mqm_ready) );
-  cc->state = new_state;
-  cc->mqm_ready = new_mqm_ready;
-  if (old_ready != new_ready)
-    cc->ready_cb (cc->ready_cb_cls,
-                  new_ready);
-}
-
-
-/**
- * Destroy a connection, part of the internal implementation.  Called
- * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel().
- *
- * @param cc connection to destroy
- */
-static void
-GCC_destroy (struct CadetConnection *cc)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying %s\n",
-       GCC_2s (cc));
-  if (NULL != cc->mq_man)
-  {
-    GCP_request_mq_cancel (cc->mq_man,
-                           NULL);
-    cc->mq_man = NULL;
-  }
-  if (NULL != cc->task)
-  {
-    GNUNET_SCHEDULER_cancel (cc->task);
-    cc->task = NULL;
-  }
-  if (NULL != cc->keepalive_qe)
-  {
-    GCT_send_cancel (cc->keepalive_qe);
-    cc->keepalive_qe = NULL;
-  }
-  GCPP_del_connection (cc->path,
-                       cc->off,
-                       cc);
-  for (unsigned int i=0;i<cc->off;i++)
-    GCP_remove_connection (GCPP_get_peer_at_offset (cc->path,
-                                                    i),
-                           cc);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multishortmap_remove (connections,
-                                                        &GCC_get_id (cc)->connection_of_tunnel,
-                                                        cc));
-  GNUNET_free (cc);
-}
-
-
-
-/**
- * Destroy a connection, called when the CORE layer is already done
- * (i.e. has received a BROKEN message), but if we still have to
- * communicate the destruction of the connection to the tunnel (if one
- * exists).
- *
- * @param cc connection to destroy
- */
-void
-GCC_destroy_without_core (struct CadetConnection *cc)
-{
-  if (NULL != cc->ct)
-  {
-    GCT_connection_lost (cc->ct);
-    cc->ct = NULL;
-  }
-  GCC_destroy (cc);
-}
-
-
-/**
- * Destroy a connection, called if the tunnel association with the
- * connection was already broken, but we still need to notify the CORE
- * layer about the breakage.
- *
- * @param cc connection to destroy
- */
-void
-GCC_destroy_without_tunnel (struct CadetConnection *cc)
-{
-  cc->ct = NULL;
-  if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) &&
-       (NULL != cc->mq_man) )
-  {
-    struct GNUNET_MQ_Envelope *env;
-    struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
-
-    /* Need to notify next hop that we are down. */
-    env = GNUNET_MQ_msg (destroy_msg,
-                         GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
-    destroy_msg->cid = cc->cid;
-    GCP_request_mq_cancel (cc->mq_man,
-                           env);
-    cc->mq_man = NULL;
-  }
-  GCC_destroy (cc);
-}
-
-
-/**
- * Return the tunnel associated with this connection.
- *
- * @param cc connection to query
- * @return corresponding entry in the tunnel's connection list
- */
-struct CadetTConnection *
-GCC_get_ct (struct CadetConnection *cc)
-{
-  return cc->ct;
-}
-
-
-/**
- * Obtain performance @a metrics from @a cc.
- *
- * @param cc connection to query
- * @return the metrics
- */
-const struct CadetConnectionMetrics *
-GCC_get_metrics (struct CadetConnection *cc)
-{
-  return &cc->metrics;
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
- * tunnel to prevent it from timing out.
- *
- * @param cls the `struct CadetConnection` to keep alive.
- */
-static void
-send_keepalive (void *cls);
-
-
-/**
- * Keepalive was transmitted.  Remember this, and possibly
- * schedule the next one.
- *
- * @param cls the `struct CadetConnection` to keep alive.
- * @param cid identifier of the connection within the tunnel, NULL
- *            if transmission failed
- */
-static void
-keepalive_done (void *cls,
-                const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetConnection *cc = cls;
-
-  cc->keepalive_qe = NULL;
-  if ( (GNUNET_YES == cc->mqm_ready) &&
-       (NULL == cc->task) )
-    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
-                                             &send_keepalive,
-                                             cc);
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
- * tunnel to prevent it from timing out.
- *
- * @param cls the `struct CadetConnection` to keep alive.
- */
-static void
-send_keepalive (void *cls)
-{
-  struct CadetConnection *cc = cls;
-  struct GNUNET_MessageHeader msg;
-
-  cc->task = NULL;
-  if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t))
-  {
-    /* Tunnel not yet ready, wait with keepalives... */
-    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
-                                             &send_keepalive,
-                                             cc);
-    return;
-  }
-  GNUNET_assert (NULL != cc->ct);
-  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
-  GNUNET_assert (NULL == cc->keepalive_qe);
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Sending KEEPALIVE on behalf of %s via %s\n",
-       GCC_2s (cc),
-       GCT_2s (cc->ct->t));
-  GNUNET_STATISTICS_update (stats,
-                            "# keepalives sent",
-                            1,
-                            GNUNET_NO);
-  msg.size = htons (sizeof (msg));
-  msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
-
-  cc->keepalive_qe
-    = GCT_send (cc->ct->t,
-                &msg,
-                &keepalive_done,
-                cc);
-}
-
-
-/**
- * We sent a message for which we expect to receive an ACK via
- * the connection identified by @a cti.
- *
- * @param cid connection identifier where we expect an ACK
- */
-void
-GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetConnection *cc;
-
-  cc = GCC_lookup (cid);
-  if (NULL == cc)
-    return; /* whopise, connection alredy down? */
-  cc->metrics.num_acked_transmissions++;
-}
-
-
-/**
- * We observed an ACK for a message that was originally sent via
- * the connection identified by @a cti.
- *
- * @param cti connection identifier where we got an ACK for a message
- *            that was originally sent via this connection (the ACK
- *            may have gotten back to us via a different connection).
- */
-void
-GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  struct CadetConnection *cc;
-
-  cc = GCC_lookup (cid);
-  if (NULL == cc)
-    return; /* whopise, connection alredy down? */
-  cc->metrics.num_successes++;
-}
-
-
-/**
- * We observed some the given @a latency on the connection
- * identified by @a cti.  (The same connection was taken
- * in both directions.)
- *
- * @param cid connection identifier where we measured latency
- * @param latency the observed latency
- */
-void
-GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                      struct GNUNET_TIME_Relative latency)
-{
-  struct CadetConnection *cc;
-  double weight;
-  double result;
-
-  cc = GCC_lookup (cid);
-  if (NULL == cc)
-    return; /* whopise, connection alredy down? */
-  GNUNET_STATISTICS_update (stats,
-                            "# latencies observed",
-                            1,
-                            GNUNET_NO);
-  cc->latency_datapoints++;
-  if (cc->latency_datapoints >= 7)
-    weight = 7.0;
-  else
-    weight = cc->latency_datapoints;
-  /* Compute weighted average, giving at MOST weight 7 to the
-     existing values, or less if that value is based on fewer than 7
-     measurements. */
-  result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us;
-  result /= (weight + 1.0);
-  cc->metrics.aged_latency.rel_value_us = (uint64_t) result;
-}
-
-
-/**
- * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying
- * that the end-to-end connection is up.  Process it.
- *
- * @param cc the connection that got the ACK.
- */
-void
-GCC_handle_connection_create_ack (struct CadetConnection *cc)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
-       GCC_2s (cc),
-       cc->state,
-       (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
-  if (CADET_CONNECTION_READY == cc->state)
-    return; /* Duplicate ACK, ignore */
-  if (NULL != cc->task)
-  {
-    GNUNET_SCHEDULER_cancel (cc->task);
-    cc->task = NULL;
-  }
-  cc->metrics.age = GNUNET_TIME_absolute_get ();
-  update_state (cc,
-                CADET_CONNECTION_READY,
-                cc->mqm_ready);
-  if ( (NULL == cc->keepalive_qe) &&
-       (GNUNET_YES == cc->mqm_ready) &&
-       (NULL == cc->task) )
-    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
-                                             &send_keepalive,
-                                             cc);
-}
-
-
-/**
- * Handle KX message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx (struct CadetConnection *cc,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
-{
-  if (CADET_CONNECTION_SENT == cc->state)
-  {
-    /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
-       clearly something is working, so pretend we got an ACK. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
-         GCC_2s (cc));
-    GCC_handle_connection_create_ack (cc);
-  }
-  GCT_handle_kx (cc->ct,
-                 msg);
-}
-
-
-/**
- * Handle KX_AUTH message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx_auth (struct CadetConnection *cc,
-                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
-{
-  if (CADET_CONNECTION_SENT == cc->state)
-  {
-    /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
-       clearly something is working, so pretend we got an ACK. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
-         GCC_2s (cc));
-    GCC_handle_connection_create_ack (cc);
-  }
-  GCT_handle_kx_auth (cc->ct,
-                      msg);
-}
-
-
-/**
- * Handle encrypted message.
- *
- * @param cc connection that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCC_handle_encrypted (struct CadetConnection *cc,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  if (CADET_CONNECTION_SENT == cc->state)
-  {
-    /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
-       clearly something is working, so pretend we got an ACK. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Faking connection ACK for %s due to ENCRYPTED payload\n",
-         GCC_2s (cc));
-    GCC_handle_connection_create_ack (cc);
-  }
-  cc->metrics.last_use = GNUNET_TIME_absolute_get ();
-  GCT_handle_encrypted (cc->ct,
-                        msg);
-}
-
-
-/**
- * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
- * first hop.
- *
- * @param cls the `struct CadetConnection` to initiate
- */
-static void
-send_create (void *cls)
-{
-  struct CadetConnection *cc = cls;
-  struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
-  struct GNUNET_PeerIdentity *pids;
-  struct GNUNET_MQ_Envelope *env;
-  unsigned int path_length;
-
-  cc->task = NULL;
-  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
-  path_length = GCPP_get_length (cc->path);
-  env = GNUNET_MQ_msg_extra (create_msg,
-                             (1 + path_length) * sizeof (struct GNUNET_PeerIdentity),
-                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
-  create_msg->options = htonl ((uint32_t) cc->options);
-  create_msg->cid = cc->cid;
-  pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
-  pids[0] = my_full_id;
-  for (unsigned int i=0;i<path_length;i++)
-    pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
-                                                        i));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CADET_CONNECTION_CREATE message for %s\n",
-       GCC_2s (cc));
-  cc->env = env;
-  update_state (cc,
-                CADET_CONNECTION_SENT,
-                GNUNET_NO);
-  GCP_send (cc->mq_man,
-            env);
-}
-
-
-/**
- * Send a CREATE_ACK message towards the origin.
- *
- * @param cls the `struct CadetConnection` to initiate
- */
-static void
-send_create_ack (void *cls)
-{
-  struct CadetConnection *cc = cls;
-  struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg;
-  struct GNUNET_MQ_Envelope *env;
-
-  cc->task = NULL;
-  GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending CONNECTION_CREATE_ACK message for %s\n",
-       GCC_2s (cc));
-  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
-  env = GNUNET_MQ_msg (ack_msg,
-                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK);
-  ack_msg->cid = cc->cid;
-  cc->env = env;
-  update_state (cc,
-                CADET_CONNECTION_READY,
-                GNUNET_NO);
-  GCP_send (cc->mq_man,
-            env);
-}
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
- * connection that we already have.  Either our ACK got lost
- * or something is fishy.  Consider retransmitting the ACK.
- *
- * @param cc connection that got the duplicate CREATE
- */
-void
-GCC_handle_duplicate_create (struct CadetConnection *cc)
-{
-  if (GNUNET_YES == cc->mqm_ready)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got duplicate CREATE for %s, scheduling another ACK (%s)\n",
-         GCC_2s (cc),
-         (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
-    /* Revert back to the state of having only received the 'CREATE',
-       and immediately proceed to send the CREATE_ACK. */
-    update_state (cc,
-                  CADET_CONNECTION_CREATE_RECEIVED,
-                  cc->mqm_ready);
-    if (NULL != cc->task)
-      GNUNET_SCHEDULER_cancel (cc->task);
-    cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
-                                         cc);
-  }
-  else
-  {
-    /* We are currently sending something else back, which
-       can only be an ACK or payload, either of which would
-       do. So actually no need to do anything. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n",
-         GCC_2s (cc));
-  }
-}
-
-
-/**
- * There has been a change in the message queue existence for our
- * peer at the first hop.  Adjust accordingly.
- *
- * @param cls the `struct CadetConnection`
- * @param available #GNUNET_YES if sending is now possible,
- *                  #GNUNET_NO if sending is no longer possible
- *                  #GNUNET_SYSERR if sending is no longer possible
- *                                 and the last envelope was discarded
- */
-static void
-manage_first_hop_mq (void *cls,
-                     int available)
-{
-  struct CadetConnection *cc = cls;
-
-  if (GNUNET_YES != available)
-  {
-    /* Connection is down, for now... */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Core MQ for %s went down\n",
-         GCC_2s (cc));
-    update_state (cc,
-                  CADET_CONNECTION_NEW,
-                  GNUNET_NO);
-    cc->retry_delay = GNUNET_TIME_UNIT_ZERO;
-    if (NULL != cc->task)
-    {
-      GNUNET_SCHEDULER_cancel (cc->task);
-      cc->task = NULL;
-    }
-    return;
-  }
-
-  update_state (cc,
-                cc->state,
-                GNUNET_YES);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Core MQ for %s became available in state %d\n",
-       GCC_2s (cc),
-       cc->state);
-  switch (cc->state)
-  {
-  case CADET_CONNECTION_NEW:
-    /* Transmit immediately */
-    cc->task = GNUNET_SCHEDULER_add_now (&send_create,
-                                         cc);
-    break;
-  case CADET_CONNECTION_SENDING_CREATE:
-    /* Should not be possible to be called in this state. */
-    GNUNET_assert (0);
-    break;
-  case CADET_CONNECTION_SENT:
-    /* Retry a bit later... */
-    cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
-    cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
-                                             &send_create,
-                                             cc);
-    break;
-  case CADET_CONNECTION_CREATE_RECEIVED:
-    /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
-    cc->metrics.age = GNUNET_TIME_absolute_get ();
-    cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
-                                         cc);
-    break;
-  case CADET_CONNECTION_READY:
-    if ( (NULL == cc->keepalive_qe) &&
-         (GNUNET_YES == cc->mqm_ready) &&
-         (NULL == cc->task) )
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Scheduling keepalive for %s in %s\n",
-           GCC_2s (cc),
-           GNUNET_STRINGS_relative_time_to_string (keepalive_period,
-                                                   GNUNET_YES));
-      cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
-                                               &send_keepalive,
-                                               cc);
-    }
-    break;
-  }
-}
-
-
-/**
- * Create a connection to @a destination via @a path and notify @a cb
- * whenever we are ready for more data.  Shared logic independent of
- * who is initiating the connection.
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param off offset of @a destination on @a path
- * @param options options for the connection
- * @param ct which tunnel uses this connection
- * @param init_state initial state for the connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection
- */
-static struct CadetConnection *
-connection_create (struct CadetPeer *destination,
-                   struct CadetPeerPath *path,
-                   unsigned int off,
-                   enum GNUNET_CADET_ChannelOption options,
-                   struct CadetTConnection *ct,
-                   const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                   enum CadetConnectionState init_state,
-                   GCC_ReadyCallback ready_cb,
-                   void *ready_cb_cls)
-{
-  struct CadetConnection *cc;
-  struct CadetPeer *first_hop;
-
-  cc = GNUNET_new (struct CadetConnection);
-  cc->options = options;
-  cc->state = init_state;
-  cc->ct = ct;
-  cc->cid = *cid;
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multishortmap_put (connections,
-                                                     &GCC_get_id (cc)->connection_of_tunnel,
-                                                     cc,
-                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  cc->ready_cb = ready_cb;
-  cc->ready_cb_cls = ready_cb_cls;
-  cc->path = path;
-  cc->off = off;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Creating %s using path %s\n",
-       GCC_2s (cc),
-       GCPP_2s (path));
-  GCPP_add_connection (path,
-                       off,
-                       cc);
-  for (unsigned int i=0;i<off;i++)
-    GCP_add_connection (GCPP_get_peer_at_offset (path,
-                                                 i),
-                        cc);
-
-  first_hop = GCPP_get_peer_at_offset (path,
-                                       0);
-  cc->mq_man = GCP_request_mq (first_hop,
-                               &manage_first_hop_mq,
-                               cc);
-  return cc;
-}
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.  This
- * is an inbound tunnel, so we must use the existing @a cid
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param options options for the connection
- * @param ct which tunnel uses this connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection, NULL if we already have
- *         a connection that takes precedence on @a path
- */
-struct CadetConnection *
-GCC_create_inbound (struct CadetPeer *destination,
-                    struct CadetPeerPath *path,
-                    enum GNUNET_CADET_ChannelOption options,
-                    struct CadetTConnection *ct,
-                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                    GCC_ReadyCallback ready_cb,
-                    void *ready_cb_cls)
-{
-  struct CadetConnection *cc;
-  unsigned int off;
-
-  off = GCPP_find_peer (path,
-                        destination);
-  GNUNET_assert (UINT_MAX != off);
-  cc = GCPP_get_connection (path,
-                            destination,
-                            off);
-  if (NULL != cc)
-  {
-    int cmp;
-
-    cmp = memcmp (cid,
-                  &cc->cid,
-                  sizeof (*cid));
-    if (0 == cmp)
-    {
-      /* Two peers picked the SAME random connection identifier at the
-         same time for the same path? Must be malicious.  Drop
-         connection (existing and inbound), even if it is the only
-         one. */
-      GNUNET_break_op (0);
-      GCT_connection_lost (cc->ct);
-      GCC_destroy_without_tunnel (cc);
-      return NULL;
-    }
-    if (0 < cmp)
-    {
-      /* drop existing */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got two connections on %s, dropping my existing %s\n",
-           GCPP_2s (path),
-           GCC_2s (cc));
-      GCT_connection_lost (cc->ct);
-      GCC_destroy_without_tunnel (cc);
-    }
-    else
-    {
-      /* keep existing */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got two connections on %s, keeping my existing %s\n",
-           GCPP_2s (path),
-           GCC_2s (cc));
-      return NULL;
-    }
-  }
-
-  return connection_create (destination,
-                            path,
-                            off,
-                            options,
-                            ct,
-                            cid,
-                            CADET_CONNECTION_CREATE_RECEIVED,
-                            ready_cb,
-                            ready_cb_cls);
-}
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param off offset of @a destination on @a path
- * @param options options for the connection
- * @param ct tunnel that uses the connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection
- */
-struct CadetConnection *
-GCC_create (struct CadetPeer *destination,
-            struct CadetPeerPath *path,
-            unsigned int off,
-            enum GNUNET_CADET_ChannelOption options,
-            struct CadetTConnection *ct,
-            GCC_ReadyCallback ready_cb,
-            void *ready_cb_cls)
-{
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
-  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
-                              &cid,
-                              sizeof (cid));
-  return connection_create (destination,
-                            path,
-                            off,
-                            options,
-                            ct,
-                            &cid,
-                            CADET_CONNECTION_NEW,
-                            ready_cb,
-                            ready_cb_cls);
-}
-
-
-/**
- * Transmit message @a msg via connection @a cc.  Must only be called
- * (once) after the connection has signalled that it is ready via the
- * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
- * connection is right now ready for transmission.
- *
- * @param cc connection identification
- * @param env envelope with message to transmit; must NOT
- *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
- */
-void
-GCC_transmit (struct CadetConnection *cc,
-              struct GNUNET_MQ_Envelope *env)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Scheduling message for transmission on %s\n",
-       GCC_2s (cc));
-  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
-  GNUNET_assert (CADET_CONNECTION_READY == cc->state);
-  cc->metrics.last_use = GNUNET_TIME_absolute_get ();
-  cc->mqm_ready = GNUNET_NO;
-  if (NULL != cc->task)
-  {
-    GNUNET_SCHEDULER_cancel (cc->task);
-    cc->task = NULL;
-  }
-  GCP_send (cc->mq_man,
-            env);
-}
-
-
-/**
- * Obtain the path used by this connection.
- *
- * @param cc connection
- * @return path to @a cc
- */
-struct CadetPeerPath *
-GCC_get_path (struct CadetConnection *cc)
-{
-  return cc->path;
-}
-
-
-/**
- * Obtain unique ID for the connection.
- *
- * @param cc connection.
- * @return unique number of the connection
- */
-const struct GNUNET_CADET_ConnectionTunnelIdentifier *
-GCC_get_id (struct CadetConnection *cc)
-{
-  return &cc->cid;
-}
-
-
-/**
- * Get a (static) string for a connection.
- *
- * @param cc Connection.
- */
-const char *
-GCC_2s (const struct CadetConnection *cc)
-{
-  static char buf[128];
-
-  if (NULL == cc)
-    return "Connection(NULL)";
-
-  if (NULL != cc->ct)
-  {
-    GNUNET_snprintf (buf,
-                     sizeof (buf),
-                     "Connection %s (%s)",
-                     GNUNET_sh2s (&cc->cid.connection_of_tunnel),
-                     GCT_2s (cc->ct->t));
-    return buf;
-  }
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "Connection %s",
-                   GNUNET_sh2s (&cc->cid.connection_of_tunnel));
-  return buf;
-}
-
-
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
-
-
-/**
- * Log connection info.
- *
- * @param cc connection
- * @param level Debug level to use.
- */
-void
-GCC_debug (struct CadetConnection *cc,
-           enum GNUNET_ErrorType level)
-{
-  int do_log;
-
-  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
-                                       "cadet-con",
-                                       __FILE__, __FUNCTION__, __LINE__);
-  if (0 == do_log)
-    return;
-  if (NULL == cc)
-  {
-    LOG2 (level,
-          "Connection (NULL)\n");
-    return;
-  }
-  LOG2 (level,
-        "%s to %s via path %s in state %d is %s\n",
-        GCC_2s (cc),
-        GCP_2s (cc->destination),
-        GCPP_2s (cc->path),
-        cc->state,
-        (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
-}
-
-/* end of gnunet-service-cadet-new_connection.c */
diff --git a/src/cadet/gnunet-service-cadet-new_connection.h b/src/cadet/gnunet-service-cadet-new_connection.h
deleted file mode 100644 (file)
index e48b208..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_connection.h
- * @brief A connection is a live end-to-end messaging mechanism
- *       where the peers are identified by a path and know how
- *       to forward along the route using a connection identifier
- *       for routing the data.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
-#define GNUNET_SERVICE_CADET_CONNECTION_H
-
-#include "gnunet_util_lib.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "cadet_protocol.h"
-
-
-/**
- * Function called to notify tunnel about change in our readyness.
- *
- * @param cls closure
- * @param is_ready #GNUNET_YES if the connection is now ready for transmission,
- *                 #GNUNET_NO if the connection is no longer ready for transmission
- */
-typedef void
-(*GCC_ReadyCallback)(void *cls,
-                     int is_ready);
-
-
-/**
- * Destroy a connection, called when the CORE layer is already done
- * (i.e. has received a BROKEN message), but if we still have to
- * communicate the destruction of the connection to the tunnel (if one
- * exists).
- *
- * @param cc connection to destroy
- */
-void
-GCC_destroy_without_core (struct CadetConnection *cc);
-
-
-/**
- * Destroy a connection, called if the tunnel association with the
- * connection was already broken, but we still need to notify the CORE
- * layer about the breakage.
- *
- * @param cc connection to destroy
- */
-void
-GCC_destroy_without_tunnel (struct CadetConnection *cc);
-
-
-/**
- * Lookup a connection by its identifier.
- *
- * @param cid identifier to resolve
- * @return NULL if connection was not found
- */
-struct CadetConnection *
-GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param off offset of @a destination on @a path
- * @param options options for the connection
- * @param ct which tunnel uses this connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection
- */
-struct CadetConnection *
-GCC_create (struct CadetPeer *destination,
-            struct CadetPeerPath *path,
-            unsigned int off,
-            enum GNUNET_CADET_ChannelOption options,
-            struct CadetTConnection *ct,
-            GCC_ReadyCallback ready_cb,
-            void *ready_cb_cls);
-
-
-/**
- * Create a connection to @a destination via @a path and
- * notify @a cb whenever we are ready for more data.  This
- * is an inbound tunnel, so we must use the existing @a cid
- *
- * @param destination where to go
- * @param path which path to take (may not be the full path)
- * @param options options for the connection
- * @param ct which tunnel uses this connection
- * @param ready_cb function to call when ready to transmit
- * @param ready_cb_cls closure for @a cb
- * @return handle to the connection, NULL if we already have
- *         a connection that takes precedence on @a path
- */
-struct CadetConnection *
-GCC_create_inbound (struct CadetPeer *destination,
-                    struct CadetPeerPath *path,
-                    enum GNUNET_CADET_ChannelOption options,
-                    struct CadetTConnection *ct,
-                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                    GCC_ReadyCallback ready_cb,
-                    void *ready_cb_cls);
-
-
-/**
- * Transmit message @a msg via connection @a cc.  Must only be called
- * (once) after the connection has signalled that it is ready via the
- * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
- * connection is right now ready for transmission.
- *
- * @param cc connection identification
- * @param env envelope with message to transmit;
- *            the #GNUNET_MQ_notify_send() must not have yet been used
- *            for the envelope.  Also, the message better match the
- *            connection identifier of this connection...
- */
-void
-GCC_transmit (struct CadetConnection *cc,
-              struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * A CREATE_ACK was received for this connection, process it.
- *
- * @param cc the connection that got the ACK.
- */
-void
-GCC_handle_connection_create_ack (struct CadetConnection *cc);
-
-
-/**
- * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
- * connection that we already have.  Either our ACK got lost
- * or something is fishy.  Consider retransmitting the ACK.
- *
- * @param cc connection that got the duplicate CREATE
- */
-void
-GCC_handle_duplicate_create (struct CadetConnection *cc);
-
-
-/**
- * Handle KX message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx (struct CadetConnection *cc,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
-
-
-/**
- * Handle KX_AUTH message.
- *
- * @param cc connection that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCC_handle_kx_auth (struct CadetConnection *cc,
-                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
-
-
-/**
- * Performance metrics for a connection.
- */
-struct CadetConnectionMetrics
-{
-
-  /**
-   * Our current best estimate of the latency, based on a weighted
-   * average of at least @a latency_datapoints values.
-   */
-  struct GNUNET_TIME_Relative aged_latency;
-
-  /**
-   * When was this connection first established? (by us sending or
-   * receiving the CREATE_ACK for the first time)
-   */
-  struct GNUNET_TIME_Absolute age;
-
-  /**
-   * When was this connection last used? (by us sending or
-   * receiving a PAYLOAD message on it)
-   */
-  struct GNUNET_TIME_Absolute last_use;
-
-  /**
-   * How many packets that ought to generate an ACK did we send via
-   * this connection?
-   */
-  unsigned long long num_acked_transmissions;
-
-  /**
-   * Number of packets that were sent via this connection did actually
-   * receive an ACK?  (Note: ACKs may be transmitted and lost via
-   * other connections, so this value should only be interpreted
-   * relative to @e num_acked_transmissions and in relation to other
-   * connections.)
-   */
-  unsigned long long num_successes;
-
-};
-
-
-/**
- * Obtain performance @a metrics from @a cc.
- *
- * @param cc connection to query
- * @return the metrics
- */
-const struct CadetConnectionMetrics *
-GCC_get_metrics (struct CadetConnection *cc);
-
-
-/**
- * Handle encrypted message.
- *
- * @param cc connection that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCC_handle_encrypted (struct CadetConnection *cc,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
-
-
-/**
- * We sent a message for which we expect to receive an ACK via
- * the connection identified by @a cti.
- *
- * @param cid connection identifier where we expect an ACK
- */
-void
-GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * We observed an ACK for a message that was originally sent via
- * the connection identified by @a cti.
- *
- * @param cid connection identifier where we got an ACK for a message
- *            that was originally sent via this connection (the ACK
- *            may have gotten back to us via a different connection).
- */
-void
-GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * We observed some the given @a latency on the connection
- * identified by @a cti.  (The same connection was taken
- * in both directions.)
- *
- * @param cti connection identifier where we measured latency
- * @param latency the observed latency
- */
-void
-GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
-                      struct GNUNET_TIME_Relative latency);
-
-
-/**
- * Return the tunnel associated with this connection.
- *
- * @param cc connection to query
- * @return corresponding entry in the tunnel's connection list
- */
-struct CadetTConnection *
-GCC_get_ct (struct CadetConnection *cc);
-
-
-/**
- * Obtain the path used by this connection.
- *
- * @param cc connection
- * @return path to @a cc
- */
-struct CadetPeerPath *
-GCC_get_path (struct CadetConnection *cc);
-
-
-/**
- * Obtain unique ID for the connection.
- *
- * @param cc connection.
- * @return unique number of the connection
- */
-const struct GNUNET_CADET_ConnectionTunnelIdentifier *
-GCC_get_id (struct CadetConnection *cc);
-
-
-/**
- * Get a (static) string for a connection.
- *
- * @param cc Connection.
- */
-const char *
-GCC_2s (const struct CadetConnection *cc);
-
-
-/**
- * Log connection info.
- *
- * @param cc connection
- * @param level Debug level to use.
- */
-void
-GCC_debug (struct CadetConnection *cc,
-           enum GNUNET_ErrorType level);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_core.c b/src/cadet/gnunet-service-cadet-new_core.c
deleted file mode 100644 (file)
index 3768c36..0000000
+++ /dev/null
@@ -1,1356 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_core.c
- * @brief cadet service; interaction with CORE service
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
- *
- * TODO:
- * - Optimization: given BROKEN messages, destroy paths (?)
- */
-#include "platform.h"
-#include "gnunet-service-cadet-new_core.h"
-#include "gnunet-service-cadet-new_paths.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet_core_service.h"
-#include "gnunet_statistics_service.h"
-#include "cadet_protocol.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-cor",__VA_ARGS__)
-
-/**
- * Information we keep per direction for a route.
- */
-struct RouteDirection;
-
-
-/**
- * Set of CadetRoutes that have exactly the same number of messages
- * in their buffer.  Used so we can efficiently find all of those
- * routes that have the current maximum of messages in the buffer (in
- * case we have to purge).
- */
-struct Rung
-{
-
-  /**
-   * Rung of RouteDirections with one more buffer entry each.
-   */
-  struct Rung *next;
-
-  /**
-   * Rung of RouteDirections with one less buffer entry each.
-   */
-  struct Rung *prev;
-
-  /**
-   * DLL of route directions with a number of buffer entries matching this rung.
-   */
-  struct RouteDirection *rd_head;
-
-  /**
-   * DLL of route directions with a number of buffer entries matching this rung.
-   */
-  struct RouteDirection *rd_tail;
-
-  /**
-   * Total number of route directions in this rung.
-   */
-  unsigned int num_routes;
-
-  /**
-   * Number of messages route directions at this rung have
-   * in their buffer.
-   */
-  unsigned int rung_off;
-};
-
-
-/**
- * Information we keep per direction for a route.
- */
-struct RouteDirection
-{
-
-  /**
-   * DLL of other route directions within the same `struct Rung`.
-   */
-  struct RouteDirection *prev;
-
-  /**
-   * DLL of other route directions within the same `struct Rung`.
-   */
-  struct RouteDirection *next;
-
-  /**
-   * Rung of this route direction (matches length of the buffer DLL).
-   */
-  struct Rung *rung;
-
-  /**
-   * Head of DLL of envelopes we have in the buffer for this direction.
-   */
-  struct GNUNET_MQ_Envelope *env_head;
-
-  /**
-   * Tail of DLL of envelopes we have in the buffer for this direction.
-   */
-  struct GNUNET_MQ_Envelope *env_tail;
-
-  /**
-   * Target peer.
-   */
-  struct CadetPeer *hop;
-
-  /**
-   * Route this direction is part of.
-   */
-  struct CadetRoute *my_route;
-
-  /**
-   * Message queue manager for @e hop.
-   */
-  struct GCP_MessageQueueManager *mqm;
-
-  /**
-   * Is @e mqm currently ready for transmission?
-   */
-  int is_ready;
-
-};
-
-
-/**
- * Description of a segment of a `struct CadetConnection` at the
- * intermediate peers.  Routes are basically entries in a peer's
- * routing table for forwarding traffic.  At both endpoints, the
- * routes are terminated by a `struct CadetConnection`, which knows
- * the complete `struct CadetPath` that is formed by the individual
- * routes.
- */
-struct CadetRoute
-{
-
-  /**
-   * Information about the next hop on this route.
-   */
-  struct RouteDirection next;
-
-  /**
-   * Information about the previous hop on this route.
-   */
-  struct RouteDirection prev;
-
-  /**
-   * Unique identifier for the connection that uses this route.
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-
-  /**
-   * When was this route last in use?
-   */
-  struct GNUNET_TIME_Absolute last_use;
-
-  /**
-   * Position of this route in the #route_heap.
-   */
-  struct GNUNET_CONTAINER_HeapNode *hn;
-
-  /**
-   * Options for the route, control buffering.
-   */
-  enum GNUNET_CADET_ChannelOption options;
-};
-
-
-/**
- * Handle to the CORE service.
- */
-static struct GNUNET_CORE_Handle *core;
-
-/**
- * Routes on which this peer is an intermediate.
- */
-static struct GNUNET_CONTAINER_MultiShortmap *routes;
-
-/**
- * Heap of routes, MIN-sorted by last activity.
- */
-static struct GNUNET_CONTAINER_Heap *route_heap;
-
-/**
- * Rung zero (always pointed to by #rung_head).
- */
-static struct Rung rung_zero;
-
-/**
- * DLL of rungs, with the head always point to a rung of
- * route directions with no messages in the queue.
- */
-static struct Rung *rung_head = &rung_zero;
-
-/**
- * Tail of the #rung_head DLL.
- */
-static struct Rung *rung_tail = &rung_zero;
-
-/**
- * Maximum number of concurrent routes this peer will support.
- */
-static unsigned long long max_routes;
-
-/**
- * Maximum number of envelopes we will buffer at this peer.
- */
-static unsigned long long max_buffers;
-
-/**
- * Current number of envelopes we have buffered at this peer.
- */
-static unsigned long long cur_buffers;
-
-/**
- * Task to timeout routes.
- */
-static struct GNUNET_SCHEDULER_Task *timeout_task;
-
-
-/**
- * Get the route corresponding to a hash.
- *
- * @param cid hash generated from the connection identifier
- */
-static struct CadetRoute *
-get_route (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  return GNUNET_CONTAINER_multishortmap_get (routes,
-                                             &cid->connection_of_tunnel);
-}
-
-
-/**
- * Lower the rung in which @a dir is by 1.
- *
- * @param dir direction to lower in rung.
- */
-static void
-lower_rung (struct RouteDirection *dir)
-{
-  struct Rung *rung = dir->rung;
-  struct Rung *prev;
-
-  GNUNET_CONTAINER_DLL_remove (rung->rd_head,
-                               rung->rd_tail,
-                               dir);
-  prev = rung->prev;
-  GNUNET_assert (NULL != prev);
-  if (prev->rung_off != rung->rung_off - 1)
-  {
-    prev = GNUNET_new (struct Rung);
-    prev->rung_off = rung->rung_off - 1;
-    GNUNET_CONTAINER_DLL_insert_after (rung_head,
-                                       rung_tail,
-                                       rung->prev,
-                                       prev);
-  }
-  GNUNET_assert (NULL != prev);
-  GNUNET_CONTAINER_DLL_insert (prev->rd_head,
-                               prev->rd_tail,
-                               dir);
-  dir->rung = prev;
-}
-
-
-/**
- * Discard the buffer @a env from the route direction @a dir and
- * move @a dir down a rung.
- *
- * @param dir direction that contains the @a env in the buffer
- * @param env envelope to discard
- */
-static void
-discard_buffer (struct RouteDirection *dir,
-                struct GNUNET_MQ_Envelope *env)
-{
-  GNUNET_MQ_dll_remove (&dir->env_head,
-                        &dir->env_tail,
-                        env);
-  cur_buffers--;
-  GNUNET_MQ_discard (env);
-  lower_rung (dir);
-  GNUNET_STATISTICS_set (stats,
-                         "# buffer use",
-                         cur_buffers,
-                         GNUNET_NO);
-}
-
-
-/**
- * Discard all messages from the highest rung, to make space.
- */
-static void
-discard_all_from_rung_tail ()
-{
-  struct Rung *tail = rung_tail;
-  struct RouteDirection *dir;
-
-  while (NULL != (dir = tail->rd_head))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Queue full due new message %s on connection %s, dropping old message\n",
-         GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
-    GNUNET_STATISTICS_update (stats,
-                              "# messages dropped due to full buffer",
-                              1,
-                              GNUNET_NO);
-    discard_buffer (dir,
-                    dir->env_head);
-  }
-  GNUNET_CONTAINER_DLL_remove (rung_head,
-                               rung_tail,
-                               tail);
-  GNUNET_free (tail);
-}
-
-
-/**
- * We message @a msg from @a prev.  Find its route by @a cid and
- * forward to the next hop.  Drop and signal broken route if we do not
- * have a route.
- *
- * @param prev previous hop (sender)
- * @param cid connection identifier, tells us which route to use
- * @param msg the message to forward
- */
-static void
-route_message (struct CadetPeer *prev,
-               const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-               const struct GNUNET_MessageHeader *msg)
-{
-  struct CadetRoute *route;
-  struct RouteDirection *dir;
-  struct Rung *rung;
-  struct Rung *nxt;
-  struct GNUNET_MQ_Envelope *env;
-
-  route = get_route (cid);
-  if (NULL == route)
-  {
-    struct GNUNET_MQ_Envelope *env;
-    struct GNUNET_CADET_ConnectionBrokenMessage *bm;
-
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Failed to route message of type %u from %s on connection %s: no route\n",
-         ntohs (msg->type),
-         GCP_2s (prev),
-         GNUNET_sh2s (&cid->connection_of_tunnel));
-    switch (ntohs (msg->type))
-    {
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
-      /* No need to respond to these! */
-      return;
-    }
-    env = GNUNET_MQ_msg (bm,
-                         GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
-    bm->cid = *cid;
-    bm->peer1 = my_full_id;
-    GCP_send_ooo (prev,
-                  env);
-    return;
-  }
-  route->last_use = GNUNET_TIME_absolute_get ();
-  GNUNET_CONTAINER_heap_update_cost (route->hn,
-                                     route->last_use.abs_value_us);
-  dir = (prev == route->prev.hop) ? &route->next : &route->prev;
-  if (GNUNET_YES == dir->is_ready)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Routing message of type %u from %s to %s on connection %s\n",
-         ntohs (msg->type),
-         GCP_2s (prev),
-         GNUNET_i2s (GCP_get_id (dir->hop)),
-         GNUNET_sh2s (&cid->connection_of_tunnel));
-    dir->is_ready = GNUNET_NO;
-    GCP_send (dir->mqm,
-              GNUNET_MQ_msg_copy (msg));
-    return;
-  }
-  /* Check if buffering is disallowed, and if so, make sure we only queue
-     one message per direction. */
-  if ( (0 != (route->options & GNUNET_CADET_OPTION_NOBUFFER)) &&
-       (NULL != dir->env_head) )
-    discard_buffer (dir,
-                    dir->env_head);
-  rung = dir->rung;
-  if (cur_buffers == max_buffers)
-  {
-    /* Need to make room. */
-    if (NULL != rung->next)
-    {
-      /* Easy case, drop messages from route directions in highest rung */
-      discard_all_from_rung_tail ();
-    }
-    else
-    {
-      /* We are in the highest rung, drop our own! */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Queue full due new message %s on connection %s, dropping old message\n",
-           GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
-      GNUNET_STATISTICS_update (stats,
-                                "# messages dropped due to full buffer",
-                                1,
-                                GNUNET_NO);
-      discard_buffer (dir,
-                      dir->env_head);
-      rung = dir->rung;
-    }
-  }
-  /* remove 'dir' from current rung */
-  GNUNET_CONTAINER_DLL_remove (rung->rd_head,
-                               rung->rd_tail,
-                               dir);
-  /* make 'nxt' point to the next higher rung, creat if necessary */
-  nxt = rung->next;
-  if ( (NULL == nxt) ||
-       (rung->rung_off + 1 != nxt->rung_off) )
-  {
-    nxt = GNUNET_new (struct Rung);
-    nxt->rung_off = rung->rung_off + 1;
-    GNUNET_CONTAINER_DLL_insert_after (rung_head,
-                                       rung_tail,
-                                       rung,
-                                       nxt);
-  }
-  /* insert 'dir' into next higher rung */
-  GNUNET_CONTAINER_DLL_insert (nxt->rd_head,
-                               nxt->rd_tail,
-                               dir);
-  dir->rung = nxt;
-
-  /* add message into 'dir' buffer */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Queueing new message of type %u from %s to %s on connection %s\n",
-       ntohs (msg->type),
-       GCP_2s (prev),
-       GNUNET_i2s (GCP_get_id (dir->hop)),
-       GNUNET_sh2s (&cid->connection_of_tunnel));
-  env = GNUNET_MQ_msg_copy (msg);
-  GNUNET_MQ_dll_insert_tail (&dir->env_head,
-                             &dir->env_tail,
-                             env);
-  cur_buffers++;
-  GNUNET_STATISTICS_set (stats,
-                         "# buffer use",
-                         cur_buffers,
-                         GNUNET_NO);
-  /* Clean up 'rung' if now empty (and not head) */
-  if ( (NULL == rung->rd_head) &&
-       (rung != rung_head) )
-  {
-    GNUNET_CONTAINER_DLL_remove (rung_head,
-                                 rung_tail,
-                                 rung);
-    GNUNET_free (rung);
-  }
-}
-
-
-/**
- * Check if the create_connection message has the appropriate size.
- *
- * @param cls Closure (unused).
- * @param msg Message to check.
- *
- * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
- */
-static int
-check_connection_create (void *cls,
-                         const struct GNUNET_CADET_ConnectionCreateMessage *msg)
-{
-  uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
-
-  if (0 != (size % sizeof (struct GNUNET_PeerIdentity)))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_NO;
-  }
-  return GNUNET_YES;
-}
-
-
-/**
- * Free internal data of a route direction.
- *
- * @param dir direction to destroy (do NOT free memory of 'dir' itself)
- */
-static void
-destroy_direction (struct RouteDirection *dir)
-{
-  struct GNUNET_MQ_Envelope *env;
-
-  while (NULL != (env = dir->env_head))
-  {
-    GNUNET_STATISTICS_update (stats,
-                              "# messages dropped due to route destruction",
-                              1,
-                              GNUNET_NO);
-    discard_buffer (dir,
-                    env);
-  }
-  if (NULL != dir->mqm)
-  {
-    GCP_request_mq_cancel (dir->mqm,
-                           NULL);
-    dir->mqm = NULL;
-  }
-  GNUNET_CONTAINER_DLL_remove (rung_head->rd_head,
-                               rung_head->rd_tail,
-                               dir);
-}
-
-
-/**
- * Destroy our state for @a route.
- *
- * @param route route to destroy
- */
-static void
-destroy_route (struct CadetRoute *route)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying route from %s to %s of connection %s\n",
-       GNUNET_i2s  (GCP_get_id (route->prev.hop)),
-       GNUNET_i2s2 (GCP_get_id (route->next.hop)),
-       GNUNET_sh2s (&route->cid.connection_of_tunnel));
-  GNUNET_assert (route ==
-                 GNUNET_CONTAINER_heap_remove_node (route->hn));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multishortmap_remove (routes,
-                                                        &route->cid.connection_of_tunnel,
-                                                        route));
-  GNUNET_STATISTICS_set (stats,
-                         "# routes",
-                         GNUNET_CONTAINER_multishortmap_size (routes),
-                         GNUNET_NO);
-  destroy_direction (&route->prev);
-  destroy_direction (&route->next);
-  GNUNET_free (route);
-}
-
-
-/**
- * Send message that a route is broken between @a peer1 and @a peer2.
- *
- * @param target where to send the message
- * @param cid connection identifier to use
- * @param peer1 one of the peers where a link is broken
- * @param peer2 another one of the peers where a link is broken
- */
-static void
-send_broken (struct RouteDirection *target,
-             const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-             const struct GNUNET_PeerIdentity *peer1,
-             const struct GNUNET_PeerIdentity *peer2)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_ConnectionBrokenMessage *bm;
-
-  if (NULL == target->mqm)
-    return; /* Can't send notification, connection is down! */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Notifying %s about BROKEN route at %s-%s of connection %s\n",
-       GCP_2s (target->hop),
-       GNUNET_i2s (peer1),
-       GNUNET_i2s2 (peer2),
-       GNUNET_sh2s (&cid->connection_of_tunnel));
-
-  env = GNUNET_MQ_msg (bm,
-                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
-  bm->cid = *cid;
-  if (NULL != peer1)
-    bm->peer1 = *peer1;
-  if (NULL != peer2)
-    bm->peer2 = *peer2;
-  GCP_request_mq_cancel (target->mqm,
-                         env);
-  target->mqm = NULL;
-}
-
-
-/**
- * Function called to check if any routes have timed out, and if
- * so, to clean them up.  Finally, schedules itself again at the
- * earliest time where there might be more work.
- *
- * @param cls NULL
- */
-static void
-timeout_cb (void *cls)
-{
-  struct CadetRoute *r;
-  struct GNUNET_TIME_Relative linger;
-  struct GNUNET_TIME_Absolute exp;
-
-  timeout_task = NULL;
-  linger = GNUNET_TIME_relative_multiply (keepalive_period,
-                                          3);
-  while (NULL != (r = GNUNET_CONTAINER_heap_peek (route_heap)))
-  {
-    exp = GNUNET_TIME_absolute_add (r->last_use,
-                                    linger);
-    if (0 != GNUNET_TIME_absolute_get_duration (exp).rel_value_us)
-    {
-      /* Route not yet timed out, wait until it does. */
-      timeout_task = GNUNET_SCHEDULER_add_at (exp,
-                                              &timeout_cb,
-                                              NULL);
-      return;
-    }
-    send_broken (&r->prev,
-                 &r->cid,
-                 NULL,
-                 NULL);
-    send_broken (&r->next,
-                 &r->cid,
-                 NULL,
-                 NULL);
-    destroy_route (r);
-  }
-  /* No more routes left, so no need for a #timeout_task */
-}
-
-
-/**
- * Function called when the message queue to the previous hop
- * becomes available/unavailable.  We expect this function to
- * be called immediately when we register, and then again
- * later if the connection ever goes down.
- *
- * @param cls the `struct RouteDirection`
- * @param available #GNUNET_YES if sending is now possible,
- *                  #GNUNET_NO if sending is no longer possible
- *                  #GNUNET_SYSERR if sending is no longer possible
- *                                 and the last envelope was discarded
- */
-static void
-dir_ready_cb (void *cls,
-              int ready)
-{
-  struct RouteDirection *dir = cls;
-  struct CadetRoute *route = dir->my_route;
-  struct RouteDirection *odir;
-
-  if (GNUNET_YES == ready)
-  {
-    struct GNUNET_MQ_Envelope *env;
-
-    dir->is_ready = GNUNET_YES;
-    if (NULL != (env = dir->env_head))
-    {
-      GNUNET_MQ_dll_remove (&dir->env_head,
-                            &dir->env_tail,
-                            env);
-      cur_buffers--;
-      GNUNET_STATISTICS_set (stats,
-                             "# buffer use",
-                             cur_buffers,
-                             GNUNET_NO);
-      lower_rung (dir);
-      dir->is_ready = GNUNET_NO;
-      GCP_send (dir->mqm,
-                env);
-    }
-    return;
-  }
-  odir = (dir == &route->next) ? &route->prev : &route->next;
-  send_broken (&route->next,
-               &route->cid,
-               GCP_get_id (odir->hop),
-               &my_full_id);
-  destroy_route (route);
-}
-
-
-/**
- * Initialize one of the directions of a route.
- *
- * @param route route the direction belongs to
- * @param dir direction to initialize
- * @param hop next hop on in the @a dir
- */
-static void
-dir_init (struct RouteDirection *dir,
-          struct CadetRoute *route,
-          struct CadetPeer *hop)
-{
-  dir->hop = hop;
-  dir->my_route = route;
-  dir->mqm = GCP_request_mq (hop,
-                             &dir_ready_cb,
-                             dir);
-  GNUNET_CONTAINER_DLL_insert (rung_head->rd_head,
-                               rung_head->rd_tail,
-                               dir);
-  dir->rung = rung_head;
-  GNUNET_assert (GNUNET_YES == dir->is_ready);
-}
-
-
-/**
- * We could not create the desired route.  Send a
- * #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
- * message to @a target.
- *
- * @param target who should receive the message
- * @param cid identifier of the connection/route that failed
- * @param failure_at neighbour with which we failed to route,
- *        or NULL.
- */
-static void
-send_broken_without_mqm (struct CadetPeer *target,
-                         const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                         const struct GNUNET_PeerIdentity *failure_at)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_ConnectionBrokenMessage *bm;
-
-  env = GNUNET_MQ_msg (bm,
-                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
-  bm->cid = *cid;
-  bm->peer1 = my_full_id;
-  if (NULL != failure_at)
-    bm->peer2 = *failure_at;
-  GCP_send_ooo (target,
-                env);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_connection_create (void *cls,
-                          const struct GNUNET_CADET_ConnectionCreateMessage *msg)
-{
-  struct CadetPeer *sender = cls;
-  struct CadetPeer *next;
-  const struct GNUNET_PeerIdentity *pids = (const struct GNUNET_PeerIdentity *) &msg[1];
-  struct CadetRoute *route;
-  uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
-  unsigned int path_length;
-  unsigned int off;
-  enum GNUNET_CADET_ChannelOption options;
-
-  options = (enum GNUNET_CADET_ChannelOption) ntohl (msg->options);
-  path_length = size / sizeof (struct GNUNET_PeerIdentity);
-  /* Initiator is at offset 0. */
-  for (off=1;off<path_length;off++)
-    if (0 == memcmp (&my_full_id,
-                     &pids[off],
-                     sizeof (struct GNUNET_PeerIdentity)))
-      break;
-  if (off == path_length)
-  {
-    /* We are not on the path, bogus request */
-    GNUNET_break_op (0);
-    return;
-  }
-  /* Check previous hop */
-  if (sender != GCP_get (&pids[off - 1],
-                         GNUNET_NO))
-  {
-    /* sender is not on the path, not allowed */
-    GNUNET_break_op (0);
-    return;
-  }
-  if (NULL !=
-      get_route (&msg->cid))
-  {
-    /* Duplicate CREATE, pass it on, previous one might have been lost! */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Passing on duplicate CADET_CONNECTION_CREATE message on connection %s\n",
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    route_message (sender,
-                   &msg->cid,
-                   &msg->header);
-    return;
-  }
-  if (off == path_length - 1)
-  {
-    /* We are the destination, create connection */
-    struct CadetConnection *cc;
-    struct CadetPeerPath *path;
-    struct CadetPeer *origin;
-
-    cc = GCC_lookup (&msg->cid);
-    if (NULL != cc)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Received duplicate CADET_CONNECTION_CREATE message on connection %s\n",
-           GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-      GCC_handle_duplicate_create (cc);
-      return;
-    }
-
-    origin = GCP_get (&pids[0],
-                      GNUNET_YES);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CADET_CONNECTION_CREATE message from %s for connection %s, building inverse path\n",
-         GCP_2s (origin),
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    path = GCPP_get_path_from_route (path_length - 1,
-                                     pids);
-    if (GNUNET_OK !=
-        GCT_add_inbound_connection (GCP_get_tunnel (origin,
-                                                    GNUNET_YES),
-                                    &msg->cid,
-                                    (enum GNUNET_CADET_ChannelOption) ntohl (msg->options),
-                                    path))
-    {
-      /* Send back BROKEN: duplicate connection on the same path,
-         we will use the other one. */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Received CADET_CONNECTION_CREATE from %s for %s, but %s already has a connection. Sending BROKEN\n",
-           GCP_2s (sender),
-           GNUNET_sh2s (&msg->cid.connection_of_tunnel),
-           GCPP_2s (path));
-      send_broken_without_mqm (sender,
-                               &msg->cid,
-                               NULL);
-      return;
-    }
-    return;
-  }
-  /* We are merely a hop on the way, check if we can support the route */
-  next = GCP_get (&pids[off + 1],
-                  GNUNET_NO);
-  if ( (NULL == next) ||
-       (GNUNET_NO == GCP_has_core_connection (next)) )
-  {
-    /* unworkable, send back BROKEN notification */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is down. Sending BROKEN\n",
-         GCP_2s (sender),
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel),
-         GNUNET_i2s (&pids[off + 1]),
-         off + 1);
-    send_broken_without_mqm (sender,
-                             &msg->cid,
-                             &pids[off + 1]);
-    return;
-  }
-  if (max_routes <= GNUNET_CONTAINER_multishortmap_size (routes))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CADET_CONNECTION_CREATE from %s for %s. We have reached our route limit. Sending BROKEN\n",
-         GCP_2s (sender),
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    send_broken_without_mqm (sender,
-                             &msg->cid,
-                             &pids[off - 1]);
-    return;
-  }
-
-  /* Workable route, create routing entry */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is up. Creating route\n",
-       GCP_2s (sender),
-       GNUNET_sh2s (&msg->cid.connection_of_tunnel),
-       GNUNET_i2s (&pids[off + 1]),
-       off + 1);
-  route = GNUNET_new (struct CadetRoute);
-  route->options = options;
-  route->cid = msg->cid;
-  route->last_use = GNUNET_TIME_absolute_get ();
-  dir_init (&route->prev,
-            route,
-            sender);
-  dir_init (&route->next,
-            route,
-            next);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multishortmap_put (routes,
-                                                     &route->cid.connection_of_tunnel,
-                                                     route,
-                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  GNUNET_STATISTICS_set (stats,
-                         "# routes",
-                         GNUNET_CONTAINER_multishortmap_size (routes),
-                         GNUNET_NO);
-  route->hn = GNUNET_CONTAINER_heap_insert (route_heap,
-                                            route,
-                                            route->last_use.abs_value_us);
-  if (NULL == timeout_task)
-    timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (keepalive_period,
-                                                                                3),
-                                                 &timeout_cb,
-                                                 NULL);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_connection_create_ack (void *cls,
-                              const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-
-  /* First, check if ACK belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify ACK came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received ACK from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CONNECTION_CREATE_ACK for connection %s.\n",
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    GCC_handle_connection_create_ack (cc);
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- * @deprecated duplicate logic with #handle_destroy(); dedup!
- */
-static void
-handle_connection_broken (void *cls,
-                          const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-  struct CadetRoute *route;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CONNECTION_BROKEN for connection %s. Destroying it.\n",
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    GCC_destroy_without_core (cc);
-
-    /* FIXME: also destroy the path up to the specified link! */
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-  route = get_route (&msg->cid);
-  if (NULL != route)
-    destroy_route (route);
-  /* FIXME: also destroy paths we MAY have up to the specified link! */
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_connection_destroy (void *cls,
-                           const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-  struct CadetRoute *route;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received CONNECTION_DESTROY for connection %s. Destroying connection.\n",
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-
-    GCC_destroy_without_core (cc);
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received CONNECTION_DESTROY for connection %s. Destroying route.\n",
-       GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-  route = get_route (&msg->cid);
-  if (NULL != route)
-    destroy_route (route);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_tunnel_kx (void *cls,
-                  const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    GCC_handle_kx (cc,
-                   msg);
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_tunnel_kx_auth (void *cls,
-                       const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->kx.cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    GCC_handle_kx_auth (cc,
-                        msg);
-    return;
-  }
-
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->kx.cid,
-                 &msg->kx.header);
-}
-
-
-/**
- * Check if the encrypted message has the appropriate size.
- *
- * @param cls Closure (unused).
- * @param msg Message to check.
- *
- * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
- */
-static int
-check_tunnel_encrypted (void *cls,
-                        const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  return GNUNET_YES;
-}
-
-
-/**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED.
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
- */
-static void
-handle_tunnel_encrypted (void *cls,
-                         const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  struct CadetPeer *peer = cls;
-  struct CadetConnection *cc;
-
-  /* First, check if message belongs to a connection that ends here. */
-  cc = GCC_lookup (&msg->cid);
-  if (NULL != cc)
-  {
-    /* verify message came from the right direction */
-    struct CadetPeerPath *path = GCC_get_path (cc);
-
-    if (peer !=
-        GCPP_get_peer_at_offset (path,
-                                 0))
-    {
-      /* received message from unexpected direction, ignore! */
-      GNUNET_break_op (0);
-      return;
-    }
-    GCC_handle_encrypted (cc,
-                          msg);
-    return;
-  }
-  /* We're just an intermediary peer, route the message along its path */
-  route_message (peer,
-                 &msg->cid,
-                 &msg->header);
-}
-
-
-/**
- * Function called after #GNUNET_CORE_connect has succeeded (or failed
- * for good).  Note that the private key of the peer is intentionally
- * not exposed here; if you need it, your process should try to read
- * the private key file directly (which should work if you are
- * authorized...).  Implementations of this function must not call
- * #GNUNET_CORE_disconnect (other than by scheduling a new task to
- * do this later).
- *
- * @param cls closure
- * @param my_identity ID of this peer, NULL if we failed
- */
-static void
-core_init_cb (void *cls,
-              const struct GNUNET_PeerIdentity *my_identity)
-{
-  if (NULL == my_identity)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_break (0 ==
-                memcmp (my_identity,
-                        &my_full_id,
-                        sizeof (struct GNUNET_PeerIdentity)));
-}
-
-
-/**
- * Method called whenever a given peer connects.
- *
- * @param cls closure
- * @param peer peer identity this notification is about
- */
-static void *
-core_connect_cb (void *cls,
-                 const struct GNUNET_PeerIdentity *peer,
-                 struct GNUNET_MQ_Handle *mq)
-{
-  struct CadetPeer *cp;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "CORE connection to peer %s was established.\n",
-       GNUNET_i2s (peer));
-  cp = GCP_get (peer,
-                GNUNET_YES);
-  GCP_set_mq (cp,
-              mq);
-  return cp;
-}
-
-
-/**
- * Method called whenever a peer disconnects.
- *
- * @param cls closure
- * @param peer peer identity this notification is about
- */
-static void
-core_disconnect_cb (void *cls,
-                    const struct GNUNET_PeerIdentity *peer,
-                    void *peer_cls)
-{
-  struct CadetPeer *cp = peer_cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "CORE connection to peer %s went down.\n",
-       GNUNET_i2s (peer));
-  GCP_set_mq (cp,
-              NULL);
-}
-
-
-/**
- * Initialize the CORE subsystem.
- *
- * @param c Configuration.
- */
-void
-GCO_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_var_size (connection_create,
-                           GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
-                           struct GNUNET_CADET_ConnectionCreateMessage,
-                           NULL),
-    GNUNET_MQ_hd_fixed_size (connection_create_ack,
-                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
-                             struct GNUNET_CADET_ConnectionCreateAckMessage,
-                             NULL),
-    GNUNET_MQ_hd_fixed_size (connection_broken,
-                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
-                             struct GNUNET_CADET_ConnectionBrokenMessage,
-                             NULL),
-    GNUNET_MQ_hd_fixed_size (connection_destroy,
-                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
-                             struct GNUNET_CADET_ConnectionDestroyMessage,
-                             NULL),
-    GNUNET_MQ_hd_fixed_size (tunnel_kx,
-                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
-                             struct GNUNET_CADET_TunnelKeyExchangeMessage,
-                             NULL),
-    GNUNET_MQ_hd_fixed_size (tunnel_kx_auth,
-                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH,
-                             struct GNUNET_CADET_TunnelKeyExchangeAuthMessage,
-                             NULL),
-    GNUNET_MQ_hd_var_size (tunnel_encrypted,
-                           GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
-                           struct GNUNET_CADET_TunnelEncryptedMessage,
-                           NULL),
-    GNUNET_MQ_handler_end ()
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "MAX_ROUTES",
-                                             &max_routes))
-    max_routes = 5000;
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "MAX_MSGS_QUEUE",
-                                             &max_buffers))
-    max_buffers = 10000;
-  routes = GNUNET_CONTAINER_multishortmap_create (1024,
-                                                  GNUNET_NO);
-  route_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
-  core = GNUNET_CORE_connect (c,
-                              NULL,
-                              &core_init_cb,
-                              &core_connect_cb,
-                              &core_disconnect_cb,
-                              handlers);
-}
-
-
-/**
- * Shut down the CORE subsystem.
- */
-void
-GCO_shutdown ()
-{
-  if (NULL != core)
-  {
-    GNUNET_CORE_disconnect (core);
-    core = NULL;
-  }
-  GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes));
-  GNUNET_CONTAINER_multishortmap_destroy (routes);
-  routes = NULL;
-  GNUNET_CONTAINER_heap_destroy (route_heap);
-  route_heap = NULL;
-  if (NULL != timeout_task)
-  {
-    GNUNET_SCHEDULER_cancel (timeout_task);
-    timeout_task = NULL;
-  }
-}
-
-/* end of gnunet-cadet-service_core.c */
diff --git a/src/cadet/gnunet-service-cadet-new_core.h b/src/cadet/gnunet-service-cadet-new_core.h
deleted file mode 100644 (file)
index 65b0a6b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_core.h
- * @brief cadet service; interaction with CORE service
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
- */
-
-#ifndef GNUNET_SERVICE_CADET_CORE_H
-#define GNUNET_SERVICE_CADET_CORE_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "gnunet_util_lib.h"
-
-
-/**
- * Initialize the CORE subsystem.
- *
- * @param c Configuration.
- */
-void
-GCO_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-
-/**
- * Shut down the CORE subsystem.
- */
-void
-GCO_shutdown (void);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_CORE_H */
-#endif
-/* end of gnunet-cadet-service_core.h */
diff --git a/src/cadet/gnunet-service-cadet-new_dht.c b/src/cadet/gnunet-service-cadet-new_dht.c
deleted file mode 100644 (file)
index 849562f..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_dht.c
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_dht_service.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_hello.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-/**
- * How long do we wait before first announcing our presence to the DHT.
- * Used to wait for our HELLO to be available.  Note that we also get
- * notifications when our HELLO is ready, so this is just the maximum
- * we wait for the first notification.
- */
-#define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
-
-/**
- * How long do we wait after we get an updated HELLO before publishing?
- * Allows for the HELLO to be updated again quickly, for example in
- * case multiple addresses changed and we got a partial update.
- */
-#define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
-
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
-
-
-/**
- * Handle for DHT searches.
- */
-struct GCD_search_handle
-{
-  /**
-   * DHT_GET handle.
-   */
-  struct GNUNET_DHT_GetHandle *dhtget;
-
-};
-
-
-/**
- * Handle to use DHT.
- */
-static struct GNUNET_DHT_Handle *dht_handle;
-
-/**
- * How often to PUT own ID in the DHT.
- */
-static struct GNUNET_TIME_Relative id_announce_time;
-
-/**
- * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put().
- */
-static unsigned long long dht_replication_level;
-
-/**
- * Task to periodically announce itself in the network.
- */
-static struct GNUNET_SCHEDULER_Task *announce_id_task;
-
-/**
- * Delay for the next ID announce.
- */
-static struct GNUNET_TIME_Relative announce_delay;
-
-
-/**
- * Function to process paths received for a new peer addition. The recorded
- * paths form the initial tunnel, which can be optimized later.
- * Called on each result obtained for the DHT search.
- *
- * @param cls closure
- * @param exp when will this value expire
- * @param key key of the result
- * @param get_path path of the get request
- * @param get_path_length lenght of @a get_path
- * @param put_path path of the put request
- * @param put_path_length length of the @a put_path
- * @param type type of the result
- * @param size number of bytes in data
- * @param data pointer to the result data
- */
-static void
-dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
-                    const struct GNUNET_HashCode *key,
-                    const struct GNUNET_PeerIdentity *get_path,
-                    unsigned int get_path_length,
-                    const struct GNUNET_PeerIdentity *put_path,
-                    unsigned int put_path_length,
-                    enum GNUNET_BLOCK_Type type,
-                    size_t size,
-                    const void *data)
-{
-  const struct GNUNET_HELLO_Message *hello = data;
-  struct CadetPeer *peer;
-
-  GCPP_try_path_from_dht (get_path,
-                          get_path_length,
-                          put_path,
-                          put_path_length);
-  if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
-       (ntohs (hello->header.size) == size) &&
-       (size == GNUNET_HELLO_size (hello)) )
-  {
-    peer = GCP_get (&put_path[0],
-                    GNUNET_YES);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got HELLO for %s\n",
-         GCP_2s (peer));
-    GCP_set_hello (peer,
-                   hello);
-  }
-}
-
-
-/**
- * Periodically announce self id in the DHT
- *
- * @param cls closure
- */
-static void
-announce_id (void *cls)
-{
-  struct GNUNET_HashCode phash;
-  const struct GNUNET_HELLO_Message *hello;
-  size_t size;
-  struct GNUNET_TIME_Absolute expiration;
-  struct GNUNET_TIME_Relative next_put;
-
-  hello = GCH_get_mine ();
-  size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
-  if (0 == size)
-  {
-    expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
-                                           announce_delay);
-    announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
-  }
-  else
-  {
-    expiration = GNUNET_HELLO_get_last_expiration (hello);
-    announce_delay = GNUNET_TIME_UNIT_SECONDS;
-  }
-
-  /* Call again in id_announce_time, unless HELLO expires first,
-   * but wait at least 1s. */
-  next_put
-    = GNUNET_TIME_absolute_get_remaining (expiration);
-  next_put
-    = GNUNET_TIME_relative_min (next_put,
-                                id_announce_time);
-  next_put
-    = GNUNET_TIME_relative_max (next_put,
-                                GNUNET_TIME_UNIT_SECONDS);
-  announce_id_task
-    = GNUNET_SCHEDULER_add_delayed (next_put,
-                                    &announce_id,
-                                    cls);
-  GNUNET_STATISTICS_update (stats,
-                            "# DHT announce",
-                            1,
-                            GNUNET_NO);
-  memset (&phash,
-          0,
-          sizeof (phash));
-  GNUNET_memcpy (&phash,
-                 &my_full_id,
-                 sizeof (my_full_id));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Announcing my HELLO (%u bytes) in the DHT\n",
-       size);
-  GNUNET_DHT_put (dht_handle,   /* DHT handle */
-                  &phash,       /* Key to use */
-                  dht_replication_level,     /* Replication level */
-                  GNUNET_DHT_RO_RECORD_ROUTE
-                  | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
-                  GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
-                  size,  /* Size of the data */
-                  (const char *) hello, /* Data itself */
-                  expiration,  /* Data expiration */
-                  NULL,         /* Continuation */
-                  NULL);        /* Continuation closure */
-}
-
-
-/**
- * Function called by the HELLO subsystem whenever OUR hello
- * changes. Re-triggers the DHT PUT immediately.
- */
-void
-GCD_hello_update ()
-{
-  if (NULL == announce_id_task)
-    return; /* too early */
-  GNUNET_SCHEDULER_cancel (announce_id_task);
-  announce_id_task
-    = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY,
-                                    &announce_id,
-                                    NULL);
-}
-
-
-/**
- * Initialize the DHT subsystem.
- *
- * @param c Configuration.
- */
-void
-GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "DHT_REPLICATION_LEVEL",
-                                             &dht_replication_level))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET",
-                               "DHT_REPLICATION_LEVEL",
-                               "USING DEFAULT");
-    dht_replication_level = 3;
-  }
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c,
-                                           "CADET",
-                                           "ID_ANNOUNCE_TIME",
-                                           &id_announce_time))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
-                               "CADET",
-                               "ID_ANNOUNCE_TIME",
-                               "MISSING");
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-
-  dht_handle = GNUNET_DHT_connect (c,
-                                   64);
-  GNUNET_break (NULL != dht_handle);
-  announce_delay = GNUNET_TIME_UNIT_SECONDS;
-  announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY,
-                                                   &announce_id,
-                                                   NULL);
-}
-
-
-/**
- * Shut down the DHT subsystem.
- */
-void
-GCD_shutdown (void)
-{
-  if (NULL != dht_handle)
-  {
-    GNUNET_DHT_disconnect (dht_handle);
-    dht_handle = NULL;
-  }
-  if (NULL != announce_id_task)
-  {
-    GNUNET_SCHEDULER_cancel (announce_id_task);
-    announce_id_task = NULL;
-  }
-}
-
-
-/**
- * Search DHT for paths to @a peeR_id
- *
- * @param peer_id peer to search for
- * @return handle to abort search
- */
-struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id)
-{
-  struct GNUNET_HashCode phash;
-  struct GCD_search_handle *h;
-
-  GNUNET_STATISTICS_update (stats,
-                            "# DHT search",
-                            1,
-                            GNUNET_NO);
-  memset (&phash,
-          0,
-          sizeof (phash));
-  GNUNET_memcpy (&phash,
-                 peer_id,
-                 sizeof (*peer_id));
-
-  h = GNUNET_new (struct GCD_search_handle);
-  h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
-                                    GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
-                                    &phash,     /* key to search */
-                                    dht_replication_level, /* replication level */
-                                    GNUNET_DHT_RO_RECORD_ROUTE |
-                                    GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
-                                    NULL,       /* xquery */
-                                    0,     /* xquery bits */
-                                    &dht_get_id_handler,
-                                   h);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Starting DHT GET for peer %s (%p)\n",
-       GNUNET_i2s (peer_id),
-       h);
-  return h;
-}
-
-
-/**
- * Stop DHT search started with #GCD_search().
- *
- * @param h handle to search to stop
- */
-void
-GCD_search_stop (struct GCD_search_handle *h)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Stopping DHT GET %p\n",
-       h);
-  GNUNET_DHT_get_stop (h->dhtget);
-  GNUNET_free (h);
-}
-
-/* end of gnunet-service-cadet_dht.c */
diff --git a/src/cadet/gnunet-service-cadet-new_dht.h b/src/cadet/gnunet-service-cadet-new_dht.h
deleted file mode 100644 (file)
index 5d7ab29..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_dht.h
- * @brief cadet service; dealing with DHT requests and results
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCD (Gnunet Cadet Dht)
- */
-#ifndef GNUNET_SERVICE_CADET_DHT_H
-#define GNUNET_SERVICE_CADET_DHT_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-/**
- * Handle for DHT search operation.
- */
-struct GCD_search_handle;
-
-
-/**
- * Initialize the DHT subsystem.
- *
- * @param c Configuration.
- */
-void
-GCD_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-
-/**
- * Shut down the DHT subsystem.
- */
-void
-GCD_shutdown (void);
-
-
-/**
- * Function called by the HELLO subsystem whenever OUR hello
- * changes. Re-triggers the DHT PUT immediately.
- */
-void
-GCD_hello_update (void);
-
-/**
- * Search DHT for paths to @a peeR_id
- *
- * @param peer_id peer to search for
- * @return handle to abort search
- */
-struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id);
-
-
-/**
- * Stop DHT search started with #GCD_search().
- *
- * @param h handle to search to stop
- */
-void
-GCD_search_stop (struct GCD_search_handle *h);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_DHT_H */
-#endif
-/* end of gnunet-service-cadet_dht.h */
diff --git a/src/cadet/gnunet-service-cadet-new_hello.c b/src/cadet/gnunet-service-cadet-new_hello.c
deleted file mode 100644 (file)
index a24325a..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2014, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_hello.c
- * @brief spread knowledge about how to contact other peers from PEERINFO
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * TODO:
- * - is most of this necessary/helpful?
- * - should we not simply restrict this to OUR hello?
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_statistics_service.h"
-#include "gnunet_peerinfo_service.h"
-#include "cadet_protocol.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_hello.h"
-#include "gnunet-service-cadet-new_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
-
-/**
- * Hello message of local peer.
- */
-static struct GNUNET_HELLO_Message *mine;
-
-/**
- * Handle to peerinfo service.
- */
-static struct GNUNET_PEERINFO_Handle *peerinfo;
-
-/**
- * Iterator context.
- */
-static struct GNUNET_PEERINFO_NotifyContext *nc;
-
-
-/**
- * Process each hello message received from peerinfo.
- *
- * @param cls Closure (unused).
- * @param peer Identity of the peer.
- * @param hello Hello of the peer.
- * @param err_msg Error message.
- */
-static void
-got_hello (void *cls,
-           const struct GNUNET_PeerIdentity *id,
-           const struct GNUNET_HELLO_Message *hello,
-           const char *err_msg)
-{
-  struct CadetPeer *peer;
-
-  if ( (NULL == id) ||
-       (NULL == hello) )
-    return;
-  if (0 == memcmp (id,
-                   &my_full_id,
-                   sizeof (struct GNUNET_PeerIdentity)))
-  {
-    GNUNET_free_non_null (mine);
-    mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header);
-    GCD_hello_update ();
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Hello for %s (%d bytes), expires on %s\n",
-       GNUNET_i2s (id),
-       GNUNET_HELLO_size (hello),
-       GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration (hello)));
-  peer = GCP_get (id,
-                  GNUNET_YES);
-  GCP_set_hello (peer,
-                 hello);
-}
-
-
-/**
- * Initialize the hello subsystem.
- *
- * @param c Configuration.
- */
-void
-GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
-  GNUNET_assert (NULL == nc);
-  peerinfo = GNUNET_PEERINFO_connect (c);
-  nc = GNUNET_PEERINFO_notify (c,
-                               GNUNET_NO,
-                               &got_hello,
-                               NULL);
-}
-
-
-/**
- * Shut down the hello subsystem.
- */
-void
-GCH_shutdown ()
-{
-  if (NULL != nc)
-  {
-    GNUNET_PEERINFO_notify_cancel (nc);
-    nc = NULL;
-  }
-  if (NULL != peerinfo)
-  {
-    GNUNET_PEERINFO_disconnect (peerinfo);
-    peerinfo = NULL;
-  }
-  if (NULL != mine)
-  {
-    GNUNET_free (mine);
-    mine = NULL;
-  }
-}
-
-
-/**
- * Get own hello message.
- *
- * @return Own hello message.
- */
-const struct GNUNET_HELLO_Message *
-GCH_get_mine (void)
-{
-  return mine;
-}
-
-/* end of gnunet-service-cadet-new_hello.c */
diff --git a/src/cadet/gnunet-service-cadet-new_hello.h b/src/cadet/gnunet-service-cadet-new_hello.h
deleted file mode 100644 (file)
index 4291ae9..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2014, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_hello.h
- * @brief cadet service; dealing with hello messages
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
- */
-
-#ifndef GNUNET_SERVICE_CADET_HELLO_H
-#define GNUNET_SERVICE_CADET_HELLO_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_hello_lib.h"
-
-
-/**
- * Initialize the hello subsystem.
- *
- * @param c Configuration.
- */
-void
-GCH_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-
-/**
- * Shut down the hello subsystem.
- */
-void
-GCH_shutdown (void);
-
-
-/**
- * Get own hello message.
- *
- * @return Own hello message.
- */
-const struct GNUNET_HELLO_Message *
-GCH_get_mine (void);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_HELLO_H */
-#endif
-/* end of gnunet-cadet-service_hello.h */
diff --git a/src/cadet/gnunet-service-cadet-new_paths.c b/src/cadet/gnunet-service-cadet-new_paths.c
deleted file mode 100644 (file)
index c6121a1..0000000
+++ /dev/null
@@ -1,801 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_paths.c
- * @brief Information we track per path.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__)
-
-
-/**
- * Information regarding a possible path to reach a peer.
- */
-struct CadetPeerPath
-{
-
-  /**
-   * Array of all the peers on the path.  If @e hn is non-NULL, the
-   * last one is our owner.
-   */
-  struct CadetPeerPathEntry **entries;
-
-  /**
-   * Node of this path in the owner's heap.  Used to update our position
-   * in the heap whenever our @e desirability changes.
-   */
-  struct GNUNET_CONTAINER_HeapNode *hn;
-
-  /**
-   * Desirability of the path. How unique is it for the various peers
-   * on it?
-   */
-  GNUNET_CONTAINER_HeapCostType desirability;
-
-  /**
-   * Length of the @e entries array.
-   */
-  unsigned int entries_length;
-
-};
-
-
-/**
- * Calculate the path's desirability score.
- *
- * @param path path to calculate the score for
- */
-static void
-recalculate_path_desirability (struct CadetPeerPath *path)
-{
-  double result = 0.0;
-
-  for (unsigned int i=0;i<path->entries_length;i++)
-  {
-    struct CadetPeer *cp = path->entries[i]->peer;
-
-    result += GCP_get_desirability_of_path (cp,
-                                            i);
-  }
-  path->desirability = (GNUNET_CONTAINER_HeapCostType) result;
-}
-
-
-/**
- * Return how much we like keeping the path.  This is an aggregate
- * score based on various factors, including the age of the path
- * (older == better), and the value of this path to all of its ajacent
- * peers.  For example, long paths that end at a peer that we have no
- * shorter way to reach are very desirable, while long paths that end
- * at a peer for which we have a shorter way as well are much less
- * desirable.  Higher values indicate more valuable paths.  The
- * returned value should be used to decide which paths to remember.
- *
- * @param path path to return the length for
- * @return desirability of the path, larger is more desirable
- */
-GNUNET_CONTAINER_HeapCostType
-GCPP_get_desirability (const struct CadetPeerPath *path)
-{
-  return path->desirability;
-}
-
-
-/**
- * Return connection to @a destination using @a path, or return
- * NULL if no such connection exists.
- *
- * @param path path to traverse
- * @param destination destination node to get to, must be on path
- * @param off offset of @a destination on @a path
- * @return NULL if we have no existing connection
- *         otherwise connection from us to @a destination via @a path
- */
-struct CadetConnection *
-GCPP_get_connection (struct CadetPeerPath *path,
-                     struct CadetPeer *destination,
-                     unsigned int off)
-{
-  struct CadetPeerPathEntry *entry;
-
-  GNUNET_assert (off < path->entries_length);
-  entry = path->entries[off];
-  GNUNET_assert (entry->peer == destination);
-  return entry->cc;
-}
-
-
-/**
- * Notify @a path that it is used for connection @a cc
- * which ends at the path's offset @a off.
- *
- * @param path the path to remember the @a cc
- * @param off the offset where the @a cc ends
- * @param cc the connection to remember
- */
-void
-GCPP_add_connection (struct CadetPeerPath *path,
-                     unsigned int off,
-                     struct CadetConnection *cc)
-{
-  struct CadetPeerPathEntry *entry;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Adding connection %s to path %s at offset %u\n",
-       GCC_2s (cc),
-       GCPP_2s (path),
-       off);
-  GNUNET_assert (off < path->entries_length);
-  entry = path->entries[off];
-  GNUNET_assert (NULL == entry->cc);
-  GNUNET_assert (NULL != cc);
-  entry->cc = cc;
-}
-
-
-
-/**
- * Notify @a path that it is no longer used for connection @a cc which
- * ended at the path's offset @a off.
- *
- * @param path the path to forget the @a cc
- * @param off the offset where the @a cc ended
- * @param cc the connection to forget
- */
-void
-GCPP_del_connection (struct CadetPeerPath *path,
-                     unsigned int off,
-                     struct CadetConnection *cc)
-{
-  struct CadetPeerPathEntry *entry;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Removing connection %s to path %s at offset %u\n",
-       GCC_2s (cc),
-       GCPP_2s (path),
-       off);
-  GNUNET_assert (off < path->entries_length);
-  entry = path->entries[off];
-  GNUNET_assert (cc == entry->cc);
-  entry->cc = NULL;
-}
-
-
-/**
- * This path is no longer needed, free resources.
- *
- * @param path path resources to free
- */
-static void
-path_destroy (struct CadetPeerPath *path)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying path %s\n",
-       GCPP_2s (path));
-  for (unsigned int i=0;i<path->entries_length;i++)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[i];
-
-    if (NULL != entry->cc)
-    {
-      struct CadetTConnection *ct;
-
-      ct = GCC_get_ct (entry->cc);
-      if (NULL != ct)
-        GCT_connection_lost (ct);
-      GCC_destroy_without_tunnel (entry->cc);
-    }
-    GNUNET_free (entry);
-  }
-  GNUNET_free (path->entries);
-  GNUNET_free (path);
-}
-
-
-/**
- * The owning peer of this path is no longer interested in maintaining
- * it, so the path should be discarded or shortened (in case a
- * previous peer on the path finds the path desirable).
- *
- * @param path the path that is being released
- */
-void
-GCPP_release (struct CadetPeerPath *path)
-{
-  struct CadetPeerPathEntry *entry;
-  int force;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Owner releases path %s\n",
-       GCPP_2s (path));
-  path->hn = NULL;
-  entry = path->entries[path->entries_length - 1];
-  GNUNET_assert (path == entry->path);
-  while (1)
-  {
-    /* cut 'off' end of path */
-    GNUNET_assert (NULL == entry->cc);
-    GCP_path_entry_remove (entry->peer,
-                           entry,
-                           path->entries_length - 1);
-    path->entries_length--; /* We don't bother shrinking the 'entries' array,
-                               as it's probably not worth it. */
-    GNUNET_free (entry);
-    if (0 == path->entries_length)
-      break; /* the end */
-
-    /* see if new peer at the end likes this path any better */
-    entry = path->entries[path->entries_length - 1];
-    GNUNET_assert (path == entry->path);
-    force = (NULL == entry->cc) ? GNUNET_NO : GNUNET_YES;
-    path->hn = GCP_attach_path (entry->peer,
-                                path,
-                                path->entries_length - 1,
-                                force);
-    if (NULL != path->hn)
-      return; /* yep, got attached, we are done. */
-    GNUNET_assert (GNUNET_NO == force);
-  }
-
-  /* nobody wants us, discard the path */
-  path_destroy (path);
-}
-
-
-/**
- * Updates the score for an entry on the path based
- * on our experiences with using @a path.
- *
- * @param path the path to update
- * @param off offset of the entry to update
- * @param delta change in the score to apply
- */
-void
-GCPP_update_score (struct CadetPeerPath *path,
-                   unsigned int off,
-                   int delta)
-{
-  struct CadetPeerPathEntry *entry;
-
-  GNUNET_assert (off < path->entries_length);
-  entry = path->entries[off];
-
-  /* Add delta, with checks for overflows */
-  if (delta >= 0)
-  {
-    if (delta + entry->score < entry->score)
-      entry->score = INT_MAX;
-    else
-      entry->score += delta;
-  }
-  else
-  {
-    if (delta + entry->score > entry->score)
-      entry->score = INT_MIN;
-    else
-      entry->score += delta;
-  }
-  recalculate_path_desirability (path);
-}
-
-
-/**
- * Closure for #find_peer_at() and #check_match().
- */
-struct CheckMatchContext
-{
-
-  /**
-   * Set to a matching path, if any.
-   */
-  struct CadetPeerPath *match;
-
-  /**
-   * Array the combined paths.
-   */
-  struct CadetPeer **cpath;
-
-  /**
-   * How long is the @e cpath array?
-   */
-  unsigned int cpath_length;
-
-};
-
-
-/**
- * Check if the given path is identical on all of the
- * hops until @a off, and not longer than @a off.  If the
- * @a path matches, store it in `match`.
- *
- * @param cls the `struct CheckMatchContext` to check against
- * @param path the path to check
- * @param off offset to check at
- * @return #GNUNET_YES (continue to iterate), or if found #GNUNET_NO
- */
-static int
-check_match (void *cls,
-             struct CadetPeerPath *path,
-             unsigned int off)
-{
-  struct CheckMatchContext *cm_ctx = cls;
-
-  GNUNET_assert (path->entries_length > off);
-  if ( (path->entries_length != off + 1) &&
-       (off + 1 != cm_ctx->cpath_length) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "check_match missmatch because path %s is too long (%u vs. %u vs. %u)\n",
-         GCPP_2s (path),
-         path->entries_length,
-         off + 1,
-         cm_ctx->cpath_length);
-    return GNUNET_YES; /* too long, goes somewhere else already, thus cannot be useful */
-  }
-  for (unsigned int i=0;i<off;i++)
-    if (cm_ctx->cpath[i] !=
-        GCPP_get_peer_at_offset (path,
-                                 i))
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "check_match path %s missmatches at offset %u\n",
-           GCPP_2s (path),
-           i);
-      return GNUNET_YES; /* missmatch, ignore */
-    }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "check_match found match with path %s\n",
-       GCPP_2s (path));
-  cm_ctx->match = path;
-  return GNUNET_NO; /* match, we are done! */
-}
-
-
-/**
- * Extend path @a path by the @a num_peers from the @a peers
- * array, assuming the owners past the current owner want it.
- *
- * @param path path to extend
- * @param peers list of peers beyond the end of @a path
- * @param num_peers length of the @a peers array
- * @param force force attachment, even if we have other
- *        paths already
- */
-static void
-extend_path (struct CadetPeerPath *path,
-             struct CadetPeer **peers,
-             unsigned int num_peers,
-             int force)
-{
-  unsigned int old_len = path->entries_length;
-  int i;
-
-  /* Expand path */
-  GNUNET_array_grow (path->entries,
-                     path->entries_length,
-                     old_len + num_peers);
-  for (i=num_peers-1;i >= 0;i--)
-  {
-    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
-
-    path->entries[old_len + i] = entry;
-    entry->peer = peers[i];
-    entry->path = path;
-  }
-  for (i=num_peers-1;i >= 0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[old_len + i];
-
-    GCP_path_entry_add (entry->peer,
-                        entry,
-                        old_len + i);
-  }
-
-  /* If we extend an existing path, detach it from the
-     old owner and re-attach to the new one */
-  GCP_detach_path (path->entries[old_len-1]->peer,
-                   path,
-                   path->hn);
-  path->hn = NULL;
-  for (i=num_peers-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[old_len + i];
-
-    path->entries_length = old_len + i + 1;
-    recalculate_path_desirability (path);
-    path->hn = GCP_attach_path (peers[i],
-                                path,
-                                old_len + (unsigned int) i,
-                                force);
-    if (NULL != path->hn)
-      break;
-    GNUNET_assert (NULL == entry->cc);
-    GCP_path_entry_remove (entry->peer,
-                           entry,
-                           old_len + i);
-    GNUNET_free (entry);
-    path->entries[old_len + i] = NULL;
-  }
-  if (NULL == path->hn)
-  {
-    /* none of the peers is interested in this path;
-       shrink path back and re-attach. */
-    GNUNET_array_grow (path->entries,
-                       path->entries_length,
-                       old_len);
-    path->hn = GCP_attach_path (path->entries[old_len - 1]->peer,
-                                path,
-                                old_len - 1,
-                                GNUNET_YES);
-    GNUNET_assert (NULL != path->hn);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Extended path %s\n",
-       GCPP_2s (path));
-}
-
-
-/**
- * Create a peer path based on the result of a DHT lookup.  If we
- * already know this path, or one that is longer, simply return NULL.
- * Otherwise, we try to extend an existing path, or create a new one
- * if applicable.
- *
- * @param get_path path of the get request
- * @param get_path_length lenght of @a get_path
- * @param put_path path of the put request
- * @param put_path_length length of the @a put_path
- * @return a path through the network
- */
-void
-GCPP_try_path_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 CadetPeer *cpath[get_path_length + put_path_length];
-  struct CheckMatchContext cm_ctx;
-  struct CadetPeerPath *path;
-  struct GNUNET_CONTAINER_HeapNode *hn;
-  int i;
-  unsigned int skip;
-  unsigned int total_len;
-
-  /* precompute 'cpath' so we can avoid doing the lookups lots of times */
-  skip = 0;
-  memset (cpath,
-          0,
-          sizeof (cpath)); /* Just to trigger harder errors later. */
-  total_len = get_path_length + put_path_length;
-  for (unsigned int off=0;off<total_len;off++)
-  {
-    const struct GNUNET_PeerIdentity *pid;
-
-    pid = (off < get_path_length)
-      ? &get_path[get_path_length - off]
-      : &put_path[get_path_length + put_path_length - off];
-    cpath[off - skip] = GCP_get (pid,
-                                 GNUNET_YES);
-    /* Check that no peer is twice on the path */
-    for (unsigned int i=0;i<off - skip;i++)
-    {
-     if (cpath[i] == cpath[off - skip])
-      {
-        skip = off - i;
-        break;
-      }
-    }
-  }
-  total_len -= skip;
-
-  /* First figure out if this path is a subset of an existing path, an
-     extension of an existing path, or a new path. */
-  cm_ctx.cpath_length = total_len;
-  cm_ctx.cpath = cpath;
-  cm_ctx.match = NULL;
-  for (i=total_len-1;i>=0;i--)
-  {
-    GCP_iterate_paths_at (cpath[i],
-                          (unsigned int) i,
-                          &check_match,
-                          &cm_ctx);
-    if (NULL != cm_ctx.match)
-    {
-      if (i == total_len - 1)
-      {
-        /* Existing path includes this one, nothing to do! */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Path discovered from DHT is already known\n");
-        return;
-      }
-      if (cm_ctx.match->entries_length == i + 1)
-      {
-        /* Existing path ends in the middle of new path, extend it! */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Trying to extend existing path %s by additional links discovered from DHT\n",
-             GCPP_2s (cm_ctx.match));
-        extend_path (cm_ctx.match,
-                     &cpath[i + 1],
-                     total_len - i - 1,
-                     GNUNET_NO);
-        return;
-      }
-    }
-  }
-
-  /* No match at all, create completely new path */
-  path = GNUNET_new (struct CadetPeerPath);
-  path->entries_length = total_len;
-  path->entries = GNUNET_new_array (path->entries_length,
-                                    struct CadetPeerPathEntry *);
-  for (i=path->entries_length-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
-
-    path->entries[i] = entry;
-    entry->peer = cpath[i];
-    entry->path = path;
-  }
-  for (i=path->entries_length-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[i];
-
-    GCP_path_entry_add (entry->peer,
-                        entry,
-                        i);
-  }
-
-  /* Finally, try to attach it */
-  hn = NULL;
-  for (i=total_len-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[i];
-
-    path->entries_length = i + 1;
-    recalculate_path_desirability (path);
-    hn = GCP_attach_path (cpath[i],
-                          path,
-                          (unsigned int) i,
-                          GNUNET_NO);
-    if (NULL != hn)
-      break;
-    GCP_path_entry_remove (entry->peer,
-                           entry,
-                           i);
-    GNUNET_free (entry);
-    path->entries[i] = NULL;
-  }
-  if (NULL == hn)
-  {
-    /* None of the peers on the path care about it. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Path discovered from DHT is not interesting to us\n");
-    GNUNET_free (path->entries);
-    GNUNET_free (path);
-    return;
-  }
-  path->hn = hn;
-  /* Shrink path to actual useful length */
-  GNUNET_array_grow (path->entries,
-                     path->entries_length,
-                     i + 1);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Created new path %s based on information from DHT\n",
-       GCPP_2s (path));
-}
-
-
-/**
- * We got an incoming connection, obtain the corresponding path.
- *
- * @param path_length number of segments on the @a path
- * @param pids path through the network, in reverse order (we are at the end at index @a path_length)
- * @return corresponding path object
- */
-struct CadetPeerPath *
-GCPP_get_path_from_route (unsigned int path_length,
-                          const struct GNUNET_PeerIdentity *pids)
-{
-  struct CheckMatchContext cm_ctx;
-  struct CadetPeer *cpath[path_length];
-  struct CadetPeerPath *path;
-
-  /* precompute inverted 'cpath' so we can avoid doing the lookups and
-     have the correct order */
-  for (unsigned int off=0;off<path_length;off++)
-    cpath[off] = GCP_get (&pids[path_length - 1 - off],
-                          GNUNET_YES);
-
-  /* First figure out if this path is a subset of an existing path, an
-     extension of an existing path, or a new path. */
-  cm_ctx.cpath = cpath;
-  cm_ctx.cpath_length = path_length;
-  cm_ctx.match = NULL;
-  for (int i=path_length-1;i>=0;i--)
-  {
-    GCP_iterate_paths_at (cpath[i],
-                          (unsigned int) i,
-                          &check_match,
-                          &cm_ctx);
-    if (NULL != cm_ctx.match)
-    {
-      if (i == path_length - 1)
-      {
-        /* Existing path includes this one, return the match! */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Returning existing path %s as inverse for incoming connection\n",
-             GCPP_2s (cm_ctx.match));
-        return cm_ctx.match;
-      }
-      if (cm_ctx.match->entries_length == i + 1)
-      {
-        /* Existing path ends in the middle of new path, extend it! */
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Extending existing path %s to create inverse for incoming connection\n",
-             GCPP_2s (cm_ctx.match));
-        extend_path (cm_ctx.match,
-                     &cpath[i + 1],
-                     path_length - i - 1,
-                     GNUNET_YES);
-        /* Check that extension was successful */
-        GNUNET_assert (cm_ctx.match->entries_length == path_length);
-        return cm_ctx.match;
-      }
-      /* Eh, we found a match but couldn't use it? Something is wrong. */
-      GNUNET_break (0);
-    }
-  }
-
-  /* No match at all, create completely new path */
-  path = GNUNET_new (struct CadetPeerPath);
-  path->entries_length = path_length;
-  path->entries = GNUNET_new_array (path->entries_length,
-                                    struct CadetPeerPathEntry *);
-  for (int i=path_length-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
-
-    path->entries[i] = entry;
-    entry->peer = cpath[i];
-    entry->path = path;
-  }
-  for (int i=path_length-1;i>=0;i--)
-  {
-    struct CadetPeerPathEntry *entry = path->entries[i];
-
-    GCP_path_entry_add (entry->peer,
-                        entry,
-                        i);
-  }
-  recalculate_path_desirability (path);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Created new path %s to create inverse for incoming connection\n",
-       GCPP_2s (path));
-  path->hn = GCP_attach_path (cpath[path_length - 1],
-                              path,
-                              path_length - 1,
-                              GNUNET_YES);
-  return path;
-}
-
-
-/**
- * Return the length of the path.  Excludes one end of the
- * path, so the loopback path has length 0.
- *
- * @param path path to return the length for
- * @return number of peers on the path
- */
-unsigned int
-GCPP_get_length (struct CadetPeerPath *path)
-{
-  return path->entries_length;
-}
-
-
-/**
- * Find peer's offset on path.
- *
- * @param path path to search
- * @param cp peer to look for
- * @return offset of @a cp on @a path, or UINT_MAX if not found
- */
-unsigned int
-GCPP_find_peer (struct CadetPeerPath *path,
-                struct CadetPeer *cp)
-{
-  for (unsigned int off = 0;
-       off < path->entries_length;
-       off++)
-    if (cp == GCPP_get_peer_at_offset (path,
-                                       off))
-      return off;
-  return UINT_MAX;
-}
-
-
-/**
- * Obtain the peer at offset @a off in @a path.
- *
- * @param path peer path to inspect
- * @param off offset to return, must be smaller than path length
- * @return the peer at offset @a off
- */
-struct CadetPeer *
-GCPP_get_peer_at_offset (struct CadetPeerPath *path,
-                         unsigned int off)
-{
-  GNUNET_assert (off < path->entries_length);
-  return path->entries[off]->peer;
-}
-
-
-/**
- * Convert a path to a human-readable string.
- *
- * @param path path to convert
- * @return string, to be freed by caller (unlike other *_2s APIs!)
- */
-const char *
-GCPP_2s (struct CadetPeerPath *path)
-{
-  static char buf[2048];
-  size_t off;
-  const unsigned int max_plen = (sizeof(buf) - 16) / 5 - 2; /* 5 characters per entry */
-
-  off = 0;
-  for (unsigned int i = 0;
-       i < path->entries_length;
-       i++)
-  {
-    if ( (path->entries_length > max_plen) &&
-         (i == max_plen / 2) )
-      off += GNUNET_snprintf (&buf[off],
-                              sizeof (buf) - off,
-                              "...-");
-    if ( (path->entries_length > max_plen) &&
-         (i > max_plen / 2) &&
-         (i < path->entries_length - max_plen / 2) )
-      continue;
-    off += GNUNET_snprintf (&buf[off],
-                            sizeof (buf) - off,
-                            "%s%s",
-                            GNUNET_i2s (GCP_get_id (GCPP_get_peer_at_offset (path,
-                                                                             i))),
-                            (i == path->entries_length -1) ? "" : "-");
-  }
-  GNUNET_snprintf (&buf[off],
-                   sizeof (buf) - off,
-                   "(%p)",
-                   path);
-  return buf;
-}
-
-
-/* end of gnunet-service-cadet-new_paths.c */
diff --git a/src/cadet/gnunet-service-cadet-new_paths.h b/src/cadet/gnunet-service-cadet-new_paths.h
deleted file mode 100644 (file)
index 7310d75..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_paths.h
- * @brief Information we track per path.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_PATHS_H
-#define GNUNET_SERVICE_CADET_PATHS_H
-
-#include "gnunet_util_lib.h"
-#include "gnunet-service-cadet-new.h"
-
-/**
- * Create a peer path based on the result of a DHT lookup.  If we
- * already know this path, or one that is longer, simply return NULL.
- * Otherwise, we try to extend an existing path, or create a new one
- * if applicable.
- *
- * @param get_path path of the get request
- * @param get_path_length lenght of @a get_path
- * @param put_path path of the put request
- * @param put_path_length length of the @a put_path
- */
-void
-GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
-                        unsigned int get_path_length,
-                        const struct GNUNET_PeerIdentity *put_path,
-                        unsigned int put_path_length);
-
-
-/**
- * We got an incoming connection, obtain the corresponding path.
- *
- * @param path_length number of segments on the @a path
- * @param path through the network, in reverse order (we are at the end!)
- * @return corresponding path object
- */
-struct CadetPeerPath *
-GCPP_get_path_from_route (unsigned int path_length,
-                          const struct GNUNET_PeerIdentity *pids);
-
-
-/**
- * Return the length of the path.  Excludes one end of the
- * path, so the loopback path has length 0.
- *
- * @param path path to return the length for
- * @return number of peers on the path
- */
-unsigned int
-GCPP_get_length (struct CadetPeerPath *path);
-
-
-/**
- * Return connection to @a destination using @a path, or return
- * NULL if no such connection exists.
- *
- * @param path path to traverse
- * @param destination destination node to get to, must be on path
- * @param off offset of @a destination on @a path
- * @return NULL if we have no existing connection
- *         otherwise connection from us to @a destination via @a path
- */
-struct CadetConnection *
-GCPP_get_connection (struct CadetPeerPath *path,
-                     struct CadetPeer *destination,
-                     unsigned int off);
-
-
-/**
- * Notify @a path that it is used for connection @a cc
- * which ends at the path's offset @a off.
- *
- * @param path the path to remember the @a cc
- * @param off the offset where the @a cc ends
- * @param cc the connection to remember
- */
-void
-GCPP_add_connection (struct CadetPeerPath *path,
-                     unsigned int off,
-                     struct CadetConnection *cc);
-
-
-/**
- * Notify @a path that it is no longer used for connection @a cc which
- * ended at the path's offset @a off.
- *
- * @param path the path to forget the @a cc
- * @param off the offset where the @a cc ended
- * @param cc the connection to forget
- */
-void
-GCPP_del_connection (struct CadetPeerPath *path,
-                     unsigned int off,
-                     struct CadetConnection *cc);
-
-
-/**
- * Find peer's offset on path.
- *
- * @param path path to search
- * @param cp peer to look for
- * @return offset of @a cp on @a path, or UINT_MAX if not found
- */
-unsigned int
-GCPP_find_peer (struct CadetPeerPath *path,
-                struct CadetPeer *cp);
-
-
-/**
- * Return how much we like keeping the path.  This is an aggregate
- * score based on various factors, including the age of the path
- * (older == better), and the value of this path to all of its ajacent
- * peers.  For example, long paths that end at a peer that we have no
- * shorter way to reach are very desirable, while long paths that end
- * at a peer for which we have a shorter way as well are much less
- * desirable.  Higher values indicate more valuable paths.  The
- * returned value should be used to decide which paths to remember.
- *
- * @param path path to return the length for
- * @return desirability of the path, larger is more desirable
- */
-GNUNET_CONTAINER_HeapCostType
-GCPP_get_desirability (const struct CadetPeerPath *path);
-
-
-/**
- * The given peer @a cp used to own this @a path.  However, it is no
- * longer interested in maintaining it, so the path should be
- * discarded or shortened (in case a previous peer on the path finds
- * the path desirable).
- *
- * @param path the path that is being released
- */
-void
-GCPP_release (struct CadetPeerPath *path);
-
-
-/**
- * Obtain the peer at offset @a off in @a path.
- *
- * @param path peer path to inspect
- * @param off offset to return, must be smaller than path length
- * @return peer at offset @a off
- */
-struct CadetPeer *
-GCPP_get_peer_at_offset (struct CadetPeerPath *path,
-                         unsigned int off);
-
-
-/**
- * Convert a path to a human-readable string.
- *
- * @param path path to convert
- * @return string, statically allocated
- */
-const char *
-GCPP_2s (struct CadetPeerPath *p);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_peer.c b/src/cadet/gnunet-service-cadet-new_peer.c
deleted file mode 100644 (file)
index 350c8ef..0000000
+++ /dev/null
@@ -1,1477 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_peer.c
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * TODO:
- * - optimize stopping/restarting DHT search to situations
- *   where we actually need it (i.e. not if we have a direct connection,
- *   or if we already have plenty of good short ones, or maybe even
- *   to take a break if we have some connections and have searched a lot (?))
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_hello_lib.h"
-#include "gnunet_signatures.h"
-#include "gnunet_transport_service.h"
-#include "gnunet_ats_service.h"
-#include "gnunet_core_service.h"
-#include "gnunet_statistics_service.h"
-#include "cadet_protocol.h"
-#include "gnunet-service-cadet-new.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_dht.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
-
-
-/**
- * How long do we wait until tearing down an idle peer?
- */
-#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
-
-/**
- * How long do we keep paths around if we no longer care about the peer?
- */
-#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
-
-
-
-
-/**
- * Data structure used to track whom we have to notify about changes
- * to our message queue.
- */
-struct GCP_MessageQueueManager
-{
-
-  /**
-   * Kept in a DLL.
-   */
-  struct GCP_MessageQueueManager *next;
-
-  /**
-   * Kept in a DLL.
-   */
-  struct GCP_MessageQueueManager *prev;
-
-  /**
-   * Function to call with updated message queue object.
-   */
-  GCP_MessageQueueNotificationCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-  /**
-   * The peer this is for.
-   */
-  struct CadetPeer *cp;
-
-  /**
-   * Envelope this manager would like to transmit once it is its turn.
-   */
-  struct GNUNET_MQ_Envelope *env;
-
-};
-
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetPeer
-{
-  /**
-   * ID of the peer
-   */
-  struct GNUNET_PeerIdentity pid;
-
-  /**
-   * Last time we heard from this peer (currently not used!)
-   */
-  struct GNUNET_TIME_Absolute last_contactXXX;
-
-  /**
-   * Array of DLLs of paths traversing the peer, organized by the
-   * offset of the peer on the larger path.
-   */
-  struct CadetPeerPathEntry **path_heads;
-
-  /**
-   * Array of DLL of paths traversing the peer, organized by the
-   * offset of the peer on the larger path.
-   */
-  struct CadetPeerPathEntry **path_tails;
-
-  /**
-   * Notifications to call when @e core_mq changes.
-   */
-  struct GCP_MessageQueueManager *mqm_head;
-
-  /**
-   * Notifications to call when @e core_mq changes.
-   */
-  struct GCP_MessageQueueManager *mqm_tail;
-
-  /**
-   * Pointer to first "ready" entry in @e mqm_head.
-   */
-  struct GCP_MessageQueueManager *mqm_ready_ptr;
-
-  /**
-   * MIN-heap of paths owned by this peer (they also end at this
-   * peer).  Ordered by desirability.
-   */
-  struct GNUNET_CONTAINER_Heap *path_heap;
-
-  /**
-   * Handle to stop the DHT search for paths to this peer
-   */
-  struct GCD_search_handle *search_h;
-
-  /**
-   * Task to clean up @e path_heap asynchronously.
-   */
-  struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
-
-  /**
-   * Task to destroy this entry.
-   */
-  struct GNUNET_SCHEDULER_Task *destroy_task;
-
-  /**
-   * Tunnel to this peer, if any.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Connections that go through this peer; indexed by tid.
-   */
-  struct GNUNET_CONTAINER_MultiShortmap *connections;
-
-  /**
-   * Handle for core transmissions.
-   */
-  struct GNUNET_MQ_Handle *core_mq;
-
-  /**
-   * Hello message of the peer.
-   */
-  struct GNUNET_HELLO_Message *hello;
-
-  /**
-   * Handle to us offering the HELLO to the transport.
-   */
-  struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
-
-  /**
-   * Handle to our ATS request asking ATS to suggest an address
-   * to TRANSPORT for this peer (to establish a direct link).
-   */
-  struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
-
-  /**
-   * How many messages are in the queue to this peer.
-   */
-  unsigned int queue_n;
-
-  /**
-   * How many paths do we have to this peer (in all @e path_heads DLLs combined).
-   */
-  unsigned int num_paths;
-
-  /**
-   * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
-   * Used to speed-up @GCP_get_desirability_of_path() calculation.
-   */
-  unsigned int off_sum;
-
-  /**
-   * Number of message queue managers of this peer that have a message in waiting.
-   *
-   * Used to quickly see if we need to bother scanning the @e msm_head DLL.
-   * TODO: could be replaced by another DLL that would then allow us to avoid
-   * the O(n)-scan of the DLL for ready entries!
-   */
-  unsigned int mqm_ready_counter;
-
-  /**
-   * Current length of the @e path_heads and @path_tails arrays.
-   * The arrays should be grown as needed.
-   */
-  unsigned int path_dll_length;
-
-};
-
-
-/**
- * Get the static string for a peer ID.
- *
- * @param cp Peer.
- * @return Static string for it's ID.
- */
-const char *
-GCP_2s (const struct CadetPeer *cp)
-{
-  static char buf[32];
-
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "P(%s)",
-                   GNUNET_i2s (&cp->pid));
-  return buf;
-}
-
-
-/**
- * Calculate how desirable a path is for @a cp if @a cp
- * is at offset @a off.
- *
- * The 'desirability_table.c' program can be used to compute a list of
- * sample outputs for different scenarios.  Basically, we score paths
- * lower if there are many alternatives, and higher if they are
- * shorter than average, and very high if they are much shorter than
- * average and without many alternatives.
- *
- * @param cp a peer reachable via a path
- * @param off offset of @a cp in the path
- * @return score how useful a path is to reach @a cp,
- *         positive scores mean path is more desirable
- */
-double
-GCP_get_desirability_of_path (struct CadetPeer *cp,
-                              unsigned int off)
-{
-  unsigned int num_alts = cp->num_paths;
-  unsigned int off_sum;
-  double avg_sum;
-  double path_delta;
-  double weight_alts;
-
-  GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
-  GNUNET_assert (0 != cp->path_dll_length);
-
-  /* We maintain 'off_sum' in 'peer' and thereby
-     avoid the SLOW recalculation each time. Kept here
-     just to document what is going on. */
-#if SLOW
-  off_sum = 0;
-  for (unsigned int j=0;j<cp->path_dll_length;j++)
-    for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
-         NULL != pe;
-         pe = pe->next)
-      off_sum += j;
-  GNUNET_assert (off_sum == cp->off_sum);
-#else
-  off_sum = cp->off_sum;
-#endif
-  avg_sum = off_sum * 1.0 / cp->path_dll_length;
-  path_delta = off - avg_sum;
-  /* path_delta positiv: path off of peer above average (bad path for peer),
-     path_delta negativ: path off of peer below average (good path for peer) */
-  if (path_delta <= - 1.0)
-    weight_alts = - num_alts / path_delta; /* discount alternative paths */
-  else if (path_delta >= 1.0)
-    weight_alts = num_alts * path_delta; /* overcount alternative paths */
-  else
-    weight_alts = num_alts; /* count alternative paths normally */
-
-
-  /* off+1: long paths are generally harder to find and thus count
-     a bit more as they get longer.  However, above-average paths
-     still need to count less, hence the squaring of that factor. */
-  return (off + 1.0) / (weight_alts * weight_alts);
-}
-
-
-/**
- * This peer is no longer be needed, clean it up now.
- *
- * @param cls peer to clean up
- */
-static void
-destroy_peer (void *cls)
-{
-  struct CadetPeer *cp = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying state about peer %s\n",
-       GCP_2s (cp));
-  cp->destroy_task = NULL;
-  GNUNET_assert (NULL == cp->t);
-  GNUNET_assert (NULL == cp->core_mq);
-  GNUNET_assert (0 == cp->num_paths);
-  for (unsigned int i=0;i<cp->path_dll_length;i++)
-    GNUNET_assert (NULL == cp->path_heads[i]);
-  GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multipeermap_remove (peers,
-                                                       &cp->pid,
-                                                       cp));
-  GNUNET_free_non_null (cp->path_heads);
-  GNUNET_free_non_null (cp->path_tails);
-  cp->path_dll_length = 0;
-  if (NULL != cp->search_h)
-  {
-    GCD_search_stop (cp->search_h);
-    cp->search_h = NULL;
-  }
-  /* FIXME: clean up search_delayedXXX! */
-
-  if (NULL != cp->hello_offer)
-  {
-    GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
-    cp->hello_offer = NULL;
-  }
-  if (NULL != cp->connectivity_suggestion)
-  {
-    GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
-    cp->connectivity_suggestion = NULL;
-  }
-  GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
-  if (NULL != cp->path_heap)
-  {
-    GNUNET_CONTAINER_heap_destroy (cp->path_heap);
-    cp->path_heap = NULL;
-  }
-  if (NULL != cp->heap_cleanup_task)
-  {
-    GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
-    cp->heap_cleanup_task = NULL;
-  }
-  GNUNET_free_non_null (cp->hello);
-  /* Peer should not be freed if paths exist; if there are no paths,
-     there ought to be no connections, and without connections, no
-     notifications. Thus we can assert that mqm_head is empty at this
-     point. */
-  GNUNET_assert (NULL == cp->mqm_head);
-  GNUNET_assert (NULL == cp->mqm_ready_ptr);
-  GNUNET_free (cp);
-}
-
-
-/**
- * This peer is now on more "active" duty, activate processes related to it.
- *
- * @param cp the more-active peer
- */
-static void
-consider_peer_activate (struct CadetPeer *cp)
-{
-  uint32_t strength;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Updating peer %s activation state (%u connections)%s%s\n",
-       GCP_2s (cp),
-       GNUNET_CONTAINER_multishortmap_size (cp->connections),
-       (NULL == cp->t) ? "" : " with tunnel",
-       (NULL == cp->core_mq) ? "" : " with CORE link");
-  if (NULL != cp->destroy_task)
-  {
-    /* It's active, do not destory! */
-    GNUNET_SCHEDULER_cancel (cp->destroy_task);
-    cp->destroy_task = NULL;
-  }
-  if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
-       (NULL == cp->t) )
-  {
-    /* We're just on a path or directly connected; don't bother too much */
-    if (NULL != cp->connectivity_suggestion)
-    {
-      GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
-      cp->connectivity_suggestion = NULL;
-    }
-    if (NULL != cp->search_h)
-    {
-      GCD_search_stop (cp->search_h);
-      cp->search_h = NULL;
-    }
-    return;
-  }
-  if (NULL == cp->core_mq)
-  {
-    /* Lacks direct connection, try to create one by querying the DHT */
-    if ( (NULL == cp->search_h) &&
-         (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
-      cp->search_h
-        = GCD_search (&cp->pid);
-  }
-  else
-  {
-    /* Have direct connection, stop DHT search if active */
-    if (NULL != cp->search_h)
-    {
-      GCD_search_stop (cp->search_h);
-      cp->search_h = NULL;
-    }
-  }
-
-  /* If we have a tunnel, our urge for connections is much bigger */
-  strength = (NULL != cp->t) ? 32 : 1;
-  if (NULL != cp->connectivity_suggestion)
-    GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
-  cp->connectivity_suggestion
-    = GNUNET_ATS_connectivity_suggest (ats_ch,
-                                       &cp->pid,
-                                       strength);
-}
-
-
-/**
- * This peer may no longer be needed, consider cleaning it up.
- *
- * @param cp peer to clean up
- */
-static void
-consider_peer_destroy (struct CadetPeer *cp);
-
-
-/**
- * We really no longere care about a peer, stop hogging memory with paths to it.
- * Afterwards, see if there is more to be cleaned up about this peer.
- *
- * @param cls a `struct CadetPeer`.
- */
-static void
-drop_paths (void *cls)
-{
-  struct CadetPeer *cp = cls;
-  struct CadetPeerPath *path;
-
-  cp->destroy_task = NULL;
-  while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
-    GCPP_release (path);
-  consider_peer_destroy (cp);
-}
-
-
-/**
- * This peer may no longer be needed, consider cleaning it up.
- *
- * @param cp peer to clean up
- */
-static void
-consider_peer_destroy (struct CadetPeer *cp)
-{
-  struct GNUNET_TIME_Relative exp;
-
-  if (NULL != cp->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (cp->destroy_task);
-    cp->destroy_task = NULL;
-  }
-  if (NULL != cp->t)
-    return; /* still relevant! */
-  if (NULL != cp->core_mq)
-    return; /* still relevant! */
-  if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
-    return; /* still relevant! */
-  if ( (NULL != cp->path_heap) &&
-       (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
-  {
-    cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
-                                                     &drop_paths,
-                                                     cp);
-    return;
-  }
-  if (0 != cp->num_paths)
-    return; /* still relevant! */
-  if (NULL != cp->hello)
-  {
-    /* relevant only until HELLO expires */
-    exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
-    cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
-                                                     &destroy_peer,
-                                                     cp);
-    return;
-  }
-  cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
-                                                   &destroy_peer,
-                                                   cp);
-}
-
-
-/**
- * Set the message queue to @a mq for peer @a cp and notify watchers.
- *
- * @param cp peer to modify
- * @param mq message queue to set (can be NULL)
- */
-void
-GCP_set_mq (struct CadetPeer *cp,
-            struct GNUNET_MQ_Handle *mq)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Message queue for peer %s is now %p\n",
-       GCP_2s (cp),
-       mq);
-  cp->core_mq = mq;
-  for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
-       NULL != mqm;
-       mqm = next)
-  {
-    /* Save next pointer in case mqm gets freed by the callback */
-    next = mqm->next;
-    if (NULL == mq)
-    {
-      if (NULL != mqm->env)
-      {
-        GNUNET_MQ_discard (mqm->env);
-        mqm->env = NULL;
-        mqm->cb (mqm->cb_cls,
-                 GNUNET_SYSERR);
-      }
-      else
-      {
-        mqm->cb (mqm->cb_cls,
-                 GNUNET_NO);
-      }
-    }
-    else
-    {
-      GNUNET_assert (NULL == mqm->env);
-      mqm->cb (mqm->cb_cls,
-               GNUNET_YES);
-    }
-  }
-  if ( (NULL != mq) ||
-       (NULL != cp->t) )
-    consider_peer_activate (cp);
-  else
-    consider_peer_destroy (cp);
-
-  if ( (NULL != mq) &&
-       (NULL != cp->t) )
-  {
-    /* have a new, direct path to the target, notify tunnel */
-    struct CadetPeerPath *path;
-
-    path = GCPP_get_path_from_route (1,
-                                     &cp->pid);
-    GCT_consider_path (cp->t,
-                       path,
-                       0);
-  }
-}
-
-
-/**
- * Debug function should NEVER return true in production code, useful to
- * simulate losses for testcases.
- *
- * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
- */
-static int
-should_I_drop (void)
-{
-  if (0 == drop_percent)
-    return GNUNET_NO;
-  if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                101) < drop_percent)
-    return GNUNET_YES;
-  return GNUNET_NO;
-}
-
-
-/**
- * Function called when CORE took one of the messages from
- * a message queue manager and transmitted it.
- *
- * @param cls the `struct CadetPeeer` where we made progress
- */
-static void
-mqm_send_done (void *cls);
-
-
-/**
- * Transmit current envelope from this @a mqm.
- *
- * @param mqm mqm to transmit message for now
- */
-static void
-mqm_execute (struct GCP_MessageQueueManager *mqm)
-{
-  struct CadetPeer *cp = mqm->cp;
-
-  /* Move ready pointer to the next entry that might be ready. */
-  if ( (mqm == cp->mqm_ready_ptr) &&
-       (NULL != mqm->next) )
-    cp->mqm_ready_ptr = mqm->next;
-  /* Move entry to the end of the DLL, to be fair. */
-  if (mqm != cp->mqm_tail)
-  {
-    GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
-                                 cp->mqm_tail,
-                                 mqm);
-    GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
-                                      cp->mqm_tail,
-                                      mqm);
-  }
-  cp->mqm_ready_counter--;
-  if (GNUNET_YES == should_I_drop ())
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "DROPPING message to peer %s from MQM %p\n",
-         GCP_2s (cp),
-         mqm);
-    GNUNET_MQ_discard (mqm->env);
-    mqm->env = NULL;
-    mqm_send_done (cp);
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Sending to peer %s from MQM %p\n",
-         GCP_2s (cp),
-         mqm);
-    GNUNET_MQ_send (cp->core_mq,
-                    mqm->env);
-    mqm->env = NULL;
-  }
-  mqm->cb (mqm->cb_cls,
-           GNUNET_YES);
-}
-
-
-/**
- * Find the next ready message in the queue (starting
- * the search from the `cp->mqm_ready_ptr`) and if possible
- * execute the transmission.
- *
- * @param cp peer to try to send the next ready message to
- */
-static void
-send_next_ready (struct CadetPeer *cp)
-{
-  struct GCP_MessageQueueManager *mqm;
-
-  if (0 == cp->mqm_ready_counter)
-    return;
-  while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
-          (NULL == mqm->env) )
-    cp->mqm_ready_ptr = mqm->next;
-  if (NULL == mqm)
-    return; /* nothing to do */
-  mqm_execute (mqm);
-}
-
-
-/**
- * Function called when CORE took one of the messages from
- * a message queue manager and transmitted it.
- *
- * @param cls the `struct CadetPeeer` where we made progress
- */
-static void
-mqm_send_done (void *cls)
-{
-  struct CadetPeer *cp = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending to peer %s completed\n",
-       GCP_2s (cp));
-  send_next_ready (cp);
-}
-
-
-/**
- * Send the message in @a env to @a cp.
- *
- * @param mqm the message queue manager to use for transmission
- * @param env envelope with the message to send; must NOT
- *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
- */
-void
-GCP_send (struct GCP_MessageQueueManager *mqm,
-          struct GNUNET_MQ_Envelope *env)
-{
-  struct CadetPeer *cp = mqm->cp;
-
-  GNUNET_assert (NULL != env);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Queueing message to peer %s in MQM %p\n",
-       GCP_2s (cp),
-       mqm);
-  GNUNET_assert (NULL != cp->core_mq);
-  GNUNET_assert (NULL == mqm->env);
-  GNUNET_MQ_notify_sent (env,
-                         &mqm_send_done,
-                         cp);
-  mqm->env = env;
-  cp->mqm_ready_counter++;
-  if (mqm != cp->mqm_ready_ptr)
-    cp->mqm_ready_ptr = cp->mqm_head;
-  if (1 == cp->mqm_ready_counter)
-    cp->mqm_ready_ptr = mqm;
-  if (0 != GNUNET_MQ_get_length (cp->core_mq))
-    return;
-  send_next_ready (cp);
-}
-
-
-/**
- * Function called to destroy a peer now.
- *
- * @param cls NULL
- * @param pid identity of the peer (unused)
- * @param value the `struct CadetPeer` to clean up
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-destroy_iterator_cb (void *cls,
-                     const struct GNUNET_PeerIdentity *pid,
-                     void *value)
-{
-  struct CadetPeer *cp = value;
-
-  if (NULL != cp->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (cp->destroy_task);
-    cp->destroy_task = NULL;
-  }
-  destroy_peer (cp);
-  return GNUNET_OK;
-}
-
-
-/**
- * Clean up all entries about all peers.
- * Must only be called after all tunnels, CORE-connections and
- * connections are down.
- */
-void
-GCP_destroy_all_peers ()
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying all peers now\n");
-  GNUNET_CONTAINER_multipeermap_iterate (peers,
-                                         &destroy_iterator_cb,
-                                         NULL);
-}
-
-
-/**
- * Drop all paths owned by this peer, and do not
- * allow new ones to be added: We are shutting down.
- *
- * @param cp peer to drop paths to
- */
-void
-GCP_drop_owned_paths (struct CadetPeer *cp)
-{
-  struct CadetPeerPath *path;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying all paths to %s\n",
-       GCP_2s (cp));
-  while (NULL != (path =
-                  GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
-    GCPP_release (path);
-  GNUNET_CONTAINER_heap_destroy (cp->path_heap);
-  cp->path_heap = NULL;
-}
-
-
-/**
- * Add an entry to the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_add (struct CadetPeer *cp,
-                    struct CadetPeerPathEntry *entry,
-                    unsigned int off)
-{
-  GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
-                                                off));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Discovered that peer %s is on path %s at offset %u\n",
-       GCP_2s (cp),
-       GCPP_2s (entry->path),
-       off);
-  if (off >= cp->path_dll_length)
-  {
-    unsigned int len = cp->path_dll_length;
-
-    GNUNET_array_grow (cp->path_heads,
-                       len,
-                       off + 4);
-    GNUNET_array_grow (cp->path_tails,
-                       cp->path_dll_length,
-                       off + 4);
-  }
-  GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
-                               cp->path_tails[off],
-                               entry);
-  cp->off_sum += off;
-  cp->num_paths++;
-
-  /* If we have a tunnel to this peer, tell the tunnel that there is a
-     new path available. */
-  if (NULL != cp->t)
-    GCT_consider_path (cp->t,
-                       entry->path,
-                       off);
-
-  if ( (NULL != cp->search_h) &&
-       (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
-  {
-    /* Now I have enough paths, stop search */
-    GCD_search_stop (cp->search_h);
-    cp->search_h = NULL;
-  }
-  if (NULL != cp->destroy_task)
-  {
-    /* paths changed, this resets the destroy timeout counter
-       and aborts a destroy task that may no longer be valid
-       to have (as we now have more paths via this peer). */
-    consider_peer_destroy (cp);
-  }
-}
-
-
-/**
- * Remove an entry from the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_remove (struct CadetPeer *cp,
-                       struct CadetPeerPathEntry *entry,
-                       unsigned int off)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Removing knowledge about peer %s beging on path %s at offset %u\n",
-       GCP_2s (cp),
-       GCPP_2s (entry->path),
-       off);
-  GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
-                               cp->path_tails[off],
-                               entry);
-  GNUNET_assert (0 < cp->num_paths);
-  cp->off_sum -= off;
-  cp->num_paths--;
-  if ( (NULL == cp->core_mq) &&
-       (NULL != cp->t) &&
-       (NULL == cp->search_h) &&
-       (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
-    cp->search_h
-      = GCD_search (&cp->pid);
-  if (NULL == cp->destroy_task)
-  {
-    /* paths changed, we might now be ready for destruction, check again */
-    consider_peer_destroy (cp);
-  }
-}
-
-
-/**
- * Prune down the number of paths to this peer, we seem to
- * have way too many.
- *
- * @param cls the `struct CadetPeer` to maintain the path heap for
- */
-static void
-path_heap_cleanup (void *cls)
-{
-  struct CadetPeer *cp = cls;
-  struct CadetPeerPath *root;
-
-  cp->heap_cleanup_task = NULL;
-  while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
-         2 * DESIRED_CONNECTIONS_PER_TUNNEL)
-  {
-    /* Now we have way too many, drop least desirable UNLESS it is in use!
-       (Note that this intentionally keeps highly desireable, but currently
-       unused paths around in the hope that we might be able to switch, even
-       if the number of paths exceeds the threshold.) */
-    root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
-    if (NULL !=
-        GCPP_get_connection (root,
-                             cp,
-                             GCPP_get_length (root) - 1))
-      break; /* can't fix */
-    /* Got plenty of paths to this destination, and this is a low-quality
-       one that we don't care about. Allow it to die. */
-    GNUNET_assert (root ==
-                   GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
-    GCPP_release (root);
-  }
-}
-
-
-/**
- * Try adding a @a path to this @a peer.  If the peer already
- * has plenty of paths, return NULL.
- *
- * @param cp peer to which the @a path leads to
- * @param path a path looking for an owner; may not be fully initialized yet!
- * @param off offset of @a cp in @a path
- * @param force force attaching the path
- * @return NULL if this peer does not care to become a new owner,
- *         otherwise the node in the peer's path heap for the @a path.
- */
-struct GNUNET_CONTAINER_HeapNode *
-GCP_attach_path (struct CadetPeer *cp,
-                 struct CadetPeerPath *path,
-                 unsigned int off,
-                 int force)
-{
-  GNUNET_CONTAINER_HeapCostType desirability;
-  struct CadetPeerPath *root;
-  GNUNET_CONTAINER_HeapCostType root_desirability;
-  struct GNUNET_CONTAINER_HeapNode *hn;
-
-  GNUNET_assert (off == GCPP_get_length (path) - 1);
-  GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
-                                                off));
-  if (NULL == cp->path_heap)
-  {
-    /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
-    GNUNET_assert (GNUNET_NO == force);
-    return NULL;
-  }
-  desirability = GCPP_get_desirability (path);
-  if (GNUNET_NO == force)
-  {
-    /* FIXME: desirability is not yet initialized; tricky! */
-    if (GNUNET_NO ==
-        GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
-                                     (void **) &root,
-                                     &root_desirability))
-    {
-      root = NULL;
-      root_desirability = 0;
-    }
-
-    if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
-         (desirability < root_desirability) )
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Decided to not attach path %p to peer %s due to undesirability\n",
-           GCPP_2s (path),
-           GCP_2s (cp));
-      return NULL;
-    }
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Attaching path %s to peer %s (%s)\n",
-       GCPP_2s (path),
-       GCP_2s (cp),
-       (GNUNET_NO == force) ? "desirable" : "forced");
-
-  /* Yes, we'd like to add this path, add to our heap */
-  hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
-                                     path,
-                                     desirability);
-
-  /* Consider maybe dropping other paths because of the new one */
-  if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
-        2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
-       (NULL != cp->heap_cleanup_task) )
-    cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
-                                                      cp);
-  return hn;
-}
-
-
-/**
- * This peer can no longer own @a path as the path
- * has been extended and a peer further down the line
- * is now the new owner.
- *
- * @param cp old owner of the @a path
- * @param path path where the ownership is lost
- * @param hn note in @a cp's path heap that must be deleted
- */
-void
-GCP_detach_path (struct CadetPeer *cp,
-                 struct CadetPeerPath *path,
-                 struct GNUNET_CONTAINER_HeapNode *hn)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Detatching path %s from peer %s\n",
-       GCPP_2s (path),
-       GCP_2s (cp));
-  GNUNET_assert (path ==
-                 GNUNET_CONTAINER_heap_remove_node (hn));
-}
-
-
-/**
- * Add a @a connection to this @a cp.
- *
- * @param cp peer via which the @a connection goes
- * @param cc the connection to add
- */
-void
-GCP_add_connection (struct CadetPeer *cp,
-                    struct CadetConnection *cc)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Adding connection %s to peer %s\n",
-       GCC_2s (cc),
-       GCP_2s (cp));
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multishortmap_put (cp->connections,
-                                                     &GCC_get_id (cc)->connection_of_tunnel,
-                                                     cc,
-                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  if (NULL != cp->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (cp->destroy_task);
-    cp->destroy_task = NULL;
-  }
-}
-
-
-/**
- * Remove a @a connection that went via this @a cp.
- *
- * @param cp peer via which the @a connection went
- * @param cc the connection to remove
- */
-void
-GCP_remove_connection (struct CadetPeer *cp,
-                       struct CadetConnection *cc)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Removing connection %s from peer %s\n",
-       GCC_2s (cc),
-       GCP_2s (cp));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
-                                                        &GCC_get_id (cc)->connection_of_tunnel,
-                                                        cc));
-  consider_peer_destroy (cp);
-}
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the
- * peer. Optionally create one and insert it in the appropriate
- * structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- *               #GNUNET_NO to return NULL if peer is unknown.
- * @return Existing or newly created peer structure.
- *         NULL if unknown and not requested @a create
- */
-struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id,
-         int create)
-{
-  struct CadetPeer *cp;
-
-  cp = GNUNET_CONTAINER_multipeermap_get (peers,
-                                          peer_id);
-  if (NULL != cp)
-    return cp;
-  if (GNUNET_NO == create)
-    return NULL;
-  cp = GNUNET_new (struct CadetPeer);
-  cp->pid = *peer_id;
-  cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
-                                                           GNUNET_YES);
-  cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multipeermap_put (peers,
-                                                    &cp->pid,
-                                                    cp,
-                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Creating peer %s\n",
-       GCP_2s (cp));
-  return cp;
-}
-
-
-/**
- * Obtain the peer identity for a `struct CadetPeer`.
- *
- * @param cp our peer handle
- * @return the peer identity
- */
-const struct GNUNET_PeerIdentity *
-GCP_get_id (struct CadetPeer *cp)
-{
-  return &cp->pid;
-}
-
-
-/**
- * Iterate over all known peers.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
-                 void *cls)
-{
-  GNUNET_CONTAINER_multipeermap_iterate (peers,
-                                         iter,
-                                         cls);
-}
-
-
-/**
- * Count the number of known paths toward the peer.
- *
- * @param cp Peer to get path info.
- * @return Number of known paths.
- */
-unsigned int
-GCP_count_paths (const struct CadetPeer *cp)
-{
-  return cp->num_paths;
-}
-
-
-/**
- * Iterate over the paths to a peer.
- *
- * @param cp Peer to get path info.
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths (struct CadetPeer *cp,
-                   GCP_PathIterator callback,
-                   void *callback_cls)
-{
-  unsigned int ret = 0;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Iterating over paths to peer %s%s\n",
-       GCP_2s (cp),
-       (NULL == cp->core_mq) ? "" : " including direct link");
-  if (NULL != cp->core_mq)
-  {
-    struct CadetPeerPath *path;
-
-    path = GCPP_get_path_from_route (1,
-                                     &cp->pid);
-    ret++;
-    if (GNUNET_NO ==
-        callback (callback_cls,
-                  path,
-                  0))
-      return ret;
-  }
-  for (unsigned int i=0;i<cp->path_dll_length;i++)
-  {
-    for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
-         NULL != pe;
-         pe = pe->next)
-    {
-      ret++;
-      if (GNUNET_NO ==
-          callback (callback_cls,
-                    pe->path,
-                    i))
-        return ret;
-    }
-  }
-  return ret;
-}
-
-
-/**
- * Iterate over the paths to @a cp where
- * @a cp is at distance @a dist from us.
- *
- * @param cp Peer to get path info.
- * @param dist desired distance of @a cp to us on the path
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths_at (struct CadetPeer *cp,
-                      unsigned int dist,
-                      GCP_PathIterator callback,
-                      void *callback_cls)
-{
-  unsigned int ret = 0;
-
-  if (dist >= cp->path_dll_length)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Asked to look for paths at distance %u, but maximum for me is < %u\n",
-         dist,
-         cp->path_dll_length);
-    return 0;
-  }
-  for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
-       NULL != pe;
-       pe = pe->next)
-  {
-    if (GNUNET_NO ==
-        callback (callback_cls,
-                  pe->path,
-                  dist))
-      return ret;
-    ret++;
-  }
-  return ret;
-}
-
-
-/**
- * Get the tunnel towards a peer.
- *
- * @param cp Peer to get from.
- * @param create #GNUNET_YES to create a tunnel if we do not have one
- * @return Tunnel towards peer.
- */
-struct CadetTunnel *
-GCP_get_tunnel (struct CadetPeer *cp,
-                int create)
-{
-  if (NULL == cp)
-    return NULL;
-  if ( (NULL != cp->t) ||
-       (GNUNET_NO == create) )
-    return cp->t;
-  cp->t = GCT_create_tunnel (cp);
-  consider_peer_activate (cp);
-  return cp->t;
-}
-
-
-/**
- * Hello offer was passed to the transport service. Mark it
- * as done.
- *
- * @param cls the `struct CadetPeer` where the offer completed
- */
-static void
-hello_offer_done (void *cls)
-{
-  struct CadetPeer *cp = cls;
-
-  cp->hello_offer = NULL;
-}
-
-
-/**
- * We got a HELLO for a @a peer, remember it, and possibly
- * trigger adequate actions (like trying to connect).
- *
- * @param cp the peer we got a HELLO for
- * @param hello the HELLO to remember
- */
-void
-GCP_set_hello (struct CadetPeer *cp,
-               const struct GNUNET_HELLO_Message *hello)
-{
-  struct GNUNET_HELLO_Message *mrg;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got %u byte HELLO for peer %s\n",
-       (unsigned int) GNUNET_HELLO_size (hello),
-       GCP_2s (cp));
-  if (NULL != cp->hello_offer)
-  {
-    GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
-    cp->hello_offer = NULL;
-  }
-  if (NULL != cp->hello)
-  {
-    mrg = GNUNET_HELLO_merge (hello,
-                              cp->hello);
-    GNUNET_free (cp->hello);
-    cp->hello = mrg;
-  }
-  else
-  {
-    cp->hello = GNUNET_memdup (hello,
-                               GNUNET_HELLO_size (hello));
-  }
-  cp->hello_offer
-    = GNUNET_TRANSPORT_offer_hello (cfg,
-                                    GNUNET_HELLO_get_header (cp->hello) ,
-                                    &hello_offer_done,
-                                    cp);
-  /* New HELLO means cp's destruction time may change... */
-  consider_peer_destroy (cp);
-}
-
-
-/**
- * The tunnel to the given peer no longer exists, remove it from our
- * data structures, and possibly clean up the peer itself.
- *
- * @param cp the peer affected
- * @param t the dead tunnel
- */
-void
-GCP_drop_tunnel (struct CadetPeer *cp,
-                 struct CadetTunnel *t)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Dropping tunnel %s to peer %s\n",
-       GCT_2s (t),
-       GCP_2s (cp));
-  GNUNET_assert (cp->t == t);
-  cp->t = NULL;
-  consider_peer_destroy (cp);
-}
-
-
-/**
- * Test if @a cp has a core-level connection
- *
- * @param cp peer to test
- * @return #GNUNET_YES if @a cp has a core-level connection
- */
-int
-GCP_has_core_connection (struct CadetPeer *cp)
-{
-  return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
-}
-
-
-/**
- * Start message queue change notifications.
- *
- * @param cp peer to notify for
- * @param cb function to call if mq becomes available or unavailable
- * @param cb_cls closure for @a cb
- * @return handle to cancel request
- */
-struct GCP_MessageQueueManager *
-GCP_request_mq (struct CadetPeer *cp,
-                GCP_MessageQueueNotificationCallback cb,
-                void *cb_cls)
-{
-  struct GCP_MessageQueueManager *mqm;
-
-  mqm = GNUNET_new (struct GCP_MessageQueueManager);
-  mqm->cb = cb;
-  mqm->cb_cls = cb_cls;
-  mqm->cp = cp;
-  GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
-                               cp->mqm_tail,
-                               mqm);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Creating MQM %p for peer %s\n",
-       mqm,
-       GCP_2s (cp));
-  if (NULL != cp->core_mq)
-    cb (cb_cls,
-        GNUNET_YES);
-  return mqm;
-}
-
-
-/**
- * Stops message queue change notifications.
- *
- * @param mqm handle matching request to cancel
- * @param last_env final message to transmit, or NULL
- */
-void
-GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
-                       struct GNUNET_MQ_Envelope *last_env)
-{
-  struct CadetPeer *cp = mqm->cp;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying MQM %p for peer %s%s\n",
-       mqm,
-       GCP_2s (cp),
-       (NULL == last_env) ? "" : " with last ditch transmission");
-  if (NULL != mqm->env)
-    GNUNET_MQ_discard (mqm->env);
-  if (NULL != last_env)
-  {
-    if (NULL != cp->core_mq)
-    {
-      GNUNET_MQ_notify_sent (last_env,
-                             &mqm_send_done,
-                             cp);
-      GNUNET_MQ_send (cp->core_mq,
-                      last_env);
-    }
-    else
-    {
-      GNUNET_MQ_discard (last_env);
-    }
-  }
-  if (cp->mqm_ready_ptr == mqm)
-    cp->mqm_ready_ptr = mqm->next;
-  GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
-                               cp->mqm_tail,
-                               mqm);
-  GNUNET_free (mqm);
-}
-
-
-/**
- * Send the message in @a env to @a cp, overriding queueing logic.
- * This function should only be used to send error messages outside
- * of flow and congestion control, similar to ICMP.  Note that
- * the envelope may be silently discarded as well.
- *
- * @param cp peer to send the message to
- * @param env envelope with the message to send
- */
-void
-GCP_send_ooo (struct CadetPeer *cp,
-              struct GNUNET_MQ_Envelope *env)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending message to %s out of management\n",
-       GCP_2s (cp));
-  if (NULL == cp->core_mq)
-  {
-    GNUNET_MQ_discard (env);
-    return;
-  }
-  GNUNET_MQ_notify_sent (env,
-                         &mqm_send_done,
-                         cp);
-  GNUNET_MQ_send (cp->core_mq,
-                  env);
-}
-
-
-
-
-/* end of gnunet-service-cadet-new_peer.c */
diff --git a/src/cadet/gnunet-service-cadet-new_peer.h b/src/cadet/gnunet-service-cadet-new_peer.h
deleted file mode 100644 (file)
index e1d6fc3..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_peer.h
- * @brief Information we track per peer.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_PEER_H
-#define GNUNET_SERVICE_CADET_PEER_H
-
-#include "gnunet-service-cadet-new.h"
-#include "gnunet_hello_lib.h"
-
-
-/**
- * Get the static string for a peer ID.
- *
- * @param peer Peer.
- *
- * @return Static string for it's ID.
- */
-const char *
-GCP_2s (const struct CadetPeer *peer);
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the
- * peer. Optionally create one and insert it in the appropriate
- * structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- *               #GNUNET_NO to return NULL if peer is unknown.
- * @return Existing or newly created peer structure.
- *         NULL if unknown and not requested @a create
- */
-struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id,
-         int create);
-
-
-/**
- * Calculate how desirable a path is for @a cp if
- * @a cp is at offset @a off in the path.
- *
- * @param cp a peer reachable via a path
- * @param off offset of @a cp in a path
- * @return score how useful a path is to reach @a cp,
- *         positive scores mean path is more desirable
- */
-double
-GCP_get_desirability_of_path (struct CadetPeer *cp,
-                              unsigned int off);
-
-
-/**
- * Obtain the peer identity for a `struct CadetPeer`.
- *
- * @param cp our peer handle
- * @return the peer identity
- */
-const struct GNUNET_PeerIdentity *
-GCP_get_id (struct CadetPeer *cp);
-
-
-/**
- * Iterate over all known peers.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
-                 void *cls);
-
-
-/**
- * Count the number of known paths toward the peer.
- *
- * @param cp Peer to get path info.
- * @return Number of known paths.
- */
-unsigned int
-GCP_count_paths (const struct CadetPeer *cp);
-
-
-/**
- * Drop all paths owned by this peer, and do not
- * allow new ones to be added: We are shutting down.
- *
- * @param cp peer to drop paths to
- */
-void
-GCP_drop_owned_paths (struct CadetPeer *cp);
-
-
-/**
- * Peer path iterator.
- *
- * @param cls Closure.
- * @param path Path itself
- * @param off offset of the target peer in @a path
- * @return #GNUNET_YES if should keep iterating.
- *         #GNUNET_NO otherwise.
- */
-typedef int
-(*GCP_PathIterator) (void *cls,
-                     struct CadetPeerPath *path,
-                     unsigned int off);
-
-
-/**
- * Iterate over the paths to a peer.
- *
- * @param cp Peer to get path info.
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths (struct CadetPeer *cp,
-                   GCP_PathIterator callback,
-                   void *callback_cls);
-
-
-/**
- * Iterate over the paths to @a peer where
- * @a peer is at distance @a dist from us.
- *
- * @param cp Peer to get path info.
- * @param dist desired distance of @a peer to us on the path
- * @param callback Function to call for every path.
- * @param callback_cls Closure for @a callback.
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths_at (struct CadetPeer *cp,
-                      unsigned int dist,
-                      GCP_PathIterator callback,
-                      void *callback_cls);
-
-
-/**
- * Remove an entry from the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_remove (struct CadetPeer *cp,
-                       struct CadetPeerPathEntry *entry,
-                       unsigned int off);
-
-
-/**
- * Add an entry to the DLL of all of the paths that this peer is on.
- *
- * @param cp peer to modify
- * @param entry an entry on a path
- * @param off offset of this peer on the path
- */
-void
-GCP_path_entry_add (struct CadetPeer *cp,
-                    struct CadetPeerPathEntry *entry,
-                    unsigned int off);
-
-
-/**
- * Get the tunnel towards a peer.
- *
- * @param cp Peer to get from.
- * @param create #GNUNET_YES to create a tunnel if we do not have one
- * @return Tunnel towards peer.
- */
-struct CadetTunnel *
-GCP_get_tunnel (struct CadetPeer *cp,
-                int create);
-
-
-/**
- * The tunnel to the given peer no longer exists, remove it from our
- * data structures, and possibly clean up the peer itself.
- *
- * @param cp the peer affected
- * @param t the dead tunnel
- */
-void
-GCP_drop_tunnel (struct CadetPeer *cp,
-                 struct CadetTunnel *t);
-
-
-/**
- * Try adding a @a path to this @a cp.  If the peer already
- * has plenty of paths, return NULL.
- *
- * @param cp peer to which the @a path leads to
- * @param path a path looking for an owner; may not be fully initialized yet!
- * @param off offset of @a cp in @a path
- * @param force for attaching the path
- * @return NULL if this peer does not care to become a new owner,
- *         otherwise the node in the peer's path heap for the @a path.
- */
-struct GNUNET_CONTAINER_HeapNode *
-GCP_attach_path (struct CadetPeer *cp,
-                 struct CadetPeerPath *path,
-                 unsigned int off,
-                 int force);
-
-
-/**
- * This peer can no longer own @a path as the path
- * has been extended and a peer further down the line
- * is now the new owner.
- *
- * @param cp old owner of the @a path
- * @param path path where the ownership is lost
- * @param hn note in @a cp's path heap that must be deleted
- */
-void
-GCP_detach_path (struct CadetPeer *cp,
-                 struct CadetPeerPath *path,
-                 struct GNUNET_CONTAINER_HeapNode *hn);
-
-
-/**
- * Add a @a connection to this @a cp.
- *
- * @param cp peer via which the @a connection goes
- * @param cc the connection to add
- */
-void
-GCP_add_connection (struct CadetPeer *cp,
-                    struct CadetConnection *cc);
-
-
-/**
- * Remove a @a connection that went via this @a cp.
- *
- * @param cp peer via which the @a connection went
- * @param cc the connection to remove
- */
-void
-GCP_remove_connection (struct CadetPeer *cp,
-                       struct CadetConnection *cc);
-
-
-/**
- * We got a HELLO for a @a cp, remember it, and possibly
- * trigger adequate actions (like trying to connect).
- *
- * @param cp the peer we got a HELLO for
- * @param hello the HELLO to remember
- */
-void
-GCP_set_hello (struct CadetPeer *cp,
-               const struct GNUNET_HELLO_Message *hello);
-
-
-/**
- * Clean up all entries about all peers.
- * Must only be called after all tunnels, CORE-connections and
- * connections are down.
- */
-void
-GCP_destroy_all_peers (void);
-
-
-/**
- * Data structure used to track whom we have to notify about changes
- * in our ability to transmit to a given peer.
- *
- * All queue managers will be given equal chance for sending messages
- * to @a cp.  This construct this guarantees fairness for access to @a
- * cp among the different message queues.  Each connection or route
- * will have its respective message queue managers for each direction.
- */
-struct GCP_MessageQueueManager;
-
-
-/**
- * Function to call with updated message queue object.
- *
- * @param cls closure
- * @param available #GNUNET_YES if sending is now possible,
- *                  #GNUNET_NO if sending is no longer possible
- *                  #GNUNET_SYSERR if sending is no longer possible
- *                                 and the last envelope was discarded
- */
-typedef void
-(*GCP_MessageQueueNotificationCallback)(void *cls,
-                                        int available);
-
-
-/**
- * Start message queue change notifications.  Will create a new slot
- * to manage the message queue to the given @a cp.
- *
- * @param cp peer to notify for
- * @param cb function to call if mq becomes available or unavailable
- * @param cb_cls closure for @a cb
- * @return handle to cancel request
- */
-struct GCP_MessageQueueManager *
-GCP_request_mq (struct CadetPeer *cp,
-                GCP_MessageQueueNotificationCallback cb,
-                void *cb_cls);
-
-
-/**
- * Test if @a cp has a core-level connection
- *
- * @param cp peer to test
- * @return #GNUNET_YES if @a cp has a core-level connection
- */
-int
-GCP_has_core_connection (struct CadetPeer *cp);
-
-
-/**
- * Send the message in @a env via a @a mqm.  Must only be called at
- * most once after the respective
- * #GCP_MessageQueueNotificationCallback was called with `available`
- * set to #GNUNET_YES, and not after the callback was called with
- * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
- *
- * @param mqm message queue manager for the transmission
- * @param env envelope with the message to send; must NOT
- *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
- */
-void
-GCP_send (struct GCP_MessageQueueManager *mqm,
-          struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * Send the message in @a env to @a cp, overriding queueing logic.
- * This function should only be used to send error messages outside
- * of flow and congestion control, similar to ICMP.  Note that
- * the envelope may be silently discarded as well.
- *
- * @param cp peer to send the message to
- * @param env envelope with the message to send
- */
-void
-GCP_send_ooo (struct CadetPeer *cp,
-              struct GNUNET_MQ_Envelope *env);
-
-
-/**
- * Stops message queue change notifications and sends a last message.
- * In practice, this is implemented by sending that @a last_env
- * message immediately (if any), ignoring queue order.
- *
- * @param mqm handle matching request to cancel
- * @param last_env final message to transmit, or NULL
- */
-void
-GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
-                       struct GNUNET_MQ_Envelope *last_env);
-
-
-/**
- * Set the message queue to @a mq for peer @a cp and notify watchers.
- *
- * @param cp peer to modify
- * @param mq message queue to set (can be NULL)
- */
-void
-GCP_set_mq (struct CadetPeer *cp,
-            struct GNUNET_MQ_Handle *mq);
-
-
-#endif
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet-new_tunnels.c
deleted file mode 100644 (file)
index bf05fae..0000000
+++ /dev/null
@@ -1,3437 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet-new_tunnels.c
- * @brief Information we track per tunnel.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- *
- * FIXME:
- * - proper connection evaluation during connection management:
- *   + consider quality (or quality spread?) of current connection set
- *     when deciding how often to do maintenance
- *   + interact with PEER to drive DHT GET/PUT operations based
- *     on how much we like our connections
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_statistics_service.h"
-#include "gnunet_signatures.h"
-#include "gnunet-service-cadet-new.h"
-#include "cadet_protocol.h"
-#include "gnunet-service-cadet-new_channel.h"
-#include "gnunet-service-cadet-new_connection.h"
-#include "gnunet-service-cadet-new_tunnels.h"
-#include "gnunet-service-cadet-new_peer.h"
-#include "gnunet-service-cadet-new_paths.h"
-
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
-
-/**
- * How often do we try to decrypt payload with unverified key
- * material?  Used to limit CPU increase upon receiving bogus
- * KX.
- */
-#define MAX_UNVERIFIED_ATTEMPTS 16
-
-/**
- * How long do we wait until tearing down an idle tunnel?
- */
-#define IDLE_DESTROY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
-
-/**
- * How long do we wait initially before retransmitting the KX?
- * TODO: replace by 2 RTT if/once we have connection-level RTT data!
- */
-#define INITIAL_KX_RETRY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
-
-/**
- * Maximum number of skipped keys we keep in memory per tunnel.
- */
-#define MAX_SKIPPED_KEYS 64
-
-/**
- * Maximum number of keys (and thus ratchet steps) we are willing to
- * skip before we decide this is either a bogus packet or a DoS-attempt.
- */
-#define MAX_KEY_GAP 256
-
-
-/**
- * Struct to old keys for skipped messages while advancing the Axolotl ratchet.
- */
-struct CadetTunnelSkippedKey
-{
-  /**
-   * DLL next.
-   */
-  struct CadetTunnelSkippedKey *next;
-
-  /**
-   * DLL prev.
-   */
-  struct CadetTunnelSkippedKey *prev;
-
-  /**
-   * When was this key stored (for timeout).
-   */
-  struct GNUNET_TIME_Absolute timestamp;
-
-  /**
-   * Header key.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey HK;
-
-  /**
-   * Message key.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-
-  /**
-   * Key number for a given HK.
-   */
-  unsigned int Kn;
-};
-
-
-/**
- * Axolotl data, according to https://github.com/trevp/axolotl/wiki .
- */
-struct CadetTunnelAxolotl
-{
-  /**
-   * A (double linked) list of stored message keys and associated header keys
-   * for "skipped" messages, i.e. messages that have not been
-   * received despite the reception of more recent messages, (head).
-   */
-  struct CadetTunnelSkippedKey *skipped_head;
-
-  /**
-   * Skipped messages' keys DLL, tail.
-   */
-  struct CadetTunnelSkippedKey *skipped_tail;
-
-  /**
-   * 32-byte root key which gets updated by DH ratchet.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey RK;
-
-  /**
-   * 32-byte header key (currently used for sending).
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey HKs;
-
-  /**
-   * 32-byte header key (currently used for receiving)
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey HKr;
-
-  /**
-   * 32-byte next header key (for sending), used once the
-   * ratchet advances.  We are sure that the sender has this
-   * key as well only after @e ratchet_allowed is #GNUNET_YES.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey NHKs;
-
-  /**
-   * 32-byte next header key (for receiving).  To be tried
-   * when decrypting with @e HKr fails and thus the sender
-   * may have advanced the ratchet.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey NHKr;
-
-  /**
-   * 32-byte chain keys (used for forward-secrecy) for
-   * sending messages. Updated for every message.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey CKs;
-
-  /**
-   * 32-byte chain keys (used for forward-secrecy) for
-   * receiving messages. Updated for every message. If
-   * messages are skipped, the respective derived MKs
-   * (and the current @HKr) are kept in the @e skipped_head DLL.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
-
-  /**
-   * ECDH for key exchange (A0 / B0).
-   */
-  struct GNUNET_CRYPTO_EcdhePrivateKey kx_0;
-
-  /**
-   * ECDH Ratchet key (our private key in the current DH).
-   */
-  struct GNUNET_CRYPTO_EcdhePrivateKey DHRs;
-
-  /**
-   * ECDH Ratchet key (other peer's public key in the current DH).
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
-
-  /**
-   * Time when the current ratchet expires and a new one is triggered
-   * (if @e ratchet_allowed is #GNUNET_YES).
-   */
-  struct GNUNET_TIME_Absolute ratchet_expiration;
-
-  /**
-   * Number of elements in @a skipped_head <-> @a skipped_tail.
-   */
-  unsigned int skipped;
-
-  /**
-   * Message number (reset to 0 with each new ratchet, next message to send).
-   */
-  uint32_t Ns;
-
-  /**
-   * Message number (reset to 0 with each new ratchet, next message to recv).
-   */
-  uint32_t Nr;
-
-  /**
-   * Previous message numbers (# of msgs sent under prev ratchet)
-   */
-  uint32_t PNs;
-
-  /**
-   * True (#GNUNET_YES) if we have to send a new ratchet key in next msg.
-   */
-  int ratchet_flag;
-
-  /**
-   * True (#GNUNET_YES) if we have received a message from the
-   * other peer that uses the keys from our last ratchet step.
-   * This implies that we are again allowed to advance the ratchet,
-   * otherwise we have to wait until the other peer sees our current
-   * ephemeral key and advances first.
-   *
-   * #GNUNET_NO if we have advanced the ratched but lack any evidence
-   * that the other peer has noticed this.
-   */
-  int ratchet_allowed;
-
-  /**
-   * Number of messages recieved since our last ratchet advance.
-   *
-   * If this counter = 0, we cannot send a new ratchet key in the next
-   * message.
-   *
-   * If this counter > 0, we could (but don't have to) send a new key.
-   *
-   * Once the @e ratchet_counter is larger than
-   * #ratchet_messages (or @e ratchet_expiration time has past), and
-   * @e ratchet_allowed is #GNUNET_YES, we advance the ratchet.
-   */
-  unsigned int ratchet_counter;
-
-};
-
-
-/**
- * Struct used to save messages in a non-ready tunnel to send once connected.
- */
-struct CadetTunnelQueueEntry
-{
-  /**
-   * We are entries in a DLL
-   */
-  struct CadetTunnelQueueEntry *next;
-
-  /**
-   * We are entries in a DLL
-   */
-  struct CadetTunnelQueueEntry *prev;
-
-  /**
-   * Tunnel these messages belong in.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Continuation to call once sent (on the channel layer).
-   */
-  GCT_SendContinuation cont;
-
-  /**
-   * Closure for @c cont.
-   */
-  void *cont_cls;
-
-  /**
-   * Envelope of message to send follows.
-   */
-  struct GNUNET_MQ_Envelope *env;
-
-  /**
-   * Where to put the connection identifier into the payload
-   * of the message in @e env once we have it?
-   */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier *cid;
-};
-
-
-/**
- * Struct containing all information regarding a tunnel to a peer.
- */
-struct CadetTunnel
-{
-  /**
-   * Destination of the tunnel.
-   */
-  struct CadetPeer *destination;
-
-  /**
-   * Peer's ephemeral key, to recreate @c e_key and @c d_key when own
-   * ephemeral key changes.
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key;
-
-  /**
-   * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
-
-  /**
-   * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
-
-  /**
-   * Axolotl info.
-   */
-  struct CadetTunnelAxolotl ax;
-
-  /**
-   * Unverified Axolotl info, used only if we got a fresh KX (not a
-   * KX_AUTH) while our end of the tunnel was still up.  In this case,
-   * we keep the fresh KX around but do not put it into action until
-   * we got encrypted payload that assures us of the authenticity of
-   * the KX.
-   */
-  struct CadetTunnelAxolotl *unverified_ax;
-
-  /**
-   * Task scheduled if there are no more channels using the tunnel.
-   */
-  struct GNUNET_SCHEDULER_Task *destroy_task;
-
-  /**
-   * Task to trim connections if too many are present.
-   */
-  struct GNUNET_SCHEDULER_Task *maintain_connections_task;
-
-  /**
-   * Task to send messages from queue (if possible).
-   */
-  struct GNUNET_SCHEDULER_Task *send_task;
-
-  /**
-   * Task to trigger KX.
-   */
-  struct GNUNET_SCHEDULER_Task *kx_task;
-
-  /**
-   * Tokenizer for decrypted messages.
-   */
-  struct GNUNET_MessageStreamTokenizer *mst;
-
-  /**
-   * Dispatcher for decrypted messages only (do NOT use for sending!).
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * DLL of ready connections that are actively used to reach the destination peer.
-   */
-  struct CadetTConnection *connection_ready_head;
-
-  /**
-   * DLL of ready connections that are actively used to reach the destination peer.
-   */
-  struct CadetTConnection *connection_ready_tail;
-
-  /**
-   * DLL of connections that we maintain that might be used to reach the destination peer.
-   */
-  struct CadetTConnection *connection_busy_head;
-
-  /**
-   * DLL of connections that we maintain that might be used to reach the destination peer.
-   */
-  struct CadetTConnection *connection_busy_tail;
-
-  /**
-   * Channels inside this tunnel. Maps
-   * `struct GNUNET_CADET_ChannelTunnelNumber` to a `struct CadetChannel`.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
-
-  /**
-   * Channel ID for the next created channel in this tunnel.
-   */
-  struct GNUNET_CADET_ChannelTunnelNumber next_ctn;
-
-  /**
-   * Queued messages, to transmit once tunnel gets connected.
-   */
-  struct CadetTunnelQueueEntry *tq_head;
-
-  /**
-   * Queued messages, to transmit once tunnel gets connected.
-   */
-  struct CadetTunnelQueueEntry *tq_tail;
-
-  /**
-   * Identification of the connection from which we are currently processing
-   * a message. Only valid (non-NULL) during #handle_decrypted() and the
-   * handle-*()-functions called from our @e mq during that function.
-   */
-  struct CadetTConnection *current_ct;
-
-  /**
-   * How long do we wait until we retry the KX?
-   */
-  struct GNUNET_TIME_Relative kx_retry_delay;
-
-  /**
-   * When do we try the next KX?
-   */
-  struct GNUNET_TIME_Absolute next_kx_attempt;
-
-  /**
-   * Number of connections in the @e connection_ready_head DLL.
-   */
-  unsigned int num_ready_connections;
-
-  /**
-   * Number of connections in the @e connection_busy_head DLL.
-   */
-  unsigned int num_busy_connections;
-
-  /**
-   * How often have we tried and failed to decrypt a message using
-   * the unverified KX material from @e unverified_ax?  Used to
-   * stop trying after #MAX_UNVERIFIED_ATTEMPTS.
-   */
-  unsigned int unverified_attempts;
-
-  /**
-   * Number of entries in the @e tq_head DLL.
-   */
-  unsigned int tq_len;
-
-  /**
-   * State of the tunnel encryption.
-   */
-  enum CadetTunnelEState estate;
-
-  /**
-   * Force triggering KX_AUTH independent of @e estate.
-   */
-  int kx_auth_requested;
-
-};
-
-
-/**
- * Connection @a ct is now unready, clear it's ready flag
- * and move it from the ready DLL to the busy DLL.
- *
- * @param ct connection to move to unready status
- */
-static void
-mark_connection_unready (struct CadetTConnection *ct)
-{
-  struct CadetTunnel *t = ct->t;
-
-  GNUNET_assert (GNUNET_YES == ct->is_ready);
-  GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
-                               t->connection_ready_tail,
-                               ct);
-  GNUNET_assert (0 < t->num_ready_connections);
-  t->num_ready_connections--;
-  ct->is_ready = GNUNET_NO;
-  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
-                               t->connection_busy_tail,
-                               ct);
-  t->num_busy_connections++;
-}
-
-
-/**
- * Get the static string for the peer this tunnel is directed.
- *
- * @param t Tunnel.
- *
- * @return Static string the destination peer's ID.
- */
-const char *
-GCT_2s (const struct CadetTunnel *t)
-{
-  static char buf[64];
-
-  if (NULL == t)
-    return "Tunnel(NULL)";
-  GNUNET_snprintf (buf,
-                   sizeof (buf),
-                   "Tunnel %s",
-                   GNUNET_i2s (GCP_get_id (t->destination)));
-  return buf;
-}
-
-
-/**
- * Get string description for tunnel encryption state.
- *
- * @param es Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-estate2s (enum CadetTunnelEState es)
-{
-  static char buf[32];
-
-  switch (es)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED:
-    return "CADET_TUNNEL_KEY_UNINITIALIZED";
-  case CADET_TUNNEL_KEY_AX_RECV:
-    return "CADET_TUNNEL_KEY_AX_RECV";
-  case CADET_TUNNEL_KEY_AX_SENT:
-    return "CADET_TUNNEL_KEY_AX_SENT";
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-    return "CADET_TUNNEL_KEY_AX_SENT_AND_RECV";
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    return "CADET_TUNNEL_KEY_AX_AUTH_SENT";
-  case CADET_TUNNEL_KEY_OK:
-    return "CADET_TUNNEL_KEY_OK";
-  default:
-    GNUNET_snprintf (buf,
-                     sizeof (buf),
-                     "%u (UNKNOWN STATE)",
-                     es);
-    return buf;
-  }
-}
-
-
-/**
- * Return the peer to which this tunnel goes.
- *
- * @param t a tunnel
- * @return the destination of the tunnel
- */
-struct CadetPeer *
-GCT_get_destination (struct CadetTunnel *t)
-{
-  return t->destination;
-}
-
-
-/**
- * Count channels of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of channels.
- */
-unsigned int
-GCT_count_channels (struct CadetTunnel *t)
-{
-  return GNUNET_CONTAINER_multihashmap32_size (t->channels);
-}
-
-
-/**
- * Lookup a channel by its @a ctn.
- *
- * @param t tunnel to look in
- * @param ctn number of channel to find
- * @return NULL if channel does not exist
- */
-struct CadetChannel *
-lookup_channel (struct CadetTunnel *t,
-                struct GNUNET_CADET_ChannelTunnelNumber ctn)
-{
-  return GNUNET_CONTAINER_multihashmap32_get (t->channels,
-                                              ntohl (ctn.cn));
-}
-
-
-/**
- * Count all created connections of a tunnel. Not necessarily ready connections!
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections created, either being established or ready.
- */
-unsigned int
-GCT_count_any_connections (const struct CadetTunnel *t)
-{
-  return t->num_ready_connections + t->num_busy_connections;
-}
-
-
-/**
- * Find first connection that is ready in the list of
- * our connections.  Picks ready connections round-robin.
- *
- * @param t tunnel to search
- * @return NULL if we have no connection that is ready
- */
-static struct CadetTConnection *
-get_ready_connection (struct CadetTunnel *t)
-{
-  struct CadetTConnection *hd = t->connection_ready_head;
-
-  GNUNET_assert ( (NULL == hd) ||
-                  (GNUNET_YES == hd->is_ready) );
-  return hd;
-}
-
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnelEState
-GCT_get_estate (struct CadetTunnel *t)
-{
-  return t->estate;
-}
-
-
-/**
- * Called when either we have a new connection, or a new message in the
- * queue, or some existing connection has transmission capacity.  Looks
- * at our message queue and if there is a message, picks a connection
- * to send it on.
- *
- * @param cls the `struct CadetTunnel` to process messages on
- */
-static void
-trigger_transmissions (void *cls);
-
-
-/* ************************************** start core crypto ***************************** */
-
-
-/**
- * Create a new Axolotl ephemeral (ratchet) key.
- *
- * @param ax key material to update
- */
-static void
-new_ephemeral (struct CadetTunnelAxolotl *ax)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Creating new ephemeral ratchet key (DHRs)\n");
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_ecdhe_key_create2 (&ax->DHRs));
-}
-
-
-/**
- * Calculate HMAC.
- *
- * @param plaintext Content to HMAC.
- * @param size Size of @c plaintext.
- * @param iv Initialization vector for the message.
- * @param key Key to use.
- * @param hmac[out] Destination to store the HMAC.
- */
-static void
-t_hmac (const void *plaintext,
-        size_t size,
-        uint32_t iv,
-        const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
-        struct GNUNET_ShortHashCode *hmac)
-{
-  static const char ctx[] = "cadet authentication key";
-  struct GNUNET_CRYPTO_AuthKey auth_key;
-  struct GNUNET_HashCode hash;
-
-  GNUNET_CRYPTO_hmac_derive_key (&auth_key,
-                                 key,
-                                 &iv, sizeof (iv),
-                                 key, sizeof (*key),
-                                 ctx, sizeof (ctx),
-                                 NULL);
-  /* Two step: GNUNET_ShortHash is only 256 bits,
-     GNUNET_HashCode is 512, so we truncate. */
-  GNUNET_CRYPTO_hmac (&auth_key,
-                      plaintext,
-                      size,
-                      &hash);
-  GNUNET_memcpy (hmac,
-                 &hash,
-                 sizeof (*hmac));
-}
-
-
-/**
- * Perform a HMAC.
- *
- * @param key Key to use.
- * @param[out] hash Resulting HMAC.
- * @param source Source key material (data to HMAC).
- * @param len Length of @a source.
- */
-static void
-t_ax_hmac_hash (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
-                struct GNUNET_HashCode *hash,
-                const void *source,
-                unsigned int len)
-{
-  static const char ctx[] = "axolotl HMAC-HASH";
-  struct GNUNET_CRYPTO_AuthKey auth_key;
-
-  GNUNET_CRYPTO_hmac_derive_key (&auth_key,
-                                 key,
-                                 ctx, sizeof (ctx),
-                                 NULL);
-  GNUNET_CRYPTO_hmac (&auth_key,
-                      source,
-                      len,
-                      hash);
-}
-
-
-/**
- * Derive a symmetric encryption key from an HMAC-HASH.
- *
- * @param key Key to use for the HMAC.
- * @param[out] out Key to generate.
- * @param source Source key material (data to HMAC).
- * @param len Length of @a source.
- */
-static void
-t_hmac_derive_key (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
-                   struct GNUNET_CRYPTO_SymmetricSessionKey *out,
-                   const void *source,
-                   unsigned int len)
-{
-  static const char ctx[] = "axolotl derive key";
-  struct GNUNET_HashCode h;
-
-  t_ax_hmac_hash (key,
-                  &h,
-                  source,
-                  len);
-  GNUNET_CRYPTO_kdf (out, sizeof (*out),
-                     ctx, sizeof (ctx),
-                     &h, sizeof (h),
-                     NULL);
-}
-
-
-/**
- * Encrypt data with the axolotl tunnel key.
- *
- * @param ax key material to use.
- * @param dst Destination with @a size bytes for the encrypted data.
- * @param src Source of the plaintext. Can overlap with @c dst, must contain @a size bytes
- * @param size Size of the buffers at @a src and @a dst
- */
-static void
-t_ax_encrypt (struct CadetTunnelAxolotl *ax,
-              void *dst,
-              const void *src,
-              size_t size)
-{
-  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  size_t out_size;
-
-  ax->ratchet_counter++;
-  if ( (GNUNET_YES == ax->ratchet_allowed) &&
-       ( (ratchet_messages <= ax->ratchet_counter) ||
-         (0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us)) )
-  {
-    ax->ratchet_flag = GNUNET_YES;
-  }
-  if (GNUNET_YES == ax->ratchet_flag)
-  {
-    /* Advance ratchet */
-    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3];
-    struct GNUNET_HashCode dh;
-    struct GNUNET_HashCode hmac;
-    static const char ctx[] = "axolotl ratchet";
-
-    new_ephemeral (ax);
-    ax->HKs = ax->NHKs;
-
-    /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
-    GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
-                            &ax->DHRr,
-                            &dh);
-    t_ax_hmac_hash (&ax->RK,
-                    &hmac,
-                    &dh,
-                    sizeof (dh));
-    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
-                       ctx, sizeof (ctx),
-                       &hmac, sizeof (hmac),
-                       NULL);
-    ax->RK = keys[0];
-    ax->NHKs = keys[1];
-    ax->CKs = keys[2];
-
-    ax->PNs = ax->Ns;
-    ax->Ns = 0;
-    ax->ratchet_flag = GNUNET_NO;
-    ax->ratchet_allowed = GNUNET_NO;
-    ax->ratchet_counter = 0;
-    ax->ratchet_expiration
-      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
-                                  ratchet_time);
-  }
-
-  t_hmac_derive_key (&ax->CKs,
-                     &MK,
-                     "0",
-                     1);
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &MK,
-                                     NULL, 0,
-                                     NULL);
-
-  out_size = GNUNET_CRYPTO_symmetric_encrypt (src,
-                                              size,
-                                              &MK,
-                                              &iv,
-                                              dst);
-  GNUNET_assert (size == out_size);
-  t_hmac_derive_key (&ax->CKs,
-                     &ax->CKs,
-                     "1",
-                     1);
-}
-
-
-/**
- * Decrypt data with the axolotl tunnel key.
- *
- * @param ax key material to use.
- * @param dst Destination for the decrypted data, must contain @a size bytes.
- * @param src Source of the ciphertext. Can overlap with @c dst, must contain @a size bytes.
- * @param size Size of the @a src and @a dst buffers
- */
-static void
-t_ax_decrypt (struct CadetTunnelAxolotl *ax,
-              void *dst,
-              const void *src,
-              size_t size)
-{
-  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  size_t out_size;
-
-  t_hmac_derive_key (&ax->CKr,
-                     &MK,
-                     "0",
-                     1);
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &MK,
-                                     NULL, 0,
-                                     NULL);
-  GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
-  out_size = GNUNET_CRYPTO_symmetric_decrypt (src,
-                                              size,
-                                              &MK,
-                                              &iv,
-                                              dst);
-  GNUNET_assert (out_size == size);
-  t_hmac_derive_key (&ax->CKr,
-                     &ax->CKr,
-                     "1",
-                     1);
-}
-
-
-/**
- * Encrypt header with the axolotl header key.
- *
- * @param ax key material to use.
- * @param[in|out] msg Message whose header to encrypt.
- */
-static void
-t_h_encrypt (struct CadetTunnelAxolotl *ax,
-             struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  size_t out_size;
-
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &ax->HKs,
-                                     NULL, 0,
-                                     NULL);
-  out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->ax_header,
-                                              sizeof (struct GNUNET_CADET_AxHeader),
-                                              &ax->HKs,
-                                              &iv,
-                                              &msg->ax_header);
-  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
-}
-
-
-/**
- * Decrypt header with the current axolotl header key.
- *
- * @param ax key material to use.
- * @param src Message whose header to decrypt.
- * @param dst Where to decrypt header to.
- */
-static void
-t_h_decrypt (struct CadetTunnelAxolotl *ax,
-             const struct GNUNET_CADET_TunnelEncryptedMessage *src,
-             struct GNUNET_CADET_TunnelEncryptedMessage *dst)
-{
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  size_t out_size;
-
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &ax->HKr,
-                                     NULL, 0,
-                                     NULL);
-  out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
-                                              sizeof (struct GNUNET_CADET_AxHeader),
-                                              &ax->HKr,
-                                              &iv,
-                                              &dst->ax_header.Ns);
-  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
-}
-
-
-/**
- * Delete a key from the list of skipped keys.
- *
- * @param ax key material to delete @a key from.
- * @param key Key to delete.
- */
-static void
-delete_skipped_key (struct CadetTunnelAxolotl *ax,
-                    struct CadetTunnelSkippedKey *key)
-{
-  GNUNET_CONTAINER_DLL_remove (ax->skipped_head,
-                               ax->skipped_tail,
-                               key);
-  GNUNET_free (key);
-  ax->skipped--;
-}
-
-
-/**
- * Decrypt and verify data with the appropriate tunnel key and verify that the
- * data has not been altered since it was sent by the remote peer.
- *
- * @param ax key material to use.
- * @param dst Destination for the plaintext.
- * @param src Source of the message. Can overlap with @c dst.
- * @param size Size of the message.
- * @return Size of the decrypted data, -1 if an error was encountered.
- */
-static ssize_t
-try_old_ax_keys (struct CadetTunnelAxolotl *ax,
-                 void *dst,
-                 const struct GNUNET_CADET_TunnelEncryptedMessage *src,
-                 size_t size)
-{
-  struct CadetTunnelSkippedKey *key;
-  struct GNUNET_ShortHashCode *hmac;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
-  struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK;
-  size_t esize;
-  size_t res;
-  size_t len;
-  unsigned int N;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Trying skipped keys\n");
-  hmac = &plaintext_header.hmac;
-  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-
-  /* Find a correct Header Key */
-  valid_HK = NULL;
-  for (key = ax->skipped_head; NULL != key; key = key->next)
-  {
-    t_hmac (&src->ax_header,
-            sizeof (struct GNUNET_CADET_AxHeader) + esize,
-            0,
-            &key->HK,
-            hmac);
-    if (0 == memcmp (hmac,
-                     &src->hmac,
-                     sizeof (*hmac)))
-    {
-      valid_HK = &key->HK;
-      break;
-    }
-  }
-  if (NULL == key)
-    return -1;
-
-  /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */
-  GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage));
-  len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-  GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader));
-
-  /* Decrypt header */
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &key->HK,
-                                     NULL, 0,
-                                     NULL);
-  res = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
-                                         sizeof (struct GNUNET_CADET_AxHeader),
-                                         &key->HK,
-                                         &iv,
-                                         &plaintext_header.ax_header.Ns);
-  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == res);
-
-  /* Find the correct message key */
-  N = ntohl (plaintext_header.ax_header.Ns);
-  while ( (NULL != key) &&
-          (N != key->Kn) )
-    key = key->next;
-  if ( (NULL == key) ||
-       (0 != memcmp (&key->HK,
-                     valid_HK,
-                     sizeof (*valid_HK))) )
-    return -1;
-
-  /* Decrypt payload */
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
-                                     &key->MK,
-                                     NULL,
-                                     0,
-                                     NULL);
-  res = GNUNET_CRYPTO_symmetric_decrypt (&src[1],
-                                         len,
-                                         &key->MK,
-                                         &iv,
-                                         dst);
-  delete_skipped_key (ax,
-                      key);
-  return res;
-}
-
-
-/**
- * Delete a key from the list of skipped keys.
- *
- * @param ax key material to delete from.
- * @param HKr Header Key to use.
- */
-static void
-store_skipped_key (struct CadetTunnelAxolotl *ax,
-                   const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr)
-{
-  struct CadetTunnelSkippedKey *key;
-
-  key = GNUNET_new (struct CadetTunnelSkippedKey);
-  key->timestamp = GNUNET_TIME_absolute_get ();
-  key->Kn = ax->Nr;
-  key->HK = ax->HKr;
-  t_hmac_derive_key (&ax->CKr,
-                     &key->MK,
-                     "0",
-                     1);
-  t_hmac_derive_key (&ax->CKr,
-                     &ax->CKr,
-                     "1",
-                     1);
-  GNUNET_CONTAINER_DLL_insert (ax->skipped_head,
-                               ax->skipped_tail,
-                               key);
-  ax->skipped++;
-  ax->Nr++;
-}
-
-
-/**
- * Stage skipped AX keys and calculate the message key.
- * Stores each HK and MK for skipped messages.
- *
- * @param ax key material to use
- * @param HKr Header key.
- * @param Np Received meesage number.
- * @return #GNUNET_OK if keys were stored.
- *         #GNUNET_SYSERR if an error ocurred (@a Np not expected).
- */
-static int
-store_ax_keys (struct CadetTunnelAxolotl *ax,
-               const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr,
-               uint32_t Np)
-{
-  int gap;
-
-  gap = Np - ax->Nr;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Storing skipped keys [%u, %u)\n",
-       ax->Nr,
-       Np);
-  if (MAX_KEY_GAP < gap)
-  {
-    /* Avoid DoS (forcing peer to do more than #MAX_KEY_GAP HMAC operations) */
-    /* TODO: start new key exchange on return */
-    GNUNET_break_op (0);
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Got message %u, expected %u+\n",
-         Np,
-         ax->Nr);
-    return GNUNET_SYSERR;
-  }
-  if (0 > gap)
-  {
-    /* Delayed message: don't store keys, flag to try old keys. */
-    return GNUNET_SYSERR;
-  }
-
-  while (ax->Nr < Np)
-    store_skipped_key (ax,
-                       HKr);
-
-  while (ax->skipped > MAX_SKIPPED_KEYS)
-    delete_skipped_key (ax,
-                        ax->skipped_tail);
-  return GNUNET_OK;
-}
-
-
-/**
- * Decrypt and verify data with the appropriate tunnel key and verify that the
- * data has not been altered since it was sent by the remote peer.
- *
- * @param ax key material to use
- * @param dst Destination for the plaintext.
- * @param src Source of the message. Can overlap with @c dst.
- * @param size Size of the message.
- * @return Size of the decrypted data, -1 if an error was encountered.
- */
-static ssize_t
-t_ax_decrypt_and_validate (struct CadetTunnelAxolotl *ax,
-                           void *dst,
-                           const struct GNUNET_CADET_TunnelEncryptedMessage *src,
-                           size_t size)
-{
-  struct GNUNET_ShortHashCode msg_hmac;
-  struct GNUNET_HashCode hmac;
-  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
-  uint32_t Np;
-  uint32_t PNp;
-  size_t esize; /* Size of encryped payload */
-
-  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-
-  /* Try current HK */
-  t_hmac (&src->ax_header,
-          sizeof (struct GNUNET_CADET_AxHeader) + esize,
-          0, &ax->HKr,
-          &msg_hmac);
-  if (0 != memcmp (&msg_hmac,
-                   &src->hmac,
-                   sizeof (msg_hmac)))
-  {
-    static const char ctx[] = "axolotl ratchet";
-    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */
-    struct GNUNET_CRYPTO_SymmetricSessionKey HK;
-    struct GNUNET_HashCode dh;
-    struct GNUNET_CRYPTO_EcdhePublicKey *DHRp;
-
-    /* Try Next HK */
-    t_hmac (&src->ax_header,
-            sizeof (struct GNUNET_CADET_AxHeader) + esize,
-            0,
-            &ax->NHKr,
-            &msg_hmac);
-    if (0 != memcmp (&msg_hmac,
-                     &src->hmac,
-                     sizeof (msg_hmac)))
-    {
-      /* Try the skipped keys, if that fails, we're out of luck. */
-      return try_old_ax_keys (ax,
-                              dst,
-                              src,
-                              size);
-    }
-    HK = ax->HKr;
-    ax->HKr = ax->NHKr;
-    t_h_decrypt (ax,
-                 src,
-                 &plaintext_header);
-    Np = ntohl (plaintext_header.ax_header.Ns);
-    PNp = ntohl (plaintext_header.ax_header.PNs);
-    DHRp = &plaintext_header.ax_header.DHRs;
-    store_ax_keys (ax,
-                   &HK,
-                   PNp);
-
-    /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
-    GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
-                            DHRp,
-                            &dh);
-    t_ax_hmac_hash (&ax->RK,
-                    &hmac,
-                    &dh, sizeof (dh));
-    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
-                       ctx, sizeof (ctx),
-                       &hmac, sizeof (hmac),
-                       NULL);
-
-    /* Commit "purported" keys */
-    ax->RK = keys[0];
-    ax->NHKr = keys[1];
-    ax->CKr = keys[2];
-    ax->DHRr = *DHRp;
-    ax->Nr = 0;
-    ax->ratchet_allowed = GNUNET_YES;
-  }
-  else
-  {
-    t_h_decrypt (ax,
-                 src,
-                 &plaintext_header);
-    Np = ntohl (plaintext_header.ax_header.Ns);
-    PNp = ntohl (plaintext_header.ax_header.PNs);
-  }
-  if ( (Np != ax->Nr) &&
-       (GNUNET_OK != store_ax_keys (ax,
-                                    &ax->HKr,
-                                    Np)) )
-  {
-    /* Try the skipped keys, if that fails, we're out of luck. */
-    return try_old_ax_keys (ax,
-                            dst,
-                            src,
-                            size);
-  }
-
-  t_ax_decrypt (ax,
-                dst,
-                &src[1],
-                esize);
-  ax->Nr = Np + 1;
-  return esize;
-}
-
-
-/**
- * Our tunnel became ready for the first time, notify channels
- * that have been waiting.
- *
- * @param cls our tunnel, not used
- * @param key unique ID of the channel, not used
- * @param value the `struct CadetChannel` to notify
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-notify_tunnel_up_cb (void *cls,
-                     uint32_t key,
-                     void *value)
-{
-  struct CadetChannel *ch = value;
-
-  GCCH_tunnel_up (ch);
-  return GNUNET_OK;
-}
-
-
-/**
- * Change the tunnel encryption state.
- * If the encryption state changes to OK, stop the rekey task.
- *
- * @param t Tunnel whose encryption state to change, or NULL.
- * @param state New encryption state.
- */
-void
-GCT_change_estate (struct CadetTunnel *t,
-                   enum CadetTunnelEState state)
-{
-  enum CadetTunnelEState old = t->estate;
-
-  t->estate = state;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s estate changed from %s to %s\n",
-       GCT_2s (t),
-       estate2s (old),
-       estate2s (state));
-
-  if ( (CADET_TUNNEL_KEY_OK != old) &&
-       (CADET_TUNNEL_KEY_OK == t->estate) )
-  {
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    /* notify all channels that have been waiting */
-    GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
-                                             &notify_tunnel_up_cb,
-                                             t);
-    if (NULL != t->send_task)
-      GNUNET_SCHEDULER_cancel (t->send_task);
-    t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
-                                             t);
-  }
-}
-
-
-/**
- * Send a KX message.
- *
- * @param t tunnel on which to send the KX_AUTH
- * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
- *           we are to find one that is ready.
- * @param ax axolotl key context to use
- */
-static void
-send_kx (struct CadetTunnel *t,
-         struct CadetTConnection *ct,
-         struct CadetTunnelAxolotl *ax)
-{
-  struct CadetConnection *cc;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_TunnelKeyExchangeMessage *msg;
-  enum GNUNET_CADET_KX_Flags flags;
-
-  if ( (NULL == ct) ||
-       (GNUNET_NO == ct->is_ready) )
-    ct = get_ready_connection (t);
-  if (NULL == ct)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Wanted to send %s in state %s, but no connection is ready, deferring\n",
-         GCT_2s (t),
-         estate2s (t->estate));
-    t->next_kx_attempt = GNUNET_TIME_absolute_get ();
-    return;
-  }
-  cc = ct->cc;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending KX on %s via %s in state %s\n",
-       GCT_2s (t),
-       GCC_2s (cc),
-       estate2s (t->estate));
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
-  flags = GNUNET_CADET_KX_FLAG_FORCE_REPLY; /* always for KX */
-  msg->flags = htonl (flags);
-  msg->cid = *GCC_get_id (cc);
-  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
-                                      &msg->ephemeral_key);
-  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
-                                      &msg->ratchet_key);
-  mark_connection_unready (ct);
-  t->kx_retry_delay = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
-  t->next_kx_attempt = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
-  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_SENT);
-  else if (CADET_TUNNEL_KEY_AX_RECV == t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
-  GCC_transmit (cc,
-                env);
-}
-
-
-/**
- * Send a KX_AUTH message.
- *
- * @param t tunnel on which to send the KX_AUTH
- * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
- *           we are to find one that is ready.
- * @param ax axolotl key context to use
- * @param force_reply Force the other peer to reply with a KX_AUTH message
- *         (set if we would like to transmit right now, but cannot)
- */
-static void
-send_kx_auth (struct CadetTunnel *t,
-              struct CadetTConnection *ct,
-              struct CadetTunnelAxolotl *ax,
-              int force_reply)
-{
-  struct CadetConnection *cc;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg;
-  enum GNUNET_CADET_KX_Flags flags;
-
-  if ( (NULL == ct) ||
-       (GNUNET_NO == ct->is_ready) )
-    ct = get_ready_connection (t);
-  if (NULL == ct)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Wanted to send KX_AUTH on %s, but no connection is ready, deferring\n",
-         GCT_2s (t));
-    t->next_kx_attempt = GNUNET_TIME_absolute_get ();
-    t->kx_auth_requested = GNUNET_YES; /* queue KX_AUTH independent of estate */
-    return;
-  }
-  t->kx_auth_requested = GNUNET_NO; /* clear flag */
-  cc = ct->cc;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending KX_AUTH on %s using %s\n",
-       GCT_2s (t),
-       GCC_2s (ct->cc));
-
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH);
-  flags = GNUNET_CADET_KX_FLAG_NONE;
-  if (GNUNET_YES == force_reply)
-    flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
-  msg->kx.flags = htonl (flags);
-  msg->kx.cid = *GCC_get_id (cc);
-  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
-                                      &msg->kx.ephemeral_key);
-  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
-                                      &msg->kx.ratchet_key);
-  /* Compute authenticator (this is the main difference to #send_kx()) */
-  GNUNET_CRYPTO_hash (&ax->RK,
-                      sizeof (ax->RK),
-                      &msg->auth);
-
-  /* Compute when to be triggered again; actual job will
-     be scheduled via #connection_ready_cb() */
-  t->kx_retry_delay
-    = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
-  t->next_kx_attempt
-    = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
-
-  /* Send via cc, mark it as unready */
-  mark_connection_unready (ct);
-
-  /* Update state machine, unless we are already OK */
-  if (CADET_TUNNEL_KEY_OK != t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_AUTH_SENT);
-
-  GCC_transmit (cc,
-                env);
-}
-
-
-/**
- * Cleanup state used by @a ax.
- *
- * @param ax state to free, but not memory of @a ax itself
- */
-static void
-cleanup_ax (struct CadetTunnelAxolotl *ax)
-{
-  while (NULL != ax->skipped_head)
-    delete_skipped_key (ax,
-                        ax->skipped_head);
-  GNUNET_assert (0 == ax->skipped);
-  GNUNET_CRYPTO_ecdhe_key_clear (&ax->kx_0);
-  GNUNET_CRYPTO_ecdhe_key_clear (&ax->DHRs);
-}
-
-
-/**
- * Update our Axolotl key state based on the KX data we received.
- * Computes the new chain keys, and root keys, etc, and also checks
- * wether this is a replay of the current chain.
- *
- * @param[in|out] axolotl chain key state to recompute
- * @param pid peer identity of the other peer
- * @param ephemeral_key ephemeral public key of the other peer
- * @param ratchet_key senders next ephemeral public key
- * @return #GNUNET_OK on success, #GNUNET_NO if the resulting
- *       root key is already in @a ax and thus the KX is useless;
- *       #GNUNET_SYSERR on hard errors (i.e. @a pid is #my_full_id)
- */
-static int
-update_ax_by_kx (struct CadetTunnelAxolotl *ax,
-                 const struct GNUNET_PeerIdentity *pid,
-                 const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
-                 const struct GNUNET_CRYPTO_EcdhePublicKey *ratchet_key)
-{
-  struct GNUNET_HashCode key_material[3];
-  struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
-  const char salt[] = "CADET Axolotl salt";
-  int am_I_alice;
-
-  if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
-                                           pid))
-    am_I_alice = GNUNET_YES;
-  else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
-                                                pid))
-    am_I_alice = GNUNET_NO;
-  else
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-
-  if (0 == memcmp (&ax->DHRr,
-                   ratchet_key,
-                   sizeof (*ratchet_key)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ratchet key already known. Ignoring KX.\n");
-    return GNUNET_NO;
-  }
-
-  ax->DHRr = *ratchet_key;
-
-  /* ECDH A B0 */
-  if (GNUNET_YES == am_I_alice)
-  {
-    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
-                              ephemeral_key, /* B0 */
-                              &key_material[0]);
-  }
-  else
-  {
-    GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0,            /* B0 */
-                              &pid->public_key,    /* A */
-                              &key_material[0]);
-  }
-
-  /* ECDH A0 B */
-  if (GNUNET_YES == am_I_alice)
-  {
-    GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0,            /* A0 */
-                              &pid->public_key,    /* B */
-                              &key_material[1]);
-  }
-  else
-  {
-    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
-                              ephemeral_key, /* B0 */
-                              &key_material[1]);
-
-
-  }
-
-  /* ECDH A0 B0 */
-  /* (This is the triple-DH, we could probably safely skip this,
-     as A0/B0 are already in the key material.) */
-  GNUNET_CRYPTO_ecc_ecdh (&ax->kx_0,             /* A0 or B0 */
-                          ephemeral_key,  /* B0 or A0 */
-                          &key_material[2]);
-
-  /* KDF */
-  GNUNET_CRYPTO_kdf (keys, sizeof (keys),
-                     salt, sizeof (salt),
-                     &key_material, sizeof (key_material),
-                     NULL);
-
-  if (0 == memcmp (&ax->RK,
-                   &keys[0],
-                   sizeof (ax->RK)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Root key of handshake already known. Ignoring KX.\n");
-    return GNUNET_NO;
-  }
-
-  ax->RK = keys[0];
-  if (GNUNET_YES == am_I_alice)
-  {
-    ax->HKr = keys[1];
-    ax->NHKs = keys[2];
-    ax->NHKr = keys[3];
-    ax->CKr = keys[4];
-    ax->ratchet_flag = GNUNET_YES;
-  }
-  else
-  {
-    ax->HKs = keys[1];
-    ax->NHKr = keys[2];
-    ax->NHKs = keys[3];
-    ax->CKs = keys[4];
-    ax->ratchet_flag = GNUNET_NO;
-    ax->ratchet_expiration
-      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
-                                  ratchet_time);
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Try to redo the KX or KX_AUTH handshake, if we can.
- *
- * @param cls the `struct CadetTunnel` to do KX for.
- */
-static void
-retry_kx (void *cls)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetTunnelAxolotl *ax;
-
-  t->kx_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Trying to make KX progress on %s in state %s\n",
-       GCT_2s (t),
-       estate2s (t->estate));
-  switch (t->estate)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED: /* first attempt */
-  case CADET_TUNNEL_KEY_AX_SENT:       /* trying again */
-    send_kx (t,
-             NULL,
-             &t->ax);
-    break;
-  case CADET_TUNNEL_KEY_AX_RECV:
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-    /* We are responding, so only require reply
-       if WE have a channel waiting. */
-    if (NULL != t->unverified_ax)
-    {
-      /* Send AX_AUTH so we might get this one verified */
-      ax = t->unverified_ax;
-    }
-    else
-    {
-      /* How can this be? */
-      GNUNET_break (0);
-      ax = &t->ax;
-    }
-    send_kx_auth (t,
-                  NULL,
-                  ax,
-                  (0 == GCT_count_channels (t))
-                  ? GNUNET_NO
-                  : GNUNET_YES);
-    break;
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    /* We are responding, so only require reply
-       if WE have a channel waiting. */
-    if (NULL != t->unverified_ax)
-    {
-      /* Send AX_AUTH so we might get this one verified */
-      ax = t->unverified_ax;
-    }
-    else
-    {
-      /* How can this be? */
-      GNUNET_break (0);
-      ax = &t->ax;
-    }
-    send_kx_auth (t,
-                  NULL,
-                  ax,
-                  (0 == GCT_count_channels (t))
-                  ? GNUNET_NO
-                  : GNUNET_YES);
-    break;
-  case CADET_TUNNEL_KEY_OK:
-    /* Must have been the *other* peer asking us to
-       respond with a KX_AUTH. */
-    if (NULL != t->unverified_ax)
-    {
-      /* Sending AX_AUTH in response to AX so we might get this one verified */
-      ax = t->unverified_ax;
-    }
-    else
-    {
-      /* Sending AX_AUTH in response to AX_AUTH */
-      ax = &t->ax;
-    }
-    send_kx_auth (t,
-                  NULL,
-                  ax,
-                  GNUNET_NO);
-    break;
-  }
-}
-
-
-/**
- * Handle KX message that lacks authentication (and which will thus
- * only be considered authenticated after we respond with our own
- * KX_AUTH and finally successfully decrypt payload).
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCT_handle_kx (struct CadetTConnection *ct,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
-{
-  struct CadetTunnel *t = ct->t;
-  struct CadetTunnelAxolotl *ax;
-  int ret;
-
-  if (0 ==
-      memcmp (&t->ax.DHRr,
-              &msg->ratchet_key,
-              sizeof (msg->ratchet_key)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Got duplicate KX. Firing back KX_AUTH.\n");
-    send_kx_auth (t,
-                  ct,
-                  &t->ax,
-                  GNUNET_NO);
-    return;
-  }
-
-  /* We only keep ONE unverified KX around, so if there is an existing one,
-     clean it up. */
-  if (NULL != t->unverified_ax)
-  {
-    if (0 ==
-        memcmp (&t->unverified_ax->DHRr,
-                &msg->ratchet_key,
-                sizeof (msg->ratchet_key)))
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Got duplicate unverified KX on %s. Fire back KX_AUTH again.\n",
-           GCT_2s (t));
-      send_kx_auth (t,
-                    ct,
-                    t->unverified_ax,
-                    GNUNET_NO);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Dropping old unverified KX state. Got a fresh KX for %s.\n",
-         GCT_2s (t));
-    memset (t->unverified_ax,
-            0,
-            sizeof (struct CadetTunnelAxolotl));
-    t->unverified_ax->DHRs = t->ax.DHRs;
-    t->unverified_ax->kx_0 = t->ax.kx_0;
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Creating fresh unverified KX for %s.\n",
-         GCT_2s (t));
-    t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl);
-    t->unverified_ax->DHRs = t->ax.DHRs;
-    t->unverified_ax->kx_0 = t->ax.kx_0;
-  }
-  /* Set as the 'current' RK/DHRr the one we are currently using,
-     so that the duplicate-detection logic of
-     #update_ax_by_kx can work. */
-  t->unverified_ax->RK = t->ax.RK;
-  t->unverified_ax->DHRr = t->ax.DHRr;
-  t->unverified_attempts = 0;
-  ax = t->unverified_ax;
-
-  /* Update 'ax' by the new key material */
-  ret = update_ax_by_kx (ax,
-                         GCP_get_id (t->destination),
-                         &msg->ephemeral_key,
-                         &msg->ratchet_key);
-  GNUNET_break (GNUNET_SYSERR != ret);
-  if (GNUNET_OK != ret)
-    return; /* duplicate KX, nothing to do */
-
-  /* move ahead in our state machine */
-  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_RECV);
-  else if (CADET_TUNNEL_KEY_AX_SENT == t->estate)
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
-
-  /* KX is still not done, try again our end. */
-  if (CADET_TUNNEL_KEY_OK != t->estate)
-  {
-    if (NULL != t->kx_task)
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-    t->kx_task
-      = GNUNET_SCHEDULER_add_now (&retry_kx,
-                                  t);
-  }
-}
-
-
-/**
- * Handle KX_AUTH message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCT_handle_kx_auth (struct CadetTConnection *ct,
-                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
-{
-  struct CadetTunnel *t = ct->t;
-  struct CadetTunnelAxolotl ax_tmp;
-  struct GNUNET_HashCode kx_auth;
-  int ret;
-
-  if ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
-       (CADET_TUNNEL_KEY_AX_RECV == t->estate) )
-  {
-    /* Confusing, we got a KX_AUTH before we even send our own
-       KX. This should not happen. We'll send our own KX ASAP anyway,
-       so let's ignore this here. */
-    GNUNET_break_op (0);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Handling KX_AUTH message for %s\n",
-       GCT_2s (t));
-
-  /* We do everything in ax_tmp until we've checked the authentication
-     so we don't clobber anything we care about by accident. */
-  ax_tmp = t->ax;
-
-  /* Update 'ax' by the new key material */
-  ret = update_ax_by_kx (&ax_tmp,
-                         GCP_get_id (t->destination),
-                         &msg->kx.ephemeral_key,
-                         &msg->kx.ratchet_key);
-  if (GNUNET_OK != ret)
-  {
-    if (GNUNET_NO == ret)
-      GNUNET_STATISTICS_update (stats,
-                                "# redundant KX_AUTH received",
-                                1,
-                                GNUNET_NO);
-    else
-      GNUNET_break (0); /* connect to self!? */
-    return;
-  }
-  GNUNET_CRYPTO_hash (&ax_tmp.RK,
-                      sizeof (ax_tmp.RK),
-                      &kx_auth);
-  if (0 != memcmp (&kx_auth,
-                   &msg->auth,
-                   sizeof (kx_auth)))
-  {
-    /* This KX_AUTH is not using the latest KX/KX_AUTH data
-       we transmitted to the sender, refuse it, try KX again. */
-    GNUNET_STATISTICS_update (stats,
-                              "# KX_AUTH not using our last KX received (auth failure)",
-                              1,
-                              GNUNET_NO);
-    send_kx (t,
-             ct,
-             &t->ax);
-    return;
-  }
-  /* Yep, we're good. */
-  t->ax = ax_tmp;
-  if (NULL != t->unverified_ax)
-  {
-    /* We got some "stale" KX before, drop that. */
-    cleanup_ax (t->unverified_ax);
-    GNUNET_free (t->unverified_ax);
-    t->unverified_ax = NULL;
-  }
-
-  /* move ahead in our state machine */
-  switch (t->estate)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED:
-  case CADET_TUNNEL_KEY_AX_RECV:
-    /* Checked above, this is impossible. */
-    GNUNET_assert (0);
-    break;
-  case CADET_TUNNEL_KEY_AX_SENT:      /* This is the normal case */
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV: /* both peers started KX */
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT: /* both peers now did KX_AUTH */
-    GCT_change_estate (t,
-                       CADET_TUNNEL_KEY_OK);
-    break;
-  case CADET_TUNNEL_KEY_OK:
-    /* Did not expect another KX_AUTH, but so what, still acceptable.
-       Nothing to do here. */
-    break;
-  }
-}
-
-
-
-/* ************************************** end core crypto ***************************** */
-
-
-/**
- * Compute the next free channel tunnel number for this tunnel.
- *
- * @param t the tunnel
- * @return unused number that can uniquely identify a channel in the tunnel
- */
-static struct GNUNET_CADET_ChannelTunnelNumber
-get_next_free_ctn (struct CadetTunnel *t)
-{
-#define HIGH_BIT 0x8000000
-  struct GNUNET_CADET_ChannelTunnelNumber ret;
-  uint32_t ctn;
-  int cmp;
-  uint32_t highbit;
-
-  cmp = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
-                                         GCP_get_id (GCT_get_destination (t)));
-  if (0 < cmp)
-    highbit = HIGH_BIT;
-  else if (0 > cmp)
-    highbit = 0;
-  else
-    GNUNET_assert (0); // loopback must never go here!
-  ctn = ntohl (t->next_ctn.cn);
-  while (NULL !=
-         GNUNET_CONTAINER_multihashmap32_get (t->channels,
-                                              ctn | highbit))
-  {
-    ctn = ((ctn + 1) & (~ HIGH_BIT));
-  }
-  t->next_ctn.cn = htonl ((ctn + 1) & (~ HIGH_BIT));
-  ret.cn = htonl (ctn | highbit);
-  return ret;
-}
-
-
-/**
- * Add a channel to a tunnel, and notify channel that we are ready
- * for transmission if we are already up.  Otherwise that notification
- * will be done later in #notify_tunnel_up_cb().
- *
- * @param t Tunnel.
- * @param ch Channel
- * @return unique number identifying @a ch within @a t
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCT_add_channel (struct CadetTunnel *t,
-                 struct CadetChannel *ch)
-{
-  struct GNUNET_CADET_ChannelTunnelNumber ctn;
-
-  ctn = get_next_free_ctn (t);
-  if (NULL != t->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->destroy_task);
-    t->destroy_task = NULL;
-  }
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
-                                                      ntohl (ctn.cn),
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Adding %s to %s\n",
-       GCCH_2s (ch),
-       GCT_2s (t));
-  switch (t->estate)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED:
-    /* waiting for connection to start KX */
-    break;
-  case CADET_TUNNEL_KEY_AX_RECV:
-  case CADET_TUNNEL_KEY_AX_SENT:
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-    /* we're currently waiting for KX to complete */
-    break;
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    /* waiting for OTHER peer to send us data,
-       we might need to prompt more aggressively! */
-    if (NULL == t->kx_task)
-      t->kx_task
-        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
-                                   &retry_kx,
-                                   t);
-    break;
-  case CADET_TUNNEL_KEY_OK:
-    /* We are ready. Tell the new channel that we are up. */
-    GCCH_tunnel_up (ch);
-    break;
-  }
-  return ctn;
-}
-
-
-/**
- * We lost a connection, remove it from our list and clean up
- * the connection object itself.
- *
- * @param ct binding of connection to tunnel of the connection that was lost.
- */
-void
-GCT_connection_lost (struct CadetTConnection *ct)
-{
-  struct CadetTunnel *t = ct->t;
-
-  if (GNUNET_YES == ct->is_ready)
-  {
-    GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
-                                 t->connection_ready_tail,
-                                 ct);
-    t->num_ready_connections--;
-  }
-  else
-  {
-    GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
-                                 t->connection_busy_tail,
-                                 ct);
-    t->num_busy_connections--;
-  }
-  GNUNET_free (ct);
-}
-
-
-/**
- * Clean up connection @a ct of a tunnel.
- *
- * @param cls the `struct CadetTunnel`
- * @param ct connection to clean up
- */
-static void
-destroy_t_connection (void *cls,
-                      struct CadetTConnection *ct)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetConnection *cc = ct->cc;
-
-  GNUNET_assert (ct->t == t);
-  GCT_connection_lost (ct);
-  GCC_destroy_without_tunnel (cc);
-}
-
-
-/**
- * This tunnel is no longer used, destroy it.
- *
- * @param cls the idle tunnel
- */
-static void
-destroy_tunnel (void *cls)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetTunnelQueueEntry *tq;
-
-  t->destroy_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Destroying idle %s\n",
-       GCT_2s (t));
-  GNUNET_assert (0 == GCT_count_channels (t));
-  GCT_iterate_connections (t,
-                           &destroy_t_connection,
-                           t);
-  GNUNET_assert (NULL == t->connection_ready_head);
-  GNUNET_assert (NULL == t->connection_busy_head);
-  while (NULL != (tq = t->tq_head))
-  {
-    if (NULL != tq->cont)
-      tq->cont (tq->cont_cls,
-                NULL);
-    GCT_send_cancel (tq);
-  }
-  GCP_drop_tunnel (t->destination,
-                   t);
-  GNUNET_CONTAINER_multihashmap32_destroy (t->channels);
-  if (NULL != t->maintain_connections_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->maintain_connections_task);
-    t->maintain_connections_task = NULL;
-  }
-  if (NULL != t->send_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->send_task);
-    t->send_task = NULL;
-  }
-  if (NULL != t->kx_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->kx_task);
-    t->kx_task = NULL;
-  }
-  GNUNET_MST_destroy (t->mst);
-  GNUNET_MQ_destroy (t->mq);
-  if (NULL != t->unverified_ax)
-  {
-    cleanup_ax (t->unverified_ax);
-    GNUNET_free (t->unverified_ax);
-  }
-  cleanup_ax (&t->ax);
-  GNUNET_assert (NULL == t->destroy_task);
-  GNUNET_free (t);
-}
-
-
-/**
- * Remove a channel from a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel
- * @param ctn unique number identifying @a ch within @a t
- */
-void
-GCT_remove_channel (struct CadetTunnel *t,
-                    struct CadetChannel *ch,
-                    struct GNUNET_CADET_ChannelTunnelNumber ctn)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Removing %s from %s\n",
-       GCCH_2s (ch),
-       GCT_2s (t));
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
-                                                         ntohl (ctn.cn),
-                                                         ch));
-  if ( (0 ==
-        GCT_count_channels (t)) &&
-       (NULL == t->destroy_task) )
-  {
-    t->destroy_task
-      = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
-                                      &destroy_tunnel,
-                                      t);
-  }
-}
-
-
-/**
- * Destroy remaining channels during shutdown.
- *
- * @param cls the `struct CadetTunnel` of the channel
- * @param key key of the channel
- * @param value the `struct CadetChannel`
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-destroy_remaining_channels (void *cls,
-                            uint32_t key,
-                            void *value)
-{
-  struct CadetChannel *ch = value;
-
-  GCCH_handle_remote_destroy (ch,
-                              NULL);
-  return GNUNET_OK;
-}
-
-
-/**
- * Destroys the tunnel @a t now, without delay. Used during shutdown.
- *
- * @param t tunnel to destroy
- */
-void
-GCT_destroy_tunnel_now (struct CadetTunnel *t)
-{
-  GNUNET_assert (GNUNET_YES == shutting_down);
-  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
-                                           &destroy_remaining_channels,
-                                           t);
-  GNUNET_assert (0 ==
-                 GCT_count_channels (t));
-  if (NULL != t->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->destroy_task);
-    t->destroy_task = NULL;
-  }
-  destroy_tunnel (t);
-}
-
-
-/**
- * Send normal payload from queue in @a t via connection @a ct.
- * Does nothing if our payload queue is empty.
- *
- * @param t tunnel to send data from
- * @param ct connection to use for transmission (is ready)
- */
-static void
-try_send_normal_payload (struct CadetTunnel *t,
-                         struct CadetTConnection *ct)
-{
-  struct CadetTunnelQueueEntry *tq;
-
-  GNUNET_assert (GNUNET_YES == ct->is_ready);
-  tq = t->tq_head;
-  if (NULL == tq)
-  {
-    /* no messages pending right now */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Not sending payload of %s on ready %s (nothing pending)\n",
-         GCT_2s (t),
-         GCC_2s (ct->cc));
-    return;
-  }
-  /* ready to send message 'tq' on tunnel 'ct' */
-  GNUNET_assert (t == tq->t);
-  GNUNET_CONTAINER_DLL_remove (t->tq_head,
-                               t->tq_tail,
-                               tq);
-  if (NULL != tq->cid)
-    *tq->cid = *GCC_get_id (ct->cc);
-  mark_connection_unready (ct);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending payload of %s on %s\n",
-       GCT_2s (t),
-       GCC_2s (ct->cc));
-  GCC_transmit (ct->cc,
-                tq->env);
-  if (NULL != tq->cont)
-    tq->cont (tq->cont_cls,
-              GCC_get_id (ct->cc));
-  GNUNET_free (tq);
-}
-
-
-/**
- * A connection is @a is_ready for transmission.  Looks at our message
- * queue and if there is a message, sends it out via the connection.
- *
- * @param cls the `struct CadetTConnection` that is @a is_ready
- * @param is_ready #GNUNET_YES if connection are now ready,
- *                 #GNUNET_NO if connection are no longer ready
- */
-static void
-connection_ready_cb (void *cls,
-                     int is_ready)
-{
-  struct CadetTConnection *ct = cls;
-  struct CadetTunnel *t = ct->t;
-
-  if (GNUNET_NO == is_ready)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "%s no longer ready for %s\n",
-         GCC_2s (ct->cc),
-         GCT_2s (t));
-    mark_connection_unready (ct);
-    return;
-  }
-  GNUNET_assert (GNUNET_NO == ct->is_ready);
-  GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
-                               t->connection_busy_tail,
-                               ct);
-  GNUNET_assert (0 < t->num_busy_connections);
-  t->num_busy_connections--;
-  ct->is_ready = GNUNET_YES;
-  GNUNET_CONTAINER_DLL_insert_tail (t->connection_ready_head,
-                                    t->connection_ready_tail,
-                                    ct);
-  t->num_ready_connections++;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s now ready for %s in state %s\n",
-       GCC_2s (ct->cc),
-       GCT_2s (t),
-       estate2s (t->estate));
-  switch (t->estate)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED:
-    /* Do not begin KX if WE have no channels waiting! */
-    if (0 == GCT_count_channels (t))
-      return;
-    /* We are uninitialized, just transmit immediately,
-       without undue delay. */
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx (t,
-             ct,
-             &t->ax);
-    break;
-  case CADET_TUNNEL_KEY_AX_RECV:
-  case CADET_TUNNEL_KEY_AX_SENT:
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    /* we're currently waiting for KX to complete, schedule job */
-    if (NULL == t->kx_task)
-      t->kx_task
-        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
-                                   &retry_kx,
-                                   t);
-    break;
-  case CADET_TUNNEL_KEY_OK:
-    if (GNUNET_YES == t->kx_auth_requested)
-    {
-      if (NULL != t->kx_task)
-      {
-        GNUNET_SCHEDULER_cancel (t->kx_task);
-        t->kx_task = NULL;
-      }
-      send_kx_auth (t,
-                    ct,
-                    &t->ax,
-                    GNUNET_NO);
-      return;
-    }
-    try_send_normal_payload (t,
-                             ct);
-    break;
-  }
-}
-
-
-/**
- * Called when either we have a new connection, or a new message in the
- * queue, or some existing connection has transmission capacity.  Looks
- * at our message queue and if there is a message, picks a connection
- * to send it on.
- *
- * @param cls the `struct CadetTunnel` to process messages on
- */
-static void
-trigger_transmissions (void *cls)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetTConnection *ct;
-
-  t->send_task = NULL;
-  if (NULL == t->tq_head)
-    return; /* no messages pending right now */
-  ct = get_ready_connection (t);
-  if (NULL == ct)
-    return; /* no connections ready */
-  try_send_normal_payload (t,
-                           ct);
-}
-
-
-/**
- * Closure for #evaluate_connection. Used to assemble summary information
- * about the existing connections so we can evaluate a new path.
- */
-struct EvaluationSummary
-{
-
-  /**
-   * Minimum length of any of our connections, `UINT_MAX` if we have none.
-   */
-  unsigned int min_length;
-
-  /**
-   * Maximum length of any of our connections, 0 if we have none.
-   */
-  unsigned int max_length;
-
-  /**
-   * Minimum desirability of any of our connections, UINT64_MAX if we have none.
-   */
-  GNUNET_CONTAINER_HeapCostType min_desire;
-
-  /**
-   * Maximum desirability of any of our connections, 0 if we have none.
-   */
-  GNUNET_CONTAINER_HeapCostType max_desire;
-
-  /**
-   * Path we are comparing against for #evaluate_connection, can be NULL.
-   */
-  struct CadetPeerPath *path;
-
-  /**
-   * Connection deemed the "worst" so far encountered by #evaluate_connection,
-   * NULL if we did not yet encounter any connections.
-   */
-  struct CadetTConnection *worst;
-
-  /**
-   * Numeric score of @e worst, only set if @e worst is non-NULL.
-   */
-  double worst_score;
-
-  /**
-   * Set to #GNUNET_YES if we have a connection over @e path already.
-   */
-  int duplicate;
-
-};
-
-
-/**
- * Evaluate a connection, updating our summary information in @a cls about
- * what kinds of connections we have.
- *
- * @param cls the `struct EvaluationSummary *` to update
- * @param ct a connection to include in the summary
- */
-static void
-evaluate_connection (void *cls,
-                     struct CadetTConnection *ct)
-{
-  struct EvaluationSummary *es = cls;
-  struct CadetConnection *cc = ct->cc;
-  struct CadetPeerPath *ps = GCC_get_path (cc);
-  const struct CadetConnectionMetrics *metrics;
-  GNUNET_CONTAINER_HeapCostType ct_desirability;
-  struct GNUNET_TIME_Relative uptime;
-  struct GNUNET_TIME_Relative last_use;
-  uint32_t ct_length;
-  double score;
-  double success_rate;
-
-  if (ps == es->path)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring duplicate path %s.\n",
-         GCPP_2s (es->path));
-    es->duplicate = GNUNET_YES;
-    return;
-  }
-  ct_desirability = GCPP_get_desirability (ps);
-  ct_length = GCPP_get_length (ps);
-  metrics = GCC_get_metrics (cc);
-  uptime = GNUNET_TIME_absolute_get_duration (metrics->age);
-  last_use = GNUNET_TIME_absolute_get_duration (metrics->last_use);
-  /* We add 1.0 here to avoid division by zero. */
-  success_rate = (metrics->num_acked_transmissions + 1.0) / (metrics->num_successes + 1.0);
-  score
-    = ct_desirability
-    + 100.0 / (1.0 + ct_length) /* longer paths = better */
-    + sqrt (uptime.rel_value_us / 60000000LL) /* larger uptime = better */
-    - last_use.rel_value_us / 1000L;          /* longer idle = worse */
-  score *= success_rate;        /* weigh overall by success rate */
-
-  if ( (NULL == es->worst) ||
-       (score < es->worst_score) )
-  {
-    es->worst = ct;
-    es->worst_score = score;
-  }
-  es->min_length = GNUNET_MIN (es->min_length,
-                               ct_length);
-  es->max_length = GNUNET_MAX (es->max_length,
-                               ct_length);
-  es->min_desire = GNUNET_MIN (es->min_desire,
-                               ct_desirability);
-  es->max_desire = GNUNET_MAX (es->max_desire,
-                               ct_desirability);
-}
-
-
-/**
- * Consider using the path @a p for the tunnel @a t.
- * The tunnel destination is at offset @a off in path @a p.
- *
- * @param cls our tunnel
- * @param path a path to our destination
- * @param off offset of the destination on path @a path
- * @return #GNUNET_YES (should keep iterating)
- */
-static int
-consider_path_cb (void *cls,
-                  struct CadetPeerPath *path,
-                  unsigned int off)
-{
-  struct CadetTunnel *t = cls;
-  struct EvaluationSummary es;
-  struct CadetTConnection *ct;
-
-  GNUNET_assert (off < GCPP_get_length (path));
-  es.min_length = UINT_MAX;
-  es.max_length = 0;
-  es.max_desire = 0;
-  es.min_desire = UINT64_MAX;
-  es.path = path;
-  es.duplicate = GNUNET_NO;
-  es.worst = NULL;
-
-  /* Compute evaluation summary over existing connections. */
-  GCT_iterate_connections (t,
-                           &evaluate_connection,
-                           &es);
-  if (GNUNET_YES == es.duplicate)
-    return GNUNET_YES;
-
-  /* FIXME: not sure we should really just count
-     'num_connections' here, as they may all have
-     consistently failed to connect. */
-
-  /* We iterate by increasing path length; if we have enough paths and
-     this one is more than twice as long than what we are currently
-     using, then ignore all of these super-long ones! */
-  if ( (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) &&
-       (es.min_length * 2 < off) &&
-       (es.max_length < off) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring paths of length %u, they are way too long.\n",
-         es.min_length * 2);
-    return GNUNET_NO;
-  }
-  /* If we have enough paths and this one looks no better, ignore it. */
-  if ( (GCT_count_any_connections (t) >= DESIRED_CONNECTIONS_PER_TUNNEL) &&
-       (es.min_length < GCPP_get_length (path)) &&
-       (es.min_desire > GCPP_get_desirability (path)) &&
-       (es.max_length < off) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring path (%u/%llu) to %s, got something better already.\n",
-         GCPP_get_length (path),
-         (unsigned long long) GCPP_get_desirability (path),
-         GCP_2s (t->destination));
-    return GNUNET_YES;
-  }
-
-  /* Path is interesting (better by some metric, or we don't have
-     enough paths yet). */
-  ct = GNUNET_new (struct CadetTConnection);
-  ct->created = GNUNET_TIME_absolute_get ();
-  ct->t = t;
-  ct->cc = GCC_create (t->destination,
-                       path,
-                       off,
-                       GNUNET_CADET_OPTION_DEFAULT, /* FIXME: set based on what channels want/need! */
-                       ct,
-                       &connection_ready_cb,
-                       ct);
-
-  /* FIXME: schedule job to kill connection (and path?)  if it takes
-     too long to get ready! (And track performance data on how long
-     other connections took with the tunnel!)
-     => Note: to be done within 'connection'-logic! */
-  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
-                               t->connection_busy_tail,
-                               ct);
-  t->num_busy_connections++;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Found interesting path %s for %s, created %s\n",
-       GCPP_2s (path),
-       GCT_2s (t),
-       GCC_2s (ct->cc));
-  return GNUNET_YES;
-}
-
-
-/**
- * Function called to maintain the connections underlying our tunnel.
- * Tries to maintain (incl. tear down) connections for the tunnel, and
- * if there is a significant change, may trigger transmissions.
- *
- * Basically, needs to check if there are connections that perform
- * badly, and if so eventually kill them and trigger a replacement.
- * The strategy is to open one more connection than
- * #DESIRED_CONNECTIONS_PER_TUNNEL, and then periodically kick out the
- * least-performing one, and then inquire for new ones.
- *
- * @param cls the `struct CadetTunnel`
- */
-static void
-maintain_connections_cb (void *cls)
-{
-  struct CadetTunnel *t = cls;
-  struct GNUNET_TIME_Relative delay;
-  struct EvaluationSummary es;
-
-  t->maintain_connections_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Performing connection maintenance for %s.\n",
-       GCT_2s (t));
-
-  es.min_length = UINT_MAX;
-  es.max_length = 0;
-  es.max_desire = 0;
-  es.min_desire = UINT64_MAX;
-  es.path = NULL;
-  es.worst = NULL;
-  es.duplicate = GNUNET_NO;
-  GCT_iterate_connections (t,
-                           &evaluate_connection,
-                           &es);
-  if ( (NULL != es.worst) &&
-       (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) )
-  {
-    /* Clear out worst-performing connection 'es.worst'. */
-    destroy_t_connection (t,
-                          es.worst);
-  }
-
-  /* Consider additional paths */
-  (void) GCP_iterate_paths (t->destination,
-                            &consider_path_cb,
-                            t);
-
-  /* FIXME: calculate when to try again based on how well we are doing;
-     in particular, if we have to few connections, we might be able
-     to do without this (as PATHS should tell us whenever a new path
-     is available instantly; however, need to make sure this job is
-     restarted after that happens).
-     Furthermore, if the paths we do know are in a reasonably narrow
-     quality band and are plentyful, we might also consider us stabilized
-     and then reduce the frequency accordingly.  */
-  delay = GNUNET_TIME_UNIT_MINUTES;
-  t->maintain_connections_task
-    = GNUNET_SCHEDULER_add_delayed (delay,
-                                    &maintain_connections_cb,
-                                    t);
-}
-
-
-/**
- * Consider using the path @a p for the tunnel @a t.
- * The tunnel destination is at offset @a off in path @a p.
- *
- * @param cls our tunnel
- * @param path a path to our destination
- * @param off offset of the destination on path @a path
- */
-void
-GCT_consider_path (struct CadetTunnel *t,
-                   struct CadetPeerPath *p,
-                   unsigned int off)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Considering %s for %s\n",
-       GCPP_2s (p),
-       GCT_2s (t));
-  (void) consider_path_cb (t,
-                           p,
-                           off);
-}
-
-
-/**
- * We got a keepalive. Track in statistics.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param msg  the message we received on the tunnel
- */
-static void
-handle_plaintext_keepalive (void *cls,
-                            const struct GNUNET_MessageHeader *msg)
-{
-  struct CadetTunnel *t = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received KEEPALIVE on %s\n",
-       GCT_2s (t));
-  GNUNET_STATISTICS_update (stats,
-                            "# keepalives received",
-                            1,
-                            GNUNET_NO);
-}
-
-
-/**
- * Check that @a msg is well-formed.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param msg  the message we received on the tunnel
- * @return #GNUNET_OK (any variable-size payload goes)
- */
-static int
-check_plaintext_data (void *cls,
-                      const struct GNUNET_CADET_ChannelAppDataMessage *msg)
-{
-  return GNUNET_OK;
-}
-
-
-/**
- * We received payload data for a channel.  Locate the channel
- * and process the data, or return an error if the channel is unknown.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param msg the message we received on the tunnel
- */
-static void
-handle_plaintext_data (void *cls,
-                       const struct GNUNET_CADET_ChannelAppDataMessage *msg)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (t,
-                       msg->ctn);
-  if (NULL == ch)
-  {
-    /* We don't know about such a channel, might have been destroyed on our
-       end in the meantime, or never existed. Send back a DESTROY. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received %u bytes of application data for unknown channel %u, sending DESTROY\n",
-         (unsigned int) (ntohs (msg->header.size) - sizeof (*msg)),
-         ntohl (msg->ctn.cn));
-    GCT_send_channel_destroy (t,
-                              msg->ctn);
-    return;
-  }
-  GCCH_handle_channel_plaintext_data (ch,
-                                      GCC_get_id (t->current_ct->cc),
-                                      msg);
-}
-
-
-/**
- * We received an acknowledgement for data we sent on a channel.
- * Locate the channel and process it, or return an error if the
- * channel is unknown.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param ack the message we received on the tunnel
- */
-static void
-handle_plaintext_data_ack (void *cls,
-                           const struct GNUNET_CADET_ChannelDataAckMessage *ack)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (t,
-                       ack->ctn);
-  if (NULL == ch)
-  {
-    /* We don't know about such a channel, might have been destroyed on our
-       end in the meantime, or never existed. Send back a DESTROY. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received DATA_ACK for unknown channel %u, sending DESTROY\n",
-         ntohl (ack->ctn.cn));
-    GCT_send_channel_destroy (t,
-                              ack->ctn);
-    return;
-  }
-  GCCH_handle_channel_plaintext_data_ack (ch,
-                                          GCC_get_id (t->current_ct->cc),
-                                          ack);
-}
-
-
-/**
- * We have received a request to open a channel to a port from
- * another peer.  Creates the incoming channel.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param copen the message we received on the tunnel
- */
-static void
-handle_plaintext_channel_open (void *cls,
-                               const struct GNUNET_CADET_ChannelOpenMessage *copen)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetChannel *ch;
-
-  ch = GNUNET_CONTAINER_multihashmap32_get (t->channels,
-                                            ntohl (copen->ctn.cn));
-  if (NULL != ch)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received duplicate channel CHANNEL_OPEN on port %s from %s (%s), resending ACK\n",
-         GNUNET_h2s (&copen->port),
-         GCT_2s (t),
-         GCCH_2s (ch));
-    GCCH_handle_duplicate_open (ch,
-                                GCC_get_id (t->current_ct->cc));
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received CHANNEL_OPEN on port %s from %s\n",
-       GNUNET_h2s (&copen->port),
-       GCT_2s (t));
-  ch = GCCH_channel_incoming_new (t,
-                                  copen->ctn,
-                                  &copen->port,
-                                  ntohl (copen->opt));
-  if (NULL != t->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->destroy_task);
-    t->destroy_task = NULL;
-  }
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
-                                                      ntohl (copen->ctn.cn),
-                                                      ch,
-                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-}
-
-
-/**
- * Send a DESTROY message via the tunnel.
- *
- * @param t the tunnel to transmit over
- * @param ctn ID of the channel to destroy
- */
-void
-GCT_send_channel_destroy (struct CadetTunnel *t,
-                          struct GNUNET_CADET_ChannelTunnelNumber ctn)
-{
-  struct GNUNET_CADET_ChannelManageMessage msg;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending DESTORY message for channel ID %u\n",
-       ntohl (ctn.cn));
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
-  msg.reserved = htonl (0);
-  msg.ctn = ctn;
-  GCT_send (t,
-            &msg.header,
-            NULL,
-            NULL);
-}
-
-
-/**
- * We have received confirmation from the target peer that the
- * given channel could be established (the port is open).
- * Tell the client.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param cm the message we received on the tunnel
- */
-static void
-handle_plaintext_channel_open_ack (void *cls,
-                                   const struct GNUNET_CADET_ChannelManageMessage *cm)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (t,
-                       cm->ctn);
-  if (NULL == ch)
-  {
-    /* We don't know about such a channel, might have been destroyed on our
-       end in the meantime, or never existed. Send back a DESTROY. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received channel OPEN_ACK for unknown channel %u, sending DESTROY\n",
-         ntohl (cm->ctn.cn));
-    GCT_send_channel_destroy (t,
-                              cm->ctn);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received channel OPEN_ACK on channel %s from %s\n",
-       GCCH_2s (ch),
-       GCT_2s (t));
-  GCCH_handle_channel_open_ack (ch,
-                                GCC_get_id (t->current_ct->cc));
-}
-
-
-/**
- * We received a message saying that a channel should be destroyed.
- * Pass it on to the correct channel.
- *
- * @param cls the `struct CadetTunnel` for which we decrypted the message
- * @param cm the message we received on the tunnel
- */
-static void
-handle_plaintext_channel_destroy (void *cls,
-                                  const struct GNUNET_CADET_ChannelManageMessage *cm)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetChannel *ch;
-
-  ch = lookup_channel (t,
-                       cm->ctn);
-  if (NULL == ch)
-  {
-    /* We don't know about such a channel, might have been destroyed on our
-       end in the meantime, or never existed. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Received channel DESTORY for unknown channel %u. Ignoring.\n",
-         ntohl (cm->ctn.cn));
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received channel DESTROY on %s from %s\n",
-       GCCH_2s (ch),
-       GCT_2s (t));
-  GCCH_handle_remote_destroy (ch,
-                              GCC_get_id (t->current_ct->cc));
-}
-
-
-/**
- * Handles a message we decrypted, by injecting it into
- * our message queue (which will do the dispatching).
- *
- * @param cls the `struct CadetTunnel` that got the message
- * @param msg the message
- * @return #GNUNET_OK (continue to process)
- */
-static int
-handle_decrypted (void *cls,
-                  const struct GNUNET_MessageHeader *msg)
-{
-  struct CadetTunnel *t = cls;
-
-  GNUNET_assert (NULL != t->current_ct);
-  GNUNET_MQ_inject_message (t->mq,
-                            msg);
-  return GNUNET_OK;
-}
-
-
-/**
- * Function called if we had an error processing
- * an incoming decrypted message.
- *
- * @param cls the `struct CadetTunnel`
- * @param error error code
- */
-static void
-decrypted_error_cb (void *cls,
-                    enum GNUNET_MQ_Error error)
-{
-  GNUNET_break_op (0);
-}
-
-
-/**
- * Create a tunnel to @a destionation.  Must only be called
- * from within #GCP_get_tunnel().
- *
- * @param destination where to create the tunnel to
- * @return new tunnel to @a destination
- */
-struct CadetTunnel *
-GCT_create_tunnel (struct CadetPeer *destination)
-{
-  struct CadetTunnel *t = GNUNET_new (struct CadetTunnel);
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_fixed_size (plaintext_keepalive,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE,
-                             struct GNUNET_MessageHeader,
-                             t),
-    GNUNET_MQ_hd_var_size (plaintext_data,
-                           GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA,
-                           struct GNUNET_CADET_ChannelAppDataMessage,
-                           t),
-    GNUNET_MQ_hd_fixed_size (plaintext_data_ack,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK,
-                             struct GNUNET_CADET_ChannelDataAckMessage,
-                             t),
-    GNUNET_MQ_hd_fixed_size (plaintext_channel_open,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN,
-                             struct GNUNET_CADET_ChannelOpenMessage,
-                             t),
-    GNUNET_MQ_hd_fixed_size (plaintext_channel_open_ack,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK,
-                             struct GNUNET_CADET_ChannelManageMessage,
-                             t),
-    GNUNET_MQ_hd_fixed_size (plaintext_channel_destroy,
-                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
-                             struct GNUNET_CADET_ChannelManageMessage,
-                             t),
-    GNUNET_MQ_handler_end ()
-  };
-
-  t->kx_retry_delay = INITIAL_KX_RETRY_DELAY;
-  new_ephemeral (&t->ax);
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_ecdhe_key_create2 (&t->ax.kx_0));
-  t->destination = destination;
-  t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
-  t->maintain_connections_task
-    = GNUNET_SCHEDULER_add_now (&maintain_connections_cb,
-                                t);
-  t->mq = GNUNET_MQ_queue_for_callbacks (NULL,
-                                         NULL,
-                                         NULL,
-                                         NULL,
-                                         handlers,
-                                         &decrypted_error_cb,
-                                         t);
-  t->mst = GNUNET_MST_create (&handle_decrypted,
-                              t);
-  return t;
-}
-
-
-/**
- * Add a @a connection to the @a tunnel.
- *
- * @param t a tunnel
- * @param cid connection identifer to use for the connection
- * @param options options for the connection
- * @param path path to use for the connection
- * @return #GNUNET_OK on success,
- *         #GNUNET_SYSERR on failure (duplicate connection)
- */
-int
-GCT_add_inbound_connection (struct CadetTunnel *t,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                            enum GNUNET_CADET_ChannelOption options,
-                            struct CadetPeerPath *path)
-{
-  struct CadetTConnection *ct;
-
-  ct = GNUNET_new (struct CadetTConnection);
-  ct->created = GNUNET_TIME_absolute_get ();
-  ct->t = t;
-  ct->cc = GCC_create_inbound (t->destination,
-                               path,
-                               options,
-                               ct,
-                               cid,
-                               &connection_ready_cb,
-                               ct);
-  if (NULL == ct->cc)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "%s refused inbound %s (duplicate)\n",
-         GCT_2s (t),
-         GCC_2s (ct->cc));
-    GNUNET_free (ct);
-    return GNUNET_SYSERR;
-  }
-  /* FIXME: schedule job to kill connection (and path?)  if it takes
-     too long to get ready! (And track performance data on how long
-     other connections took with the tunnel!)
-     => Note: to be done within 'connection'-logic! */
-  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
-                               t->connection_busy_tail,
-                               ct);
-  t->num_busy_connections++;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s has new %s\n",
-       GCT_2s (t),
-       GCC_2s (ct->cc));
-  return GNUNET_OK;
-}
-
-
-/**
- * Handle encrypted message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCT_handle_encrypted (struct CadetTConnection *ct,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  struct CadetTunnel *t = ct->t;
-  uint16_t size = ntohs (msg->header.size);
-  char cbuf [size] GNUNET_ALIGN;
-  ssize_t decrypted_size;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s received %u bytes of encrypted data in state %d\n",
-       GCT_2s (t),
-       (unsigned int) size,
-       t->estate);
-
-  switch (t->estate)
-  {
-  case CADET_TUNNEL_KEY_UNINITIALIZED:
-  case CADET_TUNNEL_KEY_AX_RECV:
-    /* We did not even SEND our KX, how can the other peer
-       send us encrypted data? Must have been that we went
-       down and the other peer still things we are up.
-       Let's send it KX back. */
-    GNUNET_STATISTICS_update (stats,
-                              "# received encrypted without any KX",
-                              1,
-                              GNUNET_NO);
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx (t,
-             ct,
-             &t->ax);
-    return;
-  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
-    /* We send KX, and other peer send KX to us at the same time.
-       Neither KX is AUTH'ed, so let's try KX_AUTH this time. */
-    GNUNET_STATISTICS_update (stats,
-                              "# received encrypted without KX_AUTH",
-                              1,
-                              GNUNET_NO);
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx_auth (t,
-                  ct,
-                  &t->ax,
-                  GNUNET_YES);
-    return;
-  case CADET_TUNNEL_KEY_AX_SENT:
-    /* We did not get the KX of the other peer, but that
-       might have been lost.  Send our KX again immediately. */
-    GNUNET_STATISTICS_update (stats,
-                              "# received encrypted without KX",
-                              1,
-                              GNUNET_NO);
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx (t,
-             ct,
-             &t->ax);
-    return;
-  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-    /* Great, first payload, we might graduate to OK! */
-  case CADET_TUNNEL_KEY_OK:
-    /* We are up and running, all good. */
-    break;
-  }
-
-  GNUNET_STATISTICS_update (stats,
-                            "# received encrypted",
-                            1,
-                            GNUNET_NO);
-  decrypted_size = -1;
-  if (CADET_TUNNEL_KEY_OK == t->estate)
-  {
-    /* We have well-established key material available,
-       try that. (This is the common case.) */
-    decrypted_size = t_ax_decrypt_and_validate (&t->ax,
-                                                cbuf,
-                                                msg,
-                                                size);
-  }
-
-  if ( (-1 == decrypted_size) &&
-       (NULL != t->unverified_ax) )
-  {
-    /* We have un-authenticated KX material available. We should try
-       this as a back-up option, in case the sender crashed and
-       switched keys. */
-    decrypted_size = t_ax_decrypt_and_validate (t->unverified_ax,
-                                                cbuf,
-                                                msg,
-                                                size);
-    if (-1 != decrypted_size)
-    {
-      /* It worked! Treat this as authentication of the AX data! */
-      cleanup_ax (&t->ax);
-      t->ax = *t->unverified_ax;
-      GNUNET_free (t->unverified_ax);
-      t->unverified_ax = NULL;
-    }
-    if (CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate)
-    {
-      /* First time it worked, move tunnel into production! */
-      GCT_change_estate (t,
-                         CADET_TUNNEL_KEY_OK);
-      if (NULL != t->send_task)
-        GNUNET_SCHEDULER_cancel (t->send_task);
-      t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
-                                               t);
-    }
-  }
-  if (NULL != t->unverified_ax)
-  {
-    /* We had unverified KX material that was useless; so increment
-       counter and eventually move to ignore it.  Note that we even do
-       this increment if we successfully decrypted with the old KX
-       material and thus didn't even both with the new one.  This is
-       the ideal case, as a malicious injection of bogus KX data
-       basically only causes us to increment a counter a few times. */
-    t->unverified_attempts++;
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Failed to decrypt message with unverified KX data %u times\n",
-         t->unverified_attempts);
-    if (t->unverified_attempts > MAX_UNVERIFIED_ATTEMPTS)
-    {
-      cleanup_ax (t->unverified_ax);
-      GNUNET_free (t->unverified_ax);
-      t->unverified_ax = NULL;
-    }
-  }
-
-  if (-1 == decrypted_size)
-  {
-    /* Decryption failed for good, complain. */
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "%s failed to decrypt and validate encrypted data, retrying KX\n",
-         GCT_2s (t));
-    GNUNET_STATISTICS_update (stats,
-                              "# unable to decrypt",
-                              1,
-                              GNUNET_NO);
-    if (NULL != t->kx_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->kx_task);
-      t->kx_task = NULL;
-    }
-    send_kx (t,
-             ct,
-             &t->ax);
-    return;
-  }
-
-  /* The MST will ultimately call #handle_decrypted() on each message. */
-  t->current_ct = ct;
-  GNUNET_break_op (GNUNET_OK ==
-                   GNUNET_MST_from_buffer (t->mst,
-                                           cbuf,
-                                           decrypted_size,
-                                           GNUNET_YES,
-                                           GNUNET_NO));
-  t->current_ct = NULL;
-}
-
-
-/**
- * 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 cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- * @return Handle to cancel message
- */
-struct CadetTunnelQueueEntry *
-GCT_send (struct CadetTunnel *t,
-          const struct GNUNET_MessageHeader *message,
-          GCT_SendContinuation cont,
-          void *cont_cls)
-{
-  struct CadetTunnelQueueEntry *tq;
-  uint16_t payload_size;
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
-
-  if (CADET_TUNNEL_KEY_OK != t->estate)
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-  payload_size = ntohs (message->size);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Encrypting %u bytes for %s\n",
-       (unsigned int) payload_size,
-       GCT_2s (t));
-  env = GNUNET_MQ_msg_extra (ax_msg,
-                             payload_size,
-                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
-  t_ax_encrypt (&t->ax,
-                &ax_msg[1],
-                message,
-                payload_size);
-  ax_msg->ax_header.Ns = htonl (t->ax.Ns++);
-  ax_msg->ax_header.PNs = htonl (t->ax.PNs);
-  /* FIXME: we should do this once, not once per message;
-     this is a point multiplication, and DHRs does not
-     change all the time. */
-  GNUNET_CRYPTO_ecdhe_key_get_public (&t->ax.DHRs,
-                                      &ax_msg->ax_header.DHRs);
-  t_h_encrypt (&t->ax,
-               ax_msg);
-  t_hmac (&ax_msg->ax_header,
-          sizeof (struct GNUNET_CADET_AxHeader) + payload_size,
-          0,
-          &t->ax.HKs,
-          &ax_msg->hmac);
-
-  tq = GNUNET_malloc (sizeof (*tq));
-  tq->t = t;
-  tq->env = env;
-  tq->cid = &ax_msg->cid; /* will initialize 'ax_msg->cid' once we know the connection */
-  tq->cont = cont;
-  tq->cont_cls = cont_cls;
-  GNUNET_CONTAINER_DLL_insert_tail (t->tq_head,
-                                    t->tq_tail,
-                                    tq);
-  if (NULL != t->send_task)
-    GNUNET_SCHEDULER_cancel (t->send_task);
-  t->send_task
-    = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
-                                t);
-  return tq;
-}
-
-
-/**
- * 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 tq Handle to the queue entry to cancel.
- */
-void
-GCT_send_cancel (struct CadetTunnelQueueEntry *tq)
-{
-  struct CadetTunnel *t = tq->t;
-
-  GNUNET_CONTAINER_DLL_remove (t->tq_head,
-                               t->tq_tail,
-                               tq);
-  GNUNET_MQ_discard (tq->env);
-  GNUNET_free (tq);
-}
-
-
-/**
- * Iterate over all connections of a tunnel.
- *
- * @param t Tunnel whose connections to iterate.
- * @param iter Iterator.
- * @param iter_cls Closure for @c iter.
- */
-void
-GCT_iterate_connections (struct CadetTunnel *t,
-                         GCT_ConnectionIterator iter,
-                         void *iter_cls)
-{
-  struct CadetTConnection *n;
-  for (struct CadetTConnection *ct = t->connection_ready_head;
-       NULL != ct;
-       ct = n)
-  {
-    n = ct->next;
-    iter (iter_cls,
-          ct);
-  }
-  for (struct CadetTConnection *ct = t->connection_busy_head;
-       NULL != ct;
-       ct = n)
-  {
-    n = ct->next;
-    iter (iter_cls,
-          ct);
-  }
-}
-
-
-/**
- * Closure for #iterate_channels_cb.
- */
-struct ChanIterCls
-{
-  /**
-   * Function to call.
-   */
-  GCT_ChannelIterator iter;
-
-  /**
-   * Closure for @e iter.
-   */
-  void *iter_cls;
-};
-
-
-/**
- * Helper function for #GCT_iterate_channels.
- *
- * @param cls the `struct ChanIterCls`
- * @param key unused
- * @param value a `struct CadetChannel`
- * @return #GNUNET_OK
- */
-static int
-iterate_channels_cb (void *cls,
-                     uint32_t key,
-                     void *value)
-{
-  struct ChanIterCls *ctx = cls;
-  struct CadetChannel *ch = value;
-
-  ctx->iter (ctx->iter_cls,
-             ch);
-  return GNUNET_OK;
-}
-
-
-/**
- * Iterate over all channels of a tunnel.
- *
- * @param t Tunnel whose channels to iterate.
- * @param iter Iterator.
- * @param iter_cls Closure for @c iter.
- */
-void
-GCT_iterate_channels (struct CadetTunnel *t,
-                      GCT_ChannelIterator iter,
-                      void *iter_cls)
-{
-  struct ChanIterCls ctx;
-
-  ctx.iter = iter;
-  ctx.iter_cls = iter_cls;
-  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
-                                           &iterate_channels_cb,
-                                           &ctx);
-
-}
-
-
-/**
- * Call #GCCH_debug() on a channel.
- *
- * @param cls points to the log level to use
- * @param key unused
- * @param value the `struct CadetChannel` to dump
- * @return #GNUNET_OK (continue iteration)
- */
-static int
-debug_channel (void *cls,
-               uint32_t key,
-               void *value)
-{
-  const enum GNUNET_ErrorType *level = cls;
-  struct CadetChannel *ch = value;
-
-  GCCH_debug (ch, *level);
-  return GNUNET_OK;
-}
-
-
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)
-
-
-/**
- * Log all possible info about the tunnel state.
- *
- * @param t Tunnel to debug.
- * @param level Debug level to use.
- */
-void
-GCT_debug (const struct CadetTunnel *t,
-           enum GNUNET_ErrorType level)
-{
-  struct CadetTConnection *iter_c;
-  int do_log;
-
-  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
-                                       "cadet-tun",
-                                       __FILE__, __FUNCTION__, __LINE__);
-  if (0 == do_log)
-    return;
-
-  LOG2 (level,
-        "TTT TUNNEL TOWARDS %s in estate %s tq_len: %u #cons: %u\n",
-        GCT_2s (t),
-        estate2s (t->estate),
-        t->tq_len,
-        GCT_count_any_connections (t));
-  LOG2 (level,
-        "TTT channels:\n");
-  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
-                                           &debug_channel,
-                                           &level);
-  LOG2 (level,
-        "TTT connections:\n");
-  for (iter_c = t->connection_ready_head; NULL != iter_c; iter_c = iter_c->next)
-    GCC_debug (iter_c->cc,
-               level);
-  for (iter_c = t->connection_busy_head; NULL != iter_c; iter_c = iter_c->next)
-    GCC_debug (iter_c->cc,
-               level);
-
-  LOG2 (level,
-        "TTT TUNNEL END\n");
-}
-
-
-/* end of gnunet-service-cadet-new_tunnels.c */
diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h b/src/cadet/gnunet-service-cadet-new_tunnels.h
deleted file mode 100644 (file)
index a81bc23..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2001-2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet-new_tunnels.h
- * @brief Information we track per tunnel.
- * @author Bartlomiej Polot
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_CADET_TUNNELS_H
-#define GNUNET_SERVICE_CADET_TUNNELS_H
-
-#include "gnunet-service-cadet-new.h"
-#include "cadet_protocol.h"
-
-
-/**
- * How many connections would we like to have per tunnel?
- */
-#define DESIRED_CONNECTIONS_PER_TUNNEL 3
-
-
-/**
- * All the encryption states a tunnel can be in.
- */
-enum CadetTunnelEState
-{
-  /**
-   * Uninitialized status, we need to send KX.  We will stay
-   * in this state until the first connection is up.
-   */
-  CADET_TUNNEL_KEY_UNINITIALIZED,
-
-  /**
-   * KX message sent, waiting for other peer's KX_AUTH.
-   */
-  CADET_TUNNEL_KEY_AX_SENT,
-
-  /**
-   * KX message received, trying to send back KX_AUTH.
-   */
-  CADET_TUNNEL_KEY_AX_RECV,
-
-  /**
-   * KX message sent and received, trying to send back KX_AUTH.
-   */
-  CADET_TUNNEL_KEY_AX_SENT_AND_RECV,
-
-  /**
-   * KX received and we sent KX_AUTH back, but we got no traffic yet,
-   * so we're waiting for either KX_AUTH or ENCRYPED traffic from
-   * the other peer.
-   *
-   * We will not yet send traffic, as this might have been a replay.
-   * The other (initiating) peer should send a CHANNEL_OPEN next
-   * anyway, and then we are in business!
-   */
-  CADET_TUNNEL_KEY_AX_AUTH_SENT,
-
-  /**
-   * Handshake completed: session key available.
-   */
-  CADET_TUNNEL_KEY_OK
-
-};
-
-
-/**
- * Get the static string for the peer this tunnel is directed.
- *
- * @param t Tunnel.
- *
- * @return Static string the destination peer's ID.
- */
-const char *
-GCT_2s (const struct CadetTunnel *t);
-
-
-/**
- * Create a tunnel to @a destionation.  Must only be called
- * from within #GCP_get_tunnel().
- *
- * @param destination where to create the tunnel to
- * @return new tunnel to @a destination
- */
-struct CadetTunnel *
-GCT_create_tunnel (struct CadetPeer *destination);
-
-
-/**
- * Destroys the tunnel @a t now, without delay. Used during shutdown.
- *
- * @param t tunnel to destroy
- */
-void
-GCT_destroy_tunnel_now (struct CadetTunnel *t);
-
-
-/**
- * Add a @a connection to the @a tunnel.
- *
- * @param t a tunnel
- * @param cid connection identifer to use for the connection
- * @param options options for the connection
- * @param path path to use for the connection
- * @return #GNUNET_OK on success,
- *         #GNUNET_SYSERR on failure (duplicate connection)
- */
-int
-GCT_add_inbound_connection (struct CadetTunnel *t,
-                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-                            enum GNUNET_CADET_ChannelOption options,
-                            struct CadetPeerPath *path);
-
-
-/**
- * We lost a connection, remove it from our list and clean up
- * the connection object itself.
- *
- * @param ct binding of connection to tunnel of the connection that was lost.
- */
-void
-GCT_connection_lost (struct CadetTConnection *ct);
-
-
-/**
- * Return the peer to which this tunnel goes.
- *
- * @param t a tunnel
- * @return the destination of the tunnel
- */
-struct CadetPeer *
-GCT_get_destination (struct CadetTunnel *t);
-
-
-/**
- * Consider using the path @a p for the tunnel @a t.
- * The tunnel destination is at offset @a off in path @a p.
- *
- * @param cls our tunnel
- * @param path a path to our destination
- * @param off offset of the destination on path @a path
- */
-void
-GCT_consider_path (struct CadetTunnel *t,
-                   struct CadetPeerPath *p,
-                   unsigned int off);
-
-
-/**
- * Add a channel to a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel
- * @return unique number identifying @a ch within @a t
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCT_add_channel (struct CadetTunnel *t,
-                 struct CadetChannel *ch);
-
-
-/**
- * Remove a channel from a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel
- * @param ctn unique number identifying @a ch within @a t
- */
-void
-GCT_remove_channel (struct CadetTunnel *t,
-                    struct CadetChannel *ch,
-                    struct GNUNET_CADET_ChannelTunnelNumber ctn);
-
-
-/**
- * Send a DESTROY message via the tunnel.
- *
- * @param t the tunnel to transmit over
- * @param ctn ID of the channel to destroy
- */
-void
-GCT_send_channel_destroy (struct CadetTunnel *t,
-                          struct GNUNET_CADET_ChannelTunnelNumber ctn);
-
-
-/**
- * Function called when a transmission requested using #GCT_send is done.
- *
- * @param cls closure
- * @param ctn identifier of the connection used for transmission, NULL if
- *            the transmission failed (to be used to match ACKs to the
- *            respective connection for connection performance evaluation)
- */
-typedef void
-(*GCT_SendContinuation)(void *cls,
-                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
-
-
-/**
- * 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 cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- * @return Handle to cancel message.
- */
-struct CadetTunnelQueueEntry *
-GCT_send (struct CadetTunnel *t,
-          const struct GNUNET_MessageHeader *message,
-          GCT_SendContinuation cont,
-          void *cont_cls);
-
-
-/**
- * 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 entry to cancel.
- */
-void
-GCT_send_cancel (struct CadetTunnelQueueEntry *q);
-
-
-/**
- * Return the number of channels using a tunnel.
- *
- * @param t tunnel to count obtain the number of channels for
- * @return number of channels using the tunnel
- */
-unsigned int
-GCT_count_channels (struct CadetTunnel *t);
-
-
-/**
- * Return the number of connections available for a tunnel.
- *
- * @param t tunnel to count obtain the number of connections for
- * @return number of connections available for the tunnel
- */
-unsigned int
-GCT_count_any_connections (const struct CadetTunnel *t);
-
-
-/**
- * Iterator over connections.
- *
- * @param cls closure
- * @param ct one of the connections
- */
-typedef void
-(*GCT_ConnectionIterator) (void *cls,
-                           struct CadetTConnection *ct);
-
-
-/**
- * Iterate over all connections of a tunnel.
- *
- * @param t Tunnel whose connections to iterate.
- * @param iter Iterator.
- * @param iter_cls Closure for @c iter.
- */
-void
-GCT_iterate_connections (struct CadetTunnel *t,
-                         GCT_ConnectionIterator iter,
-                         void *iter_cls);
-
-
-/**
- * Iterator over channels.
- *
- * @param cls closure
- * @param ch one of the channels
- */
-typedef void
-(*GCT_ChannelIterator) (void *cls,
-                        struct CadetChannel *ch);
-
-
-/**
- * Iterate over all channels of a tunnel.
- *
- * @param t Tunnel whose channels to iterate.
- * @param iter Iterator.
- * @param iter_cls Closure for @c iter.
- */
-void
-GCT_iterate_channels (struct CadetTunnel *t,
-                      GCT_ChannelIterator iter,
-                      void *iter_cls);
-
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnelEState
-GCT_get_estate (struct CadetTunnel *t);
-
-
-/**
- * Handle KX message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCT_handle_kx (struct CadetTConnection *ct,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
-
-
-/**
- * Handle KX_AUTH message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the key exchange message
- */
-void
-GCT_handle_kx_auth (struct CadetTConnection *ct,
-                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
-
-
-/**
- * Handle encrypted message.
- *
- * @param ct connection/tunnel combo that received encrypted message
- * @param msg the encrypted message to decrypt
- */
-void
-GCT_handle_encrypted (struct CadetTConnection *ct,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
-
-
-/**
- * Log all possible info about the tunnel state.
- *
- * @param t Tunnel to debug.
- * @param level Debug level to use.
- */
-void
-GCT_debug (const struct CadetTunnel *t,
-           enum GNUNET_ErrorType level);
-
-
-#endif
index 3a07f0ee58e3de12258fbe4d85be84dc02e648b5..a7e1fca472e15ae4d36c37bce42e155c3f1393cb 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2001-2013 GNUnet e.V.
+     Copyright (C) 2001-2013, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
  * @file cadet/gnunet-service-cadet.c
  * @brief GNUnet CADET service with encryption
  * @author Bartlomiej Polot
- *
- *  FIXME in progress:
- * - rekey - reliability interaction
- * - channel retransmit timing
- *
- * TODO:
- * - relay corking down to core
- * - set ttl relative to path length
- * TODO END
+ * @author Christian Grothoff
  *
  * Dictionary:
  * - peer: other cadet instance. If there is direct connection it's a neighbor.
- * - tunnel: encrypted connection to a peer, neighbor or not.
- * - channel: connection between two clients, on the same or different peers.
- *            have properties like reliability.
  * - path: series of directly connected peer from one peer to another.
  * - connection: path which is being used in a tunnel.
+ * - tunnel: encrypted connection to a peer, neighbor or not.
+ * - channel: logical link between two clients, on the same or different peers.
+ *            have properties like reliability.
  */
 
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "cadet.h"
 #include "gnunet_statistics_service.h"
-
-#include "gnunet-service-cadet_local.h"
+#include "gnunet-service-cadet.h"
 #include "gnunet-service-cadet_channel.h"
 #include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_tunnel.h"
+#include "gnunet-service-cadet_core.h"
 #include "gnunet-service-cadet_dht.h"
-#include "gnunet-service-cadet_peer.h"
 #include "gnunet-service-cadet_hello.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+
+#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
+
+
+/**
+ * Struct containing information about a client of the service
+ */
+struct CadetClient
+{
+  /**
+   * Linked list next
+   */
+  struct CadetClient *next;
+
+  /**
+   * Linked list prev
+   */
+  struct CadetClient *prev;
+
+  /**
+   * Tunnels that belong to this client, indexed by local id,
+   * value is a `struct CadetChannel`.
+   */
+  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
+
+  /**
+   * Handle to communicate with the client
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * Client handle.
+   */
+  struct GNUNET_SERVICE_Client *client;
+
+  /**
+   * Ports that this client has declared interest in.
+   * Indexed by port, contains *Client.
+   */
+  struct GNUNET_CONTAINER_MultiHashMap *ports;
 
+  /**
+   * Channel ID to use for the next incoming channel for this client.
+   * Wraps around (in theory).
+   */
+  struct GNUNET_CADET_ClientChannelNumber next_ccn;
+
+  /**
+   * ID of the client, mainly for debug messages. Purely internal to this file.
+   */
+  unsigned int id;
+};
 
 /******************************************************************************/
 /***********************      GLOBAL VARIABLES     ****************************/
 
 /****************************** Global variables ******************************/
 
+/**
+ * Handle to our configuration.
+ */
+const struct GNUNET_CONFIGURATION_Handle *cfg;
+
 /**
  * Handle to the statistics service.
  */
 struct GNUNET_STATISTICS_Handle *stats;
 
 /**
- * Local peer own ID (memory efficient handle).
+ * Handle to communicate with ATS.
  */
-GNUNET_PEER_Id myid;
+struct GNUNET_ATS_ConnectivityHandle *ats_ch;
 
 /**
- * Local peer own ID (full value).
+ * Local peer own ID.
  */
 struct GNUNET_PeerIdentity my_full_id;
 
+/**
+ * Own private key.
+ */
+struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
 
 /**
- * Signal that shutdown is happening: prevent recover measures.
+ * Signal that shutdown is happening: prevent recovery measures.
  */
 int shutting_down;
 
-/*************************** Static global variables **************************/
+/**
+ * DLL with all the clients, head.
+ */
+static struct CadetClient *clients_head;
 
 /**
- * Own private key.
+ * DLL with all the clients, tail.
  */
-static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+static struct CadetClient *clients_tail;
 
+/**
+ * Next ID to assign to a client.
+ */
+static unsigned int next_client_id;
+
+/**
+ * All ports clients of this peer have opened.
+ */
+struct GNUNET_CONTAINER_MultiHashMap *open_ports;
+
+/**
+ * Map from ports to channels where the ports were closed at the
+ * time we got the inbound connection.
+ * Indexed by port, contains `struct CadetChannel`.
+ */
+struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
+
+/**
+ * Map from PIDs to `struct CadetPeer` entries.
+ */
+struct GNUNET_CONTAINER_MultiPeerMap *peers;
+
+/**
+ * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
+ * hash codes to `struct CadetConnection` objects.
+ */
+struct GNUNET_CONTAINER_MultiShortmap *connections;
+
+/**
+ * How many messages are needed to trigger an AXOLOTL ratchet advance.
+ */
+unsigned long long ratchet_messages;
+
+/**
+ * How long until we trigger a ratched advance due to time.
+ */
+struct GNUNET_TIME_Relative ratchet_time;
+
+/**
+ * How frequently do we send KEEPALIVE messages on idle connections?
+ */
+struct GNUNET_TIME_Relative keepalive_period;
+
+/**
+ * Set to non-zero values to create random drops to test retransmissions.
+ */
+unsigned long long drop_percent;
+
+
+/**
+ * Send a message to a client.
+ *
+ * @param c client to get the message
+ * @param env envelope with the message
+ */
+void
+GSC_send_to_client (struct CadetClient *c,
+                    struct GNUNET_MQ_Envelope *env)
+{
+  GNUNET_MQ_send (c->mq,
+                  env);
+}
+
+
+/**
+ * Return identifier for a client as a string.
+ *
+ * @param c client to identify
+ * @return string for debugging
+ */
+const char *
+GSC_2s (struct CadetClient *c)
+{
+  static char buf[32];
+
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "Client(%u)",
+                   c->id);
+  return buf;
+}
+
+
+/**
+ * Lookup channel of client @a c by @a ccn.
+ *
+ * @param c client to look in
+ * @param ccn channel ID to look up
+ * @return NULL if no such channel exists
+ */
+static struct CadetChannel *
+lookup_channel (struct CadetClient *c,
+                struct GNUNET_CADET_ClientChannelNumber ccn)
+{
+  return GNUNET_CONTAINER_multihashmap32_get (c->channels,
+                                              ntohl (ccn.channel_of_client));
+}
+
+
+/**
+ * Obtain the next LID to use for incoming connections to
+ * the given client.
+ *
+ * @param c client handle
+ */
+static struct GNUNET_CADET_ClientChannelNumber
+client_get_next_ccn (struct CadetClient *c)
+{
+  struct GNUNET_CADET_ClientChannelNumber ccn = c->next_ccn;
+
+  /* increment until we have a free one... */
+  while (NULL !=
+         lookup_channel (c,
+                         ccn))
+  {
+    ccn.channel_of_client
+      = htonl (1 + (ntohl (ccn.channel_of_client)));
+    if (ntohl (ccn.channel_of_client) >=
+        GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+      ccn.channel_of_client = htonl (0);
+  }
+  c->next_ccn.channel_of_client
+    = htonl (1 + (ntohl (ccn.channel_of_client)));
+  return ccn;
+}
+
+
+/**
+ * Bind incoming channel to this client, and notify client about
+ * incoming connection.  Caller is responsible for notifying the other
+ * peer about our acceptance of the channel.
+ *
+ * @param c client to bind to
+ * @param ch channel to be bound
+ * @param dest peer that establishes the connection
+ * @param port port number
+ * @param options options
+ * @return local channel number assigned to the new client
+ */
+struct GNUNET_CADET_ClientChannelNumber
+GSC_bind (struct CadetClient *c,
+          struct CadetChannel *ch,
+          struct CadetPeer *dest,
+          const struct GNUNET_HashCode *port,
+          uint32_t options)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalChannelCreateMessage *cm;
+  struct GNUNET_CADET_ClientChannelNumber ccn;
+
+  ccn = client_get_next_ccn (c);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
+                                                      ntohl (ccn.channel_of_client),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Accepting incoming %s from %s on open port %s (%u), assigning ccn %X\n",
+       GCCH_2s (ch),
+       GCP_2s (dest),
+       GNUNET_h2s (port),
+       (uint32_t) ntohl (options),
+       (uint32_t) ntohl (ccn.channel_of_client));
+  /* notify local client about incoming connection! */
+  env = GNUNET_MQ_msg (cm,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
+  cm->ccn = ccn;
+  cm->port = *port;
+  cm->opt = htonl (options);
+  cm->peer = *GCP_get_id (dest);
+  GSC_send_to_client (c,
+                      env);
+  return ccn;
+}
+
+
+/**
+ * Callback invoked on all peers to destroy all tunnels
+ * that may still exist.
+ *
+ * @param cls NULL
+ * @param pid identify of a peer
+ * @param value a `struct CadetPeer` that may still have a tunnel
+ * @return #GNUNET_OK (iterate over all entries)
+ */
+static int
+destroy_tunnels_now (void *cls,
+                     const struct GNUNET_PeerIdentity *pid,
+                     void *value)
+{
+  struct CadetPeer *cp = value;
+  struct CadetTunnel *t = GCP_get_tunnel (cp,
+                                          GNUNET_NO);
+
+  if (NULL != t)
+    GCT_destroy_tunnel_now (t);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Callback invoked on all peers to destroy all tunnels
+ * that may still exist.
+ *
+ * @param cls NULL
+ * @param pid identify of a peer
+ * @param value a `struct CadetPeer` that may still have a tunnel
+ * @return #GNUNET_OK (iterate over all entries)
+ */
+static int
+destroy_paths_now (void *cls,
+                   const struct GNUNET_PeerIdentity *pid,
+                   void *value)
+{
+  struct CadetPeer *cp = value;
+
+  GCP_drop_owned_paths (cp);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown everything once the clients have disconnected.
+ */
+static void
+shutdown_rest ()
+{
+  if (NULL != stats)
+  {
+    GNUNET_STATISTICS_destroy (stats,
+                               GNUNET_NO);
+    stats = NULL;
+  }
+  if (NULL != open_ports)
+  {
+    GNUNET_CONTAINER_multihashmap_destroy (open_ports);
+    open_ports = NULL;
+  }
+  if (NULL != loose_channels)
+  {
+    GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
+    loose_channels = NULL;
+  }
+  /* Destroy tunnels.  Note that all channels must be destroyed first! */
+  GCP_iterate_all (&destroy_tunnels_now,
+                   NULL);
+  /* All tunnels, channels, connections and CORE must be down before this point. */
+  GCP_iterate_all (&destroy_paths_now,
+                   NULL);
+  /* All paths, tunnels, channels, connections and CORE must be down before this point. */
+  GCP_destroy_all_peers ();
+  if (NULL != peers)
+  {
+    GNUNET_CONTAINER_multipeermap_destroy (peers);
+    peers = NULL;
+  }
+  if (NULL != connections)
+  {
+    GNUNET_CONTAINER_multishortmap_destroy (connections);
+    connections = NULL;
+  }
+  if (NULL != ats_ch)
+  {
+    GNUNET_ATS_connectivity_done (ats_ch);
+    ats_ch = NULL;
+  }
+  GCD_shutdown ();
+  GCH_shutdown ();
+  GNUNET_free_non_null (my_private_key);
+  my_private_key = NULL;
+}
 
-/******************************************************************************/
-/************************      MAIN FUNCTIONS      ****************************/
-/******************************************************************************/
 
 /**
  * Task run during shutdown.
@@ -102,83 +426,1071 @@ static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
 static void
 shutdown_task (void *cls)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n");
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Shutting down\n");
   shutting_down = GNUNET_YES;
+  GCO_shutdown ();
+  if (NULL == clients_head)
+    shutdown_rest ();
+}
 
-  GML_shutdown ();
-  GCH_shutdown ();
-  GCC_shutdown ();
-  GCT_shutdown ();
-  GCD_shutdown ();
-  GCP_shutdown ();
 
-  GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
-  stats = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shut down\n");
+/**
+ * We had a remote connection @a value to port @a port before
+ * client @a cls opened port @a port.  Bind them now.
+ *
+ * @param cls the `struct CadetClient`
+ * @param port the port
+ * @param value the `struct CadetChannel`
+ * @return #GNUNET_YES (iterate over all such channels)
+ */
+static int
+bind_loose_channel (void *cls,
+                    const struct GNUNET_HashCode *port,
+                    void *value)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch = value;
+
+  GCCH_bind (ch,
+             c);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
+                                                       port,
+                                                       value));
+  return GNUNET_YES;
 }
 
 
 /**
- * Process cadet requests.
+ * Handle port open request.  Creates a mapping from the
+ * port to the respective client and checks whether we have
+ * loose channels trying to bind to the port.  If so, those
+ * are bound.
  *
- * @param cls closure
- * @param server the initialized server
- * @param c configuration to use
+ * @param cls Identification of the client.
+ * @param pmsg The actual message.
  */
 static void
-run (void *cls, struct GNUNET_SERVER_Handle *server,
-     const struct GNUNET_CONFIGURATION_Handle *c)
+handle_port_open (void *cls,
+                  const struct GNUNET_CADET_PortMessage *pmsg)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n");
+  struct CadetClient *c = cls;
 
-  stats = GNUNET_STATISTICS_create ("cadet", c);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Open port %s requested by %s\n",
+       GNUNET_h2s (&pmsg->port),
+       GSC_2s (c));
+  if (NULL == c->ports)
+    c->ports = GNUNET_CONTAINER_multihashmap_create (4,
+                                                      GNUNET_NO);
+  if (GNUNET_OK !=
+      GNUNET_CONTAINER_multihashmap_put (c->ports,
+                                         &pmsg->port,
+                                         c,
+                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  (void) GNUNET_CONTAINER_multihashmap_put (open_ports,
+                                            &pmsg->port,
+                                            c,
+                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+  GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
+                                              &pmsg->port,
+                                              &bind_loose_channel,
+                                              c);
+  GNUNET_SERVICE_client_continue (c->client);
+}
 
-  /* Scheduled the task to clean up when shutdown is called */
-  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
-                                NULL);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "reading key\n");
-  my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
-  GNUNET_assert (NULL != my_private_key);
-  GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_full_id.public_key);
-  myid = GNUNET_PEER_intern (&my_full_id);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "STARTING SERVICE (cadet) for peer [%s]\n",
-              GNUNET_i2s (&my_full_id));
 
-  GML_init (server);    /* Local clients */
-  GCH_init (c);         /* Hellos */
-  GCC_init (c);         /* Connections */
-  GCP_init (c);         /* Peers */
-  GCD_init (c);         /* DHT */
-  GCT_init (c, my_private_key); /* Tunnels */
+/**
+ * Handler for port close requests.  Marks this port as closed
+ * (unless of course we have another client with the same port
+ * open).  Note that existing channels accepted on the port are
+ * not affected.
+ *
+ * @param cls Identification of the client.
+ * @param pmsg The actual message.
+ */
+static void
+handle_port_close (void *cls,
+                   const struct GNUNET_CADET_PortMessage *pmsg)
+{
+  struct CadetClient *c = cls;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Closing port %s as requested by %s\n",
+       GNUNET_h2s (&pmsg->port),
+       GSC_2s (c));
+  if (GNUNET_YES !=
+      GNUNET_CONTAINER_multihashmap_remove (c->ports,
+                                            &pmsg->port,
+                                            c))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (open_ports,
+                                                       &pmsg->port,
+                                                       c));
+  GNUNET_SERVICE_client_continue (c->client);
 }
 
 
 /**
- * The main function for the cadet service.
+ * Handler for requests for us creating a new channel to another peer and port.
  *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
+ * @param cls Identification of the client.
+ * @param tcm The actual message.
  */
-int
-main (int argc, char *const *argv)
+static void
+handle_channel_create (void *cls,
+                       const struct GNUNET_CADET_LocalChannelCreateMessage *tcm)
 {
-  int r;
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch;
 
-  shutting_down = GNUNET_NO;
-  r = GNUNET_SERVICE_run (argc, argv, "cadet", GNUNET_SERVICE_OPTION_NONE, &run,
-                          NULL);
-  GNUNET_free (my_private_key);
+  if (ntohl (tcm->ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+  {
+    /* Channel ID not in allowed range. */
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  ch = lookup_channel (c,
+                       tcm->ccn);
+  if (NULL != ch)
+  {
+    /* Channel ID already in use. Not allowed. */
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "New channel to %s at port %s requested by %s\n",
+       GNUNET_i2s (&tcm->peer),
+       GNUNET_h2s (&tcm->port),
+       GSC_2s (c));
 
-  if (GNUNET_OK != r)
+  /* Create channel */
+  ch = GCCH_channel_local_new (c,
+                               tcm->ccn,
+                               GCP_get (&tcm->peer,
+                                        GNUNET_YES),
+                               &tcm->port,
+                               ntohl (tcm->opt));
+  if (NULL == ch)
   {
-    FPRINTF (stderr, "GNUNET_SERVICE_run for CADET has failed!\n");
-    return 1;
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
   }
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (c->channels,
+                                                      ntohl (tcm->ccn.channel_of_client),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
 
-  return 0;
+  GNUNET_SERVICE_client_continue (c->client);
 }
+
+
+/**
+ * Handler for requests of destroying an existing channel.
+ *
+ * @param cls client identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_channel_destroy (void *cls,
+                        const struct GNUNET_CADET_LocalChannelDestroyMessage *msg)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (c,
+                       msg->ccn);
+  if (NULL == ch)
+  {
+    /* Client attempted to destroy unknown channel.
+       Can happen if the other side went down at the same time.*/
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "%s tried to destroy unknown channel %X\n",
+         GSC_2s(c),
+         (uint32_t) ntohl (msg->ccn.channel_of_client));
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s is destroying %s\n",
+       GSC_2s(c),
+       GCCH_2s (ch));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+                                                         ntohl (msg->ccn.channel_of_client),
+                                                         ch));
+  GCCH_channel_local_destroy (ch,
+                              c,
+                              msg->ccn);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Check for client traffic data message is well-formed.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
+ */
+static int
+check_local_data (void *cls,
+                  const struct GNUNET_CADET_LocalData *msg)
+{
+  size_t payload_size;
+  size_t payload_claimed_size;
+  const char *buf;
+  struct GNUNET_MessageHeader pa;
+
+  /* FIXME: what is the format we shall allow for @a msg?
+     ONE payload item or multiple? Seems current cadet_api
+     at least in theory allows more than one. Next-gen
+     cadet_api will likely no more, so we could then
+     simplify this mess again. */
+  /* Sanity check for message size */
+  payload_size = ntohs (msg->header.size) - sizeof (*msg);
+  buf = (const char *) &msg[1];
+  while (payload_size >= sizeof (struct GNUNET_MessageHeader))
+  {
+    /* need to memcpy() for alignment */
+    GNUNET_memcpy (&pa,
+                   buf,
+                   sizeof (pa));
+    payload_claimed_size = ntohs (pa.size);
+    if ( (payload_size < payload_claimed_size) ||
+         (payload_claimed_size < sizeof (struct GNUNET_MessageHeader)) ||
+         (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size) )
+    {
+      GNUNET_break (0);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Local data of %u total size had sub-message %u at %u with %u bytes\n",
+           ntohs (msg->header.size),
+           ntohs (pa.type),
+           (unsigned int) (buf - (const char *) &msg[1]),
+           (unsigned int) payload_claimed_size);
+      return GNUNET_SYSERR;
+    }
+    payload_size -= payload_claimed_size;
+    buf += payload_claimed_size;
+  }
+  if (0 != payload_size)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handler for client payload traffic to be send on a channel to
+ * another peer.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_local_data (void *cls,
+                   const struct GNUNET_CADET_LocalData *msg)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch;
+  size_t payload_size;
+  const char *buf;
+
+  ch = lookup_channel (c,
+                       msg->ccn);
+  if (NULL == ch)
+  {
+    /* Channel does not exist (anymore) */
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Dropping payload for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
+         (unsigned int) ntohl (msg->ccn.channel_of_client));
+    GNUNET_SERVICE_client_continue (c->client);
+    return;
+  }
+  payload_size = ntohs (msg->header.size) - sizeof (*msg);
+  GNUNET_STATISTICS_update (stats,
+                            "# payload received from clients",
+                            payload_size,
+                            GNUNET_NO);
+  buf = (const char *) &msg[1];
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received %u bytes payload from %s for %s\n",
+       (unsigned int) payload_size,
+       GSC_2s (c),
+       GCCH_2s (ch));
+  if (GNUNET_OK !=
+      GCCH_handle_local_data (ch,
+                              msg->ccn,
+                              buf,
+                              payload_size))
+  {
+    GNUNET_SERVICE_client_drop (c->client);
+    return;
+  }
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for client's ACKs for payload traffic.
+ *
+ * @param cls identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_local_ack (void *cls,
+                  const struct GNUNET_CADET_LocalAck *msg)
+{
+  struct CadetClient *c = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (c,
+                       msg->ccn);
+  if (NULL == ch)
+  {
+    /* Channel does not exist (anymore) */
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Ignoring local ACK for channel %u from client (channel unknown, other endpoint may have disconnected)\n",
+         (unsigned int) ntohl (msg->ccn.channel_of_client));
+    GNUNET_SERVICE_client_continue (c->client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got a local ACK from %s for %s\n",
+       GSC_2s(c),
+       GCCH_2s (ch));
+  GCCH_handle_local_ack (ch,
+                         msg->ccn);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all peers to send a monitoring client info about each peer.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Peer info.
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_peers_iterator (void *cls,
+                        const struct GNUNET_PeerIdentity *peer,
+                        void *value)
+{
+  struct CadetClient *c = cls;
+  struct CadetPeer *p = value;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalInfoPeer *msg;
+
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+  msg->destination = *peer;
+  msg->paths = htons (GCP_count_paths (p));
+  msg->tunnel = htons (NULL != GCP_get_tunnel (p,
+                                               GNUNET_NO));
+  GNUNET_MQ_send (c->mq,
+                  env);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO PEERS request.
+ *
+ * @param cls Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_peers (void *cls,
+                  const struct GNUNET_MessageHeader *message)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *reply;
+
+  GCP_iterate_all (&get_all_peers_iterator,
+                   c);
+  env = GNUNET_MQ_msg (reply,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+  GNUNET_MQ_send (c->mq,
+                  env);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all paths of a peer to build an InfoPeer message.
+ * Message contains blocks of peers, first not included.
+ *
+ * @param cls message queue for transmission
+ * @param path Path itself
+ * @param off offset of the peer on @a path
+ * @return #GNUNET_YES if should keep iterating.
+ *         #GNUNET_NO otherwise.
+ */
+static int
+path_info_iterator (void *cls,
+                    struct CadetPeerPath *path,
+                    unsigned int off)
+{
+  struct GNUNET_MQ_Handle *mq = cls;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *resp;
+  struct GNUNET_PeerIdentity *id;
+  uint16_t path_size;
+  unsigned int i;
+  unsigned int path_length;
+
+  path_length = GCPP_get_length (path);
+  path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
+  if (sizeof (*resp) + path_size > UINT16_MAX)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Path of %u entries is too long for info message\n",
+         path_length);
+    return GNUNET_YES;
+  }
+  env = GNUNET_MQ_msg_extra (resp,
+                             path_size,
+                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
+  id = (struct GNUNET_PeerIdentity *) &resp[1];
+
+  /* Don't copy first peer.  First peer is always the local one.  Last
+   * peer is always the destination (leave as 0, EOL).
+   */
+  for (i = 0; i < off; i++)
+    id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
+                                                  i + 1));
+  GNUNET_MQ_send (mq,
+                  env);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's SHOW_PEER request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_show_peer (void *cls,
+                  const struct GNUNET_CADET_LocalInfo *msg)
+{
+  struct CadetClient *c = cls;
+  struct CadetPeer *p;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *resp;
+
+  p = GCP_get (&msg->peer,
+               GNUNET_NO);
+  if (NULL != p)
+    GCP_iterate_paths (p,
+                       &path_info_iterator,
+                       c->mq);
+  /* Send message with 0/0 to indicate the end */
+  env = GNUNET_MQ_msg (resp,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
+  GNUNET_MQ_send (c->mq,
+                  env);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all tunnels to send a monitoring client info about each tunnel.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value a `struct CadetPeer`
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_tunnels_iterator (void *cls,
+                          const struct GNUNET_PeerIdentity *peer,
+                          void *value)
+{
+  struct CadetClient *c = cls;
+  struct CadetPeer *p = value;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalInfoTunnel *msg;
+  struct CadetTunnel *t;
+
+  t = GCP_get_tunnel (p,
+                      GNUNET_NO);
+  if (NULL == t)
+    return GNUNET_YES;
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+  msg->destination = *peer;
+  msg->channels = htonl (GCT_count_channels (t));
+  msg->connections = htonl (GCT_count_any_connections (t));
+  msg->cstate = htons (0);
+  msg->estate = htons ((uint16_t) GCT_get_estate (t));
+  GNUNET_MQ_send (c->mq,
+                  env);
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS request.
+ *
+ * @param cls client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_info_tunnels (void *cls,
+                     const struct GNUNET_MessageHeader *message)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *reply;
+
+  GCP_iterate_all (&get_all_tunnels_iterator,
+                   c);
+  env = GNUNET_MQ_msg (reply,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+  GNUNET_MQ_send (c->mq,
+                  env);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Update the message with information about the connection.
+ *
+ * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
+ * @param ct a connection about which we should store information in @a cls
+ */
+static void
+iter_connection (void *cls,
+                 struct CadetTConnection *ct)
+{
+  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+  struct CadetConnection *cc = ct->cc;
+  struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
+
+  h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
+  h[msg->connections++] = *(GCC_get_id (cc));
+}
+
+
+/**
+ * Update the message with information about the channel.
+ *
+ * @param cls a `struct GNUNET_CADET_LocalInfoTunnel` message to update
+ * @param ch a channel about which we should store information in @a cls
+ */
+static void
+iter_channel (void *cls,
+              struct CadetChannel *ch)
+{
+  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+  struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
+  struct GNUNET_CADET_ChannelTunnelNumber *chn
+    = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
+
+  chn[msg->channels++] = GCCH_get_id (ch);
+}
+
+
+/**
+ * Handler for client's #GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_info_tunnel (void *cls,
+                    const struct GNUNET_CADET_LocalInfo *msg)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalInfoTunnel *resp;
+  struct CadetTunnel *t;
+  struct CadetPeer *p;
+  unsigned int ch_n;
+  unsigned int c_n;
+
+  p = GCP_get (&msg->peer,
+               GNUNET_NO);
+  t = GCP_get_tunnel (p,
+                      GNUNET_NO);
+  if (NULL == t)
+  {
+    /* We don't know the tunnel */
+    struct GNUNET_MQ_Envelope *env;
+    struct GNUNET_CADET_LocalInfoTunnel *warn;
+
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "Tunnel to %s unknown\n",
+         GNUNET_i2s_full (&msg->peer));
+    env = GNUNET_MQ_msg (warn,
+                         GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+    warn->destination = msg->peer;
+    GNUNET_MQ_send (c->mq,
+                    env);
+    GNUNET_SERVICE_client_continue (c->client);
+    return;
+  }
+
+  /* Initialize context */
+  ch_n = GCT_count_channels (t);
+  c_n = GCT_count_any_connections (t);
+  env = GNUNET_MQ_msg_extra (resp,
+                             c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
+                             ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber),
+                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+  resp->destination = msg->peer;
+  /* Do not reorder! #iter_channel needs counters in HBO! */
+  GCT_iterate_connections (t,
+                           &iter_connection,
+                           resp);
+  GCT_iterate_channels (t,
+                        &iter_channel,
+                        resp);
+  resp->connections = htonl (resp->connections);
+  resp->channels = htonl (resp->channels);
+  resp->cstate = htons (0);
+  resp->estate = htons (GCT_get_estate (t));
+  GNUNET_MQ_send (c->mq,
+                  env);
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all peers to dump info for each peer.
+ *
+ * @param cls Closure (unused).
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Peer info.
+ *
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+show_peer_iterator (void *cls,
+                    const struct GNUNET_PeerIdentity *peer,
+                    void *value)
+{
+  struct CadetPeer *p = value;
+  struct CadetTunnel *t;
+
+  t = GCP_get_tunnel (p,
+                      GNUNET_NO);
+  if (NULL != t)
+    GCT_debug (t,
+               GNUNET_ERROR_TYPE_ERROR);
+  LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO_DUMP request.
+ *
+ * @param cls Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_info_dump (void *cls,
+                  const struct GNUNET_MessageHeader *message)
+{
+  struct CadetClient *c = cls;
+
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Received dump info request from client %u\n",
+       c->id);
+
+  LOG (GNUNET_ERROR_TYPE_ERROR,
+       "*************************** DUMP START ***************************\n");
+  for (struct CadetClient *ci = clients_head;
+       NULL != ci;
+       ci = ci->next)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         "Client %u (%p), handle: %p, ports: %u, channels: %u\n",
+         ci->id,
+         ci,
+         ci->client,
+         (NULL != c->ports)
+         ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
+         : 0,
+         GNUNET_CONTAINER_multihashmap32_size (ci->channels));
+  }
+  LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
+  GCP_iterate_all (&show_peer_iterator,
+                   NULL);
+
+  LOG (GNUNET_ERROR_TYPE_ERROR,
+       "**************************** DUMP END ****************************\n");
+
+  GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+
+/**
+ * Callback called when a client connects to the service.
+ *
+ * @param cls closure for the service
+ * @param client the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return @a c
+ */
+static void *
+client_connect_cb (void *cls,
+                  struct GNUNET_SERVICE_Client *client,
+                  struct GNUNET_MQ_Handle *mq)
+{
+  struct CadetClient *c;
+
+  c = GNUNET_new (struct CadetClient);
+  c->client = client;
+  c->mq = mq;
+  c->id = next_client_id++; /* overflow not important: just for debug */
+  c->channels
+    = GNUNET_CONTAINER_multihashmap32_create (32);
+  GNUNET_CONTAINER_DLL_insert (clients_head,
+                               clients_tail,
+                               c);
+  GNUNET_STATISTICS_update (stats,
+                            "# clients",
+                            +1,
+                            GNUNET_NO);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s connected\n",
+       GSC_2s (c));
+  return c;
+}
+
+
+/**
+ * A channel was destroyed by the other peer. Tell our client.
+ *
+ * @param c client that lost a channel
+ * @param ccn channel identification number for the client
+ * @param ch the channel object
+ */
+void
+GSC_handle_remote_channel_destroy (struct CadetClient *c,
+                                   struct GNUNET_CADET_ClientChannelNumber ccn,
+                                   struct CadetChannel *ch)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalChannelDestroyMessage *tdm;
+
+  env = GNUNET_MQ_msg (tdm,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
+  tdm->ccn = ccn;
+  GSC_send_to_client (c,
+                      env);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+                                                         ntohl (ccn.channel_of_client),
+                                                         ch));
+}
+
+
+/**
+ * A client that created a loose channel that was not bound to a port
+ * disconnected, drop it from the #loose_channels list.
+ *
+ * @param port the port the channel was trying to bind to
+ * @param ch the channel that was lost
+ */
+void
+GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
+                        struct CadetChannel *ch)
+{
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (loose_channels,
+                                                       port,
+                                                       ch));
+}
+
+
+/**
+ * Iterator for deleting each channel whose client endpoint disconnected.
+ *
+ * @param cls Closure (client that has disconnected).
+ * @param key The local channel id in host byte order
+ * @param value The value stored at the key (channel to destroy).
+ * @return #GNUNET_OK, keep iterating.
+ */
+static int
+channel_destroy_iterator (void *cls,
+                          uint32_t key,
+                          void *value)
+{
+  struct CadetClient *c = cls;
+  struct GNUNET_CADET_ClientChannelNumber ccn;
+  struct CadetChannel *ch = value;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying %s, due to %s disconnecting.\n",
+       GCCH_2s (ch),
+       GSC_2s (c));
+  ccn.channel_of_client = htonl (key);
+  GCCH_channel_local_destroy (ch,
+                              c,
+                              ccn);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (c->channels,
+                                                         key,
+                                                         ch));
+  return GNUNET_OK;
+}
+
+
+/**
+ * Remove client's ports from the global hashmap on disconnect.
+ *
+ * @param cls Closure (unused).
+ * @param key the port.
+ * @param value the `struct CadetClient` to remove
+ * @return #GNUNET_OK, keep iterating.
+ */
+static int
+client_release_ports (void *cls,
+                      const struct GNUNET_HashCode *key,
+                      void *value)
+{
+  struct CadetClient *c = value;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Closing port %s due to %s disconnect.\n",
+       GNUNET_h2s (key),
+       GSC_2s (c));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (open_ports,
+                                                       key,
+                                                       value));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap_remove (c->ports,
+                                                       key,
+                                                       value));
+  return GNUNET_OK;
+}
+
+
+/**
+ * Callback called when a client disconnected from the service
+ *
+ * @param cls closure for the service
+ * @param client the client that disconnected
+ * @param internal_cls should be equal to @a c
+ */
+static void
+client_disconnect_cb (void *cls,
+                     struct GNUNET_SERVICE_Client *client,
+                     void *internal_cls)
+{
+  struct CadetClient *c = internal_cls;
+
+  GNUNET_assert (c->client == client);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s is disconnecting.\n",
+       GSC_2s (c));
+  if (NULL != c->channels)
+  {
+    GNUNET_CONTAINER_multihashmap32_iterate (c->channels,
+                                             &channel_destroy_iterator,
+                                             c);
+    GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap32_size (c->channels));
+    GNUNET_CONTAINER_multihashmap32_destroy (c->channels);
+  }
+  if (NULL != c->ports)
+  {
+    GNUNET_CONTAINER_multihashmap_iterate (c->ports,
+                                           &client_release_ports,
+                                           c);
+    GNUNET_CONTAINER_multihashmap_destroy (c->ports);
+  }
+  GNUNET_CONTAINER_DLL_remove (clients_head,
+                               clients_tail,
+                               c);
+  GNUNET_STATISTICS_update (stats,
+                            "# clients",
+                            -1,
+                            GNUNET_NO);
+  GNUNET_free (c);
+  if ( (NULL == clients_head) &&
+       (GNUNET_YES == shutting_down) )
+    shutdown_rest ();
+}
+
+
+/**
+ * Setup CADET internals.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls,
+     const struct GNUNET_CONFIGURATION_Handle *c,
+     struct GNUNET_SERVICE_Handle *service)
+{
+  cfg = c;
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "RATCHET_MESSAGES",
+                                             &ratchet_messages))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+                               "CADET",
+                               "RATCHET_MESSAGES",
+                               "needs to be a number");
+    ratchet_messages = 64;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (c,
+                                           "CADET",
+                                           "RATCHET_TIME",
+                                           &ratchet_time))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+                               "CADET",
+                               "RATCHET_TIME",
+                               "need delay value");
+    ratchet_time = GNUNET_TIME_UNIT_HOURS;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_time (c,
+                                           "CADET",
+                                           "REFRESH_CONNECTION_TIME",
+                                           &keepalive_period))
+  {
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+                               "CADET",
+                               "REFRESH_CONNECTION_TIME",
+                               "need delay value");
+    keepalive_period = GNUNET_TIME_UNIT_MINUTES;
+  }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "DROP_PERCENT",
+                                             &drop_percent))
+  {
+    drop_percent = 0;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
+  }
+  my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
+  if (NULL == my_private_key)
+  {
+    GNUNET_break (0);
+    GNUNET_SCHEDULER_shutdown ();
+    return;
+  }
+  GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
+                                      &my_full_id.public_key);
+  stats = GNUNET_STATISTICS_create ("cadet",
+                                    c);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                NULL);
+  ats_ch = GNUNET_ATS_connectivity_init (c);
+  /* FIXME: optimize code to allow GNUNET_YES here! */
+  open_ports = GNUNET_CONTAINER_multihashmap_create (16,
+                                                     GNUNET_NO);
+  loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
+                                                         GNUNET_NO);
+  peers = GNUNET_CONTAINER_multipeermap_create (16,
+                                                GNUNET_YES);
+  connections = GNUNET_CONTAINER_multishortmap_create (256,
+                                                       GNUNET_YES);
+  GCH_init (c);
+  GCD_init (c);
+  GCO_init (c);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "CADET started for peer %s\n",
+              GNUNET_i2s (&my_full_id));
+
+}
+
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("cadet",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_fixed_size (port_open,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
+                          struct GNUNET_CADET_PortMessage,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (port_close,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
+                          struct GNUNET_CADET_PortMessage,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (channel_create,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
+                          struct GNUNET_CADET_LocalChannelCreateMessage,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (channel_destroy,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
+                          struct GNUNET_CADET_LocalChannelDestroyMessage,
+                          NULL),
+ GNUNET_MQ_hd_var_size (local_data,
+                        GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
+                        struct GNUNET_CADET_LocalData,
+                        NULL),
+ GNUNET_MQ_hd_fixed_size (local_ack,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
+                          struct GNUNET_CADET_LocalAck,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (get_peers,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
+                          struct GNUNET_MessageHeader,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (show_peer,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
+                          struct GNUNET_CADET_LocalInfo,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (info_tunnels,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
+                          struct GNUNET_MessageHeader,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (info_tunnel,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
+                          struct GNUNET_CADET_LocalInfo,
+                          NULL),
+ GNUNET_MQ_hd_fixed_size (info_dump,
+                          GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
+                          struct GNUNET_MessageHeader,
+                          NULL),
+ GNUNET_MQ_handler_end ());
+
+/* end of gnunet-service-cadet-new.c */
diff --git a/src/cadet/gnunet-service-cadet.h b/src/cadet/gnunet-service-cadet.h
new file mode 100644 (file)
index 0000000..2f2d7ba
--- /dev/null
@@ -0,0 +1,308 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet.h
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_H
+#define GNUNET_SERVICE_CADET_H
+
+#include "gnunet_util_lib.h"
+#define NEW_CADET 1
+#include "cadet_protocol.h"
+
+/**
+ * A client to the CADET service.  Each client gets a unique handle.
+ */
+struct CadetClient;
+
+/**
+ * A peer in the GNUnet network.  Each peer we care about must have one globally
+ * unique such handle within this process.
+ */
+struct CadetPeer;
+
+/**
+ * Tunnel from us to another peer.  There can only be at most one
+ * tunnel per peer.
+ */
+struct CadetTunnel;
+
+/**
+ * Entry in the message queue of a `struct CadetTunnel`.
+ */
+struct CadetTunnelQueueEntry;
+
+/**
+ * A path of peer in the GNUnet network.  There must only be at most
+ * once such path.  Paths may share disjoint prefixes, but must all
+ * end at a unique suffix.  Paths must also not be proper subsets of
+ * other existing paths.
+ */
+struct CadetPeerPath;
+
+/**
+ * Entry in a peer path.
+ */
+struct CadetPeerPathEntry
+{
+  /**
+   * DLL of paths where the same @e peer is at the same offset.
+   */
+  struct CadetPeerPathEntry *next;
+
+  /**
+   * DLL of paths where the same @e peer is at the same offset.
+   */
+  struct CadetPeerPathEntry *prev;
+
+  /**
+   * The peer at this offset of the path.
+   */
+  struct CadetPeer *peer;
+
+  /**
+   * Path this entry belongs to.
+   */
+  struct CadetPeerPath *path;
+
+  /**
+   * Connection using this path, or NULL for none.
+   */
+  struct CadetConnection *cc;
+
+  /**
+   * Path's historic score up to this point.  Basically, how often did
+   * we succeed or fail to use the path up to this entry in a
+   * connection.  Positive values indicate good experiences, negative
+   * values bad experiences.  Code updating the score must guard
+   * against overflows.
+   */
+  int score;
+
+};
+
+/**
+ * Entry in list of connections used by tunnel, with metadata.
+ */
+struct CadetTConnection
+{
+  /**
+   * Next in DLL.
+   */
+  struct CadetTConnection *next;
+
+  /**
+   * Prev in DLL.
+   */
+  struct CadetTConnection *prev;
+
+  /**
+   * Connection handle.
+   */
+  struct CadetConnection *cc;
+
+  /**
+   * Tunnel this connection belongs to.
+   */
+  struct CadetTunnel *t;
+
+  /**
+   * Creation time, to keep oldest connection alive.
+   */
+  struct GNUNET_TIME_Absolute created;
+
+  /**
+   * Connection throughput, to keep fastest connection alive.
+   */
+  uint32_t throughput;
+
+  /**
+   * Is the connection currently ready for transmission?
+   */
+  int is_ready;
+};
+
+
+/**
+ * Active path through the network (used by a tunnel).  There may
+ * be at most one connection per path.
+ */
+struct CadetConnection;
+
+/**
+ * Description of a segment of a `struct CadetConnection` at the
+ * intermediate peers.  Routes are basically entries in a peer's
+ * routing table for forwarding traffic.  At both endpoints, the
+ * routes are terminated by a `struct CadetConnection`, which knows
+ * the complete `struct CadetPath` that is formed by the individual
+ * routes.
+ */
+struct CadetRoute;
+
+/**
+ * Logical end-to-end conenction between clients.  There can be
+ * any number of channels between clients.
+ */
+struct CadetChannel;
+
+/**
+ * Handle to our configuration.
+ */
+extern const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+/**
+ * Handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Handle to communicate with ATS.
+ */
+extern struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+
+/**
+ * Local peer own ID.
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
+/**
+ * Own private key.
+ */
+extern struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+
+/**
+ * All ports clients of this peer have opened.
+ */
+extern struct GNUNET_CONTAINER_MultiHashMap *open_ports;
+
+/**
+ * Map from `struct GNUNET_CADET_ConnectionTunnelIdentifier`
+ * hash codes to `struct CadetConnection` objects.
+ */
+extern struct GNUNET_CONTAINER_MultiShortmap *connections;
+
+/**
+ * Map from ports to channels where the ports were closed at the
+ * time we got the inbound connection.
+ * Indexed by port, contains `struct CadetChannel`.
+ */
+extern struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
+
+/**
+ * Map from PIDs to `struct CadetPeer` entries.
+ */
+extern struct GNUNET_CONTAINER_MultiPeerMap *peers;
+
+/**
+ * How many messages are needed to trigger an AXOLOTL ratchet advance.
+ */
+extern unsigned long long ratchet_messages;
+
+/**
+ * How long until we trigger a ratched advance due to time.
+ */
+extern struct GNUNET_TIME_Relative ratchet_time;
+
+/**
+ * How frequently do we send KEEPALIVE messages on idle connections?
+ */
+extern struct GNUNET_TIME_Relative keepalive_period;
+
+/**
+ * Signal that shutdown is happening: prevent recovery measures.
+ */
+extern int shutting_down;
+
+/**
+ * Set to non-zero values to create random drops to test retransmissions.
+ */
+extern unsigned long long drop_percent;
+
+
+/**
+ * Send a message to a client.
+ *
+ * @param c client to get the message
+ * @param env envelope with the message
+ */
+void
+GSC_send_to_client (struct CadetClient *c,
+                    struct GNUNET_MQ_Envelope *env);
+
+
+/**
+ * A channel was destroyed by the other peer. Tell our client.
+ *
+ * @param c client that lost a channel
+ * @param ccn channel identification number for the client
+ * @param ch the channel object
+ */
+void
+GSC_handle_remote_channel_destroy (struct CadetClient *c,
+                                   struct GNUNET_CADET_ClientChannelNumber ccn,
+                                   struct CadetChannel *ch);
+
+/**
+ * A client that created a loose channel that was not bound to a port
+ * disconnected, drop it from the #loose_channels list.
+ *
+ * @param port the port the channel was trying to bind to
+ * @param ch the channel that was lost
+ */
+void
+GSC_drop_loose_channel (const struct GNUNET_HashCode *port,
+                        struct CadetChannel *ch);
+
+
+/**
+ * Bind incoming channel to this client, and notify client
+ * about incoming connection.
+ *
+ * @param c client to bind to
+ * @param ch channel to be bound
+ * @param dest peer that establishes the connection
+ * @param port port number
+ * @param options options
+ * @return local channel number assigned to the new client
+ */
+struct GNUNET_CADET_ClientChannelNumber
+GSC_bind (struct CadetClient *c,
+          struct CadetChannel *ch,
+          struct CadetPeer *dest,
+          const struct GNUNET_HashCode *port,
+          uint32_t options);
+
+
+/**
+ * Return identifier for a client as a string.
+ *
+ * @param c client to identify
+ * @return string for debugging
+ */
+const char *
+GSC_2s (struct CadetClient *c);
+
+
+#endif
index 7b7c6e57ce4351c3028f9e0a0deecbe5b5410914..68e29b66b59d6b6caa58fcadd53250ca4f6575d3 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
+     Copyright (C) 2001-2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      Boston, MA 02110-1301, USA.
 */
-
-
+/**
+ * @file cadet/gnunet-service-cadet_channel.c
+ * @brief logical links between CADET clients
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - Congestion/flow control:
+ *   + estimate max bandwidth using bursts and use to for CONGESTION CONTROL!
+ *     (and figure out how/where to use this!)
+ *   + figure out flow control without ACKs (unreliable traffic!)
+ * - revisit handling of 'unbuffered' traffic!
+ *   (need to push down through tunnel into connection selection)
+ * - revisit handling of 'buffered' traffic: 4 is a rather small buffer; maybe
+ *   reserve more bits in 'options' to allow for buffer size control?
+ */
 #include "platform.h"
-#include "gnunet_util_lib.h"
-
+#include "cadet.h"
 #include "gnunet_statistics_service.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_paths.h"
 
-#include "cadet.h"
-#include "cadet_protocol.h"
+#define LOG(level,...) GNUNET_log_from (level,"cadet-chn",__VA_ARGS__)
 
-#include "gnunet-service-cadet_channel.h"
-#include "gnunet-service-cadet_local.h"
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_peer.h"
+/**
+ * How long do we initially wait before retransmitting?
+ */
+#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
 
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-chn",__VA_ARGS__)
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
+/**
+ * How long do we wait before dropping state about incoming
+ * connection to closed port?
+ */
+#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
+
+/**
+ * How long do we wait at least before retransmitting ever?
+ */
+#define MIN_RTT_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 75)
 
-#define CADET_RETRANSMIT_TIME    GNUNET_TIME_relative_multiply(\
-                                    GNUNET_TIME_UNIT_MILLISECONDS, 250)
-#define CADET_RETRANSMIT_MARGIN  4
+/**
+ * Maximum message ID into the future we accept for out-of-order messages.
+ * If the message is more than this into the future, we drop it.  This is
+ * important both to detect values that are actually in the past, as well
+ * as to limit adversarially triggerable memory consumption.
+ *
+ * Note that right now we have "max_pending_messages = 4" hard-coded in
+ * the logic below, so a value of 4 would suffice here. But we plan to
+ * allow larger windows in the future...
+ */
+#define MAX_OUT_OF_ORDER_DISTANCE 1024
 
 
 /**
- * All the states a connection can be in.
+ * All the states a channel can be in.
  */
 enum CadetChannelState
 {
@@ -51,9 +83,15 @@ enum CadetChannelState
   CADET_CHANNEL_NEW,
 
   /**
-   * Connection create message sent, waiting for ACK.
+   * Channel is to a port that is not open, we're waiting for the
+   * port to be opened.
+   */
+  CADET_CHANNEL_LOOSE,
+
+  /**
+   * CHANNEL_OPEN message sent, waiting for CHANNEL_OPEN_ACK.
    */
-  CADET_CHANNEL_SENT,
+  CADET_CHANNEL_OPEN_SENT,
 
   /**
    * Connection confirmed, ready to carry traffic.
@@ -63,138 +101,144 @@ enum CadetChannelState
 
 
 /**
- * Info holder for channel messages in queues.
+ * Info needed to retry a message in case it gets lost.
+ * Note that we DO use this structure also for unreliable
+ * messages.
  */
-struct CadetChannelQueue
+struct CadetReliableMessage
 {
   /**
-   * Tunnel Queue.
+   * Double linked list, FIFO style
    */
-  struct CadetTunnelQueue *tq;
+  struct CadetReliableMessage *next;
 
   /**
-   * Message type (DATA/DATA_ACK)
+   * Double linked list, FIFO style
    */
-  uint16_t type;
+  struct CadetReliableMessage *prev;
 
   /**
-   * Message copy (for DATAs, to start retransmission timer)
+   * Which channel is this message in?
    */
-  struct CadetReliableMessage *copy;
+  struct CadetChannel *ch;
 
   /**
-   * Reliability (for DATA_ACKs, to access rel->ack_q)
+   * Entry in the tunnels queue for this message, NULL if it has left
+   * the tunnel.  Used to cancel transmission in case we receive an
+   * ACK in time.
    */
-  struct CadetChannelReliability *rel;
-};
+  struct CadetTunnelQueueEntry *qe;
 
-
-/**
- * Info needed to retry a message in case it gets lost.
- */
-struct CadetReliableMessage
-{
   /**
-   * Double linked list, FIFO style
+   * Data message we are trying to send.
    */
-  struct CadetReliableMessage   *next;
-  struct CadetReliableMessage   *prev;
+  struct GNUNET_CADET_ChannelAppDataMessage *data_message;
 
   /**
-   * Type of message (payload, channel management).
+   * How soon should we retry if we fail to get an ACK?
+   * Messages in the queue are sorted by this value.
    */
-  int16_t                       type;
+  struct GNUNET_TIME_Absolute next_retry;
 
   /**
-   * Tunnel Reliability queue this message is in.
+   * How long do we wait for an ACK after transmission?
+   * Use for the back-off calculation.
    */
-  struct CadetChannelReliability *rel;
+  struct GNUNET_TIME_Relative retry_delay;
 
   /**
-   * ID of the message (ACK needed to free)
+   * Time when we first successfully transmitted the message
+   * (that is, set @e num_transmissions to 1).
    */
-  uint32_t                      mid;
+  struct GNUNET_TIME_Absolute first_transmission_time;
 
   /**
-   * Tunnel Queue.
+   * Identifier of the connection that this message took when it
+   * was first transmitted.  Only useful if @e num_transmissions is 1.
    */
-  struct CadetChannelQueue      *chq;
+  struct GNUNET_CADET_ConnectionTunnelIdentifier connection_taken;
 
   /**
-   * When was this message issued (to calculate ACK delay)
+   * How often was this message transmitted?  #GNUNET_SYSERR if there
+   * was an error transmitting the message, #GNUNET_NO if it was not
+   * yet transmitted ever, otherwise the number of (re) transmissions.
    */
-  struct GNUNET_TIME_Absolute   timestamp;
+  int num_transmissions;
 
-  /* struct GNUNET_CADET_ChannelAppDataMessage with payload */
 };
 
 
 /**
- * Info about the traffic state for a client in a channel.
+ * List of received out-of-order data messages.
  */
-struct CadetChannelReliability
+struct CadetOutOfOrderMessage
 {
   /**
-   * Channel this is about.
+   * Double linked list, FIFO style
    */
-  struct CadetChannel *ch;
+  struct CadetOutOfOrderMessage *next;
 
   /**
-   * DLL of messages sent and not yet ACK'd.
+   * Double linked list, FIFO style
    */
-  struct CadetReliableMessage        *head_sent;
-  struct CadetReliableMessage        *tail_sent;
+  struct CadetOutOfOrderMessage *prev;
 
   /**
-   * DLL of messages received out of order.
+   * ID of the message (messages up to this point needed
+   * before we give this one to the client).
    */
-  struct CadetReliableMessage        *head_recv;
-  struct CadetReliableMessage        *tail_recv;
+  struct ChannelMessageIdentifier mid;
 
   /**
-   * Messages received.
+   * The envelope with the payload of the out-of-order message
    */
-  unsigned int                      n_recv;
+  struct GNUNET_MQ_Envelope *env;
 
-  /**
-   * Next MID to use for outgoing traffic.
-   */
-  uint32_t                          mid_send;
+};
 
-  /**
-   * Next MID expected for incoming traffic.
-   */
-  uint32_t                          mid_recv;
 
+/**
+ * Client endpoint of a `struct CadetChannel`.  A channel may be a
+ * loopback channel, in which case it has two of these endpoints.
+ * Note that flow control also is required in both directions.
+ */
+struct CadetChannelClient
+{
   /**
-   * Handle for queued unique data CREATE, DATA_ACK.
+   * Client handle.  Not by itself sufficient to designate
+   * the client endpoint, as the same client handle may
+   * be used for both the owner and the destination, and
+   * we thus also need the channel ID to identify the client.
    */
-  struct CadetChannelQueue           *uniq;
+  struct CadetClient *c;
 
   /**
-   * Can we send data to the client?
+   * Head of DLL of messages received out of order or while client was unready.
    */
-  int                               client_ready;
+  struct CadetOutOfOrderMessage *head_recv;
 
   /**
-   * Can the client send data to us?
+   * Tail DLL of messages received out of order or while client was unready.
    */
-  int                               client_allowed;
+  struct CadetOutOfOrderMessage *tail_recv;
 
   /**
-   * Task to resend/poll in case no ACK is received.
+   * Local tunnel number for this client.
+   * (if owner >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI,
+   *  otherwise < #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
    */
-  struct GNUNET_SCHEDULER_Task *   retry_task;
+  struct GNUNET_CADET_ClientChannelNumber ccn;
 
   /**
-   * Counter for exponential backoff.
+   * Number of entries currently in @a head_recv DLL.
    */
-  struct GNUNET_TIME_Relative       retry_timer;
+  unsigned int num_recv;
 
   /**
-   * How long does it usually take to get an ACK.
+   * Can we send data to the client?
    */
-  struct GNUNET_TIME_Relative       expected_delay;
+  int client_ready;
+
 };
 
 
@@ -209,41 +253,44 @@ struct CadetChannel
   struct CadetTunnel *t;
 
   /**
-   * Destination port of the channel.
+   * Client owner of the tunnel, if any.
+   * (Used if this channel represends the initiating end of the tunnel.)
    */
-  struct GNUNET_HashCode port;
+  struct CadetChannelClient *owner;
 
   /**
-   * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+   * Client destination of the tunnel, if any.
+   * (Used if this channel represents the listening end of the tunnel.)
    */
-  struct GNUNET_CADET_ChannelTunnelNumber gid;
+  struct CadetChannelClient *dest;
 
   /**
-   * Local tunnel number for root (owner) client.
-   * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 )
+   * Last entry in the tunnel's queue relating to control messages
+   * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN or
+   * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK).  Used to cancel
+   * transmission in case we receive updated information.
    */
-  struct GNUNET_CADET_ClientChannelNumber lid_root;
+  struct CadetTunnelQueueEntry *last_control_qe;
 
   /**
-   * Local tunnel number for local destination clients (incoming number)
-   * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0).
+   * Head of DLL of messages sent and not yet ACK'd.
    */
-  struct GNUNET_CADET_ClientChannelNumber lid_dest;
+  struct CadetReliableMessage *head_sent;
 
   /**
-   * Channel state.
+   * Tail of DLL of messages sent and not yet ACK'd.
    */
-  enum CadetChannelState state;
+  struct CadetReliableMessage *tail_sent;
 
   /**
-   * Is the tunnel bufferless (minimum latency)?
+   * Task to resend/poll in case no ACK is received.
    */
-  int nobuffer;
+  struct GNUNET_SCHEDULER_Task *retry_control_task;
 
   /**
-   * Is the tunnel reliable?
+   * Task to resend/poll in case no ACK is received.
    */
-  int reliable;
+  struct GNUNET_SCHEDULER_Task *retry_data_task;
 
   /**
    * Last time the channel was used
@@ -251,21 +298,29 @@ struct CadetChannel
   struct GNUNET_TIME_Absolute timestamp;
 
   /**
-   * Client owner of the tunnel, if any
+   * Destination port of the channel.
    */
-  struct CadetClient *root;
+  struct GNUNET_HashCode port;
 
   /**
-   * Client destination of the tunnel, if any.
+   * Counter for exponential backoff.
    */
-  struct CadetClient *dest;
+  struct GNUNET_TIME_Relative retry_time;
 
   /**
-   * Flag to signal the destruction of the channel.
-   * If this is set to #GNUNET_YES the channel will be destroyed
-   * when the queue is empty.
+   * Bitfield of already-received messages past @e mid_recv.
    */
-  int destroy;
+  uint64_t mid_futures;
+
+  /**
+   * Next MID expected for incoming traffic.
+   */
+  struct ChannelMessageIdentifier mid_recv;
+
+  /**
+   * Next MID to use for outgoing traffic.
+   */
+  struct ChannelMessageIdentifier mid_send;
 
   /**
    * Total (reliable) messages pending ACK for this channel.
@@ -273,2290 +328,1710 @@ struct CadetChannel
   unsigned int pending_messages;
 
   /**
-   * Reliability data.
-   * Only present (non-NULL) at the owner of a tunnel.
+   * Maximum (reliable) messages pending ACK for this channel
+   * before we throttle the client.
    */
-  struct CadetChannelReliability *root_rel;
+  unsigned int max_pending_messages;
 
   /**
-   * Reliability data.
-   * Only present (non-NULL) at the destination of a tunnel.
+   * Number identifying this channel in its tunnel.
    */
-  struct CadetChannelReliability *dest_rel;
+  struct GNUNET_CADET_ChannelTunnelNumber ctn;
 
-};
+  /**
+   * Channel state.
+   */
+  enum CadetChannelState state;
 
+  /**
+   * Count how many ACKs we skipped, used to prevent long
+   * sequences of ACK skipping.
+   */
+  unsigned int skip_ack_series;
 
-/******************************************************************************/
-/*******************************   GLOBALS  ***********************************/
-/******************************************************************************/
+  /**
+   * Is the tunnel bufferless (minimum latency)?
+   */
+  int nobuffer;
 
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
+  /**
+   * Is the tunnel reliable?
  */
+  int reliable;
 
-/**
- * Local peer own ID (memory efficient handle).
- */
-extern GNUNET_PEER_Id myid;
+  /**
+   * Is the tunnel out-of-order?
  */
+  int out_of_order;
 
+  /**
+   * Is this channel a loopback channel, where the destination is us again?
+   */
+  int is_loopback;
 
-/******************************************************************************/
-/********************************   STATIC  ***********************************/
-/******************************************************************************/
+  /**
+   * Flag to signal the destruction of the channel.  If this is set to
+   * #GNUNET_YES the channel will be destroyed once the queue is
+   * empty.
+   */
+  int destroy;
 
+};
 
-/**
- * Destroy a reliable message after it has been acknowledged, either by
- * direct mid ACK or bitfield. Updates the appropriate data structures and
- * timers and frees all memory.
- *
- * @param copy Message that is no longer needed: remote peer got it.
- * @param update_time Is the timing information relevant?
- *                    If this message is ACK in a batch the timing information
- *                    is skewed by the retransmission, count only for the
- *                    retransmitted message.
- *
- * @return #GNUNET_YES if channel was destroyed as a result of the call,
- *         #GNUNET_NO otherwise.
- */
-static int
-rel_message_free (struct CadetReliableMessage *copy, int update_time);
 
 /**
- * send a channel create message.
+ * Get the static string for identification of the channel.
  *
- * @param ch Channel for which to send.
- */
-static void
-send_create (struct CadetChannel *ch);
-
-/**
- * Confirm we got a channel create, FWD ack.
+ * @param ch Channel.
  *
- * @param ch The channel to confirm.
- * @param fwd Should we send a FWD ACK? (going dest->root)
+ * @return Static string with the channel IDs.
  */
-static void
-send_ack (struct CadetChannel *ch, int fwd);
-
+const char *
+GCCH_2s (const struct CadetChannel *ch)
+{
+  static char buf[128];
+
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "Channel %s:%s ctn:%X(%X/%X)",
+                   (GNUNET_YES == ch->is_loopback)
+                   ? "loopback"
+                   : GNUNET_i2s (GCP_get_id (GCT_get_destination (ch->t))),
+                   GNUNET_h2s (&ch->port),
+                   ch->ctn,
+                   (NULL == ch->owner) ? 0 : ntohl (ch->owner->ccn.channel_of_client),
+                   (NULL == ch->dest) ? 0 : ntohl (ch->dest->ccn.channel_of_client));
+  return buf;
+}
 
 
 /**
- * Test if the channel is loopback: both root and dest are on the local peer.
+ * Get the channel's public ID.
  *
- * @param ch Channel to test.
+ * @param ch Channel.
  *
- * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise.
+ * @return ID used to identify the channel with the remote peer.
  */
-static int
-is_loopback (const struct CadetChannel *ch)
+struct GNUNET_CADET_ChannelTunnelNumber
+GCCH_get_id (const struct CadetChannel *ch)
 {
-  if (NULL != ch->t)
-    return GCT_is_loopback (ch->t);
-
-  return (NULL != ch->root && NULL != ch->dest);
+  return ch->ctn;
 }
 
 
 /**
- * Save a copy of the data message for later retransmission.
+ * Release memory associated with @a ccc
  *
- * @param msg Message to copy.
- * @param mid Message ID.
- * @param rel Reliability data for retransmission.
+ * @param ccc data structure to clean up
  */
-static struct CadetReliableMessage *
-copy_message (const struct GNUNET_CADET_ChannelAppDataMessage *msg, uint32_t mid,
-              struct CadetChannelReliability *rel)
+static void
+free_channel_client (struct CadetChannelClient *ccc)
 {
-  struct CadetReliableMessage *copy;
-  uint16_t size;
-
-  size = ntohs (msg->header.size);
-  copy = GNUNET_malloc (sizeof (*copy) + size);
-  copy->mid = mid;
-  copy->rel = rel;
-  copy->type = GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA;
-  GNUNET_memcpy (&copy[1], msg, size);
+  struct CadetOutOfOrderMessage *com;
 
-  return copy;
+  while (NULL != (com = ccc->head_recv))
+  {
+    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                                 ccc->tail_recv,
+                                 com);
+    ccc->num_recv--;
+    GNUNET_MQ_discard (com->env);
+    GNUNET_free (com);
+  }
+  GNUNET_free (ccc);
 }
 
+
 /**
- * We have received a message out of order, or the client is not ready.
- * Buffer it until we receive an ACK from the client or the missing
- * message from the channel.
+ * Destroy the given channel.
  *
- * @param msg Message to buffer (MUST be of type CADET_DATA).
- * @param rel Reliability data to the corresponding direction.
+ * @param ch channel to destroy
  */
 static void
-add_buffered_data (const struct GNUNET_CADET_ChannelAppDataMessage *msg,
-                   struct CadetChannelReliability *rel)
+channel_destroy (struct CadetChannel *ch)
 {
-  struct CadetReliableMessage *copy;
-  struct CadetReliableMessage *prev;
-  uint32_t mid;
+  struct CadetReliableMessage *crm;
 
-  mid = ntohl (msg->mid);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data MID %u (%u)\n",
-       mid, rel->n_recv);
-
-  rel->n_recv++;
-
-  // FIXME do something better than O(n), although n < 64...
-  // FIXME start from the end (most messages are the latest ones)
-  for (prev = rel->head_recv; NULL != prev; prev = prev->next)
+  while (NULL != (crm = ch->head_sent))
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " prev %u\n", prev->mid);
-    if (prev->mid == mid)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " already there!\n");
-      rel->n_recv--;
-      return;
-    }
-    else if (GC_is_pid_bigger (prev->mid, mid))
+    GNUNET_assert (ch == crm->ch);
+    if (NULL != crm->qe)
     {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n");
-      copy = copy_message (msg, mid, rel);
-      GNUNET_CONTAINER_DLL_insert_before (rel->head_recv, rel->tail_recv,
-                                          prev, copy);
-      return;
+      GCT_send_cancel (crm->qe);
+      crm->qe = NULL;
     }
+    GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+                                 ch->tail_sent,
+                                 crm);
+    GNUNET_free (crm->data_message);
+    GNUNET_free (crm);
+  }
+  if (NULL != ch->owner)
+  {
+    free_channel_client (ch->owner);
+    ch->owner = NULL;
+  }
+  if (NULL != ch->dest)
+  {
+    free_channel_client (ch->dest);
+    ch->dest = NULL;
+  }
+  if (NULL != ch->last_control_qe)
+  {
+    GCT_send_cancel (ch->last_control_qe);
+    ch->last_control_qe = NULL;
+  }
+  if (NULL != ch->retry_data_task)
+  {
+    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+    ch->retry_data_task = NULL;
+  }
+  if (NULL != ch->retry_control_task)
+  {
+    GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+    ch->retry_control_task = NULL;
+  }
+  if (GNUNET_NO == ch->is_loopback)
+  {
+    GCT_remove_channel (ch->t,
+                        ch,
+                        ch->ctn);
+    ch->t = NULL;
   }
-  copy = copy_message (msg, mid, rel);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail! (now: %u)\n", rel->n_recv);
-  GNUNET_CONTAINER_DLL_insert_tail (rel->head_recv, rel->tail_recv, copy);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data END\n");
+  GNUNET_free (ch);
 }
 
 
 /**
- * Add a destination client to a channel, initializing all data structures
- * in the channel and the client.
+ * Send a channel create message.
  *
- * @param ch Channel to which add the destination.
- * @param c Client which to add to the channel.
+ * @param cls Channel for which to send.
  */
 static void
-add_destination (struct CadetChannel *ch, struct CadetClient *c)
-{
-  if (NULL != ch->dest)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  /* Assign local id as destination */
-  ch->lid_dest = GML_get_next_ccn (c);
-
-  /* Store in client's hashmap */
-  GML_channel_add (c, ch->lid_dest, ch);
-
-  GNUNET_break (NULL == ch->dest_rel);
-  ch->dest_rel = GNUNET_new (struct CadetChannelReliability);
-  ch->dest_rel->ch = ch;
-  ch->dest_rel->expected_delay.rel_value_us = 0;
-  ch->dest_rel->retry_timer = CADET_RETRANSMIT_TIME;
-
-  ch->dest = c;
-}
+send_channel_open (void *cls);
 
 
 /**
- * Set options in a channel, extracted from a bit flag field.
+ * Function called once the tunnel confirms that we sent the
+ * create message.  Delays for a bit until we retry.
  *
- * @param ch Channel to set options to.
- * @param options Bit array in host byte order.
+ * @param cls our `struct CadetChannel`.
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
  */
 static void
-channel_set_options (struct CadetChannel *ch, uint32_t options)
+channel_open_sent_cb (void *cls,
+                      const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
 {
-  ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ?
-  GNUNET_YES : GNUNET_NO;
-  ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ?
-  GNUNET_YES : GNUNET_NO;
+  struct CadetChannel *ch = cls;
+
+  GNUNET_assert (NULL != ch->last_control_qe);
+  ch->last_control_qe = NULL;
+  ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sent CADET_CHANNEL_OPEN on %s, retrying in %s\n",
+       GCCH_2s (ch),
+       GNUNET_STRINGS_relative_time_to_string (ch->retry_time,
+                                               GNUNET_YES));
+  ch->retry_control_task
+    = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
+                                    &send_channel_open,
+                                    ch);
 }
 
 
 /**
- * Get a bit flag field with the options of a channel.
- *
- * @param ch Channel to get options from.
+ * Send a channel open message.
  *
- * @return Bit array in host byte order.
+ * @param cls Channel for which to send.
  */
-static uint32_t
-channel_get_options (struct CadetChannel *ch)
+static void
+send_channel_open (void *cls)
 {
+  struct CadetChannel *ch = cls;
+  struct GNUNET_CADET_ChannelOpenMessage msgcc;
   uint32_t options;
 
+  ch->retry_control_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending CHANNEL_OPEN message for %s\n",
+       GCCH_2s (ch));
   options = 0;
   if (ch->nobuffer)
     options |= GNUNET_CADET_OPTION_NOBUFFER;
   if (ch->reliable)
     options |= GNUNET_CADET_OPTION_RELIABLE;
+  if (ch->out_of_order)
+    options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
+  msgcc.header.size = htons (sizeof (msgcc));
+  msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
+  msgcc.opt = htonl (options);
+  msgcc.port = ch->port;
+  msgcc.ctn = ch->ctn;
+  ch->state = CADET_CHANNEL_OPEN_SENT;
+  if (NULL != ch->last_control_qe)
+    GCT_send_cancel (ch->last_control_qe);
+  ch->last_control_qe = GCT_send (ch->t,
+                                  &msgcc.header,
+                                  &channel_open_sent_cb,
+                                  ch);
+  GNUNET_assert (NULL == ch->retry_control_task);
+}
 
-  return options;
+
+/**
+ * Function called once and only once after a channel was bound
+ * to its tunnel via #GCT_add_channel() is ready for transmission.
+ * Note that this is only the case for channels that this peer
+ * initiates, as for incoming channels we assume that they are
+ * ready for transmission immediately upon receiving the open
+ * message.  Used to bootstrap the #GCT_send() process.
+ *
+ * @param ch the channel for which the tunnel is now ready
+ */
+void
+GCCH_tunnel_up (struct CadetChannel *ch)
+{
+  GNUNET_assert (NULL == ch->retry_control_task);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Tunnel up, sending CHANNEL_OPEN on %s now\n",
+       GCCH_2s (ch));
+  ch->retry_control_task
+    = GNUNET_SCHEDULER_add_now (&send_channel_open,
+                                ch);
 }
 
 
 /**
- * Notify a client that the channel is no longer valid.
+ * Create a new channel.
  *
- * @param ch Channel that is destroyed.
- * @param local_only Should we avoid sending it to other peers?
+ * @param owner local client owning the channel
+ * @param ccn local number of this channel at the @a owner
+ * @param destination peer to which we should build the channel
+ * @param port desired port at @a destination
+ * @param options options for the channel
+ * @return handle to the new channel
  */
-static void
-send_destroy (struct CadetChannel *ch, int local_only)
+struct CadetChannel *
+GCCH_channel_local_new (struct CadetClient *owner,
+                        struct GNUNET_CADET_ClientChannelNumber ccn,
+                        struct CadetPeer *destination,
+                        const struct GNUNET_HashCode *port,
+                        uint32_t options)
 {
-  struct GNUNET_CADET_ChannelManageMessage msg;
-
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
-  msg.header.size = htons (sizeof (msg));
-  msg.ctn = ch->gid;
+  struct CadetChannel *ch;
+  struct CadetChannelClient *ccco;
 
-  /* If root is not NULL, notify.
-   * If it's NULL, check lid_root. When a local destroy comes in, root
-   * is set to NULL but lid_root is left untouched. In this case, do nothing,
-   * the client is the one who requested the channel to be destroyed.
-   */
-  if (NULL != ch->root)
-    GML_send_channel_destroy (ch->root, ch->lid_root);
-  else if (0 == ch->lid_root.channel_of_client && GNUNET_NO == local_only)
-    GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
+  ccco = GNUNET_new (struct CadetChannelClient);
+  ccco->c = owner;
+  ccco->ccn = ccn;
+  ccco->client_ready = GNUNET_YES;
 
-  if (NULL != ch->dest)
-    GML_send_channel_destroy (ch->dest, ch->lid_dest);
-  else if (0 == ch->lid_dest.channel_of_client && GNUNET_NO == local_only)
-    GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL);
+  ch = GNUNET_new (struct CadetChannel);
+  ch->mid_recv.mid = htonl (1); /* The OPEN_ACK counts as message 0! */
+  ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
+  ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
+  ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
+  ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
+  ch->owner = ccco;
+  ch->port = *port;
+  if (0 == memcmp (&my_full_id,
+                   GCP_get_id (destination),
+                   sizeof (struct GNUNET_PeerIdentity)))
+  {
+    struct CadetClient *c;
+
+    ch->is_loopback = GNUNET_YES;
+    c = GNUNET_CONTAINER_multihashmap_get (open_ports,
+                                           port);
+    if (NULL == c)
+    {
+      /* port closed, wait for it to possibly open */
+      ch->state = CADET_CHANNEL_LOOSE;
+      (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
+                                                port,
+                                                ch,
+                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Created loose incoming loopback channel to port %s\n",
+           GNUNET_h2s (&ch->port));
+    }
+    else
+    {
+      GCCH_bind (ch,
+                 c);
+    }
+  }
+  else
+  {
+    ch->t = GCP_get_tunnel (destination,
+                            GNUNET_YES);
+    ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
+    ch->ctn = GCT_add_channel (ch->t,
+                               ch);
+  }
+  GNUNET_STATISTICS_update (stats,
+                            "# channels",
+                            1,
+                            GNUNET_NO);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Created channel to port %s at peer %s for %s using %s\n",
+       GNUNET_h2s (port),
+       GCP_2s (destination),
+       GSC_2s (owner),
+       (GNUNET_YES == ch->is_loopback) ? "loopback" : GCT_2s (ch->t));
+  return ch;
 }
 
 
 /**
- * Notify the destination client that a new incoming channel was created.
+ * We had an incoming channel to a port that is closed.
+ * It has not been opened for a while, drop it.
  *
- * @param ch Channel that was created.
+ * @param cls the channel to drop
  */
 static void
-send_client_create (struct CadetChannel *ch)
+timeout_closed_cb (void *cls)
 {
-  uint32_t opt;
-
-  if (NULL == ch->dest)
-    return;
-
-  opt = 0;
-  opt |= GNUNET_YES == ch->reliable ? GNUNET_CADET_OPTION_RELIABLE : 0;
-  opt |= GNUNET_YES == ch->nobuffer ? GNUNET_CADET_OPTION_NOBUFFER : 0;
-  GML_send_channel_create (ch->dest,
-                           ch->lid_dest,
-                           &ch->port,
-                           opt,
-                           GCT_get_destination (ch->t));
+  struct CadetChannel *ch = cls;
 
+  ch->retry_control_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Closing incoming channel to port %s from peer %s due to timeout\n",
+       GNUNET_h2s (&ch->port),
+       GCP_2s (GCT_get_destination (ch->t)));
+  channel_destroy (ch);
 }
 
 
 /**
- * Send data to a client.
+ * Create a new channel based on a request coming in over the network.
  *
- * 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?
+ * @param t tunnel to the remote peer
+ * @param ctn identifier of this channel in the tunnel
+ * @param port desired local port
+ * @param options options for the channel
+ * @return handle to the new channel
  */
-static void
-send_client_data (struct CadetChannel *ch,
-                  const struct GNUNET_CADET_ChannelAppDataMessage *msg,
-                  int fwd)
+struct CadetChannel *
+GCCH_channel_incoming_new (struct CadetTunnel *t,
+                           struct GNUNET_CADET_ChannelTunnelNumber ctn,
+                           const struct GNUNET_HashCode *port,
+                           uint32_t options)
 {
-  if (fwd)
+  struct CadetChannel *ch;
+  struct CadetClient *c;
+
+  ch = GNUNET_new (struct CadetChannel);
+  ch->port = *port;
+  ch->t = t;
+  ch->ctn = ctn;
+  ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
+  ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
+  ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
+  ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
+  ch->max_pending_messages = (ch->nobuffer) ? 1 : 4; /* FIXME: 4!? Do not hardcode! */
+  GNUNET_STATISTICS_update (stats,
+                            "# channels",
+                            1,
+                            GNUNET_NO);
+
+  c = GNUNET_CONTAINER_multihashmap_get (open_ports,
+                                         port);
+  if (NULL == c)
   {
-    if (ch->dest_rel->client_ready)
-    {
-      GML_send_data (ch->dest, msg, ch->lid_dest);
-      ch->dest_rel->client_ready = GNUNET_NO;
-      ch->dest_rel->mid_recv++;
-    }
-    else
-      add_buffered_data (msg, ch->dest_rel);
+    /* port closed, wait for it to possibly open */
+    ch->state = CADET_CHANNEL_LOOSE;
+    (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
+                                              port,
+                                              ch,
+                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+    GNUNET_assert (NULL == ch->retry_control_task);
+    ch->retry_control_task
+      = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
+                                      &timeout_closed_cb,
+                                      ch);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Created loose incoming channel to port %s from peer %s\n",
+         GNUNET_h2s (&ch->port),
+         GCP_2s (GCT_get_destination (ch->t)));
   }
   else
   {
-    if (ch->root_rel->client_ready)
-    {
-      GML_send_data (ch->root, msg, ch->lid_root);
-      ch->root_rel->client_ready = GNUNET_NO;
-      ch->root_rel->mid_recv++;
-    }
-    else
-      add_buffered_data (msg, ch->root_rel);
+    GCCH_bind (ch,
+               c);
   }
+  GNUNET_STATISTICS_update (stats,
+                            "# channels",
+                            1,
+                            GNUNET_NO);
+  return ch;
 }
 
 
 /**
- * Send a buffered message to the client, for in order delivery or
- * as result of client ACK.
+ * Function called once the tunnel confirms that we sent the
+ * ACK message.  Just remembers it was sent, we do not expect
+ * ACKs for ACKs ;-).
  *
- * @param ch Channel on which to empty the message buffer.
- * @param c Client to send to.
- * @param fwd Is this to send FWD data?.
+ * @param cls our `struct CadetChannel`.
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
  */
 static void
-send_client_buffered_data (struct CadetChannel *ch,
-                           struct CadetClient *c,
-                           int fwd)
+send_ack_cb (void *cls,
+             const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
 {
-  struct CadetReliableMessage *copy;
-  struct CadetChannelReliability *rel;
+  struct CadetChannel *ch = cls;
 
-  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_ChannelAppDataMessage *msg = (struct GNUNET_CADET_ChannelAppDataMessage *) &copy[1];
-
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " have %u! now expecting %u\n",
-           copy->mid, rel->mid_recv + 1);
-      send_client_data (ch, msg, fwd);
-      rel->n_recv--;
-      GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " free copy recv MID %u (%p), %u left\n",
-           copy->mid, copy, rel->n_recv);
-      GNUNET_free (copy);
-      GCCH_send_data_ack (ch, fwd);
-    }
-    else
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " reliable && don't have %u, next is %u\n",
-           rel->mid_recv, copy->mid);
-      if (GNUNET_YES == ch->destroy)
-      {
-        /* We don't have the next data piece and the remote peer has closed the
-         * channel. We won't receive it anymore, so just destroy the channel.
-         * FIXME: wait some time to allow other connections to
-         *        deliver missing messages
-         */
-        send_destroy (ch, GNUNET_YES);
-        GCCH_destroy (ch);
-      }
-    }
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data END\n");
+  GNUNET_assert (NULL != ch->last_control_qe);
+  ch->last_control_qe = NULL;
 }
 
 
 /**
- * Allow a client to send more data.
- *
- * In case the client was already allowed to send data, do nothing.
+ * Compute and send the current #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK to the other peer.
  *
- * @param ch Channel.
- * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root)
+ * @param ch channel to send the #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK for
  */
 static void
-send_client_ack (struct CadetChannel *ch, int fwd)
+send_channel_data_ack (struct CadetChannel *ch)
 {
-  struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel;
-  struct CadetClient *c = fwd ? ch->root : ch->dest;
+  struct GNUNET_CADET_ChannelDataAckMessage msg;
 
-  if (NULL == c)
-  {
-    GNUNET_break (GNUNET_NO != ch->destroy);
-    return;
-  }
+  if (GNUNET_NO == ch->reliable)
+    return; /* no ACKs */
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
+  msg.header.size = htons (sizeof (msg));
+  msg.ctn = ch->ctn;
+  msg.mid.mid = htonl (ntohl (ch->mid_recv.mid));
+  msg.futures = GNUNET_htonll (ch->mid_futures);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "  sending %s ack to client on channel %s\n",
-       GC_f2s (fwd), GCCH_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);
+       "Sending DATA_ACK %u:%llX via %s\n",
+       (unsigned int) ntohl (msg.mid.mid),
+       (unsigned long long) ch->mid_futures,
+       GCCH_2s (ch));
+  if (NULL != ch->last_control_qe)
+    GCT_send_cancel (ch->last_control_qe);
+  ch->last_control_qe = GCT_send (ch->t,
+                                  &msg.header,
+                                  &send_ack_cb,
+                                  ch);
 }
 
 
 /**
- * We haven't received an ACK after a certain time: restransmit the message.
+ * Send our initial #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK to the client confirming that the
+ * connection is up.
  *
- * @param cls Closure (CadetChannelReliability with the message to restransmit)
+ * @param cls the `struct CadetChannel`
  */
 static void
-channel_retransmit_message (void *cls)
+send_open_ack (void *cls)
 {
-  struct CadetChannelReliability *rel = cls;
-  struct CadetReliableMessage *copy;
-  struct CadetChannel *ch;
-  struct GNUNET_CADET_ChannelAppDataMessage *payload;
-  int fwd;
-
-  rel->retry_task = NULL;
-  ch = rel->ch;
-  copy = rel->head_sent;
-  if (NULL == copy)
-  {
-    GNUNET_break (0); // FIXME tripped in rps testcase
-    return;
-  }
-
-  payload = (struct GNUNET_CADET_ChannelAppDataMessage *) &copy[1];
-  fwd = (rel == ch->root_rel);
-
-  /* Message not found in the queue that we are going to use. */
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "RETRANSMIT MID %u\n", copy->mid);
+  struct CadetChannel *ch = cls;
+  struct GNUNET_CADET_ChannelManageMessage msg;
 
-  GCCH_send_prebuilt_message (&payload->header, ch, fwd, copy);
-  GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO);
+  ch->retry_control_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending CHANNEL_OPEN_ACK on %s\n",
+       GCCH_2s (ch));
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
+  msg.header.size = htons (sizeof (msg));
+  msg.reserved = htonl (0);
+  msg.ctn = ch->ctn;
+  if (NULL != ch->last_control_qe)
+    GCT_send_cancel (ch->last_control_qe);
+  ch->last_control_qe = GCT_send (ch->t,
+                                  &msg.header,
+                                  &send_ack_cb,
+                                  ch);
 }
 
 
 /**
- * We haven't received an Channel ACK after a certain time: resend the CREATE.
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
+ * this channel.  If the binding was successful, (re)transmit the
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
  *
- * @param cls Closure (CadetChannelReliability of the channel to recreate)
+ * @param ch channel that got the duplicate open
+ * @param cti identifier of the connection that delivered the message
  */
-static void
-channel_recreate (void *cls)
+void
+GCCH_handle_duplicate_open (struct CadetChannel *ch,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
 {
-  struct CadetChannelReliability *rel = cls;
-
-  rel->retry_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "RE-CREATE\n");
-  GNUNET_STATISTICS_update (stats,
-                           "# data retransmitted", 1, GNUNET_NO);
-
-  if (rel == rel->ch->root_rel)
-  {
-    send_create (rel->ch);
-  }
-  else if (rel == rel->ch->dest_rel)
+  if (NULL == ch->dest)
   {
-    send_ack (rel->ch, GNUNET_YES);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring duplicate CHANNEL_OPEN on %s: port is closed\n",
+         GCCH_2s (ch));
+    return;
   }
-  else
+  if (NULL != ch->retry_control_task)
   {
-    GNUNET_break (0);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring duplicate CHANNEL_OPEN on %s: control message is pending\n",
+         GCCH_2s (ch));
+    return;
   }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Retransmitting CHANNEL_OPEN_ACK on %s\n",
+       GCCH_2s (ch));
+  ch->retry_control_task
+    = GNUNET_SCHEDULER_add_now (&send_open_ack,
+                                ch);
 }
 
 
 /**
- * Message has been sent: start retransmission timer.
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK to the client to solicit more messages.
  *
- * @param cls Closure (queue structure).
- * @param t Tunnel.
- * @param q Queue handler (no longer valid).
- * @param type Type of message.
- * @param size Size of the message.
+ * @param ch channel the ack is for
+ * @param to_owner #GNUNET_YES to send to owner,
+ *                 #GNUNET_NO to send to dest
  */
 static void
-ch_message_sent (void *cls,
-                 struct CadetTunnel *t,
-                 struct CadetTunnelQueue *q,
-                 uint16_t type, size_t size)
+send_ack_to_client (struct CadetChannel *ch,
+                    int to_owner)
 {
-  struct CadetChannelQueue *chq = cls;
-  struct CadetReliableMessage *copy = chq->copy;
-  struct CadetChannelReliability *rel;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalAck *ack;
+  struct CadetChannelClient *ccc;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "channel_message_sent callback %s\n",
-       GC_m2s (chq->type));
-
-  switch (chq->type)
+  ccc = (GNUNET_YES == to_owner) ? ch->owner : ch->dest;
+  if (NULL == ccc)
   {
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "data MID %u sent\n", copy->mid);
-      GNUNET_assert (chq == copy->chq);
-      copy->timestamp = GNUNET_TIME_absolute_get ();
-      rel = copy->rel;
-      if (NULL == rel->retry_task)
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "  scheduling retry in %d * %s\n",
-             CADET_RETRANSMIT_MARGIN,
-             GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
-                                                     GNUNET_YES));
-        if (0 != rel->expected_delay.rel_value_us)
-        {
-          rel->retry_timer =
-              GNUNET_TIME_relative_saturating_multiply (rel->expected_delay,
-                                                        CADET_RETRANSMIT_MARGIN);
-        }
-        else
-        {
-          rel->retry_timer = CADET_RETRANSMIT_TIME;
-        }
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "  using delay %s\n",
-             GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
-                                                     GNUNET_NO));
-        rel->retry_task =
-            GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
-                                          &channel_retransmit_message, rel);
-      }
-      else
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "retry running %p\n", rel->retry_task);
-      }
-      copy->chq = NULL;
-      break;
-
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "sent %s\n", GC_m2s (chq->type));
-      rel = chq->rel;
-      GNUNET_assert (rel->uniq == chq);
-      rel->uniq = NULL;
-
-      if (CADET_CHANNEL_READY != rel->ch->state
-          && GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK != type
-          && GNUNET_NO == rel->ch->destroy)
-      {
-        GNUNET_assert (NULL == rel->retry_task);
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "STD BACKOFF %s\n",
-             GNUNET_STRINGS_relative_time_to_string (rel->retry_timer,
-                                                     GNUNET_NO));
-        rel->retry_timer = GNUNET_TIME_STD_BACKOFF (rel->retry_timer);
-        rel->retry_task = GNUNET_SCHEDULER_add_delayed (rel->retry_timer,
-                                                        &channel_recreate, rel);
-      }
-      break;
-
-    default:
-      GNUNET_break (0);
+    /* This can happen if we are just getting ACKs after
+       our local client already disconnected. */
+    GNUNET_assert (GNUNET_YES == ch->destroy);
+    return;
   }
-
-  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_ChannelOpenMessage msgcc;
-
-  msgcc.header.size = htons (sizeof (msgcc));
-  msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN);
-  msgcc.ctn = ch->gid;
-  msgcc.port = ch->port;
-  msgcc.opt = htonl (channel_get_options (ch));
-
-  GCCH_send_prebuilt_message (&msgcc.header, ch, GNUNET_YES, NULL);
+  env = GNUNET_MQ_msg (ack,
+                       GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
+  ack->ccn = ccc->ccn;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending CADET_LOCAL_ACK to %s (%s) at ccn %X (%u/%u pending)\n",
+       GSC_2s (ccc->c),
+       (GNUNET_YES == to_owner) ? "owner" : "dest",
+       ntohl (ack->ccn.channel_of_client),
+       ch->pending_messages,
+       ch->max_pending_messages);
+  GSC_send_to_client (ccc->c,
+                      env);
 }
 
 
 /**
- * Confirm we got a channel create or FWD ack.
+ * A client is bound to the port that we have a channel
+ * open to.  Send the acknowledgement for the connection
+ * request and establish the link with the client.
  *
- * @param ch The channel to confirm.
- * @param fwd Should we send a FWD ACK? (going dest->root)
+ * @param ch open incoming channel
+ * @param c client listening on the respective port
  */
-static void
-send_ack (struct CadetChannel *ch, int fwd)
+void
+GCCH_bind (struct CadetChannel *ch,
+           struct CadetClient *c)
 {
-  struct GNUNET_CADET_ChannelManageMessage msg;
+  uint32_t options;
+  struct CadetChannelClient *cccd;
 
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "  sending channel %s ack for channel %s\n",
-       GC_f2s (fwd), GCCH_2s (ch));
-
-  msg.ctn =ch->gid;
-  GCCH_send_prebuilt_message (&msg.header, ch, !fwd, NULL);
+       "Binding %s from %s to port %s of %s\n",
+       GCCH_2s (ch),
+       GCT_2s (ch->t),
+       GNUNET_h2s (&ch->port),
+       GSC_2s (c));
+  if (NULL != ch->retry_control_task)
+  {
+    /* there might be a timeout task here */
+    GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+    ch->retry_control_task = NULL;
+  }
+  options = 0;
+  if (ch->nobuffer)
+    options |= GNUNET_CADET_OPTION_NOBUFFER;
+  if (ch->reliable)
+    options |= GNUNET_CADET_OPTION_RELIABLE;
+  if (ch->out_of_order)
+    options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
+  cccd = GNUNET_new (struct CadetChannelClient);
+  GNUNET_assert (NULL == ch->dest);
+  ch->dest = cccd;
+  cccd->c = c;
+  cccd->client_ready = GNUNET_YES;
+  cccd->ccn = GSC_bind (c,
+                        ch,
+                        (GNUNET_YES == ch->is_loopback)
+                        ? GCP_get (&my_full_id,
+                                   GNUNET_YES)
+                        : GCT_get_destination (ch->t),
+                        &ch->port,
+                        options);
+  GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
+                 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
+  ch->mid_recv.mid = htonl (1); /* The OPEN counts as message 0! */
+  if (GNUNET_YES == ch->is_loopback)
+  {
+    ch->state = CADET_CHANNEL_OPEN_SENT;
+    GCCH_handle_channel_open_ack (ch,
+                                  NULL);
+  }
+  else
+  {
+    /* notify other peer that we accepted the connection */
+    ch->state = CADET_CHANNEL_READY;
+    ch->retry_control_task
+      = GNUNET_SCHEDULER_add_now (&send_open_ack,
+                                  ch);
+  }
+  /* give client it's initial supply of ACKs */
+  GNUNET_assert (ntohl (cccd->ccn.channel_of_client) <
+                 GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
+  for (unsigned int i=0;i<ch->max_pending_messages;i++)
+    send_ack_to_client (ch,
+                        GNUNET_NO);
 }
 
 
 /**
- * Send a message and don't keep any info about it: we won't need to cancel it
- * or resend it.
+ * One of our clients has disconnected, tell the other one that we
+ * are finished. Done asynchronously to avoid concurrent modification
+ * issues if this is the same client.
  *
- * @param msg Header of the message to fire away.
- * @param ch Channel on which the message should go.
- * @param force Is this a forced (undroppable) message?
+ * @param cls the `struct CadetChannel` where one of the ends is now dead
  */
 static void
-fire_and_forget (const struct GNUNET_MessageHeader *msg,
-                 struct CadetChannel *ch,
-                 int force)
+signal_remote_destroy_cb (void *cls)
 {
-  GNUNET_break (NULL ==
-                GCT_send_prebuilt_message (msg, ch->t, NULL,
-                                           force, NULL, NULL));
+  struct CadetChannel *ch = cls;
+  struct CadetChannelClient *ccc;
+
+  /* Find which end is left... */
+  ch->retry_control_task = NULL;
+  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+  GSC_handle_remote_channel_destroy (ccc->c,
+                                     ccc->ccn,
+                                     ch);
+  channel_destroy (ch);
 }
 
 
 /**
- * Notify that a channel create didn't succeed.
+ * Destroy locally created channel.  Called by the local client, so no
+ * need to tell the client.
  *
- * @param ch The channel to reject.
+ * @param ch channel to destroy
+ * @param c client that caused the destruction
+ * @param ccn client number of the client @a c
  */
-static void
-send_nack (struct CadetChannel *ch)
+void
+GCCH_channel_local_destroy (struct CadetChannel *ch,
+                            struct CadetClient *c,
+                            struct GNUNET_CADET_ClientChannelNumber ccn)
 {
-  struct GNUNET_CADET_ChannelManageMessage msg;
-
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "  sending channel NACK for channel %s\n",
+       "%s asks for destruction of %s\n",
+       GSC_2s (c),
        GCCH_2s (ch));
+  GNUNET_assert (NULL != c);
+  if ( (NULL != ch->owner) &&
+       (c == ch->owner->c) &&
+       (ccn.channel_of_client == ch->owner->ccn.channel_of_client) )
+  {
+    free_channel_client (ch->owner);
+    ch->owner = NULL;
+  }
+  else if ( (NULL != ch->dest) &&
+            (c == ch->dest->c) &&
+            (ccn.channel_of_client == ch->dest->ccn.channel_of_client) )
+  {
+    free_channel_client (ch->dest);
+    ch->dest = NULL;
+  }
+  else
+  {
+    GNUNET_assert (0);
+  }
 
-  msg.ctn = ch->gid;
-  GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL);
-}
-
-
-/**
- * Destroy all reliable messages queued for a channel,
- * during a channel destruction.
- * Frees the reliability structure itself.
- *
- * @param rel Reliability data for a channel.
- */
-static void
-channel_rel_free_all (struct CadetChannelReliability *rel)
-{
-  struct CadetReliableMessage *copy;
-  struct CadetReliableMessage *next;
-
-  if (NULL == rel)
-    return;
-
-  for (copy = rel->head_recv; NULL != copy; copy = next)
+  if (GNUNET_YES == ch->destroy)
   {
-    next = copy->next;
-    GNUNET_CONTAINER_DLL_remove (rel->head_recv, rel->tail_recv, copy);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL RECV %p\n", copy);
-    GNUNET_break (NULL == copy->chq);
-    GNUNET_free (copy);
+    /* other end already destroyed, with the local client gone, no need
+       to finish transmissions, just destroy immediately. */
+    channel_destroy (ch);
+    return;
   }
-  for (copy = rel->head_sent; NULL != copy; copy = next)
+  if ( (NULL != ch->head_sent) &&
+       ( (NULL != ch->owner) ||
+         (NULL != ch->dest) ) )
   {
-    next = copy->next;
-    GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE ALL SEND %p\n", copy);
-    if (NULL != copy->chq)
-    {
-      if (NULL != copy->chq->tq)
-      {
-        GCT_cancel (copy->chq->tq);
-        /* ch_message_sent will free copy->q */
-      }
-      else
-      {
-        GNUNET_free (copy->chq);
-        GNUNET_break (0);
-      }
-    }
-    GNUNET_free (copy);
+    /* Wait for other end to destroy us as well,
+       and otherwise allow send queue to be transmitted first */
+    ch->destroy = GNUNET_YES;
+    return;
   }
-  if (NULL != rel->uniq && NULL != rel->uniq->tq)
+  if ( (GNUNET_YES == ch->is_loopback) &&
+       ( (NULL != ch->owner) ||
+         (NULL != ch->dest) ) )
   {
-    GCT_cancel (rel->uniq->tq);
-    /* ch_message_sent is called freeing uniq */
+    if (NULL != ch->retry_control_task)
+      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+    ch->retry_control_task
+      = GNUNET_SCHEDULER_add_now (&signal_remote_destroy_cb,
+                                  ch);
+    return;
   }
-  if (NULL != rel->retry_task)
+  if (GNUNET_NO == ch->is_loopback)
   {
-    GNUNET_SCHEDULER_cancel (rel->retry_task);
-    rel->retry_task = NULL;
+    /* If the we ever sent the CHANNEL_CREATE, we need to send a destroy message. */
+    switch (ch->state)
+    {
+    case CADET_CHANNEL_NEW:
+      /* We gave up on a channel that we created as a client to a remote
+         target, but that never went anywhere. Nothing to do here. */
+      break;
+    case CADET_CHANNEL_LOOSE:
+      GSC_drop_loose_channel (&ch->port,
+                              ch);
+      break;
+    default:
+      GCT_send_channel_destroy (ch->t,
+                                ch->ctn);
+    }
   }
-  GNUNET_free (rel);
+  /* Nothing left to do, just finish destruction */
+  channel_destroy (ch);
 }
 
 
 /**
- * Mark future messages as ACK'd.
- *
- * @param rel Reliability data.
- * @param msg DataACK message with a bitfield of future ACK'd messages.
+ * We got an acknowledgement for the creation of the channel
+ * (the port is open on the other side). Begin transmissions.
  *
- * @return How many messages have been freed.
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message
  */
-static unsigned int
-channel_rel_free_sent (struct CadetChannelReliability *rel,
-                       const struct GNUNET_CADET_ChannelDataAckMessage *msg)
+void
+GCCH_handle_channel_open_ack (struct CadetChannel *ch,
+                              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
 {
-  struct CadetReliableMessage *copy;
-  struct CadetReliableMessage *next;
-  uint64_t bitfield;
-  uint64_t mask;
-  uint32_t mid;
-  uint32_t target;
-  unsigned int i;
-  unsigned int r;
-
-  bitfield = msg->futures;
-  mid = ntohl (msg->mid);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable %u %lX\n", mid, bitfield);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " rel %p, head %p\n", rel, rel->head_sent);
-  for (i = 0, r = 0, copy = rel->head_sent;
-       i < 64 && NULL != copy && 0 != bitfield;
-       i++)
+  switch (ch->state)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " trying bit %u (mid %u)\n", i, mid + i + 1);
-    mask = 0x1LL << i;
-    if (0 == (bitfield & mask))
-     continue;
-
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " set!\n");
-    /* Bit was set, clear the bit from the bitfield */
-    bitfield &= ~mask;
-
-    /* The i-th bit was set. Do we have that copy? */
-    /* Skip copies with mid < target */
-    target = mid + i + 1;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " target %u\n", target);
-    while (NULL != copy && GC_is_pid_bigger (target, copy->mid))
-      copy = copy->next;
-
-    /* Did we run out of copies? (previously freed, it's ok) */
-    if (NULL == copy)
+  case CADET_CHANNEL_NEW:
+    /* this should be impossible */
+    GNUNET_break (0);
+    break;
+  case CADET_CHANNEL_LOOSE:
+    /* This makes no sense. */
+    GNUNET_break_op (0);
+    break;
+  case CADET_CHANNEL_OPEN_SENT:
+    if (NULL == ch->owner)
     {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n");
-      return r;
+      /* We're not the owner, wrong direction! */
+      GNUNET_break_op (0);
+      return;
     }
-
-    /* Did we overshoot the target? (previously freed, it's ok) */
-    if (GC_is_pid_bigger (copy->mid, target))
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CHANNEL_OPEN_ACK for waiting %s, entering READY state\n",
+         GCCH_2s (ch));
+    if (NULL != ch->retry_control_task) /* can be NULL if ch->is_loopback */
     {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " next copy %u\n", copy->mid);
-      i += copy->mid - target - 1;   /* MID: 90, t = 85, i += 4 (i++ later) */
-      mask = (0x1LL << (i + 1)) - 1; /* Mask = i-th bit and all before */
-      bitfield &= ~mask;             /* Clear all bits up to MID - 1 */
-      continue;
+      GNUNET_SCHEDULER_cancel (ch->retry_control_task);
+      ch->retry_control_task = NULL;
     }
-
-    /* Now copy->mid == target, free it */
-    next = copy->next;
-    GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES));
-    r++;
-    copy = next;
+    ch->state = CADET_CHANNEL_READY;
+    /* On first connect, send client as many ACKs as we allow messages
+       to be buffered! */
+    for (unsigned int i=0;i<ch->max_pending_messages;i++)
+      send_ack_to_client (ch,
+                          GNUNET_YES);
+    break;
+  case CADET_CHANNEL_READY:
+    /* duplicate ACK, maybe we retried the CREATE. Ignore. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received duplicate channel OPEN_ACK for %s\n",
+         GCCH_2s (ch));
+    GNUNET_STATISTICS_update (stats,
+                              "# duplicate CREATE_ACKs",
+                              1,
+                              GNUNET_NO);
+    break;
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "free_sent_reliable END\n");
-  return r;
 }
 
 
 /**
- * Destroy a reliable message after it has been acknowledged, either by
- * direct mid ACK or bitfield. Updates the appropriate data structures and
- * timers and frees all memory.
- *
- * @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.
+ * Test if element @a e1 comes before element @a e2.
  *
- * @return #GNUNET_YES if channel was destroyed as a result of the call,
- *         #GNUNET_NO otherwise.
+ * @param cls closure, to a flag where we indicate duplicate packets
+ * @param m1 a message of to sort
+ * @param m2 another message to sort
+ * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
  */
 static int
-rel_message_free (struct CadetReliableMessage *copy, int update_time)
+is_before (void *cls,
+           struct CadetOutOfOrderMessage *m1,
+           struct CadetOutOfOrderMessage *m2)
 {
-  struct CadetChannelReliability *rel;
-  struct GNUNET_TIME_Relative time;
+  int *duplicate = cls;
+  uint32_t v1 = ntohl (m1->mid.mid);
+  uint32_t v2 = ntohl (m2->mid.mid);
+  uint32_t delta;
 
-  rel = copy->rel;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Freeing %u\n", copy->mid);
-  if (GNUNET_YES == update_time)
+  delta = v2 - v1;
+  if (0 == delta)
+    *duplicate = GNUNET_YES;
+  if (delta > (uint32_t) INT_MAX)
   {
-    time = GNUNET_TIME_absolute_get_duration (copy->timestamp);
-    if (0 == rel->expected_delay.rel_value_us)
-      rel->expected_delay = time;
-    else
-    {
-      rel->expected_delay.rel_value_us *= 7;
-      rel->expected_delay.rel_value_us += time.rel_value_us;
-      rel->expected_delay.rel_value_us /= 8;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  message time %12s\n",
-         GNUNET_STRINGS_relative_time_to_string (time, GNUNET_NO));
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  new delay    %12s\n",
-         GNUNET_STRINGS_relative_time_to_string (rel->expected_delay,
-                                                 GNUNET_NO));
-    rel->retry_timer = rel->expected_delay;
+    /* in overflow range, we can safely assume we wrapped around */
+    return GNUNET_NO;
   }
   else
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "batch free, ignoring timing\n");
-  }
-  rel->ch->pending_messages--;
-  if (NULL != copy->chq)
-  {
-    GCT_cancel (copy->chq->tq);
-    /* copy->q is set to NULL by ch_message_sent */
-  }
-  GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " free send copy MID %u at %p\n",
-       copy->mid, copy);
-  GNUNET_free (copy);
-
-  if (GNUNET_NO != rel->ch->destroy && 0 == rel->ch->pending_messages)
-  {
-    GCCH_destroy (rel->ch);
+    /* result is small, thus v2 > v1, thus m1 < m2 */
     return GNUNET_YES;
   }
-  return GNUNET_NO;
 }
 
 
 /**
- * Channel was ACK'd by remote peer, mark as ready and cancel retransmission.
+ * We got payload data for a channel.  Pass it on to the client
+ * and send an ACK to the other end (once flow control allows it!)
  *
- * @param ch Channel to mark as ready.
- * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK)
+ * @param ch channel that got data
+ * @param cti identifier of the connection that delivered the message
+ * @param msg message that was received
  */
-static void
-channel_confirm (struct CadetChannel *ch, int fwd)
+void
+GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
+                                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                                    const struct GNUNET_CADET_ChannelAppDataMessage *msg)
 {
-  struct CadetChannelReliability *rel;
-  enum CadetChannelState oldstate;
-
-  rel = fwd ? ch->root_rel : ch->dest_rel;
-  if (NULL == rel)
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_LocalData *ld;
+  struct CadetChannelClient *ccc;
+  size_t payload_size;
+  struct CadetOutOfOrderMessage *com;
+  int duplicate;
+  uint32_t mid_min;
+  uint32_t mid_max;
+  uint32_t mid_msg;
+  uint32_t delta;
+
+  GNUNET_assert (GNUNET_NO == ch->is_loopback);
+  if ( (GNUNET_YES == ch->destroy) &&
+       (NULL == ch->owner) &&
+       (NULL == ch->dest) )
+  {
+    /* This client is gone, but we still have messages to send to
+       the other end (which is why @a ch is not yet dead).  However,
+       we cannot pass messages to our client anymore. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Dropping incoming payload on %s as this end is already closed\n",
+         GCCH_2s (ch));
+    /* send back DESTROY notification to stop further retransmissions! */
+    GCT_send_channel_destroy (ch->t,
+                              ch->ctn);
+    return;
+  }
+  payload_size = ntohs (msg->header.size) - sizeof (*msg);
+  env = GNUNET_MQ_msg_extra (ld,
+                             payload_size,
+                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
+  ld->ccn = (NULL == ch->dest) ? ch->owner->ccn : ch->dest->ccn;
+  GNUNET_memcpy (&ld[1],
+                 &msg[1],
+                 payload_size);
+  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+  if ( (GNUNET_YES == ccc->client_ready) &&
+       ( (GNUNET_YES == ch->out_of_order) ||
+         (msg->mid.mid == ch->mid_recv.mid) ) )
   {
-    GNUNET_break (GNUNET_NO != ch->destroy);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Giving %u bytes of payload with MID %u from %s to client %s\n",
+         (unsigned int) payload_size,
+         ntohl (msg->mid.mid),
+         GCCH_2s (ch),
+         GSC_2s (ccc->c));
+    ccc->client_ready = GNUNET_NO;
+    GSC_send_to_client (ccc->c,
+                        env);
+    ch->mid_recv.mid = htonl (1 + ntohl (ch->mid_recv.mid));
+    ch->mid_futures >>= 1;
+    send_channel_data_ack (ch);
     return;
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  channel confirm %s %s\n",
-       GC_f2s (fwd), GCCH_2s (ch));
-  oldstate = ch->state;
-  ch->state = CADET_CHANNEL_READY;
 
-  if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch))
+  if (GNUNET_YES == ch->reliable)
   {
-    rel->client_ready = GNUNET_YES;
-    rel->expected_delay = rel->retry_timer;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  confirm retry timer %s\n",
-         GNUNET_STRINGS_relative_time_to_string (rel->retry_timer, GNUNET_NO));
-    if (GCT_get_connections_buffer (ch->t) > 0 || GCT_is_loopback (ch->t))
-      send_client_ack (ch, fwd);
-
-    if (NULL != rel->retry_task)
+    /* check if message ought to be dropped because it is ancient/too distant/duplicate */
+    mid_min = ntohl (ch->mid_recv.mid);
+    mid_max = mid_min + ch->max_pending_messages;
+    mid_msg = ntohl (msg->mid.mid);
+    if ( ( (uint32_t) (mid_msg - mid_min) > ch->max_pending_messages) ||
+         ( (uint32_t) (mid_max - mid_msg) > ch->max_pending_messages) )
     {
-      GNUNET_SCHEDULER_cancel (rel->retry_task);
-      rel->retry_task = NULL;
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "%s at %u drops ancient or far-future message %u\n",
+           GCCH_2s (ch),
+           (unsigned int) mid_min,
+           ntohl (msg->mid.mid));
+
+      GNUNET_STATISTICS_update (stats,
+                                "# duplicate DATA (ancient or future)",
+                                1,
+                                GNUNET_NO);
+      GNUNET_MQ_discard (env);
+      send_channel_data_ack (ch);
+      return;
     }
-    else if (NULL != rel->uniq)
+    /* mark bit for future ACKs */
+    delta = mid_msg - mid_min - 1; /* overflow/underflow are OK here */
+    if (delta < 64)
     {
-      GCT_cancel (rel->uniq->tq);
-      /* ch_message_sent will free and NULL uniq */
+      if (0 != (ch->mid_futures & (1LLU << delta)))
+      {
+        /* Duplicate within the queue, drop also */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
+             (unsigned int) payload_size,
+             GCCH_2s (ch),
+             ntohl (msg->mid.mid));
+        GNUNET_STATISTICS_update (stats,
+                                  "# duplicate DATA",
+                                  1,
+                                  GNUNET_NO);
+        GNUNET_MQ_discard (env);
+        send_channel_data_ack (ch);
+        return;
+      }
+      ch->mid_futures |= (1LLU << delta);
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Marked bit %llX for mid %u (base: %u); now: %llX\n",
+           (1LLU << delta),
+           mid_msg,
+           mid_min,
+           ch->mid_futures);
     }
-    else if (GNUNET_NO == is_loopback (ch))
+  }
+  else /* ! ch->reliable */
+  {
+    /* Channel is unreliable, so we do not ACK. But we also cannot
+       allow buffering everything, so check if we have space... */
+    if (ccc->num_recv >= ch->max_pending_messages)
     {
-      /* We SHOULD have been trying to retransmit this! */
-      GNUNET_break (0);
+      struct CadetOutOfOrderMessage *drop;
+
+      /* Yep, need to drop. Drop the oldest message in
+         the buffer. */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Queue full due slow client on %s, dropping oldest message\n",
+           GCCH_2s (ch));
+      GNUNET_STATISTICS_update (stats,
+                                "# messages dropped due to slow client",
+                                1,
+                                GNUNET_NO);
+      drop = ccc->head_recv;
+      GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                                   ccc->tail_recv,
+                                   drop);
+      ccc->num_recv--;
+      GNUNET_MQ_discard (drop->env);
+      GNUNET_free (drop);
     }
   }
 
-  /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */
-  if (GNUNET_YES == fwd)
-    send_ack (ch, GNUNET_NO);
+  /* Insert message into sorted out-of-order queue */
+  com = GNUNET_new (struct CadetOutOfOrderMessage);
+  com->mid = msg->mid;
+  com->env = env;
+  duplicate = GNUNET_NO;
+  GNUNET_CONTAINER_DLL_insert_sorted (struct CadetOutOfOrderMessage,
+                                      is_before,
+                                      &duplicate,
+                                      ccc->head_recv,
+                                      ccc->tail_recv,
+                                      com);
+  ccc->num_recv++;
+  if (GNUNET_YES == duplicate)
+  {
+    /* Duplicate within the queue, drop also (this is not covered by
+       the case above if "delta" >= 64, which could be the case if
+       max_pending_messages is also >= 64 or if our client is unready
+       and we are seeing retransmissions of the message our client is
+       blocked on. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Duplicate payload of %u bytes on %s (mid %u) dropped\n",
+         (unsigned int) payload_size,
+         GCCH_2s (ch),
+         ntohl (msg->mid.mid));
+    GNUNET_STATISTICS_update (stats,
+                              "# duplicate DATA",
+                              1,
+                              GNUNET_NO);
+    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                                 ccc->tail_recv,
+                                 com);
+    ccc->num_recv--;
+    GNUNET_MQ_discard (com->env);
+    GNUNET_free (com);
+    send_channel_data_ack (ch);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Queued %s payload of %u bytes on %s-%X(%p) (mid %u, need %u first)\n",
+       (GNUNET_YES == ccc->client_ready)
+       ? "out-of-order"
+       : "client-not-ready",
+       (unsigned int) payload_size,
+       GCCH_2s (ch),
+       ntohl (ccc->ccn.channel_of_client),
+       ccc,
+       ntohl (msg->mid.mid),
+       ntohl (ch->mid_recv.mid));
+  /* NOTE: this ACK we _could_ skip, as the packet is out-of-order and
+     the sender may already be transmitting the previous one.  Needs
+     experimental evaluation to see if/when this ACK helps or
+     hurts. (We might even want another option.) */
+  send_channel_data_ack (ch);
 }
 
 
 /**
- * Save a copy to retransmit in case it gets lost.
- *
- * Initializes all needed callbacks and timers.
+ * Function called once the tunnel has sent one of our messages.
+ * If the message is unreliable, simply frees the `crm`. If the
+ * message was reliable, calculate retransmission time and
+ * wait for ACK (or retransmit).
+ *
+ * @param cls the `struct CadetReliableMessage` that was sent
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
+ */
+static void
+data_sent_cb (void *cls,
+              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
+
+
+/**
+ * We need to retry a transmission, the last one took too long to
+ * be acknowledged.
  *
- * @param ch Channel this message goes on.
- * @param msg Message to copy.
- * @param fwd Is this fwd traffic?
+ * @param cls the `struct CadetChannel` where we need to retransmit
  */
-static struct CadetReliableMessage *
-channel_save_copy (struct CadetChannel *ch,
-                   const struct GNUNET_MessageHeader *msg,
-                   int fwd)
+static void
+retry_transmission (void *cls)
 {
-  struct CadetChannelReliability *rel;
-  struct CadetReliableMessage *copy;
-  uint32_t mid;
-  uint16_t type;
-  uint16_t size;
-
-  rel = fwd ? ch->root_rel : ch->dest_rel;
-  mid = rel->mid_send - 1;
-  type = ntohs (msg->type);
-  size = ntohs (msg->size);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "save MID %u %s\n", mid, GC_m2s (type));
-  copy = GNUNET_malloc (sizeof (struct CadetReliableMessage) + size);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  at %p\n", copy);
-  copy->mid = mid;
-  copy->rel = rel;
-  copy->type = type;
-  GNUNET_memcpy (&copy[1], msg, size);
-  GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy);
-  ch->pending_messages++;
+  struct CadetChannel *ch = cls;
+  struct CadetReliableMessage *crm = ch->head_sent;
 
-  return copy;
+  ch->retry_data_task = NULL;
+  GNUNET_assert (NULL == crm->qe);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Retrying transmission on %s of message %u\n",
+       GCCH_2s (ch),
+       (unsigned int) ntohl (crm->data_message->mid.mid));
+  crm->qe = GCT_send (ch->t,
+                      &crm->data_message->header,
+                      &data_sent_cb,
+                      crm);
+  GNUNET_assert (NULL == ch->retry_data_task);
 }
 
 
 /**
- * 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.
+ * We got an PLAINTEXT_DATA_ACK for a message in our queue, remove it from
+ * the queue and tell our client that it can send more.
  *
- * @return A new initialized channel. NULL on error.
+ * @param ch the channel that got the PLAINTEXT_DATA_ACK
+ * @param cti identifier of the connection that delivered the message
+ * @param crm the message that got acknowledged
  */
-static struct CadetChannel *
-channel_new (struct CadetTunnel *t,
-             struct CadetClient *owner,
-             struct GNUNET_CADET_ClientChannelNumber lid_root)
+static void
+handle_matching_ack (struct CadetChannel *ch,
+                     const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                     struct CadetReliableMessage *crm)
 {
-  struct CadetChannel *ch;
-
-  ch = GNUNET_new (struct CadetChannel);
-  ch->root = owner;
-  ch->lid_root = lid_root;
-  ch->t = t;
-
-  GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO);
-
-  if (NULL != owner)
-  {
-    ch->gid = GCT_get_next_ctn (t);
-    GML_channel_add (owner, lid_root, ch);
+  GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+                               ch->tail_sent,
+                               crm);
+  ch->pending_messages--;
+  GNUNET_assert (ch->pending_messages < ch->max_pending_messages);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received DATA_ACK on %s for message %u (%u ACKs pending)\n",
+       GCCH_2s (ch),
+       (unsigned int) ntohl (crm->data_message->mid.mid),
+       ch->pending_messages);
+  if (NULL != crm->qe)
+  {
+    GCT_send_cancel (crm->qe);
+    crm->qe = NULL;
+  }
+  if ( (1 == crm->num_transmissions) &&
+       (NULL != cti) )
+  {
+    GCC_ack_observed (cti);
+    if (0 == memcmp (cti,
+                     &crm->connection_taken,
+                     sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier)))
+    {
+      GCC_latency_observed (cti,
+                            GNUNET_TIME_absolute_get_duration (crm->first_transmission_time));
+    }
   }
-  GCT_add_channel (t, ch);
-
-  return ch;
+  GNUNET_free (crm->data_message);
+  GNUNET_free (crm);
+  send_ack_to_client (ch,
+                      (NULL == ch->owner)
+                      ? GNUNET_NO
+                      : GNUNET_YES);
 }
 
 
 /**
- * Handle a loopback message: call the appropriate handler for the message type.
+ * We got an acknowledgement for payload data for a channel.
+ * Possibly resume transmissions.
  *
- * @param ch Channel this message is on.
- * @param msgh Message header.
- * @param fwd Is this FWD traffic?
+ * @param ch channel that got the ack
+ * @param cti identifier of the connection that delivered the message
+ * @param ack details about what was received
  */
 void
-handle_loopback (struct CadetChannel *ch,
-                 const struct GNUNET_MessageHeader *msgh,
-                 int fwd)
+GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
+                                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                                        const struct GNUNET_CADET_ChannelDataAckMessage *ack)
 {
-  uint16_t type;
-
-  type = ntohs (msgh->type);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Loopback %s %s message!\n",
-       GC_f2s (fwd), GC_m2s (type));
+  struct CadetReliableMessage *crm;
+  struct CadetReliableMessage *crmn;
+  int found;
+  uint32_t mid_base;
+  uint64_t mid_mask;
+  unsigned int delta;
 
-  switch (type)
+  GNUNET_break (GNUNET_NO == ch->is_loopback);
+  if (GNUNET_NO == ch->reliable)
   {
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
-      /* Don't send hop ACK, wait for client to ACK */
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "SEND loopback %u (%u)\n",
-           ntohl (((struct GNUNET_CADET_ChannelAppDataMessage *) msgh)->mid), ntohs (msgh->size));
-      GCCH_handle_data (ch, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
-      GCCH_handle_data_ack (ch,
-                            (const struct GNUNET_CADET_ChannelDataAckMessage *) msgh, fwd);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
-      GCCH_handle_create (ch->t,
-                          (const struct GNUNET_CADET_ChannelOpenMessage *) msgh);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
-      GCCH_handle_ack (ch,
-                       (const struct GNUNET_CADET_ChannelManageMessage *) msgh,
-                       fwd);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
-      GCCH_handle_nack (ch);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
-      GCCH_handle_destroy (ch,
-                           (const struct GNUNET_CADET_ChannelManageMessage *) msgh,
-                           fwd);
-      break;
-
-    default:
-      GNUNET_break_op (0);
+    /* not expecting ACKs on unreliable channel, odd */
+    GNUNET_break_op (0);
+    return;
+  }
+  /* mid_base is the MID of the next message that the
+     other peer expects (i.e. that is missing!), everything
+     LOWER (but excluding mid_base itself) was received. */
+  mid_base = ntohl (ack->mid.mid);
+  mid_mask = GNUNET_htonll (ack->futures);
+  found = GNUNET_NO;
+  for (crm = ch->head_sent;
+        NULL != crm;
+       crm = crmn)
+  {
+    crmn = crm->next;
+    delta = (unsigned int) (ntohl (crm->data_message->mid.mid) - mid_base);
+    if (delta >= UINT_MAX - ch->max_pending_messages)
+    {
+      /* overflow, means crm was a bit in the past, so this ACK counts for it. */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got DATA_ACK with base %u satisfying past message %u on %s\n",
+           (unsigned int) mid_base,
+           ntohl (crm->data_message->mid.mid),
+           GCCH_2s (ch));
+      handle_matching_ack (ch,
+                           cti,
+                           crm);
+      found = GNUNET_YES;
+      continue;
+    }
+    delta--;
+    if (delta >= 64)
+      continue;
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Testing bit %llX for mid %u (base: %u)\n",
+         (1LLU << delta),
+         ntohl (crm->data_message->mid.mid),
+         mid_base);
+    if (0 != (mid_mask & (1LLU << delta)))
+    {
       LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "end-to-end message not known (%u)\n",
-           ntohs (msgh->type));
+           "Got DATA_ACK with mask for %u on %s\n",
+           ntohl (crm->data_message->mid.mid),
+           GCCH_2s (ch));
+      handle_matching_ack (ch,
+                           cti,
+                           crm);
+      found = GNUNET_YES;
+    }
+  }
+  if (GNUNET_NO == found)
+  {
+    /* ACK for message we already dropped, might have been a
+       duplicate ACK? Ignore. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Duplicate DATA_ACK on %s, ignoring\n",
+         GCCH_2s (ch));
+    GNUNET_STATISTICS_update (stats,
+                              "# duplicate DATA_ACKs",
+                              1,
+                              GNUNET_NO);
+    return;
+  }
+  if (NULL != ch->retry_data_task)
+  {
+    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+    ch->retry_data_task = NULL;
   }
+  if ( (NULL != ch->head_sent) &&
+       (NULL == ch->head_sent->qe) )
+    ch->retry_data_task
+      = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
+                                 &retry_transmission,
+                                 ch);
 }
 
 
-
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
-
 /**
- * Destroy a channel and free all resources.
+ * Destroy channel, based on the other peer closing the
+ * connection.  Also needs to remove this channel from
+ * the tunnel.
  *
- * @param ch Channel to destroy.
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message,
+ *            NULL if we are simulating receiving a destroy due to shutdown
  */
 void
-GCCH_destroy (struct CadetChannel *ch)
+GCCH_handle_remote_destroy (struct CadetChannel *ch,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti)
 {
-  struct CadetClient *c;
-  struct CadetTunnel *t;
+  struct CadetChannelClient *ccc;
 
-  if (NULL == ch)
-    return;
-  if (2 == ch->destroy)
-    return; /* recursive call */
-  ch->destroy = 2;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n",
-              GCT_2s (ch->t), ch->gid);
-  GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG);
-
-  c = ch->root;
-  if (NULL != c)
-  {
-    GML_channel_remove (c, ch->lid_root, ch);
-  }
-
-  c = ch->dest;
-  if (NULL != c)
-  {
-    GML_channel_remove (c, ch->lid_dest, ch);
-  }
-
-  channel_rel_free_all (ch->root_rel);
-  channel_rel_free_all (ch->dest_rel);
-
-  t = ch->t;
-  GCT_remove_channel (t, ch);
-  GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO);
-
-  GNUNET_free (ch);
-  GCT_destroy_if_empty (t);
-}
-
-
-/**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_get_id (const struct CadetChannel *ch)
-{
-  return ch->gid;
-}
-
-
-/**
- * Get the channel tunnel.
- *
- * @param ch Channel to get the tunnel from.
- *
- * @return tunnel of the channel.
- */
-struct CadetTunnel *
-GCCH_get_tunnel (const struct CadetChannel *ch)
-{
-  return ch->t;
-}
-
-
-/**
- * Get free buffer space towards the client on a specific channel.
- *
- * @param ch Channel.
- * @param fwd Is query about FWD traffic?
- *
- * @return Free buffer space [0 - 64]
- */
-unsigned int
-GCCH_get_buffer (struct CadetChannel *ch, int fwd)
-{
-  struct CadetChannelReliability *rel;
-
-  rel = fwd ? ch->dest_rel : ch->root_rel;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "   get buffer, channel %s\n", GCCH_2s (ch));
-  GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG);
-  /* If rel is NULL it means that the end is not yet created,
-   * most probably is a loopback channel at the point of sending
-   * the ChannelCreate to itself.
-   */
-  if (NULL == rel)
+  GNUNET_assert (GNUNET_NO == ch->is_loopback);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received remote channel DESTROY for %s\n",
+       GCCH_2s (ch));
+  if (GNUNET_YES == ch->destroy)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  rel is NULL: max\n");
-    return 64;
+    /* Local client already gone, this is instant-death. */
+    channel_destroy (ch);
+    return;
   }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "   n_recv %d\n", rel->n_recv);
-  return (64 - rel->n_recv);
-}
-
-
-/**
- * Get flow control status of end point: is client allow to send?
- *
- * @param ch Channel.
- * @param fwd Is query about FWD traffic? (Request root status).
- *
- * @return #GNUNET_YES if client is allowed to send us data.
- */
-int
-GCCH_get_allowed (struct CadetChannel *ch, int fwd)
-{
-  struct CadetChannelReliability *rel;
-
-  rel = fwd ? ch->root_rel : ch->dest_rel;
-
-  if (NULL == rel)
+  ccc = (NULL != ch->owner) ? ch->owner : ch->dest;
+  if ( (NULL != ccc) &&
+       (NULL != ccc->head_recv) )
   {
-    /* Probably shutting down: root/dest NULL'ed to mark disconnection */
-    GNUNET_break (GNUNET_NO != ch->destroy);
-    return 0;
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Lost end of transmission due to remote shutdown on %s\n",
+         GCCH_2s (ch));
+    /* FIXME: change API to notify client about truncated transmission! */
   }
-
-  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
-GCCH_is_origin (struct CadetChannel *ch, int fwd)
-{
-  struct CadetClient *c;
-
-  c = fwd ? ch->root : ch->dest;
-  return NULL != c;
+  ch->destroy = GNUNET_YES;
+  if (NULL != ccc)
+    GSC_handle_remote_channel_destroy (ccc->c,
+                                       ccc->ccn,
+                                       ch);
+  channel_destroy (ch);
 }
 
 
 /**
- * Is the destination client for this channel on this peer?
+ * Test if element @a e1 comes before element @a e2.
  *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
- *
- * @return #GNUNET_YES in case it is.
+ * @param cls closure, to a flag where we indicate duplicate packets
+ * @param crm1 an element of to sort
+ * @param crm2 another element to sort
+ * @return #GNUNET_YES if @e1 < @e2, otherwise #GNUNET_NO
  */
-int
-GCCH_is_terminal (struct CadetChannel *ch, int fwd)
+static int
+cmp_crm_by_next_retry (void *cls,
+                       struct CadetReliableMessage *crm1,
+                       struct CadetReliableMessage *crm2)
 {
-  struct CadetClient *c;
-
-  c = fwd ? ch->dest : ch->root;
-  return NULL != c;
+  if (crm1->next_retry.abs_value_us <
+      crm2->next_retry.abs_value_us)
+    return GNUNET_YES;
+  return GNUNET_NO;
 }
 
 
 /**
- * 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)
+ * Function called once the tunnel has sent one of our messages.
+ * If the message is unreliable, simply frees the `crm`. If the
+ * message was reliable, calculate retransmission time and
+ * wait for ACK (or retransmit).
+ *
+ * @param cls the `struct CadetReliableMessage` that was sent
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
  */
-void
-GCCH_send_data_ack (struct CadetChannel *ch, int fwd)
+static void
+data_sent_cb (void *cls,
+              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
 {
-  struct GNUNET_CADET_ChannelDataAckMessage msg;
-  struct CadetChannelReliability *rel;
-  struct CadetReliableMessage *copy;
-  unsigned int delta;
-  uint64_t mask;
-  uint32_t ack;
-
+  struct CadetReliableMessage *crm = cls;
+  struct CadetChannel *ch = crm->ch;
+
+  GNUNET_assert (GNUNET_NO == ch->is_loopback);
+  GNUNET_assert (NULL != crm->qe);
+  crm->qe = NULL;
+  GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+                               ch->tail_sent,
+                               crm);
   if (GNUNET_NO == ch->reliable)
-    return;
-
-  rel = fwd ? ch->dest_rel : ch->root_rel;
-  ack = rel->mid_recv - 1;
-
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK);
-  msg.header.size = htons (sizeof (msg));
-  msg.ctn = ch->gid;
-  msg.mid = htonl (ack);
-
-  msg.futures = 0LL;
-  for (copy = rel->head_recv; NULL != copy; copy = copy->next)
   {
-    if (copy->type != GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " Type %s, expected DATA\n",
-           GC_m2s (copy->type));
-      continue;
-    }
-    GNUNET_assert (GC_is_pid_bigger(copy->mid, ack));
-    delta = copy->mid - (ack + 1);
-    if (63 < delta)
-      break;
-    mask = 0x1LL << delta;
-    msg.futures |= mask;
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         " setting bit for %u (delta %u) (%lX) -> %lX\n",
-         copy->mid, delta, mask, msg.futures);
+    GNUNET_free (crm->data_message);
+    GNUNET_free (crm);
+    ch->pending_messages--;
+    send_ack_to_client (ch,
+                        (NULL == ch->owner)
+                        ? GNUNET_NO
+                        : GNUNET_YES);
+    return;
   }
-
-  GCCH_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
-GCCH_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)
+  if (NULL == cid)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n");
-    return;
+    /* There was an error sending. */
+    crm->num_transmissions = GNUNET_SYSERR;
   }
-
-  if (GNUNET_YES == ch->reliable)
+  else if (GNUNET_SYSERR != crm->num_transmissions)
   {
-    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);
-        struct CadetReliableMessage *aux;
-        for (aux = rel->head_sent; NULL != aux; aux = aux->next)
-        {
-          LOG (GNUNET_ERROR_TYPE_DEBUG, "   - sent mid %u\n", aux->mid);
-        }
-      }
-    }
-    else
+    /* Increment transmission counter, and possibly store @a cid
+       if this was the first transmission. */
+    crm->num_transmissions++;
+    if (1 == crm->num_transmissions)
     {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n");
+      crm->first_transmission_time = GNUNET_TIME_absolute_get ();
+      crm->connection_taken = *cid;
+      GCC_ack_expected (cid);
     }
   }
-
-  if (is_loopback (ch))
-    buffer = GCCH_get_buffer (ch, fwd);
-  else
-    buffer = GCT_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.
- * @param level Debug level to use.
- */
-void
-GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level)
-{
-  int do_log;
-
-  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
-                                       "cadet-chn",
-                                       __FILE__, __FUNCTION__, __LINE__);
-  if (0 == do_log)
-    return;
-
-  if (NULL == ch)
-  {
-    LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
-    return;
-  }
-  LOG2 (level, "CHN Channel %s:%X (%p)\n", GCT_2s (ch->t), ch->gid, ch);
-  LOG2 (level, "CHN   root %p/%p\n", ch->root, ch->root_rel);
-  if (NULL != ch->root)
+  if ( (0 == crm->retry_delay.rel_value_us) &&
+       (NULL != cid) )
   {
-    LOG2 (level, "CHN   cli %s\n", GML_2s (ch->root));
-    LOG2 (level, "CHN   ready %s\n", ch->root_rel->client_ready ? "YES" : "NO");
-    LOG2 (level, "CHN   id %X\n", ch->lid_root.channel_of_client);
-    LOG2 (level, "CHN   recv %d\n", ch->root_rel->n_recv);
-    LOG2 (level, "CHN   MID r: %d, s: %d\n",
-          ch->root_rel->mid_recv, ch->root_rel->mid_send);
-  }
-  LOG2 (level, "CHN   dest %p/%p\n",
-              ch->dest, ch->dest_rel);
-  if (NULL != ch->dest)
-  {
-    LOG2 (level, "CHN   cli %s\n", GML_2s (ch->dest));
-    LOG2 (level, "CHN   ready %s\n", ch->dest_rel->client_ready ? "YES" : "NO");
-    LOG2 (level, "CHN   id %X\n", ch->lid_dest);
-    LOG2 (level, "CHN   recv %d\n", ch->dest_rel->n_recv);
-    LOG2 (level, "CHN   MID r: %d, s: %d\n",
-          ch->dest_rel->mid_recv, ch->dest_rel->mid_send);
-
-  }
-}
+    struct CadetConnection *cc = GCC_lookup (cid);
 
-
-/**
- * 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
-GCCH_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);
-    GCCH_destroy (ch);
-    return;
-  }
-  /* if loopback is marked for destruction, no need to ACK to the other peer,
-   * it requested the destruction and is already gone, therefore, else if.
-   */
-  else if (is_loopback (ch))
-  {
-    unsigned int buffer;
-
-    buffer = GCCH_get_buffer (ch, fwd);
-    if (0 < buffer)
-      GCCH_allow_client (ch, fwd);
-
-    return;
+    if (NULL != cc)
+      crm->retry_delay = GCC_get_metrics (cc)->aged_latency;
+    else
+      crm->retry_delay = ch->retry_time;
+  }
+  crm->retry_delay = GNUNET_TIME_STD_BACKOFF (crm->retry_delay);
+  crm->retry_delay = GNUNET_TIME_relative_max (crm->retry_delay,
+                                               MIN_RTT_DELAY);
+  crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
+
+  GNUNET_CONTAINER_DLL_insert_sorted (struct CadetReliableMessage,
+                                      cmp_crm_by_next_retry,
+                                      NULL,
+                                      ch->head_sent,
+                                      ch->tail_sent,
+                                      crm);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Message %u sent, next transmission on %s in %s\n",
+       (unsigned int) ntohl (crm->data_message->mid.mid),
+       GCCH_2s (ch),
+       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (ch->head_sent->next_retry),
+                                               GNUNET_YES));
+  if (NULL == ch->head_sent->qe)
+  {
+    if (NULL != ch->retry_data_task)
+      GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+    ch->retry_data_task
+      = GNUNET_SCHEDULER_add_at (ch->head_sent->next_retry,
+                                 &retry_transmission,
+                                 ch);
   }
-  GCT_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.
+ * Check whether the client is allowed to send in this tunnel, save if
+ * channel is reliable and send an ACK to the client if there is still
+ * buffer space in the tunnel.
  *
  * @param ch Channel.
- * @param c Client which sent the data.
- * @param fwd Is this a FWD data?
- * @param message Data message.
- * @param size Size of data.
- *
- * @return #GNUNET_OK if everything goes well, #GNUNET_SYSERR in case of en error.
+ * @param sender_ccn ccn of the sender
+ * @param buf payload to transmit.
+ * @param buf_len number of bytes in @a buf
+ * @return #GNUNET_OK if everything goes well,
+ *         #GNUNET_SYSERR in case of an error.
  */
 int
 GCCH_handle_local_data (struct CadetChannel *ch,
-                        struct CadetClient *c,
-                        int fwd,
-                        const struct GNUNET_MessageHeader *message,
-                        size_t size)
+                        struct GNUNET_CADET_ClientChannelNumber sender_ccn,
+                        const char *buf,
+                        size_t buf_len)
 {
-  struct CadetChannelReliability *rel;
-  struct GNUNET_CADET_ChannelAppDataMessage *payload;
-  uint16_t p2p_size = sizeof(struct GNUNET_CADET_ChannelAppDataMessage) + size;
-  unsigned char cbuf[p2p_size];
-  unsigned char buffer;
-
-  /* Is the client in the channel? */
-  if ( !( (fwd &&
-           ch->root == c)
-         ||
-          (!fwd &&
-           ch->dest == c) ) )
-  {
-    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;
-  }
+  struct CadetReliableMessage *crm;
 
-  rel->client_allowed = GNUNET_NO;
-
-  /* Ok, everything is correct, send the message. */
-  payload = (struct GNUNET_CADET_ChannelAppDataMessage *) cbuf;
-  payload->mid = htonl (rel->mid_send);
-  rel->mid_send++;
-  GNUNET_memcpy (&payload[1], message, size);
-  payload->header.size = htons (p2p_size);
-  payload->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
-  payload->ctn = ch->gid;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  sending on channel...\n");
-  GCCH_send_prebuilt_message (&payload->header, ch, fwd, NULL);
-
-  if (is_loopback (ch))
-    buffer = GCCH_get_buffer (ch, fwd);
-  else
-    buffer = GCT_get_connections_buffer (ch->t);
-
-  if (0 < buffer)
-    GCCH_allow_client (ch, fwd);
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Handle a channel destroy requested by a client.
- *
- * TODO: add "reason" field
- *
- * Destroy the channel and the tunnel in case this was the last channel.
- *
- * @param ch Channel.
- * @param c Client that requested the destruction (to avoid notifying him).
- * @param is_root Is the request coming from root?
- */
-void
-GCCH_handle_local_destroy (struct CadetChannel *ch,
-                           struct CadetClient *c,
-                           int is_root)
-{
-  ch->destroy = GNUNET_YES;
-  /* Cleanup after the tunnel */
-  if (GNUNET_NO == is_root && c == ch->dest)
-  {
-    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)
-    GCCH_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
-GCCH_handle_local_create (struct CadetClient *c,
-                          struct GNUNET_CADET_LocalChannelCreateMessage *msg)
-{
-  struct CadetChannel *ch;
-  struct CadetTunnel *t;
-  struct CadetPeer *peer;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  towards %s:%u\n",
-       GNUNET_i2s (&msg->peer), GNUNET_h2s (&msg->port));
-  ccn = msg->ccn;
-
-  /* Sanity check for duplicate channel IDs */
-  if (NULL != GML_channel_get (c, ccn))
+  if (ch->pending_messages > ch->max_pending_messages)
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-
-  peer = GCP_get (&msg->peer, GNUNET_YES);
-  GCP_add_tunnel (peer);
-  t = GCP_get_tunnel (peer);
-
-  if (GCP_get_short_id (peer) == myid)
-  {
-    GCT_change_cstate (t, CADET_TUNNEL_READY);
-  }
-  else
+  if (GNUNET_YES == ch->destroy)
   {
-    /* FIXME change to a tunnel API, eliminate ch <-> peer connection */
-    GCP_connect (peer);
+    /* we are going down, drop messages */
+    return GNUNET_OK;
   }
+  ch->pending_messages++;
 
-  /* Create channel */
-  ch = channel_new (t, c, ccn);
-  if (NULL == ch)
-  {
-    GNUNET_break (0);
-    return GNUNET_SYSERR;
-  }
-  ch->port = msg->port;
-  channel_set_options (ch, ntohl (msg->opt));
-
-  /* In unreliable channels, we'll use the DLL to buffer BCK data */
-  ch->root_rel = GNUNET_new (struct CadetChannelReliability);
-  ch->root_rel->ch = ch;
-  ch->root_rel->retry_timer = CADET_RETRANSMIT_TIME;
-  ch->root_rel->expected_delay.rel_value_us = 0;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "CREATED CHANNEL %s\n", GCCH_2s (ch));
-
-  send_create (ch);
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Handler for cadet network payload traffic.
- *
- * @param ch Channel for the message.
- * @param msg Unencryted data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GCCH_handle_data (struct CadetChannel *ch,
-                  const struct GNUNET_CADET_ChannelAppDataMessage *msg,
-                  int fwd)
-{
-  struct CadetChannelReliability *rel;
-  struct CadetClient *c;
-  struct GNUNET_MessageHeader *payload_msg;
-  uint32_t mid;
-  uint16_t payload_type;
-  uint16_t payload_size;
-
-  /* If this is a remote (non-loopback) channel, find 'fwd'. */
-  if (GNUNET_SYSERR == fwd)
-  {
-    if (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)
+  if (GNUNET_YES == ch->is_loopback)
   {
-    GNUNET_break (GNUNET_NO != ch->destroy);
-    return;
-  }
+    struct CadetChannelClient *receiver;
+    struct GNUNET_MQ_Envelope *env;
+    struct GNUNET_CADET_LocalData *ld;
+    int ack_to_owner;
 
-  if (CADET_CHANNEL_READY != ch->state)
-  {
-    if (GNUNET_NO == fwd)
+    env = GNUNET_MQ_msg_extra (ld,
+                               buf_len,
+                               GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
+    if ( (NULL != ch->owner) &&
+         (sender_ccn.channel_of_client ==
+          ch->owner->ccn.channel_of_client) )
     {
-      /* If we are the root, this means the other peer has sent traffic before
-       * receiving our ACK. Even if the SYNACK goes missing, no traffic should
-       * be sent before the ACK.
-       */
-      GNUNET_break_op (0);
-      return;
+      receiver = ch->dest;
+      ack_to_owner = GNUNET_YES;
     }
-    /* If we are the dest, this means that the SYNACK got to the root but
-     * the ACK went missing. Treat this as an ACK.
-     */
-    channel_confirm (ch, GNUNET_NO);
-  }
-
-  payload_msg = (struct GNUNET_MessageHeader *) &msg[1];
-  payload_type = ntohs (payload_msg->type);
-  payload_size = ntohs (payload_msg->size);
-
-  GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
-  GNUNET_STATISTICS_update (stats, "# bytes received", payload_size, GNUNET_NO);
-
-  mid = ntohl (msg->mid);
-  LOG (GNUNET_ERROR_TYPE_INFO, "<== %s (%s %4u) on chan %s (%p) %s [%5u]\n",
-       GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA), GC_m2s (payload_type), mid,
-       GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
-
-  if ( (GNUNET_NO == ch->reliable) ||
-       ( (! GC_is_pid_bigger (rel->mid_recv, mid)) &&
-        GC_is_pid_bigger (rel->mid_recv + 64, mid) ) )
-  {
-    if (GNUNET_YES == ch->reliable)
+    else if ( (NULL != ch->dest) &&
+              (sender_ccn.channel_of_client ==
+               ch->dest->ccn.channel_of_client) )
     {
-      /* Is this the exact next expected messasge? */
-      if (mid == rel->mid_recv)
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-            "as expected, sending to client\n");
-        send_client_data (ch, msg, fwd);
-      }
-      else
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-            "save for later\n");
-        add_buffered_data (msg, rel);
-      }
+      receiver = ch->owner;
+      ack_to_owner = GNUNET_NO;
     }
     else
     {
-      /* Tunnel is unreliable: send to clients directly */
-      /* FIXME: accept Out Of Order traffic */
-      rel->mid_recv = mid + 1;
-      send_client_data (ch, msg, fwd);
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
     }
-  }
-  else
-  {
-    GNUNET_STATISTICS_update (stats, "# duplicate MID", 1, GNUNET_NO);
-    if (GC_is_pid_bigger (rel->mid_recv, mid))
+    GNUNET_assert (NULL != receiver);
+    ld->ccn = receiver->ccn;
+    GNUNET_memcpy (&ld[1],
+                   buf,
+                   buf_len);
+    if (GNUNET_YES == receiver->client_ready)
     {
-      GNUNET_break_op (0);
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-           "MID %u on channel %s not expected (window: %u - %u). Dropping!\n",
-           mid, GCCH_2s (ch), rel->mid_recv, rel->mid_recv + 63);
+      ch->pending_messages--;
+      GSC_send_to_client (receiver->c,
+                          env);
+      send_ack_to_client (ch,
+                          ack_to_owner);
     }
     else
     {
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           "Duplicate MID %u, channel %s (expecting MID %u). Re-sending ACK!\n",
-           mid, GCCH_2s (ch), rel->mid_recv);
-      if (NULL != rel->uniq)
-      {
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             "We are trying to send an ACK, but don't seem have the "
-             "bandwidth. Have you set enough [ats] QUOTA in your config?\n");
-      }
-
+      struct CadetOutOfOrderMessage *oom;
+
+      oom = GNUNET_new (struct CadetOutOfOrderMessage);
+      oom->env = env;
+      GNUNET_CONTAINER_DLL_insert_tail (receiver->head_recv,
+                                        receiver->tail_recv,
+                                        oom);
+      receiver->num_recv++;
     }
-  }
-
-  GCCH_send_data_ack (ch, fwd);
+    return GNUNET_OK;
+  }
+
+  /* Everything is correct, send the message. */
+  crm = GNUNET_malloc (sizeof (*crm));
+  crm->ch = ch;
+  crm->data_message = GNUNET_malloc (sizeof (struct GNUNET_CADET_ChannelAppDataMessage)
+                                     + buf_len);
+  crm->data_message->header.size = htons (sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + buf_len);
+  crm->data_message->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA);
+  ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
+  crm->data_message->mid = ch->mid_send;
+  crm->data_message->ctn = ch->ctn;
+  GNUNET_memcpy (&crm->data_message[1],
+                 buf,
+                 buf_len);
+  GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
+                                    ch->tail_sent,
+                                    crm);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending message %u from local client to %s with %u bytes\n",
+       ntohl (crm->data_message->mid.mid),
+       GCCH_2s (ch),
+       buf_len);
+  if (NULL != ch->retry_data_task)
+  {
+    GNUNET_SCHEDULER_cancel (ch->retry_data_task);
+    ch->retry_data_task = NULL;
+  }
+  crm->qe = GCT_send (ch->t,
+                      &crm->data_message->header,
+                      &data_sent_cb,
+                      crm);
+  GNUNET_assert (NULL == ch->retry_data_task);
+  return GNUNET_OK;
 }
 
 
 /**
- * Handler for cadet network traffic end-to-end ACKs.
+ * Handle ACK from client on local channel.  Means the client is ready
+ * for more data, see if we have any for it.
  *
- * @param ch Channel on which we got this message.
- * @param msg Data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
+ * @param ch channel to destroy
+ * @param client_ccn ccn of the client sending the ack
  */
 void
-GCCH_handle_data_ack (struct CadetChannel *ch,
-                      const struct GNUNET_CADET_ChannelDataAckMessage *msg,
-                      int fwd)
+GCCH_handle_local_ack (struct CadetChannel *ch,
+                       struct GNUNET_CADET_ClientChannelNumber client_ccn)
 {
-  struct CadetChannelReliability *rel;
-  struct CadetReliableMessage *copy;
-  struct CadetReliableMessage *next;
-  uint32_t ack;
-  int work;
-
-  /* If this is a remote (non-loopback) channel, find 'fwd'. */
-  if (GNUNET_SYSERR == fwd)
-  {
-    if (is_loopback (ch))
-    {
-      /* It is a loopback channel after all... */
-      GNUNET_break (0);
-      return;
-    }
-    /* Inverted: if message came 'FWD' is a 'BCK ACK'. */
-    fwd = (NULL != ch->dest) ? GNUNET_NO : GNUNET_YES;
-  }
-
-  ack = ntohl (msg->mid);
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "<== %s (0x%010lX %4u) on chan %s (%p) %s [%5u]\n",
-       GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK), msg->futures, ack,
-       GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
-
-  if (GNUNET_YES == fwd)
-    rel = ch->root_rel;
+  struct CadetChannelClient *ccc;
+  struct CadetOutOfOrderMessage *com;
+
+  if ( (NULL != ch->owner) &&
+       (ch->owner->ccn.channel_of_client == client_ccn.channel_of_client) )
+    ccc = ch->owner;
+  else if ( (NULL != ch->dest) &&
+            (ch->dest->ccn.channel_of_client == client_ccn.channel_of_client) )
+    ccc = ch->dest;
   else
-    rel = ch->dest_rel;
-
-  if (NULL == rel)
-  {
-    GNUNET_break (GNUNET_NO != ch->destroy);
-    return;
-  }
-
-  /* Free ACK'd copies: no need to retransmit those anymore FIXME refactor */
-  for (work = GNUNET_NO, copy = rel->head_sent; copy != NULL; copy = next)
+    GNUNET_assert (0);
+  ccc->client_ready = GNUNET_YES;
+  com = ccc->head_recv;
+  if (NULL == com)
   {
-    if (GC_is_pid_bigger (copy->mid, ack))
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "  head %u, out!\n", copy->mid);
-      if (0 < channel_rel_free_sent (rel, msg))
-        work = GNUNET_YES;
-      break;
-    }
-    work = GNUNET_YES;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  id %u\n", copy->mid);
-    next = copy->next;
-    if (GNUNET_YES == rel_message_free (copy, GNUNET_YES))
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got LOCAL_ACK, %s-%X ready to receive more data, but none pending on %s-%X(%p)!\n",
+         GSC_2s (ccc->c),
+         ntohl (client_ccn.channel_of_client),
+         GCCH_2s (ch),
+         ntohl (ccc->ccn.channel_of_client),
+         ccc);
+    return; /* none pending */
+  }
+  if (GNUNET_YES == ch->is_loopback)
+  {
+    int to_owner;
+
+    /* Messages are always in-order, just send */
+    GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                                 ccc->tail_recv,
+                                 com);
+    ccc->num_recv--;
+    GSC_send_to_client (ccc->c,
+                        com->env);
+    /* Notify sender that we can receive more */
+    if ( (NULL != ch->owner) &&
+         (ccc->ccn.channel_of_client ==
+          ch->owner->ccn.channel_of_client) )
     {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " channel destoyed\n");
-      return;
-    }
-  }
-
-  /* ACK client if needed and possible */
-  GCCH_allow_client (ch, fwd);
-
-  /* If some message was free'd, update the retransmission delay */
-  if (GNUNET_YES == work)
-  {
-    if (NULL != rel->retry_task)
-    {
-      GNUNET_SCHEDULER_cancel (rel->retry_task);
-      rel->retry_task = NULL;
-      if (NULL != rel->head_sent && NULL == rel->head_sent->chq)
-      {
-        struct GNUNET_TIME_Absolute new_target;
-        struct GNUNET_TIME_Relative delay;
-
-        delay = GNUNET_TIME_relative_saturating_multiply (rel->retry_timer,
-                                                          CADET_RETRANSMIT_MARGIN);
-        new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp,
-                                               delay);
-        delay = GNUNET_TIME_absolute_get_remaining (new_target);
-        rel->retry_task =
-            GNUNET_SCHEDULER_add_delayed (delay,
-                                          &channel_retransmit_message,
-                                          rel);
-      }
+      to_owner = GNUNET_NO;
     }
     else
     {
-      /* Work was done but no task was pending.
-       * Task was cancelled by a retransmission that is sitting in the queue.
-       */
-      // FIXME add test to make sure this is the case, probably add return
-      // value to GCCH_send_prebuilt_message
+      GNUNET_assert ( (NULL != ch->dest) &&
+                      (ccc->ccn.channel_of_client ==
+                       ch->dest->ccn.channel_of_client) );
+      to_owner = GNUNET_YES;
     }
+    send_ack_to_client (ch,
+                        to_owner);
+    GNUNET_free (com);
+    return;
   }
-}
-
-
-/**
- * Handler for channel create messages.
- *
- * Does not have fwd parameter because it's always 'FWD': channel is incoming.
- *
- * @param t Tunnel this channel will be in.
- * @param msg Channel crate message.
- */
-struct CadetChannel *
-GCCH_handle_create (struct CadetTunnel *t,
-                    const struct GNUNET_CADET_ChannelOpenMessage *msg)
-{
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-  struct GNUNET_CADET_ChannelTunnelNumber gid;
-  struct CadetChannel *ch;
-  struct CadetClient *c;
-  int new_channel;
-  const struct GNUNET_HashCode *port;
 
-  gid = msg->ctn;
-  ch = GCT_get_channel (t, gid);
-  if (NULL == ch)
-  {
-    /* Create channel */
-    ccn.channel_of_client = htonl (0);
-    ch = channel_new (t, NULL, ccn);
-    ch->gid = gid;
-    channel_set_options (ch, ntohl (msg->opt));
-    new_channel = GNUNET_YES;
-  }
-  else
+  if ( (com->mid.mid != ch->mid_recv.mid) &&
+       (GNUNET_NO == ch->out_of_order) &&
+       (GNUNET_YES == ch->reliable) )
   {
-    new_channel = GNUNET_NO;
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got LOCAL_ACK, %s-%X ready to receive more data (but next one is out-of-order %u vs. %u)!\n",
+         GSC_2s (ccc->c),
+         ntohl (ccc->ccn.channel_of_client),
+         ntohl (com->mid.mid),
+         ntohl (ch->mid_recv.mid));
+    return; /* missing next one in-order */
   }
-  port = &msg->port;
-
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "<== %s (  0x%08X %4u) on chan %s (%p) %s [%5u]\n",
-       GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN), ccn, port,
-       GCCH_2s (ch), ch, GC_f2s (GNUNET_YES), ntohs (msg->header.size));
-
-  if (GNUNET_YES == new_channel || GCT_is_loopback (t))
-  {
-    /* Find a destination client */
-    ch->port = *port;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "   port %s\n", GNUNET_h2s (port));
-    c = GML_client_get_by_port (port);
-    if (NULL == c)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "  no client has port registered\n");
-      if (is_loopback (ch))
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "  loopback: destroy on handler\n");
-        send_nack (ch);
-      }
-      else
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "  not loopback: destroy now\n");
-        send_nack (ch);
-        GCCH_destroy (ch);
-      }
-      return NULL;
-    }
-    else
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "  client %p has port registered\n", c);
-    }
-
-    add_destination (ch, c);
-    if (GNUNET_YES == ch->reliable)
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Reliable\n");
-    else
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Not Reliable\n");
 
-    send_client_create (ch);
-    ch->state =  CADET_CHANNEL_SENT;
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  duplicate create channel\n");
-    if (NULL != ch->dest_rel->retry_task)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "  clearing retry task\n");
-      /* we were waiting to re-send our 'SYNACK', wait no more! */
-      GNUNET_SCHEDULER_cancel (ch->dest_rel->retry_task);
-      ch->dest_rel->retry_task = NULL;
-    }
-    else if (NULL != ch->dest_rel->uniq)
-    {
-      /* we are waiting to for our 'SYNACK' to leave the queue, all done! */
-      return ch;
-    }
-  }
-  send_ack (ch, GNUNET_YES);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got LOCAL_ACK, giving payload message %u to %s-%X on %s\n",
+       ntohl (com->mid.mid),
+       GSC_2s (ccc->c),
+       ntohl (ccc->ccn.channel_of_client),
+       GCCH_2s (ch));
 
-  return ch;
+  /* all good, pass next message to client */
+  GNUNET_CONTAINER_DLL_remove (ccc->head_recv,
+                               ccc->tail_recv,
+                               com);
+  ccc->num_recv--;
+  /* FIXME: if unreliable, this is not aggressive
+     enough, as it would be OK to have lost some! */
+
+  ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
+  ch->mid_futures >>= 1; /* equivalent to division by 2 */
+  ccc->client_ready = GNUNET_NO;
+  GSC_send_to_client (ccc->c,
+                      com->env);
+  GNUNET_free (com);
+  send_channel_data_ack (ch);
+  if (NULL != ccc->head_recv)
+    return;
+  if (GNUNET_NO == ch->destroy)
+    return;
+  GCT_send_channel_destroy (ch->t,
+                            ch->ctn);
+  channel_destroy (ch);
 }
 
 
-/**
- * Handler for channel NACK messages.
- *
- * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
- *
- * @param ch Channel.
- */
-void
-GCCH_handle_nack (struct CadetChannel *ch)
-{
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "<== %s (  0x%08X %4u) on chan %s (%p) %s [%5u]\n",
-       GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED), ch->gid, 0,
-       GCCH_2s (ch), ch, "---", 0);
-
-  send_client_nack (ch);
-  GCCH_destroy (ch);
-}
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
 
 
 /**
- * Handler for channel ack messages.
+ * Log channel info.
  *
  * @param ch Channel.
- * @param msg Message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GCCH_handle_ack (struct CadetChannel *ch,
-                 const struct GNUNET_CADET_ChannelManageMessage *msg,
-                 int fwd)
-{
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "<== %s (  0x%08X %4u) on chan %s (%p) %s [%5u]\n",
-       GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK), ch->gid, 0,
-       GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
-
-  /* If this is a remote (non-loopback) channel, find 'fwd'. */
-  if (GNUNET_SYSERR == fwd)
-  {
-    if (is_loopback (ch))
-    {
-      /* It is a loopback channel after all... */
-      GNUNET_break (0);
-      return;
-    }
-    fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
-  }
-
-  channel_confirm (ch, !fwd);
-}
-
-
-/**
- * Handler for channel destroy messages.
- *
- * @param ch Channel to be destroyed of.
- * @param msg Message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
+ * @param level Debug level to use.
  */
 void
-GCCH_handle_destroy (struct CadetChannel *ch,
-                     const struct GNUNET_CADET_ChannelManageMessage *msg,
-                     int fwd)
+GCCH_debug (struct CadetChannel *ch,
+            enum GNUNET_ErrorType level)
 {
-  struct CadetChannelReliability *rel;
-
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "<== %s (  0x%08X %4u) on chan %s (%p) %s [%5u]\n",
-       GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY), ch->gid, 0,
-       GCCH_2s (ch), ch, GC_f2s (fwd), ntohs (msg->header.size));
-
-  /* If this is a remote (non-loopback) channel, find 'fwd'. */
-  if (GNUNET_SYSERR == fwd)
-  {
-    if (is_loopback (ch))
-    {
-      /* It is a loopback channel after all... */
-      GNUNET_break (0);
-      return;
-    }
-    fwd = (NULL != ch->dest) ? GNUNET_YES : GNUNET_NO;
-  }
+  int do_log;
 
-  GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG);
-  if ( (fwd && NULL == ch->dest) || (!fwd && NULL == ch->root) )
-  {
-    /* Not for us (don't destroy twice a half-open loopback channel) */
+  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
+                                       "cadet-chn",
+                                       __FILE__, __FUNCTION__, __LINE__);
+  if (0 == do_log)
     return;
-  }
-
-  rel = fwd ? ch->dest_rel : ch->root_rel;
-  if (0 == rel->n_recv)
-  {
-    send_destroy (ch, GNUNET_YES);
-    GCCH_destroy (ch);
-  }
-  else
-  {
-    ch->destroy = GNUNET_YES;
-  }
-}
-
-
-/**
- * Sends an already built message on a channel.
- *
- * If the channel is on a loopback tunnel, notifies the appropriate destination
- * client locally.
- *
- * On a normal channel passes the message to the tunnel for encryption and
- * sending on a connection.
- *
- * This function DOES NOT save the message for retransmission.
- *
- * @param message Message to send. Function makes a copy of it.
- * @param ch Channel on which this message is transmitted.
- * @param fwd Is this a fwd message?
- * @param existing_copy This is a retransmission, don't save a copy.
- */
-void
-GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
-                            struct CadetChannel *ch, int fwd,
-                            void *existing_copy)
-{
-  struct CadetChannelQueue *chq;
-  uint32_t data_id;
-  uint16_t type;
-  uint16_t size;
-  char info[32];
-
-  type = ntohs (message->type);
-  size = ntohs (message->size);
 
-  data_id = 0;
-  switch (type)
-  {
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
-    {
-      struct GNUNET_CADET_ChannelAppDataMessage *data_msg;
-      struct GNUNET_MessageHeader *payload_msg;
-      uint16_t payload_type;
-
-      data_msg = (struct GNUNET_CADET_ChannelAppDataMessage *) message;
-      data_id = ntohl (data_msg->mid);
-      payload_msg = (struct GNUNET_MessageHeader *) &data_msg[1];
-      payload_type = ntohs (payload_msg->type);
-      strncpy (info, GC_m2s (payload_type), 31);
-      info[31] = '\0';
-      break;
-    }
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
-    {
-      struct GNUNET_CADET_ChannelDataAckMessage *ack_msg;
-      ack_msg = (struct GNUNET_CADET_ChannelDataAckMessage *) message;
-      data_id = ntohl (ack_msg->mid);
-      SPRINTF (info, "0x%010lX",
-              (unsigned long int) ack_msg->futures);
-      break;
-    }
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
-    {
-      struct GNUNET_CADET_ChannelOpenMessage *cc_msg;
-      cc_msg = (struct GNUNET_CADET_ChannelOpenMessage *) message;
-      SPRINTF (info, "  0x%08X", ntohl (cc_msg->ctn.cn));
-      break;
-    }
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
-    {
-      struct GNUNET_CADET_ChannelManageMessage *m_msg;
-      m_msg = (struct GNUNET_CADET_ChannelManageMessage *) message;
-      SPRINTF (info, "  0x%08X", ntohl (m_msg->ctn.cn));
-      break;
-    }
-    default:
-      info[0] = '\0';
-  }
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "==> %s (%12s %4u) on chan %s (%p) %s [%5u]\n",
-       GC_m2s (type), info, data_id,
-       GCCH_2s (ch), ch, GC_f2s (fwd), size);
-
-  if (GCT_is_loopback (ch->t))
+  if (NULL == ch)
   {
-    handle_loopback (ch, message, fwd);
+    LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
     return;
   }
-
-  switch (type)
+  LOG2 (level,
+        "CHN %s:%X (%p)\n",
+        GCT_2s (ch->t),
+        ch->ctn,
+        ch);
+  if (NULL != ch->owner)
   {
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
-      if (GNUNET_YES == ch->reliable)
-      {
-        chq = GNUNET_new (struct CadetChannelQueue);
-        chq->type = type;
-        if (NULL == existing_copy)
-          chq->copy = channel_save_copy (ch, message, fwd);
-        else
-        {
-          chq->copy = (struct CadetReliableMessage *) existing_copy;
-          if (NULL != chq->copy->chq)
-          {
-            /* Last retransmission was queued but not yet sent!
-             * This retransmission was scheduled by a ch_message_sent which
-             * followed a very fast RTT, so the tiny delay made the
-             * retransmission function to execute before the previous
-             * retransmitted message even had a chance to leave the peer.
-             * Cancel this message and wait until the pending
-             * retransmission leaves the peer and ch_message_sent starts
-             * the timer for the next one.
-             */
-            GNUNET_free (chq);
-            LOG (GNUNET_ERROR_TYPE_DEBUG,
-                 "  exisitng copy not yet transmitted!\n");
-            return;
-          }
-          LOG (GNUNET_ERROR_TYPE_DEBUG,
-               "  using existing copy: %p {r:%p q:%p t:%u}\n",
-               existing_copy,
-               chq->copy->rel, chq->copy->chq, chq->copy->type);
-        }
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "  new chq: %p\n", chq);
-        chq->copy->chq = chq;
-        chq->tq = GCT_send_prebuilt_message (message, ch->t, NULL,
-                                             GNUNET_YES,
-                                             &ch_message_sent, chq);
-        /* q itself is stored in copy */
-        GNUNET_assert (NULL != chq->tq || GNUNET_NO != ch->destroy);
-      }
-      else
-      {
-        fire_and_forget (message, ch, GNUNET_NO);
-      }
-      break;
-
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
-      chq = GNUNET_new (struct CadetChannelQueue);
-      chq->type = type;
-      chq->rel = fwd ? ch->root_rel : ch->dest_rel;
-      if (NULL != chq->rel->uniq)
-      {
-        if (NULL != chq->rel->uniq->tq)
-        {
-          GCT_cancel (chq->rel->uniq->tq);
-          /* ch_message_sent is called, freeing and NULLing uniq */
-          GNUNET_break (NULL == chq->rel->uniq);
-        }
-        else
-        {
-          GNUNET_break (0);
-          GNUNET_free (chq->rel->uniq);
-        }
-      }
-
-      chq->rel->uniq = chq;
-      chq->tq = GCT_send_prebuilt_message (message, ch->t, NULL, GNUNET_YES,
-                                           &ch_message_sent, chq);
-      if (NULL == chq->tq)
-      {
-        GNUNET_break (0);
-       chq->rel->uniq = NULL;
-        GCT_debug (ch->t, GNUNET_ERROR_TYPE_ERROR);
-        GNUNET_free (chq);
-        chq = NULL;
-        return;
-      }
-      break;
-
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
-      fire_and_forget (message, ch, GNUNET_YES);
-      break;
-
-
-    default:
-      GNUNET_break (0);
-      LOG (GNUNET_ERROR_TYPE_WARNING, "type %s unknown!\n", GC_m2s (type));
-      fire_and_forget (message, ch, GNUNET_YES);
+    LOG2 (level,
+          "CHN origin %s ready %s local-id: %u\n",
+          GSC_2s (ch->owner->c),
+          ch->owner->client_ready ? "YES" : "NO",
+          ntohl (ch->owner->ccn.channel_of_client));
   }
+  if (NULL != ch->dest)
+  {
+    LOG2 (level,
+          "CHN destination %s ready %s local-id: %u\n",
+          GSC_2s (ch->dest->c),
+          ch->dest->client_ready ? "YES" : "NO",
+          ntohl (ch->dest->ccn.channel_of_client));
+  }
+  LOG2 (level,
+        "CHN  Message IDs recv: %d (%LLX), send: %d\n",
+        ntohl (ch->mid_recv.mid),
+        (unsigned long long) ch->mid_futures,
+        ntohl (ch->mid_send.mid));
 }
 
 
-/**
- * Get the static string for identification of the channel.
- *
- * @param ch Channel.
- *
- * @return Static string with the channel IDs.
- */
-const char *
-GCCH_2s (const struct CadetChannel *ch)
-{
-  static char buf[64];
-
-  if (NULL == ch)
-    return "(NULL Channel)";
 
-  SPRINTF (buf,
-           "%s:%s gid:%X (%X / %X)",
-           GCT_2s (ch->t),
-           GNUNET_h2s (&ch->port),
-           ntohl (ch->gid.cn),
-           ntohl (ch->lid_root.channel_of_client),
-           ntohl (ch->lid_dest.channel_of_client));
-
-  return buf;
-}
+/* end of gnunet-service-cadet-new_channel.c */
index 9d4893269737b98cf3adbe9fa8aaaf27a4932545..a3ef9a06d7c85981b8e1986e4853c793f48aa51e 100644 (file)
@@ -1,6 +1,7 @@
+
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
+     Copyright (C) 2001-2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
 /**
  * @file cadet/gnunet-service-cadet_channel.h
- * @brief cadet service; dealing with end-to-end channels
+ * @brief GNUnet CADET service with encryption
  * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel)
+ * @author Christian Grothoff
  */
-
 #ifndef GNUNET_SERVICE_CADET_CHANNEL_H
 #define GNUNET_SERVICE_CADET_CHANNEL_H
 
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
+#include "gnunet-service-cadet.h"
+#include "gnunet-service-cadet_peer.h"
 #include "cadet_protocol.h"
-#include "cadet.h"
-
-/**
- * Struct containing all information regarding a channel to a remote client.
- */
-struct CadetChannel;
-
-
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_local.h"
-
-
-/**
- * Destroy a channel and free all resources.
- *
- * @param ch Channel to destroy.
- */
-void
-GCCH_destroy (struct CadetChannel *ch);
 
 
 /**
- * Get the channel's public ID.
- *
- * @param ch Channel.
- *
- * @return ID used to identify the channel with the remote peer.
+ * A channel is a bidirectional connection between two CADET
+ * clients.  Communiation can be reliable, unreliable, in-order
+ * or out-of-order.  One client is the "local" client, this
+ * one initiated the connection.   The other client is the
+ * "incoming" client, this one listened on a port to accept
+ * the connection from the "local" client.
  */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCCH_get_id (const struct CadetChannel *ch);
-
-
-/**
- * Get the channel tunnel.
- *
- * @param ch Channel to get the tunnel from.
- *
- * @return tunnel of the channel.
- */
-struct CadetTunnel *
-GCCH_get_tunnel (const struct CadetChannel *ch);
+struct CadetChannel;
 
 
 /**
- * Get free buffer space towards the client on a specific channel.
+ * Get the static string for identification of the channel.
  *
  * @param ch Channel.
- * @param fwd Is query about FWD traffic?
  *
- * @return Free buffer space [0 - 64]
+ * @return Static string with the channel IDs.
  */
-unsigned int
-GCCH_get_buffer (struct CadetChannel *ch, int fwd);
+const char *
+GCCH_2s (const struct CadetChannel *ch);
 
 
 /**
- * Get flow control status of end point: is client allow to send?
+ * Log channel info.
  *
  * @param ch Channel.
- * @param fwd Is query about FWD traffic? (Request root status).
- *
- * @return #GNUNET_YES if client is allowed to send us data.
+ * @param level Debug level to use.
  */
-int
-GCCH_get_allowed (struct CadetChannel *ch, int fwd);
+void
+GCCH_debug (struct CadetChannel *ch,
+            enum GNUNET_ErrorType level);
 
 
 /**
- * Is the root client for this channel on this peer?
+ * Get the channel's public ID.
  *
  * @param ch Channel.
- * @param fwd Is this for fwd traffic?
  *
- * @return #GNUNET_YES in case it is.
+ * @return ID used to identify the channel with the remote peer.
  */
-int
-GCCH_is_origin (struct CadetChannel *ch, int fwd);
+struct GNUNET_CADET_ChannelTunnelNumber
+GCCH_get_id (const struct CadetChannel *ch);
 
-/**
- * Is the destination client for this channel on this peer?
- *
- * @param ch Channel.
- * @param fwd Is this for fwd traffic?
- *
- * @return #GNUNET_YES in case it is.
- */
-int
-GCCH_is_terminal (struct CadetChannel *ch, int fwd);
 
 /**
- * Send an end-to-end ACK message for the most recent in-sequence payload.
- *
- * If channel is not reliable, do nothing.
- *
- * @param ch Channel this is about.
- * @param fwd Is for FWD traffic? (ACK dest->owner)
+ * Create a new channel.
+ *
+ * @param owner local client owning the channel
+ * @param owner_id local chid of this channel at the @a owner
+ * @param destination peer to which we should build the channel
+ * @param port desired port at @a destination
+ * @param options options for the channel
+ * @return handle to the new channel
  */
-void
-GCCH_send_data_ack (struct CadetChannel *ch, int fwd);
+struct CadetChannel *
+GCCH_channel_local_new (struct CadetClient *owner,
+                        struct GNUNET_CADET_ClientChannelNumber owner_id,
+                        struct CadetPeer *destination,
+                        const struct GNUNET_HashCode *port,
+                        uint32_t options);
 
-/**
- * Notify the destination client that a new incoming channel was created.
- *
- * @param ch Channel that was created.
- */
-void
-GCCH_send_create (struct CadetChannel *ch);
 
 /**
- * Allow a client to send us more data, in case it was choked.
+ * A client is bound to the port that we have a channel
+ * open to.  Send the acknowledgement for the connection
+ * request and establish the link with the client.
  *
- * @param ch Channel.
- * @param fwd Is this about FWD traffic? (Root client).
+ * @param ch open incoming channel
+ * @param c client listening on the respective port
  */
 void
-GCCH_allow_client (struct CadetChannel *ch, int fwd);
+GCCH_bind (struct CadetChannel *ch,
+           struct CadetClient *c);
 
-/**
- * Log channel info.
- *
- * @param ch Channel.
- * @param level Debug level to use.
- */
-void
-GCCH_debug (struct CadetChannel *ch, enum GNUNET_ErrorType level);
 
 /**
- * Handle an ACK given by a client.
+ * Destroy locally created channel.  Called by the
+ * local client, so no need to tell the client.
  *
- * Mark client as ready and send him any buffered data we could have for him.
- *
- * @param ch Channel.
- * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK)
+ * @param ch channel to destroy
+ * @param c client that caused the destruction
+ * @param ccn client number of the client @a c
  */
 void
-GCCH_handle_local_ack (struct CadetChannel *ch, int fwd);
+GCCH_channel_local_destroy (struct CadetChannel *ch,
+                            struct CadetClient *c,
+                            struct GNUNET_CADET_ClientChannelNumber ccn);
 
-/**
- * Handle data given by a client.
- *
- * Check whether the client is allowed to send in this tunnel, save if channel
- * is reliable and send an ACK to the client if there is still buffer space
- * in the tunnel.
- *
- * @param ch Channel.
- * @param c Client which sent the data.
- * @param fwd Is this a FWD data?
- * @param message Data message.
- * @param size Size of data.
- *
- * @return GNUNET_OK if everything goes well, GNUNET_SYSERR in case of en error.
- */
-int
-GCCH_handle_local_data (struct CadetChannel *ch,
-                        struct CadetClient *c, int fwd,
-                        const struct GNUNET_MessageHeader *message,
-                        size_t size);
 
 /**
- * Handle a channel destroy requested by a client.
- *
- * Destroy the channel and the tunnel in case this was the last channel.
- *
- * @param ch Channel.
- * @param c Client that requested the destruction (to avoid notifying him).
- * @param is_root Is the request coming from root?
+ * Function called once and only once after a channel was bound
+ * to its tunnel via #GCT_add_channel() is ready for transmission.
+ * Note that this is only the case for channels that this peer
+ * initiates, as for incoming channels we assume that they are
+ * ready for transmission immediately upon receiving the open
+ * message.  Used to bootstrap the #GCT_send() process.
+ *
+ * @param ch the channel for which the tunnel is now ready
  */
 void
-GCCH_handle_local_destroy (struct CadetChannel *ch,
-                           struct CadetClient *c,
-                           int is_root);
+GCCH_tunnel_up (struct CadetChannel *ch);
 
 
 /**
- * Handle a channel create requested by a client.
- *
- * Create the channel and the tunnel in case this was the first0 channel.
- *
- * @param c Client that requested the creation (will be the root).
- * @param msg Create Channel message.
- *
- * @return #GNUNET_OK if everything went fine, #GNUNET_SYSERR otherwise.
+ * Create a new channel based on a request coming in over the network.
+ *
+ * @param t tunnel to the remote peer
+ * @param chid identifier of this channel in the tunnel
+ * @param origin peer to who initiated the channel
+ * @param port desired local port
+ * @param options options for the channel
+ * @return handle to the new channel
  */
-int
-GCCH_handle_local_create (struct CadetClient *c,
-                          struct GNUNET_CADET_LocalChannelCreateMessage *msg);
-
-/**
- * Handler for cadet network payload traffic.
- *
- * @param ch Channel for the message.
- * @param msg Unencryted data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-void
-GCCH_handle_data (struct CadetChannel *ch,
-                  const struct GNUNET_CADET_ChannelAppDataMessage *msg,
-                  int fwd);
+struct CadetChannel *
+GCCH_channel_incoming_new (struct CadetTunnel *t,
+                           struct GNUNET_CADET_ChannelTunnelNumber chid,
+                           const struct GNUNET_HashCode *port,
+                           uint32_t options);
 
 
 /**
- * Handler for cadet network traffic end-to-end ACKs.
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN message again for
+ * this channel.  If the binding was successful, (re)transmit the
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK.
  *
- * @param ch Channel on which we got this message.
- * @param msg Data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
+ * @param ch channel that got the duplicate open
+ * @param cti identifier of the connection that delivered the message
  */
 void
-GCCH_handle_data_ack (struct CadetChannel *ch,
-                      const struct GNUNET_CADET_ChannelDataAckMessage *msg,
-                      int fwd);
+GCCH_handle_duplicate_open (struct CadetChannel *ch,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
 
 
-/**
- * Handler for channel create messages.
- *
- * Does not have fwd parameter because it's always 'FWD': channel is incoming.
- *
- * @param t Tunnel this channel will be in.
- * @param msg Channel crate message.
- */
-struct CadetChannel *
-GCCH_handle_create (struct CadetTunnel *t,
-                    const struct GNUNET_CADET_ChannelOpenMessage *msg);
-
 
 /**
- * Handler for channel NACK messages.
+ * We got payload data for a channel.  Pass it on to the client.
  *
- * NACK messages always go dest -> root, no need for 'fwd' or 'msg' parameter.
- *
- * @param ch Channel.
+ * @param ch channel that got data
+ * @param cti identifier of the connection that delivered the message
+ * @param msg message that was received
  */
 void
-GCCH_handle_nack (struct CadetChannel *ch);
+GCCH_handle_channel_plaintext_data (struct CadetChannel *ch,
+                                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                                    const struct GNUNET_CADET_ChannelAppDataMessage *msg);
 
 
 /**
- * Handler for channel ack messages.
+ * We got an acknowledgement for payload data for a channel.
+ * Possibly resume transmissions.
  *
- * @param ch Channel this channel is to be created in.
- * @param msg Message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
+ * @param ch channel that got the ack
+ * @param cti identifier of the connection that delivered the message
+ * @param ack details about what was received
  */
 void
-GCCH_handle_ack (struct CadetChannel *ch,
-                 const struct GNUNET_CADET_ChannelManageMessage *msg,
-                 int fwd);
+GCCH_handle_channel_plaintext_data_ack (struct CadetChannel *ch,
+                                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                                        const struct GNUNET_CADET_ChannelDataAckMessage *ack);
 
 
 /**
- * Handler for channel destroy messages.
+ * We got an acknowledgement for the creation of the channel
+ * (the port is open on the other side). Begin transmissions.
  *
- * @param ch Channel this channel is to be destroyed of.
- * @param msg Message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message,
+ *        NULL if the ACK was inferred because we got payload or are on loopback
  */
 void
-GCCH_handle_destroy (struct CadetChannel *ch,
-                     const struct GNUNET_CADET_ChannelManageMessage *msg,
-                     int fwd);
+GCCH_handle_channel_open_ack (struct CadetChannel *ch,
+                              const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
 
 
 /**
- * Sends an already built message on a channel.
+ * Destroy channel, based on the other peer closing the
+ * connection.  Also needs to remove this channel from
+ * the tunnel.
  *
- * If the channel is on a loopback tunnel, notifies the appropriate destination
- * client locally.
+ * FIXME: need to make it possible to defer destruction until we have
+ * received all messages up to the destroy, and right now the destroy
+ * message (and this API) fails to give is the information we need!
  *
- * On a normal channel passes the message to the tunnel for encryption and
- * sending on a connection.
+ * FIXME: also need to know if the other peer got a destroy from
+ * us before!
  *
- * This function DOES NOT save the message for retransmission.
- *
- * @param message Message to send. Function makes a copy of it.
- * @param ch Channel on which this message is transmitted.
- * @param fwd Is this a fwd message?
- * @param existing_copy This is a retransmission, don't save a copy.
+ * @param ch channel to destroy
+ * @param cti identifier of the connection that delivered the message,
+ *            NULL during shutdown
  */
 void
-GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
-                            struct CadetChannel *ch, int fwd,
-                            void *existing_copy);
+GCCH_handle_remote_destroy (struct CadetChannel *ch,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti);
 
 
 /**
- * Get the static string for identification of the channel.
+ * Handle data given by a client.
  *
- * @param ch Channel.i
+ * Check whether the client is allowed to send in this tunnel, save if
+ * channel is reliable and send an ACK to the client if there is still
+ * buffer space in the tunnel.
  *
- * @return Static string with the channel IDs.
+ * @param ch Channel.
+ * @param sender_ccn ccn of the sender
+ * @param buf payload to transmit.
+ * @param buf_len number of bytes in @a buf
+ * @return #GNUNET_OK if everything goes well,
+ *         #GNUNET_SYSERR in case of an error.
  */
-const char *
-GCCH_2s (const struct CadetChannel *ch);
-
-
+int
+GCCH_handle_local_data (struct CadetChannel *ch,
+                        struct GNUNET_CADET_ClientChannelNumber sender_ccn,
+                        const char *buf,
+                        size_t buf_len);
 
 
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
+/**
+ * Handle ACK from client on local channel.
+ *
+ * @param ch channel to destroy
+ * @param client_ccn ccn of the client sending the ack
+ */
+void
+GCCH_handle_local_ack (struct CadetChannel *ch,
+                       struct GNUNET_CADET_ClientChannelNumber client_ccn);
 
-/* ifndef GNUNET_SERVICE_CADET_CHANNEL_H */
 #endif
-/* end of gnunet-service-cadet_channel.h */
index 2d5087f817a4eba5fb137f619fce9ebc7e83d727..7b66f61a26dd6daf2598f61bbdee7655d93fd242 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2001-2015 GNUnet e.V.
+     Copyright (C) 2001-2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      Boston, MA 02110-1301, USA.
 */
+
 /**
  * @file cadet/gnunet-service-cadet_connection.c
- * @brief GNUnet CADET service connection handling
+ * @brief management of CORE-level end-to-end connections; establishes
+ *        end-to-end routes and transmits messages along the route
  * @author Bartlomiej Polot
+ * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_util_lib.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_paths.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet_cadet_service.h"
 #include "gnunet_statistics_service.h"
-#include "cadet_path.h"
 #include "cadet_protocol.h"
-#include "cadet.h"
-#include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_peer.h"
-#include "gnunet-service-cadet_tunnel.h"
-
-
-/**
- * Should we run somewhat expensive checks on our invariants?
- */
-#define CHECK_INVARIANTS 0
-
-
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-con",__VA_ARGS__)
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
-
-
-#define CADET_MAX_POLL_TIME      GNUNET_TIME_relative_multiply (\
-                                  GNUNET_TIME_UNIT_MINUTES,\
-                                  10)
-#define AVG_MSGS                32
-
-
-/******************************************************************************/
-/********************************   STRUCTS  **********************************/
-/******************************************************************************/
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetConnectionQueue
-{
-
-  struct CadetConnectionQueue *next;
-  struct CadetConnectionQueue *prev;
-
-  /**
-   * Peer queue handle, to cancel if necessary.
-   */
-  struct CadetPeerQueue *peer_q;
-
-  /**
-   * Continuation to call once sent.
-   */
-  GCC_sent cont;
 
-  /**
-   * Closure for @e cont.
-   */
-  void *cont_cls;
 
-  /**
-   * Was this a forced message? (Do not account for it)
-   */
-  int forced;
-};
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-con",__VA_ARGS__)
 
 
 /**
- * Struct to encapsulate all the Flow Control information to a peer to which
- * we are directly connected (on a core level).
+ * All the states a connection can be in.
  */
-struct CadetFlowControl
+enum CadetConnectionState
 {
   /**
-   * Connection this controls.
-   */
-  struct CadetConnection *c;
-
-  struct CadetConnectionQueue *q_head;
-  struct CadetConnectionQueue *q_tail;
-
-  /**
-   * How many messages are in the queue on this connection.
-   */
-  unsigned int queue_n;
-
-  /**
-   * How many messages do we accept in the queue.
-   * If 0, the connection is broken in this direction (next hop disconnected).
-   */
-  unsigned int queue_max;
-
-  /**
-   * ID of the next packet to send.
-   */
-  struct CadetEncryptedMessageIdentifier next_pid;
-
-  /**
-   * ID of the last packet sent towards the peer.
-   */
-  struct CadetEncryptedMessageIdentifier last_pid_sent;
-
-  /**
-   * ID of the last packet received from the peer.
-   */
-  struct CadetEncryptedMessageIdentifier last_pid_recv;
-
-  /**
-   * Bitmap of past 32 messages received:
-   * - LSB being @c last_pid_recv.
-   * - MSB being @c last_pid_recv - 31 (mod UINTMAX).
-   */
-  uint32_t recv_bitmap;
-
-  /**
-   * Last ACK sent to the peer (peer is not allowed to send
-   * messages with PIDs higher than this value).
-   */
-  struct CadetEncryptedMessageIdentifier last_ack_sent;
-
-  /**
-   * Last ACK sent towards the origin (for traffic towards leaf node).
-   */
-  struct CadetEncryptedMessageIdentifier last_ack_recv;
-
-  /**
-   * Task to poll the peer in case of a lost ACK causes stall.
-   */
-  struct GNUNET_SCHEDULER_Task *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).
+   * Uninitialized status, we have not yet even gotten the message queue.
    */
-  struct CadetConnectionQueue *poll_msg;
+  CADET_CONNECTION_NEW,
 
   /**
-   * Queued poll message, to cancel if not necessary anymore (got ACK).
+   * Connection create message in queue, awaiting transmission by CORE.
    */
-  struct CadetConnectionQueue *ack_msg;
-};
+  CADET_CONNECTION_SENDING_CREATE,
 
-/**
- * Keep a record of the last messages sent on this connection.
- */
-struct CadetConnectionPerformance
-{
   /**
-   * Circular buffer for storing measurements.
+   * Connection create message sent, waiting for ACK.
    */
-  double usecsperbyte[AVG_MSGS];
+  CADET_CONNECTION_SENT,
 
   /**
-   * Running average of @c usecsperbyte.
+   * We are an inbound connection, and received a CREATE. Need to
+   * send an CREATE_ACK back.
    */
-  double avg;
+  CADET_CONNECTION_CREATE_RECEIVED,
 
   /**
-   * How many values of @c usecsperbyte are valid.
+   * Connection confirmed, ready to carry traffic.
    */
-  uint16_t size;
+  CADET_CONNECTION_READY
 
-  /**
-   * Index of the next "free" position in @c usecsperbyte.
-   */
-  uint16_t idx;
 };
 
 
 /**
- * Struct containing all information regarding a connection to a peer.
+ * Low-level connection to a destination.
  */
 struct CadetConnection
 {
-  /**
-   * Tunnel this connection is part of.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Flow control information for traffic fwd.
-   */
-  struct CadetFlowControl fwd_fc;
 
   /**
-   * Flow control information for traffic bck.
+   * ID of the connection.
    */
-  struct CadetFlowControl bck_fc;
+  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
 
   /**
-   * Measure connection performance on the endpoint.
+   * To which peer does this connection go?
    */
-  struct CadetConnectionPerformance *perf;
+  struct CadetPeer *destination;
 
   /**
-   * ID of the connection.
+   * Which tunnel is using this connection?
    */
-  struct GNUNET_CADET_ConnectionTunnelIdentifier id;
+  struct CadetTConnection *ct;
 
   /**
-   * 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.
+   * Path we are using to our destination.
    */
   struct CadetPeerPath *path;
 
   /**
-   * Task to keep the used paths alive at the owner,
-   * time tunnel out on all the other peers.
+   * Pending message, NULL if we are ready to transmit.
    */
-  struct GNUNET_SCHEDULER_Task *fwd_maintenance_task;
+  struct GNUNET_MQ_Envelope *env;
 
   /**
-   * Task to keep the used paths alive at the destination,
-   * time tunnel out on all the other peers.
+   * Handle for calling #GCP_request_mq_cancel() once we are finished.
    */
-  struct GNUNET_SCHEDULER_Task *bck_maintenance_task;
+  struct GCP_MessageQueueManager *mq_man;
 
   /**
-   * Queue handle for maintainance traffic. One handle for FWD and BCK since
-   * one peer never needs to maintain both directions (no loopback connections).
+   * Task for connection maintenance.
    */
-  struct CadetPeerQueue *maintenance_q;
+  struct GNUNET_SCHEDULER_Task *task;
 
   /**
-   * Should equal #get_next_hop(), or NULL if that peer disconnected.
+   * Queue entry for keepalive messages.
    */
-  struct CadetPeer *next_peer;
+  struct CadetTunnelQueueEntry *keepalive_qe;
 
   /**
-   * Should equal #get_prev_hop(), or NULL if that peer disconnected.
+   * Function to call once we are ready to transmit.
    */
-  struct CadetPeer *prev_peer;
+  GCC_ReadyCallback ready_cb;
 
   /**
-   * State of the connection.
+   * Closure for @e ready_cb.
    */
-  enum CadetConnectionState state;
+  void *ready_cb_cls;
 
   /**
-   * Position of the local peer in the path.
+   * How long do we wait before we try again with a CREATE message?
    */
-  unsigned int own_pos;
+  struct GNUNET_TIME_Relative retry_delay;
 
   /**
-   * Pending message count.
+   * Performance metrics for this connection.
    */
-  unsigned int pending_messages;
+  struct CadetConnectionMetrics metrics;
 
   /**
-   * Destroy flag:
-   * - if 0, connection in use.
-   * - if 1, destroy on last message.
-   * - if 2, connection is being destroyed don't re-enter.
+   * State of the connection.
    */
-  int destroy;
+  enum CadetConnectionState state;
 
   /**
-   * In-connection-map flag. Sometimes, when @e destroy is set but
-   * actual destruction is delayed to enable us to finish processing
-   * queues (i.e. in the direction that is still working), we remove
-   * the connection from the map to prevent it from still being
-   * found (and used) by accident. This flag is set to #GNUNET_YES
-   * for a connection that is not in the #connections map.  Should
-   * only be #GNUNET_YES if #destroy is also non-zero.
+   * Options for the route, control buffering.
    */
-  int was_removed;
+  enum GNUNET_CADET_ChannelOption options;
 
   /**
-   * Counter to do exponential backoff when creating a connection (max 64).
+   * How many latency observations did we make for this connection?
    */
-  unsigned short create_retry;
+  unsigned int latency_datapoints;
 
   /**
-   * Task to check if connection has duplicates.
+   * Offset of our @e destination in @e path.
    */
-  struct GNUNET_SCHEDULER_Task *check_duplicates_task;
-};
-
-
-/******************************************************************************/
-/*******************************   GLOBALS  ***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Local peer own ID (memory efficient handle).
- */
-extern GNUNET_PEER_Id myid;
-
-/**
- * Local peer own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-/**
- * Connections known, indexed by cid (CadetConnection).
- */
-static struct GNUNET_CONTAINER_MultiShortmap *connections;
-
-/**
- * How many connections are we willing to maintain.
- *  Local connections are always allowed,
- * even if there are more connections than max.
- */
-static unsigned long long max_connections;
-
-/**
- * How many messages *in total* are we willing to queue, divide by number of
- * connections to get connection queue size.
- */
-static unsigned long long max_msgs_queue;
-
-/**
- * How often to send path keepalives. Paths timeout after 4 missed.
- */
-static struct GNUNET_TIME_Relative refresh_connection_time;
-
-/**
- * How often to send path create / ACKs.
- */
-static struct GNUNET_TIME_Relative create_connection_time;
-
-
-/******************************************************************************/
-/********************************   STATIC  ***********************************/
-/******************************************************************************/
-
-
-
-#if 0 // avoid compiler warning for unused static function
-static void
-fc_debug (struct CadetFlowControl *fc)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "    IN: %u/%u\n",
-       ntohl (fc->last_pid_recv.pid),
-       ntohl (fc->last_ack_sent.pid));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "    OUT: %u/%u\n",
-              fc->last_pid_sent, fc->last_ack_recv);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "    QUEUE: %u/%u\n",
-              fc->queue_n, fc->queue_max);
-}
-
-static void
-connection_debug (struct CadetConnection *c)
-{
-  if (NULL == c)
-  {
-    LOG (GNUNET_ERROR_TYPE_INFO, "DEBUG NULL CONNECTION\n");
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n",
-              peer2s (c->t->peer), GCC_2s (c));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  state: %u, pending msgs: %u\n",
-              c->state, c->pending_messages);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  FWD FC\n");
-  fc_debug (&c->fwd_fc);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  BCK FC\n");
-  fc_debug (&c->bck_fc);
-}
-#endif
-
-
-/**
- * Schedule next keepalive task, taking in consideration
- * the connection state and number of retries.
- *
- * @param c Connection for which to schedule the next keepalive.
- * @param fwd Direction for the next keepalive.
- */
-static void
-schedule_next_keepalive (struct CadetConnection *c, int fwd);
-
-
-/**
- * Resets the connection timeout task, some other message has done the
- * task's job.
- * - For the first peer on the direction this means to send
- *   a keepalive or a path confirmation message (either create or ACK).
- * - For all other peers, this means to destroy the connection,
- *   due to lack of activity.
- * Starts the timeout if no timeout was running (connection just created).
- *
- * @param c Connection whose timeout to reset.
- * @param fwd Is this forward?
- */
-static void
-connection_reset_timeout (struct CadetConnection *c, int fwd);
-
-
-/**
- * Get string description for tunnel state. Reentrant.
- *
- * @param s Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-GCC_state2s (enum CadetConnectionState s)
-{
-  switch (s)
-  {
-    case CADET_CONNECTION_NEW:
-      return "CADET_CONNECTION_NEW";
-    case CADET_CONNECTION_SENT:
-      return "CADET_CONNECTION_SENT";
-    case CADET_CONNECTION_ACK:
-      return "CADET_CONNECTION_ACK";
-    case CADET_CONNECTION_READY:
-      return "CADET_CONNECTION_READY";
-    case CADET_CONNECTION_DESTROYED:
-      return "CADET_CONNECTION_DESTROYED";
-    case CADET_CONNECTION_BROKEN:
-      return "CADET_CONNECTION_BROKEN";
-    default:
-      GNUNET_break (0);
-      LOG (GNUNET_ERROR_TYPE_ERROR, " conn state %u unknown!\n", s);
-      return "CADET_CONNECTION_STATE_ERROR";
-  }
-}
-
-
-/**
- * Initialize a Flow Control structure to the initial state.
- *
- * @param fc Flow Control structure to initialize.
- */
-static void
-fc_init (struct CadetFlowControl *fc)
-{
-  fc->next_pid.pid = 0;
-  fc->last_pid_sent.pid = htonl (UINT32_MAX);
-  fc->last_pid_recv.pid = htonl (UINT32_MAX);
-  fc->last_ack_sent.pid = (uint32_t) 0;
-  fc->last_ack_recv.pid = (uint32_t) 0;
-  fc->poll_task = NULL;
-  fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
-  fc->queue_n = 0;
-  fc->queue_max = (max_msgs_queue / max_connections) + 1;
-}
-
-
-/**
- * Find a connection.
- *
- * @param cid Connection ID.
- *
- * @return conntection with the given ID @cid or NULL if not found.
- */
-static struct CadetConnection *
-connection_get (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
-{
-  return GNUNET_CONTAINER_multishortmap_get (connections,
-                                             &cid->connection_of_tunnel);
-}
-
-
-/**
- * Change the connection state. Cannot change a connection marked as destroyed.
- *
- * @param c Connection to change.
- * @param state New state to set.
- */
-static void
-connection_change_state (struct CadetConnection* c,
-                         enum CadetConnectionState state)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Connection %s state %s -> %s\n",
-       GCC_2s (c), GCC_state2s (c->state), GCC_state2s (state));
-  if (CADET_CONNECTION_DESTROYED <= c->state) /* Destroyed or broken. */
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "state not changing anymore\n");
-    return;
-  }
-  c->state = state;
-  if (CADET_CONNECTION_READY == state)
-    c->create_retry = 1;
-}
-
-
-/**
- * Mark a connection as "destroyed", to send all pending traffic and freeing
- * all associated resources, without accepting new status changes on it.
- *
- * @param c Connection to mark as destroyed.
- */
-static void
-mark_destroyed (struct CadetConnection *c)
-{
-  c->destroy = GNUNET_YES;
-  connection_change_state (c, CADET_CONNECTION_DESTROYED);
-}
-
-
-/**
- * Function called if a connection has been stalled for a while,
- * possibly due to a missed ACK. Poll the neighbor about its ACK status.
- *
- * @param cls Closure (poll ctx).
- */
-static void
-send_poll (void *cls);
-
+  unsigned int off;
 
-/**
- * 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)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct CadetFlowControl *next_fc;
-  struct CadetFlowControl *prev_fc;
-  struct GNUNET_CADET_ConnectionEncryptedAckMessage msg;
-  struct CadetEncryptedMessageIdentifier ack_cemi;
-  int delta;
-
-  GCC_check_connections ();
-  GNUNET_assert (GNUNET_NO == GCC_is_origin (c, fwd));
-
-  next_fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  prev_fc = fwd ? &c->bck_fc : &c->fwd_fc;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "send %s ack on %s\n",
-       GC_f2s (fwd), GCC_2s (c));
-
-  /* Check if we need to transmit the ACK. */
-  delta = ntohl (prev_fc->last_ack_sent.pid) - ntohl (prev_fc->last_pid_recv.pid);
-  if (3 < delta && buffer < delta && GNUNET_NO == force)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending ACK, delta > 3\n");
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "  last pid recv: %u, last ack sent: %u\n",
-         ntohl (prev_fc->last_pid_recv.pid),
-         ntohl (prev_fc->last_ack_sent.pid));
-    GCC_check_connections ();
-    return;
-  }
-
-  /* Ok, ACK might be necessary, what PID to ACK? */
-  ack_cemi.pid = htonl (ntohl (prev_fc->last_pid_recv.pid) + buffer);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " ACK %u, last PID %u, last ACK %u, qmax %u, q %u\n",
-       ntohl (ack_cemi.pid),
-       ntohl (prev_fc->last_pid_recv.pid),
-       ntohl (prev_fc->last_ack_sent.pid),
-       next_fc->queue_max, next_fc->queue_n);
-  if ( (ack_cemi.pid == prev_fc->last_ack_sent.pid) &&
-       (GNUNET_NO == force) )
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Not sending FWD ACK, not needed\n");
-    GCC_check_connections ();
-    return;
-  }
-
-  /* Check if message is already in queue */
-  if (NULL != prev_fc->ack_msg)
-  {
-    if (GC_is_pid_bigger (ntohl (ack_cemi.pid),
-                          ntohl (prev_fc->last_ack_sent.pid)))
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " canceling old ACK\n");
-      GCC_cancel (prev_fc->ack_msg);
-      /* GCC_cancel triggers ack_sent(), which clears fc->ack_msg */
-    }
-    else
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " same ACK already in queue\n");
-      GCC_check_connections ();
-      return;
-    }
-  }
-  GNUNET_break (GC_is_pid_bigger (ntohl (ack_cemi.pid),
-                                 ntohl (prev_fc->last_ack_sent.pid)));
-  prev_fc->last_ack_sent = ack_cemi;
-
-  /* Build ACK message and send on conn */
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK);
-  msg.cemi_max = ack_cemi;
-  msg.cid = c->id;
-
-  prev_fc->ack_msg = GCC_send_prebuilt_message (&msg.header,
-                                               UINT16_MAX,
-                                               zero,
-                                                c,
-                                                !fwd,
-                                                GNUNET_YES,
-                                                NULL, NULL);
-  GNUNET_assert (NULL != prev_fc->ack_msg);
-  GCC_check_connections ();
-}
-
-
-/**
- * Update performance information if we are a connection's endpoint.
- *
- * @param c Connection to update.
- * @param wait How much time did we wait to send the last message.
- * @param size Size of the last message.
- */
-static void
-update_perf (struct CadetConnection *c,
-             struct GNUNET_TIME_Relative wait,
-             uint16_t size)
-{
-  struct CadetConnectionPerformance *p;
-  double usecsperbyte;
-
-  if (NULL == c->perf)
-    return; /* Only endpoints are interested in timing. */
-
-  p = c->perf;
-  usecsperbyte = ((double) wait.rel_value_us) / size;
-  if (p->size == AVG_MSGS)
-  {
-    /* Array is full. Substract oldest value, add new one and store. */
-    p->avg -= (p->usecsperbyte[p->idx] / AVG_MSGS);
-    p->usecsperbyte[p->idx] = usecsperbyte;
-    p->avg += (p->usecsperbyte[p->idx] / AVG_MSGS);
-  }
-  else
-  {
-    /* Array not yet full. Add current value to avg and store. */
-    p->usecsperbyte[p->idx] = usecsperbyte;
-    p->avg *= p->size;
-    p->avg += p->usecsperbyte[p->idx];
-    p->size++;
-    p->avg /= p->size;
-  }
-  p->idx = (p->idx + 1) % AVG_MSGS;
-}
-
-
-/**
- * Callback called when a connection queued message is sent.
- *
- * Calculates the average time and connection packet tracking.
- *
- * @param cls Closure (ConnectionQueue Handle), can be NULL.
- * @param c Connection this message was on.
- * @param fwd Was this a FWD going message?
- * @param sent Was it really sent? (Could have been canceled)
- * @param type Type of message sent.
- * @param payload_type Type of payload, if applicable.
- * @param pid Message ID, or 0 if not applicable (create, destroy, etc).
- * @param size Size of the message.
- * @param wait Time spent waiting for core (only the time for THIS message)
- */
-static void
-conn_message_sent (void *cls,
-                   struct CadetConnection *c,
-                   int fwd,
-                   int sent,
-                   uint16_t type,
-                   uint16_t payload_type,
-                   struct CadetEncryptedMessageIdentifier pid,
-                   size_t size,
-                   struct GNUNET_TIME_Relative wait)
-{
-  struct CadetConnectionQueue *q = cls;
-  struct CadetFlowControl *fc;
-  int forced;
-
-  GCC_check_connections ();
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         ">>> %s (%s %4u) on conn %s (%p) %s [%5u] in queue %s\n",
-         GC_m2s (type), GC_m2s (payload_type),
-         ntohl (pid.pid),
-         GCC_2s (c),
-         c,
-         GC_f2s (fwd), size,
-         GNUNET_STRINGS_relative_time_to_string (wait, GNUNET_YES));
-
-  /* If c is NULL, nothing to update. */
-  if (NULL == c)
-  {
-    if (type != GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
-        && type != GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY)
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR, "Message %s sent on NULL connection!\n",
-           GC_m2s (type));
-    }
-    GCC_check_connections ();
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " %ssent %s %s pid %u\n",
-       sent ? "" : "not ", GC_f2s (fwd),
-       GC_m2s (type), GC_m2s (payload_type),
-       ntohl (pid.pid));
-  GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
-
-  /* Update flow control info. */
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-
-  if (NULL != q)
-  {
-    GNUNET_CONTAINER_DLL_remove (fc->q_head, fc->q_tail, q);
-    forced = q->forced;
-    if (NULL != q->cont)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " calling cont\n");
-      q->cont (q->cont_cls, c, q, type, fwd, size);
-    }
-    GNUNET_free (q);
-  }
-  else /* CONN_CREATE or CONN_ACK */
-  {
-    GNUNET_assert (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED != type);
-    forced = GNUNET_YES;
-  }
-
-  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");
-    GCC_destroy (c);
-    GCC_check_connections ();
-    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_CREATE_ACK:
-      c->maintenance_q = NULL;
-      /* Don't trigger a keepalive for sent ACKs, only SYN and SYNACKs */
-      if (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE == type || !fwd)
-        schedule_next_keepalive (c, fwd);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED:
-      if (GNUNET_YES == sent)
-      {
-        fc->last_pid_sent = pid;
-        if (GC_is_pid_bigger (ntohl (fc->last_pid_sent.pid) + 1,
-                              ntohl (fc->last_ack_recv.pid)) )
-          GCC_start_poll (c, fwd);
-        GCC_send_ack (c, fwd, GNUNET_NO);
-        connection_reset_timeout (c, fwd);
-      }
-
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "!  Q_N- %p %u\n", fc, fc->queue_n);
-      if (GNUNET_NO == forced)
-      {
-        fc->queue_n--;
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "!   accounting pid %u\n",
-             ntohl (fc->last_pid_sent.pid));
-      }
-      else
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "!   forced, Q_N not accounting pid %u\n",
-             ntohl (fc->last_pid_sent.pid));
-      }
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
-      if (GNUNET_YES == sent)
-        connection_reset_timeout (c, fwd);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL:
-      fc->poll_msg = NULL;
-      if (2 == c->destroy)
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL canceled on shutdown\n");
-        return;
-      }
-      if (0 == fc->queue_max)
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL cancelled: neighbor disconnected\n");
-        return;
-      }
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL sent for %s, scheduling new one!\n",
-          GCC_2s (c));
-      GNUNET_assert (NULL == fc->poll_task);
-      fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
-      fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
-                                                    &send_poll, fc);
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK:
-      fc->ack_msg = NULL;
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
-      break;
-
-    default:
-      LOG (GNUNET_ERROR_TYPE_ERROR, "%s unknown\n", GC_m2s (type));
-      GNUNET_break (0);
-      break;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "!  message sent!\n");
-
-  update_perf (c, wait, size);
-  GCC_check_connections ();
-}
-
-
-/**
- * Get the previous hop in a connection
- *
- * @param c Connection.
- *
- * @return Previous peer in the connection.
- */
-static struct CadetPeer *
-get_prev_hop (const struct CadetConnection *c)
-{
-  GNUNET_PEER_Id id;
-
-  if (NULL == c->path)
-    return NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " get prev hop %s [%u/%u]\n",
-       GCC_2s (c), c->own_pos, c->path->length);
-  if (0 == c->own_pos || c->path->length < 2)
-    id = c->path->peers[0];
-  else
-    id = c->path->peers[c->own_pos - 1];
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  ID: %s (%u)\n",
-       GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
-
-  return GCP_get_short (id, GNUNET_YES);
-}
-
-
-/**
- * Get the next hop in a connection
- *
- * @param c Connection.
- *
- * @return Next peer in the connection.
- */
-static struct CadetPeer *
-get_next_hop (const struct CadetConnection *c)
-{
-  GNUNET_PEER_Id id;
-
-  if (NULL == c->path)
-    return NULL;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " get next hop %s [%u/%u]\n",
-       GCC_2s (c), c->own_pos, c->path->length);
-  if ((c->path->length - 1) == c->own_pos || c->path->length < 2)
-    id = c->path->peers[c->path->length - 1];
-  else
-    id = c->path->peers[c->own_pos + 1];
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  ID: %s (%u)\n",
-       GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
-
-  return GCP_get_short (id, GNUNET_YES);
-}
-
-
-/**
- * Check that the direct neighbours (previous and next hop)
- * are properly associated with this connection.
- *
- * @param c connection to check
- */
-static void
-check_neighbours (const struct CadetConnection *c)
-{
-  if (NULL == c->path)
-    return; /* nothing to check */
-  GCP_check_connection (get_next_hop (c), c);
-  GCP_check_connection (get_prev_hop (c), c);
-}
-
-
-/**
- * Helper for #GCC_check_connections().  Calls #check_neighbours().
- *
- * @param cls NULL
- * @param key ignored
- * @param value the `struct CadetConnection` to check
- * @return #GNUNET_OK (continue to iterate)
- */
-static int
-check_connection (void *cls,
-                  const struct GNUNET_ShortHashCode *key,
-                  void *value)
-{
-  struct CadetConnection *c = value;
-
-  check_neighbours (c);
-  return GNUNET_OK;
-}
-
-
-/**
- * Check invariants for all connections using #check_neighbours().
- */
-void
-GCC_check_connections ()
-{
-  if (0 == CHECK_INVARIANTS)
-    return;
-  if (NULL == connections)
-    return;
-  GNUNET_CONTAINER_multishortmap_iterate (connections,
-                                          &check_connection,
-                                          NULL);
-}
-
-
-/**
- * Get the hop in a connection.
- *
- * @param c Connection.
- * @param fwd Next in the FWD direction?
- *
- * @return Next peer in the connection.
- */
-static struct CadetPeer *
-get_hop (struct CadetConnection *c, int fwd)
-{
-  return (fwd) ? get_next_hop (c) : get_prev_hop (c);
-}
-
-
-/**
- * Get a bit mask for a message received out-of-order.
- *
- * @param last_pid_recv Last PID we received prior to the out-of-order.
- * @param ooo_pid PID of the out-of-order message.
- */
-static uint32_t
-get_recv_bitmask (struct CadetEncryptedMessageIdentifier last_pid_recv,
-                  struct CadetEncryptedMessageIdentifier ooo_pid)
-{
-  // FIXME: should assert that the delta is in range...
-  return 1 << (ntohl (last_pid_recv.pid) - ntohl (ooo_pid.pid));
-}
-
-
-/**
- * Check is an out-of-order message is ok:
- * - at most 31 messages behind.
- * - not duplicate.
- *
- * @param last_pid_recv Last in-order PID received.
- */
-static int
-is_ooo_ok (struct CadetEncryptedMessageIdentifier last_pid_recv,
-           struct CadetEncryptedMessageIdentifier ooo_pid,
-           uint32_t ooo_bitmap)
-{
-  uint32_t mask;
-
-  if (GC_is_pid_bigger (ntohl (last_pid_recv.pid) - 31,
-                        ntohl (ooo_pid.pid)))
-    return GNUNET_NO;
-
-  mask = get_recv_bitmask (last_pid_recv,
-                           ooo_pid);
-  if (0 != (ooo_bitmap & mask))
-    return GNUNET_NO;
-
-  return GNUNET_YES;
-}
-
-
-/**
- * Is traffic coming from this sender 'FWD' traffic?
- *
- * @param c Connection to check.
- * @param sender Short peer identity of neighbor.
- *
- * @return #GNUNET_YES in case the sender is the 'prev' hop and therefore
- *         the traffic is 'FWD'.
- *         #GNUNET_NO for BCK.
- *         #GNUNET_SYSERR for errors (sender isn't a hop in the connection).
- */
-static int
-is_fwd (const struct CadetConnection *c,
-        const struct CadetPeer *sender)
-{
-  GNUNET_PEER_Id id;
-
-  id = GCP_get_short_id (sender);
-  if (GCP_get_short_id (get_prev_hop (c)) == id)
-    return GNUNET_YES;
-
-  if (GCP_get_short_id (get_next_hop (c)) == id)
-    return GNUNET_NO;
-
-  return GNUNET_SYSERR;
-}
-
-
-/**
- * Sends a CONNECTION ACK message in reponse to a received CONNECTION_CREATE
- * or a first CONNECTION_ACK directed to us.
- *
- * @param c Connection to confirm.
- * @param fwd Should we send it FWD? (root->dest)
- *            (First (~SYNACK) goes BCK, second (~ACK) goes FWD)
- */
-static void
-send_connection_ack (struct CadetConnection *c, int fwd)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct GNUNET_CADET_ConnectionCreateAckMessage msg;
-  struct CadetTunnel *t;
-  const uint16_t size = sizeof (struct GNUNET_CADET_ConnectionCreateAckMessage);
-  const uint16_t type = GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK;
-
-  GCC_check_connections ();
-  t = c->t;
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "==> %s ({ C %s ACK}    0) on conn %s (%p) %s [%5u]\n",
-       GC_m2s (type), GC_f2s (!fwd), GCC_2s (c), c, GC_f2s (fwd), size);
-
-  msg.header.size = htons (size);
-  msg.header.type = htons (type);
-  msg.reserved = htonl (0);
-  msg.cid = c->id;
-
-  GNUNET_assert (NULL == c->maintenance_q);
-  c->maintenance_q = GCP_send (get_hop (c, fwd),
-                               &msg.header,
-                               GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
-                               zero,
-                               c,
-                               fwd,
-                               &conn_message_sent, NULL);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  C_P+ %p %u (conn`ACK)\n",
-       c, c->pending_messages);
-  c->pending_messages++;
-
-  if (CADET_TUNNEL_NEW == GCT_get_cstate (t))
-    GCT_change_cstate (t, CADET_TUNNEL_WAITING);
-  if (CADET_CONNECTION_READY != c->state)
-    connection_change_state (c, CADET_CONNECTION_SENT);
-  GCC_check_connections ();
-}
-
-
-/**
- * Send a notification that a connection is broken.
- *
- * @param c Connection that is broken.
- * @param id1 Peer that has disconnected.
- * @param id2 Peer that has disconnected.
- * @param fwd Direction towards which to send it.
- */
-static void
-send_broken (struct CadetConnection *c,
-             const struct GNUNET_PeerIdentity *id1,
-             const struct GNUNET_PeerIdentity *id2,
-             int fwd)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct GNUNET_CADET_ConnectionBrokenMessage msg;
-
-  GCC_check_connections ();
-  msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBrokenMessage));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
-  msg.cid = c->id;
-  msg.reserved = htonl (0);
-  msg.peer1 = *id1;
-  msg.peer2 = *id2;
-  (void) GCC_send_prebuilt_message (&msg.header,
-                                    UINT16_MAX,
-                                    zero,
-                                    c,
-                                    fwd,
-                                    GNUNET_YES,
-                                    NULL, NULL);
-  GCC_check_connections ();
-}
-
-
-/**
- * Send a notification that a connection is broken, when a connection
- * isn't even known to the local peer or soon to be destroyed.
- *
- * @param connection_id Connection ID.
- * @param id1 Peer that has disconnected, probably local peer.
- * @param id2 Peer that has disconnected can be NULL if unknown.
- * @param neighbor Peer to notify (neighbor who sent the connection).
- */
-static void
-send_broken_unknown (const struct GNUNET_CADET_ConnectionTunnelIdentifier *connection_id,
-                     const struct GNUNET_PeerIdentity *id1,
-                     const struct GNUNET_PeerIdentity *id2,
-                     struct CadetPeer *neighbor)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct GNUNET_CADET_ConnectionBrokenMessage msg;
-
-  GCC_check_connections ();
-  LOG (GNUNET_ERROR_TYPE_INFO, "--> BROKEN on unknown connection %s\n",
-       GNUNET_sh2s (&connection_id->connection_of_tunnel));
-
-  msg.header.size = htons (sizeof (struct GNUNET_CADET_ConnectionBrokenMessage));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
-  msg.cid = *connection_id;
-  msg.reserved = htonl (0);
-  msg.peer1 = *id1;
-  if (NULL != id2)
-    msg.peer2 = *id2;
-  else
-    memset (&msg.peer2, 0, sizeof (msg.peer2));
-  GNUNET_assert (NULL != GCP_send (neighbor,
-                                   &msg.header,
-                                   UINT16_MAX,
-                                   zero,
-                                   NULL,
-                                   GNUNET_SYSERR, /* connection, fwd */
-                                   NULL, NULL)); /* continuation */
-  GCC_check_connections ();
-}
-
-
-/**
- * Send keepalive packets for a connection.
- *
- * @param c Connection to keep alive..
- * @param fwd Is this a FWD keepalive? (owner -> dest).
- */
-static void
-send_connection_keepalive (struct CadetConnection *c, int fwd)
-{
-  struct GNUNET_MessageHeader msg;
-  struct CadetFlowControl *fc;
-  int tunnel_ready;
-
-  GCC_check_connections ();
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "keepalive %s for connection %s\n",
-       GC_f2s (fwd), GCC_2s (c));
-
-  GNUNET_assert (NULL != c->t);
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  tunnel_ready = GNUNET_YES == GCT_has_queued_traffic (c->t)
-                 && CADET_TUNNEL_KEY_OK <= GCT_get_estate (c->t);
-  if (0 < fc->queue_n || tunnel_ready)
-  {
-    LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, traffic in queue\n");
-    return;
-  }
-
-  GNUNET_STATISTICS_update (stats, "# keepalives sent", 1, GNUNET_NO);
-
-  GNUNET_assert (NULL != c->t);
-  msg.size = htons (sizeof (msg));
-  msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
-
-  GNUNET_assert (NULL ==
-                 GCT_send_prebuilt_message (&msg, c->t, c,
-                                            GNUNET_NO, NULL, NULL));
-  GCC_check_connections ();
-}
-
-
-/**
- * Send CONNECTION_{CREATE/ACK} packets for a connection.
- *
- * @param c Connection for which to send the message.
- * @param fwd If #GNUNET_YES, send CREATE, otherwise send ACK.
- */
-static void
-connection_recreate (struct CadetConnection *c, int fwd)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "sending connection recreate\n");
-  if (fwd)
-    GCC_send_create (c);
-  else
-    send_connection_ack (c, GNUNET_NO);
-}
-
-
-/**
- * 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)
-  {
-    LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, being destroyed\n");
-    return;
-  }
-
-  if (NULL == c->t)
-  {
-    GNUNET_break (0);
-    GCC_debug (c, GNUNET_ERROR_TYPE_ERROR);
-    return;
-  }
-
-  if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (c->t))
-  {
-    /* If status is SEARCHING, why is there a connection? Should be WAITING */
-    GNUNET_break (0);
-    GCT_debug (c->t, GNUNET_ERROR_TYPE_ERROR);
-    LOG (GNUNET_ERROR_TYPE_INFO, "not sending keepalive, tunnel SEARCHING\n");
-    schedule_next_keepalive (c, fwd);
-    return;
-  }
-  switch (c->state)
-  {
-    case CADET_CONNECTION_NEW:
-      GNUNET_break (0);
-      /* fall-through */
-    case CADET_CONNECTION_SENT:
-      connection_recreate (c, fwd);
-      break;
-    case CADET_CONNECTION_READY:
-      send_connection_keepalive (c, fwd);
-      break;
-    default:
-      break;
-  }
-}
-
-
-/**
- * Keep the connection alive.
- *
- * @param c Connection to keep alive.
- * @param fwd Direction.
- */
-static void
-connection_keepalive (struct CadetConnection *c,
-                     int fwd)
-{
-  GCC_check_connections ();
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "%s keepalive for %s\n",
-       GC_f2s (fwd), GCC_2s (c));
-
-  if (fwd)
-    c->fwd_maintenance_task = NULL;
-  else
-    c->bck_maintenance_task = NULL;
-  connection_maintain (c, fwd);
-  GCC_check_connections ();
-  /* Next execution will be scheduled by message_sent or _maintain*/
-}
-
-
-/**
- * Keep the connection alive in the FWD direction.
- *
- * @param cls Closure (connection to keepalive).
- */
-static void
-connection_fwd_keepalive (void *cls)
-{
-  struct CadetConnection *c = cls;
-
-  GCC_check_connections ();
-  connection_keepalive (c,
-                        GNUNET_YES);
-  GCC_check_connections ();
-}
-
-
-/**
- * Keep the connection alive in the BCK direction.
- *
- * @param cls Closure (connection to keepalive).
- */
-static void
-connection_bck_keepalive (void *cls)
-{
-  struct CadetConnection *c = cls;
-
-  GCC_check_connections ();
-  connection_keepalive (c,
-                        GNUNET_NO);
-  GCC_check_connections ();
-}
-
-
-/**
- * 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;
-  struct GNUNET_SCHEDULER_Task * *task_id;
-  GNUNET_SCHEDULER_TaskCallback keepalive_task;
-
-  GCC_check_connections ();
-  if (GNUNET_NO == GCC_is_origin (c, fwd))
-    return;
-
-  /* Calculate delay to use, depending on the state of the connection */
-  if (CADET_CONNECTION_READY == c->state)
-  {
-    delay = refresh_connection_time;
-  }
-  else
-  {
-    if (1 > c->create_retry)
-      c->create_retry = 1;
-    delay = GNUNET_TIME_relative_saturating_multiply (create_connection_time,
-                                                      c->create_retry);
-    if (c->create_retry < 64) // TODO make configurable
-      c->create_retry *= 2;
-  }
-
-  /* Select direction-dependent parameters */
-  if (GNUNET_YES == fwd)
-  {
-    task_id = &c->fwd_maintenance_task;
-    keepalive_task = &connection_fwd_keepalive;
-  }
-  else
-  {
-    task_id = &c->bck_maintenance_task;
-    keepalive_task = &connection_bck_keepalive;
-  }
-
-  /* Check that no one scheduled it before us */
-  if (NULL != *task_id)
-  {
-    /* No need for a _break. It can happen for instance when sending a SYNACK
-     * for a duplicate SYN: the first SYNACK scheduled the task. */
-    GNUNET_SCHEDULER_cancel (*task_id);
-  }
-
-  /* Schedule the task */
-  *task_id = GNUNET_SCHEDULER_add_delayed (delay,
-                                           keepalive_task,
-                                           c);
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "next keepalive for %s in in %s\n",
-       GCC_2s (c), GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
-  GCC_check_connections ();
-}
-
-
-/**
- * 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;
-
-  GCC_check_connections ();
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Cancel %s queues for connection %s\n",
-       GC_f2s (fwd), GCC_2s (c));
-  if (NULL == c)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  if (NULL != fc->poll_task)
-  {
-    GNUNET_SCHEDULER_cancel (fc->poll_task);
-    fc->poll_task = NULL;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  cancelled POLL task for fc %p\n", fc);
-  }
-  if (NULL != fc->poll_msg)
-  {
-    GCC_cancel (fc->poll_msg);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  cancelled POLL msg for fc %p\n", fc);
-  }
-
-  while (NULL != fc->q_head)
-  {
-    GCC_cancel (fc->q_head);
-  }
-  GCC_check_connections ();
-}
-
-
-/**
- * Function called if a connection has been stalled for a while,
- * possibly due to a missed ACK. Poll the neighbor about its ACK status.
- *
- * @param cls Closure (poll ctx).
- */
-static void
-send_poll (void *cls)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct CadetFlowControl *fc = cls;
-  struct GNUNET_CADET_ConnectionHopByHopPollMessage msg;
-  struct CadetConnection *c;
-  int fwd;
-
-  fc->poll_task = NULL;
-  GCC_check_connections ();
-  c = fc->c;
-  fwd = fc == &c->fwd_fc;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Polling connection %s %s\n",
-       GCC_2s (c),  GC_f2s (fwd));
-
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL);
-  msg.header.size = htons (sizeof (msg));
-  msg.cid = c->id;
-  msg.cemi = fc->last_pid_sent;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " last pid sent: %u\n", ntohl (fc->last_pid_sent.pid));
-  fc->poll_msg
-    = GCC_send_prebuilt_message (&msg.header,
-                                 UINT16_MAX,
-                                 zero,
-                                 c,
-                                 fc == &c->fwd_fc,
-                                 GNUNET_YES,
-                                 NULL,
-                                 NULL);
-  GNUNET_assert (NULL != fc->poll_msg);
-  GCC_check_connections ();
-}
-
-
-/**
- * Generic connection timeout implementation.
- *
- * Timeout function due to lack of keepalive/traffic from an endpoint.
- * Destroys connection if called.
- *
- * @param c Connection to destroy.
- * @param fwd Was the timeout from the origin? (FWD timeout)
- */
-static void
-connection_timeout (struct CadetConnection *c, int fwd)
-{
-  GCC_check_connections ();
-
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Connection %s %s timed out. Destroying.\n",
-       GCC_2s (c),
-       GC_f2s (fwd));
-  GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
-
-  if (GCC_is_origin (c, fwd)) /* Loopback? Something is wrong! */
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  /* If dest, send "broken" notification. */
-  if (GCC_is_terminal (c, fwd))
-  {
-    struct CadetPeer *next_hop;
-
-    next_hop = fwd ? get_prev_hop (c) : get_next_hop (c);
-    send_broken_unknown (&c->id, &my_full_id, NULL, next_hop);
-  }
-
-  GCC_destroy (c);
-  GCC_check_connections ();
-}
-
-
-/**
- * Timeout function due to lack of keepalive/traffic from the owner.
- * Destroys connection if called.
- *
- * @param cls Closure (connection to destroy).
- */
-static void
-connection_fwd_timeout (void *cls)
-{
-  struct CadetConnection *c = cls;
-
-  c->fwd_maintenance_task = NULL;
-  GCC_check_connections ();
-  connection_timeout (c, GNUNET_YES);
-  GCC_check_connections ();
-}
-
-
-/**
- * Timeout function due to lack of keepalive/traffic from the destination.
- * Destroys connection if called.
- *
- * @param cls Closure (connection to destroy).
- */
-static void
-connection_bck_timeout (void *cls)
-{
-  struct CadetConnection *c = cls;
-
-  c->bck_maintenance_task = NULL;
-  GCC_check_connections ();
-  connection_timeout (c, GNUNET_NO);
-  GCC_check_connections ();
-}
-
-
-/**
- * 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", GC_f2s (fwd));
-  if (GCC_is_origin (c, fwd)) /* Startpoint */
-  {
-    schedule_next_keepalive (c, fwd);
-    if (NULL != c->maintenance_q)
-    {
-      GCP_send_cancel (c->maintenance_q);
-      c->maintenance_q = NULL; /* Is set to NULL by conn_message_sent anyway */
-    }
-  }
-  else /* Relay, endpoint. */
-  {
-    struct GNUNET_TIME_Relative delay;
-    struct GNUNET_SCHEDULER_Task * *ti;
-    GNUNET_SCHEDULER_TaskCallback f;
-
-    ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task;
-
-    if (NULL != *ti)
-      GNUNET_SCHEDULER_cancel (*ti);
-    delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 4);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "  timing out in %s\n",
-         GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO));
-    f = fwd ? &connection_fwd_timeout : &connection_bck_timeout;
-    *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c);
-  }
-}
-
-
-/**
- * Iterator to compare each connection's path with the path of a new connection.
- *
- * If the connection coincides, the c member of path is set to the connection
- * and the destroy flag of the connection is set.
- *
- * @param cls Closure (new path).
- * @param c Connection in the tunnel to check.
- */
-static void
-check_path (void *cls, struct CadetConnection *c)
-{
-  struct CadetConnection *new_conn = cls;
-  struct CadetPeerPath *path = new_conn->path;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  checking %s (%p), length %u\n",
-       GCC_2s (c), c, c->path->length);
-
-  if (c != new_conn
-      && GNUNET_NO == c->destroy
-      && CADET_CONNECTION_BROKEN != c->state
-      && CADET_CONNECTION_DESTROYED != c->state
-      && path_equivalent (path, c->path))
-  {
-    new_conn->destroy = GNUNET_YES; /* Do not mark_destroyed, */
-    new_conn->path->c = c;          /* this is only a flag for the Iterator. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  MATCH!\n");
-  }
-}
-
-
-/**
- * Finds out if this path is already being used by an existing connection.
- *
- * Checks the tunnel towards the destination to see if it contains
- * any connection with the same path.
- *
- * If the existing connection is ready, it is kept.
- * Otherwise if the sender has a smaller ID that ours, we accept it (and
- * the peer will eventually reject our attempt).
- *
- * @param path Path to check.
- * @return #GNUNET_YES if the tunnel has a connection with the same path,
- *         #GNUNET_NO otherwise.
- */
-static int
-does_connection_exist (struct CadetConnection *conn)
-{
-  struct CadetPeer *p;
-  struct CadetTunnel *t;
-  struct CadetConnection *c;
-
-  p = GCP_get_short (conn->path->peers[0], GNUNET_NO);
-  if (NULL == p)
-    return GNUNET_NO;
-  t = GCP_get_tunnel (p);
-  if (NULL == t)
-    return GNUNET_NO;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking for duplicates\n");
-
-  GCT_iterate_connections (t, &check_path, conn);
-
-  if (GNUNET_YES == conn->destroy)
-  {
-    c = conn->path->c;
-    conn->destroy = GNUNET_NO;
-    conn->path->c = conn;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " found duplicate of %s\n", GCC_2s (conn));
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate: %s\n", GCC_2s (c));
-    GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
-    if (CADET_CONNECTION_READY == c->state)
-    {
-      /* The other peer confirmed a live connection with this path,
-       * why are they trying to duplicate it? */
-      GNUNET_STATISTICS_update (stats, "# duplicate connections", 1, GNUNET_NO);
-      return GNUNET_YES;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate not ready, connection unique\n");
-    return GNUNET_NO;
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " %s has no duplicates\n", GCC_2s (conn));
-    return GNUNET_NO;
-  }
-}
-
-
-/**
- * @brief Check if the tunnel this connection belongs to has any other
- * connection with the same path, and destroy one if so.
- *
- * @param cls Closure (connection to check).
- */
-static void
-check_duplicates (void *cls)
-{
-  struct CadetConnection *c = cls;
-
-  c->check_duplicates_task = NULL;
-  if (GNUNET_YES == does_connection_exist (c))
-  {
-    GCT_debug (c->t, GNUNET_ERROR_TYPE_DEBUG);
-    send_broken (c, &my_full_id, &my_full_id, GCC_is_origin (c, GNUNET_YES));
-    GCC_destroy (c);
-  }
-}
-
-
-/**
- * Wait for enough time to let any dead connections time out and check for
- * any remaining duplicates.
- *
- * @param c Connection that is a potential duplicate.
- */
-static void
-schedule_check_duplicates (struct CadetConnection *c)
-{
-  struct GNUNET_TIME_Relative delay;
-
-  if (NULL != c->check_duplicates_task)
-    return;
-  delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 5);
-  c->check_duplicates_task = GNUNET_SCHEDULER_add_delayed (delay,
-                                                           &check_duplicates,
-                                                           c);
-}
-
-
-/**
- * Add the connection to the list of both neighbors.
- *
- * @param c Connection.
- *
- * @return #GNUNET_OK if everything went fine
- *         #GNUNET_SYSERR if the was an error and @c c is malformed.
- */
-static int
-register_neighbors (struct CadetConnection *c)
-{
-  c->next_peer = get_next_hop (c);
-  c->prev_peer = get_prev_hop (c);
-  GNUNET_assert (c->next_peer != c->prev_peer);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "register neighbors for connection %s\n",
-       GCC_2s (c));
-  path_debug (c->path);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "own pos %u\n", c->own_pos);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "putting connection %s to next peer %p\n",
-       GCC_2s (c),
-       c->next_peer);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "next peer %p %s\n",
-       c->next_peer,
-       GCP_2s (c->next_peer));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "putting connection %s to prev peer %p\n",
-       GCC_2s (c),
-       c->prev_peer);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "prev peer %p %s\n",
-       c->prev_peer,
-       GCP_2s (c->prev_peer));
-
-  if ( (GNUNET_NO == GCP_is_neighbor (c->next_peer)) ||
-       (GNUNET_NO == GCP_is_neighbor (c->prev_peer)) )
-  {
-    if (GCC_is_origin (c, GNUNET_YES))
-      GNUNET_STATISTICS_update (stats, "# local bad paths", 1, GNUNET_NO);
-    GNUNET_STATISTICS_update (stats, "# bad paths", 1, GNUNET_NO);
-
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "  register neighbors failed\n");
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "  prev: %s, neighbor?: %d\n",
-         GCP_2s (c->prev_peer),
-         GCP_is_neighbor (c->prev_peer));
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "  next: %s, neighbor?: %d\n",
-         GCP_2s (c->next_peer),
-         GCP_is_neighbor (c->next_peer));
-    return GNUNET_SYSERR;
-  }
-  GCP_add_connection (c->next_peer, c, GNUNET_NO);
-  GCP_add_connection (c->prev_peer, c, GNUNET_YES);
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Remove the connection from the list of both neighbors.
- *
- * @param c Connection.
- */
-static void
-unregister_neighbors (struct CadetConnection *c)
-{
-//  struct CadetPeer *peer; FIXME dont use next_peer, prev_peer
-  /* Either already unregistered or never got registered, it's ok either way. */
-  if (NULL == c->path)
-    return;
-  if (NULL != c->next_peer)
-  {
-    GCP_remove_connection (c->next_peer, c);
-    c->next_peer = NULL;
-  }
-  if (NULL != c->prev_peer)
-  {
-    GCP_remove_connection (c->prev_peer, c);
-    c->prev_peer = NULL;
-  }
-}
-
-
-/**
- * Invalidates all paths towards all peers that comprise the connection which
- * rely on the disconnected peer.
- *
- * ~O(n^3) (peers in connection * paths/peer * links/path)
- *
- * @param c Connection whose peers' paths to clean.
- * @param disconnected Peer that disconnected.
- */
-static void
-invalidate_paths (struct CadetConnection *c,
-                 struct CadetPeer *disconnected)
-{
-  struct CadetPeer *peer;
-  unsigned int i;
-
-  for (i = 0; i < c->path->length; i++)
-  {
-    peer = GCP_get_short (c->path->peers[i], GNUNET_NO);
-    if (NULL != peer)
-      GCP_notify_broken_link (peer, &my_full_id, GCP_get_id (disconnected));
-  }
-}
-
-
-/**
- * Bind the connection to the peer and the tunnel to that peer.
- *
- * If the peer has no tunnel, create one. Update tunnel and connection
- * data structres to reflect new status.
- *
- * @param c Connection.
- * @param peer Peer.
- */
-static void
-add_to_peer (struct CadetConnection *c,
-             struct CadetPeer *peer)
-{
-  GCP_add_tunnel (peer);
-  c->t = GCP_get_tunnel (peer);
-  GCT_add_connection (c->t, c);
-}
-
-
-/**
- * Log receipt of message on stderr (INFO level).
- *
- * @param message Message received.
- * @param peer    Peer who sent the message.
- * @param conn_id Connection ID of the message.
- */
-static void
-log_message (const struct GNUNET_MessageHeader *message,
-             const struct CadetPeer *peer,
-             const struct GNUNET_CADET_ConnectionTunnelIdentifier *conn_id)
-{
-  uint16_t size;
-  uint16_t type;
-  char *arrow;
-
-  size = ntohs (message->size);
-  type = ntohs (message->type);
-  switch (type)
-  {
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK:
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
-      arrow = "==";
-      break;
-    default:
-      arrow = "--";
-  }
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "<%s %s on conn %s from %s, %6u bytes\n",
-       arrow,
-       GC_m2s (type),
-       GNUNET_sh2s (&conn_id->connection_of_tunnel),
-       GCP_2s(peer),
-       (unsigned int) size);
-}
-
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
-
-/**
- * Handler for connection creation.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_create (struct CadetPeer *peer,
-                   const struct GNUNET_CADET_ConnectionCreateMessage *msg)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid;
-  struct GNUNET_PeerIdentity *id;
-  struct CadetPeerPath *path;
-  struct CadetPeer *dest_peer;
-  struct CadetPeer *orig_peer;
-  struct CadetConnection *c;
-  unsigned int own_pos;
-  uint16_t size;
-
-  GCC_check_connections ();
-  size = ntohs (msg->header.size);
-
-  /* Calculate hops */
-  size -= sizeof (struct GNUNET_CADET_ConnectionCreateMessage);
-  if (0 != size % sizeof (struct GNUNET_PeerIdentity))
-  {
-    GNUNET_break_op (0);
-    return;
-  }
-  size /= sizeof (struct GNUNET_PeerIdentity);
-  if (1 > size)
-  {
-    GNUNET_break_op (0);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "    path has %u hops.\n", size);
-
-  /* Get parameters */
-  cid = &msg->cid;
-  log_message (&msg->header, peer, cid);
-  id = (struct GNUNET_PeerIdentity *) &msg[1];
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "    origin: %s\n", GNUNET_i2s (id));
-
-  /* Create connection */
-  c = connection_get (cid);
-  if (NULL == c)
-  {
-    path = path_build_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1],
-                                     size, myid, &own_pos);
-    if (NULL == path)
-    {
-      /* Path was malformed, probably our own ID was not in it. */
-      GNUNET_STATISTICS_update (stats, "# malformed paths", 1, GNUNET_NO);
-      GNUNET_break_op (0);
-      return;
-    }
-    if (0 == own_pos)
-    {
-      /* We received this request from a neighbor, we cannot be origin */
-      GNUNET_STATISTICS_update (stats, "# fake paths", 1, GNUNET_NO);
-      GNUNET_break_op (0);
-      path_destroy (path);
-      return;
-    }
-
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  Own position: %u\n", own_pos);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  Creating connection\n");
-    c = GCC_new (cid, NULL, path, own_pos);
-    if (NULL == c)
-    {
-      if (path->length - 1 == own_pos)
-      {
-        /* If we are destination, why did the creation fail? */
-        GNUNET_break (0);
-        path_destroy (path);
-        GCC_check_connections ();
-        return;
-      }
-      send_broken_unknown (cid, &my_full_id,
-                           GNUNET_PEER_resolve2 (path->peers[own_pos + 1]),
-                           peer);
-      path_destroy (path);
-      GCC_check_connections ();
-      return;
-    }
-    GCP_add_path_to_all (path, GNUNET_NO);
-    connection_reset_timeout (c, GNUNET_YES);
-  }
-  else
-  {
-    path = path_duplicate (c->path);
-  }
-  if (CADET_CONNECTION_NEW == c->state)
-    connection_change_state (c, CADET_CONNECTION_SENT);
-
-  /* Remember peers */
-  dest_peer = GCP_get (&id[size - 1], GNUNET_YES);
-  orig_peer = GCP_get (&id[0], GNUNET_YES);
-
-  /* Is it a connection to us? */
-  if (c->own_pos == path->length - 1)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  It's for us!\n");
-    GCP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES);
-
-    add_to_peer (c, orig_peer);
-    if (GNUNET_YES == does_connection_exist (c))
-    {
-      /* Peer created a connection equal to one we think exists
-       * and is fine.
-       * Solution: Keep both and postpone disambiguation. In the meantime
-       * the connection will time out or peer will inform us it is broken.
-       *
-       * Other options:
-       * - Use explicit duplicate.
-       * - Accept new conn and destroy the old. (interruption in higher level)
-       * - Keep the one with higher ID / created by peer with higher ID. */
-       schedule_check_duplicates (c);
-    }
-
-    if (CADET_TUNNEL_NEW == GCT_get_cstate (c->t))
-      GCT_change_cstate (c->t,  CADET_TUNNEL_WAITING);
-    if (NULL == c->maintenance_q)
-      send_connection_ack (c, GNUNET_NO);
-    if (CADET_CONNECTION_SENT == c->state)
-      connection_change_state (c, CADET_CONNECTION_ACK);
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  not for us, retransmitting...\n");
-    GCP_add_path (dest_peer, path_duplicate (path), GNUNET_NO);
-    GCP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_NO);
-    (void) GCC_send_prebuilt_message (&msg->header,
-                                      0,
-                                      zero,
-                                      c,
-                                      GNUNET_YES, GNUNET_YES,
-                                      NULL, NULL);
-  }
-  path_destroy (path);
-  GCC_check_connections ();
-}
-
-
-/**
- * Handler for connection confirmations.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_confirm (struct CadetPeer *peer,
-                    const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct CadetConnection *c;
-  enum CadetConnectionState oldstate;
-  int fwd;
-
-  GCC_check_connections ();
-  log_message (&msg->header, peer, &msg->cid);
-  c = connection_get (&msg->cid);
-  if (NULL == c)
-  {
-    GNUNET_STATISTICS_update (stats, "# control on unknown connection",
-                              1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "  don't know the connection!\n");
-    send_broken_unknown (&msg->cid, &my_full_id, NULL, peer);
-    GCC_check_connections ();
-    return;
-  }
-  if (GNUNET_NO != c->destroy)
-  {
-    GNUNET_assert (CADET_CONNECTION_DESTROYED == c->state);
-    GNUNET_STATISTICS_update (stats, "# control on dying connection",
-                              1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "connection %s being destroyed, ignoring confirm\n",
-         GCC_2s (c));
-    GCC_check_connections ();
-    return;
-  }
-
-  oldstate = c->state;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  via peer %s\n", GCP_2s (peer));
-  if (get_next_hop (c) == peer)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  SYNACK\n");
-    fwd = GNUNET_NO;
-    if (CADET_CONNECTION_SENT == oldstate)
-      connection_change_state (c, CADET_CONNECTION_ACK);
-  }
-  else if (get_prev_hop (c) == peer)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  FINAL ACK\n");
-    fwd = GNUNET_YES;
-    connection_change_state (c, CADET_CONNECTION_READY);
-  }
-  else
-  {
-    GNUNET_STATISTICS_update (stats, "# control on connection from wrong peer",
-                              1, GNUNET_NO);
-    GNUNET_break_op (0);
-    return;
-  }
-
-  connection_reset_timeout (c, fwd);
-
-  GNUNET_assert (NULL != c->path);
-  GCP_add_path_to_all (c->path, GNUNET_YES);
-
-  /* Message for us as creator? */
-  if (GNUNET_YES == GCC_is_origin (c, GNUNET_YES))
-  {
-    if (GNUNET_NO != fwd)
-    {
-      GNUNET_break (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  Connection (SYN)ACK for us!\n");
-
-    /* If just created, cancel the short timeout and start a long one */
-    if (CADET_CONNECTION_SENT == oldstate)
-    {
-      c->create_retry = 1;
-      connection_reset_timeout (c, GNUNET_YES);
-    }
-
-    /* Change connection state, send ACK */
-    connection_change_state (c, CADET_CONNECTION_READY);
-    send_connection_ack (c, GNUNET_YES);
-
-    /* Change tunnel state, trigger KX */
-    if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t))
-      GCT_change_cstate (c->t, CADET_TUNNEL_READY);
-    GCC_check_connections ();
-    return;
-  }
-
-  /* Message for us as destination? */
-  if (GCC_is_terminal (c, GNUNET_YES))
-  {
-    if (GNUNET_YES != fwd)
-    {
-      GNUNET_break (0);
-      return;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  Connection ACK for us!\n");
-
-    /* If just created, cancel the short timeout and start a long one */
-    if (CADET_CONNECTION_ACK == oldstate)
-      connection_reset_timeout (c, GNUNET_NO);
-
-    /* Change tunnel state */
-    if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t))
-      GCT_change_cstate (c->t, CADET_TUNNEL_READY);
-    GCC_check_connections ();
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  not for us, retransmitting...\n");
-    (void) GCC_send_prebuilt_message (&msg->header, 0,
-                                      zero,
-                                      c,
-                                      fwd,
-                                      GNUNET_YES, NULL, NULL);
-  }
-  GCC_check_connections ();
-}
-
-
-/**
- * Handler for notifications of broken connections.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_broken (struct CadetPeer *peer,
-                   const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct CadetConnection *c;
-  struct CadetTunnel *t;
-  int fwd;
-
-  GCC_check_connections ();
-  log_message (&msg->header, peer, &msg->cid);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  regarding %s\n", GNUNET_i2s (&msg->peer1));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  regarding %s\n", GNUNET_i2s (&msg->peer2));
-  c = connection_get (&msg->cid);
-  if (NULL == c)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  duplicate CONNECTION_BROKEN\n");
-    GNUNET_STATISTICS_update (stats, "# duplicate CONNECTION_BROKEN",
-                              1, GNUNET_NO);
-    GCC_check_connections ();
-    return;
-  }
-
-  t = c->t;
-
-  fwd = is_fwd (c, peer);
-  if (GNUNET_SYSERR == fwd)
-  {
-    GNUNET_break_op (0);
-    GCC_check_connections ();
-    return;
-  }
-  mark_destroyed (c);
-  if (GCC_is_terminal (c, fwd))
-  {
-    struct CadetPeer *endpoint;
-
-    if (NULL == t)
-    {
-      /* A terminal connection should not have 't' set to NULL. */
-      GNUNET_break (0);
-      GCC_debug (c, GNUNET_ERROR_TYPE_ERROR);
-      return;
-    }
-    endpoint = GCP_get_short (c->path->peers[c->path->length - 1], GNUNET_YES);
-    if (2 < c->path->length)
-      path_invalidate (c->path);
-    GCP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2);
-
-    connection_change_state (c, CADET_CONNECTION_BROKEN);
-    GCT_remove_connection (t, c);
-    c->t = NULL;
-
-    GCC_destroy (c);
-  }
-  else
-  {
-    (void) GCC_send_prebuilt_message (&msg->header, 0,
-                                      zero, c, fwd,
-                                      GNUNET_YES, NULL, NULL);
-    connection_cancel_queues (c, !fwd);
-  }
-  GCC_check_connections ();
-  return;
-}
-
-
-/**
- * Handler for notifications of destroyed connections.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_destroy (struct CadetPeer *peer,
-                    const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct CadetConnection *c;
-  int fwd;
-
-  GCC_check_connections ();
-  log_message (&msg->header, peer, &msg->cid);
-  c = connection_get (&msg->cid);
-  if (NULL == c)
-  {
-    /* 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 destroyed: previously destroyed?\n");
-    GCC_check_connections ();
-    return;
-  }
-
-  fwd = is_fwd (c, peer);
-  if (GNUNET_SYSERR == fwd)
-  {
-    GNUNET_break_op (0);
-    GCC_check_connections ();
-    return;
-  }
-
-  if (GNUNET_NO == GCC_is_terminal (c, fwd))
-  {
-    (void) GCC_send_prebuilt_message (&msg->header, 0,
-                                      zero, c, fwd,
-                                      GNUNET_YES, NULL, NULL);
-  }
-  else if (0 == c->pending_messages)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  directly destroying connection!\n");
-    GCC_destroy (c);
-    GCC_check_connections ();
-    return;
-  }
-  mark_destroyed (c);
-  if (NULL != c->t)
-  {
-    GCT_remove_connection (c->t, c);
-    c->t = NULL;
-  }
-  GCC_check_connections ();
-  return;
-}
-
-
-/**
- * Handler for cadet network traffic hop-by-hop acks.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_ack (struct CadetPeer *peer,
-                const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg)
-{
-  struct CadetConnection *c;
-  struct CadetFlowControl *fc;
-  struct CadetEncryptedMessageIdentifier ack;
-  int fwd;
-
-  GCC_check_connections ();
-  log_message (&msg->header, peer, &msg->cid);
-  c = connection_get (&msg->cid);
-  if (NULL == c)
-  {
-    GNUNET_STATISTICS_update (stats,
-                              "# ack on unknown connection",
-                              1,
-                              GNUNET_NO);
-    send_broken_unknown (&msg->cid,
-                         &my_full_id,
-                         NULL,
-                         peer);
-    GCC_check_connections ();
-    return;
-  }
-
-  /* Is this a forward or backward ACK? */
-  if (get_next_hop (c) == peer)
-  {
-    fc = &c->fwd_fc;
-    fwd = GNUNET_YES;
-  }
-  else if (get_prev_hop (c) == peer)
-  {
-    fc = &c->bck_fc;
-    fwd = GNUNET_NO;
-  }
-  else
-  {
-    GNUNET_break_op (0);
-    return;
-  }
-
-  ack = msg->cemi_max;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " %s ACK %u (was %u)\n",
-       GC_f2s (fwd),
-       ntohl (ack.pid),
-       ntohl (fc->last_ack_recv.pid));
-  if (GC_is_pid_bigger (ntohl (ack.pid),
-                        ntohl (fc->last_ack_recv.pid)))
-    fc->last_ack_recv = ack;
-
-  /* Cancel polling if the ACK is big enough. */
-  if ( (NULL != fc->poll_task) &
-       GC_is_pid_bigger (ntohl (fc->last_ack_recv.pid),
-                         ntohl (fc->last_pid_sent.pid)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  Cancel poll\n");
-    GNUNET_SCHEDULER_cancel (fc->poll_task);
-    fc->poll_task = NULL;
-    fc->poll_time = GNUNET_TIME_UNIT_SECONDS;
-  }
-
-  GCC_check_connections ();
-}
-
-
-/**
- * Handler for cadet network traffic hop-by-hop data counter polls.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_poll (struct CadetPeer *peer,
-                 const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg)
-{
-  struct CadetConnection *c;
-  struct CadetFlowControl *fc;
-  struct CadetEncryptedMessageIdentifier pid;
-  int fwd;
-
-  GCC_check_connections ();
-  log_message (&msg->header, peer, &msg->cid);
-  c = connection_get (&msg->cid);
-  if (NULL == c)
-  {
-    GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1,
-                              GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "POLL message on unknown connection %s!\n",
-         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
-    send_broken_unknown (&msg->cid,
-                         &my_full_id,
-                         NULL,
-                         peer);
-    GCC_check_connections ();
-    return;
-  }
-
-  /* Is this a forward or backward ACK?
-   * Note: a poll should never be needed in a loopback case,
-   * since there is no possiblility of packet loss there, so
-   * this way of discerining FWD/BCK should not be a problem.
-   */
-  if (get_next_hop (c) == peer)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  FWD FC\n");
-    fc = &c->fwd_fc;
-  }
-  else if (get_prev_hop (c) == peer)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  BCK FC\n");
-    fc = &c->bck_fc;
-  }
-  else
-  {
-    GNUNET_break_op (0);
-    return;
-  }
-
-  pid = msg->cemi;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "  PID %u, OLD %u\n",
-       ntohl (pid.pid),
-       ntohl (fc->last_pid_recv.pid));
-  fc->last_pid_recv = pid;
-  fwd = fc == &c->bck_fc;
-  GCC_send_ack (c, fwd, GNUNET_YES);
-  GCC_check_connections ();
-}
-
-
-/**
- * Check the message against internal state and test if it goes FWD or BCK.
- *
- * Updates the PID, state and timeout values for the connection.
- *
- * @param message Message to check. It must belong to an existing connection.
- * @param cid Connection ID (even if @a c is NULL, the ID is still needed).
- * @param c Connection this message should belong. If NULL, check fails.
- * @param sender Neighbor that sent the message.
- *
- * @return #GNUNET_YES if the message goes FWD.
- *         #GNUNET_NO if it goes BCK.
- *         #GNUNET_SYSERR if there is an error (unauthorized sender, ...).
- */
-static int
-check_message (const struct GNUNET_MessageHeader *message,
-               const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid,
-               struct CadetConnection *c,
-               struct CadetPeer *sender,
-               struct CadetEncryptedMessageIdentifier pid)
-{
-  struct CadetFlowControl *fc;
-  struct CadetPeer *hop;
-  int fwd;
-  uint16_t type;
-
-  /* Check connection */
-  if (NULL == c)
-  {
-    GNUNET_STATISTICS_update (stats,
-                              "# unknown connection",
-                              1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "%s on unknown connection %s\n",
-         GC_m2s (ntohs (message->type)),
-         GNUNET_sh2s (&cid->connection_of_tunnel));
-    GNUNET_break_op (0);
-    send_broken_unknown (cid,
-                         &my_full_id,
-                         NULL,
-                         sender);
-    return GNUNET_SYSERR;
-  }
-
-  /* Check if origin is as expected */
-  hop = get_prev_hop (c);
-  if (sender == hop)
-  {
-    fwd = GNUNET_YES;
-  }
-  else
-  {
-    hop = get_next_hop (c);
-    GNUNET_break (hop == c->next_peer);
-    if (sender == hop)
-    {
-      fwd = GNUNET_NO;
-    }
-    else
-    {
-      /* Unexpected peer sending traffic on a connection. */
-      GNUNET_break_op (0);
-      return GNUNET_SYSERR;
-    }
-  }
-
-  /* Check PID for payload messages */
-  type = ntohs (message->type);
-  if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == type)
-  {
-    fc = fwd ? &c->bck_fc : &c->fwd_fc;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " PID %u (expected in interval [%u,%u])\n",
-         ntohl (pid.pid),
-        ntohl (fc->last_pid_recv.pid) + 1,
-        ntohl (fc->last_ack_sent.pid));
-    if (GC_is_pid_bigger (ntohl (pid.pid),
-                          ntohl (fc->last_ack_sent.pid)))
-    {
-      GNUNET_STATISTICS_update (stats,
-                               "# unsolicited message",
-                               1,
-                               GNUNET_NO);
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-          "Received PID %u, (prev %u), ACK %u\n",
-          pid, fc->last_pid_recv, fc->last_ack_sent);
-      return GNUNET_SYSERR;
-    }
-    if (GC_is_pid_bigger (ntohl (pid.pid),
-                          ntohl (fc->last_pid_recv.pid)))
-    {
-      unsigned int delta;
-
-      delta = ntohl (pid.pid) - ntohl (fc->last_pid_recv.pid);
-      fc->last_pid_recv = pid;
-      fc->recv_bitmap <<= delta;
-      fc->recv_bitmap |= 1;
-    }
-    else
-    {
-      GNUNET_STATISTICS_update (stats,
-                               "# out of order PID",
-                               1,
-                               GNUNET_NO);
-      if (GNUNET_NO == is_ooo_ok (fc->last_pid_recv,
-                                 pid,
-                                 fc->recv_bitmap))
-      {
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-            "PID %u unexpected (%u+), dropping!\n",
-             ntohl (pid.pid),
-             ntohl (fc->last_pid_recv.pid) - 31);
-        return GNUNET_SYSERR;
-      }
-      fc->recv_bitmap |= get_recv_bitmask (fc->last_pid_recv,
-                                           pid);
-    }
-  }
-
-  /* Count as connection confirmation. */
-  if ( (CADET_CONNECTION_SENT == c->state) ||
-       (CADET_CONNECTION_ACK == c->state) )
-  {
-    connection_change_state (c, CADET_CONNECTION_READY);
-    if (NULL != c->t)
-    {
-      if (CADET_TUNNEL_WAITING == GCT_get_cstate (c->t))
-        GCT_change_cstate (c->t, CADET_TUNNEL_READY);
-    }
-  }
-  connection_reset_timeout (c, fwd);
+  /**
+   * Are we ready to transmit via @e mq_man right now?
+   */
+  int mqm_ready;
 
-  return fwd;
-}
+};
 
 
 /**
- * Handler for key exchange traffic (Axolotl KX).
+ * Lookup a connection by its identifier.
  *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cid identifier to resolve
+ * @return NULL if connection was not found
  */
-void
-GCC_handle_kx (struct CadetPeer *peer,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
+struct CadetConnection *
+GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
 {
-  static struct CadetEncryptedMessageIdentifier zero;
-  const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid;
-  struct CadetConnection *c;
-  int fwd;
-
-  GCC_check_connections ();
-  cid = &msg->cid;
-  log_message (&msg->header, peer, cid);
-
-  c = connection_get (cid);
-  fwd = check_message (&msg->header,
-                       cid,
-                       c,
-                       peer,
-                       zero);
-
-  /* If something went wrong, discard message. */
-  if (GNUNET_SYSERR == fwd)
-  {
-    GNUNET_break_op (0);
-    GCC_check_connections ();
-    return;
-  }
-
-  /* Is this message for us? */
-  if (GCC_is_terminal (c, fwd))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  message for us!\n");
-    GNUNET_STATISTICS_update (stats, "# received KX", 1, GNUNET_NO);
-    if (NULL == c->t)
-    {
-      GNUNET_break (0);
-      return;
-    }
-    GCT_handle_kx (c->t, msg);
-    GCC_check_connections ();
-    return;
-  }
-
-  /* Message not for us: forward to next hop */
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  not for us, retransmitting...\n");
-  GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
-  (void) GCC_send_prebuilt_message (&msg->header, 0,
-                                    zero, c, fwd,
-                                    GNUNET_NO, NULL, NULL);
-  GCC_check_connections ();
+  return GNUNET_CONTAINER_multishortmap_get (connections,
+                                             &cid->connection_of_tunnel);
 }
 
 
 /**
- * Handler for encrypted cadet network traffic (channel mgmt, data).
+ * Update the connection state. Also triggers the necessary
+ * MQM notifications.
  *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection to update the state for
+ * @param new_state new state for @a cc
+ * @param new_mqm_ready new `mqm_ready` state for @a cc
  */
-void
-GCC_handle_encrypted (struct CadetPeer *peer,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+static void
+update_state (struct CadetConnection *cc,
+              enum CadetConnectionState new_state,
+              int new_mqm_ready)
 {
-  static struct CadetEncryptedMessageIdentifier zero;
-  const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid;
-  struct CadetConnection *c;
-  struct CadetEncryptedMessageIdentifier pid;
-  int fwd;
-
-  GCC_check_connections ();
-  cid = &msg->cid;
-  pid = msg->cemi;
-  log_message (&msg->header, peer, cid);
-
-  c = connection_get (cid);
-  fwd = check_message (&msg->header,
-                       cid,
-                       c,
-                       peer,
-                       pid);
-
-  /* If something went wrong, discard message. */
-  if (GNUNET_SYSERR == fwd)
-  {
-    GCC_check_connections ();
-    return;
-  }
+  int old_ready;
+  int new_ready;
 
-  /* Is this message for us? */
-  if (GCC_is_terminal (c, fwd))
-  {
-    GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO);
-
-    if (NULL == c->t)
-    {
-      GNUNET_break (GNUNET_NO != c->destroy);
-      return;
-    }
-    GCT_handle_encrypted (c->t, msg);
-    GCC_send_ack (c, fwd, GNUNET_NO);
-    GCC_check_connections ();
-    return;
-  }
-
-  /* Message not for us: forward to next hop */
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  not for us, retransmitting...\n");
-  GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
-  (void) GCC_send_prebuilt_message (&msg->header, 0,
-                                    zero, c, fwd,
-                                    GNUNET_NO, NULL, NULL);
-  GCC_check_connections ();
+  if ( (new_state == cc->state) &&
+       (new_mqm_ready == cc->mqm_ready) )
+    return; /* no change, nothing to do */
+  old_ready = ( (CADET_CONNECTION_READY == cc->state) &&
+                (GNUNET_YES == cc->mqm_ready) );
+  new_ready = ( (CADET_CONNECTION_READY == new_state) &&
+                (GNUNET_YES == new_mqm_ready) );
+  cc->state = new_state;
+  cc->mqm_ready = new_mqm_ready;
+  if (old_ready != new_ready)
+    cc->ready_cb (cc->ready_cb_cls,
+                  new_ready);
 }
 
 
 /**
- * Initialize the connections subsystem
+ * Destroy a connection, part of the internal implementation.  Called
+ * only from #GCC_destroy_from_core() or #GCC_destroy_from_tunnel().
  *
- * @param c Configuration handle.
+ * @param cc connection to destroy
  */
-void
-GCC_init (const struct GNUNET_CONFIGURATION_Handle *c)
+static void
+GCC_destroy (struct CadetConnection *cc)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_MSGS_QUEUE",
-                                             &max_msgs_queue))
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying %s\n",
+       GCC_2s (cc));
+  if (NULL != cc->mq_man)
   {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
-                               "CADET", "MAX_MSGS_QUEUE", "MISSING");
-    GNUNET_SCHEDULER_shutdown ();
-    return;
+    GCP_request_mq_cancel (cc->mq_man,
+                           NULL);
+    cc->mq_man = NULL;
   }
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_CONNECTIONS",
-                                             &max_connections))
+  if (NULL != cc->task)
   {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
-                               "CADET", "MAX_CONNECTIONS", "MISSING");
-    GNUNET_SCHEDULER_shutdown ();
-    return;
+    GNUNET_SCHEDULER_cancel (cc->task);
+    cc->task = NULL;
   }
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REFRESH_CONNECTION_TIME",
-                                           &refresh_connection_time))
+  if (NULL != cc->keepalive_qe)
   {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
-                               "CADET", "REFRESH_CONNECTION_TIME", "MISSING");
-    GNUNET_SCHEDULER_shutdown ();
-    return;
+    GCT_send_cancel (cc->keepalive_qe);
+    cc->keepalive_qe = NULL;
   }
-  create_connection_time = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS,
-                                                     refresh_connection_time);
-  connections = GNUNET_CONTAINER_multishortmap_create (1024,
-                                                       GNUNET_YES);
+  GCPP_del_connection (cc->path,
+                       cc->off,
+                       cc);
+  for (unsigned int i=0;i<cc->off;i++)
+    GCP_remove_connection (GCPP_get_peer_at_offset (cc->path,
+                                                    i),
+                           cc);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multishortmap_remove (connections,
+                                                        &GCC_get_id (cc)->connection_of_tunnel,
+                                                        cc));
+  GNUNET_free (cc);
 }
 
 
-/**
- * Destroy each connection on shutdown.
- *
- * @param cls Closure (unused).
- * @param key Current key code (CID, unused).
- * @param value Value in the hash map (`struct CadetConnection`)
- *
- * @return #GNUNET_YES, because we should continue to iterate
- */
-static int
-shutdown_iterator (void *cls,
-                   const struct GNUNET_ShortHashCode *key,
-                   void *value)
-{
-  struct CadetConnection *c = value;
-
-  c->state = CADET_CONNECTION_DESTROYED;
-  GCC_destroy (c);
-  return GNUNET_YES;
-}
-
 
 /**
- * Shut down the connections subsystem.
+ * Destroy a connection, called when the CORE layer is already done
+ * (i.e. has received a BROKEN message), but if we still have to
+ * communicate the destruction of the connection to the tunnel (if one
+ * exists).
+ *
+ * @param cc connection to destroy
  */
 void
-GCC_shutdown (void)
+GCC_destroy_without_core (struct CadetConnection *cc)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connections\n");
-  GCC_check_connections ();
-  GNUNET_CONTAINER_multishortmap_iterate (connections,
-                                          &shutdown_iterator,
-                                          NULL);
-  GNUNET_CONTAINER_multishortmap_destroy (connections);
-  connections = NULL;
-}
-
-
-/**
- * Create a connection.
- *
- * @param cid Connection ID (either created locally or imposed remotely).
- * @param t Tunnel this connection belongs to (or NULL for transit connections);
- * @param path Path this connection has to use (copy is made).
- * @param own_pos Own position in the @c path path.
- *
- * @return Newly created connection.
- *         NULL in case of error: own id not in path, wrong neighbors, ...
-*/
-struct CadetConnection *
-GCC_new (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-         struct CadetTunnel *t,
-         struct CadetPeerPath *path,
-         unsigned int own_pos)
-{
-  struct CadetConnection *c;
-  struct CadetPeerPath *cpath;
-
-  GCC_check_connections ();
-  cpath = path_duplicate (path);
-  GNUNET_assert (NULL != cpath);
-  c = GNUNET_new (struct CadetConnection);
-  c->id = *cid;
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multishortmap_put (connections,
-                                                     &c->id.connection_of_tunnel,
-                                                     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 <= cpath->length - 1);
-  c->own_pos = own_pos;
-  c->path = cpath;
-  cpath->c = c;
-  if (GNUNET_OK != register_neighbors (c))
+  if (NULL != cc->ct)
   {
-    if (0 == own_pos)
-    {
-      /* We were the origin of this request, this means we have invalid
-       * info about the paths to reach the destination. We must invalidate
-       * the *original* path to avoid trying it again in the next minute.
-       */
-      if (2 < path->length)
-        path_invalidate (path);
-      else
-      {
-        GNUNET_break (0);
-        GCT_debug(t, GNUNET_ERROR_TYPE_WARNING);
-      }
-      c->t = NULL;
-    }
-    path_destroy (c->path);
-    c->path = NULL;
-    GCC_destroy (c);
-    return NULL;
+    GCT_connection_lost (cc->ct);
+    cc->ct = NULL;
   }
-  LOG (GNUNET_ERROR_TYPE_INFO, "New connection %s\n", GCC_2s (c));
-  GCC_check_connections ();
-  return c;
+  GCC_destroy (cc);
 }
 
 
 /**
- * Connection is no longer needed: destroy it.
+ * Destroy a connection, called if the tunnel association with the
+ * connection was already broken, but we still need to notify the CORE
+ * layer about the breakage.
  *
- * 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.
+ * @param cc connection to destroy
  */
 void
-GCC_destroy (struct CadetConnection *c)
+GCC_destroy_without_tunnel (struct CadetConnection *cc)
 {
-  GCC_check_connections ();
-  if (NULL == c)
+  cc->ct = NULL;
+  if ( (CADET_CONNECTION_SENDING_CREATE != cc->state) &&
+       (NULL != cc->mq_man) )
   {
-    GNUNET_break (0);
-    return;
-  }
-
-  if (2 == c->destroy) /* cancel queues -> GCP_queue_cancel -> q_destroy -> */
-    return;            /* -> message_sent -> GCC_destroy. Don't loop. */
-  c->destroy = 2;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "destroying connection %s\n",
-       GCC_2s (c));
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " fc's f: %p, b: %p\n",
-       &c->fwd_fc, &c->bck_fc);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " fc tasks f: %u, b: %u\n",
-       c->fwd_fc.poll_task,
-       c->bck_fc.poll_task);
+    struct GNUNET_MQ_Envelope *env;
+    struct GNUNET_CADET_ConnectionDestroyMessage *destroy_msg;
 
-  /* Cancel all traffic */
-  if (NULL != c->path)
-  {
-    connection_cancel_queues (c, GNUNET_YES);
-    connection_cancel_queues (c, GNUNET_NO);
-    if (NULL != c->maintenance_q)
-    {
-      GCP_send_cancel (c->maintenance_q);
-      c->maintenance_q = NULL;
-    }
-  }
-  unregister_neighbors (c);
-  path_destroy (c->path);
-  c->path = NULL;
-
-  /* Delete from tunnel */
-  if (NULL != c->t)
-    GCT_remove_connection (c->t, c);
-
-  if (NULL != c->check_duplicates_task)
-    GNUNET_SCHEDULER_cancel (c->check_duplicates_task);
-  if (NULL != c->fwd_maintenance_task)
-    GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
-  if (NULL != c->bck_maintenance_task)
-    GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
-
-  if (GNUNET_NO == c->was_removed)
-  {
-    GNUNET_break (GNUNET_YES ==
-                  GNUNET_CONTAINER_multishortmap_remove (connections,
-                                                         &c->id.connection_of_tunnel,
-                                                         c));
+    /* Need to notify next hop that we are down. */
+    env = GNUNET_MQ_msg (destroy_msg,
+                         GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
+    destroy_msg->cid = cc->cid;
+    GCP_request_mq_cancel (cc->mq_man,
+                           env);
+    cc->mq_man = NULL;
   }
-  GNUNET_STATISTICS_update (stats,
-                            "# connections",
-                            -1,
-                            GNUNET_NO);
-  GNUNET_free (c);
-  GCC_check_connections ();
+  GCC_destroy (cc);
 }
 
 
 /**
- * Get the connection ID.
- *
- * @param c Connection to get the ID from.
+ * Return the tunnel associated with this connection.
  *
- * @return ID of the connection.
+ * @param cc connection to query
+ * @return corresponding entry in the tunnel's connection list
  */
-const struct GNUNET_CADET_ConnectionTunnelIdentifier *
-GCC_get_id (const struct CadetConnection *c)
+struct CadetTConnection *
+GCC_get_ct (struct CadetConnection *cc)
 {
-  return &c->id;
+  return cc->ct;
 }
 
 
 /**
- * Get the connection path.
- *
- * @param c Connection to get the path from.
+ * Obtain performance @a metrics from @a cc.
  *
- * @return path used by the connection.
+ * @param cc connection to query
+ * @return the metrics
  */
-const struct CadetPeerPath *
-GCC_get_path (const struct CadetConnection *c)
+const struct CadetConnectionMetrics *
+GCC_get_metrics (struct CadetConnection *cc)
 {
-  if (GNUNET_NO == c->destroy)
-    return c->path;
-  return NULL;
+  return &cc->metrics;
 }
 
 
 /**
- * Get the connection state.
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
+ * tunnel to prevent it from timing out.
  *
- * @param c Connection to get the state from.
- *
- * @return state of the connection.
- */
-enum CadetConnectionState
-GCC_get_state (const struct CadetConnection *c)
-{
-  return c->state;
-}
-
-/**
- * Get the connection tunnel.
- *
- * @param c Connection to get the tunnel from.
- *
- * @return tunnel of the connection.
+ * @param cls the `struct CadetConnection` to keep alive.
  */
-struct CadetTunnel *
-GCC_get_tunnel (const struct CadetConnection *c)
-{
-  return c->t;
-}
+static void
+send_keepalive (void *cls);
 
 
 /**
- * Get free buffer space in a connection.
+ * Keepalive was transmitted.  Remember this, and possibly
+ * schedule the next one.
  *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Free buffer space [0 - max_msgs_queue/max_connections]
+ * @param cls the `struct CadetConnection` to keep alive.
+ * @param cid identifier of the connection within the tunnel, NULL
+ *            if transmission failed
  */
-unsigned int
-GCC_get_buffer (struct CadetConnection *c, int fwd)
+static void
+keepalive_done (void *cls,
+                const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
 {
-  struct CadetFlowControl *fc;
-
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  Get %s buffer on %s: %u - %u\n",
-       GC_f2s (fwd), GCC_2s (c), fc->queue_max, fc->queue_n);
-  GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG);
+  struct CadetConnection *cc = cls;
 
-  return (fc->queue_max - fc->queue_n);
+  cc->keepalive_qe = NULL;
+  if ( (GNUNET_YES == cc->mqm_ready) &&
+       (NULL == cc->task) )
+    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                             &send_keepalive,
+                                             cc);
 }
 
 
 /**
- * Get how many messages have we allowed to send to us from a direction.
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE through the
+ * tunnel to prevent it from timing out.
  *
- * @param c Connection.
- * @param fwd Are we asking about traffic from FWD (BCK messages)?
- *
- * @return last_ack_sent - last_pid_recv
+ * @param cls the `struct CadetConnection` to keep alive.
  */
-unsigned int
-GCC_get_allowed (struct CadetConnection *c, int fwd)
+static void
+send_keepalive (void *cls)
 {
-  struct CadetFlowControl *fc;
+  struct CadetConnection *cc = cls;
+  struct GNUNET_MessageHeader msg;
 
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  if ( (CADET_CONNECTION_READY != c->state) ||
-       GC_is_pid_bigger (ntohl (fc->last_pid_recv.pid),
-                        ntohl (fc->last_ack_sent.pid)) )
+  cc->task = NULL;
+  if (CADET_TUNNEL_KEY_OK != GCT_get_estate (cc->ct->t))
   {
-    return 0;
+    /* Tunnel not yet ready, wait with keepalives... */
+    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                             &send_keepalive,
+                                             cc);
+    return;
   }
-  return (ntohl (fc->last_ack_sent.pid) - ntohl (fc->last_pid_recv.pid));
+  GNUNET_assert (NULL != cc->ct);
+  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+  GNUNET_assert (NULL == cc->keepalive_qe);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Sending KEEPALIVE on behalf of %s via %s\n",
+       GCC_2s (cc),
+       GCT_2s (cc->ct->t));
+  GNUNET_STATISTICS_update (stats,
+                            "# keepalives sent",
+                            1,
+                            GNUNET_NO);
+  msg.size = htons (sizeof (msg));
+  msg.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE);
+
+  cc->keepalive_qe
+    = GCT_send (cc->ct->t,
+                &msg,
+                &keepalive_done,
+                cc);
 }
 
 
 /**
- * Get messages queued in a connection.
+ * We sent a message for which we expect to receive an ACK via
+ * the connection identified by @a cti.
  *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Number of messages queued.
+ * @param cid connection identifier where we expect an ACK
  */
-unsigned int
-GCC_get_qn (struct CadetConnection *c, int fwd)
+void
+GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
 {
-  struct CadetFlowControl *fc;
+  struct CadetConnection *cc;
 
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-
-  return fc->queue_n;
+  cc = GCC_lookup (cid);
+  if (NULL == cc)
+    return; /* whopise, connection alredy down? */
+  cc->metrics.num_acked_transmissions++;
 }
 
 
 /**
- * Get next PID to use.
+ * We observed an ACK for a message that was originally sent via
+ * the connection identified by @a cti.
  *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- * @return Next PID to use.
+ * @param cti connection identifier where we got an ACK for a message
+ *            that was originally sent via this connection (the ACK
+ *            may have gotten back to us via a different connection).
  */
-struct CadetEncryptedMessageIdentifier
-GCC_get_pid (struct CadetConnection *c, int fwd)
+void
+GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
 {
-  struct CadetFlowControl *fc;
-  struct CadetEncryptedMessageIdentifier pid;
+  struct CadetConnection *cc;
 
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  pid = fc->next_pid;
-  fc->next_pid.pid = htonl (1 + ntohl (pid.pid));
-  return pid;
+  cc = GCC_lookup (cid);
+  if (NULL == cc)
+    return; /* whopise, connection alredy down? */
+  cc->metrics.num_successes++;
 }
 
 
 /**
- * Allow the connection to advertise a buffer of the given size.
+ * We observed some the given @a latency on the connection
+ * identified by @a cti.  (The same connection was taken
+ * in both directions.)
  *
- * 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).
+ * @param cid connection identifier where we measured latency
+ * @param latency the observed latency
  */
 void
-GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd)
+GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                      struct GNUNET_TIME_Relative latency)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  allowing %s %u messages %s\n",
-       GCC_2s (c), buffer, GC_f2s (fwd));
-  send_ack (c, buffer, fwd, GNUNET_NO);
+  struct CadetConnection *cc;
+  double weight;
+  double result;
+
+  cc = GCC_lookup (cid);
+  if (NULL == cc)
+    return; /* whopise, connection alredy down? */
+  GNUNET_STATISTICS_update (stats,
+                            "# latencies observed",
+                            1,
+                            GNUNET_NO);
+  cc->latency_datapoints++;
+  if (cc->latency_datapoints >= 7)
+    weight = 7.0;
+  else
+    weight = cc->latency_datapoints;
+  /* Compute weighted average, giving at MOST weight 7 to the
+     existing values, or less if that value is based on fewer than 7
+     measurements. */
+  result = (weight * cc->metrics.aged_latency.rel_value_us) + 1.0 * latency.rel_value_us;
+  result /= (weight + 1.0);
+  cc->metrics.aged_latency.rel_value_us = (uint64_t) result;
 }
 
 
 /**
- * Notify other peers on a connection of a broken link. Mark connections
- * to destroy after all traffic has been sent.
+ * A #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK was received for this connection, implying
+ * that the end-to-end connection is up.  Process it.
  *
- * @param c Connection on which there has been a disconnection.
- * @param peer Peer that disconnected.
+ * @param cc the connection that got the ACK.
  */
 void
-GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer)
+GCC_handle_connection_create_ack (struct CadetConnection *cc)
 {
-  struct CadetFlowControl *fc;
-  char peer_name[16];
-  int fwd;
-
-  GCC_check_connections ();
-  strncpy (peer_name, GCP_2s (peer), 16);
-  peer_name[15] = '\0';
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "shutting down %s, %s disconnected\n",
-       GCC_2s (c), peer_name);
-
-  invalidate_paths (c, peer);
-
-  fwd = is_fwd (c, peer);
-  if (GNUNET_SYSERR == fwd)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if ( (GNUNET_YES == GCC_is_terminal (c, fwd)) ||
-       (GNUNET_NO != c->destroy) )
+       "Received CADET_CONNECTION_CREATE_ACK for %s in state %d (%s)\n",
+       GCC_2s (cc),
+       cc->state,
+       (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
+  if (CADET_CONNECTION_READY == cc->state)
+    return; /* Duplicate ACK, ignore */
+  if (NULL != cc->task)
   {
-    /* Local shutdown, or other peer already down (hence 'c->destroy');
-       so there is no one to notify about this, just clean up. */
-    GCC_destroy (c);
-    GCC_check_connections ();
-    return;
+    GNUNET_SCHEDULER_cancel (cc->task);
+    cc->task = NULL;
   }
-  /* Mark FlowControl towards the peer as unavaliable. */
-  fc = fwd ? &c->bck_fc : &c->fwd_fc;
-  fc->queue_max = 0;
-
-  send_broken (c, &my_full_id, GCP_get_id (peer), fwd);
-
-  /* Connection will have at least one pending message
-   * (the one we just scheduled), so delay destruction
-   * and remove from map so we don't use accidentally. */
-  mark_destroyed (c);
-  GNUNET_assert (GNUNET_NO == c->was_removed);
-  c->was_removed = GNUNET_YES;
-  GNUNET_break (GNUNET_YES ==
-                GNUNET_CONTAINER_multishortmap_remove (connections,
-                                                       &c->id.connection_of_tunnel,
-                                                       c));
-  /* Cancel queue in the direction that just died. */
-  connection_cancel_queues (c, ! fwd);
-  GCC_stop_poll (c, ! fwd);
-  unregister_neighbors (c);
-  GCC_check_connections ();
+  cc->metrics.age = GNUNET_TIME_absolute_get ();
+  update_state (cc,
+                CADET_CONNECTION_READY,
+                cc->mqm_ready);
+  if ( (NULL == cc->keepalive_qe) &&
+       (GNUNET_YES == cc->mqm_ready) &&
+       (NULL == cc->task) )
+    cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                             &send_keepalive,
+                                             cc);
 }
 
 
 /**
- * Is this peer the first one on the connection?
+ * Handle KX message.
  *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- *
- * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal.
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
  */
-int
-GCC_is_origin (struct CadetConnection *c, int fwd)
+void
+GCC_handle_kx (struct CadetConnection *cc,
+               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
 {
-  if (!fwd && c->path->length - 1 == c->own_pos )
-    return GNUNET_YES;
-  if (fwd && 0 == c->own_pos)
-    return GNUNET_YES;
-  return GNUNET_NO;
+  if (CADET_CONNECTION_SENT == cc->state)
+  {
+    /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
+       clearly something is working, so pretend we got an ACK. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
+         GCC_2s (cc));
+    GCC_handle_connection_create_ack (cc);
+  }
+  GCT_handle_kx (cc->ct,
+                 msg);
 }
 
 
 /**
- * Is this peer the last one on the connection?
+ * Handle KX_AUTH message.
  *
- * @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.
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
  */
-int
-GCC_is_terminal (struct CadetConnection *c, int fwd)
+void
+GCC_handle_kx_auth (struct CadetConnection *cc,
+                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
 {
-  return GCC_is_origin (c, ! fwd);
+  if (CADET_CONNECTION_SENT == cc->state)
+  {
+    /* We didn't get the CADET_CONNECTION_CREATE_ACK, but instead got payload. That's fine,
+       clearly something is working, so pretend we got an ACK. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Faking connection CADET_CONNECTION_CREATE_ACK for %s due to KX\n",
+         GCC_2s (cc));
+    GCC_handle_connection_create_ack (cc);
+  }
+  GCT_handle_kx_auth (cc->ct,
+                      msg);
 }
 
 
 /**
- * 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?
+ * Handle encrypted message.
  *
- * @return #GNUNET_YES in case it's OK to send.
+ * @param cc connection that received encrypted message
+ * @param msg the encrypted message to decrypt
  */
-int
-GCC_is_sendable (struct CadetConnection *c, int fwd)
+void
+GCC_handle_encrypted (struct CadetConnection *cc,
+                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
 {
-  struct CadetFlowControl *fc;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " checking sendability of %s traffic on %s\n",
-       GC_f2s (fwd), GCC_2s (c));
-  if (NULL == c)
-  {
-    GNUNET_break (0);
-    return GNUNET_YES;
-  }
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " last ack recv: %u, last pid sent: %u\n",
-       ntohl (fc->last_ack_recv.pid),
-       ntohl (fc->last_pid_sent.pid));
-  if (GC_is_pid_bigger (ntohl (fc->last_ack_recv.pid),
-                        ntohl (fc->last_pid_sent.pid)))
+  if (CADET_CONNECTION_SENT == cc->state)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable\n");
-    return GNUNET_YES;
+    /* We didn't get the CREATE_ACK, but instead got payload. That's fine,
+       clearly something is working, so pretend we got an ACK. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Faking connection ACK for %s due to ENCRYPTED payload\n",
+         GCC_2s (cc));
+    GCC_handle_connection_create_ack (cc);
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n");
-  return GNUNET_NO;
+  cc->metrics.last_use = GNUNET_TIME_absolute_get ();
+  GCT_handle_encrypted (cc->ct,
+                        msg);
 }
 
 
 /**
- * Check if this connection is a direct one (never trim a direct connection).
+ * Send a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE message to the
+ * first hop.
  *
- * @param c Connection.
- *
- * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise.
+ * @param cls the `struct CadetConnection` to initiate
  */
-int
-GCC_is_direct (struct CadetConnection *c)
-{
-  return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO;
+static void
+send_create (void *cls)
+{
+  struct CadetConnection *cc = cls;
+  struct GNUNET_CADET_ConnectionCreateMessage *create_msg;
+  struct GNUNET_PeerIdentity *pids;
+  struct GNUNET_MQ_Envelope *env;
+  unsigned int path_length;
+
+  cc->task = NULL;
+  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+  path_length = GCPP_get_length (cc->path);
+  env = GNUNET_MQ_msg_extra (create_msg,
+                             (1 + path_length) * sizeof (struct GNUNET_PeerIdentity),
+                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
+  create_msg->options = htonl ((uint32_t) cc->options);
+  create_msg->cid = cc->cid;
+  pids = (struct GNUNET_PeerIdentity *) &create_msg[1];
+  pids[0] = my_full_id;
+  for (unsigned int i=0;i<path_length;i++)
+    pids[i + 1] = *GCP_get_id (GCPP_get_peer_at_offset (cc->path,
+                                                        i));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending CADET_CONNECTION_CREATE message for %s\n",
+       GCC_2s (cc));
+  cc->env = env;
+  update_state (cc,
+                CADET_CONNECTION_SENT,
+                GNUNET_NO);
+  GCP_send (cc->mq_man,
+            env);
 }
 
 
 /**
- * Sends a completely built message on a connection, properly registering
- * all used resources.
+ * Send a CREATE_ACK message towards the origin.
  *
- * @param message Message to send.
- * @param payload_type Type of payload, in case the message is encrypted.
- *                     0 for restransmissions (when type is no longer known)
- *                     UINT16_MAX when not applicable.
- * @param payload_id ID of the payload (PID, ACK, ...).
- * @param c Connection on which this message is transmitted.
- * @param fwd Is this a fwd message?
- * @param force Force the connection to accept the message (buffer overfill).
- * @param cont Continuation called once message is sent. Can be NULL.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel the message before it's sent.
- *         NULL on error.
- *         Invalid on @c cont call.
+ * @param cls the `struct CadetConnection` to initiate
  */
-struct CadetConnectionQueue *
-GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
-                           uint16_t payload_type,
-                           struct CadetEncryptedMessageIdentifier payload_id,
-                           struct CadetConnection *c, int fwd, int force,
-                           GCC_sent cont, void *cont_cls)
+static void
+send_create_ack (void *cls)
 {
-  struct CadetFlowControl *fc;
-  struct CadetConnectionQueue *q;
-  uint16_t size;
-  uint16_t type;
-
-  size = ntohs (message->size);
-  type = ntohs (message->type);
-
-  GCC_check_connections ();
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  if (0 == fc->queue_max)
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "--> %s (%s %4u) on conn %s (%p) %s [%5u]\n",
-       GC_m2s (type), GC_m2s (payload_type), payload_id, GCC_2s (c), c,
-       GC_f2s(fwd), size);
-  switch (type)
-  {
-    case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED:
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "  Q_N+ %p %u, PIDsnt: %u, ACKrcv: %u\n",
-           fc,
-           fc->queue_n,
-           ntohl (fc->last_pid_sent.pid),
-           ntohl (fc->last_ack_recv.pid));
-      if (GNUNET_NO == force)
-      {
-        fc->queue_n++;
-      }
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX:
-      /* nothing to do here */
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE:
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK:
-       /* Should've only be used for restransmissions. */
-      GNUNET_break (0 == payload_type);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK:
-    case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL:
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
-    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
-      GNUNET_assert (GNUNET_YES == force);
-      break;
-
-    default:
-      GNUNET_break (0);
-      return NULL;
-  }
-
-  if (fc->queue_n > fc->queue_max && GNUNET_NO == force)
-  {
-    GNUNET_STATISTICS_update (stats, "# messages dropped (buffer full)",
-                              1, GNUNET_NO);
-    GNUNET_break (0);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "queue full: %u/%u\n",
-         fc->queue_n, fc->queue_max);
-    if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == type)
-    {
-      fc->queue_n--;
-    }
-    return NULL; /* Drop this message */
-  }
+  struct CadetConnection *cc = cls;
+  struct GNUNET_CADET_ConnectionCreateAckMessage *ack_msg;
+  struct GNUNET_MQ_Envelope *env;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  C_P+ %s %u\n",
-       GCC_2s (c), c->pending_messages);
-  c->pending_messages++;
-
-  q = GNUNET_new (struct CadetConnectionQueue);
-  q->cont = cont;
-  q->cont_cls = cont_cls;
-  q->forced = force;
-  GNUNET_CONTAINER_DLL_insert (fc->q_head, fc->q_tail, q);
-  q->peer_q = GCP_send (get_hop (c, fwd),
-                        message,
-                        payload_type,
-                        payload_id,
-                        c,
-                        fwd,
-                        &conn_message_sent, q);
-  if (NULL == q->peer_q)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "dropping msg on %s, NULL q\n", GCC_2s (c));
-    GNUNET_CONTAINER_DLL_remove (fc->q_head, fc->q_tail, q);
-    GNUNET_free (q);
-    GCC_check_connections ();
-    return NULL;
-  }
-  GCC_check_connections ();
-  return q;
+  cc->task = NULL;
+  GNUNET_assert (CADET_CONNECTION_CREATE_RECEIVED == cc->state);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending CONNECTION_CREATE_ACK message for %s\n",
+       GCC_2s (cc));
+  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+  env = GNUNET_MQ_msg (ack_msg,
+                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK);
+  ack_msg->cid = cc->cid;
+  cc->env = env;
+  update_state (cc,
+                CADET_CONNECTION_READY,
+                GNUNET_NO);
+  GCP_send (cc->mq_man,
+            env);
 }
 
 
 /**
- * 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.
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
+ * connection that we already have.  Either our ACK got lost
+ * or something is fishy.  Consider retransmitting the ACK.
  *
- * @param q Handle to the queue.
+ * @param cc connection that got the duplicate CREATE
  */
 void
-GCC_cancel (struct CadetConnectionQueue *q)
+GCC_handle_duplicate_create (struct CadetConnection *cc)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "!  GCC cancel message\n");
-
-  /* send_cancel calls message_sent, which calls q->cont and frees q */
-  GCP_send_cancel (q->peer_q);
-  GCC_check_connections ();
+  if (GNUNET_YES == cc->mqm_ready)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got duplicate CREATE for %s, scheduling another ACK (%s)\n",
+         GCC_2s (cc),
+         (GNUNET_YES == cc->mqm_ready) ? "MQM ready" : "MQM busy");
+    /* Revert back to the state of having only received the 'CREATE',
+       and immediately proceed to send the CREATE_ACK. */
+    update_state (cc,
+                  CADET_CONNECTION_CREATE_RECEIVED,
+                  cc->mqm_ready);
+    if (NULL != cc->task)
+      GNUNET_SCHEDULER_cancel (cc->task);
+    cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
+                                         cc);
+  }
+  else
+  {
+    /* We are currently sending something else back, which
+       can only be an ACK or payload, either of which would
+       do. So actually no need to do anything. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got duplicate CREATE for %s. MQ is busy, not queueing another ACK\n",
+         GCC_2s (cc));
+  }
 }
 
 
 /**
- * Sends a CREATE CONNECTION message for a path to a peer.
- * Changes the connection and tunnel states if necessary.
+ * There has been a change in the message queue existence for our
+ * peer at the first hop.  Adjust accordingly.
  *
- * @param c Connection to create.
+ * @param cls the `struct CadetConnection`
+ * @param available #GNUNET_YES if sending is now possible,
+ *                  #GNUNET_NO if sending is no longer possible
+ *                  #GNUNET_SYSERR if sending is no longer possible
+ *                                 and the last envelope was discarded
  */
-void
-GCC_send_create (struct CadetConnection *c)
+static void
+manage_first_hop_mq (void *cls,
+                     int available)
 {
-  static struct CadetEncryptedMessageIdentifier zero;
-  enum CadetTunnelCState state;
-  size_t size;
+  struct CadetConnection *cc = cls;
 
-  GCC_check_connections ();
-  size = sizeof (struct GNUNET_CADET_ConnectionCreateMessage);
-  size += c->path->length * sizeof (struct GNUNET_PeerIdentity);
+  if (GNUNET_YES != available)
   {
-    /* Allocate message on the stack */
-    unsigned char cbuf[size];
-    struct GNUNET_CADET_ConnectionCreateMessage *msg;
-    struct GNUNET_PeerIdentity *peers;
-
-
-    msg = (struct GNUNET_CADET_ConnectionCreateMessage *) cbuf;
-    msg->header.size = htons (size);
-    msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE);
-    msg->options = htonl (0);
-    msg->cid = *GCC_get_id (c);
-    peers = (struct GNUNET_PeerIdentity *) &msg[1];
-    for (int i = 0; i < c->path->length; i++)
+    /* Connection is down, for now... */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Core MQ for %s went down\n",
+         GCC_2s (cc));
+    update_state (cc,
+                  CADET_CONNECTION_NEW,
+                  GNUNET_NO);
+    cc->retry_delay = GNUNET_TIME_UNIT_ZERO;
+    if (NULL != cc->task)
     {
-      GNUNET_PEER_resolve (c->path->peers[i], peers++);
+      GNUNET_SCHEDULER_cancel (cc->task);
+      cc->task = NULL;
     }
-    GNUNET_assert (NULL == c->maintenance_q);
-    c->maintenance_q = GCP_send (get_next_hop (c),
-                                 &msg->header,
-                                 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
-                                 zero,
-                                 c, GNUNET_YES,
-                                 &conn_message_sent, NULL);
+    return;
   }
 
-  LOG (GNUNET_ERROR_TYPE_INFO, "==> %s %19s on conn %s (%p) FWD [%5u]\n",
-       GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE), "",
-       GCC_2s (c), c, size);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  C_P+ %p %u (create)\n",
-         c, c->pending_messages);
-  c->pending_messages++;
-
-  state = GCT_get_cstate (c->t);
-  if (CADET_TUNNEL_SEARCHING == state || CADET_TUNNEL_NEW == state)
-    GCT_change_cstate (c->t, CADET_TUNNEL_WAITING);
-  if (CADET_CONNECTION_NEW == c->state)
-    connection_change_state (c, CADET_CONNECTION_SENT);
-  GCC_check_connections ();
+  update_state (cc,
+                cc->state,
+                GNUNET_YES);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Core MQ for %s became available in state %d\n",
+       GCC_2s (cc),
+       cc->state);
+  switch (cc->state)
+  {
+  case CADET_CONNECTION_NEW:
+    /* Transmit immediately */
+    cc->task = GNUNET_SCHEDULER_add_now (&send_create,
+                                         cc);
+    break;
+  case CADET_CONNECTION_SENDING_CREATE:
+    /* Should not be possible to be called in this state. */
+    GNUNET_assert (0);
+    break;
+  case CADET_CONNECTION_SENT:
+    /* Retry a bit later... */
+    cc->retry_delay = GNUNET_TIME_STD_BACKOFF (cc->retry_delay);
+    cc->task = GNUNET_SCHEDULER_add_delayed (cc->retry_delay,
+                                             &send_create,
+                                             cc);
+    break;
+  case CADET_CONNECTION_CREATE_RECEIVED:
+    /* We got the 'CREATE' (incoming connection), should send the CREATE_ACK */
+    cc->metrics.age = GNUNET_TIME_absolute_get ();
+    cc->task = GNUNET_SCHEDULER_add_now (&send_create_ack,
+                                         cc);
+    break;
+  case CADET_CONNECTION_READY:
+    if ( (NULL == cc->keepalive_qe) &&
+         (GNUNET_YES == cc->mqm_ready) &&
+         (NULL == cc->task) )
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Scheduling keepalive for %s in %s\n",
+           GCC_2s (cc),
+           GNUNET_STRINGS_relative_time_to_string (keepalive_period,
+                                                   GNUNET_YES));
+      cc->task = GNUNET_SCHEDULER_add_delayed (keepalive_period,
+                                               &send_keepalive,
+                                               cc);
+    }
+    break;
+  }
 }
 
 
 /**
- * Send an ACK on the appropriate connection/channel, depending on
- * the direction and the position of the peer.
+ * Create a connection to @a destination via @a path and notify @a cb
+ * whenever we are ready for more data.  Shared logic independent of
+ * who is initiating the connection.
  *
- * @param c Which connection to send the hop-by-hop ACK.
- * @param fwd Is this a fwd ACK? (will go dest->root).
- * @param force Send the ACK even if suboptimal (e.g. requested by POLL).
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param off offset of @a destination on @a path
+ * @param options options for the connection
+ * @param ct which tunnel uses this connection
+ * @param init_state initial state for the connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection
  */
-void
-GCC_send_ack (struct CadetConnection *c, int fwd, int force)
-{
-  unsigned int buffer;
-
-  GCC_check_connections ();
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "GCC send %s ACK on %s\n",
-       GC_f2s (fwd), GCC_2s (c));
-
-  if (NULL == c)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  if (GNUNET_NO != c->destroy)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  being destroyed, why bother...\n");
-    GCC_check_connections ();
-    return;
-  }
-
-  /* Get available buffer space */
-  if (GCC_is_terminal (c, fwd))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  getting from all channels\n");
-    buffer = GCT_get_channels_buffer (c->t);
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  getting from one connection\n");
-    buffer = GCC_get_buffer (c, fwd);
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  buffer available: %u\n", buffer);
-  if (0 == buffer && GNUNET_NO == force)
-  {
-    GCC_check_connections ();
-    return;
+static struct CadetConnection *
+connection_create (struct CadetPeer *destination,
+                   struct CadetPeerPath *path,
+                   unsigned int off,
+                   enum GNUNET_CADET_ChannelOption options,
+                   struct CadetTConnection *ct,
+                   const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                   enum CadetConnectionState init_state,
+                   GCC_ReadyCallback ready_cb,
+                   void *ready_cb_cls)
+{
+  struct CadetConnection *cc;
+  struct CadetPeer *first_hop;
+
+  cc = GNUNET_new (struct CadetConnection);
+  cc->options = options;
+  cc->state = init_state;
+  cc->ct = ct;
+  cc->cid = *cid;
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multishortmap_put (connections,
+                                                     &GCC_get_id (cc)->connection_of_tunnel,
+                                                     cc,
+                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  cc->ready_cb = ready_cb;
+  cc->ready_cb_cls = ready_cb_cls;
+  cc->path = path;
+  cc->off = off;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating %s using path %s\n",
+       GCC_2s (cc),
+       GCPP_2s (path));
+  GCPP_add_connection (path,
+                       off,
+                       cc);
+  for (unsigned int i=0;i<off;i++)
+    GCP_add_connection (GCPP_get_peer_at_offset (path,
+                                                 i),
+                        cc);
+
+  first_hop = GCPP_get_peer_at_offset (path,
+                                       0);
+  cc->mq_man = GCP_request_mq (first_hop,
+                               &manage_first_hop_mq,
+                               cc);
+  return cc;
+}
+
+
+/**
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.  This
+ * is an inbound tunnel, so we must use the existing @a cid
+ *
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param options options for the connection
+ * @param ct which tunnel uses this connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection, NULL if we already have
+ *         a connection that takes precedence on @a path
+ */
+struct CadetConnection *
+GCC_create_inbound (struct CadetPeer *destination,
+                    struct CadetPeerPath *path,
+                    enum GNUNET_CADET_ChannelOption options,
+                    struct CadetTConnection *ct,
+                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                    GCC_ReadyCallback ready_cb,
+                    void *ready_cb_cls)
+{
+  struct CadetConnection *cc;
+  unsigned int off;
+
+  off = GCPP_find_peer (path,
+                        destination);
+  GNUNET_assert (UINT_MAX != off);
+  cc = GCPP_get_connection (path,
+                            destination,
+                            off);
+  if (NULL != cc)
+  {
+    int cmp;
+
+    cmp = memcmp (cid,
+                  &cc->cid,
+                  sizeof (*cid));
+    if (0 == cmp)
+    {
+      /* Two peers picked the SAME random connection identifier at the
+         same time for the same path? Must be malicious.  Drop
+         connection (existing and inbound), even if it is the only
+         one. */
+      GNUNET_break_op (0);
+      GCT_connection_lost (cc->ct);
+      GCC_destroy_without_tunnel (cc);
+      return NULL;
+    }
+    if (0 < cmp)
+    {
+      /* drop existing */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got two connections on %s, dropping my existing %s\n",
+           GCPP_2s (path),
+           GCC_2s (cc));
+      GCT_connection_lost (cc->ct);
+      GCC_destroy_without_tunnel (cc);
+    }
+    else
+    {
+      /* keep existing */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got two connections on %s, keeping my existing %s\n",
+           GCPP_2s (path),
+           GCC_2s (cc));
+      return NULL;
+    }
   }
 
-  /* Send available buffer space */
-  if (GNUNET_YES == GCC_is_origin (c, fwd))
-  {
-    GNUNET_assert (NULL != c->t);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  sending on channels...\n");
-    GCT_unchoke_channels (c->t);
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  sending on connection\n");
-    send_ack (c, buffer, fwd, force);
-  }
-  GCC_check_connections ();
+  return connection_create (destination,
+                            path,
+                            off,
+                            options,
+                            ct,
+                            cid,
+                            CADET_CONNECTION_CREATE_RECEIVED,
+                            ready_cb,
+                            ready_cb_cls);
 }
 
 
 /**
- * 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.
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.
  *
- * @param c The connection whose peers to notify.
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param off offset of @a destination on @a path
+ * @param options options for the connection
+ * @param ct tunnel that uses the connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection
  */
-void
-GCC_send_destroy (struct CadetConnection *c)
+struct CadetConnection *
+GCC_create (struct CadetPeer *destination,
+            struct CadetPeerPath *path,
+            unsigned int off,
+            enum GNUNET_CADET_ChannelOption options,
+            struct CadetTConnection *ct,
+            GCC_ReadyCallback ready_cb,
+            void *ready_cb_cls)
 {
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct GNUNET_CADET_ConnectionDestroyMessage msg;
+  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
 
-  if (GNUNET_YES == c->destroy)
-    return;
-  GCC_check_connections ();
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY);
-  msg.cid = c->id;
-  msg.reserved = htonl (0);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-              "  sending connection destroy for connection %s\n",
-              GCC_2s (c));
-
-  if (GNUNET_NO == GCC_is_terminal (c, GNUNET_YES))
-    (void) GCC_send_prebuilt_message (&msg.header,
-                                      UINT16_MAX,
-                                      zero,
-                                      c,
-                                      GNUNET_YES, GNUNET_YES, NULL, NULL);
-  if (GNUNET_NO == GCC_is_terminal (c, GNUNET_NO))
-    (void) GCC_send_prebuilt_message (&msg.header,
-                                      UINT16_MAX,
-                                      zero,
-                                      c,
-                                      GNUNET_NO, GNUNET_YES, NULL, NULL);
-  mark_destroyed (c);
-  GCC_check_connections ();
+  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+                              &cid,
+                              sizeof (cid));
+  return connection_create (destination,
+                            path,
+                            off,
+                            options,
+                            ct,
+                            &cid,
+                            CADET_CONNECTION_NEW,
+                            ready_cb,
+                            ready_cb_cls);
 }
 
 
 /**
- * @brief Start a polling timer for the connection.
+ * Transmit message @a msg via connection @a cc.  Must only be called
+ * (once) after the connection has signalled that it is ready via the
+ * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
+ * connection is right now ready for transmission.
  *
- * When a neighbor does not accept more traffic on the connection it could be
- * caused by a simple congestion or by a lost ACK. Polling enables to check
- * for the lastest ACK status for a connection.
- *
- * @param c Connection.
- * @param fwd Should we poll in the FWD direction?
+ * @param cc connection identification
+ * @param env envelope with message to transmit; must NOT
+ *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
  */
 void
-GCC_start_poll (struct CadetConnection *c, int fwd)
+GCC_transmit (struct CadetConnection *cc,
+              struct GNUNET_MQ_Envelope *env)
 {
-  struct CadetFlowControl *fc;
-
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL %s requested\n",
-       GC_f2s (fwd));
-  if (NULL != fc->poll_task || NULL != fc->poll_msg)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  POLL already in progress (t: %p, m: %p)\n",
-         fc->poll_task, fc->poll_msg);
-    return;
-  }
-  if (0 == fc->queue_max)
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Scheduling message for transmission on %s\n",
+       GCC_2s (cc));
+  GNUNET_assert (GNUNET_YES == cc->mqm_ready);
+  GNUNET_assert (CADET_CONNECTION_READY == cc->state);
+  cc->metrics.last_use = GNUNET_TIME_absolute_get ();
+  cc->mqm_ready = GNUNET_NO;
+  if (NULL != cc->task)
   {
-    /* Should not be needed, traffic should've been cancelled. */
-    GNUNET_break (0);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  POLL not possible, peer disconnected\n");
-    return;
+    GNUNET_SCHEDULER_cancel (cc->task);
+    cc->task = NULL;
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL started on request\n");
-  fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, &send_poll, fc);
+  GCP_send (cc->mq_man,
+            env);
 }
 
 
 /**
- * @brief Stop polling a connection for ACKs.
- *
- * Once we have enough ACKs for future traffic, polls are no longer necessary.
+ * Obtain the path used by this connection.
  *
- * @param c Connection.
- * @param fwd Should we stop the poll in the FWD direction?
+ * @param cc connection
+ * @return path to @a cc
  */
-void
-GCC_stop_poll (struct CadetConnection *c, int fwd)
+struct CadetPeerPath *
+GCC_get_path (struct CadetConnection *cc)
 {
-  struct CadetFlowControl *fc;
+  return cc->path;
+}
 
-  fc = fwd ? &c->fwd_fc : &c->bck_fc;
-  if (NULL != fc->poll_task)
-  {
-    GNUNET_SCHEDULER_cancel (fc->poll_task);
-    fc->poll_task = NULL;
-  }
-  if (NULL != fc->poll_msg)
-  {
-    GCC_cancel (fc->poll_msg);
-    fc->poll_msg = NULL;
-  }
+
+/**
+ * Obtain unique ID for the connection.
+ *
+ * @param cc connection.
+ * @return unique number of the connection
+ */
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc)
+{
+  return &cc->cid;
 }
 
 
 /**
  * Get a (static) string for a connection.
  *
- * @param c Connection.
+ * @param cc Connection.
  */
 const char *
-GCC_2s (const struct CadetConnection *c)
+GCC_2s (const struct CadetConnection *cc)
 {
-  if (NULL == c)
-    return "NULL";
+  static char buf[128];
 
-  if (NULL != c->t)
-  {
-    static char buf[128];
+  if (NULL == cc)
+    return "Connection(NULL)";
 
-    SPRINTF (buf, "%s (->%s)",
-             GNUNET_sh2s (&GCC_get_id (c)->connection_of_tunnel),
-             GCT_2s (c->t));
+  if (NULL != cc->ct)
+  {
+    GNUNET_snprintf (buf,
+                     sizeof (buf),
+                     "Connection %s (%s)",
+                     GNUNET_sh2s (&cc->cid.connection_of_tunnel),
+                     GCT_2s (cc->ct->t));
     return buf;
   }
-  return GNUNET_sh2s (&c->id.connection_of_tunnel);
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "Connection %s",
+                   GNUNET_sh2s (&cc->cid.connection_of_tunnel));
+  return buf;
 }
 
 
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-con",__VA_ARGS__)
+
+
 /**
- * Log all possible info about the connection state.
+ * Log connection info.
  *
- * @param c Connection to debug.
+ * @param cc connection
  * @param level Debug level to use.
  */
 void
-GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level)
+GCC_debug (struct CadetConnection *cc,
+           enum GNUNET_ErrorType level)
 {
   int do_log;
-  char *s;
 
   do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
                                        "cadet-con",
                                        __FILE__, __FUNCTION__, __LINE__);
   if (0 == do_log)
     return;
-
-  if (NULL == c)
+  if (NULL == cc)
   {
-    LOG2 (level, "CCC DEBUG NULL CONNECTION\n");
+    LOG2 (level,
+          "Connection (NULL)\n");
     return;
   }
-
-  LOG2 (level, "CCC DEBUG CONNECTION %s\n", GCC_2s (c));
-  s = path_2s (c->path);
-  LOG2 (level, "CCC  path %s, own pos: %u\n", s, c->own_pos);
-  GNUNET_free (s);
-  LOG2 (level, "CCC  state: %s, destroy: %u\n",
-        GCC_state2s (c->state), c->destroy);
-  LOG2 (level, "CCC  pending messages: %u\n", c->pending_messages);
-  if (NULL != c->perf)
-    LOG2 (level, "CCC  us/byte: %f\n", c->perf->avg);
-
-  LOG2 (level, "CCC  FWD flow control:\n");
-  LOG2 (level, "CCC   queue: %u/%u\n", c->fwd_fc.queue_n, c->fwd_fc.queue_max);
-  LOG2 (level, "CCC   last PID sent: %5u, recv: %5u\n",
-        ntohl (c->fwd_fc.last_pid_sent.pid),
-        ntohl (c->fwd_fc.last_pid_recv.pid));
-  LOG2 (level, "CCC   last ACK sent: %5u, recv: %5u\n",
-        ntohl (c->fwd_fc.last_ack_sent.pid),
-        ntohl (c->fwd_fc.last_ack_recv.pid));
-  LOG2 (level, "CCC   recv PID bitmap: %X\n", c->fwd_fc.recv_bitmap);
-  LOG2 (level, "CCC   poll: task %d, msg  %p, msg_ack %p)\n",
-        c->fwd_fc.poll_task, c->fwd_fc.poll_msg, c->fwd_fc.ack_msg);
-
-  LOG2 (level, "CCC  BCK flow control:\n");
-  LOG2 (level, "CCC   queue: %u/%u\n", c->bck_fc.queue_n, c->bck_fc.queue_max);
-  LOG2 (level, "CCC   last PID sent: %5u, recv: %5u\n",
-        ntohl (c->bck_fc.last_pid_sent.pid),
-        ntohl (c->bck_fc.last_pid_recv.pid));
-  LOG2 (level, "CCC   last ACK sent: %5u, recv: %5u\n",
-        ntohl (c->bck_fc.last_ack_sent.pid),
-        ntohl (c->bck_fc.last_ack_recv.pid));
-  LOG2 (level, "CCC   recv PID bitmap: %X\n", c->bck_fc.recv_bitmap);
-  LOG2 (level, "CCC   poll: task %d, msg  %p, msg_ack %p)\n",
-        c->bck_fc.poll_task, c->bck_fc.poll_msg, c->bck_fc.ack_msg);
-
-  LOG2 (level, "CCC DEBUG CONNECTION END\n");
+  LOG2 (level,
+        "%s to %s via path %s in state %d is %s\n",
+        GCC_2s (cc),
+        GCP_2s (cc->destination),
+        GCPP_2s (cc->path),
+        cc->state,
+        (GNUNET_YES == cc->mqm_ready) ? "ready" : "busy");
 }
+
+/* end of gnunet-service-cadet-new_connection.c */
index 307cb42c2b7c5537b5d57f18cc2a1afcbafbd39f..fdb1843661e6ddd2861bcf7f3dff1d2e0dc104b9 100644 (file)
@@ -1,6 +1,7 @@
+
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
+     Copyright (C) 2001-2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
 /**
  * @file cadet/gnunet-service-cadet_connection.h
- * @brief cadet service; dealing with connections
+ * @brief A connection is a live end-to-end messaging mechanism
+ *       where the peers are identified by a path and know how
+ *       to forward along the route using a connection identifier
+ *       for routing the data.
  * @author Bartlomiej Polot
- *
- * All functions in this file use the prefix GCC (GNUnet Cadet Connection)
+ * @author Christian Grothoff
  */
-
 #ifndef GNUNET_SERVICE_CADET_CONNECTION_H
 #define GNUNET_SERVICE_CADET_CONNECTION_H
 
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
 #include "gnunet_util_lib.h"
-
-
-/**
- * All the states a connection can be in.
- */
-enum CadetConnectionState
-{
-  /**
-   * Uninitialized status, should never appear in operation.
-   */
-  CADET_CONNECTION_NEW,
-
-  /**
-   * Connection create message sent, waiting for ACK.
-   */
-  CADET_CONNECTION_SENT,
-
-  /**
-   * Connection ACK sent, waiting for ACK.
-   */
-  CADET_CONNECTION_ACK,
-
-  /**
-   * Connection confirmed, ready to carry traffic.
-   */
-  CADET_CONNECTION_READY,
-
-  /**
-   * Connection to be destroyed, just waiting to empty queues.
-   */
-  CADET_CONNECTION_DESTROYED,
-
-  /**
-   * Connection to be destroyed because of a distant peer, same as DESTROYED.
-   */
-  CADET_CONNECTION_BROKEN,
-};
-
-
-/**
- * Struct containing all information regarding a connection to a peer.
- */
-struct CadetConnection;
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetConnectionQueue;
-
-#include "cadet_path.h"
-#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet.h"
 #include "gnunet-service-cadet_peer.h"
+#include "cadet_protocol.h"
 
 
 /**
- * Check invariants for all connections using #check_neighbours().
- */
-void
-GCC_check_connections (void);
-
-
-/**
- * Callback called when a queued message is sent.
+ * Function called to notify tunnel about change in our readyness.
  *
- * @param cls Closure.
- * @param c Connection this message was on.
- * @param type Type of message sent.
- * @param fwd Was this a FWD going message?
- * @param size Size of the message.
+ * @param cls closure
+ * @param is_ready #GNUNET_YES if the connection is now ready for transmission,
+ *                 #GNUNET_NO if the connection is no longer ready for transmission
  */
 typedef void
-(*GCC_sent) (void *cls,
-             struct CadetConnection *c,
-             struct CadetConnectionQueue *q,
-             uint16_t type,
-             int fwd,
-             size_t size);
+(*GCC_ReadyCallback)(void *cls,
+                     int is_ready);
 
 
 /**
- * Handler for connection creation.
+ * Destroy a connection, called when the CORE layer is already done
+ * (i.e. has received a BROKEN message), but if we still have to
+ * communicate the destruction of the connection to the tunnel (if one
+ * exists).
  *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection to destroy
  */
 void
-GCC_handle_create (struct CadetPeer *peer,
-                   const struct GNUNET_CADET_ConnectionCreateMessage *msg);
+GCC_destroy_without_core (struct CadetConnection *cc);
 
 
 /**
- * Handler for connection confirmations.
+ * Destroy a connection, called if the tunnel association with the
+ * connection was already broken, but we still need to notify the CORE
+ * layer about the breakage.
  *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection to destroy
  */
 void
-GCC_handle_confirm (struct CadetPeer *peer,
-                    const struct GNUNET_CADET_ConnectionCreateAckMessage *msg);
+GCC_destroy_without_tunnel (struct CadetConnection *cc);
 
 
 /**
- * Handler for notifications of broken connections.
+ * Lookup a connection by its identifier.
  *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cid identifier to resolve
+ * @return NULL if connection was not found
  */
-void
-GCC_handle_broken (struct CadetPeer *peer,
-                   const struct GNUNET_CADET_ConnectionBrokenMessage *msg);
+struct CadetConnection *
+GCC_lookup (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
 
-/**
- * Handler for notifications of destroyed connections.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_destroy (struct CadetPeer *peer,
-                    const struct GNUNET_CADET_ConnectionDestroyMessage *msg);
 
 /**
- * Handler for cadet network traffic hop-by-hop acks.
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.
  *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param off offset of @a destination on @a path
+ * @param options options for the connection
+ * @param ct which tunnel uses this connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection
  */
-void
-GCC_handle_ack (struct CadetPeer *peer,
-                const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg);
+struct CadetConnection *
+GCC_create (struct CadetPeer *destination,
+            struct CadetPeerPath *path,
+            unsigned int off,
+            enum GNUNET_CADET_ChannelOption options,
+            struct CadetTConnection *ct,
+            GCC_ReadyCallback ready_cb,
+            void *ready_cb_cls);
 
-/**
- * Handler for cadet network traffic hop-by-hop data counter polls.
- *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
- */
-void
-GCC_handle_poll (struct CadetPeer *peer,
-                 const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg);
 
 /**
- * Handler for key exchange traffic (Axolotl KX).
+ * Create a connection to @a destination via @a path and
+ * notify @a cb whenever we are ready for more data.  This
+ * is an inbound tunnel, so we must use the existing @a cid
  *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param destination where to go
+ * @param path which path to take (may not be the full path)
+ * @param options options for the connection
+ * @param ct which tunnel uses this connection
+ * @param ready_cb function to call when ready to transmit
+ * @param ready_cb_cls closure for @a cb
+ * @return handle to the connection, NULL if we already have
+ *         a connection that takes precedence on @a path
  */
-void
-GCC_handle_kx (struct CadetPeer *peer,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
+struct CadetConnection *
+GCC_create_inbound (struct CadetPeer *destination,
+                    struct CadetPeerPath *path,
+                    enum GNUNET_CADET_ChannelOption options,
+                    struct CadetTConnection *ct,
+                    const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                    GCC_ReadyCallback ready_cb,
+                    void *ready_cb_cls);
+
 
 /**
- * Handler for encrypted cadet network traffic (channel mgmt, data).
+ * Transmit message @a msg via connection @a cc.  Must only be called
+ * (once) after the connection has signalled that it is ready via the
+ * `ready_cb`.  Clients can also use #GCC_is_ready() to check if the
+ * connection is right now ready for transmission.
  *
- * @param peer Message sender (neighbor).
- * @param msg Message itself.
+ * @param cc connection identification
+ * @param env envelope with message to transmit;
+ *            the #GNUNET_MQ_notify_send() must not have yet been used
+ *            for the envelope.  Also, the message better match the
+ *            connection identifier of this connection...
  */
 void
-GCC_handle_encrypted (struct CadetPeer *peer,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
+GCC_transmit (struct CadetConnection *cc,
+              struct GNUNET_MQ_Envelope *env);
 
-/**
- * Core handler for axolotl key exchange traffic.
- *
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Neighbor who sent the message.
- *
- * @return GNUNET_OK, to keep the connection open.
- */
-int
-GCC_handle_ax_kx (void *cls, const struct GNUNET_PeerIdentity *peer,
-                  const struct GNUNET_MessageHeader *message);
 
 /**
- * Core handler for axolotl encrypted cadet network traffic.
+ * A CREATE_ACK was received for this connection, process it.
  *
- * @param cls Closure (unused).
- * @param message Message received.
- * @param peer Neighbor who sent the message.
- *
- * @return GNUNET_OK, to keep the connection open.
+ * @param cc the connection that got the ACK.
  */
-int
-GCC_handle_ax (void *cls, const struct GNUNET_PeerIdentity *peer,
-               struct GNUNET_MessageHeader *message);
+void
+GCC_handle_connection_create_ack (struct CadetConnection *cc);
 
-/**
- * Core handler for cadet keepalives.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- * @return GNUNET_OK to keep the connection open,
- *         GNUNET_SYSERR to close it (signal serious error)
- *
- * TODO: Check who we got this from, to validate route.
- */
-int
-GCC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer,
-                      const struct GNUNET_MessageHeader *message);
 
 /**
- * Send an ACK on the appropriate connection/channel, depending on
- * the direction and the position of the peer.
+ * We got a #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE for a
+ * connection that we already have.  Either our ACK got lost
+ * or something is fishy.  Consider retransmitting the ACK.
  *
- * @param c Which connection to send the hop-by-hop ACK.
- * @param fwd Is this a fwd ACK? (will go dest->root).
- * @param force Send the ACK even if suboptimal (e.g. requested by POLL).
+ * @param cc connection that got the duplicate CREATE
  */
 void
-GCC_send_ack (struct CadetConnection *c, int fwd, int force);
+GCC_handle_duplicate_create (struct CadetConnection *cc);
 
-/**
- * Initialize the connections subsystem
- *
- * @param c Configuration handle.
- */
-void
-GCC_init (const struct GNUNET_CONFIGURATION_Handle *c);
 
 /**
- * Shut down the connections subsystem.
+ * Handle KX message.
+ *
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
  */
 void
-GCC_shutdown (void);
+GCC_handle_kx (struct CadetConnection *cc,
+               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
 
-/**
- * Create a connection.
- *
- * @param cid Connection ID (either created locally or imposed remotely).
- * @param t Tunnel this connection belongs to (or NULL for transit connections);
- * @param path Path this connection has to use (copy is made).
- * @param own_pos Own position in the @c path path.
- *
- * @return Newly created connection.
- *         NULL in case of error: own id not in path, wrong neighbors, ...
- */
-struct CadetConnection *
-GCC_new (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
-         struct CadetTunnel *t,
-         struct CadetPeerPath *path,
-         unsigned int own_pos);
 
 /**
- * Connection is no longer needed: destroy it.
- *
- * Cancels all pending traffic (including possible DESTROY messages), all
- * maintenance tasks and removes the connection from neighbor peers and tunnel.
+ * Handle KX_AUTH message.
  *
- * @param c Connection to destroy.
+ * @param cc connection that received encrypted message
+ * @param msg the key exchange message
  */
 void
-GCC_destroy (struct CadetConnection *c);
-
-/**
- * Get the connection ID.
- *
- * @param c Connection to get the ID from.
- *
- * @return ID of the connection.
- */
-const struct GNUNET_CADET_ConnectionTunnelIdentifier *
-GCC_get_id (const struct CadetConnection *c);
+GCC_handle_kx_auth (struct CadetConnection *cc,
+                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
 
 
 /**
- * Get the connection path.
- *
- * @param c Connection to get the path from.
- *
- * @return path used by the connection.
+ * Performance metrics for a connection.
  */
-const struct CadetPeerPath *
-GCC_get_path (const struct CadetConnection *c);
+struct CadetConnectionMetrics
+{
 
-/**
- * Get the connection state.
- *
- * @param c Connection to get the state from.
- *
- * @return state of the connection.
- */
-enum CadetConnectionState
-GCC_get_state (const struct CadetConnection *c);
+  /**
+   * Our current best estimate of the latency, based on a weighted
+   * average of at least @a latency_datapoints values.
+   */
+  struct GNUNET_TIME_Relative aged_latency;
 
-/**
- * Get the connection tunnel.
- *
- * @param c Connection to get the tunnel from.
- *
- * @return tunnel of the connection.
- */
-struct CadetTunnel *
-GCC_get_tunnel (const struct CadetConnection *c);
+  /**
+   * When was this connection first established? (by us sending or
+   * receiving the CREATE_ACK for the first time)
+   */
+  struct GNUNET_TIME_Absolute age;
 
-/**
- * Get free buffer space in a connection.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Free buffer space [0 - max_msgs_queue/max_connections]
- */
-unsigned int
-GCC_get_buffer (struct CadetConnection *c, int fwd);
+  /**
+   * When was this connection last used? (by us sending or
+   * receiving a PAYLOAD message on it)
+   */
+  struct GNUNET_TIME_Absolute last_use;
 
-/**
- * Get how many messages have we allowed to send to us from a direction.
- *
- * @param c Connection.
- * @param fwd Are we asking about traffic from FWD (BCK messages)?
- *
- * @return last_ack_sent - last_pid_recv
- */
-unsigned int
-GCC_get_allowed (struct CadetConnection *c, int fwd);
+  /**
+   * How many packets that ought to generate an ACK did we send via
+   * this connection?
+   */
+  unsigned long long num_acked_transmissions;
 
-/**
- * Get messages queued in a connection.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- *
- * @return Number of messages queued.
- */
-unsigned int
-GCC_get_qn (struct CadetConnection *c, int fwd);
+  /**
+   * Number of packets that were sent via this connection did actually
+   * receive an ACK?  (Note: ACKs may be transmitted and lost via
+   * other connections, so this value should only be interpreted
+   * relative to @e num_acked_transmissions and in relation to other
+   * connections.)
+   */
+  unsigned long long num_successes;
 
-/**
- * Get next PID to use.
- *
- * @param c Connection.
- * @param fwd Is query about FWD traffic?
- * @return Next PID to use.
- */
-struct CadetEncryptedMessageIdentifier
-GCC_get_pid (struct CadetConnection *c, int fwd);
+};
 
-/**
- * Allow the connection to advertise a buffer of the given size.
- *
- * The connection will send an @c fwd ACK message (so: in direction !fwd)
- * allowing up to last_pid_recv + buffer.
- *
- * @param c Connection.
- * @param buffer How many more messages the connection can accept.
- * @param fwd Is this about FWD traffic? (The ack will go dest->root).
- */
-void
-GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd);
 
 /**
- * Send FWD keepalive packets for a connection.
+ * Obtain performance @a metrics from @a cc.
  *
- * @param cls Closure (connection for which to send the keepalive).
- * @param tc Notification context.
+ * @param cc connection to query
+ * @return the metrics
  */
-void
-GCC_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+const struct CadetConnectionMetrics *
+GCC_get_metrics (struct CadetConnection *cc);
+
 
 /**
- * Send BCK keepalive packets for a connection.
+ * Handle encrypted message.
  *
- * @param cls Closure (connection for which to send the keepalive).
- * @param tc Notification context.
+ * @param cc connection that received encrypted message
+ * @param msg the encrypted message to decrypt
  */
 void
-GCC_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+GCC_handle_encrypted (struct CadetConnection *cc,
+                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
 
 
 /**
- * Notify other peers on a connection of a broken link. Mark connections
- * to destroy after all traffic has been sent.
+ * We sent a message for which we expect to receive an ACK via
+ * the connection identified by @a cti.
  *
- * @param c Connection on which there has been a disconnection.
- * @param peer Peer that disconnected.
+ * @param cid connection identifier where we expect an ACK
  */
 void
-GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer);
+GCC_ack_expected (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
 
-/**
- * Is this peer the first one on the connection?
- *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- *
- * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal.
- */
-int
-GCC_is_origin (struct CadetConnection *c, int fwd);
 
 /**
- * Is this peer the last one on the connection?
- *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- *            Note that the ROOT is the terminal for BCK traffic!
+ * We observed an ACK for a message that was originally sent via
+ * the connection identified by @a cti.
  *
- * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin.
+ * @param cid connection identifier where we got an ACK for a message
+ *            that was originally sent via this connection (the ACK
+ *            may have gotten back to us via a different connection).
  */
-int
-GCC_is_terminal (struct CadetConnection *c, int fwd);
-
-/**
- * See if we are allowed to send by the next hop in the given direction.
- *
- * @param c Connection.
- * @param fwd Is this about fwd traffic?
- *
- * @return #GNUNET_YES in case it's OK to send.
- */
-int
-GCC_is_sendable (struct CadetConnection *c, int fwd);
+void
+GCC_ack_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
 
-/**
- * Check if this connection is a direct one (never trim a direct connection).
- *
- * @param c Connection.
- *
- * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise.
- */
-int
-GCC_is_direct (struct CadetConnection *c);
 
 /**
- * Cancel a previously sent message while it's in the queue.
+ * We observed some the given @a latency on the connection
+ * identified by @a cti.  (The same connection was taken
+ * in both directions.)
  *
- * ONLY can be called before the continuation given to the send function
- * is called. Once the continuation is called, the message is no longer in the
- * queue.
- *
- * @param q Handle to the queue.
+ * @param cti connection identifier where we measured latency
+ * @param latency the observed latency
  */
 void
-GCC_cancel (struct CadetConnectionQueue *q);
+GCC_latency_observed (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cti,
+                      struct GNUNET_TIME_Relative latency);
 
-/**
- * Sends an already built message on a connection, properly registering
- * all used resources.
- *
- * @param message Message to send.
- * @param payload_type Type of payload, in case the message is encrypted.
- *                     0 for restransmissions (when type is no longer known)
- *                     UINT16_MAX when not applicable.
- * @param payload_id ID of the payload (PID, ACK, ...).
- * @param c Connection on which this message is transmitted.
- * @param fwd Is this a fwd message?
- * @param force Force the connection to accept the message (buffer overfill).
- * @param cont Continuation called once message is sent. Can be NULL.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel the message before it's sent.
- *         NULL on error.
- *         Invalid on @c cont call.
- */
-struct CadetConnectionQueue *
-GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
-                           uint16_t payload_type,
-                           struct CadetEncryptedMessageIdentifier payload_id,
-                           struct CadetConnection *c, int fwd, int force,
-                           GCC_sent cont, void *cont_cls);
 
 /**
- * Sends a CREATE CONNECTION message for a path to a peer.
- * Changes the connection and tunnel states if necessary.
+ * Return the tunnel associated with this connection.
  *
- * @param connection Connection to create.
+ * @param cc connection to query
+ * @return corresponding entry in the tunnel's connection list
  */
-void
-GCC_send_create (struct CadetConnection *connection);
+struct CadetTConnection *
+GCC_get_ct (struct CadetConnection *cc);
 
-/**
- * Send a message to all peers in this connection that the connection
- * is no longer valid.
- *
- * If some peer should not receive the message, it should be zero'ed out
- * before calling this function.
- *
- * @param c The connection whose peers to notify.
- */
-void
-GCC_send_destroy (struct CadetConnection *c);
 
 /**
- * @brief Start a polling timer for the connection.
+ * Obtain the path used by this connection.
  *
- * When a neighbor does not accept more traffic on the connection it could be
- * caused by a simple congestion or by a lost ACK. Polling enables to check
- * for the lastest ACK status for a connection.
- *
- * @param c Connection.
- * @param fwd Should we poll in the FWD direction?
+ * @param cc connection
+ * @return path to @a cc
  */
-void
-GCC_start_poll (struct CadetConnection *c, int fwd);
+struct CadetPeerPath *
+GCC_get_path (struct CadetConnection *cc);
 
 
 /**
- * @brief Stop polling a connection for ACKs.
- *
- * Once we have enough ACKs for future traffic, polls are no longer necessary.
+ * Obtain unique ID for the connection.
  *
- * @param c Connection.
- * @param fwd Should we stop the poll in the FWD direction?
+ * @param cc connection.
+ * @return unique number of the connection
  */
-void
-GCC_stop_poll (struct CadetConnection *c, int fwd);
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc);
+
 
 /**
  * Get a (static) string for a connection.
  *
- * @param c Connection.
+ * @param cc Connection.
  */
 const char *
-GCC_2s (const struct CadetConnection *c);
+GCC_2s (const struct CadetConnection *cc);
+
 
 /**
- * Log all possible info about the connection state.
+ * Log connection info.
  *
- * @param c Connection to debug.
+ * @param cc connection
  * @param level Debug level to use.
  */
 void
-GCC_debug (const struct CadetConnection *c, enum GNUNET_ErrorType level);
+GCC_debug (struct CadetConnection *cc,
+           enum GNUNET_ErrorType level);
 
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
 
-/* ifndef GNUNET_SERVICE_CADET_CONNECTION_H */
 #endif
-/* end of gnunet-service-cadet_connection.h */
diff --git a/src/cadet/gnunet-service-cadet_core.c b/src/cadet/gnunet-service-cadet_core.c
new file mode 100644 (file)
index 0000000..ae03b4f
--- /dev/null
@@ -0,0 +1,1356 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_core.c
+ * @brief cadet service; interaction with CORE service
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
+ *
+ * TODO:
+ * - Optimization: given BROKEN messages, destroy paths (?)
+ */
+#include "platform.h"
+#include "gnunet-service-cadet_core.h"
+#include "gnunet-service-cadet_paths.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet_core_service.h"
+#include "gnunet_statistics_service.h"
+#include "cadet_protocol.h"
+
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-cor",__VA_ARGS__)
+
+/**
+ * Information we keep per direction for a route.
+ */
+struct RouteDirection;
+
+
+/**
+ * Set of CadetRoutes that have exactly the same number of messages
+ * in their buffer.  Used so we can efficiently find all of those
+ * routes that have the current maximum of messages in the buffer (in
+ * case we have to purge).
+ */
+struct Rung
+{
+
+  /**
+   * Rung of RouteDirections with one more buffer entry each.
+   */
+  struct Rung *next;
+
+  /**
+   * Rung of RouteDirections with one less buffer entry each.
+   */
+  struct Rung *prev;
+
+  /**
+   * DLL of route directions with a number of buffer entries matching this rung.
+   */
+  struct RouteDirection *rd_head;
+
+  /**
+   * DLL of route directions with a number of buffer entries matching this rung.
+   */
+  struct RouteDirection *rd_tail;
+
+  /**
+   * Total number of route directions in this rung.
+   */
+  unsigned int num_routes;
+
+  /**
+   * Number of messages route directions at this rung have
+   * in their buffer.
+   */
+  unsigned int rung_off;
+};
+
+
+/**
+ * Information we keep per direction for a route.
+ */
+struct RouteDirection
+{
+
+  /**
+   * DLL of other route directions within the same `struct Rung`.
+   */
+  struct RouteDirection *prev;
+
+  /**
+   * DLL of other route directions within the same `struct Rung`.
+   */
+  struct RouteDirection *next;
+
+  /**
+   * Rung of this route direction (matches length of the buffer DLL).
+   */
+  struct Rung *rung;
+
+  /**
+   * Head of DLL of envelopes we have in the buffer for this direction.
+   */
+  struct GNUNET_MQ_Envelope *env_head;
+
+  /**
+   * Tail of DLL of envelopes we have in the buffer for this direction.
+   */
+  struct GNUNET_MQ_Envelope *env_tail;
+
+  /**
+   * Target peer.
+   */
+  struct CadetPeer *hop;
+
+  /**
+   * Route this direction is part of.
+   */
+  struct CadetRoute *my_route;
+
+  /**
+   * Message queue manager for @e hop.
+   */
+  struct GCP_MessageQueueManager *mqm;
+
+  /**
+   * Is @e mqm currently ready for transmission?
+   */
+  int is_ready;
+
+};
+
+
+/**
+ * Description of a segment of a `struct CadetConnection` at the
+ * intermediate peers.  Routes are basically entries in a peer's
+ * routing table for forwarding traffic.  At both endpoints, the
+ * routes are terminated by a `struct CadetConnection`, which knows
+ * the complete `struct CadetPath` that is formed by the individual
+ * routes.
+ */
+struct CadetRoute
+{
+
+  /**
+   * Information about the next hop on this route.
+   */
+  struct RouteDirection next;
+
+  /**
+   * Information about the previous hop on this route.
+   */
+  struct RouteDirection prev;
+
+  /**
+   * Unique identifier for the connection that uses this route.
+   */
+  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
+
+  /**
+   * When was this route last in use?
+   */
+  struct GNUNET_TIME_Absolute last_use;
+
+  /**
+   * Position of this route in the #route_heap.
+   */
+  struct GNUNET_CONTAINER_HeapNode *hn;
+
+  /**
+   * Options for the route, control buffering.
+   */
+  enum GNUNET_CADET_ChannelOption options;
+};
+
+
+/**
+ * Handle to the CORE service.
+ */
+static struct GNUNET_CORE_Handle *core;
+
+/**
+ * Routes on which this peer is an intermediate.
+ */
+static struct GNUNET_CONTAINER_MultiShortmap *routes;
+
+/**
+ * Heap of routes, MIN-sorted by last activity.
+ */
+static struct GNUNET_CONTAINER_Heap *route_heap;
+
+/**
+ * Rung zero (always pointed to by #rung_head).
+ */
+static struct Rung rung_zero;
+
+/**
+ * DLL of rungs, with the head always point to a rung of
+ * route directions with no messages in the queue.
+ */
+static struct Rung *rung_head = &rung_zero;
+
+/**
+ * Tail of the #rung_head DLL.
+ */
+static struct Rung *rung_tail = &rung_zero;
+
+/**
+ * Maximum number of concurrent routes this peer will support.
+ */
+static unsigned long long max_routes;
+
+/**
+ * Maximum number of envelopes we will buffer at this peer.
+ */
+static unsigned long long max_buffers;
+
+/**
+ * Current number of envelopes we have buffered at this peer.
+ */
+static unsigned long long cur_buffers;
+
+/**
+ * Task to timeout routes.
+ */
+static struct GNUNET_SCHEDULER_Task *timeout_task;
+
+
+/**
+ * Get the route corresponding to a hash.
+ *
+ * @param cid hash generated from the connection identifier
+ */
+static struct CadetRoute *
+get_route (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid)
+{
+  return GNUNET_CONTAINER_multishortmap_get (routes,
+                                             &cid->connection_of_tunnel);
+}
+
+
+/**
+ * Lower the rung in which @a dir is by 1.
+ *
+ * @param dir direction to lower in rung.
+ */
+static void
+lower_rung (struct RouteDirection *dir)
+{
+  struct Rung *rung = dir->rung;
+  struct Rung *prev;
+
+  GNUNET_CONTAINER_DLL_remove (rung->rd_head,
+                               rung->rd_tail,
+                               dir);
+  prev = rung->prev;
+  GNUNET_assert (NULL != prev);
+  if (prev->rung_off != rung->rung_off - 1)
+  {
+    prev = GNUNET_new (struct Rung);
+    prev->rung_off = rung->rung_off - 1;
+    GNUNET_CONTAINER_DLL_insert_after (rung_head,
+                                       rung_tail,
+                                       rung->prev,
+                                       prev);
+  }
+  GNUNET_assert (NULL != prev);
+  GNUNET_CONTAINER_DLL_insert (prev->rd_head,
+                               prev->rd_tail,
+                               dir);
+  dir->rung = prev;
+}
+
+
+/**
+ * Discard the buffer @a env from the route direction @a dir and
+ * move @a dir down a rung.
+ *
+ * @param dir direction that contains the @a env in the buffer
+ * @param env envelope to discard
+ */
+static void
+discard_buffer (struct RouteDirection *dir,
+                struct GNUNET_MQ_Envelope *env)
+{
+  GNUNET_MQ_dll_remove (&dir->env_head,
+                        &dir->env_tail,
+                        env);
+  cur_buffers--;
+  GNUNET_MQ_discard (env);
+  lower_rung (dir);
+  GNUNET_STATISTICS_set (stats,
+                         "# buffer use",
+                         cur_buffers,
+                         GNUNET_NO);
+}
+
+
+/**
+ * Discard all messages from the highest rung, to make space.
+ */
+static void
+discard_all_from_rung_tail ()
+{
+  struct Rung *tail = rung_tail;
+  struct RouteDirection *dir;
+
+  while (NULL != (dir = tail->rd_head))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Queue full due new message %s on connection %s, dropping old message\n",
+         GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
+    GNUNET_STATISTICS_update (stats,
+                              "# messages dropped due to full buffer",
+                              1,
+                              GNUNET_NO);
+    discard_buffer (dir,
+                    dir->env_head);
+  }
+  GNUNET_CONTAINER_DLL_remove (rung_head,
+                               rung_tail,
+                               tail);
+  GNUNET_free (tail);
+}
+
+
+/**
+ * We message @a msg from @a prev.  Find its route by @a cid and
+ * forward to the next hop.  Drop and signal broken route if we do not
+ * have a route.
+ *
+ * @param prev previous hop (sender)
+ * @param cid connection identifier, tells us which route to use
+ * @param msg the message to forward
+ */
+static void
+route_message (struct CadetPeer *prev,
+               const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+               const struct GNUNET_MessageHeader *msg)
+{
+  struct CadetRoute *route;
+  struct RouteDirection *dir;
+  struct Rung *rung;
+  struct Rung *nxt;
+  struct GNUNET_MQ_Envelope *env;
+
+  route = get_route (cid);
+  if (NULL == route)
+  {
+    struct GNUNET_MQ_Envelope *env;
+    struct GNUNET_CADET_ConnectionBrokenMessage *bm;
+
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to route message of type %u from %s on connection %s: no route\n",
+         ntohs (msg->type),
+         GCP_2s (prev),
+         GNUNET_sh2s (&cid->connection_of_tunnel));
+    switch (ntohs (msg->type))
+    {
+    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY:
+    case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN:
+      /* No need to respond to these! */
+      return;
+    }
+    env = GNUNET_MQ_msg (bm,
+                         GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
+    bm->cid = *cid;
+    bm->peer1 = my_full_id;
+    GCP_send_ooo (prev,
+                  env);
+    return;
+  }
+  route->last_use = GNUNET_TIME_absolute_get ();
+  GNUNET_CONTAINER_heap_update_cost (route->hn,
+                                     route->last_use.abs_value_us);
+  dir = (prev == route->prev.hop) ? &route->next : &route->prev;
+  if (GNUNET_YES == dir->is_ready)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Routing message of type %u from %s to %s on connection %s\n",
+         ntohs (msg->type),
+         GCP_2s (prev),
+         GNUNET_i2s (GCP_get_id (dir->hop)),
+         GNUNET_sh2s (&cid->connection_of_tunnel));
+    dir->is_ready = GNUNET_NO;
+    GCP_send (dir->mqm,
+              GNUNET_MQ_msg_copy (msg));
+    return;
+  }
+  /* Check if buffering is disallowed, and if so, make sure we only queue
+     one message per direction. */
+  if ( (0 != (route->options & GNUNET_CADET_OPTION_NOBUFFER)) &&
+       (NULL != dir->env_head) )
+    discard_buffer (dir,
+                    dir->env_head);
+  rung = dir->rung;
+  if (cur_buffers == max_buffers)
+  {
+    /* Need to make room. */
+    if (NULL != rung->next)
+    {
+      /* Easy case, drop messages from route directions in highest rung */
+      discard_all_from_rung_tail ();
+    }
+    else
+    {
+      /* We are in the highest rung, drop our own! */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Queue full due new message %s on connection %s, dropping old message\n",
+           GNUNET_sh2s (&dir->my_route->cid.connection_of_tunnel));
+      GNUNET_STATISTICS_update (stats,
+                                "# messages dropped due to full buffer",
+                                1,
+                                GNUNET_NO);
+      discard_buffer (dir,
+                      dir->env_head);
+      rung = dir->rung;
+    }
+  }
+  /* remove 'dir' from current rung */
+  GNUNET_CONTAINER_DLL_remove (rung->rd_head,
+                               rung->rd_tail,
+                               dir);
+  /* make 'nxt' point to the next higher rung, creat if necessary */
+  nxt = rung->next;
+  if ( (NULL == nxt) ||
+       (rung->rung_off + 1 != nxt->rung_off) )
+  {
+    nxt = GNUNET_new (struct Rung);
+    nxt->rung_off = rung->rung_off + 1;
+    GNUNET_CONTAINER_DLL_insert_after (rung_head,
+                                       rung_tail,
+                                       rung,
+                                       nxt);
+  }
+  /* insert 'dir' into next higher rung */
+  GNUNET_CONTAINER_DLL_insert (nxt->rd_head,
+                               nxt->rd_tail,
+                               dir);
+  dir->rung = nxt;
+
+  /* add message into 'dir' buffer */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Queueing new message of type %u from %s to %s on connection %s\n",
+       ntohs (msg->type),
+       GCP_2s (prev),
+       GNUNET_i2s (GCP_get_id (dir->hop)),
+       GNUNET_sh2s (&cid->connection_of_tunnel));
+  env = GNUNET_MQ_msg_copy (msg);
+  GNUNET_MQ_dll_insert_tail (&dir->env_head,
+                             &dir->env_tail,
+                             env);
+  cur_buffers++;
+  GNUNET_STATISTICS_set (stats,
+                         "# buffer use",
+                         cur_buffers,
+                         GNUNET_NO);
+  /* Clean up 'rung' if now empty (and not head) */
+  if ( (NULL == rung->rd_head) &&
+       (rung != rung_head) )
+  {
+    GNUNET_CONTAINER_DLL_remove (rung_head,
+                                 rung_tail,
+                                 rung);
+    GNUNET_free (rung);
+  }
+}
+
+
+/**
+ * Check if the create_connection message has the appropriate size.
+ *
+ * @param cls Closure (unused).
+ * @param msg Message to check.
+ *
+ * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
+ */
+static int
+check_connection_create (void *cls,
+                         const struct GNUNET_CADET_ConnectionCreateMessage *msg)
+{
+  uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
+
+  if (0 != (size % sizeof (struct GNUNET_PeerIdentity)))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_NO;
+  }
+  return GNUNET_YES;
+}
+
+
+/**
+ * Free internal data of a route direction.
+ *
+ * @param dir direction to destroy (do NOT free memory of 'dir' itself)
+ */
+static void
+destroy_direction (struct RouteDirection *dir)
+{
+  struct GNUNET_MQ_Envelope *env;
+
+  while (NULL != (env = dir->env_head))
+  {
+    GNUNET_STATISTICS_update (stats,
+                              "# messages dropped due to route destruction",
+                              1,
+                              GNUNET_NO);
+    discard_buffer (dir,
+                    env);
+  }
+  if (NULL != dir->mqm)
+  {
+    GCP_request_mq_cancel (dir->mqm,
+                           NULL);
+    dir->mqm = NULL;
+  }
+  GNUNET_CONTAINER_DLL_remove (rung_head->rd_head,
+                               rung_head->rd_tail,
+                               dir);
+}
+
+
+/**
+ * Destroy our state for @a route.
+ *
+ * @param route route to destroy
+ */
+static void
+destroy_route (struct CadetRoute *route)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying route from %s to %s of connection %s\n",
+       GNUNET_i2s  (GCP_get_id (route->prev.hop)),
+       GNUNET_i2s2 (GCP_get_id (route->next.hop)),
+       GNUNET_sh2s (&route->cid.connection_of_tunnel));
+  GNUNET_assert (route ==
+                 GNUNET_CONTAINER_heap_remove_node (route->hn));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multishortmap_remove (routes,
+                                                        &route->cid.connection_of_tunnel,
+                                                        route));
+  GNUNET_STATISTICS_set (stats,
+                         "# routes",
+                         GNUNET_CONTAINER_multishortmap_size (routes),
+                         GNUNET_NO);
+  destroy_direction (&route->prev);
+  destroy_direction (&route->next);
+  GNUNET_free (route);
+}
+
+
+/**
+ * Send message that a route is broken between @a peer1 and @a peer2.
+ *
+ * @param target where to send the message
+ * @param cid connection identifier to use
+ * @param peer1 one of the peers where a link is broken
+ * @param peer2 another one of the peers where a link is broken
+ */
+static void
+send_broken (struct RouteDirection *target,
+             const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+             const struct GNUNET_PeerIdentity *peer1,
+             const struct GNUNET_PeerIdentity *peer2)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_ConnectionBrokenMessage *bm;
+
+  if (NULL == target->mqm)
+    return; /* Can't send notification, connection is down! */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Notifying %s about BROKEN route at %s-%s of connection %s\n",
+       GCP_2s (target->hop),
+       GNUNET_i2s (peer1),
+       GNUNET_i2s2 (peer2),
+       GNUNET_sh2s (&cid->connection_of_tunnel));
+
+  env = GNUNET_MQ_msg (bm,
+                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
+  bm->cid = *cid;
+  if (NULL != peer1)
+    bm->peer1 = *peer1;
+  if (NULL != peer2)
+    bm->peer2 = *peer2;
+  GCP_request_mq_cancel (target->mqm,
+                         env);
+  target->mqm = NULL;
+}
+
+
+/**
+ * Function called to check if any routes have timed out, and if
+ * so, to clean them up.  Finally, schedules itself again at the
+ * earliest time where there might be more work.
+ *
+ * @param cls NULL
+ */
+static void
+timeout_cb (void *cls)
+{
+  struct CadetRoute *r;
+  struct GNUNET_TIME_Relative linger;
+  struct GNUNET_TIME_Absolute exp;
+
+  timeout_task = NULL;
+  linger = GNUNET_TIME_relative_multiply (keepalive_period,
+                                          3);
+  while (NULL != (r = GNUNET_CONTAINER_heap_peek (route_heap)))
+  {
+    exp = GNUNET_TIME_absolute_add (r->last_use,
+                                    linger);
+    if (0 != GNUNET_TIME_absolute_get_duration (exp).rel_value_us)
+    {
+      /* Route not yet timed out, wait until it does. */
+      timeout_task = GNUNET_SCHEDULER_add_at (exp,
+                                              &timeout_cb,
+                                              NULL);
+      return;
+    }
+    send_broken (&r->prev,
+                 &r->cid,
+                 NULL,
+                 NULL);
+    send_broken (&r->next,
+                 &r->cid,
+                 NULL,
+                 NULL);
+    destroy_route (r);
+  }
+  /* No more routes left, so no need for a #timeout_task */
+}
+
+
+/**
+ * Function called when the message queue to the previous hop
+ * becomes available/unavailable.  We expect this function to
+ * be called immediately when we register, and then again
+ * later if the connection ever goes down.
+ *
+ * @param cls the `struct RouteDirection`
+ * @param available #GNUNET_YES if sending is now possible,
+ *                  #GNUNET_NO if sending is no longer possible
+ *                  #GNUNET_SYSERR if sending is no longer possible
+ *                                 and the last envelope was discarded
+ */
+static void
+dir_ready_cb (void *cls,
+              int ready)
+{
+  struct RouteDirection *dir = cls;
+  struct CadetRoute *route = dir->my_route;
+  struct RouteDirection *odir;
+
+  if (GNUNET_YES == ready)
+  {
+    struct GNUNET_MQ_Envelope *env;
+
+    dir->is_ready = GNUNET_YES;
+    if (NULL != (env = dir->env_head))
+    {
+      GNUNET_MQ_dll_remove (&dir->env_head,
+                            &dir->env_tail,
+                            env);
+      cur_buffers--;
+      GNUNET_STATISTICS_set (stats,
+                             "# buffer use",
+                             cur_buffers,
+                             GNUNET_NO);
+      lower_rung (dir);
+      dir->is_ready = GNUNET_NO;
+      GCP_send (dir->mqm,
+                env);
+    }
+    return;
+  }
+  odir = (dir == &route->next) ? &route->prev : &route->next;
+  send_broken (&route->next,
+               &route->cid,
+               GCP_get_id (odir->hop),
+               &my_full_id);
+  destroy_route (route);
+}
+
+
+/**
+ * Initialize one of the directions of a route.
+ *
+ * @param route route the direction belongs to
+ * @param dir direction to initialize
+ * @param hop next hop on in the @a dir
+ */
+static void
+dir_init (struct RouteDirection *dir,
+          struct CadetRoute *route,
+          struct CadetPeer *hop)
+{
+  dir->hop = hop;
+  dir->my_route = route;
+  dir->mqm = GCP_request_mq (hop,
+                             &dir_ready_cb,
+                             dir);
+  GNUNET_CONTAINER_DLL_insert (rung_head->rd_head,
+                               rung_head->rd_tail,
+                               dir);
+  dir->rung = rung_head;
+  GNUNET_assert (GNUNET_YES == dir->is_ready);
+}
+
+
+/**
+ * We could not create the desired route.  Send a
+ * #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
+ * message to @a target.
+ *
+ * @param target who should receive the message
+ * @param cid identifier of the connection/route that failed
+ * @param failure_at neighbour with which we failed to route,
+ *        or NULL.
+ */
+static void
+send_broken_without_mqm (struct CadetPeer *target,
+                         const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                         const struct GNUNET_PeerIdentity *failure_at)
+{
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_ConnectionBrokenMessage *bm;
+
+  env = GNUNET_MQ_msg (bm,
+                       GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN);
+  bm->cid = *cid;
+  bm->peer1 = my_full_id;
+  if (NULL != failure_at)
+    bm->peer2 = *failure_at;
+  GCP_send_ooo (target,
+                env);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_connection_create (void *cls,
+                          const struct GNUNET_CADET_ConnectionCreateMessage *msg)
+{
+  struct CadetPeer *sender = cls;
+  struct CadetPeer *next;
+  const struct GNUNET_PeerIdentity *pids = (const struct GNUNET_PeerIdentity *) &msg[1];
+  struct CadetRoute *route;
+  uint16_t size = ntohs (msg->header.size) - sizeof (*msg);
+  unsigned int path_length;
+  unsigned int off;
+  enum GNUNET_CADET_ChannelOption options;
+
+  options = (enum GNUNET_CADET_ChannelOption) ntohl (msg->options);
+  path_length = size / sizeof (struct GNUNET_PeerIdentity);
+  /* Initiator is at offset 0. */
+  for (off=1;off<path_length;off++)
+    if (0 == memcmp (&my_full_id,
+                     &pids[off],
+                     sizeof (struct GNUNET_PeerIdentity)))
+      break;
+  if (off == path_length)
+  {
+    /* We are not on the path, bogus request */
+    GNUNET_break_op (0);
+    return;
+  }
+  /* Check previous hop */
+  if (sender != GCP_get (&pids[off - 1],
+                         GNUNET_NO))
+  {
+    /* sender is not on the path, not allowed */
+    GNUNET_break_op (0);
+    return;
+  }
+  if (NULL !=
+      get_route (&msg->cid))
+  {
+    /* Duplicate CREATE, pass it on, previous one might have been lost! */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Passing on duplicate CADET_CONNECTION_CREATE message on connection %s\n",
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    route_message (sender,
+                   &msg->cid,
+                   &msg->header);
+    return;
+  }
+  if (off == path_length - 1)
+  {
+    /* We are the destination, create connection */
+    struct CadetConnection *cc;
+    struct CadetPeerPath *path;
+    struct CadetPeer *origin;
+
+    cc = GCC_lookup (&msg->cid);
+    if (NULL != cc)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Received duplicate CADET_CONNECTION_CREATE message on connection %s\n",
+           GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+      GCC_handle_duplicate_create (cc);
+      return;
+    }
+
+    origin = GCP_get (&pids[0],
+                      GNUNET_YES);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CADET_CONNECTION_CREATE message from %s for connection %s, building inverse path\n",
+         GCP_2s (origin),
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    path = GCPP_get_path_from_route (path_length - 1,
+                                     pids);
+    if (GNUNET_OK !=
+        GCT_add_inbound_connection (GCP_get_tunnel (origin,
+                                                    GNUNET_YES),
+                                    &msg->cid,
+                                    (enum GNUNET_CADET_ChannelOption) ntohl (msg->options),
+                                    path))
+    {
+      /* Send back BROKEN: duplicate connection on the same path,
+         we will use the other one. */
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Received CADET_CONNECTION_CREATE from %s for %s, but %s already has a connection. Sending BROKEN\n",
+           GCP_2s (sender),
+           GNUNET_sh2s (&msg->cid.connection_of_tunnel),
+           GCPP_2s (path));
+      send_broken_without_mqm (sender,
+                               &msg->cid,
+                               NULL);
+      return;
+    }
+    return;
+  }
+  /* We are merely a hop on the way, check if we can support the route */
+  next = GCP_get (&pids[off + 1],
+                  GNUNET_NO);
+  if ( (NULL == next) ||
+       (GNUNET_NO == GCP_has_core_connection (next)) )
+  {
+    /* unworkable, send back BROKEN notification */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is down. Sending BROKEN\n",
+         GCP_2s (sender),
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel),
+         GNUNET_i2s (&pids[off + 1]),
+         off + 1);
+    send_broken_without_mqm (sender,
+                             &msg->cid,
+                             &pids[off + 1]);
+    return;
+  }
+  if (max_routes <= GNUNET_CONTAINER_multishortmap_size (routes))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CADET_CONNECTION_CREATE from %s for %s. We have reached our route limit. Sending BROKEN\n",
+         GCP_2s (sender),
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    send_broken_without_mqm (sender,
+                             &msg->cid,
+                             &pids[off - 1]);
+    return;
+  }
+
+  /* Workable route, create routing entry */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received CADET_CONNECTION_CREATE from %s for %s. Next hop %s:%u is up. Creating route\n",
+       GCP_2s (sender),
+       GNUNET_sh2s (&msg->cid.connection_of_tunnel),
+       GNUNET_i2s (&pids[off + 1]),
+       off + 1);
+  route = GNUNET_new (struct CadetRoute);
+  route->options = options;
+  route->cid = msg->cid;
+  route->last_use = GNUNET_TIME_absolute_get ();
+  dir_init (&route->prev,
+            route,
+            sender);
+  dir_init (&route->next,
+            route,
+            next);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multishortmap_put (routes,
+                                                     &route->cid.connection_of_tunnel,
+                                                     route,
+                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  GNUNET_STATISTICS_set (stats,
+                         "# routes",
+                         GNUNET_CONTAINER_multishortmap_size (routes),
+                         GNUNET_NO);
+  route->hn = GNUNET_CONTAINER_heap_insert (route_heap,
+                                            route,
+                                            route->last_use.abs_value_us);
+  if (NULL == timeout_task)
+    timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (keepalive_period,
+                                                                                3),
+                                                 &timeout_cb,
+                                                 NULL);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_connection_create_ack (void *cls,
+                              const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+
+  /* First, check if ACK belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify ACK came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received ACK from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CONNECTION_CREATE_ACK for connection %s.\n",
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    GCC_handle_connection_create_ack (cc);
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ * @deprecated duplicate logic with #handle_destroy(); dedup!
+ */
+static void
+handle_connection_broken (void *cls,
+                          const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+  struct CadetRoute *route;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CONNECTION_BROKEN for connection %s. Destroying it.\n",
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+    GCC_destroy_without_core (cc);
+
+    /* FIXME: also destroy the path up to the specified link! */
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+  route = get_route (&msg->cid);
+  if (NULL != route)
+    destroy_route (route);
+  /* FIXME: also destroy paths we MAY have up to the specified link! */
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_connection_destroy (void *cls,
+                           const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+  struct CadetRoute *route;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received CONNECTION_DESTROY for connection %s. Destroying connection.\n",
+         GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+
+    GCC_destroy_without_core (cc);
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received CONNECTION_DESTROY for connection %s. Destroying route.\n",
+       GNUNET_sh2s (&msg->cid.connection_of_tunnel));
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+  route = get_route (&msg->cid);
+  if (NULL != route)
+    destroy_route (route);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_tunnel_kx (void *cls,
+                  const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    GCC_handle_kx (cc,
+                   msg);
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_tunnel_kx_auth (void *cls,
+                       const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->kx.cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    GCC_handle_kx_auth (cc,
+                        msg);
+    return;
+  }
+
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->kx.cid,
+                 &msg->kx.header);
+}
+
+
+/**
+ * Check if the encrypted message has the appropriate size.
+ *
+ * @param cls Closure (unused).
+ * @param msg Message to check.
+ *
+ * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
+ */
+static int
+check_tunnel_encrypted (void *cls,
+                        const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+{
+  return GNUNET_YES;
+}
+
+
+/**
+ * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED.
+ *
+ * @param cls Closure (CadetPeer for neighbor that sent the message).
+ * @param msg Message itself.
+ */
+static void
+handle_tunnel_encrypted (void *cls,
+                         const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+{
+  struct CadetPeer *peer = cls;
+  struct CadetConnection *cc;
+
+  /* First, check if message belongs to a connection that ends here. */
+  cc = GCC_lookup (&msg->cid);
+  if (NULL != cc)
+  {
+    /* verify message came from the right direction */
+    struct CadetPeerPath *path = GCC_get_path (cc);
+
+    if (peer !=
+        GCPP_get_peer_at_offset (path,
+                                 0))
+    {
+      /* received message from unexpected direction, ignore! */
+      GNUNET_break_op (0);
+      return;
+    }
+    GCC_handle_encrypted (cc,
+                          msg);
+    return;
+  }
+  /* We're just an intermediary peer, route the message along its path */
+  route_message (peer,
+                 &msg->cid,
+                 &msg->header);
+}
+
+
+/**
+ * Function called after #GNUNET_CORE_connect has succeeded (or failed
+ * for good).  Note that the private key of the peer is intentionally
+ * not exposed here; if you need it, your process should try to read
+ * the private key file directly (which should work if you are
+ * authorized...).  Implementations of this function must not call
+ * #GNUNET_CORE_disconnect (other than by scheduling a new task to
+ * do this later).
+ *
+ * @param cls closure
+ * @param my_identity ID of this peer, NULL if we failed
+ */
+static void
+core_init_cb (void *cls,
+              const struct GNUNET_PeerIdentity *my_identity)
+{
+  if (NULL == my_identity)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_break (0 ==
+                memcmp (my_identity,
+                        &my_full_id,
+                        sizeof (struct GNUNET_PeerIdentity)));
+}
+
+
+/**
+ * Method called whenever a given peer connects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void *
+core_connect_cb (void *cls,
+                 const struct GNUNET_PeerIdentity *peer,
+                 struct GNUNET_MQ_Handle *mq)
+{
+  struct CadetPeer *cp;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "CORE connection to peer %s was established.\n",
+       GNUNET_i2s (peer));
+  cp = GCP_get (peer,
+                GNUNET_YES);
+  GCP_set_mq (cp,
+              mq);
+  return cp;
+}
+
+
+/**
+ * Method called whenever a peer disconnects.
+ *
+ * @param cls closure
+ * @param peer peer identity this notification is about
+ */
+static void
+core_disconnect_cb (void *cls,
+                    const struct GNUNET_PeerIdentity *peer,
+                    void *peer_cls)
+{
+  struct CadetPeer *cp = peer_cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "CORE connection to peer %s went down.\n",
+       GNUNET_i2s (peer));
+  GCP_set_mq (cp,
+              NULL);
+}
+
+
+/**
+ * Initialize the CORE subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCO_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (connection_create,
+                           GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
+                           struct GNUNET_CADET_ConnectionCreateMessage,
+                           NULL),
+    GNUNET_MQ_hd_fixed_size (connection_create_ack,
+                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
+                             struct GNUNET_CADET_ConnectionCreateAckMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (connection_broken,
+                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
+                             struct GNUNET_CADET_ConnectionBrokenMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (connection_destroy,
+                             GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
+                             struct GNUNET_CADET_ConnectionDestroyMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (tunnel_kx,
+                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
+                             struct GNUNET_CADET_TunnelKeyExchangeMessage,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (tunnel_kx_auth,
+                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH,
+                             struct GNUNET_CADET_TunnelKeyExchangeAuthMessage,
+                             NULL),
+    GNUNET_MQ_hd_var_size (tunnel_encrypted,
+                           GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
+                           struct GNUNET_CADET_TunnelEncryptedMessage,
+                           NULL),
+    GNUNET_MQ_handler_end ()
+  };
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "MAX_ROUTES",
+                                             &max_routes))
+    max_routes = 5000;
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
+                                             "MAX_MSGS_QUEUE",
+                                             &max_buffers))
+    max_buffers = 10000;
+  routes = GNUNET_CONTAINER_multishortmap_create (1024,
+                                                  GNUNET_NO);
+  route_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
+  core = GNUNET_CORE_connect (c,
+                              NULL,
+                              &core_init_cb,
+                              &core_connect_cb,
+                              &core_disconnect_cb,
+                              handlers);
+}
+
+
+/**
+ * Shut down the CORE subsystem.
+ */
+void
+GCO_shutdown ()
+{
+  if (NULL != core)
+  {
+    GNUNET_CORE_disconnect (core);
+    core = NULL;
+  }
+  GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (routes));
+  GNUNET_CONTAINER_multishortmap_destroy (routes);
+  routes = NULL;
+  GNUNET_CONTAINER_heap_destroy (route_heap);
+  route_heap = NULL;
+  if (NULL != timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (timeout_task);
+    timeout_task = NULL;
+  }
+}
+
+/* end of gnunet-cadet-service_core.c */
diff --git a/src/cadet/gnunet-service-cadet_core.h b/src/cadet/gnunet-service-cadet_core.h
new file mode 100644 (file)
index 0000000..65b0a6b
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_core.h
+ * @brief cadet service; interaction with CORE service
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCO (Gnunet Cadet cOre (bottom))
+ */
+
+#ifndef GNUNET_SERVICE_CADET_CORE_H
+#define GNUNET_SERVICE_CADET_CORE_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0                           /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "gnunet_util_lib.h"
+
+
+/**
+ * Initialize the CORE subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCO_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+
+/**
+ * Shut down the CORE subsystem.
+ */
+void
+GCO_shutdown (void);
+
+
+#if 0                           /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_CORE_H */
+#endif
+/* end of gnunet-cadet-service_core.h */
index 22673b16706f49ddec79a97f094982e92e39a864..f00c0caf3b42e7a8a8f7cde008a3fa632c85c0a3 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
+     Copyright (C) 2013, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      Boston, MA 02110-1301, USA.
 */
-
+/**
+ * @file cadet/gnunet-service-cadet_dht.c
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
 
 #include "platform.h"
 #include "gnunet_util_lib.h"
-
 #include "gnunet_dht_service.h"
 #include "gnunet_statistics_service.h"
-
-#include "cadet_path.h"
+#include "gnunet-service-cadet.h"
 #include "gnunet-service-cadet_dht.h"
-#include "gnunet-service-cadet_peer.h"
 #include "gnunet-service-cadet_hello.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
 
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
+/**
+ * How long do we wait before first announcing our presence to the DHT.
+ * Used to wait for our HELLO to be available.  Note that we also get
+ * notifications when our HELLO is ready, so this is just the maximum
+ * we wait for the first notification.
+ */
+#define STARTUP_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 500)
 
+/**
+ * How long do we wait after we get an updated HELLO before publishing?
+ * Allows for the HELLO to be updated again quickly, for example in
+ * case multiple addresses changed and we got a partial update.
+ */
+#define CHANGE_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100)
+
+
+#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
 
-/******************************************************************************/
-/********************************   STRUCTS  **********************************/
-/******************************************************************************/
 
 /**
  * Handle for DHT searches.
@@ -47,42 +63,9 @@ struct GCD_search_handle
    */
   struct GNUNET_DHT_GetHandle *dhtget;
 
-  /**
-   * Provided callback to call when a path is found.
-   */
-  GCD_search_callback callback;
-
-  /**
-   * Provided closure.
-   */
-  void *cls;
-
-  /**
-   * Peer ID searched for
-   */
-  GNUNET_PEER_Id peer_id;
 };
 
 
-/******************************************************************************/
-/*******************************   GLOBALS  ***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Own ID (short value).
- */
-extern GNUNET_PEER_Id myid;
-
-/**
- * Own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
 /**
  * Handle to use DHT.
  */
@@ -94,69 +77,20 @@ static struct GNUNET_DHT_Handle *dht_handle;
 static struct GNUNET_TIME_Relative id_announce_time;
 
 /**
- * DHT replication level, see DHT API: GNUNET_DHT_get_start, GNUNET_DHT_put.
+ * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put().
  */
 static unsigned long long dht_replication_level;
 
 /**
  * Task to periodically announce itself in the network.
  */
-static struct GNUNET_SCHEDULER_Task * announce_id_task;
+static struct GNUNET_SCHEDULER_Task *announce_id_task;
 
 /**
  * Delay for the next ID announce.
  */
 static struct GNUNET_TIME_Relative announce_delay;
 
-/**
- * GET requests to stop on shutdown.
- */
-static struct GNUNET_CONTAINER_MultiHashMap32 *get_requests;
-
-/******************************************************************************/
-/********************************   STATIC  ***********************************/
-/******************************************************************************/
-
-
-/**
- * Build a PeerPath from the paths returned from the DHT, reversing the paths
- * to obtain a local peer -> destination path and interning the peer ids.
- *
- * @return Newly allocated and created path
- *
- * FIXME refactor and use build_path_from_peer_ids
- */
-static struct CadetPeerPath *
-path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
-                     unsigned int get_path_length,
-                     const struct GNUNET_PeerIdentity *put_path,
-                     unsigned int put_path_length)
-{
-  size_t size = get_path_length + put_path_length + 1;
-  struct GNUNET_PeerIdentity peers[size];
-  const struct GNUNET_PeerIdentity *peer;
-  struct CadetPeerPath *p;
-  unsigned int own_pos;
-  int i;
-
-  peers[0] = my_full_id;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "   GET has %d hops.\n", get_path_length);
-  for (i = 0 ; i < get_path_length; i++)
-  {
-    peer = &get_path[get_path_length - i - 1];
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "   From GET: %s\n", GNUNET_i2s (peer));
-    peers[i + 1] = *peer;
-  }
-  for (i = 0 ; i < put_path_length; i++)
-  {
-    peer = &put_path[put_path_length - i - 1];
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "   From PUT: %s\n", GNUNET_i2s (peer));
-    peers[i + get_path_length + 1] = *peer;
-  }
-  p = path_build_from_peer_ids (peers, size, myid, &own_pos);
-  return p;
-}
-
 
 /**
  * Function to process paths received for a new peer addition. The recorded
@@ -176,42 +110,34 @@ path_build_from_dht (const struct GNUNET_PeerIdentity *get_path,
  */
 static void
 dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
-                    const struct GNUNET_HashCode * key,
+                    const struct GNUNET_HashCode *key,
                     const struct GNUNET_PeerIdentity *get_path,
                     unsigned int get_path_length,
                     const struct GNUNET_PeerIdentity *put_path,
-                    unsigned int put_path_length, enum GNUNET_BLOCK_Type type,
-                    size_t size, const void *data)
+                    unsigned int put_path_length,
+                    enum GNUNET_BLOCK_Type type,
+                    size_t size,
+                    const void *data)
 {
-  struct GCD_search_handle *h = cls;
-  struct GNUNET_HELLO_Message *hello;
-  struct CadetPeerPath *p;
+  const struct GNUNET_HELLO_Message *hello = data;
   struct CadetPeer *peer;
-  char *s;
 
-  p = path_build_from_dht (get_path, get_path_length,
-                           put_path, put_path_length);
-  if (NULL == p)
+  GCPP_try_path_from_dht (get_path,
+                          get_path_length,
+                          put_path,
+                          put_path_length);
+  if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
+       (ntohs (hello->header.size) == size) &&
+       (size == GNUNET_HELLO_size (hello)) )
   {
-    GNUNET_break_op (0);
-    return;
+    peer = GCP_get (&put_path[0],
+                    GNUNET_YES);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got HELLO for %s\n",
+         GCP_2s (peer));
+    GCP_set_hello (peer,
+                   hello);
   }
-
-  s = path_2s (p);
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Got path from DHT: %s\n",
-       s);
-  GNUNET_free_non_null (s);
-
-  peer = GCP_get_short (p->peers[p->length - 1], GNUNET_YES);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Got HELLO for %s\n",
-       GCP_2s (peer));
-  h->callback (h->cls, p);
-  path_destroy (p);
-  hello = (struct GNUNET_HELLO_Message *) data;
-  GCP_set_hello (peer, hello);
-  GCP_try_connect (peer);
 }
 
 
@@ -229,19 +155,10 @@ announce_id (void *cls)
   struct GNUNET_TIME_Absolute expiration;
   struct GNUNET_TIME_Relative next_put;
 
-  announce_id_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Announce ID\n");
   hello = GCH_get_mine ();
   size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
-  if ( (NULL == hello) || (0 == size) )
+  if (0 == size)
   {
-    /* Peerinfo gave us no hello yet, try again soon. */
-    LOG (GNUNET_ERROR_TYPE_INFO,
-        "  no hello, waiting!\n");
-    GNUNET_STATISTICS_update (stats,
-                             "# DHT announce skipped (no hello)",
-                              1,
-                             GNUNET_NO);
     expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
                                            announce_delay);
     announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
@@ -252,71 +169,64 @@ announce_id (void *cls)
     announce_delay = GNUNET_TIME_UNIT_SECONDS;
   }
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Hello %p size: %u\n",
-       hello,
-       size);
-  if (NULL != hello)
-  {
-    GNUNET_STATISTICS_update (stats,
-                             "# DHT announce",
-                             1, GNUNET_NO);
-    memset (&phash,
-           0,
-           sizeof (phash));
-    GNUNET_memcpy (&phash,
-                  &my_full_id,
-                  sizeof (my_full_id));
-    GNUNET_DHT_put (dht_handle,   /* DHT handle */
-                   &phash,       /* Key to use */
-                   dht_replication_level,     /* Replication level */
-                   GNUNET_DHT_RO_RECORD_ROUTE
-                   | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
-                   GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
-                   size,  /* Size of the data */
-                   (const char *) hello, /* Data itself */
-                   expiration,  /* Data expiration */
-                   NULL,         /* Continuation */
-                   NULL);        /* Continuation closure */
-  }
   /* Call again in id_announce_time, unless HELLO expires first,
    * but wait at least 1s. */
-  next_put = GNUNET_TIME_absolute_get_remaining (expiration);
-  next_put = GNUNET_TIME_relative_min (next_put,
-                                      id_announce_time);
-  next_put = GNUNET_TIME_relative_max (next_put,
-                                      GNUNET_TIME_UNIT_SECONDS);
-  announce_id_task = GNUNET_SCHEDULER_add_delayed (next_put,
-                                                  &announce_id,
-                                                  cls);
+  next_put
+    = GNUNET_TIME_absolute_get_remaining (expiration);
+  next_put
+    = GNUNET_TIME_relative_min (next_put,
+                                id_announce_time);
+  next_put
+    = GNUNET_TIME_relative_max (next_put,
+                                GNUNET_TIME_UNIT_SECONDS);
+  announce_id_task
+    = GNUNET_SCHEDULER_add_delayed (next_put,
+                                    &announce_id,
+                                    cls);
+  GNUNET_STATISTICS_update (stats,
+                            "# DHT announce",
+                            1,
+                            GNUNET_NO);
+  memset (&phash,
+          0,
+          sizeof (phash));
+  GNUNET_memcpy (&phash,
+                 &my_full_id,
+                 sizeof (my_full_id));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Announcing my HELLO (%u bytes) in the DHT\n",
+       size);
+  GNUNET_DHT_put (dht_handle,   /* DHT handle */
+                  &phash,       /* Key to use */
+                  dht_replication_level,     /* Replication level */
+                  GNUNET_DHT_RO_RECORD_ROUTE
+                  | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,    /* DHT options */
+                  GNUNET_BLOCK_TYPE_DHT_HELLO,       /* Block type */
+                  size,  /* Size of the data */
+                  (const char *) hello, /* Data itself */
+                  expiration,  /* Data expiration */
+                  NULL,         /* Continuation */
+                  NULL);        /* Continuation closure */
 }
 
+
 /**
- * Iterator over hash map entries and stop GET requests before disconnecting
- * from the DHT.
- *
- * @param cls Closure (unused)
- * @param key Current peer ID.
- * @param value Value in the hash map (GCD_search_handle).
- *
- * @return #GNUNET_YES, we should continue to iterate,
+ * Function called by the HELLO subsystem whenever OUR hello
+ * changes. Re-triggers the DHT PUT immediately.
  */
-int
-stop_get (void *cls,
-          uint32_t key,
-          void *value)
+void
+GCD_hello_update ()
 {
-  struct GCD_search_handle *h = value;
-
-  GCD_search_stop (h);
-  return GNUNET_YES;
+  if (NULL == announce_id_task)
+    return; /* too early */
+  GNUNET_SCHEDULER_cancel (announce_id_task);
+  announce_id_task
+    = GNUNET_SCHEDULER_add_delayed (CHANGE_DELAY,
+                                    &announce_id,
+                                    NULL);
 }
 
 
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
-
 /**
  * Initialize the DHT subsystem.
  *
@@ -325,36 +235,40 @@ stop_get (void *cls,
 void
 GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c, "CADET",
+      GNUNET_CONFIGURATION_get_value_number (c,
+                                             "CADET",
                                              "DHT_REPLICATION_LEVEL",
                                              &dht_replication_level))
   {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, "CADET",
-                               "DHT_REPLICATION_LEVEL", "USING DEFAULT");
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+                               "CADET",
+                               "DHT_REPLICATION_LEVEL",
+                               "USING DEFAULT");
     dht_replication_level = 3;
   }
 
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME",
+      GNUNET_CONFIGURATION_get_value_time (c,
+                                           "CADET",
+                                           "ID_ANNOUNCE_TIME",
                                            &id_announce_time))
   {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "CADET",
-                               "ID_ANNOUNCE_TIME", "MISSING");
+    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+                               "CADET",
+                               "ID_ANNOUNCE_TIME",
+                               "MISSING");
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
 
-  dht_handle = GNUNET_DHT_connect (c, 64);
-  if (NULL == dht_handle)
-  {
-    GNUNET_break (0);
-  }
-
+  dht_handle = GNUNET_DHT_connect (c,
+                                   64);
+  GNUNET_break (NULL != dht_handle);
   announce_delay = GNUNET_TIME_UNIT_SECONDS;
-  announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL);
-  get_requests = GNUNET_CONTAINER_multihashmap32_create (32);
+  announce_id_task = GNUNET_SCHEDULER_add_delayed (STARTUP_DELAY,
+                                                   &announce_id,
+                                                   NULL);
 }
 
 
@@ -364,10 +278,7 @@ GCD_init (const struct GNUNET_CONFIGURATION_Handle *c)
 void
 GCD_shutdown (void)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down DHT\n");
-  GNUNET_CONTAINER_multihashmap32_iterate (get_requests, &stop_get, NULL);
-  GNUNET_CONTAINER_multihashmap32_destroy (get_requests);
-  if (dht_handle != NULL)
+  if (NULL != dht_handle)
   {
     GNUNET_DHT_disconnect (dht_handle);
     dht_handle = NULL;
@@ -379,22 +290,31 @@ GCD_shutdown (void)
   }
 }
 
+
+/**
+ * Search DHT for paths to @a peeR_id
+ *
+ * @param peer_id peer to search for
+ * @return handle to abort search
+ */
 struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id,
-            GCD_search_callback callback, void *cls)
+GCD_search (const struct GNUNET_PeerIdentity *peer_id)
 {
   struct GNUNET_HashCode phash;
   struct GCD_search_handle *h;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting DHT GET for peer %s\n",
-       GNUNET_i2s (peer_id));
-  GNUNET_STATISTICS_update (stats, "# DHT search", 1, GNUNET_NO);
-  memset (&phash, 0, sizeof (phash));
-  GNUNET_memcpy (&phash, peer_id, sizeof (*peer_id));
+  GNUNET_STATISTICS_update (stats,
+                            "# DHT search",
+                            1,
+                            GNUNET_NO);
+  memset (&phash,
+          0,
+          sizeof (phash));
+  GNUNET_memcpy (&phash,
+                 peer_id,
+                 sizeof (*peer_id));
+
   h = GNUNET_new (struct GCD_search_handle);
-  h->peer_id = GNUNET_PEER_intern (peer_id);
-  h->callback = callback;
-  h->cls = cls;
   h->dhtget = GNUNET_DHT_get_start (dht_handle,    /* handle */
                                     GNUNET_BLOCK_TYPE_DHT_HELLO, /* type */
                                     &phash,     /* key to search */
@@ -405,20 +325,27 @@ GCD_search (const struct GNUNET_PeerIdentity *peer_id,
                                     0,     /* xquery bits */
                                     &dht_get_id_handler,
                                    h);
-  GNUNET_CONTAINER_multihashmap32_put (get_requests,
-                                      h->peer_id,
-                                      h,
-                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Starting DHT GET for peer %s (%p)\n",
+       GNUNET_i2s (peer_id),
+       h);
   return h;
 }
 
 
+/**
+ * Stop DHT search started with #GCD_search().
+ *
+ * @param h handle to search to stop
+ */
 void
 GCD_search_stop (struct GCD_search_handle *h)
 {
-  GNUNET_break (GNUNET_OK ==
-                GNUNET_CONTAINER_multihashmap32_remove (get_requests,
-                                                        h->peer_id, h));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Stopping DHT GET %p\n",
+       h);
   GNUNET_DHT_get_stop (h->dhtget);
   GNUNET_free (h);
 }
+
+/* end of gnunet-service-cadet_dht.c */
index b70dfe975f016f64cf896cb689f1ea6aaca4290c..5d7ab29a067ebed4da138cc4614fd2600f7777a9 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
+     Copyright (C) 2013, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
  * @file cadet/gnunet-service-cadet_dht.h
  * @brief cadet service; dealing with DHT requests and results
  * @author Bartlomiej Polot
+ * @author Christian Grothoff
  *
- * All functions in this file should use the prefix GMD (Gnunet Cadet Dht)
+ * All functions in this file should use the prefix GCD (Gnunet Cadet Dht)
  */
-
 #ifndef GNUNET_SERVICE_CADET_DHT_H
 #define GNUNET_SERVICE_CADET_DHT_H
 
@@ -40,23 +40,11 @@ extern "C"
 #include "platform.h"
 #include "gnunet_util_lib.h"
 
-struct GCD_search_handle;
-
-
 /**
- * Callback called on each path found over the DHT.
- *
- * @param cls Closure.
- * @param path An unchecked, unoptimized path to the target node.
- *             After callback will no longer be valid!
+ * Handle for DHT search operation.
  */
-typedef void
-(*GCD_search_callback) (void *cls,
-                        const struct CadetPeerPath *path);
+struct GCD_search_handle;
 
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
 
 /**
  * Initialize the DHT subsystem.
@@ -66,6 +54,7 @@ typedef void
 void
 GCD_init (const struct GNUNET_CONFIGURATION_Handle *c);
 
+
 /**
  * Shut down the DHT subsystem.
  */
@@ -73,14 +62,32 @@ void
 GCD_shutdown (void);
 
 
+/**
+ * Function called by the HELLO subsystem whenever OUR hello
+ * changes. Re-triggers the DHT PUT immediately.
+ */
+void
+GCD_hello_update (void);
+
+/**
+ * Search DHT for paths to @a peeR_id
+ *
+ * @param peer_id peer to search for
+ * @return handle to abort search
+ */
 struct GCD_search_handle *
-GCD_search (const struct GNUNET_PeerIdentity *peer_id,
-            GCD_search_callback callback, void *cls);
+GCD_search (const struct GNUNET_PeerIdentity *peer_id);
 
 
+/**
+ * Stop DHT search started with #GCD_search().
+ *
+ * @param h handle to search to stop
+ */
 void
 GCD_search_stop (struct GCD_search_handle *h);
 
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif
@@ -88,6 +95,6 @@ GCD_search_stop (struct GCD_search_handle *h);
 }
 #endif
 
-/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */
+/* ifndef GNUNET_CADET_SERVICE_DHT_H */
 #endif
-/* end of gnunet-cadet-service_LOCAL.h */
+/* end of gnunet-service-cadet_dht.h */
index 3c63f3551b610bae1f881be64537b535aad7b563..6d85de39f6af8561366306dbe926a5cdb6185e43 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2014 GNUnet e.V.
+     Copyright (C) 2014, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      Boston, MA 02110-1301, USA.
 */
-
+/**
+ * @file cadet/gnunet-service-cadet_hello.c
+ * @brief spread knowledge about how to contact other peers from PEERINFO
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - is most of this necessary/helpful?
+ * - should we not simply restrict this to OUR hello?
+ */
 #include "platform.h"
 #include "gnunet_util_lib.h"
 
 #include "gnunet_statistics_service.h"
 #include "gnunet_peerinfo_service.h"
-
 #include "cadet_protocol.h"
-#include "cadet_path.h"
-
+#include "gnunet-service-cadet.h"
+#include "gnunet-service-cadet_dht.h"
 #include "gnunet-service-cadet_hello.h"
 #include "gnunet-service-cadet_peer.h"
 
 #define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
 
-
-/******************************************************************************/
-/********************************   STRUCTS  **********************************/
-/******************************************************************************/
-
-
-
-/******************************************************************************/
-/*******************************   GLOBALS  ***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Local peer own ID (memory efficient handle).
- */
-extern GNUNET_PEER_Id myid;
-
-/**
- * Local peer own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-
-/**
- * Don't try to recover tunnels if shutting down.
- */
-extern int shutting_down;
-
-
 /**
  * Hello message of local peer.
  */
-const struct GNUNET_HELLO_Message *mine;
+static struct GNUNET_HELLO_Message *mine;
 
 /**
  * Handle to peerinfo service.
@@ -78,13 +53,9 @@ static struct GNUNET_PEERINFO_Handle *peerinfo;
 /**
  * Iterator context.
  */
-struct GNUNET_PEERINFO_NotifyContext* nc;
+static struct GNUNET_PEERINFO_NotifyContext *nc;
 
 
-/******************************************************************************/
-/********************************   STATIC  ***********************************/
-/******************************************************************************/
-
 /**
  * Process each hello message received from peerinfo.
  *
@@ -94,31 +65,37 @@ struct GNUNET_PEERINFO_NotifyContext* nc;
  * @param err_msg Error message.
  */
 static void
-got_hello (void *cls, const struct GNUNET_PeerIdentity *id,
+got_hello (void *cls,
+           const struct GNUNET_PeerIdentity *id,
            const struct GNUNET_HELLO_Message *hello,
            const char *err_msg)
 {
   struct CadetPeer *peer;
 
-  if (NULL == id || NULL == hello)
+  if ( (NULL == id) ||
+       (NULL == hello) )
+    return;
+  if (0 == memcmp (id,
+                   &my_full_id,
+                   sizeof (struct GNUNET_PeerIdentity)))
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " hello with id %p and msg %p\n", id, hello);
+    GNUNET_free_non_null (mine);
+    mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header);
+    GCD_hello_update ();
     return;
   }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " hello for %s (%d bytes), expires on %s\n",
-       GNUNET_i2s (id), GNUNET_HELLO_size (hello),
-       GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration(hello)));
-  peer = GCP_get (id, GNUNET_YES);
-  GCP_set_hello (peer, hello);
-
-  if (GCP_get_short_id (peer) == myid)
-    mine = GCP_get_hello (peer);
-}
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Hello for %s (%d bytes), expires on %s\n",
+       GNUNET_i2s (id),
+       GNUNET_HELLO_size (hello),
+       GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration (hello)));
+  peer = GCP_get (id,
+                  GNUNET_YES);
+  GCP_set_hello (peer,
+                 hello);
+}
 
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
 
 /**
  * Initialize the hello subsystem.
@@ -128,10 +105,12 @@ got_hello (void *cls, const struct GNUNET_PeerIdentity *id,
 void
 GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
   GNUNET_assert (NULL == nc);
   peerinfo = GNUNET_PEERINFO_connect (c);
-  nc = GNUNET_PEERINFO_notify (c, GNUNET_NO, &got_hello, NULL);
+  nc = GNUNET_PEERINFO_notify (c,
+                               GNUNET_NO,
+                               &got_hello,
+                               NULL);
 }
 
 
@@ -141,7 +120,6 @@ GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
 void
 GCH_shutdown ()
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down channels\n");
   if (NULL != nc)
   {
     GNUNET_PEERINFO_notify_cancel (nc);
@@ -152,6 +130,11 @@ GCH_shutdown ()
     GNUNET_PEERINFO_disconnect (peerinfo);
     peerinfo = NULL;
   }
+  if (NULL != mine)
+  {
+    GNUNET_free (mine);
+    mine = NULL;
+  }
 }
 
 
@@ -166,35 +149,4 @@ GCH_get_mine (void)
   return mine;
 }
 
-
-/**
- * Get another peer's hello message.
- *
- * @param id ID of the peer whose hello message is requested.
- *
- * @return Hello message, if any (NULL possible).
- */
-const struct GNUNET_HELLO_Message *
-GCH_get (const struct GNUNET_PeerIdentity *id)
-{
-  struct CadetPeer *p;
-
-  p = GCP_get (id, GNUNET_NO);
-  if (NULL == p)
-    return NULL;
-  return GCP_get_hello (p);
-}
-
-
-/**
- * Convert a hello message to a string.
- *
- * @param h Hello message.
- */
-char *
-GCH_2s (const struct GNUNET_HELLO_Message *h)
-{
-  return "hello (TODO)";
-}
-
-
+/* end of gnunet-service-cadet-new_hello.c */
index 34121e1e0106f18bf46ea6516823ceb3b033215b..4291ae985da55f266cda94350f808d5a06081213 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2014 GNUnet e.V.
+     Copyright (C) 2014, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -22,8 +22,9 @@
  * @file cadet/gnunet-service-cadet_hello.h
  * @brief cadet service; dealing with hello messages
  * @author Bartlomiej Polot
+ * @author Christian Grothoff
  *
- * All functions in this file should use the prefix GMH (Gnunet Cadet Hello)
+ * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
  */
 
 #ifndef GNUNET_SERVICE_CADET_HELLO_H
diff --git a/src/cadet/gnunet-service-cadet_local.c b/src/cadet/gnunet-service-cadet_local.c
deleted file mode 100644 (file)
index dea6681..0000000
+++ /dev/null
@@ -1,1553 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#include "gnunet_statistics_service.h"
-
-#include "cadet.h"
-#include "cadet_protocol.h" /* GNUNET_CADET_Data is shared */
-
-#include "gnunet-service-cadet_local.h"
-#include "gnunet-service-cadet_channel.h"
-
-/* INFO DEBUG */
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-loc",__VA_ARGS__)
-
-/******************************************************************************/
-/********************************   STRUCTS  **********************************/
-/******************************************************************************/
-
-/**
- * Struct containing information about a client of the service
- *
- * TODO: add a list of 'waiting' ports
- */
-struct CadetClient
-{
-  /**
-   * Linked list next
-   */
-  struct CadetClient *next;
-
-  /**
-   * Linked list prev
-   */
-  struct CadetClient *prev;
-
-  /**
-   * Tunnels that belong to this client, indexed by local id
-   */
-  struct GNUNET_CONTAINER_MultiHashMap32 *own_channels;
-
-  /**
-   * Tunnels this client has accepted, indexed by incoming local id
-   */
-  struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels;
-
-  /**
-   * Channel ID for the next incoming channel.
-   */
-  struct GNUNET_CADET_ClientChannelNumber next_ccn;
-
-  /**
-   * Handle to communicate with the client
-   */
-  struct GNUNET_SERVER_Client *handle;
-
-  /**
-   * Ports that this client has declared interest in.
-   * Indexed by port, contains *Client.
-   */
-  struct GNUNET_CONTAINER_MultiHashMap *ports;
-
-  /**
-   * Whether the client is active or shutting down (don't send confirmations
-   * to a client that is shutting down.
-   */
-  int shutting_down;
-
-  /**
-   * ID of the client, mainly for debug messages
-   */
-  unsigned int id;
-};
-
-/******************************************************************************/
-/*******************************   GLOBALS  ***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Handle to server lib.
- */
-static struct GNUNET_SERVER_Handle *server_handle;
-
-/**
- * DLL with all the clients, head.
- */
-static struct CadetClient *clients_head;
-
-/**
- * DLL with all the clients, tail.
- */
-static struct CadetClient *clients_tail;
-
-/**
- * Next ID to assign to a client.
- */
-unsigned int next_client_id;
-
-/**
- * All ports clients of this peer have opened.
- */
-static struct GNUNET_CONTAINER_MultiHashMap *ports;
-
-/**
- * Notification context, to send messages to local clients.
- */
-static struct GNUNET_SERVER_NotificationContext *nc;
-
-
-/******************************************************************************/
-/********************************   STATIC  ***********************************/
-/******************************************************************************/
-
-/**
- * Remove client's ports from the global hashmap on disconnect.
- *
- * @param cls Closure (unused).
- * @param key Port.
- * @param value Client structure.
- *
- * @return #GNUNET_OK, keep iterating.
- */
-static int
-client_release_ports (void *cls,
-                      const struct GNUNET_HashCode *key,
-                      void *value)
-{
-  int res;
-
-  res = GNUNET_CONTAINER_multihashmap_remove (ports, key, value);
-  if (GNUNET_YES != res)
-  {
-    GNUNET_break (0);
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Port %s by client %p was not registered.\n",
-         GNUNET_h2s (key), value);
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Iterator for deleting each channel whose client endpoint disconnected.
- *
- * @param cls Closure (client that has disconnected).
- * @param key The local channel id (used to access the hashmap).
- * @param value The value stored at the key (channel to destroy).
- *
- * @return #GNUNET_OK, keep iterating.
- */
-static int
-channel_destroy_iterator (void *cls,
-                          uint32_t key,
-                          void *value)
-{
-  struct CadetChannel *ch = value;
-  struct CadetClient *c = cls;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " Channel %s destroy, due to client %s shutdown.\n",
-       GCCH_2s (ch), GML_2s (c));
-
-  GCCH_handle_local_destroy (ch,
-                             c,
-                             key < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-  return GNUNET_OK;
-}
-
-
-/**
- * Unregister data and free memory for a client.
- *
- * @param c Client to destroy. No longer valid after call.
- */
-static void
-client_destroy (struct CadetClient *c)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  client destroy: %p/%u\n", c, c->id);
-  GNUNET_SERVER_client_drop (c->handle);
-  c->shutting_down = GNUNET_YES;
-
-  if (NULL != c->own_channels)
-  {
-    GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels,
-                                             &channel_destroy_iterator, c);
-    GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels);
-  }
-  if (NULL != c->incoming_channels)
-  {
-    GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels,
-                                             &channel_destroy_iterator, c);
-    GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels);
-  }
-  if (NULL != c->ports)
-  {
-    GNUNET_CONTAINER_multihashmap_iterate (c->ports,
-                                           &client_release_ports, c);
-    GNUNET_CONTAINER_multihashmap_destroy (c->ports);
-  }
-
-  GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c);
-  GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO);
-  GNUNET_SERVER_client_set_user_context (c->handle, NULL);
-  GNUNET_free (c);
-}
-
-
-/**
- * Create a client record, register data and initialize memory.
- *
- * @param client Client's handle.
- */
-static struct CadetClient *
-client_new (struct GNUNET_SERVER_Client *client)
-{
-  struct CadetClient *c;
-
-  GNUNET_SERVER_client_keep (client);
-  GNUNET_SERVER_notification_context_add (nc, client);
-
-  c = GNUNET_new (struct CadetClient);
-  c->handle = client;
-  c->id = next_client_id++; /* overflow not important: just for debug */
-
-  c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32);
-  c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32);
-
-  GNUNET_SERVER_client_set_user_context (client, c);
-  GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c);
-  GNUNET_STATISTICS_update (stats, "# clients", +1, GNUNET_NO);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  client created: %p/%u\n", c, c->id);
-
-  return c;
-}
-
-
-/******************************************************************************/
-/********************************  HANDLES  ***********************************/
-/******************************************************************************/
-
-/**
- * Handler for client connection.
- *
- * @param cls Closure (unused).
- * @param client Client handler.
- */
-static void
-handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client);
-  if (NULL == client)
-    return;
-
-  (void) client_new (client);
-}
-
-
-/**
- * Handler for client disconnection
- *
- * @param cls closure
- * @param client identification of the client; NULL
- *        for the last call when the server is destroyed
- */
-static void
-handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
-{
-  struct CadetClient *c;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected: %p\n", client);
-
-  c = GML_client_get (client);
-  if (NULL != c)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n",
-                c->id, c);
-    client_destroy (c);
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " disconnecting client's context NULL\n");
-  }
-  return;
-}
-
-
-/**
- * Handler for port open requests.
- *
- * @param cls Closure.
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_port_open (void *cls, struct GNUNET_SERVER_Client *client,
-                  const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c;
-  struct GNUNET_CADET_PortMessage *pmsg;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "open port requested\n");
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  by client %u\n", c->id);
-
-  /* Message size sanity check */
-  if (sizeof (struct GNUNET_CADET_PortMessage) != ntohs (message->size))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  pmsg = (struct GNUNET_CADET_PortMessage *) message;
-  if (NULL == c->ports)
-  {
-    c->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO);
-  }
-  /* store in client's hashmap */
-  if (GNUNET_OK !=
-      GNUNET_CONTAINER_multihashmap_put (c->ports, &pmsg->port, c,
-                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-  /* store in global hashmap */
-  /* FIXME only allow one client to have the port open,
-   *       have a backup hashmap with waiting clients */
-  GNUNET_CONTAINER_multihashmap_put (ports, &pmsg->port, c,
-                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
-
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handler for port close requests.
- *
- * @param cls Closure.
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_port_close (void *cls, struct GNUNET_SERVER_Client *client,
-                   const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c;
-  struct GNUNET_CADET_PortMessage *pmsg;
-  int removed;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "close port requested\n");
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  by client %u\n", c->id);
-
-    /* Message size sanity check */
-  if (sizeof (struct GNUNET_CADET_PortMessage) != ntohs (message->size))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  pmsg = (struct GNUNET_CADET_PortMessage *) message;
-  removed = GNUNET_CONTAINER_multihashmap_remove (c->ports, &pmsg->port, c);
-  GNUNET_break_op (GNUNET_YES == removed);
-  removed = GNUNET_CONTAINER_multihashmap_remove (ports, &pmsg->port, c);
-  GNUNET_break_op (GNUNET_YES == removed);
-
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handler for requests of new channels.
- *
- * @param cls Closure.
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client,
-                       const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n");
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  by client %u\n", c->id);
-
-  /* Message size sanity check */
-  if (sizeof (struct GNUNET_CADET_LocalChannelCreateMessage)
-      != ntohs (message->size))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  if (GNUNET_OK !=
-      GCCH_handle_local_create (c,
-                                (struct GNUNET_CADET_LocalChannelCreateMessage *)
-                                message))
-  {
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handler for requests of deleting tunnels
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
-                        const struct GNUNET_MessageHeader *message)
-{
-  const struct GNUNET_CADET_LocalChannelDestroyMessage *msg;
-  struct CadetClient *c;
-  struct CadetChannel *ch;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n");
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  by client %u\n", c->id);
-
-  /* Message sanity check */
-  if (sizeof (struct GNUNET_CADET_LocalChannelDestroyMessage)
-      != ntohs (message->size))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  msg = (const struct GNUNET_CADET_LocalChannelDestroyMessage *) message;
-
-  /* Retrieve tunnel */
-  ccn = msg->ccn;
-  ch = GML_channel_get (c, ccn);
-
-  LOG (GNUNET_ERROR_TYPE_INFO, "Client %u is destroying channel %X\n",
-       c->id, ccn);
-
-  if (NULL == ch)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING, "  channel %X not found\n", ccn);
-    GNUNET_STATISTICS_update (stats,
-                              "# client destroy messages on unknown channel",
-                              1, GNUNET_NO);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  GCCH_handle_local_destroy (ch,
-                             c,
-                             ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handler for client traffic
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_data (void *cls, struct GNUNET_SERVER_Client *client,
-             const struct GNUNET_MessageHeader *message)
-{
-  const struct GNUNET_MessageHeader *payload;
-  struct GNUNET_CADET_LocalData *msg;
-  struct CadetClient *c;
-  struct CadetChannel *ch;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-  size_t message_size;
-  size_t payload_size;
-  size_t payload_claimed_size;
-  int fwd;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data from a client\n");
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  /* Sanity check for message size */
-  message_size = ntohs (message->size);
-  if (sizeof (struct GNUNET_CADET_LocalData)
-      + sizeof (struct GNUNET_MessageHeader) > message_size
-      || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < message_size)
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  /* Sanity check for payload size */
-  payload_size = message_size - sizeof (struct GNUNET_CADET_LocalData);
-  msg = (struct GNUNET_CADET_LocalData *) message;
-  payload = (struct GNUNET_MessageHeader *) &msg[1];
-  payload_claimed_size = ntohs (payload->size);
-  if (sizeof (struct GNUNET_MessageHeader) > payload_claimed_size
-      || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size
-      || payload_claimed_size > payload_size)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "client claims to send %u bytes in %u payload\n",
-         payload_claimed_size, payload_size);
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  ccn = msg->ccn;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  %u bytes (%u payload) by client %u\n",
-       payload_size, payload_claimed_size, c->id);
-
-  /* Channel exists? */
-  fwd = ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
-  ch = GML_channel_get (c, ccn);
-  if (NULL == ch)
-  {
-    GNUNET_STATISTICS_update (stats,
-                              "# client data messages on unknown channel",
-                              1, GNUNET_NO);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  if (GNUNET_OK != GCCH_handle_local_data (ch, c, fwd, payload, payload_size))
-  {
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n");
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
-  return;
-}
-
-
-/**
- * Handler for client's ACKs for payload traffic.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_ack (void *cls, struct GNUNET_SERVER_Client *client,
-            const struct GNUNET_MessageHeader *message)
-{
-  struct GNUNET_CADET_LocalAck *msg;
-  struct CadetChannel *ch;
-  struct CadetClient *c;
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-  int fwd;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "\n");
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n");
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  by client %u\n", c->id);
-
-  msg = (struct GNUNET_CADET_LocalAck *) message;
-
-  /* Channel exists? */
-  ccn = msg->ccn;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  on channel %X\n",
-       ntohl (ccn.channel_of_client));
-  ch = GML_channel_get (c, ccn);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "   -- ch %p\n", ch);
-  if (NULL == ch)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Channel %X unknown.\n",
-         ntohl (ccn.channel_of_client));
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  for client %u.\n", c->id);
-    GNUNET_STATISTICS_update (stats,
-                              "# client ack messages on unknown channel",
-                              1, GNUNET_NO);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */
-  /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */
-  fwd = ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
-
-  GCCH_handle_local_ack (ch, fwd);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Iterator over all peers to send a monitoring client info about each peer.
- *
- * @param cls Closure ().
- * @param peer Peer ID (tunnel remote peer).
- * @param value Peer info.
- *
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-get_all_peers_iterator (void *cls,
-                        const struct GNUNET_PeerIdentity * peer,
-                        void *value)
-{
-  struct GNUNET_SERVER_Client *client = cls;
-  struct CadetPeer *p = value;
-  struct GNUNET_CADET_LocalInfoPeer msg;
-
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
-  msg.destination = *peer;
-  msg.paths = htons (GCP_count_paths (p));
-  msg.tunnel = htons (NULL != GCP_get_tunnel (p));
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about peer %s\n",
-       GNUNET_i2s (peer));
-
-  GNUNET_SERVER_notification_context_unicast (nc, client,
-                                              &msg.header, GNUNET_NO);
-  return GNUNET_YES;
-}
-
-
-/**
- * Iterator over all peers to dump info for each peer.
- *
- * @param cls Closure (unused).
- * @param peer Peer ID (tunnel remote peer).
- * @param value Peer info.
- *
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-show_peer_iterator (void *cls,
-                        const struct GNUNET_PeerIdentity * peer,
-                        void *value)
-{
-  struct CadetPeer *p = value;
-  struct CadetTunnel *t;
-
-  t = GCP_get_tunnel (p);
-  if (NULL != t)
-    GCT_debug (t, GNUNET_ERROR_TYPE_ERROR);
-
-  LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
-
-  return GNUNET_YES;
-}
-
-
-/**
- * Iterator over all paths of a peer to build an InfoPeer message.
- *
- * Message contains blocks of peers, first not included.
- *
- * @param cls Closure (message to build).
- * @param peer Peer this path is towards.
- * @param path Path itself
- * @return #GNUNET_YES if should keep iterating.
- *         #GNUNET_NO otherwise.
- */
-static int
-path_info_iterator (void *cls,
-                    struct CadetPeer *peer,
-                    struct CadetPeerPath *path)
-{
-  struct GNUNET_CADET_LocalInfoPeer *resp = cls;
-  struct GNUNET_PeerIdentity *id;
-  uint16_t msg_size;
-  uint16_t path_size;
-  unsigned int i;
-
-  msg_size = ntohs (resp->header.size);
-  path_size = sizeof (struct GNUNET_PeerIdentity) * (path->length - 1);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Info Path %u\n", path->length);
-  if (msg_size + path_size > UINT16_MAX)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING, "path too long for info message\n");
-    return GNUNET_NO;
-  }
-
-  i = msg_size - sizeof (struct GNUNET_CADET_LocalInfoPeer);
-  i = i / sizeof (struct GNUNET_PeerIdentity);
-
-  /* Set id to the address of the first free peer slot. */
-  id = (struct GNUNET_PeerIdentity *) &resp[1];
-  id = &id[i];
-
-  /* Don't copy first peers.
-   * First peer is always the local one.
-   * Last peer is always the destination (leave as 0, EOL).
-   */
-  for (i = 0; i < path->length - 1; i++)
-  {
-    GNUNET_PEER_resolve (path->peers[i + 1], &id[i]);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&id[i]));
-  }
-
-  resp->header.size = htons (msg_size + path_size);
-
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO PEERS request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_get_peers (void *cls, struct GNUNET_SERVER_Client *client,
-                    const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c;
-  struct GNUNET_MessageHeader reply;
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received get peers request from client %u (%p)\n",
-       c->id, client);
-
-  GCP_iterate_all (get_all_peers_iterator, client);
-  reply.size = htons (sizeof (reply));
-  reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
-  GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Get peers request from client %u completed\n", c->id);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handler for client's SHOW_PEER request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-void
-handle_show_peer (void *cls, struct GNUNET_SERVER_Client *client,
-                  const struct GNUNET_MessageHeader *message)
-{
-  const struct GNUNET_CADET_LocalInfo *msg;
-  struct GNUNET_CADET_LocalInfoPeer *resp;
-  struct CadetPeer *p;
-  struct CadetClient *c;
-  unsigned char cbuf[64 * 1024];
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  msg = (struct GNUNET_CADET_LocalInfo *) message;
-  resp = (struct GNUNET_CADET_LocalInfoPeer *) cbuf;
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Received peer info request from client %u for peer %s\n",
-       c->id, GNUNET_i2s_full (&msg->peer));
-
-  resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
-  resp->header.size = htons (sizeof (struct GNUNET_CADET_LocalInfoPeer));
-  resp->destination = msg->peer;
-  p = GCP_get (&msg->peer, GNUNET_NO);
-  if (NULL == p)
-  {
-    /* We don't know the peer */
-
-    LOG (GNUNET_ERROR_TYPE_INFO, "Peer %s unknown\n",
-         GNUNET_i2s_full (&msg->peer));
-    resp->paths = htons (0);
-    resp->tunnel = htons (NULL != GCP_get_tunnel (p));
-
-    GNUNET_SERVER_notification_context_unicast (nc, client,
-                                                &resp->header,
-                                                GNUNET_NO);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  resp->paths = htons (GCP_count_paths (p));
-  resp->tunnel = htons (NULL != GCP_get_tunnel (p));
-  GCP_iterate_paths (p, &path_info_iterator, resp);
-
-  GNUNET_SERVER_notification_context_unicast (nc, c->handle,
-                                              &resp->header, GNUNET_NO);
-
-  LOG (GNUNET_ERROR_TYPE_INFO, "Show peer from client %u completed.\n", c->id);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Iterator over all tunnels to send a monitoring client info about each tunnel.
- *
- * @param cls Closure ().
- * @param peer Peer ID (tunnel remote peer).
- * @param value Tunnel info.
- *
- * @return #GNUNET_YES, to keep iterating.
- */
-static int
-get_all_tunnels_iterator (void *cls,
-                          const struct GNUNET_PeerIdentity * peer,
-                          void *value)
-{
-  struct GNUNET_SERVER_Client *client = cls;
-  struct CadetTunnel *t = value;
-  struct GNUNET_CADET_LocalInfoTunnel msg;
-
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
-  msg.destination = *peer;
-  msg.channels = htonl (GCT_count_channels (t));
-  msg.connections = htonl (GCT_count_any_connections (t));
-  msg.cstate = htons ((uint16_t) GCT_get_cstate (t));
-  msg.estate = htons ((uint16_t) GCT_get_estate (t));
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about tunnel ->%s\n",
-       GNUNET_i2s (peer));
-
-  GNUNET_SERVER_notification_context_unicast (nc, client,
-                                              &msg.header, GNUNET_NO);
-  return GNUNET_YES;
-}
-
-
-/**
- * Handler for client's INFO TUNNELS request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-static void
-handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client,
-                    const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c;
-  struct GNUNET_MessageHeader reply;
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received get tunnels request from client %u (%p)\n",
-       c->id, client);
-
-  GCT_iterate_all (get_all_tunnels_iterator, client);
-  reply.size = htons (sizeof (reply));
-  reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
-  GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Get tunnels request from client %u completed\n", c->id);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-static void
-iter_connection (void *cls, struct CadetConnection *c)
-{
-  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
-  struct GNUNET_CADET_ConnectionTunnelIdentifier *h;
-
-  h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
-  h[msg->connections] = *(GCC_get_id (c));
-  msg->connections++;
-}
-
-static void
-iter_channel (void *cls, struct CadetChannel *ch)
-{
-  struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
-  struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1];
-  struct GNUNET_CADET_ChannelTunnelNumber *chn = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections];
-
-  chn[msg->channels] = GCCH_get_id (ch);
-  msg->channels++;
-}
-
-
-/**
- * Handler for client's SHOW_TUNNEL request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-void
-handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client,
-                    const struct GNUNET_MessageHeader *message)
-{
-  const struct GNUNET_CADET_LocalInfo *msg;
-  struct GNUNET_CADET_LocalInfoTunnel *resp;
-  struct CadetClient *c;
-  struct CadetTunnel *t;
-  unsigned int ch_n;
-  unsigned int c_n;
-  size_t size;
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  msg = (struct GNUNET_CADET_LocalInfo *) message;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received tunnel info request from client %u for tunnel %s\n",
-       c->id, GNUNET_i2s_full(&msg->peer));
-
-  t = GCP_get_tunnel (GCP_get (&msg->peer, GNUNET_NO));
-  if (NULL == t)
-  {
-    /* We don't know the tunnel */
-    struct GNUNET_CADET_LocalInfoTunnel warn;
-
-    LOG (GNUNET_ERROR_TYPE_INFO, "Tunnel %s unknown %u\n",
-         GNUNET_i2s_full(&msg->peer), sizeof (warn));
-    warn.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
-    warn.header.size = htons (sizeof (warn));
-    warn.destination = msg->peer;
-    warn.channels = htonl (0);
-    warn.connections = htonl (0);
-    warn.cstate = htons (0);
-    warn.estate = htons (0);
-
-    GNUNET_SERVER_notification_context_unicast (nc, client,
-                                                &warn.header,
-                                                GNUNET_NO);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  /* Initialize context */
-  ch_n = GCT_count_channels (t);
-  c_n = GCT_count_any_connections (t);
-
-  size = sizeof (struct GNUNET_CADET_LocalInfoTunnel);
-  size += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier);
-  size += ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber);
-
-  resp = GNUNET_malloc (size);
-  resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
-  resp->header.size = htons (size);
-  resp->destination = msg->peer;
-  /* Do not interleave with iterators, iter_channel needs conn in HBO */
-  GCT_iterate_connections (t, &iter_connection, resp);
-  GCT_iterate_channels (t, &iter_channel, resp);
-  resp->connections = htonl (resp->connections);
-  resp->channels = htonl (resp->channels);
-  /* Do not interleave end */
-  resp->cstate = htons (GCT_get_cstate (t));
-  resp->estate = htons (GCT_get_estate (t));
-  GNUNET_SERVER_notification_context_unicast (nc, c->handle,
-                                              &resp->header, GNUNET_NO);
-  GNUNET_free (resp);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Show tunnel request from client %u completed. %u conn, %u ch\n",
-       c->id, c_n, ch_n);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Handler for client's INFO_DUMP request.
- *
- * @param cls Closure (unused).
- * @param client Identification of the client.
- * @param message The actual message.
- */
-void
-handle_info_dump (void *cls, struct GNUNET_SERVER_Client *client,
-                  const struct GNUNET_MessageHeader *message)
-{
-  struct CadetClient *c;
-
-  /* Sanity check for client registration */
-  if (NULL == (c = GML_client_get (client)))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_INFO, "Received dump info request from client %u\n",
-       c->id);
-  LOG (GNUNET_ERROR_TYPE_ERROR,
-       "*************************** DUMP START ***************************\n");
-
-  for (c = clients_head; NULL != c; c = c->next)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR, "Client %u (%p), handle: %p\n",
-         c->id, c, c->handle);
-    if (NULL != c->ports)
-      LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u ports registered\n",
-           GNUNET_CONTAINER_multihashmap_size (c->ports));
-    else
-      LOG (GNUNET_ERROR_TYPE_ERROR, "\t no ports registered\n");
-    LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u own channles\n",
-         GNUNET_CONTAINER_multihashmap32_size (c->own_channels));
-    LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u incoming channles\n",
-         GNUNET_CONTAINER_multihashmap32_size (c->incoming_channels));
-  }
-  LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
-  GCP_iterate_all (&show_peer_iterator, NULL);
-
-  LOG (GNUNET_ERROR_TYPE_ERROR,
-       "**************************** DUMP END ****************************\n");
-
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Functions to handle messages from clients
- */
-static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
-  {&handle_port_open, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
-    sizeof (struct GNUNET_CADET_PortMessage)},
-  {&handle_port_close, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
-    sizeof (struct GNUNET_CADET_PortMessage)},
-  {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE,
-   sizeof (struct GNUNET_CADET_LocalChannelCreateMessage)},
-  {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY,
-   sizeof (struct GNUNET_CADET_LocalChannelDestroyMessage)},
-  {&handle_data, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, 0},
-  {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
-   sizeof (struct GNUNET_CADET_LocalAck)},
-  {&handle_get_peers, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
-   sizeof (struct GNUNET_MessageHeader)},
-  {&handle_show_peer, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
-   sizeof (struct GNUNET_CADET_LocalInfo)},
-  {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
-   sizeof (struct GNUNET_MessageHeader)},
-  {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
-   sizeof (struct GNUNET_CADET_LocalInfo)},
-  {&handle_info_dump, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
-   sizeof (struct GNUNET_MessageHeader)},
-  {NULL, NULL, 0, 0}
-};
-
-
-
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
-
-/**
- * Initialize server subsystem.
- *
- * @param handle Server handle.
- */
-void
-GML_init (struct GNUNET_SERVER_Handle *handle)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
-  server_handle = handle;
-  GNUNET_SERVER_suspend (server_handle);
-  ports = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
-}
-
-
-/**
- * Install server (service) handlers and start listening to clients.
- */
-void
-GML_start (void)
-{
-  GNUNET_SERVER_add_handlers (server_handle, client_handlers);
-  GNUNET_SERVER_connect_notify (server_handle,  &handle_client_connect, NULL);
-  GNUNET_SERVER_disconnect_notify (server_handle, &handle_client_disconnect,
-                                   NULL);
-  nc = GNUNET_SERVER_notification_context_create (server_handle, 1);
-
-  clients_head = NULL;
-  clients_tail = NULL;
-  next_client_id = 0;
-  GNUNET_SERVER_resume (server_handle);
-}
-
-
-/**
- * Shutdown server.
- */
-void
-GML_shutdown (void)
-{
-  struct CadetClient *c;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down local\n");
-
-  for (c = clients_head; NULL != clients_head; c = clients_head)
-    client_destroy (c);
-
-  if (nc != NULL)
-  {
-    GNUNET_SERVER_notification_context_destroy (nc);
-    nc = NULL;
-  }
-
-}
-
-
-/**
- * Get a channel from a client.
- *
- * @param c Client to check.
- * @param ccn Channel ID, must be local (> 0x800...).
- *
- * @return non-NULL if channel exists in the clients lists
- */
-struct CadetChannel *
-GML_channel_get (struct CadetClient *c,
-                 struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  struct GNUNET_CONTAINER_MultiHashMap32 *map;
-
-  if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-    map = c->own_channels;
-  else
-    map = c->incoming_channels;
-
-  if (NULL == map)
-  {
-    GNUNET_break (0);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Client %s does no t have a valid map for CCN %X\n",
-         GML_2s (c), ccn);
-    return NULL;
-  }
-  return GNUNET_CONTAINER_multihashmap32_get (map,
-                                              ccn.channel_of_client);
-}
-
-
-/**
- * Add a channel to a client
- *
- * @param client Client.
- * @param ccn Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_add (struct CadetClient *client,
-                 struct GNUNET_CADET_ClientChannelNumber ccn,
-                 struct CadetChannel *ch)
-{
-  if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-    GNUNET_CONTAINER_multihashmap32_put (client->own_channels,
-                                         ccn.channel_of_client,
-                                         ch,
-                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-  else
-    GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels,
-                                         ccn.channel_of_client,
-                                         ch,
-                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-}
-
-
-/**
- * Remove a channel from a client.
- *
- * @param client Client.
- * @param ccn Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_remove (struct CadetClient *client,
-                    struct GNUNET_CADET_ClientChannelNumber ccn,
-                    struct CadetChannel *ch)
-{
-  if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-    GNUNET_CONTAINER_multihashmap32_remove (client->own_channels,
-                                            ccn.channel_of_client,
-                                            ch);
-  else
-    GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels,
-                                            ccn.channel_of_client,
-                                            ch);
-}
-
-
-/**
- * Get the tunnel's next free local channel ID.
- *
- * @param c Client.
- *
- * @return LID of a channel free to use.
- */
-struct GNUNET_CADET_ClientChannelNumber
-GML_get_next_ccn (struct CadetClient *c)
-{
-  struct GNUNET_CADET_ClientChannelNumber ccn;
-
-  while (NULL != GML_channel_get (c,
-                                  c->next_ccn))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Channel %u exists...\n",
-         c->next_ccn);
-    c->next_ccn.channel_of_client
-      = htonl (1 + (ntohl (c->next_ccn.channel_of_client)));
-    if (ntohl (c->next_ccn.channel_of_client) >=
-        GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-      c->next_ccn.channel_of_client = htonl (0);
-  }
-  ccn = c->next_ccn;
-  c->next_ccn.channel_of_client
-    = htonl (1 + (ntohl (c->next_ccn.channel_of_client)));
-
-  return ccn;
-}
-
-
-/**
- * Check if client has registered with the service and has not disconnected
- *
- * @param client the client to check
- *
- * @return non-NULL if client exists in the global DLL
- */
-struct CadetClient *
-GML_client_get (struct GNUNET_SERVER_Client *client)
-{
-  if (NULL == client)
-    return NULL;
-  return GNUNET_SERVER_client_get_user_context (client,
-                                                struct CadetClient);
-}
-
-
-/**
- * Find a client that has opened a port
- *
- * @param port Port to check.
- *
- * @return non-NULL if a client has the port.
- */
-struct CadetClient *
-GML_client_get_by_port (const struct GNUNET_HashCode *port)
-{
-  return GNUNET_CONTAINER_multihashmap_get (ports, port);
-}
-
-
-/**
- * Deletes a channel from a client (either owner or destination).
- *
- * @param c Client whose tunnel to delete.
- * @param ch Channel which should be deleted.
- * @param id Channel ID.
- */
-void
-GML_client_delete_channel (struct CadetClient *c,
-                           struct CadetChannel *ch,
-                           struct GNUNET_CADET_ClientChannelNumber id)
-{
-  int res;
-
-  if (ntohl (id.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
-  {
-    res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
-                                                  id.channel_of_client,
-                                                  ch);
-    if (GNUNET_YES != res)
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n");
-  }
-  else
-  {
-    res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
-                                                  id.channel_of_client,
-                                                  ch);
-    if (GNUNET_YES != res)
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n");
-  }
-}
-
-/**
- * Build a local ACK message and send it to a local client, if needed.
- *
- * If the client was already allowed to send data, do nothing.
- *
- * @param c Client to whom send the ACK.
- * @param ccn Channel ID to use
- */
-void
-GML_send_ack (struct CadetClient *c,
-              struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  struct GNUNET_CADET_LocalAck msg;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "send local %s ack on %X towards %p\n",
-       ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI
-       ? "FWD" : "BCK",
-       ntohl (ccn.channel_of_client),
-       c);
-
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
-  msg.ccn = ccn;
-  GNUNET_SERVER_notification_context_unicast (nc,
-                                              c->handle,
-                                              &msg.header,
-                                              GNUNET_NO);
-
-}
-
-
-
-/**
- * Notify the client that a new incoming channel was created.
- *
- * @param c Client to notify.
- * @param ccn Channel ID.
- * @param port Channel's destination port.
- * @param opt Options (bit array).
- * @param peer Origin peer.
- */
-void
-GML_send_channel_create (struct CadetClient *c,
-                         struct GNUNET_CADET_ClientChannelNumber ccn,
-                         const struct GNUNET_HashCode *port,
-                         uint32_t opt,
-                         const struct GNUNET_PeerIdentity *peer)
-{
-  struct GNUNET_CADET_LocalChannelCreateMessage msg;
-
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE);
-  msg.ccn = ccn;
-  msg.port = *port;
-  msg.opt = htonl (opt);
-  msg.peer = *peer;
-  GNUNET_SERVER_notification_context_unicast (nc, c->handle,
-                                              &msg.header, GNUNET_NO);
-}
-
-
-/**
- * Build a local channel NACK message and send it to a local client.
- *
- * @param c Client to whom send the NACK.
- * @param ccn Channel ID to use
- */
-void
-GML_send_channel_nack (struct CadetClient *c,
-                       struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  struct GNUNET_CADET_LocalAck msg;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "send local nack on %X towards %p\n",
-       ntohl (ccn.channel_of_client),
-       c);
-
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED);
-  msg.ccn = ccn;
-  GNUNET_SERVER_notification_context_unicast (nc,
-                                              c->handle,
-                                              &msg.header,
-                                              GNUNET_NO);
-
-}
-
-/**
- * Notify a client that a channel is no longer valid.
- *
- * @param c Client.
- * @param ccn ID of the channel that is destroyed.
- */
-void
-GML_send_channel_destroy (struct CadetClient *c,
-                          struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  struct GNUNET_CADET_LocalChannelDestroyMessage msg;
-
-  if (NULL == c)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  if (GNUNET_YES == c->shutting_down)
-    return;
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY);
-  msg.ccn = ccn;
-  GNUNET_SERVER_notification_context_unicast (nc, c->handle,
-                                              &msg.header, GNUNET_NO);
-}
-
-
-/**
- * Modify the cadet message ID from global to local and send to client.
- *
- * @param c Client to send to.
- * @param msg Message to modify and send.
- * @param ccn Channel ID to use (c can be both owner and client).
- */
-void
-GML_send_data (struct CadetClient *c,
-               const struct GNUNET_CADET_ChannelAppDataMessage *msg,
-               struct GNUNET_CADET_ClientChannelNumber ccn)
-{
-  struct GNUNET_CADET_LocalData *copy;
-  uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_ChannelAppDataMessage);
-  char cbuf[size + sizeof (struct GNUNET_CADET_LocalData)];
-
-  if (size < sizeof (struct GNUNET_MessageHeader))
-  {
-    GNUNET_break_op (0);
-    return;
-  }
-  if (NULL == c)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  copy = (struct GNUNET_CADET_LocalData *) cbuf;
-  GNUNET_memcpy (&copy[1], &msg[1], size);
-  copy->header.size = htons (sizeof (struct GNUNET_CADET_LocalData) + size);
-  copy->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA);
-  copy->ccn = ccn;
-  GNUNET_SERVER_notification_context_unicast (nc, c->handle,
-                                              &copy->header, GNUNET_NO);
-}
-
-
-/**
- * Get the static string to represent a client.
- *
- * @param c Client.
- *
- * @return Static string for the client.
- */
-const char *
-GML_2s (const struct CadetClient *c)
-{
-  static char buf[32];
-
-  SPRINTF (buf, "%u", c->id);
-  return buf;
-}
diff --git a/src/cadet/gnunet-service-cadet_local.h b/src/cadet/gnunet-service-cadet_local.h
deleted file mode 100644 (file)
index 113c2f4..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_local.h
- * @brief cadet service; dealing with local clients
- * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GML (Gnunet Cadet Local)
- */
-
-#ifndef GNUNET_SERVICE_CADET_LOCAL_H
-#define GNUNET_SERVICE_CADET_LOCAL_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-/**
- * Struct containing information about a client of the service
- */
-struct CadetClient;
-
-#include "gnunet-service-cadet_channel.h"
-
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
-
-/**
- * Initialize server subsystem.
- *
- * @param handle Server handle.
- */
-void
-GML_init (struct GNUNET_SERVER_Handle *handle);
-
-/**
- * Install server (service) handlers and start listening to clients.
- */
-void
-GML_start (void);
-
-/**
- * Shutdown server.
- */
-void
-GML_shutdown (void);
-
-/**
- * Get a channel from a client.
- *
- * @param c Client to check.
- * @param ccn Channel ID, must be local (> 0x800...).
- *
- * @return non-NULL if channel exists in the clients lists
- */
-struct CadetChannel *
-GML_channel_get (struct CadetClient *c,
-                 struct GNUNET_CADET_ClientChannelNumber ccn);
-
-/**
- * Add a channel to a client
- *
- * @param client Client.
- * @param ccn Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_add (struct CadetClient *client,
-                 struct GNUNET_CADET_ClientChannelNumber ccn,
-                 struct CadetChannel *ch);
-
-/**
- * Remove a channel from a client
- *
- * @param client Client.
- * @param ccn Channel ID.
- * @param ch Channel.
- */
-void
-GML_channel_remove (struct CadetClient *client,
-                    struct GNUNET_CADET_ClientChannelNumber ccn,
-                    struct CadetChannel *ch);
-
-/**
- * Get the tunnel's next free local channel ID.
- *
- * @param c Client.
- *
- * @return LID of a channel free to use.
- */
-struct GNUNET_CADET_ClientChannelNumber
-GML_get_next_ccn (struct CadetClient *c);
-
-/**
- * Check if client has registered with the service and has not disconnected
- *
- * @param client the client to check
- *
- * @return non-NULL if client exists in the global DLL
- */
-struct CadetClient *
-GML_client_get (struct GNUNET_SERVER_Client *client);
-
-/**
- * Find a client that has opened a port
- *
- * @param port Port to check.
- *
- * @return non-NULL if a client has the port.
- */
-struct CadetClient *
-GML_client_get_by_port (const struct GNUNET_HashCode *port);
-
-/**
- * Deletes a tunnel from a client (either owner or destination).
- *
- * @param c Client whose tunnel to delete.
- * @param ch Channel which should be deleted.
- * @param id Channel ID.
- */
-void
-GML_client_delete_channel (struct CadetClient *c,
-                           struct CadetChannel *ch,
-                           struct GNUNET_CADET_ClientChannelNumber id);
-
-/**
- * Build a local ACK message and send it to a local client, if needed.
- *
- * If the client was already allowed to send data, do nothing.
- *
- * @param c Client to whom send the ACK.
- * @param id Channel ID to use
- */
-void
-GML_send_ack (struct CadetClient *c,
-              struct GNUNET_CADET_ClientChannelNumber id);
-
-/**
- * Notify the appropriate client that a new incoming channel was created.
- *
- * @param c Client to notify.
- * @param id Channel ID.
- * @param port Channel's destination port.
- * @param opt Options (bit array).
- * @param peer Origin peer.
- */
-void
-GML_send_channel_create (struct CadetClient *c,
-                         struct GNUNET_CADET_ClientChannelNumber id,
-                         const struct GNUNET_HashCode *port,
-                         uint32_t opt,
-                         const struct GNUNET_PeerIdentity *peer);
-
-/**
- * Build a local channel NACK message and send it to a local client.
- *
- * @param c Client to whom send the NACK.
- * @param id Channel ID to use
- */
-void
-GML_send_channel_nack (struct CadetClient *c,
-                       struct GNUNET_CADET_ClientChannelNumber id);
-
-
-/**
- * Notify a client that a channel is no longer valid.
- *
- * @param c Client.
- * @param id ID of the channel that is destroyed.
- */
-void
-GML_send_channel_destroy (struct CadetClient *c,
-                          struct GNUNET_CADET_ClientChannelNumber id);
-
-
-/**
- * Modify the cadet message ID from global to local and send to client.
- *
- * @param c Client to send to.
- * @param msg Message to modify and send.
- * @param id Channel ID to use (c can be both owner and client).
- */
-void
-GML_send_data (struct CadetClient *c,
-               const struct GNUNET_CADET_ChannelAppDataMessage *msg,
-               struct GNUNET_CADET_ClientChannelNumber id);
-
-/**
- * Get the static string to represent a client.
- *
- * @param c Client.
- *
- * @return Static string for the client.
- */
-const char *
-GML_2s (const struct CadetClient *c);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */
-#endif
-/* end of gnunet-cadet-service_LOCAL.h */
diff --git a/src/cadet/gnunet-service-cadet_paths.c b/src/cadet/gnunet-service-cadet_paths.c
new file mode 100644 (file)
index 0000000..1375264
--- /dev/null
@@ -0,0 +1,801 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/gnunet-service-cadet_paths.c
+ * @brief Information we track per path.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-pat",__VA_ARGS__)
+
+
+/**
+ * Information regarding a possible path to reach a peer.
+ */
+struct CadetPeerPath
+{
+
+  /**
+   * Array of all the peers on the path.  If @e hn is non-NULL, the
+   * last one is our owner.
+   */
+  struct CadetPeerPathEntry **entries;
+
+  /**
+   * Node of this path in the owner's heap.  Used to update our position
+   * in the heap whenever our @e desirability changes.
+   */
+  struct GNUNET_CONTAINER_HeapNode *hn;
+
+  /**
+   * Desirability of the path. How unique is it for the various peers
+   * on it?
+   */
+  GNUNET_CONTAINER_HeapCostType desirability;
+
+  /**
+   * Length of the @e entries array.
+   */
+  unsigned int entries_length;
+
+};
+
+
+/**
+ * Calculate the path's desirability score.
+ *
+ * @param path path to calculate the score for
+ */
+static void
+recalculate_path_desirability (struct CadetPeerPath *path)
+{
+  double result = 0.0;
+
+  for (unsigned int i=0;i<path->entries_length;i++)
+  {
+    struct CadetPeer *cp = path->entries[i]->peer;
+
+    result += GCP_get_desirability_of_path (cp,
+                                            i);
+  }
+  path->desirability = (GNUNET_CONTAINER_HeapCostType) result;
+}
+
+
+/**
+ * Return how much we like keeping the path.  This is an aggregate
+ * score based on various factors, including the age of the path
+ * (older == better), and the value of this path to all of its ajacent
+ * peers.  For example, long paths that end at a peer that we have no
+ * shorter way to reach are very desirable, while long paths that end
+ * at a peer for which we have a shorter way as well are much less
+ * desirable.  Higher values indicate more valuable paths.  The
+ * returned value should be used to decide which paths to remember.
+ *
+ * @param path path to return the length for
+ * @return desirability of the path, larger is more desirable
+ */
+GNUNET_CONTAINER_HeapCostType
+GCPP_get_desirability (const struct CadetPeerPath *path)
+{
+  return path->desirability;
+}
+
+
+/**
+ * Return connection to @a destination using @a path, or return
+ * NULL if no such connection exists.
+ *
+ * @param path path to traverse
+ * @param destination destination node to get to, must be on path
+ * @param off offset of @a destination on @a path
+ * @return NULL if we have no existing connection
+ *         otherwise connection from us to @a destination via @a path
+ */
+struct CadetConnection *
+GCPP_get_connection (struct CadetPeerPath *path,
+                     struct CadetPeer *destination,
+                     unsigned int off)
+{
+  struct CadetPeerPathEntry *entry;
+
+  GNUNET_assert (off < path->entries_length);
+  entry = path->entries[off];
+  GNUNET_assert (entry->peer == destination);
+  return entry->cc;
+}
+
+
+/**
+ * Notify @a path that it is used for connection @a cc
+ * which ends at the path's offset @a off.
+ *
+ * @param path the path to remember the @a cc
+ * @param off the offset where the @a cc ends
+ * @param cc the connection to remember
+ */
+void
+GCPP_add_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc)
+{
+  struct CadetPeerPathEntry *entry;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Adding connection %s to path %s at offset %u\n",
+       GCC_2s (cc),
+       GCPP_2s (path),
+       off);
+  GNUNET_assert (off < path->entries_length);
+  entry = path->entries[off];
+  GNUNET_assert (NULL == entry->cc);
+  GNUNET_assert (NULL != cc);
+  entry->cc = cc;
+}
+
+
+
+/**
+ * Notify @a path that it is no longer used for connection @a cc which
+ * ended at the path's offset @a off.
+ *
+ * @param path the path to forget the @a cc
+ * @param off the offset where the @a cc ended
+ * @param cc the connection to forget
+ */
+void
+GCPP_del_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc)
+{
+  struct CadetPeerPathEntry *entry;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing connection %s to path %s at offset %u\n",
+       GCC_2s (cc),
+       GCPP_2s (path),
+       off);
+  GNUNET_assert (off < path->entries_length);
+  entry = path->entries[off];
+  GNUNET_assert (cc == entry->cc);
+  entry->cc = NULL;
+}
+
+
+/**
+ * This path is no longer needed, free resources.
+ *
+ * @param path path resources to free
+ */
+static void
+path_destroy (struct CadetPeerPath *path)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying path %s\n",
+       GCPP_2s (path));
+  for (unsigned int i=0;i<path->entries_length;i++)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[i];
+
+    if (NULL != entry->cc)
+    {
+      struct CadetTConnection *ct;
+
+      ct = GCC_get_ct (entry->cc);
+      if (NULL != ct)
+        GCT_connection_lost (ct);
+      GCC_destroy_without_tunnel (entry->cc);
+    }
+    GNUNET_free (entry);
+  }
+  GNUNET_free (path->entries);
+  GNUNET_free (path);
+}
+
+
+/**
+ * The owning peer of this path is no longer interested in maintaining
+ * it, so the path should be discarded or shortened (in case a
+ * previous peer on the path finds the path desirable).
+ *
+ * @param path the path that is being released
+ */
+void
+GCPP_release (struct CadetPeerPath *path)
+{
+  struct CadetPeerPathEntry *entry;
+  int force;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Owner releases path %s\n",
+       GCPP_2s (path));
+  path->hn = NULL;
+  entry = path->entries[path->entries_length - 1];
+  GNUNET_assert (path == entry->path);
+  while (1)
+  {
+    /* cut 'off' end of path */
+    GNUNET_assert (NULL == entry->cc);
+    GCP_path_entry_remove (entry->peer,
+                           entry,
+                           path->entries_length - 1);
+    path->entries_length--; /* We don't bother shrinking the 'entries' array,
+                               as it's probably not worth it. */
+    GNUNET_free (entry);
+    if (0 == path->entries_length)
+      break; /* the end */
+
+    /* see if new peer at the end likes this path any better */
+    entry = path->entries[path->entries_length - 1];
+    GNUNET_assert (path == entry->path);
+    force = (NULL == entry->cc) ? GNUNET_NO : GNUNET_YES;
+    path->hn = GCP_attach_path (entry->peer,
+                                path,
+                                path->entries_length - 1,
+                                force);
+    if (NULL != path->hn)
+      return; /* yep, got attached, we are done. */
+    GNUNET_assert (GNUNET_NO == force);
+  }
+
+  /* nobody wants us, discard the path */
+  path_destroy (path);
+}
+
+
+/**
+ * Updates the score for an entry on the path based
+ * on our experiences with using @a path.
+ *
+ * @param path the path to update
+ * @param off offset of the entry to update
+ * @param delta change in the score to apply
+ */
+void
+GCPP_update_score (struct CadetPeerPath *path,
+                   unsigned int off,
+                   int delta)
+{
+  struct CadetPeerPathEntry *entry;
+
+  GNUNET_assert (off < path->entries_length);
+  entry = path->entries[off];
+
+  /* Add delta, with checks for overflows */
+  if (delta >= 0)
+  {
+    if (delta + entry->score < entry->score)
+      entry->score = INT_MAX;
+    else
+      entry->score += delta;
+  }
+  else
+  {
+    if (delta + entry->score > entry->score)
+      entry->score = INT_MIN;
+    else
+      entry->score += delta;
+  }
+  recalculate_path_desirability (path);
+}
+
+
+/**
+ * Closure for #find_peer_at() and #check_match().
+ */
+struct CheckMatchContext
+{
+
+  /**
+   * Set to a matching path, if any.
+   */
+  struct CadetPeerPath *match;
+
+  /**
+   * Array the combined paths.
+   */
+  struct CadetPeer **cpath;
+
+  /**
+   * How long is the @e cpath array?
+   */
+  unsigned int cpath_length;
+
+};
+
+
+/**
+ * Check if the given path is identical on all of the
+ * hops until @a off, and not longer than @a off.  If the
+ * @a path matches, store it in `match`.
+ *
+ * @param cls the `struct CheckMatchContext` to check against
+ * @param path the path to check
+ * @param off offset to check at
+ * @return #GNUNET_YES (continue to iterate), or if found #GNUNET_NO
+ */
+static int
+check_match (void *cls,
+             struct CadetPeerPath *path,
+             unsigned int off)
+{
+  struct CheckMatchContext *cm_ctx = cls;
+
+  GNUNET_assert (path->entries_length > off);
+  if ( (path->entries_length != off + 1) &&
+       (off + 1 != cm_ctx->cpath_length) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "check_match missmatch because path %s is too long (%u vs. %u vs. %u)\n",
+         GCPP_2s (path),
+         path->entries_length,
+         off + 1,
+         cm_ctx->cpath_length);
+    return GNUNET_YES; /* too long, goes somewhere else already, thus cannot be useful */
+  }
+  for (unsigned int i=0;i<off;i++)
+    if (cm_ctx->cpath[i] !=
+        GCPP_get_peer_at_offset (path,
+                                 i))
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "check_match path %s missmatches at offset %u\n",
+           GCPP_2s (path),
+           i);
+      return GNUNET_YES; /* missmatch, ignore */
+    }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "check_match found match with path %s\n",
+       GCPP_2s (path));
+  cm_ctx->match = path;
+  return GNUNET_NO; /* match, we are done! */
+}
+
+
+/**
+ * Extend path @a path by the @a num_peers from the @a peers
+ * array, assuming the owners past the current owner want it.
+ *
+ * @param path path to extend
+ * @param peers list of peers beyond the end of @a path
+ * @param num_peers length of the @a peers array
+ * @param force force attachment, even if we have other
+ *        paths already
+ */
+static void
+extend_path (struct CadetPeerPath *path,
+             struct CadetPeer **peers,
+             unsigned int num_peers,
+             int force)
+{
+  unsigned int old_len = path->entries_length;
+  int i;
+
+  /* Expand path */
+  GNUNET_array_grow (path->entries,
+                     path->entries_length,
+                     old_len + num_peers);
+  for (i=num_peers-1;i >= 0;i--)
+  {
+    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
+
+    path->entries[old_len + i] = entry;
+    entry->peer = peers[i];
+    entry->path = path;
+  }
+  for (i=num_peers-1;i >= 0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[old_len + i];
+
+    GCP_path_entry_add (entry->peer,
+                        entry,
+                        old_len + i);
+  }
+
+  /* If we extend an existing path, detach it from the
+     old owner and re-attach to the new one */
+  GCP_detach_path (path->entries[old_len-1]->peer,
+                   path,
+                   path->hn);
+  path->hn = NULL;
+  for (i=num_peers-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[old_len + i];
+
+    path->entries_length = old_len + i + 1;
+    recalculate_path_desirability (path);
+    path->hn = GCP_attach_path (peers[i],
+                                path,
+                                old_len + (unsigned int) i,
+                                force);
+    if (NULL != path->hn)
+      break;
+    GNUNET_assert (NULL == entry->cc);
+    GCP_path_entry_remove (entry->peer,
+                           entry,
+                           old_len + i);
+    GNUNET_free (entry);
+    path->entries[old_len + i] = NULL;
+  }
+  if (NULL == path->hn)
+  {
+    /* none of the peers is interested in this path;
+       shrink path back and re-attach. */
+    GNUNET_array_grow (path->entries,
+                       path->entries_length,
+                       old_len);
+    path->hn = GCP_attach_path (path->entries[old_len - 1]->peer,
+                                path,
+                                old_len - 1,
+                                GNUNET_YES);
+    GNUNET_assert (NULL != path->hn);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Extended path %s\n",
+       GCPP_2s (path));
+}
+
+
+/**
+ * Create a peer path based on the result of a DHT lookup.  If we
+ * already know this path, or one that is longer, simply return NULL.
+ * Otherwise, we try to extend an existing path, or create a new one
+ * if applicable.
+ *
+ * @param get_path path of the get request
+ * @param get_path_length lenght of @a get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the @a put_path
+ * @return a path through the network
+ */
+void
+GCPP_try_path_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 CadetPeer *cpath[get_path_length + put_path_length];
+  struct CheckMatchContext cm_ctx;
+  struct CadetPeerPath *path;
+  struct GNUNET_CONTAINER_HeapNode *hn;
+  int i;
+  unsigned int skip;
+  unsigned int total_len;
+
+  /* precompute 'cpath' so we can avoid doing the lookups lots of times */
+  skip = 0;
+  memset (cpath,
+          0,
+          sizeof (cpath)); /* Just to trigger harder errors later. */
+  total_len = get_path_length + put_path_length;
+  for (unsigned int off=0;off<total_len;off++)
+  {
+    const struct GNUNET_PeerIdentity *pid;
+
+    pid = (off < get_path_length)
+      ? &get_path[get_path_length - off]
+      : &put_path[get_path_length + put_path_length - off];
+    cpath[off - skip] = GCP_get (pid,
+                                 GNUNET_YES);
+    /* Check that no peer is twice on the path */
+    for (unsigned int i=0;i<off - skip;i++)
+    {
+     if (cpath[i] == cpath[off - skip])
+      {
+        skip = off - i;
+        break;
+      }
+    }
+  }
+  total_len -= skip;
+
+  /* First figure out if this path is a subset of an existing path, an
+     extension of an existing path, or a new path. */
+  cm_ctx.cpath_length = total_len;
+  cm_ctx.cpath = cpath;
+  cm_ctx.match = NULL;
+  for (i=total_len-1;i>=0;i--)
+  {
+    GCP_iterate_paths_at (cpath[i],
+                          (unsigned int) i,
+                          &check_match,
+                          &cm_ctx);
+    if (NULL != cm_ctx.match)
+    {
+      if (i == total_len - 1)
+      {
+        /* Existing path includes this one, nothing to do! */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Path discovered from DHT is already known\n");
+        return;
+      }
+      if (cm_ctx.match->entries_length == i + 1)
+      {
+        /* Existing path ends in the middle of new path, extend it! */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Trying to extend existing path %s by additional links discovered from DHT\n",
+             GCPP_2s (cm_ctx.match));
+        extend_path (cm_ctx.match,
+                     &cpath[i + 1],
+                     total_len - i - 1,
+                     GNUNET_NO);
+        return;
+      }
+    }
+  }
+
+  /* No match at all, create completely new path */
+  path = GNUNET_new (struct CadetPeerPath);
+  path->entries_length = total_len;
+  path->entries = GNUNET_new_array (path->entries_length,
+                                    struct CadetPeerPathEntry *);
+  for (i=path->entries_length-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
+
+    path->entries[i] = entry;
+    entry->peer = cpath[i];
+    entry->path = path;
+  }
+  for (i=path->entries_length-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[i];
+
+    GCP_path_entry_add (entry->peer,
+                        entry,
+                        i);
+  }
+
+  /* Finally, try to attach it */
+  hn = NULL;
+  for (i=total_len-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[i];
+
+    path->entries_length = i + 1;
+    recalculate_path_desirability (path);
+    hn = GCP_attach_path (cpath[i],
+                          path,
+                          (unsigned int) i,
+                          GNUNET_NO);
+    if (NULL != hn)
+      break;
+    GCP_path_entry_remove (entry->peer,
+                           entry,
+                           i);
+    GNUNET_free (entry);
+    path->entries[i] = NULL;
+  }
+  if (NULL == hn)
+  {
+    /* None of the peers on the path care about it. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Path discovered from DHT is not interesting to us\n");
+    GNUNET_free (path->entries);
+    GNUNET_free (path);
+    return;
+  }
+  path->hn = hn;
+  /* Shrink path to actual useful length */
+  GNUNET_array_grow (path->entries,
+                     path->entries_length,
+                     i + 1);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Created new path %s based on information from DHT\n",
+       GCPP_2s (path));
+}
+
+
+/**
+ * We got an incoming connection, obtain the corresponding path.
+ *
+ * @param path_length number of segments on the @a path
+ * @param pids path through the network, in reverse order (we are at the end at index @a path_length)
+ * @return corresponding path object
+ */
+struct CadetPeerPath *
+GCPP_get_path_from_route (unsigned int path_length,
+                          const struct GNUNET_PeerIdentity *pids)
+{
+  struct CheckMatchContext cm_ctx;
+  struct CadetPeer *cpath[path_length];
+  struct CadetPeerPath *path;
+
+  /* precompute inverted 'cpath' so we can avoid doing the lookups and
+     have the correct order */
+  for (unsigned int off=0;off<path_length;off++)
+    cpath[off] = GCP_get (&pids[path_length - 1 - off],
+                          GNUNET_YES);
+
+  /* First figure out if this path is a subset of an existing path, an
+     extension of an existing path, or a new path. */
+  cm_ctx.cpath = cpath;
+  cm_ctx.cpath_length = path_length;
+  cm_ctx.match = NULL;
+  for (int i=path_length-1;i>=0;i--)
+  {
+    GCP_iterate_paths_at (cpath[i],
+                          (unsigned int) i,
+                          &check_match,
+                          &cm_ctx);
+    if (NULL != cm_ctx.match)
+    {
+      if (i == path_length - 1)
+      {
+        /* Existing path includes this one, return the match! */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Returning existing path %s as inverse for incoming connection\n",
+             GCPP_2s (cm_ctx.match));
+        return cm_ctx.match;
+      }
+      if (cm_ctx.match->entries_length == i + 1)
+      {
+        /* Existing path ends in the middle of new path, extend it! */
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Extending existing path %s to create inverse for incoming connection\n",
+             GCPP_2s (cm_ctx.match));
+        extend_path (cm_ctx.match,
+                     &cpath[i + 1],
+                     path_length - i - 1,
+                     GNUNET_YES);
+        /* Check that extension was successful */
+        GNUNET_assert (cm_ctx.match->entries_length == path_length);
+        return cm_ctx.match;
+      }
+      /* Eh, we found a match but couldn't use it? Something is wrong. */
+      GNUNET_break (0);
+    }
+  }
+
+  /* No match at all, create completely new path */
+  path = GNUNET_new (struct CadetPeerPath);
+  path->entries_length = path_length;
+  path->entries = GNUNET_new_array (path->entries_length,
+                                    struct CadetPeerPathEntry *);
+  for (int i=path_length-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = GNUNET_new (struct CadetPeerPathEntry);
+
+    path->entries[i] = entry;
+    entry->peer = cpath[i];
+    entry->path = path;
+  }
+  for (int i=path_length-1;i>=0;i--)
+  {
+    struct CadetPeerPathEntry *entry = path->entries[i];
+
+    GCP_path_entry_add (entry->peer,
+                        entry,
+                        i);
+  }
+  recalculate_path_desirability (path);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Created new path %s to create inverse for incoming connection\n",
+       GCPP_2s (path));
+  path->hn = GCP_attach_path (cpath[path_length - 1],
+                              path,
+                              path_length - 1,
+                              GNUNET_YES);
+  return path;
+}
+
+
+/**
+ * Return the length of the path.  Excludes one end of the
+ * path, so the loopback path has length 0.
+ *
+ * @param path path to return the length for
+ * @return number of peers on the path
+ */
+unsigned int
+GCPP_get_length (struct CadetPeerPath *path)
+{
+  return path->entries_length;
+}
+
+
+/**
+ * Find peer's offset on path.
+ *
+ * @param path path to search
+ * @param cp peer to look for
+ * @return offset of @a cp on @a path, or UINT_MAX if not found
+ */
+unsigned int
+GCPP_find_peer (struct CadetPeerPath *path,
+                struct CadetPeer *cp)
+{
+  for (unsigned int off = 0;
+       off < path->entries_length;
+       off++)
+    if (cp == GCPP_get_peer_at_offset (path,
+                                       off))
+      return off;
+  return UINT_MAX;
+}
+
+
+/**
+ * Obtain the peer at offset @a off in @a path.
+ *
+ * @param path peer path to inspect
+ * @param off offset to return, must be smaller than path length
+ * @return the peer at offset @a off
+ */
+struct CadetPeer *
+GCPP_get_peer_at_offset (struct CadetPeerPath *path,
+                         unsigned int off)
+{
+  GNUNET_assert (off < path->entries_length);
+  return path->entries[off]->peer;
+}
+
+
+/**
+ * Convert a path to a human-readable string.
+ *
+ * @param path path to convert
+ * @return string, to be freed by caller (unlike other *_2s APIs!)
+ */
+const char *
+GCPP_2s (struct CadetPeerPath *path)
+{
+  static char buf[2048];
+  size_t off;
+  const unsigned int max_plen = (sizeof(buf) - 16) / 5 - 2; /* 5 characters per entry */
+
+  off = 0;
+  for (unsigned int i = 0;
+       i < path->entries_length;
+       i++)
+  {
+    if ( (path->entries_length > max_plen) &&
+         (i == max_plen / 2) )
+      off += GNUNET_snprintf (&buf[off],
+                              sizeof (buf) - off,
+                              "...-");
+    if ( (path->entries_length > max_plen) &&
+         (i > max_plen / 2) &&
+         (i < path->entries_length - max_plen / 2) )
+      continue;
+    off += GNUNET_snprintf (&buf[off],
+                            sizeof (buf) - off,
+                            "%s%s",
+                            GNUNET_i2s (GCP_get_id (GCPP_get_peer_at_offset (path,
+                                                                             i))),
+                            (i == path->entries_length -1) ? "" : "-");
+  }
+  GNUNET_snprintf (&buf[off],
+                   sizeof (buf) - off,
+                   "(%p)",
+                   path);
+  return buf;
+}
+
+
+/* end of gnunet-service-cadet-new_paths.c */
diff --git a/src/cadet/gnunet-service-cadet_paths.h b/src/cadet/gnunet-service-cadet_paths.h
new file mode 100644 (file)
index 0000000..6b7bef6
--- /dev/null
@@ -0,0 +1,182 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_paths.h
+ * @brief Information we track per path.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_PATHS_H
+#define GNUNET_SERVICE_CADET_PATHS_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet-service-cadet.h"
+
+/**
+ * Create a peer path based on the result of a DHT lookup.  If we
+ * already know this path, or one that is longer, simply return NULL.
+ * Otherwise, we try to extend an existing path, or create a new one
+ * if applicable.
+ *
+ * @param get_path path of the get request
+ * @param get_path_length lenght of @a get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the @a put_path
+ */
+void
+GCPP_try_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
+                        unsigned int get_path_length,
+                        const struct GNUNET_PeerIdentity *put_path,
+                        unsigned int put_path_length);
+
+
+/**
+ * We got an incoming connection, obtain the corresponding path.
+ *
+ * @param path_length number of segments on the @a path
+ * @param path through the network, in reverse order (we are at the end!)
+ * @return corresponding path object
+ */
+struct CadetPeerPath *
+GCPP_get_path_from_route (unsigned int path_length,
+                          const struct GNUNET_PeerIdentity *pids);
+
+
+/**
+ * Return the length of the path.  Excludes one end of the
+ * path, so the loopback path has length 0.
+ *
+ * @param path path to return the length for
+ * @return number of peers on the path
+ */
+unsigned int
+GCPP_get_length (struct CadetPeerPath *path);
+
+
+/**
+ * Return connection to @a destination using @a path, or return
+ * NULL if no such connection exists.
+ *
+ * @param path path to traverse
+ * @param destination destination node to get to, must be on path
+ * @param off offset of @a destination on @a path
+ * @return NULL if we have no existing connection
+ *         otherwise connection from us to @a destination via @a path
+ */
+struct CadetConnection *
+GCPP_get_connection (struct CadetPeerPath *path,
+                     struct CadetPeer *destination,
+                     unsigned int off);
+
+
+/**
+ * Notify @a path that it is used for connection @a cc
+ * which ends at the path's offset @a off.
+ *
+ * @param path the path to remember the @a cc
+ * @param off the offset where the @a cc ends
+ * @param cc the connection to remember
+ */
+void
+GCPP_add_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc);
+
+
+/**
+ * Notify @a path that it is no longer used for connection @a cc which
+ * ended at the path's offset @a off.
+ *
+ * @param path the path to forget the @a cc
+ * @param off the offset where the @a cc ended
+ * @param cc the connection to forget
+ */
+void
+GCPP_del_connection (struct CadetPeerPath *path,
+                     unsigned int off,
+                     struct CadetConnection *cc);
+
+
+/**
+ * Find peer's offset on path.
+ *
+ * @param path path to search
+ * @param cp peer to look for
+ * @return offset of @a cp on @a path, or UINT_MAX if not found
+ */
+unsigned int
+GCPP_find_peer (struct CadetPeerPath *path,
+                struct CadetPeer *cp);
+
+
+/**
+ * Return how much we like keeping the path.  This is an aggregate
+ * score based on various factors, including the age of the path
+ * (older == better), and the value of this path to all of its ajacent
+ * peers.  For example, long paths that end at a peer that we have no
+ * shorter way to reach are very desirable, while long paths that end
+ * at a peer for which we have a shorter way as well are much less
+ * desirable.  Higher values indicate more valuable paths.  The
+ * returned value should be used to decide which paths to remember.
+ *
+ * @param path path to return the length for
+ * @return desirability of the path, larger is more desirable
+ */
+GNUNET_CONTAINER_HeapCostType
+GCPP_get_desirability (const struct CadetPeerPath *path);
+
+
+/**
+ * The given peer @a cp used to own this @a path.  However, it is no
+ * longer interested in maintaining it, so the path should be
+ * discarded or shortened (in case a previous peer on the path finds
+ * the path desirable).
+ *
+ * @param path the path that is being released
+ */
+void
+GCPP_release (struct CadetPeerPath *path);
+
+
+/**
+ * Obtain the peer at offset @a off in @a path.
+ *
+ * @param path peer path to inspect
+ * @param off offset to return, must be smaller than path length
+ * @return peer at offset @a off
+ */
+struct CadetPeer *
+GCPP_get_peer_at_offset (struct CadetPeerPath *path,
+                         unsigned int off);
+
+
+/**
+ * Convert a path to a human-readable string.
+ *
+ * @param path path to convert
+ * @return string, statically allocated
+ */
+const char *
+GCPP_2s (struct CadetPeerPath *p);
+
+
+#endif
index fa3f2be806f590a23e856a834039562adaaf832a..71c7c67d0c11af201e23b08dd201720eb82719f0 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013, 2015 GNUnet e.V.
+     Copyright (C) 2001-2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      Boston, MA 02110-1301, USA.
 */
+
 /**
  * @file cadet/gnunet-service-cadet_peer.c
- * @brief GNUnet CADET service connection handling
+ * @brief Information we track per peer.
  * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - optimize stopping/restarting DHT search to situations
+ *   where we actually need it (i.e. not if we have a direct connection,
+ *   or if we already have plenty of good short ones, or maybe even
+ *   to take a break if we have some connections and have searched a lot (?))
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
 #include "gnunet_signatures.h"
 #include "gnunet_transport_service.h"
 #include "gnunet_ats_service.h"
 #include "gnunet_core_service.h"
 #include "gnunet_statistics_service.h"
 #include "cadet_protocol.h"
-#include "gnunet-service-cadet_peer.h"
-#include "gnunet-service-cadet_dht.h"
 #include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_tunnel.h"
-#include "cadet_path.h"
+#include "gnunet-service-cadet_dht.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+#include "gnunet-service-cadet_tunnels.h"
 
-#define LOG(level, ...) GNUNET_log_from (level,"cadet-p2p",__VA_ARGS__)
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-p2p",__VA_ARGS__)
 
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-per",__VA_ARGS__)
 
-/******************************************************************************/
-/********************************   STRUCTS  **********************************/
-/******************************************************************************/
 
 /**
- * Information about a queued message on the peer level.
+ * How long do we wait until tearing down an idle peer?
  */
-struct CadetPeerQueue {
-
-    struct CadetPeerQueue *next;
-    struct CadetPeerQueue *prev;
-
-    /**
-     * Envelope to cancel message before MQ sends it.
-     */
-    struct GNUNET_MQ_Envelope *env;
-
-    /**
-     * Peer (neighbor) this message is being sent to.
-     */
-    struct CadetPeer *peer;
-
-    /**
-     * Continuation to call to notify higher layers about message sent.
-     */
-    GCP_sent cont;
-
-    /**
-     * Closure for @a cont.
-     */
-    void *cont_cls;
-
-    /**
-     * Task to asynchronously run the drop continuation.
-     */
-    struct GNUNET_SCHEDULER_Task *drop_task;
-
-    /**
-     * Time when message was queued for sending.
-     */
-    struct GNUNET_TIME_Absolute queue_timestamp;
-
-    /**
-     * #GNUNET_YES if message was management traffic (POLL, ACK, ...).
-     */
-    int management_traffic;
-
-    /**
-     * Message type.
-     */
-    uint16_t type;
-
-    /**
-     * Message size.
-     */
-    uint16_t size;
-
-    /**
-     * Type of the message's payload, if it was encrypted data.
-     */
-    uint16_t payload_type;
-
-    /**
-     * ID of the payload (PID, ACK #, ...).
-     */
-    struct CadetEncryptedMessageIdentifier payload_id;
-
-    /**
-     * Connection this message was sent on.
-     */
-    struct CadetConnection *c;
-
-    /**
-     * Direction in @a c this message was send on (#GNUNET_YES = FWD).
-     */
-    int c_fwd;
-};
-
+#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
 
 /**
- * Struct containing all information regarding a given peer
+ * How long do we keep paths around if we no longer care about the peer?
  */
-struct CadetPeer
-{
-    /**
-     * ID of the peer
-     */
-    GNUNET_PEER_Id id;
-
-    struct CadetPeerQueue *q_head;
-    struct CadetPeerQueue *q_tail;
-
-    /**
-     * Last time we heard from this peer
-     */
-    struct GNUNET_TIME_Absolute last_contact;
-
-    /**
-     * Paths to reach the peer, ordered by ascending hop count
-     */
-    struct CadetPeerPath *path_head;
-
-    /**
-     * Paths to reach the peer, ordered by ascending hop count
-     */
-    struct CadetPeerPath *path_tail;
-
-    /**
-     * Handle to stop the DHT search for paths to this peer
-     */
-    struct GCD_search_handle *search_h;
-
-    /**
-     * Handle to stop the DHT search for paths to this peer
-     */
-    struct GNUNET_SCHEDULER_Task *search_delayed;
-
-    /**
-     * Tunnel to this peer, if any.
-     */
-    struct CadetTunnel *tunnel;
-
-    /**
-     * Connections that go through this peer; indexed by tid.
-     */
-    struct GNUNET_CONTAINER_MultiShortmap  *connections;
-
-    /**
-     * Handle for core transmissions.
-     */
-    struct GNUNET_MQ_Handle *core_mq;
-
-    /**
-     * How many messages are in the queue to this peer.
-     */
-    unsigned int queue_n;
-
-    /**
-     * Hello message.
-     */
-    struct GNUNET_HELLO_Message* hello;
-
-    /**
-     * Handle to us offering the HELLO to the transport.
-     */
-    struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
-
-    /**
-     * Handle to our ATS request asking ATS to suggest an address
-     * to TRANSPORT for this peer (to establish a direct link).
-     */
-    struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
+#define IDLE_PATH_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 2)
 
-};
 
 
-/******************************************************************************/
-/*******************************   GLOBALS  ***********************************/
-/******************************************************************************/
 
 /**
- * Global handle to the statistics service.
+ * Data structure used to track whom we have to notify about changes
+ * to our message queue.
  */
-extern struct GNUNET_STATISTICS_Handle *stats;
+struct GCP_MessageQueueManager
+{
 
-/**
* Local peer own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
+  /**
  * Kept in a DLL.
  */
+  struct GCP_MessageQueueManager *next;
 
-/**
- * Local peer own ID (short)
- */
-extern GNUNET_PEER_Id myid;
+  /**
+   * Kept in a DLL.
  */
+  struct GCP_MessageQueueManager *prev;
 
-/**
* Peers known, indexed by PeerIdentity, values of type `struct CadetPeer`.
- */
-static struct GNUNET_CONTAINER_MultiPeerMap *peers;
+  /**
  * Function to call with updated message queue object.
  */
+  GCP_MessageQueueNotificationCallback cb;
 
-/**
- * How many peers do we want to remember?
- */
-static unsigned long long max_peers;
+  /**
+   * Closure for @e cb.
  */
+  void *cb_cls;
 
-/**
* Percentage of messages that will be dropped (for test purposes only).
- */
-static unsigned long long drop_percent;
+  /**
  * The peer this is for.
  */
+  struct CadetPeer *cp;
 
-/**
- * Handle to communicate with CORE.
- */
-static struct GNUNET_CORE_Handle *core_handle;
+  /**
+   * Envelope this manager would like to transmit once it is its turn.
+   */
+  struct GNUNET_MQ_Envelope *env;
+
+};
 
-/**
- * Our configuration;
- */
-static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
 /**
- * Handle to communicate with ATS.
+ * Struct containing all information regarding a given peer
  */
-static struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+struct CadetPeer
+{
+  /**
+   * ID of the peer
+   */
+  struct GNUNET_PeerIdentity pid;
+
+  /**
+   * Last time we heard from this peer (currently not used!)
+   */
+  struct GNUNET_TIME_Absolute last_contactXXX;
+
+  /**
+   * Array of DLLs of paths traversing the peer, organized by the
+   * offset of the peer on the larger path.
+   */
+  struct CadetPeerPathEntry **path_heads;
+
+  /**
+   * Array of DLL of paths traversing the peer, organized by the
+   * offset of the peer on the larger path.
+   */
+  struct CadetPeerPathEntry **path_tails;
+
+  /**
+   * Notifications to call when @e core_mq changes.
+   */
+  struct GCP_MessageQueueManager *mqm_head;
+
+  /**
+   * Notifications to call when @e core_mq changes.
+   */
+  struct GCP_MessageQueueManager *mqm_tail;
+
+  /**
+   * Pointer to first "ready" entry in @e mqm_head.
+   */
+  struct GCP_MessageQueueManager *mqm_ready_ptr;
+
+  /**
+   * MIN-heap of paths owned by this peer (they also end at this
+   * peer).  Ordered by desirability.
+   */
+  struct GNUNET_CONTAINER_Heap *path_heap;
+
+  /**
+   * Handle to stop the DHT search for paths to this peer
+   */
+  struct GCD_search_handle *search_h;
+
+  /**
+   * Task to clean up @e path_heap asynchronously.
+   */
+  struct GNUNET_SCHEDULER_Task *heap_cleanup_task;
+
+  /**
+   * Task to destroy this entry.
+   */
+  struct GNUNET_SCHEDULER_Task *destroy_task;
+
+  /**
+   * Tunnel to this peer, if any.
+   */
+  struct CadetTunnel *t;
+
+  /**
+   * Connections that go through this peer; indexed by tid.
+   */
+  struct GNUNET_CONTAINER_MultiShortmap *connections;
+
+  /**
+   * Handle for core transmissions.
+   */
+  struct GNUNET_MQ_Handle *core_mq;
+
+  /**
+   * Hello message of the peer.
+   */
+  struct GNUNET_HELLO_Message *hello;
+
+  /**
+   * Handle to us offering the HELLO to the transport.
+   */
+  struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
+
+  /**
+   * Handle to our ATS request asking ATS to suggest an address
+   * to TRANSPORT for this peer (to establish a direct link).
+   */
+  struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
+
+  /**
+   * How many messages are in the queue to this peer.
+   */
+  unsigned int queue_n;
+
+  /**
+   * How many paths do we have to this peer (in all @e path_heads DLLs combined).
+   */
+  unsigned int num_paths;
+
+  /**
+   * Sum over all of the offsets of all of the paths in the @a path_heads DLLs.
+   * Used to speed-up @GCP_get_desirability_of_path() calculation.
+   */
+  unsigned int off_sum;
+
+  /**
+   * Number of message queue managers of this peer that have a message in waiting.
+   *
+   * Used to quickly see if we need to bother scanning the @e msm_head DLL.
+   * TODO: could be replaced by another DLL that would then allow us to avoid
+   * the O(n)-scan of the DLL for ready entries!
+   */
+  unsigned int mqm_ready_counter;
+
+  /**
+   * Current length of the @e path_heads and @path_tails arrays.
+   * The arrays should be grown as needed.
+   */
+  unsigned int path_dll_length;
+
+};
+
 
 /**
- * Shutdown falg.
+ * Get the static string for a peer ID.
+ *
+ * @param cp Peer.
+ * @return Static string for it's ID.
  */
-static int in_shutdown;
+const char *
+GCP_2s (const struct CadetPeer *cp)
+{
+  static char buf[32];
+
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "P(%s)",
+                   GNUNET_i2s (&cp->pid));
+  return buf;
+}
+
+
+/**
+ * Calculate how desirable a path is for @a cp if @a cp
+ * is at offset @a off.
+ *
+ * The 'desirability_table.c' program can be used to compute a list of
+ * sample outputs for different scenarios.  Basically, we score paths
+ * lower if there are many alternatives, and higher if they are
+ * shorter than average, and very high if they are much shorter than
+ * average and without many alternatives.
+ *
+ * @param cp a peer reachable via a path
+ * @param off offset of @a cp in the path
+ * @return score how useful a path is to reach @a cp,
+ *         positive scores mean path is more desirable
+ */
+double
+GCP_get_desirability_of_path (struct CadetPeer *cp,
+                              unsigned int off)
+{
+  unsigned int num_alts = cp->num_paths;
+  unsigned int off_sum;
+  double avg_sum;
+  double path_delta;
+  double weight_alts;
+
+  GNUNET_assert (num_alts >= 1); /* 'path' should be in there! */
+  GNUNET_assert (0 != cp->path_dll_length);
+
+  /* We maintain 'off_sum' in 'peer' and thereby
+     avoid the SLOW recalculation each time. Kept here
+     just to document what is going on. */
+#if SLOW
+  off_sum = 0;
+  for (unsigned int j=0;j<cp->path_dll_length;j++)
+    for (struct CadetPeerPathEntry *pe = cp->path_heads[j];
+         NULL != pe;
+         pe = pe->next)
+      off_sum += j;
+  GNUNET_assert (off_sum == cp->off_sum);
+#else
+  off_sum = cp->off_sum;
+#endif
+  avg_sum = off_sum * 1.0 / cp->path_dll_length;
+  path_delta = off - avg_sum;
+  /* path_delta positiv: path off of peer above average (bad path for peer),
+     path_delta negativ: path off of peer below average (good path for peer) */
+  if (path_delta <= - 1.0)
+    weight_alts = - num_alts / path_delta; /* discount alternative paths */
+  else if (path_delta >= 1.0)
+    weight_alts = num_alts * path_delta; /* overcount alternative paths */
+  else
+    weight_alts = num_alts; /* count alternative paths normally */
 
 
-/******************************************************************************/
-/*****************************  CORE HELPERS  *********************************/
-/******************************************************************************/
+  /* off+1: long paths are generally harder to find and thus count
+     a bit more as they get longer.  However, above-average paths
+     still need to count less, hence the squaring of that factor. */
+  return (off + 1.0) / (weight_alts * weight_alts);
+}
 
 
 /**
- * Iterator to notify all connections of a broken link. Mark connections
- * to destroy after all traffic has been sent.
- *
- * @param cls Closure (disconnected peer).
- * @param key Current key code (peer id).
- * @param value Value in the hash map (connection).
+ * This peer is no longer be needed, clean it up now.
  *
- * @return #GNUNET_YES to continue to iterate.
+ * @param cls peer to clean up
  */
-static int
-notify_broken (void *cls,
-               const struct GNUNET_ShortHashCode *key,
-               void *value)
-{
-    struct CadetPeer *peer = cls;
-    struct CadetConnection *c = value;
+static void
+destroy_peer (void *cls)
+{
+  struct CadetPeer *cp = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying state about peer %s\n",
+       GCP_2s (cp));
+  cp->destroy_task = NULL;
+  GNUNET_assert (NULL == cp->t);
+  GNUNET_assert (NULL == cp->core_mq);
+  GNUNET_assert (0 == cp->num_paths);
+  for (unsigned int i=0;i<cp->path_dll_length;i++)
+    GNUNET_assert (NULL == cp->path_heads[i]);
+  GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multipeermap_remove (peers,
+                                                       &cp->pid,
+                                                       cp));
+  GNUNET_free_non_null (cp->path_heads);
+  GNUNET_free_non_null (cp->path_tails);
+  cp->path_dll_length = 0;
+  if (NULL != cp->search_h)
+  {
+    GCD_search_stop (cp->search_h);
+    cp->search_h = NULL;
+  }
+  /* FIXME: clean up search_delayedXXX! */
 
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Notifying %s due to %s disconnect\n",
-         GCC_2s (c), GCP_2s (peer));
-    GCC_neighbor_disconnected (c, peer);
-    return GNUNET_YES;
+  if (NULL != cp->hello_offer)
+  {
+    GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
+    cp->hello_offer = NULL;
+  }
+  if (NULL != cp->connectivity_suggestion)
+  {
+    GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+    cp->connectivity_suggestion = NULL;
+  }
+  GNUNET_CONTAINER_multishortmap_destroy (cp->connections);
+  if (NULL != cp->path_heap)
+  {
+    GNUNET_CONTAINER_heap_destroy (cp->path_heap);
+    cp->path_heap = NULL;
+  }
+  if (NULL != cp->heap_cleanup_task)
+  {
+    GNUNET_SCHEDULER_cancel (cp->heap_cleanup_task);
+    cp->heap_cleanup_task = NULL;
+  }
+  GNUNET_free_non_null (cp->hello);
+  /* Peer should not be freed if paths exist; if there are no paths,
+     there ought to be no connections, and without connections, no
+     notifications. Thus we can assert that mqm_head is empty at this
+     point. */
+  GNUNET_assert (NULL == cp->mqm_head);
+  GNUNET_assert (NULL == cp->mqm_ready_ptr);
+  GNUNET_free (cp);
 }
 
 
 /**
- * Remove the direct path to the peer.
+ * This peer is now on more "active" duty, activate processes related to it.
  *
- * @param peer Peer to remove the direct path from.
+ * @param cp the more-active peer
  */
-static struct CadetPeerPath *
-pop_direct_path (struct CadetPeer *peer)
+static void
+consider_peer_activate (struct CadetPeer *cp)
 {
-    struct CadetPeerPath *iter;
+  uint32_t strength;
 
-    for (iter = peer->path_head; NULL != iter; iter = iter->next)
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Updating peer %s activation state (%u connections)%s%s\n",
+       GCP_2s (cp),
+       GNUNET_CONTAINER_multishortmap_size (cp->connections),
+       (NULL == cp->t) ? "" : " with tunnel",
+       (NULL == cp->core_mq) ? "" : " with CORE link");
+  if (NULL != cp->destroy_task)
+  {
+    /* It's active, do not destory! */
+    GNUNET_SCHEDULER_cancel (cp->destroy_task);
+    cp->destroy_task = NULL;
+  }
+  if ( (0 == GNUNET_CONTAINER_multishortmap_size (cp->connections)) &&
+       (NULL == cp->t) )
+  {
+    /* We're just on a path or directly connected; don't bother too much */
+    if (NULL != cp->connectivity_suggestion)
     {
-        if (2 >= iter->length)
-        {
-            GNUNET_CONTAINER_DLL_remove (peer->path_head,
-                                         peer->path_tail,
-                                         iter);
-            return iter;
-        }
+      GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+      cp->connectivity_suggestion = NULL;
     }
-    return NULL;
+    if (NULL != cp->search_h)
+    {
+      GCD_search_stop (cp->search_h);
+      cp->search_h = NULL;
+    }
+    return;
+  }
+  if (NULL == cp->core_mq)
+  {
+    /* Lacks direct connection, try to create one by querying the DHT */
+    if ( (NULL == cp->search_h) &&
+         (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
+      cp->search_h
+        = GCD_search (&cp->pid);
+  }
+  else
+  {
+    /* Have direct connection, stop DHT search if active */
+    if (NULL != cp->search_h)
+    {
+      GCD_search_stop (cp->search_h);
+      cp->search_h = NULL;
+    }
+  }
+
+  /* If we have a tunnel, our urge for connections is much bigger */
+  strength = (NULL != cp->t) ? 32 : 1;
+  if (NULL != cp->connectivity_suggestion)
+    GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+  cp->connectivity_suggestion
+    = GNUNET_ATS_connectivity_suggest (ats_ch,
+                                       &cp->pid,
+                                       strength);
 }
 
+
 /**
- * Call the continuation after a message has been sent or dropped.
- *
- * This funcion removes the message from the queue.
+ * This peer may no longer be needed, consider cleaning it up.
  *
- * @param q Queue handle.
- * @param sent #GNUNET_YES if was sent to CORE, #GNUNET_NO if dropped.
+ * @param cp peer to clean up
  */
 static void
-call_peer_cont (struct CadetPeerQueue *q, int sent);
-
-
-/******************************************************************************/
-/***************************** CORE CALLBACKS *********************************/
-/******************************************************************************/
+consider_peer_destroy (struct CadetPeer *cp);
 
 
 /**
- * Method called whenever a given peer connects.
+ * We really no longere care about a peer, stop hogging memory with paths to it.
+ * Afterwards, see if there is more to be cleaned up about this peer.
  *
- * @param cls Core closure (unused).
- * @param peer Peer identity this notification is about
- * @param mq Message Queue to this peer.
- *
- * @return Internal closure for handlers (CadetPeer struct).
+ * @param cls a `struct CadetPeer`.
  */
-static void *
-core_connect_handler (void *cls,
-                      const struct GNUNET_PeerIdentity *peer,
-                      struct GNUNET_MQ_Handle *mq)
+static void
+drop_paths (void *cls)
 {
-    struct CadetPeer *neighbor;
-    struct CadetPeerPath *path;
-    char own_id[16];
-
-    GCC_check_connections ();
-    GNUNET_snprintf (own_id,
-                     sizeof (own_id),
-                     "%s",
-                     GNUNET_i2s (&my_full_id));
-
-    /* Save a path to the neighbor */
-    neighbor = GCP_get (peer, GNUNET_YES);
-    if (myid == neighbor->id)
-    {
-        LOG (GNUNET_ERROR_TYPE_INFO,
-             "CONNECTED %s (self)\n",
-             own_id);
-        path = path_new (1);
-    }
-    else
-    {
-        LOG (GNUNET_ERROR_TYPE_INFO,
-             "CONNECTED %s <= %s\n",
-             own_id,
-             GNUNET_i2s (peer));
-        path = path_new (2);
-        path->peers[1] = neighbor->id;
-        GNUNET_PEER_change_rc (neighbor->id, 1);
-        GNUNET_assert (NULL == neighbor->core_mq);
-        neighbor->core_mq = mq;
-    }
-    path->peers[0] = myid;
-    GNUNET_PEER_change_rc (myid, 1);
-    GCP_add_path (neighbor, path, GNUNET_YES);
-
-    /* Create the connections hashmap */
-    GNUNET_assert (NULL == neighbor->connections);
-    neighbor->connections = GNUNET_CONTAINER_multishortmap_create (16,
-                                                                   GNUNET_YES);
-    GNUNET_STATISTICS_update (stats,
-                              "# peers",
-                              1,
-                              GNUNET_NO);
-
-    if ( (NULL != GCP_get_tunnel (neighbor)) &&
-            (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) )
-    {
-        GCP_connect (neighbor);
-    }
-    GCC_check_connections ();
+  struct CadetPeer *cp = cls;
+  struct CadetPeerPath *path;
 
-    return neighbor;
+  cp->destroy_task = NULL;
+  while (NULL != (path = GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
+    GCPP_release (path);
+  consider_peer_destroy (cp);
 }
 
 
 /**
- * Method called whenever a peer disconnects.
+ * This peer may no longer be needed, consider cleaning it up.
  *
- * @param cls Core closure (unused).
- * @param peer Peer identity this notification is about.
- * @param internal_cls Internal closure (CadetPeer struct).
+ * @param cp peer to clean up
  */
 static void
-core_disconnect_handler (void *cls,
-                         const struct GNUNET_PeerIdentity *peer,
-                         void *internal_cls)
+consider_peer_destroy (struct CadetPeer *cp)
 {
-    struct CadetPeer *p = internal_cls;
-    struct CadetPeerPath *direct_path;
-    char own_id[16];
-
-    GCC_check_connections ();
-    strncpy (own_id, GNUNET_i2s (&my_full_id), 16);
-    own_id[15] = '\0';
-    if (myid == p->id)
+  struct GNUNET_TIME_Relative exp;
+
+  if (NULL != cp->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (cp->destroy_task);
+    cp->destroy_task = NULL;
+  }
+  if (NULL != cp->t)
+    return; /* still relevant! */
+  if (NULL != cp->core_mq)
+    return; /* still relevant! */
+  if (0 != GNUNET_CONTAINER_multishortmap_size (cp->connections))
+    return; /* still relevant! */
+  if ( (NULL != cp->path_heap) &&
+       (0 < GNUNET_CONTAINER_heap_get_size (cp->path_heap)) )
+  {
+    cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PATH_TIMEOUT,
+                                                     &drop_paths,
+                                                     cp);
+    return;
+  }
+  if (0 != cp->num_paths)
+    return; /* still relevant! */
+  if (NULL != cp->hello)
+  {
+    /* relevant only until HELLO expires */
+    exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (cp->hello));
+    cp->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
+                                                     &destroy_peer,
+                                                     cp);
+    return;
+  }
+  cp->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
+                                                   &destroy_peer,
+                                                   cp);
+}
+
+
+/**
+ * Set the message queue to @a mq for peer @a cp and notify watchers.
+ *
+ * @param cp peer to modify
+ * @param mq message queue to set (can be NULL)
+ */
+void
+GCP_set_mq (struct CadetPeer *cp,
+            struct GNUNET_MQ_Handle *mq)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Message queue for peer %s is now %p\n",
+       GCP_2s (cp),
+       mq);
+  cp->core_mq = mq;
+  for (struct GCP_MessageQueueManager *mqm = cp->mqm_head, *next;
+       NULL != mqm;
+       mqm = next)
+  {
+    /* Save next pointer in case mqm gets freed by the callback */
+    next = mqm->next;
+    if (NULL == mq)
     {
-        LOG (GNUNET_ERROR_TYPE_INFO,
-             "DISCONNECTED %s (self)\n",
-             own_id);
+      if (NULL != mqm->env)
+      {
+        GNUNET_MQ_discard (mqm->env);
+        mqm->env = NULL;
+        mqm->cb (mqm->cb_cls,
+                 GNUNET_SYSERR);
+      }
+      else
+      {
+        mqm->cb (mqm->cb_cls,
+                 GNUNET_NO);
+      }
     }
     else
     {
-        LOG (GNUNET_ERROR_TYPE_INFO,
-             "DISCONNECTED %s <= %s\n",
-             own_id, GNUNET_i2s (peer));
-        p->core_mq = NULL;
-    }
-    direct_path = pop_direct_path (p);
-    if (NULL != p->connections)
-    {
-      GNUNET_CONTAINER_multishortmap_iterate (p->connections,
-                                              &notify_broken,
-                                              p);
-      GNUNET_CONTAINER_multishortmap_destroy (p->connections);
-      p->connections = NULL;
+      GNUNET_assert (NULL == mqm->env);
+      mqm->cb (mqm->cb_cls,
+               GNUNET_YES);
     }
-    GNUNET_STATISTICS_update (stats,
-                              "# peers",
-                              -1,
-                              GNUNET_NO);
-    path_destroy (direct_path);
-    GCC_check_connections ();
-}
+  }
+  if ( (NULL != mq) ||
+       (NULL != cp->t) )
+    consider_peer_activate (cp);
+  else
+    consider_peer_destroy (cp);
+
+  if ( (NULL != mq) &&
+       (NULL != cp->t) )
+  {
+    /* have a new, direct path to the target, notify tunnel */
+    struct CadetPeerPath *path;
 
+    path = GCPP_get_path_from_route (1,
+                                     &cp->pid);
+    GCT_consider_path (cp->t,
+                       path,
+                       0);
+  }
+}
 
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
 
 /**
- * Check if the create_connection message has the appropriate size.
- *
- * @param cls Closure (unused).
- * @param msg Message to check.
+ * Debug function should NEVER return true in production code, useful to
+ * simulate losses for testcases.
  *
- * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
+ * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
  */
 static int
-check_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg)
+should_I_drop (void)
 {
-    uint16_t size;
-
-    size = ntohs (msg->header.size);
-    if (size < sizeof (*msg))
-    {
-        GNUNET_break_op (0);
-        return GNUNET_NO;
-    }
+  if (0 == drop_percent)
+    return GNUNET_NO;
+  if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                101) < drop_percent)
     return GNUNET_YES;
+  return GNUNET_NO;
 }
 
+
 /**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE
+ * Function called when CORE took one of the messages from
+ * a message queue manager and transmitted it.
  *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param cls the `struct CadetPeeer` where we made progress
  */
 static void
-handle_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg)
-{
-    struct CadetPeer *peer = cls;
-    GCC_handle_create (peer, msg);
-}
+mqm_send_done (void *cls);
 
 
 /**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK
+ * Transmit current envelope from this @a mqm.
  *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param mqm mqm to transmit message for now
  */
 static void
-handle_confirm (void *cls, const struct GNUNET_CADET_ConnectionCreateAckMessage *msg)
+mqm_execute (struct GCP_MessageQueueManager *mqm)
 {
-    struct CadetPeer *peer = cls;
-    GCC_handle_confirm (peer, msg);
+  struct CadetPeer *cp = mqm->cp;
+
+  /* Move ready pointer to the next entry that might be ready. */
+  if ( (mqm == cp->mqm_ready_ptr) &&
+       (NULL != mqm->next) )
+    cp->mqm_ready_ptr = mqm->next;
+  /* Move entry to the end of the DLL, to be fair. */
+  if (mqm != cp->mqm_tail)
+  {
+    GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
+                                 cp->mqm_tail,
+                                 mqm);
+    GNUNET_CONTAINER_DLL_insert_tail (cp->mqm_head,
+                                      cp->mqm_tail,
+                                      mqm);
+  }
+  cp->mqm_ready_counter--;
+  if (GNUNET_YES == should_I_drop ())
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "DROPPING message to peer %s from MQM %p\n",
+         GCP_2s (cp),
+         mqm);
+    GNUNET_MQ_discard (mqm->env);
+    mqm->env = NULL;
+    mqm_send_done (cp);
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Sending to peer %s from MQM %p\n",
+         GCP_2s (cp),
+         mqm);
+    GNUNET_MQ_send (cp->core_mq,
+                    mqm->env);
+    mqm->env = NULL;
+  }
+  mqm->cb (mqm->cb_cls,
+           GNUNET_YES);
 }
 
 
 /**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN
+ * Find the next ready message in the queue (starting
+ * the search from the `cp->mqm_ready_ptr`) and if possible
+ * execute the transmission.
  *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param cp peer to try to send the next ready message to
  */
 static void
-handle_broken (void *cls, const struct GNUNET_CADET_ConnectionBrokenMessage *msg)
+send_next_ready (struct CadetPeer *cp)
 {
-    struct CadetPeer *peer = cls;
-    GCC_handle_broken (peer, msg);
+  struct GCP_MessageQueueManager *mqm;
+
+  if (0 == cp->mqm_ready_counter)
+    return;
+  while ( (NULL != (mqm = cp->mqm_ready_ptr)) &&
+          (NULL == mqm->env) )
+    cp->mqm_ready_ptr = mqm->next;
+  if (NULL == mqm)
+    return; /* nothing to do */
+  mqm_execute (mqm);
 }
 
 
 /**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY
+ * Function called when CORE took one of the messages from
+ * a message queue manager and transmitted it.
  *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param cls the `struct CadetPeeer` where we made progress
  */
 static void
-handle_destroy (void *cls, const struct GNUNET_CADET_ConnectionDestroyMessage *msg)
+mqm_send_done (void *cls)
 {
-    struct CadetPeer *peer = cls;
-    GCC_handle_destroy (peer, msg);
+  struct CadetPeer *cp = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending to peer %s completed\n",
+       GCP_2s (cp));
+  send_next_ready (cp);
 }
 
 
 /**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK
+ * Send the message in @a env to @a cp.
  *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param mqm the message queue manager to use for transmission
+ * @param env envelope with the message to send; must NOT
+ *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
  */
-static void
-handle_ack (void *cls, const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg)
+void
+GCP_send (struct GCP_MessageQueueManager *mqm,
+          struct GNUNET_MQ_Envelope *env)
 {
-    struct CadetPeer *peer = cls;
-    GCC_handle_ack (peer, msg);
+  struct CadetPeer *cp = mqm->cp;
+
+  GNUNET_assert (NULL != env);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Queueing message to peer %s in MQM %p\n",
+       GCP_2s (cp),
+       mqm);
+  GNUNET_assert (NULL != cp->core_mq);
+  GNUNET_assert (NULL == mqm->env);
+  GNUNET_MQ_notify_sent (env,
+                         &mqm_send_done,
+                         cp);
+  mqm->env = env;
+  cp->mqm_ready_counter++;
+  if (mqm != cp->mqm_ready_ptr)
+    cp->mqm_ready_ptr = cp->mqm_head;
+  if (1 == cp->mqm_ready_counter)
+    cp->mqm_ready_ptr = mqm;
+  if (0 != GNUNET_MQ_get_length (cp->core_mq))
+    return;
+  send_next_ready (cp);
 }
 
 
 /**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL
+ * Function called to destroy a peer now.
  *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param cls NULL
+ * @param pid identity of the peer (unused)
+ * @param value the `struct CadetPeer` to clean up
+ * @return #GNUNET_OK (continue to iterate)
  */
-static void
-handle_poll (void *cls, const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg)
+static int
+destroy_iterator_cb (void *cls,
+                     const struct GNUNET_PeerIdentity *pid,
+                     void *value)
 {
-    struct CadetPeer *peer = cls;
-    GCC_handle_poll (peer, msg);
+  struct CadetPeer *cp = value;
+
+  if (NULL != cp->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (cp->destroy_task);
+    cp->destroy_task = NULL;
+  }
+  destroy_peer (cp);
+  return GNUNET_OK;
 }
 
 
 /**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX
- *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * Clean up all entries about all peers.
+ * Must only be called after all tunnels, CORE-connections and
+ * connections are down.
  */
-static void
-handle_kx (void *cls, const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
+void
+GCP_destroy_all_peers ()
 {
-    struct CadetPeer *peer = cls;
-    GCC_handle_kx (peer, msg);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying all peers now\n");
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         &destroy_iterator_cb,
+                                         NULL);
 }
 
 
 /**
- * Check if the encrypted message has the appropriate size.
+ * Drop all paths owned by this peer, and do not
+ * allow new ones to be added: We are shutting down.
  *
- * @param cls Closure (unused).
- * @param msg Message to check.
- *
- * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise.
+ * @param cp peer to drop paths to
  */
-static int
-check_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+void
+GCP_drop_owned_paths (struct CadetPeer *cp)
 {
-    uint16_t size;
-    uint16_t minimum_size;
-
-    size = ntohs (msg->header.size);
-    minimum_size = sizeof (struct GNUNET_CADET_TunnelEncryptedMessage)
-                   + sizeof (struct GNUNET_MessageHeader);
+  struct CadetPeerPath *path;
 
-    if (size < minimum_size)
-    {
-        GNUNET_break_op (0);
-        return GNUNET_NO;
-    }
-    return GNUNET_YES;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying all paths to %s\n",
+       GCP_2s (cp));
+  while (NULL != (path =
+                  GNUNET_CONTAINER_heap_remove_root (cp->path_heap)))
+    GCPP_release (path);
+  GNUNET_CONTAINER_heap_destroy (cp->path_heap);
+  cp->path_heap = NULL;
 }
 
+
 /**
- * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED.
+ * Add an entry to the DLL of all of the paths that this peer is on.
  *
- * @param cls Closure (CadetPeer for neighbor that sent the message).
- * @param msg Message itself.
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
  */
-static void
-handle_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-    struct CadetPeer *peer = cls;
-    GCC_handle_encrypted (peer, msg);
+void
+GCP_path_entry_add (struct CadetPeer *cp,
+                    struct CadetPeerPathEntry *entry,
+                    unsigned int off)
+{
+  GNUNET_assert (cp == GCPP_get_peer_at_offset (entry->path,
+                                                off));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Discovered that peer %s is on path %s at offset %u\n",
+       GCP_2s (cp),
+       GCPP_2s (entry->path),
+       off);
+  if (off >= cp->path_dll_length)
+  {
+    unsigned int len = cp->path_dll_length;
+
+    GNUNET_array_grow (cp->path_heads,
+                       len,
+                       off + 4);
+    GNUNET_array_grow (cp->path_tails,
+                       cp->path_dll_length,
+                       off + 4);
+  }
+  GNUNET_CONTAINER_DLL_insert (cp->path_heads[off],
+                               cp->path_tails[off],
+                               entry);
+  cp->off_sum += off;
+  cp->num_paths++;
+
+  /* If we have a tunnel to this peer, tell the tunnel that there is a
+     new path available. */
+  if (NULL != cp->t)
+    GCT_consider_path (cp->t,
+                       entry->path,
+                       off);
+
+  if ( (NULL != cp->search_h) &&
+       (DESIRED_CONNECTIONS_PER_TUNNEL <= cp->num_paths) )
+  {
+    /* Now I have enough paths, stop search */
+    GCD_search_stop (cp->search_h);
+    cp->search_h = NULL;
+  }
+  if (NULL != cp->destroy_task)
+  {
+    /* paths changed, this resets the destroy timeout counter
+       and aborts a destroy task that may no longer be valid
+       to have (as we now have more paths via this peer). */
+    consider_peer_destroy (cp);
+  }
 }
 
 
 /**
- * To be called on core init/fail.
+ * Remove an entry from the DLL of all of the paths that this peer is on.
  *
- * @param cls Closure (config)
- * @param identity The public identity of this peer.
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
  */
-static void
-core_init_notify (void *cls,
-                  const struct GNUNET_PeerIdentity *identity);
-
-
-static void
-connect_to_core (const struct GNUNET_CONFIGURATION_Handle *c)
-{
-    struct GNUNET_MQ_MessageHandler core_handlers[] = {
-        GNUNET_MQ_hd_var_size (create,
-                               GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE,
-                               struct GNUNET_CADET_ConnectionCreateMessage,
-                               NULL),
-        GNUNET_MQ_hd_fixed_size (confirm,
-                                 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK,
-                                 struct GNUNET_CADET_ConnectionCreateAckMessage,
-                                 NULL),
-        GNUNET_MQ_hd_fixed_size (broken,
-                                GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN,
-                                struct GNUNET_CADET_ConnectionBrokenMessage,
-                                NULL),
-        GNUNET_MQ_hd_fixed_size (destroy,
-                                 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY,
-                                 struct GNUNET_CADET_ConnectionDestroyMessage,
-                                 NULL),
-        GNUNET_MQ_hd_fixed_size (ack,
-                                 GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK,
-                                 struct GNUNET_CADET_ConnectionEncryptedAckMessage,
-                                 NULL),
-        GNUNET_MQ_hd_fixed_size (poll,
-                                 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL,
-                                 struct GNUNET_CADET_ConnectionHopByHopPollMessage,
-                                 NULL),
-        GNUNET_MQ_hd_fixed_size (kx,
-                                 GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX,
-                                 struct GNUNET_CADET_TunnelKeyExchangeMessage,
-                                 NULL),
-        GNUNET_MQ_hd_var_size (encrypted,
-                               GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED,
-                               struct GNUNET_CADET_TunnelEncryptedMessage,
-                               NULL),
-        GNUNET_MQ_handler_end ()
-    };
-    core_handle = GNUNET_CORE_connect (c, NULL,
-                                       &core_init_notify,
-                                       &core_connect_handler,
-                                       &core_disconnect_handler,
-                                       core_handlers);
+void
+GCP_path_entry_remove (struct CadetPeer *cp,
+                       struct CadetPeerPathEntry *entry,
+                       unsigned int off)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing knowledge about peer %s beging on path %s at offset %u\n",
+       GCP_2s (cp),
+       GCPP_2s (entry->path),
+       off);
+  GNUNET_CONTAINER_DLL_remove (cp->path_heads[off],
+                               cp->path_tails[off],
+                               entry);
+  GNUNET_assert (0 < cp->num_paths);
+  cp->off_sum -= off;
+  cp->num_paths--;
+  if ( (NULL == cp->core_mq) &&
+       (NULL != cp->t) &&
+       (NULL == cp->search_h) &&
+       (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) )
+    cp->search_h
+      = GCD_search (&cp->pid);
+  if (NULL == cp->destroy_task)
+  {
+    /* paths changed, we might now be ready for destruction, check again */
+    consider_peer_destroy (cp);
+  }
 }
 
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
-/******************************************************************************/
 
 /**
- * To be called on core init/fail.
+ * Prune down the number of paths to this peer, we seem to
+ * have way too many.
  *
- * @param cls Closure (config)
- * @param identity The public identity of this peer.
+ * @param cls the `struct CadetPeer` to maintain the path heap for
  */
 static void
-core_init_notify (void *cls,
-                  const struct GNUNET_PeerIdentity *core_identity)
+path_heap_cleanup (void *cls)
 {
-    const struct GNUNET_CONFIGURATION_Handle *c = cls;
+  struct CadetPeer *cp = cls;
+  struct CadetPeerPath *root;
 
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n");
-    if (0 != memcmp (core_identity, &my_full_id, sizeof (my_full_id)))
-    {
-        LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n"));
-        LOG (GNUNET_ERROR_TYPE_ERROR, " core id %s\n", GNUNET_i2s (core_identity));
-        LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id));
-        GNUNET_CORE_disconnect (core_handle);
-        connect_to_core (c);
-        return;
-    }
-    GML_start ();
+  cp->heap_cleanup_task = NULL;
+  while (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
+         2 * DESIRED_CONNECTIONS_PER_TUNNEL)
+  {
+    /* Now we have way too many, drop least desirable UNLESS it is in use!
+       (Note that this intentionally keeps highly desireable, but currently
+       unused paths around in the hope that we might be able to switch, even
+       if the number of paths exceeds the threshold.) */
+    root = GNUNET_CONTAINER_heap_peek (cp->path_heap);
+    GNUNET_assert (NULL != root);
+    if (NULL !=
+        GCPP_get_connection (root,
+                             cp,
+                             GCPP_get_length (root) - 1))
+      break; /* can't fix */
+    /* Got plenty of paths to this destination, and this is a low-quality
+       one that we don't care about. Allow it to die. */
+    GNUNET_assert (root ==
+                   GNUNET_CONTAINER_heap_remove_root (cp->path_heap));
+    GCPP_release (root);
+  }
 }
 
 
-/******************************************************************************/
-/********************************   STATIC  ***********************************/
-/******************************************************************************/
-
-
 /**
- * Get priority for a queued message.
- *
- * @param q Queued message
+ * Try adding a @a path to this @a peer.  If the peer already
+ * has plenty of paths, return NULL.
  *
- * @return CORE priority to use.
- *
- * FIXME make static
- * FIXME use when sending
+ * @param cp peer to which the @a path leads to
+ * @param path a path looking for an owner; may not be fully initialized yet!
+ * @param off offset of @a cp in @a path
+ * @param force force attaching the path
+ * @return NULL if this peer does not care to become a new owner,
+ *         otherwise the node in the peer's path heap for the @a path.
  */
-enum GNUNET_CORE_Priority
-get_priority (struct CadetPeerQueue *q)
+struct GNUNET_CONTAINER_HeapNode *
+GCP_attach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path,
+                 unsigned int off,
+                 int force)
 {
-    enum GNUNET_CORE_Priority low;
-    enum GNUNET_CORE_Priority high;
+  GNUNET_CONTAINER_HeapCostType desirability;
+  struct CadetPeerPath *root;
+  GNUNET_CONTAINER_HeapCostType root_desirability;
+  struct GNUNET_CONTAINER_HeapNode *hn;
 
-    if (NULL == q)
+  GNUNET_assert (off == GCPP_get_length (path) - 1);
+  GNUNET_assert (cp == GCPP_get_peer_at_offset (path,
+                                                off));
+  if (NULL == cp->path_heap)
+  {
+    /* #GCP_drop_owned_paths() was already called, we cannot take new ones! */
+    GNUNET_assert (GNUNET_NO == force);
+    return NULL;
+  }
+  desirability = GCPP_get_desirability (path);
+  if (GNUNET_NO == force)
+  {
+    /* FIXME: desirability is not yet initialized; tricky! */
+    if (GNUNET_NO ==
+        GNUNET_CONTAINER_heap_peek2 (cp->path_heap,
+                                     (void **) &root,
+                                     &root_desirability))
     {
-        GNUNET_break (0);
-        return GNUNET_CORE_PRIO_BACKGROUND;
+      root = NULL;
+      root_desirability = 0;
     }
 
-    /* Relayed traffic has lower priority, our own traffic has higher */
-    if (NULL == q->c || GNUNET_NO == GCC_is_origin (q->c, q->c_fwd))
-    {
-        low = GNUNET_CORE_PRIO_BEST_EFFORT;
-        high = GNUNET_CORE_PRIO_URGENT;
-    }
-    else
+    if ( (DESIRED_CONNECTIONS_PER_TUNNEL > cp->num_paths) &&
+         (desirability < root_desirability) )
     {
-        low = GNUNET_CORE_PRIO_URGENT;
-        high = GNUNET_CORE_PRIO_CRITICAL_CONTROL;
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Decided to not attach path %p to peer %s due to undesirability\n",
+           GCPP_2s (path),
+           GCP_2s (cp));
+      return NULL;
     }
+  }
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Attaching path %s to peer %s (%s)\n",
+       GCPP_2s (path),
+       GCP_2s (cp),
+       (GNUNET_NO == force) ? "desirable" : "forced");
 
-    /* Bulky payload has lower priority, control traffic has higher. */
-    if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == q->type)
-        return low;
-    return high;
+  /* Yes, we'd like to add this path, add to our heap */
+  hn = GNUNET_CONTAINER_heap_insert (cp->path_heap,
+                                     path,
+                                     desirability);
+
+  /* Consider maybe dropping other paths because of the new one */
+  if ( (GNUNET_CONTAINER_heap_get_size (cp->path_heap) >=
+        2 * DESIRED_CONNECTIONS_PER_TUNNEL) &&
+       (NULL != cp->heap_cleanup_task) )
+    cp->heap_cleanup_task = GNUNET_SCHEDULER_add_now (&path_heap_cleanup,
+                                                      cp);
+  return hn;
 }
 
 
 /**
- * Cancel all messages queued to CORE MQ towards this peer.
+ * This peer can no longer own @a path as the path
+ * has been extended and a peer further down the line
+ * is now the new owner.
  *
- * @param peer Peer towards which to cancel all messages.
+ * @param cp old owner of the @a path
+ * @param path path where the ownership is lost
+ * @param hn note in @a cp's path heap that must be deleted
  */
-static void
-cancel_queued_messages (struct CadetPeer *peer)
+void
+GCP_detach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path,
+                 struct GNUNET_CONTAINER_HeapNode *hn)
 {
-    while (NULL != peer->q_head)
-    {
-        struct CadetPeerQueue *q;
-
-        q = peer->q_head;
-        call_peer_cont (q, GNUNET_NO);
-        GNUNET_free (q);
-    }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Detatching path %s from peer %s\n",
+       GCPP_2s (path),
+       GCP_2s (cp));
+  GNUNET_assert (path ==
+                 GNUNET_CONTAINER_heap_remove_node (hn));
 }
 
 
 /**
- * Destroy the peer_info and free any allocated resources linked to it
+ * Add a @a connection to this @a cp.
  *
- * @param peer The peer_info to destroy.
- * @return #GNUNET_OK on success
+ * @param cp peer via which the @a connection goes
+ * @param cc the connection to add
  */
-static int
-peer_destroy (struct CadetPeer *peer)
-{
-    struct GNUNET_PeerIdentity id;
-    struct CadetPeerPath *p;
-    struct CadetPeerPath *nextp;
-
-    GNUNET_PEER_resolve (peer->id, &id);
-    GNUNET_PEER_change_rc (peer->id, -1);
-
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         "destroying peer %s\n",
-         GNUNET_i2s (&id));
-
-    if (GNUNET_YES !=
-            GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer))
-    {
-        GNUNET_break (0);
-        LOG (GNUNET_ERROR_TYPE_WARNING, " peer not in peermap!!\n");
-    }
-    GCP_stop_search (peer);
-    p = peer->path_head;
-    while (NULL != p)
-    {
-        nextp = p->next;
-        GNUNET_CONTAINER_DLL_remove (peer->path_head,
-                                     peer->path_tail,
-                                     p);
-        path_destroy (p);
-        p = nextp;
-    }
-    if (NULL != peer->tunnel)
-        GCT_destroy_empty (peer->tunnel);
-    if (NULL != peer->connections)
-    {
-        GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (peer->connections));
-        GNUNET_CONTAINER_multishortmap_destroy (peer->connections);
-        peer->connections = NULL;
-    }
-    if (NULL != peer->hello_offer)
-    {
-        GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
-        peer->hello_offer = NULL;
-    }
-    if (NULL != peer->connectivity_suggestion)
-    {
-        GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion);
-        peer->connectivity_suggestion = NULL;
-    }
-    cancel_queued_messages (peer);
-
-    GNUNET_free_non_null (peer->hello);
-    GNUNET_free (peer);
-    return GNUNET_OK;
+void
+GCP_add_connection (struct CadetPeer *cp,
+                    struct CadetConnection *cc)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Adding connection %s to peer %s\n",
+       GCC_2s (cc),
+       GCP_2s (cp));
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multishortmap_put (cp->connections,
+                                                     &GCC_get_id (cc)->connection_of_tunnel,
+                                                     cc,
+                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  if (NULL != cp->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (cp->destroy_task);
+    cp->destroy_task = NULL;
+  }
 }
 
 
 /**
- * Iterator over peer hash map entries to destroy the peer during in_shutdown.
+ * Remove a @a connection that went via this @a cp.
  *
- * @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.
+ * @param cp peer via which the @a connection went
+ * @param cc the connection to remove
  */
-static int
-shutdown_peer (void *cls,
-               const struct GNUNET_PeerIdentity *key,
-               void *value)
+void
+GCP_remove_connection (struct CadetPeer *cp,
+                       struct CadetConnection *cc)
 {
-    struct CadetPeer *p = value;
-    struct CadetTunnel *t = p->tunnel;
-
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  shutting down %s\n", GCP_2s (p));
-    if (NULL != t)
-        GCT_destroy (t);
-    p->tunnel = NULL;
-    peer_destroy (p);
-    return GNUNET_YES;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing connection %s from peer %s\n",
+       GCC_2s (cc),
+       GCP_2s (cp));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multishortmap_remove (cp->connections,
+                                                        &GCC_get_id (cc)->connection_of_tunnel,
+                                                        cc));
+  consider_peer_destroy (cp);
 }
 
 
 /**
- * Check if peer is searching for a path (either active or delayed search).
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
  *
- * @param peer Peer to check
- * @return #GNUNET_YES if there is a search active.
- *         #GNUNET_NO otherwise.
+ * @param peer_id Full identity of the peer.
+ * @param create #GNUNET_YES if a new peer should be created if unknown.
+ *               #GNUNET_NO to return NULL if peer is unknown.
+ * @return Existing or newly created peer structure.
+ *         NULL if unknown and not requested @a create
  */
-static int
-is_searching (const struct CadetPeer *peer)
+struct CadetPeer *
+GCP_get (const struct GNUNET_PeerIdentity *peer_id,
+         int create)
 {
-    return ( (NULL == peer->search_h) &&
-             (NULL == peer->search_delayed) ) ?
-           GNUNET_NO : GNUNET_YES;
+  struct CadetPeer *cp;
+
+  cp = GNUNET_CONTAINER_multipeermap_get (peers,
+                                          peer_id);
+  if (NULL != cp)
+    return cp;
+  if (GNUNET_NO == create)
+    return NULL;
+  cp = GNUNET_new (struct CadetPeer);
+  cp->pid = *peer_id;
+  cp->connections = GNUNET_CONTAINER_multishortmap_create (32,
+                                                           GNUNET_YES);
+  cp->path_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multipeermap_put (peers,
+                                                    &cp->pid,
+                                                    cp,
+                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating peer %s\n",
+       GCP_2s (cp));
+  return cp;
 }
 
 
 /**
- * @brief Start a search for a peer.
+ * Obtain the peer identity for a `struct CadetPeer`.
  *
- * @param cls Closure (Peer to search for).
+ * @param cp our peer handle
+ * @return the peer identity
  */
-static void
-delayed_search (void *cls)
+const struct GNUNET_PeerIdentity *
+GCP_get_id (struct CadetPeer *cp)
 {
-    struct CadetPeer *peer = cls;
-
-    peer->search_delayed = NULL;
-    GCC_check_connections ();
-    GCP_start_search (peer);
-    GCC_check_connections ();
+  return &cp->pid;
 }
 
 
 /**
- * Returns if peer is used (has a tunnel or is neighbor).
+ * Iterate over all known peers.
  *
- * @param peer Peer to check.
- * @return #GNUNET_YES if peer is in use.
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
  */
-static int
-peer_is_used (struct CadetPeer *peer)
+void
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+                 void *cls)
 {
-    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;
+  GNUNET_CONTAINER_multipeermap_iterate (peers,
+                                         iter,
+                                         cls);
 }
 
 
 /**
- * Iterator over all the peers to get the oldest timestamp.
+ * Count the number of known paths toward the peer.
  *
- * @param cls Closure (unsued).
- * @param key ID of the peer.
- * @param value Peer_Info of the peer.
+ * @param cp Peer to get path info.
+ * @return Number of known paths.
  */
-static int
-peer_get_oldest (void *cls,
-                 const struct GNUNET_PeerIdentity *key,
-                 void *value)
+unsigned int
+GCP_count_paths (const struct CadetPeer *cp)
 {
-    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;
+  return cp->num_paths;
 }
 
 
 /**
- * Iterator over all the peers to remove the oldest entry.
+ * Iterate over the paths to a peer.
  *
- * @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 == GCT_is_path_used (peer->tunnel, p))
-            continue; /* If path is already in use, skip it. */
-
-        if ((cost = GCT_get_path_cost (peer->tunnel, p)) < best_cost)
-        {
-            best_cost = cost;
-            best_p = p;
-        }
-    }
-    return best_p;
-}
-
-
-/**
- * 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 (peer towards a path has been found).
- * @param path Path created from the DHT query. Will be freed afterwards.
- */
-static void
-search_handler (void *cls, const struct CadetPeerPath *path)
-{
-    struct CadetPeer *peer = cls;
-    unsigned int connection_count;
-
-    GCC_check_connections ();
-    GCP_add_path_to_all (path, GNUNET_NO);
-
-    /* Count connections */
-    connection_count = GCT_count_connections (peer->tunnel);
-
-    /* If we already have our minimum (or more) connections, it's enough */
-    if (CONNECTIONS_PER_TUNNEL <= connection_count)
-    {
-        GCC_check_connections ();
-        return;
-    }
-
-    if (CADET_TUNNEL_SEARCHING == GCT_get_cstate (peer->tunnel))
-    {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, " ... connect!\n");
-        GCP_connect (peer);
-    }
-    GCC_check_connections ();
-}
-
-
-/**
- * Test if a message type is connection management traffic
- * or regular payload traffic.
- *
- * @param type Message type.
- *
- * @return #GNUNET_YES if connection management, #GNUNET_NO otherwise.
- */
-static int
-is_connection_management (uint16_t type)
-{
-    return type == GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK ||
-           type == GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL;
-}
-
-
-/**
- * Debug function should NEVER return true in production code, useful to
- * simulate losses for testcases.
- *
- * @return #GNUNET_YES or #GNUNET_NO with the decision to drop.
- */
-static int
-should_I_drop (void)
-{
-    if (0 == drop_percent)
-        return GNUNET_NO;
-
-    if (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 101) < drop_percent)
-        return GNUNET_YES;
-
-    return GNUNET_NO;
-}
-
-
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
-
-/**
- * Call the continuation after a message has been sent or dropped.
- *
- * This funcion removes the message from the queue.
- *
- * @param q Queue handle.
- * @param sent #GNUNET_YES if was sent to CORE, #GNUNET_NO if dropped.
+ * @param cp Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
  */
-static void
-call_peer_cont (struct CadetPeerQueue *q, int sent)
+unsigned int
+GCP_iterate_paths (struct CadetPeer *cp,
+                   GCP_PathIterator callback,
+                   void *callback_cls)
 {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " core mq just sent %s\n", GC_m2s (q->type));
-    if (NULL != q->cont)
-    {
-        struct GNUNET_TIME_Relative wait_time;
-
-        wait_time = GNUNET_TIME_absolute_get_duration (q->queue_timestamp);
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             " calling callback on %s after %s\n",
-             GCC_2s (q->c),
-             GNUNET_STRINGS_relative_time_to_string (wait_time, GNUNET_NO));
-        q->cont (q->cont_cls,
-                 q->c, q->c_fwd, sent,
-                 q->type,
-                 q->payload_type,
-                 q->payload_id,
-                 q->size, wait_time);
-       q->cont = NULL;
-    }
-    GNUNET_CONTAINER_DLL_remove (q->peer->q_head, q->peer->q_tail, q);
-}
-
+  unsigned int ret = 0;
 
-/**
- * Function called by MQ when a message is sent to CORE.
- *
- * @param cls Closure (queue handle).
- */
-static void
-mq_sent (void *cls)
-{
-    struct CadetPeerQueue *q = cls;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Iterating over paths to peer %s%s\n",
+       GCP_2s (cp),
+       (NULL == cp->core_mq) ? "" : " including direct link");
+  if (NULL != cp->core_mq)
+  {
+    struct CadetPeerPath *path;
 
-    if (GNUNET_NO == q->management_traffic)
+    path = GCPP_get_path_from_route (1,
+                                     &cp->pid);
+    ret++;
+    if (GNUNET_NO ==
+        callback (callback_cls,
+                  path,
+                  0))
+      return ret;
+  }
+  for (unsigned int i=0;i<cp->path_dll_length;i++)
+  {
+    for (struct CadetPeerPathEntry *pe = cp->path_heads[i];
+         NULL != pe;
+         pe = pe->next)
     {
-        q->peer->queue_n--;
+      ret++;
+      if (GNUNET_NO ==
+          callback (callback_cls,
+                    pe->path,
+                    i))
+        return ret;
     }
-    call_peer_cont (q, GNUNET_YES);
-    GNUNET_free (q);
-}
-
-
-/**
- * Finish the drop operation.
- *
- * @param cls queue entry to finish drop for
- */
-static void
-drop_cb (void *cls)
-{
-  struct CadetPeerQueue *q = cls;
-
-  GNUNET_MQ_discard (q->env);
-  call_peer_cont (q, GNUNET_YES);
-  GNUNET_free (q);
+  }
+  return ret;
 }
 
 
 /**
- * @brief Send a message to another peer (using CORE).
+ * Iterate over the paths to @a cp where
+ * @a cp is at distance @a dist from us.
  *
- * @param peer Peer towards which to queue the message.
- * @param message Message to send.
- * @param payload_type Type of the message's payload, for debug messages.
- *                     0 if the message is a retransmission (unknown payload).
- *                     UINT16_MAX if the message does not have payload.
- * @param payload_id ID of the payload (MID, ACK #, etc)
- * @param c Connection this message belongs to (can be NULL).
- * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
- * @param cont Continuation to be called once CORE has sent the message.
- * @param cont_cls Closure for @c cont.
- *
- * @return A handle to the message in the queue or NULL (if dropped).
+ * @param cp Peer to get path info.
+ * @param dist desired distance of @a cp to us on the path
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
  */
-struct CadetPeerQueue *
-GCP_send (struct CadetPeer *peer,
-          const struct GNUNET_MessageHeader *message,
-          uint16_t payload_type,
-          struct CadetEncryptedMessageIdentifier payload_id,
-          struct CadetConnection *c,
-          int fwd,
-          GCP_sent cont,
-          void *cont_cls)
+unsigned int
+GCP_iterate_paths_at (struct CadetPeer *cp,
+                      unsigned int dist,
+                      GCP_PathIterator callback,
+                      void *callback_cls)
 {
-    struct CadetPeerQueue *q;
-    uint16_t type;
-    uint16_t size;
-
-    GCC_check_connections ();
-    type = ntohs (message->type);
-    size = ntohs (message->size);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "que %s (%s %4u) on conn %s (%p) %s towards %s (size %u)\n",
-         GC_m2s (type), GC_m2s (payload_type),
-         ntohl (payload_id.pid),
-         GCC_2s (c), c, GC_f2s (fwd), GCP_2s (peer), size);
-
-    if (NULL == peer->connections)
-    {
-        /* We are not connected to this peer, ignore request. */
-        GNUNET_break (0);
-        LOG (GNUNET_ERROR_TYPE_INFO, "%s not a neighbor\n", GCP_2s (peer));
-        GNUNET_STATISTICS_update (stats, "# messages dropped due to wrong hop", 1,
-                                  GNUNET_NO);
-        return NULL;
-    }
-
-    q = GNUNET_new (struct CadetPeerQueue);
-    q->env = GNUNET_MQ_msg_copy (message);
-    q->peer = peer;
-    q->cont = cont;
-    q->cont_cls = cont_cls;
-    q->queue_timestamp = GNUNET_TIME_absolute_get ();
-    q->management_traffic = is_connection_management (type);
-    q->type = type;
-    q->size = size;
-    q->payload_type = payload_type;
-    q->payload_id = payload_id;
-    q->c = c;
-    q->c_fwd = fwd;
-    GNUNET_MQ_notify_sent (q->env, &mq_sent, q);
-    GNUNET_CONTAINER_DLL_insert (peer->q_head, peer->q_tail, q);
-
-    if (GNUNET_YES == q->management_traffic)
-    {
-        GNUNET_MQ_send (peer->core_mq, q->env);  // FIXME implement "_urgent", use
-    }
-    else
-    {
-        if (GNUNET_YES == should_I_drop ())
-        {
-            LOG (GNUNET_ERROR_TYPE_WARNING,
-                "DD %s (%s %u) on conn %s %s (random drop for testing)\n",
-                 GC_m2s (q->type),
-                 GC_m2s (q->payload_type),
-                 ntohl (q->payload_id.pid),
-                 GCC_2s (c),
-                 GC_f2s (q->c_fwd));
-           q->drop_task = GNUNET_SCHEDULER_add_now (&drop_cb,
-                                                    q);
-           return q;
-        }
-        GNUNET_MQ_send (peer->core_mq, q->env);
-        peer->queue_n++;
-    }
-
-    GCC_check_connections ();
-    return q;
-}
-
+  unsigned int ret = 0;
 
-/**
- * Cancel sending a message. Message must have been sent with
- * #GCP_send before.  May not be called after the notify sent
- * callback has been called.
- *
- * It DOES call the continuation given to #GCP_send.
- *
- * @param q Queue handle to cancel
- */
-void
-GCP_send_cancel (struct CadetPeerQueue *q)
-{
-  if (NULL != q->drop_task)
+  if (dist >= cp->path_dll_length)
   {
-    GNUNET_SCHEDULER_cancel (q->drop_task);
-    q->drop_task = NULL;
-    GNUNET_MQ_discard (q->env);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Asked to look for paths at distance %u, but maximum for me is < %u\n",
+         dist,
+         cp->path_dll_length);
+    return 0;
   }
-  else
+  for (struct CadetPeerPathEntry *pe = cp->path_heads[dist];
+       NULL != pe;
+       pe = pe->next)
   {
-    GNUNET_MQ_send_cancel (q->env);
+    if (GNUNET_NO ==
+        callback (callback_cls,
+                  pe->path,
+                  dist))
+      return ret;
+    ret++;
   }
-  call_peer_cont (q, GNUNET_NO);
-  GNUNET_free (q);
-}
-
-
-/**
- * Initialize the peer subsystem.
- *
- * @param c Configuration.
- */
-void
-GCP_init (const struct GNUNET_CONFIGURATION_Handle *c)
-{
-    cfg = c;
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "GCP_init\n");
-    in_shutdown = GNUNET_NO;
-    peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
-    if (GNUNET_OK !=
-            GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_PEERS",
-                    &max_peers))
-    {
-        GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                                   "CADET", "MAX_PEERS", "USING DEFAULT");
-        max_peers = 1000;
-    }
-
-    if (GNUNET_OK !=
-            GNUNET_CONFIGURATION_get_value_number (c, "CADET", "DROP_PERCENT",
-                    &drop_percent))
-    {
-        drop_percent = 0;
-    }
-    else
-    {
-        LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
-        LOG (GNUNET_ERROR_TYPE_WARNING, "Cadet is running with DROP enabled.\n");
-        LOG (GNUNET_ERROR_TYPE_WARNING, "This is NOT a good idea!\n");
-        LOG (GNUNET_ERROR_TYPE_WARNING, "Remove DROP_PERCENT from config file.\n");
-        LOG (GNUNET_ERROR_TYPE_WARNING, "**************************************\n");
-    }
-    ats_ch = GNUNET_ATS_connectivity_init (c);
-    connect_to_core (c);
-    if (NULL == core_handle)
-    {
-        GNUNET_break (0);
-        GNUNET_SCHEDULER_shutdown ();
-    }
-}
-
-
-/**
- * Shut down the peer subsystem.
- */
-void
-GCP_shutdown (void)
-{
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Shutting down peer subsystem\n");
-    in_shutdown = GNUNET_YES;
-    if (NULL != core_handle)
-    {
-        GNUNET_CORE_disconnect (core_handle);
-        core_handle = NULL;
-    }
-    GNUNET_PEER_change_rc (myid, -1);
-    /* With MQ API, CORE calls the disconnect handler for every peer
-     * after calling GNUNET_CORE_disconnect, shutdown must occur *after* that.
-     */
-    GNUNET_CONTAINER_multipeermap_iterate (peers,
-                                           &shutdown_peer,
-                                           NULL);
-    if (NULL != ats_ch)
-    {
-        GNUNET_ATS_connectivity_done (ats_ch);
-        ats_ch = NULL;
-    }
-    GNUNET_CONTAINER_multipeermap_destroy (peers);
-    peers = NULL;
-}
-
-
-/**
- * Retrieve the CadetPeer stucture associated with the peer. Optionally create
- * one and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer_id Full identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- *               #GNUNET_NO otherwise.
- *
- * @return Existing or newly created peer structure.
- *         NULL if unknown and not requested @a create
- */
-struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create)
-{
-    struct CadetPeer *peer;
-
-    peer = GNUNET_CONTAINER_multipeermap_get (peers, peer_id);
-    if (NULL == peer)
-    {
-        peer = GNUNET_new (struct CadetPeer);
-        if (GNUNET_CONTAINER_multipeermap_size (peers) > max_peers)
-        {
-            peer_delete_oldest ();
-        }
-        GNUNET_assert (GNUNET_OK ==
-                       GNUNET_CONTAINER_multipeermap_put (peers,
-                               peer_id,
-                               peer,
-                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-        peer->id = GNUNET_PEER_intern (peer_id);
-    }
-    peer->last_contact = GNUNET_TIME_absolute_get ();
-
-    return peer;
+  return ret;
 }
 
 
 /**
- * Retrieve the CadetPeer stucture associated with the
- * peer. Optionally create one and insert it in the appropriate
- * structures if the peer is not known yet.
- *
- * @param peer Short identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- *               #GNUNET_NO otherwise.
+ * Get the tunnel towards a peer.
  *
- * @return Existing or newly created peer structure.
- *         NULL if unknown and not requested @a create
+ * @param cp Peer to get from.
+ * @param create #GNUNET_YES to create a tunnel if we do not have one
+ * @return Tunnel towards peer.
  */
-struct CadetPeer *
-GCP_get_short (const GNUNET_PEER_Id peer, int create)
+struct CadetTunnel *
+GCP_get_tunnel (struct CadetPeer *cp,
+                int create)
 {
-    return GCP_get (GNUNET_PEER_resolve2 (peer), create);
+  if (NULL == cp)
+    return NULL;
+  if ( (NULL != cp->t) ||
+       (GNUNET_NO == create) )
+    return cp->t;
+  cp->t = GCT_create_tunnel (cp);
+  consider_peer_activate (cp);
+  return cp->t;
 }
 
 
 /**
- * Function called once #GNUNET_TRANSPORT_offer_hello() is done.
- * Marks the operation as finished.
+ * Hello offer was passed to the transport service. Mark it
+ * as done.
  *
- * @param cls Closure (our `struct CadetPeer`).
+ * @param cls the `struct CadetPeer` where the offer completed
  */
 static void
 hello_offer_done (void *cls)
 {
-    struct CadetPeer *peer = cls;
+  struct CadetPeer *cp = cls;
 
-    peer->hello_offer = NULL;
+  cp->hello_offer = 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.
+ * We got a HELLO for a @a peer, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
  *
- * @param peer Peer to connect to.
+ * @param cp the peer we got a HELLO for
+ * @param hello the HELLO to remember
  */
 void
-GCP_connect (struct CadetPeer *peer)
-{
-    struct CadetTunnel *t;
-    struct CadetPeerPath *path;
-    struct CadetConnection *c;
-    int rerun_search;
-
-    GCC_check_connections ();
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "peer_connect towards %s\n",
-         GCP_2s (peer));
-    /* If we have a current hello, try to connect using it. */
-    GCP_try_connect (peer);
-
-    t = peer->tunnel;
-    c = NULL;
-    rerun_search = GNUNET_NO;
-
-    if (NULL != peer->path_head)
-    {
-        LOG (GNUNET_ERROR_TYPE_DEBUG, "  some path exists\n");
-        path = peer_get_best_path (peer);
-        if (NULL != path)
-        {
-            char *s;
-
-            s = path_2s (path);
-            LOG (GNUNET_ERROR_TYPE_DEBUG, "  path to use: %s\n", s);
-            GNUNET_free (s);
-
-            c = GCT_use_path (t, path);
-            if (NULL == c)
-            {
-                /* This case can happen when the path includes a first hop that is
-                 * not yet known to be connected.
-                 *
-                 * This happens quite often during testing when running cadet
-                 * under valgrind: core connect notifications come very late
-                 * and the DHT result has already come and created a valid
-                 * path.  In this case, the peer->connections
-                 * hashmaps will be NULL and tunnel_use_path will not be able
-                 * to create a connection from that path.
-                 *
-                 * Re-running the DHT GET should give core time to callback.
-                 *
-                 * GCT_use_path -> GCC_new -> register_neighbors takes care of
-                 * updating statistics about this issue.
-                 */
-                rerun_search = GNUNET_YES;
-            }
-            else
-            {
-                GCC_send_create (c);
-                return;
-            }
-        }
-        else
-        {
-            LOG (GNUNET_ERROR_TYPE_DEBUG, "  but is NULL, all paths are in use\n");
-        }
-    }
-
-    if (GNUNET_YES == rerun_search)
-    {
-        struct GNUNET_TIME_Relative delay;
-
-        GCP_stop_search (peer);
-        delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
-        peer->search_delayed = GNUNET_SCHEDULER_add_delayed (delay,
-                               &delayed_search,
-                               peer);
-        GCC_check_connections ();
-        return;
-    }
-
-    if (GNUNET_NO == is_searching (peer))
-        GCP_start_search (peer);
-    GCC_check_connections ();
-}
-
-
-/**
- * Chech whether there is a direct (core level)  connection to peer.
- *
- * @param peer Peer to check.
- *
- * @return #GNUNET_YES if there is a direct connection.
- */
-int
-GCP_is_neighbor (const struct CadetPeer *peer)
-{
-    struct CadetPeerPath *path;
-
-    if (NULL == peer->connections)
-        return GNUNET_NO;
-
-    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
-GCP_add_tunnel (struct CadetPeer *peer)
-{
-    GCC_check_connections ();
-    if (NULL != peer->tunnel)
-        return;
-    peer->tunnel = GCT_new (peer);
-    GCC_check_connections ();
-}
-
-
-/**
- * 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.
- * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor
- */
-void
-GCP_add_connection (struct CadetPeer *peer,
-                    struct CadetConnection *c,
-                    int pred)
-{
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "adding connection %s\n",
-         GCC_2s (c));
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "to peer %s\n",
-         GCP_2s (peer));
-    GNUNET_assert (NULL != peer->connections);
-    GNUNET_assert (GNUNET_OK ==
-                   GNUNET_CONTAINER_multishortmap_put (peer->connections,
-                                                       &GCC_get_id (c)->connection_of_tunnel,
-                                                       c,
-                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Peer %s has now %u connections.\n",
-         GCP_2s (peer),
-         GNUNET_CONTAINER_multishortmap_size (peer->connections));
-}
-
-
-/**
- * Add the path to the peer and update the path used to reach it in case this
- * is the shortest.
- *
- * @param peer Destination peer to add the path to.
- * @param path New path to add. Last peer must be @c peer.
- *             Path will be either used of freed if already known.
- * @param trusted Do we trust that this path is real?
- *
- * @return path if path was taken, pointer to existing duplicate if exists
- *         NULL on error.
- */
-struct CadetPeerPath *
-GCP_add_path (struct CadetPeer *peer,
-              struct CadetPeerPath *path,
-              int trusted)
-{
-    struct CadetPeerPath *aux;
-    unsigned int l;
-    unsigned int l2;
-
-    GCC_check_connections ();
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "adding path [%u] to peer %s\n",
-         path->length, GCP_2s (peer));
-
-    if (NULL == peer || NULL == path
-            || path->peers[path->length - 1] != peer->id)
-    {
-        GNUNET_break (0);
-        path_destroy (path);
-        return NULL;
-    }
-
-    for (l = 1; l < path->length; l++)
-    {
-        if (path->peers[l] == myid)
-        {
-            LOG (GNUNET_ERROR_TYPE_DEBUG, " shortening path by %u\n", l);
-            for (l2 = 0; l2 < path->length - l; l2++)
-            {
-                path->peers[l2] = path->peers[l + l2];
-            }
-            path->length -= l;
-            l = 1;
-            path->peers = GNUNET_realloc (path->peers,
-                                          path->length * sizeof (GNUNET_PEER_Id));
-        }
-    }
-
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " final length: %u\n", path->length);
-
-    if (2 >= path->length && GNUNET_NO == trusted)
-    {
-        /* Only allow CORE to tell us about direct paths */
-        path_destroy (path);
-        return NULL;
-    }
-
-    l = path_get_length (path);
-    if (0 == l)
-    {
-        path_destroy (path);
-        return NULL;
-    }
-
-    GNUNET_assert (peer->id == path->peers[path->length - 1]);
-    for (aux = peer->path_head; aux != NULL; aux = aux->next)
-    {
-        l2 = path_get_length (aux);
-        if (l2 > l)
-        {
-            LOG (GNUNET_ERROR_TYPE_DEBUG, "  added\n");
-            GNUNET_CONTAINER_DLL_insert_before (peer->path_head,
-                                                peer->path_tail, aux, path);
-            goto finish;
-        }
-        else
-        {
-            if (l2 == l && memcmp (path->peers, aux->peers, l) == 0)
-            {
-                LOG (GNUNET_ERROR_TYPE_DEBUG, "  already known\n");
-                path_destroy (path);
-                return aux;
-            }
-        }
-    }
-    GNUNET_CONTAINER_DLL_insert_tail (peer->path_head,
-                                      peer->path_tail,
-                                      path);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  added last\n");
-
-finish:
-    if (NULL != peer->tunnel
-            && CONNECTIONS_PER_TUNNEL > GCT_count_connections (peer->tunnel)
-            && 2 < path->length) /* Direct paths are handled by core_connect */
-    {
-        GCP_connect (peer);
-    }
-    GCC_check_connections ();
-    return path;
-}
-
-
-/**
- * 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 *
-GCP_add_path_to_origin (struct CadetPeer *peer,
-                        struct CadetPeerPath *path,
-                        int trusted)
-{
-    if (NULL == path)
-        return NULL;
-    path_invert (path);
-    return GCP_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
-GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed)
-{
-    unsigned int i;
-
-    /* TODO: invert and add to origin */
-    /* TODO: replace all "GCP_add_path" with this, make the other one static */
-    GCC_check_connections ();
-    for (i = 0; i < p->length && p->peers[i] != myid; i++) /* skip'em */ ;
-    for (i++; i < p->length; i++)
-    {
-        struct CadetPeer *peer;
-        struct CadetPeerPath *copy;
-
-        peer = GCP_get_short (p->peers[i], GNUNET_YES);
-        copy = path_duplicate (p);
-        copy->length = i + 1;
-        GCP_add_path (peer, copy, 3 > p->length ? GNUNET_NO : confirmed);
-    }
-    GCC_check_connections ();
-}
-
-
-/**
- * Remove any path to the peer that has the exact same peers as the one given.
- *
- * @param peer Peer to remove the path from.
- * @param path Path to remove. Is always destroyed .
- */
-void
-GCP_remove_path (struct CadetPeer *peer,
-                 struct CadetPeerPath *path)
-{
-    struct CadetPeerPath *iter;
-    struct CadetPeerPath *next;
-
-    GCC_check_connections ();
-    GNUNET_assert (myid == path->peers[0]);
-    GNUNET_assert (peer->id == path->peers[path->length - 1]);
-
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         "Removing path %p (%u) from %s\n",
-         path, path->length, GCP_2s (peer));
-
-    for (iter = peer->path_head; NULL != iter; iter = next)
-    {
-        next = iter->next;
-        if (0 == path_cmp (path, iter))
-        {
-            GNUNET_CONTAINER_DLL_remove (peer->path_head,
-                                         peer->path_tail,
-                                         iter);
-            if (iter != path)
-                path_destroy (iter);
-        }
-    }
-    path_destroy (path);
-    GCC_check_connections ();
-}
-
-
-/**
- * Check that we are aware of a connection from a neighboring peer.
- *
- * @param peer Peer to the connection is with
- * @param c Connection that should be in the map with this peer.
- */
-void
-GCP_check_connection (const struct CadetPeer *peer,
-                      const struct CadetConnection *c)
+GCP_set_hello (struct CadetPeer *cp,
+               const struct GNUNET_HELLO_Message *hello)
 {
-  GNUNET_assert (NULL != peer);
-  GNUNET_assert (NULL != peer->connections);
-  return; // ????
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multishortmap_contains_value (peer->connections,
-                                                                &GCC_get_id (c)->connection_of_tunnel,
-                                                                c));
-}
-
+  struct GNUNET_HELLO_Message *mrg;
 
-/**
- * Remove a connection from a neighboring peer.
- *
- * @param peer Peer to remove connection from.
- * @param c Connection to remove.
- */
-void
-GCP_remove_connection (struct CadetPeer *peer,
-                       const struct CadetConnection *c)
-{
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Removing connection %s\n",
-         GCC_2s (c));
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "from peer %s\n",
-         GCP_2s (peer));
-    if ( (NULL == peer) ||
-            (NULL == peer->connections) )
-        return;
-    GNUNET_assert (GNUNET_YES ==
-                   GNUNET_CONTAINER_multishortmap_remove (peer->connections,
-                                                          &GCC_get_id (c)->connection_of_tunnel,
-                                                          c));
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Peer %s remains with %u connections.\n",
-         GCP_2s (peer),
-         GNUNET_CONTAINER_multishortmap_size (peer->connections));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Got %u byte HELLO for peer %s\n",
+       (unsigned int) GNUNET_HELLO_size (hello),
+       GCP_2s (cp));
+  if (NULL != cp->hello_offer)
+  {
+    GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
+    cp->hello_offer = NULL;
+  }
+  if (NULL != cp->hello)
+  {
+    mrg = GNUNET_HELLO_merge (hello,
+                              cp->hello);
+    GNUNET_free (cp->hello);
+    cp->hello = mrg;
+  }
+  else
+  {
+    cp->hello = GNUNET_memdup (hello,
+                               GNUNET_HELLO_size (hello));
+  }
+  cp->hello_offer
+    = GNUNET_TRANSPORT_offer_hello (cfg,
+                                    GNUNET_HELLO_get_header (cp->hello) ,
+                                    &hello_offer_done,
+                                    cp);
+  /* New HELLO means cp's destruction time may change... */
+  consider_peer_destroy (cp);
 }
 
 
 /**
- * Start the DHT search for new paths towards the peer: we don't have
- * enough good connections.
+ * The tunnel to the given peer no longer exists, remove it from our
+ * data structures, and possibly clean up the peer itself.
  *
- * @param peer Destination peer.
+ * @param cp the peer affected
+ * @param t the dead tunnel
  */
 void
-GCP_start_search (struct CadetPeer *peer)
+GCP_drop_tunnel (struct CadetPeer *cp,
+                 struct CadetTunnel *t)
 {
-    const struct GNUNET_PeerIdentity *id;
-    struct CadetTunnel *t = peer->tunnel;
-
-    GCC_check_connections ();
-    if (NULL != peer->search_h)
-    {
-        GNUNET_break (0);
-        return;
-    }
-
-    if (NULL != peer->search_delayed)
-        GCP_stop_search (peer);
-
-    id = GNUNET_PEER_resolve2 (peer->id);
-    peer->search_h = GCD_search (id, &search_handler, peer);
-
-    if (NULL == t)
-    {
-        /* Why would we search for a peer with no tunnel towards it? */
-        GNUNET_break (0);
-        return;
-    }
-
-    if (CADET_TUNNEL_NEW == GCT_get_cstate (t)
-            || 0 == GCT_count_any_connections (t))
-    {
-        GCT_change_cstate (t, CADET_TUNNEL_SEARCHING);
-    }
-    GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Dropping tunnel %s to peer %s\n",
+       GCT_2s (t),
+       GCP_2s (cp));
+  GNUNET_assert (cp->t == t);
+  cp->t = NULL;
+  consider_peer_destroy (cp);
 }
 
 
 /**
- * Stop the DHT search for new paths towards the peer: we already have
- * enough good connections.
+ * Test if @a cp has a core-level connection
  *
- * @param peer Destination peer.
+ * @param cp peer to test
+ * @return #GNUNET_YES if @a cp has a core-level connection
  */
-void
-GCP_stop_search (struct CadetPeer *peer)
-{
-    GCC_check_connections ();
-    if (NULL != peer->search_h)
-    {
-        GCD_search_stop (peer->search_h);
-        peer->search_h = NULL;
-    }
-    if (NULL != peer->search_delayed)
-    {
-        GNUNET_SCHEDULER_cancel (peer->search_delayed);
-        peer->search_delayed = NULL;
-    }
-    GCC_check_connections ();
-}
-
-
-/**
- * Get the Full ID of a peer.
- *
- * @param peer Peer to get from.
- *
- * @return Full ID of peer.
- */
-const struct GNUNET_PeerIdentity *
-GCP_get_id (const struct CadetPeer *peer)
+int
+GCP_has_core_connection (struct CadetPeer *cp)
 {
-    return GNUNET_PEER_resolve2 (peer->id);
+  return (NULL != cp->core_mq) ? GNUNET_YES : GNUNET_NO;
 }
 
 
 /**
- * Get the Short ID of a peer.
+ * Start message queue change notifications.
  *
- * @param peer Peer to get from.
- *
- * @return Short ID of peer.
+ * @param cp peer to notify for
+ * @param cb function to call if mq becomes available or unavailable
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel request
  */
-GNUNET_PEER_Id
-GCP_get_short_id (const struct CadetPeer *peer)
+struct GCP_MessageQueueManager *
+GCP_request_mq (struct CadetPeer *cp,
+                GCP_MessageQueueNotificationCallback cb,
+                void *cb_cls)
 {
-    return peer->id;
-}
+  struct GCP_MessageQueueManager *mqm;
 
-
-/**
- * Set tunnel.
- *
- * If tunnel is NULL and there was a search active, stop it, as it's useless.
- *
- * @param peer Peer.
- * @param t Tunnel.
- */
-void
-GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t)
-{
-    peer->tunnel = t;
-    if (NULL == t && GNUNET_YES == is_searching (peer))
-    {
-        GCP_stop_search (peer);
-    }
-}
-
-
-/**
- * Get the tunnel towards a peer.
- *
- * @param peer Peer to get from.
- *
- * @return Tunnel towards peer.
- */
-struct CadetTunnel *
-GCP_get_tunnel (const struct CadetPeer *peer)
-{
-    if (NULL == peer)
-        return NULL;
-    return peer->tunnel;
+  mqm = GNUNET_new (struct GCP_MessageQueueManager);
+  mqm->cb = cb;
+  mqm->cb_cls = cb_cls;
+  mqm->cp = cp;
+  GNUNET_CONTAINER_DLL_insert (cp->mqm_head,
+                               cp->mqm_tail,
+                               mqm);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating MQM %p for peer %s\n",
+       mqm,
+       GCP_2s (cp));
+  if (NULL != cp->core_mq)
+    cb (cb_cls,
+        GNUNET_YES);
+  return mqm;
 }
 
 
 /**
- * Set the hello message.
+ * Stops message queue change notifications.
  *
- * @param peer Peer whose message to set.
- * @param hello Hello message.
+ * @param mqm handle matching request to cancel
+ * @param last_env final message to transmit, or NULL
  */
 void
-GCP_set_hello (struct CadetPeer *peer,
-               const struct GNUNET_HELLO_Message *hello)
-{
-    struct GNUNET_HELLO_Message *old;
-    size_t size;
-
-    GCC_check_connections ();
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "set hello for %s\n", GCP_2s (peer));
-    if (NULL == hello)
-        return;
-
-    old = GCP_get_hello (peer);
-    if (NULL == old)
+GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
+                       struct GNUNET_MQ_Envelope *last_env)
+{
+  struct CadetPeer *cp = mqm->cp;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying MQM %p for peer %s%s\n",
+       mqm,
+       GCP_2s (cp),
+       (NULL == last_env) ? "" : " with last ditch transmission");
+  if (NULL != mqm->env)
+    GNUNET_MQ_discard (mqm->env);
+  if (NULL != last_env)
+  {
+    if (NULL != cp->core_mq)
     {
-        size = GNUNET_HELLO_size (hello);
-        peer->hello = GNUNET_malloc (size);
-        GNUNET_memcpy (peer->hello, hello, size);
+      GNUNET_MQ_notify_sent (last_env,
+                             &mqm_send_done,
+                             cp);
+      GNUNET_MQ_send (cp->core_mq,
+                      last_env);
     }
     else
     {
-        peer->hello = GNUNET_HELLO_merge (old, hello);
-        GNUNET_free (old);
-    }
-    GCC_check_connections ();
-}
-
-
-/**
- * Get the hello message.
- *
- * @param peer Peer whose message to get.
- *
- * @return Hello message.
- */
-struct GNUNET_HELLO_Message *
-GCP_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
-GCP_try_connect (struct CadetPeer *peer)
-{
-    struct GNUNET_HELLO_Message *hello;
-    struct GNUNET_MessageHeader *mh;
-
-    if (GNUNET_YES !=
-            GNUNET_CONFIGURATION_get_value_yesno (cfg,
-                    "CADET",
-                    "DISABLE_TRY_CONNECT"))
-        return;
-    GCC_check_connections ();
-    if (GNUNET_YES == GCP_is_neighbor (peer))
-        return;
-    hello = GCP_get_hello (peer);
-    if (NULL == hello)
-        return;
-
-    mh = GNUNET_HELLO_get_header (hello);
-    if (NULL != peer->hello_offer)
-    {
-        GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer);
-        peer->hello_offer = NULL;
+      GNUNET_MQ_discard (last_env);
     }
-    peer->hello_offer = GNUNET_TRANSPORT_offer_hello (cfg,
-                        mh,
-                        &hello_offer_done,
-                        peer);
-    if (NULL == peer->connectivity_suggestion)
-        peer->connectivity_suggestion
-            = GNUNET_ATS_connectivity_suggest (ats_ch,
-                                               GCP_get_id (peer),
-                                               1);  /* strength */
-    GCC_check_connections ();
-}
-
-
-/**
- * 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
-GCP_notify_broken_link (struct CadetPeer *peer,
-                        const struct GNUNET_PeerIdentity *peer1,
-                        const struct GNUNET_PeerIdentity *peer2)
-{
-    struct CadetPeerPath *iter;
-    struct CadetPeerPath *next;
-    unsigned int i;
-    GNUNET_PEER_Id p1;
-    GNUNET_PEER_Id p2;
-
-    GCC_check_connections ();
-    p1 = GNUNET_PEER_search (peer1);
-    p2 = GNUNET_PEER_search (peer2);
-
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Link %u-%u broken\n", p1, p2);
-    if (0 == p1 || 0 == p2)
-    {
-        /* We don't even know them */
-        return;
-    }
-
-    for (iter = peer->path_head; NULL != iter; iter = next)
-    {
-        next = iter->next;
-        for (i = 0; i < iter->length - 1; i++)
-        {
-            if ((iter->peers[i] == p1 && iter->peers[i + 1] == p2)
-                    || (iter->peers[i] == p2 && iter->peers[i + 1] == p1))
-            {
-                char *s;
-
-                s = path_2s (iter);
-                LOG (GNUNET_ERROR_TYPE_DEBUG, " - invalidating %s\n", s);
-                GNUNET_free (s);
-
-                path_invalidate (iter);
-            }
-        }
-    }
-    GCC_check_connections ();
-}
-
-
-/**
- * Count the number of known paths toward the peer.
- *
- * @param peer Peer to get path info.
- *
- * @return Number of known paths.
- */
-unsigned int
-GCP_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 over the paths to a peer.
- *
- * @param peer Peer to get path info.
- * @param callback Function to call for every path.
- * @param cls Closure for @a callback.
- *
- * @return Number of iterated paths.
- */
-unsigned int
-GCP_iterate_paths (struct CadetPeer *peer,
-                   GCP_path_iterator callback,
-                   void *cls)
-{
-    struct CadetPeerPath *iter;
-    unsigned int i;
-
-    for (iter = peer->path_head, i = 0; NULL != iter; iter = iter->next)
-    {
-        i++;
-        if (GNUNET_YES != callback (cls, peer, iter))
-            break;
-    }
-
-    return i;
+  }
+  if (cp->mqm_ready_ptr == mqm)
+    cp->mqm_ready_ptr = mqm->next;
+  GNUNET_CONTAINER_DLL_remove (cp->mqm_head,
+                               cp->mqm_tail,
+                               mqm);
+  GNUNET_free (mqm);
 }
 
 
 /**
- * Iterate all known peers.
+ * Send the message in @a env to @a cp, overriding queueing logic.
+ * This function should only be used to send error messages outside
+ * of flow and congestion control, similar to ICMP.  Note that
+ * the envelope may be silently discarded as well.
  *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
+ * @param cp peer to send the message to
+ * @param env envelope with the message to send
  */
 void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
-                 void *cls)
+GCP_send_ooo (struct CadetPeer *cp,
+              struct GNUNET_MQ_Envelope *env)
 {
-    GCC_check_connections ();
-    GNUNET_CONTAINER_multipeermap_iterate (peers,
-                                           iter,
-                                           cls);
-    GCC_check_connections ();
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending message to %s out of management\n",
+       GCP_2s (cp));
+  if (NULL == cp->core_mq)
+  {
+    GNUNET_MQ_discard (env);
+    return;
+  }
+  GNUNET_MQ_notify_sent (env,
+                         &mqm_send_done,
+                         cp);
+  GNUNET_MQ_send (cp->core_mq,
+                  env);
 }
 
 
-/**
- * Get the static string for a peer ID.
- *
- * @param peer Peer.
- *
- * @return Static string for it's ID.
- */
-const char *
-GCP_2s (const struct CadetPeer *peer)
-{
-    if (NULL == peer)
-        return "(NULL)";
-    return GNUNET_i2s (GNUNET_PEER_resolve2 (peer->id));
-}
 
 
-/* end of gnunet-service-cadet_peer.c */
+/* end of gnunet-service-cadet-new_peer.c */
index 1e206e10f1ce059142a26395fbc68be18d9c326b..a2a6c6a92aa621fcaf924a2308ad4a688f8a29a3 100644 (file)
@@ -1,6 +1,7 @@
+
 /*
      This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
+     Copyright (C) 2001-2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 */
 
 /**
- * @file cadet/gnunet-service-cadet_peer.h
- * @brief cadet service; dealing with remote peers
+ * @file cadet/gnunet-service-cadet-new_peer.h
+ * @brief Information we track per peer.
  * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMP (Gnunet Cadet Peer)
+ * @author Christian Grothoff
  */
-
 #ifndef GNUNET_SERVICE_CADET_PEER_H
 #define GNUNET_SERVICE_CADET_PEER_H
 
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "cadet_path.h"
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetPeer;
+#include "gnunet-service-cadet.h"
+#include "gnunet_hello_lib.h"
 
-/**
- * Handle to queued messages on a peer level.
- */
-struct CadetPeerQueue;
-
-#include "gnunet-service-cadet_connection.h"
-
-
-/**
- * Callback called when a queued message is sent.
- *
- * @param cls Closure.
- * @param c Connection this message was on.
- * @param fwd Was this a FWD going message?
- * @param sent Was it really sent? (Could have been canceled)
- * @param type Type of message sent.
- * @param payload_type Type of payload, if applicable.
- * @param pid Message ID, or 0 if not applicable (create, destroy, etc).
- * @param size Size of the message.
- * @param wait Time spent waiting for core (only the time for THIS message)
- */
-typedef void
-(*GCP_sent) (void *cls,
-             struct CadetConnection *c,
-             int fwd,
-             int sent,
-             uint16_t type,
-             uint16_t payload_type,
-             struct CadetEncryptedMessageIdentifier pid,
-             size_t size,
-             struct GNUNET_TIME_Relative wait);
 
 /**
- * Peer path iterator.
+ * Get the static string for a peer ID.
  *
- * @param cls Closure.
- * @param peer Peer this path is towards.
- * @param path Path itself
- * @return #GNUNET_YES if should keep iterating.
- *         #GNUNET_NO otherwise.
- */
-typedef int
-(*GCP_path_iterator) (void *cls,
-                      struct CadetPeer *peer,
-                      struct CadetPeerPath *path);
-
-
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
-
-/**
- * Initialize peer subsystem.
+ * @param peer Peer.
  *
- * @param c Configuration.
- */
-void
-GCP_init (const struct GNUNET_CONFIGURATION_Handle *c);
-
-/**
- * Shut down the peer subsystem.
+ * @return Static string for it's ID.
  */
-void
-GCP_shutdown (void);
+const char *
+GCP_2s (const struct CadetPeer *peer);
 
 
 /**
- * Retrieve the CadetPeer stucture associated with the peer. Optionally create
- * one and insert it in the appropriate structures if the peer is not known yet.
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
  *
  * @param peer_id Full identity of the peer.
  * @param create #GNUNET_YES if a new peer should be created if unknown.
- *               #GNUNET_NO otherwise.
- *
+ *               #GNUNET_NO to return NULL if peer is unknown.
  * @return Existing or newly created peer structure.
  *         NULL if unknown and not requested @a create
  */
 struct CadetPeer *
-GCP_get (const struct GNUNET_PeerIdentity *peer_id, int create);
+GCP_get (const struct GNUNET_PeerIdentity *peer_id,
+         int create);
 
 
 /**
- * Retrieve the CadetPeer stucture associated with the peer. Optionally create
- * one and insert it in the appropriate structures if the peer is not known yet.
- *
- * @param peer Short identity of the peer.
- * @param create #GNUNET_YES if a new peer should be created if unknown.
- *               #GNUNET_NO otherwise.
+ * Calculate how desirable a path is for @a cp if
+ * @a cp is at offset @a off in the path.
  *
- * @return Existing or newly created peer structure.
- *         NULL if unknown and not requested @a create
+ * @param cp a peer reachable via a path
+ * @param off offset of @a cp in a path
+ * @return score how useful a path is to reach @a cp,
+ *         positive scores mean path is more desirable
  */
-struct CadetPeer *
-GCP_get_short (const GNUNET_PEER_Id peer, int create);
-
+double
+GCP_get_desirability_of_path (struct CadetPeer *cp,
+                              unsigned int off);
 
-/**
- * Try to establish a new connection to this peer (in its tunnel).
- * If the peer doesn't have any path to it yet, try to get one.
- * If the peer already has some path, send a CREATE CONNECTION towards it.
- *
- * @param peer Peer to connect to.
- */
-void
-GCP_connect (struct CadetPeer *peer);
 
 /**
- * @brief Send a message to another peer (using CORE).
+ * Obtain the peer identity for a `struct CadetPeer`.
  *
- * @param peer Peer towards which to queue the message.
- * @param message Message to send.
- * @param payload_type Type of the message's payload, for debug messages.
- *                     0 if the message is a retransmission (unknown payload).
- *                     UINT16_MAX if the message does not have payload.
- * @param payload_id ID of the payload (MID, ACK #, etc)
- * @param c Connection this message belongs to (can be NULL).
- * @param fwd Is this a message going root->dest? (FWD ACK are NOT FWD!)
- * @param cont Continuation to be called once CORE has sent the message.
- * @param cont_cls Closure for @c cont.
+ * @param cp our peer handle
+ * @return the peer identity
  */
-struct CadetPeerQueue *
-GCP_send (struct CadetPeer *peer,
-          const struct GNUNET_MessageHeader *message,
-          uint16_t payload_type,
-          struct CadetEncryptedMessageIdentifier payload_id,
-          struct CadetConnection *c,
-          int fwd,
-          GCP_sent cont,
-          void *cont_cls);
+const struct GNUNET_PeerIdentity *
+GCP_get_id (struct CadetPeer *cp);
 
-/**
- * Cancel sending a message. Message must have been sent with
- * #GCP_send before.  May not be called after the notify sent
- * callback has been called.
- *
- * It does NOT call the continuation given to #GCP_send.
- *
- * @param q Queue handle to cancel
- */
-void
-GCP_send_cancel (struct CadetPeerQueue *q);
 
 /**
- * Set tunnel.
+ * Iterate over all known peers.
  *
- * @param peer Peer.
- * @param t Tunnel.
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
  */
 void
-GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t);
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+                 void *cls);
 
 
 /**
- * Check whether there is a direct (core level)  connection to peer.
- *
- * @param peer Peer to check.
+ * Count the number of known paths toward the peer.
  *
- * @return #GNUNET_YES if there is a direct connection.
+ * @param cp Peer to get path info.
+ * @return Number of known paths.
  */
-int
-GCP_is_neighbor (const struct CadetPeer *peer);
+unsigned int
+GCP_count_paths (const struct CadetPeer *cp);
 
 
 /**
- * Create and initialize a new tunnel towards a peer, in case it has none.
- *
- * Does not generate any traffic, just creates the local data structures.
+ * Drop all paths owned by this peer, and do not
+ * allow new ones to be added: We are shutting down.
  *
- * @param peer Peer towards which to create the tunnel.
+ * @param cp peer to drop paths to
  */
 void
-GCP_add_tunnel (struct CadetPeer *peer);
+GCP_drop_owned_paths (struct CadetPeer *cp);
 
 
 /**
- * Add a connection to a neighboring peer.
- *
- * Store that the peer is the first hop of the connection in one
- * direction and that on peer disconnect the connection must be
- * notified and destroyed, for it will no longer be valid.
+ * Peer path iterator.
  *
- * @param peer Peer to add connection to.
- * @param c Connection to add.
- * @param pred #GNUNET_YES if we are predecessor, #GNUNET_NO if we are successor
+ * @param cls Closure.
+ * @param path Path itself
+ * @param off offset of the target peer in @a path
+ * @return #GNUNET_YES if should keep iterating.
+ *         #GNUNET_NO otherwise.
  */
-void
-GCP_add_connection (struct CadetPeer *peer,
-                    struct CadetConnection *c,
-                    int pred);
+typedef int
+(*GCP_PathIterator) (void *cls,
+                     struct CadetPeerPath *path,
+                     unsigned int off);
 
 
 /**
- * Add the path to the peer and update the path used to reach it in case this
- * is the shortest.
- *
- * @param peer Destination peer to add the path to.
- * @param path New path to add. Last peer must be the peer in arg 1.
- *             Path will be either used of freed if already known.
- * @param trusted Do we trust that this path is real?
+ * Iterate over the paths to a peer.
  *
- * @return path if path was taken, pointer to existing duplicate if exists
- *         NULL on error.
+ * @param cp Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
  */
-struct CadetPeerPath *
-GCP_add_path (struct CadetPeer *peer,
-              struct CadetPeerPath *p,
-              int trusted);
+unsigned int
+GCP_iterate_paths (struct CadetPeer *cp,
+                   GCP_PathIterator callback,
+                   void *callback_cls);
 
 
 /**
- * Add the path to the origin peer and update the path used to reach it in case
- * this is the shortest.
- * The path is given in peer_info -> destination, therefore we turn the path
- * upside down first.
+ * Iterate over the paths to @a peer where
+ * @a peer is at distance @a dist from us.
  *
- * @param peer Peer to add the path to, being the origin of the path.
- * @param path New path to add after being inversed.
- *             Path will be either used or freed.
- * @param trusted Do we trust that this path is real?
- *
- * @return path if path was taken, pointer to existing duplicate if exists
- *         NULL on error.
+ * @param cp Peer to get path info.
+ * @param dist desired distance of @a peer to us on the path
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
  */
-struct CadetPeerPath *
-GCP_add_path_to_origin (struct CadetPeer *peer,
-                        struct CadetPeerPath *path,
-                        int trusted);
+unsigned int
+GCP_iterate_paths_at (struct CadetPeer *cp,
+                      unsigned int dist,
+                      GCP_PathIterator callback,
+                      void *callback_cls);
+
 
 /**
- * Adds a path to the info of all the peers in the path
+ * Remove an entry from the DLL of all of the paths that this peer is on.
  *
- * @param p Path to process.
- * @param confirmed Whether we know if the path works or not.
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
  */
 void
-GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed);
+GCP_path_entry_remove (struct CadetPeer *cp,
+                       struct CadetPeerPathEntry *entry,
+                       unsigned int off);
 
 
 /**
- * Remove any path to the peer that has the extact same peers as the one given.
+ * Add an entry to the DLL of all of the paths that this peer is on.
  *
- * @param peer Peer to remove the path from.
- * @param path Path to remove. Is always destroyed .
+ * @param cp peer to modify
+ * @param entry an entry on a path
+ * @param off offset of this peer on the path
  */
 void
-GCP_remove_path (struct CadetPeer *peer,
-                 struct CadetPeerPath *path);
+GCP_path_entry_add (struct CadetPeer *cp,
+                    struct CadetPeerPathEntry *entry,
+                    unsigned int off);
 
 
 /**
- * Check that we are aware of a connection from a neighboring peer.
+ * Get the tunnel towards a peer.
  *
- * @param peer Peer to the connection is with
- * @param c Connection that should be in the map with this peer.
+ * @param cp Peer to get from.
+ * @param create #GNUNET_YES to create a tunnel if we do not have one
+ * @return Tunnel towards peer.
  */
-void
-GCP_check_connection (const struct CadetPeer *peer,
-                      const struct CadetConnection *c);
+struct CadetTunnel *
+GCP_get_tunnel (struct CadetPeer *cp,
+                int create);
 
 
 /**
- * Remove a connection from a neighboring peer.
+ * The tunnel to the given peer no longer exists, remove it from our
+ * data structures, and possibly clean up the peer itself.
  *
- * @param peer Peer to remove connection from.
- * @param c Connection to remove.
+ * @param cp the peer affected
+ * @param t the dead tunnel
  */
 void
-GCP_remove_connection (struct CadetPeer *peer,
-                       const struct CadetConnection *c);
+GCP_drop_tunnel (struct CadetPeer *cp,
+                 struct CadetTunnel *t);
 
 
 /**
- * Start the DHT search for new paths towards the peer: we don't have
- * enough good connections.
+ * Try adding a @a path to this @a cp.  If the peer already
+ * has plenty of paths, return NULL.
  *
- * @param peer Destination peer.
+ * @param cp peer to which the @a path leads to
+ * @param path a path looking for an owner; may not be fully initialized yet!
+ * @param off offset of @a cp in @a path
+ * @param force for attaching the path
+ * @return NULL if this peer does not care to become a new owner,
+ *         otherwise the node in the peer's path heap for the @a path.
  */
-void
-GCP_start_search (struct CadetPeer *peer);
+struct GNUNET_CONTAINER_HeapNode *
+GCP_attach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path,
+                 unsigned int off,
+                 int force);
 
 
 /**
- * Stop the DHT search for new paths towards the peer: we already have
- * enough good connections.
+ * This peer can no longer own @a path as the path
+ * has been extended and a peer further down the line
+ * is now the new owner.
  *
- * @param peer Destination peer.
+ * @param cp old owner of the @a path
+ * @param path path where the ownership is lost
+ * @param hn note in @a cp's path heap that must be deleted
  */
 void
-GCP_stop_search (struct CadetPeer *peer);
+GCP_detach_path (struct CadetPeer *cp,
+                 struct CadetPeerPath *path,
+                 struct GNUNET_CONTAINER_HeapNode *hn);
 
 
 /**
- * Get the Full ID of a peer.
- *
- * @param peer Peer to get from.
+ * Add a @a connection to this @a cp.
  *
- * @return Full ID of peer.
+ * @param cp peer via which the @a connection goes
+ * @param cc the connection to add
  */
-const struct GNUNET_PeerIdentity *
-GCP_get_id (const struct CadetPeer *peer);
+void
+GCP_add_connection (struct CadetPeer *cp,
+                    struct CadetConnection *cc);
 
 
 /**
- * Get the Short ID of a peer.
+ * Remove a @a connection that went via this @a cp.
  *
- * @param peer Peer to get from.
- *
- * @return Short ID of peer.
+ * @param cp peer via which the @a connection went
+ * @param cc the connection to remove
  */
-GNUNET_PEER_Id
-GCP_get_short_id (const struct CadetPeer *peer);
+void
+GCP_remove_connection (struct CadetPeer *cp,
+                       struct CadetConnection *cc);
 
 
 /**
- * Get the tunnel towards a peer.
- *
- * @param peer Peer to get from.
+ * We got a HELLO for a @a cp, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
  *
- * @return Tunnel towards peer.
+ * @param cp the peer we got a HELLO for
+ * @param hello the HELLO to remember
  */
-struct CadetTunnel *
-GCP_get_tunnel (const struct CadetPeer *peer);
+void
+GCP_set_hello (struct CadetPeer *cp,
+               const struct GNUNET_HELLO_Message *hello);
 
 
 /**
- * Set the hello message.
- *
- * @param peer Peer whose message to set.
- * @param hello Hello message.
+ * Clean up all entries about all peers.
+ * Must only be called after all tunnels, CORE-connections and
+ * connections are down.
  */
 void
-GCP_set_hello (struct CadetPeer *peer,
-               const struct GNUNET_HELLO_Message *hello);
+GCP_destroy_all_peers (void);
 
 
 /**
- * Get the hello message.
- *
- * @param peer Peer whose message to get.
+ * Data structure used to track whom we have to notify about changes
+ * in our ability to transmit to a given peer.
  *
- * @return Hello message.
+ * All queue managers will be given equal chance for sending messages
+ * to @a cp.  This construct this guarantees fairness for access to @a
+ * cp among the different message queues.  Each connection or route
+ * will have its respective message queue managers for each direction.
  */
-struct GNUNET_HELLO_Message *
-GCP_get_hello (struct CadetPeer *peer);
+struct GCP_MessageQueueManager;
 
 
 /**
- * Try to connect to a peer on TRANSPORT level.
+ * Function to call with updated message queue object.
  *
- * @param peer Peer to whom to connect.
+ * @param cls closure
+ * @param available #GNUNET_YES if sending is now possible,
+ *                  #GNUNET_NO if sending is no longer possible
+ *                  #GNUNET_SYSERR if sending is no longer possible
+ *                                 and the last envelope was discarded
  */
-void
-GCP_try_connect (struct CadetPeer *peer);
+typedef void
+(*GCP_MessageQueueNotificationCallback)(void *cls,
+                                        int available);
+
 
 /**
- * Notify a peer that a link between two other peers is broken. If any path
- * used that link, eliminate it.
+ * Start message queue change notifications.  Will create a new slot
+ * to manage the message queue to the given @a cp.
  *
- * @param peer Peer affected by the change.
- * @param peer1 Peer whose link is broken.
- * @param peer2 Peer whose link is broken.
+ * @param cp peer to notify for
+ * @param cb function to call if mq becomes available or unavailable
+ * @param cb_cls closure for @a cb
+ * @return handle to cancel request
  */
-void
-GCP_notify_broken_link (struct CadetPeer *peer,
-                        const struct GNUNET_PeerIdentity *peer1,
-                        const struct GNUNET_PeerIdentity *peer2);
+struct GCP_MessageQueueManager *
+GCP_request_mq (struct CadetPeer *cp,
+                GCP_MessageQueueNotificationCallback cb,
+                void *cb_cls);
 
 
 /**
- * Count the number of known paths toward the peer.
- *
- * @param peer Peer to get path info.
+ * Test if @a cp has a core-level connection
  *
- * @return Number of known paths.
+ * @param cp peer to test
+ * @return #GNUNET_YES if @a cp has a core-level connection
  */
-unsigned int
-GCP_count_paths (const struct CadetPeer *peer);
+int
+GCP_has_core_connection (struct CadetPeer *cp);
+
 
 /**
- * Iterate over the paths to a peer.
- *
- * @param peer Peer to get path info.
- * @param callback Function to call for every path.
- * @param cls Closure for @a callback.
+ * Send the message in @a env via a @a mqm.  Must only be called at
+ * most once after the respective
+ * #GCP_MessageQueueNotificationCallback was called with `available`
+ * set to #GNUNET_YES, and not after the callback was called with
+ * `available` set to #GNUNET_NO or #GNUNET_SYSERR.
  *
- * @return Number of iterated paths.
+ * @param mqm message queue manager for the transmission
+ * @param env envelope with the message to send; must NOT
+ *            yet have a #GNUNET_MQ_notify_sent() callback attached to it
  */
-unsigned int
-GCP_iterate_paths (struct CadetPeer *peer,
-                   GCP_path_iterator callback,
-                   void *cls);
+void
+GCP_send (struct GCP_MessageQueueManager *mqm,
+          struct GNUNET_MQ_Envelope *env);
 
 
 /**
- * Iterate all known peers.
+ * Send the message in @a env to @a cp, overriding queueing logic.
+ * This function should only be used to send error messages outside
+ * of flow and congestion control, similar to ICMP.  Note that
+ * the envelope may be silently discarded as well.
  *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
+ * @param cp peer to send the message to
+ * @param env envelope with the message to send
  */
 void
-GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
-                 void *cls);
+GCP_send_ooo (struct CadetPeer *cp,
+              struct GNUNET_MQ_Envelope *env);
 
 
 /**
- * Get the static string for a peer ID.
- *
- * @param peer Peer.
+ * Stops message queue change notifications and sends a last message.
+ * In practice, this is implemented by sending that @a last_env
+ * message immediately (if any), ignoring queue order.
  *
- * @return Static string for it's ID.
+ * @param mqm handle matching request to cancel
+ * @param last_env final message to transmit, or NULL
  */
-const char *
-GCP_2s (const struct CadetPeer *peer);
+void
+GCP_request_mq_cancel (struct GCP_MessageQueueManager *mqm,
+                       struct GNUNET_MQ_Envelope *last_env);
 
 
 /**
- * Log all kinds of info about a peer.
+ * Set the message queue to @a mq for peer @a cp and notify watchers.
  *
- * @param peer Peer.
+ * @param cp peer to modify
+ * @param mq message queue to set (can be NULL)
  */
 void
-GCP_debug (const struct CadetPeer *p,
-           enum GNUNET_ErrorType level);
-
+GCP_set_mq (struct CadetPeer *cp,
+            struct GNUNET_MQ_Handle *mq);
 
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
 
-/* ifndef GNUNET_CADET_SERVICE_PEER_H */
 #endif
-/* end of gnunet-cadet-service_peer.h */
diff --git a/src/cadet/gnunet-service-cadet_tunnel.c b/src/cadet/gnunet-service-cadet_tunnel.c
deleted file mode 100644 (file)
index a94e8f4..0000000
+++ /dev/null
@@ -1,3501 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/gnunet-service-cadet_tunnel.c
- * @brief logical links between CADET clients
- * @author Bartlomiej Polot
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_signatures.h"
-#include "gnunet_statistics_service.h"
-#include "cadet_protocol.h"
-#include "cadet_path.h"
-#include "gnunet-service-cadet_tunnel.h"
-#include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_channel.h"
-#include "gnunet-service-cadet_peer.h"
-
-#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
-#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)
-
-#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5)
-
-#if !defined(GNUNET_CULL_LOGGING)
-  #define DUMP_KEYS_TO_STDERR GNUNET_YES
-#else
-  #define DUMP_KEYS_TO_STDERR GNUNET_NO
-#endif
-
-#define MIN_TUNNEL_BUFFER       8
-#define MAX_TUNNEL_BUFFER       64
-#define MAX_SKIPPED_KEYS        64
-#define MAX_KEY_GAP             256
-#define AX_HEADER_SIZE (sizeof (uint32_t) * 2\
-                        + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey))
-
-/******************************************************************************/
-/********************************   STRUCTS  **********************************/
-/******************************************************************************/
-
-struct CadetTChannel
-{
-  struct CadetTChannel *next;
-  struct CadetTChannel *prev;
-  struct CadetChannel *ch;
-};
-
-
-/**
- * Entry in list of connections used by tunnel, with metadata.
- */
-struct CadetTConnection
-{
-  /**
-   * Next in DLL.
-   */
-  struct CadetTConnection *next;
-
-  /**
-   * Prev in DLL.
-   */
-  struct CadetTConnection *prev;
-
-  /**
-   * Connection handle.
-   */
-  struct CadetConnection *c;
-
-  /**
-   * Creation time, to keep oldest connection alive.
-   */
-  struct GNUNET_TIME_Absolute created;
-
-  /**
-   * Connection throughput, to keep fastest connection alive.
-   */
-  uint32_t throughput;
-};
-
-
-/**
- * Struct to old keys for skipped messages while advancing the Axolotl ratchet.
- */
-struct CadetTunnelSkippedKey
-{
-  /**
-   * DLL next.
-   */
-  struct CadetTunnelSkippedKey *next;
-
-  /**
-   * DLL prev.
-   */
-  struct CadetTunnelSkippedKey *prev;
-
-  /**
-   * When was this key stored (for timeout).
-   */
-  struct GNUNET_TIME_Absolute timestamp;
-
-  /**
-   * Header key.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey HK;
-
-  /**
-   * Message key.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-
-  /**
-   * Key number for a given HK.
-   */
-  unsigned int Kn;
-};
-
-
-/**
- * Axolotl data, according to https://github.com/trevp/axolotl/wiki .
- */
-struct CadetTunnelAxolotl
-{
-  /**
-   * A (double linked) list of stored message keys and associated header keys
-   * for "skipped" messages, i.e. messages that have not been
-   * received despite the reception of more recent messages, (head).
-   */
-  struct CadetTunnelSkippedKey *skipped_head;
-
-  /**
-   * Skipped messages' keys DLL, tail.
-   */
-  struct CadetTunnelSkippedKey *skipped_tail;
-
-  /**
-   * Elements in @a skipped_head <-> @a skipped_tail.
-   */
-  unsigned int skipped;
-
-  /**
-   * 32-byte root key which gets updated by DH ratchet.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey RK;
-
-  /**
-   * 32-byte header key (send).
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey HKs;
-
-  /**
-   * 32-byte header key (recv)
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey HKr;
-
-  /**
-   * 32-byte next header key (send).
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey NHKs;
-
-  /**
-   * 32-byte next header key (recv).
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey NHKr;
-
-  /**
-   * 32-byte chain keys (used for forward-secrecy updating, send).
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey CKs;
-
-  /**
-   * 32-byte chain keys (used for forward-secrecy updating, recv).
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
-
-  /**
-   * ECDH for key exchange (A0 / B0).
-   */
-  struct GNUNET_CRYPTO_EcdhePrivateKey *kx_0;
-
-  /**
-   * ECDH Ratchet key (send).
-   */
-  struct GNUNET_CRYPTO_EcdhePrivateKey *DHRs;
-
-  /**
-   * ECDH Ratchet key (recv).
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
-
-  /**
-   * Message number (reset to 0 with each new ratchet, next message to send).
-   */
-  uint32_t Ns;
-
-  /**
-   * Message number (reset to 0 with each new ratchet, next message to recv).
-   */
-  uint32_t Nr;
-
-  /**
-   * Previous message numbers (# of msgs sent under prev ratchet)
-   */
-  uint32_t PNs;
-
-  /**
-   * True (#GNUNET_YES) if we have to send a new ratchet key in next msg.
-   */
-  int ratchet_flag;
-
-  /**
-   * Number of messages recieved since our last ratchet advance.
-   * - If this counter = 0, we cannot send a new ratchet key in next msg.
-   * - If this counter > 0, we can (but don't yet have to) send a new key.
-   */
-  unsigned int ratchet_allowed;
-
-  /**
-   * Number of messages recieved since our last ratchet advance.
-   * - If this counter = 0, we cannot send a new ratchet key in next msg.
-   * - If this counter > 0, we can (but don't yet have to) send a new key.
-   */
-  unsigned int ratchet_counter;
-
-  /**
-   * When does this ratchet expire and a new one is triggered.
-   */
-  struct GNUNET_TIME_Absolute ratchet_expiration;
-};
-
-
-/**
- * Struct containing all information regarding a tunnel to a peer.
- */
-struct CadetTunnel
-{
-  /**
-   * Endpoint of the tunnel.
-   */
-  struct CadetPeer *peer;
-
-  /**
-   * Axolotl info.
-   */
-  struct CadetTunnelAxolotl *ax;
-
-  /**
-   * State of the tunnel connectivity.
-   */
-  enum CadetTunnelCState cstate;
-
-  /**
-   * State of the tunnel encryption.
-   */
-  enum CadetTunnelEState estate;
-
-  /**
-   * Peer's ephemeral key, to recreate @c e_key and @c d_key when own ephemeral
-   * key changes.
-   */
-  struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key;
-
-  /**
-   * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
-
-  /**
-   * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL.
-   */
-  struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
-
-  /**
-   * Task to start the rekey process.
-   */
-  struct GNUNET_SCHEDULER_Task *rekey_task;
-
-  /**
-   * Paths that are actively used to reach the destination peer.
-   */
-  struct CadetTConnection *connection_head;
-  struct CadetTConnection *connection_tail;
-
-  /**
-   * Next connection number.
-   */
-  uint32_t next_cid;
-
-  /**
-   * Channels inside this tunnel.
-   */
-  struct CadetTChannel *channel_head;
-  struct CadetTChannel *channel_tail;
-
-  /**
-   * Channel ID for the next created channel.
-   */
-  struct GNUNET_CADET_ChannelTunnelNumber next_ctn;
-
-  /**
-   * Destroy flag: if true, destroy on last message.
-   */
-  struct GNUNET_SCHEDULER_Task * destroy_task;
-
-  /**
-   * Queued messages, to transmit once tunnel gets connected.
-   */
-  struct CadetTunnelDelayed *tq_head;
-  struct CadetTunnelDelayed *tq_tail;
-
-  /**
-   * Task to trim connections if too many are present.
-   */
-  struct GNUNET_SCHEDULER_Task * trim_connections_task;
-
-  /**
-   * Ephemeral message in the queue (to avoid queueing more than one).
-   */
-  struct CadetConnectionQueue *ephm_h;
-
-  /**
-   * Pong message in the queue.
-   */
-  struct CadetConnectionQueue *pong_h;
-};
-
-
-/**
- * Struct used to save messages in a non-ready tunnel to send once connected.
- */
-struct CadetTunnelDelayed
-{
-  /**
-   * DLL
-   */
-  struct CadetTunnelDelayed *next;
-  struct CadetTunnelDelayed *prev;
-
-  /**
-   * Tunnel.
-   */
-  struct CadetTunnel *t;
-
-  /**
-   * Tunnel queue given to the channel to cancel request. Update on send_queued.
-   */
-  struct CadetTunnelQueue *tq;
-
-  /**
-   * Message to send.
-   */
-  /* struct GNUNET_MessageHeader *msg; */
-};
-
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetTunnelQueue
-{
-  /**
-   * Connection queue handle, to cancel if necessary.
-   */
-  struct CadetConnectionQueue *cq;
-
-  /**
-   * Handle in case message hasn't been given to a connection yet.
-   */
-  struct CadetTunnelDelayed *tqd;
-
-  /**
-   * Continuation to call once sent.
-   */
-  GCT_sent cont;
-
-  /**
-   * Closure for @c cont.
-   */
-  void *cont_cls;
-};
-
-
-/******************************************************************************/
-/*******************************   GLOBALS  ***********************************/
-/******************************************************************************/
-
-/**
- * Global handle to the statistics service.
- */
-extern struct GNUNET_STATISTICS_Handle *stats;
-
-/**
- * Local peer own ID (memory efficient handle).
- */
-extern GNUNET_PEER_Id myid;
-
-/**
- * Local peer own ID (full value).
- */
-extern struct GNUNET_PeerIdentity my_full_id;
-
-
-/**
- * Don't try to recover tunnels if shutting down.
- */
-extern int shutting_down;
-
-
-/**
- * Set of all tunnels, in order to trigger a new exchange on rekey.
- * Indexed by peer's ID.
- */
-static struct GNUNET_CONTAINER_MultiPeerMap *tunnels;
-
-/**
- * Own Peer ID private key.
- */
-const static struct GNUNET_CRYPTO_EddsaPrivateKey *id_key;
-
-
-/********************************  AXOLOTL ************************************/
-
-/**
- * How many messages are needed to trigger a ratchet advance.
- */
-static unsigned long long ratchet_messages;
-
-/**
- * How long until we trigger a ratched advance.
- */
-static struct GNUNET_TIME_Relative ratchet_time;
-
-
-/******************************************************************************/
-/********************************   STATIC  ***********************************/
-/******************************************************************************/
-
-/**
- * Get string description for tunnel connectivity state.
- *
- * @param cs Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-cstate2s (enum CadetTunnelCState cs)
-{
-  static char buf[32];
-
-  switch (cs)
-  {
-    case CADET_TUNNEL_NEW:
-      return "CADET_TUNNEL_NEW";
-    case CADET_TUNNEL_SEARCHING:
-      return "CADET_TUNNEL_SEARCHING";
-    case CADET_TUNNEL_WAITING:
-      return "CADET_TUNNEL_WAITING";
-    case CADET_TUNNEL_READY:
-      return "CADET_TUNNEL_READY";
-    case CADET_TUNNEL_SHUTDOWN:
-      return "CADET_TUNNEL_SHUTDOWN";
-    default:
-      SPRINTF (buf, "%u (UNKNOWN STATE)", cs);
-      return buf;
-  }
-  return "";
-}
-
-
-/**
- * Get string description for tunnel encryption state.
- *
- * @param es Tunnel state.
- *
- * @return String representation.
- */
-static const char *
-estate2s (enum CadetTunnelEState es)
-{
-  static char buf[32];
-
-  switch (es)
-  {
-    case CADET_TUNNEL_KEY_UNINITIALIZED:
-      return "CADET_TUNNEL_KEY_UNINITIALIZED";
-    case CADET_TUNNEL_KEY_AX_SENT:
-      return "CADET_TUNNEL_KEY_AX_SENT";
-    case CADET_TUNNEL_KEY_AX_AUTH_SENT:
-      return "CADET_TUNNEL_KEY_AX_AUTH_SENT";
-    case CADET_TUNNEL_KEY_OK:
-      return "CADET_TUNNEL_KEY_OK";
-    case CADET_TUNNEL_KEY_REKEY:
-      return "CADET_TUNNEL_KEY_REKEY";
-    default:
-      SPRINTF (buf, "%u (UNKNOWN STATE)", es);
-      return buf;
-  }
-  return "";
-}
-
-
-/**
- * @brief Check if tunnel is ready to send traffic.
- *
- * Tunnel must be connected and with encryption correctly set up.
- *
- * @param t Tunnel to check.
- *
- * @return #GNUNET_YES if ready, #GNUNET_NO otherwise
- */
-static int
-is_ready (struct CadetTunnel *t)
-{
-  int ready;
-  int conn_ok;
-  int enc_ok;
-
-  conn_ok = CADET_TUNNEL_READY == t->cstate;
-  enc_ok = CADET_TUNNEL_KEY_OK == t->estate
-           || CADET_TUNNEL_KEY_REKEY == t->estate
-           || CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate;
-  ready = conn_ok && enc_ok;
-  ready = ready || GCT_is_loopback (t);
-  return ready;
-}
-
-
-/**
- * Get the channel's buffer. ONLY FOR NON-LOOPBACK CHANNELS!!
- *
- * @param tch Tunnel's channel handle.
- *
- * @return Amount of messages the channel can still buffer towards the client.
- */
-static unsigned int
-get_channel_buffer (const struct CadetTChannel *tch)
-{
-  int fwd;
-
-  /* If channel is incoming, is terminal in the FWD direction and fwd is YES */
-  fwd = GCCH_is_terminal (tch->ch, GNUNET_YES);
-
-  return GCCH_get_buffer (tch->ch, fwd);
-}
-
-
-/**
- * Get the channel's allowance status.
- *
- * @param tch Tunnel's channel handle.
- *
- * @return #GNUNET_YES if we allowed the client to send data to us.
- */
-static int
-get_channel_allowed (const struct CadetTChannel *tch)
-{
-  int fwd;
-
-  /* If channel is outgoing, is origin in the FWD direction and fwd is YES */
-  fwd = GCCH_is_origin (tch->ch, GNUNET_YES);
-
-  return GCCH_get_allowed (tch->ch, fwd);
-}
-
-
-/**
- * Get the connection's buffer.
- *
- * @param tc Tunnel's connection handle.
- *
- * @return Amount of messages the connection can still buffer.
- */
-static unsigned int
-get_connection_buffer (const struct CadetTConnection *tc)
-{
-  int fwd;
-
-  /* If connection is outgoing, is origin in the FWD direction and fwd is YES */
-  fwd = GCC_is_origin (tc->c, GNUNET_YES);
-
-  return GCC_get_buffer (tc->c, fwd);
-}
-
-
-/**
- * Get the connection's allowance.
- *
- * @param tc Tunnel's connection handle.
- *
- * @return Amount of messages we have allowed the next peer to send us.
- */
-static unsigned int
-get_connection_allowed (const struct CadetTConnection *tc)
-{
-  int fwd;
-
-  /* If connection is outgoing, is origin in the FWD direction and fwd is YES */
-  fwd = GCC_is_origin (tc->c, GNUNET_YES);
-
-  return GCC_get_allowed (tc->c, fwd);
-}
-
-
-/**
- * Create a new Axolotl ephemeral (ratchet) key.
- *
- * @param t Tunnel.
- */
-static void
-new_ephemeral (struct CadetTunnel *t)
-{
-  GNUNET_free_non_null (t->ax->DHRs);
-  t->ax->DHRs = GNUNET_CRYPTO_ecdhe_key_create();
-  #if DUMP_KEYS_TO_STDERR
-  {
-    struct GNUNET_CRYPTO_EcdhePublicKey pub;
-    GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &pub);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  new DHRs generated: pub  %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub));
-  }
-  #endif
-}
-
-
-/**
- * Calculate HMAC.
- *
- * @param plaintext Content to HMAC.
- * @param size Size of @c plaintext.
- * @param iv Initialization vector for the message.
- * @param key Key to use.
- * @param hmac[out] Destination to store the HMAC.
- */
-static void
-t_hmac (const void *plaintext, size_t size,
-        uint32_t iv, const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
-        struct GNUNET_ShortHashCode *hmac)
-{
-  static const char ctx[] = "cadet authentication key";
-  struct GNUNET_CRYPTO_AuthKey auth_key;
-  struct GNUNET_HashCode hash;
-
-#if DUMP_KEYS_TO_STDERR
-  LOG (GNUNET_ERROR_TYPE_INFO, "  HMAC %u bytes with key %s\n", size,
-       GNUNET_i2s ((struct GNUNET_PeerIdentity *) key));
-#endif
-  GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
-                                 &iv, sizeof (iv),
-                                 key, sizeof (*key),
-                                 ctx, sizeof (ctx),
-                                 NULL);
-  /* Two step: CADET_Hash is only 256 bits, HashCode is 512. */
-  GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash);
-  GNUNET_memcpy (hmac, &hash, sizeof (*hmac));
-}
-
-
-/**
- * Perform a HMAC.
- *
- * @param key Key to use.
- * @param hash[out] Resulting HMAC.
- * @param source Source key material (data to HMAC).
- * @param len Length of @a source.
- */
-static void
-t_ax_hmac_hash (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
-                struct GNUNET_HashCode *hash,
-                void *source, unsigned int len)
-{
-  static const char ctx[] = "axolotl HMAC-HASH";
-  struct GNUNET_CRYPTO_AuthKey auth_key;
-
-  GNUNET_CRYPTO_hmac_derive_key (&auth_key, key,
-                                 ctx, sizeof (ctx),
-                                 NULL);
-  GNUNET_CRYPTO_hmac (&auth_key, source, len, hash);
-}
-
-
-/**
- * Derive a key from a HMAC-HASH.
- *
- * @param key Key to use for the HMAC.
- * @param out Key to generate.
- * @param source Source key material (data to HMAC).
- * @param len Length of @a source.
- */
-static void
-t_hmac_derive_key (struct GNUNET_CRYPTO_SymmetricSessionKey *key,
-                   struct GNUNET_CRYPTO_SymmetricSessionKey *out,
-                   void *source, unsigned int len)
-{
-  static const char ctx[] = "axolotl derive key";
-  struct GNUNET_HashCode h;
-
-  t_ax_hmac_hash (key, &h, source, len);
-  GNUNET_CRYPTO_kdf (out, sizeof (*out), ctx, sizeof (ctx),
-                     &h, sizeof (h), NULL);
-}
-
-
-/**
- * Encrypt data with the axolotl tunnel key.
- *
- * @param t Tunnel whose key to use.
- * @param dst Destination for the encrypted data.
- * @param src Source of the plaintext. Can overlap with @c dst.
- * @param size Size of the plaintext.
- *
- * @return Size of the encrypted data.
- */
-static int
-t_ax_encrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size)
-{
-  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  struct CadetTunnelAxolotl *ax;
-  size_t out_size;
-
-  CADET_TIMING_START;
-
-  ax = t->ax;
-  ax->ratchet_counter++;
-  if (GNUNET_YES == ax->ratchet_allowed
-      && (ratchet_messages <= ax->ratchet_counter
-          || 0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us))
-  {
-    ax->ratchet_flag = GNUNET_YES;
-  }
-
-  if (GNUNET_YES == ax->ratchet_flag)
-  {
-    /* Advance ratchet */
-    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3];
-    struct GNUNET_HashCode dh;
-    struct GNUNET_HashCode hmac;
-    static const char ctx[] = "axolotl ratchet";
-
-    new_ephemeral (t);
-    ax->HKs = ax->NHKs;
-
-    /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
-    GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, &ax->DHRr, &dh);
-    t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh));
-    GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx),
-                       &hmac, sizeof (hmac), NULL);
-    ax->RK = keys[0];
-    ax->NHKs = keys[1];
-    ax->CKs = keys[2];
-
-    ax->PNs = ax->Ns;
-    ax->Ns = 0;
-    ax->ratchet_flag = GNUNET_NO;
-    ax->ratchet_allowed = GNUNET_NO;
-    ax->ratchet_counter = 0;
-    ax->ratchet_expiration =
-      GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time);
-  }
-
-  t_hmac_derive_key (&ax->CKs, &MK, "0", 1);
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL);
-
-  #if DUMP_KEYS_TO_STDERR
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  CKs: %s\n",
-       GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs));
-  LOG (GNUNET_ERROR_TYPE_INFO, "  AX_ENC with key %u: %s\n", ax->Ns,
-       GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK));
-  #endif
-
-  out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &MK, &iv, dst);
-  t_hmac_derive_key (&ax->CKs, &ax->CKs, "1", 1);
-
-  CADET_TIMING_END;
-
-  return out_size;
-}
-
-
-/**
- * Decrypt data with the axolotl tunnel key.
- *
- * @param t Tunnel whose key to use.
- * @param dst Destination for the decrypted data.
- * @param src Source of the ciphertext. Can overlap with @c dst.
- * @param size Size of the ciphertext.
- *
- * @return Size of the decrypted data.
- */
-static int
-t_ax_decrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size)
-{
-  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  struct CadetTunnelAxolotl *ax;
-  size_t out_size;
-
-  CADET_TIMING_START;
-
-  ax = t->ax;
-
-  t_hmac_derive_key (&ax->CKr, &MK, "0", 1);
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL);
-
-  #if DUMP_KEYS_TO_STDERR
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  CKr: %s\n",
-       GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr));
-  LOG (GNUNET_ERROR_TYPE_INFO, "  AX_DEC with key %u: %s\n", ax->Nr,
-       GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK));
-  #endif
-
-  GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
-  out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, &MK, &iv, dst);
-  GNUNET_assert (out_size == size);
-
-  t_hmac_derive_key (&ax->CKr, &ax->CKr, "1", 1);
-
-  CADET_TIMING_END;
-
-  return out_size;
-}
-
-
-/**
- * Encrypt header with the axolotl header key.
- *
- * @param t Tunnel whose key to use.
- * @param msg Message whose header to encrypt.
- */
-static void
-t_h_encrypt (struct CadetTunnel *t, struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  struct CadetTunnelAxolotl *ax;
-  size_t out_size;
-
-  CADET_TIMING_START;
-  ax = t->ax;
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKs, NULL, 0, NULL);
-
-  #if DUMP_KEYS_TO_STDERR
-  LOG (GNUNET_ERROR_TYPE_INFO, "  AX_ENC_H with key %s\n",
-       GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs));
-  #endif
-
-  out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->Ns, AX_HEADER_SIZE,
-                                              &ax->HKs, &iv, &msg->Ns);
-
-  GNUNET_assert (AX_HEADER_SIZE == out_size);
-  CADET_TIMING_END;
-}
-
-
-/**
- * Decrypt header with the current axolotl header key.
- *
- * @param t Tunnel whose current ax HK to use.
- * @param src Message whose header to decrypt.
- * @param dst Where to decrypt header to.
- */
-static void
-t_h_decrypt (struct CadetTunnel *t, const struct GNUNET_CADET_TunnelEncryptedMessage *src,
-             struct GNUNET_CADET_TunnelEncryptedMessage *dst)
-{
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  struct CadetTunnelAxolotl *ax;
-  size_t out_size;
-
-  CADET_TIMING_START;
-
-  ax = t->ax;
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKr, NULL, 0, NULL);
-
-  #if DUMP_KEYS_TO_STDERR
-  LOG (GNUNET_ERROR_TYPE_INFO, "  AX_DEC_H with key %s\n",
-       GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr));
-  #endif
-
-  out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE,
-                                              &ax->HKr, &iv, &dst->Ns);
-
-  GNUNET_assert (AX_HEADER_SIZE == out_size);
-
-  CADET_TIMING_END;
-}
-
-
-/**
- * Decrypt and verify data with the appropriate tunnel key and verify that the
- * data has not been altered since it was sent by the remote peer.
- *
- * @param t Tunnel whose key to use.
- * @param dst Destination for the plaintext.
- * @param src Source of the message. Can overlap with @c dst.
- * @param size Size of the message.
- *
- * @return Size of the decrypted data, -1 if an error was encountered.
- */
-static int
-try_old_ax_keys (struct CadetTunnel *t, void *dst,
-                 const struct GNUNET_CADET_TunnelEncryptedMessage *src, size_t size)
-{
-  struct CadetTunnelSkippedKey *key;
-  struct GNUNET_ShortHashCode *hmac;
-  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
-  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
-  struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK;
-  size_t esize;
-  size_t res;
-  size_t len;
-  unsigned int N;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying old keys\n");
-  hmac = &plaintext_header.hmac;
-  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-
-  /* Find a correct Header Key */
-  for (key = t->ax->skipped_head; NULL != key; key = key->next)
-  {
-    #if DUMP_KEYS_TO_STDERR
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  Trying hmac with key %s\n",
-         GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK));
-    #endif
-    t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &key->HK, hmac);
-    if (0 == memcmp (hmac, &src->hmac, sizeof (*hmac)))
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "  hmac correct\n");
-      valid_HK = &key->HK;
-      break;
-    }
-  }
-  if (NULL == key)
-    return -1;
-
-  /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */
-  GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage));
-  len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-  GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader));
-
-  /* Decrypt header */
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->HK, NULL, 0, NULL);
-  res = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE,
-                                         &key->HK, &iv, &plaintext_header.Ns);
-  GNUNET_assert (AX_HEADER_SIZE == res);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  Message %u, previous: %u\n",
-       ntohl (plaintext_header.Ns), ntohl (plaintext_header.PNs));
-
-  /* Find the correct Message Key */
-  N = ntohl (plaintext_header.Ns);
-  while (NULL != key && N != key->Kn)
-    key = key->next;
-  if (NULL == key || 0 != memcmp (&key->HK, valid_HK, sizeof (*valid_HK)))
-    return -1;
-
-  #if DUMP_KEYS_TO_STDERR
-  LOG (GNUNET_ERROR_TYPE_INFO, "  AX_DEC_H with skipped key %s\n",
-       GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK));
-  LOG (GNUNET_ERROR_TYPE_INFO, "  AX_DEC with skipped key %u: %s\n",
-       key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK));
-  #endif
-
-  /* Decrypt payload */
-  GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->MK, NULL, 0, NULL);
-  res = GNUNET_CRYPTO_symmetric_decrypt (&src[1], len, &key->MK, &iv, dst);
-
-  /* Remove key */
-  GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key);
-  t->ax->skipped--;
-  GNUNET_free (key); /* GNUNET_free overwrites memory with 0xbaadf00d */
-
-  return res;
-}
-
-
-/**
- * Delete a key from the list of skipped keys.
- *
- * @param t Tunnel to delete from.
- * @param HKr Header Key to use.
- */
-static void
-store_skipped_key (struct CadetTunnel *t,
-                   const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr)
-{
-  struct CadetTunnelSkippedKey *key;
-
-  key = GNUNET_new (struct CadetTunnelSkippedKey);
-  key->timestamp = GNUNET_TIME_absolute_get ();
-  key->Kn = t->ax->Nr;
-  key->HK = t->ax->HKr;
-  t_hmac_derive_key (&t->ax->CKr, &key->MK, "0", 1);
-  #if DUMP_KEYS_TO_STDERR
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "    storing MK for Nr %u: %s\n",
-       key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "    for CKr: %s\n",
-       GNUNET_i2s ((struct GNUNET_PeerIdentity *) &t->ax->CKr));
-  #endif
-  t_hmac_derive_key (&t->ax->CKr, &t->ax->CKr, "1", 1);
-  GNUNET_CONTAINER_DLL_insert (t->ax->skipped_head, t->ax->skipped_tail, key);
-  t->ax->Nr++;
-  t->ax->skipped++;
-}
-
-
-/**
- * Delete a key from the list of skipped keys.
- *
- * @param t Tunnel to delete from.
- * @param key Key to delete.
- */
-static void
-delete_skipped_key (struct CadetTunnel *t, struct CadetTunnelSkippedKey *key)
-{
-  GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key);
-  GNUNET_free (key);
-  t->ax->skipped--;
-}
-
-
-/**
- * Stage skipped AX keys and calculate the message key.
- *
- * Stores each HK and MK for skipped messages.
- *
- * @param t Tunnel where to stage the keys.
- * @param HKr Header key.
- * @param Np Received meesage number.
- *
- * @return GNUNET_OK if keys were stored.
- *         GNUNET_SYSERR if an error ocurred (Np not expected).
- */
-static int
-store_ax_keys (struct CadetTunnel *t,
-               const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr,
-               uint32_t Np)
-{
-  int gap;
-
-
-  gap = Np - t->ax->Nr;
-  LOG (GNUNET_ERROR_TYPE_INFO, "Storing keys [%u, %u)\n", t->ax->Nr, Np);
-  if (MAX_KEY_GAP < gap)
-  {
-    /* Avoid DoS (forcing peer to do 2*33 chain HMAC operations) */
-    /* TODO: start new key exchange on return */
-    GNUNET_break_op (0);
-    LOG (GNUNET_ERROR_TYPE_WARNING, "Got message %u, expected %u+\n",
-         Np, t->ax->Nr);
-    return GNUNET_SYSERR;
-  }
-  if (0 > gap)
-  {
-    /* Delayed message: don't store keys, flag to try old keys. */
-    return GNUNET_SYSERR;
-  }
-
-  while (t->ax->Nr < Np)
-    store_skipped_key (t, HKr);
-
-  while (t->ax->skipped > MAX_SKIPPED_KEYS)
-    delete_skipped_key (t, t->ax->skipped_tail);
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Decrypt and verify data with the appropriate tunnel key and verify that the
- * data has not been altered since it was sent by the remote peer.
- *
- * @param t Tunnel whose key to use.
- * @param dst Destination for the plaintext.
- * @param src Source of the message. Can overlap with @c dst.
- * @param size Size of the message.
- *
- * @return Size of the decrypted data, -1 if an error was encountered.
- */
-static int
-t_ax_decrypt_and_validate (struct CadetTunnel *t, void *dst,
-                           const struct GNUNET_CADET_TunnelEncryptedMessage *src,
-                           size_t size)
-{
-  struct CadetTunnelAxolotl *ax;
-  struct GNUNET_ShortHashCode msg_hmac;
-  struct GNUNET_HashCode hmac;
-  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
-  uint32_t Np;
-  uint32_t PNp;
-  size_t esize; /* Size of encryped payload */
-  size_t osize; /* Size of output (decrypted payload) */
-
-  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-  ax = t->ax;
-  if (NULL == ax)
-    return -1;
-
-  /* Try current HK */
-  t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->HKr, &msg_hmac);
-  if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac)))
-  {
-    static const char ctx[] = "axolotl ratchet";
-    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */
-    struct GNUNET_CRYPTO_SymmetricSessionKey HK;
-    struct GNUNET_HashCode dh;
-    struct GNUNET_CRYPTO_EcdhePublicKey *DHRp;
-
-    /* Try Next HK */
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  trying next HK\n");
-    t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->NHKr, &msg_hmac);
-    if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac)))
-    {
-      /* Try the skipped keys, if that fails, we're out of luck. */
-      return try_old_ax_keys (t, dst, src, size);
-    }
-    LOG (GNUNET_ERROR_TYPE_INFO, "next HK worked\n");
-
-    HK = ax->HKr;
-    ax->HKr = ax->NHKr;
-    t_h_decrypt (t, src, &plaintext_header);
-    Np = ntohl (plaintext_header.Ns);
-    PNp = ntohl (plaintext_header.PNs);
-    DHRp = &plaintext_header.DHRs;
-    store_ax_keys (t, &HK, PNp);
-
-    /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
-    GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, DHRp, &dh);
-    t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh));
-    GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx),
-                       &hmac, sizeof (hmac), NULL);
-
-    /* Commit "purported" keys */
-    ax->RK = keys[0];
-    ax->NHKr = keys[1];
-    ax->CKr = keys[2];
-    ax->DHRr = *DHRp;
-    ax->Nr = 0;
-    ax->ratchet_allowed = GNUNET_YES;
-  }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "current HK\n");
-    t_h_decrypt (t, src, &plaintext_header);
-    Np = ntohl (plaintext_header.Ns);
-    PNp = ntohl (plaintext_header.PNs);
-  }
-  LOG (GNUNET_ERROR_TYPE_INFO, "  got AX Nr %u\n", Np);
-  if (Np != ax->Nr)
-    if (GNUNET_OK != store_ax_keys (t, &ax->HKr, Np))
-      /* Try the skipped keys, if that fails, we're out of luck. */
-      return try_old_ax_keys (t, dst, src, size);
-
-  osize = t_ax_decrypt (t, dst, &src[1], esize);
-  ax->Nr = Np + 1;
-
-  if (osize != esize)
-  {
-    GNUNET_break_op (0);
-    return -1;
-  }
-
-  return osize;
-}
-
-
-/**
- * Pick a connection on which send the next data message.
- *
- * @param t Tunnel on which to send the message.
- *
- * @return The connection on which to send the next message.
- */
-static struct CadetConnection *
-tunnel_get_connection (struct CadetTunnel *t)
-{
-  struct CadetTConnection *iter;
-  struct CadetConnection *best;
-  unsigned int qn;
-  unsigned int lowest_q;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GCT_2s (t));
-  best = NULL;
-  lowest_q = UINT_MAX;
-  for (iter = t->connection_head; NULL != iter; iter = iter->next)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  connection %s: %u\n",
-         GCC_2s (iter->c), GCC_get_state (iter->c));
-    if (CADET_CONNECTION_READY == GCC_get_state (iter->c))
-    {
-      qn = GCC_get_qn (iter->c, GCC_is_origin (iter->c, GNUNET_YES));
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "    q_n %u, \n", qn);
-      if (qn < lowest_q)
-      {
-        best = iter->c;
-        lowest_q = qn;
-      }
-    }
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GCC_2s (best));
-  return best;
-}
-
-
-/**
- * Callback called when a queued message is sent.
- *
- * Calculates the average time and connection packet tracking.
- *
- * @param cls Closure (TunnelQueue handle).
- * @param c Connection this message was on.
- * @param q Connection queue handle (unused).
- * @param type Type of message sent.
- * @param fwd Was this a FWD going message?
- * @param size Size of the message.
- */
-static void
-tun_message_sent (void *cls,
-              struct CadetConnection *c,
-              struct CadetConnectionQueue *q,
-              uint16_t type, int fwd, size_t size)
-{
-  struct CadetTunnelQueue *qt = cls;
-  struct CadetTunnel *t;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n");
-
-  GNUNET_assert (NULL != qt->cont);
-  t = NULL == c ? NULL : GCC_get_tunnel (c);
-  qt->cont (qt->cont_cls, t, qt, type, size);
-  GNUNET_free (qt);
-}
-
-
-static unsigned int
-count_queued_data (const struct CadetTunnel *t)
-{
-  struct CadetTunnelDelayed *iter;
-  unsigned int count;
-
-  for (count = 0, iter = t->tq_head; iter != NULL; iter = iter->next)
-    count++;
-
-  return count;
-}
-
-/**
- * Delete a queued message: either was sent or the channel was destroyed
- * before the tunnel's key exchange had a chance to finish.
- *
- * @param tqd Delayed queue handle.
- */
-static void
-unqueue_data (struct CadetTunnelDelayed *tqd)
-{
-  GNUNET_CONTAINER_DLL_remove (tqd->t->tq_head, tqd->t->tq_tail, tqd);
-  GNUNET_free (tqd);
-}
-
-
-/**
- * Cache a message to be sent once tunnel is online.
- *
- * @param t Tunnel to hold the message.
- * @param msg Message itself (copy will be made).
- */
-static struct CadetTunnelDelayed *
-queue_data (struct CadetTunnel *t, const struct GNUNET_MessageHeader *msg)
-{
-  struct CadetTunnelDelayed *tqd;
-  uint16_t size = ntohs (msg->size);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GCT_2s (t));
-
-  GNUNET_assert (GNUNET_NO == is_ready (t));
-
-  tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size);
-
-  tqd->t = t;
-  GNUNET_memcpy (&tqd[1], msg, size);
-  GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd);
-  return tqd;
-}
-
-
-/**
- * Sends an already built message on a tunnel, encrypting it and
- * choosing the best connection.
- *
- * @param message Message to send. Function modifies it.
- * @param t Tunnel on which this message is transmitted.
- * @param c Connection to use (autoselect if NULL).
- * @param force Force the tunnel to take the message (buffer overfill).
- * @param cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- * @param existing_q In case this a transmission of previously queued data,
- *                   this should be TunnelQueue given to the client.
- *                   Otherwise, NULL.
- * @return Handle to cancel message.
- *         NULL if @c cont is NULL or an error happens and message is dropped.
- */
-static struct CadetTunnelQueue *
-send_prebuilt_message (const struct GNUNET_MessageHeader *message,
-                       struct CadetTunnel *t,
-                       struct CadetConnection *c,
-                       int force,
-                       GCT_sent cont,
-                       void *cont_cls,
-                       struct CadetTunnelQueue *existing_q)
-{
-  struct GNUNET_MessageHeader *msg;
-  struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
-  struct CadetTunnelQueue *tq;
-  size_t size = ntohs (message->size);
-  char cbuf[sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size] GNUNET_ALIGN;
-  size_t esize;
-  uint16_t type;
-  int fwd;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GCT_2s (t));
-
-  if (GNUNET_NO == is_ready (t))
-  {
-    struct CadetTunnelDelayed *tqd;
-    /* A non null existing_q indicates sending of queued data.
-     * Should only happen after tunnel becomes ready.
-     */
-    GNUNET_assert (NULL == existing_q);
-    tqd = queue_data (t, message);
-    if (NULL == cont)
-      return NULL;
-    tq = GNUNET_new (struct CadetTunnelQueue);
-    tq->tqd = tqd;
-    tqd->tq = tq;
-    tq->cont = cont;
-    tq->cont_cls = cont_cls;
-    return tq;
-  }
-
-  GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
-
-  ax_msg = (struct GNUNET_CADET_TunnelEncryptedMessage *) cbuf;
-  msg = &ax_msg->header;
-  msg->size = htons (sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size);
-  msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
-  esize = t_ax_encrypt (t, &ax_msg[1], message, size);
-  ax_msg->Ns = htonl (t->ax->Ns++);
-  ax_msg->PNs = htonl (t->ax->PNs);
-  GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &ax_msg->DHRs);
-  t_h_encrypt (t, ax_msg);
-  t_hmac (&ax_msg->Ns, AX_HEADER_SIZE + esize, 0, &t->ax->HKs, &ax_msg->hmac);
-  GNUNET_assert (esize == size);
-
-  if (NULL == c)
-    c = tunnel_get_connection (t);
-  if (NULL == c)
-  {
-    /* Why is tunnel 'ready'? Should have been queued! */
-    if (NULL != t->destroy_task)
-    {
-      GNUNET_break (0);
-      GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
-    }
-    return NULL; /* Drop... */
-  }
-  fwd = GCC_is_origin (c, GNUNET_YES);
-  ax_msg->cid = *GCC_get_id (c);
-  ax_msg->cemi = GCC_get_pid (c, fwd);
-
-  type = htons (message->type);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending message of type %s with CEMI %u and CID %s\n",
-       GC_m2s (type),
-       htonl (ax_msg->cemi.pid),
-       GNUNET_sh2s (&ax_msg->cid.connection_of_tunnel));
-
-  if (NULL == cont)
-  {
-    (void) GCC_send_prebuilt_message (msg,
-                                      type,
-                                      ax_msg->cemi,
-                                      c,
-                                      fwd,
-                                      force, NULL, NULL);
-    return NULL;
-  }
-  if (NULL == existing_q)
-  {
-    tq = GNUNET_new (struct CadetTunnelQueue); /* FIXME valgrind: leak*/
-  }
-  else
-  {
-    tq = existing_q;
-    tq->tqd = NULL;
-  }
-  tq->cont = cont;
-  tq->cont_cls = cont_cls;
-  tq->cq = GCC_send_prebuilt_message (msg,
-                                      type,
-                                      ax_msg->cemi,
-                                      c,
-                                      fwd,
-                                      force,
-                                      &tun_message_sent, tq);
-  GNUNET_assert (NULL != tq->cq);
-
-  return tq;
-}
-
-
-/**
- * Send all cached messages that we can, tunnel is online.
- *
- * @param t Tunnel that holds the messages. Cannot be loopback.
- */
-static void
-send_queued_data (struct CadetTunnel *t)
-{
-  struct CadetTunnelDelayed *tqd;
-  struct CadetTunnelDelayed *next;
-  unsigned int room;
-
-  LOG (GNUNET_ERROR_TYPE_INFO, "Send queued data, tunnel %s\n", GCT_2s (t));
-
-  if (GCT_is_loopback (t))
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  if (GNUNET_NO == is_ready (t))
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING, "  not ready yet: %s/%s\n",
-         estate2s (t->estate), cstate2s (t->cstate));
-    return;
-  }
-
-  room = GCT_get_connections_buffer (t);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  buffer space: %u\n", room);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  tq head: %p\n", t->tq_head);
-  for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n");
-    next = tqd->next;
-    room--;
-    send_prebuilt_message ((struct GNUNET_MessageHeader *) &tqd[1],
-                           tqd->t, NULL, GNUNET_YES,
-                           NULL != tqd->tq ? tqd->tq->cont : NULL,
-                           NULL != tqd->tq ? tqd->tq->cont_cls : NULL,
-                           tqd->tq);
-    unqueue_data (tqd);
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_send_queued_data end\n", GCP_2s (t->peer));
-}
-
-
-/**
- * @brief Resend the KX until we complete the handshake.
- *
- * @param cls Closure (tunnel).
- */
-static void
-kx_resend (void *cls)
-{
-  struct CadetTunnel *t = cls;
-
-  t->rekey_task = NULL;
-  if (CADET_TUNNEL_KEY_OK == t->estate)
-  {
-    /* Should have been canceled on estate change */
-    GNUNET_break (0);
-    return;
-  }
-
-  GCT_send_kx (t, CADET_TUNNEL_KEY_AX_SENT >= t->estate);
-}
-
-
-/**
- * Callback called when a queued message is sent.
- *
- * @param cls Closure.
- * @param c Connection this message was on.
- * @param type Type of message sent.
- * @param fwd Was this a FWD going message?
- * @param size Size of the message.
- */
-static void
-ephm_sent (void *cls,
-           struct CadetConnection *c,
-           struct CadetConnectionQueue *q,
-           uint16_t type, int fwd, size_t size)
-{
-  struct CadetTunnel *t = cls;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "ephemeral sent %s\n", GC_m2s (type));
-
-  t->ephm_h = NULL;
-
-  if (CADET_TUNNEL_KEY_OK == t->estate)
-    return;
-
-  if (NULL != t->rekey_task)
-  {
-    GNUNET_break (0);
-    GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
-    GNUNET_SCHEDULER_cancel (t->rekey_task);
-  }
-  t->rekey_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
-                                                &kx_resend, t);
-
-}
-
-
-/**
- * Called only on shutdown, destroy every tunnel.
- *
- * @param cls Closure (unused).
- * @param key Current public key.
- * @param value Value in the hash map (tunnel).
- *
- * @return #GNUNET_YES, so we should continue to iterate,
- */
-static int
-destroy_iterator (void *cls,
-                const struct GNUNET_PeerIdentity *key,
-                void *value)
-{
-  struct CadetTunnel *t = value;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "GCT_shutdown destroying tunnel at %p\n", t);
-  GCT_destroy (t);
-  return GNUNET_YES;
-}
-
-
-/**
- * Notify remote peer that we don't know a channel he is talking about,
- * probably CHANNEL_DESTROY was missed.
- *
- * @param t Tunnel on which to notify.
- * @param gid ID of the channel.
- */
-static void
-send_channel_destroy (struct CadetTunnel *t,
-                      struct GNUNET_CADET_ChannelTunnelNumber gid)
-{
-  struct GNUNET_CADET_ChannelManageMessage msg;
-
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
-  msg.header.size = htons (sizeof (msg));
-  msg.ctn = gid;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "WARNING destroying unknown channel %u on tunnel %s\n",
-       ntohl (gid.cn),
-       GCT_2s (t));
-  send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL);
-}
-
-
-/**
- * Demultiplex data per channel and call appropriate channel handler.
- *
- * @param t Tunnel on which the data came.
- * @param msg Data message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_data (struct CadetTunnel *t,
-             const struct GNUNET_CADET_ChannelAppDataMessage *msg,
-             int fwd)
-{
-  struct CadetChannel *ch;
-  char buf[128];
-  size_t size;
-  uint16_t type;
-
-  /* Check size */
-  size = ntohs (msg->header.size);
-  if (size <
-      sizeof (struct GNUNET_CADET_ChannelAppDataMessage) +
-      sizeof (struct GNUNET_MessageHeader))
-  {
-    GNUNET_break (0);
-    return;
-  }
-  type = ntohs (msg[1].header.type);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n", GC_m2s (type));
-  SPRINTF (buf, "# received payload of type %hu", type);
-  GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO);
-
-
-  /* Check channel */
-  ch = GCT_get_channel (t, msg->ctn);
-  if (NULL == ch)
-  {
-    GNUNET_STATISTICS_update (stats,
-                              "# data on unknown channel",
-                              1,
-                              GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "channel 0x%X unknown\n",
-         ntohl (msg->ctn.cn));
-    send_channel_destroy (t, msg->ctn);
-    return;
-  }
-
-  GCCH_handle_data (ch, msg, fwd);
-}
-
-
-/**
- * Demultiplex data ACKs per channel and update appropriate channel buffer info.
- *
- * @param t Tunnel on which the DATA ACK came.
- * @param msg DATA ACK message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_data_ack (struct CadetTunnel *t,
-                 const struct GNUNET_CADET_ChannelDataAckMessage *msg,
-                 int fwd)
-{
-  struct CadetChannel *ch;
-  size_t size;
-
-  /* Check size */
-  size = ntohs (msg->header.size);
-  if (size != sizeof (struct GNUNET_CADET_ChannelDataAckMessage))
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  /* Check channel */
-  ch = GCT_get_channel (t, msg->ctn);
-  if (NULL == ch)
-  {
-    GNUNET_STATISTICS_update (stats, "# data ack on unknown channel",
-                              1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n",
-         ntohl (msg->ctn.cn));
-    return;
-  }
-
-  GCCH_handle_data_ack (ch, msg, fwd);
-}
-
-
-/**
- * Handle channel create.
- *
- * @param t Tunnel on which the message came.
- * @param msg ChannelCreate message.
- */
-static void
-handle_ch_create (struct CadetTunnel *t,
-                  const struct GNUNET_CADET_ChannelOpenMessage *msg)
-{
-  struct CadetChannel *ch;
-  size_t size;
-
-  /* Check size */
-  size = ntohs (msg->header.size);
-  if (size != sizeof (struct GNUNET_CADET_ChannelOpenMessage))
-  {
-    GNUNET_break_op (0);
-    return;
-  }
-
-  /* Check channel */
-  ch = GCT_get_channel (t, msg->ctn);
-  if (NULL != ch && ! GCT_is_loopback (t))
-  {
-    /* Probably a retransmission, safe to ignore */
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "   already exists...\n");
-  }
-  ch = GCCH_handle_create (t, msg);
-  if (NULL != ch)
-    GCT_add_channel (t, ch);
-}
-
-
-
-/**
- * Handle channel NACK: check correctness and call channel handler for NACKs.
- *
- * @param t Tunnel on which the NACK came.
- * @param msg NACK message.
- */
-static void
-handle_ch_nack (struct CadetTunnel *t,
-                const struct GNUNET_CADET_ChannelManageMessage *msg)
-{
-  struct CadetChannel *ch;
-  size_t size;
-
-  /* Check size */
-  size = ntohs (msg->header.size);
-  if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage))
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  /* Check channel */
-  ch = GCT_get_channel (t, msg->ctn);
-  if (NULL == ch)
-  {
-    GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel",
-                              1, GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "WARNING channel %u unknown\n",
-         ntohl (msg->ctn.cn));
-    return;
-  }
-
-  GCCH_handle_nack (ch);
-}
-
-
-/**
- * Handle a CHANNEL ACK (SYNACK/ACK).
- *
- * @param t Tunnel on which the CHANNEL ACK came.
- * @param msg CHANNEL ACK message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_ch_ack (struct CadetTunnel *t,
-               const struct GNUNET_CADET_ChannelManageMessage *msg,
-               int fwd)
-{
-  struct CadetChannel *ch;
-  size_t size;
-
-  /* Check size */
-  size = ntohs (msg->header.size);
-  if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage))
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  /* Check channel */
-  ch = GCT_get_channel (t, msg->ctn);
-  if (NULL == ch)
-  {
-    GNUNET_STATISTICS_update (stats,
-                              "# channel ack on unknown channel",
-                              1,
-                              GNUNET_NO);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "WARNING channel %u unknown\n",
-         ntohl (msg->ctn.cn));
-    return;
-  }
-
-  GCCH_handle_ack (ch, msg, fwd);
-}
-
-
-/**
- * Handle a channel destruction message.
- *
- * @param t Tunnel on which the message came.
- * @param msg Channel destroy message.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_ch_destroy (struct CadetTunnel *t,
-                   const struct GNUNET_CADET_ChannelManageMessage *msg,
-                   int fwd)
-{
-  struct CadetChannel *ch;
-  size_t size;
-
-  /* Check size */
-  size = ntohs (msg->header.size);
-  if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage))
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  /* Check channel */
-  ch = GCT_get_channel (t, msg->ctn);
-  if (NULL == ch)
-  {
-    /* Probably a retransmission, safe to ignore */
-    return;
-  }
-
-  GCCH_handle_destroy (ch, msg, fwd);
-}
-
-
-/**
- * Free Axolotl data.
- *
- * @param t Tunnel.
- */
-static void
-destroy_ax (struct CadetTunnel *t)
-{
-  if (NULL == t->ax)
-    return;
-
-  GNUNET_free_non_null (t->ax->DHRs);
-  GNUNET_free_non_null (t->ax->kx_0);
-  while (NULL != t->ax->skipped_head)
-    delete_skipped_key (t, t->ax->skipped_head);
-  GNUNET_assert (0 == t->ax->skipped);
-
-  GNUNET_free (t->ax);
-  t->ax = NULL;
-
-  if (NULL != t->rekey_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->rekey_task);
-    t->rekey_task = NULL;
-  }
-  if (NULL != t->ephm_h)
-  {
-    GCC_cancel (t->ephm_h);
-    t->ephm_h = NULL;
-  }
-}
-
-
-/**
- * Demultiplex by message type and call appropriate handler for a message
- * towards a channel of a local tunnel.
- *
- * @param t Tunnel this message came on.
- * @param msgh Message header.
- * @param fwd Is this message fwd? This only is meaningful in loopback channels.
- *            #GNUNET_YES if message is FWD on the respective channel (loopback)
- *            #GNUNET_NO if message is BCK on the respective channel (loopback)
- *            #GNUNET_SYSERR if message on a one-ended channel (remote)
- */
-static void
-handle_decrypted (struct CadetTunnel *t,
-                  const struct GNUNET_MessageHeader *msgh,
-                  int fwd)
-{
-  uint16_t type;
-  char buf[256];
-
-  type = ntohs (msgh->type);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "<-- %s on %s\n", GC_m2s (type), GCT_2s (t));
-  SPRINTF (buf, "# received encrypted of type %hu (%s)", type, GC_m2s (type));
-  GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO);
-
-  switch (type)
-  {
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE:
-      /* Do nothing, connection aleady got updated. */
-      GNUNET_STATISTICS_update (stats, "# keepalives received", 1, GNUNET_NO);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA:
-      /* Don't send hop ACK, wait for client to ACK */
-      handle_data (t, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK:
-      handle_data_ack (t, (struct GNUNET_CADET_ChannelDataAckMessage *) msgh, fwd);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN:
-      handle_ch_create (t, (struct GNUNET_CADET_ChannelOpenMessage *) msgh);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED:
-      handle_ch_nack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK:
-      handle_ch_ack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd);
-      break;
-
-    case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY:
-      handle_ch_destroy (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd);
-      break;
-
-    default:
-      GNUNET_break_op (0);
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-           "end-to-end message not known (%u)\n",
-           ntohs (msgh->type));
-      GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
-  }
-}
-
-
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
-
-/**
- * Decrypt and process an encrypted message.
- *
- * Calls the appropriate handler for a message in a channel of a local tunnel.
- *
- * @param t Tunnel this message came on.
- * @param msg Message header.
- */
-void
-GCT_handle_encrypted (struct CadetTunnel *t,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
-{
-  uint16_t size = ntohs (msg->header.size);
-  char cbuf [size];
-  int decrypted_size;
-  const struct GNUNET_MessageHeader *msgh;
-  unsigned int off;
-
-  GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO);
-
-  decrypted_size = t_ax_decrypt_and_validate (t, cbuf, msg, size);
-
-  if (-1 == decrypted_size)
-  {
-    GNUNET_STATISTICS_update (stats, "# unable to decrypt", 1, GNUNET_NO);
-    if (CADET_TUNNEL_KEY_AX_AUTH_SENT <= t->estate)
-    {
-      GNUNET_break_op (0);
-      LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong crypto, tunnel %s\n", GCT_2s (t));
-      GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
-    }
-    return;
-  }
-  GCT_change_estate (t, CADET_TUNNEL_KEY_OK);
-
-  /* FIXME: this is bad, as the structs returned from
-     this loop may be unaligned, see util's MST for
-     how to do this right. */
-  off = 0;
-  while (off + sizeof (struct GNUNET_MessageHeader) <= decrypted_size)
-  {
-    uint16_t msize;
-
-    msgh = (const struct GNUNET_MessageHeader *) &cbuf[off];
-    msize = ntohs (msgh->size);
-    if (msize < sizeof (struct GNUNET_MessageHeader))
-    {
-      GNUNET_break_op (0);
-      return;
-    }
-    if (off + msize < decrypted_size)
-    {
-      GNUNET_break_op (0);
-      return;
-    }
-    handle_decrypted (t, msgh, GNUNET_SYSERR);
-    off += msize;
-  }
-}
-
-
-/**
- * Handle a Key eXchange message.
- *
- * @param t Tunnel on which the message came.
- * @param msg KX message itself.
- */
-void
-GCT_handle_kx (struct CadetTunnel *t,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
-{
-  struct CadetTunnelAxolotl *ax;
-  struct GNUNET_HashCode key_material[3];
-  struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
-  const char salt[] = "CADET Axolotl salt";
-  const struct GNUNET_PeerIdentity *pid;
-  int am_I_alice;
-
-  CADET_TIMING_START;
-
-  LOG (GNUNET_ERROR_TYPE_INFO, "<== {        KX} on %s\n", GCT_2s (t));
-
-  if (NULL == t->ax)
-  {
-    /* Something is wrong if ax is NULL. Whose fault it is? */
-    return;
-  }
-  ax = t->ax;
-
-  pid = GCT_get_destination (t);
-  if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid))
-    am_I_alice = GNUNET_YES;
-  else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid))
-    am_I_alice = GNUNET_NO;
-  else
-  {
-    GNUNET_break_op (0);
-    return;
-  }
-
-  if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->flags)))
-  {
-    if (NULL != t->rekey_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->rekey_task);
-      t->rekey_task = NULL;
-    }
-    GCT_send_kx (t, GNUNET_NO);
-  }
-
-  if (0 == memcmp (&ax->DHRr, &msg->ratchet_key, sizeof(msg->ratchet_key)))
-  {
-    LOG (GNUNET_ERROR_TYPE_INFO, " known ratchet key, exit\n");
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_INFO, " is Alice? %s\n", am_I_alice ? "YES" : "NO");
-
-  ax->DHRr = msg->ratchet_key;
-
-  /* ECDH A B0 */
-  if (GNUNET_YES == am_I_alice)
-  {
-    GNUNET_CRYPTO_eddsa_ecdh (id_key,              /* A */
-                              &msg->ephemeral_key, /* B0 */
-                              &key_material[0]);
-  }
-  else
-  {
-    GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0,            /* B0 */
-                              &pid->public_key,    /* A */
-                              &key_material[0]);
-  }
-
-  /* ECDH A0 B */
-  if (GNUNET_YES == am_I_alice)
-  {
-    GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0,            /* A0 */
-                              &pid->public_key,    /* B */
-                              &key_material[1]);
-  }
-  else
-  {
-    GNUNET_CRYPTO_eddsa_ecdh (id_key,              /* A */
-                              &msg->ephemeral_key, /* B0 */
-                              &key_material[1]);
-
-
-  }
-
-  /* ECDH A0 B0 */
-  /* (This is the triple-DH, we could probably safely skip this,
-     as A0/B0 are already in the key material.) */
-  GNUNET_CRYPTO_ecc_ecdh (ax->kx_0,             /* A0 or B0 */
-                          &msg->ephemeral_key,  /* B0 or A0 */
-                          &key_material[2]);
-
-  #if DUMP_KEYS_TO_STDERR
-  {
-    unsigned int i;
-    for (i = 0; i < 3; i++)
-      LOG (GNUNET_ERROR_TYPE_INFO, "km[%u]: %s\n",
-           i, GNUNET_h2s (&key_material[i]));
-  }
-  #endif
-
-  /* KDF */
-  GNUNET_CRYPTO_kdf (keys, sizeof (keys),
-                     salt, sizeof (salt),
-                     &key_material, sizeof (key_material), NULL);
-
-  if (0 == memcmp (&ax->RK, &keys[0], sizeof(ax->RK)))
-  {
-    LOG (GNUNET_ERROR_TYPE_INFO, " known handshake key, exit\n");
-    return;
-  }
-  ax->RK = keys[0];
-  if (GNUNET_YES == am_I_alice)
-  {
-    ax->HKr = keys[1];
-    ax->NHKs = keys[2];
-    ax->NHKr = keys[3];
-    ax->CKr = keys[4];
-    ax->ratchet_flag = GNUNET_YES;
-  }
-  else
-  {
-    ax->HKs = keys[1];
-    ax->NHKr = keys[2];
-    ax->NHKs = keys[3];
-    ax->CKs = keys[4];
-    ax->ratchet_flag = GNUNET_NO;
-    ax->ratchet_allowed = GNUNET_NO;
-    ax->ratchet_counter = 0;
-    ax->ratchet_expiration =
-      GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time);
-  }
-  ax->PNs = 0;
-  ax->Nr = 0;
-  ax->Ns = 0;
-
-  GCT_change_estate (t, CADET_TUNNEL_KEY_AX_AUTH_SENT);
-  send_queued_data (t);
-
-  CADET_TIMING_END;
-}
-
-/**
- * Initialize the tunnel subsystem.
- *
- * @param c Configuration handle.
- * @param key ECC private key, to derive all other keys and do crypto.
- */
-void
-GCT_init (const struct GNUNET_CONFIGURATION_Handle *c,
-          const struct GNUNET_CRYPTO_EddsaPrivateKey *key)
-{
-  unsigned int expected_overhead;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
-
-  expected_overhead = 0;
-  expected_overhead += sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
-  expected_overhead += sizeof (struct GNUNET_CADET_ChannelAppDataMessage);
-  expected_overhead += sizeof (struct GNUNET_CADET_ConnectionEncryptedAckMessage);
-  GNUNET_assert (GNUNET_CONSTANTS_CADET_P2P_OVERHEAD == expected_overhead);
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (c,
-                                             "CADET",
-                                             "RATCHET_MESSAGES",
-                                             &ratchet_messages))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET",
-                               "RATCHET_MESSAGES",
-                               "USING DEFAULT");
-    ratchet_messages = 64;
-  }
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_time (c,
-                                           "CADET",
-                                           "RATCHET_TIME",
-                                           &ratchet_time))
-  {
-    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
-                               "CADET", "RATCHET_TIME", "USING DEFAULT");
-    ratchet_time = GNUNET_TIME_UNIT_HOURS;
-  }
-
-
-  id_key = key;
-  tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
-}
-
-
-/**
- * Shut down the tunnel subsystem.
- */
-void
-GCT_shutdown (void)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down tunnels\n");
-  GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL);
-  GNUNET_CONTAINER_multipeermap_destroy (tunnels);
-}
-
-
-/**
- * Create a tunnel.
- *
- * @param destination Peer this tunnel is towards.
- */
-struct CadetTunnel *
-GCT_new (struct CadetPeer *destination)
-{
-  struct CadetTunnel *t;
-
-  t = GNUNET_new (struct CadetTunnel);
-  t->next_ctn.cn = 0;
-  t->peer = destination;
-
-  if (GNUNET_OK !=
-      GNUNET_CONTAINER_multipeermap_put (tunnels, GCP_get_id (destination), t,
-                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
-  {
-    GNUNET_break (0);
-    GNUNET_free (t);
-    return NULL;
-  }
-  t->ax = GNUNET_new (struct CadetTunnelAxolotl);
-  new_ephemeral (t);
-  t->ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create ();
-  return t;
-}
-
-
-/**
- * Change the tunnel's connection state.
- *
- * @param t Tunnel whose connection state to change.
- * @param cstate New connection state.
- */
-void
-GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate)
-{
-  if (NULL == t)
-    return;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n",
-       GCP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate));
-  if (myid != GCP_get_short_id (t->peer) &&
-      CADET_TUNNEL_READY != t->cstate &&
-      CADET_TUNNEL_READY == cstate)
-  {
-    t->cstate = cstate;
-    if (CADET_TUNNEL_KEY_OK == t->estate)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "  cstate triggered send queued data\n");
-      send_queued_data (t);
-    }
-    else if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "  cstate triggered KX\n");
-      GCT_send_kx (t, GNUNET_NO);
-    }
-    else
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "estate %s\n", estate2s (t->estate));
-    }
-  }
-  t->cstate = cstate;
-
-  if (CADET_TUNNEL_READY == cstate
-      && CONNECTIONS_PER_TUNNEL <= GCT_count_connections (t))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  cstate triggered stop dht\n");
-    GCP_stop_search (t->peer);
-  }
-}
-
-
-/**
- * Change the tunnel encryption state.
- *
- * If the encryption state changes to OK, stop the rekey task.
- *
- * @param t Tunnel whose encryption state to change, or NULL.
- * @param state New encryption state.
- */
-void
-GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state)
-{
-  enum CadetTunnelEState old;
-
-  if (NULL == t)
-    return;
-
-  old = t->estate;
-  t->estate = state;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate was %s\n",
-       GCP_2s (t->peer), estate2s (old));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate is now %s\n",
-       GCP_2s (t->peer), estate2s (t->estate));
-
-  if (CADET_TUNNEL_KEY_OK != old && CADET_TUNNEL_KEY_OK == t->estate)
-  {
-    if (NULL != t->rekey_task)
-    {
-      GNUNET_SCHEDULER_cancel (t->rekey_task);
-      t->rekey_task = NULL;
-    }
-    /* Send queued data if tunnel is not loopback */
-    if (myid != GCP_get_short_id (t->peer))
-      send_queued_data (t);
-  }
-}
-
-
-/**
- * @brief Check if tunnel has too many connections, and remove one if necessary.
- *
- * Currently this means the newest connection, unless it is a direct one.
- * Implemented as a task to avoid freeing a connection that is in the middle
- * of being created/processed.
- *
- * @param cls Closure (Tunnel to check).
- */
-static void
-trim_connections (void *cls)
-{
-  struct CadetTunnel *t = cls;
-
-  t->trim_connections_task = NULL;
-  if (GCT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL)
-  {
-    struct CadetTConnection *iter;
-    struct CadetTConnection *c;
-
-    for (c = iter = t->connection_head; NULL != iter; iter = iter->next)
-    {
-      if ((iter->created.abs_value_us > c->created.abs_value_us)
-          && GNUNET_NO == GCC_is_direct (iter->c))
-      {
-        c = iter;
-      }
-    }
-    if (NULL != c)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n",
-           GCT_2s (t));
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n",
-           GCC_2s (c->c));
-      GCC_destroy (c->c);
-    }
-    else
-    {
-      GNUNET_break (0);
-    }
-  }
-}
-
-
-/**
- * Add a connection to a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c)
-{
-  struct CadetTConnection *aux;
-
-  GNUNET_assert (NULL != c);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GCC_2s (c));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GCT_2s (t));
-  for (aux = t->connection_head; aux != NULL; aux = aux->next)
-    if (aux->c == c)
-      return;
-
-  aux = GNUNET_new (struct CadetTConnection);
-  aux->c = c;
-  aux->created = GNUNET_TIME_absolute_get ();
-
-  GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, aux);
-
-  if (CADET_TUNNEL_SEARCHING == t->cstate)
-    GCT_change_cstate (t, CADET_TUNNEL_WAITING);
-
-  if (NULL != t->trim_connections_task)
-    t->trim_connections_task = GNUNET_SCHEDULER_add_now (&trim_connections, t);
-}
-
-
-/**
- * Remove a connection from a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GCT_remove_connection (struct CadetTunnel *t,
-                       struct CadetConnection *c)
-{
-  struct CadetTConnection *aux;
-  struct CadetTConnection *next;
-  unsigned int conns;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n",
-       GCC_2s (c), GCT_2s (t));
-  for (aux = t->connection_head; aux != NULL; aux = next)
-  {
-    next = aux->next;
-    if (aux->c == c)
-    {
-      GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail, aux);
-      GNUNET_free (aux);
-    }
-  }
-
-  conns = GCT_count_connections (t);
-  if (0 == conns
-      && NULL == t->destroy_task
-      && CADET_TUNNEL_SHUTDOWN != t->cstate
-      && GNUNET_NO == shutting_down)
-  {
-    if (0 == GCT_count_any_connections (t))
-      GCT_change_cstate (t, CADET_TUNNEL_SEARCHING);
-    else
-      GCT_change_cstate (t, CADET_TUNNEL_WAITING);
-  }
-
-  /* Start new connections if needed */
-  if (CONNECTIONS_PER_TUNNEL > conns
-      && CADET_TUNNEL_SHUTDOWN != t->cstate
-      && GNUNET_NO == shutting_down)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  too few connections, getting new ones\n");
-    GCP_connect (t->peer); /* Will change cstate to WAITING when possible */
-    return;
-  }
-
-  /* If not marked as ready, no change is needed */
-  if (CADET_TUNNEL_READY != t->cstate)
-    return;
-
-  /* Check if any connection is ready to maintain cstate */
-  for (aux = t->connection_head; aux != NULL; aux = aux->next)
-    if (CADET_CONNECTION_READY == GCC_get_state (aux->c))
-      return;
-}
-
-
-/**
- * Add a channel to a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GCT_add_channel (struct CadetTunnel *t,
-                 struct CadetChannel *ch)
-{
-  struct CadetTChannel *aux;
-
-  GNUNET_assert (NULL != ch);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding channel %p to tunnel %p\n", ch, t);
-
-  for (aux = t->channel_head; aux != NULL; aux = aux->next)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  already there %p\n", aux->ch);
-    if (aux->ch == ch)
-      return;
-  }
-
-  aux = GNUNET_new (struct CadetTChannel);
-  aux->ch = ch;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       " adding %p to %p\n", aux, t->channel_head);
-  GNUNET_CONTAINER_DLL_insert_tail (t->channel_head,
-                                   t->channel_tail,
-                                   aux);
-
-  if (NULL != t->destroy_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->destroy_task);
-    t->destroy_task = NULL;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n");
-  }
-}
-
-
-/**
- * Remove a channel from a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch)
-{
-  struct CadetTChannel *aux;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing channel %p from tunnel %p\n", ch, t);
-  for (aux = t->channel_head; aux != NULL; aux = aux->next)
-  {
-    if (aux->ch == ch)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GCCH_2s (ch));
-      GNUNET_CONTAINER_DLL_remove (t->channel_head,
-                                  t->channel_tail,
-                                  aux);
-      GNUNET_free (aux);
-      return;
-    }
-  }
-}
-
-
-/**
- * Search for a channel by global ID.
- *
- * @param t Tunnel containing the channel.
- * @param ctn Public channel number.
- *
- * @return channel handler, NULL if doesn't exist
- */
-struct CadetChannel *
-GCT_get_channel (struct CadetTunnel *t,
-                 struct GNUNET_CADET_ChannelTunnelNumber ctn)
-{
-  struct CadetTChannel *iter;
-
-  if (NULL == t)
-    return NULL;
-
-  for (iter = t->channel_head; NULL != iter; iter = iter->next)
-  {
-    if (GCCH_get_id (iter->ch).cn == ctn.cn)
-      break;
-  }
-
-  return NULL == iter ? NULL : iter->ch;
-}
-
-
-/**
- * @brief Destroy a tunnel and free all resources.
- *
- * Should only be called a while after the tunnel has been marked as destroyed,
- * in case there is a new channel added to the same peer shortly after marking
- * the tunnel. This way we avoid a new public key handshake.
- *
- * @param cls Closure (tunnel to destroy).
- */
-static void
-delayed_destroy (void *cls)
-{
-  struct CadetTunnel *t = cls;
-  struct CadetTConnection *iter;
-
-  t->destroy_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "delayed destroying tunnel %p\n",
-       t);
-  t->cstate = CADET_TUNNEL_SHUTDOWN;
-  for (iter = t->connection_head; NULL != iter; iter = iter->next)
-  {
-    GCC_send_destroy (iter->c);
-  }
-  GCT_destroy (t);
-}
-
-
-/**
- * Tunnel is empty: destroy it.
- *
- * Notifies all connections about the destruction.
- *
- * @param t Tunnel to destroy.
- */
-void
-GCT_destroy_empty (struct CadetTunnel *t)
-{
-  if (GNUNET_YES == shutting_down)
-    return; /* Will be destroyed immediately anyway */
-
-  if (NULL != t->destroy_task)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Tunnel %s is already scheduled for destruction. Tunnel debug dump:\n",
-         GCT_2s (t));
-    GCT_debug (t, GNUNET_ERROR_TYPE_WARNING);
-    GNUNET_break (0);
-    /* should never happen, tunnel can only become empty once, and the
-     * task identifier should be NO_TASK (cleaned when the tunnel was created
-     * or became un-empty)
-     */
-    return;
-  }
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s empty: scheduling destruction\n",
-       GCT_2s (t));
-
-  // FIXME make delay a config option
-  t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                                  &delayed_destroy, t);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled destroy of %p as %p\n",
-       t, t->destroy_task);
-}
-
-
-/**
- * Destroy tunnel if empty (no more channels).
- *
- * @param t Tunnel to destroy if empty.
- */
-void
-GCT_destroy_if_empty (struct CadetTunnel *t)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GCT_2s (t));
-  if (0 < GCT_count_channels (t))
-    return;
-
-  GCT_destroy_empty (t);
-}
-
-
-/**
- * Destroy the tunnel.
- *
- * This function does not generate any warning traffic to clients or peers.
- *
- * Tasks:
- * Cancel messages belonging to this tunnel queued to neighbors.
- * Free any allocated resources linked to the tunnel.
- *
- * @param t The tunnel to destroy.
- */
-void
-GCT_destroy (struct CadetTunnel *t)
-{
-  struct CadetTConnection *iter_c;
-  struct CadetTConnection *next_c;
-  struct CadetTChannel *iter_ch;
-  struct CadetTChannel *next_ch;
-  unsigned int keepalives_queued;
-
-  if (NULL == t)
-    return;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "destroying tunnel %s\n",
-       GCP_2s (t->peer));
-  GNUNET_break (GNUNET_YES ==
-                GNUNET_CONTAINER_multipeermap_remove (tunnels,
-                                                      GCP_get_id (t->peer), t));
-
-  for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c)
-  {
-    next_c = iter_c->next;
-    GCC_destroy (iter_c->c);
-  }
-  for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch)
-  {
-    next_ch = iter_ch->next;
-    GCCH_destroy (iter_ch->ch);
-    /* Should only happen on shutdown, but it's ok. */
-  }
-  keepalives_queued = 0;
-  while (NULL != t->tq_head)
-  {
-    /* Should have been cleaned by destuction of channel. */
-    struct GNUNET_MessageHeader *mh;
-    uint16_t type;
-
-    mh = (struct GNUNET_MessageHeader *) &t->tq_head[1];
-    type = ntohs (mh->type);
-    if (0 == keepalives_queued && GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE == type)
-    {
-      keepalives_queued = 1;
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "one keepalive left behind on tunnel shutdown\n");
-    }
-    else if (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY == type)
-    {
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-           "tunnel destroyed before a CHANNEL_DESTROY was sent to peer\n");
-    }
-    else
-    {
-      GNUNET_break (0);
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-           "message left behind on tunnel shutdown: %s\n",
-           GC_m2s (type));
-    }
-    unqueue_data (t->tq_head);
-  }
-
-
-  if (NULL != t->destroy_task)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-        "cancelling dest: %p\n",
-        t->destroy_task);
-    GNUNET_SCHEDULER_cancel (t->destroy_task);
-    t->destroy_task = NULL;
-  }
-
-  if (NULL != t->trim_connections_task)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "cancelling trim: %p\n",
-         t->trim_connections_task);
-    GNUNET_SCHEDULER_cancel (t->trim_connections_task);
-    t->trim_connections_task = NULL;
-  }
-
-  GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO);
-  GCP_set_tunnel (t->peer, NULL);
-
-  if (NULL != t->rekey_task)
-  {
-    GNUNET_SCHEDULER_cancel (t->rekey_task);
-    t->rekey_task = NULL;
-  }
-  if (NULL != t->ax)
-    destroy_ax (t);
-
-  GNUNET_free (t);
-}
-
-
-/**
- * @brief Use the given path for the tunnel.
- * Update the next and prev hops (and RCs).
- * (Re)start the path refresh in case the tunnel is locally owned.
- *
- * @param t Tunnel to update.
- * @param p Path to use.
- *
- * @return Connection created.
- */
-struct CadetConnection *
-GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *path)
-{
-  struct CadetConnection *c;
-  struct GNUNET_CADET_ConnectionTunnelIdentifier cid;
-  unsigned int own_pos;
-
-  if (NULL == t || NULL == path)
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-
-  if (CADET_TUNNEL_SHUTDOWN == t->cstate)
-  {
-    GNUNET_break (0);
-    return NULL;
-  }
-
-  for (own_pos = 0; own_pos < path->length; own_pos++)
-  {
-    if (path->peers[own_pos] == myid)
-      break;
-  }
-  if (own_pos >= path->length)
-  {
-    GNUNET_break_op (0);
-    return NULL;
-  }
-
-  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid));
-  c = GCC_new (&cid, t, path, own_pos);
-  if (NULL == c)
-  {
-    /* Path was flawed */
-    return NULL;
-  }
-  GCT_add_connection (t, c);
-  return c;
-}
-
-
-/**
- * Count all created connections of a tunnel. Not necessarily ready connections!
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections created, either being established or ready.
- */
-unsigned int
-GCT_count_any_connections (struct CadetTunnel *t)
-{
-  struct CadetTConnection *iter;
-  unsigned int count;
-
-  if (NULL == t)
-    return 0;
-
-  for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
-    count++;
-
-  return count;
-}
-
-
-/**
- * Count established (ready) connections of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections.
- */
-unsigned int
-GCT_count_connections (struct CadetTunnel *t)
-{
-  struct CadetTConnection *iter;
-  unsigned int count;
-
-  if (NULL == t)
-    return 0;
-
-  for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
-    if (CADET_CONNECTION_READY == GCC_get_state (iter->c))
-      count++;
-
-  return count;
-}
-
-
-/**
- * Count channels of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of channels.
- */
-unsigned int
-GCT_count_channels (struct CadetTunnel *t)
-{
-  struct CadetTChannel *iter;
-  unsigned int count;
-
-  for (count = 0, iter = t->channel_head;
-       NULL != iter;
-       iter = iter->next, count++) /* skip */;
-
-  return count;
-}
-
-
-/**
- * Get the connectivity state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's connectivity state.
- */
-enum CadetTunnelCState
-GCT_get_cstate (struct CadetTunnel *t)
-{
-  if (NULL == t)
-  {
-    GNUNET_assert (0);
-    return (enum CadetTunnelCState) -1;
-  }
-  return t->cstate;
-}
-
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnelEState
-GCT_get_estate (struct CadetTunnel *t)
-{
-  if (NULL == t)
-  {
-    GNUNET_break (0);
-    return (enum CadetTunnelEState) -1;
-  }
-  return t->estate;
-}
-
-/**
- * Get the maximum buffer space for a tunnel towards a local client.
- *
- * @param t Tunnel.
- *
- * @return Biggest buffer space offered by any channel in the tunnel.
- */
-unsigned int
-GCT_get_channels_buffer (struct CadetTunnel *t)
-{
-  struct CadetTChannel *iter;
-  unsigned int buffer;
-  unsigned int ch_buf;
-
-  if (NULL == t->channel_head)
-  {
-    /* Probably getting buffer for a channel create/handshake. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  no channels, allow max\n");
-    return MIN_TUNNEL_BUFFER;
-  }
-
-  buffer = 0;
-  for (iter = t->channel_head; NULL != iter; iter = iter->next)
-  {
-    ch_buf = get_channel_buffer (iter);
-    if (ch_buf > buffer)
-      buffer = ch_buf;
-  }
-  if (MIN_TUNNEL_BUFFER > buffer)
-    return MIN_TUNNEL_BUFFER;
-
-  if (MAX_TUNNEL_BUFFER < buffer)
-  {
-    GNUNET_break (0);
-    return MAX_TUNNEL_BUFFER;
-  }
-  return buffer;
-}
-
-
-/**
- * Get the total buffer space for a tunnel for P2P traffic.
- *
- * @param t Tunnel.
- *
- * @return Buffer space offered by all connections in the tunnel.
- */
-unsigned int
-GCT_get_connections_buffer (struct CadetTunnel *t)
-{
-  struct CadetTConnection *iter;
-  unsigned int buffer;
-
-  if (GNUNET_NO == is_ready (t))
-  {
-    if (count_queued_data (t) >= 3)
-      return 0;
-    else
-      return 1;
-  }
-
-  buffer = 0;
-  for (iter = t->connection_head; NULL != iter; iter = iter->next)
-  {
-    if (GCC_get_state (iter->c) != CADET_CONNECTION_READY)
-    {
-      continue;
-    }
-    buffer += get_connection_buffer (iter);
-  }
-
-  return buffer;
-}
-
-
-/**
- * Get the tunnel's destination.
- *
- * @param t Tunnel.
- *
- * @return ID of the destination peer.
- */
-const struct GNUNET_PeerIdentity *
-GCT_get_destination (struct CadetTunnel *t)
-{
-  return GCP_get_id (t->peer);
-}
-
-
-/**
- * Get the tunnel's next free global channel ID.
- *
- * @param t Tunnel.
- *
- * @return GID of a channel free to use.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCT_get_next_ctn (struct CadetTunnel *t)
-{
-  struct GNUNET_CADET_ChannelTunnelNumber ctn;
-  struct GNUNET_CADET_ChannelTunnelNumber mask;
-  int result;
-
-  /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID.
-   * If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0
-   * If peer's ID is bigger, start at 0x4... bit 30 = 1
-   */
-  result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GCP_get_id (t->peer));
-  if (0 > result)
-    mask.cn = htonl (0x40000000);
-  else
-    mask.cn = 0x0;
-  t->next_ctn.cn |= mask.cn;
-
-  while (NULL != GCT_get_channel (t, t->next_ctn))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Channel %u exists...\n",
-         t->next_ctn.cn);
-    t->next_ctn.cn = htonl ((ntohl (t->next_ctn.cn) + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI);
-    t->next_ctn.cn |= mask.cn;
-  }
-  ctn = t->next_ctn;
-  t->next_ctn.cn = (t->next_ctn.cn + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI;
-  t->next_ctn.cn |= mask.cn;
-
-  return ctn;
-}
-
-
-/**
- * Send ACK on one or more channels due to buffer in connections.
- *
- * @param t Channel which has some free buffer space.
- */
-void
-GCT_unchoke_channels (struct CadetTunnel *t)
-{
-  struct CadetTChannel *iter;
-  unsigned int buffer;
-  unsigned int channels = GCT_count_channels (t);
-  unsigned int choked_n;
-  struct CadetChannel *choked[channels];
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_unchoke_channels on %s\n", GCT_2s (t));
-  LOG (GNUNET_ERROR_TYPE_DEBUG, " head: %p\n", t->channel_head);
-  if (NULL != t->channel_head)
-    LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch);
-
-  if (NULL != t->tq_head)
-    send_queued_data (t);
-
-  /* Get buffer space */
-  buffer = GCT_get_connections_buffer (t);
-  if (0 == buffer)
-  {
-    return;
-  }
-
-  /* Count and remember choked channels */
-  choked_n = 0;
-  for (iter = t->channel_head; NULL != iter; iter = iter->next)
-  {
-    if (GNUNET_NO == get_channel_allowed (iter))
-    {
-      choked[choked_n++] = iter->ch;
-    }
-  }
-
-  /* Unchoke random channels */
-  while (0 < buffer && 0 < choked_n)
-  {
-    unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                               choked_n);
-    GCCH_allow_client (choked[r], GCCH_is_origin (choked[r], GNUNET_YES));
-    choked_n--;
-    buffer--;
-    choked[r] = choked[choked_n];
-  }
-}
-
-
-/**
- * Send ACK on one or more connections due to buffer space to the client.
- *
- * Iterates all connections of the tunnel and sends ACKs appropriately.
- *
- * @param t Tunnel.
- */
-void
-GCT_send_connection_acks (struct CadetTunnel *t)
-{
-  struct CadetTConnection *iter;
-  uint32_t allowed;
-  uint32_t to_allow;
-  uint32_t allow_per_connection;
-  unsigned int cs;
-  unsigned int buffer;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n",
-       GCT_2s (t));
-
-  if (NULL == t)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
-  if (CADET_TUNNEL_READY != t->cstate)
-    return;
-
-  buffer = GCT_get_channels_buffer (t);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  buffer %u\n", buffer);
-
-  /* Count connections, how many messages are already allowed */
-  cs = GCT_count_connections (t);
-  for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next)
-  {
-    allowed += get_connection_allowed (iter);
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "  allowed %u\n", allowed);
-
-  /* Make sure there is no overflow */
-  if (allowed > buffer)
-    return;
-
-  /* Authorize connections to send more data */
-  to_allow = buffer - allowed;
-
-  for (iter = t->connection_head;
-       NULL != iter && to_allow > 0;
-       iter = iter->next)
-  {
-    if (CADET_CONNECTION_READY != GCC_get_state (iter->c)
-        || get_connection_allowed (iter) > 64 / 3)
-    {
-      continue;
-    }
-    GNUNET_assert(cs != 0);
-    allow_per_connection = to_allow/cs;
-    to_allow -= allow_per_connection;
-    cs--;
-    GCC_allow (iter->c, allow_per_connection,
-               GCC_is_origin (iter->c, GNUNET_NO));
-  }
-
-  if (0 != to_allow)
-  {
-    /* Since we don't allow if it's allowed to send 64/3, this can happen. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "  reminding to_allow: %u\n", to_allow);
-  }
-}
-
-
-/**
- * Cancel a previously sent message while it's in the queue.
- *
- * ONLY can be called before the continuation given to the send function
- * is called. Once the continuation is called, the message is no longer in the
- * queue.
- *
- * @param q Handle to the queue.
- */
-void
-GCT_cancel (struct CadetTunnelQueue *q)
-{
-  if (NULL != q->cq)
-  {
-    GNUNET_assert (NULL == q->tqd);
-    GCC_cancel (q->cq);
-    /* tun_message_sent() will be called and free q */
-  }
-  else if (NULL != q->tqd)
-  {
-    unqueue_data (q->tqd);
-    q->tqd = NULL;
-    if (NULL != q->cont)
-      q->cont (q->cont_cls, NULL, q, 0, 0);
-    GNUNET_free (q);
-  }
-  else
-  {
-    GNUNET_break (0);
-  }
-}
-
-
-/**
- * Check if the tunnel has queued traffic.
- *
- * @param t Tunnel to check.
- *
- * @return #GNUNET_YES if there is queued traffic
- *         #GNUNET_NO otherwise
- */
-int
-GCT_has_queued_traffic (struct CadetTunnel *t)
-{
-  return (NULL != t->tq_head) ? GNUNET_YES : GNUNET_NO;
-}
-
-
-/**
- * Sends an already built message on a tunnel, encrypting it and
- * choosing the best connection if not provided.
- *
- * @param message Message to send. Function modifies it.
- * @param t Tunnel on which this message is transmitted.
- * @param c Connection to use (autoselect if NULL).
- * @param force Force the tunnel to take the message (buffer overfill).
- * @param cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel message. NULL if @c cont is NULL.
- */
-struct CadetTunnelQueue *
-GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
-                           struct CadetTunnel *t,
-                           struct CadetConnection *c,
-                           int force, GCT_sent cont, void *cont_cls)
-{
-  return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL);
-}
-
-
-/**
- * Send a KX message.
- *
- * @param t Tunnel on which to send it.
- * @param force_reply Force the other peer to reply with a KX message.
- */
-void
-GCT_send_kx (struct CadetTunnel *t, int force_reply)
-{
-  static struct CadetEncryptedMessageIdentifier zero;
-  struct CadetConnection *c;
-  struct GNUNET_CADET_TunnelKeyExchangeMessage msg;
-  enum GNUNET_CADET_KX_Flags flags;
-
-  LOG (GNUNET_ERROR_TYPE_INFO, "==> {        KX} on %s\n", GCT_2s (t));
-  if (NULL != t->ephm_h)
-  {
-    LOG (GNUNET_ERROR_TYPE_INFO, "     already queued, nop\n");
-    return;
-  }
-  GNUNET_assert (GNUNET_NO == GCT_is_loopback (t));
-
-  c = tunnel_get_connection (t);
-  if (NULL == c)
-  {
-    if (NULL == t->destroy_task && CADET_TUNNEL_READY == t->cstate)
-    {
-      GNUNET_break (0);
-      GCT_debug (t, GNUNET_ERROR_TYPE_ERROR);
-    }
-    return;
-  }
-
-  msg.header.size = htons (sizeof (msg));
-  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
-  flags = GNUNET_CADET_KX_FLAG_NONE;
-  if (GNUNET_YES == force_reply)
-    flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
-  msg.flags = htonl (flags);
-  msg.cid = *GCC_get_id (c);
-  GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->kx_0, &msg.ephemeral_key);
-  GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &msg.ratchet_key);
-
-  t->ephm_h = GCC_send_prebuilt_message (&msg.header,
-                                         UINT16_MAX,
-                                         zero,
-                                         c,
-                                         GCC_is_origin (c, GNUNET_YES),
-                                         GNUNET_YES, &ephm_sent, t);
-  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
-    GCT_change_estate (t, CADET_TUNNEL_KEY_AX_SENT);
-}
-
-
-/**
- * Is the tunnel directed towards the local peer?
- *
- * @param t Tunnel.
- *
- * @return #GNUNET_YES if it is loopback.
- */
-int
-GCT_is_loopback (const struct CadetTunnel *t)
-{
-  return (myid == GCP_get_short_id (t->peer));
-}
-
-
-/**
- * Is the tunnel this path already?
- *
- * @param t Tunnel.
- * @param p Path.
- *
- * @return #GNUNET_YES a connection uses this path.
- */
-int
-GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p)
-{
-  struct CadetTConnection *iter;
-
-  for (iter = t->connection_head; NULL != iter; iter = iter->next)
-    if (path_equivalent (GCC_get_path (iter->c), p))
-      return GNUNET_YES;
-
-  return GNUNET_NO;
-}
-
-
-/**
- * Get a cost of a path for a tunnel considering existing connections.
- *
- * @param t Tunnel.
- * @param path Candidate path.
- *
- * @return Cost of the path (path length + number of overlapping nodes)
- */
-unsigned int
-GCT_get_path_cost (const struct CadetTunnel *t,
-                   const struct CadetPeerPath *path)
-{
-  struct CadetTConnection *iter;
-  const struct CadetPeerPath *aux;
-  unsigned int overlap;
-  unsigned int i;
-  unsigned int j;
-
-  if (NULL == path)
-    return 0;
-
-  overlap = 0;
-  GNUNET_assert (NULL != t);
-
-  for (i = 0; i < path->length; i++)
-  {
-    for (iter = t->connection_head; NULL != iter; iter = iter->next)
-    {
-      aux = GCC_get_path (iter->c);
-      if (NULL == aux)
-        continue;
-
-      for (j = 0; j < aux->length; j++)
-      {
-        if (path->peers[i] == aux->peers[j])
-        {
-          overlap++;
-          break;
-        }
-      }
-    }
-  }
-  return path->length + overlap;
-}
-
-
-/**
- * Get the static string for the peer this tunnel is directed.
- *
- * @param t Tunnel.
- *
- * @return Static string the destination peer's ID.
- */
-const char *
-GCT_2s (const struct CadetTunnel *t)
-{
-  if (NULL == t)
-    return "(NULL)";
-
-  return GCP_2s (t->peer);
-}
-
-
-/******************************************************************************/
-/*****************************    INFO/DEBUG    *******************************/
-/******************************************************************************/
-
-static void
-ax_debug (const struct CadetTunnelAxolotl *ax, enum GNUNET_ErrorType level)
-{
-  struct GNUNET_CRYPTO_EcdhePublicKey pub;
-  struct CadetTunnelSkippedKey *iter;
-
-  LOG2 (level, "TTT  RK  \t %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->RK));
-
-  LOG2 (level, "TTT  HKs \t %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs));
-  LOG2 (level, "TTT  HKr \t %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr));
-  LOG2 (level, "TTT  NHKs\t %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKs));
-  LOG2 (level, "TTT  NHKr\t %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKr));
-
-  LOG2 (level, "TTT  CKs \t %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs));
-  LOG2 (level, "TTT  CKr \t %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr));
-
-  GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs, &pub);
-  LOG2 (level, "TTT  DHRs\t %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub));
-  LOG2 (level, "TTT  DHRr\t %s\n",
-        GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->DHRr));
-
-  LOG2 (level, "TTT  Nr\t %u\tNs\t%u\n", ax->Nr, ax->Ns);
-  LOG2 (level, "TTT  PNs\t %u\tSkipped\t%u\n", ax->PNs, ax->skipped);
-  LOG2 (level, "TTT  Ratchet\t%u\n", ax->ratchet_flag);
-
-  for (iter = ax->skipped_head; NULL != iter; iter = iter->next)
-  {
-    LOG2 (level, "TTT    HK\t %s\n",
-          GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->HK));
-    LOG2 (level, "TTT    MK\t %s\n",
-          GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->MK));
-  }
-}
-
-/**
- * Log all possible info about the tunnel state.
- *
- * @param t Tunnel to debug.
- * @param level Debug level to use.
- */
-void
-GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level)
-{
-  struct CadetTChannel *iter_ch;
-  struct CadetTConnection *iter_c;
-  int do_log;
-
-  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
-                                       "cadet-tun",
-                                       __FILE__, __FUNCTION__, __LINE__);
-  if (0 == do_log)
-    return;
-
-  LOG2 (level, "TTT DEBUG TUNNEL TOWARDS %s\n", GCT_2s (t));
-  LOG2 (level, "TTT  cstate %s, estate %s\n",
-       cstate2s (t->cstate), estate2s (t->estate));
-#if DUMP_KEYS_TO_STDERR
-  ax_debug (t->ax, level);
-#endif
-  LOG2 (level, "TTT  tq_head %p, tq_tail %p\n", t->tq_head, t->tq_tail);
-  LOG2 (level, "TTT  destroy %p\n", t->destroy_task);
-  LOG2 (level, "TTT  channels:\n");
-  for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = iter_ch->next)
-  {
-    GCCH_debug (iter_ch->ch, level);
-  }
-
-  LOG2 (level, "TTT  connections:\n");
-  for (iter_c = t->connection_head; NULL != iter_c; iter_c = iter_c->next)
-  {
-    GCC_debug (iter_c->c, level);
-  }
-
-  LOG2 (level, "TTT DEBUG TUNNEL END\n");
-}
-
-
-/**
- * Iterate all tunnels.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls)
-{
-  GNUNET_CONTAINER_multipeermap_iterate (tunnels, iter, cls);
-}
-
-
-/**
- * Count all tunnels.
- *
- * @return Number of tunnels to remote peers kept by this peer.
- */
-unsigned int
-GCT_count_all (void)
-{
-  return GNUNET_CONTAINER_multipeermap_size (tunnels);
-}
-
-
-/**
- * Iterate all connections of a tunnel.
- *
- * @param t Tunnel whose connections to iterate.
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCT_iterate_connections (struct CadetTunnel *t, GCT_conn_iter iter, void *cls)
-{
-  struct CadetTConnection *ct;
-
-  for (ct = t->connection_head; NULL != ct; ct = ct->next)
-    iter (cls, ct->c);
-}
-
-
-/**
- * Iterate all channels of a tunnel.
- *
- * @param t Tunnel whose channels to iterate.
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCT_iterate_channels (struct CadetTunnel *t, GCT_chan_iter iter, void *cls)
-{
-  struct CadetTChannel *cht;
-
-  for (cht = t->channel_head; NULL != cht; cht = cht->next)
-    iter (cls, cht->ch);
-}
diff --git a/src/cadet/gnunet-service-cadet_tunnel.h b/src/cadet/gnunet-service-cadet_tunnel.h
deleted file mode 100644 (file)
index 1b56a06..0000000
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2013 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/gnunet-service-cadet_tunnel.h
- * @brief cadet service; dealing with tunnels and crypto
- * @author Bartlomiej Polot
- *
- * All functions in this file should use the prefix GMT (Gnunet Cadet Tunnel)
- */
-
-#ifndef GNUNET_SERVICE_CADET_TUNNEL_H
-#define GNUNET_SERVICE_CADET_TUNNEL_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define CONNECTIONS_PER_TUNNEL 3
-
-/**
- * All the connectivity states a tunnel can be in.
- */
-enum CadetTunnelCState
-{
-  /**
-   * Uninitialized status, should never appear in operation.
-   */
-  CADET_TUNNEL_NEW,
-
-  /**
-   * No path to the peer known yet.
-   */
-  CADET_TUNNEL_SEARCHING,
-
-  /**
-   * Request sent, not yet answered.
-   */
-  CADET_TUNNEL_WAITING,
-
-  /**
-   * Peer connected and ready to accept data.
-   */
-  CADET_TUNNEL_READY,
-
-  /**
-   * Tunnel being shut down, don't try to keep it alive.
-   */
-  CADET_TUNNEL_SHUTDOWN
-};
-
-
-/**
- * All the encryption states a tunnel can be in.
- */
-enum CadetTunnelEState
-{
-  /**
-   * Uninitialized status, should never appear in operation.
-   */
-  CADET_TUNNEL_KEY_UNINITIALIZED,
-
-  /**
-   * Ephemeral key sent, waiting for peer's key.
-   */
-  CADET_TUNNEL_KEY_AX_SENT,
-
-  /**
-   * In OTR: New ephemeral key and ping sent, waiting for pong.
-   *
-   * This means that we DO have the peer's ephemeral key, otherwise the
-   * state would be KEY_SENT. We DO NOT have a valid session key (either no
-   * previous key or previous key expired).
-   *
-   *
-   * In Axolotl: Key sent and received but no deciphered traffic yet.
-   *
-   * This means that we can send traffic (otherwise we would never complete
-   * the handshake), but we don't have complete confirmation. Since the first
-   * traffic MUST be a complete channel creation 3-way handshake, no payload
-   * will be sent before confirmation.
-   */
-  CADET_TUNNEL_KEY_AX_AUTH_SENT,
-
-  /**
-   * Handshake completed: session key available.
-   */
-  CADET_TUNNEL_KEY_OK,
-
-  /**
-   * New ephemeral key and ping sent, waiting for pong. Unlike KEY_PING,
-   * we still have a valid session key and therefore we *can* still send
-   * traffic on the tunnel.
-   */
-  CADET_TUNNEL_KEY_REKEY
-};
-
-/**
- * Struct containing all information regarding a given peer
- */
-struct CadetTunnel;
-
-
-#include "gnunet-service-cadet_channel.h"
-#include "gnunet-service-cadet_connection.h"
-#include "gnunet-service-cadet_peer.h"
-
-/**
- * Handle for messages queued but not yet sent.
- */
-struct CadetTunnelQueue;
-
-/**
- * Callback called when a queued message is sent.
- *
- * @param cls Closure.
- * @param t Tunnel this message was on.
- * @param type Type of message sent.
- * @param size Size of the message.
- */
-typedef void
-(*GCT_sent) (void *cls,
-            struct CadetTunnel *t,
-            struct CadetTunnelQueue *q,
-            uint16_t type, size_t size);
-
-typedef void
-(*GCT_conn_iter) (void *cls, struct CadetConnection *c);
-
-
-typedef void
-(*GCT_chan_iter) (void *cls, struct CadetChannel *ch);
-
-
-/******************************************************************************/
-/********************************    API    ***********************************/
-/******************************************************************************/
-
-/**
- * Initialize tunnel subsystem.
- *
- * @param c Configuration handle.
- * @param key ECC private key, to derive all other keys and do crypto.
- */
-void
-GCT_init (const struct GNUNET_CONFIGURATION_Handle *c,
-          const struct GNUNET_CRYPTO_EddsaPrivateKey *key);
-
-
-/**
- * Shut down the tunnel subsystem.
- */
-void
-GCT_shutdown (void);
-
-
-/**
- * Create a tunnel.
- *
- * @param destination Peer this tunnel is towards.
- */
-struct CadetTunnel *
-GCT_new (struct CadetPeer *destination);
-
-
-/**
- * Tunnel is empty: destroy it.
- *
- * Notifies all connections about the destruction.
- *
- * @param t Tunnel to destroy.
- */
-void
-GCT_destroy_empty (struct CadetTunnel *t);
-
-
-/**
- * Destroy tunnel if empty (no more channels).
- *
- * @param t Tunnel to destroy if empty.
- */
-void
-GCT_destroy_if_empty (struct CadetTunnel *t);
-
-
-/**
- * Destroy the tunnel.
- *
- * This function does not generate any warning traffic to clients or peers.
- *
- * Tasks:
- * Cancel messages belonging to this tunnel queued to neighbors.
- * Free any allocated resources linked to the tunnel.
- *
- * @param t The tunnel to destroy.
- */
-void
-GCT_destroy (struct CadetTunnel *t);
-
-
-/**
- * Change the tunnel's connection state.
- *
- * @param t Tunnel whose connection state to change.
- * @param cstate New connection state.
- */
-void
-GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate);
-
-
-/**
- * Change the tunnel encryption state.
- *
- * @param t Tunnel whose encryption state to change.
- * @param state New encryption state.
- */
-void
-GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state);
-
-
-/**
- * Add a connection to a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c);
-
-
-/**
- * Remove a connection from a tunnel.
- *
- * @param t Tunnel.
- * @param c Connection.
- */
-void
-GCT_remove_connection (struct CadetTunnel *t, struct CadetConnection *c);
-
-
-/**
- * Add a channel to a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GCT_add_channel (struct CadetTunnel *t, struct CadetChannel *ch);
-
-
-/**
- * Remove a channel from a tunnel.
- *
- * @param t Tunnel.
- * @param ch Channel.
- */
-void
-GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch);
-
-
-/**
- * Search for a channel by global ID.
- *
- * @param t Tunnel containing the channel.
- * @param ctn Public channel number.
- *
- * @return channel handler, NULL if doesn't exist
- */
-struct CadetChannel *
-GCT_get_channel (struct CadetTunnel *t, struct GNUNET_CADET_ChannelTunnelNumber ctn);
-
-
-/**
- * Decrypt and process an encrypted message.
- *
- * Calls the appropriate handler for a message in a channel of a local tunnel.
- *
- * @param t Tunnel this message came on.
- * @param msg Message header.
- */
-void
-GCT_handle_encrypted (struct CadetTunnel *t,
-                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
-
-
-/**
- * Handle a Key eXchange message.
- *
- * @param t Tunnel on which the message came.
- * @param msg KX message itself.
- */
-void
-GCT_handle_kx (struct CadetTunnel *t,
-               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
-
-
-/**
- * @brief Use the given path for the tunnel.
- * Update the next and prev hops (and RCs).
- * (Re)start the path refresh in case the tunnel is locally owned.
- *
- * @param t Tunnel to update.
- * @param p Path to use.
- *
- * @return Connection created.
- */
-struct CadetConnection *
-GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *p);
-
-
-/**
- * Count all created connections of a tunnel. Not necessarily ready connections!
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections created, either being established or ready.
- */
-unsigned int
-GCT_count_any_connections (struct CadetTunnel *t);
-
-
-/**
- * Count established (ready) connections of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of connections.
- */
-unsigned int
-GCT_count_connections (struct CadetTunnel *t);
-
-
-/**
- * Count channels of a tunnel.
- *
- * @param t Tunnel on which to count.
- *
- * @return Number of channels.
- */
-unsigned int
-GCT_count_channels (struct CadetTunnel *t);
-
-
-/**
- * Get the connectivity state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's connectivity state.
- */
-enum CadetTunnelCState
-GCT_get_cstate (struct CadetTunnel *t);
-
-
-/**
- * Get the encryption state of a tunnel.
- *
- * @param t Tunnel.
- *
- * @return Tunnel's encryption state.
- */
-enum CadetTunnelEState
-GCT_get_estate (struct CadetTunnel *t);
-
-
-/**
- * Get the maximum buffer space for a tunnel towards a local client.
- *
- * @param t Tunnel.
- *
- * @return Biggest buffer space offered by any channel in the tunnel.
- */
-unsigned int
-GCT_get_channels_buffer (struct CadetTunnel *t);
-
-
-/**
- * Get the total buffer space for a tunnel for P2P traffic.
- *
- * @param t Tunnel.
- *
- * @return Buffer space offered by all connections in the tunnel.
- */
-unsigned int
-GCT_get_connections_buffer (struct CadetTunnel *t);
-
-
-/**
- * Get the tunnel's destination.
- *
- * @param t Tunnel.
- *
- * @return ID of the destination peer.
- */
-const struct GNUNET_PeerIdentity *
-GCT_get_destination (struct CadetTunnel *t);
-
-
-/**
- * Get the tunnel's next free Channel ID.
- *
- * @param t Tunnel.
- *
- * @return ID of a channel free to use.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-GCT_get_next_ctn (struct CadetTunnel *t);
-
-
-/**
- * Send ACK on one or more channels due to buffer in connections.
- *
- * @param t Channel which has some free buffer space.
- */
-void
-GCT_unchoke_channels (struct CadetTunnel *t);
-
-
-/**
- * Send ACK on one or more connections due to buffer space to the client.
- *
- * Iterates all connections of the tunnel and sends ACKs appropriately.
- *
- * @param t Tunnel which has some free buffer space.
- */
-void
-GCT_send_connection_acks (struct CadetTunnel *t);
-
-
-/**
- * Cancel a previously sent message while it's in the queue.
- *
- * ONLY can be called before the continuation given to the send function
- * is called. Once the continuation is called, the message is no longer in the
- * queue.
- *
- * @param q Handle to the queue.
- */
-void
-GCT_cancel (struct CadetTunnelQueue *q);
-
-
-/**
- * Check if the tunnel has queued traffic.
- *
- * @param t Tunnel to check.
- *
- * @return #GNUNET_YES if there is queued traffic
- *         #GNUNET_NO otherwise
- */
-int
-GCT_has_queued_traffic (struct CadetTunnel *t);
-
-/**
- * Sends an already built message on a tunnel, encrypting it and
- * choosing the best connection.
- *
- * @param message Message to send. Function modifies it.
- * @param t Tunnel on which this message is transmitted.
- * @param c Connection to use (autoselect if NULL).
- * @param force Force the tunnel to take the message (buffer overfill).
- * @param cont Continuation to call once message is really sent.
- * @param cont_cls Closure for @c cont.
- *
- * @return Handle to cancel message. NULL if @c cont is NULL.
- */
-struct CadetTunnelQueue *
-GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
-                           struct CadetTunnel *t, struct CadetConnection *c,
-                           int force, GCT_sent cont, void *cont_cls);
-
-
-/**
- * Send a KX message.
- *
- * @param t Tunnel on which to send it.
- * @param force_reply Force the other peer to reply with a KX message.
- */
-void
-GCT_send_kx (struct CadetTunnel *t, int force_reply);
-
-
-/**
- * Is the tunnel directed towards the local peer?
- *
- * @param t Tunnel.
- *
- * @return #GNUNET_YES if it is loopback.
- */
-int
-GCT_is_loopback (const struct CadetTunnel *t);
-
-
-/**
- * Is the tunnel using this path already?
- *
- * @param t Tunnel.
- * @param p Path.
- *
- * @return #GNUNET_YES a connection uses this path.
- */
-int
-GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p);
-
-
-/**
- * Get a cost of a path for a tunnel considering existing connections.
- *
- * @param t Tunnel.
- * @param path Candidate path.
- *
- * @return Cost of the path (path length + number of overlapping nodes)
- */
-unsigned int
-GCT_get_path_cost (const struct CadetTunnel *t,
-                   const struct CadetPeerPath *path);
-
-
-/**
- * Get the static string for the peer this tunnel is directed.
- *
- * @param t Tunnel.
- *
- * @return Static string the destination peer's ID.
- */
-const char *
-GCT_2s (const struct CadetTunnel *t);
-
-
-/**
- * Log all possible info about the tunnel state.
- *
- * @param t Tunnel to debug.
- * @param level Debug level to use.
- */
-void
-GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level);
-
-
-/**
- * Iterate all tunnels.
- *
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls);
-
-
-/**
- * Count all tunnels.
- *
- * @return Number of tunnels to remote peers kept by this peer.
- */
-unsigned int
-GCT_count_all (void);
-
-
-/**
- * Iterate all connections of a tunnel.
- *
- * @param t Tunnel whose connections to iterate.
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCT_iterate_connections (struct CadetTunnel *t, GCT_conn_iter iter, void *cls);
-
-
-/**
- * Iterate all channels of a tunnel.
- *
- * @param t Tunnel whose channels to iterate.
- * @param iter Iterator.
- * @param cls Closure for @c iter.
- */
-void
-GCT_iterate_channels (struct CadetTunnel *t,
-                      GCT_chan_iter iter,
-                      void *cls);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CADET_SERVICE_TUNNEL_H */
-#endif
-/* end of gnunet-cadet-service_tunnel.h */
diff --git a/src/cadet/gnunet-service-cadet_tunnels.c b/src/cadet/gnunet-service-cadet_tunnels.c
new file mode 100644 (file)
index 0000000..bcdeeb4
--- /dev/null
@@ -0,0 +1,3440 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2013, 2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/gnunet-service-cadet_tunnels.c
+ * @brief Information we track per tunnel.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * FIXME:
+ * - proper connection evaluation during connection management:
+ *   + consider quality (or quality spread?) of current connection set
+ *     when deciding how often to do maintenance
+ *   + interact with PEER to drive DHT GET/PUT operations based
+ *     on how much we like our connections
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_signatures.h"
+#include "cadet_protocol.h"
+#include "gnunet-service-cadet_channel.h"
+#include "gnunet-service-cadet_connection.h"
+#include "gnunet-service-cadet_tunnels.h"
+#include "gnunet-service-cadet_peer.h"
+#include "gnunet-service-cadet_paths.h"
+
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__)
+
+/**
+ * How often do we try to decrypt payload with unverified key
+ * material?  Used to limit CPU increase upon receiving bogus
+ * KX.
+ */
+#define MAX_UNVERIFIED_ATTEMPTS 16
+
+/**
+ * How long do we wait until tearing down an idle tunnel?
+ */
+#define IDLE_DESTROY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
+
+/**
+ * How long do we wait initially before retransmitting the KX?
+ * TODO: replace by 2 RTT if/once we have connection-level RTT data!
+ */
+#define INITIAL_KX_RETRY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
+
+/**
+ * Maximum number of skipped keys we keep in memory per tunnel.
+ */
+#define MAX_SKIPPED_KEYS 64
+
+/**
+ * Maximum number of keys (and thus ratchet steps) we are willing to
+ * skip before we decide this is either a bogus packet or a DoS-attempt.
+ */
+#define MAX_KEY_GAP 256
+
+
+/**
+ * Struct to old keys for skipped messages while advancing the Axolotl ratchet.
+ */
+struct CadetTunnelSkippedKey
+{
+  /**
+   * DLL next.
+   */
+  struct CadetTunnelSkippedKey *next;
+
+  /**
+   * DLL prev.
+   */
+  struct CadetTunnelSkippedKey *prev;
+
+  /**
+   * When was this key stored (for timeout).
+   */
+  struct GNUNET_TIME_Absolute timestamp;
+
+  /**
+   * Header key.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey HK;
+
+  /**
+   * Message key.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
+
+  /**
+   * Key number for a given HK.
+   */
+  unsigned int Kn;
+};
+
+
+/**
+ * Axolotl data, according to https://github.com/trevp/axolotl/wiki .
+ */
+struct CadetTunnelAxolotl
+{
+  /**
+   * A (double linked) list of stored message keys and associated header keys
+   * for "skipped" messages, i.e. messages that have not been
+   * received despite the reception of more recent messages, (head).
+   */
+  struct CadetTunnelSkippedKey *skipped_head;
+
+  /**
+   * Skipped messages' keys DLL, tail.
+   */
+  struct CadetTunnelSkippedKey *skipped_tail;
+
+  /**
+   * 32-byte root key which gets updated by DH ratchet.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey RK;
+
+  /**
+   * 32-byte header key (currently used for sending).
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey HKs;
+
+  /**
+   * 32-byte header key (currently used for receiving)
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey HKr;
+
+  /**
+   * 32-byte next header key (for sending), used once the
+   * ratchet advances.  We are sure that the sender has this
+   * key as well only after @e ratchet_allowed is #GNUNET_YES.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey NHKs;
+
+  /**
+   * 32-byte next header key (for receiving).  To be tried
+   * when decrypting with @e HKr fails and thus the sender
+   * may have advanced the ratchet.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey NHKr;
+
+  /**
+   * 32-byte chain keys (used for forward-secrecy) for
+   * sending messages. Updated for every message.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey CKs;
+
+  /**
+   * 32-byte chain keys (used for forward-secrecy) for
+   * receiving messages. Updated for every message. If
+   * messages are skipped, the respective derived MKs
+   * (and the current @HKr) are kept in the @e skipped_head DLL.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey CKr;
+
+  /**
+   * ECDH for key exchange (A0 / B0).
+   */
+  struct GNUNET_CRYPTO_EcdhePrivateKey kx_0;
+
+  /**
+   * ECDH Ratchet key (our private key in the current DH).
+   */
+  struct GNUNET_CRYPTO_EcdhePrivateKey DHRs;
+
+  /**
+   * ECDH Ratchet key (other peer's public key in the current DH).
+   */
+  struct GNUNET_CRYPTO_EcdhePublicKey DHRr;
+
+  /**
+   * Time when the current ratchet expires and a new one is triggered
+   * (if @e ratchet_allowed is #GNUNET_YES).
+   */
+  struct GNUNET_TIME_Absolute ratchet_expiration;
+
+  /**
+   * Number of elements in @a skipped_head <-> @a skipped_tail.
+   */
+  unsigned int skipped;
+
+  /**
+   * Message number (reset to 0 with each new ratchet, next message to send).
+   */
+  uint32_t Ns;
+
+  /**
+   * Message number (reset to 0 with each new ratchet, next message to recv).
+   */
+  uint32_t Nr;
+
+  /**
+   * Previous message numbers (# of msgs sent under prev ratchet)
+   */
+  uint32_t PNs;
+
+  /**
+   * True (#GNUNET_YES) if we have to send a new ratchet key in next msg.
+   */
+  int ratchet_flag;
+
+  /**
+   * True (#GNUNET_YES) if we have received a message from the
+   * other peer that uses the keys from our last ratchet step.
+   * This implies that we are again allowed to advance the ratchet,
+   * otherwise we have to wait until the other peer sees our current
+   * ephemeral key and advances first.
+   *
+   * #GNUNET_NO if we have advanced the ratched but lack any evidence
+   * that the other peer has noticed this.
+   */
+  int ratchet_allowed;
+
+  /**
+   * Number of messages recieved since our last ratchet advance.
+   *
+   * If this counter = 0, we cannot send a new ratchet key in the next
+   * message.
+   *
+   * If this counter > 0, we could (but don't have to) send a new key.
+   *
+   * Once the @e ratchet_counter is larger than
+   * #ratchet_messages (or @e ratchet_expiration time has past), and
+   * @e ratchet_allowed is #GNUNET_YES, we advance the ratchet.
+   */
+  unsigned int ratchet_counter;
+
+};
+
+
+/**
+ * Struct used to save messages in a non-ready tunnel to send once connected.
+ */
+struct CadetTunnelQueueEntry
+{
+  /**
+   * We are entries in a DLL
+   */
+  struct CadetTunnelQueueEntry *next;
+
+  /**
+   * We are entries in a DLL
+   */
+  struct CadetTunnelQueueEntry *prev;
+
+  /**
+   * Tunnel these messages belong in.
+   */
+  struct CadetTunnel *t;
+
+  /**
+   * Continuation to call once sent (on the channel layer).
+   */
+  GCT_SendContinuation cont;
+
+  /**
+   * Closure for @c cont.
+   */
+  void *cont_cls;
+
+  /**
+   * Envelope of message to send follows.
+   */
+  struct GNUNET_MQ_Envelope *env;
+
+  /**
+   * Where to put the connection identifier into the payload
+   * of the message in @e env once we have it?
+   */
+  struct GNUNET_CADET_ConnectionTunnelIdentifier *cid;
+};
+
+
+/**
+ * Struct containing all information regarding a tunnel to a peer.
+ */
+struct CadetTunnel
+{
+  /**
+   * Destination of the tunnel.
+   */
+  struct CadetPeer *destination;
+
+  /**
+   * Peer's ephemeral key, to recreate @c e_key and @c d_key when own
+   * ephemeral key changes.
+   */
+  struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key;
+
+  /**
+   * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
+
+  /**
+   * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL.
+   */
+  struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
+
+  /**
+   * Axolotl info.
+   */
+  struct CadetTunnelAxolotl ax;
+
+  /**
+   * Unverified Axolotl info, used only if we got a fresh KX (not a
+   * KX_AUTH) while our end of the tunnel was still up.  In this case,
+   * we keep the fresh KX around but do not put it into action until
+   * we got encrypted payload that assures us of the authenticity of
+   * the KX.
+   */
+  struct CadetTunnelAxolotl *unverified_ax;
+
+  /**
+   * Task scheduled if there are no more channels using the tunnel.
+   */
+  struct GNUNET_SCHEDULER_Task *destroy_task;
+
+  /**
+   * Task to trim connections if too many are present.
+   */
+  struct GNUNET_SCHEDULER_Task *maintain_connections_task;
+
+  /**
+   * Task to send messages from queue (if possible).
+   */
+  struct GNUNET_SCHEDULER_Task *send_task;
+
+  /**
+   * Task to trigger KX.
+   */
+  struct GNUNET_SCHEDULER_Task *kx_task;
+
+  /**
+   * Tokenizer for decrypted messages.
+   */
+  struct GNUNET_MessageStreamTokenizer *mst;
+
+  /**
+   * Dispatcher for decrypted messages only (do NOT use for sending!).
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * DLL of ready connections that are actively used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_ready_head;
+
+  /**
+   * DLL of ready connections that are actively used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_ready_tail;
+
+  /**
+   * DLL of connections that we maintain that might be used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_busy_head;
+
+  /**
+   * DLL of connections that we maintain that might be used to reach the destination peer.
+   */
+  struct CadetTConnection *connection_busy_tail;
+
+  /**
+   * Channels inside this tunnel. Maps
+   * `struct GNUNET_CADET_ChannelTunnelNumber` to a `struct CadetChannel`.
+   */
+  struct GNUNET_CONTAINER_MultiHashMap32 *channels;
+
+  /**
+   * Channel ID for the next created channel in this tunnel.
+   */
+  struct GNUNET_CADET_ChannelTunnelNumber next_ctn;
+
+  /**
+   * Queued messages, to transmit once tunnel gets connected.
+   */
+  struct CadetTunnelQueueEntry *tq_head;
+
+  /**
+   * Queued messages, to transmit once tunnel gets connected.
+   */
+  struct CadetTunnelQueueEntry *tq_tail;
+
+  /**
+   * Identification of the connection from which we are currently processing
+   * a message. Only valid (non-NULL) during #handle_decrypted() and the
+   * handle-*()-functions called from our @e mq during that function.
+   */
+  struct CadetTConnection *current_ct;
+
+  /**
+   * How long do we wait until we retry the KX?
+   */
+  struct GNUNET_TIME_Relative kx_retry_delay;
+
+  /**
+   * When do we try the next KX?
+   */
+  struct GNUNET_TIME_Absolute next_kx_attempt;
+
+  /**
+   * Number of connections in the @e connection_ready_head DLL.
+   */
+  unsigned int num_ready_connections;
+
+  /**
+   * Number of connections in the @e connection_busy_head DLL.
+   */
+  unsigned int num_busy_connections;
+
+  /**
+   * How often have we tried and failed to decrypt a message using
+   * the unverified KX material from @e unverified_ax?  Used to
+   * stop trying after #MAX_UNVERIFIED_ATTEMPTS.
+   */
+  unsigned int unverified_attempts;
+
+  /**
+   * Number of entries in the @e tq_head DLL.
+   */
+  unsigned int tq_len;
+
+  /**
+   * State of the tunnel encryption.
+   */
+  enum CadetTunnelEState estate;
+
+  /**
+   * Force triggering KX_AUTH independent of @e estate.
+   */
+  int kx_auth_requested;
+
+};
+
+
+/**
+ * Connection @a ct is now unready, clear it's ready flag
+ * and move it from the ready DLL to the busy DLL.
+ *
+ * @param ct connection to move to unready status
+ */
+static void
+mark_connection_unready (struct CadetTConnection *ct)
+{
+  struct CadetTunnel *t = ct->t;
+
+  GNUNET_assert (GNUNET_YES == ct->is_ready);
+  GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
+                               t->connection_ready_tail,
+                               ct);
+  GNUNET_assert (0 < t->num_ready_connections);
+  t->num_ready_connections--;
+  ct->is_ready = GNUNET_NO;
+  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
+                               t->connection_busy_tail,
+                               ct);
+  t->num_busy_connections++;
+}
+
+
+/**
+ * Get the static string for the peer this tunnel is directed.
+ *
+ * @param t Tunnel.
+ *
+ * @return Static string the destination peer's ID.
+ */
+const char *
+GCT_2s (const struct CadetTunnel *t)
+{
+  static char buf[64];
+
+  if (NULL == t)
+    return "Tunnel(NULL)";
+  GNUNET_snprintf (buf,
+                   sizeof (buf),
+                   "Tunnel %s",
+                   GNUNET_i2s (GCP_get_id (t->destination)));
+  return buf;
+}
+
+
+/**
+ * Get string description for tunnel encryption state.
+ *
+ * @param es Tunnel state.
+ *
+ * @return String representation.
+ */
+static const char *
+estate2s (enum CadetTunnelEState es)
+{
+  static char buf[32];
+
+  switch (es)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+    return "CADET_TUNNEL_KEY_UNINITIALIZED";
+  case CADET_TUNNEL_KEY_AX_RECV:
+    return "CADET_TUNNEL_KEY_AX_RECV";
+  case CADET_TUNNEL_KEY_AX_SENT:
+    return "CADET_TUNNEL_KEY_AX_SENT";
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+    return "CADET_TUNNEL_KEY_AX_SENT_AND_RECV";
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    return "CADET_TUNNEL_KEY_AX_AUTH_SENT";
+  case CADET_TUNNEL_KEY_OK:
+    return "CADET_TUNNEL_KEY_OK";
+  default:
+    GNUNET_snprintf (buf,
+                     sizeof (buf),
+                     "%u (UNKNOWN STATE)",
+                     es);
+    return buf;
+  }
+}
+
+
+/**
+ * Return the peer to which this tunnel goes.
+ *
+ * @param t a tunnel
+ * @return the destination of the tunnel
+ */
+struct CadetPeer *
+GCT_get_destination (struct CadetTunnel *t)
+{
+  return t->destination;
+}
+
+
+/**
+ * Count channels of a tunnel.
+ *
+ * @param t Tunnel on which to count.
+ *
+ * @return Number of channels.
+ */
+unsigned int
+GCT_count_channels (struct CadetTunnel *t)
+{
+  return GNUNET_CONTAINER_multihashmap32_size (t->channels);
+}
+
+
+/**
+ * Lookup a channel by its @a ctn.
+ *
+ * @param t tunnel to look in
+ * @param ctn number of channel to find
+ * @return NULL if channel does not exist
+ */
+struct CadetChannel *
+lookup_channel (struct CadetTunnel *t,
+                struct GNUNET_CADET_ChannelTunnelNumber ctn)
+{
+  return GNUNET_CONTAINER_multihashmap32_get (t->channels,
+                                              ntohl (ctn.cn));
+}
+
+
+/**
+ * Count all created connections of a tunnel. Not necessarily ready connections!
+ *
+ * @param t Tunnel on which to count.
+ *
+ * @return Number of connections created, either being established or ready.
+ */
+unsigned int
+GCT_count_any_connections (const struct CadetTunnel *t)
+{
+  return t->num_ready_connections + t->num_busy_connections;
+}
+
+
+/**
+ * Find first connection that is ready in the list of
+ * our connections.  Picks ready connections round-robin.
+ *
+ * @param t tunnel to search
+ * @return NULL if we have no connection that is ready
+ */
+static struct CadetTConnection *
+get_ready_connection (struct CadetTunnel *t)
+{
+  struct CadetTConnection *hd = t->connection_ready_head;
+
+  GNUNET_assert ( (NULL == hd) ||
+                  (GNUNET_YES == hd->is_ready) );
+  return hd;
+}
+
+
+/**
+ * Get the encryption state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's encryption state.
+ */
+enum CadetTunnelEState
+GCT_get_estate (struct CadetTunnel *t)
+{
+  return t->estate;
+}
+
+
+/**
+ * Called when either we have a new connection, or a new message in the
+ * queue, or some existing connection has transmission capacity.  Looks
+ * at our message queue and if there is a message, picks a connection
+ * to send it on.
+ *
+ * @param cls the `struct CadetTunnel` to process messages on
+ */
+static void
+trigger_transmissions (void *cls);
+
+
+/* ************************************** start core crypto ***************************** */
+
+
+/**
+ * Create a new Axolotl ephemeral (ratchet) key.
+ *
+ * @param ax key material to update
+ */
+static void
+new_ephemeral (struct CadetTunnelAxolotl *ax)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating new ephemeral ratchet key (DHRs)\n");
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CRYPTO_ecdhe_key_create2 (&ax->DHRs));
+}
+
+
+/**
+ * Calculate HMAC.
+ *
+ * @param plaintext Content to HMAC.
+ * @param size Size of @c plaintext.
+ * @param iv Initialization vector for the message.
+ * @param key Key to use.
+ * @param hmac[out] Destination to store the HMAC.
+ */
+static void
+t_hmac (const void *plaintext,
+        size_t size,
+        uint32_t iv,
+        const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+        struct GNUNET_ShortHashCode *hmac)
+{
+  static const char ctx[] = "cadet authentication key";
+  struct GNUNET_CRYPTO_AuthKey auth_key;
+  struct GNUNET_HashCode hash;
+
+  GNUNET_CRYPTO_hmac_derive_key (&auth_key,
+                                 key,
+                                 &iv, sizeof (iv),
+                                 key, sizeof (*key),
+                                 ctx, sizeof (ctx),
+                                 NULL);
+  /* Two step: GNUNET_ShortHash is only 256 bits,
+     GNUNET_HashCode is 512, so we truncate. */
+  GNUNET_CRYPTO_hmac (&auth_key,
+                      plaintext,
+                      size,
+                      &hash);
+  GNUNET_memcpy (hmac,
+                 &hash,
+                 sizeof (*hmac));
+}
+
+
+/**
+ * Perform a HMAC.
+ *
+ * @param key Key to use.
+ * @param[out] hash Resulting HMAC.
+ * @param source Source key material (data to HMAC).
+ * @param len Length of @a source.
+ */
+static void
+t_ax_hmac_hash (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+                struct GNUNET_HashCode *hash,
+                const void *source,
+                unsigned int len)
+{
+  static const char ctx[] = "axolotl HMAC-HASH";
+  struct GNUNET_CRYPTO_AuthKey auth_key;
+
+  GNUNET_CRYPTO_hmac_derive_key (&auth_key,
+                                 key,
+                                 ctx, sizeof (ctx),
+                                 NULL);
+  GNUNET_CRYPTO_hmac (&auth_key,
+                      source,
+                      len,
+                      hash);
+}
+
+
+/**
+ * Derive a symmetric encryption key from an HMAC-HASH.
+ *
+ * @param key Key to use for the HMAC.
+ * @param[out] out Key to generate.
+ * @param source Source key material (data to HMAC).
+ * @param len Length of @a source.
+ */
+static void
+t_hmac_derive_key (const struct GNUNET_CRYPTO_SymmetricSessionKey *key,
+                   struct GNUNET_CRYPTO_SymmetricSessionKey *out,
+                   const void *source,
+                   unsigned int len)
+{
+  static const char ctx[] = "axolotl derive key";
+  struct GNUNET_HashCode h;
+
+  t_ax_hmac_hash (key,
+                  &h,
+                  source,
+                  len);
+  GNUNET_CRYPTO_kdf (out, sizeof (*out),
+                     ctx, sizeof (ctx),
+                     &h, sizeof (h),
+                     NULL);
+}
+
+
+/**
+ * Encrypt data with the axolotl tunnel key.
+ *
+ * @param ax key material to use.
+ * @param dst Destination with @a size bytes for the encrypted data.
+ * @param src Source of the plaintext. Can overlap with @c dst, must contain @a size bytes
+ * @param size Size of the buffers at @a src and @a dst
+ */
+static void
+t_ax_encrypt (struct CadetTunnelAxolotl *ax,
+              void *dst,
+              const void *src,
+              size_t size)
+{
+  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  size_t out_size;
+
+  ax->ratchet_counter++;
+  if ( (GNUNET_YES == ax->ratchet_allowed) &&
+       ( (ratchet_messages <= ax->ratchet_counter) ||
+         (0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us)) )
+  {
+    ax->ratchet_flag = GNUNET_YES;
+  }
+  if (GNUNET_YES == ax->ratchet_flag)
+  {
+    /* Advance ratchet */
+    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3];
+    struct GNUNET_HashCode dh;
+    struct GNUNET_HashCode hmac;
+    static const char ctx[] = "axolotl ratchet";
+
+    new_ephemeral (ax);
+    ax->HKs = ax->NHKs;
+
+    /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */
+    GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
+                            &ax->DHRr,
+                            &dh);
+    t_ax_hmac_hash (&ax->RK,
+                    &hmac,
+                    &dh,
+                    sizeof (dh));
+    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
+                       ctx, sizeof (ctx),
+                       &hmac, sizeof (hmac),
+                       NULL);
+    ax->RK = keys[0];
+    ax->NHKs = keys[1];
+    ax->CKs = keys[2];
+
+    ax->PNs = ax->Ns;
+    ax->Ns = 0;
+    ax->ratchet_flag = GNUNET_NO;
+    ax->ratchet_allowed = GNUNET_NO;
+    ax->ratchet_counter = 0;
+    ax->ratchet_expiration
+      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
+                                  ratchet_time);
+  }
+
+  t_hmac_derive_key (&ax->CKs,
+                     &MK,
+                     "0",
+                     1);
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &MK,
+                                     NULL, 0,
+                                     NULL);
+
+  out_size = GNUNET_CRYPTO_symmetric_encrypt (src,
+                                              size,
+                                              &MK,
+                                              &iv,
+                                              dst);
+  GNUNET_assert (size == out_size);
+  t_hmac_derive_key (&ax->CKs,
+                     &ax->CKs,
+                     "1",
+                     1);
+}
+
+
+/**
+ * Decrypt data with the axolotl tunnel key.
+ *
+ * @param ax key material to use.
+ * @param dst Destination for the decrypted data, must contain @a size bytes.
+ * @param src Source of the ciphertext. Can overlap with @c dst, must contain @a size bytes.
+ * @param size Size of the @a src and @a dst buffers
+ */
+static void
+t_ax_decrypt (struct CadetTunnelAxolotl *ax,
+              void *dst,
+              const void *src,
+              size_t size)
+{
+  struct GNUNET_CRYPTO_SymmetricSessionKey MK;
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  size_t out_size;
+
+  t_hmac_derive_key (&ax->CKr,
+                     &MK,
+                     "0",
+                     1);
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &MK,
+                                     NULL, 0,
+                                     NULL);
+  GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
+  out_size = GNUNET_CRYPTO_symmetric_decrypt (src,
+                                              size,
+                                              &MK,
+                                              &iv,
+                                              dst);
+  GNUNET_assert (out_size == size);
+  t_hmac_derive_key (&ax->CKr,
+                     &ax->CKr,
+                     "1",
+                     1);
+}
+
+
+/**
+ * Encrypt header with the axolotl header key.
+ *
+ * @param ax key material to use.
+ * @param[in|out] msg Message whose header to encrypt.
+ */
+static void
+t_h_encrypt (struct CadetTunnelAxolotl *ax,
+             struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+{
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  size_t out_size;
+
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &ax->HKs,
+                                     NULL, 0,
+                                     NULL);
+  out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->ax_header,
+                                              sizeof (struct GNUNET_CADET_AxHeader),
+                                              &ax->HKs,
+                                              &iv,
+                                              &msg->ax_header);
+  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
+}
+
+
+/**
+ * Decrypt header with the current axolotl header key.
+ *
+ * @param ax key material to use.
+ * @param src Message whose header to decrypt.
+ * @param dst Where to decrypt header to.
+ */
+static void
+t_h_decrypt (struct CadetTunnelAxolotl *ax,
+             const struct GNUNET_CADET_TunnelEncryptedMessage *src,
+             struct GNUNET_CADET_TunnelEncryptedMessage *dst)
+{
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  size_t out_size;
+
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &ax->HKr,
+                                     NULL, 0,
+                                     NULL);
+  out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
+                                              sizeof (struct GNUNET_CADET_AxHeader),
+                                              &ax->HKr,
+                                              &iv,
+                                              &dst->ax_header.Ns);
+  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == out_size);
+}
+
+
+/**
+ * Delete a key from the list of skipped keys.
+ *
+ * @param ax key material to delete @a key from.
+ * @param key Key to delete.
+ */
+static void
+delete_skipped_key (struct CadetTunnelAxolotl *ax,
+                    struct CadetTunnelSkippedKey *key)
+{
+  GNUNET_CONTAINER_DLL_remove (ax->skipped_head,
+                               ax->skipped_tail,
+                               key);
+  GNUNET_free (key);
+  ax->skipped--;
+}
+
+
+/**
+ * Decrypt and verify data with the appropriate tunnel key and verify that the
+ * data has not been altered since it was sent by the remote peer.
+ *
+ * @param ax key material to use.
+ * @param dst Destination for the plaintext.
+ * @param src Source of the message. Can overlap with @c dst.
+ * @param size Size of the message.
+ * @return Size of the decrypted data, -1 if an error was encountered.
+ */
+static ssize_t
+try_old_ax_keys (struct CadetTunnelAxolotl *ax,
+                 void *dst,
+                 const struct GNUNET_CADET_TunnelEncryptedMessage *src,
+                 size_t size)
+{
+  struct CadetTunnelSkippedKey *key;
+  struct GNUNET_ShortHashCode *hmac;
+  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
+  struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK;
+  size_t esize;
+  size_t res;
+  size_t len;
+  unsigned int N;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying skipped keys\n");
+  hmac = &plaintext_header.hmac;
+  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
+
+  /* Find a correct Header Key */
+  valid_HK = NULL;
+  for (key = ax->skipped_head; NULL != key; key = key->next)
+  {
+    t_hmac (&src->ax_header,
+            sizeof (struct GNUNET_CADET_AxHeader) + esize,
+            0,
+            &key->HK,
+            hmac);
+    if (0 == memcmp (hmac,
+                     &src->hmac,
+                     sizeof (*hmac)))
+    {
+      valid_HK = &key->HK;
+      break;
+    }
+  }
+  if (NULL == key)
+    return -1;
+
+  /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */
+  GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage));
+  len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
+  GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader));
+
+  /* Decrypt header */
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &key->HK,
+                                     NULL, 0,
+                                     NULL);
+  res = GNUNET_CRYPTO_symmetric_decrypt (&src->ax_header.Ns,
+                                         sizeof (struct GNUNET_CADET_AxHeader),
+                                         &key->HK,
+                                         &iv,
+                                         &plaintext_header.ax_header.Ns);
+  GNUNET_assert (sizeof (struct GNUNET_CADET_AxHeader) == res);
+
+  /* Find the correct message key */
+  N = ntohl (plaintext_header.ax_header.Ns);
+  while ( (NULL != key) &&
+          (N != key->Kn) )
+    key = key->next;
+  if ( (NULL == key) ||
+       (0 != memcmp (&key->HK,
+                     valid_HK,
+                     sizeof (*valid_HK))) )
+    return -1;
+
+  /* Decrypt payload */
+  GNUNET_CRYPTO_symmetric_derive_iv (&iv,
+                                     &key->MK,
+                                     NULL,
+                                     0,
+                                     NULL);
+  res = GNUNET_CRYPTO_symmetric_decrypt (&src[1],
+                                         len,
+                                         &key->MK,
+                                         &iv,
+                                         dst);
+  delete_skipped_key (ax,
+                      key);
+  return res;
+}
+
+
+/**
+ * Delete a key from the list of skipped keys.
+ *
+ * @param ax key material to delete from.
+ * @param HKr Header Key to use.
+ */
+static void
+store_skipped_key (struct CadetTunnelAxolotl *ax,
+                   const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr)
+{
+  struct CadetTunnelSkippedKey *key;
+
+  key = GNUNET_new (struct CadetTunnelSkippedKey);
+  key->timestamp = GNUNET_TIME_absolute_get ();
+  key->Kn = ax->Nr;
+  key->HK = ax->HKr;
+  t_hmac_derive_key (&ax->CKr,
+                     &key->MK,
+                     "0",
+                     1);
+  t_hmac_derive_key (&ax->CKr,
+                     &ax->CKr,
+                     "1",
+                     1);
+  GNUNET_CONTAINER_DLL_insert (ax->skipped_head,
+                               ax->skipped_tail,
+                               key);
+  ax->skipped++;
+  ax->Nr++;
+}
+
+
+/**
+ * Stage skipped AX keys and calculate the message key.
+ * Stores each HK and MK for skipped messages.
+ *
+ * @param ax key material to use
+ * @param HKr Header key.
+ * @param Np Received meesage number.
+ * @return #GNUNET_OK if keys were stored.
+ *         #GNUNET_SYSERR if an error ocurred (@a Np not expected).
+ */
+static int
+store_ax_keys (struct CadetTunnelAxolotl *ax,
+               const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr,
+               uint32_t Np)
+{
+  int gap;
+
+  gap = Np - ax->Nr;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Storing skipped keys [%u, %u)\n",
+       ax->Nr,
+       Np);
+  if (MAX_KEY_GAP < gap)
+  {
+    /* Avoid DoS (forcing peer to do more than #MAX_KEY_GAP HMAC operations) */
+    /* TODO: start new key exchange on return */
+    GNUNET_break_op (0);
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Got message %u, expected %u+\n",
+         Np,
+         ax->Nr);
+    return GNUNET_SYSERR;
+  }
+  if (0 > gap)
+  {
+    /* Delayed message: don't store keys, flag to try old keys. */
+    return GNUNET_SYSERR;
+  }
+
+  while (ax->Nr < Np)
+    store_skipped_key (ax,
+                       HKr);
+
+  while (ax->skipped > MAX_SKIPPED_KEYS)
+    delete_skipped_key (ax,
+                        ax->skipped_tail);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Decrypt and verify data with the appropriate tunnel key and verify that the
+ * data has not been altered since it was sent by the remote peer.
+ *
+ * @param ax key material to use
+ * @param dst Destination for the plaintext.
+ * @param src Source of the message. Can overlap with @c dst.
+ * @param size Size of the message.
+ * @return Size of the decrypted data, -1 if an error was encountered.
+ */
+static ssize_t
+t_ax_decrypt_and_validate (struct CadetTunnelAxolotl *ax,
+                           void *dst,
+                           const struct GNUNET_CADET_TunnelEncryptedMessage *src,
+                           size_t size)
+{
+  struct GNUNET_ShortHashCode msg_hmac;
+  struct GNUNET_HashCode hmac;
+  struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header;
+  uint32_t Np;
+  uint32_t PNp;
+  size_t esize; /* Size of encryped payload */
+
+  esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage);
+
+  /* Try current HK */
+  t_hmac (&src->ax_header,
+          sizeof (struct GNUNET_CADET_AxHeader) + esize,
+          0, &ax->HKr,
+          &msg_hmac);
+  if (0 != memcmp (&msg_hmac,
+                   &src->hmac,
+                   sizeof (msg_hmac)))
+  {
+    static const char ctx[] = "axolotl ratchet";
+    struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */
+    struct GNUNET_CRYPTO_SymmetricSessionKey HK;
+    struct GNUNET_HashCode dh;
+    struct GNUNET_CRYPTO_EcdhePublicKey *DHRp;
+
+    /* Try Next HK */
+    t_hmac (&src->ax_header,
+            sizeof (struct GNUNET_CADET_AxHeader) + esize,
+            0,
+            &ax->NHKr,
+            &msg_hmac);
+    if (0 != memcmp (&msg_hmac,
+                     &src->hmac,
+                     sizeof (msg_hmac)))
+    {
+      /* Try the skipped keys, if that fails, we're out of luck. */
+      return try_old_ax_keys (ax,
+                              dst,
+                              src,
+                              size);
+    }
+    HK = ax->HKr;
+    ax->HKr = ax->NHKr;
+    t_h_decrypt (ax,
+                 src,
+                 &plaintext_header);
+    Np = ntohl (plaintext_header.ax_header.Ns);
+    PNp = ntohl (plaintext_header.ax_header.PNs);
+    DHRp = &plaintext_header.ax_header.DHRs;
+    store_ax_keys (ax,
+                   &HK,
+                   PNp);
+
+    /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */
+    GNUNET_CRYPTO_ecc_ecdh (&ax->DHRs,
+                            DHRp,
+                            &dh);
+    t_ax_hmac_hash (&ax->RK,
+                    &hmac,
+                    &dh, sizeof (dh));
+    GNUNET_CRYPTO_kdf (keys, sizeof (keys),
+                       ctx, sizeof (ctx),
+                       &hmac, sizeof (hmac),
+                       NULL);
+
+    /* Commit "purported" keys */
+    ax->RK = keys[0];
+    ax->NHKr = keys[1];
+    ax->CKr = keys[2];
+    ax->DHRr = *DHRp;
+    ax->Nr = 0;
+    ax->ratchet_allowed = GNUNET_YES;
+  }
+  else
+  {
+    t_h_decrypt (ax,
+                 src,
+                 &plaintext_header);
+    Np = ntohl (plaintext_header.ax_header.Ns);
+    PNp = ntohl (plaintext_header.ax_header.PNs);
+  }
+  if ( (Np != ax->Nr) &&
+       (GNUNET_OK != store_ax_keys (ax,
+                                    &ax->HKr,
+                                    Np)) )
+  {
+    /* Try the skipped keys, if that fails, we're out of luck. */
+    return try_old_ax_keys (ax,
+                            dst,
+                            src,
+                            size);
+  }
+
+  t_ax_decrypt (ax,
+                dst,
+                &src[1],
+                esize);
+  ax->Nr = Np + 1;
+  return esize;
+}
+
+
+/**
+ * Our tunnel became ready for the first time, notify channels
+ * that have been waiting.
+ *
+ * @param cls our tunnel, not used
+ * @param key unique ID of the channel, not used
+ * @param value the `struct CadetChannel` to notify
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+notify_tunnel_up_cb (void *cls,
+                     uint32_t key,
+                     void *value)
+{
+  struct CadetChannel *ch = value;
+
+  GCCH_tunnel_up (ch);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Change the tunnel encryption state.
+ * If the encryption state changes to OK, stop the rekey task.
+ *
+ * @param t Tunnel whose encryption state to change, or NULL.
+ * @param state New encryption state.
+ */
+void
+GCT_change_estate (struct CadetTunnel *t,
+                   enum CadetTunnelEState state)
+{
+  enum CadetTunnelEState old = t->estate;
+
+  t->estate = state;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s estate changed from %s to %s\n",
+       GCT_2s (t),
+       estate2s (old),
+       estate2s (state));
+
+  if ( (CADET_TUNNEL_KEY_OK != old) &&
+       (CADET_TUNNEL_KEY_OK == t->estate) )
+  {
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    /* notify all channels that have been waiting */
+    GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                             &notify_tunnel_up_cb,
+                                             t);
+    if (NULL != t->send_task)
+      GNUNET_SCHEDULER_cancel (t->send_task);
+    t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
+                                             t);
+  }
+}
+
+
+/**
+ * Send a KX message.
+ *
+ * @param t tunnel on which to send the KX_AUTH
+ * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
+ *           we are to find one that is ready.
+ * @param ax axolotl key context to use
+ */
+static void
+send_kx (struct CadetTunnel *t,
+         struct CadetTConnection *ct,
+         struct CadetTunnelAxolotl *ax)
+{
+  struct CadetConnection *cc;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_TunnelKeyExchangeMessage *msg;
+  enum GNUNET_CADET_KX_Flags flags;
+
+  if ( (NULL == ct) ||
+       (GNUNET_NO == ct->is_ready) )
+    ct = get_ready_connection (t);
+  if (NULL == ct)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Wanted to send %s in state %s, but no connection is ready, deferring\n",
+         GCT_2s (t),
+         estate2s (t->estate));
+    t->next_kx_attempt = GNUNET_TIME_absolute_get ();
+    return;
+  }
+  cc = ct->cc;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending KX on %s via %s in state %s\n",
+       GCT_2s (t),
+       GCC_2s (cc),
+       estate2s (t->estate));
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX);
+  flags = GNUNET_CADET_KX_FLAG_FORCE_REPLY; /* always for KX */
+  msg->flags = htonl (flags);
+  msg->cid = *GCC_get_id (cc);
+  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
+                                      &msg->ephemeral_key);
+  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
+                                      &msg->ratchet_key);
+  mark_connection_unready (ct);
+  t->kx_retry_delay = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
+  t->next_kx_attempt = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
+  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_SENT);
+  else if (CADET_TUNNEL_KEY_AX_RECV == t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
+  GCC_transmit (cc,
+                env);
+}
+
+
+/**
+ * Send a KX_AUTH message.
+ *
+ * @param t tunnel on which to send the KX_AUTH
+ * @param ct Tunnel and connection on which to send the KX_AUTH, NULL if
+ *           we are to find one that is ready.
+ * @param ax axolotl key context to use
+ * @param force_reply Force the other peer to reply with a KX_AUTH message
+ *         (set if we would like to transmit right now, but cannot)
+ */
+static void
+send_kx_auth (struct CadetTunnel *t,
+              struct CadetTConnection *ct,
+              struct CadetTunnelAxolotl *ax,
+              int force_reply)
+{
+  struct CadetConnection *cc;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg;
+  enum GNUNET_CADET_KX_Flags flags;
+
+  if ( (NULL == ct) ||
+       (GNUNET_NO == ct->is_ready) )
+    ct = get_ready_connection (t);
+  if (NULL == ct)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Wanted to send KX_AUTH on %s, but no connection is ready, deferring\n",
+         GCT_2s (t));
+    t->next_kx_attempt = GNUNET_TIME_absolute_get ();
+    t->kx_auth_requested = GNUNET_YES; /* queue KX_AUTH independent of estate */
+    return;
+  }
+  t->kx_auth_requested = GNUNET_NO; /* clear flag */
+  cc = ct->cc;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending KX_AUTH on %s using %s\n",
+       GCT_2s (t),
+       GCC_2s (ct->cc));
+
+  env = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX_AUTH);
+  flags = GNUNET_CADET_KX_FLAG_NONE;
+  if (GNUNET_YES == force_reply)
+    flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY;
+  msg->kx.flags = htonl (flags);
+  msg->kx.cid = *GCC_get_id (cc);
+  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->kx_0,
+                                      &msg->kx.ephemeral_key);
+  GNUNET_CRYPTO_ecdhe_key_get_public (&ax->DHRs,
+                                      &msg->kx.ratchet_key);
+  /* Compute authenticator (this is the main difference to #send_kx()) */
+  GNUNET_CRYPTO_hash (&ax->RK,
+                      sizeof (ax->RK),
+                      &msg->auth);
+
+  /* Compute when to be triggered again; actual job will
+     be scheduled via #connection_ready_cb() */
+  t->kx_retry_delay
+    = GNUNET_TIME_STD_BACKOFF (t->kx_retry_delay);
+  t->next_kx_attempt
+    = GNUNET_TIME_relative_to_absolute (t->kx_retry_delay);
+
+  /* Send via cc, mark it as unready */
+  mark_connection_unready (ct);
+
+  /* Update state machine, unless we are already OK */
+  if (CADET_TUNNEL_KEY_OK != t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_AUTH_SENT);
+
+  GCC_transmit (cc,
+                env);
+}
+
+
+/**
+ * Cleanup state used by @a ax.
+ *
+ * @param ax state to free, but not memory of @a ax itself
+ */
+static void
+cleanup_ax (struct CadetTunnelAxolotl *ax)
+{
+  while (NULL != ax->skipped_head)
+    delete_skipped_key (ax,
+                        ax->skipped_head);
+  GNUNET_assert (0 == ax->skipped);
+  GNUNET_CRYPTO_ecdhe_key_clear (&ax->kx_0);
+  GNUNET_CRYPTO_ecdhe_key_clear (&ax->DHRs);
+}
+
+
+/**
+ * Update our Axolotl key state based on the KX data we received.
+ * Computes the new chain keys, and root keys, etc, and also checks
+ * wether this is a replay of the current chain.
+ *
+ * @param[in|out] axolotl chain key state to recompute
+ * @param pid peer identity of the other peer
+ * @param ephemeral_key ephemeral public key of the other peer
+ * @param ratchet_key senders next ephemeral public key
+ * @return #GNUNET_OK on success, #GNUNET_NO if the resulting
+ *       root key is already in @a ax and thus the KX is useless;
+ *       #GNUNET_SYSERR on hard errors (i.e. @a pid is #my_full_id)
+ */
+static int
+update_ax_by_kx (struct CadetTunnelAxolotl *ax,
+                 const struct GNUNET_PeerIdentity *pid,
+                 const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral_key,
+                 const struct GNUNET_CRYPTO_EcdhePublicKey *ratchet_key)
+{
+  struct GNUNET_HashCode key_material[3];
+  struct GNUNET_CRYPTO_SymmetricSessionKey keys[5];
+  const char salt[] = "CADET Axolotl salt";
+  int am_I_alice;
+
+  if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+                                           pid))
+    am_I_alice = GNUNET_YES;
+  else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+                                                pid))
+    am_I_alice = GNUNET_NO;
+  else
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+
+  if (0 == memcmp (&ax->DHRr,
+                   ratchet_key,
+                   sizeof (*ratchet_key)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ratchet key already known. Ignoring KX.\n");
+    return GNUNET_NO;
+  }
+
+  ax->DHRr = *ratchet_key;
+
+  /* ECDH A B0 */
+  if (GNUNET_YES == am_I_alice)
+  {
+    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
+                              ephemeral_key, /* B0 */
+                              &key_material[0]);
+  }
+  else
+  {
+    GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0,            /* B0 */
+                              &pid->public_key,    /* A */
+                              &key_material[0]);
+  }
+
+  /* ECDH A0 B */
+  if (GNUNET_YES == am_I_alice)
+  {
+    GNUNET_CRYPTO_ecdh_eddsa (&ax->kx_0,            /* A0 */
+                              &pid->public_key,    /* B */
+                              &key_material[1]);
+  }
+  else
+  {
+    GNUNET_CRYPTO_eddsa_ecdh (my_private_key,      /* A */
+                              ephemeral_key, /* B0 */
+                              &key_material[1]);
+
+
+  }
+
+  /* ECDH A0 B0 */
+  /* (This is the triple-DH, we could probably safely skip this,
+     as A0/B0 are already in the key material.) */
+  GNUNET_CRYPTO_ecc_ecdh (&ax->kx_0,             /* A0 or B0 */
+                          ephemeral_key,  /* B0 or A0 */
+                          &key_material[2]);
+
+  /* KDF */
+  GNUNET_CRYPTO_kdf (keys, sizeof (keys),
+                     salt, sizeof (salt),
+                     &key_material, sizeof (key_material),
+                     NULL);
+
+  if (0 == memcmp (&ax->RK,
+                   &keys[0],
+                   sizeof (ax->RK)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Root key of handshake already known. Ignoring KX.\n");
+    return GNUNET_NO;
+  }
+
+  ax->RK = keys[0];
+  if (GNUNET_YES == am_I_alice)
+  {
+    ax->HKr = keys[1];
+    ax->NHKs = keys[2];
+    ax->NHKr = keys[3];
+    ax->CKr = keys[4];
+    ax->ratchet_flag = GNUNET_YES;
+  }
+  else
+  {
+    ax->HKs = keys[1];
+    ax->NHKr = keys[2];
+    ax->NHKs = keys[3];
+    ax->CKs = keys[4];
+    ax->ratchet_flag = GNUNET_NO;
+    ax->ratchet_expiration
+      = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
+                                  ratchet_time);
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Try to redo the KX or KX_AUTH handshake, if we can.
+ *
+ * @param cls the `struct CadetTunnel` to do KX for.
+ */
+static void
+retry_kx (void *cls)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetTunnelAxolotl *ax;
+
+  t->kx_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying to make KX progress on %s in state %s\n",
+       GCT_2s (t),
+       estate2s (t->estate));
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED: /* first attempt */
+  case CADET_TUNNEL_KEY_AX_SENT:       /* trying again */
+    send_kx (t,
+             NULL,
+             &t->ax);
+    break;
+  case CADET_TUNNEL_KEY_AX_RECV:
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+    /* We are responding, so only require reply
+       if WE have a channel waiting. */
+    if (NULL != t->unverified_ax)
+    {
+      /* Send AX_AUTH so we might get this one verified */
+      ax = t->unverified_ax;
+    }
+    else
+    {
+      /* How can this be? */
+      GNUNET_break (0);
+      ax = &t->ax;
+    }
+    send_kx_auth (t,
+                  NULL,
+                  ax,
+                  (0 == GCT_count_channels (t))
+                  ? GNUNET_NO
+                  : GNUNET_YES);
+    break;
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    /* We are responding, so only require reply
+       if WE have a channel waiting. */
+    if (NULL != t->unverified_ax)
+    {
+      /* Send AX_AUTH so we might get this one verified */
+      ax = t->unverified_ax;
+    }
+    else
+    {
+      /* How can this be? */
+      GNUNET_break (0);
+      ax = &t->ax;
+    }
+    send_kx_auth (t,
+                  NULL,
+                  ax,
+                  (0 == GCT_count_channels (t))
+                  ? GNUNET_NO
+                  : GNUNET_YES);
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    /* Must have been the *other* peer asking us to
+       respond with a KX_AUTH. */
+    if (NULL != t->unverified_ax)
+    {
+      /* Sending AX_AUTH in response to AX so we might get this one verified */
+      ax = t->unverified_ax;
+    }
+    else
+    {
+      /* Sending AX_AUTH in response to AX_AUTH */
+      ax = &t->ax;
+    }
+    send_kx_auth (t,
+                  NULL,
+                  ax,
+                  GNUNET_NO);
+    break;
+  }
+}
+
+
+/**
+ * Handle KX message that lacks authentication (and which will thus
+ * only be considered authenticated after we respond with our own
+ * KX_AUTH and finally successfully decrypt payload).
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCT_handle_kx (struct CadetTConnection *ct,
+               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg)
+{
+  struct CadetTunnel *t = ct->t;
+  struct CadetTunnelAxolotl *ax;
+  int ret;
+
+  if (0 ==
+      memcmp (&t->ax.DHRr,
+              &msg->ratchet_key,
+              sizeof (msg->ratchet_key)))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Got duplicate KX. Firing back KX_AUTH.\n");
+    send_kx_auth (t,
+                  ct,
+                  &t->ax,
+                  GNUNET_NO);
+    return;
+  }
+
+  /* We only keep ONE unverified KX around, so if there is an existing one,
+     clean it up. */
+  if (NULL != t->unverified_ax)
+  {
+    if (0 ==
+        memcmp (&t->unverified_ax->DHRr,
+                &msg->ratchet_key,
+                sizeof (msg->ratchet_key)))
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Got duplicate unverified KX on %s. Fire back KX_AUTH again.\n",
+           GCT_2s (t));
+      send_kx_auth (t,
+                    ct,
+                    t->unverified_ax,
+                    GNUNET_NO);
+      return;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Dropping old unverified KX state. Got a fresh KX for %s.\n",
+         GCT_2s (t));
+    memset (t->unverified_ax,
+            0,
+            sizeof (struct CadetTunnelAxolotl));
+    t->unverified_ax->DHRs = t->ax.DHRs;
+    t->unverified_ax->kx_0 = t->ax.kx_0;
+  }
+  else
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Creating fresh unverified KX for %s.\n",
+         GCT_2s (t));
+    t->unverified_ax = GNUNET_new (struct CadetTunnelAxolotl);
+    t->unverified_ax->DHRs = t->ax.DHRs;
+    t->unverified_ax->kx_0 = t->ax.kx_0;
+  }
+  /* Set as the 'current' RK/DHRr the one we are currently using,
+     so that the duplicate-detection logic of
+     #update_ax_by_kx can work. */
+  t->unverified_ax->RK = t->ax.RK;
+  t->unverified_ax->DHRr = t->ax.DHRr;
+  t->unverified_attempts = 0;
+  ax = t->unverified_ax;
+
+  /* Update 'ax' by the new key material */
+  ret = update_ax_by_kx (ax,
+                         GCP_get_id (t->destination),
+                         &msg->ephemeral_key,
+                         &msg->ratchet_key);
+  GNUNET_break (GNUNET_SYSERR != ret);
+  if (GNUNET_OK != ret)
+    return; /* duplicate KX, nothing to do */
+
+  /* move ahead in our state machine */
+  if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_RECV);
+  else if (CADET_TUNNEL_KEY_AX_SENT == t->estate)
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_AX_SENT_AND_RECV);
+
+  /* KX is still not done, try again our end. */
+  if (CADET_TUNNEL_KEY_OK != t->estate)
+  {
+    if (NULL != t->kx_task)
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+    t->kx_task
+      = GNUNET_SCHEDULER_add_now (&retry_kx,
+                                  t);
+  }
+}
+
+
+/**
+ * Handle KX_AUTH message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCT_handle_kx_auth (struct CadetTConnection *ct,
+                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg)
+{
+  struct CadetTunnel *t = ct->t;
+  struct CadetTunnelAxolotl ax_tmp;
+  struct GNUNET_HashCode kx_auth;
+  int ret;
+
+  if ( (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) ||
+       (CADET_TUNNEL_KEY_AX_RECV == t->estate) )
+  {
+    /* Confusing, we got a KX_AUTH before we even send our own
+       KX. This should not happen. We'll send our own KX ASAP anyway,
+       so let's ignore this here. */
+    GNUNET_break_op (0);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Handling KX_AUTH message for %s\n",
+       GCT_2s (t));
+
+  /* We do everything in ax_tmp until we've checked the authentication
+     so we don't clobber anything we care about by accident. */
+  ax_tmp = t->ax;
+
+  /* Update 'ax' by the new key material */
+  ret = update_ax_by_kx (&ax_tmp,
+                         GCP_get_id (t->destination),
+                         &msg->kx.ephemeral_key,
+                         &msg->kx.ratchet_key);
+  if (GNUNET_OK != ret)
+  {
+    if (GNUNET_NO == ret)
+      GNUNET_STATISTICS_update (stats,
+                                "# redundant KX_AUTH received",
+                                1,
+                                GNUNET_NO);
+    else
+      GNUNET_break (0); /* connect to self!? */
+    return;
+  }
+  GNUNET_CRYPTO_hash (&ax_tmp.RK,
+                      sizeof (ax_tmp.RK),
+                      &kx_auth);
+  if (0 != memcmp (&kx_auth,
+                   &msg->auth,
+                   sizeof (kx_auth)))
+  {
+    /* This KX_AUTH is not using the latest KX/KX_AUTH data
+       we transmitted to the sender, refuse it, try KX again. */
+    GNUNET_STATISTICS_update (stats,
+                              "# KX_AUTH not using our last KX received (auth failure)",
+                              1,
+                              GNUNET_NO);
+    send_kx (t,
+             ct,
+             &t->ax);
+    return;
+  }
+  /* Yep, we're good. */
+  t->ax = ax_tmp;
+  if (NULL != t->unverified_ax)
+  {
+    /* We got some "stale" KX before, drop that. */
+    cleanup_ax (t->unverified_ax);
+    GNUNET_free (t->unverified_ax);
+    t->unverified_ax = NULL;
+  }
+
+  /* move ahead in our state machine */
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+  case CADET_TUNNEL_KEY_AX_RECV:
+    /* Checked above, this is impossible. */
+    GNUNET_assert (0);
+    break;
+  case CADET_TUNNEL_KEY_AX_SENT:      /* This is the normal case */
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV: /* both peers started KX */
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT: /* both peers now did KX_AUTH */
+    GCT_change_estate (t,
+                       CADET_TUNNEL_KEY_OK);
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    /* Did not expect another KX_AUTH, but so what, still acceptable.
+       Nothing to do here. */
+    break;
+  }
+}
+
+
+
+/* ************************************** end core crypto ***************************** */
+
+
+/**
+ * Compute the next free channel tunnel number for this tunnel.
+ *
+ * @param t the tunnel
+ * @return unused number that can uniquely identify a channel in the tunnel
+ */
+static struct GNUNET_CADET_ChannelTunnelNumber
+get_next_free_ctn (struct CadetTunnel *t)
+{
+#define HIGH_BIT 0x8000000
+  struct GNUNET_CADET_ChannelTunnelNumber ret;
+  uint32_t ctn;
+  int cmp;
+  uint32_t highbit;
+
+  cmp = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id,
+                                         GCP_get_id (GCT_get_destination (t)));
+  if (0 < cmp)
+    highbit = HIGH_BIT;
+  else if (0 > cmp)
+    highbit = 0;
+  else
+    GNUNET_assert (0); // loopback must never go here!
+  ctn = ntohl (t->next_ctn.cn);
+  while (NULL !=
+         GNUNET_CONTAINER_multihashmap32_get (t->channels,
+                                              ctn | highbit))
+  {
+    ctn = ((ctn + 1) & (~ HIGH_BIT));
+  }
+  t->next_ctn.cn = htonl ((ctn + 1) & (~ HIGH_BIT));
+  ret.cn = htonl (ctn | highbit);
+  return ret;
+}
+
+
+/**
+ * Add a channel to a tunnel, and notify channel that we are ready
+ * for transmission if we are already up.  Otherwise that notification
+ * will be done later in #notify_tunnel_up_cb().
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @return unique number identifying @a ch within @a t
+ */
+struct GNUNET_CADET_ChannelTunnelNumber
+GCT_add_channel (struct CadetTunnel *t,
+                 struct CadetChannel *ch)
+{
+  struct GNUNET_CADET_ChannelTunnelNumber ctn;
+
+  ctn = get_next_free_ctn (t);
+  if (NULL != t->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->destroy_task);
+    t->destroy_task = NULL;
+  }
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
+                                                      ntohl (ctn.cn),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Adding %s to %s\n",
+       GCCH_2s (ch),
+       GCT_2s (t));
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+    /* waiting for connection to start KX */
+    break;
+  case CADET_TUNNEL_KEY_AX_RECV:
+  case CADET_TUNNEL_KEY_AX_SENT:
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+    /* we're currently waiting for KX to complete */
+    break;
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    /* waiting for OTHER peer to send us data,
+       we might need to prompt more aggressively! */
+    if (NULL == t->kx_task)
+      t->kx_task
+        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+                                   &retry_kx,
+                                   t);
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    /* We are ready. Tell the new channel that we are up. */
+    GCCH_tunnel_up (ch);
+    break;
+  }
+  return ctn;
+}
+
+
+/**
+ * We lost a connection, remove it from our list and clean up
+ * the connection object itself.
+ *
+ * @param ct binding of connection to tunnel of the connection that was lost.
+ */
+void
+GCT_connection_lost (struct CadetTConnection *ct)
+{
+  struct CadetTunnel *t = ct->t;
+
+  if (GNUNET_YES == ct->is_ready)
+  {
+    GNUNET_CONTAINER_DLL_remove (t->connection_ready_head,
+                                 t->connection_ready_tail,
+                                 ct);
+    t->num_ready_connections--;
+  }
+  else
+  {
+    GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
+                                 t->connection_busy_tail,
+                                 ct);
+    t->num_busy_connections--;
+  }
+  GNUNET_free (ct);
+}
+
+
+/**
+ * Clean up connection @a ct of a tunnel.
+ *
+ * @param cls the `struct CadetTunnel`
+ * @param ct connection to clean up
+ */
+static void
+destroy_t_connection (void *cls,
+                      struct CadetTConnection *ct)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetConnection *cc = ct->cc;
+
+  GNUNET_assert (ct->t == t);
+  GCT_connection_lost (ct);
+  GCC_destroy_without_tunnel (cc);
+}
+
+
+/**
+ * This tunnel is no longer used, destroy it.
+ *
+ * @param cls the idle tunnel
+ */
+static void
+destroy_tunnel (void *cls)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetTunnelQueueEntry *tq;
+
+  t->destroy_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Destroying idle %s\n",
+       GCT_2s (t));
+  GNUNET_assert (0 == GCT_count_channels (t));
+  GCT_iterate_connections (t,
+                           &destroy_t_connection,
+                           t);
+  GNUNET_assert (NULL == t->connection_ready_head);
+  GNUNET_assert (NULL == t->connection_busy_head);
+  while (NULL != (tq = t->tq_head))
+  {
+    if (NULL != tq->cont)
+      tq->cont (tq->cont_cls,
+                NULL);
+    GCT_send_cancel (tq);
+  }
+  GCP_drop_tunnel (t->destination,
+                   t);
+  GNUNET_CONTAINER_multihashmap32_destroy (t->channels);
+  if (NULL != t->maintain_connections_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->maintain_connections_task);
+    t->maintain_connections_task = NULL;
+  }
+  if (NULL != t->send_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->send_task);
+    t->send_task = NULL;
+  }
+  if (NULL != t->kx_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->kx_task);
+    t->kx_task = NULL;
+  }
+  GNUNET_MST_destroy (t->mst);
+  GNUNET_MQ_destroy (t->mq);
+  if (NULL != t->unverified_ax)
+  {
+    cleanup_ax (t->unverified_ax);
+    GNUNET_free (t->unverified_ax);
+  }
+  cleanup_ax (&t->ax);
+  GNUNET_assert (NULL == t->destroy_task);
+  GNUNET_free (t);
+}
+
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @param ctn unique number identifying @a ch within @a t
+ */
+void
+GCT_remove_channel (struct CadetTunnel *t,
+                    struct CadetChannel *ch,
+                    struct GNUNET_CADET_ChannelTunnelNumber ctn)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing %s from %s\n",
+       GCCH_2s (ch),
+       GCT_2s (t));
+  GNUNET_assert (GNUNET_YES ==
+                 GNUNET_CONTAINER_multihashmap32_remove (t->channels,
+                                                         ntohl (ctn.cn),
+                                                         ch));
+  if ( (0 ==
+        GCT_count_channels (t)) &&
+       (NULL == t->destroy_task) )
+  {
+    t->destroy_task
+      = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+                                      &destroy_tunnel,
+                                      t);
+  }
+}
+
+
+/**
+ * Destroy remaining channels during shutdown.
+ *
+ * @param cls the `struct CadetTunnel` of the channel
+ * @param key key of the channel
+ * @param value the `struct CadetChannel`
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+destroy_remaining_channels (void *cls,
+                            uint32_t key,
+                            void *value)
+{
+  struct CadetChannel *ch = value;
+
+  GCCH_handle_remote_destroy (ch,
+                              NULL);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Destroys the tunnel @a t now, without delay. Used during shutdown.
+ *
+ * @param t tunnel to destroy
+ */
+void
+GCT_destroy_tunnel_now (struct CadetTunnel *t)
+{
+  GNUNET_assert (GNUNET_YES == shutting_down);
+  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                           &destroy_remaining_channels,
+                                           t);
+  GNUNET_assert (0 ==
+                 GCT_count_channels (t));
+  if (NULL != t->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->destroy_task);
+    t->destroy_task = NULL;
+  }
+  destroy_tunnel (t);
+}
+
+
+/**
+ * Send normal payload from queue in @a t via connection @a ct.
+ * Does nothing if our payload queue is empty.
+ *
+ * @param t tunnel to send data from
+ * @param ct connection to use for transmission (is ready)
+ */
+static void
+try_send_normal_payload (struct CadetTunnel *t,
+                         struct CadetTConnection *ct)
+{
+  struct CadetTunnelQueueEntry *tq;
+
+  GNUNET_assert (GNUNET_YES == ct->is_ready);
+  tq = t->tq_head;
+  if (NULL == tq)
+  {
+    /* no messages pending right now */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Not sending payload of %s on ready %s (nothing pending)\n",
+         GCT_2s (t),
+         GCC_2s (ct->cc));
+    return;
+  }
+  /* ready to send message 'tq' on tunnel 'ct' */
+  GNUNET_assert (t == tq->t);
+  GNUNET_CONTAINER_DLL_remove (t->tq_head,
+                               t->tq_tail,
+                               tq);
+  if (NULL != tq->cid)
+    *tq->cid = *GCC_get_id (ct->cc);
+  mark_connection_unready (ct);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending payload of %s on %s\n",
+       GCT_2s (t),
+       GCC_2s (ct->cc));
+  GCC_transmit (ct->cc,
+                tq->env);
+  if (NULL != tq->cont)
+    tq->cont (tq->cont_cls,
+              GCC_get_id (ct->cc));
+  GNUNET_free (tq);
+}
+
+
+/**
+ * A connection is @a is_ready for transmission.  Looks at our message
+ * queue and if there is a message, sends it out via the connection.
+ *
+ * @param cls the `struct CadetTConnection` that is @a is_ready
+ * @param is_ready #GNUNET_YES if connection are now ready,
+ *                 #GNUNET_NO if connection are no longer ready
+ */
+static void
+connection_ready_cb (void *cls,
+                     int is_ready)
+{
+  struct CadetTConnection *ct = cls;
+  struct CadetTunnel *t = ct->t;
+
+  if (GNUNET_NO == is_ready)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "%s no longer ready for %s\n",
+         GCC_2s (ct->cc),
+         GCT_2s (t));
+    mark_connection_unready (ct);
+    return;
+  }
+  GNUNET_assert (GNUNET_NO == ct->is_ready);
+  GNUNET_CONTAINER_DLL_remove (t->connection_busy_head,
+                               t->connection_busy_tail,
+                               ct);
+  GNUNET_assert (0 < t->num_busy_connections);
+  t->num_busy_connections--;
+  ct->is_ready = GNUNET_YES;
+  GNUNET_CONTAINER_DLL_insert_tail (t->connection_ready_head,
+                                    t->connection_ready_tail,
+                                    ct);
+  t->num_ready_connections++;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s now ready for %s in state %s\n",
+       GCC_2s (ct->cc),
+       GCT_2s (t),
+       estate2s (t->estate));
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+    /* Do not begin KX if WE have no channels waiting! */
+    if (0 == GCT_count_channels (t))
+      return;
+    /* We are uninitialized, just transmit immediately,
+       without undue delay. */
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx (t,
+             ct,
+             &t->ax);
+    break;
+  case CADET_TUNNEL_KEY_AX_RECV:
+  case CADET_TUNNEL_KEY_AX_SENT:
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    /* we're currently waiting for KX to complete, schedule job */
+    if (NULL == t->kx_task)
+      t->kx_task
+        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+                                   &retry_kx,
+                                   t);
+    break;
+  case CADET_TUNNEL_KEY_OK:
+    if (GNUNET_YES == t->kx_auth_requested)
+    {
+      if (NULL != t->kx_task)
+      {
+        GNUNET_SCHEDULER_cancel (t->kx_task);
+        t->kx_task = NULL;
+      }
+      send_kx_auth (t,
+                    ct,
+                    &t->ax,
+                    GNUNET_NO);
+      return;
+    }
+    try_send_normal_payload (t,
+                             ct);
+    break;
+  }
+}
+
+
+/**
+ * Called when either we have a new connection, or a new message in the
+ * queue, or some existing connection has transmission capacity.  Looks
+ * at our message queue and if there is a message, picks a connection
+ * to send it on.
+ *
+ * @param cls the `struct CadetTunnel` to process messages on
+ */
+static void
+trigger_transmissions (void *cls)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetTConnection *ct;
+
+  t->send_task = NULL;
+  if (NULL == t->tq_head)
+    return; /* no messages pending right now */
+  ct = get_ready_connection (t);
+  if (NULL == ct)
+    return; /* no connections ready */
+  try_send_normal_payload (t,
+                           ct);
+}
+
+
+/**
+ * Closure for #evaluate_connection. Used to assemble summary information
+ * about the existing connections so we can evaluate a new path.
+ */
+struct EvaluationSummary
+{
+
+  /**
+   * Minimum length of any of our connections, `UINT_MAX` if we have none.
+   */
+  unsigned int min_length;
+
+  /**
+   * Maximum length of any of our connections, 0 if we have none.
+   */
+  unsigned int max_length;
+
+  /**
+   * Minimum desirability of any of our connections, UINT64_MAX if we have none.
+   */
+  GNUNET_CONTAINER_HeapCostType min_desire;
+
+  /**
+   * Maximum desirability of any of our connections, 0 if we have none.
+   */
+  GNUNET_CONTAINER_HeapCostType max_desire;
+
+  /**
+   * Path we are comparing against for #evaluate_connection, can be NULL.
+   */
+  struct CadetPeerPath *path;
+
+  /**
+   * Connection deemed the "worst" so far encountered by #evaluate_connection,
+   * NULL if we did not yet encounter any connections.
+   */
+  struct CadetTConnection *worst;
+
+  /**
+   * Numeric score of @e worst, only set if @e worst is non-NULL.
+   */
+  double worst_score;
+
+  /**
+   * Set to #GNUNET_YES if we have a connection over @e path already.
+   */
+  int duplicate;
+
+};
+
+
+/**
+ * Evaluate a connection, updating our summary information in @a cls about
+ * what kinds of connections we have.
+ *
+ * @param cls the `struct EvaluationSummary *` to update
+ * @param ct a connection to include in the summary
+ */
+static void
+evaluate_connection (void *cls,
+                     struct CadetTConnection *ct)
+{
+  struct EvaluationSummary *es = cls;
+  struct CadetConnection *cc = ct->cc;
+  struct CadetPeerPath *ps = GCC_get_path (cc);
+  const struct CadetConnectionMetrics *metrics;
+  GNUNET_CONTAINER_HeapCostType ct_desirability;
+  struct GNUNET_TIME_Relative uptime;
+  struct GNUNET_TIME_Relative last_use;
+  uint32_t ct_length;
+  double score;
+  double success_rate;
+
+  if (ps == es->path)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring duplicate path %s.\n",
+         GCPP_2s (es->path));
+    es->duplicate = GNUNET_YES;
+    return;
+  }
+  ct_desirability = GCPP_get_desirability (ps);
+  ct_length = GCPP_get_length (ps);
+  metrics = GCC_get_metrics (cc);
+  uptime = GNUNET_TIME_absolute_get_duration (metrics->age);
+  last_use = GNUNET_TIME_absolute_get_duration (metrics->last_use);
+  /* We add 1.0 here to avoid division by zero. */
+  success_rate = (metrics->num_acked_transmissions + 1.0) / (metrics->num_successes + 1.0);
+  score
+    = ct_desirability
+    + 100.0 / (1.0 + ct_length) /* longer paths = better */
+    + sqrt (uptime.rel_value_us / 60000000LL) /* larger uptime = better */
+    - last_use.rel_value_us / 1000L;          /* longer idle = worse */
+  score *= success_rate;        /* weigh overall by success rate */
+
+  if ( (NULL == es->worst) ||
+       (score < es->worst_score) )
+  {
+    es->worst = ct;
+    es->worst_score = score;
+  }
+  es->min_length = GNUNET_MIN (es->min_length,
+                               ct_length);
+  es->max_length = GNUNET_MAX (es->max_length,
+                               ct_length);
+  es->min_desire = GNUNET_MIN (es->min_desire,
+                               ct_desirability);
+  es->max_desire = GNUNET_MAX (es->max_desire,
+                               ct_desirability);
+}
+
+
+/**
+ * Consider using the path @a p for the tunnel @a t.
+ * The tunnel destination is at offset @a off in path @a p.
+ *
+ * @param cls our tunnel
+ * @param path a path to our destination
+ * @param off offset of the destination on path @a path
+ * @return #GNUNET_YES (should keep iterating)
+ */
+static int
+consider_path_cb (void *cls,
+                  struct CadetPeerPath *path,
+                  unsigned int off)
+{
+  struct CadetTunnel *t = cls;
+  struct EvaluationSummary es;
+  struct CadetTConnection *ct;
+
+  GNUNET_assert (off < GCPP_get_length (path));
+  es.min_length = UINT_MAX;
+  es.max_length = 0;
+  es.max_desire = 0;
+  es.min_desire = UINT64_MAX;
+  es.path = path;
+  es.duplicate = GNUNET_NO;
+  es.worst = NULL;
+
+  /* Compute evaluation summary over existing connections. */
+  GCT_iterate_connections (t,
+                           &evaluate_connection,
+                           &es);
+  if (GNUNET_YES == es.duplicate)
+    return GNUNET_YES;
+
+  /* FIXME: not sure we should really just count
+     'num_connections' here, as they may all have
+     consistently failed to connect. */
+
+  /* We iterate by increasing path length; if we have enough paths and
+     this one is more than twice as long than what we are currently
+     using, then ignore all of these super-long ones! */
+  if ( (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) &&
+       (es.min_length * 2 < off) &&
+       (es.max_length < off) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring paths of length %u, they are way too long.\n",
+         es.min_length * 2);
+    return GNUNET_NO;
+  }
+  /* If we have enough paths and this one looks no better, ignore it. */
+  if ( (GCT_count_any_connections (t) >= DESIRED_CONNECTIONS_PER_TUNNEL) &&
+       (es.min_length < GCPP_get_length (path)) &&
+       (es.min_desire > GCPP_get_desirability (path)) &&
+       (es.max_length < off) )
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Ignoring path (%u/%llu) to %s, got something better already.\n",
+         GCPP_get_length (path),
+         (unsigned long long) GCPP_get_desirability (path),
+         GCP_2s (t->destination));
+    return GNUNET_YES;
+  }
+
+  /* Path is interesting (better by some metric, or we don't have
+     enough paths yet). */
+  ct = GNUNET_new (struct CadetTConnection);
+  ct->created = GNUNET_TIME_absolute_get ();
+  ct->t = t;
+  ct->cc = GCC_create (t->destination,
+                       path,
+                       off,
+                       GNUNET_CADET_OPTION_DEFAULT, /* FIXME: set based on what channels want/need! */
+                       ct,
+                       &connection_ready_cb,
+                       ct);
+
+  /* FIXME: schedule job to kill connection (and path?)  if it takes
+     too long to get ready! (And track performance data on how long
+     other connections took with the tunnel!)
+     => Note: to be done within 'connection'-logic! */
+  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
+                               t->connection_busy_tail,
+                               ct);
+  t->num_busy_connections++;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Found interesting path %s for %s, created %s\n",
+       GCPP_2s (path),
+       GCT_2s (t),
+       GCC_2s (ct->cc));
+  return GNUNET_YES;
+}
+
+
+/**
+ * Function called to maintain the connections underlying our tunnel.
+ * Tries to maintain (incl. tear down) connections for the tunnel, and
+ * if there is a significant change, may trigger transmissions.
+ *
+ * Basically, needs to check if there are connections that perform
+ * badly, and if so eventually kill them and trigger a replacement.
+ * The strategy is to open one more connection than
+ * #DESIRED_CONNECTIONS_PER_TUNNEL, and then periodically kick out the
+ * least-performing one, and then inquire for new ones.
+ *
+ * @param cls the `struct CadetTunnel`
+ */
+static void
+maintain_connections_cb (void *cls)
+{
+  struct CadetTunnel *t = cls;
+  struct GNUNET_TIME_Relative delay;
+  struct EvaluationSummary es;
+
+  t->maintain_connections_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Performing connection maintenance for %s.\n",
+       GCT_2s (t));
+
+  es.min_length = UINT_MAX;
+  es.max_length = 0;
+  es.max_desire = 0;
+  es.min_desire = UINT64_MAX;
+  es.path = NULL;
+  es.worst = NULL;
+  es.duplicate = GNUNET_NO;
+  GCT_iterate_connections (t,
+                           &evaluate_connection,
+                           &es);
+  if ( (NULL != es.worst) &&
+       (GCT_count_any_connections (t) > DESIRED_CONNECTIONS_PER_TUNNEL) )
+  {
+    /* Clear out worst-performing connection 'es.worst'. */
+    destroy_t_connection (t,
+                          es.worst);
+  }
+
+  /* Consider additional paths */
+  (void) GCP_iterate_paths (t->destination,
+                            &consider_path_cb,
+                            t);
+
+  /* FIXME: calculate when to try again based on how well we are doing;
+     in particular, if we have to few connections, we might be able
+     to do without this (as PATHS should tell us whenever a new path
+     is available instantly; however, need to make sure this job is
+     restarted after that happens).
+     Furthermore, if the paths we do know are in a reasonably narrow
+     quality band and are plentyful, we might also consider us stabilized
+     and then reduce the frequency accordingly.  */
+  delay = GNUNET_TIME_UNIT_MINUTES;
+  t->maintain_connections_task
+    = GNUNET_SCHEDULER_add_delayed (delay,
+                                    &maintain_connections_cb,
+                                    t);
+}
+
+
+/**
+ * Consider using the path @a p for the tunnel @a t.
+ * The tunnel destination is at offset @a off in path @a p.
+ *
+ * @param cls our tunnel
+ * @param path a path to our destination
+ * @param off offset of the destination on path @a path
+ */
+void
+GCT_consider_path (struct CadetTunnel *t,
+                   struct CadetPeerPath *p,
+                   unsigned int off)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Considering %s for %s\n",
+       GCPP_2s (p),
+       GCT_2s (t));
+  (void) consider_path_cb (t,
+                           p,
+                           off);
+}
+
+
+/**
+ * We got a keepalive. Track in statistics.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param msg  the message we received on the tunnel
+ */
+static void
+handle_plaintext_keepalive (void *cls,
+                            const struct GNUNET_MessageHeader *msg)
+{
+  struct CadetTunnel *t = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received KEEPALIVE on %s\n",
+       GCT_2s (t));
+  GNUNET_STATISTICS_update (stats,
+                            "# keepalives received",
+                            1,
+                            GNUNET_NO);
+}
+
+
+/**
+ * Check that @a msg is well-formed.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param msg  the message we received on the tunnel
+ * @return #GNUNET_OK (any variable-size payload goes)
+ */
+static int
+check_plaintext_data (void *cls,
+                      const struct GNUNET_CADET_ChannelAppDataMessage *msg)
+{
+  return GNUNET_OK;
+}
+
+
+/**
+ * We received payload data for a channel.  Locate the channel
+ * and process the data, or return an error if the channel is unknown.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param msg the message we received on the tunnel
+ */
+static void
+handle_plaintext_data (void *cls,
+                       const struct GNUNET_CADET_ChannelAppDataMessage *msg)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       msg->ctn);
+  if (NULL == ch)
+  {
+    /* We don't know about such a channel, might have been destroyed on our
+       end in the meantime, or never existed. Send back a DESTROY. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received %u bytes of application data for unknown channel %u, sending DESTROY\n",
+         (unsigned int) (ntohs (msg->header.size) - sizeof (*msg)),
+         ntohl (msg->ctn.cn));
+    GCT_send_channel_destroy (t,
+                              msg->ctn);
+    return;
+  }
+  GCCH_handle_channel_plaintext_data (ch,
+                                      GCC_get_id (t->current_ct->cc),
+                                      msg);
+}
+
+
+/**
+ * We received an acknowledgement for data we sent on a channel.
+ * Locate the channel and process it, or return an error if the
+ * channel is unknown.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param ack the message we received on the tunnel
+ */
+static void
+handle_plaintext_data_ack (void *cls,
+                           const struct GNUNET_CADET_ChannelDataAckMessage *ack)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       ack->ctn);
+  if (NULL == ch)
+  {
+    /* We don't know about such a channel, might have been destroyed on our
+       end in the meantime, or never existed. Send back a DESTROY. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received DATA_ACK for unknown channel %u, sending DESTROY\n",
+         ntohl (ack->ctn.cn));
+    GCT_send_channel_destroy (t,
+                              ack->ctn);
+    return;
+  }
+  GCCH_handle_channel_plaintext_data_ack (ch,
+                                          GCC_get_id (t->current_ct->cc),
+                                          ack);
+}
+
+
+/**
+ * We have received a request to open a channel to a port from
+ * another peer.  Creates the incoming channel.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param copen the message we received on the tunnel
+ */
+static void
+handle_plaintext_channel_open (void *cls,
+                               const struct GNUNET_CADET_ChannelOpenMessage *copen)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = GNUNET_CONTAINER_multihashmap32_get (t->channels,
+                                            ntohl (copen->ctn.cn));
+  if (NULL != ch)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received duplicate channel CHANNEL_OPEN on port %s from %s (%s), resending ACK\n",
+         GNUNET_h2s (&copen->port),
+         GCT_2s (t),
+         GCCH_2s (ch));
+    GCCH_handle_duplicate_open (ch,
+                                GCC_get_id (t->current_ct->cc));
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received CHANNEL_OPEN on port %s from %s\n",
+       GNUNET_h2s (&copen->port),
+       GCT_2s (t));
+  ch = GCCH_channel_incoming_new (t,
+                                  copen->ctn,
+                                  &copen->port,
+                                  ntohl (copen->opt));
+  if (NULL != t->destroy_task)
+  {
+    GNUNET_SCHEDULER_cancel (t->destroy_task);
+    t->destroy_task = NULL;
+  }
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap32_put (t->channels,
+                                                      ntohl (copen->ctn.cn),
+                                                      ch,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+}
+
+
+/**
+ * Send a DESTROY message via the tunnel.
+ *
+ * @param t the tunnel to transmit over
+ * @param ctn ID of the channel to destroy
+ */
+void
+GCT_send_channel_destroy (struct CadetTunnel *t,
+                          struct GNUNET_CADET_ChannelTunnelNumber ctn)
+{
+  struct GNUNET_CADET_ChannelManageMessage msg;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending DESTORY message for channel ID %u\n",
+       ntohl (ctn.cn));
+  msg.header.size = htons (sizeof (msg));
+  msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY);
+  msg.reserved = htonl (0);
+  msg.ctn = ctn;
+  GCT_send (t,
+            &msg.header,
+            NULL,
+            NULL);
+}
+
+
+/**
+ * We have received confirmation from the target peer that the
+ * given channel could be established (the port is open).
+ * Tell the client.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param cm the message we received on the tunnel
+ */
+static void
+handle_plaintext_channel_open_ack (void *cls,
+                                   const struct GNUNET_CADET_ChannelManageMessage *cm)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       cm->ctn);
+  if (NULL == ch)
+  {
+    /* We don't know about such a channel, might have been destroyed on our
+       end in the meantime, or never existed. Send back a DESTROY. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received channel OPEN_ACK for unknown channel %u, sending DESTROY\n",
+         ntohl (cm->ctn.cn));
+    GCT_send_channel_destroy (t,
+                              cm->ctn);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received channel OPEN_ACK on channel %s from %s\n",
+       GCCH_2s (ch),
+       GCT_2s (t));
+  GCCH_handle_channel_open_ack (ch,
+                                GCC_get_id (t->current_ct->cc));
+}
+
+
+/**
+ * We received a message saying that a channel should be destroyed.
+ * Pass it on to the correct channel.
+ *
+ * @param cls the `struct CadetTunnel` for which we decrypted the message
+ * @param cm the message we received on the tunnel
+ */
+static void
+handle_plaintext_channel_destroy (void *cls,
+                                  const struct GNUNET_CADET_ChannelManageMessage *cm)
+{
+  struct CadetTunnel *t = cls;
+  struct CadetChannel *ch;
+
+  ch = lookup_channel (t,
+                       cm->ctn);
+  if (NULL == ch)
+  {
+    /* We don't know about such a channel, might have been destroyed on our
+       end in the meantime, or never existed. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Received channel DESTORY for unknown channel %u. Ignoring.\n",
+         ntohl (cm->ctn.cn));
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received channel DESTROY on %s from %s\n",
+       GCCH_2s (ch),
+       GCT_2s (t));
+  GCCH_handle_remote_destroy (ch,
+                              GCC_get_id (t->current_ct->cc));
+}
+
+
+/**
+ * Handles a message we decrypted, by injecting it into
+ * our message queue (which will do the dispatching).
+ *
+ * @param cls the `struct CadetTunnel` that got the message
+ * @param msg the message
+ * @return #GNUNET_OK (continue to process)
+ */
+static int
+handle_decrypted (void *cls,
+                  const struct GNUNET_MessageHeader *msg)
+{
+  struct CadetTunnel *t = cls;
+
+  GNUNET_assert (NULL != t->current_ct);
+  GNUNET_MQ_inject_message (t->mq,
+                            msg);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Function called if we had an error processing
+ * an incoming decrypted message.
+ *
+ * @param cls the `struct CadetTunnel`
+ * @param error error code
+ */
+static void
+decrypted_error_cb (void *cls,
+                    enum GNUNET_MQ_Error error)
+{
+  GNUNET_break_op (0);
+}
+
+
+/**
+ * Create a tunnel to @a destionation.  Must only be called
+ * from within #GCP_get_tunnel().
+ *
+ * @param destination where to create the tunnel to
+ * @return new tunnel to @a destination
+ */
+struct CadetTunnel *
+GCT_create_tunnel (struct CadetPeer *destination)
+{
+  struct CadetTunnel *t = GNUNET_new (struct CadetTunnel);
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_fixed_size (plaintext_keepalive,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE,
+                             struct GNUNET_MessageHeader,
+                             t),
+    GNUNET_MQ_hd_var_size (plaintext_data,
+                           GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA,
+                           struct GNUNET_CADET_ChannelAppDataMessage,
+                           t),
+    GNUNET_MQ_hd_fixed_size (plaintext_data_ack,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK,
+                             struct GNUNET_CADET_ChannelDataAckMessage,
+                             t),
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_open,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN,
+                             struct GNUNET_CADET_ChannelOpenMessage,
+                             t),
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_open_ack,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK,
+                             struct GNUNET_CADET_ChannelManageMessage,
+                             t),
+    GNUNET_MQ_hd_fixed_size (plaintext_channel_destroy,
+                             GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
+                             struct GNUNET_CADET_ChannelManageMessage,
+                             t),
+    GNUNET_MQ_handler_end ()
+  };
+
+  t->kx_retry_delay = INITIAL_KX_RETRY_DELAY;
+  new_ephemeral (&t->ax);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CRYPTO_ecdhe_key_create2 (&t->ax.kx_0));
+  t->destination = destination;
+  t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
+  t->maintain_connections_task
+    = GNUNET_SCHEDULER_add_now (&maintain_connections_cb,
+                                t);
+  t->mq = GNUNET_MQ_queue_for_callbacks (NULL,
+                                         NULL,
+                                         NULL,
+                                         NULL,
+                                         handlers,
+                                         &decrypted_error_cb,
+                                         t);
+  t->mst = GNUNET_MST_create (&handle_decrypted,
+                              t);
+  return t;
+}
+
+
+/**
+ * Add a @a connection to the @a tunnel.
+ *
+ * @param t a tunnel
+ * @param cid connection identifer to use for the connection
+ * @param options options for the connection
+ * @param path path to use for the connection
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_SYSERR on failure (duplicate connection)
+ */
+int
+GCT_add_inbound_connection (struct CadetTunnel *t,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                            enum GNUNET_CADET_ChannelOption options,
+                            struct CadetPeerPath *path)
+{
+  struct CadetTConnection *ct;
+
+  ct = GNUNET_new (struct CadetTConnection);
+  ct->created = GNUNET_TIME_absolute_get ();
+  ct->t = t;
+  ct->cc = GCC_create_inbound (t->destination,
+                               path,
+                               options,
+                               ct,
+                               cid,
+                               &connection_ready_cb,
+                               ct);
+  if (NULL == ct->cc)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "%s refused inbound %s (duplicate)\n",
+         GCT_2s (t),
+         GCC_2s (ct->cc));
+    GNUNET_free (ct);
+    return GNUNET_SYSERR;
+  }
+  /* FIXME: schedule job to kill connection (and path?)  if it takes
+     too long to get ready! (And track performance data on how long
+     other connections took with the tunnel!)
+     => Note: to be done within 'connection'-logic! */
+  GNUNET_CONTAINER_DLL_insert (t->connection_busy_head,
+                               t->connection_busy_tail,
+                               ct);
+  t->num_busy_connections++;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s has new %s\n",
+       GCT_2s (t),
+       GCC_2s (ct->cc));
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle encrypted message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the encrypted message to decrypt
+ */
+void
+GCT_handle_encrypted (struct CadetTConnection *ct,
+                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg)
+{
+  struct CadetTunnel *t = ct->t;
+  uint16_t size = ntohs (msg->header.size);
+  char cbuf [size] GNUNET_ALIGN;
+  ssize_t decrypted_size;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "%s received %u bytes of encrypted data in state %d\n",
+       GCT_2s (t),
+       (unsigned int) size,
+       t->estate);
+
+  switch (t->estate)
+  {
+  case CADET_TUNNEL_KEY_UNINITIALIZED:
+  case CADET_TUNNEL_KEY_AX_RECV:
+    /* We did not even SEND our KX, how can the other peer
+       send us encrypted data? Must have been that we went
+       down and the other peer still things we are up.
+       Let's send it KX back. */
+    GNUNET_STATISTICS_update (stats,
+                              "# received encrypted without any KX",
+                              1,
+                              GNUNET_NO);
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx (t,
+             ct,
+             &t->ax);
+    return;
+  case CADET_TUNNEL_KEY_AX_SENT_AND_RECV:
+    /* We send KX, and other peer send KX to us at the same time.
+       Neither KX is AUTH'ed, so let's try KX_AUTH this time. */
+    GNUNET_STATISTICS_update (stats,
+                              "# received encrypted without KX_AUTH",
+                              1,
+                              GNUNET_NO);
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx_auth (t,
+                  ct,
+                  &t->ax,
+                  GNUNET_YES);
+    return;
+  case CADET_TUNNEL_KEY_AX_SENT:
+    /* We did not get the KX of the other peer, but that
+       might have been lost.  Send our KX again immediately. */
+    GNUNET_STATISTICS_update (stats,
+                              "# received encrypted without KX",
+                              1,
+                              GNUNET_NO);
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx (t,
+             ct,
+             &t->ax);
+    return;
+  case CADET_TUNNEL_KEY_AX_AUTH_SENT:
+    /* Great, first payload, we might graduate to OK! */
+  case CADET_TUNNEL_KEY_OK:
+    /* We are up and running, all good. */
+    break;
+  }
+
+  decrypted_size = -1;
+  if (CADET_TUNNEL_KEY_OK == t->estate)
+  {
+    /* We have well-established key material available,
+       try that. (This is the common case.) */
+    decrypted_size = t_ax_decrypt_and_validate (&t->ax,
+                                                cbuf,
+                                                msg,
+                                                size);
+  }
+
+  if ( (-1 == decrypted_size) &&
+       (NULL != t->unverified_ax) )
+  {
+    /* We have un-authenticated KX material available. We should try
+       this as a back-up option, in case the sender crashed and
+       switched keys. */
+    decrypted_size = t_ax_decrypt_and_validate (t->unverified_ax,
+                                                cbuf,
+                                                msg,
+                                                size);
+    if (-1 != decrypted_size)
+    {
+      /* It worked! Treat this as authentication of the AX data! */
+      cleanup_ax (&t->ax);
+      t->ax = *t->unverified_ax;
+      GNUNET_free (t->unverified_ax);
+      t->unverified_ax = NULL;
+    }
+    if (CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate)
+    {
+      /* First time it worked, move tunnel into production! */
+      GCT_change_estate (t,
+                         CADET_TUNNEL_KEY_OK);
+      if (NULL != t->send_task)
+        GNUNET_SCHEDULER_cancel (t->send_task);
+      t->send_task = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
+                                               t);
+    }
+  }
+  if (NULL != t->unverified_ax)
+  {
+    /* We had unverified KX material that was useless; so increment
+       counter and eventually move to ignore it.  Note that we even do
+       this increment if we successfully decrypted with the old KX
+       material and thus didn't even both with the new one.  This is
+       the ideal case, as a malicious injection of bogus KX data
+       basically only causes us to increment a counter a few times. */
+    t->unverified_attempts++;
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to decrypt message with unverified KX data %u times\n",
+         t->unverified_attempts);
+    if (t->unverified_attempts > MAX_UNVERIFIED_ATTEMPTS)
+    {
+      cleanup_ax (t->unverified_ax);
+      GNUNET_free (t->unverified_ax);
+      t->unverified_ax = NULL;
+    }
+  }
+
+  if (-1 == decrypted_size)
+  {
+    /* Decryption failed for good, complain. */
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "%s failed to decrypt and validate encrypted data, retrying KX\n",
+         GCT_2s (t));
+    GNUNET_STATISTICS_update (stats,
+                              "# unable to decrypt",
+                              1,
+                              GNUNET_NO);
+    if (NULL != t->kx_task)
+    {
+      GNUNET_SCHEDULER_cancel (t->kx_task);
+      t->kx_task = NULL;
+    }
+    send_kx (t,
+             ct,
+             &t->ax);
+    return;
+  }
+  GNUNET_STATISTICS_update (stats,
+                            "# decrypted bytes",
+                            decrypted_size,
+                            GNUNET_NO);
+
+  /* The MST will ultimately call #handle_decrypted() on each message. */
+  t->current_ct = ct;
+  GNUNET_break_op (GNUNET_OK ==
+                   GNUNET_MST_from_buffer (t->mst,
+                                           cbuf,
+                                           decrypted_size,
+                                           GNUNET_YES,
+                                           GNUNET_NO));
+  t->current_ct = NULL;
+}
+
+
+/**
+ * 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 cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ * @return Handle to cancel message
+ */
+struct CadetTunnelQueueEntry *
+GCT_send (struct CadetTunnel *t,
+          const struct GNUNET_MessageHeader *message,
+          GCT_SendContinuation cont,
+          void *cont_cls)
+{
+  struct CadetTunnelQueueEntry *tq;
+  uint16_t payload_size;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg;
+
+  if (CADET_TUNNEL_KEY_OK != t->estate)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  payload_size = ntohs (message->size);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Encrypting %u bytes for %s\n",
+       (unsigned int) payload_size,
+       GCT_2s (t));
+  env = GNUNET_MQ_msg_extra (ax_msg,
+                             payload_size,
+                             GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED);
+  t_ax_encrypt (&t->ax,
+                &ax_msg[1],
+                message,
+                payload_size);
+  GNUNET_STATISTICS_update (stats,
+                            "# encrypted bytes",
+                            payload_size,
+                            GNUNET_NO);
+  ax_msg->ax_header.Ns = htonl (t->ax.Ns++);
+  ax_msg->ax_header.PNs = htonl (t->ax.PNs);
+  /* FIXME: we should do this once, not once per message;
+     this is a point multiplication, and DHRs does not
+     change all the time. */
+  GNUNET_CRYPTO_ecdhe_key_get_public (&t->ax.DHRs,
+                                      &ax_msg->ax_header.DHRs);
+  t_h_encrypt (&t->ax,
+               ax_msg);
+  t_hmac (&ax_msg->ax_header,
+          sizeof (struct GNUNET_CADET_AxHeader) + payload_size,
+          0,
+          &t->ax.HKs,
+          &ax_msg->hmac);
+
+  tq = GNUNET_malloc (sizeof (*tq));
+  tq->t = t;
+  tq->env = env;
+  tq->cid = &ax_msg->cid; /* will initialize 'ax_msg->cid' once we know the connection */
+  tq->cont = cont;
+  tq->cont_cls = cont_cls;
+  GNUNET_CONTAINER_DLL_insert_tail (t->tq_head,
+                                    t->tq_tail,
+                                    tq);
+  if (NULL != t->send_task)
+    GNUNET_SCHEDULER_cancel (t->send_task);
+  t->send_task
+    = GNUNET_SCHEDULER_add_now (&trigger_transmissions,
+                                t);
+  return tq;
+}
+
+
+/**
+ * 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 tq Handle to the queue entry to cancel.
+ */
+void
+GCT_send_cancel (struct CadetTunnelQueueEntry *tq)
+{
+  struct CadetTunnel *t = tq->t;
+
+  GNUNET_CONTAINER_DLL_remove (t->tq_head,
+                               t->tq_tail,
+                               tq);
+  GNUNET_MQ_discard (tq->env);
+  GNUNET_free (tq);
+}
+
+
+/**
+ * Iterate over all connections of a tunnel.
+ *
+ * @param t Tunnel whose connections to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_connections (struct CadetTunnel *t,
+                         GCT_ConnectionIterator iter,
+                         void *iter_cls)
+{
+  struct CadetTConnection *n;
+  for (struct CadetTConnection *ct = t->connection_ready_head;
+       NULL != ct;
+       ct = n)
+  {
+    n = ct->next;
+    iter (iter_cls,
+          ct);
+  }
+  for (struct CadetTConnection *ct = t->connection_busy_head;
+       NULL != ct;
+       ct = n)
+  {
+    n = ct->next;
+    iter (iter_cls,
+          ct);
+  }
+}
+
+
+/**
+ * Closure for #iterate_channels_cb.
+ */
+struct ChanIterCls
+{
+  /**
+   * Function to call.
+   */
+  GCT_ChannelIterator iter;
+
+  /**
+   * Closure for @e iter.
+   */
+  void *iter_cls;
+};
+
+
+/**
+ * Helper function for #GCT_iterate_channels.
+ *
+ * @param cls the `struct ChanIterCls`
+ * @param key unused
+ * @param value a `struct CadetChannel`
+ * @return #GNUNET_OK
+ */
+static int
+iterate_channels_cb (void *cls,
+                     uint32_t key,
+                     void *value)
+{
+  struct ChanIterCls *ctx = cls;
+  struct CadetChannel *ch = value;
+
+  ctx->iter (ctx->iter_cls,
+             ch);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Iterate over all channels of a tunnel.
+ *
+ * @param t Tunnel whose channels to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_channels (struct CadetTunnel *t,
+                      GCT_ChannelIterator iter,
+                      void *iter_cls)
+{
+  struct ChanIterCls ctx;
+
+  ctx.iter = iter;
+  ctx.iter_cls = iter_cls;
+  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                           &iterate_channels_cb,
+                                           &ctx);
+
+}
+
+
+/**
+ * Call #GCCH_debug() on a channel.
+ *
+ * @param cls points to the log level to use
+ * @param key unused
+ * @param value the `struct CadetChannel` to dump
+ * @return #GNUNET_OK (continue iteration)
+ */
+static int
+debug_channel (void *cls,
+               uint32_t key,
+               void *value)
+{
+  const enum GNUNET_ErrorType *level = cls;
+  struct CadetChannel *ch = value;
+
+  GCCH_debug (ch, *level);
+  return GNUNET_OK;
+}
+
+
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)
+
+
+/**
+ * Log all possible info about the tunnel state.
+ *
+ * @param t Tunnel to debug.
+ * @param level Debug level to use.
+ */
+void
+GCT_debug (const struct CadetTunnel *t,
+           enum GNUNET_ErrorType level)
+{
+  struct CadetTConnection *iter_c;
+  int do_log;
+
+  do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
+                                       "cadet-tun",
+                                       __FILE__, __FUNCTION__, __LINE__);
+  if (0 == do_log)
+    return;
+
+  LOG2 (level,
+        "TTT TUNNEL TOWARDS %s in estate %s tq_len: %u #cons: %u\n",
+        GCT_2s (t),
+        estate2s (t->estate),
+        t->tq_len,
+        GCT_count_any_connections (t));
+  LOG2 (level,
+        "TTT channels:\n");
+  GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+                                           &debug_channel,
+                                           &level);
+  LOG2 (level,
+        "TTT connections:\n");
+  for (iter_c = t->connection_ready_head; NULL != iter_c; iter_c = iter_c->next)
+    GCC_debug (iter_c->cc,
+               level);
+  for (iter_c = t->connection_busy_head; NULL != iter_c; iter_c = iter_c->next)
+    GCC_debug (iter_c->cc,
+               level);
+
+  LOG2 (level,
+        "TTT TUNNEL END\n");
+}
+
+
+/* end of gnunet-service-cadet-new_tunnels.c */
diff --git a/src/cadet/gnunet-service-cadet_tunnels.h b/src/cadet/gnunet-service-cadet_tunnels.h
new file mode 100644 (file)
index 0000000..4a3619a
--- /dev/null
@@ -0,0 +1,370 @@
+
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2001-2017 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_tunnels.h
+ * @brief Information we track per tunnel.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_TUNNELS_H
+#define GNUNET_SERVICE_CADET_TUNNELS_H
+
+#include "gnunet-service-cadet.h"
+#include "cadet_protocol.h"
+
+
+/**
+ * How many connections would we like to have per tunnel?
+ */
+#define DESIRED_CONNECTIONS_PER_TUNNEL 3
+
+
+/**
+ * All the encryption states a tunnel can be in.
+ */
+enum CadetTunnelEState
+{
+  /**
+   * Uninitialized status, we need to send KX.  We will stay
+   * in this state until the first connection is up.
+   */
+  CADET_TUNNEL_KEY_UNINITIALIZED,
+
+  /**
+   * KX message sent, waiting for other peer's KX_AUTH.
+   */
+  CADET_TUNNEL_KEY_AX_SENT,
+
+  /**
+   * KX message received, trying to send back KX_AUTH.
+   */
+  CADET_TUNNEL_KEY_AX_RECV,
+
+  /**
+   * KX message sent and received, trying to send back KX_AUTH.
+   */
+  CADET_TUNNEL_KEY_AX_SENT_AND_RECV,
+
+  /**
+   * KX received and we sent KX_AUTH back, but we got no traffic yet,
+   * so we're waiting for either KX_AUTH or ENCRYPED traffic from
+   * the other peer.
+   *
+   * We will not yet send traffic, as this might have been a replay.
+   * The other (initiating) peer should send a CHANNEL_OPEN next
+   * anyway, and then we are in business!
+   */
+  CADET_TUNNEL_KEY_AX_AUTH_SENT,
+
+  /**
+   * Handshake completed: session key available.
+   */
+  CADET_TUNNEL_KEY_OK
+
+};
+
+
+/**
+ * Get the static string for the peer this tunnel is directed.
+ *
+ * @param t Tunnel.
+ *
+ * @return Static string the destination peer's ID.
+ */
+const char *
+GCT_2s (const struct CadetTunnel *t);
+
+
+/**
+ * Create a tunnel to @a destionation.  Must only be called
+ * from within #GCP_get_tunnel().
+ *
+ * @param destination where to create the tunnel to
+ * @return new tunnel to @a destination
+ */
+struct CadetTunnel *
+GCT_create_tunnel (struct CadetPeer *destination);
+
+
+/**
+ * Destroys the tunnel @a t now, without delay. Used during shutdown.
+ *
+ * @param t tunnel to destroy
+ */
+void
+GCT_destroy_tunnel_now (struct CadetTunnel *t);
+
+
+/**
+ * Add a @a connection to the @a tunnel.
+ *
+ * @param t a tunnel
+ * @param cid connection identifer to use for the connection
+ * @param options options for the connection
+ * @param path path to use for the connection
+ * @return #GNUNET_OK on success,
+ *         #GNUNET_SYSERR on failure (duplicate connection)
+ */
+int
+GCT_add_inbound_connection (struct CadetTunnel *t,
+                            const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid,
+                            enum GNUNET_CADET_ChannelOption options,
+                            struct CadetPeerPath *path);
+
+
+/**
+ * We lost a connection, remove it from our list and clean up
+ * the connection object itself.
+ *
+ * @param ct binding of connection to tunnel of the connection that was lost.
+ */
+void
+GCT_connection_lost (struct CadetTConnection *ct);
+
+
+/**
+ * Return the peer to which this tunnel goes.
+ *
+ * @param t a tunnel
+ * @return the destination of the tunnel
+ */
+struct CadetPeer *
+GCT_get_destination (struct CadetTunnel *t);
+
+
+/**
+ * Consider using the path @a p for the tunnel @a t.
+ * The tunnel destination is at offset @a off in path @a p.
+ *
+ * @param cls our tunnel
+ * @param path a path to our destination
+ * @param off offset of the destination on path @a path
+ */
+void
+GCT_consider_path (struct CadetTunnel *t,
+                   struct CadetPeerPath *p,
+                   unsigned int off);
+
+
+/**
+ * Add a channel to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @return unique number identifying @a ch within @a t
+ */
+struct GNUNET_CADET_ChannelTunnelNumber
+GCT_add_channel (struct CadetTunnel *t,
+                 struct CadetChannel *ch);
+
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @param ctn unique number identifying @a ch within @a t
+ */
+void
+GCT_remove_channel (struct CadetTunnel *t,
+                    struct CadetChannel *ch,
+                    struct GNUNET_CADET_ChannelTunnelNumber ctn);
+
+
+/**
+ * Send a DESTROY message via the tunnel.
+ *
+ * @param t the tunnel to transmit over
+ * @param ctn ID of the channel to destroy
+ */
+void
+GCT_send_channel_destroy (struct CadetTunnel *t,
+                          struct GNUNET_CADET_ChannelTunnelNumber ctn);
+
+
+/**
+ * Function called when a transmission requested using #GCT_send is done.
+ *
+ * @param cls closure
+ * @param ctn identifier of the connection used for transmission, NULL if
+ *            the transmission failed (to be used to match ACKs to the
+ *            respective connection for connection performance evaluation)
+ */
+typedef void
+(*GCT_SendContinuation)(void *cls,
+                        const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid);
+
+
+/**
+ * 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 cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ * @return Handle to cancel message.
+ */
+struct CadetTunnelQueueEntry *
+GCT_send (struct CadetTunnel *t,
+          const struct GNUNET_MessageHeader *message,
+          GCT_SendContinuation cont,
+          void *cont_cls);
+
+
+/**
+ * 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 entry to cancel.
+ */
+void
+GCT_send_cancel (struct CadetTunnelQueueEntry *q);
+
+
+/**
+ * Return the number of channels using a tunnel.
+ *
+ * @param t tunnel to count obtain the number of channels for
+ * @return number of channels using the tunnel
+ */
+unsigned int
+GCT_count_channels (struct CadetTunnel *t);
+
+
+/**
+ * Return the number of connections available for a tunnel.
+ *
+ * @param t tunnel to count obtain the number of connections for
+ * @return number of connections available for the tunnel
+ */
+unsigned int
+GCT_count_any_connections (const struct CadetTunnel *t);
+
+
+/**
+ * Iterator over connections.
+ *
+ * @param cls closure
+ * @param ct one of the connections
+ */
+typedef void
+(*GCT_ConnectionIterator) (void *cls,
+                           struct CadetTConnection *ct);
+
+
+/**
+ * Iterate over all connections of a tunnel.
+ *
+ * @param t Tunnel whose connections to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_connections (struct CadetTunnel *t,
+                         GCT_ConnectionIterator iter,
+                         void *iter_cls);
+
+
+/**
+ * Iterator over channels.
+ *
+ * @param cls closure
+ * @param ch one of the channels
+ */
+typedef void
+(*GCT_ChannelIterator) (void *cls,
+                        struct CadetChannel *ch);
+
+
+/**
+ * Iterate over all channels of a tunnel.
+ *
+ * @param t Tunnel whose channels to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_channels (struct CadetTunnel *t,
+                      GCT_ChannelIterator iter,
+                      void *iter_cls);
+
+
+/**
+ * Get the encryption state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's encryption state.
+ */
+enum CadetTunnelEState
+GCT_get_estate (struct CadetTunnel *t);
+
+
+/**
+ * Handle KX message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCT_handle_kx (struct CadetTConnection *ct,
+               const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg);
+
+
+/**
+ * Handle KX_AUTH message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the key exchange message
+ */
+void
+GCT_handle_kx_auth (struct CadetTConnection *ct,
+                    const struct GNUNET_CADET_TunnelKeyExchangeAuthMessage *msg);
+
+
+/**
+ * Handle encrypted message.
+ *
+ * @param ct connection/tunnel combo that received encrypted message
+ * @param msg the encrypted message to decrypt
+ */
+void
+GCT_handle_encrypted (struct CadetTConnection *ct,
+                      const struct GNUNET_CADET_TunnelEncryptedMessage *msg);
+
+
+/**
+ * Log all possible info about the tunnel state.
+ *
+ * @param t Tunnel to debug.
+ * @param level Debug level to use.
+ */
+void
+GCT_debug (const struct CadetTunnel *t,
+           enum GNUNET_ErrorType level);
+
+
+#endif
index e57c01be270d10364aad013a17b59c3fcf019184..8963d97c9420826980ad90e9ab1eeebe3b3b9bdb 100644 (file)
@@ -21,7 +21,7 @@
  * @file cadet/test_cadet.c
  * @author Bart Polot
  * @author Christian Grothoff
- * @brief Test for the cadet service: retransmission of traffic.
+ * @brief Test for the cadet service using mq API.
  */
 #include <stdio.h>
 #include "platform.h"
 
 
 /**
- * How many messages to send
+ * Ugly workaround to unify data handlers on incoming and outgoing channels.
  */
-#define TOTAL_PACKETS 500 /* Cannot exceed 64k! */
+struct CadetTestChannelWrapper
+{
+  /**
+   * Channel pointer.
+   */
+  struct GNUNET_CADET_Channel *ch;
+};
+
+/**
+ * How many messages to send by default.
+ */
+#define TOTAL_PACKETS 500       /* Cannot exceed 64k! */
 
 /**
  * How long until we give up on connecting the peers?
@@ -42,7 +53,7 @@
 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
 
 /**
- * Time to wait for stuff that should be rather fast
+ * Time to wait by default  for stuff that should be rather fast.
  */
 #define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
 
@@ -72,6 +83,16 @@ static char *test_name;
  */
 static int test_backwards = GNUNET_NO;
 
+/**
+ * How many packets to send.
+ */
+static unsigned int total_packets;
+
+/**
+ * Time to wait for fast operations.
+ */
+static struct GNUNET_TIME_Relative short_time;
+
 /**
  * How many events have happened
  */
@@ -83,9 +104,9 @@ static int ok;
 static int ok_goal;
 
 /**
- * Size of each test packet
+ * Size of each test packet's payload
  */
-static size_t size_payload = sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t);
+static size_t size_payload = sizeof (uint32_t);
 
 /**
  * Operation to get peer ids.
@@ -158,9 +179,9 @@ static struct GNUNET_SCHEDULER_Task *disconnect_task;
 static struct GNUNET_SCHEDULER_Task *test_task;
 
 /**
- * Task runnining #data_task().
+ * Task runnining #send_next_msg().
  */
-static struct GNUNET_SCHEDULER_Task *data_job;
+static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
 
 /**
  * Cadet handle for the root peer
@@ -175,24 +196,13 @@ static struct GNUNET_CADET_Handle *h2;
 /**
  * Channel handle for the root peer
  */
-static struct GNUNET_CADET_Channel *ch;
+static struct GNUNET_CADET_Channel *outgoing_ch;
 
 /**
  * Channel handle for the dest peer
  */
 static struct GNUNET_CADET_Channel *incoming_ch;
 
-/**
- * Transmit handle for root data calls
- */
-static struct GNUNET_CADET_TransmitHandle *th;
-
-/**
- * Transmit handle for root data calls
- */
-static struct GNUNET_CADET_TransmitHandle *incoming_th;
-
-
 /**
  * Time we started the data transmission (after channel has been established
  * and initilized).
@@ -225,20 +235,26 @@ static unsigned int ka_received;
 static unsigned int msg_dropped;
 
 
+/******************************************************************************/
+
+
+/******************************************************************************/
+
+
 /**
- * Get the client number considered as the "target" or "receiver", depending on
+ * Get the channel considered as the "target" or "receiver", depending on
  * the test type and size.
  *
- * @return Peer # of the target client, either 0 (for backward tests) or
- *         the last peer in the line (for other tests).
+ * @return Channel handle of the target client, either 0 (for backward tests)
+ *         or the last peer in the line (for other tests).
  */
-static unsigned int
-get_expected_target ()
+static struct GNUNET_CADET_Channel *
+get_target_channel ()
 {
   if (SPEED == test && GNUNET_YES == test_backwards)
-    return 0;
+    return outgoing_ch;
   else
-    return peers_requested - 1;
+    return incoming_ch;
 }
 
 
@@ -251,18 +267,15 @@ show_end_data (void)
   static struct GNUNET_TIME_Absolute end_time;
   static struct GNUNET_TIME_Relative total_time;
 
-  end_time = GNUNET_TIME_absolute_get();
-  total_time = GNUNET_TIME_absolute_get_difference(start_time, end_time);
+  end_time = GNUNET_TIME_absolute_get ();
+  total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
   FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
   FPRINTF (stderr, "Test time %s\n",
-          GNUNET_STRINGS_relative_time_to_string (total_time,
-                                                  GNUNET_YES));
-  FPRINTF (stderr, "Test bandwidth: %f kb/s\n",
-          4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000)); // 4bytes * ms
-  FPRINTF (stderr, "Test throughput: %f packets/s\n\n",
-          TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000)); // packets * ms
+           GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES));
+  FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4 * total_packets * 1.0 / (total_time.rel_value_us / 1000));    // 4bytes * ms
+  FPRINTF (stderr, "Test throughput: %f packets/s\n\n", total_packets * 1000.0 / (total_time.rel_value_us / 1000));     // packets * ms
   GAUGER ("CADET", test_name,
-          TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000),
+          total_packets * 1000.0 / (total_time.rel_value_us / 1000),
           "packets/s");
 }
 
@@ -281,29 +294,19 @@ disconnect_cadet_peers (void *cls)
 
   disconnect_task = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             "disconnecting cadet service of peers, called from line %ld\n",
-             line);
+              "disconnecting cadet service of peers, called from line %ld\n",
+              line);
   for (i = 0; i < 2; i++)
   {
     GNUNET_TESTBED_operation_done (t_op[i]);
   }
-  if (NULL != ch)
+  if (NULL != outgoing_ch)
   {
-    if (NULL != th)
-    {
-      GNUNET_CADET_notify_transmit_ready_cancel (th);
-      th = NULL;
-    }
-    GNUNET_CADET_channel_destroy (ch);
-    ch = NULL;
+    GNUNET_CADET_channel_destroy (outgoing_ch);
+    outgoing_ch = NULL;
   }
   if (NULL != incoming_ch)
   {
-    if (NULL != incoming_th)
-    {
-      GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
-      incoming_th = NULL;
-    }
     GNUNET_CADET_channel_destroy (incoming_ch);
     incoming_ch = NULL;
   }
@@ -322,10 +325,10 @@ static void
 shutdown_task (void *cls)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
-  if (NULL != data_job)
+  if (NULL != send_next_msg_task)
   {
-    GNUNET_SCHEDULER_cancel (data_job);
-    data_job = NULL;
+    GNUNET_SCHEDULER_cancel (send_next_msg_task);
+    send_next_msg_task = NULL;
   }
   if (NULL != test_task)
   {
@@ -335,8 +338,8 @@ shutdown_task (void *cls)
   if (NULL != disconnect_task)
   {
     GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
-                                               (void *) __LINE__);
+    disconnect_task =
+        GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__);
   }
 }
 
@@ -351,17 +354,11 @@ shutdown_task (void *cls)
  *          operation has executed successfully.
  */
 static void
-stats_cont (void *cls,
-            struct GNUNET_TESTBED_Operation *op,
-            const char *emsg)
+stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              " KA sent: %u, KA received: %u\n",
-              ka_sent,
-              ka_received);
-  if ( (KEEPALIVE == test) &&
-       ( (ka_sent < 2) ||
-         (ka_sent > ka_received + 1)) )
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n",
+              ka_sent, ka_received);
+  if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
   {
     GNUNET_break (0);
     ok--;
@@ -370,8 +367,7 @@ stats_cont (void *cls,
 
   if (NULL != disconnect_task)
     GNUNET_SCHEDULER_cancel (disconnect_task);
-  disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
-                                             cls);
+  disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls);
 }
 
 
@@ -387,11 +383,8 @@ stats_cont (void *cls,
  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
  */
 static int
-stats_iterator (void *cls,
-                const struct GNUNET_TESTBED_Peer *peer,
-                const char *subsystem,
-                const char *name,
-                uint64_t value,
+stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
+                const char *subsystem, const char *name, uint64_t value,
                 int is_persistent)
 {
   static const char *s_sent = "# keepalives sent";
@@ -401,19 +394,15 @@ stats_iterator (void *cls,
   uint32_t i;
 
   i = GNUNET_TESTBED_get_index (peer);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "STATS PEER %u - %s [%s]: %llu\n",
-              i,
-              subsystem,
-              name,
-              (unsigned long long) value);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
+              subsystem, name, (unsigned long long) value);
   if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
     ka_sent = value;
-  if (0 == strncmp(s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
+  if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
     ka_received = value;
-  if (0 == strncmp(rdrops, name, strlen (rdrops)))
+  if (0 == strncmp (rdrops, name, strlen (rdrops)))
     msg_dropped += value;
-  if (0 == strncmp(cdrops, name, strlen (cdrops)))
+  if (0 == strncmp (cdrops, name, strlen (cdrops)))
     msg_dropped += value;
 
   return GNUNET_OK;
@@ -423,7 +412,7 @@ stats_iterator (void *cls,
 /**
  * Task to gather all statistics.
  *
- * @param cls Closure (NULL).
+ * @param cls Closure (line from which the task was scheduled).
  */
 static void
 gather_stats_and_exit (void *cls)
@@ -432,21 +421,20 @@ gather_stats_and_exit (void *cls)
 
   disconnect_task = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             "gathering statistics from line %d\n",
-             (int) l);
-  if (NULL != ch)
+              "gathering statistics from line %ld\n",
+              l);
+  if (NULL != outgoing_ch)
   {
-    if (NULL != th)
-    {
-      GNUNET_CADET_notify_transmit_ready_cancel (th);
-      th = NULL;
-    }
-    GNUNET_CADET_channel_destroy (ch);
-    ch = NULL;
+    GNUNET_CADET_channel_destroy (outgoing_ch);
+    outgoing_ch = NULL;
   }
-  stats_op = GNUNET_TESTBED_get_statistics (peers_running, testbed_peers,
-                                            "cadet", NULL,
-                                            &stats_iterator, stats_cont, cls);
+  stats_op = GNUNET_TESTBED_get_statistics (peers_running,
+                                            testbed_peers,
+                                            "cadet",
+                                            NULL,
+                                            &stats_iterator,
+                                            stats_cont,
+                                            cls);
 }
 
 
@@ -462,163 +450,151 @@ abort_test (long line)
   if (NULL != disconnect_task)
   {
     GNUNET_SCHEDULER_cancel (disconnect_task);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Aborting test from %ld\n", line);
-    disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers,
-                                                (void *) line);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line);
+    disconnect_task =
+        GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line);
   }
 }
 
-/**
- * Transmit ready callback.
- *
- * @param cls Closure (message type).
- * @param size Size of the tranmist buffer.
- * @param buf Pointer to the beginning of the buffer.
- *
- * @return Number of bytes written to buf.
- */
-static size_t
-tmt_rdy (void *cls, size_t size, void *buf);
-
 
 /**
- * Task to request a new data transmission.
+ * Send a message on the channel with the appropriate size and payload.
+ *
+ * Update the appropriate *_sent counter.
  *
- * @param cls Closure (peer #).
+ * @param channel Channel to send the message on.
  */
 static void
-data_task (void *cls)
+send_test_message (struct GNUNET_CADET_Channel *channel)
 {
-  struct GNUNET_CADET_Channel *channel;
-  static struct GNUNET_CADET_TransmitHandle **pth;
-  long src;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_MessageHeader *msg;
+  uint32_t *data;
+  int payload;
+  int size;
 
-  data_job = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data task\n");
-  if (GNUNET_YES == test_backwards)
-  {
-    channel = incoming_ch;
-    pth = &incoming_th;
-    src = peers_requested - 1;
-  }
-  else
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending test message on channel %p\n",
+              channel);
+  size = size_payload;
+  if (GNUNET_NO == initialized)
   {
-    channel = ch;
-    pth = &th;
-    src = 0;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
+    size += 1000;
+    payload = data_sent;
+    if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
+        data_sent++;
   }
-
-  GNUNET_assert (NULL != channel);
-  GNUNET_assert (NULL == *pth);
-
-  *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
-                                             GNUNET_TIME_UNIT_FOREVER_REL,
-                                             size_payload + data_sent,
-                                             &tmt_rdy, (void *) src);
-  if (NULL == *pth)
+  else if (SPEED == test || SPEED_ACK == test)
   {
-    unsigned long i = (unsigned long) cls;
-
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Retransmission\n");
-    if (0 == i)
+    if (get_target_channel() == channel)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "  in 1 ms\n");
-      data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
-                                              &data_task, (void *) 1L);
+      payload = ack_sent;
+      size += ack_sent;
+      ack_sent++;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Sending ACK %u [%d bytes]\n",
+                  payload, size);
     }
     else
     {
-      i++;
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "in %llu ms\n",
-                  (unsigned long long) i);
-      data_job = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
-                                                                             i),
-                                              &data_task, (void *) i);
+      payload = data_sent;
+      size += data_sent;
+      data_sent++;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Sending DATA %u [%d bytes]\n",
+                  data_sent, size);
     }
   }
-}
+  else if (FORWARD == test)
+  {
+    payload = ack_sent;
+  }
+  else if (P2P_SIGNAL == test)
+  {
+    payload = data_sent;
+  }
+  else
+  {
+    GNUNET_assert (0);
+  }
+  env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY);
 
+  data = (uint32_t *) &msg[1];
+  *data = htonl (payload);
+  GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
+}
 
 /**
- * Transmit ready callback
+ * Task to request a new data transmission in a SPEED test, without waiting
+ * for previous messages to be sent/arrrive.
  *
- * @param cls Closure (peer # which is sending the data).
- * @param size Size of the buffer we have.
- * @param buf Buffer to copy data to.
+ * @param cls Closure (unused).
  */
-static size_t
-tmt_rdy (void *cls, size_t size, void *buf)
+static void
+send_next_msg (void *cls)
 {
-  struct GNUNET_MessageHeader *msg = buf;
-  size_t msg_size;
-  uint32_t *data;
-  long id = (long) cls;
-  unsigned int counter;
+  struct GNUNET_CADET_Channel *channel;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "tmt_rdy on %ld, filling buffer\n",
-              id);
-  if (0 == id)
-    th = NULL;
-  else if ((peers_requested - 1) == id)
-    incoming_th = NULL;
-  else
-    GNUNET_assert (0);
-  counter = get_expected_target () == id ? ack_sent : data_sent;
-  msg_size = size_payload + counter;
-  GNUNET_assert (msg_size > sizeof (struct GNUNET_MessageHeader));
-  if ( (size < msg_size) ||
-       (NULL == buf) )
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "size %u, buf %p, data_sent %u, ack_received %u\n",
-                (unsigned int) size,
-                buf,
-                data_sent,
-                ack_received);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ok %u, ok goal %u\n", ok, ok_goal);
-    GNUNET_break (ok >= ok_goal - 2);
-
-    return 0;
-  }
-  msg->size = htons (msg_size);
-  msg->type = htons (GNUNET_MESSAGE_TYPE_DUMMY);
-  data = (uint32_t *) &msg[1];
-  *data = htonl (counter);
-  if (GNUNET_NO == initialized)
+  send_next_msg_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent);
+
+  channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
+  GNUNET_assert (NULL != channel);
+  GNUNET_assert (SPEED == test);
+  send_test_message (channel);
+  if (data_sent < total_packets)
   {
+    /* SPEED test: Send all messages as soon as possible */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "sending initializer\n");
-    msg_size = size_payload + 1000;
-    msg->size = htons (msg_size);
-    if (SPEED_ACK == test)
-        data_sent++;
+                "Scheduling message %d\n",
+                data_sent + 1);
+    send_next_msg_task =
+        GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_UNIT_SECONDS,
+                                     &send_next_msg,
+                                     NULL);
   }
-  else if ( (SPEED == test) ||
-            (SPEED_ACK == test) )
+}
+
+
+/**
+ * Every few messages cancel the timeout task and re-schedule it again, to
+ * avoid timing out when traffic keeps coming.
+ *
+ * @param line Code line number to log if a timeout occurs.
+ */
+static void
+reschedule_timeout_task (long line)
+{
+  if ((ok % 10) == 0)
   {
-    if (get_expected_target() == id)
-      ack_sent++;
-    else
-      data_sent++;
-    counter++;
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                " Sent message %u size %u\n",
-                counter,
-                (unsigned int) msg_size);
-    if ( (data_sent < TOTAL_PACKETS) &&
-         (SPEED == test) )
+    if (NULL != disconnect_task)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  " Scheduling message %d\n",
-                  counter + 1);
-      data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL);
+                  " reschedule timeout every 10 messages\n");
+      GNUNET_SCHEDULER_cancel (disconnect_task);
+      disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
+                                                      &gather_stats_and_exit,
+                                                      (void *) line);
     }
   }
+}
+
 
-  return msg_size;
+/**
+ * Check if payload is sane (size contains payload).
+ *
+ * @param cls should match #ch
+ * @param message The actual message.
+ * @return #GNUNET_OK to keep the channel open,
+ *         #GNUNET_SYSERR to close it (signal serious error).
+ */
+static int
+check_data (void *cls, const struct GNUNET_MessageHeader *message)
+{
+  if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size))
+    return GNUNET_SYSERR;
+  return GNUNET_OK;             /* all is well-formed */
 }
 
 
@@ -626,75 +602,50 @@ tmt_rdy (void *cls, size_t size, void *buf)
  * Function is called whenever a message is received.
  *
  * @param cls closure (set from GNUNET_CADET_connect(), peer number)
- * @param channel connection to the other end
- * @param channel_ctx place to store local state associated with the channel
  * @param message the actual message
- * @return #GNUNET_OK to keep the connection open,
- *         #GNUNET_SYSERR to close it (signal serious error)
  */
-static int
-data_callback (void *cls,
-               struct GNUNET_CADET_Channel *channel,
-               void **channel_ctx,
-               const struct GNUNET_MessageHeader *message)
+static void
+handle_data (void *cls, const struct GNUNET_MessageHeader *message)
 {
-  struct GNUNET_CADET_TransmitHandle **pth;
-  long client = (long) cls;
-  long expected_target_client;
+  struct CadetTestChannelWrapper *ch = cls;
+  struct GNUNET_CADET_Channel *channel = ch->ch;
   uint32_t *data;
   uint32_t payload;
-  unsigned int counter;
+  int *counter;
 
   ok++;
-  counter = get_expected_target () == client ? data_received : ack_received;
-
   GNUNET_CADET_receive_done (channel);
+  counter = get_target_channel () == channel ? &data_received : &ack_received;
 
-  if ((ok % 10) == 0)
+  reschedule_timeout_task ((long) __LINE__);
+
+  if (channel == outgoing_ch)
   {
-    if (NULL != disconnect_task)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  " reschedule timeout\n");
-      GNUNET_SCHEDULER_cancel (disconnect_task);
-      disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
-                                                      &gather_stats_and_exit,
-                                                      (void *) __LINE__);
-    }
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message.\n");
   }
-
-  switch (client)
+  else if (channel == incoming_ch)
   {
-  case 0L:
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
-    GNUNET_assert (channel == ch);
-    pth = &th;
-    break;
-  case 1L:
-  case 4L:
-    GNUNET_assert (client == peers_requested - 1);
-    GNUNET_assert (channel == incoming_ch);
-    pth = &incoming_th;
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client %ld got a message.\n",
-                client);
-    break;
-  default:
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Client %ld not valid.\n", client);
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n");
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel);
     GNUNET_assert (0);
   }
+
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
   data = (uint32_t *) &message[1];
   payload = ntohl (*data);
-  if (payload == counter)
+  if (payload == *counter)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload);
   }
   else
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, " payload %u, expected: %u\n",
-                payload, counter);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                " payload %u, expected: %u\n",
+                payload, *counter);
   }
-  expected_target_client = get_expected_target ();
 
   if (GNUNET_NO == initialized)
   {
@@ -702,189 +653,152 @@ data_callback (void *cls,
     start_time = GNUNET_TIME_absolute_get ();
     if (SPEED == test)
     {
-      GNUNET_assert (peers_requested - 1 == client);
-      data_job = GNUNET_SCHEDULER_add_now (&data_task, NULL);
-      return GNUNET_OK;
+      GNUNET_assert (incoming_ch == channel);
+      send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
+      return;
     }
   }
 
-  counter++;
-  if (client == expected_target_client) /* Normally 4 */
+  (*counter)++;
+  if (get_target_channel () == channel) /* Got "data" */
   {
-    data_received++;
     GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
     if (SPEED != test || (ok_goal - 2) == ok)
     {
       /* Send ACK */
-      GNUNET_assert (NULL == *pth);
-      *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
-                                                 GNUNET_TIME_UNIT_FOREVER_REL,
-                                                 size_payload + ack_sent,
-                                                 &tmt_rdy, (void *) client);
-      return GNUNET_OK;
+      send_test_message (channel);
+      return;
     }
     else
     {
-      if (data_received < TOTAL_PACKETS)
-        return GNUNET_OK;
+      if (data_received < total_packets)
+        return;
     }
   }
-  else /* Normally 0 */
+  else /* Got "ack" */
   {
     if (SPEED_ACK == test || SPEED == test)
     {
-      ack_received++;
       GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
-      /* send more data */
-      GNUNET_assert (NULL == *pth);
-      *pth = GNUNET_CADET_notify_transmit_ready (channel, GNUNET_NO,
-                                                 GNUNET_TIME_UNIT_FOREVER_REL,
-                                                 size_payload + data_sent,
-                                                 &tmt_rdy, (void *) client);
-      if (ack_received < TOTAL_PACKETS && SPEED != test)
-        return GNUNET_OK;
+      /* Send more data */
+      send_test_message (channel);
+      if (ack_received < total_packets && SPEED != test)
+        return;
       if (ok == 2 && SPEED == test)
-        return GNUNET_OK;
-      show_end_data();
+        return;
+      show_end_data ();
     }
     if (test == P2P_SIGNAL)
     {
-      if (NULL != incoming_th)
-      {
-        GNUNET_CADET_notify_transmit_ready_cancel (incoming_th);
-        incoming_th = NULL;
-      }
       GNUNET_CADET_channel_destroy (incoming_ch);
       incoming_ch = NULL;
     }
     else
     {
-      if (NULL != th)
-      {
-        GNUNET_CADET_notify_transmit_ready_cancel (th);
-        th = NULL;
-      }
-      GNUNET_CADET_channel_destroy (ch);
-      ch = NULL;
+      GNUNET_CADET_channel_destroy (outgoing_ch);
+      outgoing_ch = NULL;
     }
   }
-
-  return GNUNET_OK;
 }
 
 
 /**
- * Data handlers for every message type of CADET's payload.
- * {callback_function, message_type, size_expected}
- */
-static struct GNUNET_CADET_MessageHandler handlers[] = {
-  {&data_callback,
-   GNUNET_MESSAGE_TYPE_DUMMY,
-   sizeof (struct GNUNET_MessageHeader)},
-  {NULL, 0, 0}
-};
-
-
-/**
- * Method called whenever another peer has added us to a channel
- * the other peer initiated.
+ * Method called whenever a peer connects to a port in MQ-based CADET.
  *
- * @param cls Closure.
+ * @param cls Closure from #GNUNET_CADET_open_port (peer # as long).
  * @param channel New handle to the channel.
- * @param initiator Peer that started the channel.
- * @param port Port this channel is connected to.
- * @param options channel option flags
- * @return Initial channel context for the channel
- *         (can be NULL -- that's not an error).
+ * @param source Peer that started this channel.
+ * @return Closure for the incoming @a channel. It's given to:
+ *         - The #GNUNET_CADET_DisconnectEventHandler (given to
+ *           #GNUNET_CADET_open_port) when the channel dies.
+ *         - Each the #GNUNET_MQ_MessageCallback handlers for each message
+ *           received on the @a channel.
  */
 static void *
-incoming_channel (void *cls,
-                  struct GNUNET_CADET_Channel *channel,
-                  const struct GNUNET_PeerIdentity *initiator,
-                  const struct GNUNET_HashCode *port,
-                  enum GNUNET_CADET_ChannelOption options)
+connect_handler (void *cls, struct GNUNET_CADET_Channel *channel,
+                 const struct GNUNET_PeerIdentity *source)
 {
+  struct CadetTestChannelWrapper *ch;
+  long peer = (long) cls;
+
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Incoming channel from %s to peer %d:%s\n",
-              GNUNET_i2s (initiator),
-              (int) (long) cls, GNUNET_h2s (port));
+              "Incoming channel from %s to %ld: %p\n",
+              GNUNET_i2s (source), peer, channel);
   ok++;
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
-  if ((long) cls == peers_requested - 1)
+  if (peer == peers_requested - 1)
   {
     if (NULL != incoming_ch)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "Duplicate incoming channel for client %lu\n",
-                  (long) cls);
-      GNUNET_break(0);
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Duplicate incoming channel for client %lu\n", (long) cls);
+      GNUNET_assert (0);
     }
     incoming_ch = channel;
   }
   else
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Incoming channel for unexpected peer #%lu\n",
-                (long) cls);
-    GNUNET_break (0);
+                "Incoming channel for unexpected peer #%lu\n", (long) cls);
+    GNUNET_assert (0);
   }
   if (NULL != disconnect_task)
   {
     GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+    disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
                                                     &gather_stats_and_exit,
                                                     (void *) __LINE__);
   }
 
-  return NULL;
+  /* TODO: cannot return channel as-is, in order to unify the data handlers */
+  ch = GNUNET_new (struct CadetTestChannelWrapper);
+  ch->ch = channel;
+
+  return ch;
 }
 
 
 /**
- * Function called whenever an inbound channel is destroyed.  Should clean up
- * any associated state.
+ * Function called whenever an MQ-channel is destroyed, even if the destruction
+ * was requested by #GNUNET_CADET_channel_destroy.
+ * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
+ *
+ * It should clean up any associated state, including cancelling any pending
+ * transmission on this channel.
  *
- * @param cls closure (set from GNUNET_CADET_connect, peer number)
- * @param channel connection to the other end (henceforth invalid)
- * @param channel_ctx place where local state associated
- *                   with the channel is stored
+ * @param cls Channel closure (channel wrapper).
+ * @param channel Connection to the other end (henceforth invalid).
  */
 static void
-channel_cleaner (void *cls,
-                 const struct GNUNET_CADET_Channel *channel,
-                 void *channel_ctx)
+disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel)
 {
-  long i = (long) cls;
+  struct CadetTestChannelWrapper *ch_w = cls;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Incoming channel disconnected at peer %ld\n",
-              i);
-  if (peers_running - 1 == i)
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n");
+  GNUNET_assert (ch_w->ch == channel);
+  if (channel == incoming_ch)
   {
     ok++;
-    GNUNET_break (channel == incoming_ch);
     incoming_ch = NULL;
   }
-  else if (0L == i)
+  else if (outgoing_ch == channel
+  )
   {
     if (P2P_SIGNAL == test)
     {
       ok++;
     }
-    GNUNET_break (channel == ch);
-    ch = NULL;
+    outgoing_ch = NULL;
   }
   else
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Unknown peer! %d\n",
-                (int) i);
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
 
   if (NULL != disconnect_task)
   {
     GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task = GNUNET_SCHEDULER_add_now (&gather_stats_and_exit,
-                                                (void *) __LINE__);
+    disconnect_task =
+        GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__);
   }
 }
 
@@ -898,13 +812,20 @@ channel_cleaner (void *cls,
  * @param cls Closure (unused).
  */
 static void
-do_test (void *cls)
+start_test (void *cls)
 {
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (data,
+                           GNUNET_MESSAGE_TYPE_DUMMY,
+                           struct GNUNET_MessageHeader,
+                           NULL),
+    GNUNET_MQ_handler_end ()
+  };
+  struct CadetTestChannelWrapper *ch;
   enum GNUNET_CADET_ChannelOption flags;
 
   test_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "do_test\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n");
   if (NULL != disconnect_task)
   {
     GNUNET_SCHEDULER_cancel (disconnect_task);
@@ -918,30 +839,33 @@ do_test (void *cls)
     flags |= GNUNET_CADET_OPTION_RELIABLE;
   }
 
-  ch = GNUNET_CADET_channel_create (h1,
-                                    NULL,
-                                    p_id[1],
-                                    &port,
-                                    flags);
+  ch = GNUNET_new (struct CadetTestChannelWrapper);
+  outgoing_ch = GNUNET_CADET_channel_create (h1,
+                                             ch,
+                                             p_id[1],
+                                             &port,
+                                             flags,
+                                             NULL,
+                                             &disconnect_handler,
+                                             handlers);
+
+  ch->ch = outgoing_ch;
 
-  disconnect_task
-    = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
-                                    &gather_stats_and_exit,
-                                    (void *) __LINE__);
+  disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
+                                                  &gather_stats_and_exit,
+                                                  (void *) __LINE__);
   if (KEEPALIVE == test)
-    return; /* Don't send any data. */
+    return;                     /* Don't send any data. */
+
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending data initializer...\n");
   data_received = 0;
   data_sent = 0;
   ack_received = 0;
   ack_sent = 0;
-  th = GNUNET_CADET_notify_transmit_ready (ch,
-                                           GNUNET_NO,
-                                           GNUNET_TIME_UNIT_FOREVER_REL,
-                                           size_payload + 1000,
-                                           &tmt_rdy, (void *) 0L);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending data initializer on channel %p...\n",
+              outgoing_ch);
+  send_test_message (outgoing_ch);
 }
 
 
@@ -955,35 +879,26 @@ do_test (void *cls)
  *             NULL if the operation is successfull
  */
 static void
-pi_cb (void *cls,
-       struct GNUNET_TESTBED_Operation *op,
-       const struct GNUNET_TESTBED_PeerInformation *pinfo,
-       const char *emsg)
+pi_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
+       const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg)
 {
   long i = (long) cls;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "id callback for %ld\n", i);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i);
 
-  if ( (NULL == pinfo) ||
-       (NULL != emsg) )
+  if ((NULL == pinfo) || (NULL != emsg))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "pi_cb: %s\n", emsg);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
     abort_test (__LINE__);
     return;
   }
   p_id[i] = pinfo->result.id;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "  id: %s\n", GNUNET_i2s (p_id[i]));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  id: %s\n", GNUNET_i2s (p_id[i]));
   p_ids++;
   if (p_ids < 2)
     return;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Got all IDs, starting test\n");
-  test_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
-                                            &do_test,
-                                            NULL);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
+  test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL);
 }
 
 
@@ -994,7 +909,7 @@ pi_cb (void *cls,
  * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
  * @param num_peers Number of peers that are running.
  * @param peers Array of peers.
- * @param cadetes Handle to each of the CADETs of the peers.
+ * @param cadets Handle to each of the CADETs of the peers.
  */
 static void
 tmain (void *cls,
@@ -1011,16 +926,18 @@ tmain (void *cls,
   testbed_peers = peers;
   h1 = cadets[0];
   h2 = cadets[num_peers - 1];
-  disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
+  disconnect_task = GNUNET_SCHEDULER_add_delayed (short_time,
                                                   &disconnect_cadet_peers,
                                                   (void *) __LINE__);
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
   t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
                                                  GNUNET_TESTBED_PIT_IDENTITY,
-                                                 &pi_cb, (void *) 0L);
+                                                 &pi_cb,
+                                                 (void *) 0L);
   t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
                                                  GNUNET_TESTBED_PIT_IDENTITY,
-                                                 &pi_cb, (void *) 1L);
+                                                 &pi_cb,
+                                                 (void *) 1L);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
 }
 
@@ -1031,16 +948,46 @@ tmain (void *cls,
 int
 main (int argc, char *argv[])
 {
-  initialized = GNUNET_NO;
   static const struct GNUNET_HashCode *ports[2];
+  struct GNUNET_MQ_MessageHandler handlers[] = {
+    GNUNET_MQ_hd_var_size (data,
+                           GNUNET_MESSAGE_TYPE_DUMMY,
+                           struct GNUNET_MessageHeader,
+                           NULL),
+    GNUNET_MQ_handler_end ()
+  };
   const char *config_file;
   char port_id[] = "test port";
-  GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
+                                            "time",
+                                            "short_time",
+                                            gettext_noop ("set short timeout"),
+                                            &short_time),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('m',
+                                   "messages",
+                                   "NUM_MESSAGES",
+                                   gettext_noop ("set number of messages to send"),
+                                   &total_packets),
+
+    GNUNET_GETOPT_OPTION_END
+  };
 
+
+  initialized = GNUNET_NO;
   GNUNET_log_setup ("test", "DEBUG", NULL);
-  config_file = "test_cadet.conf";
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
+  total_packets = TOTAL_PACKETS;
+  short_time = SHORT_TIME;
+  if (-1 == GNUNET_GETOPT_run (argv[0], options, argc, argv))
+  {
+    FPRINTF (stderr, "test failed: problem with CLI parameters\n");
+    exit (1);
+  }
+
+  config_file = "test_cadet.conf";
+  GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
 
   /* Find out requested size */
   if (strstr (argv[0], "_2_") != NULL)
@@ -1078,11 +1025,11 @@ main (int argc, char *argv[])
   {
     /* Test is supposed to generate the following callbacks:
      * 1 incoming channel (@dest)
-     * TOTAL_PACKETS received data packet (@dest)
-     * TOTAL_PACKETS received data packet (@orig)
+     * total_packets received data packet (@dest)
+     * total_packets received data packet (@orig)
      * 1 received channel destroy (@dest)
      */
-    ok_goal = TOTAL_PACKETS * 2 + 2;
+    ok_goal = total_packets * 2 + 2;
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
     test = SPEED_ACK;
     test_name = "speed ack";
@@ -1092,11 +1039,11 @@ main (int argc, char *argv[])
     /* Test is supposed to generate the following callbacks:
      * 1 incoming channel (@dest)
      * 1 initial packet (@dest)
-     * TOTAL_PACKETS received data packet (@dest)
+     * total_packets received data packet (@dest)
      * 1 received data packet (@orig)
      * 1 received channel destroy (@dest)
      */
-    ok_goal = TOTAL_PACKETS + 4;
+    ok_goal = total_packets + 4;
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
     if (strstr (argv[0], "_reliable") != NULL)
     {
@@ -1137,22 +1084,22 @@ main (int argc, char *argv[])
   p_ids = 0;
   ports[0] = &port;
   ports[1] = NULL;
-  GNUNET_CADET_TEST_run ("test_cadet_small",
-                        config_file,
-                        peers_requested,
-                        &tmain,
-                        NULL, /* tmain cls */
-                        &incoming_channel,
-                        &channel_cleaner,
-                        handlers,
-                        ports);
+  GNUNET_CADET_TEST_ruN ("test_cadet_small",
+                         config_file,
+                         peers_requested,
+                         &tmain,
+                         NULL,        /* tmain cls */
+                         &connect_handler,
+                         NULL,
+                         &disconnect_handler,
+                         handlers,
+                         ports);
   if (NULL != strstr (argv[0], "_reliable"))
-    msg_dropped = 0; /* dropped should be retransmitted */
+    msg_dropped = 0;            /* dropped should be retransmitted */
 
   if (ok_goal > ok - msg_dropped)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "FAILED! (%d/%d)\n", ok, ok_goal);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal);
     return 1;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
diff --git a/src/cadet/test_cadet_local.c b/src/cadet/test_cadet_local.c
deleted file mode 100644 (file)
index 2b915ab..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/test_cadet_local.c
- * @brief test cadet local: test of cadet channels with just one peer
- * @author Bartlomiej Polot
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_dht_service.h"
-#include "gnunet_testing_lib.h"
-#include "gnunet_cadet_service.h"
-
-struct GNUNET_TESTING_Peer *me;
-
-static struct GNUNET_CADET_Handle *cadet_peer_1;
-
-static struct GNUNET_CADET_Handle *cadet_peer_2;
-
-static struct GNUNET_CADET_Channel *ch;
-
-static int result = GNUNET_OK;
-
-static int got_data = GNUNET_NO;
-
-static struct GNUNET_SCHEDULER_Task *abort_task;
-
-static struct GNUNET_SCHEDULER_Task *connect_task;
-
-static struct GNUNET_CADET_TransmitHandle *mth;
-
-
-/**
- * Connect to other client and send data
- *
- * @param cls Closue (unused).
- */
-static void
-do_connect (void *cls);
-
-
-/**
- * Shutdown nicely
- */
-static void
-do_shutdown (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "shutdown\n");
-  if (NULL != abort_task)
-  {
-    GNUNET_SCHEDULER_cancel (abort_task);
-    abort_task = NULL;
-  }
-  if (NULL != ch)
-  {
-    GNUNET_CADET_channel_destroy (ch);
-    ch = NULL;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Disconnect client 1\n");
-  if (NULL != cadet_peer_1)
-  {
-    GNUNET_CADET_disconnect (cadet_peer_1);
-    cadet_peer_1 = NULL;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Disconnect client 2\n");
-  if (NULL != cadet_peer_2)
-  {
-    GNUNET_CADET_disconnect (cadet_peer_2);
-    cadet_peer_2 = NULL;
-  }
-  if (NULL != connect_task)
-  {
-    GNUNET_SCHEDULER_cancel (connect_task);
-    connect_task = NULL;
-  }
-}
-
-
-/**
- * Something went wrong and timed out. Kill everything and set error flag
- */
-static void
-do_abort (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
-  result = GNUNET_SYSERR;
-  abort_task = NULL;
-  GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Function is called whenever a message is received.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end
- * @param channel_ctx place to store local state associated with the channel
- * @param message the actual message
- * @return #GNUNET_OK to keep the connection open,
- *         #GNUNET_SYSERR to close it (signal serious error)
- */
-static int
-data_callback (void *cls,
-               struct GNUNET_CADET_Channel *channel,
-               void **channel_ctx,
-               const struct GNUNET_MessageHeader *message)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Data callback! Shutting down.\n");
-  got_data = GNUNET_YES;
-  GNUNET_SCHEDULER_shutdown ();
-  GNUNET_CADET_receive_done (channel);
-  return GNUNET_OK;
-}
-
-
-/**
- * Method called whenever another peer has added us to a channel
- * the other peer initiated.
- *
- * @param cls closure
- * @param channel new handle to the channel
- * @param initiator peer that started the channel
- * @param port port number
- * @param options channel options
- * @return initial channel context for the channel
- *         (can be NULL -- that's not an error)
- */
-static void *
-inbound_channel (void *cls,
-                 struct GNUNET_CADET_Channel *channel,
-                 const struct GNUNET_PeerIdentity *initiator,
-                 const struct GNUNET_HashCode *port,
-                 enum GNUNET_CADET_ChannelOption options)
-{
-  long id = (long) cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "received incoming channel on peer %d, port %s\n",
-              (int) id,
-              GNUNET_h2s (port));
-  if (id != 2L)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "wrong peer\n");
-    result = GNUNET_SYSERR;
-  }
-  return NULL;
-}
-
-
-/**
- * Function called whenever an channel is destroyed.  Should clean up
- * any associated state.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end (henceforth invalid)
- * @param channel_ctx place where local state associated
- *                    with the channel is stored
- */
-static void
-channel_end (void *cls,
-             const struct GNUNET_CADET_Channel *channel,
-             void *channel_ctx)
-{
-  long id = (long) cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "incoming channel closed at peer %ld\n",
-              id);
-  if (NULL != mth)
-  {
-    GNUNET_CADET_notify_transmit_ready_cancel (mth);
-    mth = NULL;
-  }
-  if (channel == ch)
-    ch = NULL;
-  if (GNUNET_NO == got_data)
-  {
-    if (NULL == connect_task)
-      connect_task
-        = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
-                                                                       2),
-                                        &do_connect,
-                                        NULL);
-  }
-}
-
-
-/**
- * Handler array for traffic received on peer1
- */
-static struct GNUNET_CADET_MessageHandler handlers1[] = {
-  {&data_callback, 1, 0},
-  {NULL, 0, 0}
-};
-
-
-/**
- * Handler array for traffic received on peer2 (none expected)
- */
-static struct GNUNET_CADET_MessageHandler handlers2[] = {
-  {&data_callback, 1, 0},
-  {NULL, 0, 0}
-};
-
-
-/**
- * Data send callback: fillbuffer with test packet.
- *
- * @param cls Closure (unused).
- * @param size Buffer size.
- * @param buf Buffer to fill.
- *
- * @return size of test packet.
- */
-static size_t
-do_send (void *cls, size_t size, void *buf)
-{
-  struct GNUNET_MessageHeader *m = buf;
-
-  mth = NULL;
-  if (NULL == buf)
-  {
-    GNUNET_break (0);
-    result = GNUNET_SYSERR;
-    return 0;
-  }
-  m->size = htons (sizeof (struct GNUNET_MessageHeader));
-  m->type = htons (1);
-  GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
-  return sizeof (struct GNUNET_MessageHeader);
-}
-
-
-/**
- * Connect to other client and send data
- *
- * @param cls Closue (unused).
- */
-static void
-do_connect (void *cls)
-{
-  struct GNUNET_PeerIdentity id;
-
-  connect_task = NULL;
-  GNUNET_TESTING_peer_get_identity (me, &id);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "CONNECT BY PORT\n");
-  ch = GNUNET_CADET_channel_create (cadet_peer_1,
-                                    NULL,
-                                    &id, GC_u2h (1),
-                                    GNUNET_CADET_OPTION_DEFAULT);
-  mth = GNUNET_CADET_notify_transmit_ready (ch, GNUNET_NO,
-                                            GNUNET_TIME_UNIT_FOREVER_REL,
-                                            sizeof (struct GNUNET_MessageHeader),
-                                            &do_send, NULL);
-}
-
-
-/**
- * Initialize framework and start test
- *
- * @param cls Closure (unused).
- * @param cfg Configuration handle.
- * @param peer Testing peer handle.
- */
-static void
-run (void *cls,
-     const struct GNUNET_CONFIGURATION_Handle *cfg,
-     struct GNUNET_TESTING_Peer *peer)
-{
-  me = peer;
-  GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
-                                 NULL);
-  abort_task =
-      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
-                                    (GNUNET_TIME_UNIT_SECONDS, 15),
-                                   &do_abort,
-                                    NULL);
-  cadet_peer_1 = GNUNET_CADET_connect (cfg,       /* configuration */
-                                     (void *) 1L,       /* cls */
-                                     &channel_end,      /* channel end hndlr */
-                                     handlers1); /* traffic handlers */
-  cadet_peer_2 = GNUNET_CADET_connect (cfg,       /* configuration */
-                                     (void *) 2L,     /* cls */
-                                     &channel_end,      /* channel end hndlr */
-                                     handlers2); /* traffic handlers */
-
-  if ( (NULL == cadet_peer_1) ||
-       (NULL == cadet_peer_2) )
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               "Couldn't connect to cadet :(\n");
-    result = GNUNET_SYSERR;
-    GNUNET_SCHEDULER_shutdown ();
-    return;
-  }
-  GNUNET_CADET_open_port (cadet_peer_2,
-                          GC_u2h (1),
-                          &inbound_channel,
-                          (void *) 2L);
-  if (NULL == connect_task)
-    connect_task
-      = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
-                                                                     2),
-                                      &do_connect,
-                                      NULL);
-}
-
-
-/**
- * Main
- */
-int
-main (int argc, char *argv[])
-{
-  if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
-                                    "test_cadet.conf",
-                                &run, NULL))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "run failed\n");
-    return 2;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Final result: %d\n", result);
-  return (result == GNUNET_OK) ? 0 : 1;
-}
-
-/* end of test_cadet_local_1.c */
index 19bafbed1fae6fba0753f5bd1361d9983a15a2f3..3089c7fbb262f0bda4348a1d6064b25c655df2c3 100644 (file)
@@ -132,12 +132,12 @@ do_abort (void *cls)
 /**
  * Method called whenever a peer connects to a port in MQ-based CADET.
  *
- * @param cls Closure from #GNUNET_CADET_open_porT.
+ * @param cls Closure from #GNUNET_CADET_open_port.
  * @param channel New handle to the channel.
  * @param source Peer that started this channel.
  * @return Closure for the incoming @a channel. It's given to:
  *         - The #GNUNET_CADET_DisconnectEventHandler (given to
- *           #GNUNET_CADET_open_porT) when the channel dies.
+ *           #GNUNET_CADET_open_port) when the channel dies.
  *         - Each the #GNUNET_MQ_MessageCallback handlers for each message
  *           received on the @a channel.
  */
@@ -235,7 +235,7 @@ do_connect (void *cls)
   GNUNET_TESTING_peer_get_identity (me, &id);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "creating channel\n");
-  ch = GNUNET_CADET_channel_creatE (cadet_peer_1, /* cadet handle */
+  ch = GNUNET_CADET_channel_create (cadet_peer_1, /* cadet handle */
                                     NULL,         /* channel cls */
                                     &id,          /* destination */
                                     GC_u2h (TEST_MESSAGE_TYPE), /* port */
@@ -282,8 +282,8 @@ run (void *cls,
   abort_task = GNUNET_SCHEDULER_add_delayed (delay,
                                              &do_abort,
                                              (void *) (long) __LINE__);
-  cadet_peer_1 = GNUNET_CADET_connecT (cfg);
-  cadet_peer_2 = GNUNET_CADET_connecT (cfg);
+  cadet_peer_1 = GNUNET_CADET_connect (cfg);
+  cadet_peer_2 = GNUNET_CADET_connect (cfg);
 
   if ( (NULL == cadet_peer_1) ||
        (NULL == cadet_peer_2) )
@@ -297,7 +297,7 @@ run (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CADET 1: %p\n", cadet_peer_1);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CADET 2: %p\n", cadet_peer_2);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handlers 2: %p\n", handlers);
-  GNUNET_CADET_open_porT (cadet_peer_2,          /* cadet handle */
+  GNUNET_CADET_open_port (cadet_peer_2,          /* cadet handle */
                           GC_u2h (TEST_PORT_ID), /* port id */
                           &connected,            /* connect handler */
                           (void *) 2L,           /* handle for #connected */
diff --git a/src/cadet/test_cadet_new.c b/src/cadet/test_cadet_new.c
deleted file mode 100644 (file)
index d324048..0000000
+++ /dev/null
@@ -1,1048 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011, 2017 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file cadet/test_cadet_mq.c
- * @author Bart Polot
- * @author Christian Grothoff
- * @brief Test for the cadet service using mq API.
- */
-#include <stdio.h>
-#include "platform.h"
-#include "cadet_test_lib_new.h"
-#include "gnunet_cadet_service.h"
-#include "gnunet_statistics_service.h"
-#include <gauger.h>
-
-
-/**
- * Ugly workaround to unify data handlers on incoming and outgoing channels.
- */
-struct CadetTestChannelWrapper
-{
-  /**
-   * Channel pointer.
-   */
-  struct GNUNET_CADET_Channel *ch;
-};
-
-/**
- * How many messages to send
- */
-#define TOTAL_PACKETS 500       /* Cannot exceed 64k! */
-
-/**
- * How long until we give up on connecting the peers?
- */
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
-
-/**
- * Time to wait for stuff that should be rather fast
- */
-#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
-
-/**
- * DIFFERENT TESTS TO RUN
- */
-#define SETUP 0
-#define FORWARD 1
-#define KEEPALIVE 2
-#define SPEED 3
-#define SPEED_ACK 4
-#define SPEED_REL 8
-#define P2P_SIGNAL 10
-
-/**
- * Which test are we running?
- */
-static int test;
-
-/**
- * String with test name
- */
-static char *test_name;
-
-/**
- * Flag to send traffic leaf->root in speed tests to test BCK_ACK logic.
- */
-static int test_backwards = GNUNET_NO;
-
-/**
- * How many events have happened
- */
-static int ok;
-
-/**
- * Number of events expected to conclude the test successfully.
- */
-static int ok_goal;
-
-/**
- * Size of each test packet's payload
- */
-static size_t size_payload = sizeof (uint32_t);
-
-/**
- * Operation to get peer ids.
- */
-static struct GNUNET_TESTBED_Operation *t_op[2];
-
-/**
- * Peer ids.
- */
-static struct GNUNET_PeerIdentity *p_id[2];
-
-/**
- * Port ID
- */
-static struct GNUNET_HashCode port;
-
-/**
- * Peer ids counter.
- */
-static unsigned int p_ids;
-
-/**
- * Is the setup initialized?
- */
-static int initialized;
-
-/**
- * Number of payload packes sent.
- */
-static int data_sent;
-
-/**
- * Number of payload packets received.
- */
-static int data_received;
-
-/**
- * Number of payload packed acknowledgements sent.
- */
-static int ack_sent;
-
-/**
- * Number of payload packed explicitly (app level) acknowledged.
- */
-static int ack_received;
-
-/**
- * Total number of peers asked to run.
- */
-static unsigned long long peers_requested;
-
-/**
- * Number of currently running peers (should be same as @c peers_requested).
- */
-static unsigned long long peers_running;
-
-/**
- * Test context (to shut down).
- */
-struct GNUNET_CADET_TEST_Context *test_ctx;
-
-/**
- * Task called to disconnect peers.
- */
-static struct GNUNET_SCHEDULER_Task *disconnect_task;
-
-/**
- * Task To perform tests
- */
-static struct GNUNET_SCHEDULER_Task *test_task;
-
-/**
- * Task runnining #send_next_msg().
- */
-static struct GNUNET_SCHEDULER_Task *send_next_msg_task;
-
-/**
- * Cadet handle for the root peer
- */
-static struct GNUNET_CADET_Handle *h1;
-
-/**
- * Cadet handle for the first leaf peer
- */
-static struct GNUNET_CADET_Handle *h2;
-
-/**
- * Channel handle for the root peer
- */
-static struct GNUNET_CADET_Channel *outgoing_ch;
-
-/**
- * Channel handle for the dest peer
- */
-static struct GNUNET_CADET_Channel *incoming_ch;
-
-/**
- * Time we started the data transmission (after channel has been established
- * and initilized).
- */
-static struct GNUNET_TIME_Absolute start_time;
-
-/**
- * Peers handle.
- */
-static struct GNUNET_TESTBED_Peer **testbed_peers;
-
-/**
- * Statistics operation handle.
- */
-static struct GNUNET_TESTBED_Operation *stats_op;
-
-/**
- * Keepalives sent.
- */
-static unsigned int ka_sent;
-
-/**
- * Keepalives received.
- */
-static unsigned int ka_received;
-
-/**
- * How many messages were dropped by CADET because of full buffers?
- */
-static unsigned int msg_dropped;
-
-
-/******************************************************************************/
-
-
-/******************************************************************************/
-
-
-/**
- * Get the channel considered as the "target" or "receiver", depending on
- * the test type and size.
- *
- * @return Channel handle of the target client, either 0 (for backward tests)
- *         or the last peer in the line (for other tests).
- */
-static struct GNUNET_CADET_Channel *
-get_target_channel ()
-{
-  if (SPEED == test && GNUNET_YES == test_backwards)
-    return outgoing_ch;
-  else
-    return incoming_ch;
-}
-
-
-/**
- * Show the results of the test (banwidth acheived) and log them to GAUGER
- */
-static void
-show_end_data (void)
-{
-  static struct GNUNET_TIME_Absolute end_time;
-  static struct GNUNET_TIME_Relative total_time;
-
-  end_time = GNUNET_TIME_absolute_get ();
-  total_time = GNUNET_TIME_absolute_get_difference (start_time, end_time);
-  FPRINTF (stderr, "\nResults of test \"%s\"\n", test_name);
-  FPRINTF (stderr, "Test time %s\n",
-           GNUNET_STRINGS_relative_time_to_string (total_time, GNUNET_YES));
-  FPRINTF (stderr, "Test bandwidth: %f kb/s\n", 4 * TOTAL_PACKETS * 1.0 / (total_time.rel_value_us / 1000));    // 4bytes * ms
-  FPRINTF (stderr, "Test throughput: %f packets/s\n\n", TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000));     // packets * ms
-  GAUGER ("CADET", test_name,
-          TOTAL_PACKETS * 1000.0 / (total_time.rel_value_us / 1000),
-          "packets/s");
-}
-
-
-/**
- * Disconnect from cadet services af all peers, call shutdown.
- *
- * @param cls Closure (line number from which termination was requested).
- * @param tc Task Context.
- */
-static void
-disconnect_cadet_peers (void *cls)
-{
-  long line = (long) cls;
-  unsigned int i;
-
-  disconnect_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "disconnecting cadet service of peers, called from line %ld\n",
-              line);
-  for (i = 0; i < 2; i++)
-  {
-    GNUNET_TESTBED_operation_done (t_op[i]);
-  }
-  if (NULL != outgoing_ch)
-  {
-    GNUNET_CADET_channel_destroy (outgoing_ch);
-    outgoing_ch = NULL;
-  }
-  if (NULL != incoming_ch)
-  {
-    GNUNET_CADET_channel_destroy (incoming_ch);
-    incoming_ch = NULL;
-  }
-  GNUNET_CADET_TEST_cleanup (test_ctx);
-  GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Shut down peergroup, clean up.
- *
- * @param cls Closure (unused).
- * @param tc Task Context.
- */
-static void
-shutdown_task (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending test.\n");
-  if (NULL != send_next_msg_task)
-  {
-    GNUNET_SCHEDULER_cancel (send_next_msg_task);
-    send_next_msg_task = NULL;
-  }
-  if (NULL != test_task)
-  {
-    GNUNET_SCHEDULER_cancel (test_task);
-    test_task = NULL;
-  }
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task =
-        GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) __LINE__);
-  }
-}
-
-
-/**
- * Stats callback. Finish the stats testbed operation and when all stats have
- * been iterated, shutdown the test.
- *
- * @param cls Closure (line number from which termination was requested).
- * @param op the operation that has been finished
- * @param emsg error message in case the operation has failed; will be NULL if
- *          operation has executed successfully.
- */
-static void
-stats_cont (void *cls, struct GNUNET_TESTBED_Operation *op, const char *emsg)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " KA sent: %u, KA received: %u\n",
-              ka_sent, ka_received);
-  if ((KEEPALIVE == test) && ((ka_sent < 2) || (ka_sent > ka_received + 1)))
-  {
-    GNUNET_break (0);
-    ok--;
-  }
-  GNUNET_TESTBED_operation_done (stats_op);
-
-  if (NULL != disconnect_task)
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-  disconnect_task = GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, cls);
-}
-
-
-/**
- * Process statistic values.
- *
- * @param cls closure (line number, unused)
- * @param peer the peer the statistic belong to
- * @param subsystem name of subsystem that created the statistic
- * @param name the name of the datum
- * @param value the current value
- * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not
- * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
- */
-static int
-stats_iterator (void *cls, const struct GNUNET_TESTBED_Peer *peer,
-                const char *subsystem, const char *name, uint64_t value,
-                int is_persistent)
-{
-  static const char *s_sent = "# keepalives sent";
-  static const char *s_recv = "# keepalives received";
-  static const char *rdrops = "# messages dropped due to full buffer";
-  static const char *cdrops = "# messages dropped due to slow client";
-  uint32_t i;
-
-  i = GNUNET_TESTBED_get_index (peer);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "STATS PEER %u - %s [%s]: %llu\n", i,
-              subsystem, name, (unsigned long long) value);
-  if (0 == strncmp (s_sent, name, strlen (s_sent)) && 0 == i)
-    ka_sent = value;
-  if (0 == strncmp (s_recv, name, strlen (s_recv)) && peers_requested - 1 == i)
-    ka_received = value;
-  if (0 == strncmp (rdrops, name, strlen (rdrops)))
-    msg_dropped += value;
-  if (0 == strncmp (cdrops, name, strlen (cdrops)))
-    msg_dropped += value;
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Task to gather all statistics.
- *
- * @param cls Closure (line from which the task was scheduled).
- */
-static void
-gather_stats_and_exit (void *cls)
-{
-  long l = (long) cls;
-
-  disconnect_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "gathering statistics from line %ld\n",
-              l);
-  if (NULL != outgoing_ch)
-  {
-    GNUNET_CADET_channel_destroy (outgoing_ch);
-    outgoing_ch = NULL;
-  }
-  stats_op = GNUNET_TESTBED_get_statistics (peers_running,
-                                            testbed_peers,
-                                            "cadet",
-                                            NULL,
-                                            &stats_iterator,
-                                            stats_cont,
-                                            cls);
-}
-
-
-
-/**
- * Abort test: schedule disconnect and shutdown immediately
- *
- * @param line Line in the code the abort is requested from (__LINE__).
- */
-static void
-abort_test (long line)
-{
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Aborting test from %ld\n", line);
-    disconnect_task =
-        GNUNET_SCHEDULER_add_now (&disconnect_cadet_peers, (void *) line);
-  }
-}
-
-
-/**
- * Send a message on the channel with the appropriate size and payload.
- *
- * Update the appropriate *_sent counter.
- *
- * @param channel Channel to send the message on.
- */
-static void
-send_test_message (struct GNUNET_CADET_Channel *channel)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *msg;
-  uint32_t *data;
-  int *counter;
-  int size;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending test message on channel %p\n",
-              channel);
-  size = size_payload;
-  if (GNUNET_NO == initialized)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending INITIALIZER\n");
-    size += 1000;
-    counter = &data_sent;
-    if (SPEED_ACK == test) // FIXME unify SPEED_ACK with an initializer
-        data_sent++;
-  }
-  else if (SPEED == test || SPEED_ACK == test)
-  {
-    counter = get_target_channel() == channel ? &ack_sent : &data_sent;
-    size += *counter;
-    *counter = *counter + 1;
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sending message %u\n", *counter);
-  }
-  else
-  {
-    counter =  &ack_sent;
-  }
-  env = GNUNET_MQ_msg_extra (msg, size, GNUNET_MESSAGE_TYPE_DUMMY);
-
-  data = (uint32_t *) &msg[1];
-  *data = htonl (*counter);
-  GNUNET_MQ_send (GNUNET_CADET_get_mq (channel), env);
-}
-
-/**
- * Task to request a new data transmission in a SPEED test, without waiting
- * for previous messages to be sent/arrrive.
- *
- * @param cls Closure (unused).
- */
-static void
-send_next_msg (void *cls)
-{
-  struct GNUNET_CADET_Channel *channel;
-
-  send_next_msg_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending next message: %d\n", data_sent);
-
-  channel = GNUNET_YES == test_backwards ? incoming_ch : outgoing_ch;
-  GNUNET_assert (NULL != channel);
-  GNUNET_assert (SPEED == test);
-  send_test_message (channel);
-  if (data_sent < TOTAL_PACKETS)
-  {
-    /* SPEED test: Send all messages as soon as possible */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Scheduling message %d\n",
-                data_sent + 1);
-    send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
-  }
-}
-
-
-/**
- * Every few messages cancel the timeout task and re-schedule it again, to
- * avoid timing out when traffic keeps coming.
- *
- * @param line Code line number to log if a timeout occurs.
- */
-static void
-reschedule_timeout_task (long line)
-{
-  if ((ok % 10) == 0)
-  {
-    if (NULL != disconnect_task)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  " reschedule timeout every 10 messages\n");
-      GNUNET_SCHEDULER_cancel (disconnect_task);
-      disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
-                                                      &gather_stats_and_exit,
-                                                      (void *) line);
-    }
-  }
-}
-
-
-/**
- * Check if payload is sane (size contains payload).
- *
- * @param cls should match #ch
- * @param message The actual message.
- * @return #GNUNET_OK to keep the channel open,
- *         #GNUNET_SYSERR to close it (signal serious error).
- */
-static int
-check_data (void *cls, const struct GNUNET_MessageHeader *message)
-{
-  if (sizeof (struct GNUNET_MessageHeader) >= ntohs (message->size))
-    return GNUNET_SYSERR;
-  return GNUNET_OK;             /* all is well-formed */
-}
-
-
-/**
- * Function is called whenever a message is received.
- *
- * @param cls closure (set from GNUNET_CADET_connect(), peer number)
- * @param message the actual message
- */
-static void
-handle_data (void *cls, const struct GNUNET_MessageHeader *message)
-{
-  struct CadetTestChannelWrapper *ch = cls;
-  struct GNUNET_CADET_Channel *channel = ch->ch;
-  uint32_t *data;
-  uint32_t payload;
-  int *counter;
-
-  ok++;
-  counter = get_target_channel () == channel ? &data_received : &ack_received;
-
-  reschedule_timeout_task ((long) __LINE__);
-
-  if (channel == outgoing_ch)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Root client got a message!\n");
-  }
-  else if (channel == incoming_ch)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Leaf client got a message.\n");
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown channel %p.\n", channel);
-    GNUNET_assert (0);
-  }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: (%d/%d)\n", ok, ok_goal);
-  data = (uint32_t *) &message[1];
-  payload = ntohl (*data);
-  if (payload == *counter)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, " payload as expected: %u\n", payload);
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                " payload %u, expected: %u\n",
-                payload, *counter);
-  }
-
-  if (GNUNET_NO == initialized)
-  {
-    initialized = GNUNET_YES;
-    start_time = GNUNET_TIME_absolute_get ();
-    if (SPEED == test)
-    {
-      GNUNET_assert (incoming_ch == channel);
-      send_next_msg_task = GNUNET_SCHEDULER_add_now (&send_next_msg, NULL);
-      return;
-    }
-  }
-
-  (*counter)++;
-  if (get_target_channel () == channel) /* Got "data" */
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received data %u\n", data_received);
-    if (SPEED != test || (ok_goal - 2) == ok)
-    {
-      /* Send ACK */
-      send_test_message (channel);
-      return;
-    }
-    else
-    {
-      if (data_received < TOTAL_PACKETS)
-        return;
-    }
-  }
-  else /* Got "ack" */
-  {
-    if (SPEED_ACK == test || SPEED == test)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO, " received ack %u\n", ack_received);
-      /* Send more data */
-      send_test_message (channel);
-      if (ack_received < TOTAL_PACKETS && SPEED != test)
-        return;
-      if (ok == 2 && SPEED == test)
-        return;
-      show_end_data ();
-    }
-    if (test == P2P_SIGNAL)
-    {
-      GNUNET_CADET_channel_destroy (incoming_ch);
-      incoming_ch = NULL;
-    }
-    else
-    {
-      GNUNET_CADET_channel_destroy (outgoing_ch);
-      outgoing_ch = NULL;
-    }
-  }
-}
-
-
-/**
- * Method called whenever a peer connects to a port in MQ-based CADET.
- *
- * @param cls Closure from #GNUNET_CADET_open_porT (peer # as long).
- * @param channel New handle to the channel.
- * @param source Peer that started this channel.
- * @return Closure for the incoming @a channel. It's given to:
- *         - The #GNUNET_CADET_DisconnectEventHandler (given to
- *           #GNUNET_CADET_open_porT) when the channel dies.
- *         - Each the #GNUNET_MQ_MessageCallback handlers for each message
- *           received on the @a channel.
- */
-static void *
-connect_handler (void *cls, struct GNUNET_CADET_Channel *channel,
-                 const struct GNUNET_PeerIdentity *source)
-{
-  struct CadetTestChannelWrapper *ch;
-  long peer = (long) cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Incoming channel from %s to peer %ld\n",
-              GNUNET_i2s (source), peer);
-  ok++;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
-  if (peer == peers_requested - 1)
-  {
-    if (NULL != incoming_ch)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Duplicate incoming channel for client %lu\n", (long) cls);
-      GNUNET_assert (0);
-    }
-    incoming_ch = channel;
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Incoming channel for unexpected peer #%lu\n", (long) cls);
-    GNUNET_assert (0);
-  }
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task =
-        GNUNET_SCHEDULER_add_delayed (SHORT_TIME, &gather_stats_and_exit,
-                                      (void *) __LINE__);
-  }
-
-  /* TODO: cannot return channel as-is, in order to unify the data handlers */
-  ch = GNUNET_new (struct CadetTestChannelWrapper);
-  ch->ch = channel;
-
-  return ch;
-}
-
-
-/**
- * Function called whenever an MQ-channel is destroyed, even if the destruction
- * was requested by #GNUNET_CADET_channel_destroy.
- * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
- *
- * It should clean up any associated state, including cancelling any pending
- * transmission on this channel.
- *
- * @param cls Channel closure (channel wrapper).
- * @param channel Connection to the other end (henceforth invalid).
- */
-static void
-disconnect_handler (void *cls, const struct GNUNET_CADET_Channel *channel)
-{
-  struct CadetTestChannelWrapper *ch_w = cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Channel disconnected\n");
-  GNUNET_assert (ch_w->ch == channel);
-  if (channel == incoming_ch)
-  {
-    ok++;
-    incoming_ch = NULL;
-  }
-  else if (outgoing_ch == channel
-  )
-  {
-    if (P2P_SIGNAL == test)
-    {
-      ok++;
-    }
-    outgoing_ch = NULL;
-  }
-  else
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unknown channel! %p\n", channel);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, " ok: %d\n", ok);
-
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task =
-        GNUNET_SCHEDULER_add_now (&gather_stats_and_exit, (void *) __LINE__);
-  }
-}
-
-
-/**
- * START THE TESTCASE ITSELF, AS WE ARE CONNECTED TO THE CADET SERVICES.
- *
- * Testcase continues when the root receives confirmation of connected peers,
- * on callback function ch.
- *
- * @param cls Closure (unused).
- */
-static void
-start_test (void *cls)
-{
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_var_size (data,
-                           GNUNET_MESSAGE_TYPE_DUMMY,
-                           struct GNUNET_MessageHeader,
-                           NULL),
-    GNUNET_MQ_handler_end ()
-  };
-  struct CadetTestChannelWrapper *ch;
-  enum GNUNET_CADET_ChannelOption flags;
-
-  test_task = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "start_test\n");
-  if (NULL != disconnect_task)
-  {
-    GNUNET_SCHEDULER_cancel (disconnect_task);
-    disconnect_task = NULL;
-  }
-
-  flags = GNUNET_CADET_OPTION_DEFAULT;
-  if (SPEED_REL == test)
-  {
-    test = SPEED;
-    flags |= GNUNET_CADET_OPTION_RELIABLE;
-  }
-
-  ch = GNUNET_new (struct CadetTestChannelWrapper);
-  outgoing_ch = GNUNET_CADET_channel_creatE (h1,
-                                             ch,
-                                             p_id[1],
-                                             &port,
-                                             flags,
-                                             NULL,
-                                             &disconnect_handler,
-                                             handlers);
-  ch->ch = outgoing_ch;
-
-  disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
-                                                  &gather_stats_and_exit,
-                                                  (void *) __LINE__);
-  if (KEEPALIVE == test)
-    return;                     /* Don't send any data. */
-
-
-  data_received = 0;
-  data_sent = 0;
-  ack_received = 0;
-  ack_sent = 0;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending data initializer...\n");
-  send_test_message (outgoing_ch);
-}
-
-
-/**
- * Callback to be called when the requested peer information is available
- *
- * @param cls the closure from GNUNET_TESTBED_peer_get_information()
- * @param op the operation this callback corresponds to
- * @param pinfo the result; will be NULL if the operation has failed
- * @param emsg error message if the operation has failed;
- *             NULL if the operation is successfull
- */
-static void
-pi_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
-       const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg)
-{
-  long i = (long) cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ID callback for %ld\n", i);
-
-  if ((NULL == pinfo) || (NULL != emsg))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "pi_cb: %s\n", emsg);
-    abort_test (__LINE__);
-    return;
-  }
-  p_id[i] = pinfo->result.id;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "  id: %s\n", GNUNET_i2s (p_id[i]));
-  p_ids++;
-  if (p_ids < 2)
-    return;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n");
-  test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL);
-}
-
-
-/**
- * test main: start test when all peers are connected
- *
- * @param cls Closure.
- * @param ctx Argument to give to GNUNET_CADET_TEST_cleanup on test end.
- * @param num_peers Number of peers that are running.
- * @param peers Array of peers.
- * @param cadets Handle to each of the CADETs of the peers.
- */
-static void
-tmain (void *cls,
-       struct GNUNET_CADET_TEST_Context *ctx,
-       unsigned int num_peers,
-       struct GNUNET_TESTBED_Peer **peers,
-       struct GNUNET_CADET_Handle **cadets)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test main\n");
-  ok = 0;
-  test_ctx = ctx;
-  peers_running = num_peers;
-  GNUNET_assert (peers_running == peers_requested);
-  testbed_peers = peers;
-  h1 = cadets[0];
-  h2 = cadets[num_peers - 1];
-  disconnect_task = GNUNET_SCHEDULER_add_delayed (SHORT_TIME,
-                                                  &disconnect_cadet_peers,
-                                                  (void *) __LINE__);
-  GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
-  t_op[0] = GNUNET_TESTBED_peer_get_information (peers[0],
-                                                 GNUNET_TESTBED_PIT_IDENTITY,
-                                                 &pi_cb,
-                                                 (void *) 0L);
-  t_op[1] = GNUNET_TESTBED_peer_get_information (peers[num_peers - 1],
-                                                 GNUNET_TESTBED_PIT_IDENTITY,
-                                                 &pi_cb,
-                                                 (void *) 1L);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "requested peer ids\n");
-}
-
-
-/**
- * Main: start test
- */
-int
-main (int argc, char *argv[])
-{
-  struct GNUNET_MQ_MessageHandler handlers[] = {
-    GNUNET_MQ_hd_var_size (data,
-                           GNUNET_MESSAGE_TYPE_DUMMY,
-                           struct GNUNET_MessageHeader,
-                           NULL),
-    GNUNET_MQ_handler_end ()
-  };
-
-  initialized = GNUNET_NO;
-  static const struct GNUNET_HashCode *ports[2];
-  const char *config_file;
-  char port_id[] = "test port";
-
-  GNUNET_CRYPTO_hash (port_id, sizeof (port_id), &port);
-
-  GNUNET_log_setup ("test", "DEBUG", NULL);
-  config_file = "test_cadet.conf";
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start\n");
-
-  /* Find out requested size */
-  if (strstr (argv[0], "_2_") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "DIRECT CONNECTIONs\n");
-    peers_requested = 2;
-  }
-  else if (strstr (argv[0], "_5_") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "5 PEER LINE\n");
-    peers_requested = 5;
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SIZE UNKNOWN, USING 2\n");
-    peers_requested = 2;
-  }
-
-  /* Find out requested test */
-  if (strstr (argv[0], "_forward") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "FORWARD\n");
-    test = FORWARD;
-    test_name = "unicast";
-    ok_goal = 4;
-  }
-  else if (strstr (argv[0], "_signal") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SIGNAL\n");
-    test = P2P_SIGNAL;
-    test_name = "signal";
-    ok_goal = 4;
-  }
-  else if (strstr (argv[0], "_speed_ack") != NULL)
-  {
-    /* Test is supposed to generate the following callbacks:
-     * 1 incoming channel (@dest)
-     * TOTAL_PACKETS received data packet (@dest)
-     * TOTAL_PACKETS received data packet (@orig)
-     * 1 received channel destroy (@dest)
-     */
-    ok_goal = TOTAL_PACKETS * 2 + 2;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED_ACK\n");
-    test = SPEED_ACK;
-    test_name = "speed ack";
-  }
-  else if (strstr (argv[0], "_speed") != NULL)
-  {
-    /* Test is supposed to generate the following callbacks:
-     * 1 incoming channel (@dest)
-     * 1 initial packet (@dest)
-     * TOTAL_PACKETS received data packet (@dest)
-     * 1 received data packet (@orig)
-     * 1 received channel destroy (@dest)
-     */
-    ok_goal = TOTAL_PACKETS + 4;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "SPEED\n");
-    if (strstr (argv[0], "_reliable") != NULL)
-    {
-      test = SPEED_REL;
-      test_name = "speed reliable";
-      config_file = "test_cadet_drop.conf";
-    }
-    else
-    {
-      test = SPEED;
-      test_name = "speed";
-    }
-  }
-  else if (strstr (argv[0], "_keepalive") != NULL)
-  {
-    test = KEEPALIVE;
-    /* Test is supposed to generate the following callbacks:
-     * 1 incoming channel (@dest)
-     * [wait]
-     * 1 received channel destroy (@dest)
-     */
-    ok_goal = 2;
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "UNKNOWN\n");
-    test = SETUP;
-    ok_goal = 0;
-  }
-
-  if (strstr (argv[0], "backwards") != NULL)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "BACKWARDS (LEAF TO ROOT)\n");
-    test_backwards = GNUNET_YES;
-    GNUNET_asprintf (&test_name, "backwards %s", test_name);
-  }
-
-  p_ids = 0;
-  ports[0] = &port;
-  ports[1] = NULL;
-  GNUNET_CADET_TEST_ruN ("test_cadet_small",
-                         config_file,
-                         peers_requested,
-                         &tmain,
-                         NULL,        /* tmain cls */
-                         &connect_handler,
-                         NULL,
-                         &disconnect_handler,
-                         handlers,
-                         ports);
-  if (NULL != strstr (argv[0], "_reliable"))
-    msg_dropped = 0;            /* dropped should be retransmitted */
-
-  if (ok_goal > ok - msg_dropped)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "FAILED! (%d/%d)\n", ok, ok_goal);
-    return 1;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "success\n");
-  return 0;
-}
-
-/* end of test_cadet.c */
diff --git a/src/cadet/test_cadet_single.c b/src/cadet/test_cadet_single.c
deleted file mode 100644 (file)
index b45b0af..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file cadet/test_cadet_single.c
- * @brief test cadet single: test of cadet channels with just one client
- * @author Bartlomiej Polot
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_dht_service.h"
-#include "gnunet_testing_lib.h"
-#include "gnunet_cadet_service.h"
-
-#define REPETITIONS 5
-#define DATA_SIZE 35000
-
-struct GNUNET_TESTING_Peer *me;
-
-static struct GNUNET_CADET_Handle *cadet;
-
-static struct GNUNET_CADET_Channel *ch1;
-
-static struct GNUNET_CADET_Channel *ch2;
-
-static int result;
-
-static struct GNUNET_SCHEDULER_Task *abort_task;
-
-static struct GNUNET_SCHEDULER_Task *connect_task;
-
-static unsigned int repetition;
-
-static struct GNUNET_CADET_TransmitHandle *nth;
-
-static struct GNUNET_CADET_Port *port;
-
-
-/* forward declaration */
-static size_t
-do_send (void *cls, size_t size, void *buf);
-
-
-/**
- * Shutdown nicely
- */
-static void
-do_shutdown (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "shutdown\n");
-  if (NULL != port)
-  {
-    GNUNET_CADET_close_port (port);
-    port = NULL;
-  }
-  if (NULL != nth)
-  {
-    GNUNET_CADET_notify_transmit_ready_cancel (nth);
-    nth = NULL;
-  }
-  if (NULL != abort_task)
-  {
-    GNUNET_SCHEDULER_cancel (abort_task);
-    abort_task = NULL;
-  }
-  if (NULL != connect_task)
-  {
-    GNUNET_SCHEDULER_cancel (connect_task);
-    connect_task = NULL;
-  }
-  if (NULL != ch1)
-  {
-    GNUNET_CADET_channel_destroy (ch1);
-    ch1 = NULL;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Disconnect clients\n");
-  if (NULL != cadet)
-  {
-    GNUNET_CADET_disconnect (cadet);
-    cadet = NULL;
-  }
-  else
-  {
-    GNUNET_break (0);
-  }
-}
-
-
-/**
- * Something went wrong and timed out. Kill everything and set error flag
- */
-static void
-do_abort (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ABORT\n");
-  result = GNUNET_SYSERR;
-  abort_task = NULL;
-  GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Function is called whenever a message is received.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end
- * @param channel_ctx place to store local state associated with the channel
- * @param message the actual message
- * @return #GNUNET_OK to keep the connection open,
- *         #GNUNET_SYSERR to close it (signal serious error)
- */
-static int
-data_callback (void *cls,
-               struct GNUNET_CADET_Channel *channel,
-               void **channel_ctx,
-               const struct GNUNET_MessageHeader *message)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Data callback! Repetition %u/%u\n",
-              repetition, REPETITIONS);
-  repetition++;
-  if (repetition < REPETITIONS)
-  {
-    struct GNUNET_CADET_Channel *my_channel;
-    if (0 == repetition % 2)
-      my_channel = ch1;
-    else
-      my_channel = ch2;
-    nth = GNUNET_CADET_notify_transmit_ready (my_channel,
-                                              GNUNET_NO,
-                                              GNUNET_TIME_UNIT_FOREVER_REL,
-                                              sizeof (struct GNUNET_MessageHeader)
-                                              + DATA_SIZE,
-                                              &do_send, NULL);
-    GNUNET_CADET_receive_done (channel);
-    return GNUNET_OK;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "All data OK. Destroying channel.\n");
-  GNUNET_assert (NULL == nth);
-  GNUNET_CADET_channel_destroy (ch1);
-  ch1 = NULL;
-  return GNUNET_OK;
-}
-
-
-/**
- * Method called whenever another peer has added us to a channel
- * the other peer initiated.
- *
- * @param cls closure
- * @param channel new handle to the channel
- * @param initiator peer that started the channel
- * @param port port number
- * @param options channel option flags
- * @return initial channel context for the channel
- *         (can be NULL -- that's not an error)
- */
-static void *
-inbound_channel (void *cls,
-                 struct GNUNET_CADET_Channel *channel,
-                 const struct GNUNET_PeerIdentity *initiator,
-                 const struct GNUNET_HashCode *port,
-                 enum GNUNET_CADET_ChannelOption options)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "received incoming channel on port %s\n",
-              GNUNET_h2s (port));
-  ch2 = channel;
-  return NULL;
-}
-
-
-/**
- * Function called whenever an inbound channel is destroyed.  Should clean up
- * any associated state.
- *
- * @param cls closure (set from GNUNET_CADET_connect)
- * @param channel connection to the other end (henceforth invalid)
- * @param channel_ctx place where local state associated
- *                   with the channel is stored
- */
-static void
-channel_end (void *cls,
-             const struct GNUNET_CADET_Channel *channel,
-             void *channel_ctx)
-{
-  long id = (long) cls;
-
-  nth = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "incoming channel closed at peer %ld\n",
-              id);
-  if ( (REPETITIONS == repetition) &&
-       (channel == ch2) )
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "everything fine! finishing!\n");
-    result = GNUNET_OK;
-    GNUNET_SCHEDULER_shutdown ();
-  }
-  if (channel == ch2)
-    ch2 = NULL;
-  if (channel == ch1)
-    ch1 = NULL;
-}
-
-
-/**
- * Handler array for traffic received on peer1
- */
-static struct GNUNET_CADET_MessageHandler handlers1[] = {
-  {&data_callback, 1, 0},
-  {NULL, 0, 0}
-};
-
-
-/**
- * Data send callback: fillbuffer with test packet.
- *
- * @param cls Closure (unused).
- * @param size Buffer size.
- * @param buf Buffer to fill.
- * @return size of test packet.
- */
-static size_t
-do_send (void *cls, size_t size, void *buf)
-{
-  struct GNUNET_MessageHeader *m = buf;
-
-  nth = NULL;
-  if (NULL == buf)
-  {
-    GNUNET_break (0);
-    result = GNUNET_SYSERR;
-    return 0;
-  }
-  m->size = htons (sizeof (struct GNUNET_MessageHeader) + DATA_SIZE);
-  m->type = htons (1);
-  memset (&m[1], 0, DATA_SIZE);
-  GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader) + DATA_SIZE);
-  return sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
-}
-
-/**
- * Connect to other client and send data
- *
- * @param cls Closue (unused).
- */
-static void
-do_connect (void *cls)
-{
-  struct GNUNET_PeerIdentity id;
-  size_t size = sizeof (struct GNUNET_MessageHeader) + DATA_SIZE;
-
-  connect_task = NULL;
-  GNUNET_TESTING_peer_get_identity (me, &id);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "CONNECT BY PORT\n");
-  ch1 = GNUNET_CADET_channel_create (cadet, NULL, &id, GC_u2h (1),
-                                     GNUNET_CADET_OPTION_DEFAULT);
-  nth = GNUNET_CADET_notify_transmit_ready (ch1,
-                                            GNUNET_NO,
-                                            GNUNET_TIME_UNIT_FOREVER_REL,
-                                            size,
-                                            &do_send,
-                                            NULL);
-}
-
-
-/**
- * Initialize framework and start test
- *
- * @param cls Closure (unused).
- * @param cfg Configuration handle.
- * @param peer Testing peer handle.
- */
-static void
-run (void *cls,
-     const struct GNUNET_CONFIGURATION_Handle *cfg,
-     struct GNUNET_TESTING_Peer *peer)
-{
-  me = peer;
-  GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
-  abort_task =
-      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
-                                    (GNUNET_TIME_UNIT_SECONDS, 15), &do_abort,
-                                    NULL);
-  cadet = GNUNET_CADET_connect (cfg,       /* configuration */
-                              (void *) 1L,     /* cls */
-                              &channel_end,      /* inbound end hndlr */
-                              handlers1); /* traffic handlers */
-  port = GNUNET_CADET_open_port (cadet,
-                                 GC_u2h (1),
-                                 &inbound_channel,
-                                 (void *) 1L);
-
-
-  if (NULL == cadet)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Couldn't connect to cadet :(\n");
-    result = GNUNET_SYSERR;
-    return;
-  }
-  connect_task
-    = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
-                                   &do_connect,
-                                   NULL);
-}
-
-
-/**
- * Main
- */
-int
-main (int argc,
-      char *argv[])
-{
-  result = GNUNET_NO;
-  if (0 != GNUNET_TESTING_peer_run ("test-cadet-local",
-                                    "test_cadet.conf",
-                                    &run, NULL))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "run failed\n");
-    return 2;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Final result: %d\n",
-              result);
-  return (result == GNUNET_OK) ? 0 : 1;
-}
-
-/* end of test_cadet_single.c */
index 2b1987fbcb52b10efedbebacaaf38ee24c6b6e29..c0205ee5dca4ad4bfda02ac12a8bb9f5d801328a 100644 (file)
@@ -18,8 +18,6 @@ if USE_COVERAGE
   AM_CFLAGS = -fprofile-arcs -ftest-coverage
 endif
 
-bin_PROGRAMS = \
- gnunet-consensus-profiler
 
 libexec_PROGRAMS = \
  gnunet-service-consensus
@@ -86,6 +84,9 @@ libgnunet_plugin_block_consensus_la_LDFLAGS = \
 
 
 if HAVE_TESTING
+bin_PROGRAMS = \
+ gnunet-consensus-profiler
+
 check_PROGRAMS = \
  test_consensus_api
 
index e0002de5606b36bd2c2ff4ba45784f3ab6f3dd24..f2933ed6f8cb32c1c6e211436e2a6373791774f3 100644 (file)
@@ -45,37 +45,37 @@ GNUNET_NETWORK_STRUCT_BEGIN
 struct GNUNET_CONSENSUS_RoundContextMessage
 {
   /**
-   * Type: GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_ROUND_CONTEXT
+   * Type: #GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_ROUND_CONTEXT
    */
   struct GNUNET_MessageHeader header;
 
   /**
    * A value from 'enum PhaseKind'.
    */
-  uint16_t kind;
+  uint16_t kind GNUNET_PACKED;
 
   /**
    * Number of the first peer
    * in canonical order.
    */
-  int16_t peer1;
+  int16_t peer1 GNUNET_PACKED;
 
   /**
    * Number of the second peer in canonical order.
    */
-  int16_t peer2;
+  int16_t peer2 GNUNET_PACKED;
 
   /**
    * Repetition of the gradecast phase.
    */
-  int16_t repetition;
+  int16_t repetition GNUNET_PACKED;
 
   /**
    * Leader in the gradecast phase.
    *
    * Can be different from both peer1 and peer2.
    */
-  int16_t leader;
+  int16_t leader GNUNET_PACKED;
 
   /**
    * Non-zero if this set reconciliation
@@ -85,7 +85,7 @@ struct GNUNET_CONSENSUS_RoundContextMessage
    *
    * Ignored for set operations that are not within gradecasts.
    */
-  uint16_t is_contested;
+  uint16_t is_contested GNUNET_PACKED;
 };
 
 
@@ -104,7 +104,7 @@ struct ConsensusElement
    * Payload element_type, only valid
    * if this is not a marker element.
    */
-  uint16_t payload_type;
+  uint16_t payload_type GNUNET_PACKED;
 
   /**
    * Is this a marker element?
@@ -117,7 +117,7 @@ struct ConsensusElement
 
 struct ConsensusSizeElement
 {
-  struct ConsensusElement ce GNUNET_PACKED;
+  struct ConsensusElement ce;
 
   uint64_t size GNUNET_PACKED;
   uint8_t sender_index;
@@ -125,7 +125,7 @@ struct ConsensusSizeElement
 
 struct ConsensusStuffedElement
 {
-  struct ConsensusElement ce GNUNET_PACKED;
+  struct ConsensusElement ce;
   struct GNUNET_HashCode rand GNUNET_PACKED;
 };
 
index 65542f4cd133ac543d3a4463582f55d69b3396fe..8cc1b35120545f58ea24992c142be3cb48ff2f29 100644 (file)
@@ -515,31 +515,55 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char **argv)
 {
-   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-      { 'n', "num-peers", NULL,
-        gettext_noop ("number of peers in consensus"),
-        GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers },
-      { 'k', "value-replication", NULL,
-        gettext_noop ("how many peers (random selection without replacement) receive one value?"),
-        GNUNET_YES, &GNUNET_GETOPT_set_uint, &replication },
-      { 'x', "num-values", NULL,
-        gettext_noop ("number of values"),
-        GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_values },
-      { 't', "timeout", NULL,
-        gettext_noop ("consensus timeout"),
-        GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &conclude_timeout },
-      { 'd', "delay", NULL,
-        gettext_noop ("delay until consensus starts"),
-        GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &consensus_delay },
-      { 's', "statistics", NULL,
-        gettext_noop ("write statistics to file"),
-        GNUNET_YES, &GNUNET_GETOPT_set_filename, &statistics_filename },
-      { 'S', "dist-static", NULL,
-        gettext_noop ("distribute elements to a static subset of good peers"),
-        GNUNET_YES, &GNUNET_GETOPT_set_one, &dist_static },
-      { 'V', "verbose", NULL,
-        gettext_noop ("be more verbose (print received values)"),
-        GNUNET_NO, &GNUNET_GETOPT_set_one, &verbose },
+   struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('n',
+                                     "num-peers",
+                                     NULL,
+                                     gettext_noop ("number of peers in consensus"),
+                                     &num_peers),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('k',
+                                     "value-replication",
+                                     NULL,
+                                     gettext_noop ("how many peers (random selection without replacement) receive one value?"),
+                                     &replication),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('x',
+                                     "num-values",
+                                     NULL,
+                                     gettext_noop ("number of values"),
+                                     &num_values),
+
+      GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
+                                              "timeout",
+                                              NULL,
+                                              gettext_noop ("consensus timeout"),
+                                              &conclude_timeout),
+
+
+      GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('d',
+                                              "delay",
+                                              NULL,
+                                              gettext_noop ("delay until consensus starts"),
+                                              &consensus_delay),
+
+      GNUNET_GETOPT_OPTION_FILENAME ('s',
+                                     "statistics",
+                                     "FILENAME",
+                                     gettext_noop ("write statistics to file"),
+                                     &statistics_filename),
+
+      GNUNET_GETOPT_OPTION_SET_ONE ('S',
+                                    "dist-static",
+                                    gettext_noop ("distribute elements to a static subset of good peers"),
+                                    &dist_static),
+
+      GNUNET_GETOPT_OPTION_SET_ONE ('V',
+                                    "verbose",
+                                    gettext_noop ("be more verbose (print received values)"),
+                                    &verbose),
+
       GNUNET_GETOPT_OPTION_END
   };
   conclude_timeout = GNUNET_TIME_UNIT_SECONDS;
index b934f468fbddad7cb6ea1a635e9f6175c5b147dd..4af7199aa925e7cd03756c0fb503e9acb654e900 100644 (file)
@@ -393,6 +393,14 @@ struct DiffEntry
   struct GNUNET_CONTAINER_MultiHashMap *changes;
 };
 
+struct SetHandle
+{
+  struct SetHandle *prev;
+  struct SetHandle *next;
+
+  struct GNUNET_SET_Handle *h;
+};
+
 
 
 /**
@@ -499,6 +507,9 @@ struct ConsensusSession
    * Bounded Eppstein lower bound.
    */
   uint64_t lower_bound;
+
+  struct SetHandle *set_handles_head;
+  struct SetHandle *set_handles_tail;
 };
 
 /**
@@ -894,7 +905,7 @@ cmp_uint64_t (const void *pa, const void *pb)
  * in the result set.
  *
  * @param cls closure
- * @param element a result element, only valid if status is GNUNET_SET_STATUS_OK
+ * @param element a result element, only valid if status is #GNUNET_SET_STATUS_OK
  * @param current_size current set size
  * @param status see enum GNUNET_SET_Status
  */
@@ -1011,6 +1022,7 @@ set_result_cb (void *cls,
                     "P%u: lower bound %llu\n",
                     session->local_peer_idx,
                     (long long) session->lower_bound);
+        GNUNET_free (copy);
       }
       return;
     }
@@ -1329,7 +1341,10 @@ commit_set (struct ConsensusSession *session,
   if (PHASE_KIND_ALL_TO_ALL_2 == task->key.kind)
   {
     struct GNUNET_SET_Element element;
-    struct ConsensusSizeElement cse = { 0 };
+    struct ConsensusSizeElement cse = {
+      .size = 0,
+      .sender_index = 0
+    };
     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "inserting size marker\n");
     cse.ce.marker = CONSENSUS_MARKER_SIZE;
     cse.size = GNUNET_htonll (session->first_size);
@@ -1382,7 +1397,10 @@ commit_set (struct ConsensusSession *session,
         for (i = 0; i < evil.num; i++)
         {
           struct GNUNET_SET_Element element;
-          struct ConsensusStuffedElement se = { 0 };
+          struct ConsensusStuffedElement se = {
+            .ce.payload_type = 0,
+            .ce.marker = 0,
+          };
           element.data = &se;
           element.size = sizeof (struct ConsensusStuffedElement);
           element.element_type = GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT;
@@ -1663,6 +1681,12 @@ set_copy_cb (void *cls, struct GNUNET_SET_Handle *copy)
   struct TaskEntry *task = scc->task;
   struct SetKey dst_set_key = scc->dst_set_key;
   struct SetEntry *set;
+  struct SetHandle *sh = GNUNET_new (struct SetHandle);
+
+  sh->h = copy;
+  GNUNET_CONTAINER_DLL_insert (task->step->session->set_handles_head,
+                               task->step->session->set_handles_tail,
+                               sh);
 
   GNUNET_free (scc);
   set = GNUNET_new (struct SetEntry);
@@ -2105,7 +2129,7 @@ task_start_reconcile (struct TaskEntry *task)
 
   if (task->key.peer1 == session->local_peer_idx)
   {
-    struct GNUNET_CONSENSUS_RoundContextMessage rcm = { 0 };
+    struct GNUNET_CONSENSUS_RoundContextMessage rcm;
 
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "P%u: Looking up set {%s} to run remote union\n",
@@ -2120,6 +2144,7 @@ task_start_reconcile (struct TaskEntry *task)
     rcm.peer2 = htons (task->key.peer2);
     rcm.leader = htons (task->key.leader);
     rcm.repetition = htons (task->key.repetition);
+    rcm.is_contested = htons (0);
 
     GNUNET_assert (NULL == setop->op);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: initiating set op with P%u, our set is %s\n",
@@ -3152,6 +3177,11 @@ handle_client_join (void *cls,
     client_set = GNUNET_new (struct SetEntry);
     client_set->h = GNUNET_SET_create (cfg,
                                        GNUNET_SET_OPERATION_UNION);
+    struct SetHandle *sh = GNUNET_new (struct SetHandle);
+    sh->h = client_set->h;
+    GNUNET_CONTAINER_DLL_insert (session->set_handles_head,
+                                 session->set_handles_tail,
+                                 sh);
     client_set->key = ((struct SetKey) { SET_KIND_CURRENT, 0, 0 });
     put_set (session,
              client_set);
@@ -3370,6 +3400,14 @@ client_disconnect_cb (void *cls,
   GNUNET_CONTAINER_DLL_remove (sessions_head,
                                sessions_tail,
                                session);
+
+  while (session->set_handles_head)
+  {
+    struct SetHandle *sh = session->set_handles_head;
+    session->set_handles_head = sh->next;
+    GNUNET_SET_destroy (sh->h);
+    GNUNET_free (sh);
+  }
   GNUNET_free (session);
 }
 
index f78b77d092296641693da79324452c4b02865c23..881251a66484f2adc917b5d5920a6c20b6c1e5d4 100644 (file)
@@ -5,7 +5,7 @@ GNUNET_TEST_HOME = /tmp/test-consensus/
 #OPTIONS = -L INFO
 BINARY = gnunet-service-evil-consensus
 
-#PREFIX = valgrind
+PREFIX = valgrind
 
 #EVIL_SPEC = 0;cram-all;noreplace;5
 #EVIL_SPEC = 0;cram;5/1;cram;5
index 83313e7f8d5fc0357e66e28667bb428a4d481ab8..cc29381445f5c8d93723a6bd1eb022adcf6730c6 100644 (file)
@@ -180,7 +180,7 @@ gnunet_service_conversation_LDADD = \
   libgnunetconversation.la \
   libgnunetspeaker.la \
   libgnunetmicrophone.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(INTLLIBS)
 gnunet_service_conversation_LDFLAGS = \
index 925db4665694bde3a33794fd838b1bc4011947f9..c5275c0de4616fb0d634806c0d19b1f0f3d01d8e 100644 (file)
@@ -1265,13 +1265,20 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'e', "ego", "NAME",
-     gettext_noop ("sets the NAME of the ego to use for the phone (and name resolution)"),
-     1, &GNUNET_GETOPT_set_string, &ego_name},
-    {'p', "phone", "LINE",
-      gettext_noop ("sets the LINE to use for the phone"),
-     1, &GNUNET_GETOPT_set_string, &line},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_STRING ('e',
+                                 "ego",
+                                 "NAME",
+                                 gettext_noop ("sets the NAME of the ego to use for the phone (and name resolution)"),
+                                 &ego_name),
+
+    GNUNET_GETOPT_OPTION_STRING ('p',
+                                 "phone",
+                                 "LINE",
+                                 gettext_noop ("sets the LINE to use for the phone"),
+                                 &line),
+
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
index e965cb2aaa0c259a05a93b9b8e729f5ceb8c5f2b..4344e1d418808f512a0bf5ce1fc87c773121084b 100644 (file)
@@ -549,7 +549,6 @@ ogg_demux_and_decode ()
  */
 static int
 stdin_receiver (void *cls,
-               void *client,
                const struct GNUNET_MessageHeader *msg)
 {
   struct AudioMessage *audio;
@@ -727,12 +726,14 @@ ogg_init ()
   ogg_sync_init (&oy);
 }
 
+
 static void
 drain_callback (pa_stream*s, int success, void *userdata)
 {
   pa_threaded_mainloop_signal (m, 0);
 }
 
+
 /**
  * The main function for the playback helper.
  *
@@ -746,7 +747,7 @@ main (int argc, char *argv[])
   static unsigned long long toff;
 
   char readbuf[MAXLINE];
-  struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst;
+  struct GNUNET_MessageStreamTokenizer *stdin_mst;
   char c;
   ssize_t ret;
 #ifdef DEBUG_READ_PURE_OGG
@@ -762,7 +763,7 @@ main (int argc, char *argv[])
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "pipe");
     return 1;
   }
-  stdin_mst = GNUNET_SERVER_mst_create (&stdin_receiver, NULL);
+  stdin_mst = GNUNET_MST_create (&stdin_receiver, NULL);
   ogg_init ();
   pa_init ();
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -802,11 +803,11 @@ main (int argc, char *argv[])
     }
     else
 #endif
-    GNUNET_SERVER_mst_receive (stdin_mst, NULL,
-                              readbuf, ret,
-                              GNUNET_NO, GNUNET_NO);
+    GNUNET_MST_from_buffer (stdin_mst,
+                            readbuf, ret,
+                            GNUNET_NO, GNUNET_NO);
   }
-  GNUNET_SERVER_mst_destroy (stdin_mst);
+  GNUNET_MST_destroy (stdin_mst);
   if (stream_out)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
index f80cc1d11303e30828045d7b89976561fbac48c9..5f43bfe80d46c64a97ede40f86f9197a354b9f31 100644 (file)
@@ -779,7 +779,6 @@ handle_cadet_hangup_message (void *cls,
   {
   case CS_CALLEE_INIT:
     GNUNET_break_op (0);
-    destroy_line_cadet_channels (ch);
     return;
   case CS_CALLEE_RINGING:
   case CS_CALLEE_CONNECTED:
@@ -1110,7 +1109,7 @@ handle_client_call_message (void *cls,
                                line->channel_tail,
                                ch);
   ch->status = CS_CALLER_CALLING;
-  ch->channel = GNUNET_CADET_channel_creatE (cadet,
+  ch->channel = GNUNET_CADET_channel_create (cadet,
                                              ch,
                                              &msg->target,
                                              &msg->line_port,
@@ -1264,7 +1263,7 @@ handle_client_register_message (void *cls,
   };
 
   line->line_port = msg->line_port;
-  line->port = GNUNET_CADET_open_porT (cadet,
+  line->port = GNUNET_CADET_open_port (cadet,
                                        &msg->line_port,
                                        &inbound_channel,
                                        line,
@@ -1307,7 +1306,7 @@ run (void *cls,
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_CRYPTO_get_peer_identity (cfg,
                                                   &my_identity));
-  cadet = GNUNET_CADET_connecT (cfg);
+  cadet = GNUNET_CADET_connect (cfg);
   if (NULL == cadet)
   {
     GNUNET_break (0);
index 94f52f8dc22b4ff24aae03e8ec2cf06a56967796..7871433a33888cfe27f2247ca34f1bb9f0ab94fb 100644 (file)
@@ -64,13 +64,11 @@ struct Microphone
  * Function to process the audio from the record helper
  *
  * @param cls clsoure with our `struct Microphone`
- * @param client NULL
  * @param msg the message from the helper
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
 process_record_messages (void *cls,
-                        void *client,
                         const struct GNUNET_MessageHeader *msg)
 {
   struct Microphone *mic = cls;
index fd789295d12899f53c26c3d34adb89be6e475d6e..ed8ce364dd49f6ac9fbbfcaa23af1551ce477e24 100644 (file)
@@ -321,7 +321,7 @@ core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
 
   /* check message size for sanity */
   msize = ntohs (msg->size);
-  if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct SendMessage))
+  if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct SendMessage))
   {
     GNUNET_break (0);
     GNUNET_MQ_impl_send_continue (mq);
@@ -796,7 +796,7 @@ GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
   h->handlers = GNUNET_MQ_copy_handlers (handlers);
   h->hcnt = GNUNET_MQ_count_handlers (handlers);
   GNUNET_assert (h->hcnt <
-                 (GNUNET_SERVER_MAX_MESSAGE_SIZE -
+                 (GNUNET_MAX_MESSAGE_SIZE -
                   sizeof (struct InitMessage)) / sizeof (uint16_t));
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Connecting to CORE service\n");
index d91dc304d5c1b88152b44f994e958f9d221f9fea..ed89b19461fe22505325618c87956bdb0419a1d3 100644 (file)
@@ -171,10 +171,11 @@ main (int argc,
       char *const *argv)
 {
   int res;
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'m', "monitor", NULL,
-     gettext_noop ("provide information about all current connections (continuously)"),
-     0, &GNUNET_GETOPT_set_one, &monitor_connections},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('m',
+                                  "monitor",
+                                  gettext_noop ("provide information about all current connections (continuously)"),
+                                  &monitor_connections),
     GNUNET_GETOPT_OPTION_END
   };
 
index 31b91f12f7e813a2a2eb1f49855b12b156c11f43..625bf9655a2a66525a575510144bdcebc5b714ca 100644 (file)
@@ -807,7 +807,7 @@ GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
 {
   size_t size = msize + sizeof (struct NotifyTrafficMessage);
 
-  if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (size >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
index 9068985123fd1723489f5b102400e5177ac82ee0..8a7cada5c5a1a1b76191e7859bb54ee703c6d760 100644 (file)
@@ -262,6 +262,11 @@ struct GSC_KeyExchangeInfo
    */
   struct GNUNET_MQ_Handle *mq;
 
+  /**
+   * Our message stream tokenizer (for encrypted payload).
+   */
+  struct GNUNET_MessageStreamTokenizer *mst;
+
   /**
    * PING message we transmit to the other peer.
    */
@@ -369,11 +374,6 @@ static struct GNUNET_CRYPTO_EcdhePrivateKey *my_ephemeral_key;
  */
 static struct EphemeralKeyMessage current_ekm;
 
-/**
- * Our message stream tokenizer (for encrypted payload).
- */
-static struct GNUNET_SERVER_MessageStreamTokenizer *mst;
-
 /**
  * DLL head.
  */
@@ -701,6 +701,55 @@ setup_fresh_ping (struct GSC_KeyExchangeInfo *kx)
 }
 
 
+/**
+ * Deliver P2P message to interested clients.  Invokes send twice,
+ * once for clients that want the full message, and once for clients
+ * that only want the header
+ *
+ * @param cls the `struct GSC_KeyExchangeInfo`
+ * @param m the message
+ */
+static int
+deliver_message (void *cls,
+                 const struct GNUNET_MessageHeader *m)
+{
+  struct GSC_KeyExchangeInfo *kx = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Decrypted message of type %d from %s\n",
+              ntohs (m->type),
+              GNUNET_i2s (kx->peer));
+  if (GNUNET_CORE_KX_STATE_UP != kx->status)
+  {
+    GNUNET_STATISTICS_update (GSC_stats,
+                              gettext_noop ("# PAYLOAD dropped (out of order)"),
+                              1,
+                              GNUNET_NO);
+    return GNUNET_OK;
+  }
+  switch (ntohs (m->type))
+  {
+  case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
+  case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
+    GSC_SESSIONS_set_typemap (kx->peer, m);
+    return GNUNET_OK;
+  case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
+    GSC_SESSIONS_confirm_typemap (kx->peer, m);
+    return GNUNET_OK;
+  default:
+    GSC_CLIENTS_deliver_message (kx->peer,
+                                 m,
+                                 ntohs (m->size),
+                                 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
+    GSC_CLIENTS_deliver_message (kx->peer,
+                                 m,
+                                 sizeof (struct GNUNET_MessageHeader),
+                                 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
+  }
+  return GNUNET_OK;
+}
+
+
 /**
  * Function called by transport to notify us that
  * a peer connected to us (on the network level).
@@ -727,6 +776,8 @@ handle_transport_notify_connect (void *cls,
                             1,
                             GNUNET_NO);
   kx = GNUNET_new (struct GSC_KeyExchangeInfo);
+  kx->mst = GNUNET_MST_create (&deliver_message,
+                               kx);
   kx->mq = mq;
   kx->peer = pid;
   kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
@@ -801,6 +852,7 @@ handle_transport_notify_disconnect (void *cls,
   GNUNET_CONTAINER_DLL_remove (kx_head,
                               kx_tail,
                               kx);
+  GNUNET_MST_destroy (kx->mst);
   GNUNET_free (kx);
 }
 
@@ -1416,24 +1468,6 @@ GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
 }
 
 
-/**
- * Closure for #deliver_message()
- */
-struct DeliverMessageContext
-{
-
-  /**
-   * Key exchange context.
-   */
-  struct GSC_KeyExchangeInfo *kx;
-
-  /**
-   * Sender of the message.
-   */
-  const struct GNUNET_PeerIdentity *peer;
-};
-
-
 /**
  * We received an encrypted message.  Check that it is
  * well-formed (size-wise).
@@ -1475,7 +1509,6 @@ handle_encrypted (void *cls,
   struct GNUNET_TIME_Absolute t;
   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
   struct GNUNET_CRYPTO_AuthKey auth_key;
-  struct DeliverMessageContext dmc;
   uint16_t size = ntohs (m->header.size);
   char buf[size] GNUNET_ALIGN;
 
@@ -1620,15 +1653,12 @@ handle_encrypted (void *cls,
                             gettext_noop ("# bytes of payload decrypted"),
                             size - sizeof (struct EncryptedMessage),
                             GNUNET_NO);
-  dmc.kx = kx;
-  dmc.peer = kx->peer;
   if (GNUNET_OK !=
-      GNUNET_SERVER_mst_receive (mst,
-                                &dmc,
-                                 &buf[sizeof (struct EncryptedMessage)],
-                                 size - sizeof (struct EncryptedMessage),
-                                 GNUNET_YES,
-                                 GNUNET_NO))
+      GNUNET_MST_from_buffer (kx->mst,
+                              &buf[sizeof (struct EncryptedMessage)],
+                              size - sizeof (struct EncryptedMessage),
+                              GNUNET_YES,
+                              GNUNET_NO))
     GNUNET_break_op (0);
 }
 
@@ -1655,57 +1685,6 @@ handle_transport_notify_excess_bw (void *cls,
 }
 
 
-/**
- * Deliver P2P message to interested clients.  Invokes send twice,
- * once for clients that want the full message, and once for clients
- * that only want the header
- *
- * @param cls always NULL
- * @param client who sent us the message (struct GSC_KeyExchangeInfo)
- * @param m the message
- */
-static int
-deliver_message (void *cls,
-                 void *client,
-                 const struct GNUNET_MessageHeader *m)
-{
-  struct DeliverMessageContext *dmc = client;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Decrypted message of type %d from %s\n",
-              ntohs (m->type),
-              GNUNET_i2s (dmc->peer));
-  if (GNUNET_CORE_KX_STATE_UP != dmc->kx->status)
-  {
-    GNUNET_STATISTICS_update (GSC_stats,
-                              gettext_noop ("# PAYLOAD dropped (out of order)"),
-                              1,
-                              GNUNET_NO);
-    return GNUNET_OK;
-  }
-  switch (ntohs (m->type))
-  {
-  case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
-  case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
-    GSC_SESSIONS_set_typemap (dmc->peer, m);
-    return GNUNET_OK;
-  case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
-    GSC_SESSIONS_confirm_typemap (dmc->peer, m);
-    return GNUNET_OK;
-  default:
-    GSC_CLIENTS_deliver_message (dmc->peer,
-                                 m,
-                                 ntohs (m->size),
-                                 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
-    GSC_CLIENTS_deliver_message (dmc->peer,
-                                 m,
-                                 sizeof (struct GNUNET_MessageHeader),
-                                 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
-  }
-  return GNUNET_OK;
-}
-
-
 /**
  * Setup the message that links the ephemeral key to our persistent
  * public key and generate the appropriate signature.
@@ -1829,8 +1808,6 @@ GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
   rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY,
                                              &do_rekey,
                                              NULL);
-  mst = GNUNET_SERVER_mst_create (&deliver_message,
-                                 NULL);
   transport
     = GNUNET_TRANSPORT_core_connect (GSC_cfg,
                                     &GSC_my_identity,
@@ -1874,11 +1851,6 @@ GSC_KX_done ()
     GNUNET_free (my_private_key);
     my_private_key = NULL;
   }
-  if (NULL != mst)
-  {
-    GNUNET_SERVER_mst_destroy (mst);
-    mst = NULL;
-  }
   if (NULL != nc)
   {
     GNUNET_notification_context_destroy (nc);
index 431b3179e9e9734a7edafe939ca3222cbfc3a72d..670a64926e38cbea58ed920fd439313e0f9687b8 100644 (file)
@@ -53,6 +53,7 @@ libgnunet_plugin_datacache_sqlite_la_SOURCES = \
   plugin_datacache_sqlite.c
 libgnunet_plugin_datacache_sqlite_la_LIBADD = \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
+  $(top_builddir)/src/sq/libgnunetsq.la \
   $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
   $(LTLIBINTL)
 libgnunet_plugin_datacache_sqlite_la_LDFLAGS = \
index 5567077d3fd8738ca4ff39f20e477d62b885d481..dd79d01256e60efb84879e08027772b2665b6fed 100644 (file)
@@ -26,6 +26,7 @@
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_datacache_plugin.h"
+#include "gnunet_sq_lib.h"
 #include <sqlite3.h>
 
 #define LOG(kind,...) GNUNET_log_from (kind, "datacache-sqlite", __VA_ARGS__)
@@ -59,6 +60,41 @@ struct Plugin
    */
   char *fn;
 
+  /**
+   * Prepared statement for #sqlite_plugin_put.
+   */
+  sqlite3_stmt *insert_stmt;
+
+  /**
+   * Prepared statement for #sqlite_plugin_get.
+   */
+  sqlite3_stmt *get_count_stmt;
+
+  /**
+   * Prepared statement for #sqlite_plugin_get.
+   */
+  sqlite3_stmt *get_stmt;
+
+  /**
+   * Prepared statement for #sqlite_plugin_del.
+   */
+  sqlite3_stmt *del_select_stmt;
+
+  /**
+   * Prepared statement for #sqlite_plugin_del.
+   */
+  sqlite3_stmt *del_stmt;
+
+  /**
+   * Prepared statement for #sqlite_plugin_get_random.
+   */
+  sqlite3_stmt *get_random_stmt;
+
+  /**
+   * Prepared statement for #sqlite_plugin_get_closest.
+   */
+  sqlite3_stmt *get_closest_stmt;
+
   /**
    * Number of key-value pairs in the database.
    */
@@ -132,60 +168,47 @@ sqlite_plugin_put (void *cls,
                   const struct GNUNET_PeerIdentity *path_info)
 {
   struct Plugin *plugin = cls;
-  sqlite3_stmt *stmt;
-  int64_t dval;
+  uint32_t type32 = type;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_uint32 (&type32),
+    GNUNET_SQ_query_param_absolute_time (&discard_time),
+    GNUNET_SQ_query_param_auto_from_type (key),
+    GNUNET_SQ_query_param_fixed_size (data, size),
+    GNUNET_SQ_query_param_fixed_size (path_info,
+                                      path_info_len * sizeof (struct GNUNET_PeerIdentity)),
+    GNUNET_SQ_query_param_end
+  };
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Processing PUT of %u bytes with key `%4s' and expiration %s\n",
+       "Processing PUT of %u bytes with key `%s' and expiration %s\n",
        (unsigned int) size,
        GNUNET_h2s (key),
-       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time), GNUNET_YES));
-  dval = (int64_t) discard_time.abs_value_us;
-  if (dval < 0)
-    dval = INT64_MAX;
-  if (sq_prepare
-      (plugin->dbh,
-       "INSERT INTO ds090 (type, expire, key, value, path) VALUES (?, ?, ?, ?, ?)",
-       &stmt) != SQLITE_OK)
-  {
-    LOG_SQLITE (plugin->dbh,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sq_prepare");
-    return -1;
-  }
-  if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) ||
-      (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, dval)) ||
-      (SQLITE_OK !=
-       sqlite3_bind_blob (stmt, 3,
-                         key, sizeof (struct GNUNET_HashCode),
-                          SQLITE_TRANSIENT)) ||
-      (SQLITE_OK != sqlite3_bind_blob (stmt, 4,
-                                      data, size,
-                                      SQLITE_TRANSIENT)) ||
-      (SQLITE_OK != sqlite3_bind_blob (stmt, 5,
-                                      path_info,
-                                      path_info_len * sizeof (struct GNUNET_PeerIdentity),
-                                      SQLITE_TRANSIENT)))
+       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (discard_time),
+                                               GNUNET_YES));
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->insert_stmt,
+                      params))
   {
     LOG_SQLITE (plugin->dbh,
                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind_xxx");
-    sqlite3_finalize (stmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->insert_stmt);
     return -1;
   }
-  if (SQLITE_DONE != sqlite3_step (stmt))
+  if (SQLITE_DONE !=
+      sqlite3_step (plugin->insert_stmt))
   {
     LOG_SQLITE (plugin->dbh,
                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
-    sqlite3_finalize (stmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->insert_stmt);
     return -1;
   }
   plugin->num_items++;
-  if (SQLITE_OK != sqlite3_finalize (stmt))
-    LOG_SQLITE (plugin->dbh,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_finalize");
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->insert_stmt);
   return size + OVERHEAD;
 }
 
@@ -209,120 +232,119 @@ sqlite_plugin_get (void *cls,
                    void *iter_cls)
 {
   struct Plugin *plugin = cls;
-  sqlite3_stmt *stmt;
+  uint32_t type32 = type;
   struct GNUNET_TIME_Absolute now;
   struct GNUNET_TIME_Absolute exp;
-  unsigned int size;
-  const char *dat;
+  size_t size;
+  void *dat;
   unsigned int cnt;
-  unsigned int off;
+  uint32_t off;
   unsigned int total;
-  unsigned int psize;
-  char scratch[256];
-  int64_t ntime;
-  const struct GNUNET_PeerIdentity *path;
+  size_t psize;
+  struct GNUNET_PeerIdentity *path;
+  struct GNUNET_SQ_QueryParam params_count[] = {
+    GNUNET_SQ_query_param_auto_from_type (key),
+    GNUNET_SQ_query_param_uint32 (&type32),
+    GNUNET_SQ_query_param_absolute_time (&now),
+    GNUNET_SQ_query_param_end
+  };
+  struct GNUNET_SQ_QueryParam params_select[] = {
+    GNUNET_SQ_query_param_auto_from_type (key),
+    GNUNET_SQ_query_param_uint32 (&type32),
+    GNUNET_SQ_query_param_absolute_time (&now),
+    GNUNET_SQ_query_param_uint32 (&off),
+    GNUNET_SQ_query_param_end
+  };
+  struct GNUNET_SQ_ResultSpec rs[] = {
+    GNUNET_SQ_result_spec_variable_size (&dat,
+                                         &size),
+    GNUNET_SQ_result_spec_absolute_time (&exp),
+    GNUNET_SQ_result_spec_variable_size ((void **) &path,
+                                         &psize),
+    GNUNET_SQ_result_spec_end
+  };
 
   now = GNUNET_TIME_absolute_get ();
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Processing GET for key `%4s'\n",
+       "Processing GET for key `%s'\n",
        GNUNET_h2s (key));
-  if (sq_prepare
-      (plugin->dbh,
-       "SELECT count(*) FROM ds090 WHERE key=? AND type=? AND expire >= ?",
-       &stmt) != SQLITE_OK)
-  {
-    LOG_SQLITE (plugin->dbh,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sq_prepare");
-    return 0;
-  }
-  ntime = (int64_t) now.abs_value_us;
-  GNUNET_assert (ntime >= 0);
-  if ((SQLITE_OK !=
-       sqlite3_bind_blob (stmt, 1, key, sizeof (struct GNUNET_HashCode),
-                          SQLITE_TRANSIENT)) ||
-      (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) ||
-      (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value_us)))
+
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->get_count_stmt,
+                      params_count))
   {
     LOG_SQLITE (plugin->dbh,
                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind_xxx");
-    sqlite3_finalize (stmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->get_count_stmt);
     return 0;
   }
-
-  if (SQLITE_ROW != sqlite3_step (stmt))
+  if (SQLITE_ROW !=
+      sqlite3_step (plugin->get_count_stmt))
   {
     LOG_SQLITE (plugin->dbh, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite_step");
-    sqlite3_finalize (stmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->get_count_stmt);
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "No content found when processing GET for key `%4s'\n",
+         "No content found when processing GET for key `%s'\n",
          GNUNET_h2s (key));
     return 0;
   }
-  total = sqlite3_column_int (stmt, 0);
-  sqlite3_finalize (stmt);
-  if ((0 == total) || (NULL == iter))
+  total = sqlite3_column_int (plugin->get_count_stmt,
+                              0);
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->get_count_stmt);
+  if ( (0 == total) ||
+       (NULL == iter) )
   {
     if (0 == total)
       LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "No content found when processing GET for key `%4s'\n",
+           "No content found when processing GET for key `%s'\n",
            GNUNET_h2s (key));
     return total;
   }
 
   cnt = 0;
-  off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, total);
+  off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                  total);
   while (cnt < total)
   {
     off = (off + 1) % total;
-    GNUNET_snprintf (scratch, sizeof (scratch),
-                     "SELECT value,expire,path FROM ds090 WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET %u",
-                     off);
-    if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
-    {
-      LOG_SQLITE (plugin->dbh,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sq_prepare");
-      return cnt;
-    }
-    if ((SQLITE_OK !=
-         sqlite3_bind_blob (stmt, 1,
-                            key,
-                            sizeof (struct GNUNET_HashCode),
-                            SQLITE_TRANSIENT)) ||
-        (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) ||
-        (SQLITE_OK != sqlite3_bind_int64 (stmt, 3, now.abs_value_us)))
+    if (GNUNET_OK !=
+        GNUNET_SQ_bind (plugin->get_stmt,
+                        params_select))
     {
       LOG_SQLITE (plugin->dbh,
                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                   "sqlite3_bind_xxx");
-      sqlite3_finalize (stmt);
+      GNUNET_SQ_reset (plugin->dbh,
+                       plugin->get_stmt);
       return cnt;
     }
-    if (sqlite3_step (stmt) != SQLITE_ROW)
+    if (SQLITE_ROW !=
+        sqlite3_step (plugin->get_stmt))
       break;
-    size = sqlite3_column_bytes (stmt, 0);
-    dat = sqlite3_column_blob (stmt, 0);
-    exp.abs_value_us = sqlite3_column_int64 (stmt, 1);
-    psize = sqlite3_column_bytes (stmt, 2);
+    if (GNUNET_OK !=
+        GNUNET_SQ_extract_result (plugin->get_stmt,
+                                  rs))
+    {
+      GNUNET_break (0);
+      GNUNET_SQ_reset (plugin->dbh,
+                       plugin->get_stmt);
+      break;
+    }
     if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
     {
       GNUNET_break (0);
       psize = 0;
+      path = NULL;
     }
     psize /= sizeof (struct GNUNET_PeerIdentity);
-    if (0 != psize)
-      path = sqlite3_column_blob (stmt, 2);
-    else
-      path = NULL;
-    ntime = (int64_t) exp.abs_value_us;
-    if (ntime == INT64_MAX)
-      exp = GNUNET_TIME_UNIT_FOREVER_ABS;
     cnt++;
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Found %u-byte result when processing GET for key `%4s'\n",
+         "Found %u-byte result when processing GET for key `%s'\n",
          (unsigned int) size,
          GNUNET_h2s (key));
     if (GNUNET_OK != iter (iter_cls,
@@ -334,11 +356,17 @@ sqlite_plugin_get (void *cls,
                            psize,
                            path))
     {
-      sqlite3_finalize (stmt);
+      GNUNET_SQ_cleanup_result (rs);
+      GNUNET_SQ_reset (plugin->dbh,
+                       plugin->get_stmt);
       break;
     }
-    sqlite3_finalize (stmt);
+    GNUNET_SQ_cleanup_result (rs);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->get_stmt);
   }
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->get_stmt);
   return cnt;
 }
 
@@ -354,79 +382,73 @@ static int
 sqlite_plugin_del (void *cls)
 {
   struct Plugin *plugin = cls;
-  unsigned long long rowid;
-  unsigned int dsize;
-  sqlite3_stmt *stmt;
-  sqlite3_stmt *dstmt;
+  uint64_t rowid;
+  void *data;
+  size_t dsize;
   struct GNUNET_HashCode hc;
+  struct GNUNET_SQ_ResultSpec rs[] = {
+    GNUNET_SQ_result_spec_uint64 (&rowid),
+    GNUNET_SQ_result_spec_auto_from_type (&hc),
+    GNUNET_SQ_result_spec_variable_size ((void **) &data,
+                                         &dsize),
+    GNUNET_SQ_result_spec_end
+  };
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_uint64 (&rowid),
+    GNUNET_SQ_query_param_end
+  };
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Processing DEL\n");
-  stmt = NULL;
-  dstmt = NULL;
-  if (SQLITE_OK !=
-      sq_prepare (plugin->dbh,
-                  "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1",
-                  &stmt))
-  {
-    LOG_SQLITE (plugin->dbh,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sq_prepare");
-    if (stmt != NULL)
-      (void) sqlite3_finalize (stmt);
-    return GNUNET_SYSERR;
-  }
-  if (SQLITE_ROW != sqlite3_step (stmt))
+  if (SQLITE_ROW !=
+      sqlite3_step (plugin->del_select_stmt))
   {
     LOG_SQLITE (plugin->dbh,
                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
-    (void) sqlite3_finalize (stmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->del_select_stmt);
     return GNUNET_SYSERR;
   }
-  rowid = sqlite3_column_int64 (stmt, 0);
-  GNUNET_assert (sqlite3_column_bytes (stmt, 1) == sizeof (struct GNUNET_HashCode));
-  GNUNET_memcpy (&hc, sqlite3_column_blob (stmt, 1), sizeof (struct GNUNET_HashCode));
-  dsize = sqlite3_column_bytes (stmt, 2);
-  if (SQLITE_OK != sqlite3_finalize (stmt))
-    LOG_SQLITE (plugin->dbh,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_step");
-  if (SQLITE_OK !=
-      sq_prepare (plugin->dbh,
-                  "DELETE FROM ds090 WHERE _ROWID_=?", &dstmt))
+  if (GNUNET_OK !=
+      GNUNET_SQ_extract_result (plugin->del_select_stmt,
+                                rs))
   {
-    LOG_SQLITE (plugin->dbh,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sq_prepare");
-    if (stmt != NULL)
-      (void) sqlite3_finalize (stmt);
+    GNUNET_break (0);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->del_select_stmt);
     return GNUNET_SYSERR;
   }
-  if (SQLITE_OK != sqlite3_bind_int64 (dstmt, 1, rowid))
+  GNUNET_SQ_cleanup_result (rs);
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->del_select_stmt);
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->del_stmt,
+                      params))
   {
     LOG_SQLITE (plugin->dbh,
                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind");
-    (void) sqlite3_finalize (dstmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->del_stmt);
     return GNUNET_SYSERR;
   }
-  if (SQLITE_DONE != sqlite3_step (dstmt))
+  if (SQLITE_DONE !=
+      sqlite3_step (plugin->del_stmt))
   {
     LOG_SQLITE (plugin->dbh,
                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
-    (void) sqlite3_finalize (dstmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->del_stmt);
     return GNUNET_SYSERR;
   }
   plugin->num_items--;
   plugin->env->delete_notify (plugin->env->cls,
                               &hc,
                               dsize + OVERHEAD);
-  if (SQLITE_OK != sqlite3_finalize (dstmt))
-    LOG_SQLITE (plugin->dbh,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_finalize");
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->del_stmt);
   return GNUNET_OK;
 }
 
@@ -445,17 +467,28 @@ sqlite_plugin_get_random (void *cls,
                           void *iter_cls)
 {
   struct Plugin *plugin = cls;
-  sqlite3_stmt *stmt;
   struct GNUNET_TIME_Absolute exp;
-  unsigned int size;
-  const char *dat;
-  unsigned int off;
-  unsigned int psize;
-  unsigned int type;
-  char scratch[256];
-  int64_t ntime;
-  const struct GNUNET_PeerIdentity *path;
-  const struct GNUNET_HashCode *key;
+  size_t size;
+  void *dat;
+  uint32_t off;
+  size_t psize;
+  uint32_t type;
+  struct GNUNET_PeerIdentity *path;
+  struct GNUNET_HashCode key;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_uint32 (&off),
+    GNUNET_SQ_query_param_end
+  };
+  struct GNUNET_SQ_ResultSpec rs[] = {
+    GNUNET_SQ_result_spec_variable_size (&dat,
+                                         &size),
+    GNUNET_SQ_result_spec_absolute_time (&exp),
+    GNUNET_SQ_result_spec_variable_size ((void **) &path,
+                                         &psize),
+    GNUNET_SQ_result_spec_auto_from_type (&key),
+    GNUNET_SQ_result_spec_uint32 (&type),
+    GNUNET_SQ_result_spec_end
+  };
 
   if (0 == plugin->num_items)
     return 0;
@@ -463,60 +496,51 @@ sqlite_plugin_get_random (void *cls,
     return 1;
   off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
                                   plugin->num_items);
-  GNUNET_snprintf (scratch,
-                   sizeof (scratch),
-                   "SELECT value,expire,path,key,type FROM ds090 ORDER BY key LIMIT 1 OFFSET %u",
-                   off);
-  if (SQLITE_OK !=
-      sq_prepare (plugin->dbh, scratch, &stmt))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->get_random_stmt,
+                      params))
   {
-    LOG_SQLITE (plugin->dbh,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sq_prepare");
     return 0;
   }
-  if (SQLITE_ROW != sqlite3_step (stmt))
+  if (SQLITE_ROW !=
+      sqlite3_step (plugin->get_random_stmt))
+  {
+    GNUNET_break (0);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->get_random_stmt);
+    return 0;
+  }
+  if (GNUNET_OK !=
+      GNUNET_SQ_extract_result (plugin->get_random_stmt,
+                                rs))
   {
     GNUNET_break (0);
-    sqlite3_finalize (stmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->get_random_stmt);
     return 0;
   }
-  size = sqlite3_column_bytes (stmt, 0);
-  dat = sqlite3_column_blob (stmt, 0);
-  exp.abs_value_us = sqlite3_column_int64 (stmt, 1);
-  psize = sqlite3_column_bytes (stmt, 2);
   if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
   {
     GNUNET_break (0);
     psize = 0;
+    path = NULL;
   }
   psize /= sizeof (struct GNUNET_PeerIdentity);
-  if (0 != psize)
-    path = sqlite3_column_blob (stmt, 2);
-  else
-    path = NULL;
-
-  GNUNET_assert (sizeof (struct GNUNET_HashCode) ==
-                 sqlite3_column_bytes (stmt, 3));
-  key = sqlite3_column_blob (stmt, 3);
-  type = sqlite3_column_int (stmt, 4);
-
-  ntime = (int64_t) exp.abs_value_us;
-  if (ntime == INT64_MAX)
-    exp = GNUNET_TIME_UNIT_FOREVER_ABS;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Found %u-byte result with key %s when processing GET-RANDOM\n",
        (unsigned int) size,
-       GNUNET_h2s (key));
+       GNUNET_h2s (&key));
   (void) iter (iter_cls,
-               key,
+               &key,
                size,
                dat,
-               type,
+               (enum GNUNET_BLOCK_Type) type,
                exp,
                psize,
                path);
-  sqlite3_finalize (stmt);
+  GNUNET_SQ_cleanup_result (rs);
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->get_random_stmt);
   return 1;
 }
 
@@ -542,83 +566,73 @@ sqlite_plugin_get_closest (void *cls,
                            void *iter_cls)
 {
   struct Plugin *plugin = cls;
-  sqlite3_stmt *stmt;
+  uint32_t num_results32 = num_results;
   struct GNUNET_TIME_Absolute now;
   struct GNUNET_TIME_Absolute exp;
-  unsigned int size;
-  const char *dat;
+  size_t size;
+  void *dat;
   unsigned int cnt;
-  unsigned int psize;
-  unsigned int type;
-  int64_t ntime;
-  const struct GNUNET_PeerIdentity *path;
+  size_t psize;
+  uint32_t type;
+  struct GNUNET_HashCode hc;
+  struct GNUNET_PeerIdentity *path;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_auto_from_type (key),
+    GNUNET_SQ_query_param_absolute_time (&now),
+    GNUNET_SQ_query_param_uint32 (&num_results32),
+    GNUNET_SQ_query_param_end
+  };
+  struct GNUNET_SQ_ResultSpec rs[] = {
+    GNUNET_SQ_result_spec_variable_size (&dat,
+                                         &size),
+    GNUNET_SQ_result_spec_absolute_time (&exp),
+    GNUNET_SQ_result_spec_variable_size ((void **) &path,
+                                         &psize),
+    GNUNET_SQ_result_spec_uint32 (&type),
+    GNUNET_SQ_result_spec_auto_from_type (&hc),
+    GNUNET_SQ_result_spec_end
+  };
 
   now = GNUNET_TIME_absolute_get ();
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Processing GET_CLOSEST for key `%4s'\n",
+       "Processing GET_CLOSEST for key `%s'\n",
        GNUNET_h2s (key));
-  if (SQLITE_OK !=
-      sq_prepare (plugin->dbh,
-                  "SELECT value,expire,path,type,key FROM ds090 WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
-                  &stmt))
-  {
-    LOG_SQLITE (plugin->dbh,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sq_prepare");
-    return 0;
-  }
-  ntime = (int64_t) now.abs_value_us;
-  GNUNET_assert (ntime >= 0);
-  if ((SQLITE_OK !=
-       sqlite3_bind_blob (stmt,
-                          1,
-                          key,
-                          sizeof (struct GNUNET_HashCode),
-                          SQLITE_TRANSIENT)) ||
-      (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, now.abs_value_us)) ||
-      (SQLITE_OK != sqlite3_bind_int (stmt, 3, num_results)) )
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->get_closest_stmt,
+                      params))
   {
     LOG_SQLITE (plugin->dbh,
                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind_xxx");
-    sqlite3_finalize (stmt);
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->get_closest_stmt);
     return 0;
   }
   cnt = 0;
-  while (SQLITE_ROW == sqlite3_step (stmt))
+  while (SQLITE_ROW ==
+         sqlite3_step (plugin->get_closest_stmt))
   {
-    if (sizeof (struct GNUNET_HashCode) !=
-        sqlite3_column_bytes (stmt, 4))
+    if (GNUNET_OK !=
+        GNUNET_SQ_extract_result (plugin->get_closest_stmt,
+                                  rs))
     {
       GNUNET_break (0);
       break;
     }
-    size = sqlite3_column_bytes (stmt, 0);
-    dat = sqlite3_column_blob (stmt, 0);
-    exp.abs_value_us = sqlite3_column_int64 (stmt, 1);
-    psize = sqlite3_column_bytes (stmt, 2);
-    type = sqlite3_column_int (stmt, 3);
-    key = sqlite3_column_blob (stmt, 4);
     if (0 != psize % sizeof (struct GNUNET_PeerIdentity))
     {
       GNUNET_break (0);
       psize = 0;
+      path = NULL;
     }
     psize /= sizeof (struct GNUNET_PeerIdentity);
-    if (0 != psize)
-      path = sqlite3_column_blob (stmt, 2);
-    else
-      path = NULL;
-    ntime = (int64_t) exp.abs_value_us;
-    if (ntime == INT64_MAX)
-      exp = GNUNET_TIME_UNIT_FOREVER_ABS;
     cnt++;
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Found %u-byte result at %s when processing GET_CLOSE\n",
          (unsigned int) size,
-         GNUNET_h2s (key));
+         GNUNET_h2s (&hc));
     if (GNUNET_OK != iter (iter_cls,
-                           key,
+                           &hc,
                            size,
                            dat,
                            type,
@@ -626,11 +640,13 @@ sqlite_plugin_get_closest (void *cls,
                            psize,
                            path))
     {
-      sqlite3_finalize (stmt);
+      GNUNET_SQ_cleanup_result (rs);
       break;
     }
+    GNUNET_SQ_cleanup_result (rs);
   }
-  sqlite3_finalize (stmt);
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->get_closest_stmt);
   return cnt;
 }
 
@@ -703,6 +719,51 @@ libgnunet_plugin_datacache_sqlite_init (void *cls)
   plugin->env = env;
   plugin->dbh = dbh;
   plugin->fn = fn_utf8;
+
+  if ( (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "INSERT INTO ds090 (type, expire, key, value, path) "
+                    "VALUES (?, ?, ?, ?, ?)",
+                    &plugin->insert_stmt)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT count(*) FROM ds090 "
+                    "WHERE key=? AND type=? AND expire >= ?",
+                    &plugin->get_count_stmt)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT value,expire,path FROM ds090 "
+                    "WHERE key=? AND type=? AND expire >= ? LIMIT 1 OFFSET ?",
+                    &plugin->get_stmt)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT _ROWID_,key,value FROM ds090 ORDER BY expire ASC LIMIT 1",
+                    &plugin->del_select_stmt)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "DELETE FROM ds090 WHERE _ROWID_=?",
+                    &plugin->del_stmt)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT value,expire,path,key,type FROM ds090 "
+                    "ORDER BY key LIMIT 1 OFFSET ?",
+                    &plugin->get_random_stmt)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT value,expire,path,type,key FROM ds090 "
+                    "WHERE key>=? AND expire >= ? ORDER BY KEY ASC LIMIT ?",
+                    &plugin->get_closest_stmt))
+       )
+  {
+    LOG_SQLITE (plugin->dbh,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                "sq_prepare");
+    GNUNET_break (SQLITE_OK ==
+                  sqlite3_close (plugin->dbh));
+    GNUNET_free (plugin);
+    return NULL;
+  }
+
   api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
   api->cls = plugin;
   api->get = &sqlite_plugin_get;
@@ -741,6 +802,13 @@ libgnunet_plugin_datacache_sqlite_done (void *cls)
                        plugin->fn);
   GNUNET_free_non_null (plugin->fn);
 #endif
+  sqlite3_finalize (plugin->insert_stmt);
+  sqlite3_finalize (plugin->get_count_stmt);
+  sqlite3_finalize (plugin->get_stmt);
+  sqlite3_finalize (plugin->del_select_stmt);
+  sqlite3_finalize (plugin->del_stmt);
+  sqlite3_finalize (plugin->get_random_stmt);
+  sqlite3_finalize (plugin->get_closest_stmt);
   result = sqlite3_close (plugin->dbh);
 #if SQLITE_VERSION_NUMBER >= 3007000
   if (SQLITE_BUSY == result)
index 1285020de2796a5beab609ad09f877d42b3bd757..9b8cf365fd633f0d6646cd382ce87abed7e3d620 100644 (file)
@@ -115,6 +115,7 @@ noinst_LTLIBRARIES = \
 libgnunet_plugin_datastore_sqlite_la_SOURCES = \
   plugin_datastore_sqlite.c
 libgnunet_plugin_datastore_sqlite_la_LIBADD = \
+  $(top_builddir)/src/sq/libgnunetsq.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
   $(LTLIBINTL)
index 9de72f064e55f409fcc93ad3cf42da0f147454bb..5fd3601612062a11b612782e1518f09080afeec4 100644 (file)
@@ -119,9 +119,14 @@ struct GetKeyMessage
   uint32_t type GNUNET_PACKED;
 
   /**
-   * Offset of the result.
+   * UID at which to start the search
    */
-  uint64_t offset GNUNET_PACKED;
+  uint64_t next_uid GNUNET_PACKED;
+
+  /**
+   * If true return a random result
+   */
+  uint32_t random GNUNET_PACKED;
 
   /**
    * Desired key.
@@ -148,9 +153,14 @@ struct GetMessage
   uint32_t type GNUNET_PACKED;
 
   /**
-   * Offset of the result.
+   * UID at which to start the search
+   */
+  uint64_t next_uid GNUNET_PACKED;
+
+  /**
+   * If true return a random result
    */
-  uint64_t offset GNUNET_PACKED;
+  uint32_t random GNUNET_PACKED;
 
 };
 
@@ -172,9 +182,9 @@ struct GetZeroAnonymityMessage
   uint32_t type GNUNET_PACKED;
 
   /**
-   * Offset of the result.
+   * UID at which to start the search
    */
-  uint64_t offset GNUNET_PACKED;
+  uint64_t next_uid GNUNET_PACKED;
 
 };
 
index 916e6acaef930121af9a4bfa04f0be4c72437d35..26e1e501dde643e172e7041d4628c7069fa1441d 100644 (file)
@@ -33,6 +33,8 @@
 
 #define LOG(kind,...) GNUNET_log_from (kind, "datastore-api",__VA_ARGS__)
 
+#define DELAY_WARN_TIMEOUT GNUNET_TIME_UNIT_MINUTES
+
 /**
  * Collect an instane number of statistics?  May cause excessive IPC.
  */
@@ -137,6 +139,12 @@ struct GNUNET_DATASTORE_QueueEntry
    */
   struct GNUNET_MQ_Envelope *env;
 
+  /**
+   * Task we run if this entry stalls the queue and we
+   * need to warn the user.
+   */
+  struct GNUNET_SCHEDULER_Task *delay_warn_task;
+
   /**
    * Priority in the queue.
    */
@@ -269,10 +277,35 @@ free_queue_entry (struct GNUNET_DATASTORE_QueueEntry *qe)
   h->queue_size--;
   if (NULL != qe->env)
     GNUNET_MQ_discard (qe->env);
+  if (NULL != qe->delay_warn_task)
+    GNUNET_SCHEDULER_cancel (qe->delay_warn_task);
   GNUNET_free (qe);
 }
 
 
+/**
+ * Task that logs an error after some time.
+ *
+ * @param qe `struct GNUNET_DATASTORE_QueueEntry` about which the error is
+ */
+static void
+delay_warning (void *cls)
+{
+  struct GNUNET_DATASTORE_QueueEntry *qe = cls;
+
+  qe->delay_warn_task = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Request %p of type %u at head of datastore queue for more than %s\n",
+              qe,
+              (unsigned int) qe->response_type,
+              GNUNET_STRINGS_relative_time_to_string (DELAY_WARN_TIMEOUT,
+                                                      GNUNET_YES));
+  qe->delay_warn_task = GNUNET_SCHEDULER_add_delayed (DELAY_WARN_TIMEOUT,
+                                                      &delay_warning,
+                                                      qe);
+}
+
+
 /**
  * Handle error in sending drop request to datastore.
  *
@@ -290,8 +323,14 @@ mq_error_handler (void *cls,
        "MQ error, reconnecting to DATASTORE\n");
   do_disconnect (h);
   qe = h->queue_head;
-  if ( (NULL != qe) &&
-       (NULL == qe->env) )
+  if (NULL == qe)
+    return;
+  if (NULL != qe->delay_warn_task)
+  {
+    GNUNET_SCHEDULER_cancel (qe->delay_warn_task);
+    qe->delay_warn_task = NULL;
+  }
+  if (NULL == qe->env)
   {
     union QueueContext qc = qe->qc;
     uint16_t rt = qe->response_type;
@@ -594,6 +633,10 @@ process_queue (struct GNUNET_DATASTORE_Handle *h)
          "Not connected\n");
     return;
   }
+  GNUNET_assert (NULL == qe->delay_warn_task);
+  qe->delay_warn_task = GNUNET_SCHEDULER_add_delayed (DELAY_WARN_TIMEOUT,
+                                                      &delay_warning,
+                                                      qe);
   GNUNET_MQ_send (h->mq,
                   qe->env);
   qe->env = NULL;
@@ -958,7 +1001,7 @@ GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h,
   struct DataMessage *dm;
   union QueueContext qc;
 
-  if (size + sizeof (*dm) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (size + sizeof (*dm) >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return NULL;
@@ -1169,7 +1212,7 @@ GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h,
   struct GNUNET_MQ_Envelope *env;
   union QueueContext qc;
 
-  if (sizeof (*dm) + size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (sizeof (*dm) + size >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return NULL;
@@ -1282,10 +1325,7 @@ GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h,
  * Get a single zero-anonymity value from the datastore.
  *
  * @param h handle to the datastore
- * @param offset offset of the result (modulo num-results); set to
- *               a random 64-bit value initially; then increment by
- *               one each time; detect that all results have been found by uid
- *               being again the first uid ever returned.
+ * @param next_uid return the result with lowest uid >= next_uid
  * @param queue_priority ranking of this request in the priority queue
  * @param max_queue_size at what queue size should this request be dropped
  *        (if other requests of higher priority are in the queue)
@@ -1299,7 +1339,7 @@ GNUNET_DATASTORE_get_for_replication (struct GNUNET_DATASTORE_Handle *h,
  */
 struct GNUNET_DATASTORE_QueueEntry *
 GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
-                                     uint64_t offset,
+                                     uint64_t next_uid,
                                      unsigned int queue_priority,
                                      unsigned int max_queue_size,
                                      enum GNUNET_BLOCK_Type type,
@@ -1314,13 +1354,12 @@ GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
   GNUNET_assert (NULL != proc);
   GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Asked to get %llu-th zero-anonymity entry of type %d\n",
-       (unsigned long long) offset,
+       "Asked to get a zero-anonymity entry of type %d\n",
        type);
   env = GNUNET_MQ_msg (m,
                        GNUNET_MESSAGE_TYPE_DATASTORE_GET_ZERO_ANONYMITY);
   m->type = htonl ((uint32_t) type);
-  m->offset = GNUNET_htonll (offset);
+  m->next_uid = GNUNET_htonll (next_uid);
   qc.rc.proc = proc;
   qc.rc.proc_cls = proc_cls;
   qe = make_queue_entry (h,
@@ -1349,10 +1388,8 @@ GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
  * will only be called once.
  *
  * @param h handle to the datastore
- * @param offset offset of the result (modulo num-results); set to
- *               a random 64-bit value initially; then increment by
- *               one each time; detect that all results have been found by uid
- *               being again the first uid ever returned.
+ * @param next_uid return the result with lowest uid >= next_uid
+ * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
  * @param type desired type, 0 for any
  * @param queue_priority ranking of this request in the priority queue
@@ -1366,7 +1403,8 @@ GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
  */
 struct GNUNET_DATASTORE_QueueEntry *
 GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
-                          uint64_t offset,
+                          uint64_t next_uid,
+                          bool random,
                           const struct GNUNET_HashCode *key,
                           enum GNUNET_BLOCK_Type type,
                           unsigned int queue_priority,
@@ -1390,14 +1428,16 @@ GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
     env = GNUNET_MQ_msg (gm,
                          GNUNET_MESSAGE_TYPE_DATASTORE_GET);
     gm->type = htonl (type);
-    gm->offset = GNUNET_htonll (offset);
+    gm->next_uid = GNUNET_htonll (next_uid);
+    gm->random = random;
   }
   else
   {
     env = GNUNET_MQ_msg (gkm,
                          GNUNET_MESSAGE_TYPE_DATASTORE_GET_KEY);
     gkm->type = htonl (type);
-    gkm->offset = GNUNET_htonll (offset);
+    gkm->next_uid = GNUNET_htonll (next_uid);
+    gkm->random = random;
     gkm->key = *key;
   }
   qc.rc.proc = proc;
index b3d14c43c11ef17a3089c08daa2d5d5729e5ed66..c93bc8dd332d5140ede9e74a1968fe86d9e571eb 100644 (file)
@@ -171,7 +171,7 @@ static void
 do_get ()
 {
   qe = GNUNET_DATASTORE_get_key (db_src,
-                                offset,
+                                0, false,
                                 NULL, GNUNET_BLOCK_TYPE_ANY,
                                 0, 1,
                                 &do_put, NULL);
@@ -239,10 +239,12 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    { 's', "sourcecfg", "FILENAME",
-      gettext_noop ("specifies the configuration to use to access an alternative datastore; will merge that datastore into our current datastore"),
-      1, &GNUNET_GETOPT_set_filename, &alternative_cfg },
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_FILENAME ('s',
+                                   "sourcecfg",
+                                   "FILENAME",
+                                   gettext_noop ("specifies the configuration to use to access an alternative datastore; will merge that datastore into our current datastore"),
+                                       &alternative_cfg),
     GNUNET_GETOPT_OPTION_END
   };
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
index 1e699fea3ba2cd8f4f49d7ab978e4b72398e218b..af33c4412620419dba72effb08c2e24a5bdf1399 100644 (file)
@@ -307,7 +307,7 @@ expired_processor (void *cls,
 {
   struct GNUNET_TIME_Absolute now;
 
-  if (key == NULL)
+  if (NULL == key)
   {
     expired_kill_task =
         GNUNET_SCHEDULER_add_delayed_with_priority (MAX_EXPIRE_DELAY,
@@ -529,7 +529,7 @@ transmit_item (void *cls,
     return GNUNET_OK;
   }
   GNUNET_assert (sizeof (struct DataMessage) + size <
-                 GNUNET_SERVER_MAX_MESSAGE_SIZE);
+                 GNUNET_MAX_MESSAGE_SIZE);
   env = GNUNET_MQ_msg_extra (dm,
                              size,
                              GNUNET_MESSAGE_TYPE_DATASTORE_DATA);
@@ -984,12 +984,13 @@ handle_put (void *cls,
                         size,
                         &vhash);
     plugin->api->get_key (plugin->api->cls,
-                         0,
-                         &dm->key,
-                         &vhash,
+                          0,
+                          false,
+                          &dm->key,
+                          &vhash,
                           ntohl (dm->type),
-                         &check_present,
-                         pc);
+                          &check_present,
+                          pc);
     GNUNET_SERVICE_client_continue (client);
     return;
   }
@@ -1018,7 +1019,8 @@ handle_get (void *cls,
                             1,
                             GNUNET_NO);
   plugin->api->get_key (plugin->api->cls,
-                        GNUNET_ntohll (msg->offset),
+                        GNUNET_ntohll (msg->next_uid),
+                        msg->random,
                         NULL,
                         NULL,
                         ntohl (msg->type),
@@ -1069,7 +1071,8 @@ handle_get_key (void *cls,
     return;
   }
   plugin->api->get_key (plugin->api->cls,
-                        GNUNET_ntohll (msg->offset),
+                        GNUNET_ntohll (msg->next_uid),
+                        msg->random,
                         &msg->key,
                         NULL,
                         ntohl (msg->type),
@@ -1131,7 +1134,7 @@ handle_get_zero_anonymity (void *cls,
                             1,
                             GNUNET_NO);
   plugin->api->get_zero_anonymity (plugin->api->cls,
-                                   GNUNET_ntohll (msg->offset),
+                                   GNUNET_ntohll (msg->next_uid),
                                    type,
                                    &transmit_item,
                                    client);
@@ -1241,6 +1244,7 @@ handle_remove (void *cls,
               (uint32_t) ntohl (dm->type));
   plugin->api->get_key (plugin->api->cls,
                         0,
+                        false,
                         &dm->key,
                         &vhash,
                         (enum GNUNET_BLOCK_Type) ntohl (dm->type),
index 199c03a507e2a484074118a079fda5c3a8931c5a..e15cacb5bdfdd05bf2673d6cb6659462d5ee8406 100644 (file)
@@ -323,19 +323,19 @@ struct GetContext
 {
 
   /**
-   * Desired result offset / number of results.
+   * Lowest uid to consider.
    */
-  uint64_t offset;
+  uint64_t next_uid;
 
   /**
-   * The plugin.
+   * Value with lowest uid >= next_uid found so far.
    */
-  struct Plugin *plugin;
+  struct Value *value;
 
   /**
    * Requested value hash.
    */
-  const struct GNUNET_HashCode * vhash;
+  const struct GNUNET_HashCode *vhash;
 
   /**
    * Requested type.
@@ -343,68 +343,15 @@ struct GetContext
   enum GNUNET_BLOCK_Type type;
 
   /**
-   * Function to call with the result.
+   * If true, return a random value
    */
-  PluginDatumProcessor proc;
+  bool random;
 
-  /**
-   * Closure for 'proc'.
-   */
-  void *proc_cls;
 };
 
 
 /**
- * Test if a value matches the specification from the 'get' context
- *
- * @param gc query
- * @param value the value to check against the query
- * @return GNUNET_YES if the value matches
- */
-static int
-match (const struct GetContext *gc,
-       struct Value *value)
-{
-  struct GNUNET_HashCode vh;
-
-  if ( (gc->type != GNUNET_BLOCK_TYPE_ANY) &&
-       (gc->type != value->type) )
-    return GNUNET_NO;
-  if (NULL != gc->vhash)
-  {
-    GNUNET_CRYPTO_hash (&value[1], value->size, &vh);
-    if (0 != memcmp (&vh, gc->vhash, sizeof (struct GNUNET_HashCode)))
-      return GNUNET_NO;
-  }
-  return GNUNET_YES;
-}
-
-
-/**
- * Count number of matching values.
- *
- * @param cls the 'struct GetContext'
- * @param key unused
- * @param val the 'struct Value'
- * @return GNUNET_YES (continue iteration)
- */
-static int
-count_iterator (void *cls,
-               const struct GNUNET_HashCode *key,
-               void *val)
-{
-  struct GetContext *gc = cls;
-  struct Value *value = val;
-
-  if (GNUNET_NO == match (gc, value))
-    return GNUNET_OK;
-  gc->offset++;
-  return GNUNET_OK;
-}
-
-
-/**
- * Obtain matching value at 'offset'.
+ * Obtain the matching value with the lowest uid >= next_uid.
  *
  * @param cls the 'struct GetContext'
  * @param key unused
@@ -418,23 +365,29 @@ get_iterator (void *cls,
 {
   struct GetContext *gc = cls;
   struct Value *value = val;
+  struct GNUNET_HashCode vh;
 
-  if (GNUNET_NO == match (gc, value))
+  if ( (gc->type != GNUNET_BLOCK_TYPE_ANY) &&
+       (gc->type != value->type) )
     return GNUNET_OK;
-  if (0 != gc->offset--)
+  if (NULL != gc->vhash)
+  {
+    GNUNET_CRYPTO_hash (&value[1], value->size, &vh);
+    if (0 != memcmp (&vh, gc->vhash, sizeof (struct GNUNET_HashCode)))
+      return GNUNET_OK;
+  }
+  if (gc->random)
+  {
+    gc->value = value;
+    return GNUNET_NO;
+  }
+  if ( (uint64_t) (intptr_t) value < gc->next_uid)
     return GNUNET_OK;
-  if (GNUNET_NO ==
-      gc->proc (gc->proc_cls,
-               key,
-               value->size,
-               &value[1],
-               value->type,
-               value->priority,
-               value->anonymity,
-           value->expiration,
-               (uint64_t) (long) value))
-    delete_value (gc->plugin, value);
-  return GNUNET_NO;
+  if ( (NULL != gc->value) &&
+       (value > gc->value) )
+    return GNUNET_OK;
+  gc->value = value;
+  return GNUNET_OK;
 }
 
 
@@ -442,8 +395,8 @@ get_iterator (void *cls,
  * Get one of the results for a particular key in the datastore.
  *
  * @param cls closure
- * @param offset offset of the result (modulo num-results);
- *               specific ordering does not matter for the offset
+ * @param next_uid return the result with lowest uid >= next_uid
+ * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
  * @param vhash hash of the value, maybe NULL (to
  *        match all values that have the right key).
@@ -457,7 +410,7 @@ get_iterator (void *cls,
  * @param proc_cls closure for proc
  */
 static void
-heap_plugin_get_key (void *cls, uint64_t offset,
+heap_plugin_get_key (void *cls, uint64_t next_uid, bool random,
                     const struct GNUNET_HashCode *key,
                     const struct GNUNET_HashCode *vhash,
                     enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc,
@@ -466,46 +419,42 @@ heap_plugin_get_key (void *cls, uint64_t offset,
   struct Plugin *plugin = cls;
   struct GetContext gc;
 
-  gc.plugin = plugin;
-  gc.offset = 0;
+  gc.value = NULL;
+  gc.next_uid = next_uid;
+  gc.random = random;
   gc.vhash = vhash;
   gc.type = type;
-  gc.proc = proc;
-  gc.proc_cls = proc_cls;
   if (NULL == key)
   {
-    GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue,
-                                          &count_iterator,
-                                          &gc);
-    if (0 == gc.offset)
-    {
-      proc (proc_cls,
-           NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
-      return;
-    }
-    gc.offset = offset % gc.offset;
     GNUNET_CONTAINER_multihashmap_iterate (plugin->keyvalue,
                                           &get_iterator,
                                           &gc);
   }
   else
   {
-    GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue,
-                                               key,
-                                               &count_iterator,
-                                               &gc);
-    if (0 == gc.offset)
-    {
-      proc (proc_cls,
-           NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
-      return;
-    }
-    gc.offset = offset % gc.offset;
     GNUNET_CONTAINER_multihashmap_get_multiple (plugin->keyvalue,
                                                key,
                                                &get_iterator,
                                                &gc);
   }
+  if (NULL == gc.value)
+  {
+    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
+    return;
+  }
+  if (GNUNET_NO ==
+      proc (proc_cls,
+            &gc.value->key,
+            gc.value->size,
+            &gc.value[1],
+            gc.value->type,
+            gc.value->priority,
+            gc.value->anonymity,
+            gc.value->expiration,
+            (uint64_t) (intptr_t) gc.value))
+  {
+    delete_value (plugin, gc.value);
+  }
 }
 
 
@@ -559,7 +508,7 @@ heap_plugin_get_replication (void *cls,
            value->priority,
            value->anonymity,
            value->expiration,
-           (uint64_t) (long) value))
+           (uint64_t) (intptr_t) value))
     delete_value (plugin, value);
 }
 
@@ -595,7 +544,7 @@ heap_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
            value->priority,
            value->anonymity,
            value->expiration,
-           (uint64_t) (long) value))
+           (uint64_t) (intptr_t) value))
     delete_value (plugin, value);
 }
 
@@ -628,7 +577,7 @@ heap_plugin_update (void *cls,
 {
   struct Value *value;
 
-  value = (struct Value*) (long) uid;
+  value = (struct Value*) (intptr_t) uid;
   GNUNET_assert (NULL != value);
   if (value->expiration.abs_value_us != expire.abs_value_us)
   {
@@ -649,53 +598,43 @@ heap_plugin_update (void *cls,
  * Call the given processor on an item with zero anonymity.
  *
  * @param cls our "struct Plugin*"
- * @param offset offset of the result (modulo num-results);
- *               specific ordering does not matter for the offset
+ * @param next_uid return the result with lowest uid >= next_uid
  * @param type entries of which type should be considered?
- *        Use 0 for any type.
+ *        Must not be zero (ANY).
  * @param proc function to call on each matching value;
- *        will be called  with NULL if no value matches
+ *        will be called with NULL if no value matches
  * @param proc_cls closure for proc
  */
 static void
-heap_plugin_get_zero_anonymity (void *cls, uint64_t offset,
+heap_plugin_get_zero_anonymity (void *cls, uint64_t next_uid,
                                enum GNUNET_BLOCK_Type type,
                                PluginDatumProcessor proc, void *proc_cls)
 {
   struct Plugin *plugin = cls;
   struct ZeroAnonByType *zabt;
-  struct Value *value;
-  uint64_t count;
+  struct Value *value = NULL;
 
-  count = 0;
   for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
   {
     if ( (type != GNUNET_BLOCK_TYPE_ANY) &&
-        (type != zabt->type) )
+         (type != zabt->type) )
       continue;
-    count += zabt->array_pos;
+    for (int i = 0; i < zabt->array_pos; ++i)
+    {
+      if ( (uint64_t) (intptr_t) zabt->array[i] < next_uid)
+        continue;
+      if ( (NULL != value) &&
+           (zabt->array[i] > value) )
+        continue;
+      value = zabt->array[i];
+    }
   }
-  if (0 == count)
+  if (NULL == value)
   {
     proc (proc_cls,
-         NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
+          NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
     return;
   }
-  offset = offset % count;
-  for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next)
-  {
-    if ( (type != GNUNET_BLOCK_TYPE_ANY) &&
-        (type != zabt->type) )
-      continue;
-    if (offset >= zabt->array_pos)
-    {
-      offset -= zabt->array_pos;
-      continue;
-    }
-    break;
-  }
-  GNUNET_assert (NULL != zabt);
-  value = zabt->array[offset];
   if (GNUNET_NO ==
       proc (proc_cls,
            &value->key,
@@ -705,7 +644,7 @@ heap_plugin_get_zero_anonymity (void *cls, uint64_t offset,
            value->priority,
            value->anonymity,
            value->expiration,
-           (uint64_t) (long) value))
+           (uint64_t) (intptr_t) value))
     delete_value (plugin, value);
 }
 
index 1067064aa1ca0cfdb824ee49dbf5d918844c1a4a..5ae4485cbb9b47fc2635f6841e4a5fb35d89979a 100644 (file)
@@ -150,28 +150,19 @@ struct Plugin
 #define DELETE_ENTRY_BY_UID "DELETE FROM gn090 WHERE uid=?"
   struct GNUNET_MYSQL_StatementHandle *delete_entry_by_uid;
 
-#define COUNT_ENTRY_BY_HASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash) WHERE hash=?"
-  struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash;
+#define SELECT_ENTRY "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 WHERE uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
+  struct GNUNET_MYSQL_StatementHandle *select_entry;
 
-#define SELECT_ENTRY_BY_HASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash) WHERE hash=? ORDER BY uid LIMIT 1 OFFSET ?"
+#define SELECT_ENTRY_BY_HASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash) WHERE hash=? AND uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
   struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash;
 
-#define COUNT_ENTRY_BY_HASH_AND_VHASH "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=?"
-  struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_vhash;
-
-#define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? ORDER BY uid LIMIT 1 OFFSET ?"
+#define SELECT_ENTRY_BY_HASH_AND_VHASH "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
   struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_vhash;
 
-#define COUNT_ENTRY_BY_HASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=?"
-  struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_and_type;
-
-#define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=? ORDER BY uid LIMIT 1 OFFSET ?"
+#define SELECT_ENTRY_BY_HASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_type_uid) WHERE hash=? AND type=? AND uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
   struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_and_type;
 
-#define COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT count(*) FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=?"
-  struct GNUNET_MYSQL_StatementHandle *count_entry_by_hash_vhash_and_type;
-
-#define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=? ORDER BY uid ASC LIMIT 1 OFFSET ?"
+#define SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_hash_vhash) WHERE hash=? AND vhash=? AND type=? AND uid >= ? AND (rvalue >= ? OR 0 = ?) ORDER BY uid LIMIT 1"
   struct GNUNET_MYSQL_StatementHandle *select_entry_by_hash_vhash_and_type;
 
 #define UPDATE_ENTRY "UPDATE gn090 SET prio=prio+?,expire=IF(expire>=?,expire,?) WHERE uid=?"
@@ -185,10 +176,8 @@ struct Plugin
 
 #define SELECT_IT_NON_ANONYMOUS "SELECT type,prio,anonLevel,expire,hash,value,uid "\
    "FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) "\
-   "WHERE anonLevel=0 AND type=? AND "\
-   "(rvalue >= ? OR"\
-   "  NOT EXISTS (SELECT 1 FROM gn090 FORCE INDEX (idx_anonLevel_type_rvalue) WHERE anonLevel=0 AND type=? AND rvalue>=?)) "\
-   "ORDER BY rvalue ASC LIMIT 1"
+   "WHERE anonLevel=0 AND type=? AND uid >= ? "\
+   "ORDER BY uid LIMIT 1"
   struct GNUNET_MYSQL_StatementHandle *zero_iter;
 
 #define SELECT_IT_EXPIRATION "SELECT type,prio,anonLevel,expire,hash,value,uid FROM gn090 FORCE INDEX (idx_expire) WHERE expire < ? ORDER BY expire ASC LIMIT 1"
@@ -541,8 +530,8 @@ execute_select (struct Plugin *plugin,
  * Get one of the results for a particular key in the datastore.
  *
  * @param cls closure
- * @param offset offset of the result (modulo num-results);
- *               specific ordering does not matter for the offset
+ * @param next_uid return the result with lowest uid >= next_uid
+ * @param random if true, return a random result instead of using next_uid
  * @param key key to match, never NULL
  * @param vhash hash of the value, maybe NULL (to
  *        match all values that have the right key).
@@ -557,7 +546,8 @@ execute_select (struct Plugin *plugin,
  */
 static void
 mysql_plugin_get_key (void *cls,
-                      uint64_t offset,
+                      uint64_t next_uid,
+                      bool random,
                       const struct GNUNET_HashCode *key,
                       const struct GNUNET_HashCode *vhash,
                       enum GNUNET_BLOCK_Type type,
@@ -565,121 +555,33 @@ mysql_plugin_get_key (void *cls,
                       void *proc_cls)
 {
   struct Plugin *plugin = cls;
-  int ret;
-  uint64_t total;
-  struct GNUNET_MY_ResultSpec results_get[] = {
-    GNUNET_MY_result_spec_uint64 (&total),
-    GNUNET_MY_result_spec_end
-  };
+  uint64_t rvalue;
 
-  total = UINT64_MAX;
-  if (0 != type)
+  if (random)
   {
-    if (NULL != vhash)
-    {
-      struct GNUNET_MY_QueryParam params_get[] = {
-        GNUNET_MY_query_param_auto_from_type (key),
-        GNUNET_MY_query_param_auto_from_type (vhash),
-        GNUNET_MY_query_param_uint32 (&type),
-        GNUNET_MY_query_param_end
-      };
-
-      ret =
-        GNUNET_MY_exec_prepared (plugin->mc,
-                                 plugin->count_entry_by_hash_vhash_and_type,
-                                 params_get);
-      GNUNET_break (GNUNET_OK == ret);
-      if (GNUNET_OK == ret)
-        ret =
-          GNUNET_MY_extract_result (plugin->count_entry_by_hash_vhash_and_type,
-                                    results_get);
-      if (GNUNET_OK == ret)
-        GNUNET_break (GNUNET_NO ==
-                      GNUNET_MY_extract_result (plugin->count_entry_by_hash_vhash_and_type,
-                                                NULL));
-    }
-    else
-    {
-      struct GNUNET_MY_QueryParam params_get[] = {
-        GNUNET_MY_query_param_auto_from_type (key),
-        GNUNET_MY_query_param_uint32 (&type),
-        GNUNET_MY_query_param_end
-      };
-
-      ret =
-        GNUNET_MY_exec_prepared (plugin->mc,
-                                 plugin->count_entry_by_hash_and_type,
-                                 params_get);
-      GNUNET_break (GNUNET_OK == ret);
-      if (GNUNET_OK == ret)
-        ret =
-          GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_type,
-                                    results_get);
-      if (GNUNET_OK == ret)
-        GNUNET_break (GNUNET_NO ==
-                      GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_type,
-                                                NULL));
-    }
+    rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                       UINT64_MAX);
+    next_uid = 0;
   }
   else
-  {
-    if (NULL != vhash)
-    {
-      struct GNUNET_MY_QueryParam params_get[] = {
-        GNUNET_MY_query_param_auto_from_type (key),
-        GNUNET_MY_query_param_auto_from_type (vhash),
-        GNUNET_MY_query_param_end
-      };
+    rvalue = 0;
 
-      ret =
-        GNUNET_MY_exec_prepared (plugin->mc,
-                                 plugin->count_entry_by_hash_and_vhash,
-                                 params_get);
-      GNUNET_break (GNUNET_OK == ret);
-      if (GNUNET_OK == ret)
-        ret =
-          GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_vhash,
-                                    results_get);
-      if (GNUNET_OK == ret)
-        GNUNET_break (GNUNET_NO ==
-                      GNUNET_MY_extract_result (plugin->count_entry_by_hash_and_vhash,
-                                                NULL));
-    }
-    else
-    {
-      struct GNUNET_MY_QueryParam params_get[] = {
-        GNUNET_MY_query_param_auto_from_type (key),
-        GNUNET_MY_query_param_end
-      };
-
-      ret =
-        GNUNET_MY_exec_prepared (plugin->mc,
-                                 plugin->count_entry_by_hash,
-                                 params_get);
-      GNUNET_break (GNUNET_OK == ret);
-      if (GNUNET_OK == ret)
-        ret =
-          GNUNET_MY_extract_result (plugin->count_entry_by_hash,
-                                    results_get);
-      if (GNUNET_OK == ret)
-        GNUNET_break (GNUNET_NO ==
-                      GNUNET_MY_extract_result (plugin->count_entry_by_hash,
-                                                NULL));
-    }
-  }
-  if ( (GNUNET_OK != ret) ||
-       (0 >= total) )
+  if (NULL == key)
   {
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
+    struct GNUNET_MY_QueryParam params_select[] = {
+      GNUNET_MY_query_param_uint64 (&next_uid),
+      GNUNET_MY_query_param_uint64 (&rvalue),
+      GNUNET_MY_query_param_uint64 (&rvalue),
+      GNUNET_MY_query_param_end
+    };
+
+    execute_select (plugin,
+                    plugin->select_entry,
+                    proc,
+                    proc_cls,
+                    params_select);
   }
-  offset = offset % total;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Obtaining %llu/%lld result for GET `%s'\n",
-              (unsigned long long) offset,
-              (unsigned long long) total,
-              GNUNET_h2s (key));
-  if (type != GNUNET_BLOCK_TYPE_ANY)
+  else if (type != GNUNET_BLOCK_TYPE_ANY)
   {
     if (NULL != vhash)
     {
@@ -687,7 +589,9 @@ mysql_plugin_get_key (void *cls,
         GNUNET_MY_query_param_auto_from_type (key),
         GNUNET_MY_query_param_auto_from_type (vhash),
         GNUNET_MY_query_param_uint32 (&type),
-        GNUNET_MY_query_param_uint64 (&offset),
+        GNUNET_MY_query_param_uint64 (&next_uid),
+        GNUNET_MY_query_param_uint64 (&rvalue),
+        GNUNET_MY_query_param_uint64 (&rvalue),
         GNUNET_MY_query_param_end
       };
 
@@ -702,7 +606,9 @@ mysql_plugin_get_key (void *cls,
       struct GNUNET_MY_QueryParam params_select[] = {
         GNUNET_MY_query_param_auto_from_type (key),
         GNUNET_MY_query_param_uint32 (&type),
-        GNUNET_MY_query_param_uint64 (&offset),
+        GNUNET_MY_query_param_uint64 (&next_uid),
+        GNUNET_MY_query_param_uint64 (&rvalue),
+        GNUNET_MY_query_param_uint64 (&rvalue),
         GNUNET_MY_query_param_end
       };
 
@@ -720,7 +626,9 @@ mysql_plugin_get_key (void *cls,
       struct GNUNET_MY_QueryParam params_select[] = {
         GNUNET_MY_query_param_auto_from_type (key),
         GNUNET_MY_query_param_auto_from_type (vhash),
-        GNUNET_MY_query_param_uint64 (&offset),
+        GNUNET_MY_query_param_uint64 (&next_uid),
+        GNUNET_MY_query_param_uint64 (&rvalue),
+        GNUNET_MY_query_param_uint64 (&rvalue),
         GNUNET_MY_query_param_end
       };
 
@@ -734,7 +642,9 @@ mysql_plugin_get_key (void *cls,
     {
       struct GNUNET_MY_QueryParam params_select[] = {
         GNUNET_MY_query_param_auto_from_type (key),
-        GNUNET_MY_query_param_uint64 (&offset),
+        GNUNET_MY_query_param_uint64 (&next_uid),
+        GNUNET_MY_query_param_uint64 (&rvalue),
+        GNUNET_MY_query_param_uint64 (&rvalue),
         GNUNET_MY_query_param_end
       };
 
@@ -753,28 +663,26 @@ mysql_plugin_get_key (void *cls,
  * Get a zero-anonymity datum from the datastore.
  *
  * @param cls our `struct Plugin *`
- * @param offset offset of the result
+ * @param next_uid return the result with lowest uid >= next_uid
  * @param type entries of which type should be considered?
- *        Use 0 for any type.
- * @param proc function to call on a matching value or NULL
+ *        Must not be zero (ANY).
+ * @param proc function to call on a matching value;
+ *        will be called with NULL if no value matches
  * @param proc_cls closure for @a proc
  */
 static void
 mysql_plugin_get_zero_anonymity (void *cls,
-                                 uint64_t offset,
+                                 uint64_t next_uid,
                                  enum GNUNET_BLOCK_Type type,
                                  PluginDatumProcessor proc,
                                  void *proc_cls)
 {
   struct Plugin *plugin = cls;
   uint32_t typei = (uint32_t) type;
-  uint64_t rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
-                                              UINT64_MAX);
+
   struct GNUNET_MY_QueryParam params_zero_iter[] = {
     GNUNET_MY_query_param_uint32 (&typei),
-    GNUNET_MY_query_param_uint64 (&rvalue),
-    GNUNET_MY_query_param_uint32 (&typei),
-    GNUNET_MY_query_param_uint64 (&rvalue),
+    GNUNET_MY_query_param_uint64 (&next_uid),
     GNUNET_MY_query_param_end
   };
 
@@ -1209,6 +1117,7 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
        ") ENGINE=InnoDB") || MRUNS ("SET AUTOCOMMIT = 1") ||
       PINIT (plugin->insert_entry, INSERT_ENTRY) ||
       PINIT (plugin->delete_entry_by_uid, DELETE_ENTRY_BY_UID) ||
+      PINIT (plugin->select_entry, SELECT_ENTRY) ||
       PINIT (plugin->select_entry_by_hash, SELECT_ENTRY_BY_HASH) ||
       PINIT (plugin->select_entry_by_hash_and_vhash,
              SELECT_ENTRY_BY_HASH_AND_VHASH) ||
@@ -1216,13 +1125,7 @@ libgnunet_plugin_datastore_mysql_init (void *cls)
              SELECT_ENTRY_BY_HASH_AND_TYPE) ||
       PINIT (plugin->select_entry_by_hash_vhash_and_type,
              SELECT_ENTRY_BY_HASH_VHASH_AND_TYPE) ||
-      PINIT (plugin->count_entry_by_hash, COUNT_ENTRY_BY_HASH) ||
       PINIT (plugin->get_size, SELECT_SIZE) ||
-      PINIT (plugin->count_entry_by_hash_and_vhash,
-             COUNT_ENTRY_BY_HASH_AND_VHASH) ||
-      PINIT (plugin->count_entry_by_hash_and_type, COUNT_ENTRY_BY_HASH_AND_TYPE)
-      || PINIT (plugin->count_entry_by_hash_vhash_and_type,
-                COUNT_ENTRY_BY_HASH_VHASH_AND_TYPE) ||
       PINIT (plugin->update_entry, UPDATE_ENTRY) ||
       PINIT (plugin->dec_repl, DEC_REPL) ||
       PINIT (plugin->zero_iter, SELECT_IT_NON_ANONYMOUS) ||
index 7b04cc68a7e6d9ef17f223172f5df06e98651a82..0376ebb6cd4809542532f2bba7fdfdd7cd6f0dc2 100644 (file)
@@ -80,6 +80,7 @@ init_connection (struct Plugin *plugin)
    * we only test equality on it and can cast it to/from uint32_t. For repl, prio, and anonLevel
    * we do math or inequality tests, so we can't handle the entire range of uint32_t.
    * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
+   * PostgreSQL also recommends against using WITH OIDS.
    */
   ret =
       PQexec (plugin->dbh,
@@ -114,13 +115,17 @@ init_connection (struct Plugin *plugin)
   if (PQresultStatus (ret) == PGRES_COMMAND_OK)
   {
     if ((GNUNET_OK !=
-         GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)")) ||
+         GNUNET_POSTGRES_exec (plugin->dbh,
+                               "CREATE INDEX IF NOT EXISTS idx_hash ON gn090 (hash)")) ||
         (GNUNET_OK !=
-         GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_hash_vhash ON gn090 (hash,vhash)")) ||
+         GNUNET_POSTGRES_exec (plugin->dbh,
+                               "CREATE INDEX IF NOT EXISTS idx_hash_vhash ON gn090 (hash,vhash)")) ||
         (GNUNET_OK !=
-         GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_prio ON gn090 (prio)")) ||
+         GNUNET_POSTGRES_exec (plugin->dbh,
+                               "CREATE INDEX IF NOT EXISTS idx_prio ON gn090 (prio)")) ||
         (GNUNET_OK !=
-         GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_expire ON gn090 (expire)")) ||
+         GNUNET_POSTGRES_exec (plugin->dbh,
+                               "CREATE INDEX IF NOT EXISTS idx_expire ON gn090 (expire)")) ||
         (GNUNET_OK !=
          GNUNET_POSTGRES_exec (plugin->dbh,
                                "CREATE INDEX IF NOT EXISTS idx_prio_anon ON gn090 (prio,anonLevel)")) ||
@@ -128,9 +133,11 @@ init_connection (struct Plugin *plugin)
          GNUNET_POSTGRES_exec (plugin->dbh,
                                "CREATE INDEX IF NOT EXISTS idx_prio_hash_anon ON gn090 (prio,hash,anonLevel)")) ||
         (GNUNET_OK !=
-         GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn090 (repl,rvalue)")) ||
+         GNUNET_POSTGRES_exec (plugin->dbh,
+                               "CREATE INDEX IF NOT EXISTS idx_repl_rvalue ON gn090 (repl,rvalue)")) ||
         (GNUNET_OK !=
-         GNUNET_POSTGRES_exec (plugin->dbh, "CREATE INDEX IF NOT EXISTS idx_expire_hash ON gn090 (expire,hash)")))
+         GNUNET_POSTGRES_exec (plugin->dbh,
+                               "CREATE INDEX IF NOT EXISTS idx_expire_hash ON gn090 (expire,hash)")))
     {
       PQclear (ret);
       PQfinish (plugin->dbh);
@@ -170,40 +177,18 @@ init_connection (struct Plugin *plugin)
   }
   PQclear (ret);
   if ((GNUNET_OK !=
-       GNUNET_POSTGRES_prepare (plugin->dbh, "getvt",
-                   "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
-                   "WHERE hash=$1 AND vhash=$2 AND type=$3 "
-                   "ORDER BY oid ASC LIMIT 1 OFFSET $4", 4)) ||
-      (GNUNET_OK !=
-       GNUNET_POSTGRES_prepare (plugin->dbh, "gett",
-                   "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
-                   "WHERE hash=$1 AND type=$2 "
-                   "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) ||
-      (GNUNET_OK !=
-       GNUNET_POSTGRES_prepare (plugin->dbh, "getv",
-                   "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
-                   "WHERE hash=$1 AND vhash=$2 "
-                   "ORDER BY oid ASC LIMIT 1 OFFSET $3", 3)) ||
-      (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "get",
                    "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
-                   "WHERE hash=$1 " "ORDER BY oid ASC LIMIT 1 OFFSET $2", 2)) ||
-      (GNUNET_OK !=
-       GNUNET_POSTGRES_prepare (plugin->dbh, "count_getvt",
-                               "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2 AND type=$3", 3)) ||
-      (GNUNET_OK !=
-       GNUNET_POSTGRES_prepare (plugin->dbh, "count_gett",
-                               "SELECT count(*) FROM gn090 WHERE hash=$1 AND type=$2", 2)) ||
-      (GNUNET_OK !=
-       GNUNET_POSTGRES_prepare (plugin->dbh, "count_getv",
-                               "SELECT count(*) FROM gn090 WHERE hash=$1 AND vhash=$2", 2)) ||
-      (GNUNET_OK !=
-       GNUNET_POSTGRES_prepare (plugin->dbh, "count_get",
-                               "SELECT count(*) FROM gn090 WHERE hash=$1", 1)) ||
+                   "WHERE oid >= $1::bigint AND "
+                   "(rvalue >= $2 OR 0 = $3::smallint) AND "
+                   "(hash = $4 OR 0 = $5::smallint) AND "
+                   "(vhash = $6 OR 0 = $7::smallint) AND "
+                   "(type = $8 OR 0 = $9::smallint) "
+                   "ORDER BY oid ASC LIMIT 1", 9)) ||
       (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "put",
                    "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
-                   "VALUES ($1, $2, $3, $4, $5, RANDOM(), $6, $7, $8)", 9)) ||
+                   "VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)", 9)) ||
       (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "update",
                    "UPDATE gn090 SET prio = prio + $1, expire = CASE WHEN expire < $2 THEN $2 ELSE expire END "
@@ -215,8 +200,9 @@ init_connection (struct Plugin *plugin)
       (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "select_non_anonymous",
                    "SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
-                   "WHERE anonLevel = 0 AND type = $1 ORDER BY oid DESC LIMIT 1 OFFSET $2",
-                   1)) ||
+                   "WHERE anonLevel = 0 AND type = $1 AND oid >= $2::bigint "
+                   "ORDER BY oid ASC LIMIT 1",
+                   2)) ||
       (GNUNET_OK !=
        GNUNET_POSTGRES_prepare (plugin->dbh, "select_expiration_order",
                    "(SELECT type, prio, anonLevel, expire, hash, value, oid FROM gn090 "
@@ -322,6 +308,8 @@ postgres_plugin_put (void *cls,
   struct Plugin *plugin = cls;
   uint32_t utype = type;
   struct GNUNET_HashCode vhash;
+  uint64_t rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                              UINT64_MAX);
   PGresult *ret;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_uint32 (&replication),
@@ -329,6 +317,7 @@ postgres_plugin_put (void *cls,
     GNUNET_PQ_query_param_uint32 (&priority),
     GNUNET_PQ_query_param_uint32 (&anonymity),
     GNUNET_PQ_query_param_absolute_time (&expiration),
+    GNUNET_PQ_query_param_uint64 (&rvalue),
     GNUNET_PQ_query_param_auto_from_type (key),
     GNUNET_PQ_query_param_auto_from_type (&vhash),
     GNUNET_PQ_query_param_fixed_size (data, size),
@@ -489,12 +478,11 @@ process_result (struct Plugin *plugin,
 
 
 /**
- * Iterate over the results for a particular key
- * in the datastore.
+ * Get one of the results for a particular key in the datastore.
  *
  * @param cls closure with the 'struct Plugin'
- * @param offset offset of the result (modulo num-results);
- *        specific ordering does not matter for the offset
+ * @param next_uid return the result with lowest uid >= next_uid
+ * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
  * @param vhash hash of the value, maybe NULL (to
  *        match all values that have the right key).
@@ -504,160 +492,52 @@ process_result (struct Plugin *plugin,
  * @param type entries of which type are relevant?
  *     Use 0 for any type.
  * @param proc function to call on the matching value;
- *        will be called once with a NULL if no value matches
- * @param proc_cls closure for iter
+ *        will be called with NULL if nothing matches
+ * @param proc_cls closure for @a proc
  */
 static void
 postgres_plugin_get_key (void *cls,
-                        uint64_t offset,
+                         uint64_t next_uid,
+                         bool random,
                          const struct GNUNET_HashCode *key,
                          const struct GNUNET_HashCode *vhash,
                          enum GNUNET_BLOCK_Type type,
-                        PluginDatumProcessor proc,
+                         PluginDatumProcessor proc,
                          void *proc_cls)
 {
   struct Plugin *plugin = cls;
   uint32_t utype = type;
+  uint16_t use_rvalue = random;
+  uint16_t use_key = NULL != key;
+  uint16_t use_vhash = NULL != vhash;
+  uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type;
+  uint64_t rvalue;
+  struct GNUNET_PQ_QueryParam params[] = {
+    GNUNET_PQ_query_param_uint64 (&next_uid),
+    GNUNET_PQ_query_param_uint64 (&rvalue),
+    GNUNET_PQ_query_param_uint16 (&use_rvalue),
+    GNUNET_PQ_query_param_auto_from_type (key),
+    GNUNET_PQ_query_param_uint16 (&use_key),
+    GNUNET_PQ_query_param_auto_from_type (vhash),
+    GNUNET_PQ_query_param_uint16 (&use_vhash),
+    GNUNET_PQ_query_param_uint32 (&utype),
+    GNUNET_PQ_query_param_uint16 (&use_type),
+    GNUNET_PQ_query_param_end
+  };
   PGresult *ret;
-  uint64_t total;
-  uint64_t limit_off;
 
-  if (0 != type)
+  if (random)
   {
-    if (NULL != vhash)
-    {
-      struct GNUNET_PQ_QueryParam params[] = {
-       GNUNET_PQ_query_param_auto_from_type (key),
-       GNUNET_PQ_query_param_auto_from_type (vhash),
-       GNUNET_PQ_query_param_uint32 (&utype),
-       GNUNET_PQ_query_param_end
-      };
-      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
-                                    "count_getvt",
-                                    params);
-    }
-    else
-    {
-      struct GNUNET_PQ_QueryParam params[] = {
-       GNUNET_PQ_query_param_auto_from_type (key),
-       GNUNET_PQ_query_param_uint32 (&utype),
-       GNUNET_PQ_query_param_end
-      };
-      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
-                                    "count_gett",
-                                    params);
-    }
+    rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                       UINT64_MAX);
+    next_uid = 0;
   }
   else
-  {
-    if (NULL != vhash)
-    {
-      struct GNUNET_PQ_QueryParam params[] = {
-       GNUNET_PQ_query_param_auto_from_type (key),
-       GNUNET_PQ_query_param_auto_from_type (vhash),
-       GNUNET_PQ_query_param_end
-      };
-      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
-                                    "count_getv",
-                                    params);
-    }
-    else
-    {
-      struct GNUNET_PQ_QueryParam params[] = {
-       GNUNET_PQ_query_param_auto_from_type (key),
-       GNUNET_PQ_query_param_end
-      };
-      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
-                                    "count_get",
-                                    params);
-    }
-  }
+    rvalue = 0;
 
-  if (GNUNET_OK !=
-      GNUNET_POSTGRES_check_result (plugin->dbh,
-                                   ret,
-                                   PGRES_TUPLES_OK,
-                                   "PQexecParams",
-                                   "count"))
-  {
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0,
-         GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
-  }
-  if ( (PQntuples (ret) != 1) ||
-       (PQnfields (ret) != 1) ||
-       (PQgetlength (ret, 0, 0) != sizeof (uint64_t)))
-  {
-    GNUNET_break (0);
-    PQclear (ret);
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0,
-         GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
-  }
-  total = GNUNET_ntohll (*(const uint64_t *) PQgetvalue (ret, 0, 0));
-  PQclear (ret);
-  if (0 == total)
-  {
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0,
-         GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
-  }
-  limit_off = offset % total;
-
-  if (0 != type)
-  {
-    if (NULL != vhash)
-    {
-      struct GNUNET_PQ_QueryParam params[] = {
-       GNUNET_PQ_query_param_auto_from_type (key),
-       GNUNET_PQ_query_param_auto_from_type (vhash),
-       GNUNET_PQ_query_param_uint32 (&utype),
-       GNUNET_PQ_query_param_uint64 (&limit_off),
-       GNUNET_PQ_query_param_end
-      };
-      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
-                                    "getvt",
-                                    params);
-    }
-    else
-    {
-      struct GNUNET_PQ_QueryParam params[] = {
-       GNUNET_PQ_query_param_auto_from_type (key),
-       GNUNET_PQ_query_param_uint32 (&utype),
-       GNUNET_PQ_query_param_uint64 (&limit_off),
-       GNUNET_PQ_query_param_end
-      };
-      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
-                                    "gett",
-                                    params);
-    }
-  }
-  else
-  {
-    if (NULL != vhash)
-    {
-      struct GNUNET_PQ_QueryParam params[] = {
-       GNUNET_PQ_query_param_auto_from_type (key),
-       GNUNET_PQ_query_param_auto_from_type (vhash),
-       GNUNET_PQ_query_param_uint64 (&limit_off),
-       GNUNET_PQ_query_param_end
-      };
-      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
-                                    "getv",
-                                    params);
-    }
-    else
-    {
-      struct GNUNET_PQ_QueryParam params[] = {
-       GNUNET_PQ_query_param_auto_from_type (key),
-       GNUNET_PQ_query_param_uint64 (&limit_off),
-       GNUNET_PQ_query_param_end
-      };
-      ret = GNUNET_PQ_exec_prepared (plugin->dbh,
-                                    "get",
-                                    params);
-    }
-  }
+  ret = GNUNET_PQ_exec_prepared (plugin->dbh,
+                                 "get",
+                                 params);
   process_result (plugin,
                  proc,
                  proc_cls,
@@ -671,26 +551,25 @@ postgres_plugin_get_key (void *cls,
  * the given iterator for each of them.
  *
  * @param cls our `struct Plugin *`
- * @param offset offset of the result (modulo num-results);
- *        specific ordering does not matter for the offset
+ * @param next_uid return the result with lowest uid >= next_uid
  * @param type entries of which type should be considered?
- *        Use 0 for any type.
+ *        Must not be zero (ANY).
  * @param proc function to call on the matching value;
- *        will be called with NULL if no value matches
+ *        will be called with NULL if no value matches
  * @param proc_cls closure for @a proc
  */
 static void
 postgres_plugin_get_zero_anonymity (void *cls,
-                                   uint64_t offset,
+                                    uint64_t next_uid,
                                     enum GNUNET_BLOCK_Type type,
                                     PluginDatumProcessor proc,
-                                   void *proc_cls)
+                                    void *proc_cls)
 {
   struct Plugin *plugin = cls;
   uint32_t utype = type;
   struct GNUNET_PQ_QueryParam params[] = {
     GNUNET_PQ_query_param_uint32 (&utype),
-    GNUNET_PQ_query_param_uint64 (&offset),
+    GNUNET_PQ_query_param_uint64 (&next_uid),
     GNUNET_PQ_query_param_end
   };
   PGresult *ret;
index 9ab50714faf014f8025af4532755c450c588551a..76f791ad4296f86304fb801e2b7a0dab48d266dd 100644 (file)
@@ -1,6 +1,6 @@
  /*
   * This file is part of GNUnet
-  * Copyright (C) 2009, 2011 GNUnet e.V.
+  * Copyright (C) 2009, 2011, 2017 GNUnet e.V.
   *
   * GNUnet is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published
@@ -26,6 +26,7 @@
 
 #include "platform.h"
 #include "gnunet_datastore_plugin.h"
+#include "gnunet_sq_lib.h"
 #include <sqlite3.h>
 
 
@@ -126,6 +127,11 @@ struct Plugin
    */
   sqlite3_stmt *insertContent;
 
+  /**
+   * Precompiled SQL for selection
+   */
+  sqlite3_stmt *get;
+
   /**
    * Should the database be dropped on shutdown?
    */
@@ -150,11 +156,17 @@ sq_prepare (sqlite3 *dbh,
   char *dummy;
   int result;
 
-  result =
-      sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt,
-                          (const char **) &dummy);
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
-                   "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result);
+  result = sqlite3_prepare_v2 (dbh,
+                               zSql,
+                               strlen (zSql),
+                               ppStmt,
+                               (const char **) &dummy);
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                   "sqlite",
+                   "Prepared `%s' / %p: %d\n",
+                   zSql,
+                   *ppStmt,
+                   result);
   return result;
 }
 
@@ -310,80 +322,110 @@ database_setup (const struct GNUNET_CONFIGURATION_Handle *cfg,
    * we do math or inequality tests, so we can't handle the entire range of uint32_t.
    * This will also cause problems for expiration times after 294247-01-10-04:00:54 UTC.
    */
-  if ((sqlite3_step (stmt) == SQLITE_DONE) &&
-      (sqlite3_exec
-       (plugin->dbh,
-        "CREATE TABLE gn090 (" "  repl INT4 NOT NULL DEFAULT 0,"
-        "  type INT4 NOT NULL DEFAULT 0," "  prio INT4 NOT NULL DEFAULT 0,"
-        "  anonLevel INT4 NOT NULL DEFAULT 0,"
-        "  expire INT8 NOT NULL DEFAULT 0," "  rvalue INT8 NOT NULL,"
-        "  hash TEXT NOT NULL DEFAULT ''," "  vhash TEXT NOT NULL DEFAULT '',"
-        "  value BLOB NOT NULL DEFAULT '')", NULL, NULL, NULL) != SQLITE_OK))
+  if ( (SQLITE_DONE ==
+        sqlite3_step (stmt)) &&
+       (SQLITE_OK !=
+        sqlite3_exec (plugin->dbh,
+                      "CREATE TABLE gn090 ("
+                      "  repl INT4 NOT NULL DEFAULT 0,"
+                      "  type INT4 NOT NULL DEFAULT 0,"
+                      "  prio INT4 NOT NULL DEFAULT 0,"
+                      "  anonLevel INT4 NOT NULL DEFAULT 0,"
+                      "  expire INT8 NOT NULL DEFAULT 0,"
+                      "  rvalue INT8 NOT NULL,"
+                      "  hash TEXT NOT NULL DEFAULT '',"
+                      "  vhash TEXT NOT NULL DEFAULT '',"
+                      "  value BLOB NOT NULL DEFAULT '')",
+                      NULL,
+                      NULL,
+                      NULL)) )
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_exec");
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR,
+                "sqlite3_exec");
     sqlite3_finalize (stmt);
     return GNUNET_SYSERR;
   }
   sqlite3_finalize (stmt);
   create_indices (plugin->dbh);
 
-  if ((sq_prepare
-       (plugin->dbh,
-        "UPDATE gn090 "
-        "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?",
-        &plugin->updPrio) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
-        &plugin->updRepl) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
+  if ( (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "UPDATE gn090 "
+                    "SET prio = prio + ?, expire = MAX(expire,?) WHERE _ROWID_ = ?",
+                    &plugin->updPrio)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "UPDATE gn090 " "SET repl = MAX (0, repl - 1) WHERE _ROWID_ = ?",
+                    &plugin->updRepl)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
 #if SQLITE_VERSION_NUMBER >= 3007000
-        "INDEXED BY idx_repl_rvalue "
+                    "INDEXED BY idx_repl_rvalue "
 #endif
-        "WHERE repl=?2 AND " " (rvalue>=?1 OR "
-        "  NOT EXISTS (SELECT 1 FROM gn090 "
+                    "WHERE repl=?2 AND " " (rvalue>=?1 OR "
+                    "  NOT EXISTS (SELECT 1 FROM gn090 "
 #if SQLITE_VERSION_NUMBER >= 3007000
-        "INDEXED BY idx_repl_rvalue "
+                    "INDEXED BY idx_repl_rvalue "
 #endif
-        "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
-        "ORDER BY rvalue ASC LIMIT 1", &plugin->selRepl) != SQLITE_OK) ||
-      (sq_prepare (plugin->dbh, "SELECT MAX(repl) FROM gn090"
+                    "WHERE repl=?2 AND rvalue>=?1 LIMIT 1) ) "
+                    "ORDER BY rvalue ASC LIMIT 1",
+                    &plugin->selRepl)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT MAX(repl) FROM gn090"
 #if SQLITE_VERSION_NUMBER >= 3007000
-                   " INDEXED BY idx_repl_rvalue"
+                    " INDEXED BY idx_repl_rvalue"
 #endif
-                   "", &plugin->maxRepl) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
+                    "",
+                    &plugin->maxRepl)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
 #if SQLITE_VERSION_NUMBER >= 3007000
-        "INDEXED BY idx_expire "
+                    "INDEXED BY idx_expire "
 #endif
-        "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
-        "ORDER BY expire ASC LIMIT 1", &plugin->selExpi) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
+                    "WHERE NOT EXISTS (SELECT 1 FROM gn090 WHERE expire < ?1 LIMIT 1) OR (expire < ?1) "
+                    "ORDER BY expire ASC LIMIT 1",
+                    &plugin->selExpi)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT type,prio,anonLevel,expire,hash,value,_ROWID_ " "FROM gn090 "
 #if SQLITE_VERSION_NUMBER >= 3007000
-        "INDEXED BY idx_anon_type_hash "
+                    "INDEXED BY idx_anon_type_hash "
 #endif
-        "WHERE (anonLevel = 0 AND type=?1) "
-        "ORDER BY hash DESC LIMIT 1 OFFSET ?2",
-        &plugin->selZeroAnon) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
-        "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
-        &plugin->insertContent) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh, "DELETE FROM gn090 WHERE _ROWID_ = ?",
-        &plugin->delRow) != SQLITE_OK))
+                    "WHERE _ROWID_ >= ? AND "
+                    "anonLevel = 0 AND "
+                    "type = ? "
+                    "ORDER BY _ROWID_ ASC LIMIT 1",
+                    &plugin->selZeroAnon)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "INSERT INTO gn090 (repl, type, prio, anonLevel, expire, rvalue, hash, vhash, value) "
+                    "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
+                    &plugin->insertContent)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ FROM gn090 "
+                    "WHERE _ROWID_ >= ? AND "
+                    "(rvalue >= ? OR 0 = ?) AND "
+                    "(hash = ? OR 0 = ?) AND "
+                    "(vhash = ? OR 0 = ?) AND "
+                    "(type = ? OR 0 = ?) "
+                    "ORDER BY _ROWID_ ASC LIMIT 1",
+                    &plugin->get)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "DELETE FROM gn090 WHERE _ROWID_ = ?",
+                    &plugin->delRow))
+       )
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "precompiling");
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR,
+                "precompiling");
     return GNUNET_SYSERR;
   }
-
   return GNUNET_OK;
 }
 
@@ -398,51 +440,60 @@ static void
 database_shutdown (struct Plugin *plugin)
 {
   int result;
-
 #if SQLITE_VERSION_NUMBER >= 3007000
   sqlite3_stmt *stmt;
 #endif
 
-  if (plugin->delRow != NULL)
+  if (NULL != plugin->delRow)
     sqlite3_finalize (plugin->delRow);
-  if (plugin->updPrio != NULL)
+  if (NULL != plugin->updPrio)
     sqlite3_finalize (plugin->updPrio);
-  if (plugin->updRepl != NULL)
+  if (NULL != plugin->updRepl)
     sqlite3_finalize (plugin->updRepl);
-  if (plugin->selRepl != NULL)
+  if (NULL != plugin->selRepl)
     sqlite3_finalize (plugin->selRepl);
-  if (plugin->maxRepl != NULL)
+  if (NULL != plugin->maxRepl)
     sqlite3_finalize (plugin->maxRepl);
-  if (plugin->selExpi != NULL)
+  if (NULL != plugin->selExpi)
     sqlite3_finalize (plugin->selExpi);
-  if (plugin->selZeroAnon != NULL)
+  if (NULL != plugin->selZeroAnon)
     sqlite3_finalize (plugin->selZeroAnon);
-  if (plugin->insertContent != NULL)
+  if (NULL != plugin->insertContent)
     sqlite3_finalize (plugin->insertContent);
+  if (NULL != plugin->get)
+    sqlite3_finalize (plugin->get);
   result = sqlite3_close (plugin->dbh);
 #if SQLITE_VERSION_NUMBER >= 3007000
   if (result == SQLITE_BUSY)
   {
-    GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
-                     _
-                     ("Tried to close sqlite without finalizing all prepared statements.\n"));
-    stmt = sqlite3_next_stmt (plugin->dbh, NULL);
-    while (stmt != NULL)
+    GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+                     "sqlite",
+                     _("Tried to close sqlite without finalizing all prepared statements.\n"));
+    stmt = sqlite3_next_stmt (plugin->dbh,
+                              NULL);
+    while (NULL != stmt)
     {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
-                       "Closing statement %p\n", stmt);
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                       "sqlite",
+                       "Closing statement %p\n",
+                       stmt);
       result = sqlite3_finalize (stmt);
       if (result != SQLITE_OK)
-        GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
-                         "Failed to close statement %p: %d\n", stmt, result);
-      stmt = sqlite3_next_stmt (plugin->dbh, NULL);
+        GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+                         "sqlite",
+                         "Failed to close statement %p: %d\n",
+                         stmt,
+                         result);
+      stmt = sqlite3_next_stmt (plugin->dbh,
+                                NULL);
     }
     result = sqlite3_close (plugin->dbh);
   }
 #endif
   if (SQLITE_OK != result)
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
-
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR,
+                "sqlite3_close");
   GNUNET_free_non_null (plugin->fn);
 }
 
@@ -456,31 +507,27 @@ database_shutdown (struct Plugin *plugin)
  */
 static int
 delete_by_rowid (struct Plugin *plugin,
-                 unsigned long long rid)
+                 uint64_t rid)
 {
-  if (SQLITE_OK != sqlite3_bind_int64 (plugin->delRow, 1, rid))
-  {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (plugin->delRow))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_uint64 (&rid),
+    GNUNET_SQ_query_param_end
+  };
+
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->delRow,
+                      params))
     return GNUNET_SYSERR;
-  }
   if (SQLITE_DONE != sqlite3_step (plugin->delRow))
   {
     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
-    if (SQLITE_OK != sqlite3_reset (plugin->delRow))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->delRow);
     return GNUNET_SYSERR;
   }
-  if (SQLITE_OK != sqlite3_reset (plugin->delRow))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->delRow);
   return GNUNET_OK;
 }
 
@@ -513,12 +560,25 @@ sqlite_plugin_put (void *cls,
                    PluginPutCont cont,
                    void *cont_cls)
 {
+  uint64_t rvalue;
+  struct GNUNET_HashCode vhash;
+  uint32_t type32 = (uint32_t) type;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_uint32 (&replication),
+    GNUNET_SQ_query_param_uint32 (&type32),
+    GNUNET_SQ_query_param_uint32 (&priority),
+    GNUNET_SQ_query_param_uint32 (&anonymity),
+    GNUNET_SQ_query_param_absolute_time (&expiration),
+    GNUNET_SQ_query_param_uint64 (&rvalue),
+    GNUNET_SQ_query_param_auto_from_type (key),
+    GNUNET_SQ_query_param_auto_from_type (&vhash),
+    GNUNET_SQ_query_param_fixed_size (data, size),
+    GNUNET_SQ_query_param_end
+  };
   struct Plugin *plugin = cls;
   int n;
   int ret;
   sqlite3_stmt *stmt;
-  struct GNUNET_HashCode vhash;
-  uint64_t rvalue;
   char *msg = NULL;
 
   if (size > MAX_ITEM_SIZE)
@@ -537,26 +597,10 @@ sqlite_plugin_put (void *cls,
   GNUNET_CRYPTO_hash (data, size, &vhash);
   stmt = plugin->insertContent;
   rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
-  if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, replication)) ||
-      (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) ||
-      (SQLITE_OK != sqlite3_bind_int (stmt, 3, priority)) ||
-      (SQLITE_OK != sqlite3_bind_int (stmt, 4, anonymity)) ||
-      (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.abs_value_us)) ||
-      (SQLITE_OK != sqlite3_bind_int64 (stmt, 6, rvalue)) ||
-      (SQLITE_OK !=
-       sqlite3_bind_blob (stmt, 7, key, sizeof (struct GNUNET_HashCode),
-                          SQLITE_TRANSIENT)) ||
-      (SQLITE_OK !=
-       sqlite3_bind_blob (stmt, 8, &vhash, sizeof (struct GNUNET_HashCode),
-                          SQLITE_TRANSIENT)) ||
-      (SQLITE_OK != sqlite3_bind_blob (stmt, 9, data, size, SQLITE_TRANSIENT)))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (stmt,
+                      params))
   {
-    LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                    "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
     cont (cont_cls, key, size, GNUNET_SYSERR, msg);
     GNUNET_free_non_null(msg);
     return;
@@ -582,19 +626,16 @@ sqlite_plugin_put (void *cls,
   default:
     LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                     "sqlite3_step");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     stmt);
     database_shutdown (plugin);
     database_setup (plugin->env->cfg, plugin);
     cont (cont_cls, key, size, GNUNET_SYSERR, msg);
     GNUNET_free_non_null(msg);
     return;
   }
-  if (SQLITE_OK != sqlite3_reset (stmt))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
+  GNUNET_SQ_reset (plugin->dbh,
+                   stmt);
   cont (cont_cls, key, size, ret, msg);
   GNUNET_free_non_null(msg);
 }
@@ -619,7 +660,7 @@ sqlite_plugin_put (void *cls,
  *     MAX of any existing expiration time and
  *     this value
  * @param cont continuation called with success or failure status
- * @param cons_cls continuation closure
+ * @param cons_cls closure for @a cont
  */
 static void
 sqlite_plugin_update (void *cls,
@@ -630,27 +671,26 @@ sqlite_plugin_update (void *cls,
                       void *cont_cls)
 {
   struct Plugin *plugin = cls;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_uint32 (&delta),
+    GNUNET_SQ_query_param_absolute_time (&expire),
+    GNUNET_SQ_query_param_uint64 (&uid),
+    GNUNET_SQ_query_param_end
+  };
   int n;
   char *msg = NULL;
 
-  if ((SQLITE_OK != sqlite3_bind_int (plugin->updPrio, 1, delta)) ||
-      (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 2, expire.abs_value_us))
-      || (SQLITE_OK != sqlite3_bind_int64 (plugin->updPrio, 3, uid)))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->updPrio,
+                      params))
   {
-    LOG_SQLITE_MSG (plugin, &msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                    "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (plugin->updPrio))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
     cont (cont_cls, GNUNET_SYSERR, msg);
     GNUNET_free_non_null(msg);
     return;
   }
   n = sqlite3_step (plugin->updPrio);
-  if (SQLITE_OK != sqlite3_reset (plugin->updPrio))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->updPrio);
   switch (n)
   {
   case SQLITE_DONE:
@@ -691,75 +731,84 @@ execute_get (struct Plugin *plugin,
 {
   int n;
   struct GNUNET_TIME_Absolute expiration;
-  unsigned long long rowid;
-  unsigned int size;
+  uint32_t type;
+  uint32_t priority;
+  uint32_t anonymity;
+  uint64_t rowid;
+  void *value;
+  size_t value_size;
+  struct GNUNET_HashCode key;
   int ret;
+  struct GNUNET_SQ_ResultSpec rs[] = {
+    GNUNET_SQ_result_spec_uint32 (&type),
+    GNUNET_SQ_result_spec_uint32 (&priority),
+    GNUNET_SQ_result_spec_uint32 (&anonymity),
+    GNUNET_SQ_result_spec_absolute_time (&expiration),
+    GNUNET_SQ_result_spec_auto_from_type (&key),
+    GNUNET_SQ_result_spec_variable_size (&value,
+                                         &value_size),
+    GNUNET_SQ_result_spec_uint64 (&rowid),
+    GNUNET_SQ_result_spec_end
+  };
 
   n = sqlite3_step (stmt);
   switch (n)
   {
   case SQLITE_ROW:
-    size = sqlite3_column_bytes (stmt, 5);
-    rowid = sqlite3_column_int64 (stmt, 6);
-    if (sqlite3_column_bytes (stmt, 4) != sizeof (struct GNUNET_HashCode))
+    if (GNUNET_OK !=
+        GNUNET_SQ_extract_result (stmt,
+                                  rs))
     {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
-                       _("Invalid data in database.  Trying to fix (by deletion).\n"));
-      if (SQLITE_OK != sqlite3_reset (stmt))
-        LOG_SQLITE (plugin,
-                    GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                    "sqlite3_reset");
-      if ( (GNUNET_OK == delete_by_rowid (plugin, rowid)) &&
-           (NULL != plugin->env->duc) )
-        plugin->env->duc (plugin->env->cls,
-                          -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
+      GNUNET_break (0);
       break;
     }
-    expiration.abs_value_us = sqlite3_column_int64 (stmt, 3);
-    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                     "sqlite",
                      "Found reply in database with expiration %s\n",
                      GNUNET_STRINGS_absolute_time_to_string (expiration));
-    ret = proc (proc_cls, sqlite3_column_blob (stmt, 4) /* key */ ,
-                size, sqlite3_column_blob (stmt, 5) /* data */ ,
-                sqlite3_column_int (stmt, 0) /* type */ ,
-                sqlite3_column_int (stmt, 1) /* priority */ ,
-                sqlite3_column_int (stmt, 2) /* anonymity */ ,
-                expiration, rowid);
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+    ret = proc (proc_cls,
+                &key,
+                value_size,
+                value,
+                type,
+                priority,
+                anonymity,
+                expiration,
+                rowid);
+    GNUNET_SQ_cleanup_result (rs);
+    GNUNET_SQ_reset (plugin->dbh,
+                     stmt);
     if ( (GNUNET_NO == ret) &&
-         (GNUNET_OK == delete_by_rowid (plugin, rowid)) &&
+         (GNUNET_OK == delete_by_rowid (plugin,
+                                        rowid)) &&
          (NULL != plugin->env->duc) )
       plugin->env->duc (plugin->env->cls,
-                        -(size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
+                        -(value_size + GNUNET_DATASTORE_ENTRY_OVERHEAD));
     return;
   case SQLITE_DONE:
     /* database must be empty */
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
     break;
   case SQLITE_BUSY:
   case SQLITE_ERROR:
   case SQLITE_MISUSE:
   default:
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
-    if (SQLITE_OK != sqlite3_reset (stmt))
+    if (SQLITE_OK !=
+        sqlite3_reset (stmt))
       LOG_SQLITE (plugin,
                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                   "sqlite3_reset");
     GNUNET_break (0);
+    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
     database_shutdown (plugin);
-    database_setup (plugin->env->cfg, plugin);
-    break;
+    database_setup (plugin->env->cfg,
+                    plugin);
+    return;
   }
-  if (SQLITE_OK != sqlite3_reset (stmt))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
+  GNUNET_SQ_reset (plugin->dbh,
+                   stmt);
   proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
 }
 
@@ -769,37 +818,36 @@ execute_get (struct Plugin *plugin,
  * the given processor for the item.
  *
  * @param cls our plugin context
- * @param offset offset of the result (modulo num-results);
- *               specific ordering does not matter for the offset
+ * @param next_uid return the result with lowest uid >= next_uid
  * @param type entries of which type should be considered?
- *        Use 0 for any type.
- * @param proc function to call on each matching value;
- *        will be called once with a NULL value at the end
+ *        Must not be zero (ANY).
+ * @param proc function to call on the matching value;
+ *        will be called with NULL if no value matches
  * @param proc_cls closure for @a proc
  */
 static void
-sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset,
+sqlite_plugin_get_zero_anonymity (void *cls,
+                                  uint64_t next_uid,
                                   enum GNUNET_BLOCK_Type type,
-                                  PluginDatumProcessor proc, void *proc_cls)
+                                  PluginDatumProcessor proc,
+                                  void *proc_cls)
 {
   struct Plugin *plugin = cls;
-  sqlite3_stmt *stmt;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_uint64 (&next_uid),
+    GNUNET_SQ_query_param_uint32 (&type),
+    GNUNET_SQ_query_param_end
+  };
 
   GNUNET_assert (type != GNUNET_BLOCK_TYPE_ANY);
-  stmt = plugin->selZeroAnon;
-  if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, type)) ||
-      (SQLITE_OK != sqlite3_bind_int64 (stmt, 2, offset)))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->selZeroAnon,
+                      params))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
     return;
   }
-  execute_get (plugin, stmt, proc, proc_cls);
+  execute_get (plugin, plugin->selZeroAnon, proc, proc_cls);
 }
 
 
@@ -807,8 +855,9 @@ sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset,
  * Get results for a particular key in the datastore.
  *
  * @param cls closure
- * @param offset offset (mod count).
- * @param key key to match, never NULL
+ * @param next_uid return the result with lowest uid >= next_uid
+ * @param random if true, return a random result instead of using next_uid
+ * @param key maybe NULL (to match all entries)
  * @param vhash hash of the value, maybe NULL (to
  *        match all values that have the right key).
  *        Note that for DBlocks there is no difference
@@ -822,7 +871,8 @@ sqlite_plugin_get_zero_anonymity (void *cls, uint64_t offset,
  */
 static void
 sqlite_plugin_get_key (void *cls,
-                       uint64_t offset,
+                       uint64_t next_uid,
+                       bool random,
                        const struct GNUNET_HashCode *key,
                        const struct GNUNET_HashCode *vhash,
                        enum GNUNET_BLOCK_Type type,
@@ -830,97 +880,45 @@ sqlite_plugin_get_key (void *cls,
                        void *proc_cls)
 {
   struct Plugin *plugin = cls;
-  int ret;
-  int total;
-  int limit_off;
-  unsigned int sqoff;
-  sqlite3_stmt *stmt;
-  char scratch[256];
-
-  GNUNET_assert (proc != NULL);
-  GNUNET_assert (key != NULL);
-  GNUNET_snprintf (scratch, sizeof (scratch),
-                   "SELECT count(*) FROM gn090 WHERE hash=?%s%s",
-                   vhash == NULL ? "" : " AND vhash=?",
-                   type == 0 ? "" : " AND type=?");
-  if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
-  {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite_prepare");
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
-  }
-  sqoff = 1;
-  ret =
-      sqlite3_bind_blob (stmt, sqoff++, key, sizeof (struct GNUNET_HashCode),
-                         SQLITE_TRANSIENT);
-  if ((vhash != NULL) && (ret == SQLITE_OK))
-    ret =
-        sqlite3_bind_blob (stmt, sqoff++, vhash, sizeof (struct GNUNET_HashCode),
-                           SQLITE_TRANSIENT);
-  if ((type != 0) && (ret == SQLITE_OK))
-    ret = sqlite3_bind_int (stmt, sqoff++, type);
-  if (SQLITE_OK != ret)
-  {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_bind");
-    sqlite3_finalize (stmt);
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
-  }
-  ret = sqlite3_step (stmt);
-  if (ret != SQLITE_ROW)
-  {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite_step");
-    sqlite3_finalize (stmt);
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
-  }
-  total = sqlite3_column_int (stmt, 0);
-  sqlite3_finalize (stmt);
-  if (0 == total)
-  {
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
-  }
-  limit_off = (int) (offset % total);
-  if (limit_off < 0)
-    limit_off += total;
-  GNUNET_snprintf (scratch, sizeof (scratch),
-                   "SELECT type, prio, anonLevel, expire, hash, value, _ROWID_ "
-                   "FROM gn090 WHERE hash=?%s%s "
-                   "ORDER BY _ROWID_ ASC LIMIT 1 OFFSET ?",
-                   vhash == NULL ? "" : " AND vhash=?",
-                   type == 0 ? "" : " AND type=?");
-  if (sq_prepare (plugin->dbh, scratch, &stmt) != SQLITE_OK)
+  uint64_t rvalue;
+  uint16_t use_rvalue = random;
+  uint32_t type32 = (uint32_t) type;
+  uint16_t use_type = GNUNET_BLOCK_TYPE_ANY != type;
+  uint16_t use_key = NULL != key;
+  uint16_t use_vhash = NULL != vhash;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_uint64 (&next_uid),
+    GNUNET_SQ_query_param_uint64 (&rvalue),
+    GNUNET_SQ_query_param_uint16 (&use_rvalue),
+    GNUNET_SQ_query_param_auto_from_type (key),
+    GNUNET_SQ_query_param_uint16 (&use_key),
+    GNUNET_SQ_query_param_auto_from_type (vhash),
+    GNUNET_SQ_query_param_uint16 (&use_vhash),
+    GNUNET_SQ_query_param_uint32 (&type32),
+    GNUNET_SQ_query_param_uint16 (&use_type),
+    GNUNET_SQ_query_param_end
+  };
+
+  if (random)
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite_prepare");
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
+    rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                       UINT64_MAX);
+    next_uid = 0;
   }
-  sqoff = 1;
-  ret = sqlite3_bind_blob (stmt, sqoff++, key,
-                           sizeof (struct GNUNET_HashCode),
-                           SQLITE_TRANSIENT);
-  if ((vhash != NULL) && (ret == SQLITE_OK))
-    ret = sqlite3_bind_blob (stmt, sqoff++, vhash,
-                             sizeof (struct GNUNET_HashCode),
-                             SQLITE_TRANSIENT);
-  if ((type != 0) && (ret == SQLITE_OK))
-    ret = sqlite3_bind_int (stmt, sqoff++, type);
-  if (ret == SQLITE_OK)
-    ret = sqlite3_bind_int64 (stmt, sqoff++, limit_off);
-  if (ret != SQLITE_OK)
+  else
+    rvalue = 0;
+
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->get,
+                      params))
   {
-    LOG_SQLITE (plugin,
-                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite_bind");
     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
     return;
   }
-  execute_get (plugin, stmt, proc, proc_cls);
-  sqlite3_finalize (stmt);
+  execute_get (plugin,
+               plugin->get,
+               proc,
+               proc_cls);
 }
 
 
@@ -984,13 +982,17 @@ repl_proc (void *cls,
   struct ReplCtx *rc = cls;
   int ret;
 
+  if (GNUNET_SYSERR == rc->have_uid)
+    rc->have_uid = GNUNET_NO;
   ret = rc->proc (rc->proc_cls,
                   key,
-                  size, data,
+                  size,
+                  data,
                   type,
                   priority,
                   anonymity,
-                  expiration, uid);
+                  expiration,
+                  uid);
   if (NULL != key)
   {
     rc->uid = uid;
@@ -1011,81 +1013,77 @@ repl_proc (void *cls,
  * @param proc_cls closure for @a proc
  */
 static void
-sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc,
+sqlite_plugin_get_replication (void *cls,
+                               PluginDatumProcessor proc,
                                void *proc_cls)
 {
   struct Plugin *plugin = cls;
   struct ReplCtx rc;
   uint64_t rvalue;
   uint32_t repl;
-  sqlite3_stmt *stmt;
-
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
+  struct GNUNET_SQ_QueryParam params_sel_repl[] = {
+    GNUNET_SQ_query_param_uint64 (&rvalue),
+    GNUNET_SQ_query_param_uint32 (&repl),
+    GNUNET_SQ_query_param_end
+  };
+  struct GNUNET_SQ_QueryParam params_upd_repl[] = {
+    GNUNET_SQ_query_param_uint64 (&rc.uid),
+    GNUNET_SQ_query_param_end
+  };
+
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                   "datastore-sqlite",
                    "Getting random block based on replication order.\n");
-  rc.have_uid = GNUNET_NO;
-  rc.proc = proc;
-  rc.proc_cls = proc_cls;
-  stmt = plugin->maxRepl;
-  if (SQLITE_ROW != sqlite3_step (stmt))
+  if (SQLITE_ROW !=
+      sqlite3_step (plugin->maxRepl))
   {
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->maxRepl);
     /* DB empty */
     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
     return;
   }
-  repl = sqlite3_column_int (stmt, 0);
-  if (SQLITE_OK != sqlite3_reset (stmt))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
-  stmt = plugin->selRepl;
-  rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
-  if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, rvalue))
+  repl = sqlite3_column_int (plugin->maxRepl,
+                             0);
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->maxRepl);
+  rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                     UINT64_MAX);
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->selRepl,
+                      params_sel_repl))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
     return;
   }
-  if (SQLITE_OK != sqlite3_bind_int (stmt, 2, repl))
-  {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
-    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
-    return;
-  }
-  execute_get (plugin, stmt, &repl_proc, &rc);
+  rc.have_uid = GNUNET_SYSERR;
+  rc.proc = proc;
+  rc.proc_cls = proc_cls;
+  execute_get (plugin,
+               plugin->selRepl,
+               &repl_proc,
+               &rc);
   if (GNUNET_YES == rc.have_uid)
   {
-    if (SQLITE_OK != sqlite3_bind_int64 (plugin->updRepl, 1, rc.uid))
+    if (GNUNET_OK !=
+        GNUNET_SQ_bind (plugin->updRepl,
+                        params_upd_repl))
     {
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_bind_XXXX");
-      if (SQLITE_OK != sqlite3_reset (plugin->updRepl))
-        LOG_SQLITE (plugin,
-                    GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                    "sqlite3_reset");
+      proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
       return;
     }
-    if (SQLITE_DONE != sqlite3_step (plugin->updRepl))
+    if (SQLITE_DONE !=
+        sqlite3_step (plugin->updRepl))
       LOG_SQLITE (plugin,
                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                   "sqlite3_step");
-    if (SQLITE_OK != sqlite3_reset (plugin->updRepl))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->updRepl);
+  }
+  if (GNUNET_SYSERR == rc.have_uid)
+  {
+    /* proc was not called at all so far, do it now. */
+    proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
   }
 }
 
@@ -1105,19 +1103,20 @@ sqlite_plugin_get_expiration (void *cls, PluginDatumProcessor proc,
   struct Plugin *plugin = cls;
   sqlite3_stmt *stmt;
   struct GNUNET_TIME_Absolute now;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_absolute_time (&now),
+    GNUNET_SQ_query_param_end
+  };
 
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                   "sqlite",
                    "Getting random block based on expiration and priority order.\n");
   now = GNUNET_TIME_absolute_get ();
   stmt = plugin->selExpi;
-  if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, now.abs_value_us))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (stmt,
+                      params))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
     proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0);
     return;
   }
@@ -1138,30 +1137,47 @@ sqlite_plugin_get_keys (void *cls,
                        void *proc_cls)
 {
   struct Plugin *plugin = cls;
-  const struct GNUNET_HashCode *key;
+  struct GNUNET_HashCode key;
+  struct GNUNET_SQ_ResultSpec results[] = {
+    GNUNET_SQ_result_spec_auto_from_type (&key),
+    GNUNET_SQ_result_spec_end
+  };
   sqlite3_stmt *stmt;
   int ret;
 
-  GNUNET_assert (proc != NULL);
-  if (sq_prepare (plugin->dbh, "SELECT hash FROM gn090", &stmt) != SQLITE_OK)
+  GNUNET_assert (NULL != proc);
+  if (SQLITE_OK !=
+      sq_prepare (plugin->dbh,
+                  "SELECT hash FROM gn090",
+                  &stmt))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                "sqlite_prepare");
-    proc (proc_cls, NULL, 0);
+    proc (proc_cls,
+          NULL,
+          0);
     return;
   }
   while (SQLITE_ROW == (ret = sqlite3_step (stmt)))
   {
-    key = sqlite3_column_blob (stmt, 0);
-    if (sizeof (struct GNUNET_HashCode) == sqlite3_column_bytes (stmt, 0))
-      proc (proc_cls, key, 1);
+    if (GNUNET_OK ==
+        GNUNET_SQ_extract_result (stmt,
+                                  results))
+      proc (proc_cls,
+            &key,
+            1);
     else
       GNUNET_break (0);
   }
   if (SQLITE_DONE != ret)
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR,
+                "sqlite_step");
   sqlite3_finalize (stmt);
-  proc (proc_cls, NULL, 0);
+  proc (proc_cls,
+        NULL,
+        0);
 }
 
 
@@ -1187,7 +1203,8 @@ sqlite_plugin_drop (void *cls)
  * @return the size of the database on disk (estimate)
  */
 static void
-sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate)
+sqlite_plugin_estimate_size (void *cls,
+                             unsigned long long *estimate)
 {
   struct Plugin *plugin = cls;
   sqlite3_stmt *stmt;
@@ -1202,30 +1219,45 @@ sqlite_plugin_estimate_size (void *cls, unsigned long long *estimate)
     return;
   if (SQLITE_VERSION_NUMBER < 3006000)
   {
-    GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "datastore-sqlite",
-                     _
-                     ("sqlite version to old to determine size, assuming zero\n"));
+    GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+                     "datastore-sqlite",
+                     _("sqlite version to old to determine size, assuming zero\n"));
     *estimate = 0;
     return;
   }
-  CHECK (SQLITE_OK == sqlite3_exec (plugin->dbh, "VACUUM", NULL, NULL, ENULL));
   CHECK (SQLITE_OK ==
-         sqlite3_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL", NULL,
+         sqlite3_exec (plugin->dbh,
+                       "VACUUM",
+                       NULL,
+                       NULL,
+                       ENULL));
+  CHECK (SQLITE_OK ==
+         sqlite3_exec (plugin->dbh,
+                       "PRAGMA auto_vacuum=INCREMENTAL",
+                       NULL,
                        NULL, ENULL));
-  CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_count", &stmt));
+  CHECK (SQLITE_OK ==
+         sq_prepare (plugin->dbh,
+                     "PRAGMA page_count",
+                     &stmt));
   if (SQLITE_ROW == sqlite3_step (stmt))
-    pages = sqlite3_column_int64 (stmt, 0);
+    pages = sqlite3_column_int64 (stmt,
+                                  0);
   else
     pages = 0;
   sqlite3_finalize (stmt);
-  CHECK (SQLITE_OK == sq_prepare (plugin->dbh, "PRAGMA page_size", &stmt));
-  CHECK (SQLITE_ROW == sqlite3_step (stmt));
+  CHECK (SQLITE_OK ==
+         sq_prepare (plugin->dbh,
+                     "PRAGMA page_size",
+                     &stmt));
+  CHECK (SQLITE_ROW ==
+         sqlite3_step (stmt));
   page_size = sqlite3_column_int64 (stmt, 0);
   sqlite3_finalize (stmt);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              _
-              ("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
-              (unsigned long long) pages, (unsigned long long) page_size);
+              _("Using sqlite page utilization to estimate payload (%llu pages of size %llu bytes)\n"),
+              (unsigned long long) pages,
+              (unsigned long long) page_size);
   *estimate = pages * page_size;
 }
 
@@ -1243,9 +1275,11 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
   struct GNUNET_DATASTORE_PluginEnvironment *env = cls;
   struct GNUNET_DATASTORE_PluginFunctions *api;
 
-  if (plugin.env != NULL)
+  if (NULL != plugin.env)
     return NULL;                /* can only initialize once! */
-  memset (&plugin, 0, sizeof (struct Plugin));
+  memset (&plugin,
+          0,
+          sizeof (struct Plugin));
   plugin.env = env;
   if (GNUNET_OK != database_setup (env->cfg, &plugin))
   {
@@ -1263,7 +1297,8 @@ libgnunet_plugin_datastore_sqlite_init (void *cls)
   api->get_zero_anonymity = &sqlite_plugin_get_zero_anonymity;
   api->get_keys = &sqlite_plugin_get_keys;
   api->drop = &sqlite_plugin_drop;
-  GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "sqlite",
+  GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
+                   "sqlite",
                    _("Sqlite database running\n"));
   return api;
 }
@@ -1282,24 +1317,23 @@ libgnunet_plugin_datastore_sqlite_done (void *cls)
   struct GNUNET_DATASTORE_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
 
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                   "sqlite",
                    "sqlite plugin is done\n");
   fn = NULL;
   if (plugin->drop_on_shutdown)
     fn = GNUNET_strdup (plugin->fn);
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
-                   "Shutting down database\n");
   database_shutdown (plugin);
   plugin->env = NULL;
   GNUNET_free (api);
-  if (fn != NULL)
+  if (NULL != fn)
   {
     if (0 != UNLINK (fn))
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                "unlink",
+                                fn);
     GNUNET_free (fn);
   }
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
-                   "sqlite plugin is finished\n");
   return NULL;
 }
 
index a1e03e8eec9320aceefd1ae2f421e917d1c1a65a..18722179835ff9130ce8b2c203df07c8bd0c2ee5 100644 (file)
@@ -89,8 +89,8 @@ template_plugin_put (void *cls, const struct GNUNET_HashCode * key, uint32_t siz
  * Get one of the results for a particular key in the datastore.
  *
  * @param cls closure
- * @param offset offset of the result (modulo num-results);
- *               specific ordering does not matter for the offset
+ * @param next_uid return the result with lowest uid >= next_uid
+ * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
  * @param vhash hash of the value, maybe NULL (to
  *        match all values that have the right key).
@@ -104,7 +104,7 @@ template_plugin_put (void *cls, const struct GNUNET_HashCode * key, uint32_t siz
  * @param proc_cls closure for proc
  */
 static void
-template_plugin_get_key (void *cls, uint64_t offset,
+template_plugin_get_key (void *cls, uint64_t next_uid, bool random,
                          const struct GNUNET_HashCode * key,
                          const struct GNUNET_HashCode * vhash,
                          enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc,
@@ -185,16 +185,15 @@ template_plugin_update (void *cls, uint64_t uid, uint32_t delta,
  * Call the given processor on an item with zero anonymity.
  *
  * @param cls our "struct Plugin*"
- * @param offset offset of the result (modulo num-results);
- *               specific ordering does not matter for the offset
+ * @param next_uid return the result with lowest uid >= next_uid
  * @param type entries of which type should be considered?
- *        Use 0 for any type.
- * @param proc function to call on each matching value;
- *        will be called  with NULL if no value matches
+ *        Must not be zero (ANY).
+ * @param proc function to call on the matching value;
+ *        will be called with NULL if no value matches
  * @param proc_cls closure for proc
  */
 static void
-template_plugin_get_zero_anonymity (void *cls, uint64_t offset,
+template_plugin_get_zero_anonymity (void *cls, uint64_t next_uid,
                                     enum GNUNET_BLOCK_Type type,
                                     PluginDatumProcessor proc, void *proc_cls)
 {
index a996682408045cd26c809f30bb296a7ca2c90bbb..0da68b26643ff6a74df6ba3785bb01dca5377cce 100644 (file)
@@ -156,8 +156,6 @@ struct CpsRunContext
   void *data;
   size_t size;
 
-  uint64_t uid;
-  uint64_t offset;
   uint64_t first_uid;
 };
 
@@ -267,7 +265,6 @@ check_value (void *cls,
   GNUNET_assert (priority == get_priority (i));
   GNUNET_assert (anonymity == get_anonymity (i));
   GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
-  crc->offset++;
   if (crc->i == 0)
   {
     crc->phase = RP_DEL;
@@ -343,7 +340,6 @@ check_multiple (void *cls,
   case RP_GET_MULTIPLE:
     crc->phase = RP_GET_MULTIPLE_NEXT;
     crc->first_uid = uid;
-    crc->offset++;
     break;
   case RP_GET_MULTIPLE_NEXT:
     GNUNET_assert (uid != crc->first_uid);
@@ -354,8 +350,6 @@ check_multiple (void *cls,
     crc->phase = RP_ERROR;
     break;
   }
-  if (priority == get_priority (42))
-    crc->uid = uid;
   GNUNET_SCHEDULER_add_now (&run_continuation, crc);
 }
 
@@ -400,7 +394,8 @@ run_continuation (void *cls)
                         sizeof (int),
                         &crc->key);
     GNUNET_DATASTORE_get_key (datastore,
-                              crc->offset,
+                              0,
+                              false,
                               &crc->key,
                               get_type (crc->i),
                               1,
@@ -417,7 +412,8 @@ run_continuation (void *cls)
     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
     GNUNET_assert (NULL !=
                    GNUNET_DATASTORE_get_key (datastore,
-                                             crc->offset,
+                                             0,
+                                             false,
                                              &crc->key,
                                              get_type (crc->i),
                                              1,
@@ -450,9 +446,15 @@ run_continuation (void *cls)
                 crc->i);
     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
     GNUNET_assert (NULL !=
-                   GNUNET_DATASTORE_get_key (datastore, crc->offset, &crc->key,
-                                             get_type (crc->i), 1, 1,
-                                             &check_nothing, crc));
+                   GNUNET_DATASTORE_get_key (datastore,
+                                             0,
+                                             false,
+                                             &crc->key,
+                                             get_type (crc->i),
+                                             1,
+                                             1,
+                                             &check_nothing,
+                                             crc));
     break;
   case RP_RESERVE:
     crc->phase = RP_PUT_MULTIPLE;
@@ -483,19 +485,26 @@ run_continuation (void *cls)
   case RP_GET_MULTIPLE:
     GNUNET_assert (NULL !=
                    GNUNET_DATASTORE_get_key (datastore,
-                                             crc->offset,
+                                             0,
+                                             false,
                                              &crc->key,
-                                             get_type (42), 1, 1,
-                                             &check_multiple, crc));
+                                             get_type (42),
+                                             1,
+                                             1,
+                                             &check_multiple,
+                                             crc));
     break;
   case RP_GET_MULTIPLE_NEXT:
     GNUNET_assert (NULL !=
                    GNUNET_DATASTORE_get_key (datastore,
-                                             crc->offset,
+                                             crc->first_uid + 1,
+                                             false,
                                              &crc->key,
                                              get_type (42),
-                                             1, 1,
-                                             &check_multiple, crc));
+                                             1,
+                                             1,
+                                             &check_multiple,
+                                             crc));
     break;
   case RP_DONE:
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
index 9a3e5446bf7d815cf00706e81e2e2c81d29b6cc2..de4dc657ff34bd6adac8f61dd3564bd4dc1754f2 100644 (file)
@@ -58,7 +58,6 @@ struct CpsRunContext
   const struct GNUNET_CONFIGURATION_Handle *cfg;
   void *data;
   enum RunPhase phase;
-  uint64_t offset;
 };
 
 
@@ -159,7 +158,6 @@ check_value (void *cls, const struct GNUNET_HashCode * key, size_t size,
   GNUNET_assert (priority == get_priority (i));
   GNUNET_assert (anonymity == get_anonymity (i));
   GNUNET_assert (expiration.abs_value_us == get_expiration (i).abs_value_us);
-  crc->offset++;
   crc->i--;
   if (crc->i == 0)
     crc->phase = RP_DONE;
@@ -221,8 +219,13 @@ run_continuation (void *cls)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET",
                 crc->i);
     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
-    GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key,
-                              get_type (crc->i), 1, 1,
+    GNUNET_DATASTORE_get_key (datastore,
+                              0,
+                              false,
+                              &crc->key,
+                              get_type (crc->i),
+                              1,
+                              1,
                               &check_value,
                               crc);
     break;
@@ -230,8 +233,13 @@ run_continuation (void *cls)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing `%s' number %u\n", "GET(f)",
                 crc->i);
     GNUNET_CRYPTO_hash (&crc->i, sizeof (int), &crc->key);
-    GNUNET_DATASTORE_get_key (datastore, crc->offset++, &crc->key,
-                              get_type (crc->i), 1, 1,
+    GNUNET_DATASTORE_get_key (datastore,
+                              0,
+                              false,
+                              &crc->key,
+                              get_type (crc->i),
+                              1,
+                              1,
                               &check_nothing,
                               crc);
     break;
index 9b85d57da681a5a827b9cdc2c4a3d805e5e43775..94d93aac672a5ea09cc4937d79a289334edc9527 100644 (file)
@@ -64,7 +64,6 @@ struct CpsRunContext
   enum RunPhase phase;
   unsigned int cnt;
   unsigned int i;
-  uint64_t offset;
 };
 
 
@@ -308,7 +307,8 @@ test (void *cls)
                 "Looking for %s\n",
                 GNUNET_h2s (&key));
     crc->api->get_key (crc->api->cls,
-                       crc->offset++,
+                       0,
+                       false,
                        &key,
                        NULL,
                        GNUNET_BLOCK_TYPE_ANY,
index ee208b50e73770341630419fd71f1e95142e33f0..42ddc7b60e11828e7f29bd13d7f85965f00d95e0 100644 (file)
@@ -319,7 +319,7 @@ send_get_known_results (struct GNUNET_DHT_GetHandle *gh,
   unsigned int max;
   unsigned int transmission_offset;
 
-  max = (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*msg))
+  max = (GNUNET_MAX_MESSAGE_SIZE - sizeof (*msg))
     / sizeof (struct GNUNET_HashCode);
   transmission_offset = transmission_offset_start;
   while (transmission_offset < gh->seen_results_end)
@@ -704,9 +704,9 @@ check_client_result (void *cls,
     sizeof (struct GNUNET_PeerIdentity) * (get_path_length + put_path_length);
   if ( (msize < meta_length) ||
        (get_path_length >
-        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
+        GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
        (put_path_length >
-        GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) )
+        GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) )
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
@@ -998,8 +998,8 @@ GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle,
   struct GNUNET_DHT_PutHandle *ph;
 
   msize = sizeof (struct GNUNET_DHT_ClientPutMessage) + size;
-  if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
-      (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
+  if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
+      (size >= GNUNET_MAX_MESSAGE_SIZE))
   {
     GNUNET_break (0);
     return NULL;
@@ -1090,8 +1090,8 @@ GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle,
   size_t msize;
 
   msize = sizeof (struct GNUNET_DHT_ClientGetMessage) + xquery_size;
-  if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
-      (xquery_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE))
+  if ((msize >= GNUNET_MAX_MESSAGE_SIZE) ||
+      (xquery_size >= GNUNET_MAX_MESSAGE_SIZE))
   {
     GNUNET_break (0);
     return NULL;
index ce479dc3e240c74f19ab7a82f65aa3952bab832a..67f0ce76d49e8f2e2c0a5ab5ed53e9e725bdd4c5 100644 (file)
@@ -50,7 +50,7 @@ static struct GNUNET_TIME_Relative timeout_request = { 60000 };
 /**
  * Be verbose
  */
-static int verbose;
+static unsigned int verbose;
 
 /**
  * Use DHT demultixplex_everywhere
@@ -226,33 +226,6 @@ run (void *cls, char *const *args, const char *cfgfile,
 
 }
 
-
-/**
- * gnunet-dht-get command line options
- */
-static struct GNUNET_GETOPT_CommandLineOption options[] = {
-  {'k', "key", "KEY",
-   gettext_noop ("the query key"),
-   1, &GNUNET_GETOPT_set_string, &query_key},
-  {'r', "replication", "LEVEL",
-   gettext_noop ("how many parallel requests (replicas) to create"),
-   1, &GNUNET_GETOPT_set_uint, &replication},
-  {'t', "type", "TYPE",
-   gettext_noop ("the type of data to look for"),
-   1, &GNUNET_GETOPT_set_uint, &query_type},
-  {'T', "timeout", "TIMEOUT",
-   gettext_noop ("how long to execute this query before giving up?"),
-   1, &GNUNET_GETOPT_set_relative_time, &timeout_request},
-  {'x', "demultiplex", NULL,
-    gettext_noop ("use DHT's demultiplex everywhere option"),
-    0, &GNUNET_GETOPT_set_one, &demultixplex_everywhere},
-  {'V', "verbose", NULL,
-   gettext_noop ("be verbose (print progress information)"),
-   0, &GNUNET_GETOPT_set_one, &verbose},
-  GNUNET_GETOPT_OPTION_END
-};
-
-
 /**
  * Entry point for gnunet-dht-get
  *
@@ -263,6 +236,45 @@ static struct GNUNET_GETOPT_CommandLineOption options[] = {
 int
 main (int argc, char *const *argv)
 {
+
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+  
+    GNUNET_GETOPT_OPTION_STRING ('k',
+                                 "key",
+                                 "KEY",
+                                 gettext_noop ("the query key"),
+                                 &query_key),
+  
+    GNUNET_GETOPT_OPTION_SET_UINT ('r',
+                                   "replication",
+                                   "LEVEL",
+                                   gettext_noop ("how many parallel requests (replicas) to create"),
+                                   &replication),
+  
+  
+    GNUNET_GETOPT_OPTION_SET_UINT ('t',
+                                   "type",
+                                   "TYPE",
+                                   gettext_noop ("the type of data to look for"),
+                                   &query_type),
+  
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('T',
+                                            "timeout",
+                                            "TIMEOUT",
+                                            gettext_noop ("how long to execute this query before giving up?"),
+                                            &timeout_request),
+  
+    GNUNET_GETOPT_OPTION_SET_ONE ('x',
+                                  "demultiplex",
+                                  gettext_noop ("use DHT's demultiplex everywhere option"),
+                                  &demultixplex_everywhere),
+  
+    GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
+    GNUNET_GETOPT_OPTION_END
+  };
+
+
+
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
     return 2;
   return (GNUNET_OK ==
index 7f14255d320cac38a35ff780add5d092351071f8..e4e8c46a10bca807065bdb13f3ea7759c6b29e1b 100644 (file)
@@ -280,27 +280,6 @@ run (void *cls, char *const *args, const char *cfgfile,
                                              NULL);
 }
 
-
-/**
- * gnunet-dht-monitor command line options
- */
-static struct GNUNET_GETOPT_CommandLineOption options[] = {
-  {'k', "key", "KEY",
-   gettext_noop ("the query key"),
-   1, &GNUNET_GETOPT_set_string, &query_key},
-  {'t', "type", "TYPE",
-   gettext_noop ("the type of data to look for"),
-   1, &GNUNET_GETOPT_set_uint, &block_type},
-  {'T', "timeout", "TIMEOUT",
-   gettext_noop ("how long should the monitor command run"),
-   1, &GNUNET_GETOPT_set_relative_time, &timeout_request},
-  {'V', "verbose", NULL,
-   gettext_noop ("be verbose (print progress information)"),
-   0, &GNUNET_GETOPT_set_one, &verbose},
-  GNUNET_GETOPT_OPTION_END
-};
-
-
 /**
  * Entry point for gnunet-dht-monitor
  *
@@ -311,6 +290,35 @@ static struct GNUNET_GETOPT_CommandLineOption options[] = {
 int
 main (int argc, char *const *argv)
 {
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+  
+    GNUNET_GETOPT_OPTION_STRING ('k',
+                                 "key",
+                                 "KEY",
+                                 gettext_noop ("the query key"),
+                                 &query_key),
+  
+    GNUNET_GETOPT_OPTION_SET_UINT ('t',
+                                   "type",
+                                   "TYPE",
+                                   gettext_noop ("the type of data to look for"),
+                                   &block_type),
+  
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('T',
+                                            "timeout",
+                                            "TIMEOUT",
+                                            gettext_noop ("how long should the monitor command run"),
+                                            &timeout_request),
+  
+    GNUNET_GETOPT_OPTION_SET_ONE ('V',
+                                  "verbose",
+                                  gettext_noop ("be verbose (print progress information)"),
+                                  &verbose),
+  
+    GNUNET_GETOPT_OPTION_END
+  };
+
+
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
     return 2;
 
index 64764cb65d7e2c58406d7478190f0b618e8cf056..bf88e5ded97225b593375c9f4d80febeb67f8889 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 GNUnet e.V.
+     Copyright (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -54,7 +54,7 @@ static unsigned int replication = 5;
 /**
  * Be verbose
  */
-static int verbose;
+static unsigned int verbose;
 
 /**
  * Use #GNUNET_DHT_DEMULTIPLEX_EVERYWHERE.
@@ -148,7 +148,6 @@ run (void *cls,
      const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle *c)
 {
-  struct GNUNET_TIME_Absolute expiration;
   enum GNUNET_DHT_RouteOption ro;
 
   cfg = c;
@@ -187,44 +186,11 @@ run (void *cls,
                   query_type,
                   strlen (data),
                   data,
-                  expiration,
+                  GNUNET_TIME_relative_to_absolute (expiration),
                   &message_sent_cont,
                   NULL);
 }
 
-
-/**
- * gnunet-dht-put command line options
- */
-static struct GNUNET_GETOPT_CommandLineOption options[] = {
-  {'d', "data", "DATA",
-   gettext_noop ("the data to insert under the key"),
-   1, &GNUNET_GETOPT_set_string, &data},
-  {'e', "expiration", "EXPIRATION",
-   gettext_noop ("how long to store this entry in the dht (in seconds)"),
-   1, &GNUNET_GETOPT_set_relative_time, &expiration},
-  {'k', "key", "KEY",
-   gettext_noop ("the query key"),
-   1, &GNUNET_GETOPT_set_string, &query_key},
-  {'x', "demultiplex", NULL,
-   gettext_noop ("use DHT's demultiplex everywhere option"),
-   0, &GNUNET_GETOPT_set_one, &demultixplex_everywhere},
-  {'r', "replication", "LEVEL",
-   gettext_noop ("how many replicas to create"),
-   1, &GNUNET_GETOPT_set_uint, &replication},
-  {'R', "record", NULL,
-   gettext_noop ("use DHT's record route option"),
-   0, &GNUNET_GETOPT_set_one, &record_route},
-  {'t', "type", "TYPE",
-   gettext_noop ("the type to insert data as"),
-   1, &GNUNET_GETOPT_set_uint, &query_type},
-  {'V', "verbose", NULL,
-   gettext_noop ("be verbose (print progress information)"),
-   0, &GNUNET_GETOPT_set_one, &verbose},
-  GNUNET_GETOPT_OPTION_END
-};
-
-
 /**
  * Entry point for gnunet-dht-put
  *
@@ -235,6 +201,55 @@ static struct GNUNET_GETOPT_CommandLineOption options[] = {
 int
 main (int argc, char *const *argv)
 {
+
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+  
+    GNUNET_GETOPT_OPTION_STRING ('d',
+                                 "data",
+                                 "DATA",
+                                 gettext_noop ("the data to insert under the key"),
+                                 &data),
+  
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('e',
+                                            "expiration",
+                                            "EXPIRATION",
+                                            gettext_noop ("how long to store this entry in the dht (in seconds)"),
+                                            &expiration),
+  
+    GNUNET_GETOPT_OPTION_STRING ('k',
+                                 "key",
+                                 "KEY",
+                                 gettext_noop ("the query key"),
+                                 &query_key),
+  
+    GNUNET_GETOPT_OPTION_SET_ONE ('x',
+                                  "demultiplex",
+                                  gettext_noop ("use DHT's demultiplex everywhere option"),
+                                  &demultixplex_everywhere),
+  
+    GNUNET_GETOPT_OPTION_SET_UINT ('r',
+                                   "replication",
+                                   "LEVEL",
+                                   gettext_noop ("how many replicas to create"),
+                                   &replication),
+  
+    GNUNET_GETOPT_OPTION_SET_ONE ('R',
+                                  "record",
+                                  gettext_noop ("use DHT's record route option"),
+                                  &record_route),
+  
+    GNUNET_GETOPT_OPTION_SET_UINT ('t',
+                                   "type",
+                                   "TYPE",
+                                   gettext_noop ("the type to insert data as"),
+                                   &query_type),
+  
+    GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
+  
+    GNUNET_GETOPT_OPTION_END
+  };
+
+
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
                                                  &argc, &argv))
     return 2;
index 0f521a4015aa0e0b04311ccb00a05a92da550d65..cb155c4845bf89d4b6fc8d5bd024f9d339dee140 100644 (file)
@@ -1166,7 +1166,7 @@ GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration,
 
   msize = sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size +
     (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity);
-  if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (msize >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
index fef637cadf2102d69863d757a7fb3cefc6e6eee9..36047d56194238148f12fa3bef5b81fc645ecf5f 100644 (file)
@@ -72,7 +72,7 @@ GDS_DATACACHE_handle_put (struct GNUNET_TIME_Absolute expiration,
                 _("%s request received, but have no datacache!\n"), "PUT");
     return;
   }
-  if (data_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (data_size >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
index 15071edcae97aa5492df739f437bf5e31b38ba79..0309bea880b04bca42e18405f83a254114614ca2 100644 (file)
@@ -1423,7 +1423,7 @@ GDS_NEIGHBOURS_handle_get (enum GNUNET_BLOCK_Type type,
                                          UINT32_MAX);
   }
   msize = xquery_size + reply_bf_size;
-  if (msize + sizeof (struct PeerGetMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (msize + sizeof (struct PeerGetMessage) >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     GNUNET_free_non_null (reply_bf);
@@ -1522,12 +1522,12 @@ GDS_NEIGHBOURS_handle_reply (const struct GNUNET_PeerIdentity *target,
 
   msize = data_size + (get_path_length + put_path_length) *
       sizeof (struct GNUNET_PeerIdentity);
-  if ((msize + sizeof (struct PeerResultMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
+  if ((msize + sizeof (struct PeerResultMessage) >= GNUNET_MAX_MESSAGE_SIZE) ||
       (get_path_length >
-       GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
+       GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
       (put_path_length >
-       GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
-      (data_size > GNUNET_SERVER_MAX_MESSAGE_SIZE))
+       GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
+      (data_size > GNUNET_MAX_MESSAGE_SIZE))
   {
     GNUNET_break (0);
     return;
@@ -1627,7 +1627,7 @@ check_dht_p2p_put (void *cls,
        sizeof (struct PeerPutMessage) +
        putlen * sizeof (struct GNUNET_PeerIdentity)) ||
       (putlen >
-       GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
+       GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
   {
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
@@ -2213,9 +2213,9 @@ check_dht_p2p_result (void *cls,
                                             put_path_length) *
        sizeof (struct GNUNET_PeerIdentity)) ||
       (get_path_length >
-       GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
+       GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)) ||
       (put_path_length >
-       GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
+       GNUNET_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_PeerIdentity)))
   {
     GNUNET_break_op (0);
     return GNUNET_SYSERR;
index 460eaa5724d964004a95cac12f9fcbb2ea3a9319..f65141640adccc868c52dee51523aaad94685910 100644 (file)
@@ -1181,31 +1181,54 @@ main (int argc, char *const *argv)
 {
   int rc;
 
-  static struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'n', "peers", "COUNT",
-     gettext_noop ("number of peers to start"),
-     1, &GNUNET_GETOPT_set_uint, &num_peers},
-    {'s', "searches", "COUNT",
-     gettext_noop ("maximum number of times we try to search for successor circle formation (0 for R5N)"),
-     1, &GNUNET_GETOPT_set_uint, &max_searches},
-    {'H', "hosts", "FILENAME",
-     gettext_noop ("name of the file with the login information for the testbed"),
-     1, &GNUNET_GETOPT_set_string, &hosts_file},
-    {'D', "delay", "DELAY",
-     gettext_noop ("delay between rounds for collecting statistics (default: 30 sec)"),
-     1, &GNUNET_GETOPT_set_relative_time, &delay_stats},
-    {'P', "PUT-delay", "DELAY",
-     gettext_noop ("delay to start doing PUTs (default: 1 sec)"),
-     1, &GNUNET_GETOPT_set_relative_time, &delay_put},
-    {'G', "GET-delay", "DELAY",
-     gettext_noop ("delay to start doing GETs (default: 5 min)"),
-     1, &GNUNET_GETOPT_set_relative_time, &delay_get},
-    {'r', "replication", "DEGREE",
-     gettext_noop ("replication degree for DHT PUTs"),
-     1, &GNUNET_GETOPT_set_uint, &replication},
-    {'t', "timeout", "TIMEOUT",
-     gettext_noop ("timeout for DHT PUT and GET requests (default: 1 min)"),
-     1, &GNUNET_GETOPT_set_relative_time, &timeout},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_UINT ('n',
+                                   "peers",
+                                   "COUNT",
+                                   gettext_noop ("number of peers to start"),
+                                   &num_peers),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('s',
+                                   "searches",
+                                   "COUNT",
+                                   gettext_noop ("maximum number of times we try to search for successor circle formation (0 for R5N)"),
+                                   &max_searches),
+
+    GNUNET_GETOPT_OPTION_STRING ('H',
+                                 "hosts",
+                                 "FILENAME",
+                                 gettext_noop ("name of the file with the login information for the testbed"),
+                                 &hosts_file),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('D',
+                                            "delay",
+                                            "DELAY",
+                                            gettext_noop ("delay between rounds for collecting statistics (default: 30 sec)"),
+                                            &delay_stats),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('P',
+                                            "PUT-delay",
+                                            "DELAY",
+                                            gettext_noop ("delay to start doing PUTs (default: 1 sec)"),
+                                            &delay_put),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('G',
+                                            "GET-delay",
+                                            "DELAY",
+                                            gettext_noop ("delay to start doing GETs (default: 5 min)"),
+                                            &delay_get),
+    GNUNET_GETOPT_OPTION_SET_UINT ('r',
+                                   "replication",
+                                   "DEGREE",
+                                   gettext_noop ("replication degree for DHT PUTs"),
+                                   &replication),
+
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
+                                            "timeout",
+                                            "TIMEOUT",
+                                            gettext_noop ("timeout for DHT PUT and GET requests (default: 1 min)"),
+                                            &timeout),
     GNUNET_GETOPT_OPTION_END
   };
 
index f74c41fc58e708215a4309c2e09005a6aade5199..5af22812176ad9b81b0ef4f652ac2fb5e0986a86 100644 (file)
@@ -106,6 +106,7 @@ libgnunetdns_la_LDFLAGS = \
 libgnunet_plugin_block_dns_la_SOURCES = \
   plugin_block_dns.c
 libgnunet_plugin_block_dns_la_LIBADD = \
+  $(top_builddir)/src/block/libgnunetblockgroup.la \
   $(top_builddir)/src/util/libgnunetutil.la
 libgnunet_plugin_block_dns_la_LDFLAGS = \
   $(top_builddir)/src/block/$(GN_PLUGIN_LDFLAGS)
index e7450a1d490d98617b13bcd1660c04b7df9b5174..9f0dee9a9bc2f3e6ffc856518327ac1700d090c2 100644 (file)
@@ -317,7 +317,7 @@ GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh,
       return;
   }
   if (reply_length + sizeof (struct GNUNET_DNS_Response)
-      >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     GNUNET_free (rh);
index 5e6f90555c75b14b3e299d08d9f72c284d18ed5c..2436931fbf686c4c18a9a85ad3325554ae9fdedb 100644 (file)
@@ -52,7 +52,7 @@ static int ret;
 /**
  * Selected level of verbosity.
  */
-static int verbosity;
+static unsigned int verbosity;
 
 
 /**
@@ -346,13 +346,18 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'i', "inbound-only", NULL,
-     gettext_noop ("only monitor DNS queries"),
-     0, &GNUNET_GETOPT_set_one, &inbound_only},
-    {'o', "outbound-only", NULL,
-     gettext_noop ("only monitor DNS replies"),
-     0, &GNUNET_GETOPT_set_one, &outbound_only},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('i',
+                                  "inbound-only",
+                                  gettext_noop ("only monitor DNS queries"),
+                                  &inbound_only),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('o',
+                                  "outbound-only",
+                                  gettext_noop ("only monitor DNS queries"),
+                                  &outbound_only),
+
     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
     GNUNET_GETOPT_OPTION_END
   };
index 89929815a2e9467cbc03af0ca544211f43322e17..0469af732aff959eefa0ceacc8536e7031b0b6a3 100644 (file)
@@ -52,7 +52,7 @@ static int ret;
 /**
  * Selected level of verbosity.
  */
-static int verbosity;
+static unsigned int verbosity;
 
 
 /**
@@ -230,13 +230,19 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'4', "ipv4", "IPV4",
-     gettext_noop ("set A records"),
-     1, &GNUNET_GETOPT_set_string, &n4},
-    {'6', "ipv4", "IPV6",
-     gettext_noop ("set AAAA records"),
-     1, &GNUNET_GETOPT_set_string, &n6},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_STRING ('4',
+                                 "ipv4",
+                                 "IPV4",
+                                 gettext_noop ("set A records"),
+                                 &n4),
+
+    GNUNET_GETOPT_OPTION_STRING ('6',
+                                 "ipv4",
+                                 "IPV6",
+                                 gettext_noop ("set AAAA records"),
+                                 &n6),
+
     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
     GNUNET_GETOPT_OPTION_END
   };
index d083a9df26f051384d37517a7f032212b692f673..5cf1967f51ae9de4adf58e881cb72a50aff922f7 100644 (file)
@@ -79,7 +79,7 @@
 #include "gnunet_protocols.h"
 
 /**
- * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
  */
 #define MAX_SIZE 65536
 
index 74f595c5ed9c2ca4ec3be60592af2c5e7b736168..ffc94afb75073538aeae497761b72c822f34bd77 100644 (file)
@@ -347,7 +347,7 @@ request_done (struct RequestRecord *rr)
   }
   reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
   reply_len += rr->payload_length;
-  if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (reply_len >= GNUNET_MAX_MESSAGE_SIZE)
   {
     /* response too big, drop */
     GNUNET_break (0); /* how can this be? */
@@ -481,7 +481,7 @@ send_request_to_client (struct RequestRecord *rr,
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_DNS_Request *req;
 
-  if (sizeof (struct GNUNET_DNS_Request) + rr->payload_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (sizeof (struct GNUNET_DNS_Request) + rr->payload_length >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     cleanup_rr (rr);
@@ -882,11 +882,10 @@ handle_client_response (void *cls,
  * message is received by the tokenizer from the DNS hijack process.
  *
  * @param cls closure
- * @param client identification of the client
  * @param message the actual message, a DNS request we should handle
  */
 static int
-process_helper_messages (void *cls GNUNET_UNUSED, void *client,
+process_helper_messages (void *cls,
                         const struct GNUNET_MessageHeader *message)
 {
   uint16_t msize;
index 062f9a95ff04ffa4214f583f0617d890fcdba8c4..ab521ec1fbe11a51b4da81b54aef823112685de2 100644 (file)
@@ -437,7 +437,7 @@ GNUNET_DV_send (struct GNUNET_DV_ServiceHandle *sh,
   struct ConnectedPeer *peer;
   struct GNUNET_MQ_Envelope *env;
 
-  if (ntohs (msg->size) + sizeof (*sm) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (ntohs (msg->size) + sizeof (*sm) >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
index d0917d3631bd15086b44ffbdd15f7f84d4597ee2..cb40bb6d28e1da09e57b999107a681c1072aeaff 100644 (file)
@@ -34,7 +34,7 @@ static struct GNUNET_DV_ServiceHandle *sh;
 /**
  * Was verbose specified?
  */
-static int verbose;
+static unsigned int verbose;
 
 
 /**
@@ -161,10 +161,10 @@ main (int argc, char *const *argv)
 {
   int res;
 
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'V', "verbose", NULL,
-     gettext_noop ("verbose output"),
-     0, &GNUNET_GETOPT_set_one, &verbose},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
+
     GNUNET_GETOPT_OPTION_END
   };
 
index 7d101c8ae46d2718ae4f4a72649699c1a489ab96..fa1c16be827c220febe656688ba1da9b55a2d386 100644 (file)
@@ -399,7 +399,7 @@ send_data_to_plugin (const struct GNUNET_MessageHeader *message,
               (unsigned int) distance);
   size = sizeof (struct GNUNET_DV_ReceivedMessage) +
     ntohs (message->size);
-  if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (size >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0); /* too big */
     return;
@@ -537,7 +537,7 @@ forward_payload (struct DirectNeighbor *target,
     return;
   }
   if (sizeof (struct RouteMessage) + ntohs (payload->size)
-      >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
@@ -1530,7 +1530,7 @@ listen_set_union (void *cls,
                                        GNUNET_SET_OPERATION_UNION);
   neighbor->set_op = GNUNET_SET_accept (request,
                                        GNUNET_SET_RESULT_ADDED,
-                                        (struct GNUNET_SET_Option[]) { 0 },
+                                        (struct GNUNET_SET_Option[]) {{ 0 }},
                                        &handle_set_union_result,
                                        neighbor);
   neighbor->consensus_insertion_offset = 0;
@@ -1561,7 +1561,7 @@ initiate_set_union (void *cls)
                                          &neighbor->real_session_id,
                                          NULL,
                                          GNUNET_SET_RESULT_ADDED,
-                                         (struct GNUNET_SET_Option[]) { 0 },
+                                         (struct GNUNET_SET_Option[]) {{ 0 }},
                                          &handle_set_union_result,
                                          neighbor);
   neighbor->consensus_insertion_offset = 0;
index 271b4ebd7eaabaf96737e844abbe72b8259b3eca..aa1210269e025c856776f1f72e7e626f4a364dab 100644 (file)
@@ -54,6 +54,6 @@ gnunet_daemon_exit_LDADD = \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/tun/libgnunettun.la \
   $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/regex/libgnunetregex.la \
   $(GN_LIBINTL)
index 09576e3935fdd1573878d65ea6daa8c038f70b68..2cd3441a1e5bab291885637b445d54b799e25788 100644 (file)
@@ -979,7 +979,7 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address,
   }
   len += sizeof (struct GNUNET_TUN_TcpHeader);
   len += payload_length;
-  if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (len >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
@@ -1079,7 +1079,7 @@ send_icmp_packet_via_tun (const struct SocketAddress *destination_address,
   }
   len += sizeof (struct GNUNET_TUN_IcmpHeader);
   len += payload_length;
-  if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (len >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
@@ -1358,7 +1358,7 @@ send_udp_packet_via_tun (const struct SocketAddress *destination_address,
   }
   len += sizeof (struct GNUNET_TUN_UdpHeader);
   len += payload_length;
-  if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (len >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
@@ -2502,7 +2502,7 @@ store_service (int proto,
               GNUNET_h2s (&cadet_port),
               name,
               (unsigned int) destination_port);
-  service->port = GNUNET_CADET_open_porT (cadet_handle,
+  service->port = GNUNET_CADET_open_port (cadet_handle,
                                           &cadet_port,
                                           &new_service_channel,
                                           service,
@@ -2884,7 +2884,7 @@ tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp,
   mtcp->crc = 0;
 
   mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof (struct GNUNET_TUN_TcpHeader));
-  if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
@@ -2905,12 +2905,10 @@ tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp,
  * Receive packets from the helper-process
  *
  * @param cls unused
- * @param client unsued
  * @param message message received from helper
  */
 static int
 message_token (void *cls GNUNET_UNUSED,
-               void *client GNUNET_UNUSED,
                const struct GNUNET_MessageHeader *message)
 {
   const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun;
@@ -3579,7 +3577,7 @@ advertise_dns_exit ()
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Opening CADET port %s for DNS exit service\n",
               GNUNET_h2s (&port));
-  dns_port = GNUNET_CADET_open_porT (cadet_handle,
+  dns_port = GNUNET_CADET_open_port (cadet_handle,
                                      &port,
                                      &new_channel,
                                      NULL,
@@ -3829,7 +3827,7 @@ run (void *cls,
                                 NULL);
   stats = GNUNET_STATISTICS_create ("exit",
                                     cfg);
-  cadet_handle = GNUNET_CADET_connecT (cfg);
+  cadet_handle = GNUNET_CADET_connect (cfg);
   if (NULL == cadet_handle)
   {
     GNUNET_SCHEDULER_shutdown ();
@@ -3862,7 +3860,7 @@ run (void *cls,
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Opening CADET port %s for IPv4 gateway service\n",
                 GNUNET_h2s (&port));
-    cadet_port4 = GNUNET_CADET_open_porT (cadet_handle,
+    cadet_port4 = GNUNET_CADET_open_port (cadet_handle,
                                           &port,
                                           &new_channel,
                                           NULL,
@@ -3902,7 +3900,7 @@ run (void *cls,
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Opening CADET port %s for IPv6 gateway service\n",
                 GNUNET_h2s (&port));
-    cadet_port6 = GNUNET_CADET_open_porT (cadet_handle,
+    cadet_port6 = GNUNET_CADET_open_port (cadet_handle,
                                           &port,
                                           &new_channel,
                                           NULL,
index 6be65ccd548ac46f60b8199638cb85a0d22b3f0b..aa7a7a4a3f2379dbe5dadeaf9060047594514006 100644 (file)
@@ -77,7 +77,7 @@
 static boolean privilege_testing = FALSE;
 
 /**
- * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
  */
 #define MAX_SIZE 65536
 
index e14c6ca43fab517e4fa7ef831c05a5f994a16cc6..3c6f975575cbedbe3c2969df23cb20a3b2a54e9b 100644 (file)
@@ -62,7 +62,7 @@
 #define DEBUG GNUNET_NO
 
 /**
- * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
  */
 #define MAX_SIZE 65536
 
index 4374d45eabafb796b34ddc76fc4b88cdd69c0479..33260a79408979c1a9ae5fe75ef5d5d1d346ebe4 100644 (file)
@@ -202,7 +202,7 @@ gnunet_service_fs_LDADD =  \
  $(top_builddir)/src/block/libgnunetblock.la \
  $(top_builddir)/src/datastore/libgnunetdatastore.la \
  $(top_builddir)/src/statistics/libgnunetstatistics.la \
- $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+ $(top_builddir)/src/cadet/libgnunetcadet.la \
  $(top_builddir)/src/ats/libgnunetats.la \
  $(top_builddir)/src/core/libgnunetcore.la \
  $(top_builddir)/src/util/libgnunetutil.la \
index e85de94a79557e38f039f532453bd9576c4c0660..be22ea73e7d8277bc636e9edb422443226424b73 100644 (file)
@@ -1463,21 +1463,11 @@ struct GNUNET_FS_UnindexContext
    */
   struct GNUNET_CRYPTO_FileHashContext *fhc;
 
-  /**
-   * Which values have we seen already?
-   */
-  struct GNUNET_CONTAINER_MultiHashMap *seen_dh;
-
   /**
    * Overall size of the file.
    */
   uint64_t file_size;
 
-  /**
-   * Random offset given to #GNUNET_DATASTORE_get_key.
-   */
-  uint64_t roff;
-
   /**
    * When did we start?
    */
index a18a903bedab961abefee61baa70c392116af62e..514eb64b3b8ce16e0a5ed2836cd6b19a54d10648 100644 (file)
@@ -170,13 +170,14 @@ find_full_data (void *cls, const char *plugin_name,
  * @param data pointer to the beginning of the directory
  * @param offset offset of data in the directory
  * @param dep function to call on each entry
- * @param dep_cls closure for dep
- * @return GNUNET_OK if this could be a block in a directory,
- *         GNUNET_NO if this could be part of a directory (but not 100% OK)
- *         GNUNET_SYSERR if 'data' does not represent a directory
+ * @param dep_cls closure for @a dep
+ * @return #GNUNET_OK if this could be a block in a directory,
+ *         #GNUNET_NO if this could be part of a directory (but not 100% OK)
+ *         #GNUNET_SYSERR if @a data does not represent a directory
  */
 int
-GNUNET_FS_directory_list_contents (size_t size, const void *data,
+GNUNET_FS_directory_list_contents (size_t size,
+                                   const void *data,
                                    uint64_t offset,
                                    GNUNET_FS_DirectoryEntryProcessor dep,
                                    void *dep_cls)
@@ -194,12 +195,16 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
 
   if ((offset == 0) &&
       ((size < 8 + sizeof (uint32_t)) ||
-       (0 != memcmp (cdata, GNUNET_FS_DIRECTORY_MAGIC, 8))))
+       (0 != memcmp (cdata,
+                     GNUNET_FS_DIRECTORY_MAGIC,
+                     8))))
     return GNUNET_SYSERR;
   pos = offset;
   if (offset == 0)
   {
-    GNUNET_memcpy (&mdSize, &cdata[8], sizeof (uint32_t));
+    GNUNET_memcpy (&mdSize,
+                   &cdata[8],
+                   sizeof (uint32_t));
     mdSize = ntohl (mdSize);
     if (mdSize > size - 8 - sizeof (uint32_t))
     {
@@ -215,7 +220,12 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
       GNUNET_break (0);
       return GNUNET_SYSERR;     /* malformed ! */
     }
-    dep (dep_cls, NULL, NULL, md, 0, NULL);
+    dep (dep_cls,
+         NULL,
+         NULL,
+         md,
+         0,
+         NULL);
     GNUNET_CONTAINER_meta_data_destroy (md);
     pos = 8 + sizeof (uint32_t) + mdSize;
   }
@@ -247,7 +257,7 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
 
     uri = GNUNET_FS_uri_parse (&cdata[pos], &emsg);
     pos = epos + 1;
-    if (uri == NULL)
+    if (NULL == uri)
     {
       GNUNET_free (emsg);
       pos--;                    /* go back to '\0' to force going to next alignment */
@@ -260,7 +270,9 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
       return GNUNET_NO;         /* illegal in directory! */
     }
 
-    GNUNET_memcpy (&mdSize, &cdata[pos], sizeof (uint32_t));
+    GNUNET_memcpy (&mdSize,
+                   &cdata[pos],
+                   sizeof (uint32_t));
     mdSize = ntohl (mdSize);
     pos += sizeof (uint32_t);
     if (pos + mdSize > size)
@@ -269,8 +281,9 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
       return GNUNET_NO;         /* malformed - or partial download */
     }
 
-    md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos], mdSize);
-    if (md == NULL)
+    md = GNUNET_CONTAINER_meta_data_deserialize (&cdata[pos],
+                                                 mdSize);
+    if (NULL == md)
     {
       GNUNET_FS_uri_destroy (uri);
       GNUNET_break (0);
@@ -282,10 +295,17 @@ GNUNET_FS_directory_list_contents (size_t size, const void *data,
                                                 EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME);
     full_data.size = 0;
     full_data.data = NULL;
-    GNUNET_CONTAINER_meta_data_iterate (md, &find_full_data, &full_data);
-    if (dep != NULL)
+    GNUNET_CONTAINER_meta_data_iterate (md,
+                                        &find_full_data,
+                                        &full_data);
+    if (NULL != dep)
     {
-      dep (dep_cls, filename, uri, md, full_data.size, full_data.data);
+      dep (dep_cls,
+           filename,
+           uri,
+           md,
+           full_data.size,
+           full_data.data);
     }
     GNUNET_free_non_null (full_data.data);
     GNUNET_free_non_null (filename);
@@ -548,11 +568,12 @@ block_align (size_t start, unsigned int count, const size_t * sizes,
  * @param bld directory to finish
  * @param rsize set to the number of bytes needed
  * @param rdata set to the encoded directory
- * @return GNUNET_OK on success
+ * @return #GNUNET_OK on success
  */
 int
 GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
-                                    size_t * rsize, void **rdata)
+                                    size_t * rsize,
+                                    void **rdata)
 {
   char *data;
   char *sptr;
@@ -575,9 +596,12 @@ GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
   bes = NULL;
   if (0 < bld->count)
   {
-    sizes = GNUNET_malloc (bld->count * sizeof (size_t));
-    perm = GNUNET_malloc (bld->count * sizeof (unsigned int));
-    bes = GNUNET_malloc (bld->count * sizeof (struct BuilderEntry *));
+    sizes = GNUNET_new_array (bld->count,
+                              size_t);
+    perm = GNUNET_new_array (bld->count,
+                             unsigned int);
+    bes = GNUNET_new_array (bld->count,
+                            struct BuilderEntry *);
     pos = bld->head;
     for (i = 0; i < bld->count; i++)
     {
@@ -599,7 +623,8 @@ GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
   data = GNUNET_malloc_large (size);
   if (data == NULL)
   {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "malloc");
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                         "malloc");
     *rsize = 0;
     *rdata = NULL;
     GNUNET_free_non_null (sizes);
@@ -608,17 +633,22 @@ GNUNET_FS_directory_builder_finish (struct GNUNET_FS_DirectoryBuilder *bld,
     return GNUNET_SYSERR;
   }
   *rdata = data;
-  GNUNET_memcpy (data, GNUNET_DIRECTORY_MAGIC, strlen (GNUNET_DIRECTORY_MAGIC));
+  GNUNET_memcpy (data,
+                 GNUNET_DIRECTORY_MAGIC,
+                 strlen (GNUNET_DIRECTORY_MAGIC));
   off = strlen (GNUNET_DIRECTORY_MAGIC);
 
   sptr = &data[off + sizeof (uint32_t)];
   ret =
-      GNUNET_CONTAINER_meta_data_serialize (bld->meta, &sptr,
+      GNUNET_CONTAINER_meta_data_serialize (bld->meta,
+                                            &sptr,
                                             size - off - sizeof (uint32_t),
                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL);
   GNUNET_assert (ret != -1);
   big = htonl (ret);
-  GNUNET_memcpy (&data[off], &big, sizeof (uint32_t));
+  GNUNET_memcpy (&data[off],
+                 &big,
+                 sizeof (uint32_t));
   off += sizeof (uint32_t) + ret;
   for (j = 0; j < bld->count; j++)
   {
index 2f79c7c05b87077502e2be0b4f2484454ff17606..7b9f178fdcf511a17f0fb9a373aeb0a9b2e53fd6 100644 (file)
@@ -245,12 +245,10 @@ finish_scan (void *cls)
  * Calls the scanner progress handler.
  *
  * @param cls the closure (directory scanner object)
- * @param client always NULL
  * @param msg message from the helper process
  */
 static int
 process_helper_msgs (void *cls,
-                    void *client,
                     const struct GNUNET_MessageHeader *msg)
 {
   struct GNUNET_FS_DirScanner *ds = cls;
index 0789162bf9bfb9ca14044fd805da62bfd785c595..ce852f2d0bba1922f18b5153af5214ab95b71e22 100644 (file)
@@ -37,14 +37,14 @@ static int
 is_recursive_download (struct GNUNET_FS_DownloadContext *dc)
 {
   return (0 != (dc->options & GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE)) &&
-      ((GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) ||
-       ((NULL == dc->meta) &&
-        ((NULL == dc->filename) ||
-         ((strlen (dc->filename) >= strlen (GNUNET_FS_DIRECTORY_EXT)) &&
-          (NULL !=
-           strstr (dc->filename + strlen (dc->filename) -
-                   strlen (GNUNET_FS_DIRECTORY_EXT),
-                   GNUNET_FS_DIRECTORY_EXT))))));
+      ( (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (dc->meta)) ||
+        ( (NULL == dc->meta) &&
+          ( (NULL == dc->filename) ||
+            ( (strlen (dc->filename) >= strlen (GNUNET_FS_DIRECTORY_EXT)) &&
+              (NULL !=
+               strstr (dc->filename + strlen (dc->filename) -
+                       strlen (GNUNET_FS_DIRECTORY_EXT),
+                       GNUNET_FS_DIRECTORY_EXT)) ) ) ) );
 }
 
 
@@ -278,10 +278,12 @@ try_reconnect (struct GNUNET_FS_DownloadContext *dc);
  * @param data contents of the file (or NULL if they were not inlined)
  */
 static void
-trigger_recursive_download (void *cls, const char *filename,
+trigger_recursive_download (void *cls,
+                            const char *filename,
                             const struct GNUNET_FS_Uri *uri,
                             const struct GNUNET_CONTAINER_MetaData *meta,
-                            size_t length, const void *data);
+                            size_t length,
+                            const void *data);
 
 
 /**
@@ -304,24 +306,28 @@ full_recursive_download (struct GNUNET_FS_DownloadContext *dc)
   if (size64 != (uint64_t) size)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                _
-                ("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n"));
+                _("Recursive downloads of directories larger than 4 GB are not supported on 32-bit systems\n"));
     return;
   }
   if (NULL != dc->filename)
   {
-    h = GNUNET_DISK_file_open (dc->filename, GNUNET_DISK_OPEN_READ,
+    h = GNUNET_DISK_file_open (dc->filename,
+                               GNUNET_DISK_OPEN_READ,
                                GNUNET_DISK_PERM_NONE);
   }
   else
   {
     GNUNET_assert (NULL != dc->temp_filename);
-    h = GNUNET_DISK_file_open (dc->temp_filename, GNUNET_DISK_OPEN_READ,
+    h = GNUNET_DISK_file_open (dc->temp_filename,
+                               GNUNET_DISK_OPEN_READ,
                                GNUNET_DISK_PERM_NONE);
   }
   if (NULL == h)
     return;                     /* oops */
-  data = GNUNET_DISK_file_map (h, &m, GNUNET_DISK_MAP_TYPE_READ, size);
+  data = GNUNET_DISK_file_map (h,
+                               &m,
+                               GNUNET_DISK_MAP_TYPE_READ,
+                               size);
   if (NULL == data)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -329,15 +335,25 @@ full_recursive_download (struct GNUNET_FS_DownloadContext *dc)
   }
   else
   {
-    GNUNET_FS_directory_list_contents (size, data, 0,
-                                       &trigger_recursive_download, dc);
+    if (GNUNET_OK !=
+        GNUNET_FS_directory_list_contents (size,
+                                           data,
+                                           0,
+                                           &trigger_recursive_download,
+                                           dc))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  _("Failed to access full directroy contents of `%s' for recursive download\n"),
+                  dc->filename);
+    }
     GNUNET_DISK_file_unmap (m);
   }
   GNUNET_DISK_file_close (h);
   if (NULL == dc->filename)
   {
     if (0 != UNLINK (dc->temp_filename))
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                "unlink",
                                 dc->temp_filename);
     GNUNET_free (dc->temp_filename);
     dc->temp_filename = NULL;
@@ -362,14 +378,16 @@ check_completed (struct GNUNET_FS_DownloadContext *dc)
   struct GNUNET_FS_DownloadContext *pos;
 
   /* first, check if we need to download children */
-  if ((NULL == dc->child_head) && (is_recursive_download (dc)))
+  if (is_recursive_download (dc))
     full_recursive_download (dc);
   /* then, check if children are done already */
   for (pos = dc->child_head; NULL != pos; pos = pos->next)
   {
-    if ((pos->emsg == NULL) && (pos->completed < pos->length))
+    if ( (NULL == pos->emsg) &&
+         (pos->completed < pos->length) )
       return;                   /* not done yet */
-    if ((pos->child_head != NULL) && (pos->has_finished != GNUNET_YES))
+    if ( (NULL != pos->child_head) &&
+         (pos->has_finished != GNUNET_YES) )
       return;                   /* not transitively done yet */
   }
   /* All of our children are done, so mark this download done */
@@ -471,7 +489,11 @@ try_match_block (struct GNUNET_FS_DownloadContext *dc,
   }
   GNUNET_CRYPTO_hash (&data[dr->offset], dlen, &in_chk.key);
   GNUNET_CRYPTO_hash_to_aes_key (&in_chk.key, &sk, &iv);
-  if (-1 == GNUNET_CRYPTO_symmetric_encrypt (&data[dr->offset], dlen, &sk, &iv, enc))
+  if (-1 == GNUNET_CRYPTO_symmetric_encrypt (&data[dr->offset],
+                                             dlen,
+                                             &sk,
+                                             &iv,
+                                             enc))
   {
     GNUNET_break (0);
     return;
@@ -484,7 +506,9 @@ try_match_block (struct GNUNET_FS_DownloadContext *dc,
     dr->state = BRS_RECONSTRUCT_META_UP;
     break;
   case BRS_CHK_SET:
-    if (0 != memcmp (&in_chk, &dr->chk, sizeof (struct ContentHashKey)))
+    if (0 != memcmp (&in_chk,
+                     &dr->chk,
+                     sizeof (struct ContentHashKey)))
     {
       /* other peer provided bogus meta data */
       GNUNET_break_op (0);
@@ -591,7 +615,10 @@ match_full_data (void *cls, const char *plugin_name,
     GNUNET_break_op (0);
     return 1;                   /* bogus meta data */
   }
-  try_match_block (dc, dc->top_request, data, data_len);
+  try_match_block (dc,
+                   dc->top_request,
+                   data,
+                   data_len);
   return 1;
 }
 
@@ -820,10 +847,12 @@ schedule_block_download (struct GNUNET_FS_DownloadContext *dc,
  * @param data contents of the file (or NULL if they were not inlined)
  */
 static void
-trigger_recursive_download (void *cls, const char *filename,
+trigger_recursive_download (void *cls,
+                            const char *filename,
                             const struct GNUNET_FS_Uri *uri,
                             const struct GNUNET_CONTAINER_MetaData *meta,
-                            size_t length, const void *data)
+                            size_t length,
+                            const void *data)
 {
   struct GNUNET_FS_DownloadContext *dc = cls;
   struct GNUNET_FS_DownloadContext *cpos;
@@ -936,9 +965,17 @@ trigger_recursive_download (void *cls, const char *filename,
               (unsigned long long) GNUNET_FS_uri_chk_get_file_size (uri),
               (unsigned int)
               GNUNET_CONTAINER_meta_data_get_serialized_size (meta));
-  GNUNET_FS_download_start (dc->h, uri, meta, full_name, temp_name, 0,
+  GNUNET_FS_download_start (dc->h,
+                            uri,
+                            meta,
+                            full_name,
+                            temp_name,
+                            0,
                             GNUNET_FS_uri_chk_get_file_size (uri),
-                            dc->anonymity, dc->options, NULL, dc);
+                            dc->anonymity,
+                            dc->options,
+                            NULL,
+                            dc);
   GNUNET_free_non_null (full_name);
   GNUNET_free_non_null (temp_name);
   GNUNET_free_non_null (fn);
@@ -953,11 +990,9 @@ trigger_recursive_download (void *cls, const char *filename,
 void
 GNUNET_FS_free_download_request_ (struct DownloadRequest *dr)
 {
-  unsigned int i;
-
   if (NULL == dr)
     return;
-  for (i = 0; i < dr->num_children; i++)
+  for (unsigned int i = 0; i < dr->num_children; i++)
     GNUNET_FS_free_download_request_ (dr->children[i]);
   GNUNET_free_non_null (dr->children);
   GNUNET_free (dr);
@@ -1509,13 +1544,17 @@ create_download_request (struct DownloadRequest *parent,
   GNUNET_assert (dr->num_children > 0);
 
   dr->children =
-    GNUNET_malloc (dr->num_children * sizeof (struct DownloadRequest *));
+    GNUNET_new_array (dr->num_children,
+                      struct DownloadRequest *);
   for (i = 0; i < dr->num_children; i++)
   {
     dr->children[i] =
-      create_download_request (dr, i + head_skip, depth - 1,
+      create_download_request (dr,
+                               i + head_skip,
+                               depth - 1,
                               dr_offset + (i + head_skip) * child_block_size,
-                              file_start_offset, desired_length);
+                              file_start_offset,
+                               desired_length);
   }
   return dr;
 }
index f78e311d3dcac58e9f226915fc9152baddec509a..bfe45957e99c313a41954bcfadd8ed87398fcca1 100644 (file)
@@ -25,6 +25,7 @@
  */
 #include "platform.h"
 #include "gnunet_fs_service.h"
+#include "gnunet_getopt_lib.h"
 #include "fs_api.h"
 
 /* ******************** command-line option parsing API ******************** */
  * @param value command line argument given
  * @return GNUNET_OK on success
  */
-int
-GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext
-                               *ctx, void *scls, const char *option,
-                               const char *value)
+static int
+getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext
+                     *ctx, void *scls, const char *option,
+                      const char *value)
 {
   struct GNUNET_FS_Uri **uri = scls;
   struct GNUNET_FS_Uri *u = *uri;
@@ -107,6 +108,34 @@ GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext
   return GNUNET_OK;
 }
 
+/**
+ * Allow user to specify keywords.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] topKeywords set to the desired value
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_FS_GETOPT_KEYWORDS (char shortName,
+                           const char *name,
+                           const char *argumentHelp,
+                           const char *description,
+                           struct GNUNET_FS_Uri **topKeywords)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName = shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &getopt_set_keywords,
+    .scls = (void *) topKeywords  
+  };
+
+  return clo;
+}
 
 /**
  * Command-line option parser function that allows the user to specify
@@ -120,11 +149,11 @@ GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext
  * @param value command line argument given
  * @return #GNUNET_OK on success
  */
-int
-GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                               void *scls,
-                               const char *option,
-                               const char *value)
+static int
+getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+                     void *scls,
+                     const char *option,
+                     const char *value)
 {
   struct GNUNET_CONTAINER_MetaData **mm = scls;
 #if HAVE_EXTRACTOR_H && HAVE_LIBEXTRACTOR
@@ -200,4 +229,36 @@ GNUNET_FS_getopt_set_metadata (struct GNUNET_GETOPT_CommandLineProcessorContext
   return GNUNET_OK;
 }
 
+/**
+ * Allow user to specify metadata.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] metadata set to the desired value
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_FS_GETOPT_METADATA (char shortName,
+                           const char *name,
+                           const char *argumentHelp,
+                           const char *description,
+                           struct GNUNET_CONTAINER_MetaData **meta)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName = shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &getopt_set_metadata,
+    .scls = (void *) meta
+  };
+
+  return clo;
+}
+
+
+
+
 /* end of fs_getopt.c */
index 86a58a58bb5b1ae94e68305277304212c9e80c5e..759467ba426c599eabf2d1119b9bffed2d45336a 100644 (file)
@@ -837,7 +837,7 @@ hash_for_index_cb (void *cls,
   GNUNET_assert (fn != NULL);
   slen = strlen (fn) + 1;
   if (slen >=
-      GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct IndexStartMessage))
+      GNUNET_MAX_MESSAGE_SIZE - sizeof (struct IndexStartMessage))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 _
@@ -1226,7 +1226,7 @@ fip_signal_start (void *cls,
   {
     kc = GNUNET_FS_uri_ksk_get_keyword_count (*uri);
     pc->reserve_entries += kc;
-    pc->reserve_space += GNUNET_SERVER_MAX_MESSAGE_SIZE * kc;
+    pc->reserve_space += GNUNET_MAX_MESSAGE_SIZE * kc;
   }
   pi.status = GNUNET_FS_STATUS_PUBLISH_START;
   *client_info = GNUNET_FS_publish_make_status_ (&pi, pc, fi, 0);
index 3cbf2afefdcc0ec3f5f388735af00bec9d39d2c2..8c6f5edcf2730a8b5c76145a6c42dd1ce666becc 100644 (file)
@@ -1088,15 +1088,17 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
   unsigned int left;
   unsigned int todo;
   unsigned int fit;
-  int first_call;
   unsigned int search_request_map_offset;
   unsigned int keyword_offset;
+  int first_call;
 
   memset (&mbc, 0, sizeof (mbc));
   mbc.sc = sc;
   if (GNUNET_FS_uri_test_ksk (sc->uri))
   {
-    mbc.put_cnt = 0;
+    /* This will calculate the result set size ONLY for
+       "keyword_offset == 0", so we will have to recalculate
+       it for the other keywords later! */
     GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
                                            &find_result_set,
                                            &mbc);
@@ -1109,7 +1111,6 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
   }
   search_request_map_offset = 0;
   keyword_offset = 0;
-
   first_call = GNUNET_YES;
   while ( (0 != (left =
                  (total_seen_results - search_request_map_offset))) ||
@@ -1120,7 +1121,7 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
     if (0 != (sc->options & GNUNET_FS_SEARCH_OPTION_LOOPBACK_ONLY))
       options |= SEARCH_MESSAGE_OPTION_LOOPBACK_ONLY;
 
-    fit = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (*sm)) / sizeof (struct GNUNET_HashCode);
+    fit = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (*sm)) / sizeof (struct GNUNET_HashCode);
     todo = GNUNET_MIN (fit,
                        left);
     env = GNUNET_MQ_msg_extra (sm,
@@ -1128,6 +1129,11 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
                                GNUNET_MESSAGE_TYPE_FS_START_SEARCH);
     mbc.skip_cnt = search_request_map_offset;
     mbc.xoff = (struct GNUNET_HashCode *) &sm[1];
+    sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK);
+    sm->anonymity_level = htonl (sc->anonymity);
+    memset (&sm->target,
+            0,
+            sizeof (struct GNUNET_PeerIdentity));
 
     if (GNUNET_FS_uri_test_ksk (sc->uri))
     {
@@ -1135,17 +1141,12 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
       /* calculate how many results we can send in this message */
       mbc.put_cnt = todo;
       /* now build message */
-      sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK);
-      sm->anonymity_level = htonl (sc->anonymity);
-      memset (&sm->target,
-              0,
-              sizeof (struct GNUNET_PeerIdentity));
       sm->query = sc->requests[keyword_offset].uquery;
       GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
                                              &build_result_set,
                                              &mbc);
       search_request_map_offset += todo;
-      GNUNET_assert (0 == mbc.put_cnt); /* #4608 reports this fails? */
+      GNUNET_assert (0 == mbc.put_cnt);
       GNUNET_assert (total_seen_results >= search_request_map_offset);
       if (total_seen_results != search_request_map_offset)
       {
@@ -1156,11 +1157,17 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
       {
         sm->options = htonl (options);
         keyword_offset++;
-        search_request_map_offset = 0;
         if (sc->uri->data.ksk.keywordCount != keyword_offset)
         {
           /* more keywords => more requesting to be done... */
           first_call = GNUNET_YES;
+          search_request_map_offset = 0;
+          mbc.put_cnt = 0;
+          mbc.keyword_offset = keyword_offset;
+          GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
+                                                 &find_result_set,
+                                                 &mbc);
+          total_seen_results = mbc.put_cnt;
         }
       }
     }
@@ -1168,11 +1175,6 @@ schedule_transmit_search_request (struct GNUNET_FS_SearchContext *sc)
     {
       GNUNET_assert (GNUNET_FS_uri_test_sks (sc->uri));
 
-      sm->type = htonl (GNUNET_BLOCK_TYPE_FS_UBLOCK);
-      sm->anonymity_level = htonl (sc->anonymity);
-      memset (&sm->target,
-              0,
-              sizeof (struct GNUNET_PeerIdentity));
       GNUNET_CRYPTO_ecdsa_public_key_derive (&sc->uri->data.sks.ns,
                                              sc->uri->data.sks.identifier,
                                              "fs-ublock",
@@ -1383,9 +1385,10 @@ GNUNET_FS_search_start_searching_ (struct GNUNET_FS_SearchContext *sc)
     GNUNET_assert (0 != sc->uri->data.ksk.keywordCount);
     anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
     GNUNET_CRYPTO_ecdsa_key_get_public (anon, &anon_pub);
-    sc->requests =
-        GNUNET_malloc (sizeof (struct SearchRequestEntry) *
-                       sc->uri->data.ksk.keywordCount);
+    sc->requests
+      = GNUNET_new_array (sc->uri->data.ksk.keywordCount,
+                          struct SearchRequestEntry);
+
     for (i = 0; i < sc->uri->data.ksk.keywordCount; i++)
     {
       keyword = &sc->uri->data.ksk.keywords[i][1];
@@ -1666,8 +1669,8 @@ search_result_stop (void *cls,
   if (NULL != sr->download)
   {
     sr->download->search = NULL;
-    sr->download->top =
-        GNUNET_FS_make_top (sr->download->h,
+    sr->download->top
+      = GNUNET_FS_make_top (sr->download->h,
                             &GNUNET_FS_download_signal_suspend_,
                             sr->download);
     if (NULL != sr->download->serialization)
@@ -1679,7 +1682,8 @@ search_result_stop (void *cls,
       sr->download->serialization = NULL;
     }
     pi.status = GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT;
-    GNUNET_FS_download_make_status_ (&pi, sr->download);
+    GNUNET_FS_download_make_status_ (&pi,
+                                     sr->download);
     GNUNET_FS_download_sync_ (sr->download);
     sr->download = NULL;
   }
@@ -1745,25 +1749,28 @@ GNUNET_FS_search_stop (struct GNUNET_FS_SearchContext *sc)
   if (NULL != sc->top)
     GNUNET_FS_end_top (sc->h, sc->top);
   GNUNET_CONTAINER_multihashmap_iterate (sc->master_result_map,
-                                         &search_result_stop, sc);
+                                         &search_result_stop,
+                                         sc);
   if (NULL != sc->psearch_result)
     sc->psearch_result->update_search = NULL;
   if (NULL != sc->serialization)
   {
     GNUNET_FS_remove_sync_file_ (sc->h,
-                                 (sc->psearch_result !=
-                                  NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH :
-                                 GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
+                                 (NULL != sc->psearch_result)
+                                 ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH
+                                 GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
                                  sc->serialization);
     GNUNET_FS_remove_sync_dir_ (sc->h,
-                                (sc->psearch_result !=
-                                 NULL) ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH :
-                                GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
+                                (NULL != sc->psearch_result)
+                                ? GNUNET_FS_SYNC_PATH_CHILD_SEARCH
+                                GNUNET_FS_SYNC_PATH_MASTER_SEARCH,
                                 sc->serialization);
     GNUNET_free (sc->serialization);
   }
   pi.status = GNUNET_FS_STATUS_SEARCH_STOPPED;
-  sc->client_info = GNUNET_FS_search_make_status_ (&pi, sc->h, sc);
+  sc->client_info = GNUNET_FS_search_make_status_ (&pi,
+                                                   sc->h,
+                                                   sc);
   GNUNET_break (NULL == sc->client_info);
   if (NULL != sc->task)
   {
index b3c6322031d22532ff649e68b06c502fbe06d132..e57e4e4943e806adcc2e8ba4367203f23076bd5c 100644 (file)
@@ -285,9 +285,9 @@ GNUNET_FS_tree_encoder_create (struct GNUNET_FS_Handle *h, uint64_t size,
   te->progress = progress;
   te->cont = cont;
   te->chk_tree_depth = GNUNET_FS_compute_depth (size);
-  te->chk_tree =
-      GNUNET_malloc (te->chk_tree_depth * CHK_PER_INODE *
-                     sizeof (struct ContentHashKey));
+  te->chk_tree
+    = GNUNET_new_array (te->chk_tree_depth * CHK_PER_INODE,
+                        struct ContentHashKey);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Created tree encoder for file with %llu bytes and depth %u\n",
              (unsigned long long) size,
index a672b84d54172f5079527c01c97970b29a9dcbb3..e1c7ea535c510c2709a5b04f3e9b30c4edff3188 100644 (file)
@@ -312,8 +312,6 @@ unindex_finish (struct GNUNET_FS_UnindexContext *uc)
   uc->fh = NULL;
   GNUNET_DATASTORE_disconnect (uc->dsh, GNUNET_NO);
   uc->dsh = NULL;
-  GNUNET_CONTAINER_multihashmap_destroy (uc->seen_dh);
-  uc->seen_dh = NULL;
   uc->state = UNINDEX_STATE_FS_NOTIFY;
   GNUNET_FS_unindex_sync_ (uc);
   uc->mq = GNUNET_CLIENT_connect (uc->h->cfg,
@@ -444,7 +442,6 @@ continue_after_remove (void *cls,
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Failed to remove UBlock: %s\n"),
                msg);
-  GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
   uc->ksk_offset++;
   GNUNET_FS_unindex_do_remove_kblocks_ (uc);
 }
@@ -454,7 +451,8 @@ continue_after_remove (void *cls,
  * Function called from datastore with result from us looking for
  * a UBlock.  There are four cases:
  * 1) no result, means we move on to the next keyword
- * 2) UID is the same as the first UID, means we move on to next keyword
+ * 2) data hash is the same as an already seen data hash, means we move on to
+ *    next keyword
  * 3) UBlock for a different CHK, means we keep looking for more
  * 4) UBlock is for our CHK, means we remove the block and then move
  *           on to the next keyword
@@ -485,34 +483,15 @@ process_kblock_for_unindex (void *cls,
   const struct UBlock *ub;
   struct GNUNET_FS_Uri *chk_uri;
   struct GNUNET_HashCode query;
-  struct GNUNET_HashCode dh;
 
   uc->dqe = NULL;
   if (NULL == data)
   {
     /* no result */
-    GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
     uc->ksk_offset++;
     GNUNET_FS_unindex_do_remove_kblocks_ (uc);
     return;
   }
-  GNUNET_CRYPTO_hash (data,
-                      size,
-                      &dh);
-  if (GNUNET_YES ==
-      GNUNET_CONTAINER_multihashmap_contains (uc->seen_dh,
-                                              &dh))
-  {
-    GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
-    uc->ksk_offset++;
-    GNUNET_FS_unindex_do_remove_kblocks_ (uc);
-    return;
-  }
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONTAINER_multihashmap_put (uc->seen_dh,
-                                                    &dh,
-                                                    uc,
-                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   GNUNET_assert (GNUNET_BLOCK_TYPE_FS_UBLOCK == type);
   if (size < sizeof (struct UBlock))
   {
@@ -565,23 +544,24 @@ process_kblock_for_unindex (void *cls,
   GNUNET_FS_uri_destroy (chk_uri);
   /* matches! */
   uc->dqe = GNUNET_DATASTORE_remove (uc->dsh,
-                                    key,
+                                     key,
                                      size,
                                      data,
-                                    0 /* priority */,
+                                     0 /* priority */,
                                      1 /* queue size */,
-                                    &continue_after_remove,
-                                    uc);
+                                     &continue_after_remove,
+                                     uc);
   return;
  get_next:
   uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
-                                     uc->roff++,
-                                     &uc->uquery,
-                                     GNUNET_BLOCK_TYPE_FS_UBLOCK,
-                                     0 /* priority */,
+                                      uid + 1 /* next_uid */,
+                                      false /* random */,
+                                      &uc->uquery,
+                                      GNUNET_BLOCK_TYPE_FS_UBLOCK,
+                                      0 /* priority */,
                                       1 /* queue size */,
-                                     &process_kblock_for_unindex,
-                                     uc);
+                                      &process_kblock_for_unindex,
+                                      uc);
 }
 
 
@@ -626,13 +606,14 @@ GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc)
                      sizeof (dpub),
                      &uc->uquery);
   uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
-                                     uc->roff++,
-                                     &uc->uquery,
-                                     GNUNET_BLOCK_TYPE_FS_UBLOCK,
-                                     0 /* priority */,
+                                      0 /* next_uid */,
+                                      false /* random */,
+                                      &uc->uquery,
+                                      GNUNET_BLOCK_TYPE_FS_UBLOCK,
+                                      0 /* priority */,
                                       1 /* queue size */,
-                                     &process_kblock_for_unindex,
-                                     uc);
+                                      &process_kblock_for_unindex,
+                                      uc);
 }
 
 
@@ -825,8 +806,6 @@ GNUNET_FS_unindex_start (struct GNUNET_FS_Handle *h,
   uc->start_time = GNUNET_TIME_absolute_get ();
   uc->file_size = size;
   uc->client_info = cctx;
-  uc->seen_dh = GNUNET_CONTAINER_multihashmap_create (4,
-                                                       GNUNET_NO);
   GNUNET_FS_unindex_sync_ (uc);
   pi.status = GNUNET_FS_STATUS_UNINDEX_START;
   pi.value.unindex.eta = GNUNET_TIME_UNIT_FOREVER_REL;
index fa27e6e9b8f833d5cc1c70403a06234f55876393..11968b750ee9e8d8b30e0c93b0f400bb395e3afa 100644 (file)
@@ -309,7 +309,8 @@ uri_ksk_parse (const char *s,
   }
   iret = max;
   dup = GNUNET_strdup (s);
-  keywords = GNUNET_malloc (max * sizeof (char *));
+  keywords = GNUNET_new_array (max,
+                               char *);
   for (i = slen - 1; i >= (int) pos; i--)
   {
     if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22")))
@@ -937,7 +938,8 @@ GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1,
     return NULL;
   }
   kc = u1->data.ksk.keywordCount;
-  kl = GNUNET_malloc ((kc + u2->data.ksk.keywordCount) * sizeof (char *));
+  kl = GNUNET_new_array (kc + u2->data.ksk.keywordCount,
+                         char *);
   for (i = 0; i < u1->data.ksk.keywordCount; i++)
     kl[i] = GNUNET_strdup (u1->data.ksk.keywords[i]);
   for (i = 0; i < u2->data.ksk.keywordCount; i++)
@@ -991,8 +993,9 @@ GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri)
     }
     if (ret->data.ksk.keywordCount > 0)
     {
-      ret->data.ksk.keywords =
-          GNUNET_malloc (ret->data.ksk.keywordCount * sizeof (char *));
+      ret->data.ksk.keywords
+        = GNUNET_new_array (ret->data.ksk.keywordCount,
+                            char *);
       for (i = 0; i < ret->data.ksk.keywordCount; i++)
         ret->data.ksk.keywords[i] = GNUNET_strdup (uri->data.ksk.keywords[i]);
     }
@@ -1078,7 +1081,8 @@ GNUNET_FS_uri_ksk_create (const char *keywords,
     *emsg = GNUNET_strdup (_("Number of double-quotes not balanced!\n"));
     return NULL;
   }
-  keywordarr = GNUNET_malloc (num_Words * sizeof (char *));
+  keywordarr = GNUNET_new_array (num_Words,
+                                 char *);
   num_Words = 0;
   inWord = 0;
   pos = searchString;
@@ -1151,7 +1155,8 @@ GNUNET_FS_uri_ksk_create_from_args (unsigned int argc,
   uri = GNUNET_new (struct GNUNET_FS_Uri);
   uri->type = GNUNET_FS_URI_KSK;
   uri->data.ksk.keywordCount = argc;
-  uri->data.ksk.keywords = GNUNET_malloc (argc * sizeof (char *));
+  uri->data.ksk.keywords = GNUNET_new_array (argc,
+                                             char *);
   for (i = 0; i < argc; i++)
   {
     keyword = argv[i];
@@ -1766,8 +1771,9 @@ GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData
     }
     /* x3 because there might be a normalized variant of every keyword,
        plus theoretically one more for mime... */
-    ret->data.ksk.keywords = GNUNET_malloc
-      (sizeof (char *) * (ent + tok_keywords + paren_keywords) * 3);
+    ret->data.ksk.keywords
+      = GNUNET_new_array ((ent + tok_keywords + paren_keywords) * 3,
+                          char *);
     GNUNET_CONTAINER_meta_data_iterate (md, &gather_uri_data, ret);
   }
   if (tok_keywords > 0)
index cc0111111e98915d21e674ce33f26bb2450be205..2f980520a5550e44002cdd8803e9b6ba465d538d 100644 (file)
@@ -72,7 +72,7 @@ static int ret;
 /**
  * Are we running 'verbosely'?
  */
-static int verbose;
+static unsigned int verbose;
 
 /**
  * Configuration to use.
@@ -759,26 +759,38 @@ free_item (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'a', "anonymity", "LEVEL",
-     gettext_noop ("set the desired LEVEL of sender-anonymity"),
-     1, &GNUNET_GETOPT_set_uint, &anonymity_level},
-    {'d', "disable-creation-time", NULL,
-     gettext_noop
-     ("disable adding the creation time to the metadata of the uploaded file"),
-     0, &GNUNET_GETOPT_set_one, &do_disable_creation_time},
-    {'D', "disable-extractor", NULL,
-     gettext_noop ("do not use libextractor to add keywords or metadata"),
-     0, &GNUNET_GETOPT_set_one, &disable_extractor},
-    {'p', "priority", "PRIORITY",
-     gettext_noop ("specify the priority of the content"),
-     1, &GNUNET_GETOPT_set_uint, &content_priority},
-    {'r', "replication", "LEVEL",
-     gettext_noop ("set the desired replication LEVEL"),
-     1, &GNUNET_GETOPT_set_uint, &replication_level},
-    {'V', "verbose", NULL,
-     gettext_noop ("be verbose (print progress information)"),
-     0, &GNUNET_GETOPT_set_one, &verbose},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('a',
+                                   "anonymity",
+                                   "LEVEL",
+                                   gettext_noop ("set the desired LEVEL of sender-anonymity"),
+                                   &anonymity_level),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                  "disable-creation-time",
+                                  gettext_noop ("disable adding the creation time to the metadata of the uploaded file"),
+                                  &do_disable_creation_time),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('D',
+                                  "disable-extractor",
+                                  gettext_noop ("do not use libextractor to add keywords or metadata"),
+                                  &disable_extractor),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('p',
+                                   "priority",
+                                   "PRIORITY",
+                                   gettext_noop ("specify the priority of the content"),
+                                   &content_priority),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('r',
+                                   "replication",
+                                   "LEVEL",
+                                   gettext_noop ("set the desired replication LEVEL"),
+                                   &replication_level),
+
+    GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
+
     GNUNET_GETOPT_OPTION_END
   };
   struct WorkItem *wi;
index 6d9adb8abe46db55bb120291db753818d0683da7..4d6f30587b0c9115a6ac7b94e84c2104b75a5b47 100644 (file)
@@ -30,7 +30,7 @@
 
 static int ret;
 
-static int verbose;
+static unsigned int verbose;
 
 static int delete_incomplete;
 
@@ -299,33 +299,51 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'a', "anonymity", "LEVEL",
-     gettext_noop ("set the desired LEVEL of receiver-anonymity"),
-     1, &GNUNET_GETOPT_set_uint, &anonymity},
-    {'D', "delete-incomplete", NULL,
-     gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"),
-     0, &GNUNET_GETOPT_set_one, &delete_incomplete},
-    {'n', "no-network", NULL,
-     gettext_noop ("only search the local peer (no P2P network search)"),
-     0, &GNUNET_GETOPT_set_one, &local_only},
-    {'o', "output", "FILENAME",
-     gettext_noop ("write the file to FILENAME"),
-     1, &GNUNET_GETOPT_set_string, &filename},
-    {'p', "parallelism", "DOWNLOADS",
-     gettext_noop
-     ("set the maximum number of parallel downloads that is allowed"),
-     1, &GNUNET_GETOPT_set_uint, &parallelism},
-    {'r', "request-parallelism", "REQUESTS",
-     gettext_noop
-     ("set the maximum number of parallel requests for blocks that is allowed"),
-     1, &GNUNET_GETOPT_set_uint, &request_parallelism},
-    {'R', "recursive", NULL,
-     gettext_noop ("download a GNUnet directory recursively"),
-     0, &GNUNET_GETOPT_set_one, &do_recursive},
-    {'V', "verbose", NULL,
-     gettext_noop ("be verbose (print progress information)"),
-     0, &GNUNET_GETOPT_increment_value, &verbose},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_UINT ('a',
+                                   "anonymity",
+                                   "LEVEL",
+                                   gettext_noop ("set the desired LEVEL of receiver-anonymity"),
+                                   &anonymity),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('D',
+                                  "delete-incomplete",
+                                  gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"),
+                                  &delete_incomplete),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "no-network",
+                                  gettext_noop ("only search the local peer (no P2P network search)"),
+                                  &local_only), 
+
+    GNUNET_GETOPT_OPTION_STRING ('o',
+                                 "output",
+                                 "FILENAME",
+                                 gettext_noop ("write the file to FILENAME"),
+                                 &filename),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('p',
+                                   "parallelism",
+                                   "DOWNLOADS",
+                                   gettext_noop ("set the maximum number of parallel downloads that is allowed"),
+                                   &parallelism),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('r',
+                                   "request-parallelism",
+                                   "REQUESTS",
+                                   gettext_noop ("set the maximum number of parallel requests for blocks that is allowed"),
+                                   &request_parallelism), 
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('R',
+                                  "recursive",
+                                  gettext_noop ("download a GNUnet directory recursively"),
+                                  &do_recursive),
+
+    GNUNET_GETOPT_OPTION_INCREMENT_VALUE ('V',
+                                          "verbose",
+                                          gettext_noop ("be verbose (print progress information)"),
+                                          &verbose), 
+
     GNUNET_GETOPT_OPTION_END
   };
 
index cfbe57bbdbca4a40b9295900e33fd1d41203afe5..fb99d8f9051fc77b5565a51df7c1a6d01206afaa 100644 (file)
@@ -203,16 +203,26 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'n', "num-peers", "COUNT",
-     gettext_noop ("run the experiment with COUNT peers"),
-     1, &GNUNET_GETOPT_set_uint, &num_peers},
-    {'H', "hosts", "HOSTFILE",
-     gettext_noop ("specifies name of a file with the HOSTS the testbed should use"),
-     1, &GNUNET_GETOPT_set_string, &host_filename},
-    {'t', "timeout", "DELAY",
-     gettext_noop ("automatically terminate experiment after DELAY"),
-     1, &GNUNET_GETOPT_set_relative_time, &timeout},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('n',
+                                   "num-peers",
+                                   "COUNT",
+                                   gettext_noop ("run the experiment with COUNT peers"),
+                                   &num_peers),
+
+    GNUNET_GETOPT_OPTION_STRING ('H',
+                                 "hosts",
+                                 "HOSTFILE",
+                                 gettext_noop ("specifies name of a file with the HOSTS the testbed should use"),
+                                 &host_filename),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
+                                            "timeout",
+                                            "DELAY",
+                                            gettext_noop ("automatically terminate experiment after DELAY"),
+                                            &timeout),
+
     GNUNET_GETOPT_OPTION_END
   };
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
index 7c20e025fce98d2706cbb0b76130fe74d2d0a8b2..2b24b71245376989f24c70992fc5a15f3f1cc25f 100644 (file)
@@ -43,7 +43,7 @@ static int list_indexed_files;
 /**
  * Option -v given?
  */
-static int verbose;
+static unsigned int verbose;
 
 
 /**
@@ -112,10 +112,13 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'i', "list-indexed", NULL,
-     gettext_noop ("print a list of all indexed files"), 0,
-     &GNUNET_GETOPT_set_one, &list_indexed_files},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('i',
+                                  "list-indexed",
+                                  gettext_noop ("print a list of all indexed files"),
+                                  &list_indexed_files),
+
     GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
     GNUNET_GETOPT_OPTION_END
   };
index 55836e772711d916777f2400a03db685494aa8bf..72a656de1571ed156fa0534a760d74f280d2e16f 100644 (file)
@@ -480,7 +480,7 @@ make_dev_zero (int fd,
   GNUNET_assert (-1 != z);
   if (z == fd)
     return;
-  dup2 (z, fd);
+  GNUNET_break (fd == dup2 (z, fd));
   GNUNET_assert (0 == close (z));
 }
 
index a563d7b7a76d9e1c9baebde7ce73f9d5335aa732..2229e45e7d81ce141c1c176cae8dcc7e5ee10a76 100644 (file)
@@ -37,7 +37,7 @@ static int ret;
 /**
  * Command line option 'verbose' set
  */
-static int verbose;
+static unsigned int verbose;
 
 /**
  * Handle to our configuration.
@@ -893,63 +893,98 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'a', "anonymity", "LEVEL",
-     gettext_noop ("set the desired LEVEL of sender-anonymity"),
-     1, &GNUNET_GETOPT_set_uint, &bo.anonymity_level},
-    {'d', "disable-creation-time", NULL,
-     gettext_noop
-     ("disable adding the creation time to the metadata of the uploaded file"),
-     0, &GNUNET_GETOPT_set_one, &do_disable_creation_time},
-    {'D', "disable-extractor", NULL,
-     gettext_noop ("do not use libextractor to add keywords or metadata"),
-     0, &GNUNET_GETOPT_set_one, &disable_extractor},
-    {'e', "extract", NULL,
-     gettext_noop
-     ("print list of extracted keywords that would be used, but do not perform upload"),
-     0, &GNUNET_GETOPT_set_one, &extract_only},
-    {'k', "key", "KEYWORD",
-     gettext_noop
-     ("add an additional keyword for the top-level file or directory"
-      " (this option can be specified multiple times)"),
-     1, &GNUNET_FS_getopt_set_keywords, &topKeywords},
-    {'m', "meta", "TYPE:VALUE",
-     gettext_noop ("set the meta-data for the given TYPE to the given VALUE"),
-     1, &GNUNET_FS_getopt_set_metadata, &meta},
-    {'n', "noindex", NULL,
-     gettext_noop ("do not index, perform full insertion (stores entire "
-                   "file in encrypted form in GNUnet database)"),
-     0, &GNUNET_GETOPT_set_one, &do_insert},
-    {'N', "next", "ID",
-     gettext_noop
-     ("specify ID of an updated version to be published in the future"
-      " (for namespace insertions only)"),
-     1, &GNUNET_GETOPT_set_string, &next_id},
-    {'p', "priority", "PRIORITY",
-     gettext_noop ("specify the priority of the content"),
-     1, &GNUNET_GETOPT_set_uint, &bo.content_priority},
-    {'P', "pseudonym", "NAME",
-     gettext_noop
-     ("publish the files under the pseudonym NAME (place file into namespace)"),
-     1, &GNUNET_GETOPT_set_string, &pseudonym},
-    {'r', "replication", "LEVEL",
-     gettext_noop ("set the desired replication LEVEL"),
-     1, &GNUNET_GETOPT_set_uint, &bo.replication_level},
-    {'s', "simulate-only", NULL,
-     gettext_noop ("only simulate the process but do not do any "
-                   "actual publishing (useful to compute URIs)"),
-     0, &GNUNET_GETOPT_set_one, &do_simulate},
-    {'t', "this", "ID",
-     gettext_noop ("set the ID of this version of the publication"
-                   " (for namespace insertions only)"),
-     1, &GNUNET_GETOPT_set_string, &this_id},
-    {'u', "uri", "URI",
-     gettext_noop ("URI to be published (can be used instead of passing a "
-                   "file to add keywords to the file with the respective URI)"),
-     1, &GNUNET_GETOPT_set_string, &uri_string},
-    {'V', "verbose", NULL,
-     gettext_noop ("be verbose (print progress information)"),
-     0, &GNUNET_GETOPT_set_one, &verbose},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_UINT ('a',
+                                   "anonymity",
+                                   "LEVEL",
+                                   gettext_noop ("set the desired LEVEL of sender-anonymity"),
+                                   &bo.anonymity_level),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                  "disable-creation-time",
+                                  gettext_noop ("disable adding the creation time to the "
+                                                "metadata of the uploaded file"),
+                                  &do_disable_creation_time),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('D',
+                                  "disable-extractor",
+                                  gettext_noop ("do not use libextractor to add keywords or metadata"),
+                                  &disable_extractor),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('e',
+                                  "extract",
+                                  gettext_noop ("print list of extracted keywords that would "
+                                                "be used, but do not perform upload"),
+                                  &extract_only),
+
+    GNUNET_FS_GETOPT_KEYWORDS ('k',
+                               "key",
+                               "KEYWORD",
+                               gettext_noop ("add an additional keyword for the top-level "
+                                             "file or directory (this option can be specified multiple times)"),
+                               &topKeywords),
+
+    GNUNET_FS_GETOPT_METADATA ('m',
+                               "meta",
+                               "TYPE:VALUE",
+                               gettext_noop ("set the meta-data for the given TYPE to the given VALUE"),
+                               &meta),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "noindex",
+                                  gettext_noop ("do not index, perform full insertion (stores "
+                                                "entire file in encrypted form in GNUnet database)"),
+                                  &do_insert),
+
+    GNUNET_GETOPT_OPTION_STRING ('N',
+                                 "next",
+                                 "ID",
+                                 gettext_noop ("specify ID of an updated version to be "
+                                               "published in the future (for namespace insertions only)"),
+                                 &next_id),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('p',
+                                   "priority",
+                                   "PRIORITY",
+                                   gettext_noop ("specify the priority of the content"),
+                                   &bo.content_priority),
+
+    GNUNET_GETOPT_OPTION_STRING ('P',
+                                 "pseudonym",
+                                 "NAME",
+                                 gettext_noop ("publish the files under the pseudonym "
+                                               "NAME (place file into namespace)"),
+                                 &pseudonym),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('r',
+                                   "replication",
+                                   "LEVEL",
+                                   gettext_noop ("set the desired replication LEVEL"),
+                                   &bo.replication_level),
+
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('s',
+                                  "simulate-only",
+                                  gettext_noop ("only simulate the process but do not do "
+                                                "any actual publishing (useful to compute URIs)"),
+                                  &do_simulate),
+
+    GNUNET_GETOPT_OPTION_STRING ('t',
+                                 "this",
+                                 "ID",
+                                 gettext_noop ("set the ID of this version of the publication "
+                                               "(for namespace insertions only)"),
+                                 &this_id),
+
+    GNUNET_GETOPT_OPTION_STRING ('u',
+                                 "uri",
+                                 "URI",
+                                 gettext_noop ("URI to be published (can be used instead of passing a "
+                                               "file to add keywords to the file with the respective URI)"),
+                                 &uri_string), 
+
+    GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
+
     GNUNET_GETOPT_OPTION_END
   };
   bo.expiration_time =
index dfe6d0e75f4439c1452ce092b3c0e2eb75ff6e05..22e790cf3c5f0e0dd7ec01e3132faacf177367ee 100644 (file)
@@ -51,7 +51,7 @@ static unsigned int results_limit;
 
 static unsigned int results;
 
-static int verbose;
+static unsigned int verbose;
 
 static int local_only;
 
@@ -305,26 +305,42 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'a', "anonymity", "LEVEL",
-     gettext_noop ("set the desired LEVEL of receiver-anonymity"),
-     1, &GNUNET_GETOPT_set_uint, &anonymity},
-    {'n', "no-network", NULL,
-     gettext_noop ("only search the local peer (no P2P network search)"),
-     0, &GNUNET_GETOPT_set_one, &local_only},
-    {'o', "output", "PREFIX",
-     gettext_noop ("write search results to file starting with PREFIX"),
-     1, &GNUNET_GETOPT_set_string, &output_filename},
-    {'t', "timeout", "DELAY",
-     gettext_noop ("automatically terminate search after DELAY"),
-     1, &GNUNET_GETOPT_set_relative_time, &timeout},
-    {'V', "verbose", NULL,
-     gettext_noop ("be verbose (print progress information)"),
-     0, &GNUNET_GETOPT_set_one, &verbose},
-    {'N', "results", "VALUE",
-     gettext_noop
-     ("automatically terminate search after VALUE results are found"),
-     1, &GNUNET_GETOPT_set_uint, &results_limit},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('a',
+                                   "anonymity",
+                                   "LEVEL",
+                                   gettext_noop ("set the desired LEVEL of receiver-anonymity"),
+                                   &anonymity),
+
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "no-network",
+                                  gettext_noop ("only search the local peer (no P2P network search)"),
+                                  &local_only),
+                                  
+    GNUNET_GETOPT_OPTION_STRING ('o',
+                                 "output",
+                                 "PREFIX",
+                                 gettext_noop ("write search results to file starting with PREFIX"),
+                                 &output_filename),                              
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t', 
+                                            "timeout",
+                                            "DELAY",
+                                            gettext_noop ("automatically terminate search after DELAY"),
+                                            &timeout),
+
+
+    GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('N',
+                                   "results",
+                                   "VALUE",
+                                   gettext_noop ("automatically terminate search "
+                                                 "after VALUE results are found"),
+                                   &results_limit),
+
     GNUNET_GETOPT_OPTION_END
   };
 
index 256d0c2b8d6f676bdea084b7119214ee9cc61ecc..09b1e05d8f49f1e53f3561a80753c6d687c270f2 100644 (file)
@@ -38,7 +38,6 @@
 #include "gnunet_util_lib.h"
 #include "gnunet-service-fs_cp.h"
 #include "gnunet-service-fs_indexing.h"
-#include "gnunet-service-fs_lc.h"
 #include "gnunet-service-fs_pe.h"
 #include "gnunet-service-fs_pr.h"
 #include "gnunet-service-fs_push.h"
index 55e0cbc24629a686bba7c96aa04bf14c95e10cdf..c729ebe414e9214ca453e16ae3b4b90038104512 100644 (file)
@@ -487,7 +487,7 @@ reset_cadet (struct CadetHandle *mh)
     GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
                         strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
                         &port);
-    mh->channel = GNUNET_CADET_channel_creatE (cadet_handle,
+    mh->channel = GNUNET_CADET_channel_create (cadet_handle,
                                                mh,
                                                &mh->target,
                                                &port,
@@ -627,7 +627,7 @@ get_cadet (const struct GNUNET_PeerIdentity *target)
     GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
                         strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
                         &port);
-    mh->channel = GNUNET_CADET_channel_creatE (cadet_handle,
+    mh->channel = GNUNET_CADET_channel_create (cadet_handle,
                                                mh,
                                                &mh->target,
                                                &port,
index adbce1154568a4cabc2c351f8f15d8494b3db7d9..f8619b8125de44916c060aba0f68bf5b552e2567 100644 (file)
@@ -289,7 +289,7 @@ handle_datastore_reply (void *cls,
     }
     return;
   }
-  if (msize > GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (msize > GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     continue_writing (sc);
@@ -345,12 +345,13 @@ handle_request (void *cls,
                            GNUNET_NO);
   refresh_timeout_task (sc);
   sc->qe = GNUNET_DATASTORE_get_key (GSF_dsh,
-                                    0,
-                                    &sqm->query,
-                                    ntohl (sqm->type),
-                                    0 /* priority */,
-                                    GSF_datastore_queue_size,
-                                    &handle_datastore_reply,
+                                     0 /* next_uid */,
+                                     false /* random */,
+                                     &sqm->query,
+                                     ntohl (sqm->type),
+                                     0 /* priority */,
+                                     GSF_datastore_queue_size,
+                                     &handle_datastore_reply,
                                      sc);
   if (NULL == sc->qe)
   {
@@ -499,12 +500,12 @@ GSF_cadet_start_server ()
              "Initializing cadet FS server with a limit of %llu connections\n",
              sc_count_max);
   cadet_map = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
-  cadet_handle = GNUNET_CADET_connecT (GSF_cfg);
+  cadet_handle = GNUNET_CADET_connect (GSF_cfg);
   GNUNET_assert (NULL != cadet_handle);
   GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER,
                       strlen (GNUNET_APPLICATION_PORT_FS_BLOCK_TRANSFER),
                       &port);
-  cadet_port = GNUNET_CADET_open_porT (cadet_handle,
+  cadet_port = GNUNET_CADET_open_port (cadet_handle,
                                        &port,
                                        &connect_cb,
                                        NULL,
index 3f7783dedd3fb7dc659864114fb3972d85a3c746..817aed257b2d016a4fc06858013f45e78083e25b 100644 (file)
@@ -859,7 +859,7 @@ handle_p2p_reply (void *cls,
   size_t msize;
 
   GNUNET_assert (data_len + sizeof (struct PutMessage) <
-                 GNUNET_SERVER_MAX_MESSAGE_SIZE);
+                 GNUNET_MAX_MESSAGE_SIZE);
   GNUNET_assert (peerreq->pr == pr);
   prd = GSF_pending_request_get_data_ (pr);
   if (NULL == data)
@@ -883,7 +883,7 @@ handle_p2p_reply (void *cls,
                             gettext_noop ("# replies received for other peers"),
                             1, GNUNET_NO);
   msize = sizeof (struct PutMessage) + data_len;
-  if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (msize >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
index 3ce68f487db3c507bbc01695f12886492f56ef2d..ce6bcec414f124d6bc8f48146bb81fda54acdda2 100644 (file)
@@ -438,7 +438,7 @@ GNUNET_FS_indexing_send_list (struct GNUNET_MQ_Handle *mq)
     fn = pos->filename;
     slen = strlen (fn) + 1;
     if (slen + sizeof (struct IndexInfoMessage) >=
-        GNUNET_SERVER_MAX_MESSAGE_SIZE)
+        GNUNET_MAX_MESSAGE_SIZE)
     {
       GNUNET_break (0);
       break;
diff --git a/src/fs/gnunet-service-fs_lc.c b/src/fs/gnunet-service-fs_lc.c
deleted file mode 100644 (file)
index 9ffd6ca..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file fs/gnunet-service-fs_lc.c
- * @brief API to handle 'local clients'
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "gnunet-service-fs.h"
-#include "gnunet-service-fs_lc.h"
-#include "gnunet-service-fs_cp.h"
-#include "gnunet-service-fs_pr.h"
-
-
-
-/* end of gnunet-service-fs_lc.c */
diff --git a/src/fs/gnunet-service-fs_lc.h b/src/fs/gnunet-service-fs_lc.h
deleted file mode 100644 (file)
index 6671ed3..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2011 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file fs/gnunet-service-fs_lc.h
- * @brief API to handle 'local clients'
- * @author Christian Grothoff
- */
-#ifndef GNUNET_SERVICE_FS_LC_H
-#define GNUNET_SERVICE_FS_LC_H
-
-#include "gnunet-service-fs.h"
-
-
-#endif
-/* end of gnunet-service-fs_lc.h */
index b0fda24b55cfd72185d4beba0ab4ddb134373b19..b736b49c2ba08262443b3ac2d5f8ba442c992930 100644 (file)
@@ -160,19 +160,26 @@ struct GSF_PendingRequest
   struct GNUNET_SCHEDULER_Task * warn_task;
 
   /**
-   * Current offset for querying our local datastore for results.
-   * Starts at a random value, incremented until we get the same
-   * UID again (detected using 'first_uid'), which is then used
-   * to termiante the iteration.
+   * Do we have a first UID yet?
+   */
+  bool have_first_uid;
+
+  /**
+   * Have we seen a NULL result yet?
    */
-  uint64_t local_result_offset;
+  bool seen_null;
 
   /**
    * Unique ID of the first result from the local datastore;
-   * used to detect wrap-around of the offset.
+   * used to terminate the loop.
    */
   uint64_t first_uid;
 
+  /**
+   * Result count.
+   */
+  size_t result_count;
+
   /**
    * How often have we retried this request via 'cadet'?
    * (used to bound overall retries).
@@ -189,11 +196,6 @@ struct GSF_PendingRequest
    */
   unsigned int replies_seen_size;
 
-  /**
-   * Do we have a first UID yet?
-   */
-  unsigned int have_first_uid;
-
 };
 
 
@@ -332,8 +334,6 @@ GSF_pending_request_create_ (enum GSF_PendingRequestOptions options,
   if (NULL != target)
     extra += sizeof (struct GNUNET_PeerIdentity);
   pr = GNUNET_malloc (sizeof (struct GSF_PendingRequest) + extra);
-  pr->local_result_offset =
-      GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
   pr->public_data.query = *query;
   eptr = (struct GNUNET_HashCode *) &pr[1];
   if (NULL != target)
@@ -1340,6 +1340,123 @@ odc_warn_delay_task (void *cls)
 }
 
 
+/* Call our continuation (if we have any) */
+static void
+call_continuation (struct GSF_PendingRequest *pr)
+{
+  GSF_LocalLookupContinuation cont = pr->llc_cont;
+
+  GNUNET_assert (NULL == pr->qe);
+  if (NULL != pr->warn_task)
+  {
+    GNUNET_SCHEDULER_cancel (pr->warn_task);
+    pr->warn_task = NULL;
+  }
+  if (NULL == cont)
+    return;                     /* no continuation */
+  pr->llc_cont = NULL;
+  if (0 != (GSF_PRO_LOCAL_ONLY & pr->public_data.options))
+  {
+    if (GNUNET_BLOCK_EVALUATION_OK_LAST != pr->local_result)
+    {
+      /* Signal that we are done and that there won't be any
+         additional results to allow client to clean up state. */
+      pr->rh (pr->rh_cls,
+               GNUNET_BLOCK_EVALUATION_OK_LAST,
+               pr,
+               UINT32_MAX,
+               GNUNET_TIME_UNIT_ZERO_ABS,
+               GNUNET_TIME_UNIT_FOREVER_ABS,
+               GNUNET_BLOCK_TYPE_ANY,
+               NULL,
+               0);
+    }
+    /* Finally, call our continuation to signal that we are
+       done with local processing of this request; i.e. to
+       start reading again from the client. */
+    cont (pr->llc_cont_cls, NULL, GNUNET_BLOCK_EVALUATION_OK_LAST);
+    return;
+  }
+
+  cont (pr->llc_cont_cls, pr, pr->local_result);
+}
+
+
+/* Update stats and call continuation */
+static void
+no_more_local_results (struct GSF_PendingRequest *pr)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+              "No further local responses available.\n");
+#if INSANE_STATISTICS
+  if ( (GNUNET_BLOCK_TYPE_FS_DBLOCK == pr->public_data.type) ||
+       (GNUNET_BLOCK_TYPE_FS_IBLOCK == pr->public_data.type) )
+    GNUNET_STATISTICS_update (GSF_stats,
+                              gettext_noop ("# requested DBLOCK or IBLOCK not found"),
+                              1,
+                              GNUNET_NO);
+#endif
+  call_continuation (pr);
+}
+
+
+/* forward declaration */
+static void
+process_local_reply (void *cls,
+                     const struct GNUNET_HashCode *key,
+                     size_t size,
+                     const void *data,
+                     enum GNUNET_BLOCK_Type type,
+                     uint32_t priority,
+                     uint32_t anonymity,
+                     struct GNUNET_TIME_Absolute expiration,
+                     uint64_t uid);
+
+
+/* Start a local query */
+static void
+start_local_query (struct GSF_PendingRequest *pr,
+                   uint64_t next_uid,
+                   bool random)
+{
+  pr->qe_start = GNUNET_TIME_absolute_get ();
+  pr->warn_task =
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+                                    &warn_delay_task,
+                                    pr);
+  pr->qe =
+      GNUNET_DATASTORE_get_key (GSF_dsh,
+                                next_uid,
+                                random,
+                                &pr->public_data.query,
+                                pr->public_data.type ==
+                                GNUNET_BLOCK_TYPE_FS_DBLOCK ?
+                                GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
+                                (0 !=
+                                 (GSF_PRO_PRIORITY_UNLIMITED & pr->
+                                  public_data.options)) ? UINT_MAX : 1
+                                /* queue priority */ ,
+                                (0 !=
+                                 (GSF_PRO_PRIORITY_UNLIMITED & pr->
+                                  public_data.options)) ? UINT_MAX :
+                                GSF_datastore_queue_size
+                                /* max queue size */ ,
+                                &process_local_reply, pr);
+  if (NULL != pr->qe)
+    return;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "ERROR Requesting `%s' of type %d with next_uid %llu from datastore.\n",
+              GNUNET_h2s (&pr->public_data.query),
+              pr->public_data.type,
+              (unsigned long long) next_uid);
+  GNUNET_STATISTICS_update (GSF_stats,
+                            gettext_noop ("# Datastore lookups concluded (error queueing)"),
+                            1,
+                            GNUNET_NO);
+  call_continuation (pr);
+}
+
+
 /**
  * We're processing (local) results for a search request
  * from another peer.  Pass applicable results to the
@@ -1369,69 +1486,71 @@ process_local_reply (void *cls,
                      uint64_t uid)
 {
   struct GSF_PendingRequest *pr = cls;
-  GSF_LocalLookupContinuation cont;
   struct ProcessReplyClosure prq;
   struct GNUNET_HashCode query;
   unsigned int old_rf;
 
   GNUNET_SCHEDULER_cancel (pr->warn_task);
   pr->warn_task = NULL;
-  if (NULL != pr->qe)
+  if (NULL == pr->qe)
+    goto called_from_on_demand;
+  pr->qe = NULL;
+  if ( (NULL == key) &&
+       pr->seen_null &&
+       !pr->have_first_uid) /* We have hit the end for the 2nd time with no results */
   {
-    pr->qe = NULL;
-    if (NULL == key)
-    {
+    /* No results */
 #if INSANE_STATISTICS
-      GNUNET_STATISTICS_update (GSF_stats,
-                                gettext_noop
-                                ("# Datastore lookups concluded (no results)"),
-                                1, GNUNET_NO);
+    GNUNET_STATISTICS_update (GSF_stats,
+                              gettext_noop
+                              ("# Datastore lookups concluded (no results)"),
+                              1, GNUNET_NO);
 #endif
-    }
-    if (GNUNET_NO == pr->have_first_uid)
-    {
-      pr->first_uid = uid;
-      pr->have_first_uid = 1;
-    }
-    else
-    {
-      if ((uid == pr->first_uid) && (key != NULL))
-      {
-        GNUNET_STATISTICS_update (GSF_stats,
-                                  gettext_noop
-                                  ("# Datastore lookups concluded (seen all)"),
-                                  1, GNUNET_NO);
-        key = NULL;             /* all replies seen! */
-      }
-      pr->have_first_uid++;
-      if ((pr->have_first_uid > MAX_RESULTS) && (key != NULL))
-      {
-        GNUNET_STATISTICS_update (GSF_stats,
-                                  gettext_noop
-                                  ("# Datastore lookups aborted (more than MAX_RESULTS)"),
-                                  1, GNUNET_NO);
-        key = NULL;             /* all replies seen! */
-      }
-    }
+    no_more_local_results (pr);
+    return;
+  }
+  if ( ( (NULL == key) &&
+         pr->seen_null ) || /* We have hit the end for the 2nd time OR */
+       ( pr->seen_null &&
+         pr->have_first_uid &&
+         (uid >= pr->first_uid) ) ) /* We have hit the end and past first UID */
+  {
+    /* Seen all results */
+    GNUNET_STATISTICS_update (GSF_stats,
+                              gettext_noop
+                              ("# Datastore lookups concluded (seen all)"),
+                              1, GNUNET_NO);
+    no_more_local_results (pr);
+    return;
   }
   if (NULL == key)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-                "No further local responses available.\n");
-#if INSANE_STATISTICS
-    if ((pr->public_data.type == GNUNET_BLOCK_TYPE_FS_DBLOCK) ||
-        (pr->public_data.type == GNUNET_BLOCK_TYPE_FS_IBLOCK))
-      GNUNET_STATISTICS_update (GSF_stats,
-                                gettext_noop
-                                ("# requested DBLOCK or IBLOCK not found"), 1,
-                                GNUNET_NO);
-#endif
-    goto check_error_and_continue;
+    GNUNET_assert (!pr->seen_null);
+    pr->seen_null = true;
+    start_local_query (pr,
+                       0 /* next_uid */,
+                       false /* random */);
+    return;
+  }
+  if (!pr->have_first_uid)
+  {
+    pr->first_uid = uid;
+    pr->have_first_uid = true;
+  }
+  pr->result_count++;
+  if (pr->result_count > MAX_RESULTS)
+  {
+    GNUNET_STATISTICS_update (GSF_stats,
+                              gettext_noop
+                              ("# Datastore lookups aborted (more than MAX_RESULTS)"),
+                              1, GNUNET_NO);
+    no_more_local_results (pr);
+    return;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received reply for `%s' of type %d with UID %llu from datastore.\n",
               GNUNET_h2s (key), type, (unsigned long long) uid);
-  if (type == GNUNET_BLOCK_TYPE_FS_ONDEMAND)
+  if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Found ONDEMAND block, performing on-demand encoding\n");
@@ -1458,33 +1577,12 @@ process_local_reply (void *cls,
                               gettext_noop ("# on-demand lookups failed"), 1,
                               GNUNET_NO);
     GNUNET_SCHEDULER_cancel (pr->warn_task);
-    pr->warn_task =
-        GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                      &warn_delay_task, pr);
-    pr->qe =
-        GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1,
-                                  &pr->public_data.query,
-                                  pr->public_data.type ==
-                                  GNUNET_BLOCK_TYPE_FS_DBLOCK ?
-                                  GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
-                                  (0 !=
-                                   (GSF_PRO_PRIORITY_UNLIMITED &
-                                    pr->public_data.options)) ? UINT_MAX : 1
-                                  /* queue priority */ ,
-                                  (0 !=
-                                   (GSF_PRO_PRIORITY_UNLIMITED &
-                                    pr->public_data.options)) ? UINT_MAX :
-                                  GSF_datastore_queue_size
-                                  /* max queue size */ ,
-                                  &process_local_reply, pr);
-    if (NULL != pr->qe)
-      return;                   /* we're done */
-    GNUNET_STATISTICS_update (GSF_stats,
-                              gettext_noop
-                              ("# Datastore lookups concluded (error queueing)"),
-                              1, GNUNET_NO);
-    goto check_error_and_continue;
+    start_local_query (pr,
+                       uid + 1 /* next_uid */,
+                       false /* random */);
+    return;
   }
+called_from_on_demand:
   old_rf = pr->public_data.results_found;
   memset (&prq, 0, sizeof (prq));
   prq.data = data;
@@ -1496,34 +1594,9 @@ process_local_reply (void *cls,
     GNUNET_break (0);
     GNUNET_DATASTORE_remove (GSF_dsh, key, size, data, -1, -1,
                              NULL, NULL);
-    pr->qe_start = GNUNET_TIME_absolute_get ();
-    pr->warn_task =
-        GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                      &warn_delay_task, pr);
-    pr->qe =
-        GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset - 1,
-                                  &pr->public_data.query,
-                                  pr->public_data.type ==
-                                  GNUNET_BLOCK_TYPE_FS_DBLOCK ?
-                                  GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
-                                  (0 !=
-                                   (GSF_PRO_PRIORITY_UNLIMITED &
-                                    pr->public_data.options)) ? UINT_MAX : 1
-                                  /* queue priority */ ,
-                                  (0 !=
-                                   (GSF_PRO_PRIORITY_UNLIMITED &
-                                    pr->public_data.options)) ? UINT_MAX :
-                                  GSF_datastore_queue_size
-                                  /* max queue size */ ,
-                                  &process_local_reply, pr);
-    if (NULL == pr->qe)
-    {
-      GNUNET_STATISTICS_update (GSF_stats,
-                                gettext_noop
-                                ("# Datastore lookups concluded (error queueing)"),
-                                1, GNUNET_NO);
-      goto check_error_and_continue;
-    }
+    start_local_query (pr,
+                       uid + 1 /* next_uid */,
+                       false /* random */);
     return;
   }
   prq.type = type;
@@ -1535,14 +1608,15 @@ process_local_reply (void *cls,
   prq.eo = GNUNET_BLOCK_EO_LOCAL_SKIP_CRYPTO;
   process_reply (&prq, key, pr);
   pr->local_result = prq.eval;
-  if (prq.eval == GNUNET_BLOCK_EVALUATION_OK_LAST)
+  if (GNUNET_BLOCK_EVALUATION_OK_LAST == prq.eval)
   {
     GNUNET_STATISTICS_update (GSF_stats,
                               gettext_noop
                               ("# Datastore lookups concluded (found last result)"),
                               1,
                               GNUNET_NO);
-    goto check_error_and_continue;
+    call_continuation (pr);
+    return;
   }
   if ((0 == (GSF_PRO_PRIORITY_UNLIMITED & pr->public_data.options)) &&
       ((GNUNET_YES == GSF_test_get_load_too_high_ (0)) ||
@@ -1554,66 +1628,12 @@ process_local_reply (void *cls,
                               gettext_noop ("# Datastore lookups concluded (load too high)"),
                               1,
                               GNUNET_NO);
-    goto check_error_and_continue;
-  }
-  pr->qe_start = GNUNET_TIME_absolute_get ();
-  pr->warn_task =
-      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                    &warn_delay_task,
-                                    pr);
-  pr->qe =
-      GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++,
-                                &pr->public_data.query,
-                                pr->public_data.type ==
-                                GNUNET_BLOCK_TYPE_FS_DBLOCK ?
-                                GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
-                                (0 !=
-                                 (GSF_PRO_PRIORITY_UNLIMITED & pr->
-                                  public_data.options)) ? UINT_MAX : 1
-                                /* queue priority */ ,
-                                (0 !=
-                                 (GSF_PRO_PRIORITY_UNLIMITED & pr->
-                                  public_data.options)) ? UINT_MAX :
-                                GSF_datastore_queue_size
-                                /* max queue size */ ,
-                                &process_local_reply, pr);
-  /* check if we successfully queued another datastore request;
-   * if so, return, otherwise call our continuation (if we have
-   * any) */
-check_error_and_continue:
-  if (NULL != pr->qe)
+    call_continuation (pr);
     return;
-  if (NULL != pr->warn_task)
-  {
-    GNUNET_SCHEDULER_cancel (pr->warn_task);
-    pr->warn_task = NULL;
   }
-  if (NULL == (cont = pr->llc_cont))
-    return;                     /* no continuation */
-  pr->llc_cont = NULL;
-  if (0 != (GSF_PRO_LOCAL_ONLY & pr->public_data.options))
-  {
-    if (GNUNET_BLOCK_EVALUATION_OK_LAST != pr->local_result)
-    {
-      /* Signal that we are done and that there won't be any
-         additional results to allow client to clean up state. */
-      pr->rh (pr->rh_cls,
-               GNUNET_BLOCK_EVALUATION_OK_LAST,
-               pr,
-               UINT32_MAX,
-               GNUNET_TIME_UNIT_ZERO_ABS,
-               GNUNET_TIME_UNIT_FOREVER_ABS,
-               GNUNET_BLOCK_TYPE_ANY,
-               NULL, 0);
-    }
-    /* Finally, call our continuation to signal that we are
-       done with local processing of this request; i.e. to
-       start reading again from the client. */
-    cont (pr->llc_cont_cls, NULL, GNUNET_BLOCK_EVALUATION_OK_LAST);
-    return;
-  }
-
-  cont (pr->llc_cont_cls, pr, pr->local_result);
+  start_local_query (pr,
+                     uid + 1 /* next_uid */,
+                     false /* random */);
 }
 
 
@@ -1657,43 +1677,14 @@ GSF_local_lookup_ (struct GSF_PendingRequest *pr,
   GNUNET_assert (NULL == pr->llc_cont);
   pr->llc_cont = cont;
   pr->llc_cont_cls = cont_cls;
-  pr->qe_start = GNUNET_TIME_absolute_get ();
-  pr->warn_task =
-      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                    &warn_delay_task,
-                                    pr);
 #if INSANE_STATISTICS
   GNUNET_STATISTICS_update (GSF_stats,
                             gettext_noop ("# Datastore lookups initiated"), 1,
                             GNUNET_NO);
 #endif
-  pr->qe =
-      GNUNET_DATASTORE_get_key (GSF_dsh, pr->local_result_offset++,
-                                &pr->public_data.query,
-                                pr->public_data.type ==
-                                GNUNET_BLOCK_TYPE_FS_DBLOCK ?
-                                GNUNET_BLOCK_TYPE_ANY : pr->public_data.type,
-                                (0 !=
-                                 (GSF_PRO_PRIORITY_UNLIMITED & pr->
-                                  public_data.options)) ? UINT_MAX : 1
-                                /* queue priority */ ,
-                                (0 !=
-                                 (GSF_PRO_PRIORITY_UNLIMITED & pr->
-                                  public_data.options)) ? UINT_MAX :
-                                GSF_datastore_queue_size
-                                /* max queue size */ ,
-                                &process_local_reply, pr);
-  if (NULL != pr->qe)
-    return;
-  GNUNET_STATISTICS_update (GSF_stats,
-                            gettext_noop
-                            ("# Datastore lookups concluded (error queueing)"),
-                            1, GNUNET_NO);
-  GNUNET_SCHEDULER_cancel (pr->warn_task);
-  pr->warn_task = NULL;
-  pr->llc_cont = NULL;
-  if (NULL != cont)
-    cont (cont_cls, pr, pr->local_result);
+  start_local_query(pr,
+                    0 /* next_uid */,
+                    true /* random */);
 }
 
 
index bb4cb4ecb9afc3b97b5086392b4795a149d3c183..cd062bf2b71efe55e8be7dd9bce68a211a95925b 100644 (file)
@@ -72,9 +72,14 @@ struct PutOperator
   uint64_t zero_anonymity_count_estimate;
 
   /**
-   * Current offset when iterating the database.
+   * Count of results received from the database.
    */
-  uint64_t current_offset;
+  uint64_t result_count;
+
+  /**
+   * Next UID to request when iterating the database.
+   */
+  uint64_t next_uid;
 };
 
 
@@ -177,37 +182,43 @@ delay_dht_put_task (void *cls)
  */
 static void
 process_dht_put_content (void *cls,
-                        const struct GNUNET_HashCode * key,
-                        size_t size,
+                         const struct GNUNET_HashCode * key,
+                         size_t size,
                          const void *data,
-                        enum GNUNET_BLOCK_Type type,
-                         uint32_t priority, uint32_t anonymity,
-                         struct GNUNET_TIME_Absolute expiration, uint64_t uid)
+                         enum GNUNET_BLOCK_Type type,
+                         uint32_t priority,
+                         uint32_t anonymity,
+                         struct GNUNET_TIME_Absolute expiration,
+                         uint64_t uid)
 {
   struct PutOperator *po = cls;
 
   po->dht_qe = NULL;
   if (key == NULL)
   {
-    po->zero_anonymity_count_estimate = po->current_offset - 1;
-    po->current_offset = 0;
+    po->zero_anonymity_count_estimate = po->result_count;
+    po->result_count = 0;
+    po->next_uid = 0;
     po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po);
     return;
   }
+  po->result_count++;
+  po->next_uid = uid + 1;
   po->zero_anonymity_count_estimate =
-      GNUNET_MAX (po->current_offset, po->zero_anonymity_count_estimate);
+    GNUNET_MAX (po->result_count, po->zero_anonymity_count_estimate);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Retrieved block `%s' of type %u for DHT PUT\n", GNUNET_h2s (key),
               type);
   po->dht_put = GNUNET_DHT_put (GSF_dht,
                                 key,
                                 DEFAULT_PUT_REPLICATION,
-                               GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
+                                GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
                                 type,
                                 size,
                                 data,
-                               expiration,
-                               &delay_dht_put_blocks, po);
+                                expiration,
+                                &delay_dht_put_blocks,
+                                po);
 }
 
 
@@ -223,10 +234,13 @@ gather_dht_put_blocks (void *cls)
 
   po->dht_task = NULL;
   po->dht_qe =
-      GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh, po->current_offset++, 0,
+      GNUNET_DATASTORE_get_zero_anonymity (GSF_dsh,
+                                           po->next_uid,
+                                           0,
                                            UINT_MAX,
                                            po->dht_put_type,
-                                           &process_dht_put_content, po);
+                                           &process_dht_put_content,
+                                           po);
   if (NULL == po->dht_qe)
     po->dht_task = GNUNET_SCHEDULER_add_now (&delay_dht_put_task, po);
 }
index 40fa13b629467a92350e6d9d4b6cc26e5ef0d2cc..c53a85fb4b72ec87e97837d14f1740bc82aa5b7a 100644 (file)
@@ -30,7 +30,7 @@
 
 static int ret;
 
-static int verbose;
+static unsigned int verbose;
 
 static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
@@ -162,10 +162,10 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'V', "verbose", NULL,
-     gettext_noop ("be verbose (print progress information)"),
-     0, &GNUNET_GETOPT_set_one, &verbose},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
+
     GNUNET_GETOPT_OPTION_END
   };
 
index 15a59a4bc78c2dd340e13674b33d612db01a4759..26293f4df836a161665e3842d8ce8f57e55ca4d1 100644 (file)
@@ -391,7 +391,7 @@ GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
        "Trying to lookup `%s' in GNS\n",
        name);
   nlen = strlen (name) + 1;
-  if (nlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*lr))
+  if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*lr))
   {
     GNUNET_break (0);
     return NULL;
index 21471350d195833afa578384e0a1e1f6de1e1122..fb7ac10c18424c493d6ed6e49fa6bc44f14e6445 100644 (file)
@@ -514,10 +514,14 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'p', "port", "PORT",
-      gettext_noop ("Run HTTP serve on port PORT (default is 8888)"), 1,
-      &GNUNET_GETOPT_set_uint, &port},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('p',
+                                   "port",
+                                   "PORT",
+                                   gettext_noop ("Run HTTP serve on port PORT (default is 8888)"),
+                                   &port),
+
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
index 813ecdf8ef9c7dfe3036fbd2652b6c7d7bb1cb37..c9b4bde9c17af85d8812bb2937a2555214753669 100644 (file)
@@ -776,22 +776,38 @@ int
 main (int argc,
       char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'d', "dns", "IP",
-      gettext_noop ("IP of recursive DNS resolver to use (required)"), 1,
-      &GNUNET_GETOPT_set_string, &dns_ip},
-    {'f', "fcfs", "NAME",
-      gettext_noop ("Authoritative FCFS suffix to use (optional); default: fcfs.zkey.eu"), 1,
-      &GNUNET_GETOPT_set_string, &fcfs_suffix},
-    {'s', "suffix", "SUFFIX",
-      gettext_noop ("Authoritative DNS suffix to use (optional); default: zkey.eu"), 1,
-      &GNUNET_GETOPT_set_string, &dns_suffix},
-    {'p', "port", "UDPPORT",
-      gettext_noop ("UDP port to listen on for inbound DNS requests; default: 2853"), 1,
-      &GNUNET_GETOPT_set_uint, &listen_port},
-    {'z', "zone", "PUBLICKEY",
-      gettext_noop ("Public key of the GNS zone to use (overrides default)"), 1,
-      &GNUNET_GETOPT_set_string, &gns_zone_str},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_STRING ('d',
+                                 "dns",
+                                 "IP",
+                                 gettext_noop ("IP of recursive DNS resolver to use (required)"),
+                                 &dns_ip),
+
+    GNUNET_GETOPT_OPTION_STRING ('f',
+                                 "fcfs",
+                                 "NAME",
+                                 gettext_noop ("Authoritative FCFS suffix to use (optional); default: fcfs.zkey.eu"),
+                                 &fcfs_suffix),
+
+    GNUNET_GETOPT_OPTION_STRING ('s',
+                                 "suffix",
+                                 "SUFFIX",
+                                 gettext_noop ("Authoritative DNS suffix to use (optional); default: zkey.eu"),
+                                 &dns_suffix),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('p',
+                                   "port",
+                                   "UDPPORT",
+                                   gettext_noop ("UDP port to listen on for inbound DNS requests; default: 2853"),
+                                   &listen_port),
+
+    GNUNET_GETOPT_OPTION_STRING ('z',
+                                 "zone",
+                                 "PUBLICKEY",
+                                 gettext_noop ("Public key of the GNS zone to use (overrides default)"),
+                                 &gns_zone_str), 
+
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
index 6eb87a95e07a07b4316748fd35f8beb79ce56e82..35f42cdecaa875be7139f55f6662dde1a276841a 100644 (file)
@@ -621,7 +621,7 @@ struct Socks5Request
 /**
  * The port the proxy is running on (default 7777)
  */
-static unsigned long port = GNUNET_GNS_PROXY_PORT;
+static unsigned long long port = GNUNET_GNS_PROXY_PORT;
 
 /**
  * The CA file (pem) to use for the proxy CA
@@ -865,7 +865,8 @@ check_ssl_certificate (struct Socks5Request *s5r)
   const char *name;
 
   s5r->ssl_checked = GNUNET_YES;
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "XXXXXX\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Checking SSL certificate\n");
   if (CURLE_OK !=
       curl_easy_getinfo (s5r->curl,
                         CURLINFO_TLS_SESSION,
@@ -1882,19 +1883,22 @@ mhd_connection_cb (void *cls,
       {
         if (GNUNET_NETWORK_get_fd (s5r->sock) == sock)
         {
-          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Context set...\n");
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "Context set...\n");
+          s5r->ssl_checked = GNUNET_NO;
           *con_cls = s5r;
           break;
         }
       }
-      s5r->ssl_checked = GNUNET_NO;
       break;
     case MHD_CONNECTION_NOTIFY_CLOSED:
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection closed... cleaning up\n");
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Connection closed... cleaning up\n");
       s5r = *con_cls;
       if (NULL == s5r)
       {
-        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Connection stale!\n");
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "Connection stale!\n");
         return;
       }
       cleanup_s5r (s5r);
@@ -3104,7 +3108,7 @@ run_cont ()
     return;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Proxy listens on port %lu\n",
+              "Proxy listens on port %llu\n",
               port);
 
   /* start MHD daemon for HTTP */
@@ -3257,13 +3261,20 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'p', "port", NULL,
-      gettext_noop ("listen on specified port (default: 7777)"), 1,
-      &GNUNET_GETOPT_set_ulong, &port},
-    {'a', "authority", NULL,
-      gettext_noop ("pem file to use as CA"), 1,
-      &GNUNET_GETOPT_set_string, &cafile_opt},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_ULONG ('p',
+                                    "port",
+                                    NULL,
+                                    gettext_noop ("listen on specified port (default: 7777)"),
+                                    &port),
+
+    GNUNET_GETOPT_OPTION_STRING ('a',
+                                 "authority",
+                                 NULL,
+                                 gettext_noop ("pem file to use as CA"),
+                                 &cafile_opt),
+
     GNUNET_GETOPT_OPTION_END
   };
   static const char* page =
index a261e008b7f0f98661695bc81bacd702018f21e8..c85ddfe81c2781771106483263bf8d8d928d7e4a 100644 (file)
@@ -420,25 +420,43 @@ int
 main (int argc,
       char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'u', "lookup", "NAME",
-      gettext_noop ("Lookup a record for the given name"), 1,
-      &GNUNET_GETOPT_set_string, &lookup_name},
-    {'t', "type", "TYPE",
-      gettext_noop ("Specify the type of the record to lookup"), 1,
-      &GNUNET_GETOPT_set_string, &lookup_type},
-    { 'T', "timeout", "DELAY",
-      gettext_noop ("Specify timeout for the lookup"), 1,
-      &GNUNET_GETOPT_set_relative_time, &timeout },
-    {'r', "raw", NULL,
-      gettext_noop ("No unneeded output"), 0,
-      &GNUNET_GETOPT_set_one, &raw},
-    {'p', "public-key", "PKEY",
-      gettext_noop ("Specify the public key of the zone to lookup the record in"), 1,
-      &GNUNET_GETOPT_set_string, &public_key},
-    {'z', "zone", "NAME",
-      gettext_noop ("Specify the name of the ego of the zone to lookup the record in"), 1,
-      &GNUNET_GETOPT_set_string, &zone_ego_name},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_STRING ('u',
+                                 "lookup",
+                                 "NAME",
+                                 gettext_noop ("Lookup a record for the given name"),
+                                 &lookup_name),
+
+    GNUNET_GETOPT_OPTION_STRING ('t',
+                                 "type",
+                                 "TYPE",
+                                 gettext_noop ("Specify the type of the record to lookup"),
+                                 &lookup_type),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('T',
+                                            "timeout",
+                                            "DELAY",
+                                            gettext_noop ("Specify timeout for the lookup"),
+                                            &timeout),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('r',
+                                  "raw",
+                                  gettext_noop ("No unneeded output"),
+                                  &raw),
+
+    GNUNET_GETOPT_OPTION_STRING ('p',
+                                 "public-key",
+                                 "PKEY",
+                                 gettext_noop ("Specify the public key of the zone to lookup the record in"),
+                                 &public_key),
+    
+    GNUNET_GETOPT_OPTION_STRING ('z',
+                                 "zone",
+                                 "NAME",
+                                 gettext_noop ("Specify the name of the ego of the zone to lookup the record in"),
+                                 &zone_ego_name),
+
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
index 5faca4578accc258c2cc90d890542fab1c241f66..5d611e19e4ddd72afcd4855ae96379a7c11b7e4e 100644 (file)
@@ -279,9 +279,10 @@ gns_string_to_value (void *cls,
         }
         *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
         *data = vpn = GNUNET_malloc (*data_size);
-        if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
-                                                                     strlen (s_peer),
-                                                                     &vpn->peer.public_key))
+        if (GNUNET_OK !=
+            GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
+                                                        strlen (s_peer),
+                                                        &vpn->peer.public_key))
         {
           GNUNET_free (vpn);
           *data_size = 0;
@@ -362,9 +363,14 @@ gns_string_to_value (void *cls,
         }
         *data_size = sizeof (struct GNUNET_GNSRECORD_ReverseRecord) + strlen (known_by) + 1;
         *data = rev = GNUNET_malloc (*data_size);
-        GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey_str,
-                                                    strlen (pkey_str),
-                                                    &rev->pkey);
+        if (GNUNET_OK !=
+            GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey_str,
+                                                        strlen (pkey_str),
+                                                        &rev->pkey))
+        {
+          GNUNET_free (rev);
+          return GNUNET_SYSERR;
+        }
         rev->expiration = expiration;
         GNUNET_memcpy (&rev[1],
                        known_by,
index f9b21aa4f1a58529e68308c3378063c3f36e7e1f..27580275fff24a4636cd70e32be889dc2449f4f2 100644 (file)
@@ -206,7 +206,7 @@ GNUNET_HELLO_create (const struct GNUNET_CRYPTO_EddsaPublicKey *public_key,
                      void *addrgen_cls,
                      int friend_only)
 {
-  char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - 256 -
+  char buffer[GNUNET_MAX_MESSAGE_SIZE - 1 - 256 -
               sizeof (struct GNUNET_HELLO_Message)];
   size_t max;
   size_t used;
index a83d46e0711635456e5e53516c2ec9c361579ad2..9b4790c32b14172378f42ed80fa7a8c56c4d6619 100644 (file)
@@ -369,23 +369,26 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
 #if HAVE_MHD
-    {'a', "advertise", NULL,
-     gettext_noop ("advertise our hostlist to other peers"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &advertising},
+    GNUNET_GETOPT_OPTION_SET_ONE ('a',
+                                  "advertise",
+                                  gettext_noop ("advertise our hostlist to other peers"),
+                                  &advertising),
 #endif
-    {'b', "bootstrap", NULL,
-     gettext_noop
-     ("bootstrap using hostlists (it is highly recommended that you always use this option)"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &bootstrapping},
-    {'e', "enable-learning", NULL,
-     gettext_noop ("enable learning about hostlist servers from other peers"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &learning},
+    GNUNET_GETOPT_OPTION_SET_ONE ('b',
+                                  "bootstrap",
+                                  gettext_noop ("bootstrap using hostlists (it is highly recommended that you always use this option)"),
+                                  &bootstrapping),
+    GNUNET_GETOPT_OPTION_SET_ONE ('e',
+                                  "enable-learning",
+                                  gettext_noop ("enable learning about hostlist servers from other peers"),
+                                  &learning),
 #if HAVE_MHD
-    {'p', "provide-hostlist", NULL,
-     gettext_noop ("provide a hostlist server"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &provide_hostlist},
+    GNUNET_GETOPT_OPTION_SET_ONE ('p',
+                                  "provide-hostlist",
+                                  gettext_noop ("provide a hostlist server"),
+                                  &provide_hostlist),
 #endif
     GNUNET_GETOPT_OPTION_END
   };
index a973fcc280b2a89092c47012be36b84647c53440..207cc4a8119418539c4150f6ab1022b1d09d9af7 100644 (file)
@@ -350,7 +350,7 @@ callback_download (void *ptr,
                    size_t nmemb,
                    void *ctx)
 {
-  static char download_buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+  static char download_buffer[GNUNET_MAX_MESSAGE_SIZE - 1];
   const char *cbuf = ptr;
   const struct GNUNET_MessageHeader *msg;
   struct HelloOffer *ho;
@@ -373,7 +373,7 @@ callback_download (void *ptr,
   left = total;
   while ((left > 0) || (download_pos > 0))
   {
-    cpy = GNUNET_MIN (left, GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - download_pos);
+    cpy = GNUNET_MIN (left, GNUNET_MAX_MESSAGE_SIZE - 1 - download_pos);
     GNUNET_memcpy (&download_buffer[download_pos], cbuf, cpy);
     cbuf += cpy;
     download_pos += cpy;
@@ -1042,7 +1042,7 @@ download_hostlist ()
 #if 0
   CURL_EASY_SETOPT (curl, CURLOPT_VERBOSE, 1);
 #endif
-  CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
+  CURL_EASY_SETOPT (curl, CURLOPT_BUFFERSIZE, GNUNET_MAX_MESSAGE_SIZE);
   if (0 == strncmp (current_url, "http", 4))
     CURL_EASY_SETOPT (curl, CURLOPT_USERAGENT, "GNUnet");
   CURL_EASY_SETOPT (curl, CURLOPT_CONNECTTIMEOUT, 60L);
index 48c1a56221011ddabb11504affd709d72261ddfb..3df6f1ef864cc6f86443cf4a11f1cbf67df6b3a2 100644 (file)
@@ -489,7 +489,7 @@ connect_handler (void *cls,
     return NULL;
   size = strlen (hostlist_uri) + 1;
   if (size + sizeof (struct GNUNET_MessageHeader) >=
-      GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return NULL;
index 4bb3292bee1caa1eba7215651b8d1a1ed816e47c..906899ea761353d4946796e3422eefb954bd15bf 100644 (file)
@@ -158,13 +158,18 @@ run (void *cls,
 int
 main(int argc, char *const argv[])
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'t', "token", NULL,
-      gettext_noop ("GNUid token"), 1,
-      &GNUNET_GETOPT_set_string, &token},
-    {'p', "print", NULL,
-      gettext_noop ("Print token contents"), 0,
-      &GNUNET_GETOPT_set_one, &print_token},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_STRING ('t',
+                                 "token",
+                                 NULL,
+                                 gettext_noop ("GNUid token"),
+                                 &token),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('p',
+                                  "print",
+                                  gettext_noop ("Print token contents"),
+                                  &print_token),
 
     GNUNET_GETOPT_OPTION_END
   };
index 32c3cb7033bdcbea6fa155d6d19e562ea5fe7588..845d1f7534d2c476722bf32bbc62a1b0b1a679b5 100644 (file)
@@ -440,7 +440,7 @@ GNUNET_IDENTITY_PROVIDER_issue_token (struct GNUNET_IDENTITY_PROVIDER_Handle *id
   size_t slen;
 
   slen = strlen (scopes) + 1;
-  if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct IssueMessage))
+  if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct IssueMessage))
   {
     GNUNET_break (0);
     return NULL;
@@ -493,7 +493,7 @@ GNUNET_IDENTITY_PROVIDER_exchange_ticket (struct GNUNET_IDENTITY_PROVIDER_Handle
   ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket);
 
   slen = strlen (ticket_str) + 1;
-  if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct ExchangeMessage))
+  if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct ExchangeMessage))
   {
     GNUNET_free (ticket_str);
     GNUNET_break (0);
index 8c8485249ad2da8986829b022a78d43fa3b4151c..5c457ef5d53a4629b7c0a154856d37bf15025c91 100644 (file)
@@ -349,25 +349,41 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'C', "create", "NAME",
-     gettext_noop ("create ego NAME"),
-     1, &GNUNET_GETOPT_set_string, &create_ego},
-    {'D', "delete", "NAME",
-     gettext_noop ("delete ego NAME "),
-     1, &GNUNET_GETOPT_set_string, &delete_ego},
-    {'d', "display", NULL,
-     gettext_noop ("display all egos"),
-     0, &GNUNET_GETOPT_set_one, &list},
-    {'e', "ego", "NAME",
-     gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -s)"),
-     1, &GNUNET_GETOPT_set_string, &set_ego},
-    {'m', "monitor", NULL,
-     gettext_noop ("run in monitor mode egos"),
-     0, &GNUNET_GETOPT_set_one, &monitor},
-    {'s', "set", "SUBSYSTEM",
-     gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -e)"),
-     1, &GNUNET_GETOPT_set_string, &set_subsystem},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_STRING ('C',
+                                 "create",
+                                 "NAME",
+                                 gettext_noop ("create ego NAME"),
+                                 &create_ego),
+
+    GNUNET_GETOPT_OPTION_STRING ('D',
+                                 "delete",
+                                 "NAME",
+                                 gettext_noop ("delete ego NAME "),
+                                 &delete_ego),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                  "display",
+                                  gettext_noop ("display all egos"),
+                                  &list),
+    
+    GNUNET_GETOPT_OPTION_STRING ('e',
+                                 "ego",
+                                 "NAME",
+                                 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -s)"),
+                                 &set_ego),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('m',
+                                  "monitor",
+                                  gettext_noop ("run in monitor mode egos"),
+                                  &monitor),
+
+    GNUNET_GETOPT_OPTION_STRING ('s',
+                                 "set",
+                                 "SUBSYSTEM",
+                                 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -e)"),
+                                 &set_subsystem),
+
     GNUNET_GETOPT_OPTION_END
   };
   int res;
index 905b3fd8b5a216fe716445c10e7afa8771d0782b..1601ae2fdaec1cbac601f1a424f61a2eb411a5f4 100644 (file)
@@ -671,7 +671,7 @@ GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *h,
   if (NULL == h->mq)
     return NULL;
   slen = strlen (service_name) + 1;
-  if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GetDefaultMessage))
+  if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct GetDefaultMessage))
   {
     GNUNET_break (0);
     return NULL;
@@ -722,7 +722,7 @@ GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *h,
   if (NULL == h->mq)
     return NULL;
   slen = strlen (service_name) + 1;
-  if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct SetDefaultMessage))
+  if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct SetDefaultMessage))
   {
     GNUNET_break (0);
     return NULL;
@@ -773,7 +773,7 @@ GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
   if (NULL == h->mq)
     return NULL;
   slen = strlen (name) + 1;
-  if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct CreateRequestMessage))
+  if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct CreateRequestMessage))
   {
     GNUNET_break (0);
     return NULL;
@@ -830,9 +830,9 @@ GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *h,
     return NULL;
   slen_old = strlen (old_name) + 1;
   slen_new = strlen (new_name) + 1;
-  if ( (slen_old >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
-       (slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
-       (slen_old + slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct RenameMessage)) )
+  if ( (slen_old >= GNUNET_MAX_MESSAGE_SIZE) ||
+       (slen_new >= GNUNET_MAX_MESSAGE_SIZE) ||
+       (slen_old + slen_new >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct RenameMessage)) )
   {
     GNUNET_break (0);
     return NULL;
@@ -885,7 +885,7 @@ GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *h,
   if (NULL == h->mq)
     return NULL;
   slen = strlen (name) + 1;
-  if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct DeleteMessage))
+  if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct DeleteMessage))
   {
     GNUNET_break (0);
     return NULL;
index 4fb2577fdffe025cf8e6479142448fa5ba42f596..b745da125ff7ac99b0171cd35bcc2d11f246c844 100644 (file)
@@ -38,7 +38,6 @@ gnunetinclude_HEADERS = \
   gnunet_common.h \
   gnunet_constants.h \
   gnunet_configuration_lib.h \
-  gnunet_connection_lib.h \
   gnunet_consensus_service.h \
   gnunet_container_lib.h \
   gnunet_conversation_service.h \
@@ -107,7 +106,6 @@ gnunetinclude_HEADERS = \
   gnunet_scalarproduct_service.h \
   gnunet_scheduler_lib.h \
   gnunet_secretsharing_service.h \
-  gnunet_server_lib.h \
   gnunet_service_lib.h \
   gnunet_set_service.h \
   gnunet_signal_lib.h \
index 7fb14d3ace791b62038206509791bd66c3288cc9..f8d71bd8b551f498e6ba07d9734ff5f962204117 100644 (file)
@@ -61,26 +61,10 @@ enum GNUNET_ARM_RequestStatus
    */
   GNUNET_ARM_REQUEST_SENT_OK = 0,
 
-  /**
-   * Misconfiguration (can't connect to the ARM service).
-   */
-  GNUNET_ARM_REQUEST_CONFIGURATION_ERROR = 1,
-
   /**
    * We disconnected from ARM, and request was not sent.
    */
-  GNUNET_ARM_REQUEST_DISCONNECTED = 2,
-
-  /**
-   * ARM API is busy (probably trying to connect to ARM),
-   * and request was not sent. Try again later.
-   */
-  GNUNET_ARM_REQUEST_BUSY = 3,
-
-  /**
-   * Request time ran out before we had a chance to send it.
-   */
-  GNUNET_ARM_REQUEST_TIMEOUT = 5
+  GNUNET_ARM_REQUEST_DISCONNECTED = 2
 
 };
 
index 178ddaaacaacb0026b61c00aae49b1d10dfc44ae..967d50dea3f5303923d50539f2bedaa177a54a94 100644 (file)
@@ -133,7 +133,7 @@ struct GNUNET_BANDWIDTH_Tracker
   /**
    * Maximum number of seconds over which bandwidth may "accumulate".
    * Note that additionally, we also always allow at least
-   * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate.
+   * #GNUNET_MAX_MESSAGE_SIZE to accumulate.
    */
   uint32_t max_carry_s__;
 };
@@ -214,10 +214,10 @@ GNUNET_BANDWIDTH_value_max (struct GNUNET_BANDWIDTH_Value32NBO b1,
 /**
  * Initialize bandwidth tracker.  Note that in addition to the
  * 'max_carry_s' limit, we also always allow at least
- * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate.  So if the
+ * #GNUNET_MAX_MESSAGE_SIZE to accumulate.  So if the
  * bytes-per-second limit is so small that within 'max_carry_s' not
- * even #GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is
- * ignored and replaced by #GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in
+ * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
+ * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in
  * bytes).
  *
  * @param av tracker to initialize
@@ -238,10 +238,10 @@ GNUNET_BANDWIDTH_tracker_init (struct GNUNET_BANDWIDTH_Tracker *av,
 /**
  * Initialize bandwidth tracker.  Note that in addition to the
  * 'max_carry_s' limit, we also always allow at least
- * GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate.  So if the
+ * GNUNET_MAX_MESSAGE_SIZE to accumulate.  So if the
  * bytes-per-second limit is so small that within 'max_carry_s' not
- * even GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is
- * ignored and replaced by GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in
+ * even GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
+ * ignored and replaced by GNUNET_MAX_MESSAGE_SIZE (which is in
  * bytes).
  *
  * @param av tracker to initialize
index fd838df8d63d998911901478f8c22754c50fd532..f76f17a518eb67e9b5962492a386d7bcda9b32da 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2009-2014 GNUnet e.V.
+     Copyright (C) 2009-2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -49,7 +49,7 @@ extern "C"
 /**
  * Version number of GNUnet-cadet API.
  */
-#define GNUNET_CADET_VERSION 0x00000004
+#define GNUNET_CADET_VERSION 0x00000005
 
 
 /**
@@ -68,6 +68,33 @@ struct GNUNET_CADET_Channel;
 struct GNUNET_CADET_Port;
 
 
+/**
+ * Hash uniquely identifying a connection below a tunnel.
+ */
+struct GNUNET_CADET_ConnectionTunnelIdentifier
+{
+  struct GNUNET_ShortHashCode connection_of_tunnel;
+};
+
+
+/**
+ * Number identifying a CADET channel within a tunnel.
+ */
+struct GNUNET_CADET_ChannelTunnelNumber
+{
+  /**
+   * Which number does this channel have that uniquely identfies
+   * it within its tunnel, in network byte order.
+   *
+   * Given two peers, both may initiate channels over the same tunnel.
+   * The @e cn must be greater or equal to 0x80000000 (high-bit set)
+   * for tunnels initiated with the peer that has the larger peer
+   * identity as compared using #GNUNET_CRYPTO_cmp_peer_identity().
+   */
+  uint32_t cn GNUNET_PACKED;
+};
+
+
 /**
  * Channel options.  Second line indicates filed in the
  * CadetChannelInfo union carrying the answer.
@@ -108,118 +135,67 @@ enum GNUNET_CADET_ChannelOption
 
 
 /**
- * Functions with this signature are 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.
+ * Method called whenever a peer connects to a port in MQ-based CADET.
  *
- * @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).
- */
-typedef int
-(*GNUNET_CADET_MessageCallback) (void *cls,
-                                 struct GNUNET_CADET_Channel *channel,
-                                 void **channel_ctx,
-                                 const struct GNUNET_MessageHeader *message);
-
-
-/**
- * Message handler.  Each struct specifies how to handle on particular
- * type of message received.
+ * @param cls Closure from #GNUNET_CADET_open_port.
+ * @param channel New handle to the channel.
+ * @param source Peer that started this channel.
+ * @return Closure for the incoming @a channel. It's given to:
+ *         - The #GNUNET_CADET_DisconnectEventHandler (given to
+ *           #GNUNET_CADET_open_port) when the channel dies.
+ *         - Each the #GNUNET_MQ_MessageCallback handlers for each message
+ *           received on the @a channel.
  */
-struct GNUNET_CADET_MessageHandler
-{
-  /**
-   * Function to call for messages of type @e type.
-   */
-  GNUNET_CADET_MessageCallback callback;
-
-  /**
-   * Type of the message this handler covers.
-   */
-  uint16_t type;
-
-  /**
-   * Expected size of messages of this type.  Use 0 for variable-size.
-   * If non-zero, messages of the given type will be discarded if they
-   * do not have the right size.
-   */
-  uint16_t expected_size;
-};
+typedef void *
+(*GNUNET_CADET_ConnectEventHandler) (void *cls,
+                                     struct GNUNET_CADET_Channel *channel,
+                                     const struct GNUNET_PeerIdentity *source);
 
 
 /**
- * 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.
+ * Function called whenever an MQ-channel is destroyed, even if the destruction
+ * was requested by #GNUNET_CADET_channel_destroy.
+ * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
  *
- * @param cls closure
- * @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.
+ * It should clean up any associated state, including cancelling any pending
+ * transmission on this channel.
  *
- * @return initial channel context for the channel
- *         (can be NULL -- that's not an error)
+ * @param cls Channel closure.
+ * @param channel Connection to the other end (henceforth invalid).
  */
-typedef void *
-(GNUNET_CADET_InboundChannelNotificationHandler) (void *cls,
-                                                  struct GNUNET_CADET_Channel *channel,
-                                                  const struct GNUNET_PeerIdentity *initiator,
-                                                  const struct GNUNET_HashCode *port,
-                                                  enum GNUNET_CADET_ChannelOption options);
+typedef void
+(*GNUNET_CADET_DisconnectEventHandler) (void *cls,
+                                        const struct GNUNET_CADET_Channel *channel);
 
 
 /**
- * Function called whenever a channel is destroyed.  Should clean up
- * any associated state, including cancelling any pending transmission on this
- * channel.
+ * Function called whenever an MQ-channel's transmission window size changes.
  *
- * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
+ * The first callback in an outgoing channel will be with a non-zero value
+ * and will mean the channel is connected to the destination.
+ *
+ * For an incoming channel it will be called immediately after the
+ * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value.
  *
- * @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
+ * @param cls Channel closure.
+ * @param channel Connection to the other end --- FIXME: drop?
+ * @param window_size New window size. If the is more messages than buffer size
+ *                    this value will be negative. -- FIXME: make unsigned, we never call negative?
  */
 typedef void
-(GNUNET_CADET_ChannelEndHandler) (void *cls,
-                                  const struct GNUNET_CADET_Channel *channel,
-                                  void *channel_ctx);
+(*GNUNET_CADET_WindowSizeEventHandler) (void *cls,
+                                        const struct GNUNET_CADET_Channel *channel,
+                                        int window_size);
 
 
 /**
- * Connect to the cadet service.
+ * Connect to the MQ-based cadet service.
  *
  * @param cfg Configuration to use.
- * @param cls Closure for the various callbacks that follow (including
- *            handlers in the handlers array).
- * @param cleaner Function called when a channel is destroyed.
- *                It is called immediately if #GNUNET_CADET_channel_destroy
- *                is called on the channel.
- * @param handlers Callbacks for messages we care about, NULL-terminated. Each
- *                 one must call #GNUNET_CADET_receive_done on the channel to
- *                 receive the next message.  Messages of a type that is not
- *                 in the handlers array are ignored if received.
- *
- * @return handle to the cadet service NULL on error
- *         (in this case, init is never called)
+ * @return Handle to the cadet service NULL on error.
  */
 struct GNUNET_CADET_Handle *
-GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                      void *cls,
-                      GNUNET_CADET_ChannelEndHandler cleaner,
-                      const struct GNUNET_CADET_MessageHandler *handlers);
+GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg);
 
 
 /**
@@ -233,21 +209,29 @@ GNUNET_CADET_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
 void
 GNUNET_CADET_disconnect (struct GNUNET_CADET_Handle *handle);
 
+
 /**
- * Open a port to receive incomming channels.
+ * Open a port to receive incomming MQ-based channels.
  *
  * @param h CADET handle.
- * @param port Hash representing the port number.
- * @param new_channel Function called when an channel is received.
- * @param new_channel_cls Closure for @a new_channel.
- *
+ * @param port Hash identifying the port.
+ * @param connects Function called when an incoming channel is connected.
+ * @param connects_cls Closure for the @a connects handler.
+ * @param window_changes Function called when the transmit window size changes.
+ *                       Can be NULL.
+ * @param disconnects Function called when a channel is disconnected.
+ * @param handlers Callbacks for messages we care about, NULL-terminated.
  * @return Port handle.
  */
 struct GNUNET_CADET_Port *
 GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
-                       const struct GNUNET_HashCode *port,
-                       GNUNET_CADET_InboundChannelNotificationHandler new_channel,
-                       void *new_channel_cls);
+                        const struct GNUNET_HashCode *port,
+                        GNUNET_CADET_ConnectEventHandler connects,
+                        void *connects_cls,
+                        GNUNET_CADET_WindowSizeEventHandler window_changes,
+                        GNUNET_CADET_DisconnectEventHandler disconnects,
+                        const struct GNUNET_MQ_MessageHandler *handlers);
+
 
 /**
  * Close a port opened with @a GNUNET_CADET_open_port.
@@ -258,27 +242,38 @@ GNUNET_CADET_open_port (struct GNUNET_CADET_Handle *h,
 void
 GNUNET_CADET_close_port (struct GNUNET_CADET_Port *p);
 
+
 /**
  * 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
+ * does not accept the channel, @a disconnects 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 hash (port number).
+ * @param h CADET handle.
+ * @param channel_cls Closure for the channel. It's given to:
+ *                    - The management handler @a window_changes.
+ *                    - The disconnect handler @a disconnects
+ *                    - Each message type callback in @a handlers
+ * @param destination Peer identity the channel should go to.
+ * @param port Identification of the destination port.
  * @param options CadetOption flag field, with all desired option bits set to 1.
- *
- * @return handle to the channel
+ * @param window_changes Function called when the transmit window size changes.
+ *                       Can be NULL if this data is of no interest.
+ * TODO                  Not yet implemented.
+ * @param disconnects Function called when the channel is disconnected.
+ * @param handlers Callbacks for messages we care about, NULL-terminated.
+ * @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,
-                            const struct GNUNET_HashCode *port,
-                            enum GNUNET_CADET_ChannelOption options);
+                             void *channel_cls,
+                             const struct GNUNET_PeerIdentity *destination,
+                             const struct GNUNET_HashCode *port,
+                             enum GNUNET_CADET_ChannelOption options,
+                             GNUNET_CADET_WindowSizeEventHandler window_changes,
+                             GNUNET_CADET_DisconnectEventHandler disconnects,
+                             const struct GNUNET_MQ_MessageHandler *handlers);
 
 
 /**
@@ -294,6 +289,52 @@ void
 GNUNET_CADET_channel_destroy (struct GNUNET_CADET_Channel *channel);
 
 
+/**
+ * Obtain the message queue for a connected channel.
+ *
+ * @param channel The channel handle from which to get the MQ.
+ * @return The message queue of the channel.
+ */
+struct GNUNET_MQ_Handle *
+GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel);
+
+
+/**
+ * Indicate readiness to receive the next message on a channel.
+ *
+ * Should only be called once per handler called.
+ *
+ * @param channel Channel that will be allowed to call another handler.
+ */
+void
+GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel);
+
+
+/******************************************************************************/
+/********************       MONITORING /DEBUG API     *************************/
+/******************************************************************************/
+/* The following calls are not useful for normal CADET operation, but for      */
+/* debug and monitoring of the cadet state. They can be safely ignored.        */
+/* The API can change at any point without notice.                            */
+/* Please contact the developer if you consider any of this calls useful for  */
+/* normal cadet applications.                                                  */
+/******************************************************************************/
+
+
+/**
+ * Transitional function to convert an unsigned int port to a hash value.
+ * WARNING: local static value returned, NOT reentrant!
+ * WARNING: do not use this function for new code!
+ *
+ * @param port Numerical port (unsigned int format).
+ *
+ * @return A GNUNET_HashCode usable for the new CADET API.
+ */
+const struct GNUNET_HashCode *
+GC_u2h (uint32_t port);
+
+
+
 /**
  * Struct to retrieve info about a channel.
  */
@@ -326,76 +367,6 @@ GNUNET_CADET_channel_get_info (struct GNUNET_CADET_Channel *channel,
                                ...);
 
 
-/**
- * Handle for a transmission request.
- */
-struct GNUNET_CADET_TransmitHandle;
-
-
-/**
- * Ask the cadet to call @a notify once it is ready to transmit the
- * given number of bytes to the specified channel.
- * Only one call can be active at any time, to issue another request,
- * wait for the callback or cancel the current request.
- *
- * @param channel channel to use for transmission
- * @param cork is corking allowed for this transmission?
- * @param maxdelay how long can the message wait?
- * @param notify_size how many bytes of buffer space does notify want?
- * @param notify function to call when buffer space is available;
- *        will be called with NULL on timeout or if the overall queue
- *        for this peer is larger than queue_size and this is currently
- *        the message with the lowest priority
- * @param notify_cls closure for @a notify
- * @return non-NULL if the notify callback was queued,
- *         NULL if we can not even queue the request (insufficient
- *         memory); if NULL is returned, @a notify will NOT be called.
- */
-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);
-
-
-/**
- * Cancel the specified transmission-ready notification.
- *
- * #DEPRECATED
- * Since soon we will send immediately with mq (via request_data),
- * there will be time or need to cancel a "pending" transmission.
- *
- * @param th handle that was returned by "notify_transmit_ready".
- */
-void
-GNUNET_CADET_notify_transmit_ready_cancel (struct GNUNET_CADET_TransmitHandle *th);
-
-
-/**
- * Indicate readiness to receive the next message on a channel.
- *
- * Should only be called once per handler called.
- *
- * @param channel Channel that will be allowed to call another handler.
- */
-void
-GNUNET_CADET_receive_done (struct GNUNET_CADET_Channel *channel);
-
-
-
-/******************************************************************************/
-/********************       MONITORING /DEBUG API     *************************/
-/******************************************************************************/
-/* The following calls are not useful for normal CADET operation, but for      */
-/* debug and monitoring of the cadet state. They can be safely ignored.        */
-/* The API can change at any point without notice.                            */
-/* Please contact the developer if you consider any of this calls useful for  */
-/* normal cadet applications.                                                  */
-/******************************************************************************/
-
-
 /**
  * Method called to retrieve information about a specific channel the cadet peer
  * is aware of, including all transit nodes.
@@ -481,33 +452,6 @@ typedef void
                            uint16_t cstate);
 
 
-/**
- * Hash uniquely identifying a connection below a tunnel.
- */
-struct GNUNET_CADET_ConnectionTunnelIdentifier
-{
-  struct GNUNET_ShortHashCode connection_of_tunnel;
-};
-
-
-/**
- * Number identifying a CADET channel within a tunnel.
- */
-struct GNUNET_CADET_ChannelTunnelNumber
-{
-  /**
-   * Which number does this channel have that uniquely identfies
-   * it within its tunnel, in network byte order.
-   *
-   * Given two peers, both may initiate channels over the same tunnel.
-   * The @e cn must be greater or equal to 0x80000000 (high-bit set)
-   * for tunnels initiated with the peer that has the larger peer
-   * identity as compared using #GNUNET_CRYPTO_cmp_peer_identity().
-   */
-  uint32_t cn GNUNET_PACKED;
-};
-
-
 /**
  * Method called to retrieve information about a specific tunnel the cadet peer
  * has established, o`r is trying to establish.
@@ -667,169 +611,6 @@ GNUNET_CADET_get_tunnel (struct GNUNET_CADET_Handle *h,
                          void *callback_cls);
 
 
-/**
- * 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);
-
-
-/**
- * Transitional function to convert an unsigned int port to a hash value.
- * WARNING: local static value returned, NOT reentrant!
- * WARNING: do not use this function for new code!
- *
- * @param port Numerical port (unsigned int format).
- *
- * @return A GNUNET_HashCode usable for the new CADET API.
- */
-const struct GNUNET_HashCode *
-GC_u2h (uint32_t port);
-
-
-/******************************************************************************/
-/******************************* MQ-BASED API *********************************/
-/******************************************************************************/
-
-/**
- * Method called whenever a peer connects to a port in MQ-based CADET.
- *
- * @param cls Closure from #GNUNET_CADET_open_porT.
- * @param channel New handle to the channel.
- * @param source Peer that started this channel.
- * @return Closure for the incoming @a channel. It's given to:
- *         - The #GNUNET_CADET_DisconnectEventHandler (given to
- *           #GNUNET_CADET_open_porT) when the channel dies.
- *         - Each the #GNUNET_MQ_MessageCallback handlers for each message
- *           received on the @a channel.
- */
-typedef void *
-(*GNUNET_CADET_ConnectEventHandler) (void *cls,
-                                     struct GNUNET_CADET_Channel *channel,
-                                     const struct GNUNET_PeerIdentity *source);
-
-
-/**
- * Function called whenever an MQ-channel is destroyed, even if the destruction
- * was requested by #GNUNET_CADET_channel_destroy.
- * It must NOT call #GNUNET_CADET_channel_destroy on the channel.
- *
- * It should clean up any associated state, including cancelling any pending
- * transmission on this channel.
- *
- * @param cls Channel closure.
- * @param channel Connection to the other end (henceforth invalid).
- */
-typedef void
-(*GNUNET_CADET_DisconnectEventHandler) (void *cls,
-                                        const struct GNUNET_CADET_Channel *channel);
-
-
-/**
- * Function called whenever an MQ-channel's transmission window size changes.
- *
- * The first callback in an outgoing channel will be with a non-zero value
- * and will mean the channel is connected to the destination.
- *
- * For an incoming channel it will be called immediately after the
- * #GNUNET_CADET_ConnectEventHandler, also with a non-zero value.
- *
- * @param cls Channel closure.
- * @param channel Connection to the other end --- FIXME: drop?
- * @param window_size New window size. If the is more messages than buffer size
- *                    this value will be negative. -- FIXME: make unsigned, we never call negative?
- */
-typedef void
-(*GNUNET_CADET_WindowSizeEventHandler) (void *cls,
-                                        const struct GNUNET_CADET_Channel *channel,
-                                        int window_size);
-
-
-/**
- * Connect to the MQ-based cadet service.
- *
- * @param cfg Configuration to use.
- * @return Handle to the cadet service NULL on error.
- */
-struct GNUNET_CADET_Handle *
-GNUNET_CADET_connecT (const struct GNUNET_CONFIGURATION_Handle *cfg);
-
-
-/**
- * Open a port to receive incomming MQ-based channels.
- *
- * @param h CADET handle.
- * @param port Hash identifying the port.
- * @param connects Function called when an incoming channel is connected.
- * @param connects_cls Closure for the @a connects handler.
- * @param window_changes Function called when the transmit window size changes.
- *                       Can be NULL.
- * @param disconnects Function called when a channel is disconnected.
- * @param handlers Callbacks for messages we care about, NULL-terminated.
- * @return Port handle.
- */
-struct GNUNET_CADET_Port *
-GNUNET_CADET_open_porT (struct GNUNET_CADET_Handle *h,
-                        const struct GNUNET_HashCode *port,
-                        GNUNET_CADET_ConnectEventHandler connects,
-                        void *connects_cls,
-                        GNUNET_CADET_WindowSizeEventHandler window_changes,
-                        GNUNET_CADET_DisconnectEventHandler disconnects,
-                        const struct GNUNET_MQ_MessageHandler *handlers);
-
-/**
- * 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_cls Closure for the channel. It's given to:
- *                    - The management handler @a window_changes.
- *                    - The disconnect handler @a disconnects
- *                    - Each message type callback in @a handlers
- * @param destination Peer identity the channel should go to.
- * @param port Identification of the destination port.
- * @param options CadetOption flag field, with all desired option bits set to 1.
- * @param window_changes Function called when the transmit window size changes.
- *                       Can be NULL if this data is of no interest.
- * TODO                  Not yet implemented.
- * @param disconnects Function called when the channel is disconnected.
- * @param handlers Callbacks for messages we care about, NULL-terminated.
- * @return Handle to the channel.
- */
-struct GNUNET_CADET_Channel *
-GNUNET_CADET_channel_creatE (struct GNUNET_CADET_Handle *h,
-                             void *channel_cls,
-                             const struct GNUNET_PeerIdentity *destination,
-                             const struct GNUNET_HashCode *port,
-                             enum GNUNET_CADET_ChannelOption options,
-                             GNUNET_CADET_WindowSizeEventHandler window_changes,
-                             GNUNET_CADET_DisconnectEventHandler disconnects,
-                             const struct GNUNET_MQ_MessageHandler *handlers);
-
-
-/**
- * Obtain the message queue for a connected channel.
- *
- * @param channel The channel handle from which to get the MQ.
- * @return The message queue of the channel.
- */
-struct GNUNET_MQ_Handle *
-GNUNET_CADET_get_mq (const struct GNUNET_CADET_Channel *channel);
-
-
-/******************************************************************************/
-/******************************* MQ-BASED API *********************************/
-/******************************************************************************/
-
-
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
index 746dea61fe77b20fc0f4b4ef3d3ae7353a46915b..c1537e4f8a68ad1cc0b68911821a431224f167a3 100644 (file)
@@ -281,8 +281,8 @@ GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 int
-GNUNET_CONFIGURATION_get_value_float  (const struct GNUNET_CONFIGURATION_Handle
-                                       *cfg, const char *section,
+GNUNET_CONFIGURATION_get_value_float  (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                                       const char *section,
                                        const char *option,
                                        float *number);
 
@@ -454,9 +454,6 @@ GNUNET_CONFIGURATION_get_data (const struct GNUNET_CONFIGURATION_Handle *cfg,
                                size_t buf_size);
 
 
-
-
-
 /**
  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
  * where either in the "PATHS" section or the environtment "FOO" is
diff --git a/src/include/gnunet_connection_lib.h b/src/include/gnunet_connection_lib.h
deleted file mode 100644 (file)
index e9dd95d..0000000
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @author Christian Grothoff
- *
- * @file include/gnunet_connection_lib.h
- * Basic, low-level TCP networking interface
- *
- * @defgroup connection  Connection library
- * Basic, low-level TCP networking interface
- * @{
- */
-#ifndef GNUNET_CONNECTION_LIB_H
-#define GNUNET_CONNECTION_LIB_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "gnunet_network_lib.h"
-#include "gnunet_scheduler_lib.h"
-#include "gnunet_time_lib.h"
-
-/**
- * Timeout we use on TCP connect before trying another
- * result from the DNS resolver.  Actual value used
- * is this value divided by the number of address families.
- * Default is 5s.
- */
-#define GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
-
-/**
- * @brief handle for a network connection
- */
-struct GNUNET_CONNECTION_Handle;
-
-
-/**
- * Credentials for UNIX domain sockets.
- */
-struct GNUNET_CONNECTION_Credentials
-{
-  /**
-   * UID of the other end of the connection.
-   */
-  uid_t uid;
-
-  /**
-   * GID of the other end of the connection.
-   */
-  gid_t gid;
-};
-
-
-/**
- * Function to call for access control checks.
- *
- * @param cls closure
- * @param ucred credentials, if available, otherwise NULL
- * @param addr address
- * @param addrlen length of address
- * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
- *   for unknown address family (will be denied).
- */
-typedef int (*GNUNET_CONNECTION_AccessCheck) (void *cls,
-                                              const struct
-                                              GNUNET_CONNECTION_Credentials *
-                                              ucred,
-                                              const struct sockaddr * addr,
-                                              socklen_t addrlen);
-
-
-/**
- * Callback function for data received from the network.  Note that
- * both "available" and "err" would be 0 if the read simply timed out.
- *
- * @param cls closure
- * @param buf pointer to received data
- * @param available number of bytes availabe in "buf",
- *        possibly 0 (on errors)
- * @param addr address of the sender
- * @param addrlen size of addr
- * @param errCode value of errno (on errors receiving)
- */
-typedef void (*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
-                                            size_t available,
-                                            const struct sockaddr * addr,
-                                            socklen_t addrlen, int errCode);
-
-/**
- * Set the persist option on this connection handle.  Indicates
- * that the underlying socket or fd should never really be closed.
- * Used for indicating process death.
- *
- * @param connection the connection to set persistent
- */
-void
-GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection);
-
-/**
- * Disable the "CORK" feature for communication with the given socket,
- * forcing the OS to immediately flush the buffer on transmission
- * instead of potentially buffering multiple messages.  Essentially
- * reduces the OS send buffers to zero.
- * Used to make sure that the last messages sent through the connection
- * reach the other side before the process is terminated.
- *
- * @param connection the connection to make flushing and blocking
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Create a connection handle by (asynchronously) connecting to a host.
- * This function returns immediately, even if the connection has not
- * yet been established.  This function only creates TCP connections.
- *
- * @param s socket to connect
- * @param serv_addr server address
- * @param addrlen length of server address
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
-                                  const struct sockaddr *serv_addr,
-                                  socklen_t addrlen);
-
-
-/**
- * Create a connection handle by boxing an existing OS socket.  The OS
- * socket should henceforth be no longer used directly.
- * #GNUNET_CONNECTION_destroy() will close it.
- *
- * @param osSocket existing socket to box
- * @return the boxed socket handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket);
-
-
-/**
- * Create a connection handle by accepting on a listen socket.  This
- * function may block if the listen socket has no connection ready.
- *
- * @param access_cb function to use to check if access is allowed
- * @param access_cb_cls closure for @a access_cb
- * @param lsock listen socket
- * @return the connection handle, NULL on error (for example, access refused)
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
-                                      void *access_cb_cls,
-                                      struct GNUNET_NETWORK_Handle *lsock);
-
-
-/**
- * Create a connection handle by (asynchronously) connecting to a host.
- * This function returns immediately, even if the connection has not
- * yet been established.  This function only creates TCP connections.
- *
- * @param cfg configuration to use
- * @param hostname name of the host to connect to
- * @param port port to connect to
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle
-                                       *cfg, const char *hostname,
-                                       uint16_t port);
-
-
-/**
- * Create a connection handle by connecting to a UNIX domain service.
- * This function returns immediately, even if the connection has not
- * yet been established.  This function only creates UNIX connections.
- *
- * @param cfg configuration to use
- * @param unixpath path to connect to)
- * @return the connection handle, NULL on systems without UNIX support
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
-                                                   GNUNET_CONFIGURATION_Handle
-                                                   *cfg, const char *unixpath);
-
-
-
-
-/**
- * Create a connection handle by (asynchronously) connecting to a host.
- * This function returns immediately, even if the connection has not
- * yet been established.  This function only creates TCP connections.
- *
- * @param af_family address family to use
- * @param serv_addr server address
- * @param addrlen length of server address
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_sockaddr (int af_family,
-                                        const struct sockaddr *serv_addr,
-                                        socklen_t addrlen);
-
-/**
- * Check if connection is valid (no fatal errors have happened so far).
- * Note that a connection that is still trying to connect is considered
- * valid.
- *
- * @param connection handle to check
- * @return GNUNET_YES if valid, GNUNET_NO otherwise
- */
-int
-GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Obtain the network address of the other party.
- *
- * @param connection the client to get the address for
- * @param addr where to store the address
- * @param addrlen where to store the length of the address
- * @return GNUNET_OK on success
- */
-int
-GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
-                               void **addr, size_t * addrlen);
-
-
-/**
- * Close the connection and free associated resources.  There must
- * not be any pending requests for reading or writing to the
- * connection at this time.
- *
- * @param connection connection to destroy
- */
-void
-GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Receive data from the given connection.  Note that this function will
- * call "receiver" asynchronously using the scheduler.  It will
- * "immediately" return.  Note that there MUST only be one active
- * receive call per connection at any given point in time (so do not
- * call receive again until the receiver callback has been invoked).
- *
- * @param connection connection handle
- * @param max maximum number of bytes to read
- * @param timeout maximum amount of time to wait
- * @param receiver function to call with received data
- * @param receiver_cls closure for receiver
- */
-void
-GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection, size_t max,
-                           struct GNUNET_TIME_Relative timeout,
-                           GNUNET_CONNECTION_Receiver receiver,
-                           void *receiver_cls);
-
-
-/**
- * Cancel receive job on the given connection.  Note that the
- * receiver callback must not have been called yet in order
- * for the cancellation to be valid.
- *
- * @param connection connection handle
- * @return closure of the original receiver callback closure
- */
-void *
-GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Function called to notify a client about the connection begin ready
- * to queue more data.  @a buf will be NULL and @a size zero if the
- * connection was closed for writing in the meantime.
- *
- * @param cls closure
- * @param size number of bytes available in @a buf
- * @param buf where the callee should write the message
- * @return number of bytes written to @a buf
- */
-typedef size_t
-(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
-                                          size_t size,
-                                          void *buf);
-
-
-/**
- * Opaque handle that can be used to cancel
- * a transmit-ready notification.
- */
-struct GNUNET_CONNECTION_TransmitHandle;
-
-/**
- * Ask the connection to call us once the specified number of bytes
- * are free in the transmission buffer.  Will never call the @a notify
- * callback in this task, but always first go into the scheduler.  Note that
- * this function will abort if "size" is greater than
- * #GNUNET_SERVER_MAX_MESSAGE_SIZE.
- *
- * Note that "notify" will be called either when enough
- * buffer space is available OR when the connection is destroyed.
- * The size parameter given to notify is guaranteed to be
- * larger or equal to size if the buffer is ready, or zero
- * if the connection was destroyed (or at least closed for
- * writing).  Finally, any time before 'notify' is called, a
- * client may call "notify_transmit_ready_cancel" to cancel
- * the transmission request.
- *
- * Only one transmission request can be scheduled at the same
- * time.  Notify will be run with the same scheduler priority
- * as that of the caller.
- *
- * @param connection connection
- * @param size number of bytes to send
- * @param timeout after how long should we give up (and call
- *        notify with buf NULL and size 0)?
- * @param notify function to call when buffer space is available
- * @param notify_cls closure for notify
- * @return non-NULL if the notify callback was queued,
- *         NULL if we are already going to notify someone else (busy)
- */
-struct GNUNET_CONNECTION_TransmitHandle *
-GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
-                                         size_t size,
-                                         struct GNUNET_TIME_Relative timeout,
-                                         GNUNET_CONNECTION_TransmitReadyNotify
-                                         notify, void *notify_cls);
-
-
-/**
- * Cancel the specified transmission-ready
- * notification.
- *
- * @param th handle for notification to cancel
- */
-void
-GNUNET_CONNECTION_notify_transmit_ready_cancel (struct
-                                                GNUNET_CONNECTION_TransmitHandle
-                                                *th);
-
-
-/**
- * Create a connection to be proxied using a given connection.
- *
- * @param cph connection to proxy server
- * @return connection to be proxied
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph);
-
-
-/**
- * Activate proxied connection and destroy initial proxy handshake connection.
- * There must not be any pending requests for reading or writing to the
- * proxy hadshake connection at this time.
- *
- * @param proxied connection connection to proxy server
- */
-void
-GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_CONNECTION_LIB_H */
-#endif
-
-/** @} */  /* end of group */
-
-/* end of gnunet_connection_lib.h */
index 1d0232cea11973413e29e6097038569065059420..1c48298a021945962bdd6ee0a6e8dd4763dd716e 100644 (file)
@@ -40,6 +40,8 @@ extern "C"
 #endif
 #endif
 
+
+
 /**
  * Bandwidth (in/out) to assume initially (before either peer has
  * communicated any particular preference).  Should be rather low; set
index 8136770b7803ad304a3c7010d3d68d935258da59..ace223c1122225df02d2603fde4fb1869a2bf322 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2009-2014, 2016 GNUnet e.V.
+     Copyright (C) 2009-2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -196,57 +196,6 @@ GNUNET_CORE_get_mq (const struct GNUNET_CORE_Handle *h,
                    const struct GNUNET_PeerIdentity *pid);
 
 
-/**
- * Handle for a transmission request.
- */
-struct GNUNET_CORE_TransmitHandle;
-
-
-/**
- * Ask the core to call @a notify once it is ready to transmit the
- * given number of bytes to the specified @a target.  Must only be
- * called after a connection to the respective peer has been
- * established (and the client has been informed about this).  You may
- * have one request of this type pending for each connected peer at
- * any time.  If a peer disconnects, the application MUST call
- * #GNUNET_CORE_notify_transmit_ready_cancel() on the respective
- * transmission request, if one such request is pending.
- *
- * @param handle connection to core service
- * @param cork is corking allowed for this transmission?
- * @param priority how important is the message?
- * @param maxdelay how long can the message wait? Only effective if @a cork is #GNUNET_YES
- * @param target who should receive the message, never NULL (can be this peer's identity for loopback)
- * @param notify_size how many bytes of buffer space does @a notify want?
- * @param notify function to call when buffer space is available;
- *        will be called with NULL on timeout; clients MUST cancel
- *        all pending transmission requests DURING the disconnect
- *        handler
- * @param notify_cls closure for @a notify
- * @return non-NULL if the notify callback was queued,
- *         NULL if we can not even queue the request (request already pending);
- *         if NULL is returned, @a notify will NOT be called.
- */
-struct GNUNET_CORE_TransmitHandle *
-GNUNET_CORE_notify_transmit_ready (struct GNUNET_CORE_Handle *handle,
-                                   int cork,
-                                   enum GNUNET_CORE_Priority priority,
-                                   struct GNUNET_TIME_Relative maxdelay,
-                                   const struct GNUNET_PeerIdentity *target,
-                                   size_t notify_size,
-                                   GNUNET_CONNECTION_TransmitReadyNotify notify,
-                                   void *notify_cls);
-
-
-/**
- * Cancel the specified transmission-ready notification.
- *
- * @param th handle that was returned by #GNUNET_CORE_notify_transmit_ready().
- */
-void
-GNUNET_CORE_notify_transmit_ready_cancel (struct GNUNET_CORE_TransmitHandle *th);
-
-
 /**
  * Handle to a CORE monitoring operation.
  */
index 2295d4e7216d456b395174c186b41f1e19f389a9..b1c9cb7c331ffafc9ffa7ebe5104ca6eda056fcb 100644 (file)
@@ -204,9 +204,9 @@ typedef void
  * Get one of the results for a particular key in the datastore.
  *
  * @param cls closure
- * @param offset offset of the result (modulo num-results);
- *               specific ordering does not matter for the offset
- * @param key key to match, never NULL
+ * @param next_uid return the result with lowest uid >= next_uid
+ * @param random if true, return a random result instead of using next_uid
+ * @param key maybe NULL (to match all entries)
  * @param vhash hash of the value, maybe NULL (to
  *        match all values that have the right key).
  *        Note that for DBlocks there is no difference
@@ -215,17 +215,18 @@ typedef void
  * @param type entries of which type are relevant?
  *     Use 0 for any type.
  * @param proc function to call on the matching value;
- *        proc should be called with NULL if there is no result
+ *        will be called with NULL if nothing matches
  * @param proc_cls closure for @a proc
  */
 typedef void
 (*PluginGetKey) (void *cls,
-                uint64_t offset,
-                const struct GNUNET_HashCode *key,
-                const struct GNUNET_HashCode *vhash,
-                enum GNUNET_BLOCK_Type type,
-                PluginDatumProcessor proc,
-                void *proc_cls);
+                 uint64_t next_uid,
+                 bool random,
+                 const struct GNUNET_HashCode *key,
+                 const struct GNUNET_HashCode *vhash,
+                 enum GNUNET_BLOCK_Type type,
+                 PluginDatumProcessor proc,
+                 void *proc_cls);
 
 
 /**
@@ -285,23 +286,22 @@ typedef void
 
 
 /**
- * Select a single item from the datastore at the specified offset
- * (among those applicable).
+ * Select a single item from the datastore (among those applicable).
  *
  * @param cls closure
- * @param offset offset of the result (modulo num-results);
- *               specific ordering does not matter for the offset
+ * @param next_uid return the result with lowest uid >= next_uid
  * @param type entries of which type should be considered?
  *        Must not be zero (ANY).
- * @param proc function to call on the matching value
+ * @param proc function to call on the matching value;
+ *        will be called with NULL if no value matches
  * @param proc_cls closure for @a proc
  */
 typedef void
 (*PluginGetType) (void *cls,
-                 uint64_t offset,
-                 enum GNUNET_BLOCK_Type type,
-                 PluginDatumProcessor proc,
-                 void *proc_cls);
+                  uint64_t next_uid,
+                  enum GNUNET_BLOCK_Type type,
+                  PluginDatumProcessor proc,
+                  void *proc_cls);
 
 
 /**
@@ -354,9 +354,6 @@ struct GNUNET_DATASTORE_PluginFunctions
 
   /**
    * Get datum (of the specified type) with anonymity level zero.
-   * This function is allowed to ignore the 'offset' argument
-   * and instead return a random result (with zero anonymity of
-   * the correct type) if implementing an offset is expensive.
    */
   PluginGetType get_zero_anonymity;
 
index f594d8fa61134faaabb8f307c305f450e0b30aeb..830e7da866b772870987c56c577e365cd1710bdb 100644 (file)
@@ -200,33 +200,6 @@ GNUNET_DATASTORE_release_reserve (struct GNUNET_DATASTORE_Handle *h,
                                   void *cont_cls);
 
 
-/**
- * Update a value in the datastore.
- *
- * @param h handle to the datastore
- * @param uid identifier for the value
- * @param priority how much to increase the priority of the value
- * @param expiration new expiration value should be MAX of existing and this argument
- * @param queue_priority ranking of this request in the priority queue
- * @param max_queue_size at what queue size should this request be dropped
- *        (if other requests of higher priority are in the queue)
- * @param cont continuation to call when done
- * @param cont_cls closure for @a cont
- * @return NULL if the entry was not queued, otherwise a handle that can be used to
- *         cancel; note that even if NULL is returned, the callback will be invoked
- *         (or rather, will already have been invoked)
- */
-struct GNUNET_DATASTORE_QueueEntry *
-GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h,
-                         uint64_t uid,
-                         uint32_t priority,
-                         struct GNUNET_TIME_Absolute expiration,
-                         unsigned int queue_priority,
-                         unsigned int max_queue_size,
-                         GNUNET_DATASTORE_ContinuationWithStatus cont,
-                         void *cont_cls);
-
-
 /**
  * Explicitly remove some content from the database.  @a cont will be
  * called with status #GNUNET_OK if content was removed, #GNUNET_NO if
@@ -288,10 +261,8 @@ typedef void
  * will only be called once.
  *
  * @param h handle to the datastore
- * @param offset offset of the result (modulo num-results); set to
- *               a random 64-bit value initially; then increment by
- *               one each time; detect that all results have been found by uid
- *               being again the first uid ever returned.
+ * @param next_uid return the result with lowest uid >= next_uid
+ * @param random if true, return a random result instead of using next_uid
  * @param key maybe NULL (to match all entries)
  * @param type desired type, 0 for any
  * @param queue_priority ranking of this request in the priority queue
@@ -305,7 +276,8 @@ typedef void
  */
 struct GNUNET_DATASTORE_QueueEntry *
 GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
-                          uint64_t offset,
+                          uint64_t next_uid,
+                          bool random,
                           const struct GNUNET_HashCode *key,
                           enum GNUNET_BLOCK_Type type,
                           unsigned int queue_priority,
@@ -316,16 +288,9 @@ GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
 
 /**
  * Get a single zero-anonymity value from the datastore.
- * Note that some implementations can ignore the 'offset' and
- * instead return a random zero-anonymity value.  In that case,
- * detecting the wrap-around based on a repeating UID is at best
- * probabilistic.
  *
  * @param h handle to the datastore
- * @param offset offset of the result (modulo num-results); set to
- *               a random 64-bit value initially; then increment by
- *               one each time; detect that all results have been found by uid
- *               being again the first uid ever returned.
+ * @param next_uid return the result with lowest uid >= next_uid
  * @param queue_priority ranking of this request in the priority queue
  * @param max_queue_size at what queue size should this request be dropped
  *        (if other requests of higher priority are in the queue)
@@ -339,7 +304,7 @@ GNUNET_DATASTORE_get_key (struct GNUNET_DATASTORE_Handle *h,
  */
 struct GNUNET_DATASTORE_QueueEntry *
 GNUNET_DATASTORE_get_zero_anonymity (struct GNUNET_DATASTORE_Handle *h,
-                                     uint64_t offset,
+                                     uint64_t next_uid,
                                      unsigned int queue_priority,
                                      unsigned int max_queue_size,
                                      enum GNUNET_BLOCK_Type type,
index a9c7e894446b1c03a5f1400ca89207c7ec2bc01c..ac418072ec20436ab8b869f21692b6a9a4634abc 100644 (file)
@@ -438,23 +438,36 @@ GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData
 /* ******************** command-line option parsing API *********************** */
 
 /**
- * Command-line option parser function that allows the user
- * to specify one or more '-k' options with keywords.  Each
- * specified keyword will be added to the URI.  A pointer to
- * the URI must be passed as the "scls" argument.
- *
- * @param ctx command line processor context
- * @param scls must be of type "struct GNUNET_FS_Uri **"
- * @param option name of the option (typically 'k')
- * @param value command line argument given
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_FS_getopt_set_keywords (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                               void *scls,
-                               const char *option,
-                               const char *value);
-
+ * Allow user to specify keywords.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] topKeywords set to the desired value
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_FS_GETOPT_KEYWORDS (char shortName,
+                           const char *name,
+                           const char *argumentHelp,
+                           const char *description,
+                           struct GNUNET_FS_Uri **topKeywords);
+
+/**
+ * Allow user to specify metadata.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] metadata set to the desired value
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_FS_GETOPT_METADATA (char shortName,
+                           const char *name,
+                           const char *argumentHelp,
+                           const char *description,
+                           struct GNUNET_CONTAINER_MetaData **meta);
 
 /**
  * Command-line option parser function that allows the user to specify
index b04020a7057fde8e5dba8ca6dc3d108def2ffc10..c2bd72340db00d2b2e7bf1ad20ca36ff2cf0d497 100644 (file)
@@ -97,6 +97,7 @@ typedef int
                                              const char *option,
                                              const char *value);
 
+
 /**
  * @brief Definition of a command line option.
  */
@@ -129,11 +130,22 @@ struct GNUNET_GETOPT_CommandLineOption
    */
   int require_argument;
 
+  /**
+   * Is the presence of this option mandatory?
+   */
+  int option_mandatory;
+
   /**
    * Handler for the option.
    */
   GNUNET_GETOPT_CommandLineOptionProcessor processor;
 
+  /**
+   * Function to call on @e scls to clean up after processing all
+   * the arguments. Can be NULL.
+   */
+  void (*cleaner)(void *cls);
+
   /**
    * Specific closure to pass to the processor.
    */
@@ -141,244 +153,279 @@ struct GNUNET_GETOPT_CommandLineOption
 
 };
 
+
 /**
- * Macro defining the option to print the command line
+ * Defining the option to print the command line
  * help text (-h option).
  *
  * @param about string with brief description of the application
  */
-#define GNUNET_GETOPT_OPTION_HELP(about) \
-  { 'h', "help", (const char *) NULL, gettext_noop("print this help"), 0, &GNUNET_GETOPT_format_help_, (void *) about }
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_HELP (const char *about);
 
 
 /**
- * Macro defining the option to print the version of
+ * Define the option to print the version of
  * the application (-v option)
  *
  * @param version string with the version number
  */
-#define GNUNET_GETOPT_OPTION_VERSION(version) \
-  { 'v', "version", (const char *) NULL, gettext_noop("print the version number"), 0, &GNUNET_GETOPT_print_version_, (void *) version }
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_VERSION (const char *version);
+
 
 
 /**
  * Allow user to specify log file name (-l option)
  *
- * @param logfn set to the name of the logfile
+ * @param[out] logfn set to the name of the logfile
  */
-#define GNUNET_GETOPT_OPTION_LOGFILE(logfn)                            \
-  { 'l', "logfile", "LOGFILE", gettext_noop("configure logging to write logs to LOGFILE"), 1, &GNUNET_GETOPT_set_string, (void *) logfn }
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_LOGFILE (char **logfn);
 
 
 /**
- * Allow user to specify log level (-L option)
+ * Allow user to specify a string.
  *
- * @param loglev set to the log level
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] str set to the string
  */
-#define GNUNET_GETOPT_OPTION_LOGLEVEL(loglev)                          \
-  { 'L', "log", "LOGLEVEL", gettext_noop("configure logging to use LOGLEVEL"), 1, &GNUNET_GETOPT_set_string, (void *) loglev }
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_STRING (char shortName,
+                             const char *name,
+                             const char *argumentHelp,
+                             const char *description,
+                             char **str);
+
+/**
+ * Allow user to specify a filename (automatically path expanded).
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] str set to the string
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_FILENAME (char shortName,
+                               const char *name,
+                               const char *argumentHelp,
+                               const char *description,
+                               char **str);
 
 
 /**
- * Get number of verbose (-V) flags
+ * Allow user to specify a binary value using Crockford
+ * Base32 encoding.
  *
- * @param level where to store the verbosity level (should be an 'int')
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val binary value decoded from Crockford Base32-encoded argument
+ * @param val_size size of @a val in bytes
  */
-#define GNUNET_GETOPT_OPTION_VERBOSE(level)                            \
-  { 'V', "verbose", (const char *) NULL, gettext_noop("be verbose"), 0, &GNUNET_GETOPT_increment_value, (void *) level }
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE (char shortName,
+                                            const char *name,
+                                            const char *argumentHelp,
+                                            const char *description,
+                                            void *val,
+                                            size_t val_size);
 
 
 /**
- * Get configuration file name (-c option)
+ * Allow user to specify a binary value using Crockford
+ * Base32 encoding where the size of the binary value is
+ * automatically determined from its type.
  *
- * @param fn set to the configuration file name
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val binary value decoded from Crockford Base32-encoded argument;
+ *             size is determined by type (sizeof (*val)).
  */
-#define GNUNET_GETOPT_OPTION_CFG_FILE(fn)                              \
-  { 'c', "config", "FILENAME", gettext_noop("use configuration file FILENAME"), 1, &GNUNET_GETOPT_set_string, (void *) fn }
+#define GNUNET_GETOPT_OPTION_SET_BASE32_AUTO(shortName,name,argumentHelp,description,val) \
+  GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE(shortName,name,argumentHelp,description,val,sizeof(*val))
 
 
 /**
- * Marker for the end of the list of options.
+ * Allow user to specify a flag (which internally means setting
+ * an integer to 1/#GNUNET_YES/#GNUNET_OK.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param description long help text for the option
+ * @param[out] val set to 1 if the option is present
  */
-#define GNUNET_GETOPT_OPTION_END \
-  { '\0', NULL, NULL, NULL, 0, NULL, NULL }
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_ONE (char shortName,
+                              const char *name,
+                              const char *description,
+                              int *val);
 
 
 /**
- * Parse the command line.
+ * Allow user to specify an `unsigned int`.
  *
- * @param binaryOptions Name of application with option summary
- * @param allOptions defined options and handlers
- * @param argc number of arguments in @a argv
- * @param argv actual arguments
- * @return index into argv with first non-option
- *   argument, or #GNUNET_SYSERR on error
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the value specified at the command line
  */
-int
-GNUNET_GETOPT_run (const char *binaryOptions,
-                   const struct GNUNET_GETOPT_CommandLineOption *allOptions,
-                   unsigned int argc, char *const *argv);
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_UINT (char shortName,
+                               const char *name,
+                               const char *argumentHelp,
+                               const char *description,
+                               unsigned int *val);
 
 
 /**
- * Set an option of type 'unsigned long long' from the command line.
- * A pointer to this function should be passed as part of the
- * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
- * of this type.  It should be followed by a pointer to a value of
- * type `unsigned long long`.
+ * Allow user to specify an `unsigned long long`.
  *
- * @param ctx command line processing context
- * @param scls additional closure (will point to the 'unsigned long long')
- * @param option name of the option
- * @param value actual value of the option as a string.
- * @return #GNUNET_OK if parsing the value worked
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the value specified at the command line
  */
-int
-GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                         void *scls, const char *option, const char *value);
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_ULONG (char shortName,
+                                const char *name,
+                                const char *argumentHelp,
+                                const char *description,
+                                unsigned long long *val);
 
 
 /**
- * Set an option of type 'struct GNUNET_TIME_Relative' from the command line.
- * A pointer to this function should be passed as part of the
- * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
- * of this type.  It should be followed by a pointer to a value of
- * type `struct GNUNET_TIME_Relative`.
+ * Allow user to specify a `struct GNUNET_TIME_Relative`
+ * (using human-readable "fancy" time).
  *
- * @param ctx command line processing context
- * @param scls additional closure (will point to the 'struct GNUNET_TIME_Relative')
- * @param option name of the option
- * @param value actual value of the option as a string.
- * @return #GNUNET_OK if parsing the value worked
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the time specified at the command line
  */
-int
-GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                                void *scls, const char *option, const char *value);
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME (char shortName,
+                                        const char *name,
+                                        const char *argumentHelp,
+                                        const char *description,
+                                        struct GNUNET_TIME_Relative *val);
 
 
 /**
- * Set an option of type 'unsigned int' from the command line.
- * A pointer to this function should be passed as part of the
- * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
- * of this type.  It should be followed by a pointer to a value of
- * type `unsigned int`.
+ * Allow user to specify a `struct GNUNET_TIME_Absolute`
+ * (using human-readable "fancy" time).
  *
- * @param ctx command line processing context
- * @param scls additional closure (will point to the 'unsigned int')
- * @param option name of the option
- * @param value actual value of the option as a string.
- * @return #GNUNET_OK if parsing the value worked
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the time specified at the command line
  */
-int
-GNUNET_GETOPT_set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                        void *scls, const char *option, const char *value);
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_ABSOLUTE_TIME (char shortName,
+                                        const char *name,
+                                        const char *argumentHelp,
+                                        const char *description,
+                                        struct GNUNET_TIME_Absolute *val);
 
 
 /**
- * Set an option of type 'int' from the command line to 1 if the
- * given option is present.
- * A pointer to this function should be passed as part of the
- * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
- * of this type.  It should be followed by a pointer to a value of
- * type `int`.
+ * Increment @a val each time the option flag is given by one.
  *
- * @param ctx command line processing context
- * @param scls additional closure (will point to the `int`)
- * @param option name of the option
- * @param value not used (NULL)
- * @return #GNUNET_OK (always)
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to 1 if the option is present
  */
-int
-GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                       void *scls, const char *option, const char *value);
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_INCREMENT_VALUE (char shortName,
+                                      const char *name,
+                                      const char *description,
+                                      unsigned int *val);
 
 
 /**
- * Set an option of type 'char *' from the command line.
- * A pointer to this function should be passed as part of the
- * `struct GNUNET_GETOPT_CommandLineOption` array to initialize options
- * of this type.  It should be followed by a pointer to a value of
- * type `char *`, which will be allocated with the requested string.
+ * Define the '-L' log level option.  Note that we do not check
+ * that the log level is valid here.
  *
- * @param ctx command line processing context
- * @param scls additional closure (will point to the `char *`,
- *             which will be allocated)
- * @param option name of the option
- * @param value actual value of the option (a string)
- * @return #GNUNET_OK (always)
+ * @param[out] level set to the log level
  */
-int
-GNUNET_GETOPT_set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                          void *scls, const char *option, const char *value);
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_LOGLEVEL (char **level);
 
 
 /**
- * Set an option of type 'char *' from the command line doing fs expansion.
- * A pointer to this function should be passed as part of the
- * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
- * of this type.  It should be followed by a pointer to a value of
- * type 'char *', which will be allocated with the requested string.
+ * Define the '-V' verbosity option.  Using the option more
+ * than once increments @a level each time.
  *
- * @param ctx command line processing context
- * @param scls additional closure (will point to the 'char *',
- *             which will be allocated)
- * @param option name of the option
- * @param value actual value of the option (a string)
- * @return #GNUNET_OK (always)
+ * @param[out] level set to the verbosity level
  */
-int
-GNUNET_GETOPT_set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                            void *scls, const char *option, const char *value);
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_VERBOSE (unsigned int *level);
+
 
 /**
- * Set an option of type 'unsigned int' from the command line. Each
- * time the option flag is given, the value is incremented by one.
- * A pointer to this function should be passed as part of the
- * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
- * of this type.  It should be followed by a pointer to a value of
- * type 'int'.
+ * Allow user to specify log file name (-l option)
  *
- * @param ctx command line processing context
- * @param scls additional closure (will point to the 'int')
- * @param option name of the option
- * @param value not used (NULL)
- * @return #GNUNET_OK (always)
+ * @param[out] logfn set to the name of the logfile
  */
-int
-GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext
-                               *ctx, void *scls, const char *option,
-                               const char *value);
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_LOGFILE (char **logfn);
 
 
-/* *************** internal prototypes - use macros above! ************* */
+/**
+ * Allow user to specify configuration file name (-c option)
+ *
+ * @param[out] fn set to the name of the configuration file
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_CFG_FILE (char **fn);
+
 
 /**
- * Print out details on command line options (implements --help).
+ * Make the given option mandatory.
  *
- * @param ctx command line processing context
- * @param scls additional closure (points to about text)
- * @param option name of the option
- * @param value not used (NULL)
- * @return #GNUNET_NO (do not continue, not an error)
+ * @param opt option to modify
+ * @return @a opt with the mandatory flag set.
  */
-int
-GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext
-                            *ctx, void *scls, const char *option,
-                            const char *value);
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_MANDATORY (struct GNUNET_GETOPT_CommandLineOption opt);
+
 
 /**
- * Print out program version (implements --version).
+ * Marker for the end of the list of options.
+ */
+#define GNUNET_GETOPT_OPTION_END \
+  { '\0', NULL, NULL, NULL, 0, 0, NULL, NULL, NULL }
+
+
+/**
+ * Parse the command line.
  *
- * @param ctx command line processing context
- * @param scls additional closure (points to version string)
- * @param option name of the option
- * @param value not used (NULL)
- * @return #GNUNET_NO (do not continue, not an error)
+ * @param binaryOptions Name of application with option summary
+ * @param allOptions defined options and handlers
+ * @param argc number of arguments in @a argv
+ * @param argv actual arguments
+ * @return index into argv with first non-option
+ *   argument, or #GNUNET_SYSERR on error
  */
 int
-GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext
-                              *ctx, void *scls, const char *option,
-                              const char *value);
+GNUNET_GETOPT_run (const char *binaryOptions,
+                   const struct GNUNET_GETOPT_CommandLineOption *allOptions,
+                   unsigned int argc,
+                   char *const *argv);
+
 
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
index db0ca98aafc17655bd26528e113d3b25c943a753..60b3ff6816f7c355f8e7cbe36f181c9b302355a7 100644 (file)
@@ -38,7 +38,8 @@
 #define GNUNET_HELPER_LIB_H
 
 #include "gnunet_scheduler_lib.h"
-#include "gnunet_server_lib.h"
+#include "gnunet_mst_lib.h"
+
 
 /**
  * The handle to a helper process.
@@ -52,7 +53,8 @@ struct GNUNET_HELPER_Handle;
  *
  * @param cls the closure from GNUNET_HELPER_start()
  */
-typedef void (*GNUNET_HELPER_ExceptionCallback) (void *cls);
+typedef void
+(*GNUNET_HELPER_ExceptionCallback) (void *cls);
 
 
 /**
@@ -75,7 +77,7 @@ struct GNUNET_HELPER_Handle *
 GNUNET_HELPER_start (int with_control_pipe,
                     const char *binary_name,
                     char *const binary_argv[],
-                    GNUNET_SERVER_MessageTokenizerCallback cb,
+                    GNUNET_MessageTokenizerCallback cb,
                     GNUNET_HELPER_ExceptionCallback exp_cb,
                     void *cb_cls);
 
index 9e5f9e28486fe19dce48d77bb75905ca337ff268..ce721d8d81bd4b9918f878b9f437aad4e0d953a7 100644 (file)
@@ -427,6 +427,26 @@ void
 GNUNET_JSON_post_parser_cleanup (void *con_cls);
 
 
+/* ****************** GETOPT JSON helper ******************* */
+
+
+/**
+ * Allow user to specify a JSON input value.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the JSON specified at the command line
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_JSON_getopt (char shortName,
+                    const char *name,
+                    const char *argumentHelp,
+                    const char *description,
+                    json_t **json);
+
+
 #endif
 
 /* end of gnunet_json_lib.h */
index b05128ccc3bd8314abe892c91ee495145175ffd3..ecee1b223bd2ac690aebd956d9048ef8336fe4e3 100644 (file)
@@ -35,6 +35,7 @@
 #ifndef GNUNET_MQ_LIB_H
 #define GNUNET_MQ_LIB_H
 
+#include "gnunet_scheduler_lib.h"
 
 /**
  * Allocate an envelope, with extra space allocated after the space needed
index 3829a7040e1fa34b9b71aed64768df7a28546f50..5645207dd11f92f260b64eadd1d21edcfb743b71 100644 (file)
@@ -617,6 +617,7 @@ GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
  *         data.  If 0 is returned in @a data_size the transmission is paused,
  *         and can be resumed with GNUNET_MULTICAST_origin_to_all_resume().
  *         #GNUNET_YES if this completes the transmission (all data supplied)
+ * @deprecated should move to MQ-style API!
  */
 typedef int
 (*GNUNET_MULTICAST_OriginTransmitNotify) (void *cls,
@@ -647,6 +648,7 @@ struct GNUNET_MULTICAST_OriginTransmitHandle;
  *        Closure for @a notify.
  *
  * @return NULL on error (i.e. request already pending).
+ * @deprecated should move to MQ-style API!
  */
 struct GNUNET_MULTICAST_OriginTransmitHandle *
 GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *origin,
@@ -854,6 +856,7 @@ GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *member,
  *         data.  If 0 is returned in @a data_size the transmission is paused,
  *         and can be resumed with GNUNET_MULTICAST_member_to_origin_resume().
  *         #GNUNET_YES if this completes the transmission (all data supplied)
+ * @deprecated should move to MQ-style API!
  */
 typedef int
 (*GNUNET_MULTICAST_MemberTransmitNotify) (void *cls,
@@ -880,6 +883,7 @@ struct GNUNET_MULTICAST_MemberTransmitHandle;
  *        Closure for @a notify.
  *
  * @return Handle to cancel request, NULL on error (i.e. request already pending).
+ * @deprecated should move to MQ-style API!
  */
 struct GNUNET_MULTICAST_MemberTransmitHandle *
 GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *member,
index 3cafe70b855f45651fd783d461dad9f242ef3464..c636447c20dcb100fdade4afce4fd9726565ef17 100644 (file)
@@ -86,7 +86,7 @@ struct GNUNET_PEERSTORE_Record
   /**
    * Peer Identity
    */
-  struct GNUNET_PeerIdentity *peer;
+  struct GNUNET_PeerIdentity peer;
 
   /**
    * Record key string
@@ -106,7 +106,7 @@ struct GNUNET_PEERSTORE_Record
   /**
    * Expiry time of entry
    */
-  struct GNUNET_TIME_Absolute *expiry;
+  struct GNUNET_TIME_Absolute expiry;
 
   /**
    * Client from which this record originated.
diff --git a/src/include/gnunet_server_lib.h b/src/include/gnunet_server_lib.h
deleted file mode 100644 (file)
index 5da31bc..0000000
+++ /dev/null
@@ -1,887 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009-2013 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @author Christian Grothoff
- *
- * @file
- * Library for building GNUnet network servers
-
- * @defgroup server  Server library
- * Library for building GNUnet network servers
- *
- * Provides functions for a server that communicates with clients.
- *
- * @see [Documentation](https://gnunet.org/ipc)
- *
- * @{
- */
-
-#ifndef GNUNET_SERVER_LIB_H
-#define GNUNET_SERVER_LIB_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#if 0                           /* keep Emacsens' auto-indent happy */
-}
-#endif
-#endif
-
-#include "gnunet_common.h"
-#include "gnunet_connection_lib.h"
-
-
-/**
- * Largest supported message (to be precise, one byte more
- * than the largest possible message, so tests involving
- * this value should check for messages being smaller than
- * this value).
- */
-#define GNUNET_SERVER_MAX_MESSAGE_SIZE 65536
-
-/**
- * Smallest supported message.
- */
-#define GNUNET_SERVER_MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader)
-
-/**
- * @brief handle for a server
- */
-struct GNUNET_SERVER_Handle;
-
-/**
- * @brief opaque handle for a client of the server
- */
-struct GNUNET_SERVER_Client;
-
-/**
- * @brief opaque handle server returns for aborting transmission to a client.
- */
-struct GNUNET_SERVER_TransmitHandle;
-
-
-/**
- * Functions with this signature are called whenever a message is
- * received.
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-typedef void
-(*GNUNET_SERVER_MessageCallback) (void *cls,
-                                  struct GNUNET_SERVER_Client *client,
-                                  const struct GNUNET_MessageHeader *message);
-
-
-/**
- * Message handler.  Each struct specifies how to handle on particular
- * type of message received.
- */
-struct GNUNET_SERVER_MessageHandler
-{
-  /**
-   * Function to call for messages of "type".
-   */
-  GNUNET_SERVER_MessageCallback callback;
-
-  /**
-   * Closure argument for @e callback.
-   */
-  void *callback_cls;
-
-  /**
-   * Type of the message this handler covers.
-   */
-  uint16_t type;
-
-  /**
-   * Expected size of messages of this type.  Use 0 for
-   * variable-size.  If non-zero, messages of the given
-   * type will be discarded (and the connection closed)
-   * if they do not have the right size.
-   */
-  uint16_t expected_size;
-
-};
-
-
-/**
- * Create a new server.
- *
- * @param access_cb function for access control
- * @param access_cb_cls closure for @a access_cb
- * @param lsocks NULL-terminated array of listen sockets
- * @param idle_timeout after how long should we timeout idle connections?
- * @param require_found if #GNUNET_YES, connections sending messages of unknown type
- *        will be closed
- * @return handle for the new server, NULL on error
- *         (typically, "port" already in use)
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
-                                   void *access_cb_cls,
-                                   struct GNUNET_NETWORK_Handle **lsocks,
-                                   struct GNUNET_TIME_Relative idle_timeout,
-                                   int require_found);
-
-/**
- * Create a new server.
- *
- * @param access_cb function for access control
- * @param access_cb_cls closure for @a access_cb
- * @param server_addr address toes listen on (including port), NULL terminated array
- * @param socklen lengths of respective @a server_addr
- * @param idle_timeout after how long should we timeout idle connections?
- * @param require_found if #GNUNET_YES, connections sending messages of unknown type
- *        will be closed
- * @return handle for the new server, NULL on error
- *         (typically, "port" already in use)
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
-                     void *access_cb_cls,
-                      struct sockaddr *const *server_addr,
-                      const socklen_t *socklen,
-                      struct GNUNET_TIME_Relative idle_timeout,
-                      int require_found);
-
-
-/**
- * Suspend accepting connections from the listen socket temporarily.
- * Resume activity using #GNUNET_SERVER_resume.
- *
- * @param server server to stop accepting connections.
- */
-void
-GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
-
-
-/**
- * Resume accepting connections from the listen socket.
- *
- * @param server server to resume accepting connections.
- */
-void
-GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
-
-
-/**
- * Stop the listen socket and get ready to shutdown the server once
- * only clients marked using #GNUNET_SERVER_client_mark_monitor are
- * left.
- *
- * @param server server to stop listening on
- */
-void
-GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server);
-
-
-/**
- * Free resources held by this server.
- *
- * @param server server to destroy
- */
-void
-GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
-
-
-/**
- * Add additional handlers to an existing server.
- *
- * @param server the server to add handlers to
- * @param handlers array of message handlers for
- *        incoming messages; the last entry must
- *        have "NULL" for the "callback"; multiple
- *        entries for the same type are allowed,
- *        they will be called in order of occurence.
- *        These handlers can be removed later;
- *        the handlers array must exist until removed
- *        (or server is destroyed).
- */
-void
-GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
-                            const struct GNUNET_SERVER_MessageHandler *handlers);
-
-
-/**
- * Notify us when the server has enough space to transmit
- * a message of the given size to the given client.
- *
- * @param client client to transmit message to
- * @param size requested amount of buffer space
- * @param timeout after how long should we give up (and call
- *        notify with buf NULL and size 0)?
- * @param callback function to call when space is available
- * @param callback_cls closure for @a callback
- * @return non-NULL if the notify callback was queued; can be used
- *           to cancel the request using
- *           #GNUNET_SERVER_notify_transmit_ready_cancel.
- *         NULL if we are already going to notify someone else (busy)
- */
-struct GNUNET_SERVER_TransmitHandle *
-GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
-                                     size_t size,
-                                     struct GNUNET_TIME_Relative timeout,
-                                     GNUNET_CONNECTION_TransmitReadyNotify callback,
-                                     void *callback_cls);
-
-
-/**
- * Abort transmission request.
- *
- * @param th request to abort
- */
-void
-GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
-
-
-/**
- * Set the 'monitor' flag on this client.  Clients which have been
- * marked as 'monitors' won't prevent the server from shutting down
- * once #GNUNET_SERVER_stop_listening has been invoked.  The idea is
- * that for "normal" clients we likely want to allow them to process
- * their requests; however, monitor-clients are likely to 'never'
- * disconnect during shutdown and thus will not be considered when
- * determining if the server should continue to exist after
- * #GNUNET_SERVER_destroy has been called.
- *
- * @param client the client to set the 'monitor' flag on
- */
-void
-GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Set the persistent flag on this client, used to setup client
- * connection to only be killed when the process of the service it's
- * connected to is actually dead.  This API is used during shutdown
- * signalling within ARM, and it is not expected that typical users
- * of the API would need this function.
- *
- * @param client the client to set the persistent flag on
- */
-void
-GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Resume receiving from this client, we are done processing the
- * current request.  This function must be called from within each
- * #GNUNET_SERVER_MessageCallback (or its respective continuations).
- *
- * @param client client we were processing a message of
- * @param success #GNUNET_OK to keep the connection open and
- *                          continue to receive
- *                #GNUNET_NO to close the connection (normal behavior)
- *                #GNUNET_SYSERR to close the connection (signal
- *                          serious error)
- */
-void
-GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
-                           int success);
-
-
-/**
- * Change the timeout for a particular client.  Decreasing the timeout
- * may not go into effect immediately (only after the previous timeout
- * times out or activity happens on the socket).
- *
- * @param client the client to update
- * @param timeout new timeout for activities on the socket
- */
-void
-GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
-                                  struct GNUNET_TIME_Relative timeout);
-
-
-/**
- * Return user context associated with the given client.
- * Note: you should probably use the macro (call without the underscore).
- *
- * @param client client to query
- * @param size number of bytes in user context struct (for verification only)
- * @return pointer to user context
- */
-void *
-GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
-                                       size_t size);
-
-
-/**
- * Set user context to be associated with the given client.
- * Note: you should probably use the macro (call without the underscore).
- *
- * @param client client to query
- * @param ptr pointer to user context
- * @param size number of bytes in user context struct (for verification only)
- */
-void
-GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
-                                       void *ptr,
-                                       size_t size);
-
-
-/**
- * Return user context associated with the given client.
- *
- * @param client client to query
- * @param type expected return type (i.e. 'struct Foo')
- * @return pointer to user context of type 'type *'.
- */
-#define GNUNET_SERVER_client_get_user_context(client,type)              \
-  (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
-
-/**
- * Set user context to be associated with the given client.
- *
- * @param client client to query
- * @param value pointer to user context
- */
-#define GNUNET_SERVER_client_set_user_context(client,value)             \
-  GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
-
-
-/**
- * Disable the warning the server issues if a message is not acknowledged
- * in a timely fashion.  Use this call if a client is intentionally delayed
- * for a while.  Only applies to the current message.
- *
- * @param client client for which to disable the warning
- */
-void
-GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client
-                                            *client);
-
-
-/**
- * Inject a message into the server, pretend it came
- * from the specified client.  Delivery of the message
- * will happen instantly (if a handler is installed;
- * otherwise the call does nothing).
- *
- * @param server the server receiving the message
- * @param sender the "pretended" sender of the message
- *        can be NULL!
- * @param message message to transmit
- * @return #GNUNET_OK if the message was OK and the
- *                   connection can stay open
- *         #GNUNET_SYSERR if the connection to the
- *         client should be shut down
- */
-int
-GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
-                      struct GNUNET_SERVER_Client *sender,
-                      const struct GNUNET_MessageHeader *message);
-
-
-/**
- * Add a TCP socket-based connection to the set of handles managed by
- * this server.  Use this function for outgoing (P2P) connections that
- * we initiated (and where this server should process incoming
- * messages).
- *
- * @param server the server to use
- * @param connection the connection to manage (client must
- *        stop using this connection from now on)
- * @return the client handle
- */
-struct GNUNET_SERVER_Client *
-GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
-                              struct GNUNET_CONNECTION_Handle *connection);
-
-
-/**
- * Notify the server that the given client handle should
- * be kept (keeps the connection up if possible, increments
- * the internal reference counter).
- *
- * @param client the client to keep
- */
-void
-GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Notify the server that the given client handle is no
- * longer required.  Decrements the reference counter.  If
- * that counter reaches zero an inactive connection maybe
- * closed.
- *
- * @param client the client to drop
- */
-void
-GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Obtain the network address of the other party.
- *
- * @param client the client to get the address for
- * @param addr where to store the address
- * @param addrlen where to store the length of @a addr
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
-                                  void **addr, size_t *addrlen);
-
-
-/**
- * Functions with this signature are called whenever a client
- * is disconnected on the network level.
- *
- * @param cls closure
- * @param client identification of the client; NULL
- *        for the last call when the server is destroyed
- */
-typedef void
-(*GNUNET_SERVER_DisconnectCallback) (void *cls,
-                                     struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Functions with this signature are called whenever a client
- * is connected on the network level.
- *
- * @param cls closure
- * @param client identification of the client
- */
-typedef void
-(*GNUNET_SERVER_ConnectCallback) (void *cls,
-                                  struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Ask the server to notify us whenever a client disconnects.
- * This function is called whenever the actual network connection
- * is closed; the reference count may be zero or larger than zero
- * at this point.  If the server is destroyed before this
- * notification is explicitly cancelled, the 'callback' will
- * once be called with a 'client' argument of NULL to indicate
- * that the server itself is now gone (and that the callback
- * won't be called anymore and also can no longer be cancelled).
- *
- * @param server the server manageing the clients
- * @param callback function to call on disconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
-                                 GNUNET_SERVER_DisconnectCallback callback,
-                                 void *callback_cls);
-
-
-/**
- * Ask the server to notify us whenever a client connects.
- * This function is called whenever the actual network connection
- * is opened. If the server is destroyed before this
- * notification is explicitly cancelled, the @a callback will
- * once be called with a 'client' argument of NULL to indicate
- * that the server itself is now gone (and that the callback
- * won't be called anymore and also can no longer be cancelled).
- *
- * @param server the server manageing the clients
- * @param callback function to call on sconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
-                             GNUNET_SERVER_ConnectCallback callback,
-                             void *callback_cls);
-
-
-/**
- * Ask the server to stop notifying us whenever a client disconnects.
- * Arguments must match exactly those given to
- * #GNUNET_SERVER_disconnect_notify.  It is not necessary to call this
- * function during shutdown of the server; in fact, most applications
- * will never use this function.
- *
- * @param server the server manageing the clients
- * @param callback function to call on disconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
-                                        GNUNET_SERVER_DisconnectCallback callback,
-                                        void *callback_cls);
-
-
-/**
- * Ask the server to stop notifying us whenever a client connects.
- * Arguments must match exactly those given to
- * #GNUNET_SERVER_connect_notify.  It is not necessary to call this
- * function during shutdown of the server; in fact, most applications
- * will never use this function.
- *
- * @param server the server manageing the clients
- * @param callback function to call on connect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
-                                    GNUNET_SERVER_ConnectCallback callback,
-                                    void *callback_cls);
-
-
-/**
- * Ask the server to disconnect from the given client.  This is the
- * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
- * except that it allows dropping of a client even when not handling a
- * message from that client.
- *
- * @param client the client to disconnect from
- */
-void
-GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Disable the "CORK" feature for communication with the given client,
- * forcing the OS to immediately flush the buffer on transmission
- * instead of potentially buffering multiple messages.
- *
- * @param client handle to the client
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * The tansmit context is the key datastructure for a conveniance API
- * used for transmission of complex results to the client followed
- * ONLY by signaling receive_done with success or error
- */
-struct GNUNET_SERVER_TransmitContext;
-
-
-/**
- * Create a new transmission context for the given client.
- *
- * @param client client to create the context for.
- * @return NULL on error
- */
-struct GNUNET_SERVER_TransmitContext *
-GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Append a message to the transmission context.
- * All messages in the context will be sent by
- * the #GNUNET_SERVER_transmit_context_run method.
- *
- * @param tc context to use
- * @param data what to append to the result message
- * @param length length of @a data
- * @param type type of the message
- */
-void
-GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext *tc,
-                                            const void *data,
-                                            size_t length, uint16_t type);
-
-
-/**
- * Append a message to the transmission context.
- * All messages in the context will be sent by
- * the transmit_context_run method.
- *
- * @param tc context to use
- * @param msg message to append
- */
-void
-GNUNET_SERVER_transmit_context_append_message (struct GNUNET_SERVER_TransmitContext *tc,
-                                               const struct GNUNET_MessageHeader *msg);
-
-
-/**
- * Execute a transmission context.  If there is an error in the
- * transmission, the receive_done method will be called with an error
- * code (#GNUNET_SYSERR), otherwise with #GNUNET_OK.
- *
- * @param tc transmission context to use
- * @param timeout when to time out and abort the transmission
- */
-void
-GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc,
-                                    struct GNUNET_TIME_Relative timeout);
-
-
-/**
- * Destroy a transmission context.  This function must not be called
- * after #GNUNET_SERVER_transmit_context_run.
- *
- * @param tc transmission context to destroy
- * @param success code to give to #GNUNET_SERVER_receive_done  for
- *        the client: #GNUNET_OK to keep the connection open and
- *                          continue to receive
- *                #GNUNET_NO to close the connection (normal behavior)
- *                #GNUNET_SYSERR to close the connection (signal
- *                          serious error)
- */
-void
-GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext *tc,
-                                        int success);
-
-
-/**
- * The notification context is the key datastructure for a conveniance
- * API used for transmission of notifications to the client until the
- * client disconnects or is disconnected (or the notification context
- * is destroyed, in which case we disconnect these clients).
- * Essentially, all (notification) messages are queued up until the
- * client is able to read them.
- */
-struct GNUNET_SERVER_NotificationContext;
-
-
-/**
- * Create a new notification context.
- *
- * @param server server for which this function creates the context
- * @param queue_length maximum number of messages to keep in
- *        the notification queue; optional messages are dropped
- *        if the queue gets longer than this number of messages
- * @return handle to the notification context
- */
-struct GNUNET_SERVER_NotificationContext *
-GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server,
-                                           unsigned int queue_length);
-
-
-/**
- * Destroy the context, force disconnect for all clients.
- *
- * @param nc context to destroy.
- */
-void
-GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc);
-
-
-/**
- * Add a client to the notification context.
- *
- * @param nc context to modify
- * @param client client to add
- */
-void
-GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc,
-                                        struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Send a message to a particular client; must have
- * already been added to the notification context.
- *
- * @param nc context to modify
- * @param client client to transmit to
- * @param msg message to send
- * @param can_drop can this message be dropped due to queue length limitations
- */
-void
-GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc,
-                                            struct GNUNET_SERVER_Client *client,
-                                            const struct GNUNET_MessageHeader *msg,
-                                            int can_drop);
-
-
-/**
- * Send a message to all clients of this context.
- *
- * @param nc context to modify
- * @param msg message to send
- * @param can_drop can this message be dropped due to queue length limitations
- */
-void
-GNUNET_SERVER_notification_context_broadcast (struct GNUNET_SERVER_NotificationContext *nc,
-                                              const struct GNUNET_MessageHeader *msg,
-                                              int can_drop);
-
-
-/**
- * Return active number of subscribers in this context.
- *
- * @param nc context to query
- * @return number of current subscribers
- */
-unsigned int
-GNUNET_SERVER_notification_context_get_size (struct GNUNET_SERVER_NotificationContext *nc);
-
-
-/**
- * Create a message queue for a server's client.
- *
- * @param client the client
- * @return the message queue
- */
-struct GNUNET_MQ_Handle *
-GNUNET_MQ_queue_for_server_client (struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Handle to a message stream tokenizer.
- */
-struct GNUNET_SERVER_MessageStreamTokenizer;
-
-
-/**
- * Functions with this signature are called whenever a
- * complete message is received by the tokenizer.
- *
- * Do not call #GNUNET_SERVER_mst_destroy from within
- * the scope of this callback.
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
- */
-typedef int
-(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
-                                           void *client,
-                                           const struct GNUNET_MessageHeader *message);
-
-
-/**
- * Create a message stream tokenizer.
- *
- * @param cb function to call on completed messages
- * @param cb_cls closure for @a cb
- * @return handle to tokenizer
- */
-struct GNUNET_SERVER_MessageStreamTokenizer *
-GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
-                          void *cb_cls);
-
-
-/**
- * Add incoming data to the receive buffer and call the
- * callback for all complete messages.
- *
- * @param mst tokenizer to use
- * @param client_identity ID of client for which this is a buffer,
- *        can be NULL (will be passed back to 'cb')
- * @param buf input data to add
- * @param size number of bytes in @a buf
- * @param purge should any excess bytes in the buffer be discarded
- *       (i.e. for packet-based services like UDP)
- * @param one_shot only call callback once, keep rest of message in buffer
- * @return #GNUNET_OK if we are done processing (need more data)
- *         #GNUNET_NO if one_shot was set and we have another message ready
- *         #GNUNET_SYSERR if the data stream is corrupt
- */
-int
-GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
-                           void *client_identity,
-                           const char *buf, size_t size,
-                           int purge, int one_shot);
-
-
-/**
- * Destroys a tokenizer.
- *
- * @param mst tokenizer to destroy
- */
-void
-GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
-
-
-/**
- * Signature of a function to create a custom tokenizer.
- *
- * @param cls closure from #GNUNET_SERVER_set_callbacks
- * @param client handle to client the tokenzier will be used for
- * @return handle to custom tokenizer ('mst')
- */
-typedef void*
-(*GNUNET_SERVER_MstCreateCallback) (void *cls,
-                                    struct GNUNET_SERVER_Client *client);
-
-
-/**
- * Signature of a function to destroy a custom tokenizer.
- *
- * @param cls closure from #GNUNET_SERVER_set_callbacks
- * @param mst custom tokenizer handle
- */
-typedef void
-(*GNUNET_SERVER_MstDestroyCallback) (void *cls,
-                                     void *mst);
-
-
-/**
- * Signature of a function to receive data for a custom tokenizer.
- *
- * @param cls closure from #GNUNET_SERVER_set_callbacks
- * @param mst custom tokenizer handle
- * @param client_identity ID of client for which this is a buffer,
- *        can be NULL (will be passed back to 'cb')
- * @param buf input data to add
- * @param size number of bytes in @a buf
- * @param purge should any excess bytes in the buffer be discarded
- *       (i.e. for packet-based services like UDP)
- * @param one_shot only call callback once, keep rest of message in buffer
- * @return #GNUNET_OK if we are done processing (need more data)
- *         #GNUNET_NO if one_shot was set and we have another message ready
- *         #GNUNET_SYSERR if the data stream is corrupt
- */
-typedef int
-(*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
-                                     struct GNUNET_SERVER_Client *client,
-                                     const char *buf,
-                                     size_t size,
-                                     int purge,
-                                     int one_shot);
-
-
-/**
- * Change functions used by the server to tokenize the message stream.
- * (very rarely used).
- *
- * @param server server to modify
- * @param create new tokenizer initialization function
- * @param destroy new tokenizer destruction function
- * @param receive new tokenizer receive function
- * @param cls closure for @a create, @a receive and @a destroy
- */
-void
-GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
-                             GNUNET_SERVER_MstCreateCallback create,
-                             GNUNET_SERVER_MstDestroyCallback destroy,
-                             GNUNET_SERVER_MstReceiveCallback receive,
-                             void *cls);
-
-
-#if 0                           /* keep Emacsens' auto-indent happy */
-{
-#endif
-#ifdef __cplusplus
-}
-#endif
-
-/* ifndef GNUNET_SERVER_LIB_H */
-#endif
-
-/** @} */  /* end of group server */
-
-/* end of gnunet_server_lib.h */
index 75b8805304abafe6ff96b13f8f8243016693dd86..aacafe9565cec73a1b0d16af77de1151185e1ebb 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2009-2013, 2016 GNUnet e.V.
+     Copyright (C) 2009-2013, 2016, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -44,24 +44,9 @@ extern "C"
 #endif
 
 #include "gnunet_configuration_lib.h"
-#include "gnunet_server_lib.h"
 #include "gnunet_mq_lib.h"
 
 
-/**
- * Function called by the service's run
- * method to run service-specific setup code.
- *
- * @param cls closure
- * @param server the initialized server
- * @param cfg configuration to use
- */
-typedef void
-(*GNUNET_SERVICE_Main) (void *cls,
-                        struct GNUNET_SERVER_Handle *server,
-                        const struct GNUNET_CONFIGURATION_Handle *cfg);
-
-
 /**
  * Options for the service (bitmask).
  */
@@ -88,84 +73,6 @@ enum GNUNET_SERVICE_Options
 };
 
 
-/**
- * Run a standard GNUnet service startup sequence (initialize loggers
- * and configuration, parse options).
- *
- * @param argc number of command line arguments in @a argv
- * @param argv command line arguments
- * @param service_name our service name
- * @param options service options
- * @param task main task of the service
- * @param task_cls closure for @a task
- * @return #GNUNET_SYSERR on error, #GNUNET_OK
- *         if we shutdown nicely
- * @deprecated
- */
-int
-GNUNET_SERVICE_run (int argc,
-                    char *const *argv,
-                   const char *service_name,
-                    enum GNUNET_SERVICE_Options options,
-                   GNUNET_SERVICE_Main task,
-                   void *task_cls);
-
-
-/**
- * Opaque handle for a service.
- */
-struct GNUNET_SERVICE_Context;
-
-
-/**
- * Run a service startup sequence within an existing
- * initialized system.
- *
- * @param service_name our service name
- * @param cfg configuration to use
- * @param options service options
- * @return NULL on error, service handle
- * @deprecated
- */
-struct GNUNET_SERVICE_Context *
-GNUNET_SERVICE_start (const char *service_name,
-                      const struct GNUNET_CONFIGURATION_Handle *cfg,
-                     enum GNUNET_SERVICE_Options options);
-
-
-/**
- * Obtain the server used by a service.  Note that the server must NOT
- * be destroyed by the caller.
- *
- * @param ctx the service context returned from the start function
- * @return handle to the server for this service, NULL if there is none
- * @deprecated
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx);
-
-
-/**
- * Get the NULL-terminated array of listen sockets for this service.
- *
- * @param ctx service context to query
- * @return NULL if there are no listen sockets, otherwise NULL-terminated
- *              array of listen sockets.
- * @deprecated
- */
-struct GNUNET_NETWORK_Handle *const *
-GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx);
-
-
-/**
- * Stop a service that was started with #GNUNET_SERVICE_start.
- *
- * @param sctx the service context returned from the start function
- * @deprecated
- */
-void
-GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx);
-
 
 /* **************** NEW SERVICE API ********************** */
 
@@ -245,7 +152,7 @@ typedef void
  * dropped. Additionally, clients can be dropped at any time using
  * #GNUNET_SERVICE_client_drop().
  *
- * The service must be stopped using #GNUNET_SERVICE_stoP().
+ * The service must be stopped using #GNUNET_SERVICE_stop().
  *
  * @param service_name name of the service to run
  * @param cfg configuration to use
@@ -258,7 +165,7 @@ typedef void
  * @return NULL on error
  */
 struct GNUNET_SERVICE_Handle *
-GNUNET_SERVICE_starT (const char *service_name,
+GNUNET_SERVICE_start (const char *service_name,
                       const struct GNUNET_CONFIGURATION_Handle *cfg,
                       GNUNET_SERVICE_ConnectHandler connect_cb,
                       GNUNET_SERVICE_DisconnectHandler disconnect_cb,
@@ -267,12 +174,12 @@ GNUNET_SERVICE_starT (const char *service_name,
 
 
 /**
- * Stops a service that was started with #GNUNET_SERVICE_starT().
+ * Stops a service that was started with #GNUNET_SERVICE_start().
  *
  * @param srv service to stop
  */
 void
-GNUNET_SERVICE_stoP (struct GNUNET_SERVICE_Handle *srv);
+GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv);
 
 
 /**
@@ -317,7 +224,7 @@ GNUNET_SERVICE_stoP (struct GNUNET_SERVICE_Handle *srv);
  * @return 0 on success, non-zero on error
  */
 int
-GNUNET_SERVICE_ruN_ (int argc,
+GNUNET_SERVICE_run_ (int argc,
                      char *const *argv,
                      const char *service_name,
                      enum GNUNET_SERVICE_Options options,
@@ -393,7 +300,7 @@ GNUNET_SERVICE_ruN_ (int argc,
     struct GNUNET_MQ_MessageHandler mh[] = { \
       __VA_ARGS__ \
     };                       \
-    return GNUNET_SERVICE_ruN_ (argc, \
+    return GNUNET_SERVICE_run_ (argc, \
                                 argv, \
                                 service_name, \
                                 service_options, \
index c03f83e07b15a504f86509a420c949b84cc99731..c196d7767a24ed2fefcde87760006fc157721476 100644 (file)
@@ -181,6 +181,29 @@ struct GNUNET_SQ_QueryParam
 GNUNET_SQ_query_param_uint64 (const uint64_t *x);
 
 
+/**
+ * Execute binding operations for a prepared statement.
+ *
+ * @param db_conn database connection
+ * @param params parameters to the statement
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+GNUNET_SQ_bind (sqlite3_stmt *stmt,
+                const struct GNUNET_SQ_QueryParam *params);
+
+
+/**
+ * Reset @a stmt and log error.
+ *
+ * @param dbh database handle
+ * @param stmt statement to reset
+ */
+void
+GNUNET_SQ_reset (sqlite3 *dbh,
+                 sqlite3_stmt *stmt);
+
+
 /**
  * Extract data from a Postgres database @a result at row @a row.
  *
@@ -399,18 +422,6 @@ struct GNUNET_SQ_ResultSpec
 GNUNET_SQ_result_spec_uint64 (uint64_t *u64);
 
 
-/**
- * Execute a prepared statement.
- *
- * @param db_conn database connection
- * @param params parameters to the statement
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-int
-GNUNET_SQ_bind (sqlite3_stmt *stmt,
-                const struct GNUNET_SQ_QueryParam *params);
-
-
 /**
  * Extract results from a query result according to the given specification.
  *
index 52f5d8ab291f14c5c28601a939be5954d4706066..a9bd6c33fe6b4ac5744605c25a59b387199c57e1 100644 (file)
@@ -38,10 +38,24 @@ extern "C"
 #endif
 #endif
 
+
+/**
+ * Largest supported message (to be precise, one byte more
+ * than the largest possible message, so tests involving
+ * this value should check for messages being smaller than
+ * this value).
+ */
+#define GNUNET_MAX_MESSAGE_SIZE 65536
+
+/**
+ * Smallest supported message.
+ */
+#define GNUNET_MIN_MESSAGE_SIZE sizeof (struct GNUNET_MessageHeader)
+
+
 #include "gnunet_crypto_lib.h"
 #include "gnunet_bandwidth_lib.h"
 #include "gnunet_bio_lib.h"
-#include "gnunet_connection_lib.h"
 #include "gnunet_client_lib.h"
 #include "gnunet_container_lib.h"
 #include "gnunet_getopt_lib.h"
@@ -55,7 +69,6 @@ extern "C"
 #include "gnunet_plugin_lib.h"
 #include "gnunet_program_lib.h"
 #include "gnunet_protocols.h"
-#include "gnunet_server_lib.h"
 #include "gnunet_service_lib.h"
 #include "gnunet_signal_lib.h"
 #include "gnunet_strings_lib.h"
index add58821f77b1c5b77575b5976ea7843ba05cb9d..6095d02588da4d7edf73920ea8cb80c0c80f6865 100644 (file)
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdarg.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <signal.h>
 #include <libgen.h>
index 8d3356cbc7935b50046bff8bcdeedfdc3414e0f5..1be582650718aa0028571062a00d9c7a1dadb340 100644 (file)
@@ -1,5 +1,5 @@
-@INLINE@ ../../contrib/no_forcestart.conf
-@INLINE@ ../../contrib/no_autostart_above_core.conf
+@INLINE@ ../../../contrib/no_forcestart.conf
+@INLINE@ ../../../contrib/no_autostart_above_core.conf
 
 [fs]
 FORCESTART = YES
index a2d1a9608619337120882a3ab330d2c505f2c4d2..c182a02f434952b2c2fdf5bc0d3b8a5f0f5624f1 100644 (file)
@@ -1,6 +1,6 @@
 /*
   This file is part of GNUnet
-  Copyright (C) 2014, 2015, 2016 GNUnet e.V.
+  Copyright (C) 2014-2017 GNUnet e.V.
 
   GNUnet is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
@@ -82,13 +82,78 @@ GNUNET_JSON_parse (const json_t *root,
 void
 GNUNET_JSON_parse_free (struct GNUNET_JSON_Specification *spec)
 {
-  unsigned int i;
-
-  for (i=0;NULL != spec[i].parser;i++)
+  for (unsigned int i=0;NULL != spec[i].parser;i++)
     if (NULL != spec[i].cleaner)
       spec[i].cleaner (spec[i].cls,
                        &spec[i]);
 }
 
 
+/**
+ * Set an option with a JSON value from the command line.
+ * A pointer to this function should be passed as part of the
+ * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
+ * of this type.
+ *
+ * @param ctx command line processing context
+ * @param scls additional closure (will point to the 'json_t *')
+ * @param option name of the option
+ * @param value actual value of the option as a string.
+ * @return #GNUNET_OK if parsing the value worked
+ */
+static int
+set_json (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+          void *scls,
+          const char *option,
+          const char *value)
+{
+  json_t **json = scls;
+  json_error_t error;
+
+  *json = json_loads (value,
+                      JSON_REJECT_DUPLICATES,
+                      &error);
+  if (NULL == *json)
+  {
+    FPRINTF (stderr,
+             _("Failed to parse JSON in option `%s': %s (%s)\n"),
+             option,
+             error.text,
+             error.source);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Allow user to specify a JSON input value.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the JSON specified at the command line
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_JSON_getopt (char shortName,
+                    const char *name,
+                    const char *argumentHelp,
+                    const char *description,
+                    json_t **json)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &set_json,
+    .scls = (void *) json
+  };
+
+  return clo;
+}
+
+
 /* end of json.c */
index d38ca9c021d339adf84be6658fa2b4b392c39de5..43752ec4b825f733fbab0d75e704007c3945772e 100644 (file)
@@ -2,3 +2,4 @@ gnunet-service-multicast
 gnunet-multicast
 test_multicast 
 test_multicast_multipeer
+test_multicast_2peers
index 61821d9730d25dc9bd386038f564df0d75eda89f..1a61abb0954d3bab8335558309d7b1d3c3f50429 100644 (file)
@@ -33,7 +33,8 @@ bin_PROGRAMS = \
  gnunet-multicast
 
 libexec_PROGRAMS = \
- gnunet-service-multicast
+ gnunet-service-multicast \
+ $(EXP_LIBEXEC)
 
 gnunet_multicast_SOURCES = \
  gnunet-multicast.c
@@ -45,17 +46,17 @@ gnunet_service_multicast_SOURCES = \
  gnunet-service-multicast.c
 gnunet_service_multicast_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(GN_LIBINTL)
 
-
 check_PROGRAMS = \
  test_multicast \
- test_multicast_multipeer
+ test_multicast_2peers
+# test_multicast_multipeer
 
 if ENABLE_TEST_RUN
-AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME; export GNUNET_FORCE_LOG=';;;;INFO'
+AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME; export GNUNET_FORCE_LOG=';;;;INFO';
 TESTS = $(check_PROGRAMS)
 endif
 
@@ -66,9 +67,9 @@ test_multicast_LDADD = \
   $(top_builddir)/src/testing/libgnunettesting.la \
   $(top_builddir)/src/util/libgnunetutil.la
 
-test_multicast_multipeer_SOURCE = \
- test_multicast_multipeer.c
-test_multicast_multipeer_LDADD = \
+test_multicast_2peers_SOURCE = \
+ test_multicast_2peers.c
+test_multicast_2peers_LDADD = \
   libgnunetmulticast.la \
   $(top_builddir)/src/testbed/libgnunettestbed.la \
   $(top_builddir)/src/util/libgnunetutil.la
index 3f356af834c6232be9649ac9a2be0bd8869298ed..9683efcff66e4d9edc9d292a627aa7f916c5856a 100644 (file)
@@ -1302,7 +1302,7 @@ cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer)
     GNUNET_MQ_handler_end ()
   };
 
-  chn->channel = GNUNET_CADET_channel_creatE (cadet, chn, &chn->peer,
+  chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer,
                                               &grp->cadet_port_hash,
                                               GNUNET_CADET_OPTION_RELIABLE,
                                               cadet_notify_window_change,
@@ -1392,7 +1392,7 @@ handle_client_origin_start (void *cls,
     };
 
 
-    orig->cadet_port = GNUNET_CADET_open_porT (cadet,
+    orig->cadet_port = GNUNET_CADET_open_port (cadet,
                                                &grp->cadet_port_hash,
                                                cadet_notify_connect,
                                                NULL,
@@ -2085,7 +2085,7 @@ run (void *cls,
   replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
   replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
 
-  cadet = GNUNET_CADET_connecT (cfg);
+  cadet = GNUNET_CADET_connect (cfg);
 
   GNUNET_assert (NULL != cadet);
 
index 675776bbc3bdc5ee79bdcea91632317eafe04715..3081aeecc053a06ba8d70e12d6df738f028582fa 100644 (file)
@@ -1,4 +1,12 @@
+[testbed]
+HOSTNAME = localhost
+
 [arm]
 GLOBAL_POSTFIX=-L ERROR
 
-#PREFIX = sakura -t test-multicast -e cgdb --args
+[multicast]
+#PREFIX = xterm -T peer -e gdb --args
+UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock
+
+[vpn]
+AUTOSTART = NO
diff --git a/src/multicast/test_multicast_2peers.c b/src/multicast/test_multicast_2peers.c
new file mode 100644 (file)
index 0000000..058533e
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * This file is part of GNUnet
+ * Copyright (C) 2013 GNUnet e.V.
+ *
+ * GNUnet is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your
+ * option) any later version.
+ *
+ * GNUnet is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNUnet; see the file COPYING.  If not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file multicast/test_multicast_2peers.c
+ * @brief Tests for the Multicast API with two peers doing the ping
+ *        pong test.
+ * @author xrs
+ */
+
+#include <inttypes.h>
+
+#include "platform.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_common.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include "gnunet_multicast_service.h"
+
+#define NUM_PEERS 2
+
+static struct GNUNET_TESTBED_Operation *op0;
+static struct GNUNET_TESTBED_Operation *op1;
+static struct GNUNET_TESTBED_Operation *pi_op0;
+static struct GNUNET_TESTBED_Operation *pi_op1;
+
+static struct GNUNET_TESTBED_Peer **peers;
+const struct GNUNET_PeerIdentity *peer_id[2];
+
+static struct GNUNET_SCHEDULER_Task *timeout_tid;
+
+static struct GNUNET_MULTICAST_Origin *origin;
+static struct GNUNET_MULTICAST_Member *member;
+
+struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
+struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
+
+struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
+struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
+
+/**
+ * Global result for testcase.
+ */
+static int result;
+
+
+/**
+ * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
+ * Cleans up.
+ */
+static void
+shutdown_task (void *cls)
+{
+  if (NULL != op0)
+  {
+    GNUNET_TESTBED_operation_done (op0);
+    op0 = NULL;
+  }
+  if (NULL != op1)
+  {
+    GNUNET_TESTBED_operation_done (op1);
+    op1 = NULL;
+  }
+  if (NULL != pi_op0)
+  {
+    GNUNET_TESTBED_operation_done (pi_op0);
+    pi_op0 = NULL;
+  }
+  if (NULL != pi_op1)
+  {
+    GNUNET_TESTBED_operation_done (pi_op1);
+    pi_op1 = NULL;
+  }
+  if (NULL != timeout_tid)
+    {
+      GNUNET_SCHEDULER_cancel (timeout_tid);
+      timeout_tid = NULL;
+    }
+}
+
+
+static void
+timeout_task (void *cls)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+             "Timeout!\n");
+  result = GNUNET_SYSERR;
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+
+static void
+member_join_request (void *cls,
+                     const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
+                     const struct GNUNET_MessageHeader *join_msg,
+                     struct GNUNET_MULTICAST_JoinHandle *jh)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Member sent a join request.\n");
+
+}
+
+
+static int
+notify (void *cls,
+        size_t *data_size,
+        void *data)
+{
+
+  char text[] = "ping";
+  *data_size = strlen(text)+1;
+  GNUNET_memcpy(data, text, *data_size);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Member sents message to origin: %s\n", text);
+
+  return GNUNET_YES;
+}
+
+
+static void
+member_join_decision (void *cls,
+                      int is_admitted,
+                      const struct GNUNET_PeerIdentity *peer,
+                      uint16_t relay_count,
+                      const struct GNUNET_PeerIdentity *relays,
+                      const struct GNUNET_MessageHeader *join_msg)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Member received a decision from origin: %s\n",
+              (GNUNET_YES == is_admitted)
+              ? "accepted"
+              : "rejected");
+
+  if (GNUNET_YES == is_admitted)
+  {
+    struct GNUNET_MULTICAST_MemberTransmitHandle *req;
+
+    // FIXME: move to MQ-style API!
+    req = GNUNET_MULTICAST_member_to_origin (member,
+                                             0,
+                                             &notify,
+                                             NULL);
+  }
+}
+
+
+static void
+member_message (void *cls,
+                const struct GNUNET_MULTICAST_MessageHeader *msg)
+{
+  if (0 != strncmp ("pong", (char *)&msg[1], 4))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "member did not receive pong\n");
+    result = GNUNET_SYSERR;
+    GNUNET_SCHEDULER_shutdown ();
+  }
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "member receives: %s\n", (char *)&msg[1]);
+
+  // Testcase ends here.
+  result = GNUNET_YES;
+  GNUNET_SCHEDULER_shutdown ();
+}
+
+static void
+origin_join_request (void *cls,
+                 const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
+                 const struct GNUNET_MessageHeader *join_msg,
+                 struct GNUNET_MULTICAST_JoinHandle *jh)
+{
+  struct GNUNET_MessageHeader *join_resp;
+
+  uint8_t data_size = ntohs (join_msg->size);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "origin got a join request...\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "origin receives: '%s'\n", (char *)&join_msg[1]);
+
+  const char data[] = "Come in!";
+  data_size = strlen (data) + 1;
+  join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
+  join_resp->size = htons (sizeof (join_resp) + data_size);
+  join_resp->type = htons (123);
+  GNUNET_memcpy (&join_resp[1], data, data_size);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "origin sends: '%s'\n", data);
+
+  GNUNET_MULTICAST_join_decision (jh,
+                                  GNUNET_YES,
+                                  0,
+                                  NULL,
+                                  join_resp);
+  GNUNET_free (join_resp);
+  result = GNUNET_OK;
+}
+
+int
+origin_notify (void *cls,
+               size_t *data_size,
+               void *data)
+{
+  char text[] = "pong";
+  *data_size = strlen(text)+1;
+  memcpy(data, text, *data_size);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text);
+
+  return GNUNET_YES;
+}
+
+
+static void
+origin_request (void *cls,
+                const struct GNUNET_MULTICAST_RequestHeader *req)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]);
+
+  if (0 != strncmp ("ping", (char *)&req[1], 4))
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
+
+  GNUNET_MULTICAST_origin_to_all (origin,
+                                  0,
+                                  0,
+                                  origin_notify,
+                                  NULL);
+}
+
+static void
+origin_message (void *cls,
+                const struct GNUNET_MULTICAST_MessageHeader *msg)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
+}
+
+
+static void
+service_connect1 (void *cls,
+                  struct GNUNET_TESTBED_Operation *op,
+                  void *ca_result,
+                  const char *emsg)
+{
+  member = ca_result;
+
+  if (NULL != member)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n");
+  }
+  else
+  {
+    result = GNUNET_SYSERR;
+    GNUNET_SCHEDULER_shutdown ();
+  }
+}
+
+static void
+multicast_da1 (void *cls,
+               void * op_result)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Member parting from multicast group\n");
+
+  GNUNET_MULTICAST_member_part (member, NULL, NULL);
+}
+
+
+static void *
+multicast_ca1 (void *cls,
+               const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  struct GNUNET_MessageHeader *join_msg;
+  void *ret;
+
+  // Get members keys
+  member_key = GNUNET_CRYPTO_ecdsa_key_create ();
+  GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
+
+  char data[] = "Hi, can I enter?";
+  uint8_t data_size = strlen (data) + 1;
+  join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
+  join_msg->size = htons (sizeof (join_msg) + data_size);
+  join_msg->type = htons (123);
+  GNUNET_memcpy (&join_msg[1], data, data_size);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Members tries to join multicast group\n");
+
+  ret = GNUNET_MULTICAST_member_join (cfg,
+                                       &group_pub_key,
+                                       member_key,
+                                       peer_id[0],
+                                       0,
+                                       NULL,
+                                       join_msg, /* join message */
+                                       member_join_request,
+                                       member_join_decision,
+                                       NULL, /* no test for member_replay_frag */
+                                       NULL, /* no test for member_replay_msg */
+                                       member_message,
+                                       NULL);
+  GNUNET_free (join_msg);
+  return ret;
+}
+
+
+static void
+peer_information_cb (void *cls,
+                     struct GNUNET_TESTBED_Operation *op,
+                     const struct GNUNET_TESTBED_PeerInformation *pinfo,
+                     const char *emsg)
+{
+  int i = (int) (long) cls;
+
+  if (NULL == pinfo)
+  {
+    result = GNUNET_SYSERR;
+    GNUNET_SCHEDULER_shutdown ();
+  }
+
+  peer_id[i] = pinfo->result.id;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id));
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Create member peer\n");
+
+  if (0 == i)
+  {
+    /* connect to multicast service of member */
+    op1 = GNUNET_TESTBED_service_connect (NULL,                    /* Closure for operation */
+                                          peers[1],                /* The peer whose service to connect to */
+                                          "multicast",             /* The name of the service */
+                                          service_connect1,   /* callback to call after a handle to service
+                                                                 is opened */
+                                          NULL,                    /* closure for the above callback */
+                                          multicast_ca1,      /* callback to call with peer's configuration;
+                                                                 this should open the needed service connection */
+                                          multicast_da1,     /* callback to be called when closing the
+                                                                opened service connection */
+                                          NULL);                   /* closure for the above two callbacks */
+    }
+}
+
+/**
+ * Test logic of peer "0" being origin starts here.
+ *
+ * @param cls closure, for the example: NULL
+ * @param op should be equal to "dht_op"
+ * @param ca_result result of the connect operation, the
+ *        connection to the DHT service
+ * @param emsg error message, if testbed somehow failed to
+ *        connect to the DHT.
+ */
+static void
+service_connect0 (void *cls,
+                  struct GNUNET_TESTBED_Operation *op,
+                  void *ca_result,
+                  const char *emsg)
+{
+  origin = ca_result;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Connected to multicast service of origin\n");
+
+  // Get GNUnet identity of origin
+  pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0],
+                                               GNUNET_TESTBED_PIT_IDENTITY,
+                                               peer_information_cb,
+                                               (void *) 0);
+  // Get GNUnet identity of member
+  pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1],
+                                               GNUNET_TESTBED_PIT_IDENTITY,
+                                               peer_information_cb,
+                                               (void *) 1);
+
+  /* Connection to service successful. Here we'd usually do something with
+   * the service. */
+  result = GNUNET_OK;
+  //GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
+}
+
+
+
+/**
+ * Function run when service multicast has started and is providing us
+ * with a configuration file.
+ */
+static void *
+multicast_ca0 (void *cls,
+               const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  group_key = GNUNET_CRYPTO_eddsa_key_create ();
+  GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
+
+  return GNUNET_MULTICAST_origin_start (cfg,
+                                        group_key,
+                                        0,
+                                        origin_join_request,
+                                        NULL, /* no test for origin_replay_frag */
+                                        NULL, /* no test for origin_replay_msg */
+                                        origin_request,
+                                        origin_message,
+                                        NULL);
+}
+
+static void
+multicast_da0 (void *cls,
+               void *op_result)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Origin closes multicast group\n");
+
+  GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
+}
+
+
+/**
+ * Main function inovked from TESTBED once all of the
+ * peers are up and running.  This one then connects
+ * just to the multicast service of peer 0 and 1.
+ * Peer 0 is going to be origin.
+ * Peer 1 is going to be one member.
+ * Origin will start a multicast group and the member will try to join it.
+ * After that we execute some multicast test.
+ *
+ * @param cls closure
+ * @param h the run handle
+ * @param peers started peers for the test
+ * @param num_peers size of the 'peers' array
+ * @param links_succeeded number of links between peers that were created
+ * @param links_failed number of links testbed was unable to establish
+ */
+static void
+testbed_master (void *cls,
+     struct GNUNET_TESTBED_RunHandle *h,
+     unsigned int num_peers,
+     struct GNUNET_TESTBED_Peer **p,
+     unsigned int links_succeeded,
+     unsigned int links_failed)
+{
+  /* Testbed is ready with peers running and connected in a pre-defined overlay
+     topology (FIXME)  */
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Connected to testbed_master()\n");
+
+  peers = p;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Create origin peer\n");
+  op0 = GNUNET_TESTBED_service_connect (NULL,                    /* Closure for operation */
+                                        peers[0],                /* The peer whose service to connect to */
+                                        "multicast",             /* The name of the service */
+                                        service_connect0,   /* callback to call after a handle to service
+                                                               is opened */
+                                        NULL,                    /* closure for the above callback */
+                                        multicast_ca0,      /* callback to call with peer's configuration;
+                                                               this should open the needed service connection */
+                                        multicast_da0,     /* callback to be called when closing the
+                                                              opened service connection */
+                                        NULL);                   /* closure for the above two callbacks */
+
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
+
+  /* Schedule the shutdown task with a delay of a few Seconds */
+  timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 50),
+                                             &timeout_task, NULL);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int ret;
+
+  result = GNUNET_SYSERR;
+  ret = GNUNET_TESTBED_test_run
+      ("test-multicast-multipeer",  /* test case name */
+       "test_multicast.conf", /* template configuration */
+       NUM_PEERS,       /* number of peers to start */
+       0LL, /* Event mask - set to 0 for no event notifications */
+       NULL, /* Controller event callback */
+       NULL, /* Closure for controller event callback */
+       testbed_master, /* continuation callback to be called when testbed setup is complete */
+       NULL); /* Closure for the test_master callback */
+  if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
+    return 1;
+  return 0;
+}
+
+/* end of test_multicast_multipeer.c */
index 1b76737f4f90312b0bf1b94ad6bfc1f3cee72af7..58e43d4ba331c3a5474d4235330f7b3bf897e83a 100644 (file)
@@ -107,7 +107,6 @@ shutdown_task (void *cls)
 static void
 timeout_task (void *cls)
 {
-  timeout_tid = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
              "Timeout!\n");
   result = GNUNET_SYSERR;
@@ -126,6 +125,21 @@ member_join_request (void *cls,
 
 }
 
+int notify (void *cls,
+            size_t *data_size,
+            void *data)
+{
+
+  char text[] = "ping";
+  *data_size = strlen(text)+1;
+  GNUNET_memcpy(data, text, *data_size);
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
+              "Member sents message to origin: %s\n", text);
+
+  return GNUNET_YES;
+}
+
 
 static void
 member_join_decision (void *cls,
@@ -135,11 +149,19 @@ member_join_decision (void *cls,
                       const struct GNUNET_PeerIdentity *relays,
                       const struct GNUNET_MessageHeader *join_msg)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+  struct GNUNET_MULTICAST_MemberTransmitHandle *req;
+  
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
               "Member received a decision from origin: %s\n", (GNUNET_YES == is_admitted)?"accepted":"rejected");
-
-  result = GNUNET_OK;
-  GNUNET_SCHEDULER_shutdown ();
+  
+  if (GNUNET_YES == is_admitted)
+  {
+    req = GNUNET_MULTICAST_member_to_origin (member,
+                                             0,
+                                             notify,
+                                             NULL);
+    
+  }
 }
 
 static void
@@ -161,6 +183,10 @@ member_message ()
 {
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "member message...\n");
+
+  // FIXME: not finished here
+  result = GNUNET_YES;
+  GNUNET_SCHEDULER_shutdown ();
 }
 
 static void
@@ -173,20 +199,21 @@ origin_join_request (void *cls,
 
   uint8_t data_size = ntohs (join_msg->size);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Dizzy: Mh, got a join request...\n");
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "'%s'\n", (char *)&join_msg[1]);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Dizzy: Oh, it's Bird! Let's get him in.\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
+              "origin got a join request...\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
+              "origin receives: '%s'\n", (char *)&join_msg[1]);
 
-  char data[] = "Hi, Bird. Come in!";
+  char data[] = "Come in!";
   data_size = strlen (data) + 1;
   join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
   join_resp->size = htons (sizeof (join_resp) + data_size);
   join_resp->type = htons (123);
   GNUNET_memcpy (&join_resp[1], data, data_size);
 
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
+              "origin sends: '%s'\n", data);
+
   GNUNET_MULTICAST_join_decision (jh,
                                   GNUNET_YES,
                                   0,
@@ -198,37 +225,62 @@ origin_join_request (void *cls,
 
 static void
 origin_replay_frag (void *cls,
-                const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
-                uint64_t fragment_id,
-                uint64_t flags,
-                struct GNUNET_MULTICAST_ReplayHandle *rh)
+                    const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
+                    uint64_t fragment_id,
+                    uint64_t flags,
+                    struct GNUNET_MULTICAST_ReplayHandle *rh)
 {
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n");
 }
 
 static void
 origin_replay_msg (void *cls,
-               const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
-               uint64_t message_id,
-               uint64_t fragment_offset,
-               uint64_t flags,
-               struct GNUNET_MULTICAST_ReplayHandle *rh)
+                   const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
+                   uint64_t message_id,
+                   uint64_t fragment_offset,
+                   uint64_t flags,
+                   struct GNUNET_MULTICAST_ReplayHandle *rh) 
 {
 
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n");
 }
 
+
+int
+origin_notify (void *cls, 
+               size_t *data_size, 
+               void *data)
+{
+  char text[] = "pong";
+  *data_size = strlen(text)+1;
+  memcpy(data, text, *data_size); 
+
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text);
+
+  return GNUNET_YES; 
+}
+
+
 static void
 origin_request (void *cls,
-            const struct GNUNET_MULTICAST_RequestHeader *req)
+                const struct GNUNET_MULTICAST_RequestHeader *req)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin request msg\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]);
+  
+  if (0 != strncmp ("ping", (char *)&req[1], 4)) {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
+  }
 
+  GNUNET_MULTICAST_origin_to_all (origin,
+                                  0,
+                                  0,
+                                  origin_notify,
+                                  NULL);
 }
 
 static void
 origin_message (void *cls,
-            const struct GNUNET_MULTICAST_MessageHeader *msg)
+                const struct GNUNET_MULTICAST_MessageHeader *msg) 
 {
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
 }
@@ -268,8 +320,8 @@ multicast_ca1 (void *cls,
   // Get members keys
   member_key = GNUNET_CRYPTO_ecdsa_key_create ();
   GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
-
-  char data[] = "Whut's up, Dizzy!";
+  
+  char data[] = "Hi, can I enter?";
   uint8_t data_size = strlen (data) + 1;
   join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
   join_msg->size = htons (sizeof (join_msg) + data_size);
@@ -453,7 +505,7 @@ testbed_master (void *cls,
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
 
   /* Schedule the shutdown task with a delay of a few Seconds */
-  timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 40),
+  timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 48),
                                              &timeout_task, NULL);
 }
 
index 89d7bffee2823ef974b38f8746bf45ac1f0dd50e..d379b2602ca1a23b4b3052bb9335c725a9b30332 100644 (file)
@@ -121,6 +121,7 @@ libgnunet_plugin_namecache_sqlite_la_SOURCES = \
   plugin_namecache_sqlite.c
 libgnunet_plugin_namecache_sqlite_la_LIBADD = \
   libgnunetnamecache.la  \
+  $(top_builddir)/src/sq/libgnunetsq.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
   $(LTLIBINTL)
@@ -172,4 +173,3 @@ EXTRA_DIST = \
   test_plugin_namecache_sqlite.conf \
   test_plugin_namecache_postgres.conf \
        test_plugin_namecache_flat.conf
-
index 490197b1e90666f87ed573954c64d7e5f87ea96c..2410c9b3c3fb3edc92d9da880d0fa1f41a37ebfe 100644 (file)
@@ -225,13 +225,19 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'n', "name", "NAME",
-     gettext_noop ("name of the record to add/delete/display"), 1,
-     &GNUNET_GETOPT_set_string, &name},
-    {'z', "zone", "PKEY",
-     gettext_noop ("spezifies the public key of the zone to look in"), 1,
-     &GNUNET_GETOPT_set_string, &pkey},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_STRING ('n',
+                                 "name",
+                                 "NAME",
+                                 gettext_noop ("name of the record to add/delete/display"),
+                                 &name),
+
+    GNUNET_GETOPT_OPTION_STRING ('z',
+                                 "zone",
+                                 "PKEY",
+                                 gettext_noop ("spezifies the public key of the zone to look in"),
+                                 &pkey),
+
     GNUNET_GETOPT_OPTION_END
   };
 
index fdce899fa2e3af20d392235958acf97136c120b2..2f7b2a9816c489acf854d72bc0a9b9dfbf7d47d2 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include "platform.h"
+#include "gnunet_sq_lib.h"
 #include "gnunet_namecache_plugin.h"
 #include "gnunet_namecache_service.h"
 #include "gnunet_gnsrecord_lib.h"
@@ -241,25 +242,28 @@ database_setup (struct Plugin *plugin)
   sqlite3_finalize (stmt);
   create_indices (plugin->dbh);
 
-  if ((sq_prepare
-       (plugin->dbh,
-        "INSERT INTO ns096blocks (query,block,expiration_time) VALUES (?, ?, ?)",
-        &plugin->cache_block) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "DELETE FROM ns096blocks WHERE expiration_time<?",
-        &plugin->expire_blocks) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "DELETE FROM ns096blocks WHERE query=? AND expiration_time<=?",
-        &plugin->delete_block) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "SELECT block FROM ns096blocks WHERE query=? ORDER BY expiration_time DESC LIMIT 1",
-        &plugin->lookup_block) != SQLITE_OK)
+  if ( (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "INSERT INTO ns096blocks (query,block,expiration_time) VALUES (?, ?, ?)",
+                    &plugin->cache_block)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "DELETE FROM ns096blocks WHERE expiration_time<?",
+                    &plugin->expire_blocks)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "DELETE FROM ns096blocks WHERE query=? AND expiration_time<=?",
+                    &plugin->delete_block)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT block FROM ns096blocks WHERE query=? "
+                    "ORDER BY expiration_time DESC LIMIT 1",
+                    &plugin->lookup_block) )
       )
   {
-    LOG_SQLITE (plugin,GNUNET_ERROR_TYPE_ERROR, "precompiling");
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR,
+                "precompiling");
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
@@ -319,35 +323,41 @@ static void
 namecache_sqlite_expire_blocks (struct Plugin *plugin)
 {
   struct GNUNET_TIME_Absolute now;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_absolute_time (&now),
+    GNUNET_SQ_query_param_end
+  };
   int n;
 
   now = GNUNET_TIME_absolute_get ();
-  if (SQLITE_OK != sqlite3_bind_int64 (plugin->expire_blocks,
-                                      1, now.abs_value_us))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->expire_blocks,
+                      params))
   {
     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (plugin->expire_blocks))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->expire_blocks);
     return;
   }
   n = sqlite3_step (plugin->expire_blocks);
-  if (SQLITE_OK != sqlite3_reset (plugin->expire_blocks))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->expire_blocks);
   switch (n)
   {
   case SQLITE_DONE:
-    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Records expired\n");
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                     "sqlite",
+                     "Records expired\n");
     return;
   case SQLITE_BUSY:
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
     return;
   default:
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
     return;
   }
@@ -368,8 +378,21 @@ namecache_sqlite_cache_block (void *cls,
   struct Plugin *plugin = cls;
   struct GNUNET_HashCode query;
   struct GNUNET_TIME_Absolute expiration;
-  int64_t dval;
-  size_t block_size;
+  size_t block_size = ntohl (block->purpose.size) +
+    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
+    sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
+  struct GNUNET_SQ_QueryParam del_params[] = {
+    GNUNET_SQ_query_param_auto_from_type (&query),
+    GNUNET_SQ_query_param_absolute_time (&expiration),
+    GNUNET_SQ_query_param_end
+  };
+  struct GNUNET_SQ_QueryParam ins_params[] = {
+    GNUNET_SQ_query_param_auto_from_type (&query),
+    GNUNET_SQ_query_param_fixed_size (block,
+                                      block_size),
+    GNUNET_SQ_query_param_absolute_time (&expiration),
+    GNUNET_SQ_query_param_end
+  };
   int n;
 
   namecache_sqlite_expire_blocks (plugin);
@@ -377,12 +400,6 @@ namecache_sqlite_cache_block (void *cls,
                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
                      &query);
   expiration = GNUNET_TIME_absolute_ntoh (block->expiration_time);
-  dval = (int64_t) expiration.abs_value_us;
-  if (dval < 0)
-    dval = INT64_MAX;
-  block_size = ntohl (block->purpose.size) +
-    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
-    sizeof (struct GNUNET_CRYPTO_EcdsaSignature);
   if (block_size > 64 * 65536)
   {
     GNUNET_break (0);
@@ -390,61 +407,48 @@ namecache_sqlite_cache_block (void *cls,
   }
 
   /* delete old version of the block */
-  if ( (SQLITE_OK !=
-        sqlite3_bind_blob (plugin->delete_block, 1,
-                           &query, sizeof (struct GNUNET_HashCode),
-                           SQLITE_STATIC)) ||
-       (SQLITE_OK !=
-        sqlite3_bind_int64 (plugin->delete_block,
-                            2, dval)) )
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->delete_block,
+                      del_params))
   {
     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (plugin->delete_block))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->delete_block);
     return GNUNET_SYSERR;
   }
   n = sqlite3_step (plugin->delete_block);
   switch (n)
   {
   case SQLITE_DONE:
-    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Old block deleted\n");
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                     "sqlite",
+                     "Old block deleted\n");
     break;
   case SQLITE_BUSY:
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
     break;
   default:
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
     break;
   }
-  if (SQLITE_OK != sqlite3_reset (plugin->delete_block))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-               "sqlite3_reset");
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->delete_block);
 
   /* insert new version of the block */
-  if ((SQLITE_OK !=
-       sqlite3_bind_blob (plugin->cache_block, 1,
-                         &query, sizeof (struct GNUNET_HashCode),
-                         SQLITE_STATIC)) ||
-      (SQLITE_OK !=
-       sqlite3_bind_blob (plugin->cache_block, 2,
-                         block, block_size,
-                         SQLITE_STATIC)) ||
-      (SQLITE_OK !=
-       sqlite3_bind_int64 (plugin->cache_block, 3,
-                          dval)))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->cache_block,
+                      ins_params))
   {
     LOG_SQLITE (plugin,
                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (plugin->cache_block))
-      LOG_SQLITE (plugin,
-                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                 "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->cache_block);
     return GNUNET_SYSERR;
 
   }
@@ -452,9 +456,8 @@ namecache_sqlite_cache_block (void *cls,
              "Caching block under derived key `%s'\n",
              GNUNET_h2s_full (&query));
   n = sqlite3_step (plugin->cache_block);
-  if (SQLITE_OK != sqlite3_reset (plugin->cache_block))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-               "sqlite3_reset");
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->cache_block);
   switch (n)
   {
   case SQLITE_DONE:
@@ -462,11 +465,13 @@ namecache_sqlite_cache_block (void *cls,
         "Record stored\n");
     return GNUNET_OK;
   case SQLITE_BUSY:
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_step");
     return GNUNET_NO;
   default:
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_step");
     return GNUNET_SYSERR;
   }
@@ -486,45 +491,63 @@ namecache_sqlite_cache_block (void *cls,
 static int
 namecache_sqlite_lookup_block (void *cls,
                               const struct GNUNET_HashCode *query,
-                              GNUNET_NAMECACHE_BlockCallback iter, void *iter_cls)
+                              GNUNET_NAMECACHE_BlockCallback iter,
+                               void *iter_cls)
 {
   struct Plugin *plugin = cls;
   int ret;
   int sret;
   size_t block_size;
   const struct GNUNET_GNSRECORD_Block *block;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_auto_from_type (query),
+    GNUNET_SQ_query_param_end
+  };
+  struct GNUNET_SQ_ResultSpec rs[] = {
+    GNUNET_SQ_result_spec_variable_size ((void **) &block,
+                                         &block_size),
+    GNUNET_SQ_result_spec_end
+  };
 
-  if (SQLITE_OK != sqlite3_bind_blob (plugin->lookup_block, 1,
-                                     query, sizeof (struct GNUNET_HashCode),
-                                     SQLITE_STATIC))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->lookup_block,
+                      params))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (plugin->lookup_block))
-      LOG_SQLITE (plugin,
-                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                 "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->lookup_block);
     return GNUNET_SYSERR;
   }
   ret = GNUNET_NO;
-  if (SQLITE_ROW == (sret = sqlite3_step (plugin->lookup_block)))
+  if (SQLITE_ROW ==
+      (sret = sqlite3_step (plugin->lookup_block)))
   {
-    block = sqlite3_column_blob (plugin->lookup_block, 0);
-    block_size = sqlite3_column_bytes (plugin->lookup_block, 0);
-    if ( (block_size < sizeof (struct GNUNET_GNSRECORD_Block)) ||
-        (ntohl (block->purpose.size) +
-         sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
-         sizeof (struct GNUNET_CRYPTO_EcdsaSignature) != block_size) )
+    if (GNUNET_OK !=
+        GNUNET_SQ_extract_result (plugin->lookup_block,
+                                  rs))
     {
       GNUNET_break (0);
       ret = GNUNET_SYSERR;
     }
+    else if ( (block_size < sizeof (struct GNUNET_GNSRECORD_Block)) ||
+              (ntohl (block->purpose.size) +
+               sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) +
+               sizeof (struct GNUNET_CRYPTO_EcdsaSignature) != block_size) )
+    {
+      GNUNET_break (0);
+      GNUNET_SQ_cleanup_result (rs);
+      ret = GNUNET_SYSERR;
+    }
     else
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "Found block under derived key `%s'\n",
                  GNUNET_h2s_full (query));
-      iter (iter_cls, block);
+      iter (iter_cls,
+            block);
+      GNUNET_SQ_cleanup_result (rs);
       ret = GNUNET_YES;
     }
   }
@@ -532,7 +555,9 @@ namecache_sqlite_lookup_block (void *cls,
   {
     if (SQLITE_DONE != sret)
     {
-      LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
+      LOG_SQLITE (plugin,
+                  GNUNET_ERROR_TYPE_ERROR,
+                  "sqlite_step");
       ret = GNUNET_SYSERR;
     }
     else
@@ -542,10 +567,8 @@ namecache_sqlite_lookup_block (void *cls,
                  GNUNET_h2s_full (query));
     }
   }
-  if (SQLITE_OK != sqlite3_reset (plugin->lookup_block))
-    LOG_SQLITE (plugin,
-               GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-               "sqlite3_reset");
+  GNUNET_SQ_reset (plugin->dbh,
+                   plugin->lookup_block);
   return ret;
 }
 
index e9b0f179ac55434e37ddd9479b2491607cb4e634..de46e9c8964e7e5f83856642e496eeec903404b0 100644 (file)
@@ -189,6 +189,7 @@ libgnunet_plugin_namestore_sqlite_la_SOURCES = \
   plugin_namestore_sqlite.c
 libgnunet_plugin_namestore_sqlite_la_LIBADD = \
   $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la  \
+  $(top_builddir)/src/sq/libgnunetsq.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
   $(LTLIBINTL)
index 457e77022ab051ccd6513fb1da21cf1067322aaa..2ce3741f8a1dd33e25be76b8bd2fd73f2181a84b 100644 (file)
@@ -1130,49 +1130,88 @@ main (int argc,
   is_public = -1;
   is_shadow = -1;
 
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'a', "add", NULL,
-     gettext_noop ("add record"), 0,
-     &GNUNET_GETOPT_set_one, &add},
-    {'d', "delete", NULL,
-     gettext_noop ("delete record"), 0,
-     &GNUNET_GETOPT_set_one, &del},
-    {'D', "display", NULL,
-     gettext_noop ("display records"), 0,
-     &GNUNET_GETOPT_set_one, &list},
-    {'e', "expiration", "TIME",
-     gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"), 1,
-     &GNUNET_GETOPT_set_string, &expirationstring},
-    {'i', "nick", "NICKNAME",
-     gettext_noop ("set the desired nick name for the zone"), 1,
-     &GNUNET_GETOPT_set_string, &nickstring},
-    {'m', "monitor", NULL,
-     gettext_noop ("monitor changes in the namestore"), 0,
-     &GNUNET_GETOPT_set_one, &monitor},
-    {'n', "name", "NAME",
-     gettext_noop ("name of the record to add/delete/display"), 1,
-     &GNUNET_GETOPT_set_string, &name},
-    {'r', "reverse", "PKEY",
-     gettext_noop ("determine our name for the given PKEY"), 1,
-     &GNUNET_GETOPT_set_string, &reverse_pkey},
-    {'t', "type", "TYPE",
-     gettext_noop ("type of the record to add/delete/display"), 1,
-     &GNUNET_GETOPT_set_string, &typestring},
-    {'u', "uri", "URI",
-     gettext_noop ("URI to import into our zone"), 1,
-     &GNUNET_GETOPT_set_string, &uri},
-    {'V', "value", "VALUE",
-     gettext_noop ("value of the record to add/delete"), 1,
-     &GNUNET_GETOPT_set_string, &value},
-    {'p', "public", NULL,
-     gettext_noop ("create or list public record"), 0,
-     &GNUNET_GETOPT_set_one, &is_public},
-    {'s', "shadow", NULL,
-     gettext_noop ("create shadow record (only valid if all other records of the same type have expired"), 0,
-     &GNUNET_GETOPT_set_one, &is_shadow},
-    {'z', "zone", "EGO",
-     gettext_noop ("name of the ego controlling the zone"), 1,
-     &GNUNET_GETOPT_set_string, &ego_name},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('a',
+                                  "add",
+                                  gettext_noop ("add record"),
+                                  &add),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                  "delete",
+                                  gettext_noop ("delete record"),
+                                  &del),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('D',
+                                  "display",
+                                  gettext_noop ("display records"),
+                                  &list), 
+
+    GNUNET_GETOPT_OPTION_STRING ('e',
+                                 "expiration",
+                                 "TIME",
+                                 gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"),
+                                 &expirationstring),
+
+    GNUNET_GETOPT_OPTION_STRING ('i',
+                                 "nick",
+                                 "NICKNAME",
+                                 gettext_noop ("set the desired nick name for the zone"),
+                                 &nickstring), 
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('m',
+                                  "monitor",
+                                  gettext_noop ("monitor changes in the namestore"),
+                                  &monitor),
+
+    GNUNET_GETOPT_OPTION_STRING ('n',
+                                 "name",
+                                 "NAME",
+                                 gettext_noop ("name of the record to add/delete/display"),
+                                 &name),
+
+    GNUNET_GETOPT_OPTION_STRING ('r',
+                                 "reverse",
+                                 "PKEY",
+                                 gettext_noop ("determine our name for the given PKEY"),
+                                 &reverse_pkey),
+
+
+
+    GNUNET_GETOPT_OPTION_STRING ('t',
+                                 "type",
+                                 "TYPE",
+                                 gettext_noop ("type of the record to add/delete/display"),
+                                 &typestring),
+
+    GNUNET_GETOPT_OPTION_STRING ('u',
+                                 "uri",
+                                 "URI",
+                                 gettext_noop ("URI to import into our zone"),
+                                 &uri),
+
+    GNUNET_GETOPT_OPTION_STRING ('V',
+                                 "value",
+                                 "VALUE",
+                                 gettext_noop ("value of the record to add/delete"),
+                                 &value),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('p',
+                                  "public",
+                                  gettext_noop ("create or list public record"),
+                                  &is_public),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('s',
+                                  "shadow",
+                                  gettext_noop ("create shadow record (only valid if all other records of the same type have expired"),
+                                  &is_shadow),
+
+    GNUNET_GETOPT_OPTION_STRING ('z',
+                                 "zone",
+                                 "EGO",
+                                 gettext_noop ("name of the ego controlling the zone"),
+                                 &ego_name), 
+
     GNUNET_GETOPT_OPTION_END
   };
 
index ae65802b05aee4c589f62d037eba0ef1adb1ef3d..6cb4290a04b020a3cdf70e7e3b92f983021245a4 100644 (file)
@@ -1136,7 +1136,7 @@ handle_zone_to_name_it (void *cls,
   name_len = (NULL == name) ? 0 : strlen (name) + 1;
   rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
   msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
-  if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (msg_size >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     ztn_ctx->success = GNUNET_SYSERR;
index d64ce10a8c5fe7059923489bb9b5e69533aa32da..5c35335065b41a1bf9b3e4c057b6326d9c06e8ce 100644 (file)
@@ -1,6 +1,6 @@
  /*
   * This file is part of GNUnet
-  * Copyright (C) 2009-2013 GNUnet e.V.
+  * Copyright (C) 2009-2017 GNUnet e.V.
   *
   * GNUnet is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published
@@ -28,6 +28,7 @@
 #include "gnunet_namestore_plugin.h"
 #include "gnunet_namestore_service.h"
 #include "gnunet_gnsrecord_lib.h"
+#include "gnunet_sq_lib.h"
 #include "namestore.h"
 #include <sqlite3.h>
 
@@ -113,16 +114,24 @@ struct Plugin
  * @return 0 on success
  */
 static int
-sq_prepare (sqlite3 * dbh, const char *zSql, sqlite3_stmt ** ppStmt)
+sq_prepare (sqlite3 *dbh,
+            const char *zSql,
+            sqlite3_stmt **ppStmt)
 {
   char *dummy;
   int result;
 
   result =
-      sqlite3_prepare_v2 (dbh, zSql, strlen (zSql), ppStmt,
+      sqlite3_prepare_v2 (dbh,
+                          zSql,
+                          strlen (zSql),
+                          ppStmt,
                           (const char **) &dummy);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Prepared `%s' / %p: %d\n", zSql, *ppStmt, result);
+       "Prepared `%s' / %p: %d\n",
+       zSql,
+       *ppStmt,
+       result);
   return result;
 }
 
@@ -275,38 +284,41 @@ database_setup (struct Plugin *plugin)
 
   create_indices (plugin->dbh);
 
-  if ((sq_prepare
-       (plugin->dbh,
-        "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label)"
-       " VALUES (?, ?, ?, ?, ?, ?)",
-        &plugin->store_records) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "DELETE FROM ns097records WHERE zone_private_key=? AND label=?",
-        &plugin->delete_records) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-        "SELECT record_count,record_data,label"
-       " FROM ns097records WHERE zone_private_key=? AND pkey=?",
-        &plugin->zone_to_name) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-       "SELECT record_count,record_data,label"
-       " FROM ns097records WHERE zone_private_key=? ORDER BY rvalue LIMIT 1 OFFSET ?",
-       &plugin->iterate_zone) != SQLITE_OK) ||
-      (sq_prepare
-       (plugin->dbh,
-       "SELECT record_count,record_data,label,zone_private_key"
-       " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET ?",
-       &plugin->iterate_all_zones) != SQLITE_OK)  ||
-      (sq_prepare
-       (plugin->dbh,
-        "SELECT record_count,record_data,label,zone_private_key"
-        " FROM ns097records WHERE zone_private_key=? AND label=?",
-        &plugin->lookup_label) != SQLITE_OK)
-      )
+  if ( (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "INSERT INTO ns097records (zone_private_key, pkey, rvalue, record_count, record_data, label)"
+                    " VALUES (?, ?, ?, ?, ?, ?)",
+                    &plugin->store_records)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "DELETE FROM ns097records WHERE zone_private_key=? AND label=?",
+                    &plugin->delete_records)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT record_count,record_data,label"
+                    " FROM ns097records WHERE zone_private_key=? AND pkey=?",
+                    &plugin->zone_to_name)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT record_count,record_data,label"
+                    " FROM ns097records WHERE zone_private_key=?"
+                    " ORDER BY rvalue LIMIT 1 OFFSET ?",
+                    &plugin->iterate_zone)) ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT record_count,record_data,label,zone_private_key"
+                    " FROM ns097records ORDER BY rvalue LIMIT 1 OFFSET ?",
+                    &plugin->iterate_all_zones))  ||
+       (SQLITE_OK !=
+        sq_prepare (plugin->dbh,
+                    "SELECT record_count,record_data,label,zone_private_key"
+                    " FROM ns097records WHERE zone_private_key=? AND label=?",
+                    &plugin->lookup_label))
+       )
   {
-    LOG_SQLITE (plugin,GNUNET_ERROR_TYPE_ERROR, "precompiling");
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR,
+                "precompiling");
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
@@ -341,21 +353,30 @@ database_shutdown (struct Plugin *plugin)
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
         _("Tried to close sqlite without finalizing all prepared statements.\n"));
-    stmt = sqlite3_next_stmt (plugin->dbh, NULL);
-    while (stmt != NULL)
+    stmt = sqlite3_next_stmt (plugin->dbh,
+                              NULL);
+    while (NULL != stmt)
     {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite",
-                       "Closing statement %p\n", stmt);
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                       "sqlite",
+                       "Closing statement %p\n",
+                       stmt);
       result = sqlite3_finalize (stmt);
       if (result != SQLITE_OK)
-        GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "sqlite",
-                         "Failed to close statement %p: %d\n", stmt, result);
-      stmt = sqlite3_next_stmt (plugin->dbh, NULL);
+        GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+                         "sqlite",
+                         "Failed to close statement %p: %d\n",
+                         stmt,
+                         result);
+      stmt = sqlite3_next_stmt (plugin->dbh,
+                                NULL);
     }
     result = sqlite3_close (plugin->dbh);
   }
   if (SQLITE_OK != result)
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR,
+                "sqlite3_close");
 
   GNUNET_free_non_null (plugin->fn);
 }
@@ -407,7 +428,13 @@ namestore_sqlite_store_records (void *cls,
     return GNUNET_SYSERR;
   }
   {
+    /* First delete 'old' records */
     char data[data_size];
+    struct GNUNET_SQ_QueryParam dparams[] = {
+      GNUNET_SQ_query_param_auto_from_type (zone_key),
+      GNUNET_SQ_query_param_string (label),
+      GNUNET_SQ_query_param_end
+    };
 
     if (data_size !=
         GNUNET_GNSRECORD_records_serialize (rd_count,
@@ -418,92 +445,71 @@ namestore_sqlite_store_records (void *cls,
       GNUNET_break (0);
       return GNUNET_SYSERR;
     }
-
-    /* First delete 'old' records */
-    if ((SQLITE_OK !=
-         sqlite3_bind_blob (plugin->delete_records,
-                            1,
-                            zone_key,
-                            sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
-                            SQLITE_STATIC)) ||
-       (SQLITE_OK !=
-         sqlite3_bind_text (plugin->delete_records,
-                            2,
-                            label,
-                            -1,
-                            SQLITE_STATIC)))
+    if (GNUNET_OK !=
+        GNUNET_SQ_bind (plugin->delete_records,
+                        dparams))
     {
       LOG_SQLITE (plugin,
                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                  "sqlite3_bind_XXXX");
-      if (SQLITE_OK != sqlite3_reset (plugin->delete_records))
-       LOG_SQLITE (plugin,
-                   GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                   "sqlite3_reset");
+      GNUNET_SQ_reset (plugin->dbh,
+                       plugin->delete_records);
       return GNUNET_SYSERR;
 
     }
     n = sqlite3_step (plugin->delete_records);
-    if (SQLITE_OK != sqlite3_reset (plugin->delete_records))
-      LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                 "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->delete_records);
 
     if (0 != rd_count)
     {
-      if ((SQLITE_OK !=
-           sqlite3_bind_blob (plugin->store_records,
-                              1,
-                              zone_key,
-                              sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
-                              SQLITE_STATIC)) ||
-         (SQLITE_OK !=
-           sqlite3_bind_blob (plugin->store_records,
-                              2,
-                              &pkey,
-                              sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
-                              SQLITE_STATIC)) ||
-         (SQLITE_OK !=
-           sqlite3_bind_int64 (plugin->store_records, 3, rvalue)) ||
-         (SQLITE_OK !=
-           sqlite3_bind_int (plugin->store_records, 4, rd_count)) ||
-         (SQLITE_OK !=
-           sqlite3_bind_blob (plugin->store_records, 5,
-                              data, data_size,
-                              SQLITE_STATIC)) ||
-         (SQLITE_OK !=
-           sqlite3_bind_text (plugin->store_records, 6,
-                              label, -1,
-                              SQLITE_STATIC)))
+      uint32_t rd_count32 = (uint32_t) rd_count;
+      struct GNUNET_SQ_QueryParam sparams[] = {
+        GNUNET_SQ_query_param_auto_from_type (zone_key),
+        GNUNET_SQ_query_param_auto_from_type (&rvalue),
+        GNUNET_SQ_query_param_uint64 (&rvalue),
+        GNUNET_SQ_query_param_uint32 (&rd_count32),
+        GNUNET_SQ_query_param_fixed_size (data, data_size),
+        GNUNET_SQ_query_param_string (label),
+        GNUNET_SQ_query_param_end
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_SQ_bind (plugin->store_records,
+                          sparams))
       {
        LOG_SQLITE (plugin,
                    GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                    "sqlite3_bind_XXXX");
-       if (SQLITE_OK != sqlite3_reset (plugin->store_records))
-         LOG_SQLITE (plugin,
-                     GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                     "sqlite3_reset");
+        GNUNET_SQ_reset (plugin->dbh,
+                         plugin->store_records);
        return GNUNET_SYSERR;
       }
       n = sqlite3_step (plugin->store_records);
-      if (SQLITE_OK != sqlite3_reset (plugin->store_records))
-       LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                   "sqlite3_reset");
+      GNUNET_SQ_reset (plugin->dbh,
+                       plugin->store_records);
     }
   }
   switch (n)
   {
   case SQLITE_DONE:
     if (0 != rd_count)
-      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record stored\n");
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                       "sqlite",
+                       "Record stored\n");
     else
-      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Record deleted\n");
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                       "sqlite",
+                       "Record deleted\n");
     return GNUNET_OK;
   case SQLITE_BUSY:
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_step");
     return GNUNET_NO;
   default:
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_step");
     return GNUNET_SYSERR;
   }
@@ -526,37 +532,47 @@ static int
 get_record_and_call_iterator (struct Plugin *plugin,
                              sqlite3_stmt *stmt,
                              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
-                             GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
+                             GNUNET_NAMESTORE_RecordIterator iter,
+                              void *iter_cls)
 {
-  unsigned int record_count;
+  uint32_t record_count;
   size_t data_size;
-  const char *data;
-  const char *label;
+  void *data;
+  char *label;
+  struct GNUNET_CRYPTO_EcdsaPrivateKey zk;
   int ret;
   int sret;
 
   ret = GNUNET_NO;
   if (SQLITE_ROW == (sret = sqlite3_step (stmt)))
   {
-    record_count = sqlite3_column_int (stmt, 0);
-    data_size = sqlite3_column_bytes (stmt, 1);
-    data = sqlite3_column_blob (stmt, 1);
-    label = (const char*) sqlite3_column_text (stmt, 2);
+    struct GNUNET_SQ_ResultSpec rs[] = {
+      GNUNET_SQ_result_spec_uint32 (&record_count),
+      GNUNET_SQ_result_spec_variable_size (&data, &data_size),
+      GNUNET_SQ_result_spec_string (&label),
+      GNUNET_SQ_result_spec_end
+    };
+    struct GNUNET_SQ_ResultSpec rsx[] = {
+      GNUNET_SQ_result_spec_uint32 (&record_count),
+      GNUNET_SQ_result_spec_variable_size (&data, &data_size),
+      GNUNET_SQ_result_spec_string (&label),
+      GNUNET_SQ_result_spec_auto_from_type (&zk),
+      GNUNET_SQ_result_spec_end
+    };
+
     if (NULL == zone_key)
     {
-      /* must be "iterate_all_zones", got one extra return value */
-      if (sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey) !=
-         sqlite3_column_bytes (stmt, 3))
-      {
-       GNUNET_break (0);
-       ret = GNUNET_SYSERR;
-      }
-      else
-      {
-       zone_key = sqlite3_column_blob (stmt, 3);
-      }
+      zone_key = &zk;
+      ret = GNUNET_SQ_extract_result (stmt,
+                                      rsx);
+    }
+    else
+    {
+      ret = GNUNET_SQ_extract_result (stmt,
+                                      rs);
     }
-    if (record_count > 64 * 1024)
+    if ( (GNUNET_OK != ret) ||
+         (record_count > 64 * 1024) )
     {
       /* sanity check, don't stack allocate far too much just
         because database might contain a large value here */
@@ -568,32 +584,40 @@ get_record_and_call_iterator (struct Plugin *plugin,
       struct GNUNET_GNSRECORD_Data rd[record_count];
 
       if (GNUNET_OK !=
-         GNUNET_GNSRECORD_records_deserialize (data_size, data,
-                                               record_count, rd))
+         GNUNET_GNSRECORD_records_deserialize (data_size,
+                                                data,
+                                               record_count,
+                                                rd))
       {
        GNUNET_break (0);
        ret = GNUNET_SYSERR;
       }
-      else if (NULL != zone_key)
+      else
       {
        if (NULL != iter)
-               iter (iter_cls, zone_key, label, record_count, rd);
+          iter (iter_cls,
+                zone_key,
+                label,
+                record_count,
+                rd);
        ret = GNUNET_YES;
       }
     }
+    GNUNET_SQ_cleanup_result (rs);
   }
   else
   {
     if (SQLITE_DONE != sret)
-      LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
+      LOG_SQLITE (plugin,
+                  GNUNET_ERROR_TYPE_ERROR,
+                  "sqlite_step");
   }
-  if (SQLITE_OK != sqlite3_reset (stmt))
-    LOG_SQLITE (plugin,
-               GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-               "sqlite3_reset");
+  GNUNET_SQ_reset (plugin->dbh,
+                   stmt);
   return ret;
 }
 
+
 /**
  * Lookup records in the datastore for which we are the authority.
  *
@@ -606,37 +630,35 @@ get_record_and_call_iterator (struct Plugin *plugin,
  */
 static int
 namestore_sqlite_lookup_records (void *cls,
-    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, const char *label,
-    GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
+                                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+                                 const char *label,
+                                 GNUNET_NAMESTORE_RecordIterator iter,
+                                 void *iter_cls)
 {
   struct Plugin *plugin = cls;
-  sqlite3_stmt *stmt;
-  int err;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_auto_from_type (zone),
+    GNUNET_SQ_query_param_string (label),
+    GNUNET_SQ_query_param_end
+  };
 
   if (NULL == zone)
-  {
     return GNUNET_SYSERR;
-  }
-  else
-  {
-    stmt = plugin->lookup_label;
-    err = ( (SQLITE_OK != sqlite3_bind_blob (stmt, 1,
-                                             zone, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
-                                             SQLITE_STATIC)) ||
-            (SQLITE_OK != sqlite3_bind_text (stmt, 2,
-                                              label, -1, SQLITE_STATIC)) );
-  }
-  if (err)
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->lookup_label,
+                      params))
   {
     LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                  GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->lookup_label);
     return GNUNET_SYSERR;
   }
-  return get_record_and_call_iterator (plugin, stmt, zone, iter, iter_cls);
+  return get_record_and_call_iterator (plugin,
+                                       plugin->lookup_label,
+                                       zone,
+                                       iter,
+                                       iter_cls);
 }
 
 
@@ -655,7 +677,8 @@ static int
 namestore_sqlite_iterate_records (void *cls,
                                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
                                  uint64_t offset,
-                                 GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
+                                 GNUNET_NAMESTORE_RecordIterator iter,
+                                  void *iter_cls)
 {
   struct Plugin *plugin = cls;
   sqlite3_stmt *stmt;
@@ -663,30 +686,41 @@ namestore_sqlite_iterate_records (void *cls,
 
   if (NULL == zone)
   {
+    struct GNUNET_SQ_QueryParam params[] = {
+      GNUNET_SQ_query_param_uint64 (&offset),
+      GNUNET_SQ_query_param_end
+    };
+
     stmt = plugin->iterate_all_zones;
-    err = (SQLITE_OK != sqlite3_bind_int64 (stmt, 1,
-                                           offset));
+    err = GNUNET_SQ_bind (stmt,
+                          params);
   }
   else
   {
+    struct GNUNET_SQ_QueryParam params[] = {
+      GNUNET_SQ_query_param_auto_from_type (zone),
+      GNUNET_SQ_query_param_uint64 (&offset),
+      GNUNET_SQ_query_param_end
+    };
+
     stmt = plugin->iterate_zone;
-    err = ( (SQLITE_OK != sqlite3_bind_blob (stmt, 1,
-                                            zone, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
-                                            SQLITE_STATIC)) ||
-           (SQLITE_OK != sqlite3_bind_int64 (stmt, 2,
-                                             offset)) );
+    err = GNUNET_SQ_bind (stmt,
+                          params);
   }
-  if (err)
+  if (GNUNET_OK != err)
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                 "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     stmt);
     return GNUNET_SYSERR;
   }
-  return get_record_and_call_iterator (plugin, stmt, zone, iter, iter_cls);
+  return get_record_and_call_iterator (plugin,
+                                       stmt,
+                                       zone,
+                                       iter,
+                                       iter_cls);
 }
 
 
@@ -708,29 +742,31 @@ namestore_sqlite_zone_to_name (void *cls,
                               GNUNET_NAMESTORE_RecordIterator iter, void *iter_cls)
 {
   struct Plugin *plugin = cls;
-  sqlite3_stmt *stmt;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_auto_from_type (zone),
+    GNUNET_SQ_query_param_auto_from_type (value_zone),
+    GNUNET_SQ_query_param_end
+  };
 
-  stmt = plugin->zone_to_name;
-  if ( (SQLITE_OK != sqlite3_bind_blob (stmt, 1,
-                                       zone, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
-                                       SQLITE_STATIC)) ||
-       (SQLITE_OK != sqlite3_bind_blob (stmt, 2,
-                                       value_zone, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
-                                       SQLITE_STATIC)) )
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (plugin->zone_to_name,
+                      params))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin,
-                 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                 "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     plugin->zone_to_name);
     return GNUNET_SYSERR;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Performing reverse lookup for `%s'\n",
        GNUNET_GNSRECORD_z2s (value_zone));
-
-  return get_record_and_call_iterator (plugin, stmt, zone, iter, iter_cls);
+  return get_record_and_call_iterator (plugin,
+                                       plugin->zone_to_name,
+                                       zone,
+                                       iter,
+                                       iter_cls);
 }
 
 
index 19695fabde8bf00540cef9f3d57c23b57088c634..14f3f2330baa163d28645eef869fcae4b5a67ed1 100644 (file)
@@ -37,11 +37,11 @@ lib_LTLIBRARIES = \
 
 libgnunetnatauto_la_SOURCES = \
   nat_auto_api.c \
-  nat_auto_api_test.c 
+  nat_auto_api_test.c
 libgnunetnatauto_la_LIBADD = \
   $(top_builddir)/src/nat/libgnunetnatnew.la \
   $(top_builddir)/src/util/libgnunetutil.la \
-  $(GN_LIBINTL) @EXT_LIBS@ 
+  $(GN_LIBINTL) @EXT_LIBS@
 libgnunetnatauto_la_LDFLAGS = \
   $(GN_LIB_LDFLAGS) $(WINFLAGS) \
   -version-info 0:0:0
@@ -55,4 +55,3 @@ gnunet_service_nat_auto_LDADD = \
   $(LIBGCRYPT_LIBS) \
   -lgcrypt \
   $(GN_LIBINTL)
-
index 9ba81eb5f17f379bd1eddb5be49cf02a09122289..8b281d1ab648ec15d39654acdf7041687b53fe7b 100644 (file)
@@ -63,7 +63,7 @@ static char *section_name;
 /**
  * Should we run autoconfiguration?
  */
-static unsigned int do_auto;
+static int do_auto;
 
 /**
  * Handle to a NAT test operation.
@@ -174,6 +174,9 @@ auto_config_cb (void *cls,
              GNUNET_NAT_AUTO_status2string (result),
              nat_type);
 
+  if (NULL == diff)
+    return;
+
   /* Shortcut: if there are no changes suggested, bail out early. */
   if (GNUNET_NO ==
       GNUNET_CONFIGURATION_is_dirty (diff))
@@ -186,20 +189,16 @@ auto_config_cb (void *cls,
      to the user */
   new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL;
 
-  if (NULL != diff)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
-               _("Suggested configuration changes:\n"));
-    GNUNET_CONFIGURATION_iterate_section_values (diff,
-                                                "nat",
-                                                &auto_conf_iter,
-                                                new_cfg);
-  }
+  GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+              _("Suggested configuration changes:\n"));
+  GNUNET_CONFIGURATION_iterate_section_values (diff,
+                                               "nat",
+                                               &auto_conf_iter,
+                                               new_cfg);
 
   /* If desired, write configuration to file; we write only the
      changes to the defaults to keep things compact. */
-  if ( (write_cfg) &&
-       (NULL != diff) )
+  if (write_cfg)
   {
     struct GNUNET_CONFIGURATION_Handle *def_cfg;
 
@@ -298,8 +297,8 @@ run (void *cls,
   if (do_auto)
   {
     ah = GNUNET_NAT_AUTO_autoconfig_start (c,
-                                     &auto_config_cb,
-                                     NULL);
+                                           &auto_config_cb,
+                                           NULL);
   }
 
   if (use_tcp && use_udp)
@@ -340,22 +339,32 @@ int
 main (int argc,
       char *const argv[])
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'a', "auto", NULL,
-     gettext_noop ("run autoconfiguration"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &do_auto },
-    {'S', "section", "NAME",
-     gettext_noop ("section name providing the configuration for the adapter"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &section_name },
-    {'t', "tcp", NULL,
-     gettext_noop ("use TCP"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp },
-    {'u', "udp", NULL,
-     gettext_noop ("use UDP"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp },
-    {'w', "write", NULL,
-     gettext_noop ("write configuration file (for autoconfiguration)"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &write_cfg },
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('a',
+                                  "auto",
+                                  gettext_noop ("run autoconfiguration"),
+                                  &do_auto),
+
+    GNUNET_GETOPT_OPTION_STRING ('S',
+                                 "section",
+                                 "NAME",
+                                 gettext_noop ("section name providing the configuration for the adapter"),
+                                 &section_name),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('t',
+                                   "tcp",
+                                   gettext_noop ("use TCP"),
+                                   &use_tcp),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('u',
+                                   "udp",
+                                   gettext_noop ("use UDP"),
+                                   &use_udp),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('w',
+                                   "write",
+                                   gettext_noop ("write configuration file (for autoconfiguration)"),
+                                   &write_cfg),
     GNUNET_GETOPT_OPTION_END
   };
 
index 371e4b27e4201dfe71fd97b1325350985aeabb85..590fad4d69dd17556ba22958c318f90591c4a68e 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2011 GNUnet e.V.
+     Copyright (C) 2011, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
 
 /**
- * Our server.
+ * Information we track per client.
  */
-static struct GNUNET_SERVER_Handle *server;
+struct ClientData
+{
+  /**
+   * Timeout task.
+   */
+  struct GNUNET_SCHEDULER_Task *tt;
+
+  /**
+   * Client handle.
+   */
+  struct GNUNET_SERVICE_Client *client;
+};
+
 
 /**
  * Our configuration.
@@ -248,21 +260,18 @@ try_send_udp (uint32_t dst_ipv4,
  * We've received a request to probe a NAT
  * traversal. Do it.
  *
- * @param cls unused
- * @param client handle to client (we always close)
+ * @param cls handle to client (we always close)
  * @param msg message with details about what to test
  */
 static void
-test (void *cls,
-      struct GNUNET_SERVER_Client *client,
-      const struct GNUNET_MessageHeader *msg)
+handle_test (void *cls,
+             const struct GNUNET_NAT_AUTO_TestMessage *tm)
 {
-  const struct GNUNET_NAT_AUTO_TestMessage *tm;
+  struct ClientData *cd = cls;
   uint16_t dport;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received test request\n");
-  tm = (const struct GNUNET_NAT_AUTO_TestMessage *) msg;
   dport = ntohs (tm->dport);
   if (0 == dport)
     try_anat (tm->dst_ipv4,
@@ -276,126 +285,119 @@ test (void *cls,
     try_send_udp (tm->dst_ipv4,
                   dport,
                   tm->data);
-  GNUNET_SERVER_receive_done (client,
-                              GNUNET_NO);
+  GNUNET_SERVICE_client_drop (cd->client);
 }
 
 
 /**
- * Task run during shutdown.
+ * Main function that will be run.
  *
- * @param cls unused
+ * @param cls closure
+ * @param c configuration
+ * @param srv service handle
  */
 static void
-shutdown_task (void *cls)
+run (void *cls,
+     const struct GNUNET_CONFIGURATION_Handle *c,
+     struct GNUNET_SERVICE_Handle *srv)
 {
-  GNUNET_SERVER_destroy (server);
-  server = NULL;
+  cfg = c;
 }
 
 
 /**
- * Main function that will be run.
+ * Forcefully drops client after 1s.
  *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param c configuration
+ * @param cls our `struct ClientData` of a client to drop
  */
 static void
-run (void *cls,
-     char *const *args,
-     const char *cfgfile,
-     const struct GNUNET_CONFIGURATION_Handle *c)
+force_timeout (void *cls)
 {
-  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
-    {&test, NULL, GNUNET_MESSAGE_TYPE_NAT_TEST,
-     sizeof (struct GNUNET_NAT_AUTO_TestMessage)},
-    {NULL, NULL, 0, 0}
-  };
-  unsigned int port;
-  struct sockaddr_in in4;
-  struct sockaddr_in6 in6;
-
-  socklen_t slen[] = {
-    sizeof (in4),
-    sizeof (in6),
-    0
-  };
-  struct sockaddr *sa[] = {
-    (struct sockaddr *) &in4,
-    (struct sockaddr *) &in6,
-    NULL
-  };
+  struct ClientData *cd = cls;
 
-  cfg = c;
-  if ( (NULL == args[0]) ||
-       (1 != SSCANF (args[0], "%u", &port)) ||
-       (0 == port) ||
-       (65536 <= port) )
-  {
-    FPRINTF (stderr,
-             _("Please pass valid port number as the first argument! (got `%s')\n"),
-             args[0]);
-    return;
-  }
-  memset (&in4, 0, sizeof (in4));
-  memset (&in6, 0, sizeof (in6));
-  in4.sin_family = AF_INET;
-  in4.sin_port = htons ((uint16_t) port);
-  in6.sin6_family = AF_INET6;
-  in6.sin6_port = htons ((uint16_t) port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  in4.sin_len = sizeof (in4);
-  in6.sin6_len = sizeof (in6);
-#endif
-  server = GNUNET_SERVER_create (NULL,
-                                NULL,
-                                (struct sockaddr * const *) sa,
-                                slen,
-                                GNUNET_TIME_UNIT_SECONDS,
-                                GNUNET_YES);
-  GNUNET_SERVER_add_handlers (server,
-                             handlers);
-  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
-                                NULL);
+  cd->tt = NULL;
+  GNUNET_SERVICE_client_drop (cd->client);
 }
 
 
+
 /**
- * Main function of gnunet-nat-server.
+ * Callback called when a client connects to the service.
  *
- * @param argc number of command-line arguments
- * @param argv command line
- * @return 0 on success, -1 on error
+ * @param cls closure for the service
+ * @param c the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return our `struct ClientData`
  */
-int
-main (int argc, char *const argv[])
+static void *
+client_connect_cb (void *cls,
+                  struct GNUNET_SERVICE_Client *c,
+                  struct GNUNET_MQ_Handle *mq)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    GNUNET_GETOPT_OPTION_END
-  };
-
-  if (GNUNET_OK !=
-      GNUNET_STRINGS_get_utf8_args (argc, argv,
-                                   &argc, &argv))
-    return 2;
-
-  if (GNUNET_OK !=
-      GNUNET_PROGRAM_run (argc,
-                         argv,
-                         "gnunet-nat-server [options] PORT",
-                          _("GNUnet NAT traversal test helper daemon"),
-                         options,
-                          &run,
-                         NULL))
-  {
-    GNUNET_free ((void*) argv);
-    return 1;
-  }
-  GNUNET_free ((void*) argv);
-  return 0;
+  struct ClientData *cd;
+
+  cd = GNUNET_new (struct ClientData);
+  cd->client = c;
+  cd->tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+                                         &force_timeout,
+                                         cd);
+  return cd;
+}
+
+
+/**
+ * Callback called when a client disconnected from the service
+ *
+ * @param cls closure for the service
+ * @param c the client that disconnected
+ * @param internal_cls our `struct ClientData`
+ */
+static void
+client_disconnect_cb (void *cls,
+                     struct GNUNET_SERVICE_Client *c,
+                     void *internal_cls)
+{
+  struct ClientData *cd = internal_cls;
+
+  if (NULL != cd->tt)
+    GNUNET_SCHEDULER_cancel (cd->tt);
+  GNUNET_free (cd);
 }
 
 
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("nat-server",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_fixed_size (test,
+                         GNUNET_MESSAGE_TYPE_NAT_TEST,
+                         struct GNUNET_NAT_AUTO_TestMessage,
+                         NULL),
+ GNUNET_MQ_handler_end ());
+
+
+#if defined(LINUX) && defined(__GLIBC__)
+#include <malloc.h>
+
+/**
+ * MINIMIZE heap size (way below 128k) since this process doesn't need much.
+ */
+void __attribute__ ((constructor))
+GNUNET_ARM_memory_init ()
+{
+  mallopt (M_TRIM_THRESHOLD, 4 * 1024);
+  mallopt (M_TOP_PAD, 1 * 1024);
+  malloc_trim (0);
+}
+#endif
+
+
+
+
 /* end of gnunet-nat-server.c */
index 6660239c3f41d62df521f9691936b794e41faacf..8a7eaf2640035bad34463b1d56a039ebf6205b93 100644 (file)
@@ -224,7 +224,7 @@ GNUNET_NAT_AUTO_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
 
   buf = GNUNET_CONFIGURATION_serialize (cfg,
                                        &size);
-  if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*req))
+  if (size > GNUNET_MAX_MESSAGE_SIZE - sizeof (*req))
   {
     GNUNET_break (0);
     GNUNET_free (buf);
index 80bfb5726d83ea28fcec10025785a47ed6a26386..50e0dff0f7ecb9cebb17b2022132f1c2e504b135 100644 (file)
@@ -34,9 +34,9 @@
 static int global_ret;
 
 /**
- * Name of section in configuration file to use for 
+ * Name of section in configuration file to use for
  * additional options.
- */ 
+ */
 static char *section_name;
 
 /**
@@ -72,7 +72,7 @@ static char *remote_addr;
 /**
  * Should we actually bind to #bind_addr and receive and process STUN requests?
  */
-static unsigned int do_stun;
+static int do_stun;
 
 /**
  * Handle to NAT operation.
@@ -81,7 +81,7 @@ static struct GNUNET_NAT_Handle *nh;
 
 /**
  * Listen socket for STUN processing.
- */ 
+ */
 static struct GNUNET_NETWORK_Handle *ls;
 
 /**
@@ -110,7 +110,7 @@ test_finished ()
  * a function to call whenever our set of 'valid' addresses changes.
  *
  * @param cls closure, NULL
- * @param add_remove #GNUNET_YES to add a new public IP address, 
+ * @param add_remove #GNUNET_YES to add a new public IP address,
  *                   #GNUNET_NO to remove a previous (now invalid) one
  * @param ac address class the address belongs to
  * @param addr either the previous or the new public IP address
@@ -123,12 +123,12 @@ address_cb (void *cls,
            const struct sockaddr *addr,
            socklen_t addrlen)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
-             "%s %s (%d)\n",
-             add_remove ? "+" : "-",
-             GNUNET_a2s (addr,
-                         addrlen),
-             (int) ac);
+  fprintf (stdout,
+           "%s %s (%d)\n",
+           add_remove ? "+" : "-",
+           GNUNET_a2s (addr,
+                       addrlen),
+           (int) ac);
 }
 
 
@@ -186,7 +186,7 @@ static void
 stun_read_task (void *cls)
 {
   ssize_t size;
-  
+
   rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                         ls,
                                         &stun_read_task,
@@ -204,7 +204,7 @@ stun_read_task (void *cls)
     struct sockaddr_storage sa;
     socklen_t salen = sizeof (sa);
     ssize_t ret;
-    
+
     ret = GNUNET_NETWORK_socket_recvfrom (ls,
                                          buf,
                                          size + 1,
@@ -269,6 +269,10 @@ run (void *cls,
     global_ret = 1;
     return;
   }
+  local_len = 0;
+  local_sa = NULL;
+  remote_len = 0;
+  remote_sa = NULL;
   if (NULL != local_addr)
   {
     local_len = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr,
@@ -279,13 +283,10 @@ run (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
                  "Invalid socket address `%s'\n",
                  local_addr);
-      global_ret = 1;
-      return;
+      goto fail_and_shutdown;
     }
   }
 
-  remote_len = 0;
-
   if (NULL != remote_addr)
   {
     remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr,
@@ -296,8 +297,7 @@ run (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
                  "Invalid socket address `%s'\n",
                  remote_addr);
-      global_ret = 1;
-      return;
+      goto fail_and_shutdown;
     }
   }
 
@@ -318,32 +318,26 @@ run (void *cls,
   else if (listen_reversal)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
-               "Use of `-W` only effective in combination with `-i`\n");    
-    global_ret = 1;
-    GNUNET_SCHEDULER_shutdown ();
-    return;
+               "Use of `-W` only effective in combination with `-i`\n");
+    goto fail_and_shutdown;
   }
 
   if (NULL != remote_addr)
   {
     int ret;
-    
+
     if ( (NULL == nh) ||
         (sizeof (struct sockaddr_in) != local_len) )
     {
       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
                  "Require IPv4 local address to initiate connection reversal\n");
-      global_ret = 1;
-      GNUNET_SCHEDULER_shutdown ();
-      return;
+      goto fail_and_shutdown;
     }
     if (sizeof (struct sockaddr_in) != remote_len)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
                  "Require IPv4 reversal target address\n");
-      global_ret = 1;
-      GNUNET_SCHEDULER_shutdown ();
-      return;
+      goto fail_and_shutdown;
     }
     GNUNET_assert (AF_INET == local_sa->sa_family);
     GNUNET_assert (AF_INET == remote_sa->sa_family);
@@ -365,24 +359,20 @@ run (void *cls,
       break;
     }
   }
-  
+
   if (do_stun)
   {
     if (NULL == local_addr)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
                  "Require local address to support STUN requests\n");
-      global_ret = 1;
-      GNUNET_SCHEDULER_shutdown ();
-      return;
+      goto fail_and_shutdown;
     }
     if (IPPROTO_UDP != proto)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
                  "STUN only supported over UDP\n");
-      global_ret = 1;
-      GNUNET_SCHEDULER_shutdown ();
-      return;
+      goto fail_and_shutdown;
     }
     ls = GNUNET_NETWORK_socket_create (af,
                                       SOCK_DGRAM,
@@ -397,17 +387,22 @@ run (void *cls,
                  GNUNET_a2s (local_sa,
                              local_len),
                  STRERROR (errno));
-      global_ret = 1;
-      GNUNET_SCHEDULER_shutdown ();
-      return;
+      goto fail_and_shutdown;
     }
     rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
                                           ls,
                                           &stun_read_task,
                                           NULL);
   }
-
+  GNUNET_free_non_null (remote_sa);
+  GNUNET_free_non_null (local_sa);
   test_finished ();
+  return;
+ fail_and_shutdown:
+  global_ret = 1;
+  GNUNET_SCHEDULER_shutdown ();
+  GNUNET_free_non_null (remote_sa);
+  GNUNET_free_non_null (local_sa);
 }
 
 
@@ -422,29 +417,46 @@ int
 main (int argc,
       char *const argv[])
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'i', "in", "ADDRESS",
-     gettext_noop ("which IP and port are we locally using to bind/listen to"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr },
-    {'r', "remote", "ADDRESS",
-     gettext_noop ("which remote IP and port should be asked for connection reversal"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr },
-    {'S', "section", NULL,
-     gettext_noop ("name of configuration section to find additional options, such as manual host punching data"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &section_name },
-    {'s', "stun", NULL,
-     gettext_noop ("enable STUN processing"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &do_stun },
-    {'t', "tcp", NULL,
-     gettext_noop ("use TCP"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp },
-    {'u', "udp", NULL,
-     gettext_noop ("use UDP"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp },
-    {'W', "watch", NULL,
-     gettext_noop ("watch for connection reversal requests"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal },
-   GNUNET_GETOPT_OPTION_END
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_STRING ('i',
+                                 "in",
+                                 "ADDRESS",
+                                 gettext_noop ("which IP and port are we locally using to bind/listen to"),
+                                 &local_addr),
+
+    GNUNET_GETOPT_OPTION_STRING ('r',
+                                 "remote",
+                                 "ADDRESS",
+                                 gettext_noop ("which remote IP and port should be asked for connection reversal"),
+                                 &remote_addr),
+
+    GNUNET_GETOPT_OPTION_STRING ('S',
+                                 "section",
+                                 NULL,
+                                 gettext_noop ("name of configuration section to find additional options, such as manual host punching data"),
+                                 &section_name),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('s',
+                                  "stun",
+                                  gettext_noop ("enable STUN processing"),
+                                  &do_stun),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('t',
+                                  "tcp",
+                                  gettext_noop ("use TCP"),
+                                  &use_tcp),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('u',
+                                  "udp",
+                                  gettext_noop ("use UDP"),
+                                  &use_udp),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('W',
+                                  "watch",
+                                  gettext_noop ("watch for connection reversal requests"),
+                                  &listen_reversal),
+    GNUNET_GETOPT_OPTION_END
   };
 
   if (GNUNET_OK !=
index bfe212308b7cb8f2220d086fb815bc92dbfd62e0..0695c7ac70b63a9ab1ad88844841e2580b74d4c5 100644 (file)
@@ -662,6 +662,11 @@ notify_client (enum GNUNET_NAT_AddressClass ac,
   struct GNUNET_MQ_Envelope *env;
   struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Notifying client about %s of IP %s\n",
+              add ? "addition" : "removal",
+              GNUNET_a2s (addr,
+                          addr_len));
   env = GNUNET_MQ_msg_extra (msg,
                             addr_len,
                             GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
@@ -693,7 +698,11 @@ check_notify_client (struct LocalAddressList *delta,
   struct sockaddr_in6 v6;
 
   if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Not notifying client as it does not care about addresses\n");
     return;
+  }
   switch (delta->af)
   {
   case AF_INET:
@@ -715,25 +724,24 @@ check_notify_client (struct LocalAddressList *delta,
           (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
        continue; /* bound to loopback, but this is not loopback */
       if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
-          (0 != c4->sin_addr.s_addr) &&
           match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
        continue; /* bound to non-loopback, but this is loopback */
-      if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
-          (0 != c4->sin_addr.s_addr) &&
-          (! is_nat_v4 (&v4.sin_addr)) )
-       continue; /* based on external-IP, but this IP is not
-                    from private address range. */
+      if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
+           (0 != c4->sin_addr.s_addr) &&
+           (! is_nat_v4 (&v4.sin_addr)) )
+       continue; /* based on external-IP, but this IP is not
+                    from private address range. */
       if ( (0 != memcmp (&v4.sin_addr,
-                        &c4->sin_addr,
-                        sizeof (struct in_addr))) &&
-          (0 != c4->sin_addr.s_addr) &&
-          ( (! is_nat_v4 (&c4->sin_addr)) ||
-            (0 == (ch->flags & GNUNET_NAT_AC_EXTERN))) )
+                         &c4->sin_addr,
+                         sizeof (struct in_addr))) &&
+           (0 != c4->sin_addr.s_addr) &&
+           (! is_nat_v4 (&c4->sin_addr)) )
        continue; /* this IP is not from private address range,
                     and IP does not match. */
 
       /* OK, IP seems relevant, notify client */
-      v4.sin_port = c4->sin_port;
+      if (0 == htons (v4.sin_port))
+        v4.sin_port = c4->sin_port;
       notify_client (delta->ac,
                     ch,
                     add,
@@ -760,13 +768,10 @@ check_notify_client (struct LocalAddressList *delta,
           (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
        continue; /* bound to loopback, but this is not loopback */
       if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
-          (0 != memcmp (&c6->sin6_addr,
-                        &in6addr_any,
-                        sizeof (struct in6_addr))) &&
           match_ipv6 ("::1", &v6.sin6_addr, 128) )
        continue; /* bound to non-loopback, but this is loopback */
-      if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
-          (0 != memcmp (&c6->sin6_addr,
+      if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
+           (0 != memcmp (&c6->sin6_addr,
                         &in6addr_any,
                         sizeof (struct in6_addr))) &&
           (! is_nat_v6 (&v6.sin6_addr)) )
@@ -793,7 +798,8 @@ check_notify_client (struct LocalAddressList *delta,
                     does not match and is not an external IP */
 
       /* OK, IP seems relevant, notify client */
-      v6.sin6_port = c6->sin6_port;
+      if (0 == htons (v6.sin6_port))
+        v6.sin6_port = c6->sin6_port;
       notify_client (delta->ac,
                     ch,
                     add,
@@ -853,6 +859,10 @@ notify_client_external_ipv4_change (void *cls,
     struct LocalAddressList lal;
     struct sockaddr_in *s4;
 
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
+                (unsigned int) ch->ext_dns_port,
+                ch->section_name);
     memset (&lal, 0, sizeof (lal));
     s4 = (struct sockaddr_in *) &lal.addr;
     s4->sin_family = AF_INET;
@@ -868,8 +878,6 @@ notify_client_external_ipv4_change (void *cls,
   /* (1) check if client cares. */
   if (! ch->natted_address)
     return;
-  if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags))
-    return;
   have_v4 = GNUNET_NO;
   for (unsigned int i=0;i<ch->num_caddrs;i++)
   {
@@ -891,6 +899,10 @@ notify_client_external_ipv4_change (void *cls,
   sa.sin_addr = *v4;
   sa.sin_port = htons (0);
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Detected eternal IP %s, notifying client of external IP (without port)\n",
+              GNUNET_a2s ((const struct sockaddr *) &sa,
+                          sizeof (sa)));
   /* (3) notify client of change */
   notify_client (is_nat_v4 (v4)
                 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
@@ -1055,7 +1067,8 @@ run_scan (void *cls)
 
        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                    "Found NATed local address %s, starting NAT server\n",
-                   GNUNET_a2s ((void *) &pos->addr, sizeof (*s4)));
+                   GNUNET_a2s ((const struct sockaddr *) &pos->addr,
+                                sizeof (*s4)));
        pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
                                               &reversal_callback,
                                               pos);
@@ -1280,6 +1293,11 @@ dyndns_lookup (void *cls)
   struct ClientHandle *ch = cls;
   struct LocalAddressList *lal;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
+              ch->section_name,
+              ch->hole_external,
+              (unsigned int) ch->ext_dns_port);
   for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
     lal->old = GNUNET_YES;
   ch->ext_dns_task = NULL;
@@ -1374,6 +1392,11 @@ lookup_hole_external (struct ClientHandle *ch)
                      ch->hole_external,
                      &s4->sin_addr))
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "IPv4 punched hole given for `%s' via `%s:%u'\n",
+                ch->section_name,
+                ch->hole_external,
+                (unsigned int) ch->ext_dns_port);
     s4->sin_port = htons (ch->ext_dns_port);
     lal->af = AF_INET;
     lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
@@ -1423,8 +1446,6 @@ handle_register (void *cls,
     GNUNET_SERVICE_client_drop (ch->client);
     return;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-             "Received REGISTER message from client\n");
   ch->flags = message->flags;
   ch->proto = message->proto;
   ch->num_caddrs = ntohs (message->num_addrs);
@@ -1512,6 +1533,9 @@ handle_register (void *cls,
   ch->section_name
     = GNUNET_strndup (off,
                      ntohs (message->str_len));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received REGISTER message from client for subsystem `%s'\n",
+              ch->section_name);
   if (GNUNET_OK ==
       GNUNET_CONFIGURATION_get_value_string (cfg,
                                             ch->section_name,
index 8df6f48a5381a3d3d89bd397bab5c6af9f94291a..f79ff407073b8af4f40299dfc61eb6197ad592b7 100644 (file)
@@ -182,6 +182,7 @@ handle_external_ip (void *cls,
   switch (result)
   {
   case GNUNET_NAT_ERROR_SUCCESS:
+    GNUNET_assert (NULL != addr);
     if (addr->s_addr == mini_external_ipv4.s_addr)
       return; /* not change */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
index e91f63beb3f39e6bd15980ced7872af26d018a80..de6531fa88b10da6a966ed62b3a4cd54df8e08a3 100644 (file)
@@ -221,6 +221,26 @@ restart_nat_server (void *cls)
   char ia[INET_ADDRSTRLEN];
 
   h->server_read_task = NULL;
+  GNUNET_assert (NULL !=
+                inet_ntop (AF_INET,
+                           &h->internal_address,
+                           ia,
+                           sizeof (ia)));
+  /* Start the server process */
+  binary
+    = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
+  if (GNUNET_YES !=
+      GNUNET_OS_check_helper_binary (binary,
+                                     GNUNET_YES,
+                                     ia))
+  {
+    /* move instantly to max delay, as this is unlikely to be fixed */
+    h->server_retry_delay
+      = GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD;
+    GNUNET_free (binary);
+    try_again (h);
+    return;
+  }
   h->server_stdout
     = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES,
                        GNUNET_NO, GNUNET_YES);
@@ -228,21 +248,14 @@ restart_nat_server (void *cls)
   {
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
                         "pipe");
+    GNUNET_free (binary);
     try_again (h);
     return;
   }
-  GNUNET_assert (NULL !=
-                inet_ntop (AF_INET,
-                           &h->internal_address,
-                           ia,
-                           sizeof (ia)));
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Starting `%s' at `%s'\n",
              "gnunet-helper-nat-server",
              ia);
-  /* Start the server process */
-  binary
-    = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
   h->server_proc
     = GNUNET_OS_start_process (GNUNET_NO,
                               0,
index eec5d3968eb3d0fe64707ee10ee20ff869ba046b..69612584e879922f6be69fd0417ca5a4afe37be6 100644 (file)
@@ -52,7 +52,7 @@ struct AddrEntry
    * Address class of the address.
    */
   enum GNUNET_NAT_AddressClass ac;
-  
+
   /**
    * Number of bytes that follow.
    */
@@ -70,7 +70,7 @@ struct GNUNET_NAT_Handle
    * Configuration we use.
    */
   const struct GNUNET_CONFIGURATION_Handle *cfg;
-  
+
   /**
    * Message queue for communicating with the NAT service.
    */
@@ -80,7 +80,7 @@ struct GNUNET_NAT_Handle
    * Our registration message.
    */
   struct GNUNET_MessageHeader *reg;
-  
+
   /**
    * Head of address DLL.
    */
@@ -95,12 +95,12 @@ struct GNUNET_NAT_Handle
    * Function to call when our addresses change.
    */
   GNUNET_NAT_AddressCallback address_callback;
-  
+
   /**
    * Function to call when another peer requests connection reversal.
    */
   GNUNET_NAT_ReversalCallback reversal_callback;
-  
+
   /**
    * Closure for the various callbacks.
    */
@@ -136,7 +136,7 @@ static void
 reconnect (struct GNUNET_NAT_Handle *nh)
 {
   struct AddrEntry *ae;
-  
+
   if (NULL != nh->mq)
   {
     GNUNET_MQ_destroy (nh->mq);
@@ -184,7 +184,7 @@ check_connection_reversal_request (void *cls,
   return GNUNET_OK;
 }
 
-  
+
 /**
  * Handle connection reversal request.
  *
@@ -247,7 +247,7 @@ check_address_change_notification (void *cls,
   return GNUNET_OK;
 }
 
-  
+
 /**
  * Handle connection reversal request.
  *
@@ -264,6 +264,8 @@ handle_address_change_notification (void *cls,
   enum GNUNET_NAT_AddressClass ac;
   struct AddrEntry *ae;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received address change notification\n");
   ac = (enum GNUNET_NAT_AddressClass) ntohl (acn->addr_class);
   if (GNUNET_YES == ntohl (acn->add_remove))
   {
@@ -395,13 +397,13 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
   size_t len;
   size_t str_len;
   char *off;
-  
+
   len = 0;
   for (unsigned int i=0;i<num_addrs;i++)
     len += addrlens[i];
   str_len = strlen (config_section) + 1;
   len += str_len;
-  if ( (len > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
+  if ( (len > GNUNET_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
        (num_addrs > UINT16_MAX) )
   {
     GNUNET_break (0);
@@ -427,6 +429,7 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
       if (sizeof (struct sockaddr_in) != addrlens[i])
       {
        GNUNET_break (0);
+        GNUNET_free (rm);
        return NULL;
       }
       break;
@@ -434,6 +437,7 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
       if (sizeof (struct sockaddr_in6) != addrlens[i])
       {
        GNUNET_break (0);
+        GNUNET_free (rm);
        return NULL;
       }
       break;
@@ -442,12 +446,14 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
       if (sizeof (struct sockaddr_un) != addrlens[i])
       {
        GNUNET_break (0);
+        GNUNET_free (rm);
        return NULL;
       }
       break;
 #endif
     default:
       GNUNET_break (0);
+      GNUNET_free (rm);
       return NULL;
     }
     GNUNET_memcpy (off,
@@ -569,7 +575,7 @@ test_stun_packet (const void *data,
  *
  * The function does some basic sanity checks on packet size and
  * content, try to extract a bit of information.
- * 
+ *
  * At the moment this only processes BIND requests, and returns the
  * externally visible address of the request to the rest of the
  * NAT logic.
@@ -663,7 +669,7 @@ GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
  * @param nh handle (used for configuration)
  * @param local_sa our local address of the peer (IPv4-only)
  * @param remote_sa the remote address of the peer (IPv4-only)
- * @return #GNUNET_SYSERR on error, 
+ * @return #GNUNET_SYSERR on error,
  *         #GNUNET_NO if connection reversal is unavailable,
  *         #GNUNET_OK otherwise (presumably in progress)
  */
index 3e42288750a1386a7e5effc95710de045abbe5f4..8d1c2720fe96e461ebef643e54bb860770ac83af 100644 (file)
@@ -70,7 +70,7 @@ struct stun_addr
    * Port number.
    */
   uint16_t port;
-  
+
   /**
    * IPv4 address. Should this be "struct in_addr"?
    */
@@ -79,7 +79,7 @@ struct stun_addr
 
 
 /**
- * STUN message classes 
+ * STUN message classes
  */
 enum StunClasses {
   INVALID_CLASS = 0,
@@ -186,18 +186,19 @@ stun_msg2str (int msg)
   static char result[64];
   const char *msg_class = NULL;
   const char *method = NULL;
-  int value;
+  enum StunClasses cvalue;
+  enum StunMethods mvalue;
 
-  value = decode_class (msg);
+  cvalue = decode_class (msg);
   for (unsigned int i = 0; classes[i].name; i++)
-    if (classes[i].value == value)
+    if (classes[i].value == cvalue)
     {
       msg_class = classes[i].name;
       break;
     }
-  value = decode_method (msg);
+  mvalue = decode_method (msg);
   for (unsigned int i = 0; methods[i].name; i++)
-    if (methods[i].value == value)
+    if (methods[i].value == mvalue)
     {
       method = methods[i].name;
       break;
index 48afd929829c0eb2f064468e7ff75727ca10ce6f..ea28bf61017ae85eb38e8334fd7b9a7758e75c23 100644 (file)
@@ -129,7 +129,7 @@ static int ok;
 /**
  * Be verbose (configuration option)
  */
-static int verbose;
+static unsigned int verbose;
 
 /**
  * Name of the file with the hosts to run the test over (configuration option)
@@ -835,28 +835,47 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'C', "connections", "COUNT",
-     gettext_noop ("limit to the number of connections to NSE services, 0 for none"),
-     1, &GNUNET_GETOPT_set_uint, &connection_limit},
-    {'d', "details", "FILENAME",
-     gettext_noop ("name of the file for writing connection information and statistics"),
-     1, &GNUNET_GETOPT_set_string, &data_filename},
-    {'H', "hosts", "FILENAME",
-     gettext_noop ("name of the file with the login information for the testbed"),
-     1, &GNUNET_GETOPT_set_string, &hosts_file},
-    {'o', "output", "FILENAME",
-     gettext_noop ("name of the file for writing the main results"),
-     1, &GNUNET_GETOPT_set_string, &output_filename},
-    {'p', "peers", "NETWORKSIZESPEC",
-     gettext_noop ("Number of peers to run in each round, separated by commas"),
-     1, &GNUNET_GETOPT_set_string, &num_peer_spec},
-    {'V', "verbose", NULL,
-     gettext_noop ("be verbose (print progress information)"),
-     0, &GNUNET_GETOPT_increment_value, &verbose},
-    {'w', "wait", "DELAY",
-     gettext_noop ("delay between rounds"),
-     1, &GNUNET_GETOPT_set_relative_time, &wait_time},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_UINT ('C',
+                                   "connections",
+                                   "COUNT",
+                                   gettext_noop ("limit to the number of connections to NSE services, 0 for none"),
+                                   &connection_limit),
+    GNUNET_GETOPT_OPTION_STRING ('d',
+                                 "details",
+                                 "FILENAME",
+                                 gettext_noop ("name of the file for writing connection information and statistics"),
+                                 &data_filename),
+
+    GNUNET_GETOPT_OPTION_STRING ('H',
+                                 "hosts",
+                                 "FILENAME",
+                                 gettext_noop ("name of the file with the login information for the testbed"),
+                                 &hosts_file),
+
+    GNUNET_GETOPT_OPTION_STRING ('o',
+                                 "output",
+                                 "FILENAME",
+                                 gettext_noop ("name of the file for writing the main results"),
+                                 &output_filename),
+
+
+    GNUNET_GETOPT_OPTION_STRING ('p',
+                                 "peers",
+                                 "NETWORKSIZESPEC",
+                                 gettext_noop ("Number of peers to run in each round, separated by commas"),
+                                 &num_peer_spec),
+
+    GNUNET_GETOPT_OPTION_INCREMENT_VALUE ('V',
+                                          "verbose",
+                                          gettext_noop ("be verbose (print progress information)"),
+                                          &verbose),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('w',
+                                            "wait",
+                                            "DELAY",
+                                            gettext_noop ("delay between rounds"),
+                                            &wait_time),
     GNUNET_GETOPT_OPTION_END
   };
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
index a5907c63f48e660aa6b544907f5a58bc3255d7e3..59ffe2efd2eaaf4101944c54956b2c6c849c0f0f 100644 (file)
@@ -837,31 +837,48 @@ state_machine (void *cls)
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'n', "numeric", NULL,
-     gettext_noop ("don't resolve host names"),
-     0, &GNUNET_GETOPT_set_one, &no_resolve},
-    {'q', "quiet", NULL,
-     gettext_noop ("output only the identity strings"),
-     0, &GNUNET_GETOPT_set_one, &be_quiet},
-    {'f', "friends", NULL,
-     gettext_noop ("include friend-only information"),
-     0, &GNUNET_GETOPT_set_one, &include_friend_only},
-    {'s', "self", NULL,
-     gettext_noop ("output our own identity only"),
-     0, &GNUNET_GETOPT_set_one, &get_self},
-    {'i', "info", NULL,
-     gettext_noop ("list all known peers"),
-     0, &GNUNET_GETOPT_set_one, &get_info},
-    {'d', "dump-hello", NULL,
-     gettext_noop ("dump hello to file"),
-     1, &GNUNET_GETOPT_set_string, &dump_hello},
-    {'g', "get-hello", NULL,
-     gettext_noop ("also output HELLO uri(s)"),
-     0, &GNUNET_GETOPT_set_one, &get_uri},
-    {'p', "put-hello", "HELLO",
-     gettext_noop ("add given HELLO uri to the database"),
-     1, &GNUNET_GETOPT_set_string, &put_uri},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "numeric",
+                                  gettext_noop ("don't resolve host names"),
+                                  &no_resolve),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('q',
+                                  "quiet",
+                                  gettext_noop ("output only the identity strings"),
+                                  &be_quiet),
+    GNUNET_GETOPT_OPTION_SET_ONE ('f',
+                                  "friends",
+                                  gettext_noop ("include friend-only information"),
+                                  &include_friend_only),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('s',
+                                  "self",
+                                  gettext_noop ("output our own identity only"),
+                                  &get_self),
+    
+    GNUNET_GETOPT_OPTION_SET_ONE ('i',
+                                  "info",
+                                  gettext_noop ("list all known peers"),
+                                  &get_info),
+
+    GNUNET_GETOPT_OPTION_STRING ('d',
+                                 "dump-hello",
+                                 NULL,
+                                 gettext_noop ("dump hello to file"),
+                                 &dump_hello),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('g',
+                                  "get-hello",
+                                  gettext_noop ("also output HELLO uri(s)"),
+                                  &get_uri),
+
+    GNUNET_GETOPT_OPTION_STRING ('p',
+                                 "put-hello",
+                                 "HELLO",
+                                 gettext_noop ("add given HELLO uri to the database"),
+                                 &put_uri),
+
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
index bc4a2a10df9e397b63b6981f744b284a66df39ce..731c24bf1fc57783a127c5fc21f2f10047697c3e 100644 (file)
@@ -283,7 +283,7 @@ read_host_file (const char *fn,
                 int unlink_garbage,
                 struct ReadHostFileContext *r)
 {
-  char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
+  char buffer[GNUNET_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
   ssize_t size_total;
   struct GNUNET_TIME_Absolute now;
   unsigned int left;
@@ -919,7 +919,7 @@ add_to_tc (void *cls,
   {
        /* Copy public HELLO */
     hs = GNUNET_HELLO_size (pos->hello);
-    GNUNET_assert (hs < GNUNET_SERVER_MAX_MESSAGE_SIZE -
+    GNUNET_assert (hs < GNUNET_MAX_MESSAGE_SIZE -
                    sizeof (struct InfoMessage));
     env = GNUNET_MQ_msg_extra (im,
                                hs,
@@ -937,7 +937,7 @@ add_to_tc (void *cls,
   {
        /* Copy friend only HELLO */
     hs = GNUNET_HELLO_size (pos->friend_only_hello);
-    GNUNET_assert (hs < GNUNET_SERVER_MAX_MESSAGE_SIZE -
+    GNUNET_assert (hs < GNUNET_MAX_MESSAGE_SIZE -
                    sizeof (struct InfoMessage));
     env = GNUNET_MQ_msg_extra (im,
                                hs,
@@ -977,7 +977,7 @@ discard_hosts_helper (void *cls,
                       const char *fn)
 {
   struct GNUNET_TIME_Absolute *now = cls;
-  char buffer[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
+  char buffer[GNUNET_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
   const struct GNUNET_HELLO_Message *hello;
   struct GNUNET_HELLO_Message *new_hello;
   int read_size;
index 21db6ad17a9dd4a86d498110c3366a7e1dc5fdbc..3aef05769e63b71e32ddb0933b882993a8051025 100644 (file)
@@ -73,7 +73,9 @@ libgnunet_plugin_peerstore_sqlite_la_SOURCES = \
   plugin_peerstore_sqlite.c
 libgnunet_plugin_peerstore_sqlite_la_LIBADD = \
   libgnunetpeerstore.la  \
-  $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
+  $(top_builddir)/src/sq/libgnunetsq.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(XLIBS) -lsqlite3 \
   $(LTLIBINTL)
 libgnunet_plugin_peerstore_sqlite_la_LDFLAGS = \
  $(GN_PLUGIN_LDFLAGS)
index 8200c23662d808468df56a15656b75d92101714c..92d020799b9800549f721eb5083078ae65e15c40 100644 (file)
@@ -260,15 +260,23 @@ record_iterator (void *cls,
     GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (cls_record->client),
                     env);
     if (NULL == emsg)
+    {
       GNUNET_SERVICE_client_continue (cls_record->client);
+    }
     else
+    {
+      GNUNET_break (0);
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Failed to iterate: %s\n",
+                  emsg);
       GNUNET_SERVICE_client_drop (cls_record->client);
+    }
     PEERSTORE_destroy_record (cls_record);
     return;
   }
 
   env = PEERSTORE_create_record_mq_envelope (record->sub_system,
-                                             record->peer,
+                                             &record->peer,
                                              record->key,
                                              record->value,
                                              record->value_size,
@@ -301,7 +309,7 @@ watch_notifier_it (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Found a watcher to update.\n");
   env = PEERSTORE_create_record_mq_envelope (record->sub_system,
-                                             record->peer,
+                                             &record->peer,
                                              record->key,
                                              record->value,
                                              record->value_size,
@@ -325,7 +333,7 @@ watch_notifier (struct GNUNET_PEERSTORE_Record *record)
   struct GNUNET_HashCode keyhash;
 
   PEERSTORE_hash_key (record->sub_system,
-                      record->peer,
+                      &record->peer,
                       record->key,
                       &keyhash);
   GNUNET_CONTAINER_multihashmap_get_multiple (watchers,
@@ -434,17 +442,18 @@ handle_iterate (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Iterate request: ss `%s', peer `%s', key `%s'\n",
               record->sub_system,
-              (NULL == record->peer) ? "NULL" : GNUNET_i2s (record->peer),
+              GNUNET_i2s (&record->peer),
               (NULL == record->key) ? "NULL" : record->key);
   record->client = client;
   if (GNUNET_OK !=
       db->iterate_records (db->cls,
                            record->sub_system,
-                           record->peer,
+                           (ntohs (srm->peer_set)) ? &record->peer : NULL,
                            record->key,
                            &record_iterator,
                            record))
   {
+    GNUNET_break (0);
     GNUNET_SERVICE_client_drop (client);
     PEERSTORE_destroy_record (record);
   }
@@ -470,6 +479,7 @@ store_record_continuation (void *cls,
   }
   else
   {
+    GNUNET_break (0);
     GNUNET_SERVICE_client_drop (record->client);
   }
   PEERSTORE_destroy_record (record);
@@ -496,7 +506,6 @@ check_store (void *cls,
     return GNUNET_SYSERR;
   }
   if ( (NULL == record->sub_system) ||
-       (NULL == record->peer) ||
        (NULL == record->key) )
   {
     GNUNET_break (0);
@@ -525,22 +534,23 @@ handle_store (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "Received a store request. Sub system `%s' Peer `%s Key `%s' Options: %u.\n",
              record->sub_system,
-              GNUNET_i2s (record->peer),
+              GNUNET_i2s (&record->peer),
              record->key,
               (uint32_t) ntohl (srm->options));
   record->client = client;
   if (GNUNET_OK !=
       db->store_record (db->cls,
                         record->sub_system,
-                        record->peer,
+                        &record->peer,
                         record->key,
                         record->value,
                         record->value_size,
-                        *record->expiry,
+                        record->expiry,
                         ntohl (srm->options),
                         &store_record_continuation,
                         record))
   {
+    GNUNET_break (0);
     PEERSTORE_destroy_record (record);
     GNUNET_SERVICE_client_drop (client);
     return;
index 8b3c4dd92bd3004497b83ca838e177f9f6540b4c..c6b9546764dd93073fbae5a704e64494bd663421 100644 (file)
@@ -60,7 +60,7 @@ struct StoreRecordMessage
   /**
    * Expiry time of entry
    */
-  struct GNUNET_TIME_Absolute expiry GNUNET_PACKED;
+  struct GNUNET_TIME_AbsoluteNBO expiry;
 
   /**
    * Size of the key string
index c9fcd17abf32ecd18528f64d088f5fbfab126e61..df182fe104ffbd7686de4287e28aff405466edb8 100644 (file)
@@ -286,6 +286,10 @@ store_request_sent (void *cls)
 /*******************         CONNECTION FUNCTIONS         *********************/
 /******************************************************************************/
 
+
+/**
+ * Function called when we had trouble talking to the service.
+ */
 static void
 handle_client_error (void *cls,
                      enum GNUNET_MQ_Error error)
@@ -293,7 +297,7 @@ handle_client_error (void *cls,
   struct GNUNET_PEERSTORE_Handle *h = cls;
 
   LOG (GNUNET_ERROR_TYPE_ERROR,
-       _("Received an error notification from MQ of type: %d\n"),
+       "Received an error notification from MQ of type: %d\n",
        error);
   reconnect (h);
 }
@@ -341,7 +345,9 @@ iterate_timeout (void *cls)
   callback_cls = ic->callback_cls;
   GNUNET_PEERSTORE_iterate_cancel (ic);
   if (NULL != callback)
-    callback (callback_cls, NULL, _("timeout"));
+    callback (callback_cls,
+              NULL,
+              _("timeout"));
 }
 
 
@@ -510,7 +516,7 @@ GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h,
        "Storing value (size: %lu) for subsytem `%s', peer `%s', key `%s'\n",
        size, sub_system, GNUNET_i2s (peer), key);
   ev = PEERSTORE_create_record_mq_envelope (sub_system, peer, key, value, size,
-                                            &expiry, options,
+                                            expiry, options,
                                             GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
   sc = GNUNET_new (struct GNUNET_PEERSTORE_StoreContext);
 
@@ -684,8 +690,12 @@ GNUNET_PEERSTORE_iterate (struct GNUNET_PEERSTORE_Handle *h,
   struct GNUNET_MQ_Envelope *ev;
   struct GNUNET_PEERSTORE_IterateContext *ic;
 
-  ev = PEERSTORE_create_record_mq_envelope (sub_system, peer, key, NULL, 0,
+  ev = PEERSTORE_create_record_mq_envelope (sub_system,
+                                            peer,
+                                            key,
                                             NULL, 0,
+                                            GNUNET_TIME_UNIT_FOREVER_ABS,
+                                            0,
                                             GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE);
   ic = GNUNET_new (struct GNUNET_PEERSTORE_IterateContext);
 
@@ -756,7 +766,7 @@ handle_watch_record (void *cls,
     return;
   }
   PEERSTORE_hash_key (record->sub_system,
-                      record->peer,
+                      &record->peer,
                       record->key,
                       &keyhash);
   // FIXME: what if there are multiple watches for the same key?
@@ -848,9 +858,12 @@ reconnect (struct GNUNET_PEERSTORE_Handle *h)
                                               &ic->peer,
                                               ic->key,
                                               NULL, 0,
-                                              NULL, 0,
+                                              GNUNET_TIME_UNIT_FOREVER_ABS,
+                                              0,
                                               GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE);
     GNUNET_MQ_send (h->mq, ev);
+    if (NULL != ic->timeout_task)
+      GNUNET_SCHEDULER_cancel (ic->timeout_task);
     ic->timeout_task
       = GNUNET_SCHEDULER_add_delayed (ic->timeout,
                                       &iterate_timeout,
@@ -863,7 +876,7 @@ reconnect (struct GNUNET_PEERSTORE_Handle *h)
                                               sc->key,
                                               sc->value,
                                               sc->size,
-                                              &sc->expiry,
+                                              sc->expiry,
                                               sc->options,
                                               GNUNET_MESSAGE_TYPE_PEERSTORE_STORE);
     GNUNET_MQ_notify_sent (ev,
index d12c4e21eed17ee3b03ef3ff309442690c559058..e0ab778faf635a9c4cf60652917170d05973be93 100644 (file)
@@ -77,7 +77,7 @@ PEERSTORE_create_record_mq_envelope (const char *sub_system,
                                      const char *key,
                                      const void *value,
                                      size_t value_size,
-                                     struct GNUNET_TIME_Absolute *expiry,
+                                     struct GNUNET_TIME_Absolute expiry,
                                      enum GNUNET_PEERSTORE_StoreOption options,
                                      uint16_t msg_type)
 {
@@ -97,8 +97,7 @@ PEERSTORE_create_record_mq_envelope (const char *sub_system,
   msg_size = ss_size + key_size + value_size;
   ev = GNUNET_MQ_msg_extra (srm, msg_size, msg_type);
   srm->key_size = htons (key_size);
-  if (NULL != expiry)
-    srm->expiry = *expiry;
+  srm->expiry = GNUNET_TIME_absolute_hton (expiry);
   if (NULL == peer)
     srm->peer_set = htons (GNUNET_NO);
   else
@@ -147,12 +146,9 @@ PEERSTORE_parse_record_message (const struct StoreRecordMessage *srm)
   record = GNUNET_new (struct GNUNET_PEERSTORE_Record);
   if (GNUNET_YES == ntohs (srm->peer_set))
   {
-    record->peer = GNUNET_new (struct GNUNET_PeerIdentity);
-    *record->peer = srm->peer;
+    record->peer = srm->peer;
   }
-  record->expiry = GNUNET_new (struct GNUNET_TIME_Absolute);
-
-  *(record->expiry) = srm->expiry;
+  record->expiry = GNUNET_TIME_absolute_ntoh (srm->expiry);
   dummy = (char *) &srm[1];
   if (ss_size > 0)
   {
@@ -167,7 +163,9 @@ PEERSTORE_parse_record_message (const struct StoreRecordMessage *srm)
   if (value_size > 0)
   {
     record->value = GNUNET_malloc (value_size);
-    GNUNET_memcpy (record->value, dummy, value_size);
+    GNUNET_memcpy (record->value,
+                   dummy,
+                   value_size);
   }
   record->value_size = value_size;
   return record;
@@ -184,8 +182,6 @@ PEERSTORE_destroy_record (struct GNUNET_PEERSTORE_Record *record)
 {
   if (NULL != record->sub_system)
     GNUNET_free (record->sub_system);
-  if (NULL != record->peer)
-    GNUNET_free (record->peer);
   if (NULL != record->key)
     GNUNET_free (record->key);
   if (NULL != record->value)
@@ -193,7 +189,5 @@ PEERSTORE_destroy_record (struct GNUNET_PEERSTORE_Record *record)
     GNUNET_free (record->value);
     record->value = 0;
   }
-  if (NULL != record->expiry)
-    GNUNET_free (record->expiry);
   GNUNET_free (record);
 }
index 3d938b5da8600e1d12f2eaf91edad35f0146816c..0fc14d9b4859fd7a2746c47739ad14e5de5c8182 100644 (file)
@@ -56,7 +56,7 @@ PEERSTORE_create_record_mq_envelope (const char *sub_system,
                                      const char *key,
                                      const void *value,
                                      size_t value_size,
-                                     struct GNUNET_TIME_Absolute *expiry,
+                                     struct GNUNET_TIME_Absolute expiry,
                                      enum GNUNET_PEERSTORE_StoreOption options,
                                      uint16_t msg_type);
 
index 2b90719d9c098fe1db9efd0a2ce4ab0c0489dd75..c75b2b1e4a05b06c8d13bdf286ab280d9a83c961 100644 (file)
@@ -107,7 +107,9 @@ delete_entries (void *cls,
   struct GNUNET_PEERSTORE_Record *entry = value;
   if (0 != strcmp (plugin->iter_key, entry->key))
     return GNUNET_YES;
-  if (0 != memcmp (plugin->iter_peer, entry->peer, sizeof (struct GNUNET_PeerIdentity)))
+  if (0 != memcmp (plugin->iter_peer,
+                   &entry->peer,
+                   sizeof (struct GNUNET_PeerIdentity)))
     return GNUNET_YES;
   if (0 != strcmp (plugin->iter_sub_system, entry->sub_system))
     return GNUNET_YES;
@@ -153,7 +155,7 @@ expire_entries (void *cls,
   struct Plugin *plugin = cls;
   struct GNUNET_PEERSTORE_Record *entry = value;
 
-  if (entry->expiry->abs_value_us < plugin->iter_now.abs_value_us)
+  if (entry->expiry.abs_value_us < plugin->iter_now.abs_value_us)
   {
     GNUNET_CONTAINER_multihashmap_remove (plugin->hm, key, value);
     plugin->exp_changes++;
@@ -204,7 +206,7 @@ iterate_entries (void *cls,
 
   if ((NULL != plugin->iter_peer) &&
       (0 != memcmp (plugin->iter_peer,
-                    entry->peer,
+                    &entry->peer,
                     sizeof (struct GNUNET_PeerIdentity))))
   {
     return GNUNET_YES;
@@ -296,10 +298,8 @@ peerstore_flat_store_record (void *cls, const char *sub_system,
   entry->value = GNUNET_malloc (size);
   GNUNET_memcpy (entry->value, value, size);
   entry->value_size = size;
-  entry->peer = GNUNET_new (struct GNUNET_PeerIdentity);
-  GNUNET_memcpy (entry->peer, peer, sizeof (struct GNUNET_PeerIdentity));
-  entry->expiry = GNUNET_new (struct GNUNET_TIME_Absolute);
-  entry->expiry->abs_value_us = expiry.abs_value_us;
+  entry->peer = *peer;
+  entry->expiry = expiry;
 
   peer_id = GNUNET_i2s (peer);
   GNUNET_CRYPTO_hash (peer_id,
@@ -409,7 +409,7 @@ database_setup (struct Plugin *plugin)
     GNUNET_free (buffer);
     return GNUNET_SYSERR;
   }
-  
+
   buffer[size] = '\0';
   GNUNET_DISK_file_close (fh);
   if (0 < size) {
@@ -433,22 +433,35 @@ database_setup (struct Plugin *plugin)
       entry = GNUNET_new (struct GNUNET_PEERSTORE_Record);
       entry->sub_system = GNUNET_strdup (sub_system);
       entry->key = GNUNET_strdup (key);
-      GNUNET_STRINGS_base64_decode (peer,
-                                    strlen (peer),
-                                    (char**)&entry->peer);
+      {
+        size_t s;
+        char *o;
+
+        o = NULL;
+        s = GNUNET_STRINGS_base64_decode (peer,
+                                          strlen (peer),
+                                          &o);
+        if (sizeof (struct GNUNET_PeerIdentity) == s)
+          GNUNET_memcpy (&entry->peer,
+                         o,
+                         s);
+        else
+          GNUNET_break (0);
+        GNUNET_free_non_null (o);
+      }
       entry->value_size = GNUNET_STRINGS_base64_decode (value,
                                                         strlen (value),
                                                         (char**)&entry->value);
-      if (GNUNET_SYSERR == GNUNET_STRINGS_fancy_time_to_absolute (expiry,
-                                             entry->expiry))
+      if (GNUNET_SYSERR ==
+          GNUNET_STRINGS_fancy_time_to_absolute (expiry,
+                                                 &entry->expiry))
       {
         GNUNET_free (entry->sub_system);
         GNUNET_free (entry->key);
-        GNUNET_free (entry->peer);
         GNUNET_free (entry);
         break;
       }
-      peer_id = GNUNET_i2s (entry->peer);
+      peer_id = GNUNET_i2s (&entry->peer);
       GNUNET_CRYPTO_hash (peer_id,
                           strlen (peer_id),
                           &hkey);
@@ -479,8 +492,8 @@ store_and_free_entries (void *cls,
   GNUNET_STRINGS_base64_encode (entry->value,
                                 entry->value_size,
                                 &val);
-  expiry = GNUNET_STRINGS_absolute_time_to_string (*entry->expiry);
-  GNUNET_STRINGS_base64_encode ((char*)entry->peer,
+  expiry = GNUNET_STRINGS_absolute_time_to_string (entry->expiry);
+  GNUNET_STRINGS_base64_encode ((char*)&entry->peer,
                                 sizeof (struct GNUNET_PeerIdentity),
                                 &peer);
   GNUNET_asprintf (&line,
@@ -496,10 +509,8 @@ store_and_free_entries (void *cls,
                           line,
                           strlen (line));
   GNUNET_free (entry->sub_system);
-  GNUNET_free (entry->peer);
   GNUNET_free (entry->key);
   GNUNET_free (entry->value);
-  GNUNET_free (entry->expiry);
   GNUNET_free (entry);
   GNUNET_free (line);
   return GNUNET_YES;
index 2cd7e22cf1ad1e0dd9fcb2fc1394f0e27e93c7e1..440263d44b5b38075c032bbf267083c3959cd3e2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * This file is part of GNUnet
- * Copyright (C) 2013 GNUnet e.V.
+ * Copyright (C) 2013, 2017 GNUnet e.V.
  *
  * GNUnet is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published
  * @file peerstore/plugin_peerstore_sqlite.c
  * @brief sqlite-based peerstore backend
  * @author Omar Tarabai
+ * @author Christian Grothoff
  */
 
 #include "platform.h"
 #include "gnunet_peerstore_plugin.h"
 #include "gnunet_peerstore_service.h"
+#include "gnunet_sq_lib.h"
 #include "peerstore.h"
 #include <sqlite3.h>
 
@@ -111,6 +113,7 @@ struct Plugin
 
 };
 
+
 /**
  * Delete records with the given key
  *
@@ -118,40 +121,50 @@ struct Plugin
  * @param sub_system name of sub system
  * @param peer Peer identity (can be NULL)
  * @param key entry key string (can be NULL)
- * @return number of deleted records
+ * @return number of deleted records, #GNUNE_SYSERR on error
  */
 static int
-peerstore_sqlite_delete_records (void *cls, const char *sub_system,
+peerstore_sqlite_delete_records (void *cls,
+                                 const char *sub_system,
                                  const struct GNUNET_PeerIdentity *peer,
                                  const char *key)
 {
   struct Plugin *plugin = cls;
   sqlite3_stmt *stmt = plugin->delete_peerstoredata;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_string (sub_system),
+    GNUNET_SQ_query_param_auto_from_type (peer),
+    GNUNET_SQ_query_param_string (key),
+    GNUNET_SQ_query_param_end
+  };
+  int ret;
 
-  if ((SQLITE_OK !=
-       sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
-                          SQLITE_STATIC)) ||
-      (SQLITE_OK !=
-       sqlite3_bind_blob (stmt, 2, peer, sizeof (struct GNUNET_PeerIdentity),
-                          SQLITE_STATIC)) ||
-      (SQLITE_OK !=
-       sqlite3_bind_text (stmt, 3, key, strlen (key) + 1, SQLITE_STATIC)))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (stmt,
+                      params))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind");
+    GNUNET_SQ_reset (plugin->dbh,
+                     stmt);
+    return GNUNET_SYSERR;
   }
-  else if (SQLITE_DONE != sqlite3_step (stmt))
+  if (SQLITE_DONE !=
+      sqlite3_step (stmt))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
+    ret = GNUNET_SYSERR;
   }
-  if (SQLITE_OK != sqlite3_reset (stmt))
+  else
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
-    return 0;
+    ret = sqlite3_changes (plugin->dbh);
   }
-  return sqlite3_changes (plugin->dbh);
+  GNUNET_SQ_reset (plugin->dbh,
+                   stmt);
+  return ret;
 }
 
 
@@ -172,28 +185,36 @@ peerstore_sqlite_expire_records (void *cls, struct GNUNET_TIME_Absolute now,
 {
   struct Plugin *plugin = cls;
   sqlite3_stmt *stmt = plugin->expire_peerstoredata;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_absolute_time (&now),
+    GNUNET_SQ_query_param_end
+  };
 
-  if (SQLITE_OK !=
-      sqlite3_bind_int64 (stmt, 1, (sqlite3_uint64) now.abs_value_us))
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (stmt,
+                      params))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind");
+    GNUNET_SQ_reset (plugin->dbh,
+                     stmt);
+    return GNUNET_SYSERR;
   }
-  else if (SQLITE_DONE != sqlite3_step (stmt))
+  if (SQLITE_DONE != sqlite3_step (stmt))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
-  }
-  if (SQLITE_OK != sqlite3_reset (stmt))
-  {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     stmt);
     return GNUNET_SYSERR;
   }
   if (NULL != cont)
-  {
-    cont (cont_cls, sqlite3_changes (plugin->dbh));
-  }
+    cont (cont_cls,
+          sqlite3_changes (plugin->dbh));
+  GNUNET_SQ_reset (plugin->dbh,
+                   stmt);
   return GNUNET_OK;
 }
 
@@ -213,7 +234,8 @@ peerstore_sqlite_expire_records (void *cls, struct GNUNET_TIME_Absolute now,
  * called
  */
 static int
-peerstore_sqlite_iterate_records (void *cls, const char *sub_system,
+peerstore_sqlite_iterate_records (void *cls,
+                                  const char *sub_system,
                                   const struct GNUNET_PeerIdentity *peer,
                                   const char *key,
                                   GNUNET_PEERSTORE_Processor iter,
@@ -223,94 +245,115 @@ peerstore_sqlite_iterate_records (void *cls, const char *sub_system,
   sqlite3_stmt *stmt;
   int err = 0;
   int sret;
-  struct GNUNET_PEERSTORE_Record *ret;
+  struct GNUNET_PEERSTORE_Record rec;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Executing iterate request on sqlite db.\n");
-  if (NULL == peer && NULL == key)
-  {
-    stmt = plugin->select_peerstoredata;
-    err =
-        (SQLITE_OK !=
-         sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
-                            SQLITE_STATIC));
-  }
-  else if (NULL == key)
-  {
-    stmt = plugin->select_peerstoredata_by_pid;
-    err =
-        (SQLITE_OK !=
-         sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
-                            SQLITE_STATIC)) ||
-        (SQLITE_OK !=
-         sqlite3_bind_blob (stmt, 2, peer, sizeof (struct GNUNET_PeerIdentity),
-                            SQLITE_STATIC));
-  }
-  else if (NULL == peer)
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Executing iterate request on sqlite db.\n");
+  if (NULL == peer)
   {
-    stmt = plugin->select_peerstoredata_by_key;
-    err =
-        (SQLITE_OK !=
-         sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
-                            SQLITE_STATIC)) ||
-        (SQLITE_OK !=
-         sqlite3_bind_text (stmt, 2, key, strlen (key) + 1, SQLITE_STATIC));
+    if (NULL == key)
+    {
+      struct GNUNET_SQ_QueryParam params[] = {
+        GNUNET_SQ_query_param_string (sub_system),
+        GNUNET_SQ_query_param_end
+      };
+
+      stmt = plugin->select_peerstoredata;
+      err = GNUNET_SQ_bind (stmt,
+                            params);
+    }
+    else
+    {
+      struct GNUNET_SQ_QueryParam params[] = {
+        GNUNET_SQ_query_param_string (sub_system),
+        GNUNET_SQ_query_param_string (key),
+        GNUNET_SQ_query_param_end
+      };
+
+      stmt = plugin->select_peerstoredata_by_key;
+      err = GNUNET_SQ_bind (stmt,
+                            params);
+    }
   }
   else
   {
-    stmt = plugin->select_peerstoredata_by_all;
-    err =
-        (SQLITE_OK !=
-         sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
-                            SQLITE_STATIC)) ||
-        (SQLITE_OK !=
-         sqlite3_bind_blob (stmt, 2, peer, sizeof (struct GNUNET_PeerIdentity),
-                            SQLITE_STATIC)) ||
-        (SQLITE_OK !=
-         sqlite3_bind_text (stmt, 3, key, strlen (key) + 1, SQLITE_STATIC));
+    if (NULL == key)
+    {
+      struct GNUNET_SQ_QueryParam params[] = {
+        GNUNET_SQ_query_param_string (sub_system),
+        GNUNET_SQ_query_param_auto_from_type (peer),
+        GNUNET_SQ_query_param_end
+      };
+
+      stmt = plugin->select_peerstoredata_by_pid;
+      err = GNUNET_SQ_bind (stmt,
+                            params);
+    }
+    else
+    {
+      struct GNUNET_SQ_QueryParam params[] = {
+        GNUNET_SQ_query_param_string (sub_system),
+        GNUNET_SQ_query_param_auto_from_type (peer),
+        GNUNET_SQ_query_param_string (key),
+        GNUNET_SQ_query_param_end
+      };
+
+      stmt = plugin->select_peerstoredata_by_all;
+      err = GNUNET_SQ_bind (stmt,
+                            params);
+    }
   }
 
-  if (err)
+  if (GNUNET_OK != err)
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind_XXXX");
-    if (SQLITE_OK != sqlite3_reset (stmt))
-      LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                  "sqlite3_reset");
+    GNUNET_SQ_reset (plugin->dbh,
+                     stmt);
     return GNUNET_SYSERR;
   }
+
+  err = 0;
   while (SQLITE_ROW == (sret = sqlite3_step (stmt)))
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning a matched record.\n");
-    ret = GNUNET_new (struct GNUNET_PEERSTORE_Record);
-
-    ret->sub_system = (char *) sqlite3_column_text (stmt, 0);
-    ret->peer = (struct GNUNET_PeerIdentity *) sqlite3_column_blob (stmt, 1);
-    ret->key = (char *) sqlite3_column_text (stmt, 2);
-    ret->value = (void *) sqlite3_column_blob (stmt, 3);
-    ret->value_size = sqlite3_column_bytes (stmt, 3);
-    ret->expiry = GNUNET_new (struct GNUNET_TIME_Absolute);
-
-    ret->expiry->abs_value_us = (uint64_t) sqlite3_column_int64 (stmt, 4);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Returning a matched record.\n");
+    struct GNUNET_SQ_ResultSpec rs[] = {
+      GNUNET_SQ_result_spec_string (&rec.sub_system),
+      GNUNET_SQ_result_spec_auto_from_type (&rec.peer),
+      GNUNET_SQ_result_spec_string (&rec.key),
+      GNUNET_SQ_result_spec_variable_size (&rec.value, &rec.value_size),
+      GNUNET_SQ_result_spec_absolute_time (&rec.expiry),
+      GNUNET_SQ_result_spec_end
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_SQ_extract_result (stmt,
+                                  rs))
+    {
+      GNUNET_break (0);
+      break;
+    }
     if (NULL != iter)
-      iter (iter_cls, ret, NULL);
-    GNUNET_free (ret->expiry);
-    GNUNET_free (ret);
+      iter (iter_cls,
+            &rec,
+            NULL);
+    GNUNET_SQ_cleanup_result (rs);
   }
   if (SQLITE_DONE != sret)
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite_step");
-    err = 1;
-  }
-  if (SQLITE_OK != sqlite3_reset (stmt))
-  {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR,
+                "sqlite_step");
     err = 1;
   }
+  GNUNET_SQ_reset (plugin->dbh,
+                   stmt);
   if (NULL != iter)
-  {
-    iter (iter_cls, NULL, err ? "sqlite error" : NULL);
-  }
+    iter (iter_cls,
+          NULL,
+          err ? "sqlite error" : NULL);
   return GNUNET_OK;
 }
 
@@ -333,9 +376,12 @@ peerstore_sqlite_iterate_records (void *cls, const char *sub_system,
  * @return #GNUNET_OK on success, else #GNUNET_SYSERR and cont is not called
  */
 static int
-peerstore_sqlite_store_record (void *cls, const char *sub_system,
+peerstore_sqlite_store_record (void *cls,
+                               const char *sub_system,
                                const struct GNUNET_PeerIdentity *peer,
-                               const char *key, const void *value, size_t size,
+                               const char *key,
+                               const void *value,
+                               size_t size,
                                struct GNUNET_TIME_Absolute expiry,
                                enum GNUNET_PEERSTORE_StoreOption options,
                                GNUNET_PEERSTORE_Continuation cont,
@@ -343,39 +389,39 @@ peerstore_sqlite_store_record (void *cls, const char *sub_system,
 {
   struct Plugin *plugin = cls;
   sqlite3_stmt *stmt = plugin->insert_peerstoredata;
+  struct GNUNET_SQ_QueryParam params[] = {
+    GNUNET_SQ_query_param_string (sub_system),
+    GNUNET_SQ_query_param_auto_from_type (peer),
+    GNUNET_SQ_query_param_string (key),
+    GNUNET_SQ_query_param_fixed_size (value, size),
+    GNUNET_SQ_query_param_absolute_time (&expiry),
+    GNUNET_SQ_query_param_end
+  };
 
   if (GNUNET_PEERSTORE_STOREOPTION_REPLACE == options)
   {
-    peerstore_sqlite_delete_records (cls, sub_system, peer, key);
+    peerstore_sqlite_delete_records (cls,
+                                     sub_system,
+                                     peer,
+                                     key);
   }
-  if (SQLITE_OK !=
-      sqlite3_bind_text (stmt, 1, sub_system, strlen (sub_system) + 1,
-                         SQLITE_STATIC) ||
-      SQLITE_OK != sqlite3_bind_blob (stmt, 2, peer,
-                                      sizeof (struct GNUNET_PeerIdentity),
-                                      SQLITE_STATIC) ||
-      SQLITE_OK != sqlite3_bind_text (stmt, 3, key, strlen (key) + 1,
-                                      SQLITE_STATIC) ||
-      SQLITE_OK != sqlite3_bind_blob (stmt, 4, value, size, SQLITE_STATIC) ||
-      SQLITE_OK != sqlite3_bind_int64 (stmt, 5,
-                                       (sqlite3_uint64) expiry.abs_value_us))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+  if (GNUNET_OK !=
+      GNUNET_SQ_bind (stmt,
+                      params))
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_bind");
   else if (SQLITE_DONE != sqlite3_step (stmt))
   {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                 "sqlite3_step");
   }
-  if (SQLITE_OK != sqlite3_reset (stmt))
-  {
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                "sqlite3_reset");
-    return GNUNET_SYSERR;
-  }
+  GNUNET_SQ_reset (plugin->dbh,
+                   stmt);
   if (NULL != cont)
-  {
-    cont (cont_cls, GNUNET_OK);
-  }
+    cont (cont_cls,
+          GNUNET_OK);
   return GNUNET_OK;
 }
 
@@ -388,15 +434,25 @@ peerstore_sqlite_store_record (void *cls, const char *sub_system,
  * @return 0 on success
  */
 static int
-sql_exec (sqlite3 * dbh, const char *sql)
+sql_exec (sqlite3 *dbh,
+          const char *sql)
 {
   int result;
 
-  result = sqlite3_exec (dbh, sql, NULL, NULL, NULL);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Executed `%s' / %d\n", sql, result);
-  if (result != SQLITE_OK)
-    LOG (GNUNET_ERROR_TYPE_ERROR, _("Error executing SQL query: %s\n  %s\n"),
-         sqlite3_errmsg (dbh), sql);
+  result = sqlite3_exec (dbh,
+                         sql,
+                         NULL,
+                         NULL,
+                         NULL);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Executed `%s' / %d\n",
+       sql,
+       result);
+  if (SQLITE_OK != result)
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Error executing SQL query: %s\n  %s\n"),
+         sqlite3_errmsg (dbh),
+         sql);
   return result;
 }
 
@@ -410,37 +466,32 @@ sql_exec (sqlite3 * dbh, const char *sql)
  * @return 0 on success
  */
 static int
-sql_prepare (sqlite3 * dbh, const char *sql, sqlite3_stmt ** stmt)
+sql_prepare (sqlite3 *dbh,
+             const char *sql,
+             sqlite3_stmt ** stmt)
 {
   char *tail;
   int result;
 
-  result =
-      sqlite3_prepare_v2 (dbh, sql, strlen (sql), stmt, (const char **) &tail);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Prepared `%s' / %p: %d\n", sql, *stmt, result);
-  if (result != SQLITE_OK)
-    LOG (GNUNET_ERROR_TYPE_ERROR, _("Error preparing SQL query: %s\n  %s\n"),
-         sqlite3_errmsg (dbh), sql);
+  result = sqlite3_prepare_v2 (dbh,
+                               sql,
+                               strlen (sql),
+                               stmt,
+                               (const char **) &tail);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Prepared `%s' / %p: %d\n",
+       sql,
+       *stmt,
+       result);
+  if (SQLITE_OK != result)
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Error preparing SQL query: %s\n  %s\n"),
+         sqlite3_errmsg (dbh),
+         sql);
   return result;
 }
 
 
-/**
- * sqlite3 custom function for comparison of uint64_t values
- * since it is not supported by default
- */
-void
-sqlite3_lessthan (sqlite3_context * ctx, int dummy, sqlite3_value ** values)
-{
-  uint64_t v1;
-  uint64_t v2;
-
-  v1 = (uint64_t) sqlite3_value_int64 (values[0]);
-  v2 = (uint64_t) sqlite3_value_int64 (values[1]);
-  sqlite3_result_int (ctx, v1 < v2);
-}
-
-
 /**
  * Initialize the database connections and associated
  * data structures (create tables and indices
@@ -455,10 +506,13 @@ database_setup (struct Plugin *plugin)
   char *filename;
 
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "peerstore-sqlite",
-                                               "FILENAME", &filename))
+      GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
+                                               "peerstore-sqlite",
+                                               "FILENAME",
+                                               &filename))
   {
-    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "peerstore-sqlite",
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                               "peerstore-sqlite",
                                "FILENAME");
     return GNUNET_SYSERR;
   }
@@ -474,60 +528,81 @@ database_setup (struct Plugin *plugin)
   /* filename should be UTF-8-encoded. If it isn't, it's a bug */
   plugin->fn = filename;
   /* Open database and precompile statements */
-  if (SQLITE_OK != sqlite3_open (plugin->fn, &plugin->dbh))
+  if (SQLITE_OK != sqlite3_open (plugin->fn,
+                                 &plugin->dbh))
   {
-    LOG (GNUNET_ERROR_TYPE_ERROR, _("Unable to initialize SQLite: %s.\n"),
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Unable to initialize SQLite: %s.\n"),
          sqlite3_errmsg (plugin->dbh));
     return GNUNET_SYSERR;
   }
-  sql_exec (plugin->dbh, "PRAGMA temp_store=MEMORY");
-  sql_exec (plugin->dbh, "PRAGMA synchronous=OFF");
-  sql_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF");
-  sql_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL");
-  sql_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\"");
-  sql_exec (plugin->dbh, "PRAGMA page_size=4096");
-  sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS);
+  sql_exec (plugin->dbh,
+            "PRAGMA temp_store=MEMORY");
+  sql_exec (plugin->dbh,
+            "PRAGMA synchronous=OFF");
+  sql_exec (plugin->dbh,
+            "PRAGMA legacy_file_format=OFF");
+  sql_exec (plugin->dbh,
+            "PRAGMA auto_vacuum=INCREMENTAL");
+  sql_exec (plugin->dbh,
+            "PRAGMA encoding=\"UTF-8\"");
+  sql_exec (plugin->dbh,
+            "PRAGMA page_size=4096");
+  sqlite3_busy_timeout (plugin->dbh,
+                        BUSY_TIMEOUT_MS);
   /* Create tables */
   sql_exec (plugin->dbh,
             "CREATE TABLE IF NOT EXISTS peerstoredata (\n"
-            "  sub_system TEXT NOT NULL,\n" "  peer_id BLOB NOT NULL,\n"
-            "  key TEXT NOT NULL,\n" "  value BLOB NULL,\n"
-            "  expiry sqlite3_uint64 NOT NULL" ");");
-  sqlite3_create_function (plugin->dbh, "UINT64_LT", 2, SQLITE_UTF8, NULL,
-                           &sqlite3_lessthan, NULL, NULL);
+            "  sub_system TEXT NOT NULL,\n"
+            "  peer_id BLOB NOT NULL,\n"
+            "  key TEXT NOT NULL,\n"
+            "  value BLOB NULL,\n"
+            "  expiry INT8 NOT NULL" ");");
   /* Create Indices */
   if (SQLITE_OK !=
       sqlite3_exec (plugin->dbh,
                     "CREATE INDEX IF NOT EXISTS peerstoredata_key_index ON peerstoredata (sub_system, peer_id, key)",
-                    NULL, NULL, NULL))
+                    NULL,
+                    NULL,
+                    NULL))
   {
-    LOG (GNUNET_ERROR_TYPE_ERROR, _("Unable to create indices: %s.\n"),
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Unable to create indices: %s.\n"),
          sqlite3_errmsg (plugin->dbh));
     return GNUNET_SYSERR;
   }
   /* Prepare statements */
 
   sql_prepare (plugin->dbh,
-               "INSERT INTO peerstoredata (sub_system, peer_id, key, value, expiry) VALUES (?,?,?,?,?);",
+               "INSERT INTO peerstoredata (sub_system, peer_id, key, value, expiry)"
+               " VALUES (?,?,?,?,?);",
                &plugin->insert_peerstoredata);
   sql_prepare (plugin->dbh,
-               "SELECT * FROM peerstoredata" " WHERE sub_system = ?",
+               "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
+               " WHERE sub_system = ?",
                &plugin->select_peerstoredata);
   sql_prepare (plugin->dbh,
-               "SELECT * FROM peerstoredata" " WHERE sub_system = ?"
-               " AND peer_id = ?", &plugin->select_peerstoredata_by_pid);
+               "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
+               " WHERE sub_system = ?"
+               " AND peer_id = ?",
+               &plugin->select_peerstoredata_by_pid);
   sql_prepare (plugin->dbh,
-               "SELECT * FROM peerstoredata" " WHERE sub_system = ?"
-               " AND key = ?", &plugin->select_peerstoredata_by_key);
+               "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
+               " WHERE sub_system = ?"
+               " AND key = ?",
+               &plugin->select_peerstoredata_by_key);
   sql_prepare (plugin->dbh,
-               "SELECT * FROM peerstoredata" " WHERE sub_system = ?"
+               "SELECT sub_system,peer_id,key,value,expiry FROM peerstoredata"
+               " WHERE sub_system = ?"
                " AND peer_id = ?" " AND key = ?",
                &plugin->select_peerstoredata_by_all);
   sql_prepare (plugin->dbh,
-               "DELETE FROM peerstoredata" " WHERE UINT64_LT(expiry, ?)",
+               "DELETE FROM peerstoredata"
+               " WHERE expiry < ?",
                &plugin->expire_peerstoredata);
   sql_prepare (plugin->dbh,
-               "DELETE FROM peerstoredata" " WHERE sub_system = ?"
+               "DELETE FROM peerstoredata"
+               " WHERE sub_system = ?"
                " AND peer_id = ?" " AND key = ?",
                &plugin->delete_peerstoredata);
   return GNUNET_OK;
@@ -545,15 +620,20 @@ database_shutdown (struct Plugin *plugin)
   int result;
   sqlite3_stmt *stmt;
 
-  while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh, NULL)))
+  while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh,
+                                            NULL)))
   {
     result = sqlite3_finalize (stmt);
     if (SQLITE_OK != result)
-      LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to close statement %p: %d\n",
-           stmt, result);
+      LOG (GNUNET_ERROR_TYPE_WARNING,
+           "Failed to close statement %p: %d\n",
+           stmt,
+           result);
   }
   if (SQLITE_OK != sqlite3_close (plugin->dbh))
-    LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close");
+    LOG_SQLITE (plugin,
+                GNUNET_ERROR_TYPE_ERROR,
+                "sqlite3_close");
   GNUNET_free_non_null (plugin->fn);
 }
 
@@ -573,7 +653,9 @@ libgnunet_plugin_peerstore_sqlite_init (void *cls)
 
   if (NULL != plugin.cfg)
     return NULL;                /* can only initialize once! */
-  memset (&plugin, 0, sizeof (struct Plugin));
+  memset (&plugin,
+          0,
+          sizeof (struct Plugin));
   plugin.cfg = cfg;
   if (GNUNET_OK != database_setup (&plugin))
   {
@@ -585,7 +667,8 @@ libgnunet_plugin_peerstore_sqlite_init (void *cls)
   api->store_record = &peerstore_sqlite_store_record;
   api->iterate_records = &peerstore_sqlite_iterate_records;
   api->expire_records = &peerstore_sqlite_expire_records;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Sqlite plugin is running\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sqlite plugin is running\n");
   return api;
 }
 
@@ -605,7 +688,8 @@ libgnunet_plugin_peerstore_sqlite_done (void *cls)
   database_shutdown (plugin);
   plugin->cfg = NULL;
   GNUNET_free (api);
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Sqlite plugin is finished\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sqlite plugin is finished\n");
   return NULL;
 }
 
index 83a6bf7b73e060c6aa398108f64827447740ef5f..c607d9fb388ed4b5bcf9f786e1301d9d7e31aaa4 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C)
+     Copyright (C) 2013-2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -42,7 +42,8 @@ static int count = 0;
 
 
 static void
-iter3_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record,
+iter3_cb (void *cls,
+          const struct GNUNET_PEERSTORE_Record *record,
           const char *emsg)
 {
   if (NULL != emsg)
@@ -63,7 +64,8 @@ iter3_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record,
 
 
 static void
-iter2_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record,
+iter2_cb (void *cls,
+          const struct GNUNET_PEERSTORE_Record *record,
           const char *emsg)
 {
   if (NULL != emsg)
@@ -78,13 +80,19 @@ iter2_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record,
   }
   GNUNET_assert (count == 2);
   count = 0;
-  ic = GNUNET_PEERSTORE_iterate (h, ss, NULL, NULL, GNUNET_TIME_UNIT_FOREVER_REL,
-                            iter3_cb, NULL);
+  ic = GNUNET_PEERSTORE_iterate (h,
+                                 ss,
+                                 NULL,
+                                 NULL,
+                                 GNUNET_TIME_UNIT_FOREVER_REL,
+                                 &iter3_cb,
+                                 NULL);
 }
 
 
 static void
-iter1_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record,
+iter1_cb (void *cls,
+          const struct GNUNET_PEERSTORE_Record *record,
           const char *emsg)
 {
   if (NULL != emsg)
@@ -99,30 +107,61 @@ iter1_cb (void *cls, const struct GNUNET_PEERSTORE_Record *record,
   }
   GNUNET_assert (count == 1);
   count = 0;
-  ic = GNUNET_PEERSTORE_iterate (h, ss, &p1, NULL, GNUNET_TIME_UNIT_FOREVER_REL,
-                            iter2_cb, NULL);
+  ic = GNUNET_PEERSTORE_iterate (h,
+                                 ss,
+                                 &p1,
+                                 NULL,
+                                 GNUNET_TIME_UNIT_FOREVER_REL,
+                                 iter2_cb,
+                                 NULL);
 }
 
 
 static void
-run (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg,
+run (void *cls,
+     const struct GNUNET_CONFIGURATION_Handle *cfg,
      struct GNUNET_TESTING_Peer *peer)
 {
   h = GNUNET_PEERSTORE_connect (cfg);
   GNUNET_assert (NULL != h);
   memset (&p1, 1, sizeof (p1));
   memset (&p2, 2, sizeof (p2));
-  GNUNET_PEERSTORE_store (h, ss, &p1, k1, val, strlen (val) + 1,
+  GNUNET_PEERSTORE_store (h,
+                          ss,
+                          &p1,
+                          k1,
+                          val,
+                          strlen (val) + 1,
                           GNUNET_TIME_UNIT_FOREVER_ABS,
-                          GNUNET_PEERSTORE_STOREOPTION_REPLACE, NULL, NULL);
-  GNUNET_PEERSTORE_store (h, ss, &p1, k2, val, strlen (val) + 1,
+                          GNUNET_PEERSTORE_STOREOPTION_REPLACE,
+                          NULL,
+                          NULL);
+  GNUNET_PEERSTORE_store (h,
+                          ss,
+                          &p1,
+                          k2,
+                          val,
+                          strlen (val) + 1,
                           GNUNET_TIME_UNIT_FOREVER_ABS,
-                          GNUNET_PEERSTORE_STOREOPTION_REPLACE, NULL, NULL);
-  GNUNET_PEERSTORE_store (h, ss, &p2, k3, val, strlen (val) + 1,
+                          GNUNET_PEERSTORE_STOREOPTION_REPLACE,
+                          NULL,
+                          NULL);
+  GNUNET_PEERSTORE_store (h,
+                          ss,
+                          &p2,
+                          k3,
+                          val,
+                          strlen (val) + 1,
                           GNUNET_TIME_UNIT_FOREVER_ABS,
-                          GNUNET_PEERSTORE_STOREOPTION_REPLACE, NULL, NULL);
-  ic = GNUNET_PEERSTORE_iterate (h, ss, &p1, k1, GNUNET_TIME_UNIT_FOREVER_REL,
-                            iter1_cb, NULL);
+                          GNUNET_PEERSTORE_STOREOPTION_REPLACE,
+                          NULL,
+                          NULL);
+  ic = GNUNET_PEERSTORE_iterate (h,
+                                 ss,
+                                 &p1,
+                                 k1,
+                                 GNUNET_TIME_UNIT_FOREVER_REL,
+                                 &iter1_cb, NULL);
 }
 
 
index bfe1b5b55dfb362616e0ef8e3f83c94465f9ccde..978009dbbb8fb18911c3f58ff7a6d9d403314301 100644 (file)
@@ -39,6 +39,7 @@ static char *val3 = "test_peerstore_api_store_val3--";
 
 static int count = 0;
 
+
 static void
 test3_cont2 (void *cls,
              const struct GNUNET_PEERSTORE_Record *record,
@@ -49,7 +50,8 @@ test3_cont2 (void *cls,
   if (NULL != record)
   {
     GNUNET_assert ((strlen (val3) + 1) == record->value_size);
-    GNUNET_assert (0 == strcmp ((char *) val3, (char *) record->value));
+    GNUNET_assert (0 == strcmp ((char *) val3,
+                                (char *) record->value));
     count++;
     return;
   }
@@ -61,7 +63,8 @@ test3_cont2 (void *cls,
 
 
 static void
-test3_cont (void *cls, int success)
+test3_cont (void *cls,
+            int success)
 {
   if (GNUNET_YES != success)
     return;
@@ -71,7 +74,8 @@ test3_cont (void *cls, int success)
                             &pid,
                             key,
                             GNUNET_TIME_UNIT_SECONDS,
-                            &test3_cont2, NULL);
+                            &test3_cont2,
+                            NULL);
 }
 
 
@@ -81,9 +85,15 @@ test3_cont (void *cls, int success)
 static void
 test3 ()
 {
-  GNUNET_PEERSTORE_store (h, subsystem, &pid, key, val3, strlen (val3) + 1,
+  GNUNET_PEERSTORE_store (h,
+                          subsystem,
+                          &pid,
+                          key,
+                          val3,
+                          strlen (val3) + 1,
                           GNUNET_TIME_UNIT_FOREVER_ABS,
-                          GNUNET_PEERSTORE_STOREOPTION_REPLACE, &test3_cont,
+                          GNUNET_PEERSTORE_STOREOPTION_REPLACE,
+                          &test3_cont,
                           NULL);
 }
 
@@ -130,9 +140,15 @@ test2_cont (void *cls, int success)
 void
 test2 ()
 {
-  GNUNET_PEERSTORE_store (h, subsystem, &pid, key, val2, strlen (val2) + 1,
+  GNUNET_PEERSTORE_store (h,
+                          subsystem,
+                          &pid,
+                          key,
+                          val2,
+                          strlen (val2) + 1,
                           GNUNET_TIME_UNIT_FOREVER_ABS,
-                          GNUNET_PEERSTORE_STOREOPTION_MULTIPLE, &test2_cont,
+                          GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
+                          &test2_cont,
                           NULL);
 }
 
@@ -163,8 +179,13 @@ test1_cont (void *cls, int success)
   if (GNUNET_YES != success)
     return;
   count = 0;
-  GNUNET_PEERSTORE_iterate (h, subsystem, &pid, key, GNUNET_TIME_UNIT_SECONDS,
-                            &test1_cont2, NULL);
+  GNUNET_PEERSTORE_iterate (h,
+                            subsystem,
+                            &pid,
+                            key,
+                            GNUNET_TIME_UNIT_SECONDS,
+                            &test1_cont2,
+                            NULL);
 }
 
 
@@ -174,9 +195,15 @@ test1_cont (void *cls, int success)
 static void
 test1 ()
 {
-  GNUNET_PEERSTORE_store (h, subsystem, &pid, key, val1, strlen (val1) + 1,
+  GNUNET_PEERSTORE_store (h,
+                          subsystem,
+                          &pid,
+                          key,
+                          val1,
+                          strlen (val1) + 1,
                           GNUNET_TIME_UNIT_FOREVER_ABS,
-                          GNUNET_PEERSTORE_STOREOPTION_REPLACE, &test1_cont,
+                          GNUNET_PEERSTORE_STOREOPTION_REPLACE,
+                          &test1_cont,
                           NULL);
 }
 
@@ -196,8 +223,10 @@ int
 main (int argc, char *argv[])
 {
   if (0 !=
-      GNUNET_TESTING_service_run ("test-gnunet-peerstore", "peerstore",
-                                  "test_peerstore_api_data.conf", &run, NULL))
+      GNUNET_TESTING_service_run ("test-gnunet-peerstore",
+                                  "peerstore",
+                                  "test_peerstore_api_data.conf",
+                                  &run, NULL))
     return 1;
   return ok;
 }
index 179e32b526e21727fca1b3bdb271b079e8bec015..62c06be8e6f15826745ad2ab4f6aae8bcd51ea62 100644 (file)
@@ -36,6 +36,11 @@ static int ok;
 static const char *plugin_name;
 
 
+static struct GNUNET_PEERSTORE_PluginFunctions *psp;
+
+static struct GNUNET_PeerIdentity p1;
+
+
 /**
  * Function called when the service shuts down.  Unloads our namestore
  * plugin.
@@ -47,8 +52,12 @@ unload_plugin (struct GNUNET_PEERSTORE_PluginFunctions *api)
 {
   char *libname;
 
-  GNUNET_asprintf (&libname, "libgnunet_plugin_peer_%s", plugin_name);
-  GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api));
+  GNUNET_asprintf (&libname,
+                   "libgnunet_plugin_peer_%s",
+                   plugin_name);
+  GNUNET_break (NULL ==
+                GNUNET_PLUGIN_unload (libname,
+                                      api));
   GNUNET_free (libname);
 }
 
@@ -65,12 +74,18 @@ load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
   struct GNUNET_PEERSTORE_PluginFunctions *ret;
   char *libname;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' peer plugin\n"),
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              _("Loading `%s' peer plugin\n"),
               plugin_name);
-  GNUNET_asprintf (&libname, "libgnunet_plugin_peerstore_%s", plugin_name);
-  if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg)))
+  GNUNET_asprintf (&libname,
+                   "libgnunet_plugin_peerstore_%s",
+                   plugin_name);
+  if (NULL == (ret = GNUNET_PLUGIN_load (libname,
+                                         (void*) cfg)))
   {
-    FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name);
+    FPRINTF (stderr,
+             "Failed to load plugin `%s'!\n",
+             plugin_name);
     GNUNET_free (libname);
     return NULL;
   }
@@ -81,19 +96,28 @@ load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg)
 
 static void
 test_record (void *cls,
-                                                const struct GNUNET_PEERSTORE_Record *record,
-                                                const char *error)
+             const struct GNUNET_PEERSTORE_Record *record,
+             const char *error)
 {
-  struct GNUNET_PeerIdentity *id = cls;
-  char* testval = "test_val";
+  const struct GNUNET_PeerIdentity *id = cls;
+  const char* testval = "test_val";
 
   if (NULL == record)
+  {
+    unload_plugin (psp);
     return;
-
-  GNUNET_assert (0 == memcmp (record->peer, id, sizeof (struct GNUNET_PeerIdentity)));
-  GNUNET_assert (0 == strcmp ("subsys", record->sub_system));
-  GNUNET_assert (0 == strcmp ("key", record->key));
-  GNUNET_assert (0 == memcmp (testval, record->value, strlen (testval)));
+  }
+  GNUNET_assert (0 == memcmp (&record->peer,
+                              id,
+                              sizeof (struct GNUNET_PeerIdentity)));
+  GNUNET_assert (0 == strcmp ("subsys",
+                              record->sub_system));
+  GNUNET_assert (0 == strcmp ("key",
+                              record->key));
+  GNUNET_assert (0 == memcmp (testval,
+                              record->value,
+                              strlen (testval)));
+  ok = 0;
 }
 
 
@@ -101,38 +125,52 @@ static void
 get_record (struct GNUNET_PEERSTORE_PluginFunctions *psp,
             const struct GNUNET_PeerIdentity *identity)
 {
-  GNUNET_assert (GNUNET_OK == psp->iterate_records (psp->cls,
-                                           "subsys", identity, "key", &test_record, (void*)identity));
+  GNUNET_assert (GNUNET_OK ==
+                 psp->iterate_records (psp->cls,
+                                       "subsys",
+                                       identity,
+                                       "key",
+                                       &test_record,
+                                       (void*)identity));
 }
 
+
 static void
-store_cont (void *cls, int status)
+store_cont (void *cls,
+            int status)
 {
   GNUNET_assert (GNUNET_OK == status);
+  get_record (psp,
+              &p1);
 }
 
+
 static void
-put_record (struct GNUNET_PEERSTORE_PluginFunctions *psp, struct GNUNET_PeerIdentity *identity)
+put_record (struct GNUNET_PEERSTORE_PluginFunctions *psp,
+            const struct GNUNET_PeerIdentity *identity)
 {
-  GNUNET_assert (GNUNET_OK == psp->store_record (psp->cls,
-            "subsys",
-                                               identity,
-            "key", "test_value", strlen ("test_value"),
-            GNUNET_TIME_absolute_get (),
-            GNUNET_PEERSTORE_STOREOPTION_REPLACE,
-                                               &store_cont,
-            identity));
+  GNUNET_assert (GNUNET_OK ==
+                 psp->store_record (psp->cls,
+                                    "subsys",
+                                    identity,
+                                    "key",
+                                    "test_value",
+                                    strlen ("test_value"),
+                                    GNUNET_TIME_absolute_get (),
+                                    GNUNET_PEERSTORE_STOREOPTION_REPLACE,
+                                    &store_cont,
+                                    NULL));
 }
 
 
 static void
-run (void *cls, char *const *args, const char *cfgfile,
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
-  struct GNUNET_PEERSTORE_PluginFunctions *psp;
-  struct GNUNET_PeerIdentity p1;
 
-  ok = 0;
+  ok = 1;
   psp = load_plugin (cfg);
   if (NULL == psp)
   {
@@ -142,10 +180,8 @@ run (void *cls, char *const *args, const char *cfgfile,
     return;
   }
   memset (&p1, 1, sizeof (p1));
-  put_record (psp, &p1);
-  get_record (psp, &p1);
-
-  unload_plugin (psp);
+  put_record (psp,
+              &p1);
 }
 
 
@@ -163,19 +199,26 @@ main (int argc, char *argv[])
     GNUNET_GETOPT_OPTION_END
   };
 
-  //GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namestore-sqlite");
   GNUNET_log_setup ("test-plugin-peerstore",
                     "WARNING",
                     NULL);
   plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
-  GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_peerstore_%s.conf",
+  GNUNET_snprintf (cfg_name,
+                   sizeof (cfg_name),
+                   "test_plugin_peerstore_%s.conf",
                    plugin_name);
-  GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv,
-                      "test-plugin-peerstore", "nohelp", options, &run, NULL);
+  GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1,
+                      xargv,
+                      "test-plugin-peerstore",
+                      "nohelp",
+                      options,
+                      &run,
+                      NULL);
   if (ok != 0)
-    FPRINTF (stderr, "Missed some testcases: %d\n", ok);
-  //GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-namestore-sqlite");
+    FPRINTF (stderr,
+             "Missed some testcases: %d\n",
+             ok);
   return ok;
 }
 
-/* end of test_plugin_namestore.c */
+/* end of test_plugin_peerstore.c */
index f4bab4e00f2fa7f9ece6f40020ac14cbb8c88113..4e24e1ef863ad6bbe141b833f9103e76d80e48c2 100644 (file)
@@ -85,9 +85,10 @@ GNUNET_PQ_exec_prepared (PGconn *db_conn,
       off += x->num_params;
     }
     GNUNET_assert (off == len);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-               "Executing prepared SQL statement `%s'\n",
-               name);
+    GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                     "pq",
+                     "Executing prepared SQL statement `%s'\n",
+                     name);
     res = PQexecPrepared (db_conn,
                           name,
                           len,
index e12b3210c57cf0c20b474312d821a063f0220f13..14a17536790b75408a6b0109da965ba1709c31a7 100644 (file)
@@ -1 +1,2 @@
 gnunet-service-psyc
+test_psyc
index c6544df3aeda2cf74284429fed5a6580a4d013af..c93d8b3835643c35375a34712026ac4710977f2f 100644 (file)
@@ -1309,7 +1309,7 @@ channel_history_replay (struct GNUNET_PSYC_Channel *chn,
 
   GNUNET_assert (NULL != method_prefix);
   uint16_t method_size = strnlen (method_prefix,
-                                  GNUNET_SERVER_MAX_MESSAGE_SIZE
+                                  GNUNET_MAX_MESSAGE_SIZE
                                   - sizeof (*req)) + 1;
   GNUNET_assert ('\0' == method_prefix[method_size - 1]);
 
@@ -1454,7 +1454,7 @@ channel_state_get (struct GNUNET_PSYC_Channel *chn,
   sr->op_id = GNUNET_OP_add (chn->op, op_recv_state_result, sr, NULL);
 
   GNUNET_assert (NULL != name);
-  size_t name_size = strnlen (name, GNUNET_SERVER_MAX_MESSAGE_SIZE
+  size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE
                               - sizeof (*req)) + 1;
   struct GNUNET_MQ_Envelope *
     env = GNUNET_MQ_msg_extra (req, name_size, type);
index fc2e4cf8e0ddb6a1c3d3b2f9c879770b239c7201..5ec783202363a64e771325ff9cbade0bbe9f1fc7 100644 (file)
@@ -1 +1,5 @@
 gnunet-service-psycstore
+test_plugin_psycstore_mysql
+test_plugin_psycstore_sqlite
+test_plugin_psycstore_postgres
+test_psycstore
index 10c92a878d087e8a42e59d6049ca45c40dc54bc9..1bee8da65de2b7639c8197c7469aa195367bc590 100644 (file)
@@ -106,7 +106,7 @@ send_result_code (struct GNUNET_SERVICE_Client *client,
 
   if (NULL != err_msg)
     err_size = strnlen (err_msg,
-                        GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*res) - 1) + 1;
+                        GNUNET_MAX_MESSAGE_SIZE - sizeof (*res) - 1) + 1;
   struct GNUNET_MQ_Envelope *
     env = GNUNET_MQ_msg_extra (res, err_size,
                                GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE);
index 40322662ea6eb84692b5e06b80cadb3061849612..d79daa35774906a65f2fd6b3a4a1ca27b3586180 100644 (file)
@@ -809,7 +809,7 @@ GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h,
   if (NULL == method_prefix)
     method_prefix = "";
   uint16_t method_size = strnlen (method_prefix,
-                                  GNUNET_SERVER_MAX_MESSAGE_SIZE
+                                  GNUNET_MAX_MESSAGE_SIZE
                                   - sizeof (*req)) + 1;
 
   struct GNUNET_MQ_Envelope *
@@ -875,7 +875,7 @@ GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h,
   if (NULL == method_prefix)
     method_prefix = "";
   uint16_t method_size = strnlen (method_prefix,
-                                  GNUNET_SERVER_MAX_MESSAGE_SIZE
+                                  GNUNET_MAX_MESSAGE_SIZE
                                   - sizeof (*req)) + 1;
   GNUNET_assert ('\0' == method_prefix[method_size - 1]);
 
diff --git a/src/psycutil/.gitignore b/src/psycutil/.gitignore
new file mode 100644 (file)
index 0000000..03d8197
--- /dev/null
@@ -0,0 +1 @@
+test_psyc_env
index 7ea8257d5e3653117aaeba3f7180234a004c43bf..e36630ae44bdd4017826f7ea6b40337641de8d00 100644 (file)
@@ -25,7 +25,7 @@ gnunet_daemon_pt_SOURCES = \
  gnunet-daemon-pt.c
 gnunet_daemon_pt_LDADD = \
   $(top_builddir)/src/vpn/libgnunetvpn.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/dht/libgnunetdht.la \
   $(top_builddir)/src/dns/libgnunetdns.la \
   $(top_builddir)/src/dns/libgnunetdnsparser.la \
index 54556cc52c3ea4462025929ea9bd8745ebff31ab..295082c0ecf0209c03771bc912ca6e9768180680 100644 (file)
@@ -1015,7 +1015,7 @@ cadet_channel_end_cb (void *cls,
     GNUNET_CONTAINER_DLL_insert (alt->receive_queue_head,
                                  alt->receive_queue_tail,
                                  rc);
-    GNUNET_MQ_send (GNUNET_CADET_get_mq (exit->cadet_channel),
+    GNUNET_MQ_send (GNUNET_CADET_get_mq (alt->cadet_channel),
                     GNUNET_MQ_env_copy (rc->env));
   }
   try_open_exit ();
@@ -1084,7 +1084,7 @@ try_open_exit ()
 
         /* move to the head of the DLL */
        pos->cadet_channel
-          = GNUNET_CADET_channel_creatE (cadet_handle,
+          = GNUNET_CADET_channel_create (cadet_handle,
                                          pos,
                                          &pos->peer,
                                          &port,
@@ -1246,7 +1246,7 @@ run (void *cls, char *const *args GNUNET_UNUSED,
       GNUNET_SCHEDULER_shutdown ();
       return;
     }
-    cadet_handle = GNUNET_CADET_connecT (cfg);
+    cadet_handle = GNUNET_CADET_connect (cfg);
     if (NULL == cadet_handle)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
index dfbcd388a9cd0791370a7b94bfb663660eb1fb4f..71f3580f8f283bc5a5bb09282e35c66ce5fc311f 100644 (file)
@@ -1477,22 +1477,39 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'o', "output-file", "FILENAME",
-     gettext_noop ("name of the file for writing statistics"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &data_filename},
-    {'t', "matching-timeout", "TIMEOUT",
-      gettext_noop ("wait TIMEOUT before ending the experiment"),
-      GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &search_timeout_time},
-    {'p', "policy-dir", "DIRECTORY",
-      gettext_noop ("directory with policy files"),
-      GNUNET_YES, &GNUNET_GETOPT_set_filename, &policy_dir},
-    {'s', "strings-file", "FILENAME",
-      gettext_noop ("name of file with input strings"),
-      GNUNET_YES, &GNUNET_GETOPT_set_filename, &strings_file},
-    {'H', "hosts-file", "FILENAME",
-      gettext_noop ("name of file with hosts' names"),
-      GNUNET_YES, &GNUNET_GETOPT_set_filename, &hosts_file},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_FILENAME ('o',
+                                   "output-file",
+                                   "FILENAME",
+                                   gettext_noop ("name of the file for writing statistics"),
+                                   &data_filename),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
+                                            "matching-timeout",
+                                            "TIMEOUT",
+                                            gettext_noop ("wait TIMEOUT before ending the experiment"),
+                                            &search_timeout_time), 
+
+    GNUNET_GETOPT_OPTION_FILENAME ('p',
+                                   "policy-dir",
+                                   "DIRECTORY",
+                                   gettext_noop ("directory with policy files"),
+                                   &policy_dir),
+
+
+    GNUNET_GETOPT_OPTION_FILENAME ('s',
+                                   "strings-file",
+                                   "FILENAME",
+                                   gettext_noop ("name of file with input strings"),
+                                   &strings_file),
+
+    GNUNET_GETOPT_OPTION_FILENAME ('H',
+                                   "hosts-file",
+                                   "FILENAME",
+                                   gettext_noop ("name of file with hosts' names"),
+                                   &hosts_file),
+
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
index 025a7031600d735bbc78b119a4b11b96e27c93c5..422e455653096ef51a9983d1a2faa7165011a0ef 100644 (file)
@@ -691,13 +691,20 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'t', "table", "TABLENAME",
-     gettext_noop ("name of the table to write DFAs"),
-     1, &GNUNET_GETOPT_set_string, &table_name},
-    {'p', "max-path-compression", "MAX_PATH_COMPRESSION",
-     gettext_noop ("maximum path compression length"),
-     1, &GNUNET_GETOPT_set_uint, &max_path_compression},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_STRING ('t',
+                                 "table",
+                                 "TABLENAME",
+                                 gettext_noop ("name of the table to write DFAs"),
+                                 &table_name),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('p',
+                                   "max-path-compression",
+                                   "MAX_PATH_COMPRESSION",
+                                   gettext_noop ("maximum path compression length"),
+                                   &max_path_compression),
+
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
index 294670be658c8e66175430860781e82085602336..9a40a5264825a0cf0d9e1de892d7960b45ad3df4 100644 (file)
@@ -37,19 +37,14 @@ struct ClientEntry
 {
 
   /**
-   * Kept in DLL.
+   * Queue for transmissions to @e client.
    */
-  struct ClientEntry *next;
-
-  /**
-   * Kept in DLL.
-   */
-  struct ClientEntry *prev;
+  struct GNUNET_MQ_Handle *mq;
 
   /**
    * Handle identifying the client.
    */
-  struct GNUNET_SERVER_Client *client;
+  struct GNUNET_SERVICE_Client *client;
 
   /**
    * Search handle (if this client is searching).
@@ -69,7 +64,7 @@ struct ClientEntry
   /**
    * Task for re-announcing.
    */
-  struct GNUNET_SCHEDULER_Task * refresh_task;
+  struct GNUNET_SCHEDULER_Task *refresh_task;
 
 };
 
@@ -84,70 +79,12 @@ static struct GNUNET_DHT_Handle *dht;
  */
 static struct GNUNET_STATISTICS_Handle *stats;
 
-/**
- * Head of list of clients.
- */
-static struct ClientEntry *client_head;
-
-/**
- * End of list of clients.
- */
-static struct ClientEntry *client_tail;
-
-/**
- * Our notification context, used to send back results to the client.
- */
-static struct GNUNET_SERVER_NotificationContext *nc;
-
 /**
  * Private key for this peer.
  */
 static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
 
 
-/**
- * A client disconnected.  Remove all of its data structure entries.
- *
- * @param cls closure, NULL
- * @param client identification of the client
- */
-static void
-handle_client_disconnect (void *cls,
-                          struct GNUNET_SERVER_Client *client)
-{
-  struct ClientEntry *ce;
-  struct ClientEntry *nx;
-
-  nx = client_head;
-  for (ce = nx; NULL != ce; ce = nx)
-  {
-    nx = ce->next;
-    if (ce->client == client)
-    {
-      if (NULL != ce->refresh_task)
-      {
-       GNUNET_SCHEDULER_cancel (ce->refresh_task);
-       ce->refresh_task = NULL;
-      }
-      if (NULL != ce->ah)
-      {
-       REGEX_INTERNAL_announce_cancel (ce->ah);
-       ce->ah = NULL;
-      }
-      if (NULL != ce->sh)
-      {
-       REGEX_INTERNAL_search_cancel (ce->sh);
-       ce->sh = NULL;
-      }
-      GNUNET_CONTAINER_DLL_remove (client_head,
-                                   client_tail,
-                                   ce);
-      GNUNET_free (ce);
-    }
-  }
-}
-
-
 /**
  * Task run during shutdown.
  *
@@ -156,17 +93,11 @@ handle_client_disconnect (void *cls,
 static void
 cleanup_task (void *cls)
 {
-  struct ClientEntry *ce;
-
-  while (NULL != (ce = client_head))
-    handle_client_disconnect (NULL,
-                              ce->client);
   GNUNET_DHT_disconnect (dht);
   dht = NULL;
-  GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
+  GNUNET_STATISTICS_destroy (stats,
+                             GNUNET_NO);
   stats = NULL;
-  GNUNET_SERVER_notification_context_destroy (nc);
-  nc = NULL;
   GNUNET_free (my_private_key);
   my_private_key = NULL;
 }
@@ -191,35 +122,51 @@ reannounce (void *cls)
 
 
 /**
- * Handle ANNOUNCE message.
+ * Check ANNOUNCE message.
  *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
+ * @param cls identification of the client
+ * @param am the actual message
+ * @return #GNUNET_OK if @am is well-formed
  */
-static void
-handle_announce (void *cls,
-                struct GNUNET_SERVER_Client *client,
-                const struct GNUNET_MessageHeader *message)
+static int
+check_announce (void *cls,
+                const struct AnnounceMessage *am)
 {
-  const struct AnnounceMessage *am;
+  struct ClientEntry *ce = cls;
   const char *regex;
-  struct ClientEntry *ce;
   uint16_t size;
 
-  size = ntohs (message->size);
-  am = (const struct AnnounceMessage *) message;
+  size = ntohs (am->header.size) - sizeof (*am);
   regex = (const char *) &am[1];
-  if ( (size <= sizeof (struct AnnounceMessage)) ||
-       ('\0' != regex[size - sizeof (struct AnnounceMessage) - 1]) )
+  if ('\0' != regex[size - 1])
   {
     GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
+    return GNUNET_SYSERR;
+  }
+  if (NULL != ce->ah)
+  {
+    /* only one announcement per client allowed */
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
+  return GNUNET_OK;
+}
 
-  ce = GNUNET_new (struct ClientEntry);
-  ce->client = client;
+
+/**
+ * Handle ANNOUNCE message.
+ *
+ * @param cls identification of the client
+ * @param am the actual message
+ */
+static void
+handle_announce (void *cls,
+                const struct AnnounceMessage *am)
+{
+  struct ClientEntry *ce = cls;
+  const char *regex;
+
+  regex = (const char *) &am[1];
   ce->frequency = GNUNET_TIME_relative_ntoh (am->refresh_delay);
   ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency,
                                                   &reannounce,
@@ -238,14 +185,11 @@ handle_announce (void *cls,
   {
     GNUNET_break (0);
     GNUNET_SCHEDULER_cancel (ce->refresh_task);
-    GNUNET_free (ce);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    ce->refresh_task = NULL;
+    GNUNET_SERVICE_client_drop (ce->client);
     return;
   }
-  GNUNET_CONTAINER_DLL_insert (client_head,
-                              client_tail,
-                              ce);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  GNUNET_SERVICE_client_continue (ce->client);
 }
 
 
@@ -268,6 +212,7 @@ handle_search_result (void *cls,
                      unsigned int put_path_length)
 {
   struct ClientEntry *ce = cls;
+  struct GNUNET_MQ_Envelope *env;
   struct ResultMessage *result;
   struct GNUNET_PeerIdentity *gp;
   uint16_t size;
@@ -275,64 +220,78 @@ handle_search_result (void *cls,
   if ( (get_path_length >= 65536) ||
        (put_path_length >= 65536) ||
        ( (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity))
-       + sizeof (struct ResultMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+       + sizeof (struct ResultMessage) >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
   }
-  size = (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity) + sizeof (struct ResultMessage);
-  result = GNUNET_malloc (size);
-  result->header.size = htons (size);
-  result->header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_RESULT);
+  size = (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity);
+  env = GNUNET_MQ_msg_extra (result,
+                             size,
+                             GNUNET_MESSAGE_TYPE_REGEX_RESULT);
   result->get_path_length = htons ((uint16_t) get_path_length);
   result->put_path_length = htons ((uint16_t) put_path_length);
   result->id = *id;
   gp = &result->id;
   GNUNET_memcpy (&gp[1],
-         get_path,
-         get_path_length * sizeof (struct GNUNET_PeerIdentity));
+                 get_path,
+                 get_path_length * sizeof (struct GNUNET_PeerIdentity));
   GNUNET_memcpy (&gp[1 + get_path_length],
-         put_path,
-         put_path_length * sizeof (struct GNUNET_PeerIdentity));
-  GNUNET_SERVER_notification_context_unicast (nc,
-                                             ce->client,
-                                             &result->header, GNUNET_NO);
-  GNUNET_free (result);
+                 put_path,
+                 put_path_length * sizeof (struct GNUNET_PeerIdentity));
+  GNUNET_MQ_send (ce->mq,
+                  env);
 }
 
 
 /**
- * Handle SEARCH message.
+ * Check SEARCH message.
  *
- * @param cls closure
- * @param client identification of the client
+ * @param cls identification of the client
  * @param message the actual message
  */
-static void
-handle_search (void *cls,
-              struct GNUNET_SERVER_Client *client,
-              const struct GNUNET_MessageHeader *message)
+static int
+check_search (void *cls,
+              const struct RegexSearchMessage *sm)
 {
-  const struct RegexSearchMessage *sm;
+  struct ClientEntry *ce = cls;
   const char *string;
-  struct ClientEntry *ce;
   uint16_t size;
 
-  size = ntohs (message->size);
-  sm = (const struct RegexSearchMessage *) message;
+  size = ntohs (sm->header.size) - sizeof (*sm);
   string = (const char *) &sm[1];
-  if ( (size <= sizeof (struct RegexSearchMessage)) ||
-       ('\0' != string[size - sizeof (struct RegexSearchMessage) - 1]) )
+  if ('\0' != string[size - 1])
   {
     GNUNET_break (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
+    return GNUNET_SYSERR;
   }
+  if (NULL != ce->sh)
+  {
+    /* only one search allowed per client */
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle SEARCH message.
+ *
+ * @param cls identification of the client
+ * @param message the actual message
+ */
+static void
+handle_search (void *cls,
+              const struct RegexSearchMessage *sm)
+{
+  struct ClientEntry *ce = cls;
+  const char *string;
+
+  string = (const char *) &sm[1];
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Starting to search for `%s'\n",
              string);
-  ce = GNUNET_new (struct ClientEntry);
-  ce->client = client;
   ce->sh = REGEX_INTERNAL_search (dht,
                                   string,
                                   &handle_search_result,
@@ -341,15 +300,10 @@ handle_search (void *cls,
   if (NULL == ce->sh)
   {
     GNUNET_break (0);
-    GNUNET_free (ce);
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    GNUNET_SERVICE_client_drop (ce->client);
     return;
   }
-  GNUNET_CONTAINER_DLL_insert (client_head,
-                              client_tail,
-                              ce);
-  GNUNET_SERVER_notification_context_add (nc, client);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  GNUNET_SERVICE_client_continue (ce->client);
 }
 
 
@@ -357,19 +311,14 @@ handle_search (void *cls,
  * Process regex requests.
  *
  * @param cls closure
- * @param server the initialized server
  * @param cfg configuration to use
+ * @param service the initialized service
  */
 static void
-run (void *cls, struct GNUNET_SERVER_Handle *server,
-     const struct GNUNET_CONFIGURATION_Handle *cfg)
+run (void *cls,
+     const struct GNUNET_CONFIGURATION_Handle *cfg,
+     struct GNUNET_SERVICE_Handle *service)
 {
-  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
-    {&handle_announce, NULL, GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE, 0},
-    {&handle_search, NULL, GNUNET_MESSAGE_TYPE_REGEX_SEARCH, 0},
-    {NULL, NULL, 0, 0}
-  };
-
   my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
   if (NULL == my_private_key)
   {
@@ -386,28 +335,84 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
   }
   GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
                                 NULL);
-  nc = GNUNET_SERVER_notification_context_create (server, 1);
   stats = GNUNET_STATISTICS_create ("regex", cfg);
-  GNUNET_SERVER_add_handlers (server, handlers);
-  GNUNET_SERVER_disconnect_notify (server,
-                                   &handle_client_disconnect,
-                                   NULL);
 }
 
 
 /**
- * The main function for the regex service.
+ * Callback called when a client connects to the service.
  *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
+ * @param cls closure for the service
+ * @param c the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return @a c
  */
-int
-main (int argc, char *const *argv)
+static void *
+client_connect_cb (void *cls,
+                  struct GNUNET_SERVICE_Client *c,
+                  struct GNUNET_MQ_Handle *mq)
 {
-  return (GNUNET_OK ==
-          GNUNET_SERVICE_run (argc, argv, "regex",
-                              GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
+  struct ClientEntry *ce;
+
+  ce = GNUNET_new (struct ClientEntry);
+  ce->client = c;
+  ce->mq = mq;
+  return ce;
 }
 
+
+/**
+ * Callback called when a client disconnected from the service
+ *
+ * @param cls closure for the service
+ * @param c the client that disconnected
+ * @param internal_cls should be equal to @a c
+ */
+static void
+client_disconnect_cb (void *cls,
+                     struct GNUNET_SERVICE_Client *c,
+                     void *internal_cls)
+{
+  struct ClientEntry *ce = internal_cls;
+
+  if (NULL != ce->refresh_task)
+  {
+    GNUNET_SCHEDULER_cancel (ce->refresh_task);
+    ce->refresh_task = NULL;
+  }
+  if (NULL != ce->ah)
+  {
+    REGEX_INTERNAL_announce_cancel (ce->ah);
+    ce->ah = NULL;
+  }
+  if (NULL != ce->sh)
+  {
+    REGEX_INTERNAL_search_cancel (ce->sh);
+    ce->sh = NULL;
+  }
+  GNUNET_free (ce);
+}
+
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("regex",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_var_size (announce,
+                        GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE,
+                        struct AnnounceMessage,
+                        NULL),
+ GNUNET_MQ_hd_var_size (search,
+                        GNUNET_MESSAGE_TYPE_REGEX_SEARCH,
+                        struct RegexSearchMessage,
+                        NULL),
+ GNUNET_MQ_handler_end ());
+
+
 /* end of gnunet-service-regex.c */
index 70bf34bc869b5e42323b802de1a1fdaf03e4bed4..8e018f26cec4fa5416f0b8ddf7787ecb3288a343 100644 (file)
@@ -146,7 +146,7 @@ GNUNET_REGEX_announce (const struct GNUNET_CONFIGURATION_Handle *cfg,
   size_t slen;
 
   slen = strlen (regex) + 1;
-  if (slen + sizeof (struct AnnounceMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (slen + sizeof (struct AnnounceMessage) >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 _("Regex `%s' is too long!\n"),
index b7a015f87680f7fcf7fd178be169082f124faf6d..a5480ac7a6cd0e82a4b45a22be565a0e86ebb8f6 100644 (file)
@@ -206,7 +206,7 @@ GNUNET_REGEX_search (const struct GNUNET_CONFIGURATION_Handle *cfg,
   struct GNUNET_REGEX_Search *s;
   size_t slen = strlen (string) + 1;
 
-  if (slen + sizeof (struct RegexSearchMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (slen + sizeof (struct RegexSearchMessage) >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 _("Search string `%s' is too long!\n"),
index b115deb203f770aad5fb515d86502ed462a4d167..0b6c182674965cda64e9af149490f31c3d55991d 100644 (file)
@@ -66,7 +66,7 @@ static struct GNUNET_SCHEDULER_Task *httpd_task;
 /**
  * The port the service is running on (default 7776)
  */
-static unsigned long port = GNUNET_REST_SERVICE_PORT;
+static unsigned long long port = GNUNET_REST_SERVICE_PORT;
 
 /**
  * The listen socket of the service for IPv4
@@ -748,7 +748,7 @@ run (void *cls,
     return;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Service listens on port %lu\n",
+              "Service listens on port %llu\n",
               port);
   httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET,
                             0,
@@ -783,10 +783,12 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'p', "port", NULL,
-      gettext_noop ("listen on specified port (default: 7776)"), 1,
-      &GNUNET_GETOPT_set_ulong, &port},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ULONG ('p',
+                                    "port",
+                                    "PORT",
+                                    gettext_noop ("listen on specified port (default: 7776)"),
+                                    &port),
     GNUNET_GETOPT_OPTION_END
   };
   static const char* err_page =
index 133468789a853ef5367b349fa694a5fcb412d935..7b40c83d7f374241483909aaacba89f38116111e 100644 (file)
@@ -527,19 +527,31 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'f', "filename", "NAME",
-     gettext_noop ("use NAME for the name of the revocation file"),
-     1, &GNUNET_GETOPT_set_string, &filename},
-    {'R', "revoke", "NAME",
-     gettext_noop ("revoke the private key associated for the the private key associated with the ego NAME "),
-     1, &GNUNET_GETOPT_set_string, &revoke_ego},
-    {'p', "perform", NULL,
-     gettext_noop ("actually perform revocation, otherwise we just do the precomputation"),
-     0, &GNUNET_GETOPT_set_one, &perform},
-    {'t', "test", "KEY",
-     gettext_noop ("test if the public key KEY has been revoked"),
-     1, &GNUNET_GETOPT_set_string, &test_ego},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_STRING ('f',
+                                 "filename",
+                                 "NAME",
+                                 gettext_noop ("use NAME for the name of the revocation file"),
+                                 &filename),
+
+    GNUNET_GETOPT_OPTION_STRING ('R',
+                                 "revoke",
+                                 "NAME",
+                                 gettext_noop ("revoke the private key associated for the the private key associated with the ego NAME "),
+                                 &revoke_ego), 
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('p',
+                                  "perform",
+                                  gettext_noop ("actually perform revocation, otherwise we just do the precomputation"),
+                                  &perform),
+
+    GNUNET_GETOPT_OPTION_STRING ('t',
+                                 "test",
+                                 "KEY",
+                                 gettext_noop ("test if the public key KEY has been revoked"),
+                                 &test_ego), 
+
     GNUNET_GETOPT_OPTION_END
   };
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
index d3bbb879a80e44331575d0008f953b98b3928404..8d55936941f58676303cc397d1573e8b1e6e753d 100644 (file)
@@ -104,8 +104,8 @@ revocation_remote_cb (void *cls,
 
   if (GNUNET_NO == is_valid)
   {
-    fprintf (stderr,
-             "Local revocation successful\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Local revocation successful\n");
     ok = 0;
     GNUNET_SCHEDULER_shutdown ();
     return;
@@ -118,8 +118,8 @@ revocation_remote_cb (void *cls,
                                   NULL);
     return;
   }
-  fprintf (stderr,
-           "Flooding of revocation failed\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Flooding of revocation failed\n");
   ok = 2;
   GNUNET_SCHEDULER_shutdown ();
 }
@@ -141,8 +141,8 @@ revocation_cb (void *cls,
   testpeers[1].revok_handle = NULL;
   if (GNUNET_NO == is_valid)
   {
-    fprintf (stderr,
-             "Revocation successful\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Revocation successful\n");
     check_revocation (NULL);
   }
 }
@@ -386,8 +386,8 @@ test_connection (void *cls,
    /* We are generating a CLIQUE */
   if (NUM_TEST_PEERS * (NUM_TEST_PEERS -1) == links_succeeded)
   {
-    fprintf (stderr,
-             "Testbed connected peers, initializing test\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Testbed connected peers, initializing test\n");
     for (c = 0; c < num_peers; c++)
     {
       testpeers[c].p = peers[c];
@@ -403,8 +403,8 @@ test_connection (void *cls,
   }
   else
   {
-    fprintf (stderr,
-             "Testbed failed to connect peers\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Testbed failed to connect peers\n");
     ok = 5;
     GNUNET_SCHEDULER_shutdown ();
     return;
index de7f853c1d9a9d8cf76b9985902062a40b6efc0a..e6c8cd9299661e9b9c0360b9af7da0f71fe71e03 100644 (file)
@@ -100,22 +100,28 @@ AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PAT
 TESTS = $(check_PROGRAMS)
 endif
 
-test_service_rps_view_SOURCES = gnunet-service-rps_view.h gnunet-service-rps_view.c \
-                                                                                                                               test_service_rps_view.c
+test_service_rps_view_SOURCES = \
+  gnunet-service-rps_view.h gnunet-service-rps_view.c \
+  test_service_rps_view.c
 test_service_rps_view_LDADD = $(top_builddir)/src/util/libgnunetutil.la
 
-test_service_rps_peers_SOURCES = gnunet-service-rps_peers.h gnunet-service-rps_peers.c \
-                                                                                                                                test_service_rps_peers.c
-test_service_rps_peers_LDADD = $(top_builddir)/src/util/libgnunetutil.la \
-                                                                                                                        $(top_builddir)/src/cadet/libgnunetcadet.la
-
-test_service_rps_custommap_SOURCES = gnunet-service-rps_custommap.h gnunet-service-rps_custommap.c \
-                                                                                                                                test_service_rps_custommap.c
-test_service_rps_custommap_LDADD = $(top_builddir)/src/util/libgnunetutil.la
-
-test_service_rps_sampler_elem_SOURCES = gnunet-service-rps_sampler_elem.h gnunet-service-rps_sampler_elem.c \
-                                                                                                                                                               rps-test_util.h rps-test_util.c \
-                                                                                                                                       test_service_rps_sampler_elem.c
+test_service_rps_peers_SOURCES = \
+  gnunet-service-rps_peers.h gnunet-service-rps_peers.c \
+  test_service_rps_peers.c
+test_service_rps_peers_LDADD = \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la
+
+test_service_rps_custommap_SOURCES = \
+  gnunet-service-rps_custommap.h gnunet-service-rps_custommap.c \
+  test_service_rps_custommap.c
+test_service_rps_custommap_LDADD = \
+  $(top_builddir)/src/util/libgnunetutil.la
+
+test_service_rps_sampler_elem_SOURCES = \
+  gnunet-service-rps_sampler_elem.h gnunet-service-rps_sampler_elem.c \
+  rps-test_util.h rps-test_util.c \
+  test_service_rps_sampler_elem.c
 test_service_rps_sampler_elem_LDADD = $(top_builddir)/src/util/libgnunetutil.la
 
 test_rps_malicious_1_SOURCES = $(rps_test_src)
index 3dbb8053e5e4a7494e1d421bddf8429f5a7f467b..e36e547fad5b03993c39ff75b5fa7e7eb737670d 100644 (file)
@@ -43,43 +43,7 @@ static struct GNUNET_RPS_Request_Handle *req_handle;
 /**
  * PeerID (Option --seed)
  */
-static struct GNUNET_PeerIdentity *peer_id;
-
-
-/**
- * Set an option of type 'struct GNUNET_PeerIdentity *' from the command line.
- * A pointer to this function should be passed as part of the
- * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
- * of this type.  It should be followed by a pointer to a value of
- * type 'struct GNUNET_PeerIdentity *', which will be allocated with the requested string.
- *
- * @param ctx command line processing context
- * @param scls additional closure (will point to the 'char *',
- *             which will be allocated)
- * @param option name of the option
- * @param value actual value of the option (a PeerID)
- * @return #GNUNET_OK
- */
-static int
-GNUNET_GETOPT_set_peerid (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                          void *scls, const char *option, const char *value)
-{
-  struct GNUNET_PeerIdentity **val = (struct GNUNET_PeerIdentity **) scls;
-
-  GNUNET_assert (NULL != value);
-  GNUNET_free_non_null (*val);
-  /* Not quite sure whether that is a sane way */
-  *val = GNUNET_new (struct GNUNET_PeerIdentity);
-  if (GNUNET_OK !=
-      GNUNET_CRYPTO_eddsa_public_key_from_string (value,
-                                                  strlen (value),
-                                                  &((*val)->public_key)))
-  {
-    FPRINTF (stderr, "Invalid peer ID %s\n", value);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
+static struct GNUNET_PeerIdentity peer_id;
 
 
 /**
@@ -139,10 +103,13 @@ run (void *cls,
      const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   static uint64_t num_peers;
+  static struct GNUNET_PeerIdentity zero_pid;
 
   rps_handle = GNUNET_RPS_connect (cfg);
 
-  if (NULL == peer_id)
+  if (0 == memcmp (&zero_pid,
+                   &peer_id,
+                   sizeof (peer_id)))
   { /* Request n PeerIDs */
     /* If number was specified use it, else request single peer. */
     num_peers = (NULL == args[0]) ? 1 : atoi (args[0]);
@@ -153,8 +120,8 @@ run (void *cls,
   }
   else
   { /* Seed PeerID */
-    GNUNET_RPS_seed_ids (rps_handle, 1, peer_id);
-    FPRINTF (stdout, "Seeded PeerID %s\n", GNUNET_i2s_full (peer_id));
+    GNUNET_RPS_seed_ids (rps_handle, 1, &peer_id);
+    FPRINTF (stdout, "Seeded PeerID %s\n", GNUNET_i2s_full (&peer_id));
     ret = 0;
     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
   }
@@ -172,10 +139,12 @@ main (int argc, char *const *argv)
 {
   const char helpstr[] =
     "Get random GNUnet peers. If none is specified a single is requested.";
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'s', "seed", "PEER_ID",
-      gettext_noop ("Seed a PeerID"),
-      GNUNET_YES, &GNUNET_GETOPT_set_peerid, &peer_id},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_BASE32_AUTO ('s',
+                                          "seed",
+                                          "PEER_ID",
+                                          gettext_noop ("Seed a PeerID"),
+                                          &peer_id),
     GNUNET_GETOPT_OPTION_END
   };
   return (GNUNET_OK ==
index adcfe7d02fa6e539f9911d735f111e64ab1551a4..0a4543b303bffce7bb788a1f564fa5fc75883a99 100644 (file)
@@ -216,6 +216,11 @@ static struct GNUNET_NSE_Handle *nse;
  */
 static struct GNUNET_CADET_Handle *cadet_handle;
 
+/**
+ * @brief Port to communicate to other peers.
+ */
+static struct GNUNET_CADET_Port *cadet_port;
+
 /**
  * Handler to PEERINFO.
  */
@@ -838,14 +843,10 @@ clean_peer (const struct GNUNET_PeerIdentity *peer)
  */
 static void
 cleanup_destroyed_channel (void *cls,
-                           const struct GNUNET_CADET_Channel *channel,
-                           void *channel_ctx)
+                           const struct GNUNET_CADET_Channel *channel)
 {
-  struct GNUNET_PeerIdentity *peer;
-
-  peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
-      (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
-       // FIXME wait for cadet to change this function
+  struct GNUNET_PeerIdentity *peer = cls;
+  uint32_t *channel_flag;
 
   if (GNUNET_NO == Peers_check_peer_known (peer))
   { /* We don't know a context to that peer */
@@ -858,7 +859,7 @@ cleanup_destroyed_channel (void *cls,
   if (GNUNET_YES == Peers_check_peer_flag (peer, Peers_TO_DESTROY))
   { /* We are in the middle of removing that peer from our knowledge. In this
        case simply make sure that the channels are cleaned. */
-    Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
+    Peers_cleanup_destroyed_channel (cls, channel);
     to_file (file_name_view_log,
              "-%s\t(cleanup channel, ourself)",
              GNUNET_i2s_full (peer));
@@ -872,16 +873,17 @@ cleanup_destroyed_channel (void *cls,
      *  - ourselves  -> cleaning send channel -> clean context
      *  - other peer -> peer probably went down -> remove
      */
-    if (GNUNET_YES == Peers_check_channel_flag (channel_ctx, Peers_CHANNEL_CLEAN))
+    channel_flag = Peers_get_channel_flag (peer, Peers_CHANNEL_ROLE_SENDING);
+    if (GNUNET_YES == Peers_check_channel_flag (channel_flag, Peers_CHANNEL_CLEAN))
     { /* We are about to clean the sending channel. Clean the respective
        * context */
-      Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
+      Peers_cleanup_destroyed_channel (cls, channel);
       return;
     }
     else
     { /* Other peer destroyed our sending channel that he is supposed to keep
        * open. It probably went down. Remove it from our knowledge. */
-      Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
+      Peers_cleanup_destroyed_channel (cls, channel);
       remove_peer (peer);
       return;
     }
@@ -893,17 +895,18 @@ cleanup_destroyed_channel (void *cls,
      *  - ourselves  -> peer tried to establish channel twice -> clean context
      *  - other peer -> peer doesn't want to send us data -> clean
      */
+    channel_flag = Peers_get_channel_flag (peer, Peers_CHANNEL_ROLE_RECEIVING);
     if (GNUNET_YES ==
-        Peers_check_channel_flag (channel_ctx, Peers_CHANNEL_ESTABLISHED_TWICE))
+        Peers_check_channel_flag (channel_flag, Peers_CHANNEL_ESTABLISHED_TWICE))
     { /* Other peer tried to establish a channel to us twice. We do not accept
        * that. Clean the context. */
-      Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
+      Peers_cleanup_destroyed_channel (cls, channel);
       return;
     }
     else
     { /* Other peer doesn't want to send us data anymore. We are free to clean
        * it. */
-      Peers_cleanup_destroyed_channel (cls, channel, channel_ctx);
+      Peers_cleanup_destroyed_channel (cls, channel);
       clean_peer (peer);
       return;
     }
@@ -1023,7 +1026,7 @@ client_respond (void *cls,
   size_needed = sizeof (struct GNUNET_RPS_CS_ReplyMessage) +
                 num_peers * sizeof (struct GNUNET_PeerIdentity);
 
-  GNUNET_assert (GNUNET_SERVER_MAX_MESSAGE_SIZE >= size_needed);
+  GNUNET_assert (GNUNET_MAX_MESSAGE_SIZE >= size_needed);
 
   ev = GNUNET_MQ_msg_extra (out_msg,
                             num_peers * sizeof (struct GNUNET_PeerIdentity),
@@ -1048,7 +1051,6 @@ client_respond (void *cls,
  * Handle RPS request from the client.
  *
  * @param cls closure
- * @param client identification of the client
  * @param message the actual message
  */
 static void
@@ -1065,7 +1067,7 @@ handle_client_request (void *cls,
   size_needed = sizeof (struct GNUNET_RPS_CS_RequestMessage) +
                 num_peers * sizeof (struct GNUNET_PeerIdentity);
 
-  if (GNUNET_SERVER_MAX_MESSAGE_SIZE < size_needed)
+  if (GNUNET_MAX_MESSAGE_SIZE < size_needed)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 "Message received from client has size larger than expected\n");
@@ -1100,12 +1102,11 @@ handle_client_request (void *cls,
  * @brief Handle a message that requests the cancellation of a request
  *
  * @param cls unused
- * @param client the client that requests the cancellation
  * @param message the message containing the id of the request
  */
 static void
 handle_client_request_cancel (void *cls,
-                          const struct GNUNET_RPS_CS_RequestCancelMessage *msg)
+                              const struct GNUNET_RPS_CS_RequestCancelMessage *msg)
 {
   struct ClientContext *cli_ctx = cls;
   struct ReplyCls *rep_cls;
@@ -1157,7 +1158,6 @@ check_client_seed (void *cls, const struct GNUNET_RPS_CS_SeedMessage *msg)
  * Handle seed from the client.
  *
  * @param cls closure
- * @param client identification of the client
  * @param message the actual message
  */
 static void
@@ -1172,7 +1172,7 @@ handle_client_seed (void *cls,
   num_peers = ntohl (msg->num_peers);
   peers = (struct GNUNET_PeerIdentity *) &msg[1];
   //peers = GNUNET_new_array (num_peers, struct GNUNET_PeerIdentity);
-  //GNUNET_memcpy (peers, &in_msg[1], num_peers * sizeof (struct GNUNET_PeerIdentity));
+  //GNUNET_memcpy (peers, &msg[1], num_peers * sizeof (struct GNUNET_PeerIdentity));
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Client seeded peers:\n");
@@ -1200,18 +1200,15 @@ handle_client_seed (void *cls,
  * the channel is blocked for all other communication.
  *
  * @param cls Closure
- * @param channel The channel the CHECK was received over
- * @param channel_ctx The context associated with this channel
  * @param msg The message header
  */
-static int
+static void
 handle_peer_check (void *cls,
-                 struct GNUNET_CADET_Channel *channel,
-                 void **channel_ctx,
-                 const struct GNUNET_MessageHeader *msg)
+                   const struct GNUNET_MessageHeader *msg)
 {
-  GNUNET_CADET_receive_done (channel);
-  return GNUNET_OK;
+  const struct GNUNET_PeerIdentity *peer = cls;
+
+  GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
 }
 
 /**
@@ -1221,24 +1218,16 @@ handle_peer_check (void *cls,
  * in the temporary list for pushed PeerIDs.
  *
  * @param cls Closure
- * @param channel The channel the PUSH was received over
- * @param channel_ctx The context associated with this channel
  * @param msg The message header
  */
-static int
+static void
 handle_peer_push (void *cls,
-                 struct GNUNET_CADET_Channel *channel,
-                 void **channel_ctx,
-                 const struct GNUNET_MessageHeader *msg)
+                  const struct GNUNET_MessageHeader *msg)
 {
-  const struct GNUNET_PeerIdentity *peer;
+  const struct GNUNET_PeerIdentity *peer = cls;
 
   // (check the proof of work (?))
 
-  peer = (const struct GNUNET_PeerIdentity *)
-    GNUNET_CADET_channel_get_info (channel, GNUNET_CADET_OPTION_PEER);
-  // FIXME wait for cadet to change this function
-
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Received PUSH (%s)\n",
        GNUNET_i2s (peer));
@@ -1261,23 +1250,20 @@ handle_peer_push (void *cls,
                                    tmp_att_peer);
       add_peer_array_to_set (peer, 1, att_peer_set);
     }
-    GNUNET_CADET_receive_done (channel);
-    return GNUNET_OK;
+    GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
   }
 
 
   else if (2 == mal_type)
   { /* We attack one single well-known peer - simply ignore */
-    GNUNET_CADET_receive_done (channel);
-    return GNUNET_OK;
+    GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
   }
   #endif /* ENABLE_MALICIOUS */
 
   /* Add the sending peer to the push_map */
   CustomPeerMap_put (push_map, peer);
 
-  GNUNET_CADET_receive_done (channel);
-  return GNUNET_OK;
+  GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
 }
 
 
@@ -1287,24 +1273,15 @@ handle_peer_push (void *cls,
  * Reply with the view of PeerIDs.
  *
  * @param cls Closure
- * @param channel The channel the PULL REQUEST was received over
- * @param channel_ctx The context associated with this channel
  * @param msg The message header
  */
-static int
+static void
 handle_peer_pull_request (void *cls,
-                         struct GNUNET_CADET_Channel *channel,
-                         void **channel_ctx,
-                         const struct GNUNET_MessageHeader *msg)
+                          const struct GNUNET_MessageHeader *msg)
 {
-  struct GNUNET_PeerIdentity *peer;
+  struct GNUNET_PeerIdentity *peer = cls;
   const struct GNUNET_PeerIdentity *view_array;
 
-  peer = (struct GNUNET_PeerIdentity *)
-    GNUNET_CADET_channel_get_info (channel,
-                                   GNUNET_CADET_OPTION_PEER);
-  // FIXME wait for cadet to change this function
-
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REQUEST (%s)\n", GNUNET_i2s (peer));
 
   #ifdef ENABLE_MALICIOUS
@@ -1312,8 +1289,7 @@ handle_peer_pull_request (void *cls,
       || 3 == mal_type)
   { /* Try to maximise representation */
     send_pull_reply (peer, mal_peers, num_mal_peers);
-    GNUNET_CADET_receive_done (channel);
-    return GNUNET_OK;
+    GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
   }
 
   else if (2 == mal_type)
@@ -1322,101 +1298,93 @@ handle_peer_pull_request (void *cls,
     {
       send_pull_reply (peer, mal_peers, num_mal_peers);
     }
-    GNUNET_CADET_receive_done (channel);
-    return GNUNET_OK;
+    GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
   }
   #endif /* ENABLE_MALICIOUS */
 
   view_array = View_get_as_array ();
-
   send_pull_reply (peer, view_array, View_size ());
 
-  GNUNET_CADET_receive_done (channel);
-  return GNUNET_OK;
+  GNUNET_CADET_receive_done (Peers_get_recv_channel (peer));
 }
 
 
 /**
- * Handle PULL REPLY message from another peer.
- *
  * Check whether we sent a corresponding request and
  * whether this reply is the first one.
  *
  * @param cls Closure
- * @param channel The channel the PUSH was received over
- * @param channel_ctx The context associated with this channel
  * @param msg The message header
  */
 static int
-handle_peer_pull_reply (void *cls,
-                        struct GNUNET_CADET_Channel *channel,
-                        void **channel_ctx,
-                        const struct GNUNET_MessageHeader *msg)
+check_peer_pull_reply (void *cls,
+                       const struct GNUNET_RPS_P2P_PullReplyMessage *msg)
 {
-  struct GNUNET_RPS_P2P_PullReplyMessage *in_msg;
-  struct GNUNET_PeerIdentity *peers;
-  struct GNUNET_PeerIdentity *sender;
-  uint32_t i;
-#ifdef ENABLE_MALICIOUS
-  struct AttackedPeer *tmp_att_peer;
-#endif /* ENABLE_MALICIOUS */
+  struct GNUNET_PeerIdentity *sender = cls;
 
-  /* Check for protocol violation */
-  if (sizeof (struct GNUNET_RPS_P2P_PullReplyMessage) > ntohs (msg->size))
+  if (sizeof (struct GNUNET_RPS_P2P_PullReplyMessage) > ntohs (msg->header.size))
   {
     GNUNET_break_op (0);
-    GNUNET_CADET_receive_done (channel);
     return GNUNET_SYSERR;
   }
 
-  in_msg = (struct GNUNET_RPS_P2P_PullReplyMessage *) msg;
-  if ((ntohs (msg->size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
-      sizeof (struct GNUNET_PeerIdentity) != ntohl (in_msg->num_peers))
+  if ((ntohs (msg->header.size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
+      sizeof (struct GNUNET_PeerIdentity) != ntohl (msg->num_peers))
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
         "message says it sends %" PRIu32 " peers, have space for %lu peers\n",
-        ntohl (in_msg->num_peers),
-        (ntohs (msg->size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
+        ntohl (msg->num_peers),
+        (ntohs (msg->header.size) - sizeof (struct GNUNET_RPS_P2P_PullReplyMessage)) /
             sizeof (struct GNUNET_PeerIdentity));
     GNUNET_break_op (0);
-    GNUNET_CADET_receive_done (channel);
     return GNUNET_SYSERR;
   }
 
-  // Guess simply casting isn't the nicest way...
-  // FIXME wait for cadet to change this function
-  sender = (struct GNUNET_PeerIdentity *)
-      GNUNET_CADET_channel_get_info (channel, GNUNET_CADET_OPTION_PEER);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REPLY (%s)\n", GNUNET_i2s (sender));
-
   if (GNUNET_YES != Peers_check_peer_flag (sender, Peers_PULL_REPLY_PENDING))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
         "Received a pull reply from a peer we didn't request one from!\n");
-    GNUNET_CADET_receive_done (channel);
     GNUNET_break_op (0);
-    return GNUNET_OK;
+    return GNUNET_SYSERR;
   }
+  return GNUNET_OK;
+}
+
+/**
+ * Handle PULL REPLY message from another peer.
+ *
+ * @param cls Closure
+ * @param msg The message header
+ */
+static void
+handle_peer_pull_reply (void *cls,
+                        const struct GNUNET_RPS_P2P_PullReplyMessage *msg)
+{
+  struct GNUNET_PeerIdentity *peers;
+  struct GNUNET_PeerIdentity *sender = cls;
+  uint32_t i;
+#ifdef ENABLE_MALICIOUS
+  struct AttackedPeer *tmp_att_peer;
+#endif /* ENABLE_MALICIOUS */
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PULL REPLY (%s)\n", GNUNET_i2s (sender));
 
   #ifdef ENABLE_MALICIOUS
   // We shouldn't even receive pull replies as we're not sending
   if (2 == mal_type)
   {
-    GNUNET_CADET_receive_done (channel);
-    return GNUNET_OK;
+    GNUNET_CADET_receive_done (Peers_get_recv_channel (sender));
   }
   #endif /* ENABLE_MALICIOUS */
 
   /* Do actual logic */
-  peers = (struct GNUNET_PeerIdentity *) &in_msg[1];
+  peers = (struct GNUNET_PeerIdentity *) &msg[1];
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "PULL REPLY received, got following %u peers:\n",
-       ntohl (in_msg->num_peers));
+       ntohl (msg->num_peers));
 
-  for (i = 0 ; i < ntohl (in_msg->num_peers) ; i++)
+  for (i = 0; i < ntohl (msg->num_peers); i++)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "%u. %s\n",
@@ -1466,8 +1434,7 @@ handle_peer_pull_reply (void *cls,
   Peers_unset_peer_flag (sender, Peers_PULL_REPLY_PENDING);
   clean_peer (sender);
 
-  GNUNET_CADET_receive_done (channel);
-  return GNUNET_OK;
+  GNUNET_CADET_receive_done (Peers_get_recv_channel (sender));
 }
 
 
@@ -2273,15 +2240,24 @@ run (void *cls,
      const struct GNUNET_CONFIGURATION_Handle *c,
      struct GNUNET_SERVICE_Handle *service)
 {
-  static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
-    {&handle_peer_check       , GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE,
-      sizeof (struct GNUNET_MessageHeader)},
-    {&handle_peer_push        , GNUNET_MESSAGE_TYPE_RPS_PP_PUSH,
-      sizeof (struct GNUNET_MessageHeader)},
-    {&handle_peer_pull_request, GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST,
-      sizeof (struct GNUNET_MessageHeader)},
-    {&handle_peer_pull_reply  , GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY, 0},
-    {NULL, 0, 0}
+  struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
+    GNUNET_MQ_hd_fixed_size (peer_check,
+                             GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE,
+                             struct GNUNET_MessageHeader,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (peer_push,
+                             GNUNET_MESSAGE_TYPE_RPS_PP_PUSH,
+                             struct GNUNET_MessageHeader,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (peer_pull_request,
+                             GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REQUEST,
+                             struct GNUNET_MessageHeader,
+                             NULL),
+    GNUNET_MQ_hd_var_size (peer_pull_reply,
+                           GNUNET_MESSAGE_TYPE_RPS_PP_PULL_REPLY,
+                           struct GNUNET_RPS_P2P_PullReplyMessage,
+                           NULL),
+    GNUNET_MQ_handler_end ()
   };
 
   int size;
@@ -2373,21 +2349,23 @@ run (void *cls,
 
 
   /* Initialise cadet */
-  cadet_handle = GNUNET_CADET_connect (cfg,
-                                       cls,
-                                       &cleanup_destroyed_channel,
-                                       cadet_handlers);
+  cadet_handle = GNUNET_CADET_connect (cfg);
   GNUNET_assert (NULL != cadet_handle);
   GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_RPS,
                       strlen (GNUNET_APPLICATION_PORT_RPS),
                       &port);
-  GNUNET_CADET_open_port (cadet_handle,
-                          &port,
-                          &Peers_handle_inbound_channel, cls);
+  cadet_port = GNUNET_CADET_open_port (cadet_handle,
+                                       &port,
+                                       &Peers_handle_inbound_channel, /* Connect handler */
+                                       NULL, /* cls */
+                                       NULL, /* WindowSize handler */
+                                       cleanup_destroyed_channel, /* Disconnect handler */
+                                       cadet_handlers);
 
 
   peerinfo_handle = GNUNET_PEERINFO_connect (cfg);
-  Peers_initialise (fn_valid_peers, cadet_handle, &own_identity);
+  Peers_initialise (fn_valid_peers, cadet_handle, cleanup_destroyed_channel,
+                    cadet_handlers, &own_identity);
   GNUNET_free (fn_valid_peers);
 
   /* Initialise sampler */
index e0b278bd00225d9cfc85281cedfe4360409cde47..58aa84ccf5613a43a85f5bb45e63701fa954e874 100644 (file)
@@ -251,6 +251,17 @@ static const struct GNUNET_PeerIdentity *own_identity;
  */
 static struct GNUNET_CADET_Handle *cadet_handle;
 
+/**
+ * @brief Disconnect handler
+ */
+static GNUNET_CADET_DisconnectEventHandler cleanup_destroyed_channel;
+
+/**
+ * @brief cadet handlers
+ */
+static const struct GNUNET_MQ_MessageHandler *cadet_handlers;
+
+
 
 /**
  * @brief Get the #PeerContext associated with a peer
@@ -523,10 +534,13 @@ get_channel (const struct GNUNET_PeerIdentity *peer)
                         &port);
     peer_ctx->send_channel =
       GNUNET_CADET_channel_create (cadet_handle,
-                                   peer_ctx->send_channel_flags, /* context */
+                                   (struct GNUNET_PeerIdentity *) peer, /* context */
                                    peer,
                                    &port,
-                                   GNUNET_CADET_OPTION_RELIABLE);
+                                   GNUNET_CADET_OPTION_RELIABLE,
+                                   NULL, /* WindowSize handler */
+                                   cleanup_destroyed_channel, /* Disconnect handler */
+                                   cadet_handlers);
   }
   GNUNET_assert (NULL != peer_ctx->send_channel);
   return peer_ctx->send_channel;
@@ -552,7 +566,7 @@ get_mq (const struct GNUNET_PeerIdentity *peer)
   if (NULL == peer_ctx->mq)
   {
     (void) get_channel (peer);
-    peer_ctx->mq = GNUNET_CADET_mq_create (peer_ctx->send_channel);
+    peer_ctx->mq = GNUNET_CADET_get_mq (peer_ctx->send_channel);
   }
   return peer_ctx->mq;
 }
@@ -649,9 +663,7 @@ remove_pending_message (struct PendingMessage *pending_msg)
   GNUNET_CONTAINER_DLL_remove (peer_ctx->pending_messages_head,
                                peer_ctx->pending_messages_tail,
                                pending_msg);
-  /* FIXME We are not able to cancel messages as #GNUNET_CADET_mq_create () does
-   * not set a #GNUNET_MQ_CancelImpl */
-  /* GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev); */
+  GNUNET_MQ_send_cancel (peer_ctx->pending_messages_head->ev);
   GNUNET_free (pending_msg);
 }
 
@@ -932,15 +944,21 @@ restore_valid_peers ()
  *
  * @param fn_valid_peers filename of the file used to store valid peer ids
  * @param cadet_h cadet handle
+ * @param disconnect_handler Disconnect handler
+ * @param c_handlers cadet handlers
  * @param own_id own peer identity
  */
 void
 Peers_initialise (char* fn_valid_peers,
                   struct GNUNET_CADET_Handle *cadet_h,
+                  GNUNET_CADET_DisconnectEventHandler disconnect_handler,
+                  const struct GNUNET_MQ_MessageHandler *c_handlers,
                   const struct GNUNET_PeerIdentity *own_id)
 {
   filename_valid_peers = GNUNET_strdup (fn_valid_peers);
   cadet_handle = cadet_h;
+  cleanup_destroyed_channel = disconnect_handler;
+  cadet_handlers = c_handlers;
   own_identity = own_id;
   peer_map = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
   valid_peers = GNUNET_CONTAINER_multipeermap_create (4, GNUNET_NO);
@@ -1279,6 +1297,34 @@ Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags
   return check_channel_flag_set (channel_flags, flags);
 }
 
+/**
+ * @brief Get the flags for the channel in @a role for @a peer.
+ *
+ * @param peer Peer to get the channel flags for.
+ * @param role Role of channel to get flags for
+ *
+ * @return The flags.
+ */
+uint32_t *
+Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer,
+                        enum Peers_ChannelRole role)
+{
+  const struct PeerContext *peer_ctx;
+
+  peer_ctx = get_peer_ctx (peer);
+  if (Peers_CHANNEL_ROLE_SENDING == role)
+  {
+    return peer_ctx->send_channel_flags;
+  }
+  else if (Peers_CHANNEL_ROLE_RECEIVING == role)
+  {
+    return peer_ctx->recv_channel_flags;
+  }
+  else
+  {
+    GNUNET_assert (0);
+  }
+}
 
 /**
  * @brief Check whether we have information about the given peer.
@@ -1358,8 +1404,6 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
  * @param cls The closure
  * @param channel The channel the peer wants to establish
  * @param initiator The peer's peer ID
- * @param port The port the channel is being established over
- * @param options Further options
  *
  * @return initial channel context for the channel
  *         (can be NULL -- that's not an error)
@@ -1367,9 +1411,7 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer)
 void *
 Peers_handle_inbound_channel (void *cls,
                               struct GNUNET_CADET_Channel *channel,
-                              const struct GNUNET_PeerIdentity *initiator,
-                              const struct GNUNET_HashCode *port,
-                              enum GNUNET_CADET_ChannelOption options)
+                              const struct GNUNET_PeerIdentity *initiator)
 {
   struct PeerContext *peer_ctx;
 
@@ -1387,10 +1429,10 @@ Peers_handle_inbound_channel (void *cls,
                       Peers_CHANNEL_ESTABLISHED_TWICE);
     GNUNET_CADET_channel_destroy (channel);
     /* return the channel context */
-    return peer_ctx->recv_channel_flags;
+    return &peer_ctx->peer_id;
   }
   peer_ctx->recv_channel = channel;
-  return peer_ctx->recv_channel_flags;
+  return &peer_ctx->peer_id;
 }
 
 
@@ -1500,16 +1542,11 @@ Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer)
  */
 void
 Peers_cleanup_destroyed_channel (void *cls,
-                                 const struct GNUNET_CADET_Channel *channel,
-                                 void *channel_ctx)
+                                 const struct GNUNET_CADET_Channel *channel)
 {
-  struct GNUNET_PeerIdentity *peer;
+  struct GNUNET_PeerIdentity *peer = cls;
   struct PeerContext *peer_ctx;
 
-  peer = (struct GNUNET_PeerIdentity *) GNUNET_CADET_channel_get_info (
-      (struct GNUNET_CADET_Channel *) channel, GNUNET_CADET_OPTION_PEER);
-       // FIXME wait for cadet to change this function
-
   if (GNUNET_NO == Peers_check_peer_known (peer))
   {/* We don't want to implicitly create a context that we're about to kill */
   LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1635,4 +1672,23 @@ Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
   return GNUNET_NO;
 }
 
+/**
+ * @brief Get the recv_channel of @a peer.
+ * Needed to correctly handle (call #GNUNET_CADET_receive_done()) incoming
+ * messages.
+ *
+ * @param peer The peer to get the recv_channel from.
+ *
+ * @return The recv_channel.
+ */
+struct GNUNET_CADET_Channel *
+Peers_get_recv_channel (const struct GNUNET_PeerIdentity *peer)
+{
+  struct PeerContext *peer_ctx;
+
+  GNUNET_assert (GNUNET_YES == Peers_check_peer_known (peer));
+  peer_ctx = get_peer_ctx (peer);
+  return peer_ctx->recv_channel;
+}
+
 /* end of gnunet-service-rps_peers.c */
index bbac8600339c904119b36f5ce25615576e551858..15970a7cee4e606b393fc377e80541f769429420 100644 (file)
@@ -117,11 +117,15 @@ typedef int
  *
  * @param fn_valid_peers filename of the file used to store valid peer ids
  * @param cadet_h cadet handle
+ * @param disconnect_handler Disconnect handler
+ * @param c_handlers cadet handlers
  * @param own_id own peer identity
  */
 void
 Peers_initialise (char* fn_valid_peers,
                   struct GNUNET_CADET_Handle *cadet_h,
+                  GNUNET_CADET_DisconnectEventHandler disconnect_handler,
+                  const struct GNUNET_MQ_MessageHandler *c_handlers,
                   const struct GNUNET_PeerIdentity *own_id);
 
 /**
@@ -258,6 +262,18 @@ Peers_unset_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags
 int
 Peers_check_channel_flag (uint32_t *channel_flags, enum Peers_ChannelFlags flags);
 
+/**
+ * @brief Get the flags for the channel in @a role for @a peer.
+ *
+ * @param peer Peer to get the channel flags for.
+ * @param role Role of channel to get flags for
+ *
+ * @return The flags.
+ */
+uint32_t *
+Peers_get_channel_flag (const struct GNUNET_PeerIdentity *peer,
+                        enum Peers_ChannelRole role);
+
 /**
  * @brief Check whether we have information about the given peer.
  *
@@ -312,8 +328,6 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer);
  * @param cls The closure
  * @param channel The channel the peer wants to establish
  * @param initiator The peer's peer ID
- * @param port The port the channel is being established over
- * @param options Further options
  *
  * @return initial channel context for the channel
  *         (can be NULL -- that's not an error)
@@ -321,9 +335,7 @@ Peers_check_peer_send_intention (const struct GNUNET_PeerIdentity *peer);
 void *
 Peers_handle_inbound_channel (void *cls,
                               struct GNUNET_CADET_Channel *channel,
-                              const struct GNUNET_PeerIdentity *initiator,
-                              const struct GNUNET_HashCode *port,
-                              enum GNUNET_CADET_ChannelOption options);
+                              const struct GNUNET_PeerIdentity *initiator);
 
 /**
  * @brief Check whether a sending channel towards the given peer exists
@@ -379,8 +391,7 @@ Peers_destroy_sending_channel (const struct GNUNET_PeerIdentity *peer);
  */
 void
 Peers_cleanup_destroyed_channel (void *cls,
-                                 const struct GNUNET_CADET_Channel *channel,
-                                 void *channel_ctx);
+                                 const struct GNUNET_CADET_Channel *channel);
 
 /**
  * @brief Send a message to another peer.
@@ -411,4 +422,16 @@ int
 Peers_schedule_operation (const struct GNUNET_PeerIdentity *peer,
                           const PeerOp peer_op);
 
+/**
+ * @brief Get the recv_channel of @a peer.
+ * Needed to correctly handle (call #GNUNET_CADET_receive_done()) incoming
+ * messages.
+ *
+ * @param peer The peer to get the recv_channel from.
+ *
+ * @return The recv_channel.
+ */
+struct GNUNET_CADET_Channel *
+Peers_get_recv_channel (const struct GNUNET_PeerIdentity *peer);
+
 /* end of gnunet-service-rps_peers.h */
index 504f28b92091aefecf905865707079f01a44c9b6..ccd480086967d8c00481e41840a00542e902a878 100644 (file)
@@ -389,12 +389,12 @@ GNUNET_RPS_seed_ids (struct GNUNET_RPS_Handle *h,
     n * sizeof (struct GNUNET_PeerIdentity);
   /* The number of peers that fits in one message together with
    * the respective header */
-  num_peers_max = (GNUNET_SERVER_MAX_MESSAGE_SIZE -
+  num_peers_max = (GNUNET_MAX_MESSAGE_SIZE -
       sizeof (struct GNUNET_RPS_CS_SeedMessage)) /
     sizeof (struct GNUNET_PeerIdentity);
   tmp_peer_pointer = ids;
 
-  while (GNUNET_SERVER_MAX_MESSAGE_SIZE < size_needed)
+  while (GNUNET_MAX_MESSAGE_SIZE < size_needed)
   {
     ev = GNUNET_MQ_msg_extra (msg, num_peers_max * sizeof (struct GNUNET_PeerIdentity),
         GNUNET_MESSAGE_TYPE_RPS_CS_SEED);
@@ -463,12 +463,12 @@ GNUNET_RPS_act_malicious (struct GNUNET_RPS_Handle *h,
     num_peers * sizeof (struct GNUNET_PeerIdentity);
   /* The number of peers that fit in one message together with
    * the respective header */
-  num_peers_max = (GNUNET_SERVER_MAX_MESSAGE_SIZE -
+  num_peers_max = (GNUNET_MAX_MESSAGE_SIZE -
       sizeof (struct GNUNET_RPS_CS_SeedMessage)) /
     sizeof (struct GNUNET_PeerIdentity);
   tmp_peer_pointer = peer_ids;
 
-  while (GNUNET_SERVER_MAX_MESSAGE_SIZE < size_needed)
+  while (GNUNET_MAX_MESSAGE_SIZE < size_needed)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Too many peers to send at once, sending %" PRIu32 " (all we can so far)\n",
index 1ce174454dc8e909675442775057ad12e81e3793..acd3a165da9eb26a2025cdd2f8b7e85db3cfd7fe 100644 (file)
@@ -546,7 +546,7 @@ seed_peers_big (void *cls)
   unsigned int i;
 
   seed_msg_size = 8; /* sizeof (struct GNUNET_RPS_CS_SeedMessage) */
-  num_peers_max = (GNUNET_SERVER_MAX_MESSAGE_SIZE - seed_msg_size) /
+  num_peers_max = (GNUNET_MAX_MESSAGE_SIZE - seed_msg_size) /
     sizeof (struct GNUNET_PeerIdentity);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
       "Peers that fit in one seed msg; %u\n",
@@ -980,7 +980,7 @@ seed_cb (struct RPSPeer *rps_peer)
 static void
 seed_big_cb (struct RPSPeer *rps_peer)
 {
-  // TODO test seeding > GNUNET_SERVER_MAX_MESSAGE_SIZE peers
+  // TODO test seeding > GNUNET_MAX_MESSAGE_SIZE peers
   GNUNET_SCHEDULER_add_delayed (
       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2),
       seed_peers_big, rps_peer);
@@ -1457,7 +1457,7 @@ main (int argc, char *argv[])
 
   else if (strstr (argv[0], "_seed_big") != NULL)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_SERVER_MAX_MESSAGE_SIZE)\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test seeding (num_peers > GNUNET_MAX_MESSAGE_SIZE)\n");
     num_peers = 1;
     cur_test_run.name = "test-rps-seed-big";
     cur_test_run.main_test = seed_big_cb;
index 37ed1974c0781eefcc912d87232fc3dde2aaca9c..9cd677fef5134d30159f7ba7806e8be8a5d28d7d 100644 (file)
@@ -59,25 +59,25 @@ check ()
   memset (&own_id, 1, sizeof (own_id));
 
   /* Do nothing */
-  Peers_initialise (FN_VALID_PEERS, NULL, &own_id);
+  Peers_initialise (FN_VALID_PEERS, NULL, NULL, NULL, &own_id);
   Peers_terminate ();
 
 
   /* Create peer */
-  Peers_initialise (FN_VALID_PEERS, NULL, &own_id);
+  Peers_initialise (FN_VALID_PEERS, NULL, NULL, NULL, &own_id);
   CHECK (GNUNET_YES == Peers_insert_peer (&k1));
   Peers_terminate ();
 
 
   /* Create peer */
-  Peers_initialise (FN_VALID_PEERS, NULL, &own_id);
+  Peers_initialise (FN_VALID_PEERS, NULL, NULL, NULL, &own_id);
   CHECK (GNUNET_YES == Peers_insert_peer (&k1));
   CHECK (GNUNET_YES == Peers_remove_peer (&k1));
   Peers_terminate ();
 
 
   /* Insertion and Removal */
-  Peers_initialise (FN_VALID_PEERS, NULL, &own_id);
+  Peers_initialise (FN_VALID_PEERS, NULL, NULL, NULL, &own_id);
   CHECK (GNUNET_NO  == Peers_check_peer_known (&k1));
 
   CHECK (GNUNET_YES == Peers_insert_peer (&k1));
index 98829408af5995c309536c77d19d57f50e9cd38d..10e04284f188b72b316e8a40b44dc1f3a250890f 100644 (file)
@@ -42,7 +42,7 @@ gnunet_service_scalarproduct_alice_SOURCES = \
   gnunet-service-scalarproduct_alice.c
 gnunet_service_scalarproduct_alice_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/set/libgnunetset.la \
   $(LIBGCRYPT_LIBS) \
   -lgcrypt \
@@ -53,7 +53,7 @@ gnunet_service_scalarproduct_bob_SOURCES = \
   gnunet-service-scalarproduct_bob.c
 gnunet_service_scalarproduct_bob_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/set/libgnunetset.la \
   $(LIBGCRYPT_LIBS) \
   -lgcrypt \
@@ -64,7 +64,7 @@ gnunet_service_scalarproduct_ecc_alice_SOURCES = \
   gnunet-service-scalarproduct-ecc_alice.c
 gnunet_service_scalarproduct_ecc_alice_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/set/libgnunetset.la \
   $(LIBGCRYPT_LIBS) \
   -lgcrypt \
@@ -75,7 +75,7 @@ gnunet_service_scalarproduct_ecc_bob_SOURCES = \
   gnunet-service-scalarproduct-ecc_bob.c
 gnunet_service_scalarproduct_ecc_bob_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/set/libgnunetset.la \
   $(LIBGCRYPT_LIBS) \
   -lgcrypt \
index aa894b61d644f44f6a6d6f0af53c2acacd4400ee..5d0fce2b1986c5dc1131ba039c5426f15fa9bc79 100644 (file)
@@ -343,16 +343,32 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'e', "elements", "\"key1,val1;key2,val2;...,keyn,valn;\"",
-      gettext_noop ("A comma separated list of elements to compare as vector with our remote peer."),
-      1, &GNUNET_GETOPT_set_string, &input_elements},
-    {'p', "peer", "PEERID",
-      gettext_noop ("[Optional] peer to calculate our scalarproduct with. If this parameter is not given, the service will wait for a remote peer to compute the request."),
-      1, &GNUNET_GETOPT_set_string, &input_peer_id},
-    {'k', "key", "TRANSACTION_ID",
-      gettext_noop ("Transaction ID shared with peer."),
-      1, &GNUNET_GETOPT_set_string, &input_session_key},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_STRING ('e',
+                                 "elements",
+                                 "\"key1,val1;key2,val2;...,keyn,valn;\"",
+                                 gettext_noop ("A comma separated list of elements to compare as vector with our remote peer."),
+                                 &input_elements),
+
+    GNUNET_GETOPT_OPTION_STRING ('e',
+                                 "elements",
+                                 "\"key1,val1;key2,val2;...,keyn,valn;\"",
+                                 gettext_noop ("A comma separated list of elements to compare as vector with our remote peer."),
+                                 &input_elements),
+
+    GNUNET_GETOPT_OPTION_STRING ('p',
+                                 "peer",
+                                 "PEERID",
+                                 gettext_noop ("[Optional] peer to calculate our scalarproduct with. If this parameter is not given, the service will wait for a remote peer to compute the request."),
+                                 &input_peer_id),
+
+    GNUNET_GETOPT_OPTION_STRING ('k',
+                                 "key",
+                                 "TRANSACTION_ID",
+                                 gettext_noop ("Transaction ID shared with peer."),
+                                 &input_session_key),
+
     GNUNET_GETOPT_OPTION_END
   };
 
index ca92fb9ead83ce0f5456a4ad3cf4563660a6cb42..c0b33f8efe7ca0f99b1398db90ec6f3dade27a88 100644 (file)
@@ -842,7 +842,7 @@ client_request_complete_alice (struct AliceServiceSession *s)
               "Creating new channel for session with key %s.\n",
               GNUNET_h2s (&s->session_id));
   s->channel
-    = GNUNET_CADET_channel_creatE (my_cadet,
+    = GNUNET_CADET_channel_create (my_cadet,
                                    s,
                                    &s->peer,
                                    &s->session_id,
@@ -1173,7 +1173,7 @@ run (void *cls,
   GNUNET_CRYPTO_ecc_rnd_mpi (edc,
                              &my_privkey,
                              &my_privkey_inv);
-  my_cadet = GNUNET_CADET_connecT (cfg);
+  my_cadet = GNUNET_CADET_connect (cfg);
   if (NULL == my_cadet)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
index 3851ca76347b2f2aa797a937ebba329c31deda41..0b0333332a34b56e908fea8714c52671d28f35fb 100644 (file)
@@ -950,7 +950,7 @@ handle_bob_client_message (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received client request, opening port %s!\n",
               GNUNET_h2s (&msg->session_key));
-  s->port = GNUNET_CADET_open_porT (my_cadet,
+  s->port = GNUNET_CADET_open_port (my_cadet,
                                     &msg->session_key,
                                     &cb_channel_incoming,
                                     s,
@@ -1054,7 +1054,7 @@ run (void *cls,
   /* We don't really do DLOG, so we can setup with very minimal resources */
   edc = GNUNET_CRYPTO_ecc_dlog_prepare (4 /* max value */,
                                         2 /* RAM */);
-  my_cadet = GNUNET_CADET_connecT (cfg);
+  my_cadet = GNUNET_CADET_connect (cfg);
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
                                 NULL);
   if (NULL == my_cadet)
index 6d7a0a3b84e7a18077655fc4311f63d5669211d5..a55d03900972152185e32e6be70bacada8209c16 100644 (file)
@@ -1076,7 +1076,7 @@ client_request_complete_alice (struct AliceServiceSession *s)
               "Creating new channel for session with key %s.\n",
               GNUNET_h2s (&s->session_id));
   s->channel
-    = GNUNET_CADET_channel_creatE (my_cadet,
+    = GNUNET_CADET_channel_create (my_cadet,
                                    s,
                                    &s->peer,
                                    &s->session_id,
@@ -1398,7 +1398,7 @@ run (void *cls,
                     GNUNET_CRYPTO_PAILLIER_BITS / 3);
   GNUNET_CRYPTO_paillier_create (&my_pubkey,
                                  &my_privkey);
-  my_cadet = GNUNET_CADET_connecT (cfg);
+  my_cadet = GNUNET_CADET_connect (cfg);
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
                                 NULL);
   if (NULL == my_cadet)
index f3b5327f1d75f2a86b316444c1cb990299f83cf7..0c38cb42693d226375b70a74c2469c12f19b886b 100644 (file)
@@ -1230,7 +1230,7 @@ handle_bob_client_message (void *cls,
   }
   GNUNET_SERVICE_client_continue (s->client);
   /* We're ready, open the port */
-  s->port = GNUNET_CADET_open_porT (my_cadet,
+  s->port = GNUNET_CADET_open_port (my_cadet,
                                     &msg->session_key,
                                     &cb_channel_incoming,
                                     s,
@@ -1336,7 +1336,7 @@ run (void *cls,
 
   GNUNET_CRYPTO_paillier_create (&my_pubkey,
                                  &my_privkey);
-  my_cadet = GNUNET_CADET_connecT (cfg);
+  my_cadet = GNUNET_CADET_connect (cfg);
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
                                 NULL);
   if (NULL == my_cadet)
index df9f8d196c52e69ad7808e9ab4953de4650ed8cb..05c122e74dbd1f0743fbbcdb6971d2bc8c81948f 100644 (file)
@@ -268,7 +268,7 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl
     GNUNET_free (h);
     return NULL;
   }
-  possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct BobComputationMessage))
+  possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (struct BobComputationMessage))
     / sizeof (struct GNUNET_SCALARPRODUCT_Element);
   todo = GNUNET_MIN (possible,
                      element_count);
@@ -285,7 +285,7 @@ GNUNET_SCALARPRODUCT_accept_computation (const struct GNUNET_CONFIGURATION_Handl
   element_count_transfered = todo;
   GNUNET_MQ_send (h->mq,
                   env);
-  possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (*mmsg))
+  possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (*mmsg))
     / sizeof (struct GNUNET_SCALARPRODUCT_Element);
   while (element_count_transfered < element_count)
   {
@@ -426,7 +426,7 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle
   h->cfg = cfg;
   h->key = *session_key;
 
-  possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceComputationMessage))
+  possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (struct AliceComputationMessage))
       / sizeof (struct GNUNET_SCALARPRODUCT_Element);
   todo = GNUNET_MIN (possible,
                      element_count);
@@ -445,7 +445,7 @@ GNUNET_SCALARPRODUCT_start_computation (const struct GNUNET_CONFIGURATION_Handle
   GNUNET_MQ_send (h->mq,
                   env);
   element_count_transfered = todo;
-  possible = (GNUNET_SERVER_MAX_MESSAGE_SIZE - 1 - sizeof (*mmsg))
+  possible = (GNUNET_MAX_MESSAGE_SIZE - 1 - sizeof (*mmsg))
     / sizeof (struct GNUNET_SCALARPRODUCT_Element);
   while (element_count_transfered < element_count)
   {
index 485183e36f6c0a9f6db25aa3f582942b704145e4..4b9a06c40ebb6ea1c7d6fa402de527c3b2ef4618 100644 (file)
@@ -17,9 +17,6 @@ if USE_COVERAGE
 endif
 
 
-bin_PROGRAMS = \
- gnunet-secretsharing-profiler
-
 libexec_PROGRAMS = \
  gnunet-service-secretsharing
 
@@ -57,6 +54,9 @@ libgnunetsecretsharing_la_LDFLAGS = \
   $(GN_LIB_LDFLAGS)
 
 if HAVE_TESTING
+bin_PROGRAMS = \
+ gnunet-secretsharing-profiler
+
 check_PROGRAMS = \
  test_secretsharing_api
 
index 3ff5d7fdd3dc97034ecc1187d0bd9a8b65145542..e66019dc6996b9855c6e5687a546bf34770321a9 100644 (file)
@@ -41,7 +41,7 @@ static unsigned int threshold = 2;
 /**
  * Should we try to decrypt a value after the key generation?
  */
-static unsigned int decrypt = GNUNET_NO;
+static int decrypt = GNUNET_NO;
 
 /**
  * When would we like to see the operation finished?
@@ -88,7 +88,7 @@ static unsigned int num_decrypted;
 
 static struct GNUNET_HashCode session_id;
 
-static int verbose;
+static unsigned int verbose;
 
 static struct GNUNET_SECRETSHARING_Plaintext reference_plaintext;
 
@@ -602,26 +602,41 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char **argv)
 {
-   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-      { 'n', "num-peers", NULL,
-        gettext_noop ("number of peers in consensus"),
-        GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers },
-      { 'D', "delay", NULL,
-        gettext_noop ("dkg start delay"),
-        GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &delay },
-      { 't', "timeout", NULL,
-        gettext_noop ("dkg timeout"),
-        GNUNET_YES, &GNUNET_GETOPT_set_relative_time, &timeout },
-      { 'k', "threshold", NULL,
-        gettext_noop ("threshold"),
-        GNUNET_YES, &GNUNET_GETOPT_set_uint, &threshold },
-      { 'd', "decrypt", NULL,
-        gettext_noop ("also profile decryption"),
-        GNUNET_NO, &GNUNET_GETOPT_set_one, &decrypt },
-      { 'V', "verbose", NULL,
-        gettext_noop ("be more verbose (print received values)"),
-        GNUNET_NO, &GNUNET_GETOPT_set_one, &verbose },
-      GNUNET_GETOPT_OPTION_END
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('n',
+                                   "num-peers",
+                                   NULL,
+                                   gettext_noop ("number of peers in consensus"),
+                                   &num_peers),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('D',
+                                            "delay",
+                                            NULL,
+                                            gettext_noop ("dkg start delay"),
+                                            &delay),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
+                                            "timeout",
+                                            NULL,
+                                            gettext_noop ("dkg timeout"),
+                                            &timeout),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('k',
+                                   "threshold",
+                                   NULL,
+                                   gettext_noop ("threshold"),
+                                   &threshold),
+    
+    GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                  "descrypt",
+                                  gettext_noop ("also profile decryption"),
+                                  &decrypt),
+
+
+    GNUNET_GETOPT_OPTION_VERBOSE (&verbose),
+
+    GNUNET_GETOPT_OPTION_END
   };
   delay = GNUNET_TIME_UNIT_ZERO;
   timeout = GNUNET_TIME_UNIT_MINUTES;
index ddbe815766f312da393fd109f69e7f35df0d472c..ccdba12c29e45c0fe5fc883788778b1591642484 100644 (file)
@@ -108,20 +108,17 @@ struct DecryptPeerInfo
 };
 
 
+/**
+ * State we keep per client.
+ */
+struct ClientState;
+
+
 /**
  * Session to establish a threshold-shared secret.
  */
 struct KeygenSession
 {
-  /**
-   * Keygen sessions are held in a linked list.
-   */
-  struct KeygenSession *next;
-
-  /**
-   * Keygen sessions are held in a linked list.
-   */
-  struct KeygenSession *prev;
 
   /**
    * Current consensus, used for both DKG rounds.
@@ -129,15 +126,9 @@ struct KeygenSession
   struct GNUNET_CONSENSUS_Handle *consensus;
 
   /**
-   * Client that is interested in the result
-   * of this key generation session.
-   */
-  struct GNUNET_SERVER_Client *client;
-
-  /**
-   * Message queue for 'client'
+   * Which client is this for?
    */
-  struct GNUNET_MQ_Handle *client_mq;
+  struct ClientState *cs;
 
   /**
    * Randomly generated coefficients of the polynomial for sharing our
@@ -223,15 +214,6 @@ struct KeygenSession
  */
 struct DecryptSession
 {
-  /**
-   * Decrypt sessions are stored in a linked list.
-   */
-  struct DecryptSession *next;
-
-  /**
-   * Decrypt sessions are stored in a linked list.
-   */
-  struct DecryptSession *prev;
 
   /**
    * Handle to the consensus over partial decryptions.
@@ -239,14 +221,9 @@ struct DecryptSession
   struct GNUNET_CONSENSUS_Handle *consensus;
 
   /**
-   * Client connected to us.
+   * Which client is this for?
    */
-  struct GNUNET_SERVER_Client *client;
-
-  /**
-   * Message queue for 'client'.
-   */
-  struct GNUNET_MQ_Handle *client_mq;
+  struct ClientState *cs;
 
   /**
    * When should we start communicating for decryption?
@@ -279,24 +256,32 @@ struct DecryptSession
 
 
 /**
- * Decrypt sessions are held in a linked list.
+ * State we keep per client.
  */
-static struct DecryptSession *decrypt_sessions_head;
+struct ClientState
+{
+  /**
+   * Decrypt session of the client, if any.
+   */
+  struct DecryptSession *decrypt_session;
 
-/**
* Decrypt sessions are held in a linked list.
- */
-static struct DecryptSession *decrypt_sessions_tail;
+  /**
  * Keygen session of the client, if any.
  */
+  struct KeygenSession *keygen_session;
 
-/**
- * Decrypt sessions are held in a linked list.
- */
-static struct KeygenSession *keygen_sessions_head;
+  /**
+   * Client this is about.
+   */
+  struct GNUNET_SERVICE_Client *client;
+
+  /**
+   * MQ to talk to @a client.
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+};
 
-/**
- * Decrypt sessions are held in a linked list.
- */
-static struct KeygenSession *keygen_sessions_tail;
 
 /**
  * The ElGamal prime field order as libgcrypt mpi.
@@ -331,11 +316,6 @@ static struct GNUNET_CRYPTO_EddsaPrivateKey *my_peer_private_key;
  */
 static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
-/**
- * Server for this service.
- */
-static struct GNUNET_SERVER_Handle *srv;
-
 
 /**
  * Get the peer info belonging to a peer identity in a keygen session.
@@ -468,7 +448,8 @@ normalize_peers (struct GNUNET_PeerIdentity *listed,
     n += 1;
   }
 
-  normalized = GNUNET_new_array (n, struct GNUNET_PeerIdentity);
+  normalized = GNUNET_new_array (n,
+                                 struct GNUNET_PeerIdentity);
 
   if (GNUNET_NO == local_peer_in_list)
     normalized[n - 1] = my_peer;
@@ -558,10 +539,13 @@ compute_lagrange_coefficient (gcry_mpi_t coeff, unsigned int j,
 static void
 decrypt_session_destroy (struct DecryptSession *ds)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt session\n");
-
-  GNUNET_CONTAINER_DLL_remove (decrypt_sessions_head, decrypt_sessions_tail, ds);
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "destroying decrypt session\n");
+  if (NULL != ds->cs)
+  {
+    ds->cs->decrypt_session = NULL;
+    ds->cs = NULL;
+  }
   if (NULL != ds->consensus)
   {
     GNUNET_CONSENSUS_destroy (ds->consensus);
@@ -570,8 +554,7 @@ decrypt_session_destroy (struct DecryptSession *ds)
 
   if (NULL != ds->info)
   {
-    unsigned int i;
-    for (i = 0; i < ds->share->num_peers; i++)
+    for (unsigned int i = 0; i < ds->share->num_peers; i++)
     {
       if (NULL != ds->info[i].partial_decryption)
       {
@@ -582,26 +565,12 @@ decrypt_session_destroy (struct DecryptSession *ds)
     GNUNET_free (ds->info);
     ds->info = NULL;
   }
-
   if (NULL != ds->share)
   {
     GNUNET_SECRETSHARING_share_destroy (ds->share);
     ds->share = NULL;
   }
 
-  if (NULL != ds->client_mq)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying decrypt MQ\n");
-    GNUNET_MQ_destroy (ds->client_mq);
-    ds->client_mq = NULL;
-  }
-
-  if (NULL != ds->client)
-  {
-    GNUNET_SERVER_client_disconnect (ds->client);
-    ds->client = NULL;
-  }
-
   GNUNET_free (ds);
 }
 
@@ -630,14 +599,17 @@ keygen_info_destroy (struct KeygenPeerInfo *info)
 static void
 keygen_session_destroy (struct KeygenSession *ks)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen session\n");
-
-  GNUNET_CONTAINER_DLL_remove (keygen_sessions_head, keygen_sessions_tail, ks);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "destroying keygen session\n");
 
+  if (NULL != ks->cs)
+  {
+    ks->cs->keygen_session = NULL;
+    ks->cs = NULL;
+  }
   if (NULL != ks->info)
   {
-    unsigned int i;
-    for (i = 0; i < ks->num_peers; i++)
+    for (unsigned int i = 0; i < ks->num_peers; i++)
       keygen_info_destroy (&ks->info[i]);
     GNUNET_free (ks->info);
     ks->info = NULL;
@@ -651,8 +623,7 @@ keygen_session_destroy (struct KeygenSession *ks)
 
   if (NULL != ks->presecret_polynomial)
   {
-    unsigned int i;
-    for (i = 0; i < ks->threshold; i++)
+    for (unsigned int i = 0; i < ks->threshold; i++)
     {
       GNUNET_assert (NULL != ks->presecret_polynomial[i]);
       gcry_mpi_release (ks->presecret_polynomial[i]);
@@ -661,38 +632,21 @@ keygen_session_destroy (struct KeygenSession *ks)
     GNUNET_free (ks->presecret_polynomial);
     ks->presecret_polynomial = NULL;
   }
-
-  if (NULL != ks->client_mq)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "destroying keygen MQ\n");
-    GNUNET_MQ_destroy (ks->client_mq);
-    ks->client_mq = NULL;
-  }
-
   if (NULL != ks->my_share)
   {
     gcry_mpi_release (ks->my_share);
     ks->my_share = NULL;
   }
-
   if (NULL != ks->public_key)
   {
     gcry_mpi_release (ks->public_key);
     ks->public_key = NULL;
   }
-
   if (NULL != ks->peers)
   {
     GNUNET_free (ks->peers);
     ks->peers = NULL;
   }
-
-  if (NULL != ks->client)
-  {
-    GNUNET_SERVER_client_disconnect (ks->client);
-    ks->client = NULL;
-  }
-
   GNUNET_free (ks);
 }
 
@@ -706,11 +660,7 @@ keygen_session_destroy (struct KeygenSession *ks)
 static void
 cleanup_task (void *cls)
 {
-  while (NULL != decrypt_sessions_head)
-    decrypt_session_destroy (decrypt_sessions_head);
-
-  while (NULL != keygen_sessions_head)
-    keygen_session_destroy (keygen_sessions_head);
+  /* Nothing to do! */
 }
 
 
@@ -727,7 +677,8 @@ generate_presecret_polynomial (struct KeygenSession *ks)
   gcry_mpi_t v;
 
   GNUNET_assert (NULL == ks->presecret_polynomial);
-  ks->presecret_polynomial = GNUNET_new_array (ks->threshold, gcry_mpi_t);
+  ks->presecret_polynomial = GNUNET_new_array (ks->threshold,
+                                               gcry_mpi_t);
   for (i = 0; i < ks->threshold; i++)
   {
     v = ks->presecret_polynomial[i] = gcry_mpi_new (GNUNET_SECRETSHARING_ELGAMAL_BITS);
@@ -768,9 +719,9 @@ keygen_round1_new_element (void *cls,
   if (element->size != sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "keygen commit data with wrong size (%u) in consensus, "
-                " %lu expected\n",
-                element->size, sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData));
+                "keygen commit data with wrong size (%u) in consensus, %u expected\n",
+                (unsigned int) element->size,
+                (unsigned int) sizeof (struct GNUNET_SECRETSHARING_KeygenCommitData));
     return;
   }
 
@@ -855,10 +806,13 @@ keygen_round2_conclude (void *cls)
     if (GNUNET_YES == ks->info[i].round2_valid)
       share->num_peers++;
 
-  share->peers = GNUNET_new_array (share->num_peers, struct GNUNET_PeerIdentity);
+  share->peers = GNUNET_new_array (share->num_peers,
+                                   struct GNUNET_PeerIdentity);
   share->sigmas =
-      GNUNET_new_array (share->num_peers, struct GNUNET_SECRETSHARING_FieldElement);
-  share->original_indices = GNUNET_new_array (share->num_peers, uint16_t);
+      GNUNET_new_array (share->num_peers,
+                        struct GNUNET_SECRETSHARING_FieldElement);
+  share->original_indices = GNUNET_new_array (share->num_peers,
+                                              uint16_t);
 
   /* maybe we're not even in the list of peers? */
   share->my_peer = share->num_peers;
@@ -907,7 +861,8 @@ keygen_round2_conclude (void *cls)
   GNUNET_SECRETSHARING_share_destroy (share);
   share = NULL;
 
-  GNUNET_MQ_send (ks->client_mq, ev);
+  GNUNET_MQ_send (ks->cs->mq,
+                  ev);
 }
 
 
@@ -1429,9 +1384,9 @@ keygen_round2_new_element (void *cls,
   if (element->size != expected_element_size)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "keygen round2 data with wrong size (%u) in consensus, "
-                " %lu expected\n",
-                element->size, expected_element_size);
+                "keygen round2 data with wrong size (%u) in consensus, %u expected\n",
+                (unsigned int) element->size,
+                (unsigned int) expected_element_size);
     return;
   }
 
@@ -1668,74 +1623,103 @@ insert_round1_element (struct KeygenSession *ks)
 }
 
 
+/**
+ * Check that @a msg is well-formed.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ * @return #GNUNET_OK if @a msg is well-formed
+ */
+static int
+check_client_keygen (void *cls,
+                     const struct GNUNET_SECRETSHARING_CreateMessage *msg)
+{
+  unsigned int num_peers = ntohs (msg->num_peers);
+
+  if (ntohs (msg->header.size) - sizeof (*msg) !=
+      num_peers * sizeof (struct GNUNET_PeerIdentity))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
 /**
  * Functions with this signature are called whenever a message is
  * received.
  *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
+ * @param cls identification of the client
+ * @param msg the actual message
  */
-static void handle_client_keygen (void *cls,
-                                  struct GNUNET_SERVER_Client *client,
-                                  const struct GNUNET_MessageHeader
-                                  *message)
+static void
+handle_client_keygen (void *cls,
+                      const struct GNUNET_SECRETSHARING_CreateMessage *msg)
 {
-  const struct GNUNET_SECRETSHARING_CreateMessage *msg =
-      (const struct GNUNET_SECRETSHARING_CreateMessage *) message;
+  struct ClientState *cs = cls;
   struct KeygenSession *ks;
-  unsigned int i;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "client requested key generation\n");
 
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "client requested key generation\n");
+  if (NULL != cs->keygen_session)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (cs->client);
+    return;
+  }
   ks = GNUNET_new (struct KeygenSession);
-
-  /* FIXME: check if client already has some session */
-
-  GNUNET_CONTAINER_DLL_insert (keygen_sessions_head, keygen_sessions_tail, ks);
-
-  ks->client = client;
-  ks->client_mq = GNUNET_MQ_queue_for_server_client (client);
-
+  ks->cs = cs;
+  cs->keygen_session = ks;
   ks->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
   ks->threshold = ntohs (msg->threshold);
   ks->num_peers = ntohs (msg->num_peers);
 
-  ks->peers = normalize_peers ((struct GNUNET_PeerIdentity *) &msg[1], ks->num_peers,
-                               &ks->num_peers, &ks->local_peer_idx);
+  ks->peers = normalize_peers ((struct GNUNET_PeerIdentity *) &msg[1],
+                               ks->num_peers,
+                               &ks->num_peers,
+                               &ks->local_peer_idx);
 
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "first round of consensus with %u peers\n", ks->num_peers);
-  ks->consensus = GNUNET_CONSENSUS_create (cfg, ks->num_peers, ks->peers, &msg->session_id,
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "first round of consensus with %u peers\n",
+              ks->num_peers);
+  ks->consensus = GNUNET_CONSENSUS_create (cfg,
+                                           ks->num_peers,
+                                           ks->peers,
+                                           &msg->session_id,
                                            GNUNET_TIME_absolute_ntoh (msg->start),
                                            GNUNET_TIME_absolute_ntoh (msg->deadline),
-                                           keygen_round1_new_element, ks);
+                                           keygen_round1_new_element,
+                                           ks);
 
-  ks->info = GNUNET_new_array (ks->num_peers, struct KeygenPeerInfo);
+  ks->info = GNUNET_new_array (ks->num_peers,
+                               struct KeygenPeerInfo);
 
-  for (i = 0; i < ks->num_peers; i++)
+  for (unsigned int i = 0; i < ks->num_peers; i++)
     ks->info[i].peer = ks->peers[i];
 
   GNUNET_CRYPTO_paillier_create (&ks->info[ks->local_peer_idx].paillier_public_key,
                                  &ks->paillier_private_key);
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated paillier key pair\n", ks->local_peer_idx);
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "P%u: Generated paillier key pair\n",
+              ks->local_peer_idx);
   generate_presecret_polynomial (ks);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Generated presecret polynomial\n", ks->local_peer_idx);
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "P%u: Generated presecret polynomial\n",
+              ks->local_peer_idx);
   insert_round1_element (ks);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Concluding for round 1\n", ks->local_peer_idx);
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "P%u: Concluding for round 1\n",
+              ks->local_peer_idx);
   GNUNET_CONSENSUS_conclude (ks->consensus,
                              keygen_round1_conclude,
                              ks);
-
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: Waiting for round 1 elements ...\n", ks->local_peer_idx);
+  GNUNET_SERVICE_client_continue (cs->client);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "P%u: Waiting for round 1 elements ...\n",
+              ks->local_peer_idx);
 }
 
 
@@ -1771,20 +1755,24 @@ decrypt_conclude (void *cls)
     if (NULL != ds->info[i].partial_decryption)
       num++;
 
-  indices = GNUNET_malloc (num * sizeof (unsigned int));
+  indices = GNUNET_new_array (num,
+                              unsigned int);
   j = 0;
   for (i = 0; i < ds->share->num_peers; i++)
     if (NULL != ds->info[i].partial_decryption)
       indices[j++] = ds->info[i].original_index;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: decrypt conclude, with %u peers\n",
-              ds->share->my_peer, num);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "P%u: decrypt conclude, with %u peers\n",
+              ds->share->my_peer,
+              num);
 
   gcry_mpi_set_ui (prod, 1);
   for (i = 0; i < num; i++)
   {
 
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "P%u: index of %u: %u\n",
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "P%u: index of %u: %u\n",
                 ds->share->my_peer, i, indices[i]);
     compute_lagrange_coefficient (lagrange, indices[i], indices, num);
     // w_i^{\lambda_i}
@@ -1801,7 +1789,8 @@ decrypt_conclude (void *cls)
   ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT_DONE);
   GNUNET_CRYPTO_mpi_print_unsigned (&msg->plaintext, GNUNET_SECRETSHARING_ELGAMAL_BITS / 8, m);
   msg->success = htonl (1);
-  GNUNET_MQ_send (ds->client_mq, ev);
+  GNUNET_MQ_send (ds->cs->mq,
+                  ev);
 
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "sent decrypt done to client\n");
 
@@ -1945,10 +1934,15 @@ decrypt_new_element (void *cls,
   {
     char *tmp1_str;
     char *tmp2_str;
+
     tmp1_str = mpi_to_str (tmp1);
     tmp2_str = mpi_to_str (tmp2);
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "P%u: Received invalid partial decryption from P%ld (eqn 1), expected %s got %s\n",
-                session->share->my_peer, info - session->info, tmp1_str, tmp2_str);
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "P%u: Received invalid partial decryption from P%u (eqn 1), expected %s got %s\n",
+                session->share->my_peer,
+                (unsigned int) (info - session->info),
+                tmp1_str,
+                tmp2_str);
     GNUNET_free (tmp1_str);
     GNUNET_free (tmp2_str);
     goto cleanup;
@@ -1963,8 +1957,10 @@ decrypt_new_element (void *cls,
 
   if (0 != gcry_mpi_cmp (tmp1, tmp2))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "P%u: Received invalid partial decryption from P%ld (eqn 2)\n",
-                session->share->my_peer, info - session->info);
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "P%u: Received invalid partial decryption from P%u (eqn 2)\n",
+                session->share->my_peer,
+                (unsigned int) (info - session->info));
     goto cleanup;
   }
 
@@ -2099,41 +2095,64 @@ insert_decrypt_element (struct DecryptSession *ds)
 }
 
 
+/**
+ * Check that @a msg is well-formed.
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ * @return #GNUNET_OK (check deferred a bit)
+ */
+static int
+check_client_decrypt (void *cls,
+                      const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg)
+{
+  /* we check later, it's complicated */
+  return GNUNET_OK;
+}
+
+
 /**
  * Functions with this signature are called whenever a message is
  * received.
  *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
+ * @param cls identification of the client
+ * @param msg the actual message
  */
-static void handle_client_decrypt (void *cls,
-                                   struct GNUNET_SERVER_Client *client,
-                                   const struct GNUNET_MessageHeader
-                                   *message)
+static void
+handle_client_decrypt (void *cls,
+                       const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg)
 {
-  const struct GNUNET_SECRETSHARING_DecryptRequestMessage *msg =
-      (const void *) message;
+  struct ClientState *cs = cls;
   struct DecryptSession *ds;
   struct GNUNET_HashCode session_id;
-  unsigned int i;
 
+  if (NULL != cs->decrypt_session)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (cs->client);
+    return;
+  }
   ds = GNUNET_new (struct DecryptSession);
-  // FIXME: check if session already exists
-  GNUNET_CONTAINER_DLL_insert (decrypt_sessions_head, decrypt_sessions_tail, ds);
-  ds->client = client;
-  ds->client_mq = GNUNET_MQ_queue_for_server_client (client);
+  cs->decrypt_session = ds;
+  ds->cs = cs;
   ds->start = GNUNET_TIME_absolute_ntoh (msg->start);
   ds->deadline = GNUNET_TIME_absolute_ntoh (msg->deadline);
   ds->ciphertext = msg->ciphertext;
 
-  ds->share = GNUNET_SECRETSHARING_share_read (&msg[1], ntohs (msg->header.size) - sizeof *msg, NULL);
-  // FIXME: probably should be break rather than assert
-  GNUNET_assert (NULL != ds->share);
-
-  // FIXME: this is probably sufficient, but kdf/hash with all values would be nicer ...
-  GNUNET_CRYPTO_hash (&msg->ciphertext, sizeof (struct GNUNET_SECRETSHARING_Ciphertext), &session_id);
+  ds->share = GNUNET_SECRETSHARING_share_read (&msg[1],
+                                               ntohs (msg->header.size) - sizeof (*msg),
+                                               NULL);
+  if (NULL == ds->share)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (cs->client);
+    return;
+  }
 
+  /* FIXME: this is probably sufficient, but kdf/hash with all values would be nicer ... */
+  GNUNET_CRYPTO_hash (&msg->ciphertext,
+                      sizeof (struct GNUNET_SECRETSHARING_Ciphertext),
+                      &session_id);
   ds->consensus = GNUNET_CONSENSUS_create (cfg,
                                            ds->share->num_peers,
                                            ds->share->peers,
@@ -2144,20 +2163,20 @@ static void handle_client_decrypt (void *cls,
                                            ds);
 
 
-  ds->info = GNUNET_new_array (ds->share->num_peers, struct DecryptPeerInfo);
-  for (i = 0; i < ds->share->num_peers; i++)
+  ds->info = GNUNET_new_array (ds->share->num_peers,
+                               struct DecryptPeerInfo);
+  for (unsigned int i = 0; i < ds->share->num_peers; i++)
   {
     ds->info[i].peer = ds->share->peers[i];
     ds->info[i].original_index = ds->share->original_indices[i];
   }
-
   insert_decrypt_element (ds);
-
-  GNUNET_CONSENSUS_conclude (ds->consensus, decrypt_conclude, ds);
-
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "decrypting with %u peers\n",
+  GNUNET_CONSENSUS_conclude (ds->consensus,
+                             decrypt_conclude,
+                             ds);
+  GNUNET_SERVICE_client_continue (cs->client);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "decrypting with %u peers\n",
               ds->share->num_peers);
 }
 
@@ -2174,103 +2193,104 @@ init_crypto_constants (void)
 }
 
 
-static struct KeygenSession *
-keygen_session_get (struct GNUNET_SERVER_Client *client)
-{
-  struct KeygenSession *ks;
-  for (ks = keygen_sessions_head; NULL != ks; ks = ks->next)
-    if (ks->client == client)
-      return ks;
-  return NULL;
-}
-
-static struct DecryptSession *
-decrypt_session_get (struct GNUNET_SERVER_Client *client)
-{
-  struct DecryptSession *ds;
-  for (ds = decrypt_sessions_head; NULL != ds; ds = ds->next)
-    if (ds->client == client)
-      return ds;
-  return NULL;
-}
-
-
-/**
- * Clean up after a client has disconnected
- *
- * @param cls closure, unused
- * @param client the client to clean up after
- */
-static void
-handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
-{
-  struct KeygenSession *ks;
-  struct DecryptSession *ds;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "handling client disconnect\n");
-
-  ks = keygen_session_get (client);
-  if (NULL != ks)
-    keygen_session_destroy (ks);
-
-  ds = decrypt_session_get (client);
-  if (NULL != ds)
-    decrypt_session_destroy (ds);
-}
-
-
 /**
- * Process template requests.
+ * Initialize secretsharing service.
  *
  * @param cls closure
- * @param server the initialized server
  * @param c configuration to use
+ * @param service the initialized service
  */
 static void
-run (void *cls, struct GNUNET_SERVER_Handle *server,
-     const struct GNUNET_CONFIGURATION_Handle *c)
+run (void *cls,
+     const struct GNUNET_CONFIGURATION_Handle *c,
+     struct GNUNET_SERVICE_Handle *service)
 {
-  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
-    {handle_client_keygen, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE, 0},
-    {handle_client_decrypt, NULL, GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT, 0},
-    {NULL, NULL, 0, 0}
-  };
   cfg = c;
-  srv = server;
   my_peer_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
   if (NULL == my_peer_private_key)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not access host private key\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "could not access host private key\n");
     GNUNET_break (0);
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
   init_crypto_constants ();
-  if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &my_peer))
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_get_peer_identity (cfg,
+                                       &my_peer))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "could not retrieve host identity\n");
     GNUNET_break (0);
     GNUNET_SCHEDULER_shutdown ();
     return;
   }
-  GNUNET_SERVER_add_handlers (server, handlers);
-  GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
   GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
                                 NULL);
 }
 
 
 /**
- * The main function for the template service.
+ * Callback called when a client connects to the service.
+ *
+ * @param cls closure for the service
+ * @param c the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return @a c
+ */
+static void *
+client_connect_cb (void *cls,
+                  struct GNUNET_SERVICE_Client *c,
+                  struct GNUNET_MQ_Handle *mq)
+{
+  struct ClientState *cs = GNUNET_new (struct ClientState);;
+
+  cs->client = c;
+  cs->mq = mq;
+  return cs;
+}
+
+
+/**
+ * Callback called when a client disconnected from the service
  *
- * @param argc number of arguments from the command line
- * @param argv command line arguments
- * @return 0 ok, 1 on error
+ * @param cls closure for the service
+ * @param c the client that disconnected
+ * @param internal_cls should be equal to @a c
  */
-int
-main (int argc, char *const *argv)
+static void
+client_disconnect_cb (void *cls,
+                     struct GNUNET_SERVICE_Client *c,
+                     void *internal_cls)
 {
-  return (GNUNET_OK ==
-          GNUNET_SERVICE_run (argc, argv, "secretsharing",
-                              GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
+  struct ClientState *cs = internal_cls;
+
+  if (NULL != cs->keygen_session)
+    keygen_session_destroy (cs->keygen_session);
+
+  if (NULL != cs->decrypt_session)
+    decrypt_session_destroy (cs->decrypt_session);
+  GNUNET_free (cs);
 }
+
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("secretsharing",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_var_size (client_keygen,
+                        GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_GENERATE,
+                        struct GNUNET_SECRETSHARING_CreateMessage,
+                        NULL),
+ GNUNET_MQ_hd_var_size (client_decrypt,
+                        GNUNET_MESSAGE_TYPE_SECRETSHARING_CLIENT_DECRYPT,
+                        struct GNUNET_SECRETSHARING_DecryptRequestMessage,
+                        NULL),
+ GNUNET_MQ_handler_end ());
index cfe95bc1a62274b04e2d1fae06144038bd1c2a18..14667d0ef97fa0e12970c963eacc52c4a5963d28 100644 (file)
@@ -51,7 +51,7 @@ gnunet_set_ibf_profiler_LDADD = \
 
 gnunet_service_set_SOURCES = \
  gnunet-service-set.c gnunet-service-set.h \
- gnunet-service-set_union.c \
+ gnunet-service-set_union.c gnunet-service-set_union.h \
  gnunet-service-set_intersection.c \
  ibf.c ibf.h \
  gnunet-service-set_union_strata_estimator.c gnunet-service-set_union_strata_estimator.h \
@@ -60,7 +60,7 @@ gnunet_service_set_LDADD = \
   $(top_builddir)/src/util/libgnunetutil.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/core/libgnunetcore.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/block/libgnunetblock.la \
   libgnunetset.la \
   $(GN_LIBINTL)
index 30d43e8a14b53542fc584c4e7d7c3fd690ba27b0..12af653c1b3f33377e4f3598db9d0824abcb39f4 100644 (file)
@@ -1,6 +1,6 @@
 /*
       This file is part of GNUnet
-      Copyright (C) 2013, 2014, 2017 GNUnet e.V.
+      Copyright (C) 2013-2017 GNUnet e.V.
 
       GNUnet is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published
@@ -24,6 +24,8 @@
  * @author Christian Grothoff
  */
 #include "gnunet-service-set.h"
+#include "gnunet-service-set_union.h"
+#include "gnunet-service-set_intersection.h"
 #include "gnunet-service-set_protocol.h"
 #include "gnunet_statistics_service.h"
 
  */
 #define INCOMING_CHANNEL_TIMEOUT GNUNET_TIME_UNIT_MINUTES
 
+
+/**
+ * Lazy copy requests made by a client.
+ */
+struct LazyCopyRequest
+{
+  /**
+   * Kept in a DLL.
+   */
+  struct LazyCopyRequest *prev;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct LazyCopyRequest *next;
+
+  /**
+   * Which set are we supposed to copy?
+   */
+  struct Set *source_set;
+
+  /**
+   * Cookie identifying the request.
+   */
+  uint32_t cookie;
+
+};
+
+
 /**
  * A listener is inhabited by a client, and waits for evaluation
  * requests from remote peers.
@@ -50,27 +81,36 @@ struct Listener
   struct Listener *prev;
 
   /**
-   * Client that owns the listener.
-   * Only one client may own a listener.
+   * Head of DLL of operations this listener is responsible for.
+   * Once the client has accepted/declined the operation, the
+   * operation is moved to the respective set's operation DLLS.
    */
-  struct GNUNET_SERVICE_Client *client;
+  struct Operation *op_head;
 
   /**
-   * Message queue for the client
+   * Tail of DLL of operations this listener is responsible for.
+   * Once the client has accepted/declined the operation, the
+   * operation is moved to the respective set's operation DLLS.
    */
-  struct GNUNET_MQ_Handle *client_mq;
+  struct Operation *op_tail;
 
   /**
-   * Application ID for the operation, used to distinguish
-   * multiple operations of the same type with the same peer.
+   * Client that owns the listener.
+   * Only one client may own a listener.
    */
-  struct GNUNET_HashCode app_id;
+  struct ClientState *cs;
 
   /**
    * The port we are listening on with CADET.
    */
   struct GNUNET_CADET_Port *open_port;
 
+  /**
+   * Application ID for the operation, used to distinguish
+   * multiple operations of the same type with the same peer.
+   */
+  struct GNUNET_HashCode app_id;
+
   /**
    * The type of the operation.
    */
@@ -78,21 +118,6 @@ struct Listener
 };
 
 
-struct LazyCopyRequest
-{
-  struct Set *source_set;
-  uint32_t cookie;
-
-  struct LazyCopyRequest *prev;
-  struct LazyCopyRequest *next;
-};
-
-
-/**
- * Configuration of our local peer.
- */
-static const struct GNUNET_CONFIGURATION_Handle *configuration;
-
 /**
  * Handle to the cadet service, used to listen for and connect to
  * remote peers.
@@ -100,96 +125,48 @@ static const struct GNUNET_CONFIGURATION_Handle *configuration;
 static struct GNUNET_CADET_Handle *cadet;
 
 /**
- * Sets are held in a doubly linked list.
+ * DLL of lazy copy requests by this client.
  */
-static struct Set *sets_head;
+static struct LazyCopyRequest *lazy_copy_head;
 
 /**
- * Sets are held in a doubly linked list.
+ * DLL of lazy copy requests by this client.
  */
-static struct Set *sets_tail;
+static struct LazyCopyRequest *lazy_copy_tail;
 
 /**
- * Listeners are held in a doubly linked list.
+ * Generator for unique cookie we set per lazy copy request.
  */
-static struct Listener *listeners_head;
+static uint32_t lazy_copy_cookie;
 
 /**
- * Listeners are held in a doubly linked list.
+ * Statistics handle.
  */
-static struct Listener *listeners_tail;
+struct GNUNET_STATISTICS_Handle *_GSS_statistics;
 
 /**
- * Incoming sockets from remote peers are held in a doubly linked
- * list.
+ * Listeners are held in a doubly linked list.
  */
-static struct Operation *incoming_head;
+static struct Listener *listener_head;
 
 /**
- * Incoming sockets from remote peers are held in a doubly linked
- * list.
+ * Listeners are held in a doubly linked list.
  */
-static struct Operation *incoming_tail;
-
-static struct LazyCopyRequest *lazy_copy_head;
-static struct LazyCopyRequest *lazy_copy_tail;
-
-static uint32_t lazy_copy_cookie = 1;
+static struct Listener *listener_tail;
 
 /**
  * Counter for allocating unique IDs for clients, used to identify
  * incoming operation requests from remote peers, that the client can
- * choose to accept or refuse.
+ * choose to accept or refuse.  0 must not be used (reserved for
+ * uninitialized).
  */
-static uint32_t suggest_id = 1;
-
-/**
- * Statistics handle.
- */
-struct GNUNET_STATISTICS_Handle *_GSS_statistics;
-
-
-/**
- * Get set that is owned by the given client, if any.
- *
- * @param client client to look for
- * @return set that the client owns, NULL if the client
- *         does not own a set
- */
-static struct Set *
-set_get (struct GNUNET_SERVICE_Client *client)
-{
-  struct Set *set;
-
-  for (set = sets_head; NULL != set; set = set->next)
-    if (set->client == client)
-      return set;
-  return NULL;
-}
-
-
-/**
- * Get the listener associated with the given client, if any.
- *
- * @param client the client
- * @return listener associated with the client, NULL
- *         if there isn't any
- */
-static struct Listener *
-listener_get (struct GNUNET_SERVICE_Client *client)
-{
-  struct Listener *listener;
-
-  for (listener = listeners_head; NULL != listener; listener = listener->next)
-    if (listener->client == client)
-      return listener;
-  return NULL;
-}
+static uint32_t suggest_id;
 
 
 /**
  * Get the incoming socket associated with the given id.
  *
+ * @param listener the listener to look in
  * @param id id to look for
  * @return the incoming socket associated with the id,
  *         or NULL if there is none
@@ -197,43 +174,49 @@ listener_get (struct GNUNET_SERVICE_Client *client)
 static struct Operation *
 get_incoming (uint32_t id)
 {
-  struct Operation *op;
-
-  for (op = incoming_head; NULL != op; op = op->next)
-    if (op->suggest_id == id)
-    {
-      GNUNET_assert (GNUNET_YES == op->is_incoming);
-      return op;
-    }
+  for (struct Listener *listener = listener_head;
+       NULL != listener;
+       listener = listener->next)
+  {
+    for (struct Operation *op = listener->op_head; NULL != op; op = op->next)
+      if (op->suggest_id == id)
+        return op;
+  }
   return NULL;
 }
 
 
 /**
- * Destroy a listener, free all resources associated with it.
+ * Destroy an incoming request from a remote peer
  *
- * @param listener listener to destroy
+ * @param op remote request to destroy
  */
 static void
-listener_destroy (struct Listener *listener)
+incoming_destroy (struct Operation *op)
 {
-  /* If the client is not dead yet, destroy it.
-   * The client's destroy callback will destroy the listener again. */
-  if (NULL != listener->client)
-  {
-    struct GNUNET_SERVICE_Client *client = listener->client;
+  struct Listener *listener;
+  struct GNUNET_CADET_Channel *channel;
 
-    listener->client = NULL;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Disconnecting listener client\n");
-    GNUNET_SERVICE_client_drop (client);
-    return;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Destroying incoming operation %p\n",
+              op);
+  if (NULL != (listener = op->listener))
+  {
+    GNUNET_CONTAINER_DLL_remove (listener->op_head,
+                                 listener->op_tail,
+                                 op);
+    op->listener = NULL;
+  }
+  if (NULL != op->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (op->timeout_task);
+    op->timeout_task = NULL;
+  }
+  if (NULL != (channel = op->channel))
+  {
+    op->channel = NULL;
+    GNUNET_CADET_channel_destroy (channel);
   }
-  GNUNET_CADET_close_port (listener->open_port);
-  GNUNET_CONTAINER_DLL_remove (listeners_head,
-                               listeners_tail,
-                               listener);
-  GNUNET_free (listener);
 }
 
 
@@ -303,12 +286,11 @@ garbage_collect_cb (void *cls,
 static void
 collect_generation_garbage (struct Set *set)
 {
-  struct Operation *op;
   struct GarbageContext gc;
 
   gc.min_op_generation = UINT_MAX;
   gc.max_op_generation = 0;
-  for (op = set->ops_head; NULL != op; op = op->next)
+  for (struct Operation *op = set->ops_head; NULL != op; op = op->next)
   {
     gc.min_op_generation = GNUNET_MIN (gc.min_op_generation,
                                        op->generation_created);
@@ -322,23 +304,36 @@ collect_generation_garbage (struct Set *set)
 }
 
 
+/**
+ * Is @a generation in the range of exclusions?
+ *
+ * @param generation generation to query
+ * @param excluded array of generations where the element is excluded
+ * @param excluded_size length of the @a excluded array
+ * @return #GNUNET_YES if @a generation is in any of the ranges
+ */
 static int
 is_excluded_generation (unsigned int generation,
                         struct GenerationRange *excluded,
                         unsigned int excluded_size)
 {
-  unsigned int i;
-
-  for (i = 0; i < excluded_size; i++)
-  {
-    if ( (generation >= excluded[i].start) && (generation < excluded[i].end) )
+  for (unsigned int i = 0; i < excluded_size; i++)
+    if ( (generation >= excluded[i].start) &&
+         (generation < excluded[i].end) )
       return GNUNET_YES;
-  }
-
   return GNUNET_NO;
 }
 
 
+/**
+ * Is element @a ee part of the set during @a query_generation?
+ *
+ * @param ee element to test
+ * @param query_generation generation to query
+ * @param excluded array of generations where the element is excluded
+ * @param excluded_size length of the @a excluded array
+ * @return #GNUNET_YES if the element is in the set, #GNUNET_NO if not
+ */
 static int
 is_element_of_generation (struct ElementEntry *ee,
                           unsigned int query_generation,
@@ -347,11 +342,12 @@ is_element_of_generation (struct ElementEntry *ee,
 {
   struct MutationEvent *mut;
   int is_present;
-  unsigned int i;
 
   GNUNET_assert (NULL != ee->mutations);
-
-  if (GNUNET_YES == is_excluded_generation (query_generation, excluded, excluded_size))
+  if (GNUNET_YES ==
+      is_excluded_generation (query_generation,
+                              excluded,
+                              excluded_size))
   {
     GNUNET_break (0);
     return GNUNET_NO;
@@ -361,7 +357,7 @@ is_element_of_generation (struct ElementEntry *ee,
 
   /* Could be made faster with binary search, but lists
      are small, so why bother. */
-  for (i = 0; i < ee->mutations_size; i++)
+  for (unsigned int i = 0; i < ee->mutations_size; i++)
   {
     mut = &ee->mutations[i];
 
@@ -373,7 +369,10 @@ is_element_of_generation (struct ElementEntry *ee,
       continue;
     }
 
-    if (GNUNET_YES == is_excluded_generation (mut->generation, excluded, excluded_size))
+    if (GNUNET_YES ==
+        is_excluded_generation (mut->generation,
+                                excluded,
+                                excluded_size))
     {
       /* The generation is excluded (because it belongs to another
          fork via a lazy copy) and thus mutations aren't considered
@@ -382,11 +381,12 @@ is_element_of_generation (struct ElementEntry *ee,
     }
 
     /* This would be an inconsistency in how we manage mutations. */
-    if ( (GNUNET_YES == is_present) && (GNUNET_YES == mut->added) )
+    if ( (GNUNET_YES == is_present) &&
+         (GNUNET_YES == mut->added) )
       GNUNET_assert (0);
-
     /* Likewise. */
-    if ( (GNUNET_NO == is_present) && (GNUNET_NO == mut->added) )
+    if ( (GNUNET_NO == is_present) &&
+         (GNUNET_NO == mut->added) )
       GNUNET_assert (0);
 
     is_present = mut->added;
@@ -396,44 +396,33 @@ is_element_of_generation (struct ElementEntry *ee,
 }
 
 
-int
-_GSS_is_element_of_set (struct ElementEntry *ee,
-                        struct Set *set)
-{
-  return is_element_of_generation (ee,
-                                   set->current_generation,
-                                   set->excluded_generations,
-                                   set->excluded_generations_size);
-}
-
-
-static int
-is_element_of_iteration (struct ElementEntry *ee,
-                         struct Set *set)
-{
-  return is_element_of_generation (ee,
-                                   set->iter_generation,
-                                   set->excluded_generations,
-                                   set->excluded_generations_size);
-}
-
-
+/**
+ * Is element @a ee part of the set used by @a op?
+ *
+ * @param ee element to test
+ * @param op operation the defines the set and its generation
+ * @return #GNUNET_YES if the element is in the set, #GNUNET_NO if not
+ */
 int
 _GSS_is_element_of_operation (struct ElementEntry *ee,
                               struct Operation *op)
 {
   return is_element_of_generation (ee,
                                    op->generation_created,
-                                   op->spec->set->excluded_generations,
-                                   op->spec->set->excluded_generations_size);
+                                   op->set->excluded_generations,
+                                   op->set->excluded_generations_size);
 }
 
 
 /**
- * Destroy the given operation.  Call the implementation-specific
- * cancel function of the operation.  Disconnects from the remote
- * peer.  Does not disconnect the client, as there may be multiple
- * operations per set.
+ * Destroy the given operation.  Used for any operation where both
+ * peers were known and that thus actually had a vt and channel.  Must
+ * not be used for operations where 'listener' is still set and we do
+ * not know the other peer.
+ *
+ * Call the implementation-specific cancel function of the operation.
+ * Disconnects from the remote peer.  Does not disconnect the client,
+ * as there may be multiple operations per set.
  *
  * @param op operation to destroy
  * @param gc #GNUNET_YES to perform garbage collection on the set
@@ -442,44 +431,67 @@ void
 _GSS_operation_destroy (struct Operation *op,
                         int gc)
 {
-  struct Set *set;
+  struct Set *set = op->set;
   struct GNUNET_CADET_Channel *channel;
 
-  if (NULL == op->vt)
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Destroying operation %p\n",
+              op);
+  GNUNET_assert (NULL == op->listener);
+  if (NULL != op->state)
   {
-    /* already in #_GSS_operation_destroy() */
-    return;
+    set->vt->cancel (op);
+    op->state = NULL;
   }
-  GNUNET_assert (GNUNET_NO == op->is_incoming);
-  GNUNET_assert (NULL != op->spec);
-  set = op->spec->set;
-  GNUNET_CONTAINER_DLL_remove (set->ops_head,
-                               set->ops_tail,
-                               op);
-  op->vt->cancel (op);
-  op->vt = NULL;
-  if (NULL != op->spec)
+  if (NULL != set)
   {
-    if (NULL != op->spec->context_msg)
-    {
-      GNUNET_free (op->spec->context_msg);
-      op->spec->context_msg = NULL;
-    }
-    GNUNET_free (op->spec);
-    op->spec = NULL;
+    GNUNET_CONTAINER_DLL_remove (set->ops_head,
+                                 set->ops_tail,
+                                 op);
+    op->set = NULL;
+  }
+  if (NULL != op->context_msg)
+  {
+    GNUNET_free (op->context_msg);
+    op->context_msg = NULL;
   }
   if (NULL != (channel = op->channel))
   {
+    /* This will free op; called conditionally as this helper function
+       is also called from within the channel disconnect handler. */
     op->channel = NULL;
     GNUNET_CADET_channel_destroy (channel);
   }
-  if (GNUNET_YES == gc)
+  if ( (NULL != set) &&
+       (GNUNET_YES == gc) )
     collect_generation_garbage (set);
   /* We rely on the channel end handler to free 'op'. When 'op->channel' was NULL,
    * there was a channel end handler that will free 'op' on the call stack. */
 }
 
 
+/**
+ * Callback called when a client connects to the service.
+ *
+ * @param cls closure for the service
+ * @param c the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return @a `struct ClientState`
+ */
+static void *
+client_connect_cb (void *cls,
+                  struct GNUNET_SERVICE_Client *c,
+                  struct GNUNET_MQ_Handle *mq)
+{
+  struct ClientState *cs;
+
+  cs = GNUNET_new (struct ClientState);
+  cs->client = c;
+  cs->mq = mq;
+  return cs;
+}
+
+
 /**
  * Iterator over hash map entries to free element entries.
  *
@@ -496,66 +508,76 @@ destroy_elements_iterator (void *cls,
   struct ElementEntry *ee = value;
 
   GNUNET_free_non_null (ee->mutations);
-
   GNUNET_free (ee);
   return GNUNET_YES;
 }
 
 
 /**
- * Destroy a set, and free all resources and operations associated with it.
+ * Clean up after a client has disconnected
  *
- * @param set the set to destroy
+ * @param cls closure, unused
+ * @param client the client to clean up after
+ * @param internal_cls the `struct ClientState`
  */
 static void
-set_destroy (struct Set *set)
+client_disconnect_cb (void *cls,
+                      struct GNUNET_SERVICE_Client *client,
+                      void *internal_cls)
 {
-  if (NULL != set->client)
-  {
-    /* If the client is not dead yet, destroy it.  The client's destroy
-     * callback will call `set_destroy()` again in this case.  We do
-     * this so that the channel end handler still has a valid set handle
-     * to destroy. */
-    struct GNUNET_SERVICE_Client *client = set->client;
-
-    set->client = NULL;
-    GNUNET_SERVICE_client_drop (client);
-    return;
-  }
-  GNUNET_assert (NULL != set->state);
-  while (NULL != set->ops_head)
-    _GSS_operation_destroy (set->ops_head, GNUNET_NO);
-  set->vt->destroy_set (set->state);
-  set->state = NULL;
-  if (NULL != set->iter)
-  {
-    GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
-    set->iter = NULL;
-    set->iteration_id++;
-  }
+  struct ClientState *cs = internal_cls;
+  struct Operation *op;
+  struct Listener *listener;
+  struct Set *set;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Client disconnected, cleaning up\n");
+  if (NULL != (set = cs->set))
   {
-    struct SetContent *content;
+    struct SetContent *content = set->content;
     struct PendingMutation *pm;
     struct PendingMutation *pm_current;
+    struct LazyCopyRequest *lcr;
 
-    content = set->content;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Destroying client's set\n");
+    /* Destroy pending set operations */
+    while (NULL != set->ops_head)
+      _GSS_operation_destroy (set->ops_head,
+                              GNUNET_NO);
+
+    /* Destroy operation-specific state */
+    GNUNET_assert (NULL != set->state);
+    set->vt->destroy_set (set->state);
+    set->state = NULL;
+
+    /* Clean up ongoing iterations */
+    if (NULL != set->iter)
+    {
+      GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
+      set->iter = NULL;
+      set->iteration_id++;
+    }
 
-    // discard any pending mutations that reference this set
+    /* discard any pending mutations that reference this set */
     pm = content->pending_mutations_head;
     while (NULL != pm)
     {
       pm_current = pm;
       pm = pm->next;
-      if (pm_current-> set == set)
+      if (pm_current->set == set)
+      {
         GNUNET_CONTAINER_DLL_remove (content->pending_mutations_head,
                                      content->pending_mutations_tail,
                                      pm_current);
-
+        GNUNET_free (pm_current);
+      }
     }
 
+    /* free set content (or at least decrement RC) */
     set->content = NULL;
     GNUNET_assert (0 != content->refcount);
-    content->refcount -= 1;
+    content->refcount--;
     if (0 == content->refcount)
     {
       GNUNET_assert (NULL != content->elements);
@@ -566,154 +588,85 @@ set_destroy (struct Set *set)
       content->elements = NULL;
       GNUNET_free (content);
     }
-  }
-  GNUNET_free_non_null (set->excluded_generations);
-  set->excluded_generations = NULL;
-  GNUNET_CONTAINER_DLL_remove (sets_head,
-                               sets_tail,
-                               set);
+    GNUNET_free_non_null (set->excluded_generations);
+    set->excluded_generations = NULL;
 
-  // remove set from pending copy requests
-  {
-    struct LazyCopyRequest *lcr;
+    /* remove set from pending copy requests */
     lcr = lazy_copy_head;
     while (NULL != lcr)
     {
-      struct LazyCopyRequest *lcr_current;
-      lcr_current = lcr;
+      struct LazyCopyRequest *lcr_current = lcr;
+
       lcr = lcr->next;
       if (lcr_current->source_set == set)
+      {
         GNUNET_CONTAINER_DLL_remove (lazy_copy_head,
                                      lazy_copy_tail,
                                      lcr_current);
+        GNUNET_free (lcr_current);
+      }
     }
+    GNUNET_free (set);
   }
 
-  GNUNET_free (set);
-}
-
-
-/**
- * Callback called when a client connects to the service.
- *
- * @param cls closure for the service
- * @param c the new client that connected to the service
- * @param mq the message queue used to send messages to the client
- * @return @a c
- */
-static void *
-client_connect_cb (void *cls,
-                  struct GNUNET_SERVICE_Client *c,
-                  struct GNUNET_MQ_Handle *mq)
-{
-  return c;
-}
-
-
-/**
- * Clean up after a client has disconnected
- *
- * @param cls closure, unused
- * @param client the client to clean up after
- * @param internal_cls our client-specific internal data structure
- */
-static void
-client_disconnect_cb (void *cls,
-                      struct GNUNET_SERVICE_Client *client,
-                      void *internal_cls)
-{
-  struct Listener *listener;
-  struct Set *set;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "client disconnected, cleaning up\n");
-  set = set_get (client);
-  if (NULL != set)
+  if (NULL != (listener = cs->listener))
   {
-    set->client = NULL;
-    set_destroy (set);
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Client's set destroyed\n");
-  }
-  listener = listener_get (client);
-  if (NULL != listener)
-  {
-    listener->client = NULL;
-    listener_destroy (listener);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Client's listener destroyed\n");
+                "Destroying client's listener\n");
+    GNUNET_CADET_close_port (listener->open_port);
+    listener->open_port = NULL;
+    while (NULL != (op = listener->op_head))
+      incoming_destroy (op);
+    GNUNET_CONTAINER_DLL_remove (listener_head,
+                                 listener_tail,
+                                 listener);
+    GNUNET_free (listener);
   }
+  GNUNET_free (cs);
 }
 
 
 /**
- * Destroy an incoming request from a remote peer
+ * Check a request for a set operation from another peer.
  *
- * @param incoming remote request to destroy
+ * @param cls the operation state
+ * @param msg the received message
+ * @return #GNUNET_OK if the channel should be kept alive,
+ *         #GNUNET_SYSERR to destroy the channel
  */
-static void
-incoming_destroy (struct Operation *incoming)
+static int
+check_incoming_msg (void *cls,
+                    const struct OperationRequestMessage *msg)
 {
-  struct GNUNET_CADET_Channel *channel;
+  struct Operation *op = cls;
+  struct Listener *listener = op->listener;
+  const struct GNUNET_MessageHeader *nested_context;
 
-  GNUNET_assert (GNUNET_YES == incoming->is_incoming);
-  GNUNET_CONTAINER_DLL_remove (incoming_head,
-                               incoming_tail,
-                               incoming);
-  if (NULL != incoming->timeout_task)
+  /* double operation request */
+  if (0 != op->suggest_id)
   {
-    GNUNET_SCHEDULER_cancel (incoming->timeout_task);
-    incoming->timeout_task = NULL;
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
   }
-  /* make sure that the tunnel end handler will not destroy us again */
-  incoming->vt = NULL;
-  if (NULL != incoming->spec)
+  /* This should be equivalent to the previous condition, but can't hurt to check twice */
+  if (NULL == op->listener)
   {
-    GNUNET_free (incoming->spec);
-    incoming->spec = NULL;
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
   }
-  if (NULL != (channel = incoming->channel))
+  if (listener->operation != (enum GNUNET_SET_OperationType) ntohl (msg->operation))
   {
-    incoming->channel = NULL;
-    GNUNET_CADET_channel_destroy (channel);
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
   }
-}
-
-
-/**
- * Suggest the given request to the listener. The listening client can
- * then accept or reject the remote request.
- *
- * @param incoming the incoming peer with the request to suggest
- * @param listener the listener to suggest the request to
- */
-static void
-incoming_suggest (struct Operation *incoming,
-                  struct Listener *listener)
-{
-  struct GNUNET_MQ_Envelope *mqm;
-  struct GNUNET_SET_RequestMessage *cmsg;
-
-  GNUNET_assert (GNUNET_YES == incoming->is_incoming);
-  GNUNET_assert (NULL != incoming->spec);
-  GNUNET_assert (0 == incoming->suggest_id);
-  incoming->suggest_id = suggest_id++;
-  if (0 == suggest_id)
-    suggest_id++;
-  GNUNET_assert (NULL != incoming->timeout_task);
-  GNUNET_SCHEDULER_cancel (incoming->timeout_task);
-  incoming->timeout_task = NULL;
-  mqm = GNUNET_MQ_msg_nested_mh (cmsg,
-                                 GNUNET_MESSAGE_TYPE_SET_REQUEST,
-                                 incoming->spec->context_msg);
-  GNUNET_assert (NULL != mqm);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Suggesting incoming request with accept id %u to listener\n",
-              incoming->suggest_id);
-  cmsg->accept_id = htonl (incoming->suggest_id);
-  cmsg->peer_id = incoming->spec->peer;
-  GNUNET_MQ_send (listener->client_mq,
-                  mqm);
+  nested_context = GNUNET_MQ_extract_nested_mh (msg);
+  if ( (NULL != nested_context) &&
+       (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
 }
 
 
@@ -729,93 +682,85 @@ incoming_suggest (struct Operation *incoming,
  * our virtual table and subsequent msgs would be routed differently (as
  * we then know what type of operation this is).
  *
- * @param op the operation state
- * @param mh the received message
+ * @param cls the operation state
+ * @param msg the received message
  * @return #GNUNET_OK if the channel should be kept alive,
  *         #GNUNET_SYSERR to destroy the channel
  */
-static int
-handle_incoming_msg (struct Operation *op,
-                     const struct GNUNET_MessageHeader *mh)
+static void
+handle_incoming_msg (void *cls,
+                     const struct OperationRequestMessage *msg)
 {
-  const struct OperationRequestMessage *msg;
+  struct Operation *op = cls;
   struct Listener *listener = op->listener;
-  struct OperationSpecification *spec;
   const struct GNUNET_MessageHeader *nested_context;
+  struct GNUNET_MQ_Envelope *env;
+  struct GNUNET_SET_RequestMessage *cmsg;
 
-  msg = (const struct OperationRequestMessage *) mh;
-  GNUNET_assert (GNUNET_YES == op->is_incoming);
-  if (GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST != ntohs (mh->type))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  /* double operation request */
-  if (NULL != op->spec)
-  {
-    GNUNET_break_op (0);
-    return GNUNET_SYSERR;
-  }
-  spec = GNUNET_new (struct OperationSpecification);
   nested_context = GNUNET_MQ_extract_nested_mh (msg);
-  if ( (NULL != nested_context) &&
-       (ntohs (nested_context->size) > GNUNET_SET_CONTEXT_MESSAGE_MAX_SIZE) )
-  {
-    GNUNET_break_op (0);
-    GNUNET_free (spec);
-    return GNUNET_SYSERR;
-  }
   /* Make a copy of the nested_context (application-specific context
      information that is opaque to set) so we can pass it to the
      listener later on */
   if (NULL != nested_context)
-    spec->context_msg = GNUNET_copy_message (nested_context);
-  spec->operation = ntohl (msg->operation);
-  spec->app_id = listener->app_id;
-  spec->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
-                                         UINT32_MAX);
-  spec->peer = op->peer;
-  spec->remote_element_count = ntohl (msg->element_count);
-  op->spec = spec;
-
-  listener = op->listener;
+    op->context_msg = GNUNET_copy_message (nested_context);
+  op->remote_element_count = ntohl (msg->element_count);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received P2P operation request (op %u, port %s) for active listener\n",
               (uint32_t) ntohl (msg->operation),
-              GNUNET_h2s (&listener->app_id));
-  incoming_suggest (op,
-                    listener);
-  return GNUNET_OK;
+              GNUNET_h2s (&op->listener->app_id));
+  GNUNET_assert (0 == op->suggest_id);
+  if (0 == suggest_id)
+    suggest_id++;
+  op->suggest_id = suggest_id++;
+  GNUNET_assert (NULL != op->timeout_task);
+  GNUNET_SCHEDULER_cancel (op->timeout_task);
+  op->timeout_task = NULL;
+  env = GNUNET_MQ_msg_nested_mh (cmsg,
+                                 GNUNET_MESSAGE_TYPE_SET_REQUEST,
+                                 op->context_msg);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Suggesting incoming request with accept id %u to listener %p of client %p\n",
+              op->suggest_id,
+              listener,
+              listener->cs);
+  cmsg->accept_id = htonl (op->suggest_id);
+  cmsg->peer_id = op->peer;
+  GNUNET_MQ_send (listener->cs->mq,
+                  env);
+  /* NOTE: GNUNET_CADET_receive_done() will be called in
+     #handle_client_accept() */
 }
 
 
+/**
+ * Add an element to @a set as specified by @a msg
+ *
+ * @param set set to manipulate
+ * @param msg message specifying the change
+ */
 static void
 execute_add (struct Set *set,
-             const struct GNUNET_MessageHeader *m)
+             const struct GNUNET_SET_ElementMessage *msg)
 {
-  const struct GNUNET_SET_ElementMessage *msg;
   struct GNUNET_SET_Element el;
   struct ElementEntry *ee;
   struct GNUNET_HashCode hash;
 
-  GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_ADD == ntohs (m->type));
-
-  msg = (const struct GNUNET_SET_ElementMessage *) m;
-  el.size = ntohs (m->size) - sizeof *msg;
+  GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_ADD == ntohs (msg->header.type));
+  el.size = ntohs (msg->header.size) - sizeof (*msg);
   el.data = &msg[1];
   el.element_type = ntohs (msg->element_type);
-  GNUNET_SET_element_hash (&el, &hash);
-
+  GNUNET_SET_element_hash (&el,
+                           &hash);
   ee = GNUNET_CONTAINER_multihashmap_get (set->content->elements,
                                           &hash);
-
   if (NULL == ee)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Client inserts element %s of size %u\n",
                 GNUNET_h2s (&hash),
                 el.size);
-    ee = GNUNET_malloc (el.size + sizeof *ee);
+    ee = GNUNET_malloc (el.size + sizeof (*ee));
     ee->element.size = el.size;
     GNUNET_memcpy (&ee[1],
             el.data,
@@ -832,7 +777,11 @@ execute_add (struct Set *set,
                                                      ee,
                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   }
-  else if (GNUNET_YES == _GSS_is_element_of_set (ee, set))
+  else if (GNUNET_YES ==
+           is_element_of_generation (ee,
+                                     set->current_generation,
+                                     set->excluded_generations,
+                                     set->excluded_generations_size))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Client inserted element %s of size %u twice (ignored)\n",
@@ -852,24 +801,27 @@ execute_add (struct Set *set,
                          ee->mutations_size,
                          mut);
   }
-
-  set->vt->add (set->state, ee);
+  set->vt->add (set->state,
+                ee);
 }
 
 
+/**
+ * Remove an element from @a set as specified by @a msg
+ *
+ * @param set set to manipulate
+ * @param msg message specifying the change
+ */
 static void
 execute_remove (struct Set *set,
-                const struct GNUNET_MessageHeader *m)
+                const struct GNUNET_SET_ElementMessage *msg)
 {
-  const struct GNUNET_SET_ElementMessage *msg;
   struct GNUNET_SET_Element el;
   struct ElementEntry *ee;
   struct GNUNET_HashCode hash;
 
-  GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (m->type));
-
-  msg = (const struct GNUNET_SET_ElementMessage *) m;
-  el.size = ntohs (m->size) - sizeof *msg;
+  GNUNET_assert (GNUNET_MESSAGE_TYPE_SET_REMOVE == ntohs (msg->header.type));
+  el.size = ntohs (msg->header.size) - sizeof (*msg);
   el.data = &msg[1];
   el.element_type = ntohs (msg->element_type);
   GNUNET_SET_element_hash (&el, &hash);
@@ -883,7 +835,11 @@ execute_remove (struct Set *set,
                 el.size);
     return;
   }
-  if (GNUNET_NO == _GSS_is_element_of_set (ee, set))
+  if (GNUNET_NO ==
+      is_element_of_generation (ee,
+                                set->current_generation,
+                                set->excluded_generations,
+                                set->excluded_generations_size))
   {
     /* Client tried to remove element twice */
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -906,22 +862,28 @@ execute_remove (struct Set *set,
                          ee->mutations_size,
                          mut);
   }
-  set->vt->remove (set->state, ee);
+  set->vt->remove (set->state,
+                   ee);
 }
 
 
-
+/**
+ * Perform a mutation on a set as specified by the @a msg
+ *
+ * @param set the set to mutate
+ * @param msg specification of what to change
+ */
 static void
 execute_mutation (struct Set *set,
-                  const struct GNUNET_MessageHeader *m)
+                  const struct GNUNET_SET_ElementMessage *msg)
 {
-  switch (ntohs (m->type))
+  switch (ntohs (msg->header.type))
   {
     case GNUNET_MESSAGE_TYPE_SET_ADD:
-      execute_add (set, m);
+      execute_add (set, msg);
       break;
     case GNUNET_MESSAGE_TYPE_SET_REMOVE:
-      execute_remove (set, m);
+      execute_remove (set, msg);
       break;
     default:
       GNUNET_break (0);
@@ -929,6 +891,34 @@ execute_mutation (struct Set *set,
 }
 
 
+/**
+ * Execute mutations that were delayed on a set because of
+ * pending operations.
+ *
+ * @param set the set to execute mutations on
+ */
+static void
+execute_delayed_mutations (struct Set *set)
+{
+  struct PendingMutation *pm;
+
+  if (0 != set->content->iterator_count)
+    return; /* still cannot do this */
+  while (NULL != (pm = set->content->pending_mutations_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (set->content->pending_mutations_head,
+                                 set->content->pending_mutations_tail,
+                                 pm);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Executing pending mutation on %p.\n",
+                pm->set);
+    execute_mutation (pm->set,
+                      pm->msg);
+    GNUNET_free (pm->msg);
+    GNUNET_free (pm);
+  }
+}
+
 
 /**
  * Send the next element of a set to the set's client.  The next element is given by
@@ -952,65 +942,45 @@ send_client_element (struct Set *set)
   struct GNUNET_SET_IterResponseMessage *msg;
 
   GNUNET_assert (NULL != set->iter);
-
-again:
-
-  ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter,
-                                                     NULL,
-                                                     (const void **) &ee);
-  if (GNUNET_NO == ret)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Iteration on %p done.\n",
-                (void *) set);
-    ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
-    GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
-    set->iter = NULL;
-    set->iteration_id++;
-
-    GNUNET_assert (set->content->iterator_count > 0);
-    set->content->iterator_count -= 1;
-
-    if (0 == set->content->iterator_count)
+  do {
+    ret = GNUNET_CONTAINER_multihashmap_iterator_next (set->iter,
+                                                       NULL,
+                                                       (const void **) &ee);
+    if (GNUNET_NO == ret)
     {
-      while (NULL != set->content->pending_mutations_head)
-      {
-        struct PendingMutation *pm;
-
-        pm = set->content->pending_mutations_head;
-        GNUNET_CONTAINER_DLL_remove (set->content->pending_mutations_head,
-                                     set->content->pending_mutations_tail,
-                                     pm);
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                    "Executing pending mutation on %p.\n",
-                    (void *) pm->set);
-        execute_mutation (pm->set, pm->mutation_message);
-        GNUNET_free (pm->mutation_message);
-        GNUNET_free (pm);
-      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Iteration on %p done.\n",
+                  set);
+      ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_ITER_DONE);
+      GNUNET_CONTAINER_multihashmap_iterator_destroy (set->iter);
+      set->iter = NULL;
+      set->iteration_id++;
+      GNUNET_assert (set->content->iterator_count > 0);
+      set->content->iterator_count--;
+      execute_delayed_mutations (set);
+      GNUNET_MQ_send (set->cs->mq,
+                      ev);
+      return;
     }
-
-  }
-  else
-  {
     GNUNET_assert (NULL != ee);
-
-    if (GNUNET_NO == is_element_of_iteration (ee, set))
-      goto again;
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Sending iteration element on %p.\n",
-                (void *) set);
-    ev = GNUNET_MQ_msg_extra (msg,
-                              ee->element.size,
-                              GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT);
-    GNUNET_memcpy (&msg[1],
-            ee->element.data,
-            ee->element.size);
-    msg->element_type = htons (ee->element.element_type);
-    msg->iteration_id = htons (set->iteration_id);
-  }
-  GNUNET_MQ_send (set->client_mq, ev);
+  } while (GNUNET_NO ==
+           is_element_of_generation (ee,
+                                     set->iter_generation,
+                                     set->excluded_generations,
+                                     set->excluded_generations_size));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Sending iteration element on %p.\n",
+              set);
+  ev = GNUNET_MQ_msg_extra (msg,
+                            ee->element.size,
+                            GNUNET_MESSAGE_TYPE_SET_ITER_ELEMENT);
+  GNUNET_memcpy (&msg[1],
+                 ee->element.data,
+                 ee->element.size);
+  msg->element_type = htons (ee->element.element_type);
+  msg->iteration_id = htons (set->iteration_id);
+  GNUNET_MQ_send (set->cs->mq,
+                  ev);
 }
 
 
@@ -1027,22 +997,21 @@ static void
 handle_client_iterate (void *cls,
                        const struct GNUNET_MessageHeader *m)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct Set *set;
 
-  set = set_get (client);
-  if (NULL == set)
+  if (NULL == (set = cs->set))
   {
     /* attempt to iterate over a non existing set */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
   if (NULL != set->iter)
   {
     /* Only one concurrent iterate-action allowed per set */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1050,8 +1019,8 @@ handle_client_iterate (void *cls,
               (void *) set,
               set->current_generation,
               GNUNET_CONTAINER_multihashmap_size (set->content->elements));
-  GNUNET_SERVICE_client_continue (client);
-  set->content->iterator_count += 1;
+  GNUNET_SERVICE_client_continue (cs->client);
+  set->content->iterator_count++;
   set->iter = GNUNET_CONTAINER_multihashmap_iterator_create (set->content->elements);
   set->iter_generation = set->current_generation;
   send_client_element (set);
@@ -1070,17 +1039,17 @@ static void
 handle_client_create_set (void *cls,
                           const struct GNUNET_SET_CreateMessage *msg)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct Set *set;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Client created new set (operation %u)\n",
               (uint32_t) ntohl (msg->operation));
-  if (NULL != set_get (client))
+  if (NULL != cs->set)
   {
     /* There can only be one set per client */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
   set = GNUNET_new (struct Set);
@@ -1095,27 +1064,25 @@ handle_client_create_set (void *cls,
   default:
     GNUNET_free (set);
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
-  set->operation = ntohl (msg->operation);
+  set->operation = (enum GNUNET_SET_OperationType) ntohl (msg->operation);
   set->state = set->vt->create ();
   if (NULL == set->state)
   {
     /* initialization failed (i.e. out of memory) */
     GNUNET_free (set);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
   set->content = GNUNET_new (struct SetContent);
   set->content->refcount = 1;
-  set->content->elements = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES);
-  set->client = client;
-  set->client_mq = GNUNET_SERVICE_client_get_mq (client);
-  GNUNET_CONTAINER_DLL_insert (sets_head,
-                               sets_tail,
-                               set);
-  GNUNET_SERVICE_client_continue (client);
+  set->content->elements = GNUNET_CONTAINER_multihashmap_create (1,
+                                                                 GNUNET_YES);
+  set->cs = cs;
+  cs->set = set;
+  GNUNET_SERVICE_client_continue (cs->client);
 }
 
 
@@ -1131,31 +1098,12 @@ handle_client_create_set (void *cls,
 static void
 incoming_timeout_cb (void *cls)
 {
-  struct Operation *incoming = cls;
+  struct Operation *op = cls;
 
-  incoming->timeout_task = NULL;
-  GNUNET_assert (GNUNET_YES == incoming->is_incoming);
+  op->timeout_task = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Remote peer's incoming request timed out\n");
-  incoming_destroy (incoming);
-}
-
-
-/**
- * Terminates an incoming operation in case we have not yet received an
- * operation request. Called by the channel destruction handler.
- *
- * @param op the channel context
- */
-static void
-handle_incoming_disconnect (struct Operation *op)
-{
-  GNUNET_assert (GNUNET_YES == op->is_incoming);
-  /* channel is already dead, incoming_destroy must not
-   * destroy it ... */
-  op->channel = NULL;
   incoming_destroy (op);
-  op->vt = NULL;
 }
 
 
@@ -1180,32 +1128,26 @@ channel_new_cb (void *cls,
                 struct GNUNET_CADET_Channel *channel,
                 const struct GNUNET_PeerIdentity *source)
 {
-  static const struct SetVT incoming_vt = {
-    .msg_handler = &handle_incoming_msg,
-    .peer_disconnect = &handle_incoming_disconnect
-  };
   struct Listener *listener = cls;
-  struct Operation *incoming;
+  struct Operation *op;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "New incoming channel\n");
-  incoming = GNUNET_new (struct Operation);
-  incoming->listener = listener;
-  incoming->is_incoming = GNUNET_YES;
-  incoming->peer = *source;
-  incoming->channel = channel;
-  incoming->mq = GNUNET_CADET_get_mq (incoming->channel);
-  incoming->vt = &incoming_vt;
-  incoming->timeout_task
+  op = GNUNET_new (struct Operation);
+  op->listener = listener;
+  op->peer = *source;
+  op->channel = channel;
+  op->mq = GNUNET_CADET_get_mq (op->channel);
+  op->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+                                       UINT32_MAX);
+  op->timeout_task
     = GNUNET_SCHEDULER_add_delayed (INCOMING_CHANNEL_TIMEOUT,
                                     &incoming_timeout_cb,
-                                    incoming);
-  GNUNET_CONTAINER_DLL_insert_tail (incoming_head,
-                                    incoming_tail,
-                                    incoming);
-  // incoming_suggest (incoming,
-  //                  listener);
-  return incoming;
+                                    op);
+  GNUNET_CONTAINER_DLL_insert (listener->op_head,
+                               listener->op_tail,
+                               op);
+  return op;
 }
 
 
@@ -1234,22 +1176,14 @@ channel_end_cb (void *channel_ctx,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "channel_end_cb called\n");
   op->channel = NULL;
-  op->keep++;
-  /* the vt can be null if a client already requested canceling op. */
-  if (NULL != op->vt)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "calling peer disconnect due to channel end\n");
-    op->vt->peer_disconnect (op);
-  }
-  op->keep--;
-  if (0 == op->keep)
-  {
-    /* cadet will never call us with the context again! */
-    GNUNET_free (op);
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "channel_end_cb finished\n");
+  if (NULL != op->listener)
+    incoming_destroy (op);
+  else if (NULL != op->set)
+    op->set->vt->channel_death (op);
+  else
+    _GSS_operation_destroy (op,
+                            GNUNET_YES);
+  GNUNET_free (op);
 }
 
 
@@ -1275,60 +1209,6 @@ channel_window_cb (void *cls,
   /* FIXME: not implemented, we could do flow control here... */
 }
 
-/**
- * FIXME: hack-job. Migrate to proper handler array use!
- *
- * @param cls local state associated with the channel.
- * @param message The actual message.
- */
-static int
-check_p2p_message (void *cls,
-                   const struct GNUNET_MessageHeader *message)
-{
-  return GNUNET_OK;
-}
-
-
-/**
- * FIXME: hack-job. Migrate to proper handler array use!
- *
- * Functions with this signature are called whenever a message is
- * received via a cadet channel.
- *
- * The msg_handler is a virtual table set in initially either when a peer
- * creates a new channel with us, or once we create a new channel
- * ourselves (evaluate).
- *
- * Once we know the exact type of operation (union/intersection), the vt is
- * replaced with an operation specific instance (_GSS_[op]_vt).
- *
- * @param cls local state associated with the channel.
- * @param message The actual message.
- */
-static void
-handle_p2p_message (void *cls,
-                    const struct GNUNET_MessageHeader *message)
-{
-  struct Operation *op = cls;
-  int ret;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Dispatching cadet message (type: %u)\n",
-              ntohs (message->type));
-  /* do this before the handler, as the handler might kill the channel */
-  GNUNET_CADET_receive_done (op->channel);
-  if (NULL != op->vt)
-    ret = op->vt->msg_handler (op,
-                               message);
-  else
-    ret = GNUNET_SYSERR;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Handled cadet message (type: %u)\n",
-              ntohs (message->type));
-  if (GNUNET_OK != ret)
-    GNUNET_CADET_channel_destroy (op->channel);
-}
-
 
 /**
  * Called when a client wants to create a new listener.
@@ -1340,116 +1220,99 @@ static void
 handle_client_listen (void *cls,
                       const struct GNUNET_SET_ListenMessage *msg)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (incoming_msg,
                            GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
-                           struct GNUNET_MessageHeader,
+                           struct OperationRequestMessage,
                            NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_ibf,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF,
-                           struct GNUNET_MessageHeader,
+                           struct IBFMessage,
                            NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_elements,
                            GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS,
-                           struct GNUNET_MessageHeader,
+                           struct GNUNET_SET_ElementMessage,
                            NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_offer,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER,
                            struct GNUNET_MessageHeader,
                            NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_inquiry,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY,
-                           struct GNUNET_MessageHeader,
+                           struct InquiryMessage,
                            NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_demand,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND,
                            struct GNUNET_MessageHeader,
                            NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
-                           struct GNUNET_MessageHeader,
-                           NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
-                           struct GNUNET_MessageHeader,
-                           NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
-                           struct GNUNET_MessageHeader,
-                           NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_fixed_size (union_p2p_done,
+                             GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
+                             struct GNUNET_MessageHeader,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (union_p2p_full_done,
+                             GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
+                             struct GNUNET_MessageHeader,
+                             NULL),
+    GNUNET_MQ_hd_fixed_size (union_p2p_request_full,
+                             GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
+                             struct GNUNET_MessageHeader,
+                             NULL),
+    GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE,
-                           struct GNUNET_MessageHeader,
+                           struct StrataEstimatorMessage,
                            NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC,
-                           struct GNUNET_MessageHeader,
+                           struct StrataEstimatorMessage,
                            NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_full_element,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT,
-                           struct GNUNET_MessageHeader,
-                           NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
-                           struct GNUNET_MessageHeader,
+                           struct GNUNET_SET_ElementMessage,
                            NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_fixed_size (intersection_p2p_element_info,
+                             GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
+                             struct IntersectionElementInfoMessage,
+                             NULL),
+    GNUNET_MQ_hd_var_size (intersection_p2p_bf,
                            GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF,
-                           struct GNUNET_MessageHeader,
-                           NULL),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
-                           struct GNUNET_MessageHeader,
+                           struct BFMessage,
                            NULL),
+    GNUNET_MQ_hd_fixed_size (intersection_p2p_done,
+                             GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
+                             struct IntersectionDoneMessage,
+                             NULL),
     GNUNET_MQ_handler_end ()
   };
   struct Listener *listener;
 
-  if (NULL != listener_get (client))
+  if (NULL != cs->listener)
   {
     /* max. one active listener per client! */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
   listener = GNUNET_new (struct Listener);
-  listener->client = client;
-  listener->client_mq = GNUNET_SERVICE_client_get_mq (client);
+  listener->cs = cs;
   listener->app_id = msg->app_id;
-  listener->operation = ntohl (msg->operation);
-  GNUNET_CONTAINER_DLL_insert_tail (listeners_head,
-                                    listeners_tail,
-                                    listener);
+  listener->operation = (enum GNUNET_SET_OperationType) ntohl (msg->operation);
+  GNUNET_CONTAINER_DLL_insert (listener_head,
+                               listener_tail,
+                               listener);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "New listener created (op %u, port %s)\n",
               listener->operation,
               GNUNET_h2s (&listener->app_id));
-  listener->open_port = GNUNET_CADET_open_porT (cadet,
-                                                &msg->app_id,
-                                                &channel_new_cb,
-                                                listener,
-                                                &channel_window_cb,
-                                                &channel_end_cb,
-                                                cadet_handlers);
-  /* check for existing incoming requests the listener might be interested in */
-  for (struct Operation *op = incoming_head; NULL != op; op = op->next)
-  {
-    if (NULL == op->spec)
-      continue; /* no details available yet */
-    if (0 != op->suggest_id)
-      continue; /* this one has been already suggested to a listener */
-    if (listener->operation != op->spec->operation)
-      continue; /* incompatible operation */
-    if (0 != GNUNET_CRYPTO_hash_cmp (&listener->app_id,
-                                     &op->spec->app_id))
-      continue; /* incompatible appliation */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Found matching existing request\n");
-    incoming_suggest (op,
-                      listener);
-  }
-  GNUNET_SERVICE_client_continue (client);
+  listener->open_port
+    = GNUNET_CADET_open_port (cadet,
+                              &msg->app_id,
+                              &channel_new_cb,
+                              listener,
+                              &channel_window_cb,
+                              &channel_end_cb,
+                              cadet_handlers);
+  GNUNET_SERVICE_client_continue (cs->client);
 }
 
 
@@ -1464,23 +1327,26 @@ static void
 handle_client_reject (void *cls,
                       const struct GNUNET_SET_RejectMessage *msg)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
-  struct Operation *incoming;
+  struct ClientState *cs = cls;
+  struct Operation *op;
 
-  incoming = get_incoming (ntohl (msg->accept_reject_id));
-  if (NULL == incoming)
+  op = get_incoming (ntohl (msg->accept_reject_id));
+  if (NULL == op)
   {
-    /* no matching incoming operation for this reject */
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    /* no matching incoming operation for this reject;
+       could be that the other peer already disconnected... */
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Client rejected unknown operation %u\n",
+                (unsigned int) ntohl (msg->accept_reject_id));
+    GNUNET_SERVICE_client_continue (cs->client);
     return;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Peer request (op %u, app %s) rejected by client\n",
-              incoming->spec->operation,
-              GNUNET_h2s (&incoming->spec->app_id));
-  GNUNET_CADET_channel_destroy (incoming->channel);
-  GNUNET_SERVICE_client_continue (client);
+              op->listener->operation,
+              GNUNET_h2s (&cs->listener->app_id));
+  GNUNET_CADET_channel_destroy (op->channel);
+  GNUNET_SERVICE_client_continue (cs->client);
 }
 
 
@@ -1488,13 +1354,14 @@ handle_client_reject (void *cls,
  * Called when a client wants to add or remove an element to a set it inhabits.
  *
  * @param cls client that sent the message
- * @param m message sent by the client
+ * @param msg message sent by the client
  */
 static int
 check_client_mutation (void *cls,
-                       const struct GNUNET_MessageHeader *m)
+                       const struct GNUNET_SET_ElementMessage *msg)
 {
-  /* FIXME: any check we might want to do here? */
+  /* NOTE: Technically, we should probably check with the
+     block library whether the element we are given is well-formed */
   return GNUNET_OK;
 }
 
@@ -1503,25 +1370,23 @@ check_client_mutation (void *cls,
  * Called when a client wants to add or remove an element to a set it inhabits.
  *
  * @param cls client that sent the message
- * @param m message sent by the client
+ * @param msg message sent by the client
  */
 static void
 handle_client_mutation (void *cls,
-                        const struct GNUNET_MessageHeader *m)
+                        const struct GNUNET_SET_ElementMessage *msg)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct Set *set;
 
-  set = set_get (client);
-  if (NULL == set)
+  if (NULL == (set = cs->set))
   {
     /* client without a set requested an operation */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
-
-  GNUNET_SERVICE_client_continue (client);
+  GNUNET_SERVICE_client_continue (cs->client);
 
   if (0 != set->content->iterator_count)
   {
@@ -1529,16 +1394,18 @@ handle_client_mutation (void *cls,
 
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Scheduling mutation on set\n");
-
     pm = GNUNET_new (struct PendingMutation);
-    pm->mutation_message = GNUNET_copy_message (m);
+    pm->msg = (struct GNUNET_SET_ElementMessage *) GNUNET_copy_message (&msg->header);
     pm->set = set;
     GNUNET_CONTAINER_DLL_insert_tail (set->content->pending_mutations_head,
                                       set->content->pending_mutations_tail,
                                       pm);
     return;
   }
-  execute_mutation (set, m);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Executing mutation on set\n");
+  execute_mutation (set,
+                    msg);
 }
 
 
@@ -1555,8 +1422,8 @@ advance_generation (struct Set *set)
 
   if (set->current_generation == set->content->latest_generation)
   {
-    set->content->latest_generation += 1;
-    set->current_generation += 1;
+    set->content->latest_generation++;
+    set->current_generation++;
     return;
   }
 
@@ -1564,10 +1431,8 @@ advance_generation (struct Set *set)
 
   r.start = set->current_generation + 1;
   r.end = set->content->latest_generation + 1;
-
   set->content->latest_generation = r.end;
   set->current_generation = r.end;
-
   GNUNET_array_append (set->excluded_generations,
                        set->excluded_generations_size,
                        r);
@@ -1605,112 +1470,105 @@ static void
 handle_client_evaluate (void *cls,
                         const struct GNUNET_SET_EvaluateMessage *msg)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct Operation *op = GNUNET_new (struct Operation);
   const struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (incoming_msg,
                            GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
-                           struct GNUNET_MessageHeader,
+                           struct OperationRequestMessage,
                            op),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_ibf,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF,
-                           struct GNUNET_MessageHeader,
+                           struct IBFMessage,
                            op),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_elements,
                            GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS,
-                           struct GNUNET_MessageHeader,
+                           struct GNUNET_SET_ElementMessage,
                            op),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_offer,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER,
                            struct GNUNET_MessageHeader,
                            op),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_inquiry,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY,
-                           struct GNUNET_MessageHeader,
+                           struct InquiryMessage,
                            op),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_demand,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND,
                            struct GNUNET_MessageHeader,
                            op),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
-                           struct GNUNET_MessageHeader,
-                           op),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_fixed_size (union_p2p_done,
+                             GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE,
+                             struct GNUNET_MessageHeader,
+                             op),
+    GNUNET_MQ_hd_fixed_size (union_p2p_full_done,
+                             GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
+                             struct GNUNET_MessageHeader,
+                             op),
+    GNUNET_MQ_hd_fixed_size (union_p2p_request_full,
+                             GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
+                             struct GNUNET_MessageHeader,
+                             op),
+    GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE,
-                           struct GNUNET_MessageHeader,
+                           struct StrataEstimatorMessage,
                            op),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_strata_estimator,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC,
-                           struct GNUNET_MessageHeader,
-                           op),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE,
-                           struct GNUNET_MessageHeader,
+                           struct StrataEstimatorMessage,
                            op),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL,
-                           struct GNUNET_MessageHeader,
-                           op),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_var_size (union_p2p_full_element,
                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT,
-                           struct GNUNET_MessageHeader,
+                           struct GNUNET_SET_ElementMessage,
                            op),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
-                           struct GNUNET_MessageHeader,
-                           op),
-    GNUNET_MQ_hd_var_size (p2p_message,
+    GNUNET_MQ_hd_fixed_size (intersection_p2p_element_info,
+                             GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO,
+                             struct IntersectionElementInfoMessage,
+                             op),
+    GNUNET_MQ_hd_var_size (intersection_p2p_bf,
                            GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF,
-                           struct GNUNET_MessageHeader,
-                           op),
-    GNUNET_MQ_hd_var_size (p2p_message,
-                           GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
-                           struct GNUNET_MessageHeader,
+                           struct BFMessage,
                            op),
+    GNUNET_MQ_hd_fixed_size (intersection_p2p_done,
+                             GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE,
+                             struct IntersectionDoneMessage,
+                             op),
     GNUNET_MQ_handler_end ()
   };
   struct Set *set;
-  struct OperationSpecification *spec;
   const struct GNUNET_MessageHeader *context;
 
-  set = set_get (client);
-  if (NULL == set)
+  if (NULL == (set = cs->set))
   {
     GNUNET_break (0);
     GNUNET_free (op);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
-  spec = GNUNET_new (struct OperationSpecification);
-  spec->operation = set->operation;
-  spec->app_id = msg->app_id;
-  spec->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
-                                         UINT32_MAX);
-  spec->peer = msg->target_peer;
-  spec->set = set;
-  spec->result_mode = ntohl (msg->result_mode);
-  spec->client_request_id = ntohl (msg->request_id);
-  spec->byzantine = msg->byzantine;
-  spec->byzantine_lower_bound = msg->byzantine_lower_bound;
-  spec->force_full = msg->force_full;
-  spec->force_delta = msg->force_delta;
+  op->salt = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+                                       UINT32_MAX);
+  op->peer = msg->target_peer;
+  op->result_mode = ntohl (msg->result_mode);
+  op->client_request_id = ntohl (msg->request_id);
+  op->byzantine = msg->byzantine;
+  op->byzantine_lower_bound = msg->byzantine_lower_bound;
+  op->force_full = msg->force_full;
+  op->force_delta = msg->force_delta;
   context = GNUNET_MQ_extract_nested_mh (msg);
-  op->spec = spec;
 
-  // Advance generation values, so that
-  // mutations won't interfer with the running operation.
+  /* Advance generation values, so that
+     mutations won't interfer with the running operation. */
+  op->set = set;
   op->generation_created = set->current_generation;
   advance_generation (set);
-
-  op->vt = set->vt;
   GNUNET_CONTAINER_DLL_insert (set->ops_head,
                                set->ops_tail,
                                op);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Creating new CADET channel to port %s\n",
-              GNUNET_h2s (&msg->app_id));
-  op->channel = GNUNET_CADET_channel_creatE (cadet,
+              "Creating new CADET channel to port %s for set operation type %u\n",
+              GNUNET_h2s (&msg->app_id),
+              set->operation);
+  op->channel = GNUNET_CADET_channel_create (cadet,
                                              op,
                                              &msg->target_peer,
                                              &msg->app_id,
@@ -1719,9 +1577,15 @@ handle_client_evaluate (void *cls,
                                              &channel_end_cb,
                                              cadet_handlers);
   op->mq = GNUNET_CADET_get_mq (op->channel);
-  set->vt->evaluate (op,
-                     context);
-  GNUNET_SERVICE_client_continue (client);
+  op->state = set->vt->evaluate (op,
+                                 context);
+  if (NULL == op->state)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (cs->client);
+    return;
+  }
+  GNUNET_SERVICE_client_continue (cs->client);
 }
 
 
@@ -1737,15 +1601,14 @@ static void
 handle_client_iter_ack (void *cls,
                         const struct GNUNET_SET_IterAckMessage *ack)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct Set *set;
 
-  set = set_get (client);
-  if (NULL == set)
+  if (NULL == (set = cs->set))
   {
     /* client without a set acknowledged receiving a value */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
   if (NULL == set->iter)
@@ -1753,10 +1616,10 @@ handle_client_iter_ack (void *cls,
     /* client sent an ack, but we were not expecting one (as
        set iteration has finished) */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
-  GNUNET_SERVICE_client_continue (client);
+  GNUNET_SERVICE_client_continue (cs->client);
   if (ntohl (ack->send_more))
   {
     send_client_element (set);
@@ -1780,42 +1643,33 @@ static void
 handle_client_copy_lazy_prepare (void *cls,
                                  const struct GNUNET_MessageHeader *mh)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct Set *set;
   struct LazyCopyRequest *cr;
   struct GNUNET_MQ_Envelope *ev;
   struct GNUNET_SET_CopyLazyResponseMessage *resp_msg;
 
-  set = set_get (client);
-  if (NULL == set)
+  if (NULL == (set = cs->set))
   {
     /* client without a set requested an operation */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Client requested creation of lazy copy\n");
   cr = GNUNET_new (struct LazyCopyRequest);
-
-  cr->cookie = lazy_copy_cookie;
-  lazy_copy_cookie += 1;
+  cr->cookie = ++lazy_copy_cookie;
   cr->source_set = set;
-
   GNUNET_CONTAINER_DLL_insert (lazy_copy_head,
                                lazy_copy_tail,
                                cr);
-
-
   ev = GNUNET_MQ_msg (resp_msg,
                       GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_RESPONSE);
   resp_msg->cookie = cr->cookie;
-  GNUNET_MQ_send (set->client_mq, ev);
-
-
-  GNUNET_SERVICE_client_continue (client);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Client requested lazy copy\n");
+  GNUNET_MQ_send (set->cs->mq,
+                  ev);
+  GNUNET_SERVICE_client_continue (cs->client);
 }
 
 
@@ -1829,21 +1683,19 @@ static void
 handle_client_copy_lazy_connect (void *cls,
                                  const struct GNUNET_SET_CopyLazyConnectMessage *msg)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct LazyCopyRequest *cr;
   struct Set *set;
   int found;
 
-  if (NULL != set_get (client))
+  if (NULL != cs->set)
   {
     /* There can only be one set per client */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
-
   found = GNUNET_NO;
-
   for (cr = lazy_copy_head; NULL != cr; cr = cr->next)
   {
     if (cr->cookie == msg->cookie)
@@ -1852,21 +1704,20 @@ handle_client_copy_lazy_connect (void *cls,
       break;
     }
   }
-
   if (GNUNET_NO == found)
   {
     /* client asked for copy with cookie we don't know */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
-
   GNUNET_CONTAINER_DLL_remove (lazy_copy_head,
                                lazy_copy_tail,
                                cr);
-
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Client %p requested use of lazy copy\n",
+              cs);
   set = GNUNET_new (struct Set);
-
   switch (cr->source_set->operation)
   {
   case GNUNET_SET_OPERATION_INTERSECTION:
@@ -1886,37 +1737,28 @@ handle_client_copy_lazy_connect (void *cls,
     GNUNET_break (0);
     GNUNET_free (set);
     GNUNET_free (cr);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
 
   set->operation = cr->source_set->operation;
-  set->state = set->vt->copy_state (cr->source_set);
+  set->state = set->vt->copy_state (cr->source_set->state);
   set->content = cr->source_set->content;
-  set->content->refcount += 1;
+  set->content->refcount++;
 
   set->current_generation = cr->source_set->current_generation;
   set->excluded_generations_size = cr->source_set->excluded_generations_size;
-  set->excluded_generations = GNUNET_memdup (cr->source_set->excluded_generations,
-                                             set->excluded_generations_size * sizeof (struct GenerationRange));
+  set->excluded_generations
+    = GNUNET_memdup (cr->source_set->excluded_generations,
+                     set->excluded_generations_size * sizeof (struct GenerationRange));
 
   /* Advance the generation of the new set, so that mutations to the
      of the cloned set and the source set are independent. */
   advance_generation (set);
-
-
-  set->client = client;
-  set->client_mq = GNUNET_SERVICE_client_get_mq (client);
-  GNUNET_CONTAINER_DLL_insert (sets_head,
-                               sets_tail,
-                               set);
-
+  set->cs = cs;
+  cs->set = set;
   GNUNET_free (cr);
-
-  GNUNET_SERVICE_client_continue (client);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Client connected to lazy set\n");
+  GNUNET_SERVICE_client_continue (cs->client);
 }
 
 
@@ -1930,26 +1772,22 @@ static void
 handle_client_cancel (void *cls,
                       const struct GNUNET_SET_CancelMessage *msg)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct Set *set;
   struct Operation *op;
   int found;
 
-  set = set_get (client);
-  if (NULL == set)
+  if (NULL == (set = cs->set))
   {
     /* client without a set requested an operation */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Client requested cancel for op %u\n",
-              (uint32_t) ntohl (msg->request_id));
   found = GNUNET_NO;
   for (op = set->ops_head; NULL != op; op = op->next)
   {
-    if (op->spec->client_request_id == ntohl (msg->request_id))
+    if (op->client_request_id == ntohl (msg->request_id))
     {
       found = GNUNET_YES;
       break;
@@ -1962,15 +1800,19 @@ handle_client_cancel (void *cls,
      * yet and try to cancel the (just barely non-existent) operation.
      * So this is not a hard error.
      */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Client canceled non-existent op\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Client canceled non-existent op %u\n",
+                (uint32_t) ntohl (msg->request_id));
   }
   else
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Client requested cancel for op %u\n",
+                (uint32_t) ntohl (msg->request_id));
     _GSS_operation_destroy (op,
                             GNUNET_YES);
   }
-  GNUNET_SERVICE_client_continue (client);
+  GNUNET_SERVICE_client_continue (cs->client);
 }
 
 
@@ -1986,18 +1828,18 @@ static void
 handle_client_accept (void *cls,
                       const struct GNUNET_SET_AcceptMessage *msg)
 {
-  struct GNUNET_SERVICE_Client *client = cls;
+  struct ClientState *cs = cls;
   struct Set *set;
   struct Operation *op;
   struct GNUNET_SET_ResultMessage *result_message;
   struct GNUNET_MQ_Envelope *ev;
+  struct Listener *listener;
 
-  set = set_get (client);
-  if (NULL == set)
+  if (NULL == (set = cs->set))
   {
     /* client without a set requested to accept */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (client);
+    GNUNET_SERVICE_client_drop (cs->client);
     return;
   }
   op = get_incoming (ntohl (msg->accept_reject_id));
@@ -2005,71 +1847,75 @@ handle_client_accept (void *cls,
   {
     /* It is not an error if the set op does not exist -- it may
      * have been destroyed when the partner peer disconnected. */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Client accepted request that is no longer active\n");
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Client %p accepted request %u of listener %p that is no longer active\n",
+                cs,
+                ntohl (msg->accept_reject_id),
+                cs->listener);
     ev = GNUNET_MQ_msg (result_message,
                         GNUNET_MESSAGE_TYPE_SET_RESULT);
     result_message->request_id = msg->request_id;
-    result_message->element_type = 0;
     result_message->result_status = htons (GNUNET_SET_STATUS_FAILURE);
-    GNUNET_MQ_send (set->client_mq, ev);
-    GNUNET_SERVICE_client_continue (client);
+    GNUNET_MQ_send (set->cs->mq,
+                    ev);
+    GNUNET_SERVICE_client_continue (cs->client);
     return;
   }
-
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Client accepting request %u\n",
               (uint32_t) ntohl (msg->accept_reject_id));
-  GNUNET_assert (GNUNET_YES == op->is_incoming);
-  op->is_incoming = GNUNET_NO;
-  GNUNET_CONTAINER_DLL_remove (incoming_head,
-                               incoming_tail,
+  listener = op->listener;
+  op->listener = NULL;
+  GNUNET_CONTAINER_DLL_remove (listener->op_head,
+                               listener->op_tail,
                                op);
-  op->spec->set = set;
+  op->set = set;
   GNUNET_CONTAINER_DLL_insert (set->ops_head,
                                set->ops_tail,
                                op);
-  op->spec->client_request_id = ntohl (msg->request_id);
-  op->spec->result_mode = ntohl (msg->result_mode);
-  op->spec->byzantine = msg->byzantine;
-  op->spec->byzantine_lower_bound = msg->byzantine_lower_bound;
-  op->spec->force_full = msg->force_full;
-  op->spec->force_delta = msg->force_delta;
-
-  // Advance generation values, so that
-  // mutations won't interfer with the running operation.
+  op->client_request_id = ntohl (msg->request_id);
+  op->result_mode = ntohl (msg->result_mode);
+  op->byzantine = msg->byzantine;
+  op->byzantine_lower_bound = msg->byzantine_lower_bound;
+  op->force_full = msg->force_full;
+  op->force_delta = msg->force_delta;
+
+  /* Advance generation values, so that future mutations do not
+     interfer with the running operation. */
   op->generation_created = set->current_generation;
   advance_generation (set);
-
-  op->vt = set->vt;
-  op->vt->accept (op);
-  GNUNET_SERVICE_client_continue (client);
+  GNUNET_assert (NULL == op->state);
+  op->state = set->vt->accept (op);
+  if (NULL == op->state)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVICE_client_drop (cs->client);
+    return;
+  }
+  /* Now allow CADET to continue, as we did not do this in
+     #handle_incoming_msg (as we wanted to first see if the
+     local client would accept the request). */
+  GNUNET_CADET_receive_done (op->channel);
+  GNUNET_SERVICE_client_continue (cs->client);
 }
 
 
 /**
  * Called to clean up, after a shutdown has been requested.
  *
- * @param cls closure
+ * @param cls closure, NULL
  */
 static void
 shutdown_task (void *cls)
 {
-  while (NULL != incoming_head)
-    incoming_destroy (incoming_head);
-  while (NULL != listeners_head)
-    listener_destroy (listeners_head);
-  while (NULL != sets_head)
-    set_destroy (sets_head);
-
-  /* it's important to destroy cadet at the end, as all channels
-   * must be destroyed before the cadet handle! */
+  /* Delay actual shutdown to allow service to disconnect clients */
   if (NULL != cadet)
   {
     GNUNET_CADET_disconnect (cadet);
     cadet = NULL;
   }
-  GNUNET_STATISTICS_destroy (_GSS_statistics, GNUNET_YES);
+  GNUNET_STATISTICS_destroy (_GSS_statistics,
+                             GNUNET_YES);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "handled shutdown request\n");
 }
@@ -2088,15 +1934,19 @@ run (void *cls,
      const struct GNUNET_CONFIGURATION_Handle *cfg,
      struct GNUNET_SERVICE_Handle *service)
 {
-  configuration = cfg;
+  /* FIXME: need to modify SERVICE (!) API to allow
+     us to run a shutdown task *after* clients were
+     forcefully disconnected! */
   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
                                  NULL);
-  _GSS_statistics = GNUNET_STATISTICS_create ("set", cfg);
-  cadet = GNUNET_CADET_connecT (cfg);
+  _GSS_statistics = GNUNET_STATISTICS_create ("set",
+                                              cfg);
+  cadet = GNUNET_CADET_connect (cfg);
   if (NULL == cadet)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 _("Could not connect to CADET service\n"));
+    GNUNET_SCHEDULER_shutdown ();
     return;
   }
 }
@@ -2122,7 +1972,7 @@ GNUNET_SERVICE_MAIN
                           NULL),
  GNUNET_MQ_hd_var_size (client_mutation,
                         GNUNET_MESSAGE_TYPE_SET_ADD,
-                        struct GNUNET_MessageHeader,
+                        struct GNUNET_SET_ElementMessage,
                         NULL),
  GNUNET_MQ_hd_fixed_size (client_create_set,
                           GNUNET_MESSAGE_TYPE_SET_CREATE,
@@ -2146,7 +1996,7 @@ GNUNET_SERVICE_MAIN
                           NULL),
  GNUNET_MQ_hd_var_size (client_mutation,
                         GNUNET_MESSAGE_TYPE_SET_REMOVE,
-                        struct GNUNET_MessageHeader,
+                        struct GNUNET_SET_ElementMessage,
                         NULL),
  GNUNET_MQ_hd_fixed_size (client_cancel,
                           GNUNET_MESSAGE_TYPE_SET_CANCEL,
index 68d8fe81f60a6a75fcffdaa7247765fca3a1ffc8..19413fd3047ea297c13d3648cdd61e89120c82f3 100644 (file)
@@ -1,6 +1,6 @@
 /*
       This file is part of GNUnet
-      Copyright (C) 2013, 2014 GNUnet e.V.
+      Copyright (C) 2013-2017 GNUnet e.V.
 
       GNUnet is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published
@@ -67,85 +67,6 @@ struct ElementEntry;
 struct Operation;
 
 
-/**
- * Detail information about an operation.
- */
-struct OperationSpecification
-{
-
-  /**
-   * The remove peer we evaluate the operation with.
-   */
-  struct GNUNET_PeerIdentity peer;
-
-  /**
-   * Application ID for the operation, used to distinguish
-   * multiple operations of the same type with the same peer.
-   */
-  struct GNUNET_HashCode app_id;
-
-  /**
-   * Context message, may be NULL.
-   */
-  struct GNUNET_MessageHeader *context_msg;
-
-  /**
-   * Set associated with the operation, NULL until the spec has been
-   * associated with a set.
-   */
-  struct Set *set;
-
-  /**
-   * Salt to use for the operation.
-   */
-  uint32_t salt;
-
-  /**
-   * Remote peers element count
-   */
-  uint32_t remote_element_count;
-
-  /**
-   * ID used to identify an operation between service and client
-   */
-  uint32_t client_request_id;
-
-  /**
-   * The type of the operation.
-   */
-  enum GNUNET_SET_OperationType operation;
-
-  /**
-   * When are elements sent to the client, and which elements are sent?
-   */
-  enum GNUNET_SET_ResultMode result_mode;
-
-  /**
-   * Always use delta operation instead of sending full sets,
-   * even it it's less efficient.
-   */
-  int force_delta;
-
-  /**
-   * Always send full sets, even if delta operations would
-   * be more efficient.
-   */
-  int force_full;
-
-  /**
-   * #GNUNET_YES to fail operations where Byzantine faults
-   * are suspected
-   */
-  int byzantine;
-
-  /**
-   * Lower bound for the set size, used only when
-   * byzantine mode is enabled.
-   */
-  int byzantine_lower_bound;
-};
-
-
 /**
  * Signature of functions that create the implementation-specific
  * state for a set supporting a specific operation.
@@ -153,7 +74,7 @@ struct OperationSpecification
  * @return a set state specific to the supported operation, NULL on error
  */
 typedef struct SetState *
-(*CreateImpl) (void);
+(*SetCreateImpl) (void);
 
 
 /**
@@ -164,18 +85,18 @@ typedef struct SetState *
  * @param ee element message from the client
  */
 typedef void
-(*AddRemoveImpl) (struct SetState *state,
+(*SetAddRemoveImpl) (struct SetState *state,
                   struct ElementEntry *ee);
 
 
 /**
- * Signature of functions that handle disconnection of the remote
- * peer.
+ * Make a copy of a set's internal state.
  *
- * @param op the set operation, contains implementation-specific data
+ * @param state set state to copy
+ * @return copy of the internal state
  */
-typedef void
-(*PeerDisconnectImpl) (struct Operation *op);
+typedef struct SetState *
+(*SetCopyStateImpl) (struct SetState *state);
 
 
 /**
@@ -185,7 +106,7 @@ typedef void
  * @param state the set state, contains implementation-specific data
  */
 typedef void
-(*DestroySetImpl) (struct SetState *state);
+(*SetDestroyImpl) (struct SetState *state);
 
 
 /**
@@ -193,8 +114,9 @@ typedef void
  *
  * @param op operation that is created by accepting the operation,
  *        should be initialized by the implementation
+ * @return operation-specific state to keep in @a op
  */
-typedef void
+typedef struct OperationState *
 (*OpAcceptImpl) (struct Operation *op);
 
 
@@ -206,38 +128,32 @@ typedef void
  *        begin the evaluation
  * @param opaque_context message to be transmitted to the listener
  *        to convince him to accept, may be NULL
+ * @return operation-specific state to keep in @a op
  */
-typedef void
+typedef struct OperationState *
 (*OpEvaluateImpl) (struct Operation *op,
                    const struct GNUNET_MessageHeader *opaque_context);
 
-
 /**
- * Signature of functions that implement the message handling for
- * the different set operations.
+ * Signature of functions that implement operation cancelation.
+ * This includes notifying the client about the operation's final
+ * state.
  *
  * @param op operation state
- * @param msg received message
- * @return #GNUNET_OK on success, #GNUNET_SYSERR to
- *         destroy the operation and the tunnel
  */
-typedef int
-(*MsgHandlerImpl) (struct Operation *op,
-                   const struct GNUNET_MessageHeader *msg);
+typedef void
+(*OpCancelImpl) (struct Operation *op);
 
 
 /**
- * Signature of functions that implement operation cancellation
+ * Signature of functions called when the CADET channel died.
  *
  * @param op operation state
  */
 typedef void
-(*CancelImpl) (struct Operation *op);
+(*OpChannelDeathImpl) (struct Operation *op);
 
 
-typedef struct SetState *
-(*CopyStateImpl) (struct Set *op);
-
 
 /**
  * Dispatch table for a specific set operation.  Every set operation
@@ -248,49 +164,48 @@ struct SetVT
   /**
    * Callback for the set creation.
    */
-  CreateImpl create;
+  SetCreateImpl create;
 
   /**
    * Callback for element insertion
    */
-  AddRemoveImpl add;
+  SetAddRemoveImpl add;
 
   /**
    * Callback for element removal.
    */
-  AddRemoveImpl remove;
+  SetAddRemoveImpl remove;
 
   /**
-   * Callback for accepting a set operation request
+   * Callback for making a copy of a set's internal state.
    */
-  OpAcceptImpl accept;
+  SetCopyStateImpl copy_state;
 
   /**
-   * Callback for starting evaluation with a remote peer.
+   * Callback for destruction of the set state.
    */
-  OpEvaluateImpl evaluate;
+  SetDestroyImpl destroy_set;
 
   /**
-   * Callback for destruction of the set state.
+   * Callback for accepting a set operation request
    */
-  DestroySetImpl destroy_set;
+  OpAcceptImpl accept;
 
   /**
-   * Callback for handling operation-specific messages.
+   * Callback for starting evaluation with a remote peer.
    */
-  MsgHandlerImpl msg_handler;
+  OpEvaluateImpl evaluate;
 
   /**
-   * Callback for handling the remote peer's disconnect.
+   * Callback for canceling an operation.
    */
-  PeerDisconnectImpl peer_disconnect;
+  OpCancelImpl cancel;
 
   /**
-   * Callback for canceling an operation by its ID.
+   * Callback called in case the CADET channel died.
    */
-  CancelImpl cancel;
+  OpChannelDeathImpl channel_death;
 
-  CopyStateImpl copy_state;
 };
 
 
@@ -360,20 +275,56 @@ struct ElementEntry
 };
 
 
+/**
+ * A listener is inhabited by a client, and waits for evaluation
+ * requests from remote peers.
+ */
 struct Listener;
 
 
+/**
+ * State we keep per client.
+ */
+struct ClientState
+{
+  /**
+   * Set, if associated with the client, otherwise NULL.
+   */
+  struct Set *set;
+
+  /**
+   * Listener, if associated with the client, otherwise NULL.
+   */
+  struct Listener *listener;
+
+  /**
+   * Client handle.
+   */
+  struct GNUNET_SERVICE_Client *client;
+
+  /**
+   * Message queue.
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+};
+
+
 /**
  * Operation context used to execute a set operation.
  */
 struct Operation
 {
+
   /**
-   * V-Table for the operation belonging to the tunnel contest.
-   *
-   * Used for all operation specific operations after receiving the ops request
+   * Kept in a DLL of the listener, if @e listener is non-NULL.
    */
-  const struct SetVT *vt;
+  struct Operation *next;
+
+  /**
+   * Kept in a DLL of the listener, if @e listener is non-NULL.
+   */
+  struct Operation *prev;
 
   /**
    * Channel to the peer.
@@ -391,11 +342,15 @@ struct Operation
   struct GNUNET_MQ_Handle *mq;
 
   /**
-   * Detail information about the set operation, including the set to
-   * use.  When 'spec' is NULL, the operation is not yet entirely
-   * initialized.
+   * Context message, may be NULL.
+   */
+  struct GNUNET_MessageHeader *context_msg;
+
+  /**
+   * Set associated with the operation, NULL until the spec has been
+   * associated with a set.
    */
-  struct OperationSpecification *spec;
+  struct Set *set;
 
   /**
    * Operation-specific operation state.  Note that the exact
@@ -404,16 +359,6 @@ struct Operation
    */
   struct OperationState *state;
 
-  /**
-   * Evaluate operations are held in a linked list.
-   */
-  struct Operation *next;
-
-  /**
-   * Evaluate operations are held in a linked list.
-   */
-  struct Operation *prev;
-
   /**
    * The identity of the requesting peer.  Needs to
    * be stored here as the op spec might not have been created yet.
@@ -426,6 +371,50 @@ struct Operation
    */
   struct GNUNET_SCHEDULER_Task *timeout_task;
 
+  /**
+   * Salt to use for the operation.
+   */
+  uint32_t salt;
+
+  /**
+   * Remote peers element count
+   */
+  uint32_t remote_element_count;
+
+  /**
+   * ID used to identify an operation between service and client
+   */
+  uint32_t client_request_id;
+
+  /**
+   * When are elements sent to the client, and which elements are sent?
+   */
+  enum GNUNET_SET_ResultMode result_mode;
+
+  /**
+   * Always use delta operation instead of sending full sets,
+   * even it it's less efficient.
+   */
+  int force_delta;
+
+  /**
+   * Always send full sets, even if delta operations would
+   * be more efficient.
+   */
+  int force_full;
+
+  /**
+   * #GNUNET_YES to fail operations where Byzantine faults
+   * are suspected
+   */
+  int byzantine;
+
+  /**
+   * Lower bound for the set size, used only when
+   * byzantine mode is enabled.
+   */
+  int byzantine_lower_bound;
+
   /**
    * Unique request id for the request from a remote peer, sent to the
    * client, which will accept or reject the request.  Set to '0' iff
@@ -433,46 +422,27 @@ struct Operation
    */
   uint32_t suggest_id;
 
-  /**
-   * #GNUNET_YES if this is not a "real" set operation yet, and we still
-   * need to wait for the other peer to give us more details.
-   */
-  int is_incoming;
-
   /**
    * Generation in which the operation handle
    * was created.
    */
   unsigned int generation_created;
 
-  /**
-   * Incremented whenever (during shutdown) some component still
-   * needs to do something with this before the operation is freed.
-   * (Used as a reference counter, but only during termination.)
-   */
-  unsigned int keep;
 };
 
 
 /**
- * SetContent stores the actual set elements,
- * which may be shared by multiple generations derived
- * from one set.
+ * SetContent stores the actual set elements, which may be shared by
+ * multiple generations derived from one set.
  */
 struct SetContent
 {
-  /**
-   * Number of references to the content.
-   */
-  unsigned int refcount;
 
   /**
    * Maps `struct GNUNET_HashCode *` to `struct ElementEntry *`.
    */
   struct GNUNET_CONTAINER_MultiHashMap *elements;
 
-  unsigned int latest_generation;
-
   /**
    * Mutations requested by the client that we're
    * unable to execute right now because we're iterating
@@ -487,6 +457,16 @@ struct SetContent
    */
   struct PendingMutation *pending_mutations_tail;
 
+  /**
+   * Number of references to the content.
+   */
+  unsigned int refcount;
+
+  /**
+   * FIXME: document!
+   */
+  unsigned int latest_generation;
+
   /**
    * Number of concurrently active iterators.
    */
@@ -508,11 +488,24 @@ struct GenerationRange
 };
 
 
+/**
+ * Information about a mutation to apply to a set.
+ */
 struct PendingMutation
 {
+  /**
+   * Mutations are kept in a DLL.
+   */
   struct PendingMutation *prev;
+
+  /**
+   * Mutations are kept in a DLL.
+   */
   struct PendingMutation *next;
 
+  /**
+   * Set this mutation is about.
+   */
   struct Set *set;
 
   /**
@@ -520,7 +513,7 @@ struct PendingMutation
    * May only be a #GNUNET_MESSAGE_TYPE_SET_ADD or
    * #GNUNET_MESSAGE_TYPE_SET_REMOVE.
    */
-  struct GNUNET_MessageHeader *mutation_message;
+  struct GNUNET_SET_ElementMessage *msg;
 };
 
 
@@ -544,12 +537,13 @@ struct Set
    * Client that owns the set.  Only one client may own a set,
    * and there can only be one set per client.
    */
-  struct GNUNET_SERVICE_Client *client;
+  struct ClientState *cs;
 
   /**
-   * Message queue for the client.
+   * Content, possibly shared by multiple sets,
+   * and thus reference counted.
    */
-  struct GNUNET_MQ_Handle *client_mq;
+  struct SetContent *content;
 
   /**
    * Virtual table for this set.  Determined by the operation type of
@@ -582,15 +576,15 @@ struct Set
   struct Operation *ops_tail;
 
   /**
-   * Current generation, that is, number of previously executed
-   * operations and lazy copies on the underlying set content.
+   * List of generations we have to exclude, due to lazy copies.
    */
-  unsigned int current_generation;
+  struct GenerationRange *excluded_generations;
 
   /**
-   * List of generations we have to exclude, due to lazy copies.
+   * Current generation, that is, number of previously executed
+   * operations and lazy copies on the underlying set content.
    */
-  struct GenerationRange *excluded_generations;
+  unsigned int current_generation;
 
   /**
    * Number of elements in array @a excluded_generations.
@@ -602,22 +596,17 @@ struct Set
    */
   enum GNUNET_SET_OperationType operation;
 
-  /**
-   * Each @e iter is assigned a unique number, so that the client
-   * can distinguish iterations.
-   */
-  uint16_t iteration_id;
-
   /**
    * Generation we're currently iteration over.
    */
   unsigned int iter_generation;
 
   /**
-   * Content, possibly shared by multiple sets,
-   * and thus reference counted.
+   * Each @e iter is assigned a unique number, so that the client
+   * can distinguish iterations.
    */
-  struct SetContent *content;
+  uint16_t iteration_id;
+
 };
 
 
@@ -625,10 +614,14 @@ extern struct GNUNET_STATISTICS_Handle *_GSS_statistics;
 
 
 /**
- * Destroy the given operation.  Call the implementation-specific
- * cancel function of the operation.  Disconnects from the remote
- * peer.  Does not disconnect the client, as there may be multiple
- * operations per set.
+ * Destroy the given operation.   Used for any operation where both
+ * peers were known and that thus actually had a vt and channel.  Must
+ * not be used for operations where 'listener' is still set and we do
+ * not know the other peer.
+ *
+ * Call the implementation-specific cancel function of the operation.
+ * Disconnects from the remote peer.  Does not disconnect the client,
+ * as there may be multiple operations per set.
  *
  * @param op operation to destroy
  * @param gc #GNUNET_YES to perform garbage collection on the set
@@ -656,10 +649,13 @@ const struct SetVT *
 _GSS_intersection_vt (void);
 
 
-int
-_GSS_is_element_of_set (struct ElementEntry *ee,
-                        struct Set *set);
-
+/**
+ * Is element @a ee part of the set used by @a op?
+ *
+ * @param ee element to test
+ * @param op operation the defines the set and its generation
+ * @return #GNUNET_YES if the element is in the set, #GNUNET_NO if not
+ */
 int
 _GSS_is_element_of_operation (struct ElementEntry *ee,
                               struct Operation *op);
index 9fe1eabe64e98753f2db24796c01d7fe8431b1d1..9dc4217921d65fe54fce53744c91f68f19027491 100644 (file)
@@ -1,6 +1,6 @@
 /*
       This file is part of GNUnet
-      Copyright (C) 2013, 2014 GNUnet e.V.
+      Copyright (C) 2013-2017 GNUnet e.V.
 
       GNUnet is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published
@@ -28,6 +28,7 @@
 #include "gnunet-service-set.h"
 #include "gnunet_block_lib.h"
 #include "gnunet-service-set_protocol.h"
+#include "gnunet-service-set_intersection.h"
 #include <gcrypt.h>
 
 
@@ -54,6 +55,18 @@ enum IntersectionOperationPhase
    */
   PHASE_BF_EXCHANGE,
 
+  /**
+   * We must next send the P2P DONE message (after finishing mostly
+   * with the local client).  Then we will wait for the channel to close.
+   */
+  PHASE_MUST_SEND_DONE,
+
+  /**
+   * We have received the P2P DONE message, and must finish with the
+   * local client before terminating the channel.
+   */
+  PHASE_DONE_RECEIVED,
+
   /**
    * The protocol is over.  Results may still have to be sent to the
    * client.
@@ -161,6 +174,13 @@ struct OperationState
    * Did we send the client that we are done?
    */
   int client_done_sent;
+
+  /**
+   * Set whenever we reach the state where the death of the
+   * channel is perfectly find and should NOT result in the
+   * operation being cancelled.
+   */
+  int channel_death_expected;
 };
 
 
@@ -192,12 +212,12 @@ send_client_removed_element (struct Operation *op,
   struct GNUNET_MQ_Envelope *ev;
   struct GNUNET_SET_ResultMessage *rm;
 
-  if (GNUNET_SET_RESULT_REMOVED != op->spec->result_mode)
+  if (GNUNET_SET_RESULT_REMOVED != op->result_mode)
     return; /* Wrong mode for transmitting removed elements */
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Sending removed element (size %u) to client\n",
               element->size);
-  GNUNET_assert (0 != op->spec->client_request_id);
+  GNUNET_assert (0 != op->client_request_id);
   ev = GNUNET_MQ_msg_extra (rm,
                             element->size,
                             GNUNET_MESSAGE_TYPE_SET_RESULT);
@@ -207,12 +227,12 @@ send_client_removed_element (struct Operation *op,
     return;
   }
   rm->result_status = htons (GNUNET_SET_STATUS_OK);
-  rm->request_id = htonl (op->spec->client_request_id);
+  rm->request_id = htonl (op->client_request_id);
   rm->element_type = element->element_type;
   GNUNET_memcpy (&rm[1],
-          element->data,
-          element->size);
-  GNUNET_MQ_send (op->spec->set->client_mq,
+                 element->data,
+                 element->size);
+  GNUNET_MQ_send (op->set->cs->mq,
                   ev);
 }
 
@@ -396,9 +416,9 @@ fail_intersection_operation (struct Operation *op)
   ev = GNUNET_MQ_msg (msg,
                       GNUNET_MESSAGE_TYPE_SET_RESULT);
   msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
-  msg->request_id = htonl (op->spec->client_request_id);
+  msg->request_id = htonl (op->client_request_id);
   msg->element_type = htons (0);
-  GNUNET_MQ_send (op->spec->set->client_mq,
+  GNUNET_MQ_send (op->set->cs->mq,
                   ev);
   _GSS_operation_destroy (op,
                           GNUNET_YES);
@@ -427,8 +447,8 @@ send_bloomfilter (struct Operation *op)
      should use more bits to maximize its set reduction
      potential and minimize overall bandwidth consumption. */
   bf_elementbits = 2 + ceil (log2((double)
-                             (op->spec->remote_element_count /
-                                   (double) op->state->my_element_count)));
+                             (op->remote_element_count /
+                              (double) op->state->my_element_count)));
   if (bf_elementbits < 1)
     bf_elementbits = 1; /* make sure k is not 0 */
   /* optimize BF-size to ~50% of bits set */
@@ -514,18 +534,67 @@ send_client_done_and_destroy (void *cls)
   struct GNUNET_MQ_Envelope *ev;
   struct GNUNET_SET_ResultMessage *rm;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Intersection succeeded, sending DONE to local client\n");
   ev = GNUNET_MQ_msg (rm,
                       GNUNET_MESSAGE_TYPE_SET_RESULT);
-  rm->request_id = htonl (op->spec->client_request_id);
+  rm->request_id = htonl (op->client_request_id);
   rm->result_status = htons (GNUNET_SET_STATUS_DONE);
   rm->element_type = htons (0);
-  GNUNET_MQ_send (op->spec->set->client_mq,
+  GNUNET_MQ_send (op->set->cs->mq,
                   ev);
   _GSS_operation_destroy (op,
                           GNUNET_YES);
 }
 
 
+/**
+ * Remember that we are done dealing with the local client
+ * AND have sent the other peer our message that we are done,
+ * so we are not just waiting for the channel to die before
+ * telling the local client that we are done as our last act.
+ *
+ * @param cls the `struct Operation`.
+ */
+static void
+finished_local_operations (void *cls)
+{
+  struct Operation *op = cls;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "DONE sent to other peer, now waiting for other end to close the channel\n");
+  op->state->phase = PHASE_FINISHED;
+  op->state->channel_death_expected = GNUNET_YES;
+}
+
+
+/**
+ * Notify the other peer that we are done.  Once this message
+ * is out, we still need to notify the local client that we
+ * are done.
+ *
+ * @param op operation to notify for.
+ */
+static void
+send_p2p_done (struct Operation *op)
+{
+  struct GNUNET_MQ_Envelope *ev;
+  struct IntersectionDoneMessage *idm;
+
+  GNUNET_assert (PHASE_MUST_SEND_DONE == op->state->phase);
+  GNUNET_assert (GNUNET_NO == op->state->channel_death_expected);
+  ev = GNUNET_MQ_msg (idm,
+                      GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE);
+  idm->final_element_count = htonl (op->state->my_element_count);
+  idm->element_xor_hash = op->state->my_xor;
+  GNUNET_MQ_notify_sent (ev,
+                         &finished_local_operations,
+                         op);
+  GNUNET_MQ_send (op->mq,
+                  ev);
+}
+
+
 /**
  * Send all elements in the full result iterator.
  *
@@ -549,8 +618,21 @@ send_remaining_elements (void *cls)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Sending done and destroy because iterator ran out\n");
-    op->keep--;
-    send_client_done_and_destroy (op);
+    GNUNET_CONTAINER_multihashmap_iterator_destroy (op->state->full_result_iter);
+    op->state->full_result_iter = NULL;
+    if (PHASE_DONE_RECEIVED == op->state->phase)
+    {
+      op->state->phase = PHASE_FINISHED;
+      send_client_done_and_destroy (op);
+    }
+    else if (PHASE_MUST_SEND_DONE == op->state->phase)
+    {
+      send_p2p_done (op);
+    }
+    else
+    {
+      GNUNET_assert (0);
+    }
     return;
   }
   ee = nxt;
@@ -559,48 +641,136 @@ send_remaining_elements (void *cls)
               "Sending element %s:%u to client (full set)\n",
               GNUNET_h2s (&ee->element_hash),
               element->size);
-  GNUNET_assert (0 != op->spec->client_request_id);
+  GNUNET_assert (0 != op->client_request_id);
   ev = GNUNET_MQ_msg_extra (rm,
                             element->size,
                             GNUNET_MESSAGE_TYPE_SET_RESULT);
   GNUNET_assert (NULL != ev);
   rm->result_status = htons (GNUNET_SET_STATUS_OK);
-  rm->request_id = htonl (op->spec->client_request_id);
+  rm->request_id = htonl (op->client_request_id);
   rm->element_type = element->element_type;
   GNUNET_memcpy (&rm[1],
-          element->data,
-          element->size);
+                 element->data,
+                 element->size);
   GNUNET_MQ_notify_sent (ev,
                          &send_remaining_elements,
                          op);
-  GNUNET_MQ_send (op->spec->set->client_mq,
+  GNUNET_MQ_send (op->set->cs->mq,
                   ev);
 }
 
 
 /**
- * Inform the peer that this operation is complete.
+ * Fills the "my_elements" hashmap with the initial set of
+ * (non-deleted) elements from the set of the specification.
  *
- * @param op the intersection operation to fail
+ * @param cls closure with the `struct Operation *`
+ * @param key current key code for the element
+ * @param value value in the hash map with the `struct ElementEntry *`
+ * @return #GNUNET_YES (we should continue to iterate)
+ */
+static int
+initialize_map_unfiltered (void *cls,
+                           const struct GNUNET_HashCode *key,
+                           void *value)
+{
+  struct ElementEntry *ee = value;
+  struct Operation *op = cls;
+
+  if (GNUNET_NO == _GSS_is_element_of_operation (ee, op))
+    return GNUNET_YES; /* element not live in operation's generation */
+  GNUNET_CRYPTO_hash_xor (&op->state->my_xor,
+                          &ee->element_hash,
+                          &op->state->my_xor);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Initial full initialization of my_elements, adding %s:%u\n",
+              GNUNET_h2s (&ee->element_hash),
+              ee->element.size);
+  GNUNET_break (GNUNET_YES ==
+                GNUNET_CONTAINER_multihashmap_put (op->state->my_elements,
+                                                   &ee->element_hash,
+                                                   ee,
+                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+  return GNUNET_YES;
+}
+
+
+/**
+ * Send our element count to the peer, in case our element count is
+ * lower than his.
+ *
+ * @param op intersection operation
  */
 static void
-send_peer_done (struct Operation *op)
+send_element_count (struct Operation *op)
 {
   struct GNUNET_MQ_Envelope *ev;
-  struct IntersectionDoneMessage *idm;
+  struct IntersectionElementInfoMessage *msg;
 
-  op->state->phase = PHASE_FINISHED;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Intersection succeeded, sending DONE\n");
-  GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
-  op->state->local_bf = NULL;
+              "Sending our element count (%u)\n",
+              op->state->my_element_count);
+  ev = GNUNET_MQ_msg (msg,
+                      GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO);
+  msg->sender_element_count = htonl (op->state->my_element_count);
+  GNUNET_MQ_send (op->mq, ev);
+}
 
-  ev = GNUNET_MQ_msg (idm,
-                      GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE);
-  idm->final_element_count = htonl (op->state->my_element_count);
-  idm->element_xor_hash = op->state->my_xor;
-  GNUNET_MQ_send (op->mq,
-                  ev);
+
+/**
+ * We go first, initialize our map with all elements and
+ * send the first Bloom filter.
+ *
+ * @param op operation to start exchange for
+ */
+static void
+begin_bf_exchange (struct Operation *op)
+{
+  op->state->phase = PHASE_BF_EXCHANGE;
+  GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements,
+                                         &initialize_map_unfiltered,
+                                         op);
+  send_bloomfilter (op);
+}
+
+
+/**
+ * Handle the initial `struct IntersectionElementInfoMessage` from a
+ * remote peer.
+ *
+ * @param cls the intersection operation
+ * @param mh the header of the message
+ */
+void
+handle_intersection_p2p_element_info (void *cls,
+                                      const struct IntersectionElementInfoMessage *msg)
+{
+  struct Operation *op = cls;
+
+  if (GNUNET_SET_OPERATION_INTERSECTION != op->set->operation)
+  {
+    GNUNET_break_op (0);
+    fail_intersection_operation(op);
+    return;
+  }
+  op->remote_element_count = ntohl (msg->sender_element_count);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received remote element count (%u), I have %u\n",
+              op->remote_element_count,
+              op->state->my_element_count);
+  if ( ( (PHASE_INITIAL != op->state->phase) &&
+         (PHASE_COUNT_SENT != op->state->phase) ) ||
+       (op->state->my_element_count > op->remote_element_count) ||
+       (0 == op->state->my_element_count) ||
+       (0 == op->remote_element_count) )
+  {
+    GNUNET_break_op (0);
+    fail_intersection_operation(op);
+    return;
+  }
+  GNUNET_break (NULL == op->state->remote_bf);
+  begin_bf_exchange (op);
+  GNUNET_CADET_receive_done (op->channel);
 }
 
 
@@ -615,9 +785,9 @@ process_bf (struct Operation *op)
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Received BF in phase %u, foreign count is %u, my element count is %u/%u\n",
               op->state->phase,
-              op->spec->remote_element_count,
+              op->remote_element_count,
               op->state->my_element_count,
-              GNUNET_CONTAINER_multihashmap_size (op->spec->set->content->elements));
+              GNUNET_CONTAINER_multihashmap_size (op->set->content->elements));
   switch (op->state->phase)
   {
   case PHASE_INITIAL:
@@ -627,11 +797,8 @@ process_bf (struct Operation *op)
   case PHASE_COUNT_SENT:
     /* This is the first BF being sent, build our initial map with
        filtering in place */
-    op->state->my_elements
-      = GNUNET_CONTAINER_multihashmap_create (op->spec->remote_element_count,
-                                              GNUNET_YES);
     op->state->my_element_count = 0;
-    GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements,
+    GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements,
                                            &filtered_map_initialization,
                                            op);
     break;
@@ -641,6 +808,14 @@ process_bf (struct Operation *op)
                                            &iterator_bf_reduce,
                                            op);
     break;
+  case PHASE_MUST_SEND_DONE:
+    GNUNET_break_op (0);
+    fail_intersection_operation(op);
+    return;
+  case PHASE_DONE_RECEIVED:
+    GNUNET_break_op (0);
+    fail_intersection_operation(op);
+    return;
   case PHASE_FINISHED:
     GNUNET_break_op (0);
     fail_intersection_operation(op);
@@ -650,13 +825,28 @@ process_bf (struct Operation *op)
   op->state->remote_bf = NULL;
 
   if ( (0 == op->state->my_element_count) || /* fully disjoint */
-       ( (op->state->my_element_count == op->spec->remote_element_count) &&
+       ( (op->state->my_element_count == op->remote_element_count) &&
          (0 == memcmp (&op->state->my_xor,
                        &op->state->other_xor,
                        sizeof (struct GNUNET_HashCode))) ) )
   {
     /* we are done */
-    send_peer_done (op);
+    op->state->phase = PHASE_MUST_SEND_DONE;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Intersection succeeded, sending DONE to other peer\n");
+    GNUNET_CONTAINER_bloomfilter_free (op->state->local_bf);
+    op->state->local_bf = NULL;
+    if (GNUNET_SET_RESULT_FULL == op->result_mode)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Sending full result set (%u elements)\n",
+                  GNUNET_CONTAINER_multihashmap_size (op->state->my_elements));
+      op->state->full_result_iter
+        = GNUNET_CONTAINER_multihashmap_iterator_create (op->state->my_elements);
+      send_remaining_elements (op);
+      return;
+    }
+    send_p2p_done (op);
     return;
   }
   op->state->phase = PHASE_BF_EXCHANGE;
@@ -664,42 +854,54 @@ process_bf (struct Operation *op)
 }
 
 
+/**
+ * Check an BF message from a remote peer.
+ *
+ * @param cls the intersection operation
+ * @param msg the header of the message
+ * @return #GNUNET_OK if @a msg is well-formed
+ */
+int
+check_intersection_p2p_bf (void *cls,
+                           const struct BFMessage *msg)
+{
+  struct Operation *op = cls;
+
+  if (GNUNET_SET_OPERATION_INTERSECTION != op->set->operation)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
 /**
  * Handle an BF message from a remote peer.
  *
  * @param cls the intersection operation
- * @param mh the header of the message
+ * @param msg the header of the message
  */
-static void
-handle_p2p_bf (void *cls,
-               const struct GNUNET_MessageHeader *mh)
+void
+handle_intersection_p2p_bf (void *cls,
+                            const struct BFMessage *msg)
 {
   struct Operation *op = cls;
-  const struct BFMessage *msg;
   uint32_t bf_size;
   uint32_t chunk_size;
   uint32_t bf_bits_per_element;
-  uint16_t msize;
 
-  msize = htons (mh->size);
-  if (msize < sizeof (struct BFMessage))
-  {
-    GNUNET_break_op (0);
-    fail_intersection_operation (op);
-    return;
-  }
-  msg = (const struct BFMessage *) mh;
   switch (op->state->phase)
   {
   case PHASE_INITIAL:
     GNUNET_break_op (0);
     fail_intersection_operation (op);
-    break;
+    return;
   case PHASE_COUNT_SENT:
   case PHASE_BF_EXCHANGE:
     bf_size = ntohl (msg->bloomfilter_total_length);
     bf_bits_per_element = ntohl (msg->bits_per_element);
-    chunk_size = msize - sizeof (struct BFMessage);
+    chunk_size = htons (msg->header.size) - sizeof (struct BFMessage);
     op->state->other_xor = msg->element_xor_hash;
     if (bf_size == chunk_size)
     {
@@ -715,9 +917,9 @@ handle_p2p_bf (void *cls,
                                              bf_size,
                                              bf_bits_per_element);
       op->state->salt = ntohl (msg->sender_mutator);
-      op->spec->remote_element_count = ntohl (msg->sender_element_count);
+      op->remote_element_count = ntohl (msg->sender_element_count);
       process_bf (op);
-      return;
+      break;
     }
     /* multipart chunk */
     if (NULL == op->state->bf_data)
@@ -728,7 +930,7 @@ handle_p2p_bf (void *cls,
       op->state->bf_bits_per_element = bf_bits_per_element;
       op->state->bf_data_offset = 0;
       op->state->salt = ntohl (msg->sender_mutator);
-      op->spec->remote_element_count = ntohl (msg->sender_element_count);
+      op->remote_element_count = ntohl (msg->sender_element_count);
     }
     else
     {
@@ -737,7 +939,7 @@ handle_p2p_bf (void *cls,
            (op->state->bf_bits_per_element != bf_bits_per_element) ||
            (op->state->bf_data_offset + chunk_size > bf_size) ||
            (op->state->salt != ntohl (msg->sender_mutator)) ||
-           (op->spec->remote_element_count != ntohl (msg->sender_element_count)) )
+           (op->remote_element_count != ntohl (msg->sender_element_count)) )
       {
         GNUNET_break_op (0);
         fail_intersection_operation (op);
@@ -764,153 +966,9 @@ handle_p2p_bf (void *cls,
   default:
     GNUNET_break_op (0);
     fail_intersection_operation (op);
-    break;
-  }
-}
-
-
-/**
- * Fills the "my_elements" hashmap with the initial set of
- * (non-deleted) elements from the set of the specification.
- *
- * @param cls closure with the `struct Operation *`
- * @param key current key code for the element
- * @param value value in the hash map with the `struct ElementEntry *`
- * @return #GNUNET_YES (we should continue to iterate)
- */
-static int
-initialize_map_unfiltered (void *cls,
-                           const struct GNUNET_HashCode *key,
-                           void *value)
-{
-  struct ElementEntry *ee = value;
-  struct Operation *op = cls;
-
-  if (GNUNET_NO == _GSS_is_element_of_operation (ee, op))
-    return GNUNET_YES; /* element not live in operation's generation */
-  GNUNET_CRYPTO_hash_xor (&op->state->my_xor,
-                          &ee->element_hash,
-                          &op->state->my_xor);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Initial full initialization of my_elements, adding %s:%u\n",
-              GNUNET_h2s (&ee->element_hash),
-              ee->element.size);
-  GNUNET_break (GNUNET_YES ==
-                GNUNET_CONTAINER_multihashmap_put (op->state->my_elements,
-                                                   &ee->element_hash,
-                                                   ee,
-                                                   GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-  return GNUNET_YES;
-}
-
-
-/**
- * Send our element count to the peer, in case our element count is
- * lower than his.
- *
- * @param op intersection operation
- */
-static void
-send_element_count (struct Operation *op)
-{
-  struct GNUNET_MQ_Envelope *ev;
-  struct IntersectionElementInfoMessage *msg;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending our element count (%u)\n",
-              op->state->my_element_count);
-  ev = GNUNET_MQ_msg (msg,
-                      GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO);
-  msg->sender_element_count = htonl (op->state->my_element_count);
-  GNUNET_MQ_send (op->mq, ev);
-}
-
-
-/**
- * We go first, initialize our map with all elements and
- * send the first Bloom filter.
- *
- * @param op operation to start exchange for
- */
-static void
-begin_bf_exchange (struct Operation *op)
-{
-  op->state->phase = PHASE_BF_EXCHANGE;
-  op->state->my_elements
-    = GNUNET_CONTAINER_multihashmap_create (op->state->my_element_count,
-                                            GNUNET_YES);
-  GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements,
-                                         &initialize_map_unfiltered,
-                                         op);
-  send_bloomfilter (op);
-}
-
-
-/**
- * Handle the initial `struct IntersectionElementInfoMessage` from a
- * remote peer.
- *
- * @param cls the intersection operation
- * @param mh the header of the message
- */
-static void
-handle_p2p_element_info (void *cls,
-                         const struct GNUNET_MessageHeader *mh)
-{
-  struct Operation *op = cls;
-  const struct IntersectionElementInfoMessage *msg;
-
-  if (ntohs (mh->size) != sizeof (struct IntersectionElementInfoMessage))
-  {
-    GNUNET_break_op (0);
-    fail_intersection_operation(op);
-    return;
-  }
-  msg = (const struct IntersectionElementInfoMessage *) mh;
-  op->spec->remote_element_count = ntohl (msg->sender_element_count);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received remote element count (%u), I have %u\n",
-              op->spec->remote_element_count,
-              op->state->my_element_count);
-  if ( ( (PHASE_INITIAL != op->state->phase) &&
-         (PHASE_COUNT_SENT != op->state->phase) ) ||
-       (op->state->my_element_count > op->spec->remote_element_count) ||
-       (0 == op->state->my_element_count) ||
-       (0 == op->spec->remote_element_count) )
-  {
-    GNUNET_break_op (0);
-    fail_intersection_operation(op);
-    return;
-  }
-  GNUNET_break (NULL == op->state->remote_bf);
-  begin_bf_exchange (op);
-}
-
-
-/**
- * Send a result message to the client indicating that the operation
- * is over.  After the result done message has been sent to the
- * client, destroy the evaluate operation.
- *
- * @param op intersection operation
- */
-static void
-finish_and_destroy (struct Operation *op)
-{
-  GNUNET_assert (GNUNET_NO == op->state->client_done_sent);
-
-  if (GNUNET_SET_RESULT_FULL == op->spec->result_mode)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Sending full result set (%u elements)\n",
-                GNUNET_CONTAINER_multihashmap_size (op->state->my_elements));
-    op->state->full_result_iter
-      = GNUNET_CONTAINER_multihashmap_iterator_create (op->state->my_elements);
-    op->keep++;
-    send_remaining_elements (op);
     return;
   }
-  send_client_done_and_destroy (op);
+  GNUNET_CADET_receive_done (op->channel);
 }
 
 
@@ -955,28 +1013,26 @@ filter_all (void *cls,
  * @param cls the intersection operation
  * @param mh the message
  */
-static void
-handle_p2p_done (void *cls,
-                 const struct GNUNET_MessageHeader *mh)
+void
+handle_intersection_p2p_done (void *cls,
+                              const struct IntersectionDoneMessage *idm)
 {
   struct Operation *op = cls;
-  const struct IntersectionDoneMessage *idm;
 
-  if (PHASE_BF_EXCHANGE != op->state->phase)
+  if (GNUNET_SET_OPERATION_INTERSECTION != op->set->operation)
   {
-    /* wrong phase to conclude? FIXME: Or should we allow this
-       if the other peer has _initially_ already an empty set? */
     GNUNET_break_op (0);
     fail_intersection_operation (op);
     return;
   }
-  if (ntohs (mh->size) != sizeof (struct IntersectionDoneMessage))
+  if (PHASE_BF_EXCHANGE != op->state->phase)
   {
+    /* wrong phase to conclude? FIXME: Or should we allow this
+       if the other peer has _initially_ already an empty set? */
     GNUNET_break_op (0);
     fail_intersection_operation (op);
     return;
   }
-  idm = (const struct IntersectionDoneMessage *) mh;
   if (0 == ntohl (idm->final_element_count))
   {
     /* other peer determined empty set is the intersection,
@@ -998,8 +1054,22 @@ handle_p2p_done (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Got IntersectionDoneMessage, have %u elements in intersection\n",
               op->state->my_element_count);
+  op->state->phase = PHASE_DONE_RECEIVED;
+  GNUNET_CADET_receive_done (op->channel);
+
+  GNUNET_assert (GNUNET_NO == op->state->client_done_sent);
+  if (GNUNET_SET_RESULT_FULL == op->result_mode)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Sending full result set to client (%u elements)\n",
+                GNUNET_CONTAINER_multihashmap_size (op->state->my_elements));
+    op->state->full_result_iter
+      = GNUNET_CONTAINER_multihashmap_iterator_create (op->state->my_elements);
+    send_remaining_elements (op);
+    return;
+  }
   op->state->phase = PHASE_FINISHED;
-  finish_and_destroy (op);
+  send_client_done_and_destroy (op);
 }
 
 
@@ -1010,21 +1080,16 @@ handle_p2p_done (void *cls,
  *        begin the evaluation
  * @param opaque_context message to be transmitted to the listener
  *        to convince him to accept, may be NULL
+ * @return operation-specific state to keep in @a op
  */
-static void
+static struct OperationState *
 intersection_evaluate (struct Operation *op,
                        const struct GNUNET_MessageHeader *opaque_context)
 {
+  struct OperationState *state;
   struct GNUNET_MQ_Envelope *ev;
   struct OperationRequestMessage *msg;
 
-  op->state = GNUNET_new (struct OperationState);
-  /* we started the operation, thus we have to send the operation request */
-  op->state->phase = PHASE_INITIAL;
-  op->state->my_element_count = op->spec->set->state->current_set_element_count;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Initiating intersection operation evaluation\n");
   ev = GNUNET_MQ_msg_nested_mh (msg,
                                 GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
                                 opaque_context);
@@ -1032,20 +1097,30 @@ intersection_evaluate (struct Operation *op,
   {
     /* the context message is too large!? */
     GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (op->spec->set->client);
-    return;
+    return NULL;
   }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Initiating intersection operation evaluation\n");
+  state = GNUNET_new (struct OperationState);
+  /* we started the operation, thus we have to send the operation request */
+  state->phase = PHASE_INITIAL;
+  state->my_element_count = op->set->state->current_set_element_count;
+  state->my_elements
+    = GNUNET_CONTAINER_multihashmap_create (state->my_element_count,
+                                            GNUNET_YES);
+
   msg->operation = htonl (GNUNET_SET_OPERATION_INTERSECTION);
-  msg->element_count = htonl (op->state->my_element_count);
+  msg->element_count = htonl (state->my_element_count);
   GNUNET_MQ_send (op->mq,
                   ev);
-  op->state->phase = PHASE_COUNT_SENT;
+  state->phase = PHASE_COUNT_SENT;
   if (NULL != opaque_context)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Sent op request with context message\n");
   else
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Sent op request without context message\n");
+  return state;
 }
 
 
@@ -1055,90 +1130,33 @@ intersection_evaluate (struct Operation *op,
  *
  * @param op operation that will be accepted as an intersection operation
  */
-static void
+static struct OperationState *
 intersection_accept (struct Operation *op)
 {
+  struct OperationState *state;
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Accepting set intersection operation\n");
-  op->state = GNUNET_new (struct OperationState);
-  op->state->phase = PHASE_INITIAL;
-  op->state->my_element_count
-    = op->spec->set->state->current_set_element_count;
-  op->state->my_elements
-    = GNUNET_CONTAINER_multihashmap_create
-    (GNUNET_MIN (op->state->my_element_count,
-                 op->spec->remote_element_count),
-     GNUNET_YES);
-  if (op->spec->remote_element_count < op->state->my_element_count)
+  state = GNUNET_new (struct OperationState);
+  state->phase = PHASE_INITIAL;
+  state->my_element_count
+    = op->set->state->current_set_element_count;
+  state->my_elements
+    = GNUNET_CONTAINER_multihashmap_create (GNUNET_MIN (state->my_element_count,
+                                                        op->remote_element_count),
+                                            GNUNET_YES);
+  op->state = state;
+  if (op->remote_element_count < state->my_element_count)
   {
     /* If the other peer (Alice) has fewer elements than us (Bob),
        we just send the count as Alice should send the first BF */
     send_element_count (op);
-    op->state->phase = PHASE_COUNT_SENT;
-    return;
+    state->phase = PHASE_COUNT_SENT;
+    return state;
   }
   /* We have fewer elements, so we start with the BF */
   begin_bf_exchange (op);
-}
-
-
-/**
- * Dispatch messages for a intersection operation.
- *
- * @param op the state of the intersection evaluate operation
- * @param mh the received message
- * @return #GNUNET_SYSERR if the tunnel should be disconnected,
- *         #GNUNET_OK otherwise
- */
-static int
-intersection_handle_p2p_message (struct Operation *op,
-                                 const struct GNUNET_MessageHeader *mh)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Received p2p message (t: %u, s: %u)\n",
-              ntohs (mh->type), ntohs (mh->size));
-  switch (ntohs (mh->type))
-  {
-    /* this message handler is not active until after we received an
-     * operation request message, thus the ops request is not handled here
-     */
-  case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_ELEMENT_INFO:
-    handle_p2p_element_info (op, mh);
-    break;
-  case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_BF:
-    handle_p2p_bf (op, mh);
-    break;
-  case GNUNET_MESSAGE_TYPE_SET_INTERSECTION_P2P_DONE:
-    handle_p2p_done (op, mh);
-    break;
-  default:
-    /* something wrong with cadet's message handlers? */
-    GNUNET_assert (0);
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Handler for peer-disconnects, notifies the client about the aborted
- * operation.  If we did not expect anything from the other peer, we
- * gracefully terminate the operation.
- *
- * @param op the destroyed operation
- */
-static void
-intersection_peer_disconnect (struct Operation *op)
-{
-  if (PHASE_FINISHED != op->state->phase)
-  {
-    fail_intersection_operation (op);
-    return;
-  }
-  /* the session has already been concluded */
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Other peer disconnected (finished)\n");
-  if (GNUNET_NO == op->state->client_done_sent)
-    finish_and_destroy (op);
+  return state;
 }
 
 
@@ -1168,6 +1186,11 @@ intersection_op_cancel (struct Operation *op)
     GNUNET_CONTAINER_multihashmap_destroy (op->state->my_elements);
     op->state->my_elements = NULL;
   }
+  if (NULL != op->state->full_result_iter)
+  {
+    GNUNET_CONTAINER_multihashmap_iterator_destroy (op->state->full_result_iter);
+    op->state->full_result_iter = NULL;
+  }
   GNUNET_free (op->state);
   op->state = NULL;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1235,6 +1258,28 @@ intersection_remove (struct SetState *set_state,
 }
 
 
+/**
+ * Callback for channel death for the intersection operation.
+ *
+ * @param op operation that lost the channel
+ */
+static void
+intersection_channel_death (struct Operation *op)
+{
+  if (GNUNET_YES == op->state->channel_death_expected)
+  {
+    /* oh goodie, we are done! */
+    send_client_done_and_destroy (op);
+  }
+  else
+  {
+    /* sorry, channel went down early, too bad. */
+    _GSS_operation_destroy (op,
+                            GNUNET_YES);
+  }
+}
+
+
 /**
  * Get the table with implementing functions for set intersection.
  *
@@ -1245,14 +1290,13 @@ _GSS_intersection_vt ()
 {
   static const struct SetVT intersection_vt = {
     .create = &intersection_set_create,
-    .msg_handler = &intersection_handle_p2p_message,
     .add = &intersection_add,
     .remove = &intersection_remove,
     .destroy_set = &intersection_set_destroy,
     .evaluate = &intersection_evaluate,
     .accept = &intersection_accept,
-    .peer_disconnect = &intersection_peer_disconnect,
     .cancel = &intersection_op_cancel,
+    .channel_death = &intersection_channel_death,
   };
 
   return &intersection_vt;
diff --git a/src/set/gnunet-service-set_intersection.h b/src/set/gnunet-service-set_intersection.h
new file mode 100644 (file)
index 0000000..3bd2551
--- /dev/null
@@ -0,0 +1,79 @@
+
+/*
+      This file is part of GNUnet
+      Copyright (C) 2013-2017 GNUnet e.V.
+
+      GNUnet is free software; you can redistribute it and/or modify
+      it under the terms of the GNU General Public License as published
+      by the Free Software Foundation; either version 3, or (at your
+      option) any later version.
+
+      GNUnet is distributed in the hope that it will be useful, but
+      WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+      General Public License for more details.
+
+      You should have received a copy of the GNU General Public License
+      along with GNUnet; see the file COPYING.  If not, write to the
+      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+      Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file set/gnunet-service-set_intersection.h
+ * @brief two-peer set operations
+ * @author Florian Dold
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_SET_INTERSECTION_H
+#define GNUNET_SERVICE_SET_INTERSECTION_H
+
+#include "gnunet-service-set.h"
+
+
+/**
+ * Check an BF message from a remote peer.
+ *
+ * @param cls the intersection operation
+ * @param msg the header of the message
+ * @return #GNUNET_OK if @a msg is well-formed
+ */
+int
+check_intersection_p2p_bf (void *cls,
+                           const struct BFMessage *msg);
+
+
+/**
+ * Handle an BF message from a remote peer.
+ *
+ * @param cls the intersection operation
+ * @param msg the header of the message
+ */
+void
+handle_intersection_p2p_bf (void *cls,
+                            const struct BFMessage *msg);
+
+
+/**
+ * Handle the initial `struct IntersectionElementInfoMessage` from a
+ * remote peer.
+ *
+ * @param cls the intersection operation
+ * @param mh the header of the message
+ */
+void
+handle_intersection_p2p_element_info (void *cls,
+                                      const struct IntersectionElementInfoMessage *msg);
+
+
+/**
+ * Handle a done message from a remote peer
+ *
+ * @param cls the intersection operation
+ * @param mh the message
+ */
+void
+handle_intersection_p2p_done (void *cls,
+                              const struct IntersectionDoneMessage *idm);
+
+
+#endif
index a19c36206033b01c18ccf86b342a22ee2390d110..fc7e578e68ee3f861cf4dc96154e5a21b2649092 100644 (file)
@@ -1,6 +1,6 @@
 /*
       This file is part of GNUnet
-      Copyright (C) 2013-2016 GNUnet e.V.
+      Copyright (C) 2013-2017 GNUnet e.V.
 
       GNUnet is free software; you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published
 */
 /**
  * @file set/gnunet-service-set_union.c
-
  * @brief two-peer set operations
  * @author Florian Dold
+ * @author Christian Grothoff
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet-service-set.h"
 #include "ibf.h"
+#include "gnunet-service-set_union.h"
 #include "gnunet-service-set_union_strata_estimator.h"
 #include "gnunet-service-set_protocol.h"
 #include <gcrypt.h>
@@ -367,9 +368,10 @@ fail_union_operation (struct Operation *op)
        "union operation failed\n");
   ev = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_RESULT);
   msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
-  msg->request_id = htonl (op->spec->client_request_id);
+  msg->request_id = htonl (op->client_request_id);
   msg->element_type = htons (0);
-  GNUNET_MQ_send (op->spec->set->client_mq, ev);
+  GNUNET_MQ_send (op->set->cs->mq,
+                  ev);
   _GSS_operation_destroy (op, GNUNET_YES);
 }
 
@@ -400,7 +402,14 @@ get_ibf_key (const struct GNUNET_HashCode *src)
  */
 struct GetElementContext
 {
+  /**
+   * FIXME.
+   */
   struct GNUNET_HashCode hash;
+
+  /**
+   * FIXME.
+   */
   struct KeyEntry *k;
 };
 
@@ -503,6 +512,9 @@ op_register_element (struct Operation *op,
 }
 
 
+/**
+ * FIXME.
+ */
 static void
 salt_key (const struct IBF_Key *k_in,
           uint32_t salt,
@@ -516,6 +528,9 @@ salt_key (const struct IBF_Key *k_in,
 }
 
 
+/**
+ * FIXME.
+ */
 static void
 unsalt_key (const struct IBF_Key *k_in,
             uint32_t salt,
@@ -549,7 +564,9 @@ prepare_ibf_iterator (void *cls,
        (void *) op,
        (unsigned long) ke->ibf_key.key_val,
        GNUNET_h2s (&ke->element->element_hash));
-  salt_key (&ke->ibf_key, op->state->salt_send, &salted_key);
+  salt_key (&ke->ibf_key,
+            op->state->salt_send,
+            &salted_key);
   ibf_insert (op->state->local_ibf, salted_key);
   return GNUNET_YES;
 }
@@ -575,12 +592,14 @@ init_key_to_element_iterator (void *cls,
 
   /* make sure that the element belongs to the set at the time
    * of creating the operation */
-  if (GNUNET_NO == _GSS_is_element_of_operation (ee, op))
+  if (GNUNET_NO ==
+      _GSS_is_element_of_operation (ee,
+                                    op))
     return GNUNET_YES;
-
   GNUNET_assert (GNUNET_NO == ee->remote);
-
-  op_register_element (op, ee, GNUNET_NO);
+  op_register_element (op,
+                       ee,
+                       GNUNET_NO);
   return GNUNET_YES;
 }
 
@@ -597,9 +616,11 @@ initialize_key_to_element (struct Operation *op)
   unsigned int len;
 
   GNUNET_assert (NULL == op->state->key_to_element);
-  len = GNUNET_CONTAINER_multihashmap_size (op->spec->set->content->elements);
+  len = GNUNET_CONTAINER_multihashmap_size (op->set->content->elements);
   op->state->key_to_element = GNUNET_CONTAINER_multihashmap32_create (len + 1);
-  GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements, init_key_to_element_iterator, op);
+  GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements,
+                                         &init_key_to_element_iterator,
+                                         op);
 }
 
 
@@ -705,44 +726,6 @@ send_ibf (struct Operation *op,
 }
 
 
-/**
- * Send a strata estimator to the remote peer.
- *
- * @param op the union operation with the remote peer
- */
-static void
-send_strata_estimator (struct Operation *op)
-{
-  const struct StrataEstimator *se = op->state->se;
-  struct GNUNET_MQ_Envelope *ev;
-  struct StrataEstimatorMessage *strata_msg;
-  char *buf;
-  size_t len;
-  uint16_t type;
-
-  buf = GNUNET_malloc (se->strata_count * IBF_BUCKET_SIZE * se->ibf_size);
-  len = strata_estimator_write (op->state->se,
-                                buf);
-  if (len < se->strata_count * IBF_BUCKET_SIZE * se->ibf_size)
-    type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC;
-  else
-    type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE;
-  ev = GNUNET_MQ_msg_extra (strata_msg,
-                            len,
-                            type);
-  GNUNET_memcpy (&strata_msg[1],
-          buf,
-          len);
-  GNUNET_free (buf);
-  strata_msg->set_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap_size (op->spec->set->content->elements));
-  GNUNET_MQ_send (op->mq,
-                  ev);
-  op->state->phase = PHASE_EXPECT_IBF;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "sent SE, expecting IBF\n");
-}
-
-
 /**
  * Compute the necessary order of an ibf
  * from the size of the symmetric set difference.
@@ -761,7 +744,8 @@ get_order_from_difference (unsigned int diff)
     ibf_order++;
   if (ibf_order > MAX_IBF_ORDER)
     ibf_order = MAX_IBF_ORDER;
-  return ibf_order;
+  // add one for correction
+  return ibf_order + 1;
 }
 
 
@@ -775,7 +759,7 @@ get_order_from_difference (unsigned int diff)
  * @return #GNUNET_YES (to continue iterating)
  */
 static int
-send_element_iterator (void *cls,
+send_full_element_iterator (void *cls,
                        const struct GNUNET_HashCode *key,
                        void *value)
 {
@@ -785,26 +769,43 @@ send_element_iterator (void *cls,
   struct GNUNET_SET_Element *el = &ee->element;
   struct GNUNET_MQ_Envelope *ev;
 
-
-  ev = GNUNET_MQ_msg_extra (emsg, el->size, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Sending element %s\n",
+       GNUNET_h2s (key));
+  ev = GNUNET_MQ_msg_extra (emsg,
+                            el->size,
+                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT);
   emsg->element_type = htons (el->element_type);
-  GNUNET_memcpy (&emsg[1], el->data, el->size);
-  GNUNET_MQ_send (op->mq, ev);
+  GNUNET_memcpy (&emsg[1],
+                 el->data,
+                 el->size);
+  GNUNET_MQ_send (op->mq,
+                  ev);
   return GNUNET_YES;
 }
 
 
+/**
+ * Switch to full set transmission for @a op.
+ *
+ * @param op operation to switch to full set transmission.
+ */
 static void
 send_full_set (struct Operation *op)
 {
   struct GNUNET_MQ_Envelope *ev;
 
   op->state->phase = PHASE_FULL_SENDING;
-
-  (void) GNUNET_CONTAINER_multihashmap_iterate (op->spec->set->content->elements,
-                                                &send_element_iterator, op);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Dedicing to transmit the full set\n");
+  /* FIXME: use a more memory-friendly way of doing this with an
+     iterator, just as we do in the non-full case! */
+  (void) GNUNET_CONTAINER_multihashmap_iterate (op->set->content->elements,
+                                                &send_full_element_iterator,
+                                                op);
   ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE);
-  GNUNET_MQ_send (op->mq, ev);
+  GNUNET_MQ_send (op->mq,
+                  ev);
 }
 
 
@@ -812,42 +813,56 @@ send_full_set (struct Operation *op)
  * Handle a strata estimator from a remote peer
  *
  * @param cls the union operation
- * @param mh the message
- * @param is_compressed #GNUNET_YES if the estimator is compressed
- * @return #GNUNET_SYSERR if the tunnel should be disconnected,
- *         #GNUNET_OK otherwise
+ * @param msg the message
  */
-static int
-handle_p2p_strata_estimator (void *cls,
-                             const struct GNUNET_MessageHeader *mh,
-                             int is_compressed)
+int
+check_union_p2p_strata_estimator (void *cls,
+                                  const struct StrataEstimatorMessage *msg)
 {
   struct Operation *op = cls;
-  struct StrataEstimator *remote_se;
-  struct StrataEstimatorMessage *msg = (void *) mh;
-  unsigned int diff;
-  uint64_t other_size;
+  int is_compressed;
   size_t len;
 
-  GNUNET_STATISTICS_update (_GSS_statistics,
-                            "# bytes of SE received",
-                            ntohs (mh->size),
-                            GNUNET_NO);
-
   if (op->state->phase != PHASE_EXPECT_SE)
   {
     GNUNET_break (0);
-    fail_union_operation (op);
     return GNUNET_SYSERR;
   }
-  len = ntohs (mh->size) - sizeof (struct StrataEstimatorMessage);
+  is_compressed = (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC == htons (msg->header.type));
+  len = ntohs (msg->header.size) - sizeof (struct StrataEstimatorMessage);
   if ( (GNUNET_NO == is_compressed) &&
        (len != SE_STRATA_COUNT * SE_IBF_SIZE * IBF_BUCKET_SIZE) )
   {
-    fail_union_operation (op);
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle a strata estimator from a remote peer
+ *
+ * @param cls the union operation
+ * @param msg the message
+ */
+void
+handle_union_p2p_strata_estimator (void *cls,
+                                   const struct StrataEstimatorMessage *msg)
+{
+  struct Operation *op = cls;
+  struct StrataEstimator *remote_se;
+  unsigned int diff;
+  uint64_t other_size;
+  size_t len;
+  int is_compressed;
+
+  is_compressed = (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC == htons (msg->header.type));
+  GNUNET_STATISTICS_update (_GSS_statistics,
+                            "# bytes of SE received",
+                            ntohs (msg->header.size),
+                            GNUNET_NO);
+  len = ntohs (msg->header.size) - sizeof (struct StrataEstimatorMessage);
   other_size = GNUNET_ntohll (msg->set_size);
   remote_se = strata_estimator_create (SE_STRATA_COUNT,
                                        SE_IBF_SIZE,
@@ -856,7 +871,7 @@ handle_p2p_strata_estimator (void *cls,
   {
     /* insufficient resources, fail */
     fail_union_operation (op);
-    return GNUNET_SYSERR;
+    return;
   }
   if (GNUNET_OK !=
       strata_estimator_read (&msg[1],
@@ -865,49 +880,81 @@ handle_p2p_strata_estimator (void *cls,
                              remote_se))
   {
     /* decompression failed */
-    fail_union_operation (op);
     strata_estimator_destroy (remote_se);
-    return GNUNET_SYSERR;
+    fail_union_operation (op);
+    return;
   }
   GNUNET_assert (NULL != op->state->se);
   diff = strata_estimator_difference (remote_se,
                                       op->state->se);
+
+  if (diff > 200)
+    diff = diff * 3 / 2;
+
   strata_estimator_destroy (remote_se);
   strata_estimator_destroy (op->state->se);
   op->state->se = NULL;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "got se diff=%d, using ibf size %d\n",
        diff,
-       1<<get_order_from_difference (diff));
+       1U << get_order_from_difference (diff));
+
+  {
+    char *set_debug;
 
-  if ((GNUNET_YES == op->spec->byzantine) && (other_size < op->spec->byzantine_lower_bound))
+    set_debug = getenv ("GNUNET_SET_BENCHMARK");
+    if ( (NULL != set_debug) &&
+         (0 == strcmp (set_debug, "1")) )
+    {
+      FILE *f = fopen ("set.log", "a");
+      fprintf (f, "%llu\n", (unsigned long long) diff);
+      fclose (f);
+    }
+  }
+
+  if ( (GNUNET_YES == op->byzantine) &&
+       (other_size < op->byzantine_lower_bound) )
   {
     GNUNET_break (0);
     fail_union_operation (op);
-    return GNUNET_SYSERR;
+    return;
   }
 
-
-  if ( (GNUNET_YES == op->spec->force_full) || (diff > op->state->initial_size / 2))
+  if ( (GNUNET_YES == op->force_full) ||
+       (diff > op->state->initial_size / 4) ||
+       (0 == other_size) )
   {
     LOG (GNUNET_ERROR_TYPE_INFO,
-         "Sending full set (diff=%d, own set=%u)\n",
+         "Deciding to go for full set transmission (diff=%d, own set=%u)\n",
          diff,
          op->state->initial_size);
-    if (op->state->initial_size <= other_size)
+    GNUNET_STATISTICS_update (_GSS_statistics,
+                              "# of full sends",
+                              1,
+                              GNUNET_NO);
+    if ( (op->state->initial_size <= other_size) ||
+         (0 == other_size) )
     {
       send_full_set (op);
     }
     else
     {
       struct GNUNET_MQ_Envelope *ev;
+
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           "Telling other peer that we expect its full set\n");
       op->state->phase = PHASE_EXPECT_IBF;
       ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL);
-      GNUNET_MQ_send (op->mq, ev);
+      GNUNET_MQ_send (op->mq,
+                      ev);
     }
   }
   else
   {
+    GNUNET_STATISTICS_update (_GSS_statistics,
+                              "# of ibf sends",
+                              1,
+                              GNUNET_NO);
     if (GNUNET_OK !=
         send_ibf (op,
                   get_order_from_difference (diff)))
@@ -916,11 +963,10 @@ handle_p2p_strata_estimator (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   "Failed to send IBF, closing connection\n");
       fail_union_operation (op);
-      return GNUNET_SYSERR;
+      return;
     }
   }
-
-  return GNUNET_OK;
+  GNUNET_CADET_receive_done (op->channel);
 }
 
 
@@ -1001,14 +1047,16 @@ decode_and_send (struct Operation *op)
   GNUNET_assert (PHASE_INVENTORY_ACTIVE == op->state->phase);
 
   if (GNUNET_OK !=
-      prepare_ibf (op, op->state->remote_ibf->size))
+      prepare_ibf (op,
+                   op->state->remote_ibf->size))
   {
     GNUNET_break (0);
     /* allocation failed */
     return GNUNET_SYSERR;
   }
   diff_ibf = ibf_dup (op->state->local_ibf);
-  ibf_subtract (diff_ibf, op->state->remote_ibf);
+  ibf_subtract (diff_ibf,
+                op->state->remote_ibf);
 
   ibf_destroy (op->state->remote_ibf);
   op->state->remote_ibf = NULL;
@@ -1105,8 +1153,12 @@ decode_and_send (struct Operation *op)
     if (1 == side)
     {
       struct IBF_Key unsalted_key;
-      unsalt_key (&key, op->state->salt_receive, &unsalted_key);
-      send_offers_for_key (op, unsalted_key);
+
+      unsalt_key (&key,
+                  op->state->salt_receive,
+                  &unsalted_key);
+      send_offers_for_key (op,
+                           unsalted_key);
     }
     else if (-1 == side)
     {
@@ -1138,99 +1190,118 @@ decode_and_send (struct Operation *op)
 
 
 /**
- * Handle an IBF message from a remote peer.
+ * Check an IBF message from a remote peer.
  *
  * Reassemble the IBF from multiple pieces, and
  * process the whole IBF once possible.
  *
  * @param cls the union operation
- * @param mh the header of the message
- * @return #GNUNET_SYSERR if the tunnel should be disconnected,
- *         #GNUNET_OK otherwise
+ * @param msg the header of the message
+ * @return #GNUNET_OK if @a msg is well-formed
  */
-static int
-handle_p2p_ibf (void *cls,
-                const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_ibf (void *cls,
+                     const struct IBFMessage *msg)
 {
   struct Operation *op = cls;
-  const struct IBFMessage *msg;
   unsigned int buckets_in_message;
 
-  if (ntohs (mh->size) < sizeof (struct IBFMessage))
+  if (GNUNET_SET_OPERATION_UNION != op->set->operation)
   {
     GNUNET_break_op (0);
-    fail_union_operation (op);
     return GNUNET_SYSERR;
   }
-  msg = (const struct IBFMessage *) mh;
-  if ( (op->state->phase == PHASE_INVENTORY_PASSIVE) ||
-       (op->state->phase == PHASE_EXPECT_IBF) )
+  buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE;
+  if (0 == buckets_in_message)
   {
-    op->state->phase = PHASE_EXPECT_IBF_CONT;
-    GNUNET_assert (NULL == op->state->remote_ibf);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Creating new ibf of size %u\n",
-         1 << msg->order);
-    op->state->remote_ibf = ibf_create (1<<msg->order, SE_IBF_HASH_NUM);
-    op->state->salt_receive = ntohl (msg->salt);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving new IBF with salt %u\n", op->state->salt_receive);
-    if (NULL == op->state->remote_ibf)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Failed to parse remote IBF, closing connection\n");
-      fail_union_operation (op);
-      return GNUNET_SYSERR;
-    }
-    op->state->ibf_buckets_received = 0;
-    if (0 != ntohl (msg->offset))
-    {
-      GNUNET_break_op (0);
-      fail_union_operation (op);
-      return GNUNET_SYSERR;
-    }
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
   }
-  else if (op->state->phase == PHASE_EXPECT_IBF_CONT)
+  if (op->state->phase == PHASE_EXPECT_IBF_CONT)
   {
     if (ntohl (msg->offset) != op->state->ibf_buckets_received)
     {
       GNUNET_break_op (0);
-      fail_union_operation (op);
       return GNUNET_SYSERR;
     }
     if (1<<msg->order != op->state->remote_ibf->size)
     {
       GNUNET_break_op (0);
-      fail_union_operation (op);
       return GNUNET_SYSERR;
     }
     if (ntohl (msg->salt) != op->state->salt_receive)
     {
       GNUNET_break_op (0);
-      fail_union_operation (op);
       return GNUNET_SYSERR;
     }
   }
-  else
+  else if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) &&
+            (op->state->phase != PHASE_EXPECT_IBF) )
   {
-    GNUNET_assert (0);
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
   }
 
-  buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE;
+  return GNUNET_OK;
+}
 
-  if (0 == buckets_in_message)
+
+/**
+ * Handle an IBF message from a remote peer.
+ *
+ * Reassemble the IBF from multiple pieces, and
+ * process the whole IBF once possible.
+ *
+ * @param cls the union operation
+ * @param msg the header of the message
+ */
+void
+handle_union_p2p_ibf (void *cls,
+                      const struct IBFMessage *msg)
+{
+  struct Operation *op = cls;
+  unsigned int buckets_in_message;
+
+  buckets_in_message = (ntohs (msg->header.size) - sizeof *msg) / IBF_BUCKET_SIZE;
+  if ( (op->state->phase == PHASE_INVENTORY_PASSIVE) ||
+       (op->state->phase == PHASE_EXPECT_IBF) )
   {
-    GNUNET_break_op (0);
-    fail_union_operation (op);
-    return GNUNET_SYSERR;
+    op->state->phase = PHASE_EXPECT_IBF_CONT;
+    GNUNET_assert (NULL == op->state->remote_ibf);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Creating new ibf of size %u\n",
+         1 << msg->order);
+    op->state->remote_ibf = ibf_create (1<<msg->order, SE_IBF_HASH_NUM);
+    op->state->salt_receive = ntohl (msg->salt);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Receiving new IBF with salt %u\n",
+         op->state->salt_receive);
+    if (NULL == op->state->remote_ibf)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Failed to parse remote IBF, closing connection\n");
+      fail_union_operation (op);
+      return;
+    }
+    op->state->ibf_buckets_received = 0;
+    if (0 != ntohl (msg->offset))
+    {
+      GNUNET_break_op (0);
+      fail_union_operation (op);
+      return;
+    }
   }
-
-  if ((ntohs (msg->header.size) - sizeof *msg) != buckets_in_message * IBF_BUCKET_SIZE)
+  else
   {
-    GNUNET_break_op (0);
-    fail_union_operation (op);
-    return GNUNET_SYSERR;
+    GNUNET_assert (op->state->phase == PHASE_EXPECT_IBF_CONT);
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "Received more of IBF\n");
   }
-
   GNUNET_assert (NULL != op->state->remote_ibf);
 
   ibf_read_slice (&msg[1],
@@ -1250,10 +1321,11 @@ handle_p2p_ibf (void *cls,
       /* Internal error, best we can do is shut down */
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   "Failed to decode IBF, closing connection\n");
-      return GNUNET_SYSERR;
+      fail_union_operation (op);
+      return;
     }
   }
-  return GNUNET_OK;
+  GNUNET_CADET_receive_done (op->channel);
 }
 
 
@@ -1276,7 +1348,7 @@ send_client_element (struct Operation *op,
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "sending element (size %u) to client\n",
        element->size);
-  GNUNET_assert (0 != op->spec->client_request_id);
+  GNUNET_assert (0 != op->client_request_id);
   ev = GNUNET_MQ_msg_extra (rm, element->size, GNUNET_MESSAGE_TYPE_SET_RESULT);
   if (NULL == ev)
   {
@@ -1285,11 +1357,14 @@ send_client_element (struct Operation *op,
     return;
   }
   rm->result_status = htons (status);
-  rm->request_id = htonl (op->spec->client_request_id);
+  rm->request_id = htonl (op->client_request_id);
   rm->element_type = htons (element->element_type);
   rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element));
-  GNUNET_memcpy (&rm[1], element->data, element->size);
-  GNUNET_MQ_send (op->spec->set->client_mq, ev);
+  GNUNET_memcpy (&rm[1],
+                 element->data,
+                 element->size);
+  GNUNET_MQ_send (op->set->cs->mq,
+                  ev);
 }
 
 
@@ -1306,17 +1381,27 @@ send_done_and_destroy (void *cls)
   struct GNUNET_MQ_Envelope *ev;
   struct GNUNET_SET_ResultMessage *rm;
 
-  ev = GNUNET_MQ_msg (rm, GNUNET_MESSAGE_TYPE_SET_RESULT);
-  rm->request_id = htonl (op->spec->client_request_id);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Signalling client that union operation is done\n");
+  ev = GNUNET_MQ_msg (rm,
+                      GNUNET_MESSAGE_TYPE_SET_RESULT);
+  rm->request_id = htonl (op->client_request_id);
   rm->result_status = htons (GNUNET_SET_STATUS_DONE);
   rm->element_type = htons (0);
   rm->current_size = GNUNET_htonll (GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element));
-  GNUNET_MQ_send (op->spec->set->client_mq, ev);
+  GNUNET_MQ_send (op->set->cs->mq,
+                  ev);
   /* Will also call the union-specific cancel function. */
-  _GSS_operation_destroy (op, GNUNET_YES);
+  _GSS_operation_destroy (op,
+                          GNUNET_YES);
 }
 
 
+/**
+ * Tests if the operation is finished, and if so notify.
+ *
+ * @param op operation to check
+ */
 static void
 maybe_finish (struct Operation *op)
 {
@@ -1335,8 +1420,8 @@ maybe_finish (struct Operation *op)
 
       op->state->phase = PHASE_DONE;
       ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE);
-      GNUNET_MQ_send (op->mq, ev);
-
+      GNUNET_MQ_send (op->mq,
+                      ev);
       /* We now wait until the other peer closes the channel
        * after it got all elements from us. */
     }
@@ -1356,46 +1441,59 @@ maybe_finish (struct Operation *op)
 
 
 /**
- * Handle an element message from a remote peer.
- * Sent by the other peer either because we decoded an IBF and placed a demand,
- * or because the other peer switched to full set transmission.
+ * Check an element message from a remote peer.
  *
  * @param cls the union operation
- * @param mh the message
+ * @param emsg the message
  */
-static void
-handle_p2p_elements (void *cls,
-                     const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_elements (void *cls,
+                          const struct GNUNET_SET_ElementMessage *emsg)
 {
   struct Operation *op = cls;
-  struct ElementEntry *ee;
-  const struct GNUNET_SET_ElementMessage *emsg;
-  uint16_t element_size;
 
-  if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes))
+  if (GNUNET_SET_OPERATION_UNION != op->set->operation)
   {
     GNUNET_break_op (0);
-    fail_union_operation (op);
-    return;
+    return GNUNET_SYSERR;
   }
-  if (ntohs (mh->size) < sizeof (struct GNUNET_SET_ElementMessage))
+  if (0 == GNUNET_CONTAINER_multihashmap_size (op->state->demanded_hashes))
   {
     GNUNET_break_op (0);
-    fail_union_operation (op);
-    return;
+    return GNUNET_SYSERR;
   }
+  return GNUNET_OK;
+}
 
-  emsg = (const struct GNUNET_SET_ElementMessage *) mh;
 
-  element_size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ElementMessage);
+/**
+ * Handle an element message from a remote peer.
+ * Sent by the other peer either because we decoded an IBF and placed a demand,
+ * or because the other peer switched to full set transmission.
+ *
+ * @param cls the union operation
+ * @param emsg the message
+ */
+void
+handle_union_p2p_elements (void *cls,
+                           const struct GNUNET_SET_ElementMessage *emsg)
+{
+  struct Operation *op = cls;
+  struct ElementEntry *ee;
+  struct KeyEntry *ke;
+  uint16_t element_size;
+
+  element_size = ntohs (emsg->header.size) - sizeof (struct GNUNET_SET_ElementMessage);
   ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size);
-  GNUNET_memcpy (&ee[1], &emsg[1], element_size);
+  GNUNET_memcpy (&ee[1],
+                 &emsg[1],
+                 element_size);
   ee->element.size = element_size;
   ee->element.data = &ee[1];
   ee->element.element_type = ntohs (emsg->element_type);
   ee->remote = GNUNET_YES;
-  GNUNET_SET_element_hash (&ee->element, &ee->element_hash);
-
+  GNUNET_SET_element_hash (&ee->element,
+                           &ee->element_hash);
   if (GNUNET_NO ==
       GNUNET_CONTAINER_multihashmap_remove (op->state->demanded_hashes,
                                             &ee->element_hash,
@@ -1403,7 +1501,6 @@ handle_p2p_elements (void *cls,
   {
     /* We got something we didn't demand, since it's not in our map. */
     GNUNET_break_op (0);
-    GNUNET_free (ee);
     fail_union_operation (op);
     return;
   }
@@ -1422,10 +1519,9 @@ handle_p2p_elements (void *cls,
                             1,
                             GNUNET_NO);
 
-  op->state->received_total += 1;
-
-  struct KeyEntry *ke = op_get_element (op, &ee->element_hash);
+  op->state->received_total++;
 
+  ke = op_get_element (op, &ee->element_hash);
   if (NULL != ke)
   {
     /* Got repeated element.  Should not happen since
@@ -1441,10 +1537,10 @@ handle_p2p_elements (void *cls,
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Registering new element from remote peer\n");
-    op->state->received_fresh += 1;
+    op->state->received_fresh++;
     op_register_element (op, ee, GNUNET_YES);
     /* only send results immediately if the client wants it */
-    switch (op->spec->result_mode)
+    switch (op->result_mode)
     {
       case GNUNET_SET_RESULT_ADDED:
         send_client_element (op, &ee->element, GNUNET_SET_STATUS_OK);
@@ -1459,43 +1555,57 @@ handle_p2p_elements (void *cls,
     }
   }
 
-  if (op->state->received_total > 8 && op->state->received_fresh < op->state->received_total / 3)
+  if ( (op->state->received_total > 8) &&
+       (op->state->received_fresh < op->state->received_total / 3) )
   {
     /* The other peer gave us lots of old elements, there's something wrong. */
     GNUNET_break_op (0);
     fail_union_operation (op);
     return;
   }
-
+  GNUNET_CADET_receive_done (op->channel);
   maybe_finish (op);
 }
 
 
 /**
- * Handle an element message from a remote peer.
+ * Check a full element message from a remote peer.
  *
  * @param cls the union operation
- * @param mh the message
+ * @param emsg the message
  */
-static void
-handle_p2p_full_element (void *cls,
-                         const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_full_element (void *cls,
+                              const struct GNUNET_SET_ElementMessage *emsg)
 {
   struct Operation *op = cls;
-  struct ElementEntry *ee;
-  const struct GNUNET_SET_ElementMessage *emsg;
-  uint16_t element_size;
 
-  if (ntohs (mh->size) < sizeof (struct GNUNET_SET_ElementMessage))
+  if (GNUNET_SET_OPERATION_UNION != op->set->operation)
   {
     GNUNET_break_op (0);
-    fail_union_operation (op);
-    return;
+    return GNUNET_SYSERR;
   }
+  // FIXME: check that we expect full elements here?
+  return GNUNET_OK;
+}
 
-  emsg = (const struct GNUNET_SET_ElementMessage *) mh;
 
-  element_size = ntohs (mh->size) - sizeof (struct GNUNET_SET_ElementMessage);
+/**
+ * Handle an element message from a remote peer.
+ *
+ * @param cls the union operation
+ * @param emsg the message
+ */
+void
+handle_union_p2p_full_element (void *cls,
+                               const struct GNUNET_SET_ElementMessage *emsg)
+{
+  struct Operation *op = cls;
+  struct ElementEntry *ee;
+  struct KeyEntry *ke;
+  uint16_t element_size;
+
+  element_size = ntohs (emsg->header.size) - sizeof (struct GNUNET_SET_ElementMessage);
   ee = GNUNET_malloc (sizeof (struct ElementEntry) + element_size);
   GNUNET_memcpy (&ee[1], &emsg[1], element_size);
   ee->element.size = element_size;
@@ -1518,10 +1628,9 @@ handle_p2p_full_element (void *cls,
                             1,
                             GNUNET_NO);
 
-  op->state->received_total += 1;
-
-  struct KeyEntry *ke = op_get_element (op, &ee->element_hash);
+  op->state->received_total++;
 
+  ke = op_get_element (op, &ee->element_hash);
   if (NULL != ke)
   {
     /* Got repeated element.  Should not happen since
@@ -1537,10 +1646,10 @@ handle_p2p_full_element (void *cls,
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Registering new element from remote peer\n");
-    op->state->received_fresh += 1;
+    op->state->received_fresh++;
     op_register_element (op, ee, GNUNET_YES);
     /* only send results immediately if the client wants it */
-    switch (op->spec->result_mode)
+    switch (op->result_mode)
     {
       case GNUNET_SET_RESULT_ADDED:
         send_client_element (op, &ee->element, GNUNET_SET_STATUS_OK);
@@ -1555,9 +1664,9 @@ handle_p2p_full_element (void *cls,
     }
   }
 
-  if ( (GNUNET_YES == op->spec->byzantine) && 
-       (op->state->received_total > 150) && 
-       (op->state->received_fresh < op->state->received_total / 3) )
+  if ( (GNUNET_YES == op->byzantine) &&
+       (op->state->received_total > 384 + op->state->received_fresh * 4) &&
+       (op->state->received_fresh < op->state->received_total / 6) )
   {
     /* The other peer gave us lots of old elements, there's something wrong. */
     LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -1568,51 +1677,78 @@ handle_p2p_full_element (void *cls,
     fail_union_operation (op);
     return;
   }
+  GNUNET_CADET_receive_done (op->channel);
 }
 
+
 /**
  * Send offers (for GNUNET_Hash-es) in response
  * to inquiries (for IBF_Key-s).
  *
  * @param cls the union operation
- * @param mh the message
+ * @param msg the message
  */
-static void
-handle_p2p_inquiry (void *cls,
-                    const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_inquiry (void *cls,
+                         const struct InquiryMessage *msg)
 {
   struct Operation *op = cls;
-  const struct IBF_Key *ibf_key;
   unsigned int num_keys;
-  struct InquiryMessage *msg;
 
-  /* look up elements and send them */
+  if (GNUNET_SET_OPERATION_UNION != op->set->operation)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
   if (op->state->phase != PHASE_INVENTORY_PASSIVE)
   {
     GNUNET_break_op (0);
-    fail_union_operation (op);
-    return;
+    return GNUNET_SYSERR;
   }
-  num_keys = (ntohs (mh->size) - sizeof (struct InquiryMessage))
-      / sizeof (struct IBF_Key);
-  if ((ntohs (mh->size) - sizeof (struct InquiryMessage))
+  num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage))
+    / sizeof (struct IBF_Key);
+  if ((ntohs (msg->header.size) - sizeof (struct InquiryMessage))
       != num_keys * sizeof (struct IBF_Key))
   {
     GNUNET_break_op (0);
-    fail_union_operation (op);
-    return;
+    return GNUNET_SYSERR;
   }
+  return GNUNET_OK;
+}
 
-  msg = (struct InquiryMessage *) mh;
 
+/**
+ * Send offers (for GNUNET_Hash-es) in response
+ * to inquiries (for IBF_Key-s).
+ *
+ * @param cls the union operation
+ * @param msg the message
+ */
+void
+handle_union_p2p_inquiry (void *cls,
+                          const struct InquiryMessage *msg)
+{
+  struct Operation *op = cls;
+  const struct IBF_Key *ibf_key;
+  unsigned int num_keys;
+
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Received union inquiry\n");
+  num_keys = (ntohs (msg->header.size) - sizeof (struct InquiryMessage))
+    / sizeof (struct IBF_Key);
   ibf_key = (const struct IBF_Key *) &msg[1];
   while (0 != num_keys--)
   {
     struct IBF_Key unsalted_key;
-    unsalt_key (ibf_key, ntohl (msg->salt), &unsalted_key);
-    send_offers_for_key (op, unsalted_key);
+
+    unsalt_key (ibf_key,
+                ntohl (msg->salt),
+                &unsalted_key);
+    send_offers_for_key (op,
+                         unsalted_key);
     ibf_key++;
   }
+  GNUNET_CADET_receive_done (op->channel);
 }
 
 
@@ -1627,9 +1763,9 @@ handle_p2p_inquiry (void *cls,
  *         #GNUNET_NO if not.
  */
 static int
-send_missing_elements_iter (void *cls,
-                            uint32_t key,
-                            void *value)
+send_missing_full_elements_iter (void *cls,
+                                 uint32_t key,
+                                 void *value)
 {
   struct Operation *op = cls;
   struct KeyEntry *ke = value;
@@ -1639,39 +1775,50 @@ send_missing_elements_iter (void *cls,
 
   if (GNUNET_YES == ke->received)
     return GNUNET_YES;
-
-  ev = GNUNET_MQ_msg_extra (emsg, ee->element.size, GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT);
-  GNUNET_memcpy (&emsg[1], ee->element.data, ee->element.size);
-  emsg->reserved = htons (0);
+  ev = GNUNET_MQ_msg_extra (emsg,
+                            ee->element.size,
+                            GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT);
+  GNUNET_memcpy (&emsg[1],
+                 ee->element.data,
+                 ee->element.size);
   emsg->element_type = htons (ee->element.element_type);
-  GNUNET_MQ_send (op->mq, ev);
-
+  GNUNET_MQ_send (op->mq,
+                  ev);
   return GNUNET_YES;
 }
 
 
 /**
- * Handle a 
+ * Handle a request for full set transmission.
  *
  * @parem cls closure, a set union operation
  * @param mh the demand message
  */
-static void
-handle_p2p_request_full (void *cls,
-                         const struct GNUNET_MessageHeader *mh)
+void
+handle_union_p2p_request_full (void *cls,
+                               const struct GNUNET_MessageHeader *mh)
 {
   struct Operation *op = cls;
 
-  if (PHASE_EXPECT_IBF != op->state->phase)
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Received request for full set transmission\n");
+  if (GNUNET_SET_OPERATION_UNION != op->set->operation)
   {
+    GNUNET_break_op (0);
     fail_union_operation (op);
+    return;
+  }
+  if (PHASE_EXPECT_IBF != op->state->phase)
+  {
     GNUNET_break_op (0);
+    fail_union_operation (op);
     return;
   }
 
   // FIXME: we need to check that our set is larger than the
   // byzantine_lower_bound by some threshold
   send_full_set (op);
+  GNUNET_CADET_receive_done (op->channel);
 }
 
 
@@ -1681,56 +1828,101 @@ handle_p2p_request_full (void *cls,
  * @parem cls closure, a set union operation
  * @param mh the demand message
  */
-static void
-handle_p2p_full_done (void *cls,
-                      const struct GNUNET_MessageHeader *mh)
+void
+handle_union_p2p_full_done (void *cls,
+                            const struct GNUNET_MessageHeader *mh)
 {
   struct Operation *op = cls;
 
-  if (PHASE_EXPECT_IBF == op->state->phase)
+  switch (op->state->phase)
   {
-    struct GNUNET_MQ_Envelope *ev;
+  case PHASE_EXPECT_IBF:
+    {
+      struct GNUNET_MQ_Envelope *ev;
 
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "got FULL DONE, sending elements that other peer is missing\n");
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "got FULL DONE, sending elements that other peer is missing\n");
+
+      /* send all the elements that did not come from the remote peer */
+      GNUNET_CONTAINER_multihashmap32_iterate (op->state->key_to_element,
+                                               &send_missing_full_elements_iter,
+                                               op);
+
+      ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE);
+      GNUNET_MQ_notify_sent (ev,
+                             &send_done_and_destroy,
+                             op);
+      GNUNET_MQ_send (op->mq,
+                      ev);
+      op->state->phase = PHASE_DONE;
+      /* we now wait until the other peer shuts the tunnel down*/
+    }
+    break;
+  case PHASE_FULL_SENDING:
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "got FULL DONE, finishing\n");
+      /* We sent the full set, and got the response for that.  We're done. */
+      op->state->phase = PHASE_DONE;
+      GNUNET_CADET_receive_done (op->channel);
+      send_done_and_destroy (op);
+      return;
+    }
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                "Handle full done phase is %u\n",
+                (unsigned) op->state->phase);
+    GNUNET_break_op (0);
+    fail_union_operation (op);
+    return;
+  }
+  GNUNET_CADET_receive_done (op->channel);
+}
 
-    /* send all the elements that did not come from the remote peer */
-    GNUNET_CONTAINER_multihashmap32_iterate (op->state->key_to_element,
-                                             &send_missing_elements_iter,
-                                             op);
 
-    ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE);
-    GNUNET_MQ_send (op->mq, ev);
-    op->state->phase = PHASE_DONE;
+/**
+ * Check a demand by the other peer for elements based on a list
+ * of `struct GNUNET_HashCode`s.
+ *
+ * @parem cls closure, a set union operation
+ * @param mh the demand message
+ * @return #GNUNET_OK if @a mh is well-formed
+ */
+int
+check_union_p2p_demand (void *cls,
+                        const struct GNUNET_MessageHeader *mh)
+{
+  struct Operation *op = cls;
+  unsigned int num_hashes;
 
-    /* we now wait until the other peer shuts the tunnel down*/
-  }
-  else if (PHASE_FULL_SENDING == op->state->phase)
+  if (GNUNET_SET_OPERATION_UNION != op->set->operation)
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "got FULL DONE, finishing\n");
-    /* We sent the full set, and got the response for that.  We're done. */
-    op->state->phase = PHASE_DONE;
-    send_done_and_destroy (op);
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
   }
-  else
+  num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
+    / sizeof (struct GNUNET_HashCode);
+  if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
+      != num_hashes * sizeof (struct GNUNET_HashCode))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "handle full done phase is %u\n", (unsigned) op->state->phase);
     GNUNET_break_op (0);
-    fail_union_operation (op);
-    return;
+    return GNUNET_SYSERR;
   }
+  return GNUNET_OK;
 }
 
 
 /**
  * Handle a demand by the other peer for elements based on a list
- * of GNUNET_HashCode-s.
+ * of `struct GNUNET_HashCode`s.
  *
  * @parem cls closure, a set union operation
  * @param mh the demand message
  */
-static void
-handle_p2p_demand (void *cls,
-                   const struct GNUNET_MessageHeader *mh)
+void
+handle_union_p2p_demand (void *cls,
+                         const struct GNUNET_MessageHeader *mh)
 {
   struct Operation *op = cls;
   struct ElementEntry *ee;
@@ -1741,19 +1933,12 @@ handle_p2p_demand (void *cls,
 
   num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
     / sizeof (struct GNUNET_HashCode);
-  if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
-      != num_hashes * sizeof (struct GNUNET_HashCode))
-  {
-    GNUNET_break_op (0);
-    fail_union_operation (op);
-    return;
-  }
-
   for (hash = (const struct GNUNET_HashCode *) &mh[1];
        num_hashes > 0;
        hash++, num_hashes--)
   {
-    ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements, hash);
+    ee = GNUNET_CONTAINER_multihashmap_get (op->set->content->elements,
+                                            hash);
     if (NULL == ee)
     {
       /* Demand for non-existing element. */
@@ -1783,7 +1968,7 @@ handle_p2p_demand (void *cls,
                               1,
                               GNUNET_NO);
 
-    switch (op->spec->result_mode)
+    switch (op->result_mode)
     {
       case GNUNET_SET_RESULT_ADDED:
         /* Nothing to do. */
@@ -1797,42 +1982,65 @@ handle_p2p_demand (void *cls,
         break;
     }
   }
+  GNUNET_CADET_receive_done (op->channel);
 }
 
 
 /**
- * Handle offers (of GNUNET_HashCode-s) and
- * respond with demands (of GNUNET_HashCode-s).
+ * Check offer (of `struct GNUNET_HashCode`s).
  *
  * @param cls the union operation
  * @param mh the message
+ * @return #GNUNET_OK if @a mh is well-formed
  */
-static void
-handle_p2p_offer (void *cls,
-                    const struct GNUNET_MessageHeader *mh)
+int
+check_union_p2p_offer (void *cls,
+                        const struct GNUNET_MessageHeader *mh)
 {
   struct Operation *op = cls;
-  const struct GNUNET_HashCode *hash;
   unsigned int num_hashes;
 
+  if (GNUNET_SET_OPERATION_UNION != op->set->operation)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
   /* look up elements and send them */
   if ( (op->state->phase != PHASE_INVENTORY_PASSIVE) &&
        (op->state->phase != PHASE_INVENTORY_ACTIVE))
   {
     GNUNET_break_op (0);
-    fail_union_operation (op);
-    return;
+    return GNUNET_SYSERR;
   }
   num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
     / sizeof (struct GNUNET_HashCode);
-  if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
-      != num_hashes * sizeof (struct GNUNET_HashCode))
+  if ((ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader)) !=
+      num_hashes * sizeof (struct GNUNET_HashCode))
   {
     GNUNET_break_op (0);
-    fail_union_operation (op);
-    return;
+    return GNUNET_SYSERR;
   }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Handle offers (of `struct GNUNET_HashCode`s) and
+ * respond with demands (of `struct GNUNET_HashCode`s).
+ *
+ * @param cls the union operation
+ * @param mh the message
+ */
+void
+handle_union_p2p_offer (void *cls,
+                        const struct GNUNET_MessageHeader *mh)
+{
+  struct Operation *op = cls;
+  const struct GNUNET_HashCode *hash;
+  unsigned int num_hashes;
 
+  num_hashes = (ntohs (mh->size) - sizeof (struct GNUNET_MessageHeader))
+    / sizeof (struct GNUNET_HashCode);
   for (hash = (const struct GNUNET_HashCode *) &mh[1];
        num_hashes > 0;
        hash++, num_hashes--)
@@ -1841,7 +2049,7 @@ handle_p2p_offer (void *cls,
     struct GNUNET_MessageHeader *demands;
     struct GNUNET_MQ_Envelope *ev;
 
-    ee = GNUNET_CONTAINER_multihashmap_get (op->spec->set->content->elements,
+    ee = GNUNET_CONTAINER_multihashmap_get (op->set->content->elements,
                                             hash);
     if (NULL != ee)
       if (GNUNET_YES == _GSS_is_element_of_operation (ee, op))
@@ -1868,9 +2076,12 @@ handle_p2p_offer (void *cls,
     ev = GNUNET_MQ_msg_header_extra (demands,
                                      sizeof (struct GNUNET_HashCode),
                                      GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND);
-    *(struct GNUNET_HashCode *) &demands[1] = *hash;
+    GNUNET_memcpy (&demands[1],
+                   hash,
+                   sizeof (struct GNUNET_HashCode));
     GNUNET_MQ_send (op->mq, ev);
   }
+  GNUNET_CADET_receive_done (op->channel);
 }
 
 
@@ -1880,16 +2091,22 @@ handle_p2p_offer (void *cls,
  * @param cls the union operation
  * @param mh the message
  */
-static void
-handle_p2p_done (void *cls,
-                 const struct GNUNET_MessageHeader *mh)
+void
+handle_union_p2p_done (void *cls,
+                       const struct GNUNET_MessageHeader *mh)
 {
   struct Operation *op = cls;
 
-  if (op->state->phase == PHASE_INVENTORY_PASSIVE)
+  if (GNUNET_SET_OPERATION_UNION != op->set->operation)
+  {
+    GNUNET_break_op (0);
+    fail_union_operation (op);
+    return;
+  }
+  switch (op->state->phase)
   {
+  case PHASE_INVENTORY_PASSIVE:
     /* We got all requests, but still have to send our elements in response. */
-
     op->state->phase = PHASE_FINISH_WAITING;
 
     LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -1903,11 +2120,10 @@ handle_p2p_done (void *cls,
      * all our demands are satisfied, so that the active
      * peer can quit if we gave him everything.
      */
+    GNUNET_CADET_receive_done (op->channel);
     maybe_finish (op);
     return;
-  }
-  if (op->state->phase == PHASE_INVENTORY_ACTIVE)
-  {
+  case PHASE_INVENTORY_ACTIVE:
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "got DONE (as active partner), waiting to finish\n");
     /* All demands of the other peer are satisfied,
@@ -1918,11 +2134,14 @@ handle_p2p_done (void *cls,
      * to the other peer once our demands are met.
      */
     op->state->phase = PHASE_FINISH_CLOSING;
+    GNUNET_CADET_receive_done (op->channel);
     maybe_finish (op);
     return;
+  default:
+    GNUNET_break_op (0);
+    fail_union_operation (op);
+    return;
   }
-  GNUNET_break_op (0);
-  fail_union_operation (op);
 }
 
 
@@ -1933,21 +2152,31 @@ handle_p2p_done (void *cls,
  * @param opaque_context message to be transmitted to the listener
  *        to convince him to accept, may be NULL
  */
-static void
+static struct OperationState *
 union_evaluate (struct Operation *op,
                 const struct GNUNET_MessageHeader *opaque_context)
 {
+  struct OperationState *state;
   struct GNUNET_MQ_Envelope *ev;
   struct OperationRequestMessage *msg;
 
-  GNUNET_assert (NULL == op->state);
-  op->state = GNUNET_new (struct OperationState);
-  op->state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
+  ev = GNUNET_MQ_msg_nested_mh (msg,
+                                GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
+                                opaque_context);
+  if (NULL == ev)
+  {
+    /* the context message is too large */
+    GNUNET_break (0);
+    return NULL;
+  }
+  state = GNUNET_new (struct OperationState);
+  state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32,
+                                                                 GNUNET_NO);
   /* copy the current generation's strata estimator for this operation */
-  op->state->se = strata_estimator_dup (op->spec->set->state->se);
+  state->se = strata_estimator_dup (op->set->state->se);
   /* we started the operation, thus we have to send the operation request */
-  op->state->phase = PHASE_EXPECT_SE;
-  op->state->salt_receive = op->state->salt_send = 42;
+  state->phase = PHASE_EXPECT_SE;
+  state->salt_receive = state->salt_send = 42; // FIXME?????
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Initiating union operation evaluation\n");
   GNUNET_STATISTICS_update (_GSS_statistics,
@@ -1958,16 +2187,6 @@ union_evaluate (struct Operation *op,
                             "# of initiated union operations",
                             1,
                             GNUNET_NO);
-  ev = GNUNET_MQ_msg_nested_mh (msg,
-                                GNUNET_MESSAGE_TYPE_SET_P2P_OPERATION_REQUEST,
-                                opaque_context);
-  if (NULL == ev)
-  {
-    /* the context message is too large */
-    GNUNET_break (0);
-    GNUNET_SERVICE_client_drop (op->spec->set->client);
-    return;
-  }
   msg->operation = htonl (GNUNET_SET_OPERATION_UNION);
   GNUNET_MQ_send (op->mq,
                   ev);
@@ -1979,8 +2198,10 @@ union_evaluate (struct Operation *op,
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "sent op request without context message\n");
 
+  op->state = state;
   initialize_key_to_element (op);
-  op->state->initial_size = GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element);
+  state->initial_size = GNUNET_CONTAINER_multihashmap32_size (state->key_to_element);
+  return state;
 }
 
 
@@ -1990,13 +2211,19 @@ union_evaluate (struct Operation *op,
  *
  * @param op operation that will be accepted as a union operation
  */
-static void
+static struct OperationState *
 union_accept (struct Operation *op)
 {
+  struct OperationState *state;
+  const struct StrataEstimator *se;
+  struct GNUNET_MQ_Envelope *ev;
+  struct StrataEstimatorMessage *strata_msg;
+  char *buf;
+  size_t len;
+  uint16_t type;
+
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "accepting set union operation\n");
-  GNUNET_assert (NULL == op->state);
-
   GNUNET_STATISTICS_update (_GSS_statistics,
                             "# of accepted union operations",
                             1,
@@ -2006,14 +2233,37 @@ union_accept (struct Operation *op)
                             1,
                             GNUNET_NO);
 
-  op->state = GNUNET_new (struct OperationState);
-  op->state->se = strata_estimator_dup (op->spec->set->state->se);
-  op->state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
-  op->state->salt_receive = op->state->salt_send = 42;
+  state = GNUNET_new (struct OperationState);
+  state->se = strata_estimator_dup (op->set->state->se);
+  state->demanded_hashes = GNUNET_CONTAINER_multihashmap_create (32,
+                                                                 GNUNET_NO);
+  state->salt_receive = state->salt_send = 42; // FIXME?????
+  op->state = state;
   initialize_key_to_element (op);
-  op->state->initial_size = GNUNET_CONTAINER_multihashmap32_size (op->state->key_to_element);
+  state->initial_size = GNUNET_CONTAINER_multihashmap32_size (state->key_to_element);
+
   /* kick off the operation */
-  send_strata_estimator (op);
+  se = state->se;
+  buf = GNUNET_malloc (se->strata_count * IBF_BUCKET_SIZE * se->ibf_size);
+  len = strata_estimator_write (se,
+                                buf);
+  if (len < se->strata_count * IBF_BUCKET_SIZE * se->ibf_size)
+    type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC;
+  else
+    type = GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE;
+  ev = GNUNET_MQ_msg_extra (strata_msg,
+                            len,
+                            type);
+  GNUNET_memcpy (&strata_msg[1],
+                 buf,
+                 len);
+  GNUNET_free (buf);
+  strata_msg->set_size
+    = GNUNET_htonll (GNUNET_CONTAINER_multihashmap_size (op->set->content->elements));
+  GNUNET_MQ_send (op->mq,
+                  ev);
+  state->phase = PHASE_EXPECT_IBF;
+  return state;
 }
 
 
@@ -2053,7 +2303,8 @@ union_set_create (void)
  * @param ee the element to add to the set
  */
 static void
-union_add (struct SetState *set_state, struct ElementEntry *ee)
+union_add (struct SetState *set_state,
+           struct ElementEntry *ee)
 {
   strata_estimator_insert (set_state->se,
                            get_ibf_key (&ee->element_hash));
@@ -2068,7 +2319,8 @@ union_add (struct SetState *set_state, struct ElementEntry *ee)
  * @param ee set element to remove
  */
 static void
-union_remove (struct SetState *set_state, struct ElementEntry *ee)
+union_remove (struct SetState *set_state,
+              struct ElementEntry *ee)
 {
   strata_estimator_remove (set_state->se,
                            get_ibf_key (&ee->element_hash));
@@ -2093,113 +2345,35 @@ union_set_destroy (struct SetState *set_state)
 
 
 /**
- * Dispatch messages for a union operation.
+ * Copy union-specific set state.
  *
- * @param op the state of the union evaluate operation
- * @param mh the received message
- * @return #GNUNET_SYSERR if the tunnel should be disconnected,
- *         #GNUNET_OK otherwise
+ * @param state source state for copying the union state
+ * @return a copy of the union-specific set state
  */
-int
-union_handle_p2p_message (struct Operation *op,
-                          const struct GNUNET_MessageHeader *mh)
+static struct SetState *
+union_copy_state (struct SetState *state)
 {
-  //LOG (GNUNET_ERROR_TYPE_DEBUG,
-  //            "received p2p message (t: %u, s: %u)\n",
-  //            ntohs (mh->type),
-  //            ntohs (mh->size));
-  switch (ntohs (mh->type))
-  {
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_IBF:
-      return handle_p2p_ibf (op, mh);
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SE:
-      return handle_p2p_strata_estimator (op, mh, GNUNET_NO);
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_SEC:
-      return handle_p2p_strata_estimator (op, mh, GNUNET_YES);
-    case GNUNET_MESSAGE_TYPE_SET_P2P_ELEMENTS:
-      handle_p2p_elements (op, mh);
-      break;
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_ELEMENT:
-      handle_p2p_full_element (op, mh);
-      break;
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_INQUIRY:
-      handle_p2p_inquiry (op, mh);
-      break;
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DONE:
-      handle_p2p_done (op, mh);
-      break;
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_OFFER:
-      handle_p2p_offer (op, mh);
-      break;
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_DEMAND:
-      handle_p2p_demand (op, mh);
-      break;
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_FULL_DONE:
-      handle_p2p_full_done (op, mh);
-      break;
-    case GNUNET_MESSAGE_TYPE_SET_UNION_P2P_REQUEST_FULL:
-      handle_p2p_request_full (op, mh);
-      break;
-    default:
-      /* Something wrong with cadet's message handlers? */
-      GNUNET_assert (0);
-  }
-  return GNUNET_OK;
-}
+  struct SetState *new_state;
 
+  GNUNET_assert ( (NULL != state) &&
+                  (NULL != state->se) );
+  new_state = GNUNET_new (struct SetState);
+  new_state->se = strata_estimator_dup (state->se);
 
-/**
- * Handler for peer-disconnects, notifies the client
- * about the aborted operation in case the op was not concluded.
- *
- * @param op the destroyed operation
- */
-static void
-union_peer_disconnect (struct Operation *op)
-{
-  if (PHASE_DONE != op->state->phase)
-  {
-    struct GNUNET_MQ_Envelope *ev;
-    struct GNUNET_SET_ResultMessage *msg;
-
-    ev = GNUNET_MQ_msg (msg,
-                        GNUNET_MESSAGE_TYPE_SET_RESULT);
-    msg->request_id = htonl (op->spec->client_request_id);
-    msg->result_status = htons (GNUNET_SET_STATUS_FAILURE);
-    msg->element_type = htons (0);
-    GNUNET_MQ_send (op->spec->set->client_mq,
-                    ev);
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "other peer disconnected prematurely, phase %u\n",
-         op->state->phase);
-    _GSS_operation_destroy (op,
-                            GNUNET_YES);
-    return;
-  }
-  // else: the session has already been concluded
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "other peer disconnected (finished)\n");
-  if (GNUNET_NO == op->state->client_done_sent)
-    send_done_and_destroy (op);
+  return new_state;
 }
 
 
 /**
- * Copy union-specific set state.
+ * Handle case where channel went down for an operation.
  *
- * @param set source set for copying the union state
- * @return a copy of the union-specific set state
+ * @param op operation that lost the channel
  */
-static struct SetState *
-union_copy_state (struct Set *set)
+static void
+union_channel_death (struct Operation *op)
 {
-  struct SetState *new_state;
-
-  new_state = GNUNET_new (struct SetState);
-  GNUNET_assert ( (NULL != set->state) && (NULL != set->state->se) );
-  new_state->se = strata_estimator_dup (set->state->se);
-
-  return new_state;
+  _GSS_operation_destroy (op,
+                          GNUNET_YES);
 }
 
 
@@ -2214,15 +2388,14 @@ _GSS_union_vt ()
 {
   static const struct SetVT union_vt = {
     .create = &union_set_create,
-    .msg_handler = &union_handle_p2p_message,
     .add = &union_add,
     .remove = &union_remove,
     .destroy_set = &union_set_destroy,
     .evaluate = &union_evaluate,
     .accept = &union_accept,
-    .peer_disconnect = &union_peer_disconnect,
     .cancel = &union_op_cancel,
     .copy_state = &union_copy_state,
+    .channel_death = &union_channel_death
   };
 
   return &union_vt;
diff --git a/src/set/gnunet-service-set_union.h b/src/set/gnunet-service-set_union.h
new file mode 100644 (file)
index 0000000..cbf60bc
--- /dev/null
@@ -0,0 +1,239 @@
+
+/*
+      This file is part of GNUnet
+      Copyright (C) 2013-2017 GNUnet e.V.
+
+      GNUnet is free software; you can redistribute it and/or modify
+      it under the terms of the GNU General Public License as published
+      by the Free Software Foundation; either version 3, or (at your
+      option) any later version.
+
+      GNUnet is distributed in the hope that it will be useful, but
+      WITHOUT ANY WARRANTY; without even the implied warranty of
+      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+      General Public License for more details.
+
+      You should have received a copy of the GNU General Public License
+      along with GNUnet; see the file COPYING.  If not, write to the
+      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+      Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file set/gnunet-service-set_union.h
+ * @brief two-peer set operations
+ * @author Florian Dold
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_SET_UNION_H
+#define GNUNET_SERVICE_SET_UNION_H
+
+#include "gnunet-service-set.h"
+#include "gnunet-service-set_protocol.h"
+
+
+/**
+ * Handle a strata estimator from a remote peer
+ *
+ * @param cls the union operation
+ * @param msg the message
+ */
+int
+check_union_p2p_strata_estimator (void *cls,
+                                  const struct StrataEstimatorMessage *msg);
+
+
+/**
+ * Handle a strata estimator from a remote peer
+ *
+ * @param cls the union operation
+ * @param msg the message
+ */
+void
+handle_union_p2p_strata_estimator (void *cls,
+                                   const struct StrataEstimatorMessage *msg);
+
+
+/**
+ * Check an IBF message from a remote peer.
+ *
+ * Reassemble the IBF from multiple pieces, and
+ * process the whole IBF once possible.
+ *
+ * @param cls the union operation
+ * @param msg the header of the message
+ * @return #GNUNET_OK if @a msg is well-formed
+ */
+int
+check_union_p2p_ibf (void *cls,
+                     const struct IBFMessage *msg);
+
+
+/**
+ * Handle an IBF message from a remote peer.
+ *
+ * Reassemble the IBF from multiple pieces, and
+ * process the whole IBF once possible.
+ *
+ * @param cls the union operation
+ * @param msg the header of the message
+ */
+void
+handle_union_p2p_ibf (void *cls,
+                      const struct IBFMessage *msg);
+
+
+/**
+ * Check an element message from a remote peer.
+ *
+ * @param cls the union operation
+ * @param emsg the message
+ */
+int
+check_union_p2p_elements (void *cls,
+                          const struct GNUNET_SET_ElementMessage *emsg);
+
+
+/**
+ * Handle an element message from a remote peer.
+ * Sent by the other peer either because we decoded an IBF and placed a demand,
+ * or because the other peer switched to full set transmission.
+ *
+ * @param cls the union operation
+ * @param emsg the message
+ */
+void
+handle_union_p2p_elements (void *cls,
+                           const struct GNUNET_SET_ElementMessage *emsg);
+
+
+/**
+ * Check a full element message from a remote peer.
+ *
+ * @param cls the union operation
+ * @param emsg the message
+ */
+int
+check_union_p2p_full_element (void *cls,
+                              const struct GNUNET_SET_ElementMessage *emsg);
+
+
+/**
+ * Handle an element message from a remote peer.
+ *
+ * @param cls the union operation
+ * @param emsg the message
+ */
+void
+handle_union_p2p_full_element (void *cls,
+                               const struct GNUNET_SET_ElementMessage *emsg);
+
+
+/**
+ * Send offers (for GNUNET_Hash-es) in response
+ * to inquiries (for IBF_Key-s).
+ *
+ * @param cls the union operation
+ * @param msg the message
+ */
+int
+check_union_p2p_inquiry (void *cls,
+                         const struct InquiryMessage *msg);
+
+
+/**
+ * Send offers (for GNUNET_Hash-es) in response
+ * to inquiries (for IBF_Key-s).
+ *
+ * @param cls the union operation
+ * @param msg the message
+ */
+void
+handle_union_p2p_inquiry (void *cls,
+                          const struct InquiryMessage *msg);
+
+
+
+/**
+ * Handle a request for full set transmission.
+ *
+ * @parem cls closure, a set union operation
+ * @param mh the demand message
+ */
+void
+handle_union_p2p_request_full (void *cls,
+                               const struct GNUNET_MessageHeader *mh);
+
+
+
+/**
+ * Handle a "full done" message.
+ *
+ * @parem cls closure, a set union operation
+ * @param mh the demand message
+ */
+void
+handle_union_p2p_full_done (void *cls,
+                            const struct GNUNET_MessageHeader *mh);
+
+
+/**
+ * Check a demand by the other peer for elements based on a list
+ * of `struct GNUNET_HashCode`s.
+ *
+ * @parem cls closure, a set union operation
+ * @param mh the demand message
+ * @return #GNUNET_OK if @a mh is well-formed
+ */
+int
+check_union_p2p_demand (void *cls,
+                        const struct GNUNET_MessageHeader *mh);
+
+
+/**
+ * Handle a demand by the other peer for elements based on a list
+ * of `struct GNUNET_HashCode`s.
+ *
+ * @parem cls closure, a set union operation
+ * @param mh the demand message
+ */
+void
+handle_union_p2p_demand (void *cls,
+                         const struct GNUNET_MessageHeader *mh);
+
+
+/**
+ * Check offer (of `struct GNUNET_HashCode`s).
+ *
+ * @param cls the union operation
+ * @param mh the message
+ * @return #GNUNET_OK if @a mh is well-formed
+ */
+int
+check_union_p2p_offer (void *cls,
+                       const struct GNUNET_MessageHeader *mh);
+
+
+/**
+ * Handle offers (of `struct GNUNET_HashCode`s) and
+ * respond with demands (of `struct GNUNET_HashCode`s).
+ *
+ * @param cls the union operation
+ * @param mh the message
+ */
+void
+handle_union_p2p_offer (void *cls,
+                        const struct GNUNET_MessageHeader *mh);
+
+
+/**
+ * Handle a done message from a remote peer
+ *
+ * @param cls the union operation
+ * @param mh the message
+ */
+void
+handle_union_p2p_done (void *cls,
+                       const struct GNUNET_MessageHeader *mh);
+
+
+#endif
index 8d832e358fc0a1a99b8e9af6d4c3b9c2b0744c61..ac86a900d914a30511b726136bbf535a778f01dc 100644 (file)
@@ -244,24 +244,41 @@ run (void *cls,
 int
 main (int argc, char **argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'A', "asize", NULL,
-     gettext_noop ("number of element in set A-B"), 1,
-     &GNUNET_GETOPT_set_uint, &asize},
-    {'B', "bsize", NULL,
-     gettext_noop ("number of element in set B-A"), 1,
-     &GNUNET_GETOPT_set_uint, &bsize},
-    {'C', "csize", NULL,
-     gettext_noop ("number of common elements in A and B"), 1,
-     &GNUNET_GETOPT_set_uint, &csize},
-    {'k', "hash-num", NULL,
-     gettext_noop ("hash num"), 1,
-     &GNUNET_GETOPT_set_uint, &hash_num},
-    {'s', "ibf-size", NULL,
-     gettext_noop ("ibf size"), 1,
-     &GNUNET_GETOPT_set_uint, &ibf_size},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('A',
+                                   "asize",
+                                   NULL,
+                                   gettext_noop ("number of element in set A-B"),
+                                   &asize),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('B',
+                                   "bsize",
+                                   NULL,
+                                   gettext_noop ("number of element in set B-A"),
+                                   &bsize),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('C',
+                                   "csize",
+                                   NULL,
+                                   gettext_noop ("number of common elements in A and B"),
+                                   &csize),
+    
+    GNUNET_GETOPT_OPTION_SET_UINT ('k',
+                                   "hash-num",
+                                   NULL,
+                                   gettext_noop ("hash num"),
+                                   &hash_num),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('s',
+                                   "ibf-size",
+                                   NULL,
+                                   gettext_noop ("ibf size"),
+                                   &ibf_size),
+
     GNUNET_GETOPT_OPTION_END
   };
+
   GNUNET_PROGRAM_run2 (argc, argv, "gnunet-consensus-ibf",
                       "help",
                       options, &run, NULL, GNUNET_YES);
index d83e034a684c8c396b4c5ede9e4168f35803a6c2..349bce6ea1c05197e051b1ef21756a2716bb990a 100644 (file)
@@ -59,8 +59,9 @@ static struct GNUNET_PeerIdentity local_peer;
 static struct GNUNET_SET_ListenHandle *set_listener;
 
 static int byzantine;
-static int force_delta;
-static int force_full;
+static unsigned int force_delta;
+static unsigned int force_full;
+static unsigned int element_size = 32;
 
 /**
  * Handle to the statistics service.
@@ -90,7 +91,7 @@ map_remove_iterator (void *cls,
 
   GNUNET_assert (NULL != key);
 
-  ret = GNUNET_CONTAINER_multihashmap_remove (m, key, NULL);
+  ret = GNUNET_CONTAINER_multihashmap_remove_all (m, key);
   if (GNUNET_OK != ret)
     printf ("spurious element\n");
   return GNUNET_YES;
@@ -196,7 +197,7 @@ set_result_cb (void *cls,
       GNUNET_assert (0);
   }
 
-  if (element->size != sizeof (struct GNUNET_HashCode))
+  if (element->size != element_size)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "wrong element size: %u, expected %u\n",
@@ -208,8 +209,10 @@ set_result_cb (void *cls,
   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "set %s: got element (%s)\n",
               info->id, GNUNET_h2s (element->data));
   GNUNET_assert (NULL != element->data);
+  struct GNUNET_HashCode data_hash;
+  GNUNET_CRYPTO_hash (element->data, element_size, &data_hash);
   GNUNET_CONTAINER_multihashmap_put (info->received,
-                                     element->data, NULL,
+                                     &data_hash, NULL,
                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
 }
 
@@ -261,16 +264,12 @@ set_insert_iterator (void *cls,
                      void *value)
 {
   struct GNUNET_SET_Handle *set = cls;
-  struct GNUNET_SET_Element *el;
-
-  el = GNUNET_malloc (sizeof (struct GNUNET_SET_Element) +
-                      sizeof (struct GNUNET_HashCode));
-  el->element_type = 0;
-  GNUNET_memcpy (&el[1], key, sizeof *key);
-  el->data = &el[1];
-  el->size = sizeof *key;
-  GNUNET_SET_add_element (set, el, NULL, NULL);
-  GNUNET_free (el);
+  struct GNUNET_SET_Element el;
+
+  el.element_type = 0;
+  el.data = value;
+  el.size = element_size;
+  GNUNET_SET_add_element (set, &el, NULL, NULL);
   return GNUNET_YES;
 }
 
@@ -322,6 +321,8 @@ run (void *cls,
 
   config = cfg;
 
+  GNUNET_assert (element_size > 0);
+
   if (GNUNET_OK != GNUNET_CRYPTO_get_peer_identity (cfg, &local_peer))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not retrieve host identity\n");
@@ -345,22 +346,28 @@ run (void *cls,
 
   for (i = 0; i < num_a; i++)
   {
-    GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &hash);
-    GNUNET_CONTAINER_multihashmap_put (info1.sent, &hash, NULL,
+    char *data = GNUNET_malloc (element_size);
+    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
+    GNUNET_CRYPTO_hash (data, element_size, &hash);
+    GNUNET_CONTAINER_multihashmap_put (info1.sent, &hash, data,
                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
   }
 
   for (i = 0; i < num_b; i++)
   {
-    GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &hash);
-    GNUNET_CONTAINER_multihashmap_put (info2.sent, &hash, NULL,
+    char *data = GNUNET_malloc (element_size);
+    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
+    GNUNET_CRYPTO_hash (data, element_size, &hash);
+    GNUNET_CONTAINER_multihashmap_put (info2.sent, &hash, data,
                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
   }
 
   for (i = 0; i < num_c; i++)
   {
-    GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, &hash);
-    GNUNET_CONTAINER_multihashmap_put (common_sent, &hash, NULL,
+    char *data = GNUNET_malloc (element_size);
+    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, data, element_size);
+    GNUNET_CRYPTO_hash (data, element_size, &hash);
+    GNUNET_CONTAINER_multihashmap_put (common_sent, &hash, data,
                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
   }
 
@@ -419,31 +426,60 @@ pre_run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char **argv)
 {
-   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-      { 'A', "num-first", NULL,
-        gettext_noop ("number of values"),
-        GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_a },
-      { 'B', "num-second", NULL,
-        gettext_noop ("number of values"),
-        GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_b },
-      { 'b', "byzantine", NULL,
-        gettext_noop ("use byzantine mode"),
-        GNUNET_NO, &GNUNET_GETOPT_set_one, &byzantine },
-      { 'f', "force-full", NULL,
-        gettext_noop ("force sending full set"),
-        GNUNET_NO, &GNUNET_GETOPT_set_uint, &force_full },
-      { 'd', "force-delta", NULL,
-        gettext_noop ("number delta operation"),
-        GNUNET_NO, &GNUNET_GETOPT_set_uint, &force_delta },
-      { 'C', "num-common", NULL,
-        gettext_noop ("number of values"),
-        GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_c },
-      { 'x', "operation", NULL,
-        gettext_noop ("operation to execute"),
-        GNUNET_YES, &GNUNET_GETOPT_set_string, &op_str },
-      { 's', "statistics", NULL,
-        gettext_noop ("write statistics to file"),
-        GNUNET_YES, &GNUNET_GETOPT_set_filename, &statistics_filename },
+   struct GNUNET_GETOPT_CommandLineOption options[] = {
+      GNUNET_GETOPT_OPTION_SET_UINT ('A',
+                                     "num-first",
+                                     NULL,
+                                     gettext_noop ("number of values"),
+                                     &num_a),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('B',
+                                     "num-second",
+                                     NULL,
+                                     gettext_noop ("number of values"),
+                                     &num_b),
+
+      GNUNET_GETOPT_OPTION_SET_ONE ('b',
+                                    "byzantine",
+                                    gettext_noop ("use byzantine mode"),
+                                    &byzantine),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('f',
+                                     "force-full",
+                                     NULL,
+                                     gettext_noop ("force sending full set"),
+                                     &force_full),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('d',
+                                     "force-delta",
+                                     NULL,
+                                     gettext_noop ("number delta operation"),
+                                     &force_delta),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('C',
+                                     "num-common",
+                                     NULL,
+                                     gettext_noop ("number of values"),
+                                     &num_c),
+
+      GNUNET_GETOPT_OPTION_STRING ('x',
+                                   "operation",
+                                   NULL,
+                                   gettext_noop ("operation to execute"),
+                                   &op_str),
+
+      GNUNET_GETOPT_OPTION_SET_UINT ('w',
+                                     "element-size",
+                                     NULL,
+                                     gettext_noop ("element size"),
+                                     &element_size),
+
+      GNUNET_GETOPT_OPTION_FILENAME ('s',
+                                     "statistics",
+                                     "FILENAME",
+                                     gettext_noop ("write statistics to file"),
+                                     &statistics_filename),
+
       GNUNET_GETOPT_OPTION_END
   };
   GNUNET_PROGRAM_run2 (argc, argv, "gnunet-set-profiler",
index 5b5b1b8eecfdd1d97d2d7eaf92c66a9cd100a08c..f5c43a9a7c90d056db5dfab775c2fd93a52ba858 100644 (file)
@@ -76,6 +76,8 @@ struct GNUNET_SET_Handle
 
   /**
    * Should the set be destroyed once all operations are gone?
+   * #GNUNET_SYSERR if #GNUNET_SET_destroy() must raise this flag,
+   * #GNUNET_YES if #GNUNET_SET_destroy() did raise this flag.
    */
   int destroy_requested;
 
@@ -308,6 +310,8 @@ handle_iter_element (void *cls,
   struct GNUNET_MQ_Envelope *ev;
   uint16_t msize;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received element in set iteration\n");
   msize = ntohs (msg->header.size);
   if (set->iteration_id != ntohs (msg->iteration_id))
   {
@@ -344,11 +348,24 @@ handle_iter_done (void *cls,
   GNUNET_SET_ElementIterator iter = set->iterator;
 
   if (NULL == iter)
+  {
+    /* FIXME: if this is true, could cancel+start a fresh one
+       cause elements to go to the wrong iteration? */
+    LOG (GNUNET_ERROR_TYPE_INFO,
+         "Service completed set iteration that was already cancelled\n");
     return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Set iteration completed\n");
+  set->destroy_requested = GNUNET_SYSERR;
   set->iterator = NULL;
   set->iteration_id++;
   iter (set->iterator_cls,
         NULL);
+  if (GNUNET_SYSERR == set->destroy_requested)
+    set->destroy_requested = GNUNET_NO;
+  if (GNUNET_YES == set->destroy_requested)
+    GNUNET_SET_destroy (set);
 }
 
 
@@ -385,7 +402,7 @@ handle_result (void *cls,
   int destroy_set;
 
   GNUNET_assert (NULL != set->mq);
-  result_status = ntohs (msg->result_status);
+  result_status = (enum GNUNET_SET_Status) ntohs (msg->result_status);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Got result message with status %d\n",
        result_status);
@@ -500,6 +517,8 @@ GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
   struct GNUNET_SET_CancelMessage *m;
   struct GNUNET_MQ_Envelope *mqm;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Cancelling SET operation\n");
   if (NULL != set)
   {
     mqm = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_SET_CANCEL);
@@ -553,6 +572,9 @@ handle_client_set_error (void *cls,
 }
 
 
+/**
+ * FIXME.
+ */
 static struct GNUNET_SET_Handle *
 create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
                  enum GNUNET_SET_OperationType op,
@@ -611,7 +633,8 @@ create_internal (const struct GNUNET_CONFIGURATION_Handle *cfg,
                          GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_CONNECT);
     copy_msg->cookie = *cookie;
   }
-  GNUNET_MQ_send (set->mq, mqm);
+  GNUNET_MQ_send (set->mq,
+                  mqm);
   return set;
 }
 
@@ -631,7 +654,16 @@ struct GNUNET_SET_Handle *
 GNUNET_SET_create (const struct GNUNET_CONFIGURATION_Handle *cfg,
                    enum GNUNET_SET_OperationType op)
 {
-  return create_internal (cfg, op, NULL);
+  struct GNUNET_SET_Handle *set;
+
+  set = create_internal (cfg,
+                          op,
+                          NULL);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating set %p for operation %d\n",
+       set,
+       op);
+  return set;
 }
 
 
@@ -657,8 +689,10 @@ GNUNET_SET_add_element (struct GNUNET_SET_Handle *set,
   struct GNUNET_MQ_Envelope *mqm;
   struct GNUNET_SET_ElementMessage *msg;
 
-  LOG (GNUNET_ERROR_TYPE_INFO, "adding element of type %u\n", (unsigned) element->element_type);
-
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "adding element of type %u to set %p\n",
+       (unsigned int) element->element_type,
+       set);
   if (GNUNET_YES == set->invalid)
   {
     if (NULL != cont)
@@ -701,6 +735,9 @@ GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
   struct GNUNET_MQ_Envelope *mqm;
   struct GNUNET_SET_ElementMessage *msg;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Removing element from set %p\n",
+       set);
   if (GNUNET_YES == set->invalid)
   {
     if (NULL != cont)
@@ -733,8 +770,9 @@ GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
   /* destroying set while iterator is active is currently
      not supported; we should expand the API to allow
      clients to explicitly cancel the iteration! */
-  GNUNET_assert (NULL == set->iterator);
-  if (NULL != set->ops_head)
+  if ( (NULL != set->ops_head) ||
+       (NULL != set->iterator) ||
+       (GNUNET_SYSERR == set->destroy_requested) )
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Set operations are pending, delaying set destruction\n");
@@ -807,7 +845,7 @@ GNUNET_SET_prepare (const struct GNUNET_PeerIdentity *other_peer,
         msg->force_delta = GNUNET_YES;
         break;
       default:
-        LOG (GNUNET_ERROR_TYPE_ERROR, 
+        LOG (GNUNET_ERROR_TYPE_ERROR,
              "Option with type %d not recognized\n", (int) opt->type);
     }
   }
@@ -870,7 +908,8 @@ handle_request (void *cls,
   struct GNUNET_SET_RejectMessage *rmsg;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Processing incoming operation request\n");
+       "Processing incoming operation request with id %u\n",
+       ntohl (msg->accept_id));
   /* we got another valid request => reset the backoff */
   lh->reconnect_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
   req.accept_id = ntohl (msg->accept_id);
@@ -884,7 +923,8 @@ handle_request (void *cls,
   if (GNUNET_YES == req.accepted)
     return; /* the accept-case is handled in #GNUNET_SET_accept() */
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Rejecting request\n");
+       "Rejected request %u\n",
+       ntohl (msg->accept_id));
   mqm = GNUNET_MQ_msg (rmsg,
                        GNUNET_MESSAGE_TYPE_SET_REJECT);
   rmsg->accept_reject_id = msg->accept_id;
@@ -974,6 +1014,9 @@ GNUNET_SET_listen (const struct GNUNET_CONFIGURATION_Handle *cfg,
 {
   struct GNUNET_SET_ListenHandle *lh;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Starting listener for app %s\n",
+       GNUNET_h2s (app_id));
   lh = GNUNET_new (struct GNUNET_SET_ListenHandle);
   lh->listen_cb = listen_cb;
   lh->listen_cls = listen_cls;
@@ -1000,7 +1043,8 @@ void
 GNUNET_SET_listen_cancel (struct GNUNET_SET_ListenHandle *lh)
 {
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Canceling listener\n");
+       "Canceling listener %s\n",
+       GNUNET_h2s (&lh->app_id));
   if (NULL != lh->mq)
   {
     GNUNET_MQ_destroy (lh->mq);
@@ -1042,10 +1086,12 @@ GNUNET_SET_accept (struct GNUNET_SET_Request *request,
 
   GNUNET_assert (GNUNET_NO == request->accepted);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Client accepts set operation (%d)\n",
-       result_mode);
+       "Client accepts set operation (%d) with id %u\n",
+       result_mode,
+       request->accept_id);
   request->accepted = GNUNET_YES;
-  mqm = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SET_ACCEPT);
+  mqm = GNUNET_MQ_msg (msg,
+                       GNUNET_MESSAGE_TYPE_SET_ACCEPT);
   msg->accept_reject_id = htonl (request->accept_id);
   msg->result_mode = htonl (result_mode);
   oh = GNUNET_new (struct GNUNET_SET_OperationHandle);
@@ -1143,6 +1189,8 @@ GNUNET_SET_copy_lazy (struct GNUNET_SET_Handle *set,
   struct GNUNET_MQ_Envelope *ev;
   struct SetCopyRequest *req;
 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating lazy copy of set\n");
   ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_COPY_LAZY_PREPARE);
   GNUNET_MQ_send (set->mq, ev);
 
index dd3f004f247a0826ffbd7e00e2c2a4469fe87d8b..ca7d8a4e26b98c5e5795b0840d34a3d1d396e297 100644 (file)
@@ -116,6 +116,7 @@ result_cb_set2 (void *cls,
     oh2 = NULL;
     fprintf (stderr,
              "set 2: received failure status\n");
+    GNUNET_SCHEDULER_shutdown ();
     ret = 1;
     break;
   case GNUNET_SET_STATUS_DONE:
@@ -147,8 +148,6 @@ listen_cb (void *cls,
   GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "listen cb called\n");
-  GNUNET_SET_listen_cancel (listen_handle);
-  listen_handle = NULL;
   oh2 = GNUNET_SET_accept (request,
                            GNUNET_SET_RESULT_ADDED,
                            (struct GNUNET_SET_Option[]) { 0 },
@@ -200,19 +199,25 @@ init_set2 (void *cls)
 {
   struct GNUNET_SET_Element element;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "initializing set 2\n");
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "initializing set 2\n");
 
   element.element_type = 0;
-
   element.data = "hello";
   element.size = strlen(element.data);
-  GNUNET_SET_add_element (set2, &element, NULL, NULL);
+  GNUNET_SET_add_element (set2,
+                          &element,
+                          NULL, NULL);
   element.data = "quux";
   element.size = strlen(element.data);
-  GNUNET_SET_add_element (set2, &element, NULL, NULL);
+  GNUNET_SET_add_element (set2,
+                          &element,
+                          NULL, NULL);
   element.data = "baz";
   element.size = strlen(element.data);
-  GNUNET_SET_add_element (set2, &element, &start, NULL);
+  GNUNET_SET_add_element (set2,
+                          &element,
+                          &start, NULL);
 }
 
 
@@ -225,14 +230,17 @@ init_set1 (void)
   struct GNUNET_SET_Element element;
 
   element.element_type = 0;
-
   element.data = "hello";
   element.size = strlen(element.data);
-  GNUNET_SET_add_element (set1, &element, NULL, NULL);
+  GNUNET_SET_add_element (set1,
+                          &element,
+                          NULL, NULL);
   element.data = "bar";
   element.size = strlen(element.data);
-  GNUNET_SET_add_element (set1, &element, init_set2, NULL);
-
+  GNUNET_SET_add_element (set1,
+                          &element,
+                          &init_set2,
+                          NULL);
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               "initialized set 1\n");
 }
@@ -242,10 +250,15 @@ static int
 iter_cb (void *cls,
          const struct GNUNET_SET_Element *element)
 {
+  struct GNUNET_SET_Handle *set = cls;
+
   if (NULL == element)
   {
     GNUNET_assert (3 == iter_count);
-    GNUNET_SET_destroy (cls);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Iteration finished, destroying set %p\n",
+                set);
+    GNUNET_SET_destroy (set);
     return GNUNET_YES;
   }
   iter_count++;
@@ -262,21 +275,31 @@ test_iter ()
   struct GNUNET_SET_Element element;
   struct GNUNET_SET_Handle *iter_set;
 
-  iter_set = GNUNET_SET_create (config, GNUNET_SET_OPERATION_UNION);
-
+  iter_set = GNUNET_SET_create (config,
+                                GNUNET_SET_OPERATION_UNION);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Testing iteration over 3 elements on set %p\n",
+              iter_set);
   element.element_type = 0;
 
   element.data = "hello";
   element.size = strlen(element.data);
-  GNUNET_SET_add_element (iter_set, &element, NULL, NULL);
+  GNUNET_SET_add_element (iter_set,
+                          &element,
+                          NULL, NULL);
   element.data = "bar";
   element.size = strlen(element.data);
-  GNUNET_SET_add_element (iter_set, &element, NULL, NULL);
+  GNUNET_SET_add_element (iter_set,
+                          &element,
+                          NULL, NULL);
   element.data = "quux";
   element.size = strlen(element.data);
-  GNUNET_SET_add_element (iter_set, &element, NULL, NULL);
-
-  GNUNET_SET_iterate (iter_set, iter_cb, iter_set);
+  GNUNET_SET_add_element (iter_set,
+                          &element,
+                          NULL, NULL);
+  GNUNET_SET_iterate (iter_set,
+                      &iter_cb,
+                      iter_set);
 }
 
 
@@ -372,12 +395,20 @@ run (void *cls,
               GNUNET_i2s (&local_id));
   test_iter ();
 
-  set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION);
-  set2 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION);
+  set1 = GNUNET_SET_create (cfg,
+                            GNUNET_SET_OPERATION_UNION);
+  set2 = GNUNET_SET_create (cfg,
+                            GNUNET_SET_OPERATION_UNION);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Created sets %p and %p for union operation\n",
+              set1,
+              set2);
   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
                                     &app_id);
 
-  ///* test if canceling an uncommited request works! */
+  /* test if canceling an uncommited request works! */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Launching and instantly stopping set operation\n");
   my_oh = GNUNET_SET_prepare (&local_id,
                               &app_id,
                               NULL,
@@ -385,7 +416,6 @@ run (void *cls,
                               (struct GNUNET_SET_Option[]) { 0 },
                               NULL,
                               NULL);
-
   GNUNET_SET_operation_cancel (my_oh);
 
   /* test the real set reconciliation */
index c887a89588f309be408c2b47dc3adc641190a72f..242b9f2f2d786ce037031066288eeb662a16e018 100644 (file)
@@ -122,6 +122,7 @@ check_count_iter (void *cls,
       return GNUNET_NO;
     }
     ci_cls->cont (ci_cls->cont_cls);
+    GNUNET_free (ci_cls);
     return GNUNET_NO;
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -264,7 +265,8 @@ run (void *cls,
   GNUNET_TESTING_peer_get_identity (peer,
                                     &local_id);
 
-  set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION);
+  set1 = GNUNET_SET_create (cfg,
+                            GNUNET_SET_OPERATION_UNION);
   add_element_str (set1,
                    "333");
   add_element_str (set1,
index 41954615f0e2d81ca157a38a3a1f4bf76db186d8..875aa11055089f93ace204f4916f1e0af0f40586 100644 (file)
@@ -1,2 +1,3 @@
 gnunet-social
 gnunet-service-social
+test_social
index 1da51243e6ff5d155b5f33d21dfb63f0f6792e57..4a46fdc99c11464a4c346c181fb4ffa869381910 100644 (file)
@@ -67,10 +67,10 @@ static int op_guest_leave;
 static int op_guest_talk;
 
 /** --replay */
-static char *op_replay;
+static int op_replay;
 
 /** --replay-latest */
-static char *op_replay_latest;
+static int op_replay_latest;
 
 /** --look-at */
 static int op_look_at;
@@ -116,13 +116,13 @@ static char *opt_data;
 static char *opt_name;
 
 /** --start */
-static uint64_t opt_start;
+static unsigned long long opt_start;
 
 /** --until */
-static uint64_t opt_until;
+static unsigned long long opt_until;
 
 /** --limit */
-static int opt_limit;
+static unsigned long long opt_limit;
 
 
 /* global vars */
@@ -563,7 +563,7 @@ slicer_recv_method (void *cls,
               "%s (flags: %x)\n",
               message_id, method_name, ntohl (meth->flags));
   /* routing header is missing, so we just print double newline */
-  printf(".\n\n");
+  printf("\n");
   /* we output . instead of | to indicate that this is not proper PSYC syntax */
   /* FIXME: use libpsyc here */
 }
@@ -588,10 +588,11 @@ slicer_recv_modifier (void *cls,
               "Received modifier for message ID %" PRIu64 ":\n"
               "%c%s: %.*s (size: %u)\n",
               message_id, oper, name, value_size, (const char *) value, value_size);
-#endif
+#else
   /* obviously not binary safe */
   printf("%c%s\t%.*s\n",
               oper, name, value_size, (const char *) value);
+#endif
 }
 
 
@@ -611,10 +612,11 @@ slicer_recv_data (void *cls,
               "Received data for message ID %" PRIu64 ":\n"
               "%.*s\n",
               message_id, data_size, (const char *) data);
-#endif
+#else
   /* obviously not binary safe */
   printf("%s\n%.*s\n",
               method_received, data_size, (const char *) data);
+#endif
 }
 
 
@@ -1016,6 +1018,7 @@ app_connected (void *cls)
       guest_enter (&place_pub_key, &peer);
     }
   }
+  printf(".\n");
 }
 
 
@@ -1161,6 +1164,7 @@ run (void *cls, char *const *args, const char *cfgfile,
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                 _("--place missing or invalid.\n"));
+    /* FIXME: why does it segfault here? */
     exit_fail ();
     return;
   }
@@ -1195,7 +1199,7 @@ int
 main (int argc, char *const *argv)
 {
   int res;
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
     /*
      * gnunet program options in addition to the ones below:
      *
@@ -1208,120 +1212,165 @@ main (int argc, char *const *argv)
 
     /* operations */
 
-    { 'A', "host-assign", NULL,
-      gettext_noop ("assign --name in state to --data"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_assign },
-
-    { 'B', "guest-leave", NULL,
-      gettext_noop ("say good-bye and leave somebody else's place"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_leave },
-
-    { 'C', "host-enter", NULL,
-      gettext_noop ("create a place"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_enter },
-
-    { 'D', "host-leave", NULL,
-      gettext_noop ("destroy a place we were hosting"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_leave },
-
-    { 'E', "guest-enter", NULL,
-      gettext_noop ("enter somebody else's place"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_enter },
-
-    { 'F', "look-for", NULL,
-      gettext_noop ("find state matching name prefix"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_look_for },
-
-    { 'H', "replay-latest", NULL,
-      gettext_noop ("replay history of messages up to the given --limit"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_replay_latest },
-
-    { 'N', "host-reconnect", NULL,
-      gettext_noop ("reconnect to a previously created place"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_reconnect },
-
-    { 'P', "host-announce", NULL,
-      gettext_noop ("publish something to a place we are hosting"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_host_announce },
-
-    { 'R', "guest-reconnect", NULL,
-      gettext_noop ("reconnect to a previously entered place"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_reconnect },
-
-    { 'S', "look-at", NULL,
-      gettext_noop ("search for state matching exact name"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_look_at },
-
-    { 'T', "guest-talk", NULL,
-      gettext_noop ("submit something to somebody's place"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_guest_talk },
-
-    { 'U', "status", NULL,
-      gettext_noop ("list of egos and subscribed places"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_status },
-
-    { 'X', "replay", NULL,
-      gettext_noop ("extract and replay history between message IDs --start and --until"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &op_replay },
+    GNUNET_GETOPT_OPTION_SET_ONE ('A',
+                                  "host-assign",
+                                  gettext_noop ("assign --name in state to --data"),
+                                  &op_host_assign),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('B',
+                                  "guest-leave",
+                                  gettext_noop ("say good-bye and leave somebody else's place"),
+                                  &op_guest_leave),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('C',
+                                  "host-enter",
+                                  gettext_noop ("create a place"),
+                                  &op_host_enter),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('C',
+                                  "host-enter",
+                                  gettext_noop ("create a place"),
+                                  &op_host_enter),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('D',
+                                  "host-leave",
+                                  gettext_noop ("destroy a place we were hosting"),
+                                  &op_host_leave),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('E',
+                                  "guest-enter",
+                                  gettext_noop ("enter somebody else's place"),
+                                  &op_guest_enter),
+
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('F',
+                                  "look-for",
+                                  gettext_noop ("find state matching name prefix"),
+                                  &op_look_for),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('H',
+                                  "replay-latest",
+                                  gettext_noop ("replay history of messages up to the given --limit"),
+                                  &op_replay_latest),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('N',
+                                  "host-reconnect",
+                                  gettext_noop ("reconnect to a previously created place"),
+                                  &op_host_reconnect),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('P',
+                                  "host-announce",
+                                  gettext_noop ("publish something to a place we are hosting"),
+                                  &op_host_announce),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('R',
+                                  "guest-reconnect",
+                                  gettext_noop ("reconnect to a previously entered place"),
+                                  &op_guest_reconnect),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('S',
+                                  "look-at",
+                                  gettext_noop ("search for state matching exact name"),
+                                  &op_look_at),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('T',
+                                  "guest-talk",
+                                  gettext_noop ("submit something to somebody's place"),
+                                  &op_guest_talk),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('U',
+                                  "status",
+                                  gettext_noop ("list of egos and subscribed places"),
+                                  &op_status),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('X',
+                                  "replay",
+                                  gettext_noop ("extract and replay history between message IDs --start and --until"),
+                                  &op_replay),
 
 
     /* options */
 
-    { 'a', "app", "APPLICATION_ID",
-      gettext_noop ("application ID to use when connecting"),
-      GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_app },
-
-    { 'd', "data", "DATA",
-      gettext_noop ("message body or state value"),
-      GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_data },
-
-    { 'e', "ego", "NAME|PUBKEY",
-      gettext_noop ("name or public key of ego"),
-      GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_ego },
-
-    { 'f', "follow", NULL,
-      gettext_noop ("wait for incoming messages"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_follow },
-
-    { 'g', "gns", "GNS_NAME",
-      gettext_noop ("GNS name"),
-      GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_gns },
-
-    { 'i', "peer", "PEER_ID",
-      gettext_noop ("peer ID for --guest-enter"),
-      GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_peer },
-
-    { 'k', "name", "VAR_NAME",
-      gettext_noop ("name (key) to query from state"),
-      GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_name },
-
-    { 'm', "method", "METHOD_NAME",
-      gettext_noop ("method name"),
-      GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_method },
-
-    { 'n', "limit", NULL,
-      gettext_noop ("number of messages to replay from history"),
-      GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_limit },
-
-    { 'p', "place", "PUBKEY",
-      gettext_noop ("key address of place"),
-      GNUNET_YES, &GNUNET_GETOPT_set_string, &opt_place },
-
-    { 's', "start", NULL,
-      gettext_noop ("start message ID for history replay"),
-      GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_start },
-
-    { 'w', "welcome", NULL,
-      gettext_noop ("respond to entry requests by admitting all guests"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_welcome },
-
-    { 'u', "until", NULL,
-      gettext_noop ("end message ID for history replay"),
-      GNUNET_YES, &GNUNET_GETOPT_set_ulong, &opt_until },
-
-    { 'y', "deny", NULL,
-      gettext_noop ("respond to entry requests by refusing all guests"),
-      GNUNET_NO, &GNUNET_GETOPT_set_one, &opt_deny },
+    GNUNET_GETOPT_OPTION_STRING ('a',
+                                 "app",
+                                 "APPLICATION_ID",
+                                 gettext_noop ("application ID to use when connecting"),
+                                 &opt_app),
+
+    GNUNET_GETOPT_OPTION_STRING ('d',
+                                 "data",
+                                 "DATA",
+                                 gettext_noop ("message body or state value"),
+                                 &opt_data),
+
+    GNUNET_GETOPT_OPTION_STRING ('e',
+                                 "ego",
+                                 "NAME|PUBKEY",
+                                 gettext_noop ("name or public key of ego"),
+                                 &opt_ego),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('f',
+                                  "follow",
+                                  gettext_noop ("wait for incoming messages"),
+                                  &opt_follow),
+
+    GNUNET_GETOPT_OPTION_STRING ('g',
+                                 "gns",
+                                 "GNS_NAME",
+                                 gettext_noop ("GNS name"),
+                                 &opt_gns),
+
+    GNUNET_GETOPT_OPTION_STRING ('i',
+                                 "peer",
+                                 "PEER_ID",
+                                 gettext_noop ("peer ID for --guest-enter"),
+                                 &opt_peer),
+
+    GNUNET_GETOPT_OPTION_STRING ('k',
+                                 "name",
+                                 "VAR_NAME",
+                                 gettext_noop ("name (key) to query from state"),
+                                 &opt_name),
+
+    GNUNET_GETOPT_OPTION_STRING ('m',
+                                 "method",
+                                 "METHOD_NAME",
+                                 gettext_noop ("method name"),
+                                 &opt_method),
+
+    GNUNET_GETOPT_OPTION_SET_ULONG ('n',
+                                    "limit",
+                                    NULL,
+                                    gettext_noop ("number of messages to replay from history"),
+                                    &opt_limit),
+
+    GNUNET_GETOPT_OPTION_STRING ('p',
+                                 "place",
+                                 "PUBKEY",
+                                 gettext_noop ("key address of place"),
+                                 &opt_place),
+
+    GNUNET_GETOPT_OPTION_SET_ULONG ('s',
+                                    "start",
+                                    NULL,
+                                    gettext_noop ("start message ID for history replay"),
+                                    &opt_start),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('w',
+                                  "welcome",
+                                  gettext_noop ("respond to entry requests by admitting all guests"),
+                                  &opt_welcome),
+
+    GNUNET_GETOPT_OPTION_SET_ULONG ('u',
+                                    "until",
+                                    NULL,
+                                    gettext_noop ("end message ID for history replay"),
+                                    &opt_until),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('y',
+                                  "deny",
+                                  gettext_noop ("respond to entry requests by refusing all guests"),
+                                  &opt_deny),
 
     GNUNET_GETOPT_OPTION_END
   };
@@ -1350,8 +1399,8 @@ main (int argc, char *const *argv)
     "gnunet-social --guest-leave --place <PUBKEY>\n"
     "gnunet-social --guest-talk --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n"
     "\n"
-    "gnunet-social --history-replay --place <PUBKEY> --start <MSGID> --until <MSGID>  [--method <METHOD_PREFIX>]\n"
-    "gnunet-social --history-replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n"
+    "gnunet-social --replay --place <PUBKEY> --start <MSGID> --until <MSGID>  [--method <METHOD_PREFIX>]\n"
+    "gnunet-social --replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n"
     "\n"
     "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n"
     "gnunet-social --look-for --place <PUBKEY> --name <NAME_PREFIX>\n";
index a7fe0916f5609e743f39679279c1ffbbffdfcedb..af1d6e57eeb919aa6050f5eb9e4c7de280dd757b 100644 (file)
@@ -2110,7 +2110,7 @@ GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc,
   GNUNET_assert (NULL != method_prefix);
   struct MsgProcRequest *mpreq;
   uint16_t method_size = strnlen (method_prefix,
-                                  GNUNET_SERVER_MAX_MESSAGE_SIZE
+                                  GNUNET_MAX_MESSAGE_SIZE
                                   - sizeof (*mpreq)) + 1;
   GNUNET_assert ('\0' == method_prefix[method_size - 1]);
 
@@ -2159,7 +2159,7 @@ place_history_replay (struct GNUNET_SOCIAL_Place *plc,
 
   GNUNET_assert (NULL != method_prefix);
   uint16_t method_size = strnlen (method_prefix,
-                                  GNUNET_SERVER_MAX_MESSAGE_SIZE
+                                  GNUNET_MAX_MESSAGE_SIZE
                                   - sizeof (*req)) + 1;
   GNUNET_assert ('\0' == method_prefix[method_size - 1]);
 
@@ -2285,7 +2285,7 @@ place_state_get (struct GNUNET_SOCIAL_Place *plc,
   look->op_id = GNUNET_OP_add (plc->op, &op_recv_state_result, look, NULL);
 
   GNUNET_assert (NULL != name);
-  size_t name_size = strnlen (name, GNUNET_SERVER_MAX_MESSAGE_SIZE
+  size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE
                               - sizeof (*req)) + 1;
   struct GNUNET_MQ_Envelope *
     env = GNUNET_MQ_msg_extra (req, name_size, type);
@@ -2426,7 +2426,7 @@ GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app,
   size_t relay_size = relay_count * sizeof (*relays);
   size_t payload_size = name_size + password_size + relay_size;
 
-  if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (*preq) + payload_size)
+  if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*preq) + payload_size)
     return GNUNET_SYSERR;
 
   struct GNUNET_MQ_Envelope *
@@ -2506,7 +2506,7 @@ GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app,
   struct ZoneAddNymRequest *nreq;
 
   size_t name_size = strlen (name) + 1;
-  if (GNUNET_SERVER_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size)
+  if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size)
     return GNUNET_SYSERR;
 
   struct GNUNET_MQ_Envelope *
index c5f80bcf6bf0ae555e6e09d70703c1b525605f59..cfccd89f6df15b5661d2db1521126faaeecba512 100644 (file)
@@ -9,7 +9,7 @@ if USE_COVERAGE
   AM_CFLAGS = --coverage
 endif
 
-if HAVE_POSTGRESQL
+if HAVE_SQLITE
 lib_LTLIBRARIES = libgnunetsq.la
 endif
 
index dc4416761b9aed0506a12e69b3048f2ae8e7ffcf..089ebf0ffc539eb087227269d34583050de89b5a 100644 (file)
@@ -49,7 +49,14 @@ GNUNET_SQ_bind (sqlite3_stmt *stmt,
                        "sq",
                        _("Failure to bind %u-th SQL parameter\n"),
                        i);
-      return GNUNET_SYSERR;
+      if (SQLITE_OK !=
+          sqlite3_reset (stmt))
+      {
+        GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+                         "sq",
+                         _("Failure in sqlite3_reset (!)\n"));
+        return GNUNET_SYSERR;
+      }
     }
     GNUNET_assert (0 != params[i].num_params);
     j += params[i].num_params;
@@ -83,7 +90,12 @@ GNUNET_SQ_extract_result (sqlite3_stmt *result,
                     j,
                     rs[i].result_size,
                     rs[i].dst))
+    {
+      for (unsigned int k=0;k<i;k++)
+        if (NULL != rs[k].cleaner)
+          rs[k].cleaner (rs[k].cls);
       return GNUNET_SYSERR;
+    }
     GNUNET_assert (0 != rs[i].num_params);
     j += rs[i].num_params;
   }
@@ -105,4 +117,24 @@ GNUNET_SQ_cleanup_result (struct GNUNET_SQ_ResultSpec *rs)
       rs[i].cleaner (rs[i].cls);
 }
 
+
+/**
+ * Reset @a stmt and log error.
+ *
+ * @param dbh database handle
+ * @param stmt statement to reset
+ */
+void
+GNUNET_SQ_reset (sqlite3 *dbh,
+                 sqlite3_stmt *stmt)
+{
+  if (SQLITE_OK !=
+      sqlite3_reset (stmt))
+    GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                     "sqlite",
+                     _("Failed to reset sqlite statement with error: %s\n"),
+                     sqlite3_errmsg (dbh));
+}
+
+
 /* end of sq.c */
index 5529c5e6c2cae131f810c1451d023dfd3cd2920c..94a3a3f1c868ae8d169f0f9f1ca4507e7e5ff5c9 100644 (file)
@@ -90,6 +90,14 @@ bind_string (void *cls,
              sqlite3_stmt *stmt,
              unsigned int off)
 {
+  if (NULL == data)
+  {
+    if (SQLITE_OK !=
+        sqlite3_bind_null (stmt,
+                           (int) off))
+      return GNUNET_SYSERR;
+    return GNUNET_OK;
+  }
   if (SQLITE_OK !=
       sqlite3_bind_text (stmt,
                          (int) off,
@@ -234,6 +242,40 @@ GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x)
 }
 
 
+/**
+ * Function called to convert input argument into SQL parameters.
+ *
+ * @param cls closure
+ * @param data pointer to input argument
+ * @param data_len number of bytes in @a data (if applicable)
+ * @param stmt sqlite statement to bind parameters for
+ * @param off offset of the argument to bind in @a stmt, numbered from 1,
+ *            so immediately suitable for passing to `sqlite3_bind`-functions.
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+static int
+bind_abstime (void *cls,
+              const void *data,
+              size_t data_len,
+              sqlite3_stmt *stmt,
+              unsigned int off)
+{
+  const struct GNUNET_TIME_Absolute *u = data;
+  struct GNUNET_TIME_Absolute abs;
+
+  abs = *u;
+  if (abs.abs_value_us > INT64_MAX)
+    abs.abs_value_us = INT64_MAX;
+  GNUNET_assert (sizeof (uint64_t) == data_len);
+  if (SQLITE_OK !=
+      sqlite3_bind_int64 (stmt,
+                          (int) off,
+                          (sqlite3_int64) abs.abs_value_us))
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
+
+
 /**
  * Generate query parameter for an absolute time value.
  * The database must store a 64-bit integer.
@@ -243,7 +285,13 @@ GNUNET_SQ_query_param_rsa_signature (const struct GNUNET_CRYPTO_RsaSignature *x)
 struct GNUNET_SQ_QueryParam
 GNUNET_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x)
 {
-  return GNUNET_SQ_query_param_uint64 (&x->abs_value_us);
+ struct GNUNET_SQ_QueryParam qp = {
+    .conv = &bind_abstime,
+    .data = x,
+    .size = sizeof (struct GNUNET_TIME_Absolute),
+    .num_params = 1
+  };
+  return qp;
 }
 
 
@@ -269,6 +317,8 @@ bind_nbotime (void *cls,
   struct GNUNET_TIME_Absolute abs;
 
   abs = GNUNET_TIME_absolute_ntoh (*u);
+  if (abs.abs_value_us > INT64_MAX)
+    abs.abs_value_us = INT64_MAX;
   GNUNET_assert (sizeof (uint64_t) == data_len);
   if (SQLITE_OK !=
       sqlite3_bind_int64 (stmt,
index eaf606aa4436dc2a1f8afc38a8edd3bc31ce2674..9579863b2326bc1c7dc9f603138654830e5ab44e 100644 (file)
@@ -46,6 +46,15 @@ extract_var_blob (void *cls,
   const void *ret;
   void **rdst = (void **) dst;
 
+  if (SQLITE_NULL ==
+      sqlite3_column_type (result,
+                           column))
+  {
+    *rdst = NULL;
+    *dst_size = 0;
+    return GNUNET_YES;
+  }
+
   if (SQLITE_BLOB !=
       sqlite3_column_type (result,
                            column))
@@ -142,6 +151,14 @@ extract_fixed_blob (void *cls,
   int have;
   const void *ret;
 
+  if ( (0 == *dst_size) &&
+       (SQLITE_NULL ==
+        sqlite3_column_type (result,
+                             column)) )
+  {
+    return GNUNET_YES;
+  }
+
   if (SQLITE_BLOB !=
       sqlite3_column_type (result,
                            column))
@@ -211,6 +228,13 @@ extract_utf8_string (void *cls,
   const char *text;
   char **rdst = dst;
 
+  if (SQLITE_NULL ==
+      sqlite3_column_type (result,
+                           column))
+  {
+    *rdst = NULL;
+    return GNUNET_OK;
+  }
   if (SQLITE_TEXT !=
       sqlite3_column_type (result,
                            column))
@@ -458,6 +482,45 @@ GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig)
 }
 
 
+/**
+ * Extract absolute time value from a Postgres database @a result at row @a row.
+ *
+ * @param cls closure
+ * @param result where to extract data from
+ * @param column column to extract data from
+ * @param[in,out] dst_size where to store size of result, may be NULL
+ * @param[out] dst where to store the result
+ * @return
+ *   #GNUNET_YES if all results could be extracted
+ *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
+static int
+extract_abs_time (void *cls,
+                  sqlite3_stmt *result,
+                  unsigned int column,
+                  size_t *dst_size,
+                  void *dst)
+{
+  struct GNUNET_TIME_Absolute *u = dst;
+  struct GNUNET_TIME_Absolute t;
+
+  GNUNET_assert (sizeof (uint64_t) == *dst_size);
+  if (SQLITE_INTEGER !=
+      sqlite3_column_type (result,
+                           column))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  t.abs_value_us = (uint64_t) sqlite3_column_int64 (result,
+                                                    column);
+  if (INT64_MAX == t.abs_value_us)
+    t = GNUNET_TIME_UNIT_FOREVER_ABS;
+  *u = t;
+  return GNUNET_OK;
+}
+
+
 /**
  * Absolute time expected.
  *
@@ -467,7 +530,14 @@ GNUNET_SQ_result_spec_rsa_signature (struct GNUNET_CRYPTO_RsaSignature **sig)
 struct GNUNET_SQ_ResultSpec
 GNUNET_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at)
 {
-  return GNUNET_SQ_result_spec_uint64 (&at->abs_value_us);
+  struct GNUNET_SQ_ResultSpec rs = {
+    .conv = &extract_abs_time,
+    .dst = at,
+    .dst_size = sizeof (struct GNUNET_TIME_Absolute),
+    .num_params = 1
+  };
+
+  return rs;
 }
 
 
@@ -503,6 +573,8 @@ extract_abs_time_nbo (void *cls,
   }
   t.abs_value_us = (uint64_t) sqlite3_column_int64 (result,
                                                     column);
+  if (INT64_MAX == t.abs_value_us)
+    t = GNUNET_TIME_UNIT_FOREVER_ABS;
   *u = GNUNET_TIME_absolute_hton (t);
   return GNUNET_OK;
 }
index e6896861ea7cd6e135c867c24eeaf8f6fd1ad310..71380903052e1fb9d2aa16a6b81c9b23b939a99d 100644 (file)
@@ -253,8 +253,12 @@ main(int argc,
   {
     fprintf (stderr,
             "Failed to create table\n");
-    sqlite3_close (dbh);
-    unlink ("test.db");
+    GNUNET_break (SQLITE_OK ==
+                  sqlite3_close (dbh));
+    if (0 != unlink ("test.db"))
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                                "unlink",
+                                "test.db");
     return 1;
   }
 
@@ -266,12 +270,14 @@ main(int argc,
   {
     fprintf (stderr,
             "Failed to drop table\n");
-    sqlite3_close (dbh);
-    unlink ("test.db");
-    return 1;
+    ret = 1;
   }
-  sqlite3_close (dbh);
-  unlink ("test.db");
+  GNUNET_break (SQLITE_OK ==
+                sqlite3_close (dbh));
+  if (0 != unlink ("test.db"))
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                              "unlink",
+                              "test.db");
   return ret;
 }
 
index 161327421e7697180f2b851f8788fdbc4f4e4236..0cb136b99790a48f2183c8034707d54c509721d3 100644 (file)
@@ -359,7 +359,7 @@ transmit (struct ClientEntry *ce,
 
   size = strlen (e->subsystem->service) + 1 +
     strlen (e->name) + 1;
-  GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+  GNUNET_assert (size < GNUNET_MAX_MESSAGE_SIZE);
   env = GNUNET_MQ_msg_extra (m,
                             size,
                             GNUNET_MESSAGE_TYPE_STATISTICS_VALUE);
@@ -776,7 +776,7 @@ check_watch (void *cls,
   size_t size;
   const char *service;
   const char *name;
-  
+
   size = ntohs (message->size) - sizeof (struct GNUNET_MessageHeader);
   if (size !=
       GNUNET_STRINGS_buffer_tokenize ((const char *) &message[1],
@@ -870,7 +870,7 @@ handle_watch (void *cls,
 
 /**
  * Handle DISCONNECT-message.  Sync to disk and send
- * back a #GNUNET_MESSAGE_TYPE_STATISTICS_DISCONNECT_CONFIRM 
+ * back a #GNUNET_MESSAGE_TYPE_STATISTICS_DISCONNECT_CONFIRM
  * message.
  *
  * @param cls the `struct ClientEntry *`
@@ -984,6 +984,7 @@ client_disconnect_cb (void *cls,
       }
     }
   }
+  GNUNET_free (ce);
   if ( (0 == client_count) &&
        (GNUNET_YES == in_shutdown) )
     do_shutdown ();
@@ -992,7 +993,7 @@ client_disconnect_cb (void *cls,
 
 /**
  * We've read a `struct GNUNET_STATISTICS_SetMessage *` from
- * disk. Check that it is well-formed, and if so pass it to 
+ * disk. Check that it is well-formed, and if so pass it to
  * the handler for set messages.
  *
  * @param cls NULL
index ed0c3f27dac22c6d91813bb0758bb31f6a467631..6cfc5617183e86dcba165fdfe8a16b5e7291fb72 100644 (file)
@@ -378,28 +378,44 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'n', "name", "NAME",
-     gettext_noop ("limit output to statistics for the given NAME"), 1,
-     &GNUNET_GETOPT_set_string, &name},
-    {'p', "persistent", NULL,
-     gettext_noop ("make the value being set persistent"), 0,
-     &GNUNET_GETOPT_set_one, &persistent},
-    {'s', "subsystem", "SUBSYSTEM",
-     gettext_noop ("limit output to the given SUBSYSTEM"), 1,
-     &GNUNET_GETOPT_set_string, &subsystem},
-    {'q', "quiet", NULL,
-     gettext_noop ("just print the statistics value"), 0,
-     &GNUNET_GETOPT_set_one, &quiet},
-    {'w', "watch", NULL,
-     gettext_noop ("watch value continuously"), 0,
-     &GNUNET_GETOPT_set_one, &watch},
-     {'r', "remote", NULL,
-      gettext_noop ("connect to remote host"), 1,
-      &GNUNET_GETOPT_set_string, &remote_host},
-    {'o', "port", NULL,
-     gettext_noop ("port for remote host"), 1,
-     &GNUNET_GETOPT_set_uint, &remote_port},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_STRING ('n',
+                                 "name",
+                                 "NAME",
+                                 gettext_noop ("limit output to statistics for the given NAME"),
+                                 &name),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('p',
+                                  "persistent",
+                                  gettext_noop ("make the value being set persistent"),
+                                  &persistent),
+
+    GNUNET_GETOPT_OPTION_STRING ('s',
+                                 "subsystem",
+                                 "SUBSYSTEM",
+                                 gettext_noop ("limit output to the given SUBSYSTEM"),
+                                 &subsystem),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('q',
+                                  "quiet",
+                                  gettext_noop ("just print the statistics value"),
+                                  &quiet),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('w',
+                                  "watch",
+                                  gettext_noop ("watch value continuously"),
+                                  &watch),
+
+    GNUNET_GETOPT_OPTION_STRING ('r',
+                                 "remote",
+                                 "REMOTE",
+                                 gettext_noop ("connect to remote host"),
+                                 &remote_host),
+    GNUNET_GETOPT_OPTION_SET_ULONG ('o',
+                                    "port",
+                                    "PORT",
+                                    gettext_noop ("port for remote host"),
+                                    &remote_port),
     GNUNET_GETOPT_OPTION_END
   };
   remote_port = 0;
index ad4453b2a62a0e8515317e0d972bdd1c740aabab..9d04e854faeac3fc696066b3718df8219b851d49 100644 (file)
@@ -349,7 +349,7 @@ schedule_watch_request (struct GNUNET_STATISTICS_Handle *h,
   slen = strlen (watch->subsystem) + 1;
   nlen = strlen (watch->name) + 1;
   nsize = sizeof (struct GNUNET_MessageHeader) + slen + nlen;
-  if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (nsize >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
@@ -1098,7 +1098,7 @@ GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle,
   slen1 = strlen (subsystem) + 1;
   slen2 = strlen (name) + 1;
   GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) <
-                 GNUNET_SERVER_MAX_MESSAGE_SIZE);
+                 GNUNET_MAX_MESSAGE_SIZE);
   ai = GNUNET_new (struct GNUNET_STATISTICS_GetHandle);
   ai->sh = handle;
   ai->subsystem = GNUNET_strdup (subsystem);
@@ -1246,7 +1246,7 @@ add_setter_action (struct GNUNET_STATISTICS_Handle *h,
   slen = strlen (h->subsystem) + 1;
   nlen = strlen (name) + 1;
   nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen;
-  if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (nsize >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
index 1c250b306eaeb7a15cea403b7ecdd12a95ac4fc5..f915e70af439e7994a8bc4b92e4746b8b313b215 100644 (file)
 #define LOG_DEBUG(...)                          \
   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
 
-/**
- * The message queue for sending messages to clients
- */
-struct MessageQueue
-{
-  /**
-   * The message to be sent
-   */
-  struct GNUNET_MessageHeader *msg;
-
-  /**
-   * The client to send the message to
-   */
-  struct GNUNET_SERVER_Client *client;
-
-  /**
-   * next pointer for DLL
-   */
-  struct MessageQueue *next;
-
-  /**
-   * prev pointer for DLL
-   */
-  struct MessageQueue *prev;
-};
-
-/**
- * The message queue head
- */
-static struct MessageQueue *mq_head;
-
-/**
- * The message queue tail
- */
-static struct MessageQueue *mq_tail;
-
 /**
  * Handle for buffered writing.
  */
@@ -92,23 +56,38 @@ static int in_shutdown;
 
 
 /**
- * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
+ * Check #GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG messages
  *
- * @param cls NULL
- * @param client identification of the client
+ * @param cls client identification of the client
+ * @param msg the actual message
+ * @return #GNUNET_OK (they are all always OK)
+ */
+static int
+check_log_msg (void *cls,
+               const struct GNUNET_MessageHeader *msg)
+{
+  return GNUNET_OK;
+}
+
+
+/**
+ * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG messages
+ *
+ * @param cls client identification of the client
  * @param msg the actual message
  */
 static void
 handle_log_msg (void *cls,
-               struct GNUNET_SERVER_Client *client,
                 const struct GNUNET_MessageHeader *msg)
 {
+  struct GNUNET_SERVICE_Client *client = cls;
   uint16_t ms;
 
-  ms = ntohs (msg->size);
-  ms -= sizeof (struct GNUNET_MessageHeader);
-  GNUNET_BIO_write (bio, &msg[1], ms);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  ms = ntohs (msg->size) - sizeof (struct GNUNET_MessageHeader);
+  GNUNET_BIO_write (bio,
+                    &msg[1],
+                    ms);
+  GNUNET_SERVICE_client_continue (client);
 }
 
 
@@ -120,69 +99,55 @@ handle_log_msg (void *cls,
 static void
 shutdown_task (void *cls)
 {
-  struct MessageQueue *mq_entry;
-
   in_shutdown = GNUNET_YES;
   if (0 != nconn)
   {
     /* Delay shutdown if there are active connections */
-    GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
+    GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                   NULL);
     return;
   }
-  while (NULL != (mq_entry = mq_head))
-  {
-    GNUNET_free (mq_entry->msg);
-    GNUNET_SERVER_client_drop (mq_entry->client);
-    GNUNET_CONTAINER_DLL_remove (mq_head,
-                                mq_tail,
-                                mq_entry);
-    GNUNET_free (mq_entry);
-  }
-  GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (bio));
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_BIO_write_close (bio));
 }
 
 
 /**
-x * Functions with this signature are called whenever a client
- * is disconnected on the network level.
+ * Callback called when a client connects to the service.
  *
- * @param cls closure
- * @param client identification of the client; NULL
- *        for the last call when the server is destroyed
+ * @param cls closure for the service
+ * @param c the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return @a c
  */
-static void
-client_disconnected (void *cls,
-                    struct GNUNET_SERVER_Client *client)
+static void *
+client_connect_cb (void *cls,
+                  struct GNUNET_SERVICE_Client *c,
+                  struct GNUNET_MQ_Handle *mq)
 {
-  if (NULL == client)
-  {
-    GNUNET_break (0 == nconn);
-    return;
-  }
-  nconn--;
-  if (GNUNET_YES == in_shutdown)
-    GNUNET_SCHEDULER_shutdown ();
+  /* FIXME: is this really what we want here? */
+  GNUNET_SERVICE_client_persist (c);
+  nconn++;
+  return c;
 }
 
 
 /**
- * Functions with this signature are called whenever a client
- * is connected on the network level.
+ * Callback called when a client disconnected from the service
  *
- * @param cls closure
- * @param client identification of the client
+ * @param cls closure for the service
+ * @param c the client that disconnected
+ * @param internal_cls should be equal to @a c
  */
 static void
-client_connected (void *cls,
-                 struct GNUNET_SERVER_Client *client)
+client_disconnect_cb (void *cls,
+                     struct GNUNET_SERVICE_Client *c,
+                     void *internal_cls)
 {
-  if (NULL == client)
-  {
-    GNUNET_break (0 == nconn);
-    return;
-  }
-  GNUNET_SERVER_client_persist_ (client);
-  nconn++;
+  nconn--;
+  if (GNUNET_YES == in_shutdown)
+    GNUNET_SCHEDULER_shutdown ();
+  GNUNET_assert (c == internal_cls);
 }
 
 
@@ -190,18 +155,14 @@ client_connected (void *cls,
  * Testbed setup
  *
  * @param cls closure
- * @param server the initialized server
  * @param cfg configuration to use
+ * @param service the initialized service
  */
 static void
 logger_run (void *cls,
-           struct GNUNET_SERVER_Handle *server,
-           const struct GNUNET_CONFIGURATION_Handle *cfg)
+           const struct GNUNET_CONFIGURATION_Handle *cfg,
+            struct GNUNET_SERVICE_Handle *service)
 {
-  static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
-    {&handle_log_msg, NULL, GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG, 0},
-    {NULL, NULL, 0, 0}
-  };
   char *dir;
   char *fn;
   char *hname;
@@ -223,7 +184,8 @@ logger_run (void *cls,
   pid = getpid ();
   hname_len = GNUNET_OS_get_hostname_max_length ();
   hname = GNUNET_malloc (hname_len);
-  if (0 != gethostname (hname, hname_len))
+  if (0 != gethostname (hname,
+                        hname_len))
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
         "Cannot get hostname.  Exiting\n");
@@ -247,24 +209,27 @@ logger_run (void *cls,
     return;
   }
   GNUNET_free (fn);
-  GNUNET_SERVER_add_handlers (server, message_handlers);
-  GNUNET_SERVER_connect_notify (server, &client_connected, NULL);
-  GNUNET_SERVER_disconnect_notify (server, &client_disconnected, NULL);
-  GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                 NULL);
   LOG_DEBUG ("TESTBED-LOGGER startup complete\n");
 }
 
 
 /**
- * The starting point of execution
+ * Define "main" method using service macro.
  */
-int
-main (int argc, char *const *argv)
-{
-  return (GNUNET_OK ==
-          GNUNET_SERVICE_run (argc, argv, "testbed-logger",
-                              GNUNET_SERVICE_OPTION_NONE,
-                              &logger_run, NULL)) ? 0 : 1;
-}
+GNUNET_SERVICE_MAIN
+("testbed-logger",
+ GNUNET_SERVICE_OPTION_NONE,
+ &logger_run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_var_size (log_msg,
+                        GNUNET_MESSAGE_TYPE_TESTBED_LOGGER_MSG,
+                        struct GNUNET_MessageHeader,
+                        NULL),
+ GNUNET_MQ_handler_end ());
+
 
 /* end of gnunet-service-testbed-logger.c */
index 0ebe0c3f42dbde102118a8c7a5a4686069b9d80d..e627feeb4f3216d7cfca70f3df9babef814554dd 100644 (file)
@@ -258,11 +258,15 @@ main (int argc, char **argv)
   GNUNET_log_setup ("test-testbed-logger-api",
                     "WARNING",
                     NULL);
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_DISK_directory_remove ("/tmp/test-testbed"));
   ret = GNUNET_TESTING_service_run ("test-testbed-logger",
                                     "testbed-logger",
                                     "test_testbed_logger_api.conf",
                                     &test_main,
                                     NULL);
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_DISK_directory_remove ("/tmp/test-testbed"));
   if (0 != ret)
     return 1;
   if (GNUNET_OK != result)
index 25494aed059e13794c5fbcca6b747bfb5bc0419b..7aa4ade3527a339571ebcb7027693cfd74b9245f 100644 (file)
@@ -39,7 +39,7 @@
 /**
  * The size of the buffer we fill before sending out the message
  */
-#define BUFFER_SIZE (GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))
+#define BUFFER_SIZE (GNUNET_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_MessageHeader))
 
 /**
  * Connection handle for the logger service
index 94c9082950f9b49bf1bcaec28f2fb5d2dc11c28f..61cfba2ff8a7c6b675a70afa0fe72f5d331e1d40 100644 (file)
@@ -104,13 +104,13 @@ libgnunettestbed_la_SOURCES = \
   testbed_api_test.c \
   testbed_api_topology.c testbed_api_topology.h \
   testbed_api_sd.c testbed_api_sd.h \
-  testbed_api_barriers.c 
+  testbed_api_barriers.c
 libgnunettestbed_la_LIBADD = $(XLIB) \
  $(top_builddir)/src/core/libgnunetcore.la \
  $(top_builddir)/src/statistics/libgnunetstatistics.la \
  $(top_builddir)/src/transport/libgnunettransport.la \
  $(top_builddir)/src/hello/libgnunethello.la \
- -lm \
+ -lm $(Z_LIBS) \
  $(top_builddir)/src/util/libgnunetutil.la \
  $(top_builddir)/src/testing/libgnunettesting.la \
  $(LTLIBINTL)
index 36580a2a38c9f00005e313dc34a6a566ddeb4380..ab7d81c8bfaa7a2e18912d0ce48271937271f7d0 100644 (file)
@@ -70,7 +70,7 @@ enum GNUNET_TESTBED_TopologyOption topology;
 /**
  * The number of peers to include in the topology
  */
-static int num_peers;
+static unsigned int num_peers;
 
 /**
  * program result
@@ -335,11 +335,15 @@ int
 main (int argc, char *const argv[])
 {
   struct GNUNET_GETOPT_CommandLineOption option[] = {
-    {'p', "num-peers", "COUNT",
-     gettext_noop ("create COUNT number of peers"),
-     GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers},
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('p',
+                                   "num-peers",
+                                   "COUNT",
+                                   gettext_noop ("create COUNT number of peers"),
+                                   &num_peers),
     GNUNET_GETOPT_OPTION_END
   };
+
   int ret;
 
   exit_result = GNUNET_SYSERR;
index 6368fb74b3aa3e4b457174dced5c0c176cc543ee..d2a3a98b7a1f5ca39780c8baabe2c3b16457184b 100644 (file)
@@ -495,7 +495,7 @@ error:
 static void
 read_task (void *cls)
 {
-  char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
+  char buf[GNUNET_MAX_MESSAGE_SIZE];
   ssize_t sread;
 
   read_task_id = NULL;
index a201d22bb5b81eb25d5ff12988ca8b590c62d0de..681ed6df2906214ad1bfd03bff6e2974a5525ff7 100644 (file)
@@ -478,7 +478,7 @@ GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg)
   LOG_DEBUG ("Launching testbed-barrier service\n");
   barrier_map = GNUNET_CONTAINER_multihashmap_create (3,
                                                       GNUNET_YES);
-  ctx = GNUNET_SERVICE_starT ("testbed-barrier",
+  ctx = GNUNET_SERVICE_start ("testbed-barrier",
                               cfg,
                               &connect_cb,
                               &disconnect_cb,
@@ -524,7 +524,7 @@ GST_barriers_destroy ()
                                                         NULL));
   GNUNET_CONTAINER_multihashmap_destroy (barrier_map);
   GNUNET_assert (NULL != ctx);
-  GNUNET_SERVICE_stoP (ctx);
+  GNUNET_SERVICE_stop (ctx);
 }
 
 
index b775f31bd9174befcc41620ca4a182138d165161..09849797c04c617e3c9271308089c81db5044da7 100644 (file)
@@ -371,7 +371,7 @@ GST_cleanup_focc (struct ForwardedOverlayConnectContext *focc)
 /**
  * Timeout task for cancelling a forwarded overlay connect connect
  *
- * @param cls the ForwardedOverlayConnectContext
+ * @param cls the `struct ForwardedOperationContext`
  */
 static void
 forwarded_overlay_connect_timeout (void *cls)
index a977b2b9b5f222c151e2aab20e325b8631bbbfab..aacd6258324b6583f4bf5d541f5b8f11206ec8b8 100644 (file)
@@ -1137,14 +1137,8 @@ arm_req_string (enum GNUNET_ARM_RequestStatus rs)
   {
   case GNUNET_ARM_REQUEST_SENT_OK:
     return _("Message was sent successfully");
-  case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
-    return _("Misconfiguration (can't connect to the ARM service)");
   case GNUNET_ARM_REQUEST_DISCONNECTED:
     return _("We disconnected from ARM before we could send a request");
-  case GNUNET_ARM_REQUEST_BUSY:
-    return _("ARM API is busy");
-  case GNUNET_ARM_REQUEST_TIMEOUT:
-    return _("Request timed out");
   }
   return _("Unknown request status");
 }
index 9468b3c91e4f1e75bf4502e3c0b798aa2801d7d0..29f77193d3e06f130532154158fff2bd2e1f95ce 100644 (file)
@@ -276,23 +276,34 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'p', "num-peers", "COUNT",
-     gettext_noop ("create COUNT number of peers"),
-     GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers},
-    {'e', "num-errors", "COUNT",
-     gettext_noop ("tolerate COUNT number of continious timeout failures"),
-     GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_cont_fails},
-    {'n', "non-interactive", NULL,
-     gettext_noop ("run profiler in non-interactive mode where upon "
-                   "testbed setup the profiler does not wait for a "
-                   "keystroke but continues to run until a termination "
-                   "signal is received"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &noninteractive},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('p',
+                                   "num-peers",
+                                   "COUNT",
+                                   gettext_noop ("create COUNT number of peers"),
+                                   &num_peers),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('e',
+                                   "num-errors",
+                                   "COUNT",
+                                   gettext_noop ("tolerate COUNT number of continious timeout failures"),
+                                   &num_cont_fails),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "non-interactive",
+                                  gettext_noop ("run profiler in non-interactive mode where upon "
+                                                "testbed setup the profiler does not wait for a "
+                                                "keystroke but continues to run until a termination "
+                                                "signal is received"),
+                                  &noninteractive),
+
 #if !ENABLE_SUPERMUC
-    {'H', "hosts", "FILENAME",
-     gettext_noop ("name of the file with the login information for the testbed"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &hosts_file},
+    GNUNET_GETOPT_OPTION_STRING ('H',
+                                 "hosts",
+                                 "FILENAME",
+                                 gettext_noop ("name of the file with the login information for the testbed"),
+                                 &hosts_file),
 #endif
     GNUNET_GETOPT_OPTION_END
   };
index 7a2dce8a51a3d4ac79f73d96b2c9d434969a4224..7ba9e7c31346969d912b3c6e271b0f27808bde31 100644 (file)
@@ -121,10 +121,12 @@ do_abort (void *cls)
  *               #GNUNET_SYSERR during GNUNET_HELPER_stop()
  */
 static void
-cont_cb (void *cls, int result)
+cont_cb (void *cls,
+         int result)
 {
   shandle = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Message sent\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Message sent\n");
   GNUNET_assert (GNUNET_OK == result);
 }
 
@@ -138,11 +140,11 @@ cont_cb (void *cls, int result)
  * @param cls closure
  * @param client identification of the client
  * @param message the actual message
- *
  * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
  */
 static int
-mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message)
+mst_cb (void *cls,
+        const struct GNUNET_MessageHeader *message)
 {
   const struct GNUNET_TESTBED_HelperReply *msg;
   char *config;
@@ -207,8 +209,12 @@ run (void *cls, char *const *args, const char *cfgfile,
   const char *trusted_ip = "127.0.0.1";
 
   helper =
-      GNUNET_HELPER_start (GNUNET_YES, "gnunet-helper-testbed", binary_argv,
-                           &mst_cb, &exp_cb, NULL);
+      GNUNET_HELPER_start (GNUNET_YES,
+                           "gnunet-helper-testbed",
+                           binary_argv,
+                           &mst_cb,
+                           &exp_cb,
+                           NULL);
   GNUNET_assert (NULL != helper);
   cfg = GNUNET_CONFIGURATION_dup (cfg2);
   msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, NULL, cfg);
index 731944bc4818f6da21c5c17682175422123572e5..5d2c1cc3773c3ef80daeed2bda7e049791a2c81d 100644 (file)
@@ -952,10 +952,11 @@ gen_rsh_suffix_args (const char * const *append_args)
  * @param client identification of the client
  * @param message the actual message
  *
- * @return GNUNET_OK on success, GNUNET_SYSERR to stop further processing
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
  */
 static int
-helper_mst (void *cls, void *client, const struct GNUNET_MessageHeader *message)
+helper_mst (void *cls,
+            const struct GNUNET_MessageHeader *message)
 {
   struct GNUNET_TESTBED_ControllerProc *cp = cls;
   const struct GNUNET_TESTBED_HelperReply *msg;
index 2af62b44ad006f748b5c82e410f37d53e4380a1e..871e554a944a27e2346d618b1a1b581b9c32ea3f 100644 (file)
@@ -969,7 +969,7 @@ GNUNET_TESTBED_peer_manage_service (void *op_cls,
   GNUNET_assert (TESTBED_PS_STARTED == peer->state); /* peer is not running? */
   msize = strlen (service_name) + 1;
   msize += sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage);
-  if (GNUNET_SERVER_MAX_MESSAGE_SIZE < msize)
+  if (GNUNET_MAX_MESSAGE_SIZE < msize)
     return NULL;
   data = GNUNET_new (struct ManageServiceData);
   data->cb = cb;
index a21a7cf53a37ef94cbbc820da5da1bce7318bb9e..7bc36d1b4798a29c6b0e5170b1334f86542c8d82 100644 (file)
@@ -1147,9 +1147,11 @@ gen_topo_from_file (struct TopologyContext *tc,
              other_peer_id);
       while (('\n' != data[offset]) && ('|' != data[offset]) && (offset < fs))
         offset++;
-      if ('\n' == data[offset])
+      if ( (offset < fs) &&
+           ('\n' == data[offset]) )
         state = PEER_INDEX;
-      else if ('|' == data[offset])
+      else if ( (offset < fs) &&
+                ('|' == data[offset]) )
       {
         state = OTHER_PEER_INDEX;
         offset++;
@@ -1491,7 +1493,7 @@ GNUNET_TESTBED_topology_get_ (enum GNUNET_TESTBED_TopologyOption *topology,
     {
       if (NULL != topology)
         *topology = (enum GNUNET_TESTBED_TopologyOption) cnt;
-      GNUNET_assert (GNUNET_TESTBED_TOPOLOGY_OPTION_END != *topology);
+      GNUNET_assert (GNUNET_TESTBED_TOPOLOGY_OPTION_END != (enum GNUNET_TESTBED_TopologyOption) cnt);
       return GNUNET_YES;
     }
   }
index 07f1560cb9bcf0c164f93f5f4acee5da7dbd7eb0..686b38192b1268dd777ab0215141e324d19964f1 100644 (file)
@@ -348,17 +348,35 @@ run_no_scheduler (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'C', "cfg", NULL, gettext_noop ("create unique configuration files"),
-     GNUNET_NO, &GNUNET_GETOPT_set_one, &create_cfg},
-    {'k', "key", "FILENAME", gettext_noop ("extract hostkey file from pre-computed hostkey list"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &create_hostkey},
-    {'n', "number", "NUMBER", gettext_noop ("number of unique configuration files to create, or number of the hostkey to extract"),
-     GNUNET_YES, &GNUNET_GETOPT_set_uint, &create_no},
-    {'t', "template", "FILENAME", gettext_noop ("configuration template"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &create_cfg_template},
-    {'r', "run", "SERVICE", gettext_noop ("run the given service, wait on stdin for 'r' (restart) or 'q' (quit)"),
-     GNUNET_YES, &GNUNET_GETOPT_set_string, &run_service_name},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('C',
+                                  "cfg",
+                                  gettext_noop ("create unique configuration files"),
+                                  &create_cfg),
+    GNUNET_GETOPT_OPTION_STRING ('k',
+                                 "key",
+                                 "FILENAME",
+                                 gettext_noop ("extract hostkey file from pre-computed hostkey list"),
+                                 &create_hostkey),
+
+    GNUNET_GETOPT_OPTION_SET_UINT ('n',
+                                   "number",
+                                   "NUMBER",
+                                   gettext_noop ("number of unique configuration files to create, or number of the hostkey to extract"),
+                                   &create_no),
+
+
+    GNUNET_GETOPT_OPTION_STRING ('t',
+                                 "template",
+                                 "FILENAME",
+                                 gettext_noop ("configuration template"),
+                                 &create_cfg_template),
+
+    GNUNET_GETOPT_OPTION_STRING ('r',
+                                 "run",
+                                 "SERVICE",
+                                 gettext_noop ("run the given service, wait on stdin for 'r' (restart) or 'q' (quit)"),
+                                 &run_service_name),
     GNUNET_GETOPT_OPTION_END
   };
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
index 1fd46ebf205b756db4a946ddff1e766779b5802c..cfb49460aeed2d8d176b54575f07d8674c7726b2 100644 (file)
@@ -6,10 +6,6 @@ static unsigned int nkeys;
 static unsigned int nskip;
 static int result;
 
-
-
-
-
 /**
  * Main run function.
  *
@@ -87,12 +83,11 @@ run (void *cls, char *const *args, const char *cfgfile,
 int main (int argc, char *argv[])
 {
   struct GNUNET_GETOPT_CommandLineOption option[] = {
-    {'n', "num-keys", "COUNT",
-     gettext_noop ("list COUNT number of keys"),
-     GNUNET_YES, &GNUNET_GETOPT_set_uint, &nkeys},
-    {'s', "skip", "COUNT",
-     gettext_noop ("skip COUNT number of keys in the beginning"),
-     GNUNET_YES, &GNUNET_GETOPT_set_uint, &nskip},
+    GNUNET_GETOPT_OPTION_SET_UINT ('n',
+                                   "num-keys",
+                                   "COUNT",
+                                   gettext_noop ("list COUNT number of keys"),
+                                   &nkeys),
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
index bab7976ea6927d1648f1aea3c2232ffbfa80890b..ba7bf827e3ff86aa45093f6a0efd1edef4bf7c7d 100644 (file)
@@ -907,6 +907,7 @@ update_config_sections (void *cls,
       {
         ikeys[key] = ptr;
         ptr = strstr (ptr, ";");
+        GNUNET_assert (NULL != ptr); /* worked just before... */
         *ptr = '\0';
         ptr++;
       }
index 59c70e4b0de5aeb4d35cee08226bcf53c7162777..a960fad174061f7fdca78064e158b430508f9010 100644 (file)
@@ -58,14 +58,20 @@ GNUNET_FRIENDS_parse (const struct GNUNET_CONFIGURATION_Handle *cfg,
     return GNUNET_SYSERR;
   }
   if ( (GNUNET_OK != GNUNET_DISK_file_test (fn)) &&
-       (GNUNET_OK != GNUNET_DISK_fn_write (fn, NULL, 0,
+       (GNUNET_OK != GNUNET_DISK_fn_write (fn,
+                                           NULL,
+                                           0,
                                           GNUNET_DISK_PERM_USER_READ |
-                                          GNUNET_DISK_PERM_USER_WRITE)) )
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "write", fn);
+                                          GNUNET_DISK_PERM_USER_WRITE |
+                                           GNUNET_DISK_OPEN_CREATE)) )
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                              "write",
+                              fn);
   if ( (GNUNET_OK !=
         GNUNET_DISK_file_size (fn,
                                &fsize,
-                               GNUNET_NO, GNUNET_YES)) ||
+                               GNUNET_NO,
+                               GNUNET_YES)) ||
        (0 == fsize) )
   {
     GNUNET_free (fn);
@@ -93,8 +99,8 @@ GNUNET_FRIENDS_parse (const struct GNUNET_CONFIGURATION_Handle *cfg,
       pos++;
     if (GNUNET_OK !=
         GNUNET_CRYPTO_eddsa_public_key_from_string (&data[start],
-                                                      pos - start,
-                                                      &pid.public_key))
+                                                    pos - start,
+                                                    &pid.public_key))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                   _("Syntax error in FRIENDS file at offset %llu, skipping bytes `%.*s'.\n"),
index 067ebce238890b34cbaffd2abb3c3890065bea5c..537ffe059f744f21a9e7dcc81ac29b81d1f6b908 100644 (file)
@@ -499,7 +499,7 @@ schedule_next_hello (void *cls)
   /* find applicable HELLOs */
   fah.peer = pl;
   fah.result = NULL;
-  fah.max_size = GNUNET_SERVER_MAX_MESSAGE_SIZE - 1;
+  fah.max_size = GNUNET_MAX_MESSAGE_SIZE - 1;
   fah.next_adv = GNUNET_TIME_UNIT_FOREVER_REL;
   GNUNET_CONTAINER_multipeermap_iterate (peers,
                                          &find_advertisable_hello,
index acc2557c605b40d8b3554e8d798dc387a9820b29..7687f2348703ed8babe5783d1593eaefb0d4a2ca 100644 (file)
@@ -191,6 +191,8 @@ libexec_PROGRAMS = \
  $(BT_BIN) \
  gnunet-service-transport
 
+
+
 bin_PROGRAMS = \
  gnunet-transport \
  gnunet-transport-certificate-creation
@@ -561,7 +563,7 @@ TESTS = \
  $(HTTP_API_TIMEOUT_TEST) \
  $(HTTPS_API_TIMEOUT_TEST) \
  $(WLAN_TIMEOUT_TEST) \
- $(BT_TIMEOUT_TEST) 
+ $(BT_TIMEOUT_TEST)
 if HAVE_GETOPT_BINARY
 TESTS += \
 test_transport_api_slow_ats
index 684546314044514355c8c708af0396f48068c4bd..63ed9c4b796ad3abf68f9f8268c60831e22b23c9 100644 (file)
@@ -120,11 +120,11 @@ send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac)
  * type to the output forward and copy it to the buffer for stdout.
  *
  * @param cls the 'struct SendBuffer' to copy the converted message to
- * @param client unused
  * @param hdr inbound message from the FIFO
  */
 static int
-stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
+stdin_send (void *cls,
+            const struct GNUNET_MessageHeader *hdr)
 {
   struct SendBuffer *write_pout = cls;
   const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in;
@@ -166,11 +166,11 @@ stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
  * We read a full message from stdin.  Copy it to our send buffer.
  *
  * @param cls the 'struct SendBuffer' to copy to
- * @param client unused
  * @param hdr the message we received to copy to the buffer
  */
 static int
-file_in_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
+file_in_send (void *cls,
+              const struct GNUNET_MessageHeader *hdr)
 {
   struct SendBuffer *write_std = cls;
   uint16_t sendsize;
@@ -213,8 +213,8 @@ main (int argc, char *argv[])
   fd_set wfds;
   struct timeval tv;
   int retval;
-  struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst = NULL;
-  struct GNUNET_SERVER_MessageStreamTokenizer *file_in_mst = NULL;
+  struct GNUNET_MessageStreamTokenizer *stdin_mst = NULL;
+  struct GNUNET_MessageStreamTokenizer *file_in_mst = NULL;
   struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr;
   int first;
 
@@ -340,8 +340,8 @@ main (int argc, char *argv[])
   write_std.pos = 0;
   write_pout.size = 0;
   write_pout.pos = 0;
-  stdin_mst = GNUNET_SERVER_mst_create (&stdin_send, &write_pout);
-  file_in_mst = GNUNET_SERVER_mst_create (&file_in_send, &write_std);
+  stdin_mst = GNUNET_MST_create (&stdin_send, &write_pout);
+  file_in_mst = GNUNET_MST_create (&file_in_send, &write_std);
 
   /* Send 'random' mac address */
   macaddr.mac[0] = 0x13;
@@ -453,8 +453,9 @@ main (int argc, char *argv[])
       }
       else if (0 < readsize)
       {
-        GNUNET_SERVER_mst_receive (stdin_mst, NULL, readbuf, readsize,
-                                   GNUNET_NO, GNUNET_NO);
+        GNUNET_MST_from_buffer (stdin_mst,
+                                readbuf, readsize,
+                                GNUNET_NO, GNUNET_NO);
 
       }
       else
@@ -475,8 +476,9 @@ main (int argc, char *argv[])
       }
       else if (0 < readsize)
       {
-        GNUNET_SERVER_mst_receive (file_in_mst, NULL, readbuf, readsize,
-                                   GNUNET_NO, GNUNET_NO);
+        GNUNET_MST_from_buffer (file_in_mst,
+                                readbuf, readsize,
+                                GNUNET_NO, GNUNET_NO);
       }
       else
       {
@@ -489,9 +491,9 @@ main (int argc, char *argv[])
 end:
   /* clean up */
   if (NULL != stdin_mst)
-    GNUNET_SERVER_mst_destroy (stdin_mst);
+    GNUNET_MST_destroy (stdin_mst);
   if (NULL != file_in_mst)
-    GNUNET_SERVER_mst_destroy (file_in_mst);
+    GNUNET_MST_destroy (file_in_mst);
 
   if (NULL != fpout)
     fclose (fpout);
index 505626b593cf8c7b2be0b7e1c029e8bd5f6434b9..4a6d427becda1b53ff04fcc8dbb93d9b4eb80804 100644 (file)
@@ -599,7 +599,7 @@ transmit_ping_if_allowed (void *cls,
   ping.challenge = htonl (ve->challenge);
   ping.target = *pid;
 
-  if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (tsize >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     hsize = 0;
index 129df7b35b955adecb8903834f688bd6e9cd12ec..edaf4773a57c9bcfa966241c77bea8c3d7b46e4e 100644 (file)
@@ -44,7 +44,7 @@ make_dev_zero (int fd,
   GNUNET_assert (-1 != z);
   if (z == fd)
     return;
-  dup2 (z, fd);
+  GNUNET_break (fd == dup2 (z, fd));
   GNUNET_assert (0 == close (z));
 }
 #endif
index dceff7e3bab7e3d0809f3b4a118ff3c68d800e2f..9292c42d420dd636fddc1124fde7df7fab6ba86c 100644 (file)
@@ -151,7 +151,7 @@ static struct GNUNET_PeerIdentity pid;
 /**
  * Selected level of verbosity.
  */
-static int verbosity;
+static unsigned int verbosity;
 
 
 /**
@@ -520,7 +520,7 @@ run (void *cls,
   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
 
   ret = 1;
-  if (GNUNET_SERVER_MAX_MESSAGE_SIZE <= benchmark_size)
+  if (GNUNET_MAX_MESSAGE_SIZE <= benchmark_size)
   {
     FPRINTF (stderr,
              "Message size too big!\n");
@@ -610,26 +610,36 @@ main (int argc, char * const *argv)
   benchmark_iterations = DEFAULT_ITERATION_COUNT;
   benchmark_running = GNUNET_NO;
 
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-
-    { 's', "send", NULL,
-      gettext_noop ("send data to peer"),
-      0, &GNUNET_GETOPT_set_one, &benchmark_send},
-    { 'r', "receive", NULL, gettext_noop
-      ("receive data from peer"), 0,
-      &GNUNET_GETOPT_set_one, &benchmark_receive},
-    { 'i', "iterations", NULL, gettext_noop
-      ("iterations"), 1,
-      &GNUNET_GETOPT_set_uint, &benchmark_iterations},
-    { 'n', "number", NULL, gettext_noop
-      ("number of messages to send"), 1,
-      &GNUNET_GETOPT_set_uint, &benchmark_count},
-    { 'm', "messagesize", NULL, gettext_noop
-      ("message size to use"), 1,
-      &GNUNET_GETOPT_set_uint, &benchmark_size},
-    { 'p', "peer", "PEER",
-      gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string,
-      &cpid },
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('s',
+                                  "send",
+                                  gettext_noop ("send data to peer"),
+                                  &benchmark_send),
+    GNUNET_GETOPT_OPTION_SET_ONE ('r',
+                                  "receive",
+                                  gettext_noop ("receive data from peer"),
+                                  &benchmark_receive),
+    GNUNET_GETOPT_OPTION_SET_UINT ('i',
+                                   "iterations",
+                                   NULL,
+                                   gettext_noop ("iterations"),
+                                   &benchmark_iterations),
+    GNUNET_GETOPT_OPTION_SET_UINT ('n',
+                                   "number",
+                                   NULL,
+                                   gettext_noop ("number of messages to send"),
+                                   &benchmark_count),
+    GNUNET_GETOPT_OPTION_SET_UINT ('m',
+                                   "messagesize",
+                                   NULL,
+                                   gettext_noop ("message size to use"),
+                                   &benchmark_size),
+    GNUNET_GETOPT_OPTION_STRING ('p',
+                                 "peer",
+                                 "PEER",
+                                 gettext_noop ("peer identity"),
+                                 &cpid),
     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
     GNUNET_GETOPT_OPTION_END
   };
index fcfc94ac8e8b8c50c41f580d8753eafe5452ce40..8624b09b42a2a3b2db06bc9e82322abe6aa955c4 100644 (file)
@@ -166,11 +166,6 @@ struct PeerResolutionContext
  */
 #define BLOCKSIZE 4
 
-/**
- * Which peer should we connect to?
- */
-static char *cpid;
-
 /**
  * Handle to transport service.
  */
@@ -283,7 +278,7 @@ static struct GNUNET_TRANSPORT_PluginMonitor *pm;
 
 /**
  * Identity of the peer we transmit to / connect to.
- * (equivalent to 'cpid' string).
+ * ('-p' command-line option).
  */
 static struct GNUNET_PeerIdentity pid;
 
@@ -295,7 +290,7 @@ static struct GNUNET_SCHEDULER_Task *op_timeout;
 /**
  * Selected level of verbosity.
  */
-static int verbosity;
+static unsigned int verbosity;
 
 /**
  * Resolver process handle.
@@ -485,7 +480,7 @@ operation_timeout (void *cls)
                _("Failed to resolve address for peer `%s'\n"),
                GNUNET_i2s (&cur->addrcp->peer));
 
-      GNUNET_CONTAINER_DLL_remove(rc_head, 
+      GNUNET_CONTAINER_DLL_remove(rc_head,
                                  rc_tail,
                                  cur);
       GNUNET_TRANSPORT_address_to_string_cancel (cur->asc);
@@ -729,7 +724,7 @@ print_info (const struct GNUNET_PeerIdentity *id,
              GNUNET_STRINGS_absolute_time_to_string (state_timeout));
   }
   else if ( (GNUNET_YES == iterate_connections) &&
-           (GNUNET_TRANSPORT_is_connected(state)) ) 
+           (GNUNET_TRANSPORT_is_connected(state)) )
   {
     /* Only connected peers, skip state */
     FPRINTF (stdout,
@@ -1089,10 +1084,9 @@ plugin_monitoring_cb (void *cls,
     }
     return; /* shutdown */
   }
-  if ( (NULL != cpid) &&
-       (0 != memcmp (&info->address->peer,
-                     cpid,
-                     sizeof (struct GNUNET_PeerIdentity))) )
+  if (0 != memcmp (&info->address->peer,
+                   &pid,
+                   sizeof (struct GNUNET_PeerIdentity)))
     return; /* filtered */
   if (NULL == addr)
   {
@@ -1241,21 +1235,11 @@ run (void *cls,
      const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle *mycfg)
 {
+  static struct GNUNET_PeerIdentity zero_pid;
   int counter = 0;
   ret = 1;
 
   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
-  if ( (NULL != cpid) &&
-       (GNUNET_OK !=
-        GNUNET_CRYPTO_eddsa_public_key_from_string (cpid,
-                                                    strlen (cpid),
-                                                    &pid.public_key)))
-  {
-    FPRINTF (stderr,
-             _("Failed to parse peer identity `%s'\n"),
-             cpid);
-    return;
-  }
 
   counter = benchmark_send + benchmark_receive + iterate_connections
       + monitor_connections + monitor_connects + do_disconnect +
@@ -1290,7 +1274,9 @@ run (void *cls,
 
   if (do_disconnect) /* -D: Disconnect from peer */
   {
-    if (NULL == cpid)
+    if (0 == memcmp (&zero_pid,
+                     &pid,
+                     sizeof (pid)))
     {
       FPRINTF (stderr,
                _("Option `%s' makes no sense without option `%s'.\n"),
@@ -1315,7 +1301,9 @@ run (void *cls,
   }
   else if (benchmark_send) /* -s: Benchmark sending */
   {
-    if (NULL == cpid)
+    if (0 == memcmp (&zero_pid,
+                     &pid,
+                     sizeof (pid)))
     {
       FPRINTF (stderr,
               _("Option `%s' makes no sense without option `%s'.\n"),
@@ -1352,7 +1340,7 @@ run (void *cls,
                              NULL),
       GNUNET_MQ_handler_end ()
     };
-    
+
     handle = GNUNET_TRANSPORT_core_connect (cfg,
                                            NULL,
                                            handlers,
@@ -1378,7 +1366,7 @@ run (void *cls,
   else if (iterate_connections) /* -i: List information about peers once */
   {
     pic = GNUNET_TRANSPORT_monitor_peers (cfg,
-                                          (NULL == cpid) ? NULL : &pid,
+                                          &pid,
                                           GNUNET_YES,
                                           &process_peer_iteration_cb,
                                           (void *) cfg);
@@ -1391,7 +1379,7 @@ run (void *cls,
     monitored_peers = GNUNET_CONTAINER_multipeermap_create (10,
                                                            GNUNET_NO);
     pic = GNUNET_TRANSPORT_monitor_peers (cfg,
-                                         (NULL == cpid) ? NULL : &pid,
+                                         &pid,
                                           GNUNET_NO,
                                           &process_peer_monitoring_cb,
                                           NULL);
@@ -1439,37 +1427,49 @@ main (int argc,
       char * const *argv)
 {
   int res;
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    { 'a', "all", NULL,
-      gettext_noop ("print information for all peers (instead of only connected peers)"),
-      0, &GNUNET_GETOPT_set_one, &iterate_all },
-    { 'b', "benchmark", NULL,
-      gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
-      0, &GNUNET_GETOPT_set_one, &benchmark_receive },
-    { 'D', "disconnect",
-      NULL, gettext_noop ("disconnect from a peer"), 0,
-      &GNUNET_GETOPT_set_one, &do_disconnect },
-    { 'i', "information", NULL,
-      gettext_noop ("provide information about all current connections (once)"),
-      0, &GNUNET_GETOPT_set_one, &iterate_connections },
-    { 'm', "monitor", NULL,
-      gettext_noop ("provide information about all current connections (continuously)"),
-      0, &GNUNET_GETOPT_set_one, &monitor_connections },
-    { 'e', "events", NULL,
-      gettext_noop ("provide information about all connects and disconnect events (continuously)"),
-      0, &GNUNET_GETOPT_set_one, &monitor_connects },
-    { 'n', "numeric",
-      NULL, gettext_noop ("do not resolve hostnames"), 0,
-      &GNUNET_GETOPT_set_one, &numeric },
-    { 'p', "peer", "PEER",
-      gettext_noop ("peer identity"), 1, &GNUNET_GETOPT_set_string,
-      &cpid },
-    { 'P', "plugins", NULL,
-      gettext_noop ("monitor plugin sessions"), 0, &GNUNET_GETOPT_set_one,
-      &monitor_plugins },
-    { 's', "send", NULL, gettext_noop
-      ("send data for benchmarking to the other peer (until CTRL-C)"), 0,
-      &GNUNET_GETOPT_set_one, &benchmark_send },
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('a',
+                                  "all",
+                                  gettext_noop ("print information for all peers (instead of only connected peers)"),
+                                  &iterate_all),
+    GNUNET_GETOPT_OPTION_SET_ONE ('b',
+                                  "benchmark",
+                                  gettext_noop ("measure how fast we are receiving data from all peers (until CTRL-C)"),
+                                  &benchmark_receive),
+    GNUNET_GETOPT_OPTION_SET_ONE ('D',
+                                  "disconnect",
+                                  gettext_noop ("disconnect from a peer"),
+                                  &do_disconnect),
+    GNUNET_GETOPT_OPTION_SET_ONE ('i',
+                                  "information",
+                                  gettext_noop ("provide information about all current connections (once)"),
+                                  &iterate_connections),
+    GNUNET_GETOPT_OPTION_SET_ONE ('m',
+                                  "monitor",
+                                  gettext_noop ("provide information about all current connections (continuously)"),
+                                  &monitor_connections),
+    GNUNET_GETOPT_OPTION_SET_ONE ('e',
+                                  "events",
+                                  gettext_noop ("provide information about all connects and disconnect events (continuously)"),
+                                  &monitor_connects),
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "numeric",
+                                  gettext_noop ("do not resolve hostnames"),
+                                  &numeric),
+    GNUNET_GETOPT_OPTION_SET_BASE32_AUTO ('p',
+                                          "peer",
+                                          "PEER",
+                                          gettext_noop ("peer identity"),
+                                          &pid),
+    GNUNET_GETOPT_OPTION_SET_ONE ('P',
+                                  "plugins",
+                                  gettext_noop ("monitor plugin sessions"),
+                                  &monitor_plugins),
+    GNUNET_GETOPT_OPTION_SET_ONE ('s',
+                                  "send",
+                                  gettext_noop
+      ("send data for benchmarking to the other peer (until CTRL-C)"),
+                                  &benchmark_send),
     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
     GNUNET_GETOPT_OPTION_END
   };
index ceed94af8b2d700e7ddd7bdcde231364bd593e57..e20948c5acf64100819a2c796028f1770bb8c37e 100644 (file)
@@ -221,7 +221,7 @@ struct GNUNET_ATS_Session
   /**
    * Message stream tokenizer for incoming data
    */
-  struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk;
+  struct GNUNET_MessageStreamTokenizer *msg_tk;
 
   /**
    * Session timeout task
@@ -528,7 +528,7 @@ client_delete_session (struct GNUNET_ATS_Session *s)
                           GNUNET_TRANSPORT_SS_DONE);
   if (NULL != s->msg_tk)
   {
-    GNUNET_SERVER_mst_destroy (s->msg_tk);
+    GNUNET_MST_destroy (s->msg_tk);
     s->msg_tk = NULL;
   }
   GNUNET_HELLO_address_free (s->address);
@@ -1158,13 +1158,11 @@ client_wake_up (void *cls)
  * Callback for message stream tokenizer
  *
  * @param cls the session
- * @param client not used
  * @param message the message received
  * @return always #GNUNET_OK
  */
 static int
 client_receive_mst_cb (void *cls,
-                       void *client,
                        const struct GNUNET_MessageHeader *message)
 {
   struct GNUNET_ATS_Session *s = cls;
@@ -1274,14 +1272,13 @@ client_receive (void *stream,
     return CURL_WRITEFUNC_PAUSE;
   }
   if (NULL == s->msg_tk)
-    s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb,
-                                          s);
-  GNUNET_SERVER_mst_receive (s->msg_tk,
-                             s,
-                             stream,
-                             len,
-                             GNUNET_NO,
-                             GNUNET_NO);
+    s->msg_tk = GNUNET_MST_create (&client_receive_mst_cb,
+                                   s);
+  GNUNET_MST_from_buffer (s->msg_tk,
+                          stream,
+                          len,
+                          GNUNET_NO,
+                          GNUNET_NO);
   return len;
 }
 
@@ -1641,7 +1638,7 @@ client_connect_get (struct GNUNET_ATS_Session *s)
                     CURLOPT_CONNECTTIMEOUT_MS,
                     (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL));
   curl_easy_setopt (s->get.easyhandle, CURLOPT_BUFFERSIZE,
-                    2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
+                    2 * GNUNET_MAX_MESSAGE_SIZE);
 #if CURL_TCP_NODELAY
   curl_easy_setopt (ps->recv_endpoint,
                     CURLOPT_TCP_NODELAY,
@@ -1818,7 +1815,7 @@ client_connect_put (struct GNUNET_ATS_Session *s)
                     CURLOPT_CONNECTTIMEOUT_MS,
                     (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL));
   curl_easy_setopt (s->put.easyhandle, CURLOPT_BUFFERSIZE,
-                    2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
+                    2 * GNUNET_MAX_MESSAGE_SIZE);
 #if CURL_TCP_NODELAY
   curl_easy_setopt (s->put.easyhandle, CURLOPT_TCP_NODELAY, 1);
 #endif
index 63c67b81c50b673f5041472ac28a7a7e4a09946e..ff2d68602b7c8238b0bcf73420dd1b7126de8f2c 100644 (file)
@@ -201,7 +201,7 @@ struct GNUNET_ATS_Session
   /**
    * Message stream tokenizer for incoming data
    */
-  struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk;
+  struct GNUNET_MessageStreamTokenizer *msg_tk;
 
   /**
    * Client recv handle
@@ -608,7 +608,7 @@ server_delete_session (struct GNUNET_ATS_Session *s)
   }
   if (NULL != s->msg_tk)
   {
-    GNUNET_SERVER_mst_destroy (s->msg_tk);
+    GNUNET_MST_destroy (s->msg_tk);
     s->msg_tk = NULL;
   }
   GNUNET_HELLO_address_free (s->address);
@@ -1621,13 +1621,11 @@ server_send_callback (void *cls,
  * Callback called by MessageStreamTokenizer when a message has arrived
  *
  * @param cls current session as closure
- * @param client client
  * @param message the message to be forwarded to transport service
  * @return #GNUNET_OK
  */
 static int
 server_receive_mst_cb (void *cls,
-                       void *client,
                        const struct GNUNET_MessageHeader *message)
 {
   struct GNUNET_ATS_Session *s = cls;
@@ -1847,13 +1845,16 @@ server_access_cb (void *cls,
              *upload_data_size);
         if (s->msg_tk == NULL)
         {
-          s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s);
+          s->msg_tk = GNUNET_MST_create (&server_receive_mst_cb,
+                                         s);
         }
-        GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, *upload_data_size,
-            GNUNET_NO, GNUNET_NO);
+        GNUNET_MST_from_buffer (s->msg_tk,
+                                upload_data,
+                                *upload_data_size,
+                                GNUNET_NO, GNUNET_NO);
         server_mhd_connection_timeout (plugin, s,
-            GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL
-                / 1000LL);
+                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL
+                                       / 1000LL);
         (*upload_data_size) = 0;
       }
       else
@@ -1935,7 +1936,7 @@ server_disconnect_cb (void *cls,
       sc->session->server_recv = NULL;
       if (NULL != sc->session->msg_tk)
       {
-        GNUNET_SERVER_mst_destroy (sc->session->msg_tk);
+        GNUNET_MST_destroy (sc->session->msg_tk);
         sc->session->msg_tk = NULL;
       }
     }
@@ -2223,7 +2224,7 @@ run_mhd_start_daemon (struct HTTP_Server_Plugin *plugin,
                              timeout,
                              MHD_OPTION_CONNECTION_MEMORY_LIMIT,
                              (size_t) (2 *
-                                       GNUNET_SERVER_MAX_MESSAGE_SIZE),
+                                       GNUNET_MAX_MESSAGE_SIZE),
                              MHD_OPTION_NOTIFY_COMPLETED,
                              &server_disconnect_cb, plugin,
                              MHD_OPTION_EXTERNAL_LOGGER,
@@ -2757,7 +2758,7 @@ server_start_report_addresses (struct HTTP_Server_Plugin *plugin)
     return;
   }
 
-  plugin->nat 
+  plugin->nat
     = GNUNET_NAT_register (plugin->env->cfg,
                           "transport-http_server",
                           IPPROTO_TCP,
index 34bbd00e09bea1bebb138d93adaa141b6cce7d23..a63013caad6e644451869318074b6eeeb0130197 100644 (file)
  */
 #define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
 
-GNUNET_NETWORK_STRUCT_BEGIN
+/**
+ * Opaque handle that can be used to cancel
+ * a transmit-ready notification.
+ */
+struct GNUNET_CONNECTION_TransmitHandle;
+
+/**
+ * @brief handle for a server
+ */
+struct GNUNET_SERVER_Handle;
+
+/**
+ * @brief opaque handle for a client of the server
+ */
+struct GNUNET_SERVER_Client;
+
+/**
+ * @brief opaque handle server returns for aborting transmission to a client.
+ */
+struct GNUNET_SERVER_TransmitHandle;
+
+/**
+ * @brief handle for a network connection
+ */
+struct GNUNET_CONNECTION_Handle;
+
+/**
+ * @brief handle for a network service
+ */
+struct LEGACY_SERVICE_Context;
+
+
+/**
+ * Stops a service that was started with #GNUNET_SERVICE_start().
+ *
+ * @param srv service to stop
+ */
+void
+LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *srv);
+
+
+
+/**
+ * Function called to notify a client about the connection begin ready
+ * to queue more data.  @a buf will be NULL and @a size zero if the
+ * connection was closed for writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in @a buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to @a buf
+ */
+typedef size_t
+(*GNUNET_CONNECTION_TransmitReadyNotify) (void *cls,
+                                          size_t size,
+                                          void *buf);
+
+/**
+ * Credentials for UNIX domain sockets.
+ */
+struct GNUNET_CONNECTION_Credentials
+{
+  /**
+   * UID of the other end of the connection.
+   */
+  uid_t uid;
+
+  /**
+   * GID of the other end of the connection.
+   */
+  gid_t gid;
+};
+
+
+/**
+ * Functions with this signature are called whenever a client
+ * is disconnected on the network level.
+ *
+ * @param cls closure
+ * @param client identification of the client; NULL
+ *        for the last call when the server is destroyed
+ */
+typedef void
+(*GNUNET_SERVER_DisconnectCallback) (void *cls,
+                                     struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Functions with this signature are called whenever a client
+ * is connected on the network level.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ */
+typedef void
+(*GNUNET_SERVER_ConnectCallback) (void *cls,
+                                  struct GNUNET_SERVER_Client *client);
+
+
+
+
+/**
+ * Function to call for access control checks.
+ *
+ * @param cls closure
+ * @param ucred credentials, if available, otherwise NULL
+ * @param addr address
+ * @param addrlen length of address
+ * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
+ *   for unknown address family (will be denied).
+ */
+typedef int
+(*GNUNET_CONNECTION_AccessCheck) (void *cls,
+                                  const struct
+                                  GNUNET_CONNECTION_Credentials *
+                                  ucred,
+                                  const struct sockaddr * addr,
+                                  socklen_t addrlen);
+
+/**
+ * Callback function for data received from the network.  Note that
+ * both "available" and "err" would be 0 if the read simply timed out.
+ *
+ * @param cls closure
+ * @param buf pointer to received data
+ * @param available number of bytes availabe in "buf",
+ *        possibly 0 (on errors)
+ * @param addr address of the sender
+ * @param addrlen size of addr
+ * @param errCode value of errno (on errors receiving)
+ */
+typedef void
+(*GNUNET_CONNECTION_Receiver) (void *cls, const void *buf,
+                               size_t available,
+                               const struct sockaddr * addr,
+                               socklen_t addrlen, int errCode);
+
+
+
+/**
+ * Close the connection and free associated resources.  There must
+ * not be any pending requests for reading or writing to the
+ * connection at this time.
+ *
+ * @param connection connection to destroy
+ */
+void
+GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection);
+
+
+/**
+ * Signature of a function to create a custom tokenizer.
+ *
+ * @param cls closure from #GNUNET_SERVER_set_callbacks
+ * @param client handle to client the tokenzier will be used for
+ * @return handle to custom tokenizer ('mst')
+ */
+typedef void*
+(*GNUNET_SERVER_MstCreateCallback) (void *cls,
+                                    struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Signature of a function to destroy a custom tokenizer.
+ *
+ * @param cls closure from #GNUNET_SERVER_set_callbacks
+ * @param mst custom tokenizer handle
+ */
+typedef void
+(*GNUNET_SERVER_MstDestroyCallback) (void *cls,
+                                     void *mst);
+
+/**
+ * Signature of a function to receive data for a custom tokenizer.
+ *
+ * @param cls closure from #GNUNET_SERVER_set_callbacks
+ * @param mst custom tokenizer handle
+ * @param client_identity ID of client for which this is a buffer,
+ *        can be NULL (will be passed back to 'cb')
+ * @param buf input data to add
+ * @param size number of bytes in @a buf
+ * @param purge should any excess bytes in the buffer be discarded
+ *       (i.e. for packet-based services like UDP)
+ * @param one_shot only call callback once, keep rest of message in buffer
+ * @return #GNUNET_OK if we are done processing (need more data)
+ *         #GNUNET_NO if one_shot was set and we have another message ready
+ *         #GNUNET_SYSERR if the data stream is corrupt
+ */
+typedef int
+(*GNUNET_SERVER_MstReceiveCallback) (void *cls, void *mst,
+                                     struct GNUNET_SERVER_Client *client,
+                                     const char *buf,
+                                     size_t size,
+                                     int purge,
+                                     int one_shot);
+/**
+ * Functions with this signature are called whenever a message is
+ * received.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+typedef void
+(*GNUNET_SERVER_MessageCallback) (void *cls,
+                                  struct GNUNET_SERVER_Client *client,
+                                  const struct GNUNET_MessageHeader *message);
+
+/**
+ * Message handler.  Each struct specifies how to handle on particular
+ * type of message received.
+ */
+struct GNUNET_SERVER_MessageHandler
+{
+  /**
+   * Function to call for messages of "type".
+   */
+  GNUNET_SERVER_MessageCallback callback;
+
+  /**
+   * Closure argument for @e callback.
+   */
+  void *callback_cls;
+
+  /**
+   * Type of the message this handler covers.
+   */
+  uint16_t type;
+
+  /**
+   * Expected size of messages of this type.  Use 0 for
+   * variable-size.  If non-zero, messages of the given
+   * type will be discarded (and the connection closed)
+   * if they do not have the right size.
+   */
+  uint16_t expected_size;
+
+};
+
+
+/**
+ * Options for the service (bitmask).
+ */
+enum LEGACY_SERVICE_Options
+{
+  /**
+   * Use defaults.  Terminates all client connections and the listen
+   * sockets immediately upon receiving the shutdown signal.
+   */
+  LEGACY_SERVICE_OPTION_NONE = 0,
+
+  /**
+   * Do not trigger server shutdown on signal at all; instead, allow
+   * for the user to terminate the server explicitly when needed
+   * by calling #LEGACY_SERVICE_shutdown().
+   */
+  LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN = 1,
+
+  /**
+   * Trigger a SOFT server shutdown on signals, allowing active
+   * non-monitor clients to complete their transactions.
+   */
+  LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN = 2
+};
+
+
+
+/**
+ * Ask the server to disconnect from the given client.  This is the
+ * same as passing #GNUNET_SYSERR to #GNUNET_SERVER_receive_done,
+ * except that it allows dropping of a client even when not handling a
+ * message from that client.
+ *
+ * @param client the client to disconnect from
+ */
+void
+GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client);
+
+/**
+ * Return user context associated with the given client.
+ * Note: you should probably use the macro (call without the underscore).
+ *
+ * @param client client to query
+ * @param size number of bytes in user context struct (for verification only)
+ * @return pointer to user context
+ */
+void *
+GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
+                                        size_t size);
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer.
+ *
+ * Do not call #GNUNET_SERVER_mst_destroy from within
+ * the scope of this callback.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
+ */
+typedef int
+(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
+                                           void *client,
+                                           const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Create a message stream tokenizer.
+ *
+ * @param cb function to call on completed messages
+ * @param cb_cls closure for @a cb
+ * @return handle to tokenizer
+ */
+struct GNUNET_SERVER_MessageStreamTokenizer *
+GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
+                          void *cb_cls);
+
+/**
+ * Add incoming data to the receive buffer and call the
+ * callback for all complete messages.
+ *
+ * @param mst tokenizer to use
+ * @param client_identity ID of client for which this is a buffer,
+ *        can be NULL (will be passed back to 'cb')
+ * @param buf input data to add
+ * @param size number of bytes in @a buf
+ * @param purge should any excess bytes in the buffer be discarded
+ *       (i.e. for packet-based services like UDP)
+ * @param one_shot only call callback once, keep rest of message in buffer
+ * @return #GNUNET_OK if we are done processing (need more data)
+ *         #GNUNET_NO if one_shot was set and we have another message ready
+ *         #GNUNET_SYSERR if the data stream is corrupt
+ */
+int
+GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
+                           void *client_identity,
+                           const char *buf, size_t size,
+                           int purge, int one_shot);
+
+
+
+/**
+ * Destroys a tokenizer.
+ *
+ * @param mst tokenizer to destroy
+ */
+void
+GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst);
 
 
+/**
+ * Set user context to be associated with the given client.
+ * Note: you should probably use the macro (call without the underscore).
+ *
+ * @param client client to query
+ * @param ptr pointer to user context
+ * @param size number of bytes in user context struct (for verification only)
+ */
+void
+GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
+                                        void *ptr,
+                                        size_t size);
+/**
+ * Return user context associated with the given client.
+ *
+ * @param client client to query
+ * @param type expected return type (i.e. 'struct Foo')
+ * @return pointer to user context of type 'type *'.
+ */
+#define GNUNET_SERVER_client_get_user_context(client,type)              \
+  (type *) GNUNET_SERVER_client_get_user_context_ (client, sizeof (type))
+
+/**
+ * Set user context to be associated with the given client.
+ *
+ * @param client client to query
+ * @param value pointer to user context
+ */
+#define GNUNET_SERVER_client_set_user_context(client,value)             \
+  GNUNET_SERVER_client_set_user_context_ (client, value, sizeof (*value))
+
+
+
+/**
+ * Notify us when the server has enough space to transmit
+ * a message of the given size to the given client.
+ *
+ * @param client client to transmit message to
+ * @param size requested amount of buffer space
+ * @param timeout after how long should we give up (and call
+ *        notify with buf NULL and size 0)?
+ * @param callback function to call when space is available
+ * @param callback_cls closure for @a callback
+ * @return non-NULL if the notify callback was queued; can be used
+ *           to cancel the request using
+ *           #GNUNET_SERVER_notify_transmit_ready_cancel.
+ *         NULL if we are already going to notify someone else (busy)
+ */
+struct GNUNET_SERVER_TransmitHandle *
+GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
+                                     size_t size,
+                                     struct GNUNET_TIME_Relative timeout,
+                                     GNUNET_CONNECTION_TransmitReadyNotify callback,
+                                     void *callback_cls);
+
+/**
+ * Abort transmission request.
+ *
+ * @param th request to abort
+ */
+void
+GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th);
+
+
+
+
+/**
+ * Notify the server that the given client handle should
+ * be kept (keeps the connection up if possible, increments
+ * the internal reference counter).
+ *
+ * @param client the client to keep
+ */
+void
+GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Notify the server that the given client handle is no
+ * longer required.  Decrements the reference counter.  If
+ * that counter reaches zero an inactive connection maybe
+ * closed.
+ *
+ * @param client the client to drop
+ */
+void
+GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client);
+
+
+/**
+ * Function called by the service's run
+ * method to run service-specific setup code.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param cfg configuration to use
+ */
+typedef void
+(*LEGACY_SERVICE_Main) (void *cls,
+                        struct GNUNET_SERVER_Handle *server,
+                        const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+
+/**
+ * Suspend accepting connections from the listen socket temporarily.
+ * Resume activity using #GNUNET_SERVER_resume.
+ *
+ * @param server server to stop accepting connections.
+ */
+void
+GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server);
+
+/**
+ * Notify us when the server has enough space to transmit
+ * a message of the given size to the given client.
+ *
+ * @param client client to transmit message to
+ * @param size requested amount of buffer space
+ * @param timeout after how long should we give up (and call
+ *        notify with buf NULL and size 0)?
+ * @param callback function to call when space is available
+ * @param callback_cls closure for @a callback
+ * @return non-NULL if the notify callback was queued; can be used
+ *           to cancel the request using
+ *           #GNUNET_SERVER_notify_transmit_ready_cancel.
+ *         NULL if we are already going to notify someone else (busy)
+ */
+struct GNUNET_SERVER_TransmitHandle *
+GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
+                                     size_t size,
+                                     struct GNUNET_TIME_Relative timeout,
+                                     GNUNET_CONNECTION_TransmitReadyNotify callback,
+                                     void *callback_cls);
+
+
+/**
+ * Add a TCP socket-based connection to the set of handles managed by
+ * this server.  Use this function for outgoing (P2P) connections that
+ * we initiated (and where this server should process incoming
+ * messages).
+ *
+ * @param server the server to use
+ * @param connection the connection to manage (client must
+ *        stop using this connection from now on)
+ * @return the client handle
+ */
+struct GNUNET_SERVER_Client *
+GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
+                              struct GNUNET_CONNECTION_Handle *connection);
+
+
+/**
+ * Resume accepting connections from the listen socket.
+ *
+ * @param server server to resume accepting connections.
+ */
+void
+GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server);
+
+/**
+ * Free resources held by this server.
+ *
+ * @param server server to destroy
+ */
+void
+GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server);
+
+
+
+
+#include "tcp_connection_legacy.c"
+#include "tcp_server_mst_legacy.c"
+#include "tcp_server_legacy.c"
+#include "tcp_service_legacy.c"
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
 /**
  * Initial handshake message for a session.
  */
@@ -434,7 +962,7 @@ struct Plugin
   /**
    * Handle to the network service.
    */
-  struct GNUNET_SERVICE_Context *service;
+  struct LEGACY_SERVICE_Context *service;
 
   /**
    * Handle to the server for this service.
@@ -521,47 +1049,6 @@ struct Plugin
 };
 
 
-/* begin of ancient copy-and-pasted code that should be
-   specialized for TCP ...*/
-/**
- * Add the given UNIX domain path as an address to the
- * list (as the first entry).
- *
- * @param saddrs array to update
- * @param saddrlens where to store the address length
- * @param unixpath path to add
- * @param abstract #GNUNET_YES to add an abstract UNIX domain socket.  This
- *          parameter is ignore on systems other than LINUX
- */
-static void
-add_unixpath (struct sockaddr **saddrs,
-              socklen_t *saddrlens,
-              const char *unixpath,
-              int abstract)
-{
-#ifdef AF_UNIX
-  struct sockaddr_un *un;
-
-  un = GNUNET_new (struct sockaddr_un);
-  un->sun_family = AF_UNIX;
-  strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
-#ifdef LINUX
-  if (GNUNET_YES == abstract)
-    un->sun_path[0] = '\0';
-#endif
-#if HAVE_SOCKADDR_UN_SUN_LEN
-  un->sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
-  *saddrs = (struct sockaddr *) un;
-  *saddrlens = sizeof (struct sockaddr_un);
-#else
-  /* this function should never be called
-   * unless AF_UNIX is defined! */
-  GNUNET_assert (0);
-#endif
-}
-
-
 /**
  * Get the list of addresses that a server for the given service
  * should bind to.
@@ -3289,7 +3776,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
   struct GNUNET_TRANSPORT_PluginFunctions *api;
   struct Plugin *plugin;
-  struct GNUNET_SERVICE_Context *service;
+  struct LEGACY_SERVICE_Context *service;
   unsigned long long aport;
   unsigned long long bport;
   unsigned long long max_connections;
@@ -3344,9 +3831,9 @@ libgnunet_plugin_transport_tcp_init (void *cls)
     aport = 0;
   if (0 != bport)
   {
-    service = GNUNET_SERVICE_start ("transport-tcp",
+    service = LEGACY_SERVICE_start ("transport-tcp",
                                     env->cfg,
-                                    GNUNET_SERVICE_OPTION_NONE);
+                                    LEGACY_SERVICE_OPTION_NONE);
     if (NULL == service)
     {
       LOG (GNUNET_ERROR_TYPE_WARNING,
@@ -3377,7 +3864,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
   {
 #ifdef TCP_STEALTH
     plugin->myoptions |= TCP_OPTIONS_TCP_STEALTH;
-    lsocks = GNUNET_SERVICE_get_listen_sockets (service);
+    lsocks = LEGACY_SERVICE_get_listen_sockets (service);
     if (NULL != lsocks)
     {
       uint32_t len = sizeof (struct WelcomeMessage);
@@ -3470,7 +3957,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
   plugin->service = service;
   if (NULL != service)
   {
-    plugin->server = GNUNET_SERVICE_get_server (service);
+    plugin->server = LEGACY_SERVICE_get_server (service);
   }
   else
   {
@@ -3533,7 +4020,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
     GNUNET_NAT_unregister (plugin->nat);
   GNUNET_CONTAINER_multipeermap_destroy (plugin->sessionmap);
   if (NULL != service)
-    GNUNET_SERVICE_stop (service);
+    LEGACY_SERVICE_stop (service);
   GNUNET_free (plugin);
   GNUNET_free_non_null (api);
   return NULL;
@@ -3586,7 +4073,7 @@ libgnunet_plugin_transport_tcp_done (void *cls)
   }
 
   if (NULL != plugin->service)
-    GNUNET_SERVICE_stop (plugin->service);
+    LEGACY_SERVICE_stop (plugin->service);
   else
     GNUNET_SERVER_destroy (plugin->server);
   GNUNET_free (plugin->handlers);
index 76132523be12f93014d74223e3d591c778574cb1..1ff962544f2d226122f9cdbe186b4c7f5f3e9e6f 100644 (file)
@@ -158,6 +158,11 @@ struct GNUNET_ATS_Session
    */
   struct GNUNET_PeerIdentity target;
 
+  /**
+   * Tokenizer for inbound messages.
+   */
+  struct GNUNET_MessageStreamTokenizer *mst;
+
   /**
    * Plugin this session belongs to.
    */
@@ -626,6 +631,11 @@ free_session (struct GNUNET_ATS_Session *s)
     GNUNET_free (s->frag_ctx);
     s->frag_ctx = NULL;
   }
+  if (NULL != s->mst)
+  {
+    GNUNET_MST_destroy (s->mst);
+    s->mst = NULL;
+  }
   GNUNET_free (s);
 }
 
@@ -1623,7 +1633,7 @@ enqueue (struct Plugin *plugin,
     GNUNET_break (0);
     return;
   }
-  if (plugin->bytes_in_buffer + udpw->msg_size > INT64_MAX)
+  if (plugin->bytes_in_buffer > INT64_MAX - udpw->msg_size)
   {
     GNUNET_break (0);
   }
@@ -2051,7 +2061,7 @@ udp_plugin_send (void *cls,
   if ( (sizeof(struct IPv4UdpAddress) == s->address->address_length) &&
        (NULL == plugin->sockv4) )
     return GNUNET_SYSERR;
-  if (udpmlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (udpmlen >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
@@ -2499,18 +2509,16 @@ read_process_ack (struct Plugin *plugin,
  * Message tokenizer has broken up an incomming message. Pass it on
  * to the service.
  *
- * @param cls the `struct Plugin *`
- * @param client the `struct GNUNET_ATS_Session *`
+ * @param cls the `struct GNUNET_ATS_Session *`
  * @param hdr the actual message
  * @return #GNUNET_OK (always)
  */
 static int
 process_inbound_tokenized_messages (void *cls,
-                                    void *client,
                                     const struct GNUNET_MessageHeader *hdr)
 {
-  struct Plugin *plugin = cls;
-  struct GNUNET_ATS_Session *session = client;
+  struct GNUNET_ATS_Session *session = cls;
+  struct Plugin *plugin = session->plugin;
 
   if (GNUNET_YES == session->in_destroy)
     return GNUNET_OK;
@@ -2626,6 +2634,8 @@ udp_plugin_create_session (void *cls,
   struct GNUNET_ATS_Session *s;
 
   s = GNUNET_new (struct GNUNET_ATS_Session);
+  s->mst = GNUNET_MST_create (&process_inbound_tokenized_messages,
+                              s);
   s->plugin = plugin;
   s->address = GNUNET_HELLO_address_copy (address);
   s->target = address->peer;
@@ -2792,12 +2802,11 @@ process_udp_message (struct Plugin *plugin,
   GNUNET_free (address);
 
   s->rc++;
-  GNUNET_SERVER_mst_receive (plugin->mst,
-                             s,
-                             (const char *) &msg[1],
-                             ntohs (msg->header.size) - sizeof(struct UDPMessage),
-                             GNUNET_YES,
-                             GNUNET_NO);
+  GNUNET_MST_from_buffer (s->mst,
+                          (const char *) &msg[1],
+                          ntohs (msg->header.size) - sizeof(struct UDPMessage),
+                          GNUNET_YES,
+                          GNUNET_NO);
   s->rc--;
   if ( (0 == s->rc) &&
        (GNUNET_YES == s->in_destroy) )
@@ -3990,8 +3999,6 @@ libgnunet_plugin_transport_udp_init (void *cls)
   p->sessions = GNUNET_CONTAINER_multipeermap_create (16,
                                                       GNUNET_NO);
   p->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
-  p->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages,
-                                     p);
   GNUNET_BANDWIDTH_tracker_init (&p->tracker,
                                  NULL,
                                  NULL,
@@ -4008,7 +4015,6 @@ libgnunet_plugin_transport_udp_init (void *cls)
         _("Failed to create UDP network sockets\n"));
     GNUNET_CONTAINER_multipeermap_destroy (p->sessions);
     GNUNET_CONTAINER_heap_destroy (p->defrag_ctxs);
-    GNUNET_SERVER_mst_destroy (p->mst);
     if (NULL != p->nat)
       GNUNET_NAT_unregister (p->nat);
     GNUNET_free (p);
@@ -4120,11 +4126,6 @@ libgnunet_plugin_transport_udp_done (void *cls)
     GNUNET_CONTAINER_heap_destroy (plugin->defrag_ctxs);
     plugin->defrag_ctxs = NULL;
   }
-  if (NULL != plugin->mst)
-  {
-    GNUNET_SERVER_mst_destroy (plugin->mst);
-    plugin->mst = NULL;
-  }
   while (NULL != (udpw = plugin->ipv4_queue_head))
   {
     dequeue (plugin,
index 152b16099c22914f05c261ecc2b5703fb2159777..48c7365c714192d351f3a40d9f8476312853619e 100644 (file)
@@ -163,11 +163,6 @@ struct Plugin
    */
   struct GNUNET_SCHEDULER_Task *select_task_v6;
 
-  /**
-   * Tokenizer for inbound messages.
-   */
-  struct GNUNET_SERVER_MessageStreamTokenizer *mst;
-
   /**
    * Bandwidth tracker to limit global UDP traffic.
    */
@@ -192,7 +187,7 @@ struct Plugin
    * Handle to NAT traversal support.
    */
   struct GNUNET_NAT_STUN_Handle *stun;
-  
+
   /**
    * The read socket for IPv4
    */
@@ -203,11 +198,6 @@ struct Plugin
    */
   struct GNUNET_NETWORK_Handle *sockv6;
 
-  /**
-   * Tokenizer for inbound messages.
-   */
-  struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_mst;
-
   /**
    * Head of DLL of broadcast addresses
    */
index a440830fd9450252a2749bad235779b701bc1981..c6ddbce9b5ccec2e245734c5c9e2a875773d555b 100644 (file)
@@ -133,11 +133,10 @@ struct MstContext
  */
 static int
 broadcast_mst_cb (void *cls,
-                  void *client,
                   const struct GNUNET_MessageHeader *message)
 {
-  struct Plugin *plugin = cls;
-  struct MstContext *mc = client;
+  struct MstContext *mc = cls;
+  struct Plugin *plugin = mc->plugin;
   struct GNUNET_HELLO_Address *address;
   const struct GNUNET_MessageHeader *hello;
   const struct UDP_Beacon_Message *msg;
@@ -191,16 +190,20 @@ udp_broadcast_receive (struct Plugin *plugin,
                        size_t udp_addr_len,
                        enum GNUNET_ATS_Network_Type network_type)
 {
+  struct GNUNET_MessageStreamTokenizer *broadcast_mst;
   struct MstContext mc;
 
+  broadcast_mst = GNUNET_MST_create (&broadcast_mst_cb,
+                                     &mc);
+  mc.plugin = plugin;
   mc.udp_addr = udp_addr;
   mc.udp_addr_len = udp_addr_len;
   mc.ats_address_network_type = network_type;
-  GNUNET_SERVER_mst_receive (plugin->broadcast_mst,
-                             &mc,
-                             buf, size,
-                             GNUNET_NO,
-                             GNUNET_NO);
+  GNUNET_MST_from_buffer (broadcast_mst,
+                          buf, size,
+                          GNUNET_NO,
+                          GNUNET_NO);
+  GNUNET_MST_destroy (broadcast_mst);
 }
 
 
@@ -546,10 +549,6 @@ setup_broadcast (struct Plugin *plugin,
     return;
   }
 
-  /* always create tokenizers */
-  plugin->broadcast_mst =
-    GNUNET_SERVER_mst_create (&broadcast_mst_cb, plugin);
-
   if (GNUNET_YES != plugin->enable_broadcasting)
     return; /* We do not send, just receive */
 
@@ -636,13 +635,6 @@ stop_broadcast (struct Plugin *plugin)
       GNUNET_free (p);
     }
   }
-
-  /* Destroy MSTs */
-  if (NULL != plugin->broadcast_mst)
-  {
-    GNUNET_SERVER_mst_destroy (plugin->broadcast_mst);
-    plugin->broadcast_mst = NULL;
-  }
 }
 
 /* end of plugin_transport_udp_broadcasting.c */
index 376065d24cf9c5cb0fde48e8c85e9e73e13212c8..b23739d3cdfb7599a1caddc78515b052e5ab8f3d 100644 (file)
@@ -38,6 +38,7 @@
 #include "gnunet_fragmentation_lib.h"
 #include "gnunet_constants.h"
 
+
 #if BUILD_WLAN
 /* begin case wlan */
 #define PLUGIN_NAME "wlan"
@@ -48,6 +49,7 @@
 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_wlan_done
 #define LOG(kind,...) GNUNET_log_from (kind, "transport-wlan",__VA_ARGS__)
 
+
 /**
  * time out of a mac endpoint
  */
 #error need to build wlan or bluetooth
 #endif
 
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer.
+ *
+ * Do not call #GNUNET_SERVER_mst_destroy from within
+ * the scope of this callback.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
+ */
+typedef int
+(*GNUNET_SERVER_MessageTokenizerCallback) (void *cls,
+                                           void *client,
+                                           const struct GNUNET_MessageHeader *message);
+
+
+/* Include legacy message stream tokenizer that was removed from util (for now) */
+#include "tcp_server_mst_legacy.c"
+
+
 /**
  * Max size of packet (that we give to the WLAN driver for transmission)
  */
@@ -718,7 +744,7 @@ send_ack (void *cls,
     GNUNET_break (0);
     return;
   }
-  if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (size >= GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return;
@@ -1728,11 +1754,10 @@ send_hello_beacon (void *cls)
  * Function used for to process the data from the suid process
  *
  * @param cls the plugin handle
- * @param client client that send the data (not used)
  * @param hdr header of the GNUNET_MessageHeader
  */
 static int
-handle_helper_message (void *cls, void *client,
+handle_helper_message (void *cls,
                       const struct GNUNET_MessageHeader *hdr)
 {
   struct Plugin *plugin = cls;
diff --git a/src/transport/tcp_connection_legacy.c b/src/transport/tcp_connection_legacy.c
new file mode 100644 (file)
index 0000000..5b219a4
--- /dev/null
@@ -0,0 +1,1656 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009-2013 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/connection.c
+ * @brief  TCP connection management
+ * @author Christian Grothoff
+ *
+ * This code is rather complex.  Only modify it if you
+ * 1) Have a NEW testcase showing that the new code
+ *    is needed and correct
+ * 2) All EXISTING testcases pass with the new code
+ * These rules should apply in general, but for this
+ * module they are VERY, VERY important.
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_resolver_service.h"
+
+
+/**
+ * Timeout we use on TCP connect before trying another
+ * result from the DNS resolver.  Actual value used
+ * is this value divided by the number of address families.
+ * Default is 5s.
+ */
+#define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-connection", syscall)
+
+
+/**
+ * Transmission handle.  There can only be one for each connection.
+ */
+struct GNUNET_CONNECTION_TransmitHandle
+{
+
+  /**
+   * Function to call if the send buffer has notify_size
+   * bytes available.
+   */
+  GNUNET_CONNECTION_TransmitReadyNotify notify_ready;
+
+  /**
+   * Closure for notify_ready.
+   */
+  void *notify_ready_cls;
+
+  /**
+   * Our connection handle.
+   */
+  struct GNUNET_CONNECTION_Handle *connection;
+
+  /**
+   * Timeout for receiving (in absolute time).
+   */
+  struct GNUNET_TIME_Absolute transmit_timeout;
+
+  /**
+   * Task called on timeout.
+   */
+  struct GNUNET_SCHEDULER_Task * timeout_task;
+
+  /**
+   * At what number of bytes available in the
+   * write buffer should the notify method be called?
+   */
+  size_t notify_size;
+
+};
+
+
+/**
+ * During connect, we try multiple possible IP addresses
+ * to find out which one might work.
+ */
+struct AddressProbe
+{
+
+  /**
+   * This is a linked list.
+   */
+  struct AddressProbe *next;
+
+  /**
+   * This is a doubly-linked list.
+   */
+  struct AddressProbe *prev;
+
+  /**
+   * The address; do not free (allocated at the end of this struct).
+   */
+  const struct sockaddr *addr;
+
+  /**
+   * Underlying OS's socket.
+   */
+  struct GNUNET_NETWORK_Handle *sock;
+
+  /**
+   * Connection for which we are probing.
+   */
+  struct GNUNET_CONNECTION_Handle *connection;
+
+  /**
+   * Lenth of addr.
+   */
+  socklen_t addrlen;
+
+  /**
+   * Task waiting for the connection to finish connecting.
+   */
+  struct GNUNET_SCHEDULER_Task * task;
+};
+
+
+/**
+ * @brief handle for a network connection
+ */
+struct GNUNET_CONNECTION_Handle
+{
+
+  /**
+   * Configuration to use.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Linked list of sockets we are currently trying out
+   * (during connect).
+   */
+  struct AddressProbe *ap_head;
+
+  /**
+   * Linked list of sockets we are currently trying out
+   * (during connect).
+   */
+  struct AddressProbe *ap_tail;
+
+  /**
+   * Network address of the other end-point, may be NULL.
+   */
+  struct sockaddr *addr;
+
+  /**
+   * Pointer to the hostname if connection was
+   * created using DNS lookup, otherwise NULL.
+   */
+  char *hostname;
+
+  /**
+   * Underlying OS's socket, set to NULL after fatal errors.
+   */
+  struct GNUNET_NETWORK_Handle *sock;
+
+  /**
+   * Function to call on data received, NULL if no receive is pending.
+   */
+  GNUNET_CONNECTION_Receiver receiver;
+
+  /**
+   * Closure for @e receiver.
+   */
+  void *receiver_cls;
+
+  /**
+   * Pointer to our write buffer.
+   */
+  char *write_buffer;
+
+  /**
+   * Current size of our @e write_buffer.
+   */
+  size_t write_buffer_size;
+
+  /**
+   * Current write-offset in @e write_buffer (where
+   * would we write next).
+   */
+  size_t write_buffer_off;
+
+  /**
+   * Current read-offset in @e write_buffer (how many
+   * bytes have already been sent).
+   */
+  size_t write_buffer_pos;
+
+  /**
+   * Length of @e addr.
+   */
+  socklen_t addrlen;
+
+  /**
+   * Read task that we may need to wait for.
+   */
+  struct GNUNET_SCHEDULER_Task *read_task;
+
+  /**
+   * Write task that we may need to wait for.
+   */
+  struct GNUNET_SCHEDULER_Task *write_task;
+
+  /**
+   * Handle to a pending DNS lookup request.
+   */
+  struct GNUNET_RESOLVER_RequestHandle *dns_active;
+
+  /**
+   * The handle we return for #GNUNET_CONNECTION_notify_transmit_ready().
+   */
+  struct GNUNET_CONNECTION_TransmitHandle nth;
+
+  /**
+   * Timeout for receiving (in absolute time).
+   */
+  struct GNUNET_TIME_Absolute receive_timeout;
+
+  /**
+   * Maximum number of bytes to read (for receiving).
+   */
+  size_t max;
+
+  /**
+   * Port to connect to.
+   */
+  uint16_t port;
+
+  /**
+   * When shutdown, do not ever actually close the socket, but
+   * free resources.  Only should ever be set if using program
+   * termination as a signal (because only then will the leaked
+   * socket be freed!)
+   */
+  int8_t persist;
+
+  /**
+   * Usually 0.  Set to 1 if this handle is in use, and should
+   * #GNUNET_CONNECTION_destroy() be called right now, the action needs
+   * to be deferred by setting it to -1.
+   */
+  int8_t destroy_later;
+
+  /**
+   * Handle to subsequent connection after proxy handshake completes,
+   */
+  struct GNUNET_CONNECTION_Handle *proxy_handshake;
+
+};
+
+
+/**
+ * Set the persist option on this connection handle.  Indicates
+ * that the underlying socket or fd should never really be closed.
+ * Used for indicating process death.
+ *
+ * @param connection the connection to set persistent
+ */
+void
+GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection)
+{
+  connection->persist = GNUNET_YES;
+}
+
+
+/**
+ * Disable the "CORK" feature for communication with the given connection,
+ * forcing the OS to immediately flush the buffer on transmission
+ * instead of potentially buffering multiple messages.  Essentially
+ * reduces the OS send buffers to zero.
+ * Used to make sure that the last messages sent through the connection
+ * reach the other side before the process is terminated.
+ *
+ * @param connection the connection to make flushing and blocking
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
+{
+  return GNUNET_NETWORK_socket_disable_corking (connection->sock);
+}
+
+
+/**
+ * Create a connection handle by boxing an existing OS socket.  The OS
+ * socket should henceforth be no longer used directly.
+ * #GNUNET_connection_destroy() will close it.
+ *
+ * @param osSocket existing socket to box
+ * @return the boxed connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
+{
+  struct GNUNET_CONNECTION_Handle *connection;
+
+  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+  connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
+  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+  connection->sock = osSocket;
+  return connection;
+}
+
+
+/**
+ * Create a connection handle by accepting on a listen socket.  This
+ * function may block if the listen socket has no connection ready.
+ *
+ * @param access_cb function to use to check if access is allowed
+ * @param access_cb_cls closure for @a access_cb
+ * @param lsock listen socket
+ * @return the connection handle, NULL on error
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
+                                      void *access_cb_cls,
+                                      struct GNUNET_NETWORK_Handle *lsock)
+{
+  struct GNUNET_CONNECTION_Handle *connection;
+  char addr[128];
+  socklen_t addrlen;
+  struct GNUNET_NETWORK_Handle *sock;
+  int aret;
+  struct sockaddr_in *v4;
+  struct sockaddr_in6 *v6;
+  struct sockaddr *sa;
+  void *uaddr;
+#ifdef SO_PEERCRED
+  struct ucred uc;
+  socklen_t olen;
+#endif
+  struct GNUNET_CONNECTION_Credentials *gcp;
+#if HAVE_GETPEEREID || defined(SO_PEERCRED) || HAVE_GETPEERUCRED
+  struct GNUNET_CONNECTION_Credentials gc;
+
+  gc.uid = 0;
+  gc.gid = 0;
+#endif
+
+  addrlen = sizeof (addr);
+  sock =
+      GNUNET_NETWORK_socket_accept (lsock,
+                                   (struct sockaddr *) &addr,
+                                   &addrlen);
+  if (NULL == sock)
+  {
+    if (EAGAIN != errno)
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
+    return NULL;
+  }
+  if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
+  {
+    GNUNET_break (0);
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    return NULL;
+  }
+
+  sa = (struct sockaddr *) addr;
+  v6 = (struct sockaddr_in6 *) addr;
+  if ( (AF_INET6 == sa->sa_family) &&
+       (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)) )
+  {
+    /* convert to V4 address */
+    v4 = GNUNET_new (struct sockaddr_in);
+    memset (v4, 0, sizeof (struct sockaddr_in));
+    v4->sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    v4->sin_len = (u_char) sizeof (struct sockaddr_in);
+#endif
+    GNUNET_memcpy (&v4->sin_addr,
+            &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
+                                       sizeof (struct in_addr)],
+            sizeof (struct in_addr));
+    v4->sin_port = v6->sin6_port;
+    uaddr = v4;
+    addrlen = sizeof (struct sockaddr_in);
+  }
+  else
+  {
+    uaddr = GNUNET_malloc (addrlen);
+    GNUNET_memcpy (uaddr, addr, addrlen);
+  }
+  gcp = NULL;
+  if (AF_UNIX == sa->sa_family)
+  {
+#if HAVE_GETPEEREID
+    /* most BSDs */
+    if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock),
+                        &gc.uid,
+                        &gc.gid))
+      gcp = &gc;
+#else
+#ifdef SO_PEERCRED
+    /* largely traditional GNU/Linux */
+    olen = sizeof (uc);
+    if ( (0 ==
+         getsockopt (GNUNET_NETWORK_get_fd (sock),
+                     SOL_SOCKET,
+                     SO_PEERCRED,
+                     &uc,
+                     &olen)) &&
+        (olen == sizeof (uc)) )
+    {
+      gc.uid = uc.uid;
+      gc.gid = uc.gid;
+      gcp = &gc;
+    }
+#else
+#if HAVE_GETPEERUCRED
+    /* this is for Solaris 10 */
+    ucred_t *uc;
+
+    uc = NULL;
+    if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
+    {
+      gc.uid = ucred_geteuid (uc);
+      gc.gid = ucred_getegid (uc);
+      gcp = &gc;
+    }
+    ucred_free (uc);
+#endif
+#endif
+#endif
+  }
+
+  if ( (NULL != access_cb) &&
+       (GNUNET_YES != (aret = access_cb (access_cb_cls,
+                                        gcp,
+                                        uaddr,
+                                        addrlen))) )
+  {
+    if (GNUNET_NO == aret)
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Access denied to `%s'\n"),
+           GNUNET_a2s (uaddr,
+                       addrlen));
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_NETWORK_socket_shutdown (sock,
+                                                  SHUT_RDWR));
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    GNUNET_free (uaddr);
+    return NULL;
+  }
+  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+  connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
+  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+  connection->addr = uaddr;
+  connection->addrlen = addrlen;
+  connection->sock = sock;
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       _("Accepting connection from `%s': %p\n"),
+       GNUNET_a2s (uaddr,
+                  addrlen),
+       connection);
+  return connection;
+}
+
+
+/**
+ * Obtain the network address of the other party.
+ *
+ * @param connection the client to get the address for
+ * @param addr where to store the address
+ * @param addrlen where to store the length of the @a addr
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
+                               void **addr,
+                               size_t *addrlen)
+{
+  if ((NULL == connection->addr) || (0 == connection->addrlen))
+    return GNUNET_NO;
+  *addr = GNUNET_malloc (connection->addrlen);
+  GNUNET_memcpy (*addr, connection->addr, connection->addrlen);
+  *addrlen = connection->addrlen;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Tell the receiver callback that we had an IO error.
+ *
+ * @param connection connection to signal error
+ * @param errcode error code to send
+ */
+static void
+signal_receive_error (struct GNUNET_CONNECTION_Handle *connection,
+                      int errcode)
+{
+  GNUNET_CONNECTION_Receiver receiver;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Receive encounters error (%s), connection closed (%p)\n",
+       STRERROR (errcode),
+       connection);
+  GNUNET_assert (NULL != (receiver = connection->receiver));
+  connection->receiver = NULL;
+  receiver (connection->receiver_cls,
+            NULL,
+            0,
+            connection->addr,
+            connection->addrlen,
+            errcode);
+}
+
+
+/**
+ * Tell the receiver callback that a timeout was reached.
+ *
+ * @param connection connection to signal for
+ */
+static void
+signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection)
+{
+  GNUNET_CONNECTION_Receiver receiver;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Connection signals timeout to receiver (%p)!\n",
+       connection);
+  GNUNET_assert (NULL != (receiver = connection->receiver));
+  connection->receiver = NULL;
+  receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0);
+}
+
+
+/**
+ * We failed to transmit data to the service, signal the error.
+ *
+ * @param connection handle that had trouble
+ * @param ecode error code (errno)
+ */
+static void
+signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection,
+                      int ecode)
+{
+  GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Transmission encounterd error (%s), connection closed (%p)\n",
+       STRERROR (ecode),
+       connection);
+  if (NULL != connection->sock)
+  {
+    (void) GNUNET_NETWORK_socket_shutdown (connection->sock,
+                                           SHUT_RDWR);
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_NETWORK_socket_close (connection->sock));
+    connection->sock = NULL;
+    GNUNET_assert (NULL == connection->write_task);
+  }
+  if (NULL != connection->read_task)
+  {
+    /* send errors trigger read errors... */
+    GNUNET_SCHEDULER_cancel (connection->read_task);
+    connection->read_task = NULL;
+    signal_receive_timeout (connection);
+    return;
+  }
+  if (NULL == connection->nth.notify_ready)
+    return;                     /* nobody to tell about it */
+  notify = connection->nth.notify_ready;
+  connection->nth.notify_ready = NULL;
+  notify (connection->nth.notify_ready_cls,
+         0,
+         NULL);
+}
+
+
+/**
+ * We've failed for good to establish a connection (timeout or
+ * no more addresses to try).
+ *
+ * @param connection the connection we tried to establish
+ */
+static void
+connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection)
+{
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n",
+       connection->hostname,
+    connection->port);
+  GNUNET_break (NULL == connection->ap_head);
+  GNUNET_break (NULL == connection->ap_tail);
+  GNUNET_break (GNUNET_NO == connection->dns_active);
+  GNUNET_break (NULL == connection->sock);
+  GNUNET_assert (NULL == connection->write_task);
+  GNUNET_assert (NULL == connection->proxy_handshake);
+
+  /* signal errors for jobs that used to wait on the connection */
+  connection->destroy_later = 1;
+  if (NULL != connection->receiver)
+    signal_receive_error (connection,
+                          ECONNREFUSED);
+  if (NULL != connection->nth.notify_ready)
+  {
+    GNUNET_assert (NULL != connection->nth.timeout_task);
+    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+    connection->nth.timeout_task = NULL;
+    signal_transmit_error (connection,
+                           ECONNREFUSED);
+  }
+  if (-1 == connection->destroy_later)
+  {
+    /* do it now */
+    connection->destroy_later = 0;
+    GNUNET_CONNECTION_destroy (connection);
+    return;
+  }
+  connection->destroy_later = 0;
+}
+
+
+/**
+ * We are ready to transmit (or got a timeout).
+ *
+ * @param cls our connection handle
+ */
+static void
+transmit_ready (void *cls);
+
+
+/**
+ * This function is called once we either timeout or have data ready
+ * to read.
+ *
+ * @param cls connection to read from
+ */
+static void
+receive_ready (void *cls);
+
+
+/**
+ * We've succeeded in establishing a connection.
+ *
+ * @param connection the connection we tried to establish
+ */
+static void
+connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
+{
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Connection to `%s' succeeded! (%p)\n",
+       GNUNET_a2s (connection->addr,
+                  connection->addrlen),
+       connection);
+  /* trigger jobs that waited for the connection */
+  if (NULL != connection->receiver)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Connection succeeded, starting with receiving data (%p)\n",
+        connection);
+    GNUNET_assert (NULL == connection->read_task);
+    connection->read_task =
+      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
+                                     (connection->receive_timeout),
+                                    connection->sock,
+                                     &receive_ready, connection);
+  }
+  if (NULL != connection->nth.notify_ready)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Connection succeeded, starting with sending data (%p)\n",
+         connection);
+    GNUNET_assert (connection->nth.timeout_task != NULL);
+    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+    connection->nth.timeout_task = NULL;
+    GNUNET_assert (connection->write_task == NULL);
+    connection->write_task =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
+                                        (connection->nth.transmit_timeout), connection->sock,
+                                        &transmit_ready, connection);
+  }
+}
+
+
+/**
+ * Scheduler let us know that we're either ready to write on the
+ * socket OR connect timed out.  Do the right thing.
+ *
+ * @param cls the `struct AddressProbe *` with the address that we are probing
+ */
+static void
+connect_probe_continuation (void *cls)
+{
+  struct AddressProbe *ap = cls;
+  struct GNUNET_CONNECTION_Handle *connection = ap->connection;
+  const struct GNUNET_SCHEDULER_TaskContext *tc;
+  struct AddressProbe *pos;
+  int error;
+  socklen_t len;
+
+  GNUNET_assert (NULL != ap->sock);
+  GNUNET_CONTAINER_DLL_remove (connection->ap_head,
+                              connection->ap_tail,
+                              ap);
+  len = sizeof (error);
+  errno = 0;
+  error = 0;
+  tc = GNUNET_SCHEDULER_get_task_context ();
+  if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
+       (GNUNET_OK !=
+       GNUNET_NETWORK_socket_getsockopt (ap->sock,
+                                         SOL_SOCKET,
+                                         SO_ERROR,
+                                         &error,
+                                         &len)) ||
+       (0 != error) )
+  {
+    GNUNET_break (GNUNET_OK ==
+                 GNUNET_NETWORK_socket_close (ap->sock));
+    GNUNET_free (ap);
+    if ( (NULL == connection->ap_head) &&
+        (GNUNET_NO == connection->dns_active) &&
+        (NULL == connection->proxy_handshake) )
+      connect_fail_continuation (connection);
+    return;
+  }
+  GNUNET_assert (NULL == connection->sock);
+  connection->sock = ap->sock;
+  GNUNET_assert (NULL == connection->addr);
+  connection->addr = GNUNET_malloc (ap->addrlen);
+  GNUNET_memcpy (connection->addr, ap->addr, ap->addrlen);
+  connection->addrlen = ap->addrlen;
+  GNUNET_free (ap);
+  /* cancel all other attempts */
+  while (NULL != (pos = connection->ap_head))
+  {
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
+    GNUNET_SCHEDULER_cancel (pos->task);
+    GNUNET_CONTAINER_DLL_remove (connection->ap_head,
+                                connection->ap_tail,
+                                pos);
+    GNUNET_free (pos);
+  }
+  connect_success_continuation (connection);
+}
+
+
+/**
+ * Try to establish a connection given the specified address.
+ * This function is called by the resolver once we have a DNS reply.
+ *
+ * @param cls our `struct GNUNET_CONNECTION_Handle *`
+ * @param addr address to try, NULL for "last call"
+ * @param addrlen length of @a addr
+ */
+static void
+try_connect_using_address (void *cls,
+                           const struct sockaddr *addr,
+                           socklen_t addrlen)
+{
+  struct GNUNET_CONNECTION_Handle *connection = cls;
+  struct AddressProbe *ap;
+  struct GNUNET_TIME_Relative delay;
+
+  if (NULL == addr)
+  {
+    connection->dns_active = NULL;
+    if ((NULL == connection->ap_head) &&
+        (NULL == connection->sock) &&
+        (NULL == connection->proxy_handshake))
+      connect_fail_continuation (connection);
+    return;
+  }
+  if (NULL != connection->sock)
+    return;                     /* already connected */
+  GNUNET_assert (NULL == connection->addr);
+  /* try to connect */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying to connect using address `%s:%u/%s:%u'\n",
+       connection->hostname,
+       connection->port,
+       GNUNET_a2s (addr, addrlen),
+       connection->port);
+  ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
+  ap->addr = (const struct sockaddr *) &ap[1];
+  GNUNET_memcpy (&ap[1], addr, addrlen);
+  ap->addrlen = addrlen;
+  ap->connection = connection;
+
+  switch (ap->addr->sa_family)
+  {
+  case AF_INET:
+    ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port);
+    break;
+  case AF_INET6:
+    ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port);
+    break;
+  default:
+    GNUNET_break (0);
+    GNUNET_free (ap);
+    return;                     /* not supported by us */
+  }
+  ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
+                                          SOCK_STREAM, 0);
+  if (NULL == ap->sock)
+  {
+    GNUNET_free (ap);
+    return;                     /* not supported by OS */
+  }
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Trying to connect to `%s' (%p)\n",
+       GNUNET_a2s (ap->addr, ap->addrlen),
+       connection);
+  if ((GNUNET_OK !=
+       GNUNET_NETWORK_socket_connect (ap->sock,
+                                     ap->addr,
+                                     ap->addrlen)) &&
+      (EINPROGRESS != errno))
+  {
+    /* maybe refused / unsupported address, try next */
+    LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
+    GNUNET_free (ap);
+    return;
+  }
+  GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
+  delay = CONNECT_RETRY_TIMEOUT;
+  if (NULL != connection->nth.notify_ready)
+    delay = GNUNET_TIME_relative_min (delay,
+                                     GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout));
+  if (NULL != connection->receiver)
+    delay = GNUNET_TIME_relative_min (delay,
+                                     GNUNET_TIME_absolute_get_remaining (connection->receive_timeout));
+  ap->task = GNUNET_SCHEDULER_add_write_net (delay,
+                                            ap->sock,
+                                            &connect_probe_continuation,
+                                            ap);
+}
+
+
+/**
+ * Create a connection handle by (asynchronously) connecting to a host.
+ * This function returns immediately, even if the connection has not
+ * yet been established.  This function only creates TCP connections.
+ *
+ * @param cfg configuration to use
+ * @param hostname name of the host to connect to
+ * @param port port to connect to
+ * @return the connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                                       const char *hostname,
+                                       uint16_t port)
+{
+  struct GNUNET_CONNECTION_Handle *connection;
+
+  GNUNET_assert (0 < strlen (hostname));        /* sanity check */
+  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+  connection->cfg = cfg;
+  connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
+  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+  connection->port = port;
+  connection->hostname = GNUNET_strdup (hostname);
+  connection->dns_active =
+      GNUNET_RESOLVER_ip_get (connection->hostname,
+                             AF_UNSPEC,
+                              CONNECT_RETRY_TIMEOUT,
+                              &try_connect_using_address,
+                             connection);
+  return connection;
+}
+
+
+/**
+ * Create a connection handle by connecting to a UNIX domain service.
+ * This function returns immediately, even if the connection has not
+ * yet been established.  This function only creates UNIX connections.
+ *
+ * @param cfg configuration to use
+ * @param unixpath path to connect to
+ * @return the connection handle, NULL on systems without UNIX support
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                                                   const char *unixpath)
+{
+#ifdef AF_UNIX
+  struct GNUNET_CONNECTION_Handle *connection;
+  struct sockaddr_un *un;
+
+  GNUNET_assert (0 < strlen (unixpath));        /* sanity check */
+  un = GNUNET_new (struct sockaddr_un);
+  un->sun_family = AF_UNIX;
+  strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+  {
+    int abstract;
+
+    abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                                    "TESTING",
+                                                     "USE_ABSTRACT_SOCKETS");
+    if (GNUNET_YES == abstract)
+      un->sun_path[0] = '\0';
+  }
+#endif
+#if HAVE_SOCKADDR_UN_SUN_LEN
+  un->sun_len = (u_char) sizeof (struct sockaddr_un);
+#endif
+  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+  connection->cfg = cfg;
+  connection->write_buffer_size = GNUNET_MIN_MESSAGE_SIZE;
+  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+  connection->port = 0;
+  connection->hostname = NULL;
+  connection->addr = (struct sockaddr *) un;
+  connection->addrlen = sizeof (struct sockaddr_un);
+  connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX,
+                                                  SOCK_STREAM,
+                                                  0);
+  if (NULL == connection->sock)
+  {
+    GNUNET_free (connection->addr);
+    GNUNET_free (connection->write_buffer);
+    GNUNET_free (connection);
+    return NULL;
+  }
+  if ( (GNUNET_OK !=
+       GNUNET_NETWORK_socket_connect (connection->sock,
+                                      connection->addr,
+                                      connection->addrlen)) &&
+       (EINPROGRESS != errno) )
+  {
+    /* Just return; we expect everything to work eventually so don't fail HARD */
+    GNUNET_break (GNUNET_OK ==
+                 GNUNET_NETWORK_socket_close (connection->sock));
+    connection->sock = NULL;
+    return connection;
+  }
+  connect_success_continuation (connection);
+  return connection;
+#else
+  return NULL;
+#endif
+}
+
+
+/**
+ * Create a connection handle by (asynchronously) connecting to a host.
+ * This function returns immediately, even if the connection has not
+ * yet been established.  This function only creates TCP connections.
+ *
+ * @param s socket to connect
+ * @param serv_addr server address
+ * @param addrlen length of @a serv_addr
+ * @return the connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
+                                  const struct sockaddr *serv_addr,
+                                  socklen_t addrlen)
+{
+  struct GNUNET_CONNECTION_Handle *connection;
+
+  if ( (GNUNET_OK !=
+        GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) &&
+       (EINPROGRESS != errno) )
+  {
+    /* maybe refused / unsupported address, try next */
+    LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
+                  "connect");
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Attempt to connect to `%s' failed\n",
+         GNUNET_a2s (serv_addr,
+                     addrlen));
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
+    return NULL;
+  }
+  connection = GNUNET_CONNECTION_create_from_existing (s);
+  connection->addr = GNUNET_malloc (addrlen);
+  GNUNET_memcpy (connection->addr, serv_addr, addrlen);
+  connection->addrlen = addrlen;
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Trying to connect to `%s' (%p)\n",
+       GNUNET_a2s (serv_addr, addrlen),
+       connection);
+  return connection;
+}
+
+
+/**
+ * Create a connection handle by creating a socket and
+ * (asynchronously) connecting to a host.  This function returns
+ * immediately, even if the connection has not yet been established.
+ * This function only creates TCP connections.
+ *
+ * @param af_family address family to use
+ * @param serv_addr server address
+ * @param addrlen length of @a serv_addr
+ * @return the connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_sockaddr (int af_family,
+                                        const struct sockaddr *serv_addr,
+                                        socklen_t addrlen)
+{
+  struct GNUNET_NETWORK_Handle *s;
+
+  s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
+  if (NULL == s)
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+                 "socket");
+    return NULL;
+  }
+  return GNUNET_CONNECTION_connect_socket (s,
+                                          serv_addr,
+                                          addrlen);
+}
+
+
+/**
+ * Check if connection is valid (no fatal errors have happened so far).
+ * Note that a connection that is still trying to connect is considered
+ * valid.
+ *
+ * @param connection connection to check
+ * @return #GNUNET_YES if valid, #GNUNET_NO otherwise
+ */
+int
+GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection)
+{
+  if ((NULL != connection->ap_head) ||
+      (NULL != connection->dns_active) ||
+      (NULL != connection->proxy_handshake))
+    return GNUNET_YES;          /* still trying to connect */
+  if ( (0 != connection->destroy_later) ||
+       (NULL == connection->sock) )
+    return GNUNET_NO;
+  return GNUNET_YES;
+}
+
+
+/**
+ * Close the connection and free associated resources.  There must
+ * not be any pending requests for reading or writing to the
+ * connection at this time.
+ *
+ * @param connection connection to destroy
+ */
+void
+GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
+{
+  struct AddressProbe *pos;
+
+  if (0 != connection->destroy_later)
+  {
+    connection->destroy_later = -1;
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Shutting down connection (%p)\n",
+       connection);
+  GNUNET_assert (NULL == connection->nth.notify_ready);
+  GNUNET_assert (NULL == connection->receiver);
+  if (NULL != connection->write_task)
+  {
+    GNUNET_SCHEDULER_cancel (connection->write_task);
+    connection->write_task = NULL;
+    connection->write_buffer_off = 0;
+  }
+  if (NULL != connection->read_task)
+  {
+    GNUNET_SCHEDULER_cancel (connection->read_task);
+    connection->read_task = NULL;
+  }
+  if (NULL != connection->nth.timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+    connection->nth.timeout_task = NULL;
+  }
+  connection->nth.notify_ready = NULL;
+  if (NULL != connection->dns_active)
+  {
+    GNUNET_RESOLVER_request_cancel (connection->dns_active);
+    connection->dns_active = NULL;
+  }
+  if (NULL != connection->proxy_handshake)
+  {
+    /* GNUNET_CONNECTION_destroy (connection->proxy_handshake); */
+    connection->proxy_handshake->destroy_later = -1;
+    connection->proxy_handshake = NULL;  /* Not leaked ??? */
+  }
+  while (NULL != (pos = connection->ap_head))
+  {
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
+    GNUNET_SCHEDULER_cancel (pos->task);
+    GNUNET_CONTAINER_DLL_remove (connection->ap_head,
+                                connection->ap_tail,
+                                pos);
+    GNUNET_free (pos);
+  }
+  if ( (NULL != connection->sock) &&
+       (GNUNET_YES != connection->persist) )
+  {
+    if ((GNUNET_OK !=
+         GNUNET_NETWORK_socket_shutdown (connection->sock,
+                                         SHUT_RDWR)) &&
+       (ENOTCONN != errno) &&
+       (ECONNRESET != errno) )
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+                    "shutdown");
+  }
+  if (NULL != connection->sock)
+  {
+    if (GNUNET_YES != connection->persist)
+    {
+      GNUNET_break (GNUNET_OK ==
+                    GNUNET_NETWORK_socket_close (connection->sock));
+    }
+    else
+    {
+      GNUNET_NETWORK_socket_free_memory_only_ (connection->sock); /* at least no memory leak (we deliberately
+                                                                  * leak the socket in this special case) ... */
+    }
+  }
+  GNUNET_free_non_null (connection->addr);
+  GNUNET_free_non_null (connection->hostname);
+  GNUNET_free (connection->write_buffer);
+  GNUNET_free (connection);
+}
+
+
+/**
+ * This function is called once we either timeout
+ * or have data ready to read.
+ *
+ * @param cls connection to read from
+ */
+static void
+receive_ready (void *cls)
+{
+  struct GNUNET_CONNECTION_Handle *connection = cls;
+  const struct GNUNET_SCHEDULER_TaskContext *tc;
+  char buffer[connection->max];
+  ssize_t ret;
+  GNUNET_CONNECTION_Receiver receiver;
+
+  connection->read_task = NULL;
+  tc = GNUNET_SCHEDULER_get_task_context ();
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Receive from `%s' encounters error: timeout (%s, %p)\n",
+        GNUNET_a2s (connection->addr,
+                    connection->addrlen),
+        GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (connection->receive_timeout),
+                                                GNUNET_YES),
+        connection);
+    signal_receive_timeout (connection);
+    return;
+  }
+  if (NULL == connection->sock)
+  {
+    /* connect failed for good */
+    signal_receive_error (connection, ECONNREFUSED);
+    return;
+  }
+  GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready,
+                                            connection->sock));
+RETRY:
+  ret = GNUNET_NETWORK_socket_recv (connection->sock,
+                                    buffer,
+                                    connection->max);
+  if (-1 == ret)
+  {
+    if (EINTR == errno)
+      goto RETRY;
+    signal_receive_error (connection, errno);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "receive_ready read %u/%u bytes from `%s' (%p)!\n",
+       (unsigned int) ret,
+       connection->max,
+       GNUNET_a2s (connection->addr,
+                   connection->addrlen),
+       connection);
+  GNUNET_assert (NULL != (receiver = connection->receiver));
+  connection->receiver = NULL;
+  receiver (connection->receiver_cls,
+            buffer,
+            ret,
+            connection->addr,
+            connection->addrlen,
+            0);
+}
+
+
+/**
+ * Receive data from the given connection.  Note that this function
+ * will call @a receiver asynchronously using the scheduler.  It will
+ * "immediately" return.  Note that there MUST only be one active
+ * receive call per connection at any given point in time (so do not
+ * call receive again until the receiver callback has been invoked).
+ *
+ * @param connection connection handle
+ * @param max maximum number of bytes to read
+ * @param timeout maximum amount of time to wait
+ * @param receiver function to call with received data
+ * @param receiver_cls closure for @a receiver
+ */
+void
+GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection,
+                           size_t max,
+                           struct GNUNET_TIME_Relative timeout,
+                           GNUNET_CONNECTION_Receiver receiver,
+                           void *receiver_cls)
+{
+  GNUNET_assert ((NULL == connection->read_task) &&
+                 (NULL == connection->receiver));
+  GNUNET_assert (NULL != receiver);
+  connection->receiver = receiver;
+  connection->receiver_cls = receiver_cls;
+  connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
+  connection->max = max;
+  if (NULL != connection->sock)
+  {
+    connection->read_task =
+      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
+                                     (connection->receive_timeout),
+                                     connection->sock,
+                                     &receive_ready,
+                                     connection);
+    return;
+  }
+  if ((NULL == connection->dns_active) &&
+      (NULL == connection->ap_head) &&
+      (NULL == connection->proxy_handshake))
+  {
+    connection->receiver = NULL;
+    receiver (receiver_cls,
+             NULL, 0,
+             NULL, 0,
+             ETIMEDOUT);
+    return;
+  }
+}
+
+
+/**
+ * Cancel receive job on the given connection.  Note that the
+ * receiver callback must not have been called yet in order
+ * for the cancellation to be valid.
+ *
+ * @param connection connection handle
+ * @return closure of the original receiver callback closure
+ */
+void *
+GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
+{
+  if (NULL != connection->read_task)
+  {
+    GNUNET_assert (connection ==
+                   GNUNET_SCHEDULER_cancel (connection->read_task));
+    connection->read_task = NULL;
+  }
+  connection->receiver = NULL;
+  return connection->receiver_cls;
+}
+
+
+/**
+ * Try to call the transmit notify method (check if we do
+ * have enough space available first)!
+ *
+ * @param connection connection for which we should do this processing
+ * @return #GNUNET_YES if we were able to call notify
+ */
+static int
+process_notify (struct GNUNET_CONNECTION_Handle *connection)
+{
+  size_t used;
+  size_t avail;
+  size_t size;
+  GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "process_notify is running\n");
+  GNUNET_assert (NULL == connection->write_task);
+  if (NULL == (notify = connection->nth.notify_ready))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "No one to notify\n");
+    return GNUNET_NO;
+  }
+  used = connection->write_buffer_off - connection->write_buffer_pos;
+  avail = connection->write_buffer_size - used;
+  size = connection->nth.notify_size;
+  if (size > avail)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Not enough buffer\n");
+    return GNUNET_NO;
+  }
+  connection->nth.notify_ready = NULL;
+  if (connection->write_buffer_size - connection->write_buffer_off < size)
+  {
+    /* need to compact */
+    memmove (connection->write_buffer,
+             &connection->write_buffer[connection->write_buffer_pos],
+             used);
+    connection->write_buffer_off -= connection->write_buffer_pos;
+    connection->write_buffer_pos = 0;
+  }
+  avail = connection->write_buffer_size - connection->write_buffer_off;
+  GNUNET_assert (avail >= size);
+  size =
+      notify (connection->nth.notify_ready_cls, avail,
+              &connection->write_buffer[connection->write_buffer_off]);
+  GNUNET_assert (size <= avail);
+  if (0 != size)
+    connection->write_buffer_off += size;
+  return GNUNET_YES;
+}
+
+
+/**
+ * Task invoked by the scheduler when a call to transmit
+ * is timing out (we never got enough buffer space to call
+ * the callback function before the specified timeout
+ * expired).
+ *
+ * This task notifies the client about the timeout.
+ *
+ * @param cls the `struct GNUNET_CONNECTION_Handle`
+ */
+static void
+transmit_timeout (void *cls)
+{
+  struct GNUNET_CONNECTION_Handle *connection = cls;
+  GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+  connection->nth.timeout_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Transmit to `%s:%u/%s' fails, time out reached (%p).\n",
+       connection->hostname,
+       connection->port,
+       GNUNET_a2s (connection->addr,
+                   connection->addrlen),
+       connection);
+  notify = connection->nth.notify_ready;
+  GNUNET_assert (NULL != notify);
+  connection->nth.notify_ready = NULL;
+  notify (connection->nth.notify_ready_cls,
+         0,
+         NULL);
+}
+
+
+/**
+ * Task invoked by the scheduler when we failed to connect
+ * at the time of being asked to transmit.
+ *
+ * This task notifies the client about the error.
+ *
+ * @param cls the `struct GNUNET_CONNECTION_Handle`
+ */
+static void
+connect_error (void *cls)
+{
+  struct GNUNET_CONNECTION_Handle *connection = cls;
+  GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Transmission request of size %u fails (%s/%u), connection failed (%p).\n",
+       connection->nth.notify_size,
+       connection->hostname,
+       connection->port,
+       connection);
+  connection->write_task = NULL;
+  notify = connection->nth.notify_ready;
+  connection->nth.notify_ready = NULL;
+  notify (connection->nth.notify_ready_cls,
+         0,
+         NULL);
+}
+
+
+/**
+ * We are ready to transmit (or got a timeout).
+ *
+ * @param cls our connection handle
+ */
+static void
+transmit_ready (void *cls)
+{
+  struct GNUNET_CONNECTION_Handle *connection = cls;
+  GNUNET_CONNECTION_TransmitReadyNotify notify;
+  const struct GNUNET_SCHEDULER_TaskContext *tc;
+  ssize_t ret;
+  size_t have;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "transmit_ready running (%p).\n",
+       connection);
+  GNUNET_assert (NULL != connection->write_task);
+  connection->write_task = NULL;
+  GNUNET_assert (NULL == connection->nth.timeout_task);
+  tc = GNUNET_SCHEDULER_get_task_context ();
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Transmit to `%s' fails, time out reached (%p).\n",
+         GNUNET_a2s (connection->addr,
+                     connection->addrlen),
+         connection);
+    notify = connection->nth.notify_ready;
+    GNUNET_assert (NULL != notify);
+    connection->nth.notify_ready = NULL;
+    notify (connection->nth.notify_ready_cls, 0, NULL);
+    return;
+  }
+  GNUNET_assert (NULL != connection->sock);
+  if (NULL == tc->write_ready)
+  {
+    /* special circumstances (in particular, PREREQ_DONE after
+     * connect): not yet ready to write, but no "fatal" error either.
+     * Hence retry.  */
+    goto SCHEDULE_WRITE;
+  }
+  if (! GNUNET_NETWORK_fdset_isset (tc->write_ready,
+                                   connection->sock))
+  {
+    GNUNET_assert (NULL == connection->write_task);
+    /* special circumstances (in particular, shutdown): not yet ready
+     * to write, but no "fatal" error either.  Hence retry.  */
+    goto SCHEDULE_WRITE;
+  }
+  GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos);
+  if ((NULL != connection->nth.notify_ready) &&
+      (connection->write_buffer_size < connection->nth.notify_size))
+  {
+    connection->write_buffer =
+        GNUNET_realloc (connection->write_buffer, connection->nth.notify_size);
+    connection->write_buffer_size = connection->nth.notify_size;
+  }
+  process_notify (connection);
+  have = connection->write_buffer_off - connection->write_buffer_pos;
+  if (0 == have)
+  {
+    /* no data ready for writing, terminate write loop */
+    return;
+  }
+  GNUNET_assert (have <= connection->write_buffer_size);
+  GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size);
+  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
+RETRY:
+  ret =
+      GNUNET_NETWORK_socket_send (connection->sock,
+                                 &connection->write_buffer[connection->write_buffer_pos],
+                                 have);
+  if (-1 == ret)
+  {
+    if (EINTR == errno)
+      goto RETRY;
+    if (NULL != connection->write_task)
+    {
+      GNUNET_SCHEDULER_cancel (connection->write_task);
+      connection->write_task = NULL;
+    }
+    signal_transmit_error (connection, errno);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Connection transmitted %u/%u bytes to `%s' (%p)\n",
+       (unsigned int) ret,
+       have,
+       GNUNET_a2s (connection->addr,
+                  connection->addrlen),
+       connection);
+  connection->write_buffer_pos += ret;
+  if (connection->write_buffer_pos == connection->write_buffer_off)
+  {
+    /* transmitted all pending data */
+    connection->write_buffer_pos = 0;
+    connection->write_buffer_off = 0;
+  }
+  if ( (0 == connection->write_buffer_off) &&
+       (NULL == connection->nth.notify_ready) )
+    return;                     /* all data sent! */
+  /* not done writing, schedule more */
+SCHEDULE_WRITE:
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Re-scheduling transmit_ready (more to do) (%p).\n",
+       connection);
+  have = connection->write_buffer_off - connection->write_buffer_pos;
+  GNUNET_assert ( (NULL != connection->nth.notify_ready) ||
+                 (have > 0) );
+  if (NULL == connection->write_task)
+    connection->write_task =
+        GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready ==
+                                         NULL) ? GNUNET_TIME_UNIT_FOREVER_REL :
+                                        GNUNET_TIME_absolute_get_remaining
+                                        (connection->nth.transmit_timeout),
+                                        connection->sock,
+                                       &transmit_ready, connection);
+}
+
+
+/**
+ * Ask the connection to call us once the specified number of bytes
+ * are free in the transmission buffer.  Will never call the @a notify
+ * callback in this task, but always first go into the scheduler.
+ *
+ * @param connection connection
+ * @param size number of bytes to send
+ * @param timeout after how long should we give up (and call
+ *        @a notify with buf NULL and size 0)?
+ * @param notify function to call
+ * @param notify_cls closure for @a notify
+ * @return non-NULL if the notify callback was queued,
+ *         NULL if we are already going to notify someone else (busy)
+ */
+struct GNUNET_CONNECTION_TransmitHandle *
+GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
+                                         size_t size,
+                                         struct GNUNET_TIME_Relative timeout,
+                                         GNUNET_CONNECTION_TransmitReadyNotify notify,
+                                        void *notify_cls)
+{
+  if (NULL != connection->nth.notify_ready)
+  {
+    GNUNET_assert (0);
+    return NULL;
+  }
+  GNUNET_assert (NULL != notify);
+  GNUNET_assert (size < GNUNET_MAX_MESSAGE_SIZE);
+  GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
+  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
+  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off);
+  connection->nth.notify_ready = notify;
+  connection->nth.notify_ready_cls = notify_cls;
+  connection->nth.connection = connection;
+  connection->nth.notify_size = size;
+  connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
+  GNUNET_assert (NULL == connection->nth.timeout_task);
+  if ((NULL == connection->sock) &&
+      (NULL == connection->ap_head) &&
+      (NULL == connection->dns_active) &&
+      (NULL == connection->proxy_handshake))
+  {
+    if (NULL != connection->write_task)
+      GNUNET_SCHEDULER_cancel (connection->write_task);
+    connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error,
+                                                       connection);
+    return &connection->nth;
+  }
+  if (NULL != connection->write_task)
+    return &connection->nth; /* previous transmission still in progress */
+  if (NULL != connection->sock)
+  {
+    /* connected, try to transmit now */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Scheduling transmission (%p).\n",
+         connection);
+    connection->write_task =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
+                                        (connection->nth.transmit_timeout),
+                                        connection->sock,
+                                       &transmit_ready, connection);
+    return &connection->nth;
+  }
+  /* not yet connected, wait for connection */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Need to wait to schedule transmission for connection, adding timeout task (%p).\n",
+       connection);
+  connection->nth.timeout_task =
+    GNUNET_SCHEDULER_add_delayed (timeout,
+                                  &transmit_timeout,
+                                 connection);
+  return &connection->nth;
+}
+
+
+/**
+ * Cancel the specified transmission-ready notification.
+ *
+ * @param th notification to cancel
+ */
+void
+GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th)
+{
+  GNUNET_assert (NULL != th->notify_ready);
+  th->notify_ready = NULL;
+  if (NULL != th->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (th->timeout_task);
+    th->timeout_task = NULL;
+  }
+  if (NULL != th->connection->write_task)
+  {
+    GNUNET_SCHEDULER_cancel (th->connection->write_task);
+    th->connection->write_task = NULL;
+  }
+}
+
+
+/**
+ * Create a connection to be proxied using a given connection.
+ *
+ * @param cph connection to proxy server
+ * @return connection to be proxied
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph)
+{
+  struct GNUNET_CONNECTION_Handle *proxied = GNUNET_CONNECTION_create_from_existing (NULL);
+
+  proxied->proxy_handshake = cph;
+  return proxied;
+}
+
+
+/**
+ * Activate proxied connection and destroy initial proxy handshake connection.
+ * There must not be any pending requests for reading or writing to the
+ * proxy hadshake connection at this time.
+ *
+ * @param proxied connection connection to proxy server
+ */
+void
+GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied)
+{
+  struct GNUNET_CONNECTION_Handle *cph = proxied->proxy_handshake;
+
+  GNUNET_assert (NULL != cph);
+  GNUNET_assert (NULL == proxied->sock);
+  GNUNET_assert (NULL != cph->sock);
+  proxied->sock = cph->sock;
+  cph->sock = NULL;
+  GNUNET_CONNECTION_destroy (cph);
+  connect_success_continuation (proxied);
+}
+
+
+/* end of connection.c */
diff --git a/src/transport/tcp_server_legacy.c b/src/transport/tcp_server_legacy.c
new file mode 100644 (file)
index 0000000..6b4daa5
--- /dev/null
@@ -0,0 +1,1748 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009-2013 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/server.c
+ * @brief library for building GNUnet network servers
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename)
+
+
+/**
+ * List of arrays of message handlers.
+ */
+struct HandlerList
+{
+  /**
+   * This is a linked list.
+   */
+  struct HandlerList *next;
+
+  /**
+   * NULL-terminated array of handlers.
+   */
+  const struct GNUNET_SERVER_MessageHandler *handlers;
+};
+
+
+/**
+ * List of arrays of message handlers.
+ */
+struct NotifyList
+{
+  /**
+   * This is a doubly linked list.
+   */
+  struct NotifyList *next;
+
+  /**
+   * This is a doubly linked list.
+   */
+  struct NotifyList *prev;
+
+  /**
+   * Function to call.
+   */
+  GNUNET_SERVER_DisconnectCallback callback;
+
+  /**
+   * Closure for callback.
+   */
+  void *callback_cls;
+};
+
+
+/**
+ * @brief handle for a server
+ */
+struct GNUNET_SERVER_Handle
+{
+  /**
+   * List of handlers for incoming messages.
+   */
+  struct HandlerList *handlers;
+
+  /**
+   * Head of list of our current clients.
+   */
+  struct GNUNET_SERVER_Client *clients_head;
+
+  /**
+   * Head of list of our current clients.
+   */
+  struct GNUNET_SERVER_Client *clients_tail;
+
+  /**
+   * Head of linked list of functions to call on disconnects by clients.
+   */
+  struct NotifyList *disconnect_notify_list_head;
+
+  /**
+   * Tail of linked list of functions to call on disconnects by clients.
+   */
+  struct NotifyList *disconnect_notify_list_tail;
+
+  /**
+   * Head of linked list of functions to call on connects by clients.
+   */
+  struct NotifyList *connect_notify_list_head;
+
+  /**
+   * Tail of linked list of functions to call on connects by clients.
+   */
+  struct NotifyList *connect_notify_list_tail;
+
+  /**
+   * Function to call for access control.
+   */
+  GNUNET_CONNECTION_AccessCheck access_cb;
+
+  /**
+   * Closure for @e access_cb.
+   */
+  void *access_cb_cls;
+
+  /**
+   * NULL-terminated array of sockets used to listen for new
+   * connections.
+   */
+  struct GNUNET_NETWORK_Handle **listen_sockets;
+
+  /**
+   * After how long should an idle connection time
+   * out (on write).
+   */
+  struct GNUNET_TIME_Relative idle_timeout;
+
+  /**
+   * Task scheduled to do the listening.
+   */
+  struct GNUNET_SCHEDULER_Task * listen_task;
+
+  /**
+   * Alternative function to create a MST instance.
+   */
+  GNUNET_SERVER_MstCreateCallback mst_create;
+
+  /**
+   * Alternative function to destroy a MST instance.
+   */
+  GNUNET_SERVER_MstDestroyCallback mst_destroy;
+
+  /**
+   * Alternative function to give data to a MST instance.
+   */
+  GNUNET_SERVER_MstReceiveCallback mst_receive;
+
+  /**
+   * Closure for 'mst_'-callbacks.
+   */
+  void *mst_cls;
+
+  /**
+   * Do we ignore messages of types that we do not understand or do we
+   * require that a handler is found (and if not kill the connection)?
+   */
+  int require_found;
+
+  /**
+   * Set to #GNUNET_YES once we are in 'soft' shutdown where we wait for
+   * all non-monitor clients to disconnect before we call
+   * #GNUNET_SERVER_destroy.  See test_monitor_clients().  Set to
+   * #GNUNET_SYSERR once the final destroy task has been scheduled
+   * (we cannot run it in the same task).
+   */
+  int in_soft_shutdown;
+};
+
+
+/**
+ * Handle server returns for aborting transmission to a client.
+ */
+struct GNUNET_SERVER_TransmitHandle
+{
+  /**
+   * Function to call to get the message.
+   */
+  GNUNET_CONNECTION_TransmitReadyNotify callback;
+
+  /**
+   * Closure for @e callback
+   */
+  void *callback_cls;
+
+  /**
+   * Active connection transmission handle.
+   */
+  struct GNUNET_CONNECTION_TransmitHandle *cth;
+
+};
+
+
+/**
+ * @brief handle for a client of the server
+ */
+struct GNUNET_SERVER_Client
+{
+
+  /**
+   * This is a doubly linked list.
+   */
+  struct GNUNET_SERVER_Client *next;
+
+  /**
+   * This is a doubly linked list.
+   */
+  struct GNUNET_SERVER_Client *prev;
+
+  /**
+   * Processing of incoming data.
+   */
+  void *mst;
+
+  /**
+   * Server that this client belongs to.
+   */
+  struct GNUNET_SERVER_Handle *server;
+
+  /**
+   * Client closure for callbacks.
+   */
+  struct GNUNET_CONNECTION_Handle *connection;
+
+  /**
+   * User context value, manipulated using
+   * 'GNUNET_SERVER_client_{get/set}_user_context' functions.
+   */
+  void *user_context;
+
+  /**
+   * ID of task used to restart processing.
+   */
+  struct GNUNET_SCHEDULER_Task * restart_task;
+
+  /**
+   * Task that warns about missing calls to #GNUNET_SERVER_receive_done.
+   */
+  struct GNUNET_SCHEDULER_Task * warn_task;
+
+  /**
+   * Time when the warn task was started.
+   */
+  struct GNUNET_TIME_Absolute warn_start;
+
+  /**
+   * Last activity on this socket (used to time it out
+   * if reference_count == 0).
+   */
+  struct GNUNET_TIME_Absolute last_activity;
+
+  /**
+   * Transmission handle we return for this client from
+   * #GNUNET_SERVER_notify_transmit_ready.
+   */
+  struct GNUNET_SERVER_TransmitHandle th;
+
+  /**
+   * After how long should an idle connection time
+   * out (on write).
+   */
+  struct GNUNET_TIME_Relative idle_timeout;
+
+  /**
+   * Number of external entities with a reference to
+   * this client object.
+   */
+  unsigned int reference_count;
+
+  /**
+   * Was processing if incoming messages suspended while
+   * we were still processing data already received?
+   * This is a counter saying how often processing was
+   * suspended (once per handler invoked).
+   */
+  unsigned int suspended;
+
+  /**
+   * Last size given when user context was initialized; used for
+   * sanity check.
+   */
+  size_t user_context_size;
+
+  /**
+   * Are we currently in the "process_client_buffer" function (and
+   * will hence restart the receive job on exit if suspended == 0 once
+   * we are done?).  If this is set, then "receive_done" will
+   * essentially only decrement suspended; if this is not set, then
+   * "receive_done" may need to restart the receive process (either
+   * from the side-buffer or via select/recv).
+   */
+  int in_process_client_buffer;
+
+  /**
+   * We're about to close down this client.
+   */
+  int shutdown_now;
+
+  /**
+   * Are we currently trying to receive? (#GNUNET_YES if we are,
+   * #GNUNET_NO if we are not, #GNUNET_SYSERR if data is already
+   * available in MST).
+   */
+  int receive_pending;
+
+  /**
+   * Persist the file handle for this client no matter what happens,
+   * force the OS to close once the process actually dies.  Should only
+   * be used in special cases!
+   */
+  int persist;
+
+  /**
+   * Is this client a 'monitor' client that should not be counted
+   * when deciding on destroying the server during soft shutdown?
+   * (see also #GNUNET_SERVICE_start)
+   */
+  int is_monitor;
+
+  /**
+   * Type of last message processed (for warn_no_receive_done).
+   */
+  uint16_t warn_type;
+};
+
+
+
+/**
+ * Return user context associated with the given client.
+ * Note: you should probably use the macro (call without the underscore).
+ *
+ * @param client client to query
+ * @param size number of bytes in user context struct (for verification only)
+ * @return pointer to user context
+ */
+void *
+GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
+                                       size_t size)
+{
+  if ((0 == client->user_context_size) &&
+      (NULL == client->user_context))
+    return NULL; /* never set */
+  GNUNET_assert (size == client->user_context_size);
+  return client->user_context;
+}
+
+
+/**
+ * Set user context to be associated with the given client.
+ * Note: you should probably use the macro (call without the underscore).
+ *
+ * @param client client to query
+ * @param ptr pointer to user context
+ * @param size number of bytes in user context struct (for verification only)
+ */
+void
+GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
+                                       void *ptr,
+                                       size_t size)
+{
+  if (NULL == ptr)
+  {
+    client->user_context_size = 0;
+    client->user_context = ptr;
+    return;
+  }
+  client->user_context_size = size;
+  client->user_context = ptr;
+}
+
+
+/**
+ * Scheduler says our listen socket is ready.  Process it!
+ *
+ * @param cls handle to our server for which we are processing the listen
+ *        socket
+ */
+static void
+process_listen_socket (void *cls)
+{
+  struct GNUNET_SERVER_Handle *server = cls;
+  const struct GNUNET_SCHEDULER_TaskContext *tc;
+  struct GNUNET_CONNECTION_Handle *sock;
+  unsigned int i;
+
+  server->listen_task = NULL;
+  tc = GNUNET_SCHEDULER_get_task_context ();
+  for (i = 0; NULL != server->listen_sockets[i]; i++)
+  {
+    if (GNUNET_NETWORK_fdset_isset (tc->read_ready,
+                                    server->listen_sockets[i]))
+    {
+      sock =
+          GNUNET_CONNECTION_create_from_accept (server->access_cb,
+                                                server->access_cb_cls,
+                                                server->listen_sockets[i]);
+      if (NULL != sock)
+      {
+        LOG (GNUNET_ERROR_TYPE_DEBUG,
+             "Server accepted incoming connection.\n");
+        (void) GNUNET_SERVER_connect_socket (server,
+                                             sock);
+      }
+    }
+  }
+  /* listen for more! */
+  GNUNET_SERVER_resume (server);
+}
+
+
+/**
+ * Create and initialize a listen socket for the server.
+ *
+ * @param server_addr address to listen on
+ * @param socklen length of @a server_addr
+ * @return NULL on error, otherwise the listen socket
+ */
+static struct GNUNET_NETWORK_Handle *
+open_listen_socket (const struct sockaddr *server_addr,
+                   socklen_t socklen)
+{
+  struct GNUNET_NETWORK_Handle *sock;
+  uint16_t port;
+  int eno;
+
+  switch (server_addr->sa_family)
+  {
+  case AF_INET:
+    port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
+    break;
+  case AF_INET6:
+    port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
+    break;
+  case AF_UNIX:
+    port = 0;
+    break;
+  default:
+    GNUNET_break (0);
+    port = 0;
+    break;
+  }
+  sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0);
+  if (NULL == sock)
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+    errno = 0;
+    return NULL;
+  }
+  /* bind the socket */
+  if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen))
+  {
+    eno = errno;
+    if (EADDRINUSE != errno)
+    {
+      /* we don't log 'EADDRINUSE' here since an IPv4 bind may
+       * fail if we already took the port on IPv6; if both IPv4 and
+       * IPv6 binds fail, then our caller will log using the
+       * errno preserved in 'eno' */
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                    "bind");
+      if (0 != port)
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _("`%s' failed for port %d (%s).\n"),
+             "bind",
+             port,
+             (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
+      eno = 0;
+    }
+    else
+    {
+      if (0 != port)
+        LOG (GNUNET_ERROR_TYPE_WARNING,
+             _("`%s' failed for port %d (%s): address already in use\n"),
+             "bind", port,
+             (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
+      else if (AF_UNIX == server_addr->sa_family)
+      {
+        LOG (GNUNET_ERROR_TYPE_WARNING,
+             _("`%s' failed for `%s': address already in use\n"),
+             "bind",
+             GNUNET_a2s (server_addr, socklen));
+      }
+    }
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    errno = eno;
+    return NULL;
+  }
+  if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                  "listen");
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    errno = 0;
+    return NULL;
+  }
+  if (0 != port)
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Server starts to listen on port %u.\n",
+         port);
+  return sock;
+}
+
+
+/**
+ * Create a new server.
+ *
+ * @param access_cb function for access control
+ * @param access_cb_cls closure for @a access_cb
+ * @param lsocks NULL-terminated array of listen sockets
+ * @param idle_timeout after how long should we timeout idle connections?
+ * @param require_found if #GNUNET_YES, connections sending messages of unknown type
+ *        will be closed
+ * @return handle for the new server, NULL on error
+ *         (typically, "port" already in use)
+ */
+struct GNUNET_SERVER_Handle *
+GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
+                                   void *access_cb_cls,
+                                   struct GNUNET_NETWORK_Handle **lsocks,
+                                   struct GNUNET_TIME_Relative idle_timeout,
+                                   int require_found)
+{
+  struct GNUNET_SERVER_Handle *server;
+
+  server = GNUNET_new (struct GNUNET_SERVER_Handle);
+  server->idle_timeout = idle_timeout;
+  server->listen_sockets = lsocks;
+  server->access_cb = access_cb;
+  server->access_cb_cls = access_cb_cls;
+  server->require_found = require_found;
+  if (NULL != lsocks)
+    GNUNET_SERVER_resume (server);
+  return server;
+}
+
+
+/**
+ * Create a new server.
+ *
+ * @param access_cb function for access control
+ * @param access_cb_cls closure for @a access_cb
+ * @param server_addr address to listen on (including port), NULL terminated array
+ * @param socklen length of server_addr
+ * @param idle_timeout after how long should we timeout idle connections?
+ * @param require_found if YES, connections sending messages of unknown type
+ *        will be closed
+ * @return handle for the new server, NULL on error
+ *         (typically, "port" already in use)
+ */
+struct GNUNET_SERVER_Handle *
+GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
+                     void *access_cb_cls,
+                      struct sockaddr *const *server_addr,
+                      const socklen_t * socklen,
+                      struct GNUNET_TIME_Relative idle_timeout,
+                      int require_found)
+{
+  struct GNUNET_NETWORK_Handle **lsocks;
+  unsigned int i;
+  unsigned int j;
+  unsigned int k;
+  int seen;
+
+  i = 0;
+  while (NULL != server_addr[i])
+    i++;
+  if (i > 0)
+  {
+    lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1));
+    i = 0;
+    j = 0;
+    while (NULL != server_addr[i])
+    {
+      seen = 0;
+      for (k=0;k<i;k++)
+       if ( (socklen[k] == socklen[i]) &&
+            (0 == memcmp (server_addr[k], server_addr[i], socklen[i])) )
+       {
+         seen = 1;
+         break;
+       }
+      if (0 != seen)
+      {
+       /* duplicate address, skip */
+       i++;
+       continue;
+      }
+      lsocks[j] = open_listen_socket (server_addr[i], socklen[i]);
+      if (NULL != lsocks[j])
+        j++;
+      i++;
+    }
+    if (0 == j)
+    {
+      if (0 != errno)
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
+      GNUNET_free (lsocks);
+      lsocks = NULL;
+    }
+  }
+  else
+  {
+    lsocks = NULL;
+  }
+  return GNUNET_SERVER_create_with_sockets (access_cb,
+                                           access_cb_cls,
+                                           lsocks,
+                                            idle_timeout,
+                                           require_found);
+}
+
+
+/**
+ * Set the 'monitor' flag on this client.  Clients which have been
+ * marked as 'monitors' won't prevent the server from shutting down
+ * once '#GNUNET_SERVER_stop_listening()' has been invoked.  The idea is
+ * that for "normal" clients we likely want to allow them to process
+ * their requests; however, monitor-clients are likely to 'never'
+ * disconnect during shutdown and thus will not be considered when
+ * determining if the server should continue to exist after
+ * #GNUNET_SERVER_destroy() has been called.
+ *
+ * @param client the client to set the 'monitor' flag on
+ */
+void
+GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Marking client as monitor!\n");
+  client->is_monitor = GNUNET_YES;
+}
+
+
+/**
+ * Helper function for #test_monitor_clients() to trigger
+ * #GNUNET_SERVER_destroy() after the stack has unwound.
+ *
+ * @param cls the `struct GNUNET_SERVER_Handle *` to destroy
+ */
+static void
+do_destroy (void *cls)
+{
+  struct GNUNET_SERVER_Handle *server = cls;
+
+  GNUNET_SERVER_destroy (server);
+}
+
+
+/**
+ * Check if only 'monitor' clients are left.  If so, destroy the
+ * server completely.
+ *
+ * @param server server to test for full shutdown
+ */
+static void
+test_monitor_clients (struct GNUNET_SERVER_Handle *server)
+{
+  struct GNUNET_SERVER_Client *client;
+
+  if (GNUNET_YES != server->in_soft_shutdown)
+    return;
+  for (client = server->clients_head; NULL != client; client = client->next)
+    if (GNUNET_NO == client->is_monitor)
+      return; /* not done yet */
+  server->in_soft_shutdown = GNUNET_SYSERR;
+  (void) GNUNET_SCHEDULER_add_now (&do_destroy, server);
+}
+
+
+/**
+ * Suspend accepting connections from the listen socket temporarily.
+ *
+ * @param server server to stop accepting connections.
+ */
+void
+GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server)
+{
+  if (NULL != server->listen_task)
+  {
+    GNUNET_SCHEDULER_cancel (server->listen_task);
+    server->listen_task = NULL;
+  }
+}
+
+
+/**
+ * Resume accepting connections from the listen socket.
+ *
+ * @param server server to stop accepting connections.
+ */
+void
+GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
+{
+  struct GNUNET_NETWORK_FDSet *r;
+  unsigned int i;
+
+  if (NULL == server->listen_sockets)
+    return;
+  if (NULL == server->listen_sockets[0])
+    return; /* nothing to do, no listen sockets! */
+  if (NULL == server->listen_sockets[1])
+  {
+    /* simplified method: no fd set needed; this is then much simpler
+       and much more efficient */
+    server->listen_task =
+      GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
+                                                  GNUNET_SCHEDULER_PRIORITY_HIGH,
+                                                  server->listen_sockets[0],
+                                                  &process_listen_socket, server);
+    return;
+  }
+  r = GNUNET_NETWORK_fdset_create ();
+  i = 0;
+  while (NULL != server->listen_sockets[i])
+    GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
+  server->listen_task =
+    GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
+                                GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
+                                &process_listen_socket, server);
+  GNUNET_NETWORK_fdset_destroy (r);
+}
+
+
+/**
+ * Stop the listen socket and get ready to shutdown the server
+ * once only 'monitor' clients are left.
+ *
+ * @param server server to stop listening on
+ */
+void
+GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server)
+{
+  unsigned int i;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Server in soft shutdown\n");
+  if (NULL != server->listen_task)
+  {
+    GNUNET_SCHEDULER_cancel (server->listen_task);
+    server->listen_task = NULL;
+  }
+  if (NULL != server->listen_sockets)
+  {
+    i = 0;
+    while (NULL != server->listen_sockets[i])
+      GNUNET_break (GNUNET_OK ==
+                    GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
+    GNUNET_free (server->listen_sockets);
+    server->listen_sockets = NULL;
+  }
+  if (GNUNET_NO == server->in_soft_shutdown)
+    server->in_soft_shutdown = GNUNET_YES;
+  test_monitor_clients (server);
+}
+
+
+/**
+ * Free resources held by this server.
+ *
+ * @param server server to destroy
+ */
+void
+GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server)
+{
+  struct HandlerList *hpos;
+  struct NotifyList *npos;
+  unsigned int i;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Server shutting down.\n");
+  if (NULL != server->listen_task)
+  {
+    GNUNET_SCHEDULER_cancel (server->listen_task);
+    server->listen_task = NULL;
+  }
+  if (NULL != server->listen_sockets)
+  {
+    i = 0;
+    while (NULL != server->listen_sockets[i])
+      GNUNET_break (GNUNET_OK ==
+                    GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
+    GNUNET_free (server->listen_sockets);
+    server->listen_sockets = NULL;
+  }
+  while (NULL != server->clients_head)
+    GNUNET_SERVER_client_disconnect (server->clients_head);
+  while (NULL != (hpos = server->handlers))
+  {
+    server->handlers = hpos->next;
+    GNUNET_free (hpos);
+  }
+  while (NULL != (npos = server->disconnect_notify_list_head))
+  {
+    npos->callback (npos->callback_cls,
+                    NULL);
+    GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
+                                server->disconnect_notify_list_tail,
+                                npos);
+    GNUNET_free (npos);
+  }
+  while (NULL != (npos = server->connect_notify_list_head))
+  {
+    npos->callback (npos->callback_cls,
+                    NULL);
+    GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
+                                server->connect_notify_list_tail,
+                                npos);
+    GNUNET_free (npos);
+  }
+  GNUNET_free (server);
+}
+
+
+/**
+ * Add additional handlers to an existing server.
+ *
+ * @param server the server to add handlers to
+ * @param handlers array of message handlers for
+ *        incoming messages; the last entry must
+ *        have "NULL" for the "callback"; multiple
+ *        entries for the same type are allowed,
+ *        they will be called in order of occurence.
+ *        These handlers can be removed later;
+ *        the handlers array must exist until removed
+ *        (or server is destroyed).
+ */
+void
+GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
+                            const struct GNUNET_SERVER_MessageHandler *handlers)
+{
+  struct HandlerList *p;
+
+  p = GNUNET_new (struct HandlerList);
+  p->handlers = handlers;
+  p->next = server->handlers;
+  server->handlers = p;
+}
+
+
+/**
+ * Change functions used by the server to tokenize the message stream.
+ * (very rarely used).
+ *
+ * @param server server to modify
+ * @param create new tokenizer initialization function
+ * @param destroy new tokenizer destruction function
+ * @param receive new tokenizer receive function
+ * @param cls closure for @a create, @a receive, @a destroy
+ */
+void
+GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
+                             GNUNET_SERVER_MstCreateCallback create,
+                             GNUNET_SERVER_MstDestroyCallback destroy,
+                             GNUNET_SERVER_MstReceiveCallback receive,
+                             void *cls)
+{
+  server->mst_create = create;
+  server->mst_destroy = destroy;
+  server->mst_receive = receive;
+  server->mst_cls = cls;
+}
+
+
+/**
+ * Task run to warn about missing calls to #GNUNET_SERVER_receive_done.
+ *
+ * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
+ */
+static void
+warn_no_receive_done (void *cls)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+
+  GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
+  client->warn_task =
+      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+                                    &warn_no_receive_done, client);
+  LOG (GNUNET_ERROR_TYPE_WARNING,
+       _("Processing code for message of type %u did not call `GNUNET_SERVER_receive_done' after %s\n"),
+       (unsigned int) client->warn_type,
+       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
+                                              GNUNET_YES));
+}
+
+
+/**
+ * Disable the warning the server issues if a message is not acknowledged
+ * in a timely fashion.  Use this call if a client is intentionally delayed
+ * for a while.  Only applies to the current message.
+ *
+ * @param client client for which to disable the warning
+ */
+void
+GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
+{
+  if (NULL != client->warn_task)
+  {
+    GNUNET_SCHEDULER_cancel (client->warn_task);
+    client->warn_task = NULL;
+  }
+}
+
+
+/**
+ * Inject a message into the server, pretend it came
+ * from the specified client.  Delivery of the message
+ * will happen instantly (if a handler is installed;
+ * otherwise the call does nothing).
+ *
+ * @param server the server receiving the message
+ * @param sender the "pretended" sender of the message
+ *        can be NULL!
+ * @param message message to transmit
+ * @return #GNUNET_OK if the message was OK and the
+ *                   connection can stay open
+ *         #GNUNET_SYSERR if the connection to the
+ *         client should be shut down
+ */
+int
+GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
+                      struct GNUNET_SERVER_Client *sender,
+                      const struct GNUNET_MessageHeader *message)
+{
+  struct HandlerList *pos;
+  const struct GNUNET_SERVER_MessageHandler *mh;
+  unsigned int i;
+  uint16_t type;
+  uint16_t size;
+  int found;
+
+  type = ntohs (message->type);
+  size = ntohs (message->size);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Received message of type %u and size %u from client\n",
+       type, size);
+  found = GNUNET_NO;
+  for (pos = server->handlers; NULL != pos; pos = pos->next)
+  {
+    i = 0;
+    while (pos->handlers[i].callback != NULL)
+    {
+      mh = &pos->handlers[i];
+      if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
+      {
+        if ((0 != mh->expected_size) && (mh->expected_size != size))
+        {
+#if GNUNET8_NETWORK_IS_DEAD
+          LOG (GNUNET_ERROR_TYPE_WARNING,
+               "Expected %u bytes for message of type %u, got %u\n",
+               mh->expected_size, mh->type, size);
+          GNUNET_break_op (0);
+#else
+          LOG (GNUNET_ERROR_TYPE_DEBUG,
+               "Expected %u bytes for message of type %u, got %u\n",
+               mh->expected_size, mh->type, size);
+#endif
+          return GNUNET_SYSERR;
+        }
+        if (NULL != sender)
+        {
+          if ( (0 == sender->suspended) &&
+              (NULL == sender->warn_task) )
+          {
+           GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */
+            sender->warn_start = GNUNET_TIME_absolute_get ();
+            sender->warn_task =
+                GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+                                              &warn_no_receive_done,
+                                             sender);
+            sender->warn_type = type;
+          }
+          sender->suspended++;
+        }
+        mh->callback (mh->callback_cls, sender, message);
+        found = GNUNET_YES;
+      }
+      i++;
+    }
+  }
+  if (GNUNET_NO == found)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+         "Received message of unknown type %d\n", type);
+    if (GNUNET_YES == server->require_found)
+      return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * We are receiving an incoming message.  Process it.
+ *
+ * @param cls our closure (handle for the client)
+ * @param buf buffer with data received from network
+ * @param available number of bytes available in buf
+ * @param addr address of the sender
+ * @param addrlen length of @a addr
+ * @param errCode code indicating errors receiving, 0 for success
+ */
+static void
+process_incoming (void *cls,
+                  const void *buf,
+                  size_t available,
+                  const struct sockaddr *addr,
+                  socklen_t addrlen,
+                  int errCode);
+
+
+/**
+ * Process messages from the client's message tokenizer until either
+ * the tokenizer is empty (and then schedule receiving more), or
+ * until some handler is not immediately done (then wait for restart_processing)
+ * or shutdown.
+ *
+ * @param client the client to process, RC must have already been increased
+ *        using #GNUNET_SERVER_client_keep and will be decreased by one in this
+ *        function
+ * @param ret #GNUNET_NO to start processing from the buffer,
+ *            #GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
+ *            #GNUNET_SYSERR if we should instantly abort due to error in a previous step
+ */
+static void
+process_mst (struct GNUNET_SERVER_Client *client,
+             int ret)
+{
+  while ((GNUNET_SYSERR != ret) && (NULL != client->server) &&
+         (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
+  {
+    if (GNUNET_OK == ret)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "Server re-enters receive loop, timeout: %s.\n",
+           GNUNET_STRINGS_relative_time_to_string (client->idle_timeout, GNUNET_YES));
+      client->receive_pending = GNUNET_YES;
+      GNUNET_CONNECTION_receive (client->connection,
+                                 GNUNET_MAX_MESSAGE_SIZE - 1,
+                                 client->idle_timeout,
+                                 &process_incoming,
+                                 client);
+      break;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Server processes additional messages instantly.\n");
+    if (NULL != client->server->mst_receive)
+      ret =
+          client->server->mst_receive (client->server->mst_cls, client->mst,
+                                       client, NULL, 0, GNUNET_NO, GNUNET_YES);
+    else
+      ret =
+          GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
+                                     GNUNET_YES);
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
+       ret, client->server,
+       client->shutdown_now,
+       client->suspended);
+  if (GNUNET_NO == ret)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Server has more data pending but is suspended.\n");
+    client->receive_pending = GNUNET_SYSERR;    /* data pending */
+  }
+  if ( (GNUNET_SYSERR == ret) ||
+       (GNUNET_YES == client->shutdown_now) )
+    GNUNET_SERVER_client_disconnect (client);
+}
+
+
+/**
+ * We are receiving an incoming message.  Process it.
+ *
+ * @param cls our closure (handle for the client)
+ * @param buf buffer with data received from network
+ * @param available number of bytes available in buf
+ * @param addr address of the sender
+ * @param addrlen length of @a addr
+ * @param errCode code indicating errors receiving, 0 for success
+ */
+static void
+process_incoming (void *cls,
+                  const void *buf,
+                  size_t available,
+                  const struct sockaddr *addr,
+                  socklen_t addrlen,
+                  int errCode)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+  struct GNUNET_SERVER_Handle *server = client->server;
+  struct GNUNET_TIME_Absolute end;
+  struct GNUNET_TIME_Absolute now;
+  int ret;
+
+  GNUNET_assert (GNUNET_YES == client->receive_pending);
+  client->receive_pending = GNUNET_NO;
+  now = GNUNET_TIME_absolute_get ();
+  end = GNUNET_TIME_absolute_add (client->last_activity,
+                                  client->idle_timeout);
+
+  if ( (NULL == buf) &&
+       (0 == available) &&
+       (NULL == addr) &&
+       (0 == errCode) &&
+       (GNUNET_YES != client->shutdown_now) &&
+       (NULL != server) &&
+       (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
+       (end.abs_value_us > now.abs_value_us) )
+  {
+    /* wait longer, timeout changed (i.e. due to us sending) */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Receive time out, but no disconnect due to sending (%p)\n",
+         client);
+    client->receive_pending = GNUNET_YES;
+    GNUNET_CONNECTION_receive (client->connection,
+                               GNUNET_MAX_MESSAGE_SIZE - 1,
+                               GNUNET_TIME_absolute_get_remaining (end),
+                               &process_incoming,
+                               client);
+    return;
+  }
+  if ( (NULL == buf) ||
+       (0 == available) ||
+       (0 != errCode) ||
+       (NULL == server) ||
+       (GNUNET_YES == client->shutdown_now) ||
+       (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)) )
+  {
+    /* other side closed connection, error connecting, etc. */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Failed to connect or other side closed connection (%p)\n",
+         client);
+    GNUNET_SERVER_client_disconnect (client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Server receives %u bytes from `%s'.\n",
+       (unsigned int) available,
+       GNUNET_a2s (addr, addrlen));
+  GNUNET_SERVER_client_keep (client);
+  client->last_activity = now;
+
+  if (NULL != server->mst_receive)
+  {
+    ret = client->server->mst_receive (client->server->mst_cls,
+                                       client->mst,
+                                       client,
+                                       buf,
+                                       available,
+                                       GNUNET_NO,
+                                       GNUNET_YES);
+  }
+  else if (NULL != client->mst)
+  {
+    ret =
+        GNUNET_SERVER_mst_receive (client->mst,
+                                   client,
+                                   buf,
+                                   available,
+                                   GNUNET_NO,
+                                   GNUNET_YES);
+  }
+  else
+  {
+    GNUNET_break (0);
+    return;
+  }
+  process_mst (client,
+               ret);
+  GNUNET_SERVER_client_drop (client);
+}
+
+
+/**
+ * Task run to start again receiving from the network
+ * and process requests.
+ *
+ * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
+ */
+static void
+restart_processing (void *cls)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+
+  GNUNET_assert (GNUNET_YES != client->shutdown_now);
+  client->restart_task = NULL;
+  if (GNUNET_NO == client->receive_pending)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
+    client->receive_pending = GNUNET_YES;
+    GNUNET_CONNECTION_receive (client->connection,
+                               GNUNET_MAX_MESSAGE_SIZE - 1,
+                               client->idle_timeout,
+                               &process_incoming,
+                               client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Server continues processing messages still in the buffer.\n");
+  GNUNET_SERVER_client_keep (client);
+  client->receive_pending = GNUNET_NO;
+  process_mst (client,
+               GNUNET_NO);
+  GNUNET_SERVER_client_drop (client);
+}
+
+
+/**
+ * This function is called whenever our inbound message tokenizer has
+ * received a complete message.
+ *
+ * @param cls closure (struct GNUNET_SERVER_Handle)
+ * @param client identification of the client (`struct GNUNET_SERVER_Client *`)
+ * @param message the actual message
+ *
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
+ */
+static int
+client_message_tokenizer_callback (void *cls,
+                                   void *client,
+                                   const struct GNUNET_MessageHeader *message)
+{
+  struct GNUNET_SERVER_Handle *server = cls;
+  struct GNUNET_SERVER_Client *sender = client;
+  int ret;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Tokenizer gives server message of type %u and size %u from client\n",
+       ntohs (message->type), ntohs (message->size));
+  sender->in_process_client_buffer = GNUNET_YES;
+  ret = GNUNET_SERVER_inject (server, sender, message);
+  sender->in_process_client_buffer = GNUNET_NO;
+  if ( (GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now) )
+  {
+    GNUNET_SERVER_client_disconnect (sender);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Add a TCP socket-based connection to the set of handles managed by
+ * this server.  Use this function for outgoing (P2P) connections that
+ * we initiated (and where this server should process incoming
+ * messages).
+ *
+ * @param server the server to use
+ * @param connection the connection to manage (client must
+ *        stop using this connection from now on)
+ * @return the client handle
+ */
+struct GNUNET_SERVER_Client *
+GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
+                              struct GNUNET_CONNECTION_Handle *connection)
+{
+  struct GNUNET_SERVER_Client *client;
+  struct NotifyList *n;
+
+  client = GNUNET_new (struct GNUNET_SERVER_Client);
+  client->connection = connection;
+  client->server = server;
+  client->last_activity = GNUNET_TIME_absolute_get ();
+  client->idle_timeout = server->idle_timeout;
+  GNUNET_CONTAINER_DLL_insert (server->clients_head,
+                              server->clients_tail,
+                              client);
+  if (NULL != server->mst_create)
+    client->mst =
+        server->mst_create (server->mst_cls, client);
+  else
+    client->mst =
+        GNUNET_SERVER_mst_create (&client_message_tokenizer_callback,
+                                  server);
+  GNUNET_assert (NULL != client->mst);
+  for (n = server->connect_notify_list_head; NULL != n; n = n->next)
+    n->callback (n->callback_cls, client);
+  client->receive_pending = GNUNET_YES;
+  GNUNET_CONNECTION_receive (client->connection,
+                             GNUNET_MAX_MESSAGE_SIZE - 1,
+                             client->idle_timeout,
+                             &process_incoming,
+                             client);
+  return client;
+}
+
+
+/**
+ * Change the timeout for a particular client.  Decreasing the timeout
+ * may not go into effect immediately (only after the previous timeout
+ * times out or activity happens on the socket).
+ *
+ * @param client the client to update
+ * @param timeout new timeout for activities on the socket
+ */
+void
+GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
+                                  struct GNUNET_TIME_Relative timeout)
+{
+  client->idle_timeout = timeout;
+}
+
+
+/**
+ * Notify the server that the given client handle should
+ * be kept (keeps the connection up if possible, increments
+ * the internal reference counter).
+ *
+ * @param client the client to keep
+ */
+void
+GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
+{
+  client->reference_count++;
+}
+
+
+/**
+ * Notify the server that the given client handle is no
+ * longer required.  Decrements the reference counter.  If
+ * that counter reaches zero an inactive connection maybe
+ * closed.
+ *
+ * @param client the client to drop
+ */
+void
+GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
+{
+  GNUNET_assert (client->reference_count > 0);
+  client->reference_count--;
+  if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count))
+    GNUNET_SERVER_client_disconnect (client);
+}
+
+
+/**
+ * Obtain the network address of the other party.
+ *
+ * @param client the client to get the address for
+ * @param addr where to store the address
+ * @param addrlen where to store the length of the @a addr
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
+                                  void **addr, size_t * addrlen)
+{
+  return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
+}
+
+
+/**
+ * Ask the server to notify us whenever a client disconnects.
+ * This function is called whenever the actual network connection
+ * is closed; the reference count may be zero or larger than zero
+ * at this point.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on disconnect
+ * @param callback_cls closure for @a callback
+ */
+void
+GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
+                                 GNUNET_SERVER_DisconnectCallback callback,
+                                 void *callback_cls)
+{
+  struct NotifyList *n;
+
+  n = GNUNET_new (struct NotifyList);
+  n->callback = callback;
+  n->callback_cls = callback_cls;
+  GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head,
+                              server->disconnect_notify_list_tail,
+                              n);
+}
+
+
+/**
+ * Ask the server to notify us whenever a client connects.
+ * This function is called whenever the actual network connection
+ * is opened. If the server is destroyed before this
+ * notification is explicitly cancelled, the 'callback' will
+ * once be called with a 'client' argument of NULL to indicate
+ * that the server itself is now gone (and that the callback
+ * won't be called anymore and also can no longer be cancelled).
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on sconnect
+ * @param callback_cls closure for @a callback
+ */
+void
+GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
+                             GNUNET_SERVER_ConnectCallback callback,
+                             void *callback_cls)
+{
+  struct NotifyList *n;
+  struct GNUNET_SERVER_Client *client;
+
+  n = GNUNET_new (struct NotifyList);
+  n->callback = callback;
+  n->callback_cls = callback_cls;
+  GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head,
+                              server->connect_notify_list_tail,
+                              n);
+  for (client = server->clients_head; NULL != client; client = client->next)
+    callback (callback_cls, client);
+}
+
+
+/**
+ * Ask the server to stop notifying us whenever a client connects.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on connect
+ * @param callback_cls closure for @a callback
+ */
+void
+GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
+                                        GNUNET_SERVER_DisconnectCallback callback,
+                                        void *callback_cls)
+{
+  struct NotifyList *pos;
+
+  for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next)
+    if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
+      break;
+  if (NULL == pos)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
+                              server->disconnect_notify_list_tail,
+                              pos);
+  GNUNET_free (pos);
+}
+
+
+/**
+ * Ask the server to stop notifying us whenever a client disconnects.
+ *
+ * @param server the server manageing the clients
+ * @param callback function to call on disconnect
+ * @param callback_cls closure for @a callback
+ */
+void
+GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
+                                    GNUNET_SERVER_ConnectCallback callback,
+                                    void *callback_cls)
+{
+  struct NotifyList *pos;
+
+  for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next)
+    if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
+      break;
+  if (NULL == pos)
+  {
+    GNUNET_break (0);
+    return;
+  }
+  GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
+                              server->connect_notify_list_tail,
+                              pos);
+  GNUNET_free (pos);
+}
+
+
+/**
+ * Destroy the connection that is passed in via @a cls.  Used
+ * as calling #GNUNET_CONNECTION_destroy from within a function
+ * that was itself called from within process_notify() of
+ * 'connection.c' is not allowed (see #2329).
+ *
+ * @param cls connection to destroy
+ */
+static void
+destroy_connection (void *cls)
+{
+  struct GNUNET_CONNECTION_Handle *connection = cls;
+
+  GNUNET_CONNECTION_destroy (connection);
+}
+
+
+/**
+ * Ask the server to disconnect from the given client.
+ * This is the same as returning #GNUNET_SYSERR from a message
+ * handler, except that it allows dropping of a client even
+ * when not handling a message from that client.
+ *
+ * @param client the client to disconnect from
+ */
+void
+GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
+{
+  struct GNUNET_SERVER_Handle *server = client->server;
+  struct NotifyList *n;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Client is being disconnected from the server.\n");
+  if (NULL != client->restart_task)
+  {
+    GNUNET_SCHEDULER_cancel (client->restart_task);
+    client->restart_task = NULL;
+  }
+  if (NULL != client->warn_task)
+  {
+    GNUNET_SCHEDULER_cancel (client->warn_task);
+    client->warn_task = NULL;
+  }
+  if (GNUNET_YES == client->receive_pending)
+  {
+    GNUNET_CONNECTION_receive_cancel (client->connection);
+    client->receive_pending = GNUNET_NO;
+  }
+  client->shutdown_now = GNUNET_YES;
+  client->reference_count++; /* make sure nobody else clean up client... */
+  if ( (NULL != client->mst) &&
+       (NULL != server) )
+  {
+    GNUNET_CONTAINER_DLL_remove (server->clients_head,
+                                server->clients_tail,
+                                client);
+    if (NULL != server->mst_destroy)
+      server->mst_destroy (server->mst_cls,
+                           client->mst);
+    else
+      GNUNET_SERVER_mst_destroy (client->mst);
+    client->mst = NULL;
+    for (n = server->disconnect_notify_list_head; NULL != n; n = n->next)
+      n->callback (n->callback_cls,
+                   client);
+  }
+  client->reference_count--;
+  if (client->reference_count > 0)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "RC of %p still positive, not destroying everything.\n",
+         client);
+    client->server = NULL;
+    return;
+  }
+  if (GNUNET_YES == client->in_process_client_buffer)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Still processing inputs of %p, not destroying everything.\n",
+         client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "RC of %p now zero, destroying everything.\n",
+       client);
+  if (GNUNET_YES == client->persist)
+    GNUNET_CONNECTION_persist_ (client->connection);
+  if (NULL != client->th.cth)
+    GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
+  (void) GNUNET_SCHEDULER_add_now (&destroy_connection,
+                                  client->connection);
+  /* need to cancel again, as it might have been re-added
+     in the meantime (i.e. during callbacks) */
+  if (NULL != client->warn_task)
+  {
+    GNUNET_SCHEDULER_cancel (client->warn_task);
+    client->warn_task = NULL;
+  }
+  if (GNUNET_YES == client->receive_pending)
+  {
+    GNUNET_CONNECTION_receive_cancel (client->connection);
+    client->receive_pending = GNUNET_NO;
+  }
+  GNUNET_free (client);
+  /* we might be in soft-shutdown, test if we're done */
+  if (NULL != server)
+    test_monitor_clients (server);
+}
+
+
+/**
+ * Disable the "CORK" feature for communication with the given client,
+ * forcing the OS to immediately flush the buffer on transmission
+ * instead of potentially buffering multiple messages.
+ *
+ * @param client handle to the client
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
+{
+  return GNUNET_CONNECTION_disable_corking (client->connection);
+}
+
+
+/**
+ * Wrapper for transmission notification that calls the original
+ * callback and update the last activity time for our connection.
+ *
+ * @param cls the `struct GNUNET_SERVER_Client *`
+ * @param size number of bytes we can transmit
+ * @param buf where to copy the message
+ * @return number of bytes actually transmitted
+ */
+static size_t
+transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+  GNUNET_CONNECTION_TransmitReadyNotify callback;
+
+  client->th.cth = NULL;
+  callback = client->th.callback;
+  client->th.callback = NULL;
+  client->last_activity = GNUNET_TIME_absolute_get ();
+  return callback (client->th.callback_cls, size, buf);
+}
+
+
+/**
+ * Notify us when the server has enough space to transmit
+ * a message of the given size to the given client.
+ *
+ * @param client client to transmit message to
+ * @param size requested amount of buffer space
+ * @param timeout after how long should we give up (and call
+ *        notify with buf NULL and size 0)?
+ * @param callback function to call when space is available
+ * @param callback_cls closure for @a callback
+ * @return non-NULL if the notify callback was queued; can be used
+ *         to cancel the request using
+ *         #GNUNET_SERVER_notify_transmit_ready_cancel().
+ *         NULL if we are already going to notify someone else (busy)
+ */
+struct GNUNET_SERVER_TransmitHandle *
+GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
+                                     size_t size,
+                                     struct GNUNET_TIME_Relative timeout,
+                                     GNUNET_CONNECTION_TransmitReadyNotify callback,
+                                     void *callback_cls)
+{
+  if (NULL != client->th.callback)
+    return NULL;
+  client->th.callback_cls = callback_cls;
+  client->th.callback = callback;
+  client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
+                                                           timeout,
+                                                           &transmit_ready_callback_wrapper,
+                                                           client);
+  return &client->th;
+}
+
+
+/**
+ * Abort transmission request.
+ *
+ * @param th request to abort
+ */
+void
+GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th)
+{
+  GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
+  th->cth = NULL;
+  th->callback = NULL;
+}
+
+
+/**
+ * Set the persistent flag on this client, used to setup client connection
+ * to only be killed when the service it's connected to is actually dead.
+ *
+ * @param client the client to set the persistent flag on
+ */
+void
+GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
+{
+  client->persist = GNUNET_YES;
+}
+
+
+/**
+ * Resume receiving from this client, we are done processing the
+ * current request.  This function must be called from within each
+ * GNUNET_SERVER_MessageCallback (or its respective continuations).
+ *
+ * @param client client we were processing a message of
+ * @param success #GNUNET_OK to keep the connection open and
+ *                          continue to receive
+ *                #GNUNET_NO to close the connection (normal behavior)
+ *                #GNUNET_SYSERR to close the connection (signal
+ *                          serious error)
+ */
+void
+GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
+                           int success)
+{
+  if (NULL == client)
+    return;
+  GNUNET_assert (client->suspended > 0);
+  client->suspended--;
+  if (GNUNET_OK != success)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "GNUNET_SERVER_receive_done called with failure indication\n");
+    if ( (client->reference_count > 0) || (client->suspended > 0) )
+      client->shutdown_now = GNUNET_YES;
+    else
+      GNUNET_SERVER_client_disconnect (client);
+    return;
+  }
+  if (client->suspended > 0)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "GNUNET_SERVER_receive_done called, but more clients pending\n");
+    return;
+  }
+  if (NULL != client->warn_task)
+  {
+    GNUNET_SCHEDULER_cancel (client->warn_task);
+    client->warn_task = NULL;
+  }
+  if (GNUNET_YES == client->in_process_client_buffer)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "GNUNET_SERVER_receive_done called while still in processing loop\n");
+    return;
+  }
+  if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now))
+  {
+    GNUNET_SERVER_client_disconnect (client);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
+  GNUNET_assert (NULL == client->restart_task);
+  client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing,
+                                                   client);
+}
+
+
+/* end of server.c */
diff --git a/src/transport/tcp_server_mst_legacy.c b/src/transport/tcp_server_mst_legacy.c
new file mode 100644 (file)
index 0000000..78e04c1
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2010 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/server_mst.c
+ * @brief convenience functions for handling inbound message buffers
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+
+#if HAVE_UNALIGNED_64_ACCESS
+#define ALIGN_FACTOR 4
+#else
+#define ALIGN_FACTOR 8
+#endif
+
+
+/**
+ * Handle to a message stream tokenizer.
+ */
+struct GNUNET_SERVER_MessageStreamTokenizer
+{
+
+  /**
+   * Function to call on completed messages.
+   */
+  GNUNET_SERVER_MessageTokenizerCallback cb;
+
+  /**
+   * Closure for @e cb.
+   */
+  void *cb_cls;
+
+  /**
+   * Size of the buffer (starting at @e hdr).
+   */
+  size_t curr_buf;
+
+  /**
+   * How many bytes in buffer have we already processed?
+   */
+  size_t off;
+
+  /**
+   * How many bytes in buffer are valid right now?
+   */
+  size_t pos;
+
+  /**
+   * Beginning of the buffer.  Typed like this to force alignment.
+   */
+  struct GNUNET_MessageHeader *hdr;
+
+};
+
+
+
+/**
+ * Create a message stream tokenizer.
+ *
+ * @param cb function to call on completed messages
+ * @param cb_cls closure for @a cb
+ * @return handle to tokenizer
+ */
+struct GNUNET_SERVER_MessageStreamTokenizer *
+GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
+                          void *cb_cls)
+{
+  struct GNUNET_SERVER_MessageStreamTokenizer *ret;
+
+  ret = GNUNET_new (struct GNUNET_SERVER_MessageStreamTokenizer);
+  ret->hdr = GNUNET_malloc (GNUNET_MIN_MESSAGE_SIZE);
+  ret->curr_buf = GNUNET_MIN_MESSAGE_SIZE;
+  ret->cb = cb;
+  ret->cb_cls = cb_cls;
+  return ret;
+}
+
+
+/**
+ * Add incoming data to the receive buffer and call the
+ * callback for all complete messages.
+ *
+ * @param mst tokenizer to use
+ * @param client_identity ID of client for which this is a buffer
+ * @param buf input data to add
+ * @param size number of bytes in @a buf
+ * @param purge should any excess bytes in the buffer be discarded
+ *       (i.e. for packet-based services like UDP)
+ * @param one_shot only call callback once, keep rest of message in buffer
+ * @return #GNUNET_OK if we are done processing (need more data)
+ *         #GNUNET_NO if @a one_shot was set and we have another message ready
+ *         #GNUNET_SYSERR if the data stream is corrupt
+ */
+int
+GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
+                           void *client_identity,
+                           const char *buf, size_t size,
+                           int purge, int one_shot)
+{
+  const struct GNUNET_MessageHeader *hdr;
+  size_t delta;
+  uint16_t want;
+  char *ibuf;
+  int need_align;
+  unsigned long offset;
+  int ret;
+
+  GNUNET_assert (mst->off <= mst->pos);
+  GNUNET_assert (mst->pos <= mst->curr_buf);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Server-mst receives %u bytes with %u bytes already in private buffer\n",
+       (unsigned int) size, (unsigned int) (mst->pos - mst->off));
+  ret = GNUNET_OK;
+  ibuf = (char *) mst->hdr;
+  while (mst->pos > 0)
+  {
+do_align:
+    GNUNET_assert (mst->pos >= mst->off);
+    if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
+        (0 != (mst->off % ALIGN_FACTOR)))
+    {
+      /* need to align or need more space */
+      mst->pos -= mst->off;
+      memmove (ibuf, &ibuf[mst->off], mst->pos);
+      mst->off = 0;
+    }
+    if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+    {
+      delta =
+          GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) -
+                      (mst->pos - mst->off), size);
+      GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
+      mst->pos += delta;
+      buf += delta;
+      size -= delta;
+    }
+    if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+    {
+      if (purge)
+      {
+        mst->off = 0;
+        mst->pos = 0;
+      }
+      return GNUNET_OK;
+    }
+    hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+    want = ntohs (hdr->size);
+    if (want < sizeof (struct GNUNET_MessageHeader))
+    {
+      GNUNET_break_op (0);
+      return GNUNET_SYSERR;
+    }
+    if ( (mst->curr_buf - mst->off < want) &&
+        (mst->off > 0) )
+    {
+      /* can get more space by moving */
+      mst->pos -= mst->off;
+      memmove (ibuf, &ibuf[mst->off], mst->pos);
+      mst->off = 0;
+    }
+    if (mst->curr_buf < want)
+    {
+      /* need to get more space by growing buffer */
+      GNUNET_assert (0 == mst->off);
+      mst->hdr = GNUNET_realloc (mst->hdr, want);
+      ibuf = (char *) mst->hdr;
+      mst->curr_buf = want;
+    }
+    hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+    if (mst->pos - mst->off < want)
+    {
+      delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
+      GNUNET_assert (mst->pos + delta <= mst->curr_buf);
+      GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
+      mst->pos += delta;
+      buf += delta;
+      size -= delta;
+    }
+    if (mst->pos - mst->off < want)
+    {
+      if (purge)
+      {
+        mst->off = 0;
+        mst->pos = 0;
+      }
+      return GNUNET_OK;
+    }
+    if (one_shot == GNUNET_SYSERR)
+    {
+      /* cannot call callback again, but return value saying that
+       * we have another full message in the buffer */
+      ret = GNUNET_NO;
+      goto copy;
+    }
+    if (one_shot == GNUNET_YES)
+      one_shot = GNUNET_SYSERR;
+    mst->off += want;
+    if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
+      return GNUNET_SYSERR;
+    if (mst->off == mst->pos)
+    {
+      /* reset to beginning of buffer, it's free right now! */
+      mst->off = 0;
+      mst->pos = 0;
+    }
+  }
+  GNUNET_assert (0 == mst->pos);
+  while (size > 0)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Server-mst has %u bytes left in inbound buffer\n",
+         (unsigned int) size);
+    if (size < sizeof (struct GNUNET_MessageHeader))
+      break;
+    offset = (unsigned long) buf;
+    need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
+    if (GNUNET_NO == need_align)
+    {
+      /* can try to do zero-copy and process directly from original buffer */
+      hdr = (const struct GNUNET_MessageHeader *) buf;
+      want = ntohs (hdr->size);
+      if (want < sizeof (struct GNUNET_MessageHeader))
+      {
+       GNUNET_break_op (0);
+        mst->off = 0;
+        return GNUNET_SYSERR;
+      }
+      if (size < want)
+        break;                  /* or not: buffer incomplete, so copy to private buffer... */
+      if (one_shot == GNUNET_SYSERR)
+      {
+        /* cannot call callback again, but return value saying that
+         * we have another full message in the buffer */
+        ret = GNUNET_NO;
+        goto copy;
+      }
+      if (one_shot == GNUNET_YES)
+        one_shot = GNUNET_SYSERR;
+      if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
+        return GNUNET_SYSERR;
+      buf += want;
+      size -= want;
+    }
+    else
+    {
+      /* need to copy to private buffer to align;
+       * yes, we go a bit more spagetti than usual here */
+      goto do_align;
+    }
+  }
+copy:
+  if ((size > 0) && (!purge))
+  {
+    if (size + mst->pos > mst->curr_buf)
+    {
+      mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos);
+      ibuf = (char *) mst->hdr;
+      mst->curr_buf = size + mst->pos;
+    }
+    GNUNET_assert (size + mst->pos <= mst->curr_buf);
+    GNUNET_memcpy (&ibuf[mst->pos], buf, size);
+    mst->pos += size;
+  }
+  if (purge)
+  {
+    mst->off = 0;
+    mst->pos = 0;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Server-mst leaves %u bytes in private buffer\n",
+       (unsigned int) (mst->pos - mst->off));
+  return ret;
+}
+
+
+/**
+ * Destroys a tokenizer.
+ *
+ * @param mst tokenizer to destroy
+ */
+void
+GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst)
+{
+  GNUNET_free (mst->hdr);
+  GNUNET_free (mst);
+}
+
+
+
+/* end of server_mst.c */
diff --git a/src/transport/tcp_service_legacy.c b/src/transport/tcp_service_legacy.c
new file mode 100644 (file)
index 0000000..7c2d3e5
--- /dev/null
@@ -0,0 +1,1688 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2009, 2012 GNUnet e.V.
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/service.c
+ * @brief functions related to starting services
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_constants.h"
+#include "gnunet_resolver_service.h"
+
+#if HAVE_MALLINFO
+#include <malloc.h>
+#include "gauger.h"
+#endif
+
+
+/* ******************* access control ******************** */
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param add the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
+                   const struct in_addr *add)
+{
+  unsigned int i;
+
+  if (NULL == list)
+    return GNUNET_NO;
+  i = 0;
+  while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
+  {
+    if ((add->s_addr & list[i].netmask.s_addr) ==
+        (list[i].network.s_addr & list[i].netmask.s_addr))
+      return GNUNET_YES;
+    i++;
+  }
+  return GNUNET_NO;
+}
+
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param ip the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
+                   const struct in6_addr *ip)
+{
+  unsigned int i;
+  unsigned int j;
+  struct in6_addr zero;
+
+  if (NULL == list)
+    return GNUNET_NO;
+  memset (&zero, 0, sizeof (struct in6_addr));
+  i = 0;
+NEXT:
+  while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
+  {
+    for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
+      if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
+          (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
+      {
+        i++;
+        goto NEXT;
+      }
+    return GNUNET_YES;
+  }
+  return GNUNET_NO;
+}
+
+
+/* ****************** service struct ****************** */
+
+
+/**
+ * Context for "service_task".
+ */
+struct LEGACY_SERVICE_Context
+{
+  /**
+   * Our configuration.
+   */
+  const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * Handle for the server.
+   */
+  struct GNUNET_SERVER_Handle *server;
+
+  /**
+   * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
+   * listen sockets.
+   */
+  struct sockaddr **addrs;
+
+  /**
+   * Name of our service.
+   */
+  const char *service_name;
+
+  /**
+   * Main service-specific task to run.
+   */
+  LEGACY_SERVICE_Main task;
+
+  /**
+   * Closure for @e task.
+   */
+  void *task_cls;
+
+  /**
+   * IPv4 addresses that are not allowed to connect.
+   */
+  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
+
+  /**
+   * IPv6 addresses that are not allowed to connect.
+   */
+  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
+
+  /**
+   * IPv4 addresses that are allowed to connect (if not
+   * set, all are allowed).
+   */
+  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
+
+  /**
+   * IPv6 addresses that are allowed to connect (if not
+   * set, all are allowed).
+   */
+  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
+
+  /**
+   * My (default) message handlers.  Adjusted copy
+   * of "defhandlers".
+   */
+  struct GNUNET_SERVER_MessageHandler *my_handlers;
+
+  /**
+   * Array of the lengths of the entries in addrs.
+   */
+  socklen_t *addrlens;
+
+  /**
+   * NULL-terminated array of listen sockets we should take over.
+   */
+  struct GNUNET_NETWORK_Handle **lsocks;
+
+  /**
+   * Task ID of the shutdown task.
+   */
+  struct GNUNET_SCHEDULER_Task *shutdown_task;
+
+  /**
+   * Idle timeout for server.
+   */
+  struct GNUNET_TIME_Relative timeout;
+
+  /**
+   * Overall success/failure of the service start.
+   */
+  int ret;
+
+  /**
+   * If we are daemonizing, this FD is set to the
+   * pipe to the parent.  Send '.' if we started
+   * ok, '!' if not.  -1 if we are not daemonizing.
+   */
+  int ready_confirm_fd;
+
+  /**
+   * Do we close connections if we receive messages
+   * for which we have no handler?
+   */
+  int require_found;
+
+  /**
+   * Do we require a matching UID for UNIX domain socket connections?
+   * #GNUNET_NO means that the UID does not have to match (however,
+   * @e match_gid may still impose other access control checks).
+   */
+  int match_uid;
+
+  /**
+   * Do we require a matching GID for UNIX domain socket connections?
+   * Ignored if @e match_uid is #GNUNET_YES.  Note that this is about
+   * checking that the client's UID is in our group OR that the
+   * client's GID is our GID.  If both "match_gid" and @e match_uid are
+   * #GNUNET_NO, all users on the local system have access.
+   */
+  int match_gid;
+
+  /**
+   * Our options.
+   */
+  enum LEGACY_SERVICE_Options options;
+
+};
+
+
+/* ****************** message handlers ****************** */
+
+/**
+ * Send a 'TEST' message back to the client.
+ *
+ * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
+ * @param size number of bytes available in 'buf'
+ * @param buf where to copy the message
+ * @return number of bytes written to 'buf'
+ */
+static size_t
+write_test (void *cls, size_t size, void *buf)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+  struct GNUNET_MessageHeader *msg;
+
+  if (size < sizeof (struct GNUNET_MessageHeader))
+  {
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return 0;                   /* client disconnected */
+  }
+  msg = (struct GNUNET_MessageHeader *) buf;
+  msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
+  msg->size = htons (sizeof (struct GNUNET_MessageHeader));
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+/**
+ * Handler for TEST message.
+ *
+ * @param cls closure (refers to service)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_test (void *cls, struct GNUNET_SERVER_Client *client,
+             const struct GNUNET_MessageHeader *message)
+{
+  /* simply bounce message back to acknowledge */
+  if (NULL ==
+      GNUNET_SERVER_notify_transmit_ready (client,
+                                           sizeof (struct GNUNET_MessageHeader),
+                                           GNUNET_TIME_UNIT_FOREVER_REL,
+                                           &write_test, client))
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Default handlers for all services.  Will be copied and the
+ * "callback_cls" fields will be replaced with the specific service
+ * struct.
+ */
+static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
+  {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
+   sizeof (struct GNUNET_MessageHeader)},
+  {NULL, NULL, 0, 0}
+};
+
+
+/* ****************** service core routines ************** */
+
+
+/**
+ * Check if access to the service is allowed from the given address.
+ *
+ * @param cls closure
+ * @param uc credentials, if available, otherwise NULL
+ * @param addr address
+ * @param addrlen length of address
+ * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
+ *   for unknown address family (will be denied).
+ */
+static int
+check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
+              const struct sockaddr *addr, socklen_t addrlen)
+{
+  struct LEGACY_SERVICE_Context *sctx = cls;
+  const struct sockaddr_in *i4;
+  const struct sockaddr_in6 *i6;
+  int ret;
+
+  switch (addr->sa_family)
+  {
+  case AF_INET:
+    GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
+    i4 = (const struct sockaddr_in *) addr;
+    ret = ((NULL == sctx->v4_allowed) ||
+           (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
+        ((NULL == sctx->v4_denied) ||
+         (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
+    break;
+  case AF_INET6:
+    GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
+    i6 = (const struct sockaddr_in6 *) addr;
+    ret = ((NULL == sctx->v6_allowed) ||
+           (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
+        ((NULL == sctx->v6_denied) ||
+         (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
+    break;
+#ifndef WINDOWS
+  case AF_UNIX:
+    ret = GNUNET_OK;            /* controlled using file-system ACL now */
+    break;
+#endif
+  default:
+    LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
+         addr->sa_family);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK != ret)
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Access from `%s' denied to service `%s'\n"),
+        GNUNET_a2s (addr, addrlen),
+         sctx->service_name);
+  }
+  return ret;
+}
+
+
+/**
+ * Get the name of the file where we will
+ * write the PID of the service.
+ *
+ * @param sctx service context
+ * @return name of the file for the process ID
+ */
+static char *
+get_pid_file_name (struct LEGACY_SERVICE_Context *sctx)
+{
+  char *pif;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
+                                               "PIDFILE", &pif))
+    return NULL;
+  return pif;
+}
+
+
+/**
+ * Parse an IPv4 access control list.
+ *
+ * @param ret location where to write the ACL (set)
+ * @param sctx service context to use to get the configuration
+ * @param option name of the ACL option to parse
+ * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
+ *         no ACL configured)
+ */
+static int
+process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
+              struct LEGACY_SERVICE_Context *sctx,
+              const char *option)
+{
+  char *opt;
+
+  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+  {
+    *ret = NULL;
+    return GNUNET_OK;
+  }
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
+                                                       sctx->service_name,
+                                                       option, &opt));
+  if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
+         opt, sctx->service_name, option);
+    GNUNET_free (opt);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (opt);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Parse an IPv6 access control list.
+ *
+ * @param ret location where to write the ACL (set)
+ * @param sctx service context to use to get the configuration
+ * @param option name of the ACL option to parse
+ * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
+ *         no ACL configured)
+ */
+static int
+process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
+              struct LEGACY_SERVICE_Context *sctx,
+              const char *option)
+{
+  char *opt;
+
+  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+  {
+    *ret = NULL;
+    return GNUNET_OK;
+  }
+  GNUNET_break (GNUNET_OK ==
+                GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
+                                                       sctx->service_name,
+                                                       option, &opt));
+  if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
+  {
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
+         opt, sctx->service_name, option);
+    GNUNET_free (opt);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (opt);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Add the given UNIX domain path as an address to the
+ * list (as the first entry).
+ *
+ * @param saddrs array to update
+ * @param saddrlens where to store the address length
+ * @param unixpath path to add
+ * @param abstract #GNUNET_YES to add an abstract UNIX domain socket.  This
+ *          parameter is ignore on systems other than LINUX
+ */
+static void
+add_unixpath (struct sockaddr **saddrs,
+              socklen_t *saddrlens,
+              const char *unixpath,
+              int abstract)
+{
+#ifdef AF_UNIX
+  struct sockaddr_un *un;
+
+  un = GNUNET_new (struct sockaddr_un);
+  un->sun_family = AF_UNIX;
+  strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+  if (GNUNET_YES == abstract)
+    un->sun_path[0] = '\0';
+#endif
+#if HAVE_SOCKADDR_UN_SUN_LEN
+  un->sun_len = (u_char) sizeof (struct sockaddr_un);
+#endif
+  *saddrs = (struct sockaddr *) un;
+  *saddrlens = sizeof (struct sockaddr_un);
+#else
+  /* this function should never be called
+   * unless AF_UNIX is defined! */
+  GNUNET_assert (0);
+#endif
+}
+
+
+/**
+ * Get the list of addresses that a server for the given service
+ * should bind to.
+ *
+ * @param service_name name of the service
+ * @param cfg configuration (which specifies the addresses)
+ * @param addrs set (call by reference) to an array of pointers to the
+ *              addresses the server should bind to and listen on; the
+ *              array will be NULL-terminated (on success)
+ * @param addr_lens set (call by reference) to an array of the lengths
+ *              of the respective `struct sockaddr` struct in the @a addrs
+ *              array (on success)
+ * @return number of addresses found on success,
+ *              #GNUNET_SYSERR if the configuration
+ *              did not specify reasonable finding information or
+ *              if it specified a hostname that could not be resolved;
+ *              #GNUNET_NO if the number of addresses configured is
+ *              zero (in this case, `*addrs` and `*addr_lens` will be
+ *              set to NULL).
+ */
+int
+LEGACY_SERVICE_get_server_addresses (const char *service_name,
+                                     const struct GNUNET_CONFIGURATION_Handle *cfg,
+                                     struct sockaddr ***addrs,
+                                     socklen_t ** addr_lens)
+{
+  int disablev6;
+  struct GNUNET_NETWORK_Handle *desc;
+  unsigned long long port;
+  char *unixpath;
+  struct addrinfo hints;
+  struct addrinfo *res;
+  struct addrinfo *pos;
+  struct addrinfo *next;
+  unsigned int i;
+  int resi;
+  int ret;
+  int abstract;
+  struct sockaddr **saddrs;
+  socklen_t *saddrlens;
+  char *hostname;
+
+  *addrs = NULL;
+  *addr_lens = NULL;
+  desc = NULL;
+  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
+  {
+    if (GNUNET_SYSERR ==
+        (disablev6 =
+         GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
+      return GNUNET_SYSERR;
+  }
+  else
+    disablev6 = GNUNET_NO;
+
+  if (! disablev6)
+  {
+    /* probe IPv6 support */
+    desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
+    if (NULL == desc)
+    {
+      if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+          (EACCES == errno))
+      {
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+        return GNUNET_SYSERR;
+      }
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
+           service_name, STRERROR (errno));
+      disablev6 = GNUNET_YES;
+    }
+    else
+    {
+      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+      desc = NULL;
+    }
+  }
+
+  port = 0;
+  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
+  {
+    if (GNUNET_OK !=
+       GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
+                                              "PORT", &port))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Require valid port number for service `%s' in configuration!\n"),
+           service_name);
+    }
+    if (port > 65535)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Require valid port number for service `%s' in configuration!\n"),
+           service_name);
+      return GNUNET_SYSERR;
+    }
+  }
+
+  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
+  {
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
+                                                         "BINDTO", &hostname));
+  }
+  else
+    hostname = NULL;
+
+  unixpath = NULL;
+  abstract = GNUNET_NO;
+#ifdef AF_UNIX
+  if ((GNUNET_YES ==
+       GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
+      (GNUNET_OK ==
+       GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
+                                              &unixpath)) &&
+      (0 < strlen (unixpath)))
+  {
+    /* probe UNIX support */
+    struct sockaddr_un s_un;
+
+    if (strlen (unixpath) >= sizeof (s_un.sun_path))
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING,
+           _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
+           (unsigned long long) sizeof (s_un.sun_path));
+      unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
+      LOG (GNUNET_ERROR_TYPE_INFO,
+          _("Using `%s' instead\n"),
+           unixpath);
+    }
+#ifdef LINUX
+    abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                                     "TESTING",
+                                                     "USE_ABSTRACT_SOCKETS");
+    if (GNUNET_SYSERR == abstract)
+      abstract = GNUNET_NO;
+#endif
+    if ((GNUNET_YES != abstract)
+        && (GNUNET_OK !=
+            GNUNET_DISK_directory_create_for_file (unixpath)))
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+                               "mkdir",
+                               unixpath);
+  }
+  if (NULL != unixpath)
+  {
+    desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
+    if (NULL == desc)
+    {
+      if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+          (EACCES == errno))
+      {
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+        GNUNET_free_non_null (hostname);
+        GNUNET_free (unixpath);
+        return GNUNET_SYSERR;
+      }
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
+           service_name,
+           STRERROR (errno));
+      GNUNET_free (unixpath);
+      unixpath = NULL;
+    }
+    else
+    {
+      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+      desc = NULL;
+    }
+  }
+#endif
+
+  if ((0 == port) && (NULL == unixpath))
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
+         service_name);
+    GNUNET_free_non_null (hostname);
+    return GNUNET_SYSERR;
+  }
+  if (0 == port)
+  {
+    saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
+    saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
+    add_unixpath (saddrs, saddrlens, unixpath, abstract);
+    GNUNET_free_non_null (unixpath);
+    GNUNET_free_non_null (hostname);
+    *addrs = saddrs;
+    *addr_lens = saddrlens;
+    return 1;
+  }
+
+  if (NULL != hostname)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Resolving `%s' since that is where `%s' will bind to.\n",
+         hostname,
+         service_name);
+    memset (&hints, 0, sizeof (struct addrinfo));
+    if (disablev6)
+      hints.ai_family = AF_INET;
+    hints.ai_protocol = IPPROTO_TCP;
+    if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
+        (NULL == res))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Failed to resolve `%s': %s\n"),
+           hostname,
+           gai_strerror (ret));
+      GNUNET_free (hostname);
+      GNUNET_free_non_null (unixpath);
+      return GNUNET_SYSERR;
+    }
+    next = res;
+    i = 0;
+    while (NULL != (pos = next))
+    {
+      next = pos->ai_next;
+      if ((disablev6) && (pos->ai_family == AF_INET6))
+        continue;
+      i++;
+    }
+    if (0 == i)
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Failed to find %saddress for `%s'.\n"),
+           disablev6 ? "IPv4 " : "",
+           hostname);
+      freeaddrinfo (res);
+      GNUNET_free (hostname);
+      GNUNET_free_non_null (unixpath);
+      return GNUNET_SYSERR;
+    }
+    resi = i;
+    if (NULL != unixpath)
+      resi++;
+    saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+    saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+    i = 0;
+    if (NULL != unixpath)
+    {
+      add_unixpath (saddrs, saddrlens, unixpath, abstract);
+      i++;
+    }
+    next = res;
+    while (NULL != (pos = next))
+    {
+      next = pos->ai_next;
+      if ((disablev6) && (AF_INET6 == pos->ai_family))
+        continue;
+      if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
+        continue;               /* not TCP */
+      if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
+        continue;               /* huh? */
+      LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
+           service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
+      if (AF_INET == pos->ai_family)
+      {
+        GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
+        saddrlens[i] = pos->ai_addrlen;
+        saddrs[i] = GNUNET_malloc (saddrlens[i]);
+        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+        ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+      }
+      else
+      {
+        GNUNET_assert (AF_INET6 == pos->ai_family);
+        GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
+        saddrlens[i] = pos->ai_addrlen;
+        saddrs[i] = GNUNET_malloc (saddrlens[i]);
+        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+        ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+      }
+      i++;
+    }
+    GNUNET_free (hostname);
+    freeaddrinfo (res);
+    resi = i;
+  }
+  else
+  {
+    /* will bind against everything, just set port */
+    if (disablev6)
+    {
+      /* V4-only */
+      resi = 1;
+      if (NULL != unixpath)
+        resi++;
+      i = 0;
+      saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+      saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+      if (NULL != unixpath)
+      {
+        add_unixpath (saddrs, saddrlens, unixpath, abstract);
+        i++;
+      }
+      saddrlens[i] = sizeof (struct sockaddr_in);
+      saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
+#endif
+      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+    }
+    else
+    {
+      /* dual stack */
+      resi = 2;
+      if (NULL != unixpath)
+        resi++;
+      saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+      saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+      i = 0;
+      if (NULL != unixpath)
+      {
+        add_unixpath (saddrs, saddrlens, unixpath, abstract);
+        i++;
+      }
+      saddrlens[i] = sizeof (struct sockaddr_in6);
+      saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
+#endif
+      ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
+      ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+      i++;
+      saddrlens[i] = sizeof (struct sockaddr_in);
+      saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
+#endif
+      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+    }
+  }
+  GNUNET_free_non_null (unixpath);
+  *addrs = saddrs;
+  *addr_lens = saddrlens;
+  return resi;
+}
+
+
+#ifdef MINGW
+/**
+ * Read listen sockets from the parent process (ARM).
+ *
+ * @param sctx service context to initialize
+ * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
+ * and #GNUNET_SYSERR on error.
+ */
+static int
+receive_sockets_from_parent (struct LEGACY_SERVICE_Context *sctx)
+{
+  const char *env_buf;
+  int fail;
+  uint64_t count;
+  uint64_t i;
+  HANDLE lsocks_pipe;
+
+  env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
+  if ((NULL == env_buf) || (strlen (env_buf) <= 0))
+    return GNUNET_NO;
+  /* Using W32 API directly here, because this pipe will
+   * never be used outside of this function, and it's just too much of a bother
+   * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
+   */
+  lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
+  if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
+    return GNUNET_NO;
+  fail = 1;
+  do
+  {
+    int ret;
+    int fail2;
+    DWORD rd;
+
+    ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
+    if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
+      break;
+    sctx->lsocks =
+        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
+
+    fail2 = 1;
+    for (i = 0; i < count; i++)
+    {
+      WSAPROTOCOL_INFOA pi;
+      uint64_t size;
+      SOCKET s;
+
+      ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
+      if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
+        break;
+      ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
+      if ( (0 == ret) || (sizeof (pi) != rd))
+        break;
+      s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
+      sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
+      if (NULL == sctx->lsocks[i])
+        break;
+      else if (i == count - 1)
+        fail2 = 0;
+    }
+    if (fail2)
+      break;
+    sctx->lsocks[count] = NULL;
+    fail = 0;
+  }
+  while (fail);
+
+  CloseHandle (lsocks_pipe);
+
+  if (fail)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Could not access a pre-bound socket, will try to bind myself\n"));
+    for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
+      GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
+    GNUNET_free_non_null (sctx->lsocks);
+    sctx->lsocks = NULL;
+    return GNUNET_NO;
+  }
+  return GNUNET_YES;
+}
+#endif
+
+
+/**
+ * Setup addr, addrlen, idle_timeout
+ * based on configuration!
+ *
+ * Configuration may specify:
+ * - PORT (where to bind to for TCP)
+ * - UNIXPATH (where to bind to for UNIX domain sockets)
+ * - TIMEOUT (after how many ms does an inactive service timeout);
+ * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
+ * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
+ * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
+ * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
+ * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
+ * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
+ *
+ * @param sctx service context to initialize
+ * @return #GNUNET_OK if configuration succeeded
+ */
+static int
+setup_service (struct LEGACY_SERVICE_Context *sctx)
+{
+  struct GNUNET_TIME_Relative idleout;
+  int tolerant;
+
+#ifndef MINGW
+  const char *nfds;
+  unsigned int cnt;
+  int flags;
+#endif
+
+  if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT"))
+  {
+    if (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
+                                             "TIMEOUT", &idleout))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Specified value for `%s' of service `%s' is invalid\n"),
+           "TIMEOUT", sctx->service_name);
+      return GNUNET_SYSERR;
+    }
+    sctx->timeout = idleout;
+  }
+  else
+    sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+
+  if (GNUNET_CONFIGURATION_have_value
+      (sctx->cfg, sctx->service_name, "TOLERANT"))
+  {
+    if (GNUNET_SYSERR ==
+        (tolerant =
+         GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+                                               "TOLERANT")))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+           _("Specified value for `%s' of service `%s' is invalid\n"),
+           "TOLERANT", sctx->service_name);
+      return GNUNET_SYSERR;
+    }
+  }
+  else
+    tolerant = GNUNET_NO;
+
+#ifndef MINGW
+  errno = 0;
+  if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
+      (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
+      (cnt + 4 < FD_SETSIZE))
+  {
+    sctx->lsocks =
+        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
+    while (0 < cnt--)
+    {
+      flags = fcntl (3 + cnt, F_GETFD);
+      if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
+          (NULL ==
+           (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
+      {
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _
+             ("Could not access pre-bound socket %u, will try to bind myself\n"),
+             (unsigned int) 3 + cnt);
+        cnt++;
+        while (sctx->lsocks[cnt] != NULL)
+          GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
+        GNUNET_free (sctx->lsocks);
+        sctx->lsocks = NULL;
+        break;
+      }
+    }
+    unsetenv ("LISTEN_FDS");
+  }
+#else
+  if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
+  {
+    receive_sockets_from_parent (sctx);
+    putenv ("GNUNET_OS_READ_LSOCKS=");
+  }
+#endif
+
+  if ((NULL == sctx->lsocks) &&
+      (GNUNET_SYSERR ==
+       LEGACY_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
+                                            &sctx->addrs, &sctx->addrlens)))
+    return GNUNET_SYSERR;
+  sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
+  sctx->match_uid =
+      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+                                            "UNIX_MATCH_UID");
+  sctx->match_gid =
+      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+                                            "UNIX_MATCH_GID");
+  process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
+  process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
+  process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
+  process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
+
+  return GNUNET_OK;
+}
+
+
+/**
+ * Get the name of the user that'll be used
+ * to provide the service.
+ *
+ * @param sctx service context
+ * @return value of the 'USERNAME' option
+ */
+static char *
+get_user_name (struct LEGACY_SERVICE_Context *sctx)
+{
+  char *un;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
+                                               "USERNAME", &un))
+    return NULL;
+  return un;
+}
+
+
+/**
+ * Write PID file.
+ *
+ * @param sctx service context
+ * @param pid PID to write (should be equal to 'getpid()'
+ * @return  #GNUNET_OK on success (including no work to be done)
+ */
+static int
+write_pid_file (struct LEGACY_SERVICE_Context *sctx, pid_t pid)
+{
+  FILE *pidfd;
+  char *pif;
+  char *user;
+  char *rdir;
+  int len;
+
+  if (NULL == (pif = get_pid_file_name (sctx)))
+    return GNUNET_OK;           /* no file desired */
+  user = get_user_name (sctx);
+  rdir = GNUNET_strdup (pif);
+  len = strlen (rdir);
+  while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
+    len--;
+  rdir[len] = '\0';
+  if (0 != ACCESS (rdir, F_OK))
+  {
+    /* we get to create a directory -- and claim it
+     * as ours! */
+    (void) GNUNET_DISK_directory_create (rdir);
+    if ((NULL != user) && (0 < strlen (user)))
+      GNUNET_DISK_file_change_owner (rdir, user);
+  }
+  if (0 != ACCESS (rdir, W_OK | X_OK))
+  {
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
+    GNUNET_free (rdir);
+    GNUNET_free_non_null (user);
+    GNUNET_free (pif);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_free (rdir);
+  pidfd = FOPEN (pif, "w");
+  if (NULL == pidfd)
+  {
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
+    GNUNET_free (pif);
+    GNUNET_free_non_null (user);
+    return GNUNET_SYSERR;
+  }
+  if (0 > FPRINTF (pidfd, "%u", pid))
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
+  GNUNET_break (0 == FCLOSE (pidfd));
+  if ((NULL != user) && (0 < strlen (user)))
+    GNUNET_DISK_file_change_owner (pif, user);
+  GNUNET_free_non_null (user);
+  GNUNET_free (pif);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Task run during shutdown.  Stops the server/service.
+ *
+ * @param cls the `struct LEGACY_SERVICE_Context`
+ */
+static void
+shutdown_task (void *cls)
+{
+  struct LEGACY_SERVICE_Context *service = cls;
+  struct GNUNET_SERVER_Handle *server = service->server;
+
+  service->shutdown_task = NULL;
+  if (0 != (service->options & LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN))
+    GNUNET_SERVER_stop_listening (server);
+  else
+    GNUNET_SERVER_destroy (server);
+}
+
+
+/**
+ * Initial task for the service.
+ *
+ * @param cls service context
+ */
+static void
+service_task (void *cls)
+{
+  struct LEGACY_SERVICE_Context *sctx = cls;
+  unsigned int i;
+
+  GNUNET_RESOLVER_connect (sctx->cfg);
+  if (NULL != sctx->lsocks)
+    sctx->server
+      = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
+                                           sctx->timeout, sctx->require_found);
+  else
+    sctx->server
+      = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
+                              sctx->timeout, sctx->require_found);
+  if (NULL == sctx->server)
+  {
+    if (NULL != sctx->addrs)
+      for (i = 0; NULL != sctx->addrs[i]; i++)
+        LOG (GNUNET_ERROR_TYPE_INFO,
+             _("Failed to start `%s' at `%s'\n"),
+             sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
+    sctx->ret = GNUNET_SYSERR;
+    return;
+  }
+#ifndef WINDOWS
+  if (NULL != sctx->addrs)
+    for (i = 0; NULL != sctx->addrs[i]; i++)
+      if ((AF_UNIX == sctx->addrs[i]->sa_family)
+          && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
+        GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
+                                     sctx->match_uid,
+                                     sctx->match_gid);
+#endif
+
+
+  if (0 == (sctx->options & LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN))
+  {
+    /* install a task that will kill the server
+     * process if the scheduler ever gets a shutdown signal */
+    sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                                        sctx);
+  }
+  sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
+  GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
+  i = 0;
+  while (NULL != sctx->my_handlers[i].callback)
+    sctx->my_handlers[i++].callback_cls = sctx;
+  GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
+  if (-1 != sctx->ready_confirm_fd)
+  {
+    GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
+    GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
+    sctx->ready_confirm_fd = -1;
+    write_pid_file (sctx, getpid ());
+  }
+  if (NULL != sctx->addrs)
+  {
+    i = 0;
+    while (NULL != sctx->addrs[i])
+    {
+      LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
+           sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
+      i++;
+    }
+  }
+  sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
+}
+
+
+/**
+ * Detach from terminal.
+ *
+ * @param sctx service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+detach_terminal (struct LEGACY_SERVICE_Context *sctx)
+{
+#ifndef MINGW
+  pid_t pid;
+  int nullfd;
+  int filedes[2];
+
+  if (0 != PIPE (filedes))
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
+    return GNUNET_SYSERR;
+  }
+  pid = fork ();
+  if (pid < 0)
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
+    return GNUNET_SYSERR;
+  }
+  if (0 != pid)
+  {
+    /* Parent */
+    char c;
+
+    GNUNET_break (0 == CLOSE (filedes[1]));
+    c = 'X';
+    if (1 != READ (filedes[0], &c, sizeof (char)))
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
+    fflush (stdout);
+    switch (c)
+    {
+    case '.':
+      exit (0);
+    case 'I':
+      LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n"));
+      break;
+    case 'S':
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Service process could not initialize server function\n"));
+      break;
+    case 'X':
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Service process failed to report status\n"));
+      break;
+    }
+    exit (1);                   /* child reported error */
+  }
+  GNUNET_break (0 == CLOSE (0));
+  GNUNET_break (0 == CLOSE (1));
+  GNUNET_break (0 == CLOSE (filedes[0]));
+  nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
+  if (nullfd < 0)
+    return GNUNET_SYSERR;
+  /* set stdin/stdout to /dev/null */
+  if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
+    (void) CLOSE (nullfd);
+    return GNUNET_SYSERR;
+  }
+  (void) CLOSE (nullfd);
+  /* Detach from controlling terminal */
+  pid = setsid ();
+  if (-1 == pid)
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
+  sctx->ready_confirm_fd = filedes[1];
+#else
+  /* FIXME: we probably need to do something else
+   * elsewhere in order to fork the process itself... */
+  FreeConsole ();
+#endif
+  return GNUNET_OK;
+}
+
+
+/**
+ * Set user ID.
+ *
+ * @param sctx service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+set_user_id (struct LEGACY_SERVICE_Context *sctx)
+{
+  char *user;
+
+  if (NULL == (user = get_user_name (sctx)))
+    return GNUNET_OK;           /* keep */
+#ifndef MINGW
+  struct passwd *pws;
+
+  errno = 0;
+  pws = getpwnam (user);
+  if (NULL == pws)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Cannot obtain information about user `%s': %s\n"), user,
+         errno == 0 ? _("No such user") : STRERROR (errno));
+    GNUNET_free (user);
+    return GNUNET_SYSERR;
+  }
+  if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
+#if HAVE_INITGROUPS
+      (0 != initgroups (user, pws->pw_gid)) ||
+#endif
+      (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
+  {
+    if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
+        (0 != setreuid (pws->pw_uid, pws->pw_uid)))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"),
+           user, STRERROR (errno));
+      GNUNET_free (user);
+      return GNUNET_SYSERR;
+    }
+  }
+#endif
+  GNUNET_free (user);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Delete the PID file that was created by our parent.
+ *
+ * @param sctx service context
+ */
+static void
+pid_file_delete (struct LEGACY_SERVICE_Context *sctx)
+{
+  char *pif = get_pid_file_name (sctx);
+
+  if (NULL == pif)
+    return;                     /* no PID file */
+  if (0 != UNLINK (pif))
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
+  GNUNET_free (pif);
+}
+
+
+/**
+ * Run a standard GNUnet service startup sequence (initialize loggers
+ * and configuration, parse options).
+ *
+ * @param argc number of command line arguments
+ * @param argv command line arguments
+ * @param service_name our service name
+ * @param options service options
+ * @param task main task of the service
+ * @param task_cls closure for @a task
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK
+ *         if we shutdown nicely
+ */
+int
+LEGACY_SERVICE_run (int argc, char *const *argv,
+                    const char *service_name,
+                    enum LEGACY_SERVICE_Options options,
+                    LEGACY_SERVICE_Main task,
+                    void *task_cls)
+{
+#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
+
+  int err;
+  int ret;
+  char *cfg_fn;
+  char *opt_cfg_fn;
+  char *loglev;
+  char *logfile;
+  int do_daemonize;
+  unsigned int i;
+  unsigned long long skew_offset;
+  unsigned long long skew_variance;
+  long long clock_offset;
+  struct LEGACY_SERVICE_Context sctx;
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+  const char *xdg;
+
+  struct GNUNET_GETOPT_CommandLineOption service_options[] = {
+    GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn),
+    GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                  "daemonize",
+                                  gettext_noop ("do daemonize (detach from terminal)"),
+                                  &do_daemonize),
+    GNUNET_GETOPT_OPTION_HELP (NULL),
+    GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
+    GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
+    GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
+    GNUNET_GETOPT_OPTION_END
+  };
+  err = 1;
+  do_daemonize = 0;
+  logfile = NULL;
+  loglev = NULL;
+  opt_cfg_fn = NULL;
+  xdg = getenv ("XDG_CONFIG_HOME");
+  if (NULL != xdg)
+    GNUNET_asprintf (&cfg_fn,
+                     "%s%s%s",
+                     xdg,
+                     DIR_SEPARATOR_STR,
+                     GNUNET_OS_project_data_get ()->config_file);
+  else
+    cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
+  memset (&sctx, 0, sizeof (sctx));
+  sctx.options = options;
+  sctx.ready_confirm_fd = -1;
+  sctx.ret = GNUNET_OK;
+  sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+  sctx.task = task;
+  sctx.task_cls = task_cls;
+  sctx.service_name = service_name;
+  sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
+
+  /* setup subsystems */
+  ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
+  if (GNUNET_SYSERR == ret)
+    goto shutdown;
+  if (GNUNET_NO == ret)
+  {
+    err = 0;
+    goto shutdown;
+  }
+  if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
+    HANDLE_ERROR;
+  if (NULL == opt_cfg_fn)
+    opt_cfg_fn = GNUNET_strdup (cfg_fn);
+  if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
+  {
+    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  _("Malformed configuration file `%s', exit ...\n"),
+                  opt_cfg_fn);
+      goto shutdown;
+    }
+  }
+  else
+  {
+    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  _("Malformed configuration, exit ...\n"));
+      goto shutdown;
+    }
+    if (0 != strcmp (opt_cfg_fn, cfg_fn))
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Could not access configuration file `%s'\n"),
+                 opt_cfg_fn);
+  }
+  if (GNUNET_OK != setup_service (&sctx))
+    goto shutdown;
+  if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
+    HANDLE_ERROR;
+  if (GNUNET_OK != set_user_id (&sctx))
+    goto shutdown;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Service `%s' runs with configuration from `%s'\n",
+       service_name,
+       opt_cfg_fn);
+  if ((GNUNET_OK ==
+       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
+                                              "SKEW_OFFSET", &skew_offset)) &&
+      (GNUNET_OK ==
+       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
+                                              "SKEW_VARIANCE", &skew_variance)))
+  {
+    clock_offset = skew_offset - skew_variance;
+    GNUNET_TIME_set_offset (clock_offset);
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
+  }
+  /* actually run service */
+  err = 0;
+  GNUNET_SCHEDULER_run (&service_task, &sctx);
+  /* shutdown */
+  if ((1 == do_daemonize) && (NULL != sctx.server))
+    pid_file_delete (&sctx);
+  GNUNET_free_non_null (sctx.my_handlers);
+
+shutdown:
+  if (-1 != sctx.ready_confirm_fd)
+  {
+    if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
+    GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
+  }
+#if HAVE_MALLINFO
+  {
+    char *counter;
+
+    if ( (GNUNET_YES ==
+         GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
+                                          "GAUGER_HEAP")) &&
+        (GNUNET_OK ==
+         GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
+                                                "GAUGER_HEAP",
+                                                &counter)) )
+    {
+      struct mallinfo mi;
+
+      mi = mallinfo ();
+      GAUGER (service_name, counter, mi.usmblks, "blocks");
+      GNUNET_free (counter);
+    }
+  }
+#endif
+  GNUNET_CONFIGURATION_destroy (cfg);
+  i = 0;
+  if (NULL != sctx.addrs)
+    while (NULL != sctx.addrs[i])
+      GNUNET_free (sctx.addrs[i++]);
+  GNUNET_free_non_null (sctx.addrs);
+  GNUNET_free_non_null (sctx.addrlens);
+  GNUNET_free_non_null (logfile);
+  GNUNET_free_non_null (loglev);
+  GNUNET_free (cfg_fn);
+  GNUNET_free_non_null (opt_cfg_fn);
+  GNUNET_free_non_null (sctx.v4_denied);
+  GNUNET_free_non_null (sctx.v6_denied);
+  GNUNET_free_non_null (sctx.v4_allowed);
+  GNUNET_free_non_null (sctx.v6_allowed);
+
+  return err ? GNUNET_SYSERR : sctx.ret;
+}
+
+
+/**
+ * Run a service startup sequence within an existing
+ * initialized system.
+ *
+ * @param service_name our service name
+ * @param cfg configuration to use
+ * @param options service options
+ * @return NULL on error, service handle
+ */
+struct LEGACY_SERVICE_Context *
+LEGACY_SERVICE_start (const char *service_name,
+                      const struct GNUNET_CONFIGURATION_Handle *cfg,
+                     enum LEGACY_SERVICE_Options options)
+{
+  int i;
+  struct LEGACY_SERVICE_Context *sctx;
+
+  sctx = GNUNET_new (struct LEGACY_SERVICE_Context);
+  sctx->ready_confirm_fd = -1;  /* no daemonizing */
+  sctx->ret = GNUNET_OK;
+  sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+  sctx->service_name = service_name;
+  sctx->cfg = cfg;
+  sctx->options = options;
+
+  /* setup subsystems */
+  if (GNUNET_OK != setup_service (sctx))
+  {
+    LEGACY_SERVICE_stop (sctx);
+    return NULL;
+  }
+  if (NULL != sctx->lsocks)
+    sctx->server =
+        GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
+                                           sctx->timeout, sctx->require_found);
+  else
+    sctx->server =
+        GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
+                              sctx->timeout, sctx->require_found);
+
+  if (NULL == sctx->server)
+  {
+    LEGACY_SERVICE_stop (sctx);
+    return NULL;
+  }
+#ifndef WINDOWS
+  if (NULL != sctx->addrs)
+    for (i = 0; NULL != sctx->addrs[i]; i++)
+      if ((AF_UNIX == sctx->addrs[i]->sa_family)
+          && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
+        GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
+                                     sctx->match_uid,
+                                     sctx->match_gid);
+#endif
+  sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
+  GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
+  i = 0;
+  while ((sctx->my_handlers[i].callback != NULL))
+    sctx->my_handlers[i++].callback_cls = sctx;
+  GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
+  return sctx;
+}
+
+
+/**
+ * Obtain the server used by a service.  Note that the server must NOT
+ * be destroyed by the caller.
+ *
+ * @param ctx the service context returned from the start function
+ * @return handle to the server for this service, NULL if there is none
+ */
+struct GNUNET_SERVER_Handle *
+LEGACY_SERVICE_get_server (struct LEGACY_SERVICE_Context *ctx)
+{
+  return ctx->server;
+}
+
+
+/**
+ * Get the NULL-terminated array of listen sockets for this service.
+ *
+ * @param ctx service context to query
+ * @return NULL if there are no listen sockets, otherwise NULL-terminated
+ *              array of listen sockets.
+ */
+struct GNUNET_NETWORK_Handle *const*
+LEGACY_SERVICE_get_listen_sockets (struct LEGACY_SERVICE_Context *ctx)
+{
+  return ctx->lsocks;
+}
+
+
+/**
+ * Stop a service that was started with "LEGACY_SERVICE_start".
+ *
+ * @param sctx the service context returned from the start function
+ */
+void
+LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *sctx)
+{
+  unsigned int i;
+
+#if HAVE_MALLINFO
+  {
+    char *counter;
+
+    if ( (GNUNET_YES ==
+         GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
+                                          "GAUGER_HEAP")) &&
+        (GNUNET_OK ==
+         GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
+                                                "GAUGER_HEAP",
+                                                &counter)) )
+    {
+      struct mallinfo mi;
+
+      mi = mallinfo ();
+      GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
+      GNUNET_free (counter);
+    }
+  }
+#endif
+  if (NULL != sctx->shutdown_task)
+  {
+    GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
+    sctx->shutdown_task = NULL;
+  }
+  if (NULL != sctx->server)
+    GNUNET_SERVER_destroy (sctx->server);
+  GNUNET_free_non_null (sctx->my_handlers);
+  if (NULL != sctx->addrs)
+  {
+    i = 0;
+    while (NULL != sctx->addrs[i])
+      GNUNET_free (sctx->addrs[i++]);
+    GNUNET_free (sctx->addrs);
+  }
+  GNUNET_free_non_null (sctx->addrlens);
+  GNUNET_free_non_null (sctx->v4_denied);
+  GNUNET_free_non_null (sctx->v6_denied);
+  GNUNET_free_non_null (sctx->v4_allowed);
+  GNUNET_free_non_null (sctx->v6_allowed);
+  GNUNET_free (sctx);
+}
+
+
+/* end of service.c */
index be79d54992fffc5f3ff5714076836e8560e27cc3..1d92588ea2672a56302def669c1758334797e881 100644 (file)
@@ -552,7 +552,7 @@ setup_plugin_environment ()
 
 
 static int
-handle_helper_message (void *cls, void *client,
+handle_helper_message (void *cls,
                        const struct GNUNET_MessageHeader *hdr)
 {
   return GNUNET_OK;
index 375a935c8c0c3852d1c93a26b9430df7e835dceb..e5ba2831bc81b96b19bbea2ee11a497b4bc7e459 100644 (file)
@@ -217,7 +217,7 @@ notify_receive (void *cls,
 {
   static int n;
   unsigned int s;
-  char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+  char cbuf[GNUNET_MAX_MESSAGE_SIZE - 1];
 
   if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
     return;
index de9fa91c14b0fcfeee1610515a86ea8a1b9bbf16..0ebb07d741b93e16de8f1d798dc7803eaf45514b 100644 (file)
@@ -71,6 +71,7 @@ GNUNET_TRANSPORT_TESTING_log_disconnect (void *cls,
               GNUNET_i2s (other),
               me->no,
               ps);
+  GNUNET_free (ps);
 }
 
 /* end of transport-testing-loggers.c */
index a79d81cb9b302218a9bd21ab6a32bab760d7f79d..81a66e11370fdf5fdcd14292f2a49c586272a9ee 100644 (file)
@@ -146,7 +146,7 @@ struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
 
 /**
  * Information tracked per connected peer.
- */ 
+ */
 struct ConnectPairInfo
 {
   /**
@@ -235,7 +235,7 @@ my_nc (void *cls,
   struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
   struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
   struct ConnectPairInfo *cpi;
-  
+
   if (NULL != ccc->nc)
     ccc->nc (ccc->cls,
              ccc->p[ipi->off],
@@ -262,7 +262,7 @@ my_nd (void *cls,
   struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
   struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
   struct ConnectPairInfo *cpi = custom_cls;
-  
+
   if (NULL != ccc->nd)
     ccc->nd (ccc->cls,
              ccc->p[ipi->off],
@@ -535,13 +535,15 @@ GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
     ip[i].off = i;
     ip[i].ccc = ccc;
   }
-  GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
-                      argv,
-                      test_name_,
-                      "nohelp",
-                      options,
-                      &connect_check_run,
-                      ccc);
+  if (GNUNET_OK !=
+      GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
+                          argv,
+                          test_name_,
+                          "nohelp",
+                          options,
+                          &connect_check_run,
+                          ccc))
+    return GNUNET_SYSERR;
   return ccc->global_ret;
 }
 
index c0775a1354ec7fc11f283bed5366cc0d113ff15f..53a44f338bdf84d459a8aa05e4c3a7acfb11ffa3 100644 (file)
@@ -49,7 +49,7 @@ find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
  *
  * @param p1 first peer
  * @param p2 second peer
- * @param cb function to call 
+ * @param cb function to call
  * @param cb_cls closure for @a cb
  */
 void
@@ -66,7 +66,7 @@ GNUNET_TRANSPORT_TESTING_find_connecting_context (struct GNUNET_TRANSPORT_TESTIN
   {
     ccn = cc->next;
     if ( (cc->p1 == p1) &&
-        (cc->p2 == p2) ) 
+        (cc->p2 == p2) )
       cb (cb_cls,
          cc);
   }
@@ -74,7 +74,7 @@ GNUNET_TRANSPORT_TESTING_find_connecting_context (struct GNUNET_TRANSPORT_TESTIN
 
 
 static void
-set_p1c (void *cls,   
+set_p1c (void *cls,
         struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
 {
   int *found = cls;
@@ -86,7 +86,7 @@ set_p1c (void *cls,
 
 
 static void
-set_mq (void *cls,   
+set_mq (void *cls,
        struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
 {
   struct GNUNET_MQ_Handle *mq = cls;
@@ -96,7 +96,7 @@ set_mq (void *cls,
 
 
 static void
-set_p2c (void *cls,   
+set_p2c (void *cls,
         struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
 {
   int *found = cls;
@@ -108,7 +108,7 @@ set_p2c (void *cls,
 
 
 static void
-clear_p1c (void *cls,   
+clear_p1c (void *cls,
           struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
 {
   int *found = cls;
@@ -120,7 +120,7 @@ clear_p1c (void *cls,
 
 
 static void
-clear_p2c (void *cls,   
+clear_p2c (void *cls,
         struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
 {
   int *found = cls;
@@ -154,7 +154,7 @@ notify_connect (void *cls,
   else
     ret = NULL;
 
-  if (p2 != NULL)
+  if (NULL != p2)
     GNUNET_asprintf (&p2_s,
                      "%u (`%s')",
                      p2->no,
@@ -267,7 +267,7 @@ notify_disconnect (void *cls,
   int no = 0;
   struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
-  
+
   p2 = find_peer_context (p->tth,
                          peer);
   no = p->no;
@@ -386,7 +386,7 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth
   struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
   struct GNUNET_PeerIdentity *dummy;
   unsigned int i;
-  
+
   if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -407,7 +407,7 @@ GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_Handle *tth
     GNUNET_memcpy (p->handlers,
                   handlers,
                   i * sizeof (struct GNUNET_MQ_MessageHandler));
-  }    
+  }
   if (NULL != cb_cls)
     p->cb_cls = cb_cls;
   else
@@ -532,7 +532,7 @@ GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_PeerConte
 {
   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
   struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
+
   /* shutdown */
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Stopping peer %u (`%s')\n",
@@ -770,7 +770,7 @@ GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_PeerCont
       break;
     }
   }
-         
+
   cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
   cc->p1 = p1;
   cc->p2 = p2;
index b9c72dcb3d67229d85da236994c35c30e8c2c856..902764a8f3b596e6d64b9c98d8a1589f095e3c54 100644 (file)
@@ -199,10 +199,10 @@ GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle *cf
 
   alen = address->address_length;
   slen = strlen (address->transport_name) + 1;
-  if ( (alen + slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE
+  if ( (alen + slen >= GNUNET_MAX_MESSAGE_SIZE
         - sizeof (struct AddressLookupMessage)) ||
-       (alen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
-       (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) )
+       (alen >= GNUNET_MAX_MESSAGE_SIZE) ||
+       (slen >= GNUNET_MAX_MESSAGE_SIZE) )
   {
     GNUNET_break (0);
     GNUNET_free (alc);
index c99ade92f916e0891a8e92537f976cdc21e9cd30..9c29d4908ec4a57447b651386d13db9b9009cca0 100644 (file)
@@ -425,7 +425,7 @@ mq_send_impl (struct GNUNET_MQ_Handle *mq,
 
   GNUNET_assert (GNUNET_YES == n->is_ready);
   msize = ntohs (msg->size);
-  if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*obm))
+  if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*obm))
   {
     GNUNET_break (0);
     GNUNET_MQ_impl_send_continue (mq);
index df319fe7792b247755dd96091b1a9d311e6d6428..9be572bb65444ab64f22e1cf7d7a60e43b71c92d 100644 (file)
@@ -30,10 +30,9 @@ W32CONSOLEHELPER = gnunet-helper-w32-console
 endif
 
 if !MINGW
- SERVER_CLIENT_UNIX = test_server_with_client_unix
- TEST_CLIENT_UNIC_NC = test_client_unix.nc
+ TEST_CLIENT_UNIX_NC = test_client_unix.nc
 else
- TEST_CLIENT_UNIC_NC =
+ TEST_CLIENT_UNIX_NC =
 endif
 
 if USE_COVERAGE
@@ -68,7 +67,6 @@ libgnunetutil_la_SOURCES = \
   common_logging.c \
   configuration.c \
   configuration_loader.c \
-  connection.c \
   container_bloomfilter.c \
   container_heap.c \
   container_meta_data.c \
@@ -108,16 +106,10 @@ libgnunetutil_la_SOURCES = \
   program.c \
   resolver_api.c resolver.h \
   scheduler.c \
-  server.c \
-  server_mst.c \
-  server_nc.c \
-  server_tc.c \
   service.c \
-  service_new.c \
   signal.c \
   strings.c \
   time.c \
-  socks.c \
   speedup.c speedup.h
 
 libgnunetutil_la_LIBADD = \
@@ -263,14 +255,13 @@ if HAVE_BENCHMARKS
 endif
 
 if HAVE_SSH_KEY
- SSH_USING_TESTS = test_socks.nc
+# SSH_USING_TESTS = test_socks.nc
 endif
 
 check_PROGRAMS = \
  test_bio \
  test_client.nc \
  $(TEST_CLIENT_UNIX_NC) \
- $(SSH_USING_TESTS) \
  test_common_allocation \
  test_common_endian \
  test_common_logging \
@@ -298,12 +289,6 @@ check_PROGRAMS = \
  test_crypto_rsa \
  test_disk \
  test_getopt \
- test_connection.nc \
- test_connection_addressing.nc \
- test_connection_receive_cancel.nc \
- test_connection_timeout.nc \
- test_connection_timeout_no_connect.nc \
- test_connection_transmit_cancel.nc \
  test_mq \
  test_os_network \
  test_peer \
@@ -312,11 +297,6 @@ check_PROGRAMS = \
  test_resolver_api.nc \
  test_scheduler \
  test_scheduler_delay \
- test_server.nc \
- test_server_disconnect.nc \
- test_server_with_client.nc \
- test_server_mst_interrupt.nc \
- $(SERVER_CLIENT_UNIX) \
  test_service \
  test_strings \
  test_strings_to_data \
@@ -330,18 +310,7 @@ check_PROGRAMS = \
 # Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart
 # sequential execution order for them
 TEST_EXTENSIONS = .nc
-test_connection.log: test_client.log
-test_connection_addressing.log: test_connection.log
-test_connection_timeout_no_connect.log: test_connection_addressing.log
-test_connection_transmit_cancel.log: test_connection_timeout_no_connect.log
-test_connection_receive_cancel.log: test_connection_transmit_cancel.log
-test_connection_timeout.log: test_connection_receive_cancel.log
-test_resolver_api.log: test_connection_timeout.log
-test_server.log: test_resolver_api.log
-test_server_disconnect.log: test_server.log
-test_server_with_client.log: test_server_disconnect.log
-test_server_mst_interrupt.log: test_server_with_client.log
-test_client_unix.log: test_server_mst_interrupt.log
+test_test_client_unix.log: test_client.log
 
 test_bio_SOURCES = \
  test_bio.c
@@ -518,36 +487,6 @@ test_getopt_SOURCES = \
 test_getopt_LDADD = \
  libgnunetutil.la
 
-test_connection_nc_SOURCES = \
- test_connection.c
-test_connection_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_addressing_nc_SOURCES = \
- test_connection_addressing.c
-test_connection_addressing_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_receive_cancel_nc_SOURCES = \
- test_connection_receive_cancel.c
-test_connection_receive_cancel_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_timeout_nc_SOURCES = \
- test_connection_timeout.c
-test_connection_timeout_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_timeout_no_connect_nc_SOURCES = \
- test_connection_timeout_no_connect.c
-test_connection_timeout_no_connect_nc_LDADD = \
- libgnunetutil.la
-
-test_connection_transmit_cancel_nc_SOURCES = \
- test_connection_transmit_cancel.c
-test_connection_transmit_cancel_nc_LDADD = \
- libgnunetutil.la
-
 test_mq_SOURCES = \
  test_mq.c
 test_mq_LDADD = \
@@ -588,32 +527,6 @@ test_scheduler_delay_SOURCES = \
 test_scheduler_delay_LDADD = \
  libgnunetutil.la
 
-test_server_mst_interrupt_nc_SOURCES = \
- test_server_mst_interrupt.c
-test_server_mst_interrupt_nc_LDADD = \
- libgnunetutil.la
-
-test_server_nc_SOURCES = \
- test_server.c
-test_server_nc_LDADD = \
- libgnunetutil.la
-
-test_server_disconnect_nc_SOURCES = \
- test_server_disconnect.c
-test_server_disconnect_nc_LDADD = \
- libgnunetutil.la
-
-test_server_with_client_nc_SOURCES = \
- test_server_with_client.c
-test_server_with_client_nc_LDADD = \
- libgnunetutil.la
-
-test_server_with_client_unix_SOURCES = \
- test_server_with_client_unix.c
-test_server_with_client_unix_LDADD = \
- libgnunetutil.la
-
-
 test_service_SOURCES = \
  test_service.c
 test_service_LDADD = \
@@ -624,7 +537,6 @@ test_strings_SOURCES = \
 test_strings_LDADD = \
  libgnunetutil.la
 
-
 test_strings_to_data_SOURCES = \
  test_strings_to_data.c
 test_strings_to_data_LDADD = \
index a059fc73808d517e0955b325d48e35b4bb1fd647..bc0c3b9b419a91a3ed215e172047a8c58381538d 100644 (file)
@@ -184,8 +184,8 @@ update_excess (struct GNUNET_BANDWIDTH_Tracker *av)
   }
   /* negative current_consumption means that we have savings */
   max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__;
-  if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE)
-    max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE;
+  if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
+    max_carry = GNUNET_MAX_MESSAGE_SIZE;
   if (max_carry > INT64_MAX)
     max_carry = INT64_MAX;
   left_bytes = current_consumption + max_carry;
@@ -224,10 +224,10 @@ update_excess (struct GNUNET_BANDWIDTH_Tracker *av)
 /**
  * Initialize bandwidth tracker.  Note that in addition to the
  * 'max_carry_s' limit, we also always allow at least
- * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate.  So if the
+ * #GNUNET_MAX_MESSAGE_SIZE to accumulate.  So if the
  * bytes-per-second limit is so small that within 'max_carry_s' not
- * even #GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is
- * ignored and replaced by #GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in
+ * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
+ * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in
  * bytes).
  *
  * To stop notifications about updates and excess callbacks use
@@ -271,10 +271,10 @@ GNUNET_BANDWIDTH_tracker_init2 (struct GNUNET_BANDWIDTH_Tracker *av,
 /**
  * Initialize bandwidth tracker.  Note that in addition to the
  * 'max_carry_s' limit, we also always allow at least
- * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate.  So if the
+ * #GNUNET_MAX_MESSAGE_SIZE to accumulate.  So if the
  * bytes-per-second limit is so small that within 'max_carry_s' not
- * even #GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is
- * ignored and replaced by #GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in
+ * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is
+ * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in
  * bytes).
  *
  * @param av tracker to initialize
@@ -345,8 +345,8 @@ update_tracker (struct GNUNET_BANDWIDTH_Tracker *av)
     left_bytes = - av->consumption_since_last_update__;
     max_carry = ((unsigned long long) av->available_bytes_per_s__) *
                 av->max_carry_s__;
-    if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE)
-      max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE;
+    if (max_carry < GNUNET_MAX_MESSAGE_SIZE)
+      max_carry = GNUNET_MAX_MESSAGE_SIZE;
     if (max_carry > INT64_MAX)
       max_carry = INT64_MAX;
     if (max_carry > left_bytes)
index 0f7d0d35933f555e9ef1d21ffc12e471b3b5974c..3d74bff33ec5aaecc3b719ddf00103e9fd6b89a9 100644 (file)
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__)
 
+/**
+ * Timeout we use on TCP connect before trying another
+ * result from the DNS resolver.  Actual value used
+ * is this value divided by the number of address families.
+ * Default is 5s.
+ */
+#define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+
 
 /**
  * Internal state for a client connected to a GNUnet service.
@@ -298,11 +307,11 @@ recv_message (void *cls,
 
   if (GNUNET_YES == cstate->in_destroy)
     return GNUNET_SYSERR;
-
-  LOG (GNUNET_ERROR_TYPE_INFO,
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Received message of type %u and size %u from %s\n",
-       ntohs (msg->type), ntohs (msg->size), cstate->service_name);
-
+       ntohs (msg->type),
+       ntohs (msg->size),
+       cstate->service_name);
   GNUNET_MQ_inject_message (cstate->mq,
                             msg);
   if (GNUNET_YES == cstate->in_destroy)
@@ -656,7 +665,7 @@ try_connect_using_address (void *cls,
   GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
                                cstate->ap_tail,
                                ap);
-  ap->task = GNUNET_SCHEDULER_add_write_net (GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
+  ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
                                             ap->sock,
                                             &connect_probe_continuation,
                                             ap);
@@ -760,7 +769,7 @@ start_connect (void *cls)
   cstate->dns_active
     = GNUNET_RESOLVER_ip_get (cstate->hostname,
                              AF_UNSPEC,
-                              GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
+                              CONNECT_RETRY_TIMEOUT,
                               &try_connect_using_address,
                              cstate);
 }
diff --git a/src/util/connection.c b/src/util/connection.c
deleted file mode 100644 (file)
index e822b26..0000000
+++ /dev/null
@@ -1,1648 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009-2013 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/connection.c
- * @brief  TCP connection management
- * @author Christian Grothoff
- *
- * This code is rather complex.  Only modify it if you
- * 1) Have a NEW testcase showing that the new code
- *    is needed and correct
- * 2) All EXISTING testcases pass with the new code
- * These rules should apply in general, but for this
- * module they are VERY, VERY important.
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_resolver_service.h"
-
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util-connection", __VA_ARGS__)
-
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-connection", syscall)
-
-
-/**
- * Transmission handle.  There can only be one for each connection.
- */
-struct GNUNET_CONNECTION_TransmitHandle
-{
-
-  /**
-   * Function to call if the send buffer has notify_size
-   * bytes available.
-   */
-  GNUNET_CONNECTION_TransmitReadyNotify notify_ready;
-
-  /**
-   * Closure for notify_ready.
-   */
-  void *notify_ready_cls;
-
-  /**
-   * Our connection handle.
-   */
-  struct GNUNET_CONNECTION_Handle *connection;
-
-  /**
-   * Timeout for receiving (in absolute time).
-   */
-  struct GNUNET_TIME_Absolute transmit_timeout;
-
-  /**
-   * Task called on timeout.
-   */
-  struct GNUNET_SCHEDULER_Task * timeout_task;
-
-  /**
-   * At what number of bytes available in the
-   * write buffer should the notify method be called?
-   */
-  size_t notify_size;
-
-};
-
-
-/**
- * During connect, we try multiple possible IP addresses
- * to find out which one might work.
- */
-struct AddressProbe
-{
-
-  /**
-   * This is a linked list.
-   */
-  struct AddressProbe *next;
-
-  /**
-   * This is a doubly-linked list.
-   */
-  struct AddressProbe *prev;
-
-  /**
-   * The address; do not free (allocated at the end of this struct).
-   */
-  const struct sockaddr *addr;
-
-  /**
-   * Underlying OS's socket.
-   */
-  struct GNUNET_NETWORK_Handle *sock;
-
-  /**
-   * Connection for which we are probing.
-   */
-  struct GNUNET_CONNECTION_Handle *connection;
-
-  /**
-   * Lenth of addr.
-   */
-  socklen_t addrlen;
-
-  /**
-   * Task waiting for the connection to finish connecting.
-   */
-  struct GNUNET_SCHEDULER_Task * task;
-};
-
-
-/**
- * @brief handle for a network connection
- */
-struct GNUNET_CONNECTION_Handle
-{
-
-  /**
-   * Configuration to use.
-   */
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-  /**
-   * Linked list of sockets we are currently trying out
-   * (during connect).
-   */
-  struct AddressProbe *ap_head;
-
-  /**
-   * Linked list of sockets we are currently trying out
-   * (during connect).
-   */
-  struct AddressProbe *ap_tail;
-
-  /**
-   * Network address of the other end-point, may be NULL.
-   */
-  struct sockaddr *addr;
-
-  /**
-   * Pointer to the hostname if connection was
-   * created using DNS lookup, otherwise NULL.
-   */
-  char *hostname;
-
-  /**
-   * Underlying OS's socket, set to NULL after fatal errors.
-   */
-  struct GNUNET_NETWORK_Handle *sock;
-
-  /**
-   * Function to call on data received, NULL if no receive is pending.
-   */
-  GNUNET_CONNECTION_Receiver receiver;
-
-  /**
-   * Closure for @e receiver.
-   */
-  void *receiver_cls;
-
-  /**
-   * Pointer to our write buffer.
-   */
-  char *write_buffer;
-
-  /**
-   * Current size of our @e write_buffer.
-   */
-  size_t write_buffer_size;
-
-  /**
-   * Current write-offset in @e write_buffer (where
-   * would we write next).
-   */
-  size_t write_buffer_off;
-
-  /**
-   * Current read-offset in @e write_buffer (how many
-   * bytes have already been sent).
-   */
-  size_t write_buffer_pos;
-
-  /**
-   * Length of @e addr.
-   */
-  socklen_t addrlen;
-
-  /**
-   * Read task that we may need to wait for.
-   */
-  struct GNUNET_SCHEDULER_Task *read_task;
-
-  /**
-   * Write task that we may need to wait for.
-   */
-  struct GNUNET_SCHEDULER_Task *write_task;
-
-  /**
-   * Handle to a pending DNS lookup request.
-   */
-  struct GNUNET_RESOLVER_RequestHandle *dns_active;
-
-  /**
-   * The handle we return for #GNUNET_CONNECTION_notify_transmit_ready().
-   */
-  struct GNUNET_CONNECTION_TransmitHandle nth;
-
-  /**
-   * Timeout for receiving (in absolute time).
-   */
-  struct GNUNET_TIME_Absolute receive_timeout;
-
-  /**
-   * Maximum number of bytes to read (for receiving).
-   */
-  size_t max;
-
-  /**
-   * Port to connect to.
-   */
-  uint16_t port;
-
-  /**
-   * When shutdown, do not ever actually close the socket, but
-   * free resources.  Only should ever be set if using program
-   * termination as a signal (because only then will the leaked
-   * socket be freed!)
-   */
-  int8_t persist;
-
-  /**
-   * Usually 0.  Set to 1 if this handle is in use, and should
-   * #GNUNET_CONNECTION_destroy() be called right now, the action needs
-   * to be deferred by setting it to -1.
-   */
-  int8_t destroy_later;
-
-  /**
-   * Handle to subsequent connection after proxy handshake completes,
-   */
-  struct GNUNET_CONNECTION_Handle *proxy_handshake;
-
-};
-
-
-/**
- * Set the persist option on this connection handle.  Indicates
- * that the underlying socket or fd should never really be closed.
- * Used for indicating process death.
- *
- * @param connection the connection to set persistent
- */
-void
-GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection)
-{
-  connection->persist = GNUNET_YES;
-}
-
-
-/**
- * Disable the "CORK" feature for communication with the given connection,
- * forcing the OS to immediately flush the buffer on transmission
- * instead of potentially buffering multiple messages.  Essentially
- * reduces the OS send buffers to zero.
- * Used to make sure that the last messages sent through the connection
- * reach the other side before the process is terminated.
- *
- * @param connection the connection to make flushing and blocking
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
-{
-  return GNUNET_NETWORK_socket_disable_corking (connection->sock);
-}
-
-
-/**
- * Create a connection handle by boxing an existing OS socket.  The OS
- * socket should henceforth be no longer used directly.
- * #GNUNET_connection_destroy() will close it.
- *
- * @param osSocket existing socket to box
- * @return the boxed connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
-{
-  struct GNUNET_CONNECTION_Handle *connection;
-
-  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
-  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
-  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
-  connection->sock = osSocket;
-  return connection;
-}
-
-
-/**
- * Create a connection handle by accepting on a listen socket.  This
- * function may block if the listen socket has no connection ready.
- *
- * @param access_cb function to use to check if access is allowed
- * @param access_cb_cls closure for @a access_cb
- * @param lsock listen socket
- * @return the connection handle, NULL on error
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
-                                      void *access_cb_cls,
-                                      struct GNUNET_NETWORK_Handle *lsock)
-{
-  struct GNUNET_CONNECTION_Handle *connection;
-  char addr[128];
-  socklen_t addrlen;
-  struct GNUNET_NETWORK_Handle *sock;
-  int aret;
-  struct sockaddr_in *v4;
-  struct sockaddr_in6 *v6;
-  struct sockaddr *sa;
-  void *uaddr;
-#ifdef SO_PEERCRED
-  struct ucred uc;
-  socklen_t olen;
-#endif
-  struct GNUNET_CONNECTION_Credentials *gcp;
-#if HAVE_GETPEEREID || defined(SO_PEERCRED) || HAVE_GETPEERUCRED
-  struct GNUNET_CONNECTION_Credentials gc;
-
-  gc.uid = 0;
-  gc.gid = 0;
-#endif
-
-  addrlen = sizeof (addr);
-  sock =
-      GNUNET_NETWORK_socket_accept (lsock,
-                                   (struct sockaddr *) &addr,
-                                   &addrlen);
-  if (NULL == sock)
-  {
-    if (EAGAIN != errno)
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
-    return NULL;
-  }
-  if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
-  {
-    GNUNET_break (0);
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
-    return NULL;
-  }
-
-  sa = (struct sockaddr *) addr;
-  v6 = (struct sockaddr_in6 *) addr;
-  if ( (AF_INET6 == sa->sa_family) &&
-       (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)) )
-  {
-    /* convert to V4 address */
-    v4 = GNUNET_new (struct sockaddr_in);
-    memset (v4, 0, sizeof (struct sockaddr_in));
-    v4->sin_family = AF_INET;
-#if HAVE_SOCKADDR_IN_SIN_LEN
-    v4->sin_len = (u_char) sizeof (struct sockaddr_in);
-#endif
-    GNUNET_memcpy (&v4->sin_addr,
-            &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
-                                       sizeof (struct in_addr)],
-            sizeof (struct in_addr));
-    v4->sin_port = v6->sin6_port;
-    uaddr = v4;
-    addrlen = sizeof (struct sockaddr_in);
-  }
-  else
-  {
-    uaddr = GNUNET_malloc (addrlen);
-    GNUNET_memcpy (uaddr, addr, addrlen);
-  }
-  gcp = NULL;
-  if (AF_UNIX == sa->sa_family)
-  {
-#if HAVE_GETPEEREID
-    /* most BSDs */
-    if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock),
-                        &gc.uid,
-                        &gc.gid))
-      gcp = &gc;
-#else
-#ifdef SO_PEERCRED
-    /* largely traditional GNU/Linux */
-    olen = sizeof (uc);
-    if ( (0 ==
-         getsockopt (GNUNET_NETWORK_get_fd (sock),
-                     SOL_SOCKET,
-                     SO_PEERCRED,
-                     &uc,
-                     &olen)) &&
-        (olen == sizeof (uc)) )
-    {
-      gc.uid = uc.uid;
-      gc.gid = uc.gid;
-      gcp = &gc;
-    }
-#else
-#if HAVE_GETPEERUCRED
-    /* this is for Solaris 10 */
-    ucred_t *uc;
-
-    uc = NULL;
-    if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
-    {
-      gc.uid = ucred_geteuid (uc);
-      gc.gid = ucred_getegid (uc);
-      gcp = &gc;
-    }
-    ucred_free (uc);
-#endif
-#endif
-#endif
-  }
-
-  if ( (NULL != access_cb) &&
-       (GNUNET_YES != (aret = access_cb (access_cb_cls,
-                                        gcp,
-                                        uaddr,
-                                        addrlen))) )
-  {
-    if (GNUNET_NO == aret)
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           _("Access denied to `%s'\n"),
-           GNUNET_a2s (uaddr,
-                       addrlen));
-    GNUNET_break (GNUNET_OK ==
-                  GNUNET_NETWORK_socket_shutdown (sock,
-                                                  SHUT_RDWR));
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
-    GNUNET_free (uaddr);
-    return NULL;
-  }
-  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
-  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
-  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
-  connection->addr = uaddr;
-  connection->addrlen = addrlen;
-  connection->sock = sock;
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       _("Accepting connection from `%s': %p\n"),
-       GNUNET_a2s (uaddr,
-                  addrlen),
-       connection);
-  return connection;
-}
-
-
-/**
- * Obtain the network address of the other party.
- *
- * @param connection the client to get the address for
- * @param addr where to store the address
- * @param addrlen where to store the length of the @a addr
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
-                               void **addr,
-                               size_t *addrlen)
-{
-  if ((NULL == connection->addr) || (0 == connection->addrlen))
-    return GNUNET_NO;
-  *addr = GNUNET_malloc (connection->addrlen);
-  GNUNET_memcpy (*addr, connection->addr, connection->addrlen);
-  *addrlen = connection->addrlen;
-  return GNUNET_OK;
-}
-
-
-/**
- * Tell the receiver callback that we had an IO error.
- *
- * @param connection connection to signal error
- * @param errcode error code to send
- */
-static void
-signal_receive_error (struct GNUNET_CONNECTION_Handle *connection,
-                      int errcode)
-{
-  GNUNET_CONNECTION_Receiver receiver;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Receive encounters error (%s), connection closed (%p)\n",
-       STRERROR (errcode),
-       connection);
-  GNUNET_assert (NULL != (receiver = connection->receiver));
-  connection->receiver = NULL;
-  receiver (connection->receiver_cls,
-            NULL,
-            0,
-            connection->addr,
-            connection->addrlen,
-            errcode);
-}
-
-
-/**
- * Tell the receiver callback that a timeout was reached.
- *
- * @param connection connection to signal for
- */
-static void
-signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection)
-{
-  GNUNET_CONNECTION_Receiver receiver;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Connection signals timeout to receiver (%p)!\n",
-       connection);
-  GNUNET_assert (NULL != (receiver = connection->receiver));
-  connection->receiver = NULL;
-  receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0);
-}
-
-
-/**
- * We failed to transmit data to the service, signal the error.
- *
- * @param connection handle that had trouble
- * @param ecode error code (errno)
- */
-static void
-signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection,
-                      int ecode)
-{
-  GNUNET_CONNECTION_TransmitReadyNotify notify;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Transmission encounterd error (%s), connection closed (%p)\n",
-       STRERROR (ecode),
-       connection);
-  if (NULL != connection->sock)
-  {
-    (void) GNUNET_NETWORK_socket_shutdown (connection->sock,
-                                           SHUT_RDWR);
-    GNUNET_break (GNUNET_OK ==
-                  GNUNET_NETWORK_socket_close (connection->sock));
-    connection->sock = NULL;
-    GNUNET_assert (NULL == connection->write_task);
-  }
-  if (NULL != connection->read_task)
-  {
-    /* send errors trigger read errors... */
-    GNUNET_SCHEDULER_cancel (connection->read_task);
-    connection->read_task = NULL;
-    signal_receive_timeout (connection);
-    return;
-  }
-  if (NULL == connection->nth.notify_ready)
-    return;                     /* nobody to tell about it */
-  notify = connection->nth.notify_ready;
-  connection->nth.notify_ready = NULL;
-  notify (connection->nth.notify_ready_cls,
-         0,
-         NULL);
-}
-
-
-/**
- * We've failed for good to establish a connection (timeout or
- * no more addresses to try).
- *
- * @param connection the connection we tried to establish
- */
-static void
-connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection)
-{
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n",
-       connection->hostname,
-    connection->port);
-  GNUNET_break (NULL == connection->ap_head);
-  GNUNET_break (NULL == connection->ap_tail);
-  GNUNET_break (GNUNET_NO == connection->dns_active);
-  GNUNET_break (NULL == connection->sock);
-  GNUNET_assert (NULL == connection->write_task);
-  GNUNET_assert (NULL == connection->proxy_handshake);
-
-  /* signal errors for jobs that used to wait on the connection */
-  connection->destroy_later = 1;
-  if (NULL != connection->receiver)
-    signal_receive_error (connection,
-                          ECONNREFUSED);
-  if (NULL != connection->nth.notify_ready)
-  {
-    GNUNET_assert (NULL != connection->nth.timeout_task);
-    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
-    connection->nth.timeout_task = NULL;
-    signal_transmit_error (connection,
-                           ECONNREFUSED);
-  }
-  if (-1 == connection->destroy_later)
-  {
-    /* do it now */
-    connection->destroy_later = 0;
-    GNUNET_CONNECTION_destroy (connection);
-    return;
-  }
-  connection->destroy_later = 0;
-}
-
-
-/**
- * We are ready to transmit (or got a timeout).
- *
- * @param cls our connection handle
- */
-static void
-transmit_ready (void *cls);
-
-
-/**
- * This function is called once we either timeout or have data ready
- * to read.
- *
- * @param cls connection to read from
- */
-static void
-receive_ready (void *cls);
-
-
-/**
- * We've succeeded in establishing a connection.
- *
- * @param connection the connection we tried to establish
- */
-static void
-connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
-{
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Connection to `%s' succeeded! (%p)\n",
-       GNUNET_a2s (connection->addr,
-                  connection->addrlen),
-       connection);
-  /* trigger jobs that waited for the connection */
-  if (NULL != connection->receiver)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Connection succeeded, starting with receiving data (%p)\n",
-        connection);
-    GNUNET_assert (NULL == connection->read_task);
-    connection->read_task =
-      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
-                                     (connection->receive_timeout),
-                                    connection->sock,
-                                     &receive_ready, connection);
-  }
-  if (NULL != connection->nth.notify_ready)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Connection succeeded, starting with sending data (%p)\n",
-         connection);
-    GNUNET_assert (connection->nth.timeout_task != NULL);
-    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
-    connection->nth.timeout_task = NULL;
-    GNUNET_assert (connection->write_task == NULL);
-    connection->write_task =
-        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
-                                        (connection->nth.transmit_timeout), connection->sock,
-                                        &transmit_ready, connection);
-  }
-}
-
-
-/**
- * Scheduler let us know that we're either ready to write on the
- * socket OR connect timed out.  Do the right thing.
- *
- * @param cls the `struct AddressProbe *` with the address that we are probing
- */
-static void
-connect_probe_continuation (void *cls)
-{
-  struct AddressProbe *ap = cls;
-  struct GNUNET_CONNECTION_Handle *connection = ap->connection;
-  const struct GNUNET_SCHEDULER_TaskContext *tc;
-  struct AddressProbe *pos;
-  int error;
-  socklen_t len;
-
-  GNUNET_assert (NULL != ap->sock);
-  GNUNET_CONTAINER_DLL_remove (connection->ap_head,
-                              connection->ap_tail,
-                              ap);
-  len = sizeof (error);
-  errno = 0;
-  error = 0;
-  tc = GNUNET_SCHEDULER_get_task_context ();
-  if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
-       (GNUNET_OK !=
-       GNUNET_NETWORK_socket_getsockopt (ap->sock,
-                                         SOL_SOCKET,
-                                         SO_ERROR,
-                                         &error,
-                                         &len)) ||
-       (0 != error) )
-  {
-    GNUNET_break (GNUNET_OK ==
-                 GNUNET_NETWORK_socket_close (ap->sock));
-    GNUNET_free (ap);
-    if ( (NULL == connection->ap_head) &&
-        (GNUNET_NO == connection->dns_active) &&
-        (NULL == connection->proxy_handshake) )
-      connect_fail_continuation (connection);
-    return;
-  }
-  GNUNET_assert (NULL == connection->sock);
-  connection->sock = ap->sock;
-  GNUNET_assert (NULL == connection->addr);
-  connection->addr = GNUNET_malloc (ap->addrlen);
-  GNUNET_memcpy (connection->addr, ap->addr, ap->addrlen);
-  connection->addrlen = ap->addrlen;
-  GNUNET_free (ap);
-  /* cancel all other attempts */
-  while (NULL != (pos = connection->ap_head))
-  {
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
-    GNUNET_SCHEDULER_cancel (pos->task);
-    GNUNET_CONTAINER_DLL_remove (connection->ap_head,
-                                connection->ap_tail,
-                                pos);
-    GNUNET_free (pos);
-  }
-  connect_success_continuation (connection);
-}
-
-
-/**
- * Try to establish a connection given the specified address.
- * This function is called by the resolver once we have a DNS reply.
- *
- * @param cls our `struct GNUNET_CONNECTION_Handle *`
- * @param addr address to try, NULL for "last call"
- * @param addrlen length of @a addr
- */
-static void
-try_connect_using_address (void *cls,
-                           const struct sockaddr *addr,
-                           socklen_t addrlen)
-{
-  struct GNUNET_CONNECTION_Handle *connection = cls;
-  struct AddressProbe *ap;
-  struct GNUNET_TIME_Relative delay;
-
-  if (NULL == addr)
-  {
-    connection->dns_active = NULL;
-    if ((NULL == connection->ap_head) &&
-        (NULL == connection->sock) &&
-        (NULL == connection->proxy_handshake))
-      connect_fail_continuation (connection);
-    return;
-  }
-  if (NULL != connection->sock)
-    return;                     /* already connected */
-  GNUNET_assert (NULL == connection->addr);
-  /* try to connect */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Trying to connect using address `%s:%u/%s:%u'\n",
-       connection->hostname,
-       connection->port,
-       GNUNET_a2s (addr, addrlen),
-       connection->port);
-  ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
-  ap->addr = (const struct sockaddr *) &ap[1];
-  GNUNET_memcpy (&ap[1], addr, addrlen);
-  ap->addrlen = addrlen;
-  ap->connection = connection;
-
-  switch (ap->addr->sa_family)
-  {
-  case AF_INET:
-    ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port);
-    break;
-  case AF_INET6:
-    ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port);
-    break;
-  default:
-    GNUNET_break (0);
-    GNUNET_free (ap);
-    return;                     /* not supported by us */
-  }
-  ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
-                                          SOCK_STREAM, 0);
-  if (NULL == ap->sock)
-  {
-    GNUNET_free (ap);
-    return;                     /* not supported by OS */
-  }
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Trying to connect to `%s' (%p)\n",
-       GNUNET_a2s (ap->addr, ap->addrlen),
-       connection);
-  if ((GNUNET_OK !=
-       GNUNET_NETWORK_socket_connect (ap->sock,
-                                     ap->addr,
-                                     ap->addrlen)) &&
-      (EINPROGRESS != errno))
-  {
-    /* maybe refused / unsupported address, try next */
-    LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
-    GNUNET_free (ap);
-    return;
-  }
-  GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
-  delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT;
-  if (NULL != connection->nth.notify_ready)
-    delay = GNUNET_TIME_relative_min (delay,
-                                     GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout));
-  if (NULL != connection->receiver)
-    delay = GNUNET_TIME_relative_min (delay,
-                                     GNUNET_TIME_absolute_get_remaining (connection->receive_timeout));
-  ap->task = GNUNET_SCHEDULER_add_write_net (delay,
-                                            ap->sock,
-                                            &connect_probe_continuation,
-                                            ap);
-}
-
-
-/**
- * Create a connection handle by (asynchronously) connecting to a host.
- * This function returns immediately, even if the connection has not
- * yet been established.  This function only creates TCP connections.
- *
- * @param cfg configuration to use
- * @param hostname name of the host to connect to
- * @param port port to connect to
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                                       const char *hostname,
-                                       uint16_t port)
-{
-  struct GNUNET_CONNECTION_Handle *connection;
-
-  GNUNET_assert (0 < strlen (hostname));        /* sanity check */
-  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
-  connection->cfg = cfg;
-  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
-  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
-  connection->port = port;
-  connection->hostname = GNUNET_strdup (hostname);
-  connection->dns_active =
-      GNUNET_RESOLVER_ip_get (connection->hostname,
-                             AF_UNSPEC,
-                              GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
-                              &try_connect_using_address,
-                             connection);
-  return connection;
-}
-
-
-/**
- * Create a connection handle by connecting to a UNIX domain service.
- * This function returns immediately, even if the connection has not
- * yet been established.  This function only creates UNIX connections.
- *
- * @param cfg configuration to use
- * @param unixpath path to connect to
- * @return the connection handle, NULL on systems without UNIX support
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg,
-                                                   const char *unixpath)
-{
-#ifdef AF_UNIX
-  struct GNUNET_CONNECTION_Handle *connection;
-  struct sockaddr_un *un;
-
-  GNUNET_assert (0 < strlen (unixpath));        /* sanity check */
-  un = GNUNET_new (struct sockaddr_un);
-  un->sun_family = AF_UNIX;
-  strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
-#ifdef LINUX
-  {
-    int abstract;
-
-    abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
-                                                    "TESTING",
-                                                     "USE_ABSTRACT_SOCKETS");
-    if (GNUNET_YES == abstract)
-      un->sun_path[0] = '\0';
-  }
-#endif
-#if HAVE_SOCKADDR_UN_SUN_LEN
-  un->sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
-  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
-  connection->cfg = cfg;
-  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
-  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
-  connection->port = 0;
-  connection->hostname = NULL;
-  connection->addr = (struct sockaddr *) un;
-  connection->addrlen = sizeof (struct sockaddr_un);
-  connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX,
-                                                  SOCK_STREAM,
-                                                  0);
-  if (NULL == connection->sock)
-  {
-    GNUNET_free (connection->addr);
-    GNUNET_free (connection->write_buffer);
-    GNUNET_free (connection);
-    return NULL;
-  }
-  if ( (GNUNET_OK !=
-       GNUNET_NETWORK_socket_connect (connection->sock,
-                                      connection->addr,
-                                      connection->addrlen)) &&
-       (EINPROGRESS != errno) )
-  {
-    /* Just return; we expect everything to work eventually so don't fail HARD */
-    GNUNET_break (GNUNET_OK ==
-                 GNUNET_NETWORK_socket_close (connection->sock));
-    connection->sock = NULL;
-    return connection;
-  }
-  connect_success_continuation (connection);
-  return connection;
-#else
-  return NULL;
-#endif
-}
-
-
-/**
- * Create a connection handle by (asynchronously) connecting to a host.
- * This function returns immediately, even if the connection has not
- * yet been established.  This function only creates TCP connections.
- *
- * @param s socket to connect
- * @param serv_addr server address
- * @param addrlen length of @a serv_addr
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
-                                  const struct sockaddr *serv_addr,
-                                  socklen_t addrlen)
-{
-  struct GNUNET_CONNECTION_Handle *connection;
-
-  if ( (GNUNET_OK !=
-        GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) &&
-       (EINPROGRESS != errno) )
-  {
-    /* maybe refused / unsupported address, try next */
-    LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
-                  "connect");
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Attempt to connect to `%s' failed\n",
-         GNUNET_a2s (serv_addr,
-                     addrlen));
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
-    return NULL;
-  }
-  connection = GNUNET_CONNECTION_create_from_existing (s);
-  connection->addr = GNUNET_malloc (addrlen);
-  GNUNET_memcpy (connection->addr, serv_addr, addrlen);
-  connection->addrlen = addrlen;
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Trying to connect to `%s' (%p)\n",
-       GNUNET_a2s (serv_addr, addrlen),
-       connection);
-  return connection;
-}
-
-
-/**
- * Create a connection handle by creating a socket and
- * (asynchronously) connecting to a host.  This function returns
- * immediately, even if the connection has not yet been established.
- * This function only creates TCP connections.
- *
- * @param af_family address family to use
- * @param serv_addr server address
- * @param addrlen length of @a serv_addr
- * @return the connection handle
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_sockaddr (int af_family,
-                                        const struct sockaddr *serv_addr,
-                                        socklen_t addrlen)
-{
-  struct GNUNET_NETWORK_Handle *s;
-
-  s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
-  if (NULL == s)
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
-                 "socket");
-    return NULL;
-  }
-  return GNUNET_CONNECTION_connect_socket (s,
-                                          serv_addr,
-                                          addrlen);
-}
-
-
-/**
- * Check if connection is valid (no fatal errors have happened so far).
- * Note that a connection that is still trying to connect is considered
- * valid.
- *
- * @param connection connection to check
- * @return #GNUNET_YES if valid, #GNUNET_NO otherwise
- */
-int
-GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection)
-{
-  if ((NULL != connection->ap_head) ||
-      (NULL != connection->dns_active) ||
-      (NULL != connection->proxy_handshake))
-    return GNUNET_YES;          /* still trying to connect */
-  if ( (0 != connection->destroy_later) ||
-       (NULL == connection->sock) )
-    return GNUNET_NO;
-  return GNUNET_YES;
-}
-
-
-/**
- * Close the connection and free associated resources.  There must
- * not be any pending requests for reading or writing to the
- * connection at this time.
- *
- * @param connection connection to destroy
- */
-void
-GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
-{
-  struct AddressProbe *pos;
-
-  if (0 != connection->destroy_later)
-  {
-    connection->destroy_later = -1;
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Shutting down connection (%p)\n",
-       connection);
-  GNUNET_assert (NULL == connection->nth.notify_ready);
-  GNUNET_assert (NULL == connection->receiver);
-  if (NULL != connection->write_task)
-  {
-    GNUNET_SCHEDULER_cancel (connection->write_task);
-    connection->write_task = NULL;
-    connection->write_buffer_off = 0;
-  }
-  if (NULL != connection->read_task)
-  {
-    GNUNET_SCHEDULER_cancel (connection->read_task);
-    connection->read_task = NULL;
-  }
-  if (NULL != connection->nth.timeout_task)
-  {
-    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
-    connection->nth.timeout_task = NULL;
-  }
-  connection->nth.notify_ready = NULL;
-  if (NULL != connection->dns_active)
-  {
-    GNUNET_RESOLVER_request_cancel (connection->dns_active);
-    connection->dns_active = NULL;
-  }
-  if (NULL != connection->proxy_handshake)
-  {
-    /* GNUNET_CONNECTION_destroy (connection->proxy_handshake); */
-    connection->proxy_handshake->destroy_later = -1;
-    connection->proxy_handshake = NULL;  /* Not leaked ??? */
-  }
-  while (NULL != (pos = connection->ap_head))
-  {
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
-    GNUNET_SCHEDULER_cancel (pos->task);
-    GNUNET_CONTAINER_DLL_remove (connection->ap_head,
-                                connection->ap_tail,
-                                pos);
-    GNUNET_free (pos);
-  }
-  if ( (NULL != connection->sock) &&
-       (GNUNET_YES != connection->persist) )
-  {
-    if ((GNUNET_OK !=
-         GNUNET_NETWORK_socket_shutdown (connection->sock,
-                                         SHUT_RDWR)) &&
-       (ENOTCONN != errno) &&
-       (ECONNRESET != errno) )
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
-                    "shutdown");
-  }
-  if (NULL != connection->sock)
-  {
-    if (GNUNET_YES != connection->persist)
-    {
-      GNUNET_break (GNUNET_OK ==
-                    GNUNET_NETWORK_socket_close (connection->sock));
-    }
-    else
-    {
-      GNUNET_NETWORK_socket_free_memory_only_ (connection->sock); /* at least no memory leak (we deliberately
-                                                                  * leak the socket in this special case) ... */
-    }
-  }
-  GNUNET_free_non_null (connection->addr);
-  GNUNET_free_non_null (connection->hostname);
-  GNUNET_free (connection->write_buffer);
-  GNUNET_free (connection);
-}
-
-
-/**
- * This function is called once we either timeout
- * or have data ready to read.
- *
- * @param cls connection to read from
- */
-static void
-receive_ready (void *cls)
-{
-  struct GNUNET_CONNECTION_Handle *connection = cls;
-  const struct GNUNET_SCHEDULER_TaskContext *tc;
-  char buffer[connection->max];
-  ssize_t ret;
-  GNUNET_CONNECTION_Receiver receiver;
-
-  connection->read_task = NULL;
-  tc = GNUNET_SCHEDULER_get_task_context ();
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-        "Receive from `%s' encounters error: timeout (%s, %p)\n",
-        GNUNET_a2s (connection->addr,
-                    connection->addrlen),
-        GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (connection->receive_timeout),
-                                                GNUNET_YES),
-        connection);
-    signal_receive_timeout (connection);
-    return;
-  }
-  if (NULL == connection->sock)
-  {
-    /* connect failed for good */
-    signal_receive_error (connection, ECONNREFUSED);
-    return;
-  }
-  GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready,
-                                            connection->sock));
-RETRY:
-  ret = GNUNET_NETWORK_socket_recv (connection->sock,
-                                    buffer,
-                                    connection->max);
-  if (-1 == ret)
-  {
-    if (EINTR == errno)
-      goto RETRY;
-    signal_receive_error (connection, errno);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "receive_ready read %u/%u bytes from `%s' (%p)!\n",
-       (unsigned int) ret,
-       connection->max,
-       GNUNET_a2s (connection->addr,
-                   connection->addrlen),
-       connection);
-  GNUNET_assert (NULL != (receiver = connection->receiver));
-  connection->receiver = NULL;
-  receiver (connection->receiver_cls,
-            buffer,
-            ret,
-            connection->addr,
-            connection->addrlen,
-            0);
-}
-
-
-/**
- * Receive data from the given connection.  Note that this function
- * will call @a receiver asynchronously using the scheduler.  It will
- * "immediately" return.  Note that there MUST only be one active
- * receive call per connection at any given point in time (so do not
- * call receive again until the receiver callback has been invoked).
- *
- * @param connection connection handle
- * @param max maximum number of bytes to read
- * @param timeout maximum amount of time to wait
- * @param receiver function to call with received data
- * @param receiver_cls closure for @a receiver
- */
-void
-GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection,
-                           size_t max,
-                           struct GNUNET_TIME_Relative timeout,
-                           GNUNET_CONNECTION_Receiver receiver,
-                           void *receiver_cls)
-{
-  GNUNET_assert ((NULL == connection->read_task) &&
-                 (NULL == connection->receiver));
-  GNUNET_assert (NULL != receiver);
-  connection->receiver = receiver;
-  connection->receiver_cls = receiver_cls;
-  connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  connection->max = max;
-  if (NULL != connection->sock)
-  {
-    connection->read_task =
-      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
-                                     (connection->receive_timeout),
-                                     connection->sock,
-                                     &receive_ready,
-                                     connection);
-    return;
-  }
-  if ((NULL == connection->dns_active) &&
-      (NULL == connection->ap_head) &&
-      (NULL == connection->proxy_handshake))
-  {
-    connection->receiver = NULL;
-    receiver (receiver_cls,
-             NULL, 0,
-             NULL, 0,
-             ETIMEDOUT);
-    return;
-  }
-}
-
-
-/**
- * Cancel receive job on the given connection.  Note that the
- * receiver callback must not have been called yet in order
- * for the cancellation to be valid.
- *
- * @param connection connection handle
- * @return closure of the original receiver callback closure
- */
-void *
-GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
-{
-  if (NULL != connection->read_task)
-  {
-    GNUNET_assert (connection ==
-                   GNUNET_SCHEDULER_cancel (connection->read_task));
-    connection->read_task = NULL;
-  }
-  connection->receiver = NULL;
-  return connection->receiver_cls;
-}
-
-
-/**
- * Try to call the transmit notify method (check if we do
- * have enough space available first)!
- *
- * @param connection connection for which we should do this processing
- * @return #GNUNET_YES if we were able to call notify
- */
-static int
-process_notify (struct GNUNET_CONNECTION_Handle *connection)
-{
-  size_t used;
-  size_t avail;
-  size_t size;
-  GNUNET_CONNECTION_TransmitReadyNotify notify;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "process_notify is running\n");
-  GNUNET_assert (NULL == connection->write_task);
-  if (NULL == (notify = connection->nth.notify_ready))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "No one to notify\n");
-    return GNUNET_NO;
-  }
-  used = connection->write_buffer_off - connection->write_buffer_pos;
-  avail = connection->write_buffer_size - used;
-  size = connection->nth.notify_size;
-  if (size > avail)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Not enough buffer\n");
-    return GNUNET_NO;
-  }
-  connection->nth.notify_ready = NULL;
-  if (connection->write_buffer_size - connection->write_buffer_off < size)
-  {
-    /* need to compact */
-    memmove (connection->write_buffer,
-             &connection->write_buffer[connection->write_buffer_pos],
-             used);
-    connection->write_buffer_off -= connection->write_buffer_pos;
-    connection->write_buffer_pos = 0;
-  }
-  avail = connection->write_buffer_size - connection->write_buffer_off;
-  GNUNET_assert (avail >= size);
-  size =
-      notify (connection->nth.notify_ready_cls, avail,
-              &connection->write_buffer[connection->write_buffer_off]);
-  GNUNET_assert (size <= avail);
-  if (0 != size)
-    connection->write_buffer_off += size;
-  return GNUNET_YES;
-}
-
-
-/**
- * Task invoked by the scheduler when a call to transmit
- * is timing out (we never got enough buffer space to call
- * the callback function before the specified timeout
- * expired).
- *
- * This task notifies the client about the timeout.
- *
- * @param cls the `struct GNUNET_CONNECTION_Handle`
- */
-static void
-transmit_timeout (void *cls)
-{
-  struct GNUNET_CONNECTION_Handle *connection = cls;
-  GNUNET_CONNECTION_TransmitReadyNotify notify;
-
-  connection->nth.timeout_task = NULL;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Transmit to `%s:%u/%s' fails, time out reached (%p).\n",
-       connection->hostname,
-       connection->port,
-       GNUNET_a2s (connection->addr,
-                   connection->addrlen),
-       connection);
-  notify = connection->nth.notify_ready;
-  GNUNET_assert (NULL != notify);
-  connection->nth.notify_ready = NULL;
-  notify (connection->nth.notify_ready_cls,
-         0,
-         NULL);
-}
-
-
-/**
- * Task invoked by the scheduler when we failed to connect
- * at the time of being asked to transmit.
- *
- * This task notifies the client about the error.
- *
- * @param cls the `struct GNUNET_CONNECTION_Handle`
- */
-static void
-connect_error (void *cls)
-{
-  struct GNUNET_CONNECTION_Handle *connection = cls;
-  GNUNET_CONNECTION_TransmitReadyNotify notify;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Transmission request of size %u fails (%s/%u), connection failed (%p).\n",
-       connection->nth.notify_size,
-       connection->hostname,
-       connection->port,
-       connection);
-  connection->write_task = NULL;
-  notify = connection->nth.notify_ready;
-  connection->nth.notify_ready = NULL;
-  notify (connection->nth.notify_ready_cls,
-         0,
-         NULL);
-}
-
-
-/**
- * We are ready to transmit (or got a timeout).
- *
- * @param cls our connection handle
- */
-static void
-transmit_ready (void *cls)
-{
-  struct GNUNET_CONNECTION_Handle *connection = cls;
-  GNUNET_CONNECTION_TransmitReadyNotify notify;
-  const struct GNUNET_SCHEDULER_TaskContext *tc;
-  ssize_t ret;
-  size_t have;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "transmit_ready running (%p).\n",
-       connection);
-  GNUNET_assert (NULL != connection->write_task);
-  connection->write_task = NULL;
-  GNUNET_assert (NULL == connection->nth.timeout_task);
-  tc = GNUNET_SCHEDULER_get_task_context ();
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Transmit to `%s' fails, time out reached (%p).\n",
-         GNUNET_a2s (connection->addr,
-                     connection->addrlen),
-         connection);
-    notify = connection->nth.notify_ready;
-    GNUNET_assert (NULL != notify);
-    connection->nth.notify_ready = NULL;
-    notify (connection->nth.notify_ready_cls, 0, NULL);
-    return;
-  }
-  GNUNET_assert (NULL != connection->sock);
-  if (NULL == tc->write_ready)
-  {
-    /* special circumstances (in particular, PREREQ_DONE after
-     * connect): not yet ready to write, but no "fatal" error either.
-     * Hence retry.  */
-    goto SCHEDULE_WRITE;
-  }
-  if (! GNUNET_NETWORK_fdset_isset (tc->write_ready,
-                                   connection->sock))
-  {
-    GNUNET_assert (NULL == connection->write_task);
-    /* special circumstances (in particular, shutdown): not yet ready
-     * to write, but no "fatal" error either.  Hence retry.  */
-    goto SCHEDULE_WRITE;
-  }
-  GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos);
-  if ((NULL != connection->nth.notify_ready) &&
-      (connection->write_buffer_size < connection->nth.notify_size))
-  {
-    connection->write_buffer =
-        GNUNET_realloc (connection->write_buffer, connection->nth.notify_size);
-    connection->write_buffer_size = connection->nth.notify_size;
-  }
-  process_notify (connection);
-  have = connection->write_buffer_off - connection->write_buffer_pos;
-  if (0 == have)
-  {
-    /* no data ready for writing, terminate write loop */
-    return;
-  }
-  GNUNET_assert (have <= connection->write_buffer_size);
-  GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size);
-  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
-RETRY:
-  ret =
-      GNUNET_NETWORK_socket_send (connection->sock,
-                                 &connection->write_buffer[connection->write_buffer_pos],
-                                 have);
-  if (-1 == ret)
-  {
-    if (EINTR == errno)
-      goto RETRY;
-    if (NULL != connection->write_task)
-    {
-      GNUNET_SCHEDULER_cancel (connection->write_task);
-      connection->write_task = NULL;
-    }
-    signal_transmit_error (connection, errno);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Connection transmitted %u/%u bytes to `%s' (%p)\n",
-       (unsigned int) ret,
-       have,
-       GNUNET_a2s (connection->addr,
-                  connection->addrlen),
-       connection);
-  connection->write_buffer_pos += ret;
-  if (connection->write_buffer_pos == connection->write_buffer_off)
-  {
-    /* transmitted all pending data */
-    connection->write_buffer_pos = 0;
-    connection->write_buffer_off = 0;
-  }
-  if ( (0 == connection->write_buffer_off) &&
-       (NULL == connection->nth.notify_ready) )
-    return;                     /* all data sent! */
-  /* not done writing, schedule more */
-SCHEDULE_WRITE:
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Re-scheduling transmit_ready (more to do) (%p).\n",
-       connection);
-  have = connection->write_buffer_off - connection->write_buffer_pos;
-  GNUNET_assert ( (NULL != connection->nth.notify_ready) ||
-                 (have > 0) );
-  if (NULL == connection->write_task)
-    connection->write_task =
-        GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready ==
-                                         NULL) ? GNUNET_TIME_UNIT_FOREVER_REL :
-                                        GNUNET_TIME_absolute_get_remaining
-                                        (connection->nth.transmit_timeout),
-                                        connection->sock,
-                                       &transmit_ready, connection);
-}
-
-
-/**
- * Ask the connection to call us once the specified number of bytes
- * are free in the transmission buffer.  Will never call the @a notify
- * callback in this task, but always first go into the scheduler.
- *
- * @param connection connection
- * @param size number of bytes to send
- * @param timeout after how long should we give up (and call
- *        @a notify with buf NULL and size 0)?
- * @param notify function to call
- * @param notify_cls closure for @a notify
- * @return non-NULL if the notify callback was queued,
- *         NULL if we are already going to notify someone else (busy)
- */
-struct GNUNET_CONNECTION_TransmitHandle *
-GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
-                                         size_t size,
-                                         struct GNUNET_TIME_Relative timeout,
-                                         GNUNET_CONNECTION_TransmitReadyNotify notify,
-                                        void *notify_cls)
-{
-  if (NULL != connection->nth.notify_ready)
-  {
-    GNUNET_assert (0);
-    return NULL;
-  }
-  GNUNET_assert (NULL != notify);
-  GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
-  GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
-  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
-  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off);
-  connection->nth.notify_ready = notify;
-  connection->nth.notify_ready_cls = notify_cls;
-  connection->nth.connection = connection;
-  connection->nth.notify_size = size;
-  connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  GNUNET_assert (NULL == connection->nth.timeout_task);
-  if ((NULL == connection->sock) &&
-      (NULL == connection->ap_head) &&
-      (NULL == connection->dns_active) &&
-      (NULL == connection->proxy_handshake))
-  {
-    if (NULL != connection->write_task)
-      GNUNET_SCHEDULER_cancel (connection->write_task);
-    connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error,
-                                                       connection);
-    return &connection->nth;
-  }
-  if (NULL != connection->write_task)
-    return &connection->nth; /* previous transmission still in progress */
-  if (NULL != connection->sock)
-  {
-    /* connected, try to transmit now */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Scheduling transmission (%p).\n",
-         connection);
-    connection->write_task =
-        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
-                                        (connection->nth.transmit_timeout),
-                                        connection->sock,
-                                       &transmit_ready, connection);
-    return &connection->nth;
-  }
-  /* not yet connected, wait for connection */
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Need to wait to schedule transmission for connection, adding timeout task (%p).\n",
-       connection);
-  connection->nth.timeout_task =
-    GNUNET_SCHEDULER_add_delayed (timeout,
-                                  &transmit_timeout,
-                                 connection);
-  return &connection->nth;
-}
-
-
-/**
- * Cancel the specified transmission-ready notification.
- *
- * @param th notification to cancel
- */
-void
-GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th)
-{
-  GNUNET_assert (NULL != th->notify_ready);
-  th->notify_ready = NULL;
-  if (NULL != th->timeout_task)
-  {
-    GNUNET_SCHEDULER_cancel (th->timeout_task);
-    th->timeout_task = NULL;
-  }
-  if (NULL != th->connection->write_task)
-  {
-    GNUNET_SCHEDULER_cancel (th->connection->write_task);
-    th->connection->write_task = NULL;
-  }
-}
-
-
-/**
- * Create a connection to be proxied using a given connection.
- *
- * @param cph connection to proxy server
- * @return connection to be proxied
- */
-struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph)
-{
-  struct GNUNET_CONNECTION_Handle *proxied = GNUNET_CONNECTION_create_from_existing (NULL);
-
-  proxied->proxy_handshake = cph;
-  return proxied;
-}
-
-
-/**
- * Activate proxied connection and destroy initial proxy handshake connection.
- * There must not be any pending requests for reading or writing to the
- * proxy hadshake connection at this time.
- *
- * @param proxied connection connection to proxy server
- */
-void
-GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied)
-{
-  struct GNUNET_CONNECTION_Handle *cph = proxied->proxy_handshake;
-
-  GNUNET_assert (NULL != cph);
-  GNUNET_assert (NULL == proxied->sock);
-  GNUNET_assert (NULL != cph->sock);
-  proxied->sock = cph->sock;
-  cph->sock = NULL;
-  GNUNET_CONNECTION_destroy (cph);
-  connect_success_continuation (proxied);
-}
-
-
-/* end of connection.c */
index d3d5d87dc76f609578c5f187e4e1c8d4dd555634..d536ec8979b4297e153ca56a6692707844d45000 100644 (file)
@@ -329,8 +329,10 @@ GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
     BY_HANDLE_FILE_INFORMATION info;
     int succ;
 
-    fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0);
-    if (fh == NULL)
+    fh = GNUNET_DISK_file_open (filename,
+                                GNUNET_DISK_OPEN_READ,
+                                GNUNET_DISK_PERM_NONE);
+    if (NULL == fh)
       return GNUNET_SYSERR;
     succ = GetFileInformationByHandle (fh->h, &info);
     GNUNET_DISK_file_close (fh);
@@ -1191,7 +1193,7 @@ GNUNET_DISK_fn_write (const char *fn,
   fh = GNUNET_DISK_file_open (fn,
                               GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE
                               | GNUNET_DISK_OPEN_CREATE, mode);
-  if (!fh)
+  if (! fh)
     return GNUNET_SYSERR;
   ret = GNUNET_DISK_file_write (fh, buffer, n);
   GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
@@ -1756,9 +1758,10 @@ GNUNET_DISK_file_open (const char *fn,
 
 
 /**
- * Close an open file
+ * Close an open file.
+ *
  * @param h file handle
- * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
  */
 int
 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
@@ -1773,7 +1776,7 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
   ret = GNUNET_OK;
 
 #if MINGW
-  if (!CloseHandle (h->h))
+  if (! CloseHandle (h->h))
   {
     SetErrnoFromWinError (GetLastError ());
     LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
@@ -1781,7 +1784,7 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
   }
   if (h->oOverlapRead)
   {
-    if (!CloseHandle (h->oOverlapRead->hEvent))
+    if (! CloseHandle (h->oOverlapRead->hEvent))
     {
       SetErrnoFromWinError (GetLastError ());
       LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
@@ -1822,7 +1825,6 @@ struct GNUNET_DISK_FileHandle *
 GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
 {
   struct GNUNET_DISK_FileHandle *fh;
-
   DWORD dwret;
   enum GNUNET_FILE_Type ftype;
 
@@ -1836,7 +1838,8 @@ GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
     ftype = GNUNET_DISK_HANLDE_TYPE_PIPE;
     break;
   case FILE_TYPE_UNKNOWN:
-    if (GetLastError () == NO_ERROR || GetLastError () == ERROR_INVALID_HANDLE)
+    if ( (GetLastError () == NO_ERROR) ||
+         (GetLastError () == ERROR_INVALID_HANDLE) )
     {
       if (0 != ResetEvent (osfh))
         ftype = GNUNET_DISK_HANLDE_TYPE_EVENT;
index ff62dba9be0fae2d9fee7fb95917253da5f8264e..036e0f4be598d55f3d86d6ce76d2b6eb1a77dcb6 100644 (file)
@@ -26,7 +26,7 @@ USA.
 
 
 This code was heavily modified for GNUnet.
-Copyright Copyright (C) 2006 Christian Grothoff
+Copyright Copyright (C) 2006, 2017 Christian Grothoff
 */
 
 /**
@@ -845,9 +845,13 @@ GN_getopt_internal (int argc, char *const *argv, const char *optstring,
   }
 }
 
+
 static int
-GNgetopt_long (int argc, char *const *argv, const char *options,
-               const struct GNoption *long_options, int *opt_index)
+GNgetopt_long (int argc,
+               char *const *argv,
+               const char *options,
+               const struct GNoption *long_options,
+               int *opt_index)
 {
   return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0);
 }
@@ -867,16 +871,17 @@ GNgetopt_long (int argc, char *const *argv, const char *options,
 int
 GNUNET_GETOPT_run (const char *binaryOptions,
                    const struct GNUNET_GETOPT_CommandLineOption *allOptions,
-                   unsigned int argc, char *const *argv)
+                   unsigned int argc,
+                   char *const *argv)
 {
   struct GNoption *long_options;
   struct GNUNET_GETOPT_CommandLineProcessorContext clpc;
   int count;
-  int i;
   char *shorts;
   int spos;
   int cont;
   int c;
+  uint8_t *seen;
 
   GNUNET_assert (argc > 0);
   GNoptind = 0;
@@ -885,13 +890,15 @@ GNUNET_GETOPT_run (const char *binaryOptions,
   clpc.allOptions = allOptions;
   clpc.argv = argv;
   clpc.argc = argc;
-  count = 0;
-  while (allOptions[count].name != NULL)
-    count++;
-  long_options = GNUNET_malloc (sizeof (struct GNoption) * (count + 1));
+  for (count = 0; NULL != allOptions[count].name; count++) ;
+
+  long_options = GNUNET_new_array (count + 1,
+                                   struct GNoption);
+  seen = GNUNET_new_array (count,
+                           uint8_t);
   shorts = GNUNET_malloc (count * 2 + 1);
   spos = 0;
-  for (i = 0; i < count; i++)
+  for (unsigned i = 0; i < count; i++)
   {
     long_options[i].name = allOptions[i].name;
     long_options[i].has_arg = allOptions[i].require_argument;
@@ -907,13 +914,17 @@ GNUNET_GETOPT_run (const char *binaryOptions,
   long_options[count].val = '\0';
   shorts[spos] = '\0';
   cont = GNUNET_OK;
+
   /* main getopt loop */
-  while (cont == GNUNET_OK)
+  while (GNUNET_OK == cont)
   {
     int option_index = 0;
+    unsigned int i;
 
-    c = GNgetopt_long (argc, argv, shorts, long_options, &option_index);
-
+    c = GNgetopt_long (argc, argv,
+                       shorts,
+                       long_options,
+                       &option_index);
     if (c == GNUNET_SYSERR)
       break;                    /* No more flags to process */
 
@@ -922,25 +933,46 @@ GNUNET_GETOPT_run (const char *binaryOptions,
       clpc.currentArgument = GNoptind - 1;
       if ((char) c == allOptions[i].shortName)
       {
-        cont =
-            allOptions[i].processor (&clpc, allOptions[i].scls,
-                                     allOptions[i].name, GNoptarg);
+        cont = allOptions[i].processor (&clpc,
+                                        allOptions[i].scls,
+                                        allOptions[i].name,
+                                        GNoptarg);
+        seen[i] = 1;
         break;
       }
     }
     if (i == count)
     {
-      FPRINTF (stderr, _("Use %s to get a list of options.\n"), "--help");
+      FPRINTF (stderr,
+               _("Use %s to get a list of options.\n"),
+               "--help");
       cont = GNUNET_SYSERR;
     }
   }
-
   GNUNET_free (shorts);
   GNUNET_free (long_options);
-  if (cont != GNUNET_OK)
+
+  if (GNUNET_YES == cont)
   {
-    return cont;
+    for (count = 0; NULL != allOptions[count].name; count++)
+      if ( (0 == seen[count]) &&
+           (allOptions[count].option_mandatory) )
+      {
+        FPRINTF (stderr,
+                 _("Missing mandatory option `%s'.\n"),
+                 allOptions[count].name);
+        cont = GNUNET_SYSERR;
+      }
   }
+  GNUNET_free (seen);
+
+  /* call cleaners, if available */
+  for (count = 0; NULL != allOptions[count].name; count++)
+    if (NULL != allOptions[count].cleaner)
+      allOptions[count].cleaner (allOptions[count].scls);
+
+  if (GNUNET_OK != cont)
+    return cont;
   return GNoptind;
 }
 
index 4d71045031e180242c047f9b1736777166775c80..76342a6c9c4384834780d6bd373038b668a3c94a 100644 (file)
  * @param value not used (NULL)
  * @return #GNUNET_NO (do not continue, not an error)
  */
-int
-GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                             void *scls,
-                             const char *option,
-                              const char *value)
+static int
+print_version (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+               void *scls,
+               const char *option,
+               const char *value)
 {
   const char *version = scls;
 
@@ -53,6 +53,26 @@ GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext *
 }
 
 
+/**
+ * Define the option to print the version of
+ * the application (-v option)
+ *
+ * @param version string with the version number
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_VERSION (const char *version)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  'v',
+    .name = "version",
+    .description = gettext_noop("print the version number"),
+    .processor = &print_version,
+    .scls = (void *) version
+  };
+  return clo;
+}
+
+
 /**
  * At what offset does the help text start?
  */
@@ -67,11 +87,11 @@ GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext *
  * @param value not used (NULL)
  * @return #GNUNET_NO (do not continue, not an error)
  */
-int
-GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                           void *scls,
-                           const char *option,
-                            const char *value)
+static int
+format_help (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+             void *scls,
+             const char *option,
+             const char *value)
 {
   const char *about = scls;
   size_t slen;
@@ -164,6 +184,27 @@ OUTER:
 }
 
 
+/**
+ * Defining the option to print the command line
+ * help text (-h option).
+ *
+ * @param about string with brief description of the application
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_HELP (const char *about)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName = 'h',
+    .name = "help",
+    .description = gettext_noop("print this help"),
+    .processor = format_help,
+    .scls = (void *) about
+  };
+
+  return clo;
+}
+
+
 /**
  * Set an option of type 'unsigned int' from the command line. Each
  * time the option flag is given, the value is incremented by one.
@@ -173,23 +214,72 @@ OUTER:
  * type 'int'.
  *
  * @param ctx command line processing context
- * @param scls additional closure (will point to the 'int')
+ * @param scls additional closure (will point to the 'unsigned int')
  * @param option name of the option
  * @param value not used (NULL)
  * @return #GNUNET_OK
  */
-int
-GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext
-                               *ctx, void *scls, const char *option,
-                               const char *value)
+static int
+increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+                 void *scls,
+                 const char *option,
+                 const char *value)
 {
-  int *val = scls;
+  unsigned int *val = scls;
 
   (*val)++;
   return GNUNET_OK;
 }
 
 
+/**
+ * Increment @a val each time the option flag is given by one.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val increment by 1 each time the option is present
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_INCREMENT_VALUE (char shortName,
+                                      const char *name,
+                                      const char *description,
+                                      unsigned int *val)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .description = description,
+    .processor = &increment_value,
+    .scls = (void *) val
+  };
+
+  return clo;
+}
+
+
+/**
+ * Define the '-V' verbosity option.  Using the option more
+ * than once increments @a level each time.
+ *
+ * @param[out] level set to the verbosity level
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_VERBOSE (unsigned int *level)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName = 'V',
+    .name = "verbose",
+    .description = gettext_noop("be verbose"),
+    .processor = &increment_value,
+    .scls = (void *) level
+  };
+
+  return clo;
+}
+
+
 /**
  * Set an option of type 'int' from the command line to 1 if the
  * given option is present.
@@ -204,9 +294,11 @@ GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext
  * @param value not used (NULL)
  * @return #GNUNET_OK
  */
-int
-GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                       void *scls, const char *option, const char *value)
+static int
+set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+         void *scls,
+         const char *option,
+         const char *value)
 {
   int *val = scls;
 
@@ -215,6 +307,34 @@ GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
 }
 
 
+/**
+ * Allow user to specify a flag (which internally means setting
+ * an integer to 1/#GNUNET_YES/#GNUNET_OK.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to 1 if the option is present
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_ONE (char shortName,
+                              const char *name,
+                              const char *description,
+                              int *val)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .description = description,
+    .processor = &set_one,
+    .scls = (void *) val
+  };
+
+  return clo;
+}
+
+
 /**
  * Set an option of type 'char *' from the command line.
  * A pointer to this function should be passed as part of the
@@ -229,31 +349,174 @@ GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
  * @param value actual value of the option (a string)
  * @return #GNUNET_OK
  */
-int
-GNUNET_GETOPT_set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                          void *scls, const char *option, const char *value)
+static int
+set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+            void *scls,
+            const char *option,
+            const char *value)
 {
   char **val = scls;
 
-  GNUNET_assert (value != NULL);
+  GNUNET_assert (NULL != value);
   GNUNET_free_non_null (*val);
   *val = GNUNET_strdup (value);
   return GNUNET_OK;
 }
 
 
-int
-GNUNET_GETOPT_set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                            void *scls, const char *option, const char *value)
+/**
+ * Allow user to specify a string.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] str set to the string
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_STRING (char shortName,
+                             const char *name,
+                             const char *argumentHelp,
+                             const char *description,
+                             char **str)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &set_string,
+    .scls = (void *) str
+  };
+
+  return clo;
+}
+
+
+/**
+ * Define the '-L' log level option.  Note that we do not check
+ * that the log level is valid here.
+ *
+ * @param[out] level set to the log level
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_LOGLEVEL (char **level)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName = 'L',
+    .name = "log",
+    .argumentHelp = "LOGLEVEL",
+    .description = gettext_noop("configure logging to use LOGLEVEL"),
+    .require_argument = 1,
+    .processor = &set_string,
+    .scls = (void *) level
+  };
+
+  return clo;
+}
+
+
+/**
+ * Set an option of type 'char *' from the command line with
+ * filename expansion a la #GNUNET_STRINGS_filename_expand().
+ *
+ * @param ctx command line processing context
+ * @param scls additional closure (will point to the `char *`,
+ *             which will be allocated)
+ * @param option name of the option
+ * @param value actual value of the option (a string)
+ * @return #GNUNET_OK
+ */
+static int
+set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+              void *scls,
+              const char *option,
+              const char *value)
 {
   char **val = scls;
 
-  GNUNET_assert (value != NULL);
+  GNUNET_assert (NULL != value);
   GNUNET_free_non_null (*val);
   *val = GNUNET_STRINGS_filename_expand (value);
   return GNUNET_OK;
 }
 
+
+/**
+ * Allow user to specify a filename (automatically path expanded).
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] str set to the string
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_FILENAME (char shortName,
+                             const char *name,
+                             const char *argumentHelp,
+                             const char *description,
+                             char **str)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &set_filename,
+    .scls = (void *) str
+  };
+
+  return clo;
+}
+
+
+/**
+ * Allow user to specify log file name (-l option)
+ *
+ * @param[out] logfn set to the name of the logfile
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_LOGFILE (char **logfn)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  'l',
+    .name = "logfile",
+    .argumentHelp = "FILENAME",
+    .description = gettext_noop ("configure logging to write logs to FILENAME"),
+    .require_argument = 1,
+    .processor = &set_filename,
+    .scls = (void *) logfn
+  };
+
+  return clo;
+}
+
+
+/**
+ * Allow user to specify configuration file name (-c option)
+ *
+ * @param[out] fn set to the name of the configuration file
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_CFG_FILE (char **fn)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  'c',
+    .name = "config",
+    .argumentHelp = "FILENAME",
+    .description = gettext_noop("use configuration file FILENAME"),
+    .require_argument = 1,
+    .processor = &set_filename,
+    .scls = (void *) fn
+  };
+
+  return clo;
+}
+
+
 /**
  * Set an option of type 'unsigned long long' from the command line.
  * A pointer to this function should be passed as part of the
@@ -267,21 +530,57 @@ GNUNET_GETOPT_set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ct
  * @param value actual value of the option as a string.
  * @return #GNUNET_OK if parsing the value worked
  */
-int
-GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                         void *scls, const char *option, const char *value)
+static int
+set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+           void *scls,
+           const char *option,
+           const char *value)
 {
   unsigned long long *val = scls;
 
-  if (1 != SSCANF (value, "%llu", val))
+  if (1 != SSCANF (value,
+                   "%llu",
+                   val))
   {
-    FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option);
+    FPRINTF (stderr,
+             _("You must pass a number to the `%s' option.\n"),
+             option);
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
 }
 
 
+/**
+ * Allow user to specify an `unsigned long long`
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the value specified at the command line
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_ULONG (char shortName,
+                                const char *name,
+                                const char *argumentHelp,
+                                const char *description,
+                                unsigned long long *val)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &set_ulong,
+    .scls = (void *) val
+  };
+
+  return clo;
+}
+
+
 /**
  * Set an option of type 'struct GNUNET_TIME_Relative' from the command line.
  * A pointer to this function should be passed as part of the
@@ -295,9 +594,11 @@ GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
  * @param value actual value of the option as a string.
  * @return #GNUNET_OK if parsing the value worked
  */
-int
-GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                                void *scls, const char *option, const char *value)
+static int
+set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+                   void *scls,
+                   const char *option,
+                   const char *value)
 {
   struct GNUNET_TIME_Relative *val = scls;
 
@@ -305,13 +606,111 @@ GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContex
       GNUNET_STRINGS_fancy_time_to_relative (value,
                                             val))
   {
-    FPRINTF (stderr, _("You must pass relative time to the `%s' option.\n"), option);
+    FPRINTF (stderr,
+             _("You must pass relative time to the `%s' option.\n"),
+             option);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Allow user to specify a `struct GNUNET_TIME_Relative`
+ * (using human-readable "fancy" time).
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the time specified at the command line
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME (char shortName,
+                                        const char *name,
+                                        const char *argumentHelp,
+                                        const char *description,
+                                        struct GNUNET_TIME_Relative *val)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &set_relative_time,
+    .scls = (void *) val
+  };
+
+  return clo;
+}
+
+
+/**
+ * Set an option of type 'struct GNUNET_TIME_Absolute' from the command line.
+ * A pointer to this function should be passed as part of the
+ * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
+ * of this type.  It should be followed by a pointer to a value of
+ * type 'struct GNUNET_TIME_Absolute'.
+ *
+ * @param ctx command line processing context
+ * @param scls additional closure (will point to the `struct GNUNET_TIME_Absolute`)
+ * @param option name of the option
+ * @param value actual value of the option as a string.
+ * @return #GNUNET_OK if parsing the value worked
+ */
+static int
+set_absolute_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+                   void *scls,
+                   const char *option,
+                   const char *value)
+{
+  struct GNUNET_TIME_Absolute *val = scls;
+
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_fancy_time_to_absolute (value,
+                                            val))
+  {
+    FPRINTF (stderr,
+             _("You must pass absolute time to the `%s' option.\n"),
+             option);
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
 }
 
 
+/**
+ * Allow user to specify a `struct GNUNET_TIME_Absolute`
+ * (using human-readable "fancy" time).
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the time specified at the command line
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_ABSOLUTE_TIME (char shortName,
+                                        const char *name,
+                                        const char *argumentHelp,
+                                        const char *description,
+                                        struct GNUNET_TIME_Absolute *val)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &set_absolute_time,
+    .scls = (void *) val
+  };
+
+  return clo;
+}
+
+
 /**
  * Set an option of type 'unsigned int' from the command line.
  * A pointer to this function should be passed as part of the
@@ -325,19 +724,172 @@ GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContex
  * @param value actual value of the option as a string.
  * @return #GNUNET_OK if parsing the value worked
  */
-int
-GNUNET_GETOPT_set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
-                        void *scls, const char *option, const char *value)
+static int
+set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+          void *scls,
+          const char *option,
+          const char *value)
 {
   unsigned int *val = scls;
 
-  if (1 != SSCANF (value, "%u", val))
+  if (1 != SSCANF (value,
+                   "%u",
+                   val))
   {
-    FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option);
+    FPRINTF (stderr,
+             _("You must pass a number to the `%s' option.\n"),
+             option);
     return GNUNET_SYSERR;
   }
   return GNUNET_OK;
 }
 
 
+/**
+ * Allow user to specify an unsigned integer.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val set to the value specified at the command line
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_UINT (char shortName,
+                               const char *name,
+                               const char *argumentHelp,
+                               const char *description,
+                               unsigned int *val)
+{
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &set_uint,
+    .scls = (void *) val
+  };
+
+  return clo;
+}
+
+
+/**
+ * Closure for #set_base32().
+ */
+struct Base32Context
+{
+  /**
+   * Value to initialize (already allocated)
+   */
+  void *val;
+
+  /**
+   * Number of bytes expected for @e val.
+   */
+  size_t val_size;
+};
+
+
+/**
+ * Set an option of type 'unsigned int' from the command line.
+ * A pointer to this function should be passed as part of the
+ * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
+ * of this type.  It should be followed by a pointer to a value of
+ * type 'unsigned int'.
+ *
+ * @param ctx command line processing context
+ * @param scls additional closure (will point to the 'unsigned int')
+ * @param option name of the option
+ * @param value actual value of the option as a string.
+ * @return #GNUNET_OK if parsing the value worked
+ */
+static int
+set_base32 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+            void *scls,
+            const char *option,
+            const char *value)
+{
+  struct Base32Context *bc = scls;
+
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (value,
+                                     strlen (value),
+                                     bc->val,
+                                     bc->val_size))
+  {
+    fprintf (stderr,
+             _("Argument `%s' malformed. Expected base32 (Crockford) encoded value.\n"),
+             option);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Helper function to clean up after
+ * #GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE.
+ *
+ * @param cls value to GNUNET_free()
+ */
+static void
+free_bc (void *cls)
+{
+  GNUNET_free (cls);
+}
+
+
+/**
+ * Allow user to specify a binary value using Crockford
+ * Base32 encoding.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val binary value decoded from Crockford Base32-encoded argument
+ * @param val_size size of @a val in bytes
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE (char shortName,
+                                            const char *name,
+                                            const char *argumentHelp,
+                                            const char *description,
+                                            void *val,
+                                            size_t val_size)
+{
+  struct Base32Context *bc = GNUNET_new (struct Base32Context);
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &set_base32,
+    .cleaner = &free_bc,
+    .scls = (void *) bc
+  };
+
+  bc->val = val;
+  bc->val_size = val_size;
+  return clo;
+}
+
+
+/**
+ * Make the given option mandatory.
+ *
+ * @param opt option to modify
+ * @return @a opt with the mandatory flag set.
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_MANDATORY (struct GNUNET_GETOPT_CommandLineOption opt)
+{
+  opt.option_mandatory = 1;
+  return opt;
+}
+
+
 /* end of getopt_helpers.c */
index 7ec7162f1af9273577fc9a2cc9bf49ef37cd3428..2beb772a9a9fc19673f09765b1e06afbc89263f3 100644 (file)
@@ -223,34 +223,48 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    { 'f', "filename", NULL,
-      gettext_noop ("obtain option of value as a filename (with $-expansion)"),
-      0, &GNUNET_GETOPT_set_one, &is_filename },
-    { 's', "section", "SECTION",
-      gettext_noop ("name of the section to access"),
-      1, &GNUNET_GETOPT_set_string, &section },
-    { 'o', "option", "OPTION",
-      gettext_noop ("name of the option to access"),
-      1, &GNUNET_GETOPT_set_string, &option },
-    { 'V', "value", "VALUE",
-      gettext_noop ("value to set"),
-      1, &GNUNET_GETOPT_set_string, &value },
-    { 'S', "list-sections", NULL,
-      gettext_noop ("print available configuration sections"),
-      0, &GNUNET_GETOPT_set_one, &list_sections },
-    { 'w', "rewrite", NULL,
-      gettext_noop ("write configuration file that only contains delta to defaults"),
-      0, &GNUNET_GETOPT_set_one, &rewrite },
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('f',
+                                  "filename",
+                                  gettext_noop ("obtain option of value as a filename (with $-expansion)"),
+                                  &is_filename),
+    GNUNET_GETOPT_OPTION_STRING ('s',
+                                     "section",
+                                     "SECTION",
+                                     gettext_noop ("name of the section to access"),
+                                     &section),
+    GNUNET_GETOPT_OPTION_STRING ('o',
+                                     "option",
+                                     "OPTION",
+                                     gettext_noop ("name of the option to access"),
+                                     &option),
+    GNUNET_GETOPT_OPTION_STRING ('V',
+                                     "value",
+                                     "VALUE",
+                                     gettext_noop ("value to set"),
+                                     &value),
+    GNUNET_GETOPT_OPTION_SET_ONE ('S',
+                                  "list-sections",
+                                  gettext_noop ("print available configuration sections"),
+                                  &list_sections),
+    GNUNET_GETOPT_OPTION_SET_ONE ('w',
+                                  "rewrite",
+                                  gettext_noop ("write configuration file that only contains delta to defaults"),
+                                  &rewrite),
     GNUNET_GETOPT_OPTION_END
   };
-  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_get_utf8_args (argc, argv,
+                                    &argc, &argv))
     return 2;
 
   ret = (GNUNET_OK ==
-        GNUNET_PROGRAM_run (argc, argv, "gnunet-config [OPTIONS]",
+        GNUNET_PROGRAM_run (argc,
+                             argv,
+                             "gnunet-config [OPTIONS]",
                             gettext_noop ("Manipulate GNUnet configuration files"),
-                            options, &run, NULL)) ? 0 : ret;
+                            options,
+                             &run, NULL)) ? 0 : ret;
   GNUNET_free ((void*) argv);
   return ret;
 }
index ddfd9b1c3082c540d416170f3512e9ade7ed32b4..732228b52bd6f654d159d90b28d309d361a0793e 100644 (file)
@@ -41,7 +41,7 @@ static int list_keys;
 /**
  * Flag for listing public key.
  */
-static int list_keys_count;
+static unsigned int list_keys_count;
 
 /**
  * Flag for printing public key.
@@ -406,36 +406,50 @@ run (void *cls, char *const *args, const char *cfgfile,
  * @return 0 ok, 1 on error
  */
 int
-main (int argc, char *const *argv)
+main (int argc,
+      char *const *argv)
 {
   list_keys_count = UINT32_MAX;
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    { 'i', "iterate", "FILE",
-      gettext_noop ("list keys included in a file (for testing)"),
-      0, &GNUNET_GETOPT_set_one, &list_keys },
-    { 'e', "end=", "COUNT",
-      gettext_noop ("number of keys to list included in a file (for testing)"),
-      1, &GNUNET_GETOPT_set_uint, &list_keys_count },
-    { 'g', "generate-keys", "COUNT",
-      gettext_noop ("create COUNT public-private key pairs (for testing)"),
-      1, &GNUNET_GETOPT_set_uint, &make_keys },
-    { 'p', "print-public-key", NULL,
-      gettext_noop ("print the public key in ASCII format"),
-      0, &GNUNET_GETOPT_set_one, &print_public_key },
-    { 'E', "examples", NULL,
-      gettext_noop ("print examples of ECC operations (used for compatibility testing)"),
-      0, &GNUNET_GETOPT_set_one, &print_examples_flag },
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('i',
+                                  "iterate",
+                                  gettext_noop ("list keys included in a file (for testing)"),
+                                  &list_keys),
+    GNUNET_GETOPT_OPTION_SET_UINT ('e',
+                                   "end=",
+                                   "COUNT",
+                                   gettext_noop ("number of keys to list included in a file (for testing)"),
+                                   &list_keys_count),
+    GNUNET_GETOPT_OPTION_SET_UINT ('g',
+                                   "generate-keys",
+                                   "COUNT",
+                                   gettext_noop ("create COUNT public-private key pairs (for testing)"),
+                                   &make_keys),
+    GNUNET_GETOPT_OPTION_SET_ONE ('p',
+                                  "print-public-key",
+                                  gettext_noop ("print the public key in ASCII format"),
+                                  &print_public_key),
+    GNUNET_GETOPT_OPTION_SET_ONE ('E',
+                                  "examples",
+                                  gettext_noop ("print examples of ECC operations (used for compatibility testing)"),
+                                  &print_examples_flag),
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
 
-  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_get_utf8_args (argc, argv,
+                                    &argc, &argv))
     return 2;
 
   ret = (GNUNET_OK ==
-        GNUNET_PROGRAM_run (argc, argv, "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]",
+        GNUNET_PROGRAM_run (argc,
+                             argv,
+                             "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]",
                             gettext_noop ("Manipulate GNUnet private ECC key files"),
-                            options, &run, NULL)) ? 0 : 1;
+                            options,
+                             &run,
+                             NULL)) ? 0 : 1;
   GNUNET_free ((void*) argv);
   return ret;
 }
index e84a2332fb3d8d1f140f736840c8cc318a5a672c..563cf9fce410113daa6b0e327acff5df73e66392 100644 (file)
@@ -144,10 +144,11 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    { 'r', "reverse", NULL,
-      gettext_noop ("perform a reverse lookup"),
-      0, &GNUNET_GETOPT_set_one, &reverse },
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('r',
+                                  "reverse",
+                                  gettext_noop ("perform a reverse lookup"),
+                                  &reverse),
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
index ab0cf92e03cdfee4c2bf13e287dbe27506453749..7c73cfe1efd5886dac042afeaf9dac663cc994c8 100644 (file)
@@ -307,21 +307,30 @@ run (void *cls,
  * @return 0 ok, 1 on error
  */
 int
-main (int argc, char *const *argv)
+main (int argc,
+      char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    { 'b', "bits", "BITS",
-      gettext_noop ("number of bits to require for the proof of work"),
-      1, &GNUNET_GETOPT_set_ulong, &nse_work_required },
-    { 'k', "keyfile", "FILE",
-      gettext_noop ("file with private key, otherwise default is used"),
-      1, &GNUNET_GETOPT_set_filename, &pkfn },
-    { 'o', "outfile", "FILE",
-      gettext_noop ("file with proof of work, otherwise default is used"),
-      1, &GNUNET_GETOPT_set_filename, &pwfn },
-    { 't', "timeout", "TIME",
-      gettext_noop ("time to wait between calculations"),
-      1, &GNUNET_GETOPT_set_relative_time, &proof_find_delay },
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ULONG ('b',
+                                    "bits",
+                                    "BITS",
+                                    gettext_noop ("number of bits to require for the proof of work"),
+                                    &nse_work_required),
+    GNUNET_GETOPT_OPTION_FILENAME ('k',
+                                   "keyfile",
+                                   "FILE",
+                                   gettext_noop ("file with private key, otherwise default is used"),
+                                   &pkfn),
+    GNUNET_GETOPT_OPTION_FILENAME ('o',
+                                   "outfile",
+                                   "FILE",
+                                   gettext_noop ("file with proof of work, otherwise default is used"),
+                                   &pwfn),
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t',
+                                            "timeout",
+                                            "TIME",
+                                            gettext_noop ("time to wait between calculations"),
+                                            &proof_find_delay),
     GNUNET_GETOPT_OPTION_END
   };
   int ret;
@@ -334,7 +343,9 @@ main (int argc, char *const *argv)
          GNUNET_PROGRAM_run (argc, argv,
                              "gnunet-scrypt [OPTIONS] prooffile",
                              gettext_noop ("Manipulate GNUnet proof of work files"),
-                             options, &run, NULL)) ? 0 : 1;
+                             options,
+                             &run,
+                             NULL)) ? 0 : 1;
   GNUNET_free ((void*) argv);
   GNUNET_free_non_null (pwfn);
   return ret;
index cdb1b01d4fac5f59777d42c8de7a4c12fc741d9e..a84b06e6645d013c3e18fedf80afb88e42ef3440 100644 (file)
@@ -27,6 +27,7 @@
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
+#include "gnunet_mst_lib.h"
 
 
 /**
@@ -107,7 +108,7 @@ struct GNUNET_HELPER_Handle
   /**
    * The Message-Tokenizer that tokenizes the messages comming from the helper
    */
-  struct GNUNET_SERVER_MessageStreamTokenizer *mst;
+  struct GNUNET_MessageStreamTokenizer *mst;
 
   /**
    * The exception callback
@@ -272,7 +273,10 @@ GNUNET_HELPER_wait (struct GNUNET_HELPER_Handle *h)
   }
   /* purge MST buffer */
   if (NULL != h->mst)
-    (void) GNUNET_SERVER_mst_receive (h->mst, NULL, NULL, 0, GNUNET_YES, GNUNET_NO);
+    (void) GNUNET_MST_from_buffer (h->mst,
+                                   NULL, 0,
+                                   GNUNET_YES,
+                                   GNUNET_NO);
   return ret;
 }
 
@@ -319,7 +323,7 @@ static void
 helper_read (void *cls)
 {
   struct GNUNET_HELPER_Handle *h = cls;
-  char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE] GNUNET_ALIGN;
+  char buf[GNUNET_MAX_MESSAGE_SIZE] GNUNET_ALIGN;
   ssize_t t;
 
   h->read_task = NULL;
@@ -373,10 +377,10 @@ helper_read (void *cls)
                                                 h->fh_from_helper,
                                                 &helper_read, h);
   if (GNUNET_SYSERR ==
-      GNUNET_SERVER_mst_receive (h->mst,
-                                NULL,
-                                buf, t,
-                                GNUNET_NO, GNUNET_NO))
+      GNUNET_MST_from_buffer (h->mst,
+                              buf, t,
+                              GNUNET_NO,
+                              GNUNET_NO))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Failed to parse inbound message from helper `%s'\n"),
@@ -487,7 +491,7 @@ struct GNUNET_HELPER_Handle *
 GNUNET_HELPER_start (int with_control_pipe,
                     const char *binary_name,
                     char *const binary_argv[],
-                    GNUNET_SERVER_MessageTokenizerCallback cb,
+                    GNUNET_MessageTokenizerCallback cb,
                     GNUNET_HELPER_ExceptionCallback exp_cb,
                     void *cb_cls)
 {
@@ -508,7 +512,8 @@ GNUNET_HELPER_start (int with_control_pipe,
   h->binary_argv[c] = NULL;
   h->cb_cls = cb_cls;
   if (NULL != cb)
-    h->mst = GNUNET_SERVER_mst_create (cb, h->cb_cls);
+    h->mst = GNUNET_MST_create (cb,
+                                h->cb_cls);
   h->exp_cb = exp_cb;
   h->retry_back_off = 0;
   start_helper (h);
@@ -544,7 +549,7 @@ GNUNET_HELPER_destroy (struct GNUNET_HELPER_Handle *h)
     GNUNET_free (sh);
   }
   if (NULL != h->mst)
-    GNUNET_SERVER_mst_destroy (h->mst);
+    GNUNET_MST_destroy (h->mst);
   GNUNET_free (h->binary_name);
   for (c = 0; h->binary_argv[c] != NULL; c++)
     GNUNET_free (h->binary_argv[c]);
index 79e2d0455969bfcd7bff9a2b2b49e87948ca0772..90b2aa9687464afb8c5cc23a465c7fb66410dddd 100644 (file)
@@ -201,24 +201,6 @@ struct GNUNET_MQ_Handle
 };
 
 
-/**
- * Implementation-specific state for connection to
- * client (MQ for server).
- */
-struct ServerClientSocketState
-{
-  /**
-   * Handle of the client that connected to the server.
-   */
-  struct GNUNET_SERVER_Client *client;
-
-  /**
-   * Active transmission request to the client.
-   */
-  struct GNUNET_SERVER_TransmitHandle *th;
-};
-
-
 /**
  * Call the message message handler that was registered
  * for the type of the given message in the given message queue.
@@ -707,92 +689,6 @@ GNUNET_MQ_msg_nested_mh_ (struct GNUNET_MessageHeader **mhp,
 }
 
 
-/**
- * Transmit a queued message to the session's client.
- *
- * @param cls consensus session
- * @param size number of bytes available in @a buf
- * @param buf where the callee should write the message
- * @return number of bytes written to @a buf
- */
-static size_t
-transmit_queued (void *cls,
-                 size_t size,
-                 void *buf)
-{
-  struct GNUNET_MQ_Handle *mq = cls;
-  struct ServerClientSocketState *state = GNUNET_MQ_impl_state (mq);
-  const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq);
-  size_t msg_size;
-
-  GNUNET_assert (NULL != buf);
-  msg_size = ntohs (msg->size);
-  GNUNET_assert (size >= msg_size);
-  GNUNET_memcpy (buf, msg, msg_size);
-  state->th = NULL;
-
-  GNUNET_MQ_impl_send_continue (mq);
-
-  return msg_size;
-}
-
-
-static void
-server_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
-                            void *impl_state)
-{
-  struct ServerClientSocketState *state = impl_state;
-
-  if (NULL != state->th)
-  {
-    GNUNET_SERVER_notify_transmit_ready_cancel (state->th);
-    state->th = NULL;
-  }
-
-  GNUNET_assert (NULL != mq);
-  GNUNET_assert (NULL != state);
-  GNUNET_SERVER_client_drop (state->client);
-  GNUNET_free (state);
-}
-
-
-static void
-server_client_send_impl (struct GNUNET_MQ_Handle *mq,
-                         const struct GNUNET_MessageHeader *msg,
-                         void *impl_state)
-{
-  GNUNET_assert (NULL != mq);
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending message of type %u and size %u\n",
-       ntohs (msg->type), ntohs (msg->size));
-
-  struct ServerClientSocketState *state = impl_state;
-  state->th = GNUNET_SERVER_notify_transmit_ready (state->client,
-                                                  ntohs (msg->size),
-                                                  GNUNET_TIME_UNIT_FOREVER_REL,
-                                                  &transmit_queued,
-                                                   mq);
-}
-
-
-struct GNUNET_MQ_Handle *
-GNUNET_MQ_queue_for_server_client (struct GNUNET_SERVER_Client *client)
-{
-  struct GNUNET_MQ_Handle *mq;
-  struct ServerClientSocketState *scss;
-
-  mq = GNUNET_new (struct GNUNET_MQ_Handle);
-  scss = GNUNET_new (struct ServerClientSocketState);
-  mq->impl_state = scss;
-  scss->client = client;
-  GNUNET_SERVER_client_keep (client);
-  mq->send_impl = &server_client_send_impl;
-  mq->destroy_impl = &server_client_destroy_impl;
-  return mq;
-}
-
-
 /**
  * Associate the assoc_data in mq with a unique request id.
  *
@@ -811,22 +707,40 @@ GNUNET_MQ_assoc_add (struct GNUNET_MQ_Handle *mq,
     mq->assoc_id = 1;
   }
   id = mq->assoc_id++;
-  GNUNET_CONTAINER_multihashmap32_put (mq->assoc_map, id, assoc_data,
-                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap32_put (mq->assoc_map,
+                                                      id,
+                                                      assoc_data,
+                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   return id;
 }
 
 
+/**
+ * Get the data associated with a @a request_id in a queue
+ *
+ * @param mq the message queue with the association
+ * @param request_id the request id we are interested in
+ * @return the associated data
+ */
 void *
 GNUNET_MQ_assoc_get (struct GNUNET_MQ_Handle *mq,
                      uint32_t request_id)
 {
   if (NULL == mq->assoc_map)
     return NULL;
-  return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map, request_id);
+  return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map,
+                                              request_id);
 }
 
 
+/**
+ * Remove the association for a @a request_id
+ *
+ * @param mq the message queue with the association
+ * @param request_id the request id we want to remove
+ * @return the associated data
+ */
 void *
 GNUNET_MQ_assoc_remove (struct GNUNET_MQ_Handle *mq,
                         uint32_t request_id)
index 9f1d30d7ab2486a2f75ccafe8cdf62362c822461..0d90c5d1051642f0666698e312b767eaf3cc6a08 100644 (file)
@@ -90,8 +90,8 @@ GNUNET_MST_create (GNUNET_MessageTokenizerCallback cb,
   struct GNUNET_MessageStreamTokenizer *ret;
 
   ret = GNUNET_new (struct GNUNET_MessageStreamTokenizer);
-  ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE);
-  ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE;
+  ret->hdr = GNUNET_malloc (GNUNET_MIN_MESSAGE_SIZE);
+  ret->curr_buf = GNUNET_MIN_MESSAGE_SIZE;
   ret->cb = cb;
   ret->cb_cls = cb_cls;
   return ret;
index f33c31f1c8ccedf328f4526ba6096088b004a594..0c915932c4cadd176d4ff3fb903e79406b588197 100644 (file)
@@ -876,7 +876,7 @@ GNUNET_RESOLVER_ip_get (const char *hostname,
 
   slen = strlen (hostname) + 1;
   if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >=
-      GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      GNUNET_MAX_MESSAGE_SIZE)
   {
     GNUNET_break (0);
     return NULL;
diff --git a/src/util/server.c b/src/util/server.c
deleted file mode 100644 (file)
index 83c30e3..0000000
+++ /dev/null
@@ -1,1752 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009-2013 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/server.c
- * @brief library for building GNUnet network servers
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_protocols.h"
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util-server", __VA_ARGS__)
-
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-server", syscall)
-
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename)
-
-
-/**
- * List of arrays of message handlers.
- */
-struct HandlerList
-{
-  /**
-   * This is a linked list.
-   */
-  struct HandlerList *next;
-
-  /**
-   * NULL-terminated array of handlers.
-   */
-  const struct GNUNET_SERVER_MessageHandler *handlers;
-};
-
-
-/**
- * List of arrays of message handlers.
- */
-struct NotifyList
-{
-  /**
-   * This is a doubly linked list.
-   */
-  struct NotifyList *next;
-
-  /**
-   * This is a doubly linked list.
-   */
-  struct NotifyList *prev;
-
-  /**
-   * Function to call.
-   */
-  GNUNET_SERVER_DisconnectCallback callback;
-
-  /**
-   * Closure for callback.
-   */
-  void *callback_cls;
-};
-
-
-/**
- * @brief handle for a server
- */
-struct GNUNET_SERVER_Handle
-{
-  /**
-   * List of handlers for incoming messages.
-   */
-  struct HandlerList *handlers;
-
-  /**
-   * Head of list of our current clients.
-   */
-  struct GNUNET_SERVER_Client *clients_head;
-
-  /**
-   * Head of list of our current clients.
-   */
-  struct GNUNET_SERVER_Client *clients_tail;
-
-  /**
-   * Head of linked list of functions to call on disconnects by clients.
-   */
-  struct NotifyList *disconnect_notify_list_head;
-
-  /**
-   * Tail of linked list of functions to call on disconnects by clients.
-   */
-  struct NotifyList *disconnect_notify_list_tail;
-
-  /**
-   * Head of linked list of functions to call on connects by clients.
-   */
-  struct NotifyList *connect_notify_list_head;
-
-  /**
-   * Tail of linked list of functions to call on connects by clients.
-   */
-  struct NotifyList *connect_notify_list_tail;
-
-  /**
-   * Function to call for access control.
-   */
-  GNUNET_CONNECTION_AccessCheck access_cb;
-
-  /**
-   * Closure for @e access_cb.
-   */
-  void *access_cb_cls;
-
-  /**
-   * NULL-terminated array of sockets used to listen for new
-   * connections.
-   */
-  struct GNUNET_NETWORK_Handle **listen_sockets;
-
-  /**
-   * After how long should an idle connection time
-   * out (on write).
-   */
-  struct GNUNET_TIME_Relative idle_timeout;
-
-  /**
-   * Task scheduled to do the listening.
-   */
-  struct GNUNET_SCHEDULER_Task * listen_task;
-
-  /**
-   * Alternative function to create a MST instance.
-   */
-  GNUNET_SERVER_MstCreateCallback mst_create;
-
-  /**
-   * Alternative function to destroy a MST instance.
-   */
-  GNUNET_SERVER_MstDestroyCallback mst_destroy;
-
-  /**
-   * Alternative function to give data to a MST instance.
-   */
-  GNUNET_SERVER_MstReceiveCallback mst_receive;
-
-  /**
-   * Closure for 'mst_'-callbacks.
-   */
-  void *mst_cls;
-
-  /**
-   * Do we ignore messages of types that we do not understand or do we
-   * require that a handler is found (and if not kill the connection)?
-   */
-  int require_found;
-
-  /**
-   * Set to #GNUNET_YES once we are in 'soft' shutdown where we wait for
-   * all non-monitor clients to disconnect before we call
-   * #GNUNET_SERVER_destroy.  See test_monitor_clients().  Set to
-   * #GNUNET_SYSERR once the final destroy task has been scheduled
-   * (we cannot run it in the same task).
-   */
-  int in_soft_shutdown;
-};
-
-
-/**
- * Handle server returns for aborting transmission to a client.
- */
-struct GNUNET_SERVER_TransmitHandle
-{
-  /**
-   * Function to call to get the message.
-   */
-  GNUNET_CONNECTION_TransmitReadyNotify callback;
-
-  /**
-   * Closure for @e callback
-   */
-  void *callback_cls;
-
-  /**
-   * Active connection transmission handle.
-   */
-  struct GNUNET_CONNECTION_TransmitHandle *cth;
-
-};
-
-
-/**
- * @brief handle for a client of the server
- */
-struct GNUNET_SERVER_Client
-{
-
-  /**
-   * This is a doubly linked list.
-   */
-  struct GNUNET_SERVER_Client *next;
-
-  /**
-   * This is a doubly linked list.
-   */
-  struct GNUNET_SERVER_Client *prev;
-
-  /**
-   * Processing of incoming data.
-   */
-  void *mst;
-
-  /**
-   * Server that this client belongs to.
-   */
-  struct GNUNET_SERVER_Handle *server;
-
-  /**
-   * Client closure for callbacks.
-   */
-  struct GNUNET_CONNECTION_Handle *connection;
-
-  /**
-   * User context value, manipulated using
-   * 'GNUNET_SERVER_client_{get/set}_user_context' functions.
-   */
-  void *user_context;
-
-  /**
-   * ID of task used to restart processing.
-   */
-  struct GNUNET_SCHEDULER_Task * restart_task;
-
-  /**
-   * Task that warns about missing calls to #GNUNET_SERVER_receive_done.
-   */
-  struct GNUNET_SCHEDULER_Task * warn_task;
-
-  /**
-   * Time when the warn task was started.
-   */
-  struct GNUNET_TIME_Absolute warn_start;
-
-  /**
-   * Last activity on this socket (used to time it out
-   * if reference_count == 0).
-   */
-  struct GNUNET_TIME_Absolute last_activity;
-
-  /**
-   * Transmission handle we return for this client from
-   * #GNUNET_SERVER_notify_transmit_ready.
-   */
-  struct GNUNET_SERVER_TransmitHandle th;
-
-  /**
-   * After how long should an idle connection time
-   * out (on write).
-   */
-  struct GNUNET_TIME_Relative idle_timeout;
-
-  /**
-   * Number of external entities with a reference to
-   * this client object.
-   */
-  unsigned int reference_count;
-
-  /**
-   * Was processing if incoming messages suspended while
-   * we were still processing data already received?
-   * This is a counter saying how often processing was
-   * suspended (once per handler invoked).
-   */
-  unsigned int suspended;
-
-  /**
-   * Last size given when user context was initialized; used for
-   * sanity check.
-   */
-  size_t user_context_size;
-
-  /**
-   * Are we currently in the "process_client_buffer" function (and
-   * will hence restart the receive job on exit if suspended == 0 once
-   * we are done?).  If this is set, then "receive_done" will
-   * essentially only decrement suspended; if this is not set, then
-   * "receive_done" may need to restart the receive process (either
-   * from the side-buffer or via select/recv).
-   */
-  int in_process_client_buffer;
-
-  /**
-   * We're about to close down this client.
-   */
-  int shutdown_now;
-
-  /**
-   * Are we currently trying to receive? (#GNUNET_YES if we are,
-   * #GNUNET_NO if we are not, #GNUNET_SYSERR if data is already
-   * available in MST).
-   */
-  int receive_pending;
-
-  /**
-   * Persist the file handle for this client no matter what happens,
-   * force the OS to close once the process actually dies.  Should only
-   * be used in special cases!
-   */
-  int persist;
-
-  /**
-   * Is this client a 'monitor' client that should not be counted
-   * when deciding on destroying the server during soft shutdown?
-   * (see also #GNUNET_SERVICE_start)
-   */
-  int is_monitor;
-
-  /**
-   * Type of last message processed (for warn_no_receive_done).
-   */
-  uint16_t warn_type;
-};
-
-
-
-/**
- * Return user context associated with the given client.
- * Note: you should probably use the macro (call without the underscore).
- *
- * @param client client to query
- * @param size number of bytes in user context struct (for verification only)
- * @return pointer to user context
- */
-void *
-GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client,
-                                       size_t size)
-{
-  if ((0 == client->user_context_size) &&
-      (NULL == client->user_context))
-    return NULL; /* never set */
-  GNUNET_assert (size == client->user_context_size);
-  return client->user_context;
-}
-
-
-/**
- * Set user context to be associated with the given client.
- * Note: you should probably use the macro (call without the underscore).
- *
- * @param client client to query
- * @param ptr pointer to user context
- * @param size number of bytes in user context struct (for verification only)
- */
-void
-GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client,
-                                       void *ptr,
-                                       size_t size)
-{
-  if (NULL == ptr)
-  {
-    client->user_context_size = 0;
-    client->user_context = ptr;
-    return;
-  }
-  client->user_context_size = size;
-  client->user_context = ptr;
-}
-
-
-/**
- * Scheduler says our listen socket is ready.  Process it!
- *
- * @param cls handle to our server for which we are processing the listen
- *        socket
- */
-static void
-process_listen_socket (void *cls)
-{
-  struct GNUNET_SERVER_Handle *server = cls;
-  const struct GNUNET_SCHEDULER_TaskContext *tc;
-  struct GNUNET_CONNECTION_Handle *sock;
-  unsigned int i;
-
-  server->listen_task = NULL;
-  tc = GNUNET_SCHEDULER_get_task_context ();
-  for (i = 0; NULL != server->listen_sockets[i]; i++)
-  {
-    if (GNUNET_NETWORK_fdset_isset (tc->read_ready,
-                                    server->listen_sockets[i]))
-    {
-      sock =
-          GNUNET_CONNECTION_create_from_accept (server->access_cb,
-                                                server->access_cb_cls,
-                                                server->listen_sockets[i]);
-      if (NULL != sock)
-      {
-        LOG (GNUNET_ERROR_TYPE_DEBUG,
-             "Server accepted incoming connection.\n");
-        (void) GNUNET_SERVER_connect_socket (server,
-                                             sock);
-      }
-    }
-  }
-  /* listen for more! */
-  GNUNET_SERVER_resume (server);
-}
-
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @param server_addr address to listen on
- * @param socklen length of @a server_addr
- * @return NULL on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket (const struct sockaddr *server_addr,
-                   socklen_t socklen)
-{
-  struct GNUNET_NETWORK_Handle *sock;
-  uint16_t port;
-  int eno;
-
-  switch (server_addr->sa_family)
-  {
-  case AF_INET:
-    port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
-    break;
-  case AF_INET6:
-    port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
-    break;
-  case AF_UNIX:
-    port = 0;
-    break;
-  default:
-    GNUNET_break (0);
-    port = 0;
-    break;
-  }
-  sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0);
-  if (NULL == sock)
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
-    errno = 0;
-    return NULL;
-  }
-  /* bind the socket */
-  if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen))
-  {
-    eno = errno;
-    if (EADDRINUSE != errno)
-    {
-      /* we don't log 'EADDRINUSE' here since an IPv4 bind may
-       * fail if we already took the port on IPv6; if both IPv4 and
-       * IPv6 binds fail, then our caller will log using the
-       * errno preserved in 'eno' */
-      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                    "bind");
-      if (0 != port)
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _("`%s' failed for port %d (%s).\n"),
-             "bind",
-             port,
-             (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
-      eno = 0;
-    }
-    else
-    {
-      if (0 != port)
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             _("`%s' failed for port %d (%s): address already in use\n"),
-             "bind", port,
-             (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
-      else if (AF_UNIX == server_addr->sa_family)
-      {
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             _("`%s' failed for `%s': address already in use\n"),
-             "bind",
-             GNUNET_a2s (server_addr, socklen));
-      }
-    }
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
-    errno = eno;
-    return NULL;
-  }
-  if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                  "listen");
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
-    errno = 0;
-    return NULL;
-  }
-  if (0 != port)
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Server starts to listen on port %u.\n",
-         port);
-  return sock;
-}
-
-
-/**
- * Create a new server.
- *
- * @param access_cb function for access control
- * @param access_cb_cls closure for @a access_cb
- * @param lsocks NULL-terminated array of listen sockets
- * @param idle_timeout after how long should we timeout idle connections?
- * @param require_found if #GNUNET_YES, connections sending messages of unknown type
- *        will be closed
- * @return handle for the new server, NULL on error
- *         (typically, "port" already in use)
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb,
-                                   void *access_cb_cls,
-                                   struct GNUNET_NETWORK_Handle **lsocks,
-                                   struct GNUNET_TIME_Relative idle_timeout,
-                                   int require_found)
-{
-  struct GNUNET_SERVER_Handle *server;
-
-  server = GNUNET_new (struct GNUNET_SERVER_Handle);
-  server->idle_timeout = idle_timeout;
-  server->listen_sockets = lsocks;
-  server->access_cb = access_cb;
-  server->access_cb_cls = access_cb_cls;
-  server->require_found = require_found;
-  if (NULL != lsocks)
-    GNUNET_SERVER_resume (server);
-  return server;
-}
-
-
-/**
- * Create a new server.
- *
- * @param access_cb function for access control
- * @param access_cb_cls closure for @a access_cb
- * @param server_addr address to listen on (including port), NULL terminated array
- * @param socklen length of server_addr
- * @param idle_timeout after how long should we timeout idle connections?
- * @param require_found if YES, connections sending messages of unknown type
- *        will be closed
- * @return handle for the new server, NULL on error
- *         (typically, "port" already in use)
- */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb,
-                     void *access_cb_cls,
-                      struct sockaddr *const *server_addr,
-                      const socklen_t * socklen,
-                      struct GNUNET_TIME_Relative idle_timeout,
-                      int require_found)
-{
-  struct GNUNET_NETWORK_Handle **lsocks;
-  unsigned int i;
-  unsigned int j;
-  unsigned int k;
-  int seen;
-
-  i = 0;
-  while (NULL != server_addr[i])
-    i++;
-  if (i > 0)
-  {
-    lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1));
-    i = 0;
-    j = 0;
-    while (NULL != server_addr[i])
-    {
-      seen = 0;
-      for (k=0;k<i;k++)
-       if ( (socklen[k] == socklen[i]) &&
-            (0 == memcmp (server_addr[k], server_addr[i], socklen[i])) )
-       {
-         seen = 1;
-         break;
-       }
-      if (0 != seen)
-      {
-       /* duplicate address, skip */
-       i++;
-       continue;
-      }
-      lsocks[j] = open_listen_socket (server_addr[i], socklen[i]);
-      if (NULL != lsocks[j])
-        j++;
-      i++;
-    }
-    if (0 == j)
-    {
-      if (0 != errno)
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
-      GNUNET_free (lsocks);
-      lsocks = NULL;
-    }
-  }
-  else
-  {
-    lsocks = NULL;
-  }
-  return GNUNET_SERVER_create_with_sockets (access_cb,
-                                           access_cb_cls,
-                                           lsocks,
-                                            idle_timeout,
-                                           require_found);
-}
-
-
-/**
- * Set the 'monitor' flag on this client.  Clients which have been
- * marked as 'monitors' won't prevent the server from shutting down
- * once '#GNUNET_SERVER_stop_listening()' has been invoked.  The idea is
- * that for "normal" clients we likely want to allow them to process
- * their requests; however, monitor-clients are likely to 'never'
- * disconnect during shutdown and thus will not be considered when
- * determining if the server should continue to exist after
- * #GNUNET_SERVER_destroy() has been called.
- *
- * @param client the client to set the 'monitor' flag on
- */
-void
-GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Marking client as monitor!\n");
-  client->is_monitor = GNUNET_YES;
-}
-
-
-/**
- * Helper function for #test_monitor_clients() to trigger
- * #GNUNET_SERVER_destroy() after the stack has unwound.
- *
- * @param cls the `struct GNUNET_SERVER_Handle *` to destroy
- */
-static void
-do_destroy (void *cls)
-{
-  struct GNUNET_SERVER_Handle *server = cls;
-
-  GNUNET_SERVER_destroy (server);
-}
-
-
-/**
- * Check if only 'monitor' clients are left.  If so, destroy the
- * server completely.
- *
- * @param server server to test for full shutdown
- */
-static void
-test_monitor_clients (struct GNUNET_SERVER_Handle *server)
-{
-  struct GNUNET_SERVER_Client *client;
-
-  if (GNUNET_YES != server->in_soft_shutdown)
-    return;
-  for (client = server->clients_head; NULL != client; client = client->next)
-    if (GNUNET_NO == client->is_monitor)
-      return; /* not done yet */
-  server->in_soft_shutdown = GNUNET_SYSERR;
-  (void) GNUNET_SCHEDULER_add_now (&do_destroy, server);
-}
-
-
-/**
- * Suspend accepting connections from the listen socket temporarily.
- *
- * @param server server to stop accepting connections.
- */
-void
-GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server)
-{
-  if (NULL != server->listen_task)
-  {
-    GNUNET_SCHEDULER_cancel (server->listen_task);
-    server->listen_task = NULL;
-  }
-}
-
-
-/**
- * Resume accepting connections from the listen socket.
- *
- * @param server server to stop accepting connections.
- */
-void
-GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server)
-{
-  struct GNUNET_NETWORK_FDSet *r;
-  unsigned int i;
-
-  if (NULL == server->listen_sockets)
-    return;
-  if (NULL == server->listen_sockets[0])
-    return; /* nothing to do, no listen sockets! */
-  if (NULL == server->listen_sockets[1])
-  {
-    /* simplified method: no fd set needed; this is then much simpler
-       and much more efficient */
-    server->listen_task =
-      GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
-                                                  GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                                  server->listen_sockets[0],
-                                                  &process_listen_socket, server);
-    return;
-  }
-  r = GNUNET_NETWORK_fdset_create ();
-  i = 0;
-  while (NULL != server->listen_sockets[i])
-    GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]);
-  server->listen_task =
-    GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                GNUNET_TIME_UNIT_FOREVER_REL, r, NULL,
-                                &process_listen_socket, server);
-  GNUNET_NETWORK_fdset_destroy (r);
-}
-
-
-/**
- * Stop the listen socket and get ready to shutdown the server
- * once only 'monitor' clients are left.
- *
- * @param server server to stop listening on
- */
-void
-GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server)
-{
-  unsigned int i;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Server in soft shutdown\n");
-  if (NULL != server->listen_task)
-  {
-    GNUNET_SCHEDULER_cancel (server->listen_task);
-    server->listen_task = NULL;
-  }
-  if (NULL != server->listen_sockets)
-  {
-    i = 0;
-    while (NULL != server->listen_sockets[i])
-      GNUNET_break (GNUNET_OK ==
-                    GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
-    GNUNET_free (server->listen_sockets);
-    server->listen_sockets = NULL;
-  }
-  if (GNUNET_NO == server->in_soft_shutdown)
-    server->in_soft_shutdown = GNUNET_YES;
-  test_monitor_clients (server);
-}
-
-
-/**
- * Free resources held by this server.
- *
- * @param server server to destroy
- */
-void
-GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server)
-{
-  struct HandlerList *hpos;
-  struct NotifyList *npos;
-  unsigned int i;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Server shutting down.\n");
-  if (NULL != server->listen_task)
-  {
-    GNUNET_SCHEDULER_cancel (server->listen_task);
-    server->listen_task = NULL;
-  }
-  if (NULL != server->listen_sockets)
-  {
-    i = 0;
-    while (NULL != server->listen_sockets[i])
-      GNUNET_break (GNUNET_OK ==
-                    GNUNET_NETWORK_socket_close (server->listen_sockets[i++]));
-    GNUNET_free (server->listen_sockets);
-    server->listen_sockets = NULL;
-  }
-  while (NULL != server->clients_head)
-    GNUNET_SERVER_client_disconnect (server->clients_head);
-  while (NULL != (hpos = server->handlers))
-  {
-    server->handlers = hpos->next;
-    GNUNET_free (hpos);
-  }
-  while (NULL != (npos = server->disconnect_notify_list_head))
-  {
-    npos->callback (npos->callback_cls,
-                    NULL);
-    GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
-                                server->disconnect_notify_list_tail,
-                                npos);
-    GNUNET_free (npos);
-  }
-  while (NULL != (npos = server->connect_notify_list_head))
-  {
-    npos->callback (npos->callback_cls,
-                    NULL);
-    GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
-                                server->connect_notify_list_tail,
-                                npos);
-    GNUNET_free (npos);
-  }
-  GNUNET_free (server);
-}
-
-
-/**
- * Add additional handlers to an existing server.
- *
- * @param server the server to add handlers to
- * @param handlers array of message handlers for
- *        incoming messages; the last entry must
- *        have "NULL" for the "callback"; multiple
- *        entries for the same type are allowed,
- *        they will be called in order of occurence.
- *        These handlers can be removed later;
- *        the handlers array must exist until removed
- *        (or server is destroyed).
- */
-void
-GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server,
-                            const struct GNUNET_SERVER_MessageHandler *handlers)
-{
-  struct HandlerList *p;
-
-  p = GNUNET_new (struct HandlerList);
-  p->handlers = handlers;
-  p->next = server->handlers;
-  server->handlers = p;
-}
-
-
-/**
- * Change functions used by the server to tokenize the message stream.
- * (very rarely used).
- *
- * @param server server to modify
- * @param create new tokenizer initialization function
- * @param destroy new tokenizer destruction function
- * @param receive new tokenizer receive function
- * @param cls closure for @a create, @a receive, @a destroy
- */
-void
-GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server,
-                             GNUNET_SERVER_MstCreateCallback create,
-                             GNUNET_SERVER_MstDestroyCallback destroy,
-                             GNUNET_SERVER_MstReceiveCallback receive,
-                             void *cls)
-{
-  server->mst_create = create;
-  server->mst_destroy = destroy;
-  server->mst_receive = receive;
-  server->mst_cls = cls;
-}
-
-
-/**
- * Task run to warn about missing calls to #GNUNET_SERVER_receive_done.
- *
- * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
- */
-static void
-warn_no_receive_done (void *cls)
-{
-  struct GNUNET_SERVER_Client *client = cls;
-
-  GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
-  client->warn_task =
-      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                    &warn_no_receive_done, client);
-  LOG (GNUNET_ERROR_TYPE_WARNING,
-       _("Processing code for message of type %u did not call `GNUNET_SERVER_receive_done' after %s\n"),
-       (unsigned int) client->warn_type,
-       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
-                                              GNUNET_YES));
-}
-
-
-/**
- * Disable the warning the server issues if a message is not acknowledged
- * in a timely fashion.  Use this call if a client is intentionally delayed
- * for a while.  Only applies to the current message.
- *
- * @param client client for which to disable the warning
- */
-void
-GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client)
-{
-  if (NULL != client->warn_task)
-  {
-    GNUNET_SCHEDULER_cancel (client->warn_task);
-    client->warn_task = NULL;
-  }
-}
-
-
-/**
- * Inject a message into the server, pretend it came
- * from the specified client.  Delivery of the message
- * will happen instantly (if a handler is installed;
- * otherwise the call does nothing).
- *
- * @param server the server receiving the message
- * @param sender the "pretended" sender of the message
- *        can be NULL!
- * @param message message to transmit
- * @return #GNUNET_OK if the message was OK and the
- *                   connection can stay open
- *         #GNUNET_SYSERR if the connection to the
- *         client should be shut down
- */
-int
-GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server,
-                      struct GNUNET_SERVER_Client *sender,
-                      const struct GNUNET_MessageHeader *message)
-{
-  struct HandlerList *pos;
-  const struct GNUNET_SERVER_MessageHandler *mh;
-  unsigned int i;
-  uint16_t type;
-  uint16_t size;
-  int found;
-
-  type = ntohs (message->type);
-  size = ntohs (message->size);
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Received message of type %u and size %u from client\n",
-       type, size);
-  found = GNUNET_NO;
-  for (pos = server->handlers; NULL != pos; pos = pos->next)
-  {
-    i = 0;
-    while (pos->handlers[i].callback != NULL)
-    {
-      mh = &pos->handlers[i];
-      if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL))
-      {
-        if ((0 != mh->expected_size) && (mh->expected_size != size))
-        {
-#if GNUNET8_NETWORK_IS_DEAD
-          LOG (GNUNET_ERROR_TYPE_WARNING,
-               "Expected %u bytes for message of type %u, got %u\n",
-               mh->expected_size, mh->type, size);
-          GNUNET_break_op (0);
-#else
-          LOG (GNUNET_ERROR_TYPE_DEBUG,
-               "Expected %u bytes for message of type %u, got %u\n",
-               mh->expected_size, mh->type, size);
-#endif
-          return GNUNET_SYSERR;
-        }
-        if (NULL != sender)
-        {
-          if ( (0 == sender->suspended) &&
-              (NULL == sender->warn_task) )
-          {
-           GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */
-            sender->warn_start = GNUNET_TIME_absolute_get ();
-            sender->warn_task =
-                GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                              &warn_no_receive_done,
-                                             sender);
-            sender->warn_type = type;
-          }
-          sender->suspended++;
-        }
-        mh->callback (mh->callback_cls, sender, message);
-        found = GNUNET_YES;
-      }
-      i++;
-    }
-  }
-  if (GNUNET_NO == found)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
-         "Received message of unknown type %d\n", type);
-    if (GNUNET_YES == server->require_found)
-      return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * We are receiving an incoming message.  Process it.
- *
- * @param cls our closure (handle for the client)
- * @param buf buffer with data received from network
- * @param available number of bytes available in buf
- * @param addr address of the sender
- * @param addrlen length of @a addr
- * @param errCode code indicating errors receiving, 0 for success
- */
-static void
-process_incoming (void *cls,
-                  const void *buf,
-                  size_t available,
-                  const struct sockaddr *addr,
-                  socklen_t addrlen,
-                  int errCode);
-
-
-/**
- * Process messages from the client's message tokenizer until either
- * the tokenizer is empty (and then schedule receiving more), or
- * until some handler is not immediately done (then wait for restart_processing)
- * or shutdown.
- *
- * @param client the client to process, RC must have already been increased
- *        using #GNUNET_SERVER_client_keep and will be decreased by one in this
- *        function
- * @param ret #GNUNET_NO to start processing from the buffer,
- *            #GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving
- *            #GNUNET_SYSERR if we should instantly abort due to error in a previous step
- */
-static void
-process_mst (struct GNUNET_SERVER_Client *client,
-             int ret)
-{
-  while ((GNUNET_SYSERR != ret) && (NULL != client->server) &&
-         (GNUNET_YES != client->shutdown_now) && (0 == client->suspended))
-  {
-    if (GNUNET_OK == ret)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Server re-enters receive loop, timeout: %s.\n",
-           GNUNET_STRINGS_relative_time_to_string (client->idle_timeout, GNUNET_YES));
-      client->receive_pending = GNUNET_YES;
-      GNUNET_CONNECTION_receive (client->connection,
-                                 GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
-                                 client->idle_timeout,
-                                 &process_incoming,
-                                 client);
-      break;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Server processes additional messages instantly.\n");
-    if (NULL != client->server->mst_receive)
-      ret =
-          client->server->mst_receive (client->server->mst_cls, client->mst,
-                                       client, NULL, 0, GNUNET_NO, GNUNET_YES);
-    else
-      ret =
-          GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO,
-                                     GNUNET_YES);
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n",
-       ret, client->server,
-       client->shutdown_now,
-       client->suspended);
-  if (GNUNET_NO == ret)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Server has more data pending but is suspended.\n");
-    client->receive_pending = GNUNET_SYSERR;    /* data pending */
-  }
-  if ( (GNUNET_SYSERR == ret) ||
-       (GNUNET_YES == client->shutdown_now) )
-    GNUNET_SERVER_client_disconnect (client);
-}
-
-
-/**
- * We are receiving an incoming message.  Process it.
- *
- * @param cls our closure (handle for the client)
- * @param buf buffer with data received from network
- * @param available number of bytes available in buf
- * @param addr address of the sender
- * @param addrlen length of @a addr
- * @param errCode code indicating errors receiving, 0 for success
- */
-static void
-process_incoming (void *cls,
-                  const void *buf,
-                  size_t available,
-                  const struct sockaddr *addr,
-                  socklen_t addrlen,
-                  int errCode)
-{
-  struct GNUNET_SERVER_Client *client = cls;
-  struct GNUNET_SERVER_Handle *server = client->server;
-  struct GNUNET_TIME_Absolute end;
-  struct GNUNET_TIME_Absolute now;
-  int ret;
-
-  GNUNET_assert (GNUNET_YES == client->receive_pending);
-  client->receive_pending = GNUNET_NO;
-  now = GNUNET_TIME_absolute_get ();
-  end = GNUNET_TIME_absolute_add (client->last_activity,
-                                  client->idle_timeout);
-
-  if ( (NULL == buf) &&
-       (0 == available) &&
-       (NULL == addr) &&
-       (0 == errCode) &&
-       (GNUNET_YES != client->shutdown_now) &&
-       (NULL != server) &&
-       (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) &&
-       (end.abs_value_us > now.abs_value_us) )
-  {
-    /* wait longer, timeout changed (i.e. due to us sending) */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Receive time out, but no disconnect due to sending (%p)\n",
-         client);
-    client->receive_pending = GNUNET_YES;
-    GNUNET_CONNECTION_receive (client->connection,
-                               GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
-                               GNUNET_TIME_absolute_get_remaining (end),
-                               &process_incoming,
-                               client);
-    return;
-  }
-  if ( (NULL == buf) ||
-       (0 == available) ||
-       (0 != errCode) ||
-       (NULL == server) ||
-       (GNUNET_YES == client->shutdown_now) ||
-       (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)) )
-  {
-    /* other side closed connection, error connecting, etc. */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Failed to connect or other side closed connection (%p)\n",
-         client);
-    GNUNET_SERVER_client_disconnect (client);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Server receives %u bytes from `%s'.\n",
-       (unsigned int) available,
-       GNUNET_a2s (addr, addrlen));
-  GNUNET_SERVER_client_keep (client);
-  client->last_activity = now;
-
-  if (NULL != server->mst_receive)
-  {
-    ret = client->server->mst_receive (client->server->mst_cls,
-                                       client->mst,
-                                       client,
-                                       buf,
-                                       available,
-                                       GNUNET_NO,
-                                       GNUNET_YES);
-  }
-  else if (NULL != client->mst)
-  {
-    ret =
-        GNUNET_SERVER_mst_receive (client->mst,
-                                   client,
-                                   buf,
-                                   available,
-                                   GNUNET_NO,
-                                   GNUNET_YES);
-  }
-  else
-  {
-    GNUNET_break (0);
-    return;
-  }
-  process_mst (client,
-               ret);
-  GNUNET_SERVER_client_drop (client);
-}
-
-
-/**
- * Task run to start again receiving from the network
- * and process requests.
- *
- * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from
- */
-static void
-restart_processing (void *cls)
-{
-  struct GNUNET_SERVER_Client *client = cls;
-
-  GNUNET_assert (GNUNET_YES != client->shutdown_now);
-  client->restart_task = NULL;
-  if (GNUNET_NO == client->receive_pending)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n");
-    client->receive_pending = GNUNET_YES;
-    GNUNET_CONNECTION_receive (client->connection,
-                               GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
-                               client->idle_timeout,
-                               &process_incoming,
-                               client);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Server continues processing messages still in the buffer.\n");
-  GNUNET_SERVER_client_keep (client);
-  client->receive_pending = GNUNET_NO;
-  process_mst (client,
-               GNUNET_NO);
-  GNUNET_SERVER_client_drop (client);
-}
-
-
-/**
- * This function is called whenever our inbound message tokenizer has
- * received a complete message.
- *
- * @param cls closure (struct GNUNET_SERVER_Handle)
- * @param client identification of the client (`struct GNUNET_SERVER_Client *`)
- * @param message the actual message
- *
- * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
- */
-static int
-client_message_tokenizer_callback (void *cls,
-                                   void *client,
-                                   const struct GNUNET_MessageHeader *message)
-{
-  struct GNUNET_SERVER_Handle *server = cls;
-  struct GNUNET_SERVER_Client *sender = client;
-  int ret;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Tokenizer gives server message of type %u and size %u from client\n",
-       ntohs (message->type), ntohs (message->size));
-  sender->in_process_client_buffer = GNUNET_YES;
-  ret = GNUNET_SERVER_inject (server, sender, message);
-  sender->in_process_client_buffer = GNUNET_NO;
-  if ( (GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now) )
-  {
-    GNUNET_SERVER_client_disconnect (sender);
-    return GNUNET_SYSERR;
-  }
-  return GNUNET_OK;
-}
-
-
-/**
- * Add a TCP socket-based connection to the set of handles managed by
- * this server.  Use this function for outgoing (P2P) connections that
- * we initiated (and where this server should process incoming
- * messages).
- *
- * @param server the server to use
- * @param connection the connection to manage (client must
- *        stop using this connection from now on)
- * @return the client handle
- */
-struct GNUNET_SERVER_Client *
-GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server,
-                              struct GNUNET_CONNECTION_Handle *connection)
-{
-  struct GNUNET_SERVER_Client *client;
-  struct NotifyList *n;
-
-  client = GNUNET_new (struct GNUNET_SERVER_Client);
-  client->connection = connection;
-  client->server = server;
-  client->last_activity = GNUNET_TIME_absolute_get ();
-  client->idle_timeout = server->idle_timeout;
-  GNUNET_CONTAINER_DLL_insert (server->clients_head,
-                              server->clients_tail,
-                              client);
-  if (NULL != server->mst_create)
-    client->mst =
-        server->mst_create (server->mst_cls, client);
-  else
-    client->mst =
-        GNUNET_SERVER_mst_create (&client_message_tokenizer_callback,
-                                  server);
-  GNUNET_assert (NULL != client->mst);
-  for (n = server->connect_notify_list_head; NULL != n; n = n->next)
-    n->callback (n->callback_cls, client);
-  client->receive_pending = GNUNET_YES;
-  GNUNET_CONNECTION_receive (client->connection,
-                             GNUNET_SERVER_MAX_MESSAGE_SIZE - 1,
-                             client->idle_timeout,
-                             &process_incoming,
-                             client);
-  return client;
-}
-
-
-/**
- * Change the timeout for a particular client.  Decreasing the timeout
- * may not go into effect immediately (only after the previous timeout
- * times out or activity happens on the socket).
- *
- * @param client the client to update
- * @param timeout new timeout for activities on the socket
- */
-void
-GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client,
-                                  struct GNUNET_TIME_Relative timeout)
-{
-  client->idle_timeout = timeout;
-}
-
-
-/**
- * Notify the server that the given client handle should
- * be kept (keeps the connection up if possible, increments
- * the internal reference counter).
- *
- * @param client the client to keep
- */
-void
-GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client)
-{
-  client->reference_count++;
-}
-
-
-/**
- * Notify the server that the given client handle is no
- * longer required.  Decrements the reference counter.  If
- * that counter reaches zero an inactive connection maybe
- * closed.
- *
- * @param client the client to drop
- */
-void
-GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client)
-{
-  GNUNET_assert (client->reference_count > 0);
-  client->reference_count--;
-  if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count))
-    GNUNET_SERVER_client_disconnect (client);
-}
-
-
-/**
- * Obtain the network address of the other party.
- *
- * @param client the client to get the address for
- * @param addr where to store the address
- * @param addrlen where to store the length of the @a addr
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client,
-                                  void **addr, size_t * addrlen)
-{
-  return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen);
-}
-
-
-/**
- * Ask the server to notify us whenever a client disconnects.
- * This function is called whenever the actual network connection
- * is closed; the reference count may be zero or larger than zero
- * at this point.
- *
- * @param server the server manageing the clients
- * @param callback function to call on disconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server,
-                                 GNUNET_SERVER_DisconnectCallback callback,
-                                 void *callback_cls)
-{
-  struct NotifyList *n;
-
-  n = GNUNET_new (struct NotifyList);
-  n->callback = callback;
-  n->callback_cls = callback_cls;
-  GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head,
-                              server->disconnect_notify_list_tail,
-                              n);
-}
-
-
-/**
- * Ask the server to notify us whenever a client connects.
- * This function is called whenever the actual network connection
- * is opened. If the server is destroyed before this
- * notification is explicitly cancelled, the 'callback' will
- * once be called with a 'client' argument of NULL to indicate
- * that the server itself is now gone (and that the callback
- * won't be called anymore and also can no longer be cancelled).
- *
- * @param server the server manageing the clients
- * @param callback function to call on sconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server,
-                             GNUNET_SERVER_ConnectCallback callback,
-                             void *callback_cls)
-{
-  struct NotifyList *n;
-  struct GNUNET_SERVER_Client *client;
-
-  n = GNUNET_new (struct NotifyList);
-  n->callback = callback;
-  n->callback_cls = callback_cls;
-  GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head,
-                              server->connect_notify_list_tail,
-                              n);
-  for (client = server->clients_head; NULL != client; client = client->next)
-    callback (callback_cls, client);
-}
-
-
-/**
- * Ask the server to stop notifying us whenever a client connects.
- *
- * @param server the server manageing the clients
- * @param callback function to call on connect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server,
-                                        GNUNET_SERVER_DisconnectCallback callback,
-                                        void *callback_cls)
-{
-  struct NotifyList *pos;
-
-  for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next)
-    if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
-      break;
-  if (NULL == pos)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head,
-                              server->disconnect_notify_list_tail,
-                              pos);
-  GNUNET_free (pos);
-}
-
-
-/**
- * Ask the server to stop notifying us whenever a client disconnects.
- *
- * @param server the server manageing the clients
- * @param callback function to call on disconnect
- * @param callback_cls closure for @a callback
- */
-void
-GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server,
-                                    GNUNET_SERVER_ConnectCallback callback,
-                                    void *callback_cls)
-{
-  struct NotifyList *pos;
-
-  for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next)
-    if ((pos->callback == callback) && (pos->callback_cls == callback_cls))
-      break;
-  if (NULL == pos)
-  {
-    GNUNET_break (0);
-    return;
-  }
-  GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head,
-                              server->connect_notify_list_tail,
-                              pos);
-  GNUNET_free (pos);
-}
-
-
-/**
- * Destroy the connection that is passed in via @a cls.  Used
- * as calling #GNUNET_CONNECTION_destroy from within a function
- * that was itself called from within process_notify() of
- * 'connection.c' is not allowed (see #2329).
- *
- * @param cls connection to destroy
- */
-static void
-destroy_connection (void *cls)
-{
-  struct GNUNET_CONNECTION_Handle *connection = cls;
-
-  GNUNET_CONNECTION_destroy (connection);
-}
-
-
-/**
- * Ask the server to disconnect from the given client.
- * This is the same as returning #GNUNET_SYSERR from a message
- * handler, except that it allows dropping of a client even
- * when not handling a message from that client.
- *
- * @param client the client to disconnect from
- */
-void
-GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client)
-{
-  struct GNUNET_SERVER_Handle *server = client->server;
-  struct NotifyList *n;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Client is being disconnected from the server.\n");
-  if (NULL != client->restart_task)
-  {
-    GNUNET_SCHEDULER_cancel (client->restart_task);
-    client->restart_task = NULL;
-  }
-  if (NULL != client->warn_task)
-  {
-    GNUNET_SCHEDULER_cancel (client->warn_task);
-    client->warn_task = NULL;
-  }
-  if (GNUNET_YES == client->receive_pending)
-  {
-    GNUNET_CONNECTION_receive_cancel (client->connection);
-    client->receive_pending = GNUNET_NO;
-  }
-  client->shutdown_now = GNUNET_YES;
-  client->reference_count++; /* make sure nobody else clean up client... */
-  if ( (NULL != client->mst) &&
-       (NULL != server) )
-  {
-    GNUNET_CONTAINER_DLL_remove (server->clients_head,
-                                server->clients_tail,
-                                client);
-    if (NULL != server->mst_destroy)
-      server->mst_destroy (server->mst_cls,
-                           client->mst);
-    else
-      GNUNET_SERVER_mst_destroy (client->mst);
-    client->mst = NULL;
-    for (n = server->disconnect_notify_list_head; NULL != n; n = n->next)
-      n->callback (n->callback_cls,
-                   client);
-  }
-  client->reference_count--;
-  if (client->reference_count > 0)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "RC of %p still positive, not destroying everything.\n",
-         client);
-    client->server = NULL;
-    return;
-  }
-  if (GNUNET_YES == client->in_process_client_buffer)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Still processing inputs of %p, not destroying everything.\n",
-         client);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "RC of %p now zero, destroying everything.\n",
-       client);
-  if (GNUNET_YES == client->persist)
-    GNUNET_CONNECTION_persist_ (client->connection);
-  if (NULL != client->th.cth)
-    GNUNET_SERVER_notify_transmit_ready_cancel (&client->th);
-  (void) GNUNET_SCHEDULER_add_now (&destroy_connection,
-                                  client->connection);
-  /* need to cancel again, as it might have been re-added
-     in the meantime (i.e. during callbacks) */
-  if (NULL != client->warn_task)
-  {
-    GNUNET_SCHEDULER_cancel (client->warn_task);
-    client->warn_task = NULL;
-  }
-  if (GNUNET_YES == client->receive_pending)
-  {
-    GNUNET_CONNECTION_receive_cancel (client->connection);
-    client->receive_pending = GNUNET_NO;
-  }
-  GNUNET_free (client);
-  /* we might be in soft-shutdown, test if we're done */
-  if (NULL != server)
-    test_monitor_clients (server);
-}
-
-
-/**
- * Disable the "CORK" feature for communication with the given client,
- * forcing the OS to immediately flush the buffer on transmission
- * instead of potentially buffering multiple messages.
- *
- * @param client handle to the client
- * @return #GNUNET_OK on success
- */
-int
-GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client)
-{
-  return GNUNET_CONNECTION_disable_corking (client->connection);
-}
-
-
-/**
- * Wrapper for transmission notification that calls the original
- * callback and update the last activity time for our connection.
- *
- * @param cls the `struct GNUNET_SERVER_Client *`
- * @param size number of bytes we can transmit
- * @param buf where to copy the message
- * @return number of bytes actually transmitted
- */
-static size_t
-transmit_ready_callback_wrapper (void *cls, size_t size, void *buf)
-{
-  struct GNUNET_SERVER_Client *client = cls;
-  GNUNET_CONNECTION_TransmitReadyNotify callback;
-
-  client->th.cth = NULL;
-  callback = client->th.callback;
-  client->th.callback = NULL;
-  client->last_activity = GNUNET_TIME_absolute_get ();
-  return callback (client->th.callback_cls, size, buf);
-}
-
-
-/**
- * Notify us when the server has enough space to transmit
- * a message of the given size to the given client.
- *
- * @param client client to transmit message to
- * @param size requested amount of buffer space
- * @param timeout after how long should we give up (and call
- *        notify with buf NULL and size 0)?
- * @param callback function to call when space is available
- * @param callback_cls closure for @a callback
- * @return non-NULL if the notify callback was queued; can be used
- *         to cancel the request using
- *         #GNUNET_SERVER_notify_transmit_ready_cancel().
- *         NULL if we are already going to notify someone else (busy)
- */
-struct GNUNET_SERVER_TransmitHandle *
-GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client,
-                                     size_t size,
-                                     struct GNUNET_TIME_Relative timeout,
-                                     GNUNET_CONNECTION_TransmitReadyNotify callback,
-                                     void *callback_cls)
-{
-  if (NULL != client->th.callback)
-    return NULL;
-  client->th.callback_cls = callback_cls;
-  client->th.callback = callback;
-  client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size,
-                                                           timeout,
-                                                           &transmit_ready_callback_wrapper,
-                                                           client);
-  return &client->th;
-}
-
-
-/**
- * Abort transmission request.
- *
- * @param th request to abort
- */
-void
-GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th)
-{
-  GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth);
-  th->cth = NULL;
-  th->callback = NULL;
-}
-
-
-/**
- * Set the persistent flag on this client, used to setup client connection
- * to only be killed when the service it's connected to is actually dead.
- *
- * @param client the client to set the persistent flag on
- */
-void
-GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
-{
-  client->persist = GNUNET_YES;
-}
-
-
-/**
- * Resume receiving from this client, we are done processing the
- * current request.  This function must be called from within each
- * GNUNET_SERVER_MessageCallback (or its respective continuations).
- *
- * @param client client we were processing a message of
- * @param success #GNUNET_OK to keep the connection open and
- *                          continue to receive
- *                #GNUNET_NO to close the connection (normal behavior)
- *                #GNUNET_SYSERR to close the connection (signal
- *                          serious error)
- */
-void
-GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client,
-                           int success)
-{
-  if (NULL == client)
-    return;
-  GNUNET_assert (client->suspended > 0);
-  client->suspended--;
-  if (GNUNET_OK != success)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "GNUNET_SERVER_receive_done called with failure indication\n");
-    if ( (client->reference_count > 0) || (client->suspended > 0) )
-      client->shutdown_now = GNUNET_YES;
-    else
-      GNUNET_SERVER_client_disconnect (client);
-    return;
-  }
-  if (client->suspended > 0)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "GNUNET_SERVER_receive_done called, but more clients pending\n");
-    return;
-  }
-  if (NULL != client->warn_task)
-  {
-    GNUNET_SCHEDULER_cancel (client->warn_task);
-    client->warn_task = NULL;
-  }
-  if (GNUNET_YES == client->in_process_client_buffer)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "GNUNET_SERVER_receive_done called while still in processing loop\n");
-    return;
-  }
-  if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now))
-  {
-    GNUNET_SERVER_client_disconnect (client);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "GNUNET_SERVER_receive_done causes restart in reading from the socket\n");
-  GNUNET_assert (NULL == client->restart_task);
-  client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing,
-                                                   client);
-}
-
-
-/* end of server.c */
diff --git a/src/util/server_mst.c b/src/util/server_mst.c
deleted file mode 100644 (file)
index 5155b54..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2010 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/server_mst.c
- * @brief convenience functions for handling inbound message buffers
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-
-#if HAVE_UNALIGNED_64_ACCESS
-#define ALIGN_FACTOR 4
-#else
-#define ALIGN_FACTOR 8
-#endif
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util-server-mst", __VA_ARGS__)
-
-
-/**
- * Handle to a message stream tokenizer.
- */
-struct GNUNET_SERVER_MessageStreamTokenizer
-{
-
-  /**
-   * Function to call on completed messages.
-   */
-  GNUNET_SERVER_MessageTokenizerCallback cb;
-
-  /**
-   * Closure for @e cb.
-   */
-  void *cb_cls;
-
-  /**
-   * Size of the buffer (starting at @e hdr).
-   */
-  size_t curr_buf;
-
-  /**
-   * How many bytes in buffer have we already processed?
-   */
-  size_t off;
-
-  /**
-   * How many bytes in buffer are valid right now?
-   */
-  size_t pos;
-
-  /**
-   * Beginning of the buffer.  Typed like this to force alignment.
-   */
-  struct GNUNET_MessageHeader *hdr;
-
-};
-
-
-
-/**
- * Create a message stream tokenizer.
- *
- * @param cb function to call on completed messages
- * @param cb_cls closure for @a cb
- * @return handle to tokenizer
- */
-struct GNUNET_SERVER_MessageStreamTokenizer *
-GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb,
-                          void *cb_cls)
-{
-  struct GNUNET_SERVER_MessageStreamTokenizer *ret;
-
-  ret = GNUNET_new (struct GNUNET_SERVER_MessageStreamTokenizer);
-  ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE);
-  ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE;
-  ret->cb = cb;
-  ret->cb_cls = cb_cls;
-  return ret;
-}
-
-
-/**
- * Add incoming data to the receive buffer and call the
- * callback for all complete messages.
- *
- * @param mst tokenizer to use
- * @param client_identity ID of client for which this is a buffer
- * @param buf input data to add
- * @param size number of bytes in @a buf
- * @param purge should any excess bytes in the buffer be discarded
- *       (i.e. for packet-based services like UDP)
- * @param one_shot only call callback once, keep rest of message in buffer
- * @return #GNUNET_OK if we are done processing (need more data)
- *         #GNUNET_NO if @a one_shot was set and we have another message ready
- *         #GNUNET_SYSERR if the data stream is corrupt
- */
-int
-GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst,
-                           void *client_identity,
-                           const char *buf, size_t size,
-                           int purge, int one_shot)
-{
-  const struct GNUNET_MessageHeader *hdr;
-  size_t delta;
-  uint16_t want;
-  char *ibuf;
-  int need_align;
-  unsigned long offset;
-  int ret;
-
-  GNUNET_assert (mst->off <= mst->pos);
-  GNUNET_assert (mst->pos <= mst->curr_buf);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Server-mst receives %u bytes with %u bytes already in private buffer\n",
-       (unsigned int) size, (unsigned int) (mst->pos - mst->off));
-  ret = GNUNET_OK;
-  ibuf = (char *) mst->hdr;
-  while (mst->pos > 0)
-  {
-do_align:
-    GNUNET_assert (mst->pos >= mst->off);
-    if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
-        (0 != (mst->off % ALIGN_FACTOR)))
-    {
-      /* need to align or need more space */
-      mst->pos -= mst->off;
-      memmove (ibuf, &ibuf[mst->off], mst->pos);
-      mst->off = 0;
-    }
-    if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
-    {
-      delta =
-          GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) -
-                      (mst->pos - mst->off), size);
-      GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
-      mst->pos += delta;
-      buf += delta;
-      size -= delta;
-    }
-    if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
-    {
-      if (purge)
-      {
-        mst->off = 0;
-        mst->pos = 0;
-      }
-      return GNUNET_OK;
-    }
-    hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
-    want = ntohs (hdr->size);
-    if (want < sizeof (struct GNUNET_MessageHeader))
-    {
-      GNUNET_break_op (0);
-      return GNUNET_SYSERR;
-    }
-    if ( (mst->curr_buf - mst->off < want) &&
-        (mst->off > 0) )
-    {
-      /* can get more space by moving */
-      mst->pos -= mst->off;
-      memmove (ibuf, &ibuf[mst->off], mst->pos);
-      mst->off = 0;
-    }
-    if (mst->curr_buf < want)
-    {
-      /* need to get more space by growing buffer */
-      GNUNET_assert (0 == mst->off);
-      mst->hdr = GNUNET_realloc (mst->hdr, want);
-      ibuf = (char *) mst->hdr;
-      mst->curr_buf = want;
-    }
-    hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
-    if (mst->pos - mst->off < want)
-    {
-      delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
-      GNUNET_assert (mst->pos + delta <= mst->curr_buf);
-      GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
-      mst->pos += delta;
-      buf += delta;
-      size -= delta;
-    }
-    if (mst->pos - mst->off < want)
-    {
-      if (purge)
-      {
-        mst->off = 0;
-        mst->pos = 0;
-      }
-      return GNUNET_OK;
-    }
-    if (one_shot == GNUNET_SYSERR)
-    {
-      /* cannot call callback again, but return value saying that
-       * we have another full message in the buffer */
-      ret = GNUNET_NO;
-      goto copy;
-    }
-    if (one_shot == GNUNET_YES)
-      one_shot = GNUNET_SYSERR;
-    mst->off += want;
-    if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
-      return GNUNET_SYSERR;
-    if (mst->off == mst->pos)
-    {
-      /* reset to beginning of buffer, it's free right now! */
-      mst->off = 0;
-      mst->pos = 0;
-    }
-  }
-  GNUNET_assert (0 == mst->pos);
-  while (size > 0)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Server-mst has %u bytes left in inbound buffer\n",
-         (unsigned int) size);
-    if (size < sizeof (struct GNUNET_MessageHeader))
-      break;
-    offset = (unsigned long) buf;
-    need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO;
-    if (GNUNET_NO == need_align)
-    {
-      /* can try to do zero-copy and process directly from original buffer */
-      hdr = (const struct GNUNET_MessageHeader *) buf;
-      want = ntohs (hdr->size);
-      if (want < sizeof (struct GNUNET_MessageHeader))
-      {
-       GNUNET_break_op (0);
-        mst->off = 0;
-        return GNUNET_SYSERR;
-      }
-      if (size < want)
-        break;                  /* or not: buffer incomplete, so copy to private buffer... */
-      if (one_shot == GNUNET_SYSERR)
-      {
-        /* cannot call callback again, but return value saying that
-         * we have another full message in the buffer */
-        ret = GNUNET_NO;
-        goto copy;
-      }
-      if (one_shot == GNUNET_YES)
-        one_shot = GNUNET_SYSERR;
-      if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr))
-        return GNUNET_SYSERR;
-      buf += want;
-      size -= want;
-    }
-    else
-    {
-      /* need to copy to private buffer to align;
-       * yes, we go a bit more spagetti than usual here */
-      goto do_align;
-    }
-  }
-copy:
-  if ((size > 0) && (!purge))
-  {
-    if (size + mst->pos > mst->curr_buf)
-    {
-      mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos);
-      ibuf = (char *) mst->hdr;
-      mst->curr_buf = size + mst->pos;
-    }
-    GNUNET_assert (size + mst->pos <= mst->curr_buf);
-    GNUNET_memcpy (&ibuf[mst->pos], buf, size);
-    mst->pos += size;
-  }
-  if (purge)
-  {
-    mst->off = 0;
-    mst->pos = 0;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Server-mst leaves %u bytes in private buffer\n",
-       (unsigned int) (mst->pos - mst->off));
-  return ret;
-}
-
-
-/**
- * Destroys a tokenizer.
- *
- * @param mst tokenizer to destroy
- */
-void
-GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst)
-{
-  GNUNET_free (mst->hdr);
-  GNUNET_free (mst);
-}
-
-
-
-/* end of server_mst.c */
diff --git a/src/util/server_nc.c b/src/util/server_nc.c
deleted file mode 100644 (file)
index a95cd7f..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2010 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/server_nc.c
- * @brief convenience functions for transmission of
- *        a notification stream
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util-server-nc", __VA_ARGS__)
-
-
-/**
- * Entry in list of messages pending to be transmitted.
- */
-struct PendingMessageList
-{
-
-  /**
-   * This is a doubly-linked list.
-   */
-  struct PendingMessageList *next;
-
-  /**
-   * This is a doubly-linked list.
-   */
-  struct PendingMessageList *prev;
-
-  /**
-   * Message to transmit (allocated at the end of this
-   * struct, do not free)
-   */
-  const struct GNUNET_MessageHeader *msg;
-
-  /**
-   * Can this message be dropped?
-   */
-  int can_drop;
-
-};
-
-
-/**
- * Lists of clients we manage for notifications.
- */
-struct ClientList
-{
-
-  /**
-   * This is a doubly linked list.
-   */
-  struct ClientList *next;
-
-  /**
-   * This is a doubly linked list.
-   */
-  struct ClientList *prev;
-
-  /**
-   * Overall context this client belongs to.
-   */
-  struct GNUNET_SERVER_NotificationContext *nc;
-
-  /**
-   * Handle to the client.
-   */
-  struct GNUNET_SERVER_Client *client;
-
-  /**
-   * Handle for pending transmission request to the client (or NULL).
-   */
-  struct GNUNET_SERVER_TransmitHandle *th;
-
-  /**
-   * Head of linked list of requests queued for transmission.
-   */
-  struct PendingMessageList *pending_head;
-
-  /**
-   * Tail of linked list of requests queued for transmission.
-   */
-  struct PendingMessageList *pending_tail;
-
-  /**
-   * Number of messages currently in the list.
-   */
-  unsigned int num_pending;
-
-};
-
-
-/**
- * The notification context is the key datastructure for a convenience
- * API used for transmission of notifications to the client until the
- * client disconnects (or the notification context is destroyed, in
- * which case we disconnect these clients).  Essentially, all
- * (notification) messages are queued up until the client is able to
- * read them.
- */
-struct GNUNET_SERVER_NotificationContext
-{
-
-  /**
-   * Server we do notifications for.
-   */
-  struct GNUNET_SERVER_Handle *server;
-
-  /**
-   * Head of list of clients receiving notifications.
-   */
-  struct ClientList *clients_head;
-
-  /**
-   * Tail of list of clients receiving notifications.
-   */
-  struct ClientList *clients_tail;
-
-  /**
-   * Maximum number of optional messages to queue per client.
-   */
-  unsigned int queue_length;
-
-};
-
-
-/**
- * Client has disconnected, clean up.
- *
- * @param cls our `struct GNUNET_SERVER_NotificationContext *`
- * @param client handle of client that disconnected
- */
-static void
-handle_client_disconnect (void *cls,
-                          struct GNUNET_SERVER_Client *client)
-{
-  struct GNUNET_SERVER_NotificationContext *nc = cls;
-  struct ClientList *pos;
-  struct PendingMessageList *pml;
-
-  if (NULL == client)
-  {
-    nc->server = NULL;
-    return;
-  }
-  for (pos = nc->clients_head; NULL != pos; pos = pos->next)
-    if (pos->client == client)
-      break;
-  if (NULL == pos)
-    return;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Client disconnected, cleaning up %u messages in NC queue\n",
-       pos->num_pending);
-  GNUNET_CONTAINER_DLL_remove (nc->clients_head,
-                              nc->clients_tail,
-                              pos);
-  while (NULL != (pml = pos->pending_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (pos->pending_head,
-                                 pos->pending_tail,
-                                 pml);
-    GNUNET_free (pml);
-    pos->num_pending--;
-  }
-  if (NULL != pos->th)
-  {
-    GNUNET_SERVER_notify_transmit_ready_cancel (pos->th);
-    pos->th = NULL;
-  }
-  GNUNET_SERVER_client_drop (client);
-  GNUNET_assert (0 == pos->num_pending);
-  GNUNET_free (pos);
-}
-
-
-/**
- * Create a new notification context.
- *
- * @param server server for which this function creates the context
- * @param queue_length maximum number of messages to keep in
- *        the notification queue; optional messages are dropped
- *        if the queue gets longer than this number of messages
- * @return handle to the notification context
- */
-struct GNUNET_SERVER_NotificationContext *
-GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server,
-                                           unsigned int queue_length)
-{
-  struct GNUNET_SERVER_NotificationContext *ret;
-
-  ret = GNUNET_new (struct GNUNET_SERVER_NotificationContext);
-  ret->server = server;
-  ret->queue_length = queue_length;
-  GNUNET_SERVER_disconnect_notify (server,
-                                   &handle_client_disconnect,
-                                   ret);
-  return ret;
-}
-
-
-/**
- * Destroy the context, force disconnect for all clients.
- *
- * @param nc context to destroy.
- */
-void
-GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc)
-{
-  struct ClientList *pos;
-  struct PendingMessageList *pml;
-
-  while (NULL != (pos = nc->clients_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (nc->clients_head,
-                                nc->clients_tail,
-                                pos);
-    if (NULL != pos->th)
-    {
-      GNUNET_SERVER_notify_transmit_ready_cancel (pos->th);
-      pos->th = NULL;
-    }
-    GNUNET_SERVER_client_drop (pos->client);
-    while (NULL != (pml = pos->pending_head))
-    {
-      GNUNET_CONTAINER_DLL_remove (pos->pending_head,
-                                   pos->pending_tail,
-                                   pml);
-      GNUNET_free (pml);
-      pos->num_pending--;
-    }
-    GNUNET_assert (0 == pos->num_pending);
-    GNUNET_free (pos);
-  }
-  if (NULL != nc->server)
-    GNUNET_SERVER_disconnect_notify_cancel (nc->server,
-                                            &handle_client_disconnect,
-                                            nc);
-  GNUNET_free (nc);
-}
-
-
-/**
- * Add a client to the notification context.
- *
- * @param nc context to modify
- * @param client client to add
- */
-void
-GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc,
-                                        struct GNUNET_SERVER_Client *client)
-{
-  struct ClientList *cl;
-
-  for (cl = nc->clients_head; NULL != cl; cl = cl->next)
-    if (cl->client == client)
-      return; /* already present */
-  cl = GNUNET_new (struct ClientList);
-  GNUNET_CONTAINER_DLL_insert (nc->clients_head,
-                              nc->clients_tail,
-                              cl);
-  cl->nc = nc;
-  cl->client = client;
-  GNUNET_SERVER_client_keep (client);
-}
-
-
-/**
- * Function called to notify a client about the socket begin ready to
- * queue more data.  @a buf will be NULL and @a size zero if the socket
- * was closed for writing in the meantime.
- *
- * @param cls the `struct ClientList *`
- * @param size number of bytes available in @a buf
- * @param buf where the callee should write the message
- * @return number of bytes written to buf
- */
-static size_t
-transmit_message (void *cls,
-                  size_t size,
-                  void *buf)
-{
-  struct ClientList *cl = cls;
-  char *cbuf = buf;
-  struct PendingMessageList *pml;
-  uint16_t msize;
-  size_t ret;
-
-  cl->th = NULL;
-  if (NULL == buf)
-  {
-    /* 'cl' should be freed via disconnect notification shortly */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Failed to transmit message from NC queue to client\n");
-    return 0;
-  }
-  ret = 0;
-  while (NULL != (pml = cl->pending_head))
-  {
-    msize = ntohs (pml->msg->size);
-    if (size < msize)
-      break;
-    GNUNET_CONTAINER_DLL_remove (cl->pending_head,
-                                 cl->pending_tail,
-                                 pml);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Copying message of type %u and size %u from pending queue to transmission buffer\n",
-         ntohs (pml->msg->type),
-         msize);
-    GNUNET_memcpy (&cbuf[ret], pml->msg, msize);
-    ret += msize;
-    size -= msize;
-    GNUNET_free (pml);
-    cl->num_pending--;
-  }
-  if (NULL != pml)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Have %u messages left in NC queue, will try transmission again\n",
-         cl->num_pending);
-    cl->th =
-        GNUNET_SERVER_notify_transmit_ready (cl->client,
-                                             ntohs (pml->msg->size),
-                                             GNUNET_TIME_UNIT_FOREVER_REL,
-                                             &transmit_message, cl);
-  }
-  else
-  {
-    GNUNET_assert (0 == cl->num_pending);
-  }
-  return ret;
-}
-
-
-/**
- * Send a message to a particular client.
- *
- * @param nc context to modify
- * @param client client to transmit to
- * @param msg message to send
- * @param can_drop can this message be dropped due to queue length limitations
- */
-static void
-do_unicast (struct GNUNET_SERVER_NotificationContext *nc,
-            struct ClientList *client,
-            const struct GNUNET_MessageHeader *msg,
-            int can_drop)
-{
-  struct PendingMessageList *pml;
-  uint16_t size;
-
-  if ( (client->num_pending > nc->queue_length) &&
-       (GNUNET_YES == can_drop) )
-  {
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         "Dropping message of type %u and size %u due to full queue (%u entries)\n",
-         ntohs (msg->type), ntohs (msg->size), (unsigned int) nc->queue_length);
-    return;                     /* drop! */
-  }
-  if (client->num_pending > nc->queue_length)
-  {
-    /* FIXME: consider checking for other messages in the
-     * queue that are 'droppable' */
-  }
-  client->num_pending++;
-  size = ntohs (msg->size);
-  pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size);
-  pml->msg = (const struct GNUNET_MessageHeader *) &pml[1];
-  pml->can_drop = can_drop;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Adding message of type %u and size %u to pending queue (which has %u entries)\n",
-       ntohs (msg->type),
-       ntohs (msg->size),
-       (unsigned int) nc->queue_length);
-  GNUNET_memcpy (&pml[1], msg, size);
-  /* append */
-  GNUNET_CONTAINER_DLL_insert_tail (client->pending_head,
-                                    client->pending_tail,
-                                    pml);
-  if (NULL == client->th)
-    client->th =
-        GNUNET_SERVER_notify_transmit_ready (client->client,
-                                             ntohs (client->pending_head->
-                                                    msg->size),
-                                             GNUNET_TIME_UNIT_FOREVER_REL,
-                                             &transmit_message, client);
-}
-
-
-/**
- * Send a message to a particular client; must have
- * already been added to the notification context.
- *
- * @param nc context to modify
- * @param client client to transmit to
- * @param msg message to send
- * @param can_drop can this message be dropped due to queue length limitations
- */
-void
-GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc,
-                                            struct GNUNET_SERVER_Client *client,
-                                            const struct GNUNET_MessageHeader *msg,
-                                            int can_drop)
-{
-  struct ClientList *pos;
-
-  for (pos = nc->clients_head; NULL != pos; pos = pos->next)
-    if (pos->client == client)
-      break;
-  GNUNET_assert (NULL != pos);
-  do_unicast (nc, pos, msg, can_drop);
-}
-
-
-/**
- * Send a message to all clients of this context.
- *
- * @param nc context to modify
- * @param msg message to send
- * @param can_drop can this message be dropped due to queue length limitations
- */
-void
-GNUNET_SERVER_notification_context_broadcast (struct
-                                              GNUNET_SERVER_NotificationContext *nc,
-                                              const struct GNUNET_MessageHeader *msg,
-                                              int can_drop)
-{
-  struct ClientList *pos;
-
-  for (pos = nc->clients_head; NULL != pos; pos = pos->next)
-    do_unicast (nc, pos, msg, can_drop);
-}
-
-
-/**
- * Return active number of subscribers in this context.
- *
- * @param nc context to query
- * @return number of current subscribers
- */
-unsigned int
-GNUNET_SERVER_notification_context_get_size (struct GNUNET_SERVER_NotificationContext *nc)
-{
-  unsigned int num;
-  struct ClientList *pos;
-
-  num = 0;
-  for (pos = nc->clients_head; NULL != pos; pos = pos->next)
-    num++;
-  return num;
-}
-
-/* end of server_nc.c */
diff --git a/src/util/server_tc.c b/src/util/server_tc.c
deleted file mode 100644 (file)
index 8ae380a..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/server_tc.c
- * @brief convenience functions for transmission of
- *        complex responses as a server
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util-server-tc", __VA_ARGS__)
-
-
-/**
- * How much buffer space do we want to have at least
- * before transmitting another increment?
- */
-#define MIN_BLOCK_SIZE 128
-
-
-
-struct GNUNET_SERVER_TransmitContext
-{
-  /**
-   * Which client are we transmitting to?
-   */
-  struct GNUNET_SERVER_Client *client;
-
-  /**
-   * Transmission buffer. (current offset for writing).
-   */
-  char *buf;
-
-  /**
-   * Number of bytes in buf.
-   */
-  size_t total;
-
-  /**
-   * Offset for writing in buf.
-   */
-  size_t off;
-
-  /**
-   * Timeout for this request.
-   */
-  struct GNUNET_TIME_Absolute timeout;
-};
-
-
-/**
- * Helper function for incremental transmission of the response.
- */
-static size_t
-transmit_response (void *cls, size_t size, void *buf)
-{
-  struct GNUNET_SERVER_TransmitContext *tc = cls;
-  size_t msize;
-
-  if (NULL == buf)
-  {
-    GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR);
-    return 0;
-  }
-  if (tc->total - tc->off > size)
-    msize = size;
-  else
-    msize = tc->total - tc->off;
-  GNUNET_memcpy (buf, &tc->buf[tc->off], msize);
-  tc->off += msize;
-  if (tc->total == tc->off)
-  {
-    GNUNET_SERVER_receive_done (tc->client, GNUNET_OK);
-    GNUNET_SERVER_client_drop (tc->client);
-    GNUNET_free_non_null (tc->buf);
-    GNUNET_free (tc);
-  }
-  else
-  {
-    if (NULL ==
-        GNUNET_SERVER_notify_transmit_ready (tc->client,
-                                             GNUNET_MIN (MIN_BLOCK_SIZE,
-                                                         tc->total - tc->off),
-                                             GNUNET_TIME_absolute_get_remaining
-                                             (tc->timeout), &transmit_response,
-                                             tc))
-    {
-      GNUNET_break (0);
-      GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR);
-    }
-  }
-  return msize;
-}
-
-
-/**
- * Create a new transmission context for the
- * given client.
- *
- * @param client client to create the context for.
- * @return NULL on error
- */
-struct GNUNET_SERVER_TransmitContext *
-GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client)
-{
-  struct GNUNET_SERVER_TransmitContext *tc;
-
-  GNUNET_assert (NULL != client);
-  tc = GNUNET_new (struct GNUNET_SERVER_TransmitContext);
-  GNUNET_SERVER_client_keep (client);
-  tc->client = client;
-  return tc;
-}
-
-
-/**
- * Append a message to the transmission context.
- * All messages in the context will be sent by
- * the transmit_context_run method.
- *
- * @param tc context to use
- * @param data what to append to the result message
- * @param length length of data
- * @param type type of the message
- */
-void
-GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext
-                                            *tc, const void *data,
-                                            size_t length, uint16_t type)
-{
-  struct GNUNET_MessageHeader *msg;
-  size_t size;
-
-  GNUNET_assert (length < GNUNET_SERVER_MAX_MESSAGE_SIZE);
-  size = length + sizeof (struct GNUNET_MessageHeader);
-  GNUNET_assert (size > length);
-  tc->buf = GNUNET_realloc (tc->buf, tc->total + size);
-  msg = (struct GNUNET_MessageHeader *) &tc->buf[tc->total];
-  tc->total += size;
-  msg->size = htons (size);
-  msg->type = htons (type);
-  GNUNET_memcpy (&msg[1], data, length);
-}
-
-
-/**
- * Append a message to the transmission context.
- * All messages in the context will be sent by
- * the transmit_context_run method.
- *
- * @param tc context to use
- * @param msg message to append
- */
-void
-GNUNET_SERVER_transmit_context_append_message (struct
-                                               GNUNET_SERVER_TransmitContext
-                                               *tc,
-                                               const struct GNUNET_MessageHeader
-                                               *msg)
-{
-  struct GNUNET_MessageHeader *m;
-  uint16_t size;
-
-  size = ntohs (msg->size);
-  tc->buf = GNUNET_realloc (tc->buf, tc->total + size);
-  m = (struct GNUNET_MessageHeader *) &tc->buf[tc->total];
-  tc->total += size;
-  GNUNET_memcpy (m, msg, size);
-}
-
-
-/**
- * Execute a transmission context.  If there is
- * an error in the transmission, the #GNUNET_SERVER_receive_done()
- * method will be called with an error code (#GNUNET_SYSERR),
- * otherwise with #GNUNET_OK.
- *
- * @param tc transmission context to use
- * @param timeout when to time out and abort the transmission
- */
-void
-GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc,
-                                    struct GNUNET_TIME_Relative timeout)
-{
-  tc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  if (NULL ==
-      GNUNET_SERVER_notify_transmit_ready (tc->client,
-                                           GNUNET_MIN (MIN_BLOCK_SIZE,
-                                                       tc->total), timeout,
-                                           &transmit_response, tc))
-  {
-    GNUNET_break (0);
-    GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR);
-  }
-}
-
-
-/**
- * Destroy a transmission context. This function must not be called
- * after 'GNUNET_SERVER_transmit_context_run'.
- *
- * @param tc transmission context to destroy
- * @param success code to give to 'GNUNET_SERVER_receive_done' for
- *        the client:  GNUNET_OK to keep the connection open and
- *                          continue to receive
- *                GNUNET_NO to close the connection (normal behavior)
- *                GNUNET_SYSERR to close the connection (signal
- *                          serious error)
- */
-void
-GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext
-                                        *tc, int success)
-{
-  GNUNET_SERVER_receive_done (tc->client, success);
-  GNUNET_SERVER_client_drop (tc->client);
-  GNUNET_free_non_null (tc->buf);
-  GNUNET_free (tc);
-}
-
-
-/* end of server_tc.c */
index 496904fb1f5d7ac1926fc32920035eb7fdcb79c4..800d09a4256a7be88d2b57eb14cf15d1a105e4bb 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2009, 2012 GNUnet e.V.
+     Copyright (C) 2016 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 */
 
 /**
- * @file util/service.c
- * @brief functions related to starting services
+ * @file util/service_new.c
+ * @brief functions related to starting services (redesign)
  * @author Christian Grothoff
+ * @author Florian Dold
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename)
 
 
-/* ******************* access control ******************** */
-
 /**
- * Check if the given IP address is in the list of IP addresses.
- *
- * @param list a list of networks
- * @param add the IP to check (in network byte order)
- * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ * Information the service tracks per listen operation.
  */
-static int
-check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
-                   const struct in_addr *add)
+struct ServiceListenContext
 {
-  unsigned int i;
 
-  if (NULL == list)
-    return GNUNET_NO;
-  i = 0;
-  while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
-  {
-    if ((add->s_addr & list[i].netmask.s_addr) ==
-        (list[i].network.s_addr & list[i].netmask.s_addr))
-      return GNUNET_YES;
-    i++;
-  }
-  return GNUNET_NO;
-}
+  /**
+   * Kept in a DLL.
+   */
+  struct ServiceListenContext *next;
 
+  /**
+   * Kept in a DLL.
+   */
+  struct ServiceListenContext *prev;
 
-/**
- * Check if the given IP address is in the list of IP addresses.
- *
- * @param list a list of networks
- * @param ip the IP to check (in network byte order)
- * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
- */
-static int
-check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
-                   const struct in6_addr *ip)
-{
-  unsigned int i;
-  unsigned int j;
-  struct in6_addr zero;
+  /**
+   * Service this listen context belongs to.
+   */
+  struct GNUNET_SERVICE_Handle *sh;
 
-  if (NULL == list)
-    return GNUNET_NO;
-  memset (&zero, 0, sizeof (struct in6_addr));
-  i = 0;
-NEXT:
-  while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr)))
-  {
-    for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
-      if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
-          (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
-      {
-        i++;
-        goto NEXT;
-      }
-    return GNUNET_YES;
-  }
-  return GNUNET_NO;
-}
+  /**
+   * Socket we are listening on.
+   */
+  struct GNUNET_NETWORK_Handle *listen_socket;
 
+  /**
+   * Task scheduled to do the listening.
+   */
+  struct GNUNET_SCHEDULER_Task *listen_task;
 
-/* ****************** service struct ****************** */
+};
 
 
 /**
- * Context for "service_task".
+ * Handle to a service.
  */
-struct GNUNET_SERVICE_Context
+struct GNUNET_SERVICE_Handle
 {
   /**
    * Our configuration.
@@ -121,25 +89,54 @@ struct GNUNET_SERVICE_Context
   const struct GNUNET_CONFIGURATION_Handle *cfg;
 
   /**
-   * Handle for the server.
+   * Name of our service.
+   */
+  const char *service_name;
+
+  /**
+   * Main service-specific task to run.
    */
-  struct GNUNET_SERVER_Handle *server;
+  GNUNET_SERVICE_InitCallback service_init_cb;
 
   /**
-   * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
-   * listen sockets.
+   * Function to call when clients connect.
    */
-  struct sockaddr **addrs;
+  GNUNET_SERVICE_ConnectHandler connect_cb;
 
   /**
-   * Name of our service.
+   * Function to call when clients disconnect / are disconnected.
    */
-  const char *service_name;
+  GNUNET_SERVICE_DisconnectHandler disconnect_cb;
 
   /**
-   * Main service-specific task to run.
+   * Closure for @e service_init_cb, @e connect_cb, @e disconnect_cb.
+   */
+  void *cb_cls;
+
+  /**
+   * DLL of listen sockets used to accept new connections.
+   */
+  struct ServiceListenContext *slc_head;
+
+  /**
+   * DLL of listen sockets used to accept new connections.
+   */
+  struct ServiceListenContext *slc_tail;
+
+  /**
+   * Our clients, kept in a DLL.
    */
-  GNUNET_SERVICE_Main task;
+  struct GNUNET_SERVICE_Client *clients_head;
+
+  /**
+   * Our clients, kept in a DLL.
+   */
+  struct GNUNET_SERVICE_Client *clients_tail;
+
+  /**
+   * Message handlers to use for all clients.
+   */
+  struct GNUNET_MQ_MessageHandler *handlers;
 
   /**
    * Closure for @e task.
@@ -169,30 +166,38 @@ struct GNUNET_SERVICE_Context
   struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
 
   /**
-   * My (default) message handlers.  Adjusted copy
-   * of "defhandlers".
+   * Do we require a matching UID for UNIX domain socket connections?
+   * #GNUNET_NO means that the UID does not have to match (however,
+   * @e match_gid may still impose other access control checks).
    */
-  struct GNUNET_SERVER_MessageHandler *my_handlers;
+  int match_uid;
 
   /**
-   * Array of the lengths of the entries in addrs.
+   * Do we require a matching GID for UNIX domain socket connections?
+   * Ignored if @e match_uid is #GNUNET_YES.  Note that this is about
+   * checking that the client's UID is in our group OR that the
+   * client's GID is our GID.  If both "match_gid" and @e match_uid are
+   * #GNUNET_NO, all users on the local system have access.
    */
-  socklen_t *addrlens;
+  int match_gid;
 
   /**
-   * NULL-terminated array of listen sockets we should take over.
+   * Set to #GNUNET_YES if we got a shutdown signal and terminate
+   * the service if #have_non_monitor_clients() returns #GNUNET_YES.
    */
-  struct GNUNET_NETWORK_Handle **lsocks;
+  int got_shutdown;
 
   /**
-   * Task ID of the shutdown task.
+   * Our options.
    */
-  struct GNUNET_SCHEDULER_Task *shutdown_task;
+  enum GNUNET_SERVICE_Options options;
 
   /**
-   * Idle timeout for server.
+   * If we are daemonizing, this FD is set to the
+   * pipe to the parent.  Send '.' if we started
+   * ok, '!' if not.  -1 if we are not daemonizing.
    */
-  struct GNUNET_TIME_Relative timeout;
+  int ready_confirm_fd;
 
   /**
    * Overall success/failure of the service start.
@@ -200,182 +205,203 @@ struct GNUNET_SERVICE_Context
   int ret;
 
   /**
-   * If we are daemonizing, this FD is set to the
-   * pipe to the parent.  Send '.' if we started
-   * ok, '!' if not.  -1 if we are not daemonizing.
+   * If #GNUNET_YES, consider unknown message types an error where the
+   * client is disconnected.
    */
-  int ready_confirm_fd;
+  int require_found;
+};
+
+
+/**
+ * Handle to a client that is connected to a service.
+ */
+struct GNUNET_SERVICE_Client
+{
 
   /**
-   * Do we close connections if we receive messages
-   * for which we have no handler?
+   * Kept in a DLL.
    */
-  int require_found;
+  struct GNUNET_SERVICE_Client *next;
 
   /**
-   * Do we require a matching UID for UNIX domain socket connections?
-   * #GNUNET_NO means that the UID does not have to match (however,
-   * @e match_gid may still impose other access control checks).
+   * Kept in a DLL.
    */
-  int match_uid;
+  struct GNUNET_SERVICE_Client *prev;
 
   /**
-   * Do we require a matching GID for UNIX domain socket connections?
-   * Ignored if @e match_uid is #GNUNET_YES.  Note that this is about
-   * checking that the client's UID is in our group OR that the
-   * client's GID is our GID.  If both "match_gid" and @e match_uid are
-   * #GNUNET_NO, all users on the local system have access.
+   * Service that this client belongs to.
    */
-  int match_gid;
+  struct GNUNET_SERVICE_Handle *sh;
 
   /**
-   * Our options.
+   * Socket of this client.
    */
-  enum GNUNET_SERVICE_Options options;
+  struct GNUNET_NETWORK_Handle *sock;
 
-};
+  /**
+   * Message queue for the client.
+   */
+  struct GNUNET_MQ_Handle *mq;
+
+  /**
+   * Tokenizer we use for processing incoming data.
+   */
+  struct GNUNET_MessageStreamTokenizer *mst;
+
+  /**
+   * Task that warns about missing calls to
+   * #GNUNET_SERVICE_client_continue().
+   */
+  struct GNUNET_SCHEDULER_Task *warn_task;
+
+  /**
+   * Task run to finish dropping the client after the stack has
+   * properly unwound.
+   */
+  struct GNUNET_SCHEDULER_Task *drop_task;
+
+  /**
+   * Task that receives data from the client to
+   * pass it to the handlers.
+   */
+  struct GNUNET_SCHEDULER_Task *recv_task;
+
+  /**
+   * Task that transmit data to the client.
+   */
+  struct GNUNET_SCHEDULER_Task *send_task;
+
+  /**
+   * Pointer to the message to be transmitted by @e send_task.
+   */
+  const struct GNUNET_MessageHeader *msg;
+
+  /**
+   * User context value, value returned from
+   * the connect callback.
+   */
+  void *user_context;
+
+  /**
+   * Time when we last gave a message from this client
+   * to the application.
+   */
+  struct GNUNET_TIME_Absolute warn_start;
+
+  /**
+   * Current position in @e msg at which we are transmitting.
+   */
+  size_t msg_pos;
+
+  /**
+   * Persist the file handle for this client no matter what happens,
+   * force the OS to close once the process actually dies.  Should only
+   * be used in special cases!
+   */
+  int persist;
 
+  /**
+   * Is this client a 'monitor' client that should not be counted
+   * when deciding on destroying the server during soft shutdown?
+   * (see also #GNUNET_SERVICE_start)
+   */
+  int is_monitor;
+
+  /**
+   * Are we waiting for the application to call #GNUNET_SERVICE_client_continue()?
+   */
+  int needs_continue;
+
+  /**
+   * Type of last message processed (for warn_no_receive_done).
+   */
+  uint16_t warn_type;
+};
 
-/* ****************** message handlers ****************** */
 
 /**
- * Send a 'TEST' message back to the client.
+ * Check if any of the clients we have left are unrelated to
+ * monitoring.
  *
- * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
- * @param size number of bytes available in 'buf'
- * @param buf where to copy the message
- * @return number of bytes written to 'buf'
+ * @param sh service to check clients for
+ * @return #GNUNET_YES if we have non-monitoring clients left
  */
-static size_t
-write_test (void *cls, size_t size, void *buf)
+static int
+have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh)
 {
-  struct GNUNET_SERVER_Client *client = cls;
-  struct GNUNET_MessageHeader *msg;
+  struct GNUNET_SERVICE_Client *client;
 
-  if (size < sizeof (struct GNUNET_MessageHeader))
+  for (client = sh->clients_head;NULL != client; client = client->next)
   {
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return 0;                   /* client disconnected */
+    if (client->is_monitor)
+      continue;
+    return GNUNET_YES;
   }
-  msg = (struct GNUNET_MessageHeader *) buf;
-  msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
-  msg->size = htons (sizeof (struct GNUNET_MessageHeader));
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-  return sizeof (struct GNUNET_MessageHeader);
+  return GNUNET_NO;
 }
 
 
 /**
- * Handler for TEST message.
+ * Shutdown task triggered when a service should be terminated.
+ * This considers active clients and the service options to see
+ * how this specific service is to be terminated, and depending
+ * on this proceeds with the shutdown logic.
  *
- * @param cls closure (refers to service)
- * @param client identification of the client
- * @param message the actual message
+ * @param cls our `struct GNUNET_SERVICE_Handle`
  */
 static void
-handle_test (void *cls, struct GNUNET_SERVER_Client *client,
-             const struct GNUNET_MessageHeader *message)
-{
-  /* simply bounce message back to acknowledge */
-  if (NULL ==
-      GNUNET_SERVER_notify_transmit_ready (client,
-                                           sizeof (struct GNUNET_MessageHeader),
-                                           GNUNET_TIME_UNIT_FOREVER_REL,
-                                           &write_test, client))
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-}
-
-
-/**
- * Default handlers for all services.  Will be copied and the
- * "callback_cls" fields will be replaced with the specific service
- * struct.
- */
-static const struct GNUNET_SERVER_MessageHandler defhandlers[] = {
-  {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST,
-   sizeof (struct GNUNET_MessageHeader)},
-  {NULL, NULL, 0, 0}
-};
-
-
-/* ****************** service core routines ************** */
-
-
-/**
- * Check if access to the service is allowed from the given address.
- *
- * @param cls closure
- * @param uc credentials, if available, otherwise NULL
- * @param addr address
- * @param addrlen length of address
- * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
- *   for unknown address family (will be denied).
- */
-static int
-check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc,
-              const struct sockaddr *addr, socklen_t addrlen)
+service_shutdown (void *cls)
 {
-  struct GNUNET_SERVICE_Context *sctx = cls;
-  const struct sockaddr_in *i4;
-  const struct sockaddr_in6 *i6;
-  int ret;
+  struct GNUNET_SERVICE_Handle *sh = cls;
 
-  switch (addr->sa_family)
+  switch (sh->options)
   {
-  case AF_INET:
-    GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
-    i4 = (const struct sockaddr_in *) addr;
-    ret = ((NULL == sctx->v4_allowed) ||
-           (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
-        ((NULL == sctx->v4_denied) ||
-         (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
+  case GNUNET_SERVICE_OPTION_NONE:
+    GNUNET_SERVICE_shutdown (sh);
     break;
-  case AF_INET6:
-    GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
-    i6 = (const struct sockaddr_in6 *) addr;
-    ret = ((NULL == sctx->v6_allowed) ||
-           (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
-        ((NULL == sctx->v6_denied) ||
-         (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
+  case GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN:
+    /* This task should never be run if we are using
+       the manual shutdown. */
+    GNUNET_assert (0);
     break;
-#ifndef WINDOWS
-  case AF_UNIX:
-    ret = GNUNET_OK;            /* controlled using file-system ACL now */
+  case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN:
+    sh->got_shutdown = GNUNET_YES;
+    GNUNET_SERVICE_suspend (sh);
+    if (GNUNET_NO == have_non_monitor_clients (sh))
+      GNUNET_SERVICE_shutdown (sh);
     break;
-#endif
-  default:
-    LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"),
-         addr->sa_family);
-    return GNUNET_SYSERR;
   }
-  if (GNUNET_OK != ret)
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         _("Access from `%s' denied to service `%s'\n"),
-        GNUNET_a2s (addr, addrlen),
-         sctx->service_name);
-  }
-  return ret;
 }
 
 
 /**
- * Get the name of the file where we will
- * write the PID of the service.
+ * First task run by any service.  Initializes our shutdown task,
+ * starts the listening operation on our listen sockets and launches
+ * the custom logic of the application service.
  *
- * @param sctx service context
- * @return name of the file for the process ID
+ * @param cls our `struct GNUNET_SERVICE_Handle`
  */
-static char *
-get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
+static void
+service_main (void *cls)
 {
-  char *pif;
+  struct GNUNET_SERVICE_Handle *sh = cls;
 
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
-                                               "PIDFILE", &pif))
-    return NULL;
-  return pif;
+  if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN != sh->options)
+    GNUNET_SCHEDULER_add_shutdown (&service_shutdown,
+                                   sh);
+  GNUNET_SERVICE_resume (sh);
+
+  if (-1 != sh->ready_confirm_fd)
+  {
+    GNUNET_break (1 == WRITE (sh->ready_confirm_fd, ".", 1));
+    GNUNET_break (0 == CLOSE (sh->ready_confirm_fd));
+    sh->ready_confirm_fd = -1;
+  }
+
+  if (NULL != sh->service_init_cb)
+    sh->service_init_cb (sh->cb_cls,
+                        sh->cfg,
+                        sh);
 }
 
 
@@ -383,32 +409,37 @@ get_pid_file_name (struct GNUNET_SERVICE_Context *sctx)
  * Parse an IPv4 access control list.
  *
  * @param ret location where to write the ACL (set)
- * @param sctx service context to use to get the configuration
+ * @param sh service context to use to get the configuration
  * @param option name of the ACL option to parse
  * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
  *         no ACL configured)
  */
 static int
 process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
-              struct GNUNET_SERVICE_Context *sctx,
+              struct GNUNET_SERVICE_Handle *sh,
               const char *option)
 {
   char *opt;
 
-  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+  if (! GNUNET_CONFIGURATION_have_value (sh->cfg,
+                                        sh->service_name,
+                                        option))
   {
     *ret = NULL;
     return GNUNET_OK;
   }
   GNUNET_break (GNUNET_OK ==
-                GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
-                                                       sctx->service_name,
-                                                       option, &opt));
+                GNUNET_CONFIGURATION_get_value_string (sh->cfg,
+                                                       sh->service_name,
+                                                       option,
+                                                      &opt));
   if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
-         opt, sctx->service_name, option);
+         opt,
+        sh->service_name,
+        option);
     GNUNET_free (opt);
     return GNUNET_SYSERR;
   }
@@ -421,32 +452,37 @@ process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
  * Parse an IPv6 access control list.
  *
  * @param ret location where to write the ACL (set)
- * @param sctx service context to use to get the configuration
+ * @param sh service context to use to get the configuration
  * @param option name of the ACL option to parse
  * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
  *         no ACL configured)
  */
 static int
 process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
-              struct GNUNET_SERVICE_Context *sctx,
+              struct GNUNET_SERVICE_Handle *sh,
               const char *option)
 {
   char *opt;
 
-  if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
+  if (! GNUNET_CONFIGURATION_have_value (sh->cfg,
+                                        sh->service_name,
+                                        option))
   {
     *ret = NULL;
     return GNUNET_OK;
   }
   GNUNET_break (GNUNET_OK ==
-                GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
-                                                       sctx->service_name,
-                                                       option, &opt));
+                GNUNET_CONFIGURATION_get_value_string (sh->cfg,
+                                                       sh->service_name,
+                                                       option,
+                                                      &opt));
   if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
-         opt, sctx->service_name, option);
+         opt,
+        sh->service_name,
+        option);
     GNUNET_free (opt);
     return GNUNET_SYSERR;
   }
@@ -476,7 +512,9 @@ add_unixpath (struct sockaddr **saddrs,
 
   un = GNUNET_new (struct sockaddr_un);
   un->sun_family = AF_UNIX;
-  strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+  strncpy (un->sun_path,
+          unixpath,
+          sizeof (un->sun_path) - 1);
 #ifdef LINUX
   if (GNUNET_YES == abstract)
     un->sun_path[0] = '\0';
@@ -514,11 +552,11 @@ add_unixpath (struct sockaddr **saddrs,
  *              zero (in this case, `*addrs` and `*addr_lens` will be
  *              set to NULL).
  */
-int
-GNUNET_SERVICE_get_server_addresses (const char *service_name,
-                                     const struct GNUNET_CONFIGURATION_Handle *cfg,
-                                     struct sockaddr ***addrs,
-                                     socklen_t ** addr_lens)
+static int
+get_server_addresses (const char *service_name,
+                     const struct GNUNET_CONFIGURATION_Handle *cfg,
+                     struct sockaddr ***addrs,
+                     socklen_t **addr_lens)
 {
   int disablev6;
   struct GNUNET_NETWORK_Handle *desc;
@@ -539,11 +577,15 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
   *addrs = NULL;
   *addr_lens = NULL;
   desc = NULL;
-  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
+  if (GNUNET_CONFIGURATION_have_value (cfg,
+                                      service_name,
+                                      "DISABLEV6"))
   {
     if (GNUNET_SYSERR ==
         (disablev6 =
-         GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
+         GNUNET_CONFIGURATION_get_value_yesno (cfg,
+                                              service_name,
+                                              "DISABLEV6")))
       return GNUNET_SYSERR;
   }
   else
@@ -552,33 +594,44 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
   if (! disablev6)
   {
     /* probe IPv6 support */
-    desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
+    desc = GNUNET_NETWORK_socket_create (PF_INET6,
+                                        SOCK_STREAM,
+                                        0);
     if (NULL == desc)
     {
-      if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
-          (EACCES == errno))
+      if ( (ENOBUFS == errno) ||
+          (ENOMEM == errno) ||
+          (ENFILE == errno) ||
+          (EACCES == errno) )
       {
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                     "socket");
         return GNUNET_SYSERR;
       }
       LOG (GNUNET_ERROR_TYPE_INFO,
            _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
-           service_name, STRERROR (errno));
+           service_name,
+          STRERROR (errno));
       disablev6 = GNUNET_YES;
     }
     else
     {
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+      GNUNET_break (GNUNET_OK ==
+                   GNUNET_NETWORK_socket_close (desc));
       desc = NULL;
     }
   }
 
   port = 0;
-  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
+  if (GNUNET_CONFIGURATION_have_value (cfg,
+                                      service_name,
+                                      "PORT"))
   {
     if (GNUNET_OK !=
-       GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
-                                              "PORT", &port))
+       GNUNET_CONFIGURATION_get_value_number (cfg,
+                                              service_name,
+                                              "PORT",
+                                              &port))
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
            _("Require valid port number for service `%s' in configuration!\n"),
@@ -593,11 +646,15 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
     }
   }
 
-  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
+  if (GNUNET_CONFIGURATION_have_value (cfg,
+                                      service_name,
+                                      "BINDTO"))
   {
     GNUNET_break (GNUNET_OK ==
-                  GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
-                                                         "BINDTO", &hostname));
+                  GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                        service_name,
+                                                         "BINDTO",
+                                                        &hostname));
   }
   else
     hostname = NULL;
@@ -606,10 +663,14 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
   abstract = GNUNET_NO;
 #ifdef AF_UNIX
   if ((GNUNET_YES ==
-       GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
+       GNUNET_CONFIGURATION_have_value (cfg,
+                                       service_name,
+                                       "UNIXPATH")) &&
       (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH",
-                                              &unixpath)) &&
+       GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                               service_name,
+                                               "UNIXPATH",
+                                               &unixpath)) &&
       (0 < strlen (unixpath)))
   {
     /* probe UNIX support */
@@ -618,7 +679,8 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
     if (strlen (unixpath) >= sizeof (s_un.sun_path))
     {
       LOG (GNUNET_ERROR_TYPE_WARNING,
-           _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath,
+           _("UNIXPATH `%s' too long, maximum length is %llu\n"),
+          unixpath,
            (unsigned long long) sizeof (s_un.sun_path));
       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
       LOG (GNUNET_ERROR_TYPE_INFO,
@@ -632,22 +694,27 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
     if (GNUNET_SYSERR == abstract)
       abstract = GNUNET_NO;
 #endif
-    if ((GNUNET_YES != abstract)
-        && (GNUNET_OK !=
-            GNUNET_DISK_directory_create_for_file (unixpath)))
+    if ( (GNUNET_YES != abstract) &&
+        (GNUNET_OK !=
+         GNUNET_DISK_directory_create_for_file (unixpath)) )
       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
                                "mkdir",
                                unixpath);
   }
   if (NULL != unixpath)
   {
-    desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
+    desc = GNUNET_NETWORK_socket_create (AF_UNIX,
+                                        SOCK_STREAM,
+                                        0);
     if (NULL == desc)
     {
-      if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
+      if ((ENOBUFS == errno) ||
+         (ENOMEM == errno) ||
+         (ENFILE == errno) ||
           (EACCES == errno))
       {
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
+        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                     "socket");
         GNUNET_free_non_null (hostname);
         GNUNET_free (unixpath);
         return GNUNET_SYSERR;
@@ -661,7 +728,8 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
     }
     else
     {
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+      GNUNET_break (GNUNET_OK ==
+                   GNUNET_NETWORK_socket_close (desc));
       desc = NULL;
     }
   }
@@ -677,9 +745,14 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
   }
   if (0 == port)
   {
-    saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *));
-    saddrlens = GNUNET_malloc (2 * sizeof (socklen_t));
-    add_unixpath (saddrs, saddrlens, unixpath, abstract);
+    saddrs = GNUNET_new_array (2,
+                              struct sockaddr *);
+    saddrlens = GNUNET_new_array (2,
+                                 socklen_t);
+    add_unixpath (saddrs,
+                 saddrlens,
+                 unixpath,
+                 abstract);
     GNUNET_free_non_null (unixpath);
     GNUNET_free_non_null (hostname);
     *addrs = saddrs;
@@ -693,11 +766,16 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
          "Resolving `%s' since that is where `%s' will bind to.\n",
          hostname,
          service_name);
-    memset (&hints, 0, sizeof (struct addrinfo));
+    memset (&hints,
+           0,
+           sizeof (struct addrinfo));
     if (disablev6)
       hints.ai_family = AF_INET;
     hints.ai_protocol = IPPROTO_TCP;
-    if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
+    if ((0 != (ret = getaddrinfo (hostname,
+                                 NULL,
+                                 &hints,
+                                 &res))) ||
         (NULL == res))
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -713,7 +791,8 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
     while (NULL != (pos = next))
     {
       next = pos->ai_next;
-      if ((disablev6) && (pos->ai_family == AF_INET6))
+      if ( (disablev6) &&
+          (pos->ai_family == AF_INET6) )
         continue;
       i++;
     }
@@ -731,32 +810,45 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
     resi = i;
     if (NULL != unixpath)
       resi++;
-    saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
-    saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+    saddrs = GNUNET_new_array (resi + 1,
+                              struct sockaddr *);
+    saddrlens = GNUNET_new_array (resi + 1,
+                                 socklen_t);
     i = 0;
     if (NULL != unixpath)
     {
-      add_unixpath (saddrs, saddrlens, unixpath, abstract);
+      add_unixpath (saddrs,
+                   saddrlens,
+                   unixpath,
+                   abstract);
       i++;
     }
     next = res;
     while (NULL != (pos = next))
     {
       next = pos->ai_next;
-      if ((disablev6) && (AF_INET6 == pos->ai_family))
+      if ( (disablev6) &&
+          (AF_INET6 == pos->ai_family) )
         continue;
-      if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
+      if ( (IPPROTO_TCP != pos->ai_protocol) &&
+          (0 != pos->ai_protocol) )
         continue;               /* not TCP */
-      if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
+      if ( (SOCK_STREAM != pos->ai_socktype) &&
+          (0 != pos->ai_socktype) )
         continue;               /* huh? */
-      LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n",
-           service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+          "Service `%s' will bind to `%s'\n",
+           service_name,
+          GNUNET_a2s (pos->ai_addr,
+                      pos->ai_addrlen));
       if (AF_INET == pos->ai_family)
       {
         GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
         saddrlens[i] = pos->ai_addrlen;
         saddrs[i] = GNUNET_malloc (saddrlens[i]);
-        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+        GNUNET_memcpy (saddrs[i],
+                      pos->ai_addr,
+                      saddrlens[i]);
         ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
       }
       else
@@ -765,7 +857,9 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
         GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
         saddrlens[i] = pos->ai_addrlen;
         saddrs[i] = GNUNET_malloc (saddrlens[i]);
-        GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+        GNUNET_memcpy (saddrs[i],
+                      pos->ai_addr,
+                      saddrlens[i]);
         ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
       }
       i++;
@@ -784,11 +878,16 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
       if (NULL != unixpath)
         resi++;
       i = 0;
-      saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
-      saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+      saddrs = GNUNET_new_array (resi + 1,
+                                struct sockaddr *);
+      saddrlens = GNUNET_new_array (resi + 1,
+                                   socklen_t);
       if (NULL != unixpath)
       {
-        add_unixpath (saddrs, saddrlens, unixpath, abstract);
+        add_unixpath (saddrs,
+                     saddrlens,
+                     unixpath,
+                     abstract);
         i++;
       }
       saddrlens[i] = sizeof (struct sockaddr_in);
@@ -805,12 +904,17 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
       resi = 2;
       if (NULL != unixpath)
         resi++;
-      saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
-      saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+      saddrs = GNUNET_new_array (resi + 1,
+                                struct sockaddr *);
+      saddrlens = GNUNET_new_array (resi + 1,
+                                   socklen_t);
       i = 0;
       if (NULL != unixpath)
       {
-        add_unixpath (saddrs, saddrlens, unixpath, abstract);
+        add_unixpath (saddrs,
+                     saddrlens,
+                     unixpath,
+                     abstract);
         i++;
       }
       saddrlens[i] = sizeof (struct sockaddr_in6);
@@ -841,13 +945,14 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name,
 /**
  * Read listen sockets from the parent process (ARM).
  *
- * @param sctx service context to initialize
- * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself),
- * and #GNUNET_SYSERR on error.
+ * @param sh service context to initialize
+ * @return NULL-terminated array of sockets on success,
+ *         NULL if not ok (must bind yourself)
  */
-static int
-receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
+static struct GNUNET_NETWORK_Handle **
+receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh)
 {
+  static struct GNUNET_NETWORK_Handle **lsocks;
   const char *env_buf;
   int fail;
   uint64_t count;
@@ -855,15 +960,19 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
   HANDLE lsocks_pipe;
 
   env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
-  if ((NULL == env_buf) || (strlen (env_buf) <= 0))
-    return GNUNET_NO;
+  if ( (NULL == env_buf) ||
+       (strlen (env_buf) <= 0) )
+    return NULL;
   /* Using W32 API directly here, because this pipe will
    * never be used outside of this function, and it's just too much of a bother
    * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
    */
-  lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10);
-  if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe))
-    return GNUNET_NO;
+  lsocks_pipe = (HANDLE) strtoul (env_buf,
+                                 NULL,
+                                 10);
+  if ( (0 == lsocks_pipe) ||
+       (INVALID_HANDLE_VALUE == lsocks_pipe))
+    return NULL;
   fail = 1;
   do
   {
@@ -871,11 +980,17 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
     int fail2;
     DWORD rd;
 
-    ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL);
-    if ((0 == ret) || (sizeof (count) != rd) || (0 == count))
+    ret = ReadFile (lsocks_pipe,
+                   &count,
+                   sizeof (count),
+                   &rd,
+                   NULL);
+    if ( (0 == ret) ||
+        (sizeof (count) != rd) ||
+        (0 == count) )
       break;
-    sctx->lsocks =
-        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1));
+    lsocks = GNUNET_new_array (count + 1,
+                              struct GNUNET_NETWORK_Handle *);
 
     fail2 = 1;
     for (i = 0; i < count; i++)
@@ -884,160 +999,336 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx)
       uint64_t size;
       SOCKET s;
 
-      ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL);
-      if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) )
+      ret = ReadFile (lsocks_pipe,
+                     &size,
+                     sizeof (size),
+                     &rd,
+                     NULL);
+      if ( (0 == ret) ||
+          (sizeof (size) != rd) ||
+          (sizeof (pi) != size) )
         break;
-      ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL);
-      if ( (0 == ret) || (sizeof (pi) != rd))
+      ret = ReadFile (lsocks_pipe,
+                     &pi,
+                     sizeof (pi),
+                     &rd,
+                     NULL);
+      if ( (0 == ret) ||
+          (sizeof (pi) != rd))
         break;
-      s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED);
-      sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
-      if (NULL == sctx->lsocks[i])
+      s = WSASocketA (pi.iAddressFamily,
+                     pi.iSocketType,
+                     pi.iProtocol,
+                     &pi,
+                     0,
+                     WSA_FLAG_OVERLAPPED);
+      lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
+      if (NULL == lsocks[i])
         break;
       else if (i == count - 1)
         fail2 = 0;
     }
     if (fail2)
       break;
-    sctx->lsocks[count] = NULL;
+    lsocks[count] = NULL;
     fail = 0;
   }
   while (fail);
-
   CloseHandle (lsocks_pipe);
 
   if (fail)
   {
     LOG (GNUNET_ERROR_TYPE_ERROR,
          _("Could not access a pre-bound socket, will try to bind myself\n"));
-    for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++)
-      GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i]));
-    GNUNET_free_non_null (sctx->lsocks);
-    sctx->lsocks = NULL;
-    return GNUNET_NO;
+    for (i = 0; (i < count) && (NULL != lsocks[i]); i++)
+      GNUNET_break (GNUNET_OK ==
+                   GNUNET_NETWORK_socket_close (lsocks[i]));
+    GNUNET_free (lsocks);
+    return NULL;
   }
-  return GNUNET_YES;
+  return lsocks;
 }
 #endif
 
 
 /**
- * Setup addr, addrlen, idle_timeout
- * based on configuration!
- *
- * Configuration may specify:
- * - PORT (where to bind to for TCP)
- * - UNIXPATH (where to bind to for UNIX domain sockets)
- * - TIMEOUT (after how many ms does an inactive service timeout);
- * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
- * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
- * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
- * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
- * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
- * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
+ * Create and initialize a listen socket for the server.
  *
- * @param sctx service context to initialize
- * @return #GNUNET_OK if configuration succeeded
+ * @param server_addr address to listen on
+ * @param socklen length of @a server_addr
+ * @return NULL on error, otherwise the listen socket
  */
-static int
-setup_service (struct GNUNET_SERVICE_Context *sctx)
+static struct GNUNET_NETWORK_Handle *
+open_listen_socket (const struct sockaddr *server_addr,
+                   socklen_t socklen)
 {
-  struct GNUNET_TIME_Relative idleout;
-  int tolerant;
-
-#ifndef MINGW
-  const char *nfds;
-  unsigned int cnt;
-  int flags;
-#endif
-
-  if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT"))
-  {
-    if (GNUNET_OK !=
-        GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name,
-                                             "TIMEOUT", &idleout))
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-           _("Specified value for `%s' of service `%s' is invalid\n"),
-           "TIMEOUT", sctx->service_name);
-      return GNUNET_SYSERR;
-    }
-    sctx->timeout = idleout;
-  }
-  else
-    sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+  struct GNUNET_NETWORK_Handle *sock;
+  uint16_t port;
+  int eno;
 
-  if (GNUNET_CONFIGURATION_have_value
-      (sctx->cfg, sctx->service_name, "TOLERANT"))
+  switch (server_addr->sa_family)
   {
-    if (GNUNET_SYSERR ==
+  case AF_INET:
+    port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
+    break;
+  case AF_INET6:
+    port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
+    break;
+  case AF_UNIX:
+    port = 0;
+    break;
+  default:
+    GNUNET_break (0);
+    port = 0;
+    break;
+  }
+  sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
+                                      SOCK_STREAM,
+                                      0);
+  if (NULL == sock)
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                 "socket");
+    errno = 0;
+    return NULL;
+  }
+  /* bind the socket */
+  if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock,
+                                              server_addr,
+                                              socklen))
+  {
+    eno = errno;
+    if (EADDRINUSE != errno)
+    {
+      /* we don't log 'EADDRINUSE' here since an IPv4 bind may
+       * fail if we already took the port on IPv6; if both IPv4 and
+       * IPv6 binds fail, then our caller will log using the
+       * errno preserved in 'eno' */
+      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                    "bind");
+      if (0 != port)
+        LOG (GNUNET_ERROR_TYPE_ERROR,
+             _("`%s' failed for port %d (%s).\n"),
+             "bind",
+             port,
+             (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
+      eno = 0;
+    }
+    else
+    {
+      if (0 != port)
+        LOG (GNUNET_ERROR_TYPE_WARNING,
+             _("`%s' failed for port %d (%s): address already in use\n"),
+             "bind", port,
+             (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
+      else if (AF_UNIX == server_addr->sa_family)
+      {
+        LOG (GNUNET_ERROR_TYPE_WARNING,
+             _("`%s' failed for `%s': address already in use\n"),
+             "bind",
+             GNUNET_a2s (server_addr, socklen));
+      }
+    }
+    GNUNET_break (GNUNET_OK ==
+                 GNUNET_NETWORK_socket_close (sock));
+    errno = eno;
+    return NULL;
+  }
+  if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock,
+                                                5))
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                  "listen");
+    GNUNET_break (GNUNET_OK ==
+                 GNUNET_NETWORK_socket_close (sock));
+    errno = 0;
+    return NULL;
+  }
+  if (0 != port)
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Server starts to listen on port %u.\n",
+         port);
+  return sock;
+}
+
+
+/**
+ * Setup service handle
+ *
+ * Configuration may specify:
+ * - PORT (where to bind to for TCP)
+ * - UNIXPATH (where to bind to for UNIX domain sockets)
+ * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
+ * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
+ * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
+ * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
+ * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
+ * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
+ *
+ * @param sh service context to initialize
+ * @return #GNUNET_OK if configuration succeeded
+ */
+static int
+setup_service (struct GNUNET_SERVICE_Handle *sh)
+{
+  int tolerant;
+  struct GNUNET_NETWORK_Handle **lsocks;
+#ifndef MINGW
+  const char *nfds;
+  unsigned int cnt;
+  int flags;
+#endif
+
+  if (GNUNET_CONFIGURATION_have_value
+      (sh->cfg,
+       sh->service_name,
+       "TOLERANT"))
+  {
+    if (GNUNET_SYSERR ==
         (tolerant =
-         GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+         GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
+                                              sh->service_name,
                                                "TOLERANT")))
     {
       LOG (GNUNET_ERROR_TYPE_ERROR,
            _("Specified value for `%s' of service `%s' is invalid\n"),
-           "TOLERANT", sctx->service_name);
+           "TOLERANT",
+          sh->service_name);
       return GNUNET_SYSERR;
     }
   }
   else
     tolerant = GNUNET_NO;
 
+  lsocks = NULL;
 #ifndef MINGW
   errno = 0;
-  if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
-      (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
-      (cnt + 4 < FD_SETSIZE))
+  if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
+       (1 == SSCANF (nfds,
+                    "%u",
+                    &cnt)) &&
+       (cnt > 0) &&
+       (cnt < FD_SETSIZE) &&
+       (cnt + 4 < FD_SETSIZE) )
   {
-    sctx->lsocks =
-        GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1));
+    lsocks = GNUNET_new_array (cnt + 1,
+                              struct GNUNET_NETWORK_Handle *);
     while (0 < cnt--)
     {
-      flags = fcntl (3 + cnt, F_GETFD);
-      if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
-          (NULL ==
-           (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
+      flags = fcntl (3 + cnt,
+                    F_GETFD);
+      if ( (flags < 0) ||
+          (0 != (flags & FD_CLOEXEC)) ||
+          (NULL ==
+           (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
       {
         LOG (GNUNET_ERROR_TYPE_ERROR,
-             _
-             ("Could not access pre-bound socket %u, will try to bind myself\n"),
+             _("Could not access pre-bound socket %u, will try to bind myself\n"),
              (unsigned int) 3 + cnt);
         cnt++;
-        while (sctx->lsocks[cnt] != NULL)
-          GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
-        GNUNET_free (sctx->lsocks);
-        sctx->lsocks = NULL;
+        while (NULL != lsocks[cnt])
+          GNUNET_break (GNUNET_OK ==
+                       GNUNET_NETWORK_socket_close (lsocks[cnt++]));
+        GNUNET_free (lsocks);
+        lsocks = NULL;
         break;
       }
     }
     unsetenv ("LISTEN_FDS");
   }
 #else
-  if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL)
+  if (NULL != getenv ("GNUNET_OS_READ_LSOCKS"))
   {
-    receive_sockets_from_parent (sctx);
+    lsocks = receive_sockets_from_parent (sh);
     putenv ("GNUNET_OS_READ_LSOCKS=");
   }
 #endif
 
-  if ((NULL == sctx->lsocks) &&
-      (GNUNET_SYSERR ==
-       GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg,
-                                            &sctx->addrs, &sctx->addrlens)))
-    return GNUNET_SYSERR;
-  sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
-  sctx->match_uid =
-      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+  if (NULL != lsocks)
+  {
+    /* listen only on inherited sockets if we have any */
+    struct GNUNET_NETWORK_Handle **ls;
+
+    for (ls = lsocks; NULL != *ls; ls++)
+    {
+      struct ServiceListenContext *slc;
+
+      slc = GNUNET_new (struct ServiceListenContext);
+      slc->sh = sh;
+      slc->listen_socket = *ls;
+      GNUNET_CONTAINER_DLL_insert (sh->slc_head,
+                                  sh->slc_tail,
+                                  slc);
+    }
+    GNUNET_free (lsocks);
+  }
+  else
+  {
+    struct sockaddr **addrs;
+    socklen_t *addrlens;
+    int num;
+
+    num = get_server_addresses (sh->service_name,
+                               sh->cfg,
+                               &addrs,
+                               &addrlens);
+    if (GNUNET_SYSERR == num)
+      return GNUNET_SYSERR;
+
+    for (int i = 0; i < num; i++)
+    {
+      struct ServiceListenContext *slc;
+
+      slc = GNUNET_new (struct ServiceListenContext);
+      slc->sh = sh;
+      slc->listen_socket = open_listen_socket (addrs[i],
+                                              addrlens[i]);
+      if (NULL == slc->listen_socket)
+      {
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+                             "bind");
+        GNUNET_free (addrs[i++]);
+        GNUNET_free (slc);
+        continue;
+      }
+      GNUNET_free (addrs[i++]);
+      GNUNET_CONTAINER_DLL_insert (sh->slc_head,
+                                  sh->slc_tail,
+                                  slc);
+    }
+    GNUNET_free_non_null (addrlens);
+    GNUNET_free_non_null (addrs);
+    if ( (0 != num) &&
+         (NULL == sh->slc_head) )
+    {
+      /* All attempts to bind failed, hard failure */
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  _("Could not bind to any of the ports I was supposed to, refusing to run!\n"));
+      return GNUNET_SYSERR;
+    }
+  }
+
+  sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
+  sh->match_uid
+    = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
+                                           sh->service_name,
                                             "UNIX_MATCH_UID");
-  sctx->match_gid =
-      GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name,
+  sh->match_gid
+    = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
+                                           sh->service_name,
                                             "UNIX_MATCH_GID");
-  process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
-  process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
-  process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
-  process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
-
+  process_acl4 (&sh->v4_denied,
+               sh,
+               "REJECT_FROM");
+  process_acl4 (&sh->v4_allowed,
+               sh,
+               "ACCEPT_FROM");
+  process_acl6 (&sh->v6_denied,
+               sh,
+               "REJECT_FROM6");
+  process_acl6 (&sh->v6_allowed,
+               sh,
+               "ACCEPT_FROM6");
   return GNUNET_OK;
 }
 
@@ -1046,185 +1337,129 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
  * Get the name of the user that'll be used
  * to provide the service.
  *
- * @param sctx service context
+ * @param sh service context
  * @return value of the 'USERNAME' option
  */
 static char *
-get_user_name (struct GNUNET_SERVICE_Context *sctx)
+get_user_name (struct GNUNET_SERVICE_Handle *sh)
 {
   char *un;
 
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name,
-                                               "USERNAME", &un))
+      GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
+                                              sh->service_name,
+                                               "USERNAME",
+                                              &un))
     return NULL;
   return un;
 }
 
 
 /**
- * Write PID file.
+ * Set user ID.
  *
- * @param sctx service context
- * @param pid PID to write (should be equal to 'getpid()'
- * @return  #GNUNET_OK on success (including no work to be done)
+ * @param sh service context
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
-write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid)
+set_user_id (struct GNUNET_SERVICE_Handle *sh)
 {
-  FILE *pidfd;
-  char *pif;
   char *user;
-  char *rdir;
-  int len;
-
-  if (NULL == (pif = get_pid_file_name (sctx)))
-    return GNUNET_OK;           /* no file desired */
-  user = get_user_name (sctx);
-  rdir = GNUNET_strdup (pif);
-  len = strlen (rdir);
-  while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
-    len--;
-  rdir[len] = '\0';
-  if (0 != ACCESS (rdir, F_OK))
-  {
-    /* we get to create a directory -- and claim it
-     * as ours! */
-    (void) GNUNET_DISK_directory_create (rdir);
-    if ((NULL != user) && (0 < strlen (user)))
-      GNUNET_DISK_file_change_owner (rdir, user);
-  }
-  if (0 != ACCESS (rdir, W_OK | X_OK))
-  {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
-    GNUNET_free (rdir);
-    GNUNET_free_non_null (user);
-    GNUNET_free (pif);
+
+  if (NULL == (user = get_user_name (sh)))
+    return GNUNET_OK;           /* keep */
+#ifndef MINGW
+  struct passwd *pws;
+
+  errno = 0;
+  pws = getpwnam (user);
+  if (NULL == pws)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Cannot obtain information about user `%s': %s\n"),
+        user,
+         errno == 0 ? _("No such user") : STRERROR (errno));
+    GNUNET_free (user);
     return GNUNET_SYSERR;
   }
-  GNUNET_free (rdir);
-  pidfd = FOPEN (pif, "w");
-  if (NULL == pidfd)
+  if ( (0 != setgid (pws->pw_gid)) ||
+       (0 != setegid (pws->pw_gid)) ||
+#if HAVE_INITGROUPS
+       (0 != initgroups (user,
+                        pws->pw_gid)) ||
+#endif
+       (0 != setuid (pws->pw_uid)) ||
+       (0 != seteuid (pws->pw_uid)))
   {
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
-    GNUNET_free (pif);
-    GNUNET_free_non_null (user);
-    return GNUNET_SYSERR;
+    if ((0 != setregid (pws->pw_gid,
+                       pws->pw_gid)) ||
+        (0 != setreuid (pws->pw_uid,
+                       pws->pw_uid)))
+    {
+      LOG (GNUNET_ERROR_TYPE_ERROR,
+          _("Cannot change user/group to `%s': %s\n"),
+           user,
+          STRERROR (errno));
+      GNUNET_free (user);
+      return GNUNET_SYSERR;
+    }
   }
-  if (0 > FPRINTF (pidfd, "%u", pid))
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
-  GNUNET_break (0 == FCLOSE (pidfd));
-  if ((NULL != user) && (0 < strlen (user)))
-    GNUNET_DISK_file_change_owner (pif, user);
-  GNUNET_free_non_null (user);
-  GNUNET_free (pif);
+#endif
+  GNUNET_free (user);
   return GNUNET_OK;
 }
 
 
 /**
- * Task run during shutdown.  Stops the server/service.
+ * Get the name of the file where we will
+ * write the PID of the service.
  *
- * @param cls the `struct GNUNET_SERVICE_Context`
+ * @param sh service context
+ * @return name of the file for the process ID
  */
-static void
-shutdown_task (void *cls)
+static char *
+get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
 {
-  struct GNUNET_SERVICE_Context *service = cls;
-  struct GNUNET_SERVER_Handle *server = service->server;
+  char *pif;
 
-  service->shutdown_task = NULL;
-  if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN))
-    GNUNET_SERVER_stop_listening (server);
-  else
-    GNUNET_SERVER_destroy (server);
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
+                                              sh->service_name,
+                                               "PIDFILE",
+                                              &pif))
+    return NULL;
+  return pif;
 }
 
 
 /**
- * Initial task for the service.
+ * Delete the PID file that was created by our parent.
  *
- * @param cls service context
+ * @param sh service context
  */
 static void
-service_task (void *cls)
+pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
 {
-  struct GNUNET_SERVICE_Context *sctx = cls;
-  unsigned int i;
-
-  (void) GNUNET_SPEEDUP_start_ (sctx->cfg);
-  GNUNET_RESOLVER_connect (sctx->cfg);
-  if (NULL != sctx->lsocks)
-    sctx->server
-      = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
-                                           sctx->timeout, sctx->require_found);
-  else
-    sctx->server
-      = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
-                              sctx->timeout, sctx->require_found);
-  if (NULL == sctx->server)
-  {
-    if (NULL != sctx->addrs)
-      for (i = 0; NULL != sctx->addrs[i]; i++)
-        LOG (GNUNET_ERROR_TYPE_INFO,
-             _("Failed to start `%s' at `%s'\n"),
-             sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
-    sctx->ret = GNUNET_SYSERR;
-    return;
-  }
-#ifndef WINDOWS
-  if (NULL != sctx->addrs)
-    for (i = 0; NULL != sctx->addrs[i]; i++)
-      if ((AF_UNIX == sctx->addrs[i]->sa_family)
-          && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
-        GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
-                                     sctx->match_uid,
-                                     sctx->match_gid);
-#endif
-
+  char *pif = get_pid_file_name (sh);
 
-  if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN))
-  {
-    /* install a task that will kill the server
-     * process if the scheduler ever gets a shutdown signal */
-    sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
-                                                        sctx);
-  }
-  sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
-  GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
-  i = 0;
-  while (NULL != sctx->my_handlers[i].callback)
-    sctx->my_handlers[i++].callback_cls = sctx;
-  GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
-  if (-1 != sctx->ready_confirm_fd)
-  {
-    GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1));
-    GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd));
-    sctx->ready_confirm_fd = -1;
-    write_pid_file (sctx, getpid ());
-  }
-  if (NULL != sctx->addrs)
-  {
-    i = 0;
-    while (NULL != sctx->addrs[i])
-    {
-      LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"),
-           sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
-      i++;
-    }
-  }
-  sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
+  if (NULL == pif)
+    return;                     /* no PID file */
+  if (0 != UNLINK (pif))
+    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
+                      "unlink",
+                      pif);
+  GNUNET_free (pif);
 }
 
 
 /**
  * Detach from terminal.
  *
- * @param sctx service context
+ * @param sh service context
  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  */
 static int
-detach_terminal (struct GNUNET_SERVICE_Context *sctx)
+detach_terminal (struct GNUNET_SERVICE_Handle *sh)
 {
 #ifndef MINGW
   pid_t pid;
@@ -1233,13 +1468,15 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
 
   if (0 != PIPE (filedes))
   {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                 "pipe");
     return GNUNET_SYSERR;
   }
   pid = fork ();
   if (pid < 0)
   {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                 "fork");
     return GNUNET_SYSERR;
   }
   if (0 != pid)
@@ -1249,15 +1486,19 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
 
     GNUNET_break (0 == CLOSE (filedes[1]));
     c = 'X';
-    if (1 != READ (filedes[0], &c, sizeof (char)))
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
+    if (1 != READ (filedes[0],
+                  &c,
+                  sizeof (char)))
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+                   "read");
     fflush (stdout);
     switch (c)
     {
     case '.':
       exit (0);
     case 'I':
-      LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n"));
+      LOG (GNUNET_ERROR_TYPE_INFO,
+          _("Service process failed to initialize\n"));
       break;
     case 'S':
       LOG (GNUNET_ERROR_TYPE_INFO,
@@ -1273,13 +1514,16 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
   GNUNET_break (0 == CLOSE (0));
   GNUNET_break (0 == CLOSE (1));
   GNUNET_break (0 == CLOSE (filedes[0]));
-  nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND);
+  nullfd = OPEN ("/dev/null",
+                O_RDWR | O_APPEND);
   if (nullfd < 0)
     return GNUNET_SYSERR;
   /* set stdin/stdout to /dev/null */
-  if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
+  if ( (dup2 (nullfd, 0) < 0) ||
+       (dup2 (nullfd, 1) < 0) )
   {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                 "dup2");
     (void) CLOSE (nullfd);
     return GNUNET_SYSERR;
   }
@@ -1287,8 +1531,9 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
   /* Detach from controlling terminal */
   pid = setsid ();
   if (-1 == pid)
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
-  sctx->ready_confirm_fd = filedes[1];
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+                 "setsid");
+  sh->ready_confirm_fd = filedes[1];
 #else
   /* FIXME: we probably need to do something else
    * elsewhere in order to fork the process itself... */
@@ -1299,144 +1544,228 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx)
 
 
 /**
- * Set user ID.
+ * Tear down the service, closing the listen sockets and
+ * freeing the ACLs.
  *
- * @param sctx service context
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ * @param sh handle to the service to tear down.
  */
-static int
-set_user_id (struct GNUNET_SERVICE_Context *sctx)
+static void
+teardown_service (struct GNUNET_SERVICE_Handle *sh)
 {
-  char *user;
-
-  if (NULL == (user = get_user_name (sctx)))
-    return GNUNET_OK;           /* keep */
-#ifndef MINGW
-  struct passwd *pws;
+  struct ServiceListenContext *slc;
 
-  errno = 0;
-  pws = getpwnam (user);
-  if (NULL == pws)
+  GNUNET_free_non_null (sh->v4_denied);
+  GNUNET_free_non_null (sh->v6_denied);
+  GNUNET_free_non_null (sh->v4_allowed);
+  GNUNET_free_non_null (sh->v6_allowed);
+  while (NULL != (slc = sh->slc_head))
   {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("Cannot obtain information about user `%s': %s\n"), user,
-         errno == 0 ? _("No such user") : STRERROR (errno));
-    GNUNET_free (user);
-    return GNUNET_SYSERR;
+    GNUNET_CONTAINER_DLL_remove (sh->slc_head,
+                                 sh->slc_tail,
+                                 slc);
+    if (NULL != slc->listen_task)
+      GNUNET_SCHEDULER_cancel (slc->listen_task);
+    GNUNET_break (GNUNET_OK ==
+                 GNUNET_NETWORK_socket_close (slc->listen_socket));
+    GNUNET_free (slc);
   }
-  if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
-#if HAVE_INITGROUPS
-      (0 != initgroups (user, pws->pw_gid)) ||
-#endif
-      (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
+}
+
+
+/**
+ * Low-level function to start a service if the scheduler
+ * is already running.  Should only be used directly in
+ * special cases.
+ *
+ * The function will launch the service with the name @a service_name
+ * using the @a service_options to configure its shutdown
+ * behavior. When clients connect or disconnect, the respective
+ * @a connect_cb or @a disconnect_cb functions will be called. For
+ * messages received from the clients, the respective @a handlers will
+ * be invoked; for the closure of the handlers we use the return value
+ * from the @a connect_cb invocation of the respective client.
+ *
+ * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
+ * message to receive further messages from this client.  If
+ * #GNUNET_SERVICE_client_continue() is not called within a short
+ * time, a warning will be logged. If delays are expected, services
+ * should call #GNUNET_SERVICE_client_disable_continue_warning() to
+ * disable the warning.
+ *
+ * Clients sending invalid messages (based on @a handlers) will be
+ * dropped. Additionally, clients can be dropped at any time using
+ * #GNUNET_SERVICE_client_drop().
+ *
+ * The service must be stopped using #GNUNET_SERVICE_stop().
+ *
+ * @param service_name name of the service to run
+ * @param cfg configuration to use
+ * @param connect_cb function to call whenever a client connects
+ * @param disconnect_cb function to call whenever a client disconnects
+ * @param cls closure argument for @a connect_cb and @a disconnect_cb
+ * @param handlers NULL-terminated array of message handlers for the service,
+ *                 the closure will be set to the value returned by
+ *                 the @a connect_cb for the respective connection
+ * @return NULL on error
+ */
+struct GNUNET_SERVICE_Handle *
+GNUNET_SERVICE_start (const char *service_name,
+                      const struct GNUNET_CONFIGURATION_Handle *cfg,
+                      GNUNET_SERVICE_ConnectHandler connect_cb,
+                      GNUNET_SERVICE_DisconnectHandler disconnect_cb,
+                      void *cls,
+                      const struct GNUNET_MQ_MessageHandler *handlers)
+{
+  struct GNUNET_SERVICE_Handle *sh;
+
+  sh = GNUNET_new (struct GNUNET_SERVICE_Handle);
+  sh->service_name = service_name;
+  sh->cfg = cfg;
+  sh->connect_cb = connect_cb;
+  sh->disconnect_cb = disconnect_cb;
+  sh->cb_cls = cls;
+  sh->handlers = GNUNET_MQ_copy_handlers (handlers);
+  if (GNUNET_OK != setup_service (sh))
   {
-    if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
-        (0 != setreuid (pws->pw_uid, pws->pw_uid)))
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"),
-           user, STRERROR (errno));
-      GNUNET_free (user);
-      return GNUNET_SYSERR;
-    }
+    GNUNET_free_non_null (sh->handlers);
+    GNUNET_free (sh);
+    return NULL;
   }
-#endif
-  GNUNET_free (user);
-  return GNUNET_OK;
+  GNUNET_SERVICE_resume (sh);
+  return sh;
 }
 
 
 /**
- * Delete the PID file that was created by our parent.
+ * Stops a service that was started with #GNUNET_SERVICE_start().
  *
- * @param sctx service context
+ * @param srv service to stop
  */
-static void
-pid_file_delete (struct GNUNET_SERVICE_Context *sctx)
+void
+GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv)
 {
-  char *pif = get_pid_file_name (sctx);
-
-  if (NULL == pif)
-    return;                     /* no PID file */
-  if (0 != UNLINK (pif))
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
-  GNUNET_free (pif);
+  struct GNUNET_SERVICE_Client *client;
+
+  GNUNET_SERVICE_suspend (srv);
+  while (NULL != (client = srv->clients_head))
+    GNUNET_SERVICE_client_drop (client);
+  teardown_service (srv);
+  GNUNET_free_non_null (srv->handlers);
+  GNUNET_free (srv);
 }
 
 
 /**
- * Run a standard GNUnet service startup sequence (initialize loggers
- * and configuration, parse options).
+ * Creates the "main" function for a GNUnet service.  You
+ * should almost always use the #GNUNET_SERVICE_MAIN macro
+ * instead of calling this function directly (except
+ * for ARM, which should call this function directly).
+ *
+ * The function will launch the service with the name @a service_name
+ * using the @a service_options to configure its shutdown
+ * behavior. Once the service is ready, the @a init_cb will be called
+ * for service-specific initialization.  @a init_cb will be given the
+ * service handler which can be used to control the service's
+ * availability.  When clients connect or disconnect, the respective
+ * @a connect_cb or @a disconnect_cb functions will be called. For
+ * messages received from the clients, the respective @a handlers will
+ * be invoked; for the closure of the handlers we use the return value
+ * from the @a connect_cb invocation of the respective client.
+ *
+ * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
+ * message to receive further messages from this client.  If
+ * #GNUNET_SERVICE_client_continue() is not called within a short
+ * time, a warning will be logged. If delays are expected, services
+ * should call #GNUNET_SERVICE_client_disable_continue_warning() to
+ * disable the warning.
  *
- * @param argc number of command line arguments
- * @param argv command line arguments
- * @param service_name our service name
- * @param options service options
- * @param task main task of the service
- * @param task_cls closure for @a task
- * @return #GNUNET_SYSERR on error, #GNUNET_OK
- *         if we shutdown nicely
+ * Clients sending invalid messages (based on @a handlers) will be
+ * dropped. Additionally, clients can be dropped at any time using
+ * #GNUNET_SERVICE_client_drop().
+ *
+ * @param argc number of command-line arguments in @a argv
+ * @param argv array of command-line arguments
+ * @param service_name name of the service to run
+ * @param options options controlling shutdown of the service
+ * @param service_init_cb function to call once the service is ready
+ * @param connect_cb function to call whenever a client connects
+ * @param disconnect_cb function to call whenever a client disconnects
+ * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
+ * @param handlers NULL-terminated array of message handlers for the service,
+ *                 the closure will be set to the value returned by
+ *                 the @a connect_cb for the respective connection
+ * @return 0 on success, non-zero on error
  */
 int
-GNUNET_SERVICE_run (int argc, char *const *argv,
-                    const char *service_name,
-                    enum GNUNET_SERVICE_Options options,
-                    GNUNET_SERVICE_Main task,
-                    void *task_cls)
+GNUNET_SERVICE_run_ (int argc,
+                     char *const *argv,
+                     const char *service_name,
+                     enum GNUNET_SERVICE_Options options,
+                     GNUNET_SERVICE_InitCallback service_init_cb,
+                     GNUNET_SERVICE_ConnectHandler connect_cb,
+                     GNUNET_SERVICE_DisconnectHandler disconnect_cb,
+                     void *cls,
+                     const struct GNUNET_MQ_MessageHandler *handlers)
 {
-#define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0)
-
-  int err;
-  int ret;
-  char *cfg_fn;
-  char *opt_cfg_fn;
+  struct GNUNET_SERVICE_Handle sh;
+  char *cfg_filename;
+  char *opt_cfg_filename;
   char *loglev;
+  const char *xdg;
   char *logfile;
   int do_daemonize;
-  unsigned int i;
   unsigned long long skew_offset;
   unsigned long long skew_variance;
   long long clock_offset;
-  struct GNUNET_SERVICE_Context sctx;
   struct GNUNET_CONFIGURATION_Handle *cfg;
-  const char *xdg;
+  int ret;
+  int err;
 
   struct GNUNET_GETOPT_CommandLineOption service_options[] = {
-    GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn),
-    {'d', "daemonize", NULL,
-     gettext_noop ("do daemonize (detach from terminal)"), 0,
-     GNUNET_GETOPT_set_one, &do_daemonize},
+    GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_filename),
+    GNUNET_GETOPT_OPTION_SET_ONE ('d',
+                                  "daemonize",
+                                  gettext_noop ("do daemonize (detach from terminal)"),
+                                  &do_daemonize),
     GNUNET_GETOPT_OPTION_HELP (NULL),
     GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
     GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
     GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
     GNUNET_GETOPT_OPTION_END
   };
+
   err = 1;
-  do_daemonize = 0;
-  logfile = NULL;
-  loglev = NULL;
-  opt_cfg_fn = NULL;
+  memset (&sh,
+         0,
+         sizeof (sh));
   xdg = getenv ("XDG_CONFIG_HOME");
   if (NULL != xdg)
-    GNUNET_asprintf (&cfg_fn,
+    GNUNET_asprintf (&cfg_filename,
                      "%s%s%s",
                      xdg,
                      DIR_SEPARATOR_STR,
                      GNUNET_OS_project_data_get ()->config_file);
   else
-    cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
-  memset (&sctx, 0, sizeof (sctx));
-  sctx.options = options;
-  sctx.ready_confirm_fd = -1;
-  sctx.ret = GNUNET_OK;
-  sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-  sctx.task = task;
-  sctx.task_cls = task_cls;
-  sctx.service_name = service_name;
-  sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
+    cfg_filename = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
+  sh.ready_confirm_fd = -1;
+  sh.options = options;
+  sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
+  sh.service_init_cb = service_init_cb;
+  sh.connect_cb = connect_cb;
+  sh.disconnect_cb = disconnect_cb;
+  sh.cb_cls = cls;
+  sh.handlers = GNUNET_MQ_copy_handlers (handlers);
+  sh.service_name = service_name;
 
   /* setup subsystems */
-  ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
+  loglev = NULL;
+  logfile = NULL;
+  opt_cfg_filename = NULL;
+  do_daemonize = 0;
+  ret = GNUNET_GETOPT_run (service_name,
+                          service_options,
+                          argc,
+                          argv);
   if (GNUNET_SYSERR == ret)
     goto shutdown;
   if (GNUNET_NO == ret)
@@ -1444,254 +1773,844 @@ GNUNET_SERVICE_run (int argc, char *const *argv,
     err = 0;
     goto shutdown;
   }
-  if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
-    HANDLE_ERROR;
-  if (NULL == opt_cfg_fn)
-    opt_cfg_fn = GNUNET_strdup (cfg_fn);
-  if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
+  if (GNUNET_OK != GNUNET_log_setup (service_name,
+                                    loglev,
+                                    logfile))
   {
-    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
+    GNUNET_break (0);
+    goto shutdown;
+  }
+  if (NULL == opt_cfg_filename)
+    opt_cfg_filename = GNUNET_strdup (cfg_filename);
+  if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename))
+  {
+    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
+                                                   opt_cfg_filename))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("Malformed configuration file `%s', exit ...\n"),
-                  opt_cfg_fn);
+                  opt_cfg_filename);
       goto shutdown;
     }
   }
   else
   {
-    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
+    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
+                                                   NULL))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("Malformed configuration, exit ...\n"));
       goto shutdown;
     }
-    if (0 != strcmp (opt_cfg_fn, cfg_fn))
+    if (0 != strcmp (opt_cfg_filename,
+                    cfg_filename))
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                  _("Could not access configuration file `%s'\n"),
-                 opt_cfg_fn);
+                 opt_cfg_filename);
   }
-  if (GNUNET_OK != setup_service (&sctx))
+  if (GNUNET_OK != setup_service (&sh))
+    goto shutdown;
+  if ( (1 == do_daemonize) &&
+       (GNUNET_OK != detach_terminal (&sh)) )
+  {
+    GNUNET_break (0);
     goto shutdown;
-  if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
-    HANDLE_ERROR;
-  if (GNUNET_OK != set_user_id (&sctx))
+  }
+  if (GNUNET_OK != set_user_id (&sh))
     goto shutdown;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Service `%s' runs with configuration from `%s'\n",
        service_name,
-       opt_cfg_fn);
+       opt_cfg_filename);
   if ((GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
-                                              "SKEW_OFFSET", &skew_offset)) &&
+       GNUNET_CONFIGURATION_get_value_number (sh.cfg,
+                                             "TESTING",
+                                              "SKEW_OFFSET",
+                                             &skew_offset)) &&
       (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING",
-                                              "SKEW_VARIANCE", &skew_variance)))
+       GNUNET_CONFIGURATION_get_value_number (sh.cfg,
+                                             "TESTING",
+                                              "SKEW_VARIANCE",
+                                             &skew_variance)))
   {
     clock_offset = skew_offset - skew_variance;
     GNUNET_TIME_set_offset (clock_offset);
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset);
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Skewing clock by %dll ms\n",
+        clock_offset);
   }
+  GNUNET_RESOLVER_connect (sh.cfg);
+
   /* actually run service */
   err = 0;
-  GNUNET_SCHEDULER_run (&service_task, &sctx);
+  GNUNET_SCHEDULER_run (&service_main,
+                       &sh);
   /* shutdown */
-  if ((1 == do_daemonize) && (NULL != sctx.server))
-    pid_file_delete (&sctx);
-  GNUNET_free_non_null (sctx.my_handlers);
+  if (1 == do_daemonize)
+    pid_file_delete (&sh);
 
 shutdown:
-  if (-1 != sctx.ready_confirm_fd)
+  if (-1 != sh.ready_confirm_fd)
   {
-    if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1))
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
-    GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd));
+    if (1 != WRITE (sh.ready_confirm_fd,
+                   err ? "I" : "S",
+                   1))
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+                   "write");
+    GNUNET_break (0 == CLOSE (sh.ready_confirm_fd));
   }
 #if HAVE_MALLINFO
   {
     char *counter;
 
     if ( (GNUNET_YES ==
-         GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name,
+         GNUNET_CONFIGURATION_have_value (sh.cfg,
+                                          service_name,
                                           "GAUGER_HEAP")) &&
         (GNUNET_OK ==
-         GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name,
+         GNUNET_CONFIGURATION_get_value_string (sh.cfg,
+                                                service_name,
                                                 "GAUGER_HEAP",
                                                 &counter)) )
     {
       struct mallinfo mi;
 
       mi = mallinfo ();
-      GAUGER (service_name, counter, mi.usmblks, "blocks");
+      GAUGER (service_name,
+             counter,
+             mi.usmblks,
+             "blocks");
       GNUNET_free (counter);
     }
   }
 #endif
+  teardown_service (&sh);
+  GNUNET_free_non_null (sh.handlers);
   GNUNET_SPEEDUP_stop_ ();
   GNUNET_CONFIGURATION_destroy (cfg);
-  i = 0;
-  if (NULL != sctx.addrs)
-    while (NULL != sctx.addrs[i])
-      GNUNET_free (sctx.addrs[i++]);
-  GNUNET_free_non_null (sctx.addrs);
-  GNUNET_free_non_null (sctx.addrlens);
   GNUNET_free_non_null (logfile);
   GNUNET_free_non_null (loglev);
-  GNUNET_free (cfg_fn);
-  GNUNET_free_non_null (opt_cfg_fn);
-  GNUNET_free_non_null (sctx.v4_denied);
-  GNUNET_free_non_null (sctx.v6_denied);
-  GNUNET_free_non_null (sctx.v4_allowed);
-  GNUNET_free_non_null (sctx.v6_allowed);
-
-  return err ? GNUNET_SYSERR : sctx.ret;
+  GNUNET_free (cfg_filename);
+  GNUNET_free_non_null (opt_cfg_filename);
+
+  return err ? GNUNET_SYSERR : sh.ret;
 }
 
 
 /**
- * Run a service startup sequence within an existing
- * initialized system.
+ * Suspend accepting connections from the listen socket temporarily.
+ * Resume activity using #GNUNET_SERVICE_resume.
  *
- * @param service_name our service name
- * @param cfg configuration to use
- * @param options service options
- * @return NULL on error, service handle
+ * @param sh service to stop accepting connections.
  */
-struct GNUNET_SERVICE_Context *
-GNUNET_SERVICE_start (const char *service_name,
-                      const struct GNUNET_CONFIGURATION_Handle *cfg,
-                     enum GNUNET_SERVICE_Options options)
+void
+GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
 {
-  int i;
-  struct GNUNET_SERVICE_Context *sctx;
+  struct ServiceListenContext *slc;
 
-  sctx = GNUNET_new (struct GNUNET_SERVICE_Context);
-  sctx->ready_confirm_fd = -1;  /* no daemonizing */
-  sctx->ret = GNUNET_OK;
-  sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
-  sctx->service_name = service_name;
-  sctx->cfg = cfg;
-  sctx->options = options;
+  for (slc = sh->slc_head; NULL != slc; slc = slc->next)
+  {
+    if (NULL != slc->listen_task)
+    {
+      GNUNET_SCHEDULER_cancel (slc->listen_task);
+      slc->listen_task = NULL;
+    }
+  }
+}
 
-  /* setup subsystems */
-  if (GNUNET_OK != setup_service (sctx))
+
+/**
+ * Task run when we are ready to transmit data to the
+ * client.
+ *
+ * @param cls the `struct GNUNET_SERVICE_Client *` to send to
+ */
+static void
+do_send (void *cls)
+{
+  struct GNUNET_SERVICE_Client *client = cls;
+  ssize_t ret;
+  size_t left;
+  const char *buf;
+
+  client->send_task = NULL;
+  buf = (const char *) client->msg;
+  left = ntohs (client->msg->size) - client->msg_pos;
+  ret = GNUNET_NETWORK_socket_send (client->sock,
+                                   &buf[client->msg_pos],
+                                   left);
+  GNUNET_assert (ret <= (ssize_t) left);
+  if (0 == ret)
   {
-    GNUNET_SERVICE_stop (sctx);
-    return NULL;
+    GNUNET_MQ_inject_error (client->mq,
+                           GNUNET_MQ_ERROR_WRITE);
+    return;
   }
-  if (NULL != sctx->lsocks)
-    sctx->server =
-        GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks,
-                                           sctx->timeout, sctx->require_found);
-  else
-    sctx->server =
-        GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens,
-                              sctx->timeout, sctx->require_found);
+  if (-1 == ret)
+  {
+    if ( (EAGAIN == errno) ||
+        (EINTR == errno) )
+    {
+      /* ignore */
+      ret = 0;
+    }
+    else
+    {
+      if (EPIPE != errno)
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "send");
+      GNUNET_MQ_inject_error (client->mq,
+                             GNUNET_MQ_ERROR_WRITE);
+      return;
+    }
+  }
+  if (0 == client->msg_pos)
+  {
+    GNUNET_MQ_impl_send_in_flight (client->mq);
+  }
+  client->msg_pos += ret;
+  if (left > ret)
+  {
+    GNUNET_assert (NULL == client->drop_task);
+    client->send_task
+      = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                       client->sock,
+                                       &do_send,
+                                       client);
+    return;
+  }
+  GNUNET_MQ_impl_send_continue (client->mq);
+}
+
 
-  if (NULL == sctx->server)
+/**
+ * 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 our `struct GNUNET_SERVICE_Client *`
+ */
+static void
+service_mq_send (struct GNUNET_MQ_Handle *mq,
+                 const struct GNUNET_MessageHeader *msg,
+                 void *impl_state)
+{
+  struct GNUNET_SERVICE_Client *client = impl_state;
+
+  if (NULL != client->drop_task)
+    return; /* we're going down right now, do not try to send */
+  GNUNET_assert (NULL == client->send_task);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Sending message of type %u and size %u to client\n",
+       ntohs (msg->type),
+       ntohs (msg->size));
+  client->msg = msg;
+  client->msg_pos = 0;
+  client->send_task
+    = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                     client->sock,
+                                     &do_send,
+                                     client);
+}
+
+
+/**
+ * Implementation function that cancels the currently sent message.
+ *
+ * @param mq message queue
+ * @param impl_state state specific to the implementation
+ */
+static void
+service_mq_cancel (struct GNUNET_MQ_Handle *mq,
+                   void *impl_state)
+{
+  struct GNUNET_SERVICE_Client *client = impl_state;
+
+  GNUNET_assert (0 == client->msg_pos);
+  client->msg = NULL;
+  GNUNET_SCHEDULER_cancel (client->send_task);
+  client->send_task = NULL;
+}
+
+
+/**
+ * Generic error handler, called with the appropriate
+ * error code and the same closure specified at the creation of
+ * the message queue.
+ * Not every message queue implementation supports an error handler.
+ *
+ * @param cls closure with our `struct GNUNET_SERVICE_Client`
+ * @param error error code
+ */
+static void
+service_mq_error_handler (void *cls,
+                          enum GNUNET_MQ_Error error)
+{
+  struct GNUNET_SERVICE_Client *client = cls;
+  struct GNUNET_SERVICE_Handle *sh = client->sh;
+
+  if ( (GNUNET_MQ_ERROR_NO_MATCH == error) &&
+       (GNUNET_NO == sh->require_found) )
   {
-    GNUNET_SERVICE_stop (sctx);
-    return NULL;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "No handler for message of type %u found\n",
+                (unsigned int) client->warn_type);
+    GNUNET_SERVICE_client_continue (client);
+    return; /* ignore error */
+  }
+  GNUNET_SERVICE_client_drop (client);
+}
+
+
+/**
+ * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue().
+ *
+ * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from
+ */
+static void
+warn_no_client_continue (void *cls)
+{
+  struct GNUNET_SERVICE_Client *client = cls;
+
+  GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
+  client->warn_task
+    = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+                                    &warn_no_client_continue,
+                                   client);
+  LOG (GNUNET_ERROR_TYPE_WARNING,
+       _("Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"),
+       (unsigned int) client->warn_type,
+       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
+                                              GNUNET_YES));
+}
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer for a client.
+ *
+ * Do not call #GNUNET_MST_destroy() from within
+ * the scope of this callback.
+ *
+ * @param cls closure with the `struct GNUNET_SERVICE_Client *`
+ * @param message the actual message
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped
+ */
+static int
+service_client_mst_cb (void *cls,
+                       const struct GNUNET_MessageHeader *message)
+{
+  struct GNUNET_SERVICE_Client *client = cls;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Received message of type %u and size %u from client\n",
+       ntohs (message->type),
+       ntohs (message->size));
+  GNUNET_assert (GNUNET_NO == client->needs_continue);
+  client->needs_continue = GNUNET_YES;
+  client->warn_type = ntohs (message->type);
+  client->warn_start = GNUNET_TIME_absolute_get ();
+  GNUNET_assert (NULL == client->warn_task);
+  client->warn_task
+    = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
+                                   &warn_no_client_continue,
+                                   client);
+  GNUNET_MQ_inject_message (client->mq,
+                            message);
+  if (NULL != client->drop_task)
+    return GNUNET_SYSERR;
+  return GNUNET_OK;
+}
+
+
+/**
+ * A client sent us data. Receive and process it.  If we are done,
+ * reschedule this task.
+ *
+ * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
+ */
+static void
+service_client_recv (void *cls)
+{
+  struct GNUNET_SERVICE_Client *client = cls;
+  int ret;
+
+  client->recv_task = NULL;
+  ret = GNUNET_MST_read (client->mst,
+                        client->sock,
+                        GNUNET_NO,
+                        GNUNET_YES);
+  if (GNUNET_SYSERR == ret)
+  {
+    /* client closed connection (or IO error) */
+    if (NULL == client->drop_task)
+    {
+      GNUNET_assert (GNUNET_NO == client->needs_continue);
+      GNUNET_SERVICE_client_drop (client);
+    }
+    return;
+  }
+  if (GNUNET_NO == ret)
+    return; /* more messages in buffer, wait for application
+              to be done processing */
+  GNUNET_assert (GNUNET_OK == ret);
+  if (GNUNET_YES == client->needs_continue)
+    return;
+  if (NULL != client->recv_task)
+    return;
+  /* MST needs more data, re-schedule read job */
+  client->recv_task
+    = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                    client->sock,
+                                    &service_client_recv,
+                                    client);
+}
+
+
+/**
+ * We have successfully accepted a connection from a client.  Now
+ * setup the client (with the scheduler) and tell the application.
+ *
+ * @param sh service that accepted the client
+ * @param sock socket associated with the client
+ */
+static void
+start_client (struct GNUNET_SERVICE_Handle *sh,
+              struct GNUNET_NETWORK_Handle *csock)
+{
+  struct GNUNET_SERVICE_Client *client;
+
+  client = GNUNET_new (struct GNUNET_SERVICE_Client);
+  GNUNET_CONTAINER_DLL_insert (sh->clients_head,
+                               sh->clients_tail,
+                               client);
+  client->sh = sh;
+  client->sock = csock;
+  client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
+                                              NULL,
+                                              &service_mq_cancel,
+                                              client,
+                                              sh->handlers,
+                                              &service_mq_error_handler,
+                                              client);
+  client->mst = GNUNET_MST_create (&service_client_mst_cb,
+                                  client);
+  if (NULL != sh->connect_cb)
+    client->user_context = sh->connect_cb (sh->cb_cls,
+                                           client,
+                                           client->mq);
+  GNUNET_MQ_set_handlers_closure (client->mq,
+                                  client->user_context);
+  client->recv_task
+    = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                    client->sock,
+                                    &service_client_recv,
+                                    client);
+}
+
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param add the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
+                   const struct in_addr *add)
+{
+  unsigned int i;
+
+  if (NULL == list)
+    return GNUNET_NO;
+  i = 0;
+  while ( (0 != list[i].network.s_addr) ||
+         (0 != list[i].netmask.s_addr) )
+  {
+    if ((add->s_addr & list[i].netmask.s_addr) ==
+        (list[i].network.s_addr & list[i].netmask.s_addr))
+      return GNUNET_YES;
+    i++;
+  }
+  return GNUNET_NO;
+}
+
+
+/**
+ * Check if the given IP address is in the list of IP addresses.
+ *
+ * @param list a list of networks
+ * @param ip the IP to check (in network byte order)
+ * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
+ */
+static int
+check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
+                   const struct in6_addr *ip)
+{
+  unsigned int i;
+  unsigned int j;
+  struct in6_addr zero;
+
+  if (NULL == list)
+    return GNUNET_NO;
+  memset (&zero,
+         0,
+         sizeof (struct in6_addr));
+  i = 0;
+NEXT:
+  while (0 != memcmp (&zero,
+                     &list[i].network,
+                     sizeof (struct in6_addr)))
+  {
+    for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
+      if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
+          (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
+      {
+        i++;
+        goto NEXT;
+      }
+    return GNUNET_YES;
   }
+  return GNUNET_NO;
+}
+
+
+/**
+ * We have a client. Accept the incoming socket(s) (and reschedule
+ * the listen task).
+ *
+ * @param cls the `struct ServiceListenContext` of the ready listen socket
+ */
+static void
+accept_client (void *cls)
+{
+  struct ServiceListenContext *slc = cls;
+  struct GNUNET_SERVICE_Handle *sh = slc->sh;
+
+  slc->listen_task = NULL;
+  while (1)
+  {
+    struct GNUNET_NETWORK_Handle *sock;
+    const struct sockaddr_in *v4;
+    const struct sockaddr_in6 *v6;
+    struct sockaddr_storage sa;
+    socklen_t addrlen;
+    int ok;
+
+    addrlen = sizeof (sa);
+    sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
+                                        (struct sockaddr *) &sa,
+                                        &addrlen);
+    if (NULL == sock)
+      break;
+    switch (sa.ss_family)
+    {
+    case AF_INET:
+      GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
+      v4 = (const struct sockaddr_in *) &sa;
+      ok = ( ( (NULL == sh->v4_allowed) ||
+              (check_ipv4_listed (sh->v4_allowed,
+                                  &v4->sin_addr))) &&
+            ( (NULL == sh->v4_denied) ||
+              (! check_ipv4_listed (sh->v4_denied,
+                                    &v4->sin_addr)) ) );
+      break;
+    case AF_INET6:
+      GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
+      v6 = (const struct sockaddr_in6 *) &sa;
+      ok = ( ( (NULL == sh->v6_allowed) ||
+              (check_ipv6_listed (sh->v6_allowed,
+                                  &v6->sin6_addr))) &&
+            ( (NULL == sh->v6_denied) ||
+              (! check_ipv6_listed (sh->v6_denied,
+                                    &v6->sin6_addr)) ) );
+      break;
 #ifndef WINDOWS
-  if (NULL != sctx->addrs)
-    for (i = 0; NULL != sctx->addrs[i]; i++)
-      if ((AF_UNIX == sctx->addrs[i]->sa_family)
-          && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0]))
-        GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path,
-                                     sctx->match_uid,
-                                     sctx->match_gid);
+    case AF_UNIX:
+      ok = GNUNET_OK;            /* controlled using file-system ACL now */
+      break;
 #endif
-  sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers));
-  GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers));
-  i = 0;
-  while ((sctx->my_handlers[i].callback != NULL))
-    sctx->my_handlers[i++].callback_cls = sctx;
-  GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
-  return sctx;
+    default:
+      LOG (GNUNET_ERROR_TYPE_WARNING,
+          _("Unknown address family %d\n"),
+          sa.ss_family);
+      return;
+    }
+    if (! ok)
+    {
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+          "Service rejected incoming connection from %s due to policy.\n",
+          GNUNET_a2s ((const struct sockaddr *) &sa,
+                      addrlen));
+      GNUNET_break (GNUNET_OK ==
+                   GNUNET_NETWORK_socket_close (sock));
+      continue;
+    }
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Service accepted incoming connection from %s.\n",
+        GNUNET_a2s ((const struct sockaddr *) &sa,
+                    addrlen));
+    start_client (slc->sh,
+                 sock);
+  }
+  slc->listen_task
+    = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                    slc->listen_socket,
+                                    &accept_client,
+                                    slc);
 }
 
 
 /**
- * Obtain the server used by a service.  Note that the server must NOT
- * be destroyed by the caller.
+ * Resume accepting connections from the listen socket.
  *
- * @param ctx the service context returned from the start function
- * @return handle to the server for this service, NULL if there is none
+ * @param sh service to resume accepting connections.
  */
-struct GNUNET_SERVER_Handle *
-GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx)
+void
+GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
 {
-  return ctx->server;
+  struct ServiceListenContext *slc;
+
+  for (slc = sh->slc_head; NULL != slc; slc = slc->next)
+  {
+    GNUNET_assert (NULL == slc->listen_task);
+    slc->listen_task
+      = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                      slc->listen_socket,
+                                      &accept_client,
+                                      slc);
+  }
 }
 
 
 /**
- * Get the NULL-terminated array of listen sockets for this service.
+ * Task run to resume receiving data from the client after
+ * the client called #GNUNET_SERVICE_client_continue().
  *
- * @param ctx service context to query
- * @return NULL if there are no listen sockets, otherwise NULL-terminated
- *              array of listen sockets.
+ * @param cls our `struct GNUNET_SERVICE_Client`
  */
-struct GNUNET_NETWORK_Handle *const*
-GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx)
+static void
+resume_client_receive (void *cls)
 {
-  return ctx->lsocks;
+  struct GNUNET_SERVICE_Client *c = cls;
+  int ret;
+
+  c->recv_task = NULL;
+  /* first, check if there is still something in the buffer */
+  ret = GNUNET_MST_next (c->mst,
+                        GNUNET_YES);
+  if (GNUNET_SYSERR == ret)
+  {
+    if (NULL != c->drop_task)
+      GNUNET_SERVICE_client_drop (c);
+    return;
+  }
+  if (GNUNET_NO == ret)
+    return; /* done processing, wait for more later */
+  GNUNET_assert (GNUNET_OK == ret);
+  if (GNUNET_YES == c->needs_continue)
+    return; /* #GNUNET_MST_next() did give a message to the client */
+  /* need to receive more data from the network first */
+  if (NULL != c->recv_task)
+    return;
+  c->recv_task
+    = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                    c->sock,
+                                    &service_client_recv,
+                                    c);
 }
 
 
 /**
- * Stop a service that was started with "GNUNET_SERVICE_start".
+ * Continue receiving further messages from the given client.
+ * Must be called after each message received.
  *
- * @param sctx the service context returned from the start function
+ * @param c the client to continue receiving from
  */
 void
-GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx)
+GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
 {
-  unsigned int i;
+  GNUNET_assert (GNUNET_YES == c->needs_continue);
+  GNUNET_assert (NULL == c->recv_task);
+  c->needs_continue = GNUNET_NO;
+  if (NULL != c->warn_task)
+  {
+    GNUNET_SCHEDULER_cancel (c->warn_task);
+    c->warn_task = NULL;
+  }
+  c->recv_task
+    = GNUNET_SCHEDULER_add_now (&resume_client_receive,
+                               c);
+}
 
-#if HAVE_MALLINFO
+
+/**
+ * Disable the warning the server issues if a message is not
+ * acknowledged in a timely fashion.  Use this call if a client is
+ * intentionally delayed for a while.  Only applies to the current
+ * message.
+ *
+ * @param c client for which to disable the warning
+ */
+void
+GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
+{
+  GNUNET_break (NULL != c->warn_task);
+  if (NULL != c->warn_task)
   {
-    char *counter;
+    GNUNET_SCHEDULER_cancel (c->warn_task);
+    c->warn_task = NULL;
+  }
+}
 
-    if ( (GNUNET_YES ==
-         GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name,
-                                          "GAUGER_HEAP")) &&
-        (GNUNET_OK ==
-         GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name,
-                                                "GAUGER_HEAP",
-                                                &counter)) )
-    {
-      struct mallinfo mi;
 
-      mi = mallinfo ();
-      GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
-      GNUNET_free (counter);
-    }
+/**
+ * Asynchronously finish dropping the client.
+ *
+ * @param cls the `struct GNUNET_SERVICE_Client`.
+ */
+static void
+finish_client_drop (void *cls)
+{
+  struct GNUNET_SERVICE_Client *c = cls;
+  struct GNUNET_SERVICE_Handle *sh = c->sh;
+
+  c->drop_task = NULL;
+  GNUNET_assert (NULL == c->send_task);
+  GNUNET_assert (NULL == c->recv_task);
+  GNUNET_assert (NULL == c->warn_task);
+  GNUNET_MST_destroy (c->mst);
+  GNUNET_MQ_destroy (c->mq);
+  if (GNUNET_NO == c->persist)
+  {
+    GNUNET_break (GNUNET_OK ==
+                 GNUNET_NETWORK_socket_close (c->sock));
   }
-#endif
-  if (NULL != sctx->shutdown_task)
+  else
+  {
+    GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
+  }
+  GNUNET_free (c);
+  if ( (GNUNET_YES == sh->got_shutdown) &&
+       (GNUNET_NO == have_non_monitor_clients (sh)) )
+    GNUNET_SERVICE_shutdown (sh);
+}
+
+
+/**
+ * Ask the server to disconnect from the given client.  This is the
+ * same as returning #GNUNET_SYSERR within the check procedure when
+ * handling a message, wexcept that it allows dropping of a client even
+ * when not handling a message from that client.  The `disconnect_cb`
+ * will be called on @a c even if the application closes the connection
+ * using this function.
+ *
+ * @param c client to disconnect now
+ */
+void
+GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
+{
+  struct GNUNET_SERVICE_Handle *sh = c->sh;
+
+  if (NULL != c->drop_task)
   {
-    GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
-    sctx->shutdown_task = NULL;
+    /* asked to drop twice! */
+    GNUNET_assert (0);
+    return;
   }
-  if (NULL != sctx->server)
-    GNUNET_SERVER_destroy (sctx->server);
-  GNUNET_free_non_null (sctx->my_handlers);
-  if (NULL != sctx->addrs)
+  GNUNET_CONTAINER_DLL_remove (sh->clients_head,
+                               sh->clients_tail,
+                               c);
+  if (NULL != sh->disconnect_cb)
+    sh->disconnect_cb (sh->cb_cls,
+                       c,
+                       c->user_context);
+  if (NULL != c->warn_task)
   {
-    i = 0;
-    while (NULL != sctx->addrs[i])
-      GNUNET_free (sctx->addrs[i++]);
-    GNUNET_free (sctx->addrs);
-  }
-  GNUNET_free_non_null (sctx->addrlens);
-  GNUNET_free_non_null (sctx->v4_denied);
-  GNUNET_free_non_null (sctx->v6_denied);
-  GNUNET_free_non_null (sctx->v4_allowed);
-  GNUNET_free_non_null (sctx->v6_allowed);
-  GNUNET_free (sctx);
+    GNUNET_SCHEDULER_cancel (c->warn_task);
+    c->warn_task = NULL;
+  }
+  if (NULL != c->recv_task)
+  {
+    GNUNET_SCHEDULER_cancel (c->recv_task);
+    c->recv_task = NULL;
+  }
+  if (NULL != c->send_task)
+  {
+    GNUNET_SCHEDULER_cancel (c->send_task);
+    c->send_task = NULL;
+  }
+  c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop,
+                                           c);
+}
+
+
+/**
+ * Explicitly stops the service.
+ *
+ * @param sh server to shutdown
+ */
+void
+GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
+{
+  struct GNUNET_SERVICE_Client *client;
+
+  GNUNET_SERVICE_suspend (sh);
+  sh->got_shutdown = GNUNET_NO;
+  while (NULL != (client = sh->clients_head))
+    GNUNET_SERVICE_client_drop (client);
+}
+
+
+/**
+ * Set the 'monitor' flag on this client.  Clients which have been
+ * marked as 'monitors' won't prevent the server from shutting down
+ * once #GNUNET_SERVICE_stop_listening() has been invoked.  The idea is
+ * that for "normal" clients we likely want to allow them to process
+ * their requests; however, monitor-clients are likely to 'never'
+ * disconnect during shutdown and thus will not be considered when
+ * determining if the server should continue to exist after
+ * shutdown has been triggered.
+ *
+ * @param c client to mark as a monitor
+ */
+void
+GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
+{
+  c->is_monitor = GNUNET_YES;
+  if ( (GNUNET_YES == c->sh->got_shutdown) &&
+       (GNUNET_NO == have_non_monitor_clients (c->sh)) )
+    GNUNET_SERVICE_shutdown (c->sh);
+}
+
+
+/**
+ * Set the persist option on this client.  Indicates that the
+ * underlying socket or fd should never really be closed.  Used for
+ * indicating process death.
+ *
+ * @param c client to persist the socket (never to be closed)
+ */
+void
+GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
+{
+  c->persist = GNUNET_YES;
+}
+
+
+/**
+ * Obtain the message queue of @a c.  Convenience function.
+ *
+ * @param c the client to continue receiving from
+ * @return the message queue of @a c
+ */
+struct GNUNET_MQ_Handle *
+GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
+{
+  return c->mq;
 }
 
 
-/* end of service.c */
+/* end of service_new.c */
diff --git a/src/util/service_new.c b/src/util/service_new.c
deleted file mode 100644 (file)
index 22eec0b..0000000
+++ /dev/null
@@ -1,2615 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2016 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-
-/**
- * @file util/service_new.c
- * @brief functions related to starting services (redesign)
- * @author Christian Grothoff
- * @author Florian Dold
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-#include "gnunet_protocols.h"
-#include "gnunet_constants.h"
-#include "gnunet_resolver_service.h"
-#include "speedup.h"
-
-#if HAVE_MALLINFO
-#include <malloc.h>
-#include "gauger.h"
-#endif
-
-
-#define LOG(kind,...) GNUNET_log_from (kind, "util-service", __VA_ARGS__)
-
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-service", syscall)
-
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename)
-
-
-/**
- * Information the service tracks per listen operation.
- */
-struct ServiceListenContext
-{
-
-  /**
-   * Kept in a DLL.
-   */
-  struct ServiceListenContext *next;
-
-  /**
-   * Kept in a DLL.
-   */
-  struct ServiceListenContext *prev;
-
-  /**
-   * Service this listen context belongs to.
-   */
-  struct GNUNET_SERVICE_Handle *sh;
-
-  /**
-   * Socket we are listening on.
-   */
-  struct GNUNET_NETWORK_Handle *listen_socket;
-
-  /**
-   * Task scheduled to do the listening.
-   */
-  struct GNUNET_SCHEDULER_Task *listen_task;
-
-};
-
-
-/**
- * Handle to a service.
- */
-struct GNUNET_SERVICE_Handle
-{
-  /**
-   * Our configuration.
-   */
-  const struct GNUNET_CONFIGURATION_Handle *cfg;
-
-  /**
-   * Name of our service.
-   */
-  const char *service_name;
-
-  /**
-   * Main service-specific task to run.
-   */
-  GNUNET_SERVICE_InitCallback service_init_cb;
-
-  /**
-   * Function to call when clients connect.
-   */
-  GNUNET_SERVICE_ConnectHandler connect_cb;
-
-  /**
-   * Function to call when clients disconnect / are disconnected.
-   */
-  GNUNET_SERVICE_DisconnectHandler disconnect_cb;
-
-  /**
-   * Closure for @e service_init_cb, @e connect_cb, @e disconnect_cb.
-   */
-  void *cb_cls;
-
-  /**
-   * DLL of listen sockets used to accept new connections.
-   */
-  struct ServiceListenContext *slc_head;
-
-  /**
-   * DLL of listen sockets used to accept new connections.
-   */
-  struct ServiceListenContext *slc_tail;
-
-  /**
-   * Our clients, kept in a DLL.
-   */
-  struct GNUNET_SERVICE_Client *clients_head;
-
-  /**
-   * Our clients, kept in a DLL.
-   */
-  struct GNUNET_SERVICE_Client *clients_tail;
-
-  /**
-   * Message handlers to use for all clients.
-   */
-  struct GNUNET_MQ_MessageHandler *handlers;
-
-  /**
-   * Closure for @e task.
-   */
-  void *task_cls;
-
-  /**
-   * IPv4 addresses that are not allowed to connect.
-   */
-  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
-
-  /**
-   * IPv6 addresses that are not allowed to connect.
-   */
-  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
-
-  /**
-   * IPv4 addresses that are allowed to connect (if not
-   * set, all are allowed).
-   */
-  struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
-
-  /**
-   * IPv6 addresses that are allowed to connect (if not
-   * set, all are allowed).
-   */
-  struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
-
-  /**
-   * Do we require a matching UID for UNIX domain socket connections?
-   * #GNUNET_NO means that the UID does not have to match (however,
-   * @e match_gid may still impose other access control checks).
-   */
-  int match_uid;
-
-  /**
-   * Do we require a matching GID for UNIX domain socket connections?
-   * Ignored if @e match_uid is #GNUNET_YES.  Note that this is about
-   * checking that the client's UID is in our group OR that the
-   * client's GID is our GID.  If both "match_gid" and @e match_uid are
-   * #GNUNET_NO, all users on the local system have access.
-   */
-  int match_gid;
-
-  /**
-   * Set to #GNUNET_YES if we got a shutdown signal and terminate
-   * the service if #have_non_monitor_clients() returns #GNUNET_YES.
-   */
-  int got_shutdown;
-
-  /**
-   * Our options.
-   */
-  enum GNUNET_SERVICE_Options options;
-
-  /**
-   * If we are daemonizing, this FD is set to the
-   * pipe to the parent.  Send '.' if we started
-   * ok, '!' if not.  -1 if we are not daemonizing.
-   */
-  int ready_confirm_fd;
-
-  /**
-   * Overall success/failure of the service start.
-   */
-  int ret;
-
-  /**
-   * If #GNUNET_YES, consider unknown message types an error where the
-   * client is disconnected.
-   */
-  int require_found;
-};
-
-
-/**
- * Handle to a client that is connected to a service.
- */
-struct GNUNET_SERVICE_Client
-{
-
-  /**
-   * Kept in a DLL.
-   */
-  struct GNUNET_SERVICE_Client *next;
-
-  /**
-   * Kept in a DLL.
-   */
-  struct GNUNET_SERVICE_Client *prev;
-
-  /**
-   * Service that this client belongs to.
-   */
-  struct GNUNET_SERVICE_Handle *sh;
-
-  /**
-   * Socket of this client.
-   */
-  struct GNUNET_NETWORK_Handle *sock;
-
-  /**
-   * Message queue for the client.
-   */
-  struct GNUNET_MQ_Handle *mq;
-
-  /**
-   * Tokenizer we use for processing incoming data.
-   */
-  struct GNUNET_MessageStreamTokenizer *mst;
-
-  /**
-   * Task that warns about missing calls to
-   * #GNUNET_SERVICE_client_continue().
-   */
-  struct GNUNET_SCHEDULER_Task *warn_task;
-
-  /**
-   * Task run to finish dropping the client after the stack has
-   * properly unwound.
-   */
-  struct GNUNET_SCHEDULER_Task *drop_task;
-
-  /**
-   * Task that receives data from the client to
-   * pass it to the handlers.
-   */
-  struct GNUNET_SCHEDULER_Task *recv_task;
-
-  /**
-   * Task that transmit data to the client.
-   */
-  struct GNUNET_SCHEDULER_Task *send_task;
-
-  /**
-   * Pointer to the message to be transmitted by @e send_task.
-   */
-  const struct GNUNET_MessageHeader *msg;
-
-  /**
-   * User context value, value returned from
-   * the connect callback.
-   */
-  void *user_context;
-
-  /**
-   * Time when we last gave a message from this client
-   * to the application.
-   */
-  struct GNUNET_TIME_Absolute warn_start;
-
-  /**
-   * Current position in @e msg at which we are transmitting.
-   */
-  size_t msg_pos;
-
-  /**
-   * Persist the file handle for this client no matter what happens,
-   * force the OS to close once the process actually dies.  Should only
-   * be used in special cases!
-   */
-  int persist;
-
-  /**
-   * Is this client a 'monitor' client that should not be counted
-   * when deciding on destroying the server during soft shutdown?
-   * (see also #GNUNET_SERVICE_start)
-   */
-  int is_monitor;
-
-  /**
-   * Are we waiting for the application to call #GNUNET_SERVICE_client_continue()?
-   */
-  int needs_continue;
-
-  /**
-   * Type of last message processed (for warn_no_receive_done).
-   */
-  uint16_t warn_type;
-};
-
-
-/**
- * Check if any of the clients we have left are unrelated to
- * monitoring.
- *
- * @param sh service to check clients for
- * @return #GNUNET_YES if we have non-monitoring clients left
- */
-static int
-have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh)
-{
-  struct GNUNET_SERVICE_Client *client;
-
-  for (client = sh->clients_head;NULL != client; client = client->next)
-  {
-    if (client->is_monitor)
-      continue;
-    return GNUNET_YES;
-  }
-  return GNUNET_NO;
-}
-
-
-/**
- * Shutdown task triggered when a service should be terminated.
- * This considers active clients and the service options to see
- * how this specific service is to be terminated, and depending
- * on this proceeds with the shutdown logic.
- *
- * @param cls our `struct GNUNET_SERVICE_Handle`
- */
-static void
-service_shutdown (void *cls)
-{
-  struct GNUNET_SERVICE_Handle *sh = cls;
-
-  switch (sh->options)
-  {
-  case GNUNET_SERVICE_OPTION_NONE:
-    GNUNET_SERVICE_shutdown (sh);
-    break;
-  case GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN:
-    /* This task should never be run if we are using
-       the manual shutdown. */
-    GNUNET_assert (0);
-    break;
-  case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN:
-    sh->got_shutdown = GNUNET_YES;
-    GNUNET_SERVICE_suspend (sh);
-    if (GNUNET_NO == have_non_monitor_clients (sh))
-      GNUNET_SERVICE_shutdown (sh);
-    break;
-  }
-}
-
-
-/**
- * First task run by any service.  Initializes our shutdown task,
- * starts the listening operation on our listen sockets and launches
- * the custom logic of the application service.
- *
- * @param cls our `struct GNUNET_SERVICE_Handle`
- */
-static void
-service_main (void *cls)
-{
-  struct GNUNET_SERVICE_Handle *sh = cls;
-
-  if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN != sh->options)
-    GNUNET_SCHEDULER_add_shutdown (&service_shutdown,
-                                   sh);
-  GNUNET_SERVICE_resume (sh);
-
-  if (-1 != sh->ready_confirm_fd)
-  {
-    GNUNET_break (1 == WRITE (sh->ready_confirm_fd, ".", 1));
-    GNUNET_break (0 == CLOSE (sh->ready_confirm_fd));
-    sh->ready_confirm_fd = -1;
-  }
-
-  if (NULL != sh->service_init_cb)
-    sh->service_init_cb (sh->cb_cls,
-                        sh->cfg,
-                        sh);
-}
-
-
-/**
- * Parse an IPv4 access control list.
- *
- * @param ret location where to write the ACL (set)
- * @param sh service context to use to get the configuration
- * @param option name of the ACL option to parse
- * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
- *         no ACL configured)
- */
-static int
-process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
-              struct GNUNET_SERVICE_Handle *sh,
-              const char *option)
-{
-  char *opt;
-
-  if (! GNUNET_CONFIGURATION_have_value (sh->cfg,
-                                        sh->service_name,
-                                        option))
-  {
-    *ret = NULL;
-    return GNUNET_OK;
-  }
-  GNUNET_break (GNUNET_OK ==
-                GNUNET_CONFIGURATION_get_value_string (sh->cfg,
-                                                       sh->service_name,
-                                                       option,
-                                                      &opt));
-  if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
-         opt,
-        sh->service_name,
-        option);
-    GNUNET_free (opt);
-    return GNUNET_SYSERR;
-  }
-  GNUNET_free (opt);
-  return GNUNET_OK;
-}
-
-
-/**
- * Parse an IPv6 access control list.
- *
- * @param ret location where to write the ACL (set)
- * @param sh service context to use to get the configuration
- * @param option name of the ACL option to parse
- * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
- *         no ACL configured)
- */
-static int
-process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
-              struct GNUNET_SERVICE_Handle *sh,
-              const char *option)
-{
-  char *opt;
-
-  if (! GNUNET_CONFIGURATION_have_value (sh->cfg,
-                                        sh->service_name,
-                                        option))
-  {
-    *ret = NULL;
-    return GNUNET_OK;
-  }
-  GNUNET_break (GNUNET_OK ==
-                GNUNET_CONFIGURATION_get_value_string (sh->cfg,
-                                                       sh->service_name,
-                                                       option,
-                                                      &opt));
-  if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
-         opt,
-        sh->service_name,
-        option);
-    GNUNET_free (opt);
-    return GNUNET_SYSERR;
-  }
-  GNUNET_free (opt);
-  return GNUNET_OK;
-}
-
-
-/**
- * Add the given UNIX domain path as an address to the
- * list (as the first entry).
- *
- * @param saddrs array to update
- * @param saddrlens where to store the address length
- * @param unixpath path to add
- * @param abstract #GNUNET_YES to add an abstract UNIX domain socket.  This
- *          parameter is ignore on systems other than LINUX
- */
-static void
-add_unixpath (struct sockaddr **saddrs,
-              socklen_t *saddrlens,
-              const char *unixpath,
-              int abstract)
-{
-#ifdef AF_UNIX
-  struct sockaddr_un *un;
-
-  un = GNUNET_new (struct sockaddr_un);
-  un->sun_family = AF_UNIX;
-  strncpy (un->sun_path,
-          unixpath,
-          sizeof (un->sun_path) - 1);
-#ifdef LINUX
-  if (GNUNET_YES == abstract)
-    un->sun_path[0] = '\0';
-#endif
-#if HAVE_SOCKADDR_UN_SUN_LEN
-  un->sun_len = (u_char) sizeof (struct sockaddr_un);
-#endif
-  *saddrs = (struct sockaddr *) un;
-  *saddrlens = sizeof (struct sockaddr_un);
-#else
-  /* this function should never be called
-   * unless AF_UNIX is defined! */
-  GNUNET_assert (0);
-#endif
-}
-
-
-/**
- * Get the list of addresses that a server for the given service
- * should bind to.
- *
- * @param service_name name of the service
- * @param cfg configuration (which specifies the addresses)
- * @param addrs set (call by reference) to an array of pointers to the
- *              addresses the server should bind to and listen on; the
- *              array will be NULL-terminated (on success)
- * @param addr_lens set (call by reference) to an array of the lengths
- *              of the respective `struct sockaddr` struct in the @a addrs
- *              array (on success)
- * @return number of addresses found on success,
- *              #GNUNET_SYSERR if the configuration
- *              did not specify reasonable finding information or
- *              if it specified a hostname that could not be resolved;
- *              #GNUNET_NO if the number of addresses configured is
- *              zero (in this case, `*addrs` and `*addr_lens` will be
- *              set to NULL).
- */
-static int
-get_server_addresses (const char *service_name,
-                     const struct GNUNET_CONFIGURATION_Handle *cfg,
-                     struct sockaddr ***addrs,
-                     socklen_t **addr_lens)
-{
-  int disablev6;
-  struct GNUNET_NETWORK_Handle *desc;
-  unsigned long long port;
-  char *unixpath;
-  struct addrinfo hints;
-  struct addrinfo *res;
-  struct addrinfo *pos;
-  struct addrinfo *next;
-  unsigned int i;
-  int resi;
-  int ret;
-  int abstract;
-  struct sockaddr **saddrs;
-  socklen_t *saddrlens;
-  char *hostname;
-
-  *addrs = NULL;
-  *addr_lens = NULL;
-  desc = NULL;
-  if (GNUNET_CONFIGURATION_have_value (cfg,
-                                      service_name,
-                                      "DISABLEV6"))
-  {
-    if (GNUNET_SYSERR ==
-        (disablev6 =
-         GNUNET_CONFIGURATION_get_value_yesno (cfg,
-                                              service_name,
-                                              "DISABLEV6")))
-      return GNUNET_SYSERR;
-  }
-  else
-    disablev6 = GNUNET_NO;
-
-  if (! disablev6)
-  {
-    /* probe IPv6 support */
-    desc = GNUNET_NETWORK_socket_create (PF_INET6,
-                                        SOCK_STREAM,
-                                        0);
-    if (NULL == desc)
-    {
-      if ( (ENOBUFS == errno) ||
-          (ENOMEM == errno) ||
-          (ENFILE == errno) ||
-          (EACCES == errno) )
-      {
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                     "socket");
-        return GNUNET_SYSERR;
-      }
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
-           service_name,
-          STRERROR (errno));
-      disablev6 = GNUNET_YES;
-    }
-    else
-    {
-      GNUNET_break (GNUNET_OK ==
-                   GNUNET_NETWORK_socket_close (desc));
-      desc = NULL;
-    }
-  }
-
-  port = 0;
-  if (GNUNET_CONFIGURATION_have_value (cfg,
-                                      service_name,
-                                      "PORT"))
-  {
-    if (GNUNET_OK !=
-       GNUNET_CONFIGURATION_get_value_number (cfg,
-                                              service_name,
-                                              "PORT",
-                                              &port))
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-           _("Require valid port number for service `%s' in configuration!\n"),
-           service_name);
-    }
-    if (port > 65535)
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-           _("Require valid port number for service `%s' in configuration!\n"),
-           service_name);
-      return GNUNET_SYSERR;
-    }
-  }
-
-  if (GNUNET_CONFIGURATION_have_value (cfg,
-                                      service_name,
-                                      "BINDTO"))
-  {
-    GNUNET_break (GNUNET_OK ==
-                  GNUNET_CONFIGURATION_get_value_string (cfg,
-                                                        service_name,
-                                                         "BINDTO",
-                                                        &hostname));
-  }
-  else
-    hostname = NULL;
-
-  unixpath = NULL;
-  abstract = GNUNET_NO;
-#ifdef AF_UNIX
-  if ((GNUNET_YES ==
-       GNUNET_CONFIGURATION_have_value (cfg,
-                                       service_name,
-                                       "UNIXPATH")) &&
-      (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_filename (cfg,
-                                               service_name,
-                                               "UNIXPATH",
-                                               &unixpath)) &&
-      (0 < strlen (unixpath)))
-  {
-    /* probe UNIX support */
-    struct sockaddr_un s_un;
-
-    if (strlen (unixpath) >= sizeof (s_un.sun_path))
-    {
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-           _("UNIXPATH `%s' too long, maximum length is %llu\n"),
-          unixpath,
-           (unsigned long long) sizeof (s_un.sun_path));
-      unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
-      LOG (GNUNET_ERROR_TYPE_INFO,
-          _("Using `%s' instead\n"),
-           unixpath);
-    }
-#ifdef LINUX
-    abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
-                                                     "TESTING",
-                                                     "USE_ABSTRACT_SOCKETS");
-    if (GNUNET_SYSERR == abstract)
-      abstract = GNUNET_NO;
-#endif
-    if ( (GNUNET_YES != abstract) &&
-        (GNUNET_OK !=
-         GNUNET_DISK_directory_create_for_file (unixpath)) )
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
-                               "mkdir",
-                               unixpath);
-  }
-  if (NULL != unixpath)
-  {
-    desc = GNUNET_NETWORK_socket_create (AF_UNIX,
-                                        SOCK_STREAM,
-                                        0);
-    if (NULL == desc)
-    {
-      if ((ENOBUFS == errno) ||
-         (ENOMEM == errno) ||
-         (ENFILE == errno) ||
-          (EACCES == errno))
-      {
-        LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                     "socket");
-        GNUNET_free_non_null (hostname);
-        GNUNET_free (unixpath);
-        return GNUNET_SYSERR;
-      }
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
-           service_name,
-           STRERROR (errno));
-      GNUNET_free (unixpath);
-      unixpath = NULL;
-    }
-    else
-    {
-      GNUNET_break (GNUNET_OK ==
-                   GNUNET_NETWORK_socket_close (desc));
-      desc = NULL;
-    }
-  }
-#endif
-
-  if ((0 == port) && (NULL == unixpath))
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
-         service_name);
-    GNUNET_free_non_null (hostname);
-    return GNUNET_SYSERR;
-  }
-  if (0 == port)
-  {
-    saddrs = GNUNET_new_array (2,
-                              struct sockaddr *);
-    saddrlens = GNUNET_new_array (2,
-                                 socklen_t);
-    add_unixpath (saddrs,
-                 saddrlens,
-                 unixpath,
-                 abstract);
-    GNUNET_free_non_null (unixpath);
-    GNUNET_free_non_null (hostname);
-    *addrs = saddrs;
-    *addr_lens = saddrlens;
-    return 1;
-  }
-
-  if (NULL != hostname)
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Resolving `%s' since that is where `%s' will bind to.\n",
-         hostname,
-         service_name);
-    memset (&hints,
-           0,
-           sizeof (struct addrinfo));
-    if (disablev6)
-      hints.ai_family = AF_INET;
-    hints.ai_protocol = IPPROTO_TCP;
-    if ((0 != (ret = getaddrinfo (hostname,
-                                 NULL,
-                                 &hints,
-                                 &res))) ||
-        (NULL == res))
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-           _("Failed to resolve `%s': %s\n"),
-           hostname,
-           gai_strerror (ret));
-      GNUNET_free (hostname);
-      GNUNET_free_non_null (unixpath);
-      return GNUNET_SYSERR;
-    }
-    next = res;
-    i = 0;
-    while (NULL != (pos = next))
-    {
-      next = pos->ai_next;
-      if ( (disablev6) &&
-          (pos->ai_family == AF_INET6) )
-        continue;
-      i++;
-    }
-    if (0 == i)
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-           _("Failed to find %saddress for `%s'.\n"),
-           disablev6 ? "IPv4 " : "",
-           hostname);
-      freeaddrinfo (res);
-      GNUNET_free (hostname);
-      GNUNET_free_non_null (unixpath);
-      return GNUNET_SYSERR;
-    }
-    resi = i;
-    if (NULL != unixpath)
-      resi++;
-    saddrs = GNUNET_new_array (resi + 1,
-                              struct sockaddr *);
-    saddrlens = GNUNET_new_array (resi + 1,
-                                 socklen_t);
-    i = 0;
-    if (NULL != unixpath)
-    {
-      add_unixpath (saddrs,
-                   saddrlens,
-                   unixpath,
-                   abstract);
-      i++;
-    }
-    next = res;
-    while (NULL != (pos = next))
-    {
-      next = pos->ai_next;
-      if ( (disablev6) &&
-          (AF_INET6 == pos->ai_family) )
-        continue;
-      if ( (IPPROTO_TCP != pos->ai_protocol) &&
-          (0 != pos->ai_protocol) )
-        continue;               /* not TCP */
-      if ( (SOCK_STREAM != pos->ai_socktype) &&
-          (0 != pos->ai_socktype) )
-        continue;               /* huh? */
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-          "Service `%s' will bind to `%s'\n",
-           service_name,
-          GNUNET_a2s (pos->ai_addr,
-                      pos->ai_addrlen));
-      if (AF_INET == pos->ai_family)
-      {
-        GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen);
-        saddrlens[i] = pos->ai_addrlen;
-        saddrs[i] = GNUNET_malloc (saddrlens[i]);
-        GNUNET_memcpy (saddrs[i],
-                      pos->ai_addr,
-                      saddrlens[i]);
-        ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
-      }
-      else
-      {
-        GNUNET_assert (AF_INET6 == pos->ai_family);
-        GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen);
-        saddrlens[i] = pos->ai_addrlen;
-        saddrs[i] = GNUNET_malloc (saddrlens[i]);
-        GNUNET_memcpy (saddrs[i],
-                      pos->ai_addr,
-                      saddrlens[i]);
-        ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
-      }
-      i++;
-    }
-    GNUNET_free (hostname);
-    freeaddrinfo (res);
-    resi = i;
-  }
-  else
-  {
-    /* will bind against everything, just set port */
-    if (disablev6)
-    {
-      /* V4-only */
-      resi = 1;
-      if (NULL != unixpath)
-        resi++;
-      i = 0;
-      saddrs = GNUNET_new_array (resi + 1,
-                                struct sockaddr *);
-      saddrlens = GNUNET_new_array (resi + 1,
-                                   socklen_t);
-      if (NULL != unixpath)
-      {
-        add_unixpath (saddrs,
-                     saddrlens,
-                     unixpath,
-                     abstract);
-        i++;
-      }
-      saddrlens[i] = sizeof (struct sockaddr_in);
-      saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
-#endif
-      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
-      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
-    }
-    else
-    {
-      /* dual stack */
-      resi = 2;
-      if (NULL != unixpath)
-        resi++;
-      saddrs = GNUNET_new_array (resi + 1,
-                                struct sockaddr *);
-      saddrlens = GNUNET_new_array (resi + 1,
-                                   socklen_t);
-      i = 0;
-      if (NULL != unixpath)
-      {
-        add_unixpath (saddrs,
-                     saddrlens,
-                     unixpath,
-                     abstract);
-        i++;
-      }
-      saddrlens[i] = sizeof (struct sockaddr_in6);
-      saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
-#endif
-      ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
-      ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
-      i++;
-      saddrlens[i] = sizeof (struct sockaddr_in);
-      saddrs[i] = GNUNET_malloc (saddrlens[i]);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
-#endif
-      ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
-      ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
-    }
-  }
-  GNUNET_free_non_null (unixpath);
-  *addrs = saddrs;
-  *addr_lens = saddrlens;
-  return resi;
-}
-
-
-#ifdef MINGW
-/**
- * Read listen sockets from the parent process (ARM).
- *
- * @param sh service context to initialize
- * @return NULL-terminated array of sockets on success,
- *         NULL if not ok (must bind yourself)
- */
-static struct GNUNET_NETWORK_Handle **
-receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh)
-{
-  static struct GNUNET_NETWORK_Handle **lsocks;
-  const char *env_buf;
-  int fail;
-  uint64_t count;
-  uint64_t i;
-  HANDLE lsocks_pipe;
-
-  env_buf = getenv ("GNUNET_OS_READ_LSOCKS");
-  if ( (NULL == env_buf) ||
-       (strlen (env_buf) <= 0) )
-    return NULL;
-  /* Using W32 API directly here, because this pipe will
-   * never be used outside of this function, and it's just too much of a bother
-   * to create a GNUnet API that boxes a HANDLE (the way it is done with socks)
-   */
-  lsocks_pipe = (HANDLE) strtoul (env_buf,
-                                 NULL,
-                                 10);
-  if ( (0 == lsocks_pipe) ||
-       (INVALID_HANDLE_VALUE == lsocks_pipe))
-    return NULL;
-  fail = 1;
-  do
-  {
-    int ret;
-    int fail2;
-    DWORD rd;
-
-    ret = ReadFile (lsocks_pipe,
-                   &count,
-                   sizeof (count),
-                   &rd,
-                   NULL);
-    if ( (0 == ret) ||
-        (sizeof (count) != rd) ||
-        (0 == count) )
-      break;
-    lsocks = GNUNET_new_array (count + 1,
-                              struct GNUNET_NETWORK_Handle *);
-
-    fail2 = 1;
-    for (i = 0; i < count; i++)
-    {
-      WSAPROTOCOL_INFOA pi;
-      uint64_t size;
-      SOCKET s;
-
-      ret = ReadFile (lsocks_pipe,
-                     &size,
-                     sizeof (size),
-                     &rd,
-                     NULL);
-      if ( (0 == ret) ||
-          (sizeof (size) != rd) ||
-          (sizeof (pi) != size) )
-        break;
-      ret = ReadFile (lsocks_pipe,
-                     &pi,
-                     sizeof (pi),
-                     &rd,
-                     NULL);
-      if ( (0 == ret) ||
-          (sizeof (pi) != rd))
-        break;
-      s = WSASocketA (pi.iAddressFamily,
-                     pi.iSocketType,
-                     pi.iProtocol,
-                     &pi,
-                     0,
-                     WSA_FLAG_OVERLAPPED);
-      lsocks[i] = GNUNET_NETWORK_socket_box_native (s);
-      if (NULL == lsocks[i])
-        break;
-      else if (i == count - 1)
-        fail2 = 0;
-    }
-    if (fail2)
-      break;
-    lsocks[count] = NULL;
-    fail = 0;
-  }
-  while (fail);
-  CloseHandle (lsocks_pipe);
-
-  if (fail)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("Could not access a pre-bound socket, will try to bind myself\n"));
-    for (i = 0; (i < count) && (NULL != lsocks[i]); i++)
-      GNUNET_break (GNUNET_OK ==
-                   GNUNET_NETWORK_socket_close (lsocks[i]));
-    GNUNET_free (lsocks);
-    return NULL;
-  }
-  return lsocks;
-}
-#endif
-
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @param server_addr address to listen on
- * @param socklen length of @a server_addr
- * @return NULL on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket (const struct sockaddr *server_addr,
-                   socklen_t socklen)
-{
-  struct GNUNET_NETWORK_Handle *sock;
-  uint16_t port;
-  int eno;
-
-  switch (server_addr->sa_family)
-  {
-  case AF_INET:
-    port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
-    break;
-  case AF_INET6:
-    port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
-    break;
-  case AF_UNIX:
-    port = 0;
-    break;
-  default:
-    GNUNET_break (0);
-    port = 0;
-    break;
-  }
-  sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
-                                      SOCK_STREAM,
-                                      0);
-  if (NULL == sock)
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                 "socket");
-    errno = 0;
-    return NULL;
-  }
-  /* bind the socket */
-  if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock,
-                                              server_addr,
-                                              socklen))
-  {
-    eno = errno;
-    if (EADDRINUSE != errno)
-    {
-      /* we don't log 'EADDRINUSE' here since an IPv4 bind may
-       * fail if we already took the port on IPv6; if both IPv4 and
-       * IPv6 binds fail, then our caller will log using the
-       * errno preserved in 'eno' */
-      LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                    "bind");
-      if (0 != port)
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _("`%s' failed for port %d (%s).\n"),
-             "bind",
-             port,
-             (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
-      eno = 0;
-    }
-    else
-    {
-      if (0 != port)
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             _("`%s' failed for port %d (%s): address already in use\n"),
-             "bind", port,
-             (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
-      else if (AF_UNIX == server_addr->sa_family)
-      {
-        LOG (GNUNET_ERROR_TYPE_WARNING,
-             _("`%s' failed for `%s': address already in use\n"),
-             "bind",
-             GNUNET_a2s (server_addr, socklen));
-      }
-    }
-    GNUNET_break (GNUNET_OK ==
-                 GNUNET_NETWORK_socket_close (sock));
-    errno = eno;
-    return NULL;
-  }
-  if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock,
-                                                5))
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                  "listen");
-    GNUNET_break (GNUNET_OK ==
-                 GNUNET_NETWORK_socket_close (sock));
-    errno = 0;
-    return NULL;
-  }
-  if (0 != port)
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Server starts to listen on port %u.\n",
-         port);
-  return sock;
-}
-
-
-/**
- * Setup service handle
- *
- * Configuration may specify:
- * - PORT (where to bind to for TCP)
- * - UNIXPATH (where to bind to for UNIX domain sockets)
- * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
- * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
- * - ACCEPT_FROM  (only allow connections from specified IPv4 subnets)
- * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
- * - REJECT_FROM  (disallow allow connections from specified IPv4 subnets)
- * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
- *
- * @param sh service context to initialize
- * @return #GNUNET_OK if configuration succeeded
- */
-static int
-setup_service (struct GNUNET_SERVICE_Handle *sh)
-{
-  int tolerant;
-  struct GNUNET_NETWORK_Handle **lsocks;
-#ifndef MINGW
-  const char *nfds;
-  unsigned int cnt;
-  int flags;
-#endif
-
-  if (GNUNET_CONFIGURATION_have_value
-      (sh->cfg,
-       sh->service_name,
-       "TOLERANT"))
-  {
-    if (GNUNET_SYSERR ==
-        (tolerant =
-         GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
-                                              sh->service_name,
-                                               "TOLERANT")))
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-           _("Specified value for `%s' of service `%s' is invalid\n"),
-           "TOLERANT",
-          sh->service_name);
-      return GNUNET_SYSERR;
-    }
-  }
-  else
-    tolerant = GNUNET_NO;
-
-  lsocks = NULL;
-#ifndef MINGW
-  errno = 0;
-  if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
-       (1 == SSCANF (nfds,
-                    "%u",
-                    &cnt)) &&
-       (cnt > 0) &&
-       (cnt < FD_SETSIZE) &&
-       (cnt + 4 < FD_SETSIZE) )
-  {
-    lsocks = GNUNET_new_array (cnt + 1,
-                              struct GNUNET_NETWORK_Handle *);
-    while (0 < cnt--)
-    {
-      flags = fcntl (3 + cnt,
-                    F_GETFD);
-      if ( (flags < 0) ||
-          (0 != (flags & FD_CLOEXEC)) ||
-          (NULL ==
-           (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
-      {
-        LOG (GNUNET_ERROR_TYPE_ERROR,
-             _("Could not access pre-bound socket %u, will try to bind myself\n"),
-             (unsigned int) 3 + cnt);
-        cnt++;
-        while (NULL != lsocks[cnt])
-          GNUNET_break (GNUNET_OK ==
-                       GNUNET_NETWORK_socket_close (lsocks[cnt++]));
-        GNUNET_free (lsocks);
-        lsocks = NULL;
-        break;
-      }
-    }
-    unsetenv ("LISTEN_FDS");
-  }
-#else
-  if (NULL != getenv ("GNUNET_OS_READ_LSOCKS"))
-  {
-    lsocks = receive_sockets_from_parent (sh);
-    putenv ("GNUNET_OS_READ_LSOCKS=");
-  }
-#endif
-
-  if (NULL != lsocks)
-  {
-    /* listen only on inherited sockets if we have any */
-    struct GNUNET_NETWORK_Handle **ls;
-
-    for (ls = lsocks; NULL != *ls; ls++)
-    {
-      struct ServiceListenContext *slc;
-
-      slc = GNUNET_new (struct ServiceListenContext);
-      slc->sh = sh;
-      slc->listen_socket = *ls;
-      GNUNET_CONTAINER_DLL_insert (sh->slc_head,
-                                  sh->slc_tail,
-                                  slc);
-    }
-    GNUNET_free (lsocks);
-  }
-  else
-  {
-    struct sockaddr **addrs;
-    socklen_t *addrlens;
-    int num;
-
-    num = get_server_addresses (sh->service_name,
-                               sh->cfg,
-                               &addrs,
-                               &addrlens);
-    if (GNUNET_SYSERR == num)
-      return GNUNET_SYSERR;
-
-    for (int i = 0; i < num; i++)
-    {
-      struct ServiceListenContext *slc;
-
-      slc = GNUNET_new (struct ServiceListenContext);
-      slc->sh = sh;
-      slc->listen_socket = open_listen_socket (addrs[i],
-                                              addrlens[i]);
-      if (NULL == slc->listen_socket)
-      {
-        GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
-                             "bind");
-        GNUNET_free (addrs[i++]);
-        GNUNET_free (slc);
-        continue;
-      }
-      GNUNET_free (addrs[i++]);
-      GNUNET_CONTAINER_DLL_insert (sh->slc_head,
-                                  sh->slc_tail,
-                                  slc);
-    }
-    GNUNET_free_non_null (addrlens);
-    GNUNET_free_non_null (addrs);
-    if ( (0 != num) &&
-         (NULL == sh->slc_head) )
-    {
-      /* All attempts to bind failed, hard failure */
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Could not bind to any of the ports I was supposed to, refusing to run!\n"));
-      return GNUNET_SYSERR;
-    }
-  }
-
-  sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
-  sh->match_uid
-    = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
-                                           sh->service_name,
-                                            "UNIX_MATCH_UID");
-  sh->match_gid
-    = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
-                                           sh->service_name,
-                                            "UNIX_MATCH_GID");
-  process_acl4 (&sh->v4_denied,
-               sh,
-               "REJECT_FROM");
-  process_acl4 (&sh->v4_allowed,
-               sh,
-               "ACCEPT_FROM");
-  process_acl6 (&sh->v6_denied,
-               sh,
-               "REJECT_FROM6");
-  process_acl6 (&sh->v6_allowed,
-               sh,
-               "ACCEPT_FROM6");
-  return GNUNET_OK;
-}
-
-
-/**
- * Get the name of the user that'll be used
- * to provide the service.
- *
- * @param sh service context
- * @return value of the 'USERNAME' option
- */
-static char *
-get_user_name (struct GNUNET_SERVICE_Handle *sh)
-{
-  char *un;
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
-                                              sh->service_name,
-                                               "USERNAME",
-                                              &un))
-    return NULL;
-  return un;
-}
-
-
-/**
- * Set user ID.
- *
- * @param sh service context
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-set_user_id (struct GNUNET_SERVICE_Handle *sh)
-{
-  char *user;
-
-  if (NULL == (user = get_user_name (sh)))
-    return GNUNET_OK;           /* keep */
-#ifndef MINGW
-  struct passwd *pws;
-
-  errno = 0;
-  pws = getpwnam (user);
-  if (NULL == pws)
-  {
-    LOG (GNUNET_ERROR_TYPE_ERROR,
-         _("Cannot obtain information about user `%s': %s\n"),
-        user,
-         errno == 0 ? _("No such user") : STRERROR (errno));
-    GNUNET_free (user);
-    return GNUNET_SYSERR;
-  }
-  if ( (0 != setgid (pws->pw_gid)) ||
-       (0 != setegid (pws->pw_gid)) ||
-#if HAVE_INITGROUPS
-       (0 != initgroups (user,
-                        pws->pw_gid)) ||
-#endif
-       (0 != setuid (pws->pw_uid)) ||
-       (0 != seteuid (pws->pw_uid)))
-  {
-    if ((0 != setregid (pws->pw_gid,
-                       pws->pw_gid)) ||
-        (0 != setreuid (pws->pw_uid,
-                       pws->pw_uid)))
-    {
-      LOG (GNUNET_ERROR_TYPE_ERROR,
-          _("Cannot change user/group to `%s': %s\n"),
-           user,
-          STRERROR (errno));
-      GNUNET_free (user);
-      return GNUNET_SYSERR;
-    }
-  }
-#endif
-  GNUNET_free (user);
-  return GNUNET_OK;
-}
-
-
-/**
- * Get the name of the file where we will
- * write the PID of the service.
- *
- * @param sh service context
- * @return name of the file for the process ID
- */
-static char *
-get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
-{
-  char *pif;
-
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
-                                              sh->service_name,
-                                               "PIDFILE",
-                                              &pif))
-    return NULL;
-  return pif;
-}
-
-
-/**
- * Delete the PID file that was created by our parent.
- *
- * @param sh service context
- */
-static void
-pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
-{
-  char *pif = get_pid_file_name (sh);
-
-  if (NULL == pif)
-    return;                     /* no PID file */
-  if (0 != UNLINK (pif))
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING,
-                      "unlink",
-                      pif);
-  GNUNET_free (pif);
-}
-
-
-/**
- * Detach from terminal.
- *
- * @param sh service context
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-detach_terminal (struct GNUNET_SERVICE_Handle *sh)
-{
-#ifndef MINGW
-  pid_t pid;
-  int nullfd;
-  int filedes[2];
-
-  if (0 != PIPE (filedes))
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                 "pipe");
-    return GNUNET_SYSERR;
-  }
-  pid = fork ();
-  if (pid < 0)
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                 "fork");
-    return GNUNET_SYSERR;
-  }
-  if (0 != pid)
-  {
-    /* Parent */
-    char c;
-
-    GNUNET_break (0 == CLOSE (filedes[1]));
-    c = 'X';
-    if (1 != READ (filedes[0],
-                  &c,
-                  sizeof (char)))
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
-                   "read");
-    fflush (stdout);
-    switch (c)
-    {
-    case '.':
-      exit (0);
-    case 'I':
-      LOG (GNUNET_ERROR_TYPE_INFO,
-          _("Service process failed to initialize\n"));
-      break;
-    case 'S':
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           _("Service process could not initialize server function\n"));
-      break;
-    case 'X':
-      LOG (GNUNET_ERROR_TYPE_INFO,
-           _("Service process failed to report status\n"));
-      break;
-    }
-    exit (1);                   /* child reported error */
-  }
-  GNUNET_break (0 == CLOSE (0));
-  GNUNET_break (0 == CLOSE (1));
-  GNUNET_break (0 == CLOSE (filedes[0]));
-  nullfd = OPEN ("/dev/null",
-                O_RDWR | O_APPEND);
-  if (nullfd < 0)
-    return GNUNET_SYSERR;
-  /* set stdin/stdout to /dev/null */
-  if ( (dup2 (nullfd, 0) < 0) ||
-       (dup2 (nullfd, 1) < 0) )
-  {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                 "dup2");
-    (void) CLOSE (nullfd);
-    return GNUNET_SYSERR;
-  }
-  (void) CLOSE (nullfd);
-  /* Detach from controlling terminal */
-  pid = setsid ();
-  if (-1 == pid)
-    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
-                 "setsid");
-  sh->ready_confirm_fd = filedes[1];
-#else
-  /* FIXME: we probably need to do something else
-   * elsewhere in order to fork the process itself... */
-  FreeConsole ();
-#endif
-  return GNUNET_OK;
-}
-
-
-/**
- * Tear down the service, closing the listen sockets and
- * freeing the ACLs.
- *
- * @param sh handle to the service to tear down.
- */
-static void
-teardown_service (struct GNUNET_SERVICE_Handle *sh)
-{
-  struct ServiceListenContext *slc;
-
-  GNUNET_free_non_null (sh->v4_denied);
-  GNUNET_free_non_null (sh->v6_denied);
-  GNUNET_free_non_null (sh->v4_allowed);
-  GNUNET_free_non_null (sh->v6_allowed);
-  while (NULL != (slc = sh->slc_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (sh->slc_head,
-                                 sh->slc_tail,
-                                 slc);
-    if (NULL != slc->listen_task)
-      GNUNET_SCHEDULER_cancel (slc->listen_task);
-    GNUNET_break (GNUNET_OK ==
-                 GNUNET_NETWORK_socket_close (slc->listen_socket));
-    GNUNET_free (slc);
-  }
-}
-
-
-/**
- * Low-level function to start a service if the scheduler
- * is already running.  Should only be used directly in
- * special cases.
- *
- * The function will launch the service with the name @a service_name
- * using the @a service_options to configure its shutdown
- * behavior. When clients connect or disconnect, the respective
- * @a connect_cb or @a disconnect_cb functions will be called. For
- * messages received from the clients, the respective @a handlers will
- * be invoked; for the closure of the handlers we use the return value
- * from the @a connect_cb invocation of the respective client.
- *
- * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
- * message to receive further messages from this client.  If
- * #GNUNET_SERVICE_client_continue() is not called within a short
- * time, a warning will be logged. If delays are expected, services
- * should call #GNUNET_SERVICE_client_disable_continue_warning() to
- * disable the warning.
- *
- * Clients sending invalid messages (based on @a handlers) will be
- * dropped. Additionally, clients can be dropped at any time using
- * #GNUNET_SERVICE_client_drop().
- *
- * The service must be stopped using #GNUNET_SERVICE_stoP().
- *
- * @param service_name name of the service to run
- * @param cfg configuration to use
- * @param connect_cb function to call whenever a client connects
- * @param disconnect_cb function to call whenever a client disconnects
- * @param cls closure argument for @a connect_cb and @a disconnect_cb
- * @param handlers NULL-terminated array of message handlers for the service,
- *                 the closure will be set to the value returned by
- *                 the @a connect_cb for the respective connection
- * @return NULL on error
- */
-struct GNUNET_SERVICE_Handle *
-GNUNET_SERVICE_starT (const char *service_name,
-                      const struct GNUNET_CONFIGURATION_Handle *cfg,
-                      GNUNET_SERVICE_ConnectHandler connect_cb,
-                      GNUNET_SERVICE_DisconnectHandler disconnect_cb,
-                      void *cls,
-                      const struct GNUNET_MQ_MessageHandler *handlers)
-{
-  struct GNUNET_SERVICE_Handle *sh;
-
-  sh = GNUNET_new (struct GNUNET_SERVICE_Handle);
-  sh->service_name = service_name;
-  sh->cfg = cfg;
-  sh->connect_cb = connect_cb;
-  sh->disconnect_cb = disconnect_cb;
-  sh->cb_cls = cls;
-  sh->handlers = GNUNET_MQ_copy_handlers (handlers);
-  if (GNUNET_OK != setup_service (sh))
-  {
-    GNUNET_free_non_null (sh->handlers);
-    GNUNET_free (sh);
-    return NULL;
-  }
-  GNUNET_SERVICE_resume (sh);
-  return sh;
-}
-
-
-/**
- * Stops a service that was started with #GNUNET_SERVICE_starT().
- *
- * @param srv service to stop
- */
-void
-GNUNET_SERVICE_stoP (struct GNUNET_SERVICE_Handle *srv)
-{
-  struct GNUNET_SERVICE_Client *client;
-
-  GNUNET_SERVICE_suspend (srv);
-  while (NULL != (client = srv->clients_head))
-    GNUNET_SERVICE_client_drop (client);
-  teardown_service (srv);
-  GNUNET_free_non_null (srv->handlers);
-  GNUNET_free (srv);
-}
-
-
-/**
- * Creates the "main" function for a GNUnet service.  You
- * should almost always use the #GNUNET_SERVICE_MAIN macro
- * instead of calling this function directly (except
- * for ARM, which should call this function directly).
- *
- * The function will launch the service with the name @a service_name
- * using the @a service_options to configure its shutdown
- * behavior. Once the service is ready, the @a init_cb will be called
- * for service-specific initialization.  @a init_cb will be given the
- * service handler which can be used to control the service's
- * availability.  When clients connect or disconnect, the respective
- * @a connect_cb or @a disconnect_cb functions will be called. For
- * messages received from the clients, the respective @a handlers will
- * be invoked; for the closure of the handlers we use the return value
- * from the @a connect_cb invocation of the respective client.
- *
- * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
- * message to receive further messages from this client.  If
- * #GNUNET_SERVICE_client_continue() is not called within a short
- * time, a warning will be logged. If delays are expected, services
- * should call #GNUNET_SERVICE_client_disable_continue_warning() to
- * disable the warning.
- *
- * Clients sending invalid messages (based on @a handlers) will be
- * dropped. Additionally, clients can be dropped at any time using
- * #GNUNET_SERVICE_client_drop().
- *
- * @param argc number of command-line arguments in @a argv
- * @param argv array of command-line arguments
- * @param service_name name of the service to run
- * @param options options controlling shutdown of the service
- * @param service_init_cb function to call once the service is ready
- * @param connect_cb function to call whenever a client connects
- * @param disconnect_cb function to call whenever a client disconnects
- * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
- * @param handlers NULL-terminated array of message handlers for the service,
- *                 the closure will be set to the value returned by
- *                 the @a connect_cb for the respective connection
- * @return 0 on success, non-zero on error
- */
-int
-GNUNET_SERVICE_ruN_ (int argc,
-                     char *const *argv,
-                     const char *service_name,
-                     enum GNUNET_SERVICE_Options options,
-                     GNUNET_SERVICE_InitCallback service_init_cb,
-                     GNUNET_SERVICE_ConnectHandler connect_cb,
-                     GNUNET_SERVICE_DisconnectHandler disconnect_cb,
-                     void *cls,
-                     const struct GNUNET_MQ_MessageHandler *handlers)
-{
-  struct GNUNET_SERVICE_Handle sh;
-  char *cfg_filename;
-  char *opt_cfg_filename;
-  char *loglev;
-  const char *xdg;
-  char *logfile;
-  int do_daemonize;
-  unsigned long long skew_offset;
-  unsigned long long skew_variance;
-  long long clock_offset;
-  struct GNUNET_CONFIGURATION_Handle *cfg;
-  int ret;
-  int err;
-
-  struct GNUNET_GETOPT_CommandLineOption service_options[] = {
-    GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_filename),
-    {'d', "daemonize", NULL,
-     gettext_noop ("do daemonize (detach from terminal)"), 0,
-     GNUNET_GETOPT_set_one, &do_daemonize},
-    GNUNET_GETOPT_OPTION_HELP (NULL),
-    GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev),
-    GNUNET_GETOPT_OPTION_LOGFILE (&logfile),
-    GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION),
-    GNUNET_GETOPT_OPTION_END
-  };
-
-  memset (&sh,
-         0,
-         sizeof (sh));
-  xdg = getenv ("XDG_CONFIG_HOME");
-  if (NULL != xdg)
-    GNUNET_asprintf (&cfg_filename,
-                     "%s%s%s",
-                     xdg,
-                     DIR_SEPARATOR_STR,
-                     GNUNET_OS_project_data_get ()->config_file);
-  else
-    cfg_filename = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
-  sh.ready_confirm_fd = -1;
-  sh.options = options;
-  sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
-  sh.service_init_cb = service_init_cb;
-  sh.connect_cb = connect_cb;
-  sh.disconnect_cb = disconnect_cb;
-  sh.cb_cls = cls;
-  sh.handlers = GNUNET_MQ_copy_handlers (handlers);
-  sh.service_name = service_name;
-
-  /* setup subsystems */
-  loglev = NULL;
-  logfile = NULL;
-  opt_cfg_filename = NULL;
-  do_daemonize = 0;
-  ret = GNUNET_GETOPT_run (service_name,
-                          service_options,
-                          argc,
-                          argv);
-  if (GNUNET_SYSERR == ret)
-    goto shutdown;
-  if (GNUNET_NO == ret)
-  {
-    err = 0;
-    goto shutdown;
-  }
-  if (GNUNET_OK != GNUNET_log_setup (service_name,
-                                    loglev,
-                                    logfile))
-  {
-    GNUNET_break (0);
-    goto shutdown;
-  }
-  if (NULL == opt_cfg_filename)
-    opt_cfg_filename = GNUNET_strdup (cfg_filename);
-  if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename))
-  {
-    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
-                                                   opt_cfg_filename))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Malformed configuration file `%s', exit ...\n"),
-                  opt_cfg_filename);
-      goto shutdown;
-    }
-  }
-  else
-  {
-    if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg,
-                                                   NULL))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Malformed configuration, exit ...\n"));
-      goto shutdown;
-    }
-    if (0 != strcmp (opt_cfg_filename,
-                    cfg_filename))
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Could not access configuration file `%s'\n"),
-                 opt_cfg_filename);
-  }
-  if (GNUNET_OK != setup_service (&sh))
-    goto shutdown;
-  if ( (1 == do_daemonize) &&
-       (GNUNET_OK != detach_terminal (&sh)) )
-  {
-    GNUNET_break (0);
-    goto shutdown;
-  }
-  if (GNUNET_OK != set_user_id (&sh))
-    goto shutdown;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Service `%s' runs with configuration from `%s'\n",
-       service_name,
-       opt_cfg_filename);
-  if ((GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_number (sh.cfg,
-                                             "TESTING",
-                                              "SKEW_OFFSET",
-                                             &skew_offset)) &&
-      (GNUNET_OK ==
-       GNUNET_CONFIGURATION_get_value_number (sh.cfg,
-                                             "TESTING",
-                                              "SKEW_VARIANCE",
-                                             &skew_variance)))
-  {
-    clock_offset = skew_offset - skew_variance;
-    GNUNET_TIME_set_offset (clock_offset);
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-        "Skewing clock by %dll ms\n",
-        clock_offset);
-  }
-  GNUNET_RESOLVER_connect (sh.cfg);
-
-  /* actually run service */
-  err = 0;
-  GNUNET_SCHEDULER_run (&service_main,
-                       &sh);
-  /* shutdown */
-  if (1 == do_daemonize)
-    pid_file_delete (&sh);
-
-shutdown:
-  if (-1 != sh.ready_confirm_fd)
-  {
-    if (1 != WRITE (sh.ready_confirm_fd,
-                   err ? "I" : "S",
-                   1))
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
-                   "write");
-    GNUNET_break (0 == CLOSE (sh.ready_confirm_fd));
-  }
-#if HAVE_MALLINFO
-  {
-    char *counter;
-
-    if ( (GNUNET_YES ==
-         GNUNET_CONFIGURATION_have_value (sh.cfg,
-                                          service_name,
-                                          "GAUGER_HEAP")) &&
-        (GNUNET_OK ==
-         GNUNET_CONFIGURATION_get_value_string (sh.cfg,
-                                                service_name,
-                                                "GAUGER_HEAP",
-                                                &counter)) )
-    {
-      struct mallinfo mi;
-
-      mi = mallinfo ();
-      GAUGER (service_name,
-             counter,
-             mi.usmblks,
-             "blocks");
-      GNUNET_free (counter);
-    }
-  }
-#endif
-  teardown_service (&sh);
-  GNUNET_free_non_null (sh.handlers);
-  GNUNET_SPEEDUP_stop_ ();
-  GNUNET_CONFIGURATION_destroy (cfg);
-  GNUNET_free_non_null (logfile);
-  GNUNET_free_non_null (loglev);
-  GNUNET_free (cfg_filename);
-  GNUNET_free_non_null (opt_cfg_filename);
-
-  return err ? GNUNET_SYSERR : sh.ret;
-}
-
-
-/**
- * Suspend accepting connections from the listen socket temporarily.
- * Resume activity using #GNUNET_SERVICE_resume.
- *
- * @param sh service to stop accepting connections.
- */
-void
-GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
-{
-  struct ServiceListenContext *slc;
-
-  for (slc = sh->slc_head; NULL != slc; slc = slc->next)
-  {
-    if (NULL != slc->listen_task)
-    {
-      GNUNET_SCHEDULER_cancel (slc->listen_task);
-      slc->listen_task = NULL;
-    }
-  }
-}
-
-
-/**
- * Task run when we are ready to transmit data to the
- * client.
- *
- * @param cls the `struct GNUNET_SERVICE_Client *` to send to
- */
-static void
-do_send (void *cls)
-{
-  struct GNUNET_SERVICE_Client *client = cls;
-  ssize_t ret;
-  size_t left;
-  const char *buf;
-
-  client->send_task = NULL;
-  buf = (const char *) client->msg;
-  left = ntohs (client->msg->size) - client->msg_pos;
-  ret = GNUNET_NETWORK_socket_send (client->sock,
-                                   &buf[client->msg_pos],
-                                   left);
-  GNUNET_assert (ret <= (ssize_t) left);
-  if (0 == ret)
-  {
-    GNUNET_MQ_inject_error (client->mq,
-                           GNUNET_MQ_ERROR_WRITE);
-    return;
-  }
-  if (-1 == ret)
-  {
-    if ( (EAGAIN == errno) ||
-        (EINTR == errno) )
-    {
-      /* ignore */
-      ret = 0;
-    }
-    else
-    {
-      if (EPIPE != errno)
-        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
-                             "send");
-      GNUNET_MQ_inject_error (client->mq,
-                             GNUNET_MQ_ERROR_WRITE);
-      return;
-    }
-  }
-  if (0 == client->msg_pos)
-  {
-    GNUNET_MQ_impl_send_in_flight (client->mq);
-  }
-  client->msg_pos += ret;
-  if (left > ret)
-  {
-    GNUNET_assert (NULL == client->drop_task);
-    client->send_task
-      = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                       client->sock,
-                                       &do_send,
-                                       client);
-    return;
-  }
-  GNUNET_MQ_impl_send_continue (client->mq);
-}
-
-
-/**
- * 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 our `struct GNUNET_SERVICE_Client *`
- */
-static void
-service_mq_send (struct GNUNET_MQ_Handle *mq,
-                 const struct GNUNET_MessageHeader *msg,
-                 void *impl_state)
-{
-  struct GNUNET_SERVICE_Client *client = impl_state;
-
-  if (NULL != client->drop_task)
-    return; /* we're going down right now, do not try to send */
-  GNUNET_assert (NULL == client->send_task);
-
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Sending message of type %u and size %u to client\n",
-       ntohs (msg->type), ntohs (msg->size));
-
-  client->msg = msg;
-  client->msg_pos = 0;
-  client->send_task
-    = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                     client->sock,
-                                     &do_send,
-                                     client);
-}
-
-
-/**
- * Implementation function that cancels the currently sent message.
- *
- * @param mq message queue
- * @param impl_state state specific to the implementation
- */
-static void
-service_mq_cancel (struct GNUNET_MQ_Handle *mq,
-                   void *impl_state)
-{
-  struct GNUNET_SERVICE_Client *client = impl_state;
-
-  GNUNET_assert (0 == client->msg_pos);
-  client->msg = NULL;
-  GNUNET_SCHEDULER_cancel (client->send_task);
-  client->send_task = NULL;
-}
-
-
-/**
- * Generic error handler, called with the appropriate
- * error code and the same closure specified at the creation of
- * the message queue.
- * Not every message queue implementation supports an error handler.
- *
- * @param cls closure with our `struct GNUNET_SERVICE_Client`
- * @param error error code
- */
-static void
-service_mq_error_handler (void *cls,
-                          enum GNUNET_MQ_Error error)
-{
-  struct GNUNET_SERVICE_Client *client = cls;
-  struct GNUNET_SERVICE_Handle *sh = client->sh;
-
-  if ( (GNUNET_MQ_ERROR_NO_MATCH == error) &&
-       (GNUNET_NO == sh->require_found) )
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "No handler for message of type %u found\n",
-                (unsigned int) client->warn_type);
-    GNUNET_SERVICE_client_continue (client);
-    return; /* ignore error */
-  }
-  GNUNET_SERVICE_client_drop (client);
-}
-
-
-/**
- * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue().
- *
- * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from
- */
-static void
-warn_no_client_continue (void *cls)
-{
-  struct GNUNET_SERVICE_Client *client = cls;
-
-  GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */
-  client->warn_task
-    = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                    &warn_no_client_continue,
-                                   client);
-  LOG (GNUNET_ERROR_TYPE_WARNING,
-       _("Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"),
-       (unsigned int) client->warn_type,
-       GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start),
-                                              GNUNET_YES));
-}
-
-
-/**
- * Functions with this signature are called whenever a
- * complete message is received by the tokenizer for a client.
- *
- * Do not call #GNUNET_MST_destroy() from within
- * the scope of this callback.
- *
- * @param cls closure with the `struct GNUNET_SERVICE_Client *`
- * @param message the actual message
- * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped
- */
-static int
-service_client_mst_cb (void *cls,
-                       const struct GNUNET_MessageHeader *message)
-{
-  struct GNUNET_SERVICE_Client *client = cls;
-
-  LOG (GNUNET_ERROR_TYPE_INFO,
-       "Received message of type %u and size %u from client\n",
-       ntohs (message->type), ntohs (message->size));
-
-  GNUNET_assert (GNUNET_NO == client->needs_continue);
-  client->needs_continue = GNUNET_YES;
-  client->warn_type = ntohs (message->type);
-  client->warn_start = GNUNET_TIME_absolute_get ();
-  GNUNET_assert (NULL == client->warn_task);
-  client->warn_task
-    = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
-                                   &warn_no_client_continue,
-                                   client);
-  GNUNET_MQ_inject_message (client->mq,
-                            message);
-  if (NULL != client->drop_task)
-    return GNUNET_SYSERR;
-  return GNUNET_OK;
-}
-
-
-/**
- * A client sent us data. Receive and process it.  If we are done,
- * reschedule this task.
- *
- * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
- */
-static void
-service_client_recv (void *cls)
-{
-  struct GNUNET_SERVICE_Client *client = cls;
-  int ret;
-
-  client->recv_task = NULL;
-  ret = GNUNET_MST_read (client->mst,
-                        client->sock,
-                        GNUNET_NO,
-                        GNUNET_YES);
-  if (GNUNET_SYSERR == ret)
-  {
-    /* client closed connection (or IO error) */
-    if (NULL == client->drop_task)
-    {
-      GNUNET_assert (GNUNET_NO == client->needs_continue);
-      GNUNET_SERVICE_client_drop (client);
-    }
-    return;
-  }
-  if (GNUNET_NO == ret)
-    return; /* more messages in buffer, wait for application
-              to be done processing */
-  GNUNET_assert (GNUNET_OK == ret);
-  if (GNUNET_YES == client->needs_continue)
-    return;
-  if (NULL != client->recv_task)
-    return;
-  /* MST needs more data, re-schedule read job */
-  client->recv_task
-    = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                    client->sock,
-                                    &service_client_recv,
-                                    client);
-}
-
-
-/**
- * We have successfully accepted a connection from a client.  Now
- * setup the client (with the scheduler) and tell the application.
- *
- * @param sh service that accepted the client
- * @param sock socket associated with the client
- */
-static void
-start_client (struct GNUNET_SERVICE_Handle *sh,
-              struct GNUNET_NETWORK_Handle *csock)
-{
-  struct GNUNET_SERVICE_Client *client;
-
-  client = GNUNET_new (struct GNUNET_SERVICE_Client);
-  GNUNET_CONTAINER_DLL_insert (sh->clients_head,
-                               sh->clients_tail,
-                               client);
-  client->sh = sh;
-  client->sock = csock;
-  client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
-                                              NULL,
-                                              &service_mq_cancel,
-                                              client,
-                                              sh->handlers,
-                                              &service_mq_error_handler,
-                                              client);
-  client->mst = GNUNET_MST_create (&service_client_mst_cb,
-                                  client);
-  if (NULL != sh->connect_cb)
-    client->user_context = sh->connect_cb (sh->cb_cls,
-                                           client,
-                                           client->mq);
-  GNUNET_MQ_set_handlers_closure (client->mq,
-                                  client->user_context);
-  client->recv_task
-    = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                    client->sock,
-                                    &service_client_recv,
-                                    client);
-}
-
-
-/**
- * Check if the given IP address is in the list of IP addresses.
- *
- * @param list a list of networks
- * @param add the IP to check (in network byte order)
- * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
- */
-static int
-check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
-                   const struct in_addr *add)
-{
-  unsigned int i;
-
-  if (NULL == list)
-    return GNUNET_NO;
-  i = 0;
-  while ( (0 != list[i].network.s_addr) ||
-         (0 != list[i].netmask.s_addr) )
-  {
-    if ((add->s_addr & list[i].netmask.s_addr) ==
-        (list[i].network.s_addr & list[i].netmask.s_addr))
-      return GNUNET_YES;
-    i++;
-  }
-  return GNUNET_NO;
-}
-
-
-/**
- * Check if the given IP address is in the list of IP addresses.
- *
- * @param list a list of networks
- * @param ip the IP to check (in network byte order)
- * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
- */
-static int
-check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
-                   const struct in6_addr *ip)
-{
-  unsigned int i;
-  unsigned int j;
-  struct in6_addr zero;
-
-  if (NULL == list)
-    return GNUNET_NO;
-  memset (&zero,
-         0,
-         sizeof (struct in6_addr));
-  i = 0;
-NEXT:
-  while (0 != memcmp (&zero,
-                     &list[i].network,
-                     sizeof (struct in6_addr)))
-  {
-    for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++)
-      if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
-          (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
-      {
-        i++;
-        goto NEXT;
-      }
-    return GNUNET_YES;
-  }
-  return GNUNET_NO;
-}
-
-
-/**
- * We have a client. Accept the incoming socket(s) (and reschedule
- * the listen task).
- *
- * @param cls the `struct ServiceListenContext` of the ready listen socket
- */
-static void
-accept_client (void *cls)
-{
-  struct ServiceListenContext *slc = cls;
-  struct GNUNET_SERVICE_Handle *sh = slc->sh;
-
-  slc->listen_task = NULL;
-  while (1)
-  {
-    struct GNUNET_NETWORK_Handle *sock;
-    const struct sockaddr_in *v4;
-    const struct sockaddr_in6 *v6;
-    struct sockaddr_storage sa;
-    socklen_t addrlen;
-    int ok;
-
-    addrlen = sizeof (sa);
-    sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
-                                        (struct sockaddr *) &sa,
-                                        &addrlen);
-    if (NULL == sock)
-      break;
-    switch (sa.ss_family)
-    {
-    case AF_INET:
-      GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
-      v4 = (const struct sockaddr_in *) &sa;
-      ok = ( ( (NULL == sh->v4_allowed) ||
-              (check_ipv4_listed (sh->v4_allowed,
-                                  &v4->sin_addr))) &&
-            ( (NULL == sh->v4_denied) ||
-              (! check_ipv4_listed (sh->v4_denied,
-                                    &v4->sin_addr)) ) );
-      break;
-    case AF_INET6:
-      GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
-      v6 = (const struct sockaddr_in6 *) &sa;
-      ok = ( ( (NULL == sh->v6_allowed) ||
-              (check_ipv6_listed (sh->v6_allowed,
-                                  &v6->sin6_addr))) &&
-            ( (NULL == sh->v6_denied) ||
-              (! check_ipv6_listed (sh->v6_denied,
-                                    &v6->sin6_addr)) ) );
-      break;
-#ifndef WINDOWS
-    case AF_UNIX:
-      ok = GNUNET_OK;            /* controlled using file-system ACL now */
-      break;
-#endif
-    default:
-      LOG (GNUNET_ERROR_TYPE_WARNING,
-          _("Unknown address family %d\n"),
-          sa.ss_family);
-      return;
-    }
-    if (! ok)
-    {
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-          "Service rejected incoming connection from %s due to policy.\n",
-          GNUNET_a2s ((const struct sockaddr *) &sa,
-                      addrlen));
-      GNUNET_break (GNUNET_OK ==
-                   GNUNET_NETWORK_socket_close (sock));
-      continue;
-    }
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-        "Service accepted incoming connection from %s.\n",
-        GNUNET_a2s ((const struct sockaddr *) &sa,
-                    addrlen));
-    start_client (slc->sh,
-                 sock);
-  }
-  slc->listen_task
-    = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                    slc->listen_socket,
-                                    &accept_client,
-                                    slc);
-}
-
-
-/**
- * Resume accepting connections from the listen socket.
- *
- * @param sh service to resume accepting connections.
- */
-void
-GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
-{
-  struct ServiceListenContext *slc;
-
-  for (slc = sh->slc_head; NULL != slc; slc = slc->next)
-  {
-    GNUNET_assert (NULL == slc->listen_task);
-    slc->listen_task
-      = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                      slc->listen_socket,
-                                      &accept_client,
-                                      slc);
-  }
-}
-
-
-/**
- * Task run to resume receiving data from the client after
- * the client called #GNUNET_SERVICE_client_continue().
- *
- * @param cls our `struct GNUNET_SERVICE_Client`
- */
-static void
-resume_client_receive (void *cls)
-{
-  struct GNUNET_SERVICE_Client *c = cls;
-  int ret;
-
-  c->recv_task = NULL;
-  /* first, check if there is still something in the buffer */
-  ret = GNUNET_MST_next (c->mst,
-                        GNUNET_YES);
-  if (GNUNET_SYSERR == ret)
-  {
-    if (NULL != c->drop_task)
-      GNUNET_SERVICE_client_drop (c);
-    return;
-  }
-  if (GNUNET_NO == ret)
-    return; /* done processing, wait for more later */
-  GNUNET_assert (GNUNET_OK == ret);
-  if (GNUNET_YES == c->needs_continue)
-    return; /* #GNUNET_MST_next() did give a message to the client */
-  /* need to receive more data from the network first */
-  if (NULL != c->recv_task)
-    return;
-  c->recv_task
-    = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                    c->sock,
-                                    &service_client_recv,
-                                    c);
-}
-
-
-/**
- * Continue receiving further messages from the given client.
- * Must be called after each message received.
- *
- * @param c the client to continue receiving from
- */
-void
-GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
-{
-  GNUNET_assert (GNUNET_YES == c->needs_continue);
-  GNUNET_assert (NULL == c->recv_task);
-  c->needs_continue = GNUNET_NO;
-  if (NULL != c->warn_task)
-  {
-    GNUNET_SCHEDULER_cancel (c->warn_task);
-    c->warn_task = NULL;
-  }
-  c->recv_task
-    = GNUNET_SCHEDULER_add_now (&resume_client_receive,
-                               c);
-}
-
-
-/**
- * Disable the warning the server issues if a message is not
- * acknowledged in a timely fashion.  Use this call if a client is
- * intentionally delayed for a while.  Only applies to the current
- * message.
- *
- * @param c client for which to disable the warning
- */
-void
-GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
-{
-  GNUNET_break (NULL != c->warn_task);
-  if (NULL != c->warn_task)
-  {
-    GNUNET_SCHEDULER_cancel (c->warn_task);
-    c->warn_task = NULL;
-  }
-}
-
-
-/**
- * Asynchronously finish dropping the client.
- *
- * @param cls the `struct GNUNET_SERVICE_Client`.
- */
-static void
-finish_client_drop (void *cls)
-{
-  struct GNUNET_SERVICE_Client *c = cls;
-  struct GNUNET_SERVICE_Handle *sh = c->sh;
-
-  c->drop_task = NULL;
-  GNUNET_assert (NULL == c->send_task);
-  GNUNET_assert (NULL == c->recv_task);
-  GNUNET_assert (NULL == c->warn_task);
-  GNUNET_MST_destroy (c->mst);
-  GNUNET_MQ_destroy (c->mq);
-  if (GNUNET_NO == c->persist)
-  {
-    GNUNET_break (GNUNET_OK ==
-                 GNUNET_NETWORK_socket_close (c->sock));
-  }
-  else
-  {
-    GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
-  }
-  GNUNET_free (c);
-  if ( (GNUNET_YES == sh->got_shutdown) &&
-       (GNUNET_NO == have_non_monitor_clients (sh)) )
-    GNUNET_SERVICE_shutdown (sh);
-}
-
-
-/**
- * Ask the server to disconnect from the given client.  This is the
- * same as returning #GNUNET_SYSERR within the check procedure when
- * handling a message, wexcept that it allows dropping of a client even
- * when not handling a message from that client.  The `disconnect_cb`
- * will be called on @a c even if the application closes the connection
- * using this function.
- *
- * @param c client to disconnect now
- */
-void
-GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
-{
-  struct GNUNET_SERVICE_Handle *sh = c->sh;
-
-  if (NULL != c->drop_task)
-  {
-    /* asked to drop twice! */
-    GNUNET_assert (0);
-    return;
-  }
-  GNUNET_CONTAINER_DLL_remove (sh->clients_head,
-                               sh->clients_tail,
-                               c);
-  if (NULL != sh->disconnect_cb)
-    sh->disconnect_cb (sh->cb_cls,
-                       c,
-                       c->user_context);
-  if (NULL != c->warn_task)
-  {
-    GNUNET_SCHEDULER_cancel (c->warn_task);
-    c->warn_task = NULL;
-  }
-  if (NULL != c->recv_task)
-  {
-    GNUNET_SCHEDULER_cancel (c->recv_task);
-    c->recv_task = NULL;
-  }
-  if (NULL != c->send_task)
-  {
-    GNUNET_SCHEDULER_cancel (c->send_task);
-    c->send_task = NULL;
-  }
-  c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop,
-                                           c);
-}
-
-
-/**
- * Explicitly stops the service.
- *
- * @param sh server to shutdown
- */
-void
-GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
-{
-  struct GNUNET_SERVICE_Client *client;
-
-  GNUNET_SERVICE_suspend (sh);
-  sh->got_shutdown = GNUNET_NO;
-  while (NULL != (client = sh->clients_head))
-    GNUNET_SERVICE_client_drop (client);
-}
-
-
-/**
- * Set the 'monitor' flag on this client.  Clients which have been
- * marked as 'monitors' won't prevent the server from shutting down
- * once #GNUNET_SERVICE_stop_listening() has been invoked.  The idea is
- * that for "normal" clients we likely want to allow them to process
- * their requests; however, monitor-clients are likely to 'never'
- * disconnect during shutdown and thus will not be considered when
- * determining if the server should continue to exist after
- * shutdown has been triggered.
- *
- * @param c client to mark as a monitor
- */
-void
-GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
-{
-  c->is_monitor = GNUNET_YES;
-  if ( (GNUNET_YES == c->sh->got_shutdown) &&
-       (GNUNET_NO == have_non_monitor_clients (c->sh)) )
-    GNUNET_SERVICE_shutdown (c->sh);
-}
-
-
-/**
- * Set the persist option on this client.  Indicates that the
- * underlying socket or fd should never really be closed.  Used for
- * indicating process death.
- *
- * @param c client to persist the socket (never to be closed)
- */
-void
-GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
-{
-  c->persist = GNUNET_YES;
-}
-
-
-/**
- * Obtain the message queue of @a c.  Convenience function.
- *
- * @param c the client to continue receiving from
- * @return the message queue of @a c
- */
-struct GNUNET_MQ_Handle *
-GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
-{
-  return c->mq;
-}
-
-
-/* end of service_new.c */
index 37e60e3e4cd399bc963e9f18ddb11bd53bb844ce..85548fd7944a6a7ff53ee203e121cc7065616db6 100644 (file)
@@ -372,15 +372,18 @@ transmit_ready (void *cls,
     return 0;
   }
 
-  GNUNET_assert (1024 >= size && size > 0);
-  GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0);
+  GNUNET_assert ( (1024 >= size) && (size > 0) );
+  GNUNET_assert ( (SOCKS5_step_done > ih->step) && (ih->step >= 0) );
   unsigned char * b = ih->outstep[ih->step];
   unsigned char * e = ih->outstep[ih->step+1];
   GNUNET_assert (e <= &ih->outbuf[1024]);
-  unsigned l = e - b;
-  GNUNET_assert (size >= l && l >= 0);
-  GNUNET_memcpy(buf, b, l);
-  register_reciever (ih, register_reciever_wants(ih));
+  unsigned int l = e - b;
+  GNUNET_assert (size >= l);
+  GNUNET_memcpy (buf,
+                 b,
+                 l);
+  register_reciever (ih,
+                     register_reciever_wants (ih));
   return l;
 }
 
@@ -566,17 +569,25 @@ GNUNET_SOCKS_check_service (const char *service_name,
  */
 struct GNUNET_CONNECTION_Handle *
 GNUNET_SOCKS_do_connect (const char *service_name,
-                          const struct GNUNET_CONFIGURATION_Handle *cfg)
+                         const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   struct GNUNET_SOCKS_Handshake *ih;
   struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */
-  char *host0,*host1,*user,*pass;
-  unsigned long long port0,port1;
-
-  if (GNUNET_YES != GNUNET_SOCKS_check_service (service_name, cfg))
+  char *host0;
+  char *host1;
+  char *user;
+  char *pass;
+  unsigned long long port0;
+  unsigned long long port1;
+
+  if (GNUNET_YES !=
+      GNUNET_SOCKS_check_service (service_name, cfg))
     return NULL;
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "SOCKSPORT", &port0))
+      GNUNET_CONFIGURATION_get_value_number (cfg,
+                                             service_name,
+                                             "SOCKSPORT",
+                                             &port0))
     port0 = 9050;
   /* A typical Tor client should usually try port 9150 for the TBB too, but
    * GNUnet can probably assume a system Tor installation. */
@@ -588,16 +599,23 @@ GNUNET_SOCKS_do_connect (const char *service_name,
          service_name);
     return NULL;
   }
-  if ((GNUNET_OK !=
-       GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port1))
-      || (port1 > 65535) || (port1 <= 0) ||
+  if ( (GNUNET_OK !=
+        GNUNET_CONFIGURATION_get_value_number (cfg,
+                                               service_name,
+                                               "PORT",
+                                               &port1)) ||
+       (port1 > 65535) ||
+       (port1 <= 0) ||
        (GNUNET_OK !=
-        GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME", &host1)))
+        GNUNET_CONFIGURATION_get_value_string (cfg,
+                                               service_name,
+                                               "HOSTNAME",
+                                               &host1)))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
-        _
-        ("Attempting to proxy service `%s' to invalid port %d or hostname `%s'.\n"),
-        service_name,port1,host1);
+        _("Attempting to proxy service `%s' to invalid port %d or hostname.\n"),
+        service_name,
+         port1);
     return NULL;
   }
   /* Appeared to still work after host0 corrupted, so either test case is broken, or
@@ -605,20 +623,32 @@ GNUNET_SOCKS_do_connect (const char *service_name,
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0))
     host0 = NULL;
-  socks5 = GNUNET_CONNECTION_create_from_connect (cfg, (host0 != NULL)? host0:"127.0.0.1", port0);
+  socks5 = GNUNET_CONNECTION_create_from_connect (cfg,
+                                                  (host0 != NULL)
+                                                  ? host0
+                                                  :"127.0.0.1",
+                                                  port0);
   GNUNET_free_non_null (host0);
 
   /* Sets to NULL if they do not exist */
-  (void) GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSUSER", &user);
-  (void) GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSPASS", &pass);
+  (void) GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                service_name,
+                                                "SOCKSUSER",
+                                                &user);
+  (void) GNUNET_CONFIGURATION_get_value_string (cfg,
+                                                service_name,
+                                                "SOCKSPASS",
+                                                &pass);
   ih = GNUNET_SOCKS_init_handshake(user,pass);
-  if (NULL != user) GNUNET_free (user);
-  if (NULL != pass) GNUNET_free (pass);
+  GNUNET_free_non_null (user);
+  GNUNET_free_non_null (pass);
 
-  GNUNET_SOCKS_set_handshake_destination (ih,host1,port1);
+  GNUNET_SOCKS_set_handshake_destination (ih,
+                                          host1,
+                                          port1);
   GNUNET_free (host1);
-
-  return GNUNET_SOCKS_run_handshake(ih,socks5);
+  return GNUNET_SOCKS_run_handshake (ih,
+                                     socks5);
 }
 
 /* socks.c */
index f60e5b7f7513a9f55b932ff9cf874d37f353d768..527b400b050aba11dbe426b7789a972421f09635 100644 (file)
@@ -179,7 +179,7 @@ main (int argc,
     test_argv[2] = "test_client_unix.conf";
   global_ret = 1;
   if (0 !=
-      GNUNET_SERVICE_ruN_ (3,
+      GNUNET_SERVICE_run_ (3,
                           test_argv,
                           "test_client",
                           GNUNET_SERVICE_OPTION_NONE,
index 4ef98b6298e850210535105e1c2ccc8d72c202c0..4d1b6fe7d4dcb844599d166328f05690dfbd62a1 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2001, 2002, 2003, 2005, 2006 GNUnet e.V.
+     Copyright (C) 2001, 2002, 2003, 2005, 2006, 2017 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
@@ -25,6 +25,7 @@
 #include "platform.h"
 #include "gnunet_util_lib.h"
 
+
 static int
 check ()
 {
@@ -95,47 +96,57 @@ check ()
   if (ptrs[0] != NULL)
     return 9;
 
-       /* GNUNET_new_array_2d tests */
-       a2 = GNUNET_new_array_2d (17, 22, unsigned int);
-       for (i = 0; i < 17; i++)
-       {
-               for (j = 0; j < 22; j++)
-               {
-                       if (0 != a2[i][j])
-                               return 10;
-                       a2[i][j] = i * 100 + j;
-               }
-       }
-       free (a2);
-
-       /* GNUNET_new_array_3d tests */
-       a3 = GNUNET_new_array_3d (2, 3, 4, char);
-       for (i = 0; i < 2; i++)
-       {
-               for (j = 0; j < 3; j++)
-               {
-                       for (k = 0; k < 4; k++)
-                       {
-                               if (0 != a3[i][j][k])
-                                       return 11;
-                               a3[i][j][k] = i * 100 + j * 10 + k;
-                       }
-               }
-       }
-       free (a3);
+  /* GNUNET_new_array_2d tests */
+  a2 = GNUNET_new_array_2d (17, 22, unsigned int);
+  for (i = 0; i < 17; i++)
+  {
+    for (j = 0; j < 22; j++)
+    {
+      if (0 != a2[i][j])
+      {
+        GNUNET_free (a2);
+        return 10;
+      }
+      a2[i][j] = i * 100 + j;
+    }
+  }
+  GNUNET_free (a2);
 
+  /* GNUNET_new_array_3d tests */
+  a3 = GNUNET_new_array_3d (2, 3, 4, char);
+  for (i = 0; i < 2; i++)
+  {
+    for (j = 0; j < 3; j++)
+    {
+      for (k = 0; k < 4; k++)
+      {
+        if (0 != a3[i][j][k])
+        {
+          GNUNET_free (a3);
+          return 11;
+        }
+        a3[i][j][k] = i * 100 + j * 10 + k;
+      }
+    }
+  }
+  GNUNET_free (a3);
   return 0;
 }
 
+
 int
 main (int argc, char *argv[])
 {
   int ret;
 
-  GNUNET_log_setup ("test-common-allocation", "WARNING", NULL);
+  GNUNET_log_setup ("test-common-allocation",
+                    "WARNING",
+                    NULL);
   ret = check ();
   if (ret != 0)
-    FPRINTF (stderr, "ERROR %d.\n", ret);
+    FPRINTF (stderr,
+             "ERROR %d.\n",
+             ret);
   return ret;
 }
 
diff --git a/src/util/test_connection.c b/src/util/test_connection.c
deleted file mode 100644 (file)
index eaca75c..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 12435
-
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONNECTION_Handle *asock;
-
-static struct GNUNET_CONNECTION_Handle *lsock;
-
-static size_t sofar;
-
-static struct GNUNET_NETWORK_Handle *ls;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @return -1 on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket ()
-{
-  const static int on = 1;
-  struct sockaddr_in sa;
-  struct GNUNET_NETWORK_Handle *desc;
-
-  memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_port = htons (PORT);
-  sa.sin_family = AF_INET;
-  desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
-  GNUNET_assert (desc != NULL);
-  if (GNUNET_NETWORK_socket_setsockopt
-      (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
-  GNUNET_assert (GNUNET_OK ==
-                GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
-                                            sizeof (sa)));
-  GNUNET_NETWORK_socket_listen (desc, 5);
-  return desc;
-}
-
-static void
-receive_check (void *cls, const void *buf, size_t available,
-               const struct sockaddr *addr, socklen_t addrlen, int errCode)
-{
-  int *ok = cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive validates incoming data\n");
-  GNUNET_assert (buf != NULL);  /* no timeout */
-  if (0 == memcmp (&"Hello World"[sofar], buf, available))
-    sofar += available;
-  if (sofar < 12)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive needs more data\n");
-    GNUNET_CONNECTION_receive (asock, 1024,
-                               GNUNET_TIME_relative_multiply
-                               (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
-                               cls);
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive closes accepted socket\n");
-    *ok = 0;
-    GNUNET_CONNECTION_destroy (asock);
-    GNUNET_CONNECTION_destroy (csock);
-  }
-}
-
-
-static void
-run_accept (void *cls)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test accepts connection\n");
-  asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls);
-  GNUNET_assert (asock != NULL);
-  GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys listen socket\n");
-  GNUNET_CONNECTION_destroy (lsock);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Test asks to receive on accepted socket\n");
-  GNUNET_CONNECTION_receive (asock, 1024,
-                             GNUNET_TIME_relative_multiply
-                             (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
-                             cls);
-}
-
-
-static size_t
-make_hello (void *cls, size_t size, void *buf)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Test prepares to transmit on connect socket\n");
-  GNUNET_assert (size >= 12);
-  strcpy ((char *) buf, "Hello World");
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys client socket\n");
-  return 12;
-}
-
-
-static void
-task (void *cls)
-{
-  ls = open_listen_socket ();
-  lsock = GNUNET_CONNECTION_create_from_existing (ls);
-  GNUNET_assert (lsock != NULL);
-  csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
-  GNUNET_assert (csock != NULL);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks for write notification\n");
-  GNUNET_assert (NULL !=
-                 GNUNET_CONNECTION_notify_transmit_ready (csock, 12,
-                                                          GNUNET_TIME_UNIT_SECONDS,
-                                                          &make_hello, NULL));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to accept\n");
-  GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept,
-                                 cls);
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  int ok;
-
-  GNUNET_log_setup ("test_connection",
-                    "WARNING",
-                    NULL);
-
-  ok = 1;
-  cfg = GNUNET_CONFIGURATION_create ();
-  GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
-                                         "localhost");
-  GNUNET_SCHEDULER_run (&task, &ok);
-  GNUNET_CONFIGURATION_destroy (cfg);
-  return ok;
-}
-
-/* end of test_connection.c */
diff --git a/src/util/test_connection_addressing.c b/src/util/test_connection_addressing.c
deleted file mode 100644 (file)
index a6345b1..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_addressing.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-
-#define PORT 12435
-
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONNECTION_Handle *asock;
-
-static struct GNUNET_CONNECTION_Handle *lsock;
-
-static size_t sofar;
-
-static struct GNUNET_NETWORK_Handle *ls;
-
-
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @return NULL on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket ()
-{
-  const static int on = 1;
-  struct sockaddr_in sa;
-  struct GNUNET_NETWORK_Handle *desc;
-
-  memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_family = AF_INET;
-  sa.sin_port = htons (PORT);
-  desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
-  GNUNET_assert (desc != 0);
-  if (GNUNET_NETWORK_socket_setsockopt
-      (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
-  if (GNUNET_OK !=
-      GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
-                                  sizeof (sa)))
-  {
-    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-                         "bind");
-    GNUNET_assert (0);
-  }
-  GNUNET_NETWORK_socket_listen (desc, 5);
-  return desc;
-}
-
-
-static void
-receive_check (void *cls, const void *buf, size_t available,
-               const struct sockaddr *addr, socklen_t addrlen, int errCode)
-{
-  int *ok = cls;
-
-  GNUNET_assert (buf != NULL);  /* no timeout */
-  if (0 == memcmp (&"Hello World"[sofar], buf, available))
-    sofar += available;
-  if (sofar < 12)
-  {
-    GNUNET_CONNECTION_receive (asock, 1024,
-                               GNUNET_TIME_relative_multiply
-                               (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
-                               cls);
-  }
-  else
-  {
-    *ok = 0;
-    GNUNET_CONNECTION_destroy (csock);
-    GNUNET_CONNECTION_destroy (asock);
-  }
-}
-
-
-static void
-run_accept (void *cls)
-{
-  void *addr;
-  size_t alen;
-  struct sockaddr_in *v4;
-  struct sockaddr_in expect;
-
-  asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls);
-  GNUNET_assert (asock != NULL);
-  GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CONNECTION_get_address (asock, &addr, &alen));
-  GNUNET_assert (alen == sizeof (struct sockaddr_in));
-  v4 = addr;
-  memset (&expect, 0, sizeof (expect));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  expect.sin_len = sizeof (expect);
-#endif
-  expect.sin_family = AF_INET;
-  expect.sin_port = v4->sin_port;
-  expect.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-  GNUNET_assert (0 == memcmp (&expect, v4, alen));
-  GNUNET_free (addr);
-  GNUNET_CONNECTION_destroy (lsock);
-  GNUNET_CONNECTION_receive (asock, 1024,
-                             GNUNET_TIME_relative_multiply
-                             (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check,
-                             cls);
-}
-
-static size_t
-make_hello (void *cls, size_t size, void *buf)
-{
-  GNUNET_assert (size >= 12);
-  strcpy ((char *) buf, "Hello World");
-  return 12;
-}
-
-
-static void
-task (void *cls)
-{
-  struct sockaddr_in v4;
-
-  ls = open_listen_socket ();
-  lsock = GNUNET_CONNECTION_create_from_existing (ls);
-  GNUNET_assert (lsock != NULL);
-
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  v4.sin_len = sizeof (v4);
-#endif
-  v4.sin_family = AF_INET;
-  v4.sin_port = htons (PORT);
-  v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-  csock =
-      GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
-                                              (const struct sockaddr *) &v4,
-                                              sizeof (v4));
-  GNUNET_assert (csock != NULL);
-  GNUNET_assert (NULL !=
-                 GNUNET_CONNECTION_notify_transmit_ready (csock, 12,
-                                                          GNUNET_TIME_UNIT_SECONDS,
-                                                          &make_hello, NULL));
-  GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept,
-                                 cls);
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  int ok;
-
-  GNUNET_log_setup ("test_connection_addressing",
-                    "WARNING",
-                    NULL);
-  ok = 1;
-  GNUNET_SCHEDULER_run (&task, &ok);
-  return ok;
-}
-
-/* end of test_connection_addressing.c */
diff --git a/src/util/test_connection_receive_cancel.c b/src/util/test_connection_receive_cancel.c
deleted file mode 100644 (file)
index 9c0ab69..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_receive_cancel.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 12435
-
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONNECTION_Handle *asock;
-
-static struct GNUNET_CONNECTION_Handle *lsock;
-
-static struct GNUNET_NETWORK_Handle *ls;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @return NULL on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket ()
-{
-  const static int on = 1;
-  struct sockaddr_in sa;
-  struct GNUNET_NETWORK_Handle *desc;
-
-  memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_family = AF_INET;
-  sa.sin_port = htons (PORT);
-  desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
-  GNUNET_assert (desc != NULL);
-  if (GNUNET_NETWORK_socket_setsockopt
-      (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
-               "setsockopt");
-  GNUNET_assert (GNUNET_OK ==
-                GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
-                                            sizeof (sa)));
-  GNUNET_NETWORK_socket_listen (desc, 5);
-  return desc;
-}
-
-
-static void
-dead_receive (void *cls,
-             const void *buf,
-             size_t available,
-              const struct sockaddr *addr,
-             socklen_t addrlen,
-             int errCode)
-{
-  GNUNET_assert (0);
-}
-
-
-static void
-run_accept_cancel (void *cls)
-{
-  asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls);
-  GNUNET_assert (asock != NULL);
-  GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock));
-  GNUNET_CONNECTION_destroy (lsock);
-  GNUNET_CONNECTION_receive (asock, 1024,
-                             GNUNET_TIME_relative_multiply
-                             (GNUNET_TIME_UNIT_SECONDS, 5),
-                            &dead_receive, cls);
-}
-
-
-static void
-receive_cancel_task (void *cls)
-{
-  int *ok = cls;
-
-  GNUNET_CONNECTION_receive_cancel (asock);
-  GNUNET_CONNECTION_destroy (csock);
-  GNUNET_CONNECTION_destroy (asock);
-  *ok = 0;
-}
-
-
-static void
-task_receive_cancel (void *cls)
-{
-  ls = open_listen_socket ();
-  lsock = GNUNET_CONNECTION_create_from_existing (ls);
-  GNUNET_assert (lsock != NULL);
-  csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
-  GNUNET_assert (csock != NULL);
-  GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
-                                ls,
-                                 &run_accept_cancel,
-                                cls);
-  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
-                               &receive_cancel_task,
-                                cls);
-}
-
-
-/**
- * Main method, starts scheduler with task_timeout.
- */
-static int
-check_receive_cancel ()
-{
-  int ok;
-
-  ok = 1;
-  cfg = GNUNET_CONFIGURATION_create ();
-  GNUNET_CONFIGURATION_set_value_string (cfg,
-                                        "resolver",
-                                        "HOSTNAME",
-                                         "localhost");
-  GNUNET_SCHEDULER_run (&task_receive_cancel, &ok);
-  GNUNET_CONFIGURATION_destroy (cfg);
-  return ok;
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  int ret = 0;
-
-  GNUNET_log_setup ("test_connection_receive_cancel", "WARNING", NULL);
-  ret += check_receive_cancel ();
-
-  return ret;
-}
-
-/* end of test_connection_receive_cancel.c */
diff --git a/src/util/test_connection_timeout.c b/src/util/test_connection_timeout.c
deleted file mode 100644 (file)
index e78cec6..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_timeout.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 12435
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONNECTION_Handle *lsock;
-
-static struct GNUNET_NETWORK_Handle *ls;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-
-/**
- * Create and initialize a listen socket for the server.
- *
- * @return NULL on error, otherwise the listen socket
- */
-static struct GNUNET_NETWORK_Handle *
-open_listen_socket ()
-{
-  const static int on = 1;
-  struct sockaddr_in sa;
-  struct GNUNET_NETWORK_Handle *desc;
-
-  memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_family = AF_INET;
-  sa.sin_port = htons (PORT);
-  desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
-  GNUNET_assert (desc != NULL);
-  if (GNUNET_NETWORK_socket_setsockopt
-      (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK)
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt");
-  GNUNET_assert (GNUNET_OK ==
-                GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa,
-                                            sizeof (sa)));
-  GNUNET_NETWORK_socket_listen (desc, 5);
-  return desc;
-}
-
-
-static size_t
-send_kilo (void *cls, size_t size, void *buf)
-{
-  int *ok = cls;
-
-  if (size == 0)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got the desired timeout!\n");
-    GNUNET_assert (buf == NULL);
-    *ok = 0;
-    GNUNET_CONNECTION_destroy (lsock);
-    GNUNET_CONNECTION_destroy (csock);
-    return 0;
-  }
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending kilo to fill buffer.\n");
-  GNUNET_assert (size >= 1024);
-  memset (buf, 42, 1024);
-
-  GNUNET_assert (NULL !=
-                 GNUNET_CONNECTION_notify_transmit_ready (csock, 1024,
-                                                          GNUNET_TIME_UNIT_SECONDS,
-                                                          &send_kilo, cls));
-  return 1024;
-}
-
-
-static void
-task_timeout (void *cls)
-{
-
-  ls = open_listen_socket ();
-  lsock = GNUNET_CONNECTION_create_from_existing (ls);
-  GNUNET_assert (lsock != NULL);
-  csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
-  GNUNET_assert (csock != NULL);
-  GNUNET_assert (NULL !=
-                 GNUNET_CONNECTION_notify_transmit_ready (csock, 1024,
-                                                          GNUNET_TIME_UNIT_SECONDS,
-                                                          &send_kilo, cls));
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  int ok;
-
-  GNUNET_log_setup ("test_connection_timeout",
-                    "WARNING",
-                    NULL);
-
-  ok = 1;
-  cfg = GNUNET_CONFIGURATION_create ();
-  GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
-                                         "localhost");
-  GNUNET_SCHEDULER_run (&task_timeout, &ok);
-  GNUNET_CONFIGURATION_destroy (cfg);
-  return ok;
-}
-
-/* end of test_connection_timeout.c */
diff --git a/src/util/test_connection_timeout_no_connect.c b/src/util/test_connection_timeout_no_connect.c
deleted file mode 100644 (file)
index ebcd4b7..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_timeout_no_connect.c
- * @brief tests for connection.c, doing timeout which connect failure
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 13425
-
-static struct GNUNET_CONNECTION_Handle *csock;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-static size_t
-handle_timeout (void *cls, size_t size, void *buf)
-{
-  int *ok = cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received timeout signal.\n");
-  GNUNET_assert (size == 0);
-  GNUNET_assert (buf == NULL);
-  *ok = 0;
-  return 0;
-}
-
-
-static void
-task_timeout (void *cls)
-{
-  csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
-  GNUNET_assert (csock != NULL);
-  GNUNET_assert (NULL !=
-                 GNUNET_CONNECTION_notify_transmit_ready (csock, 1024,
-                                                          GNUNET_TIME_UNIT_SECONDS,
-                                                          &handle_timeout,
-                                                          cls));
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  int ok;
-
-  GNUNET_log_setup ("test_connection_timeout_no_connect",
-                    "WARNING",
-                    NULL);
-  ok = 1;
-  cfg = GNUNET_CONFIGURATION_create ();
-  GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
-                                         "localhost");
-  GNUNET_SCHEDULER_run (&task_timeout, &ok);
-  GNUNET_CONFIGURATION_destroy (cfg);
-  return ok;
-}
-
-/* end of test_connection_timeout_no_connect.c */
diff --git a/src/util/test_connection_transmit_cancel.c b/src/util/test_connection_transmit_cancel.c
deleted file mode 100644 (file)
index 9ef0720..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_connection_transmit_cancel.c
- * @brief tests for connection.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 12435
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-
-static size_t
-not_run (void *cls, size_t size, void *buf)
-{
-  GNUNET_assert (0);
-  return 0;
-}
-
-
-static void
-task_transmit_cancel (void *cls)
-{
-  int *ok = cls;
-  struct GNUNET_CONNECTION_TransmitHandle *th;
-  struct GNUNET_CONNECTION_Handle *csock;
-
-  csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT);
-  GNUNET_assert (csock != NULL);
-  th = GNUNET_CONNECTION_notify_transmit_ready (csock, 12,
-                                                GNUNET_TIME_UNIT_MINUTES,
-                                                &not_run, cls);
-  GNUNET_assert (NULL != th);
-  GNUNET_CONNECTION_notify_transmit_ready_cancel (th);
-  GNUNET_CONNECTION_destroy (csock);
-  *ok = 0;
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  int ok;
-
-  GNUNET_log_setup ("test_connection_transmit_cancel",
-                    "WARNING",
-                    NULL);
-  ok = 1;
-  cfg = GNUNET_CONFIGURATION_create ();
-  GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
-                                         "localhost");
-  GNUNET_SCHEDULER_run (&task_transmit_cancel, &ok);
-  GNUNET_CONFIGURATION_destroy (cfg);
-  return ok;
-}
-
-/* end of test_connection_transmit_cancel.c */
index 8e578640dd9b3b226b917f266a0e82ba17416999..13cedd7f51786793c523ce7ad008fa71410c7b90 100644 (file)
@@ -136,13 +136,16 @@ testLogOpts ()
     GNUNET_GETOPT_OPTION_END
   };
 
-  if (5 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 5, myargv))
+  if (5 != GNUNET_GETOPT_run ("test_getopt",
+                              logoptionlist,
+                              5, myargv))
   {
     GNUNET_break (0);
     return 1;
   }
-  GNUNET_assert (fn != NULL);
-  if ((0 != strcmp (level, "WARNING")) || (0 != strcmp (fn, "filename")))
+  GNUNET_assert (NULL != fn);
+  if ( (0 != strcmp (level, "WARNING")) ||
+       (NULL == strstr (fn, "/filename")) )
   {
     GNUNET_break (0);
     GNUNET_free (level);
@@ -170,21 +173,35 @@ testFlagNum ()
   unsigned long long lnum = 0;
 
   const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = {
-    {'f', "--flag", NULL, "helptext", 0, &GNUNET_GETOPT_set_one,
-     (void *) &flag},
-    {'n', "--num", "ARG", "helptext", 1, &GNUNET_GETOPT_set_uint,
-     (void *) &num},
-    {'N', "--lnum", "ARG", "helptext", 1, &GNUNET_GETOPT_set_ulong,
-     (void *) &lnum},
+    GNUNET_GETOPT_OPTION_SET_ONE ('f',
+                                  "--flag",
+                                  "helptext",
+                                  &flag),
+    GNUNET_GETOPT_OPTION_SET_UINT ('n',
+                                   "--num",
+                                   "ARG",
+                                   "helptext",
+                                   &num),
+    GNUNET_GETOPT_OPTION_SET_ULONG ('N',
+                                    "--lnum",
+                                    "ARG",
+                                    "helptext",
+                                    &lnum),
     GNUNET_GETOPT_OPTION_END
   };
 
-  if (6 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 6, myargv))
+  if (6 !=
+      GNUNET_GETOPT_run ("test_getopt",
+                         logoptionlist,
+                         6,
+                         myargv))
   {
     GNUNET_break (0);
     return 1;
   }
-  if ((1 != flag) || (42 != num) || (42 != lnum))
+  if ( (1 != flag) ||
+       (42 != num) ||
+       (42 != lnum))
   {
     GNUNET_break (0);
     return 1;
@@ -198,7 +215,9 @@ main (int argc, char *argv[])
 {
   int errCnt = 0;
 
-  GNUNET_log_setup ("test_getopt", "WARNING", NULL);
+  GNUNET_log_setup ("test_getopt",
+                    "WARNING",
+                    NULL);
   /* suppress output from -h, -v options */
 #ifndef MINGW
   GNUNET_break (0 == CLOSE (1));
index 669cee7bdc1ea4670c0f123f81bd4b3732051a9d..d206952af9ab1fb8a38b6926e3f1e8991a401f3a 100644 (file)
 #include "platform.h"
 #include "gnunet_util_lib.h"
 
-static int setme1, setme2;
-
-static struct GNUNET_GETOPT_CommandLineOption options1[] = {
-  {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1},
-  GNUNET_GETOPT_OPTION_END
-};
-
-static struct GNUNET_GETOPT_CommandLineOption options2[] = {
-  {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1},
-  {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2},
-  GNUNET_GETOPT_OPTION_END
-};
-
-static struct GNUNET_GETOPT_CommandLineOption options3[] = {
-  {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1},
-  {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2},
-  GNUNET_GETOPT_OPTION_END
-};
-
-static struct GNUNET_GETOPT_CommandLineOption options4[] = {
-  {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1},
-  {'n', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2},
-  GNUNET_GETOPT_OPTION_END
-};
+
+static int setme1;
+
+static int setme2;
+
 
 /**
  * Main function that will be run.
  */
-
 static void
-runner (void *cls, char *const *args, const char *cfgfile,
+runner (void *cls,
+        char *const *args,
+        const char *cfgfile,
         const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
   int *ok = cls;
@@ -62,21 +44,16 @@ runner (void *cls, char *const *args, const char *cfgfile,
   GNUNET_assert (setme1 == 1);
   GNUNET_assert (0 == strcmp (args[0], "extra"));
   GNUNET_assert (args[1] == NULL);
-  GNUNET_assert (0 == strcmp (cfgfile, "test_program_data.conf"));
-
+  GNUNET_assert (NULL != strstr (cfgfile, "/test_program_data.conf"));
   *ok = 0;
 }
 
-/**
- * Main method, starts scheduler with task1,
- * checks that "ok" is correct at the end.
- */
-static int
-check ()
+
+int
+main (int argc, char *argv[])
 {
   int ok = 1;
-
-  char *const argv[] = {
+  char *const argvx[] = {
     "test_program",
     "-c",
     "test_program_data.conf",
@@ -86,33 +63,75 @@ check ()
     "extra",
     NULL
   };
+  struct GNUNET_GETOPT_CommandLineOption options1[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "name",
+                                  "description",
+                                  &setme1),
+    GNUNET_GETOPT_OPTION_END
+  };
+  struct GNUNET_GETOPT_CommandLineOption options2[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "name",
+                                  "description",
+                                  &setme1),
+    GNUNET_GETOPT_OPTION_SET_ONE ('N',
+                                  "number",
+                                  "description",
+                                  &setme2),
+    GNUNET_GETOPT_OPTION_END
+  };
+  struct GNUNET_GETOPT_CommandLineOption options3[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('N',
+                                  "number",
+                                  "description",
+                                  &setme1),
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "name",
+                                  "description",
+                                  &setme2),
+    GNUNET_GETOPT_OPTION_END
+  };
+  struct GNUNET_GETOPT_CommandLineOption options4[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "name",
+                                  "description",
+                                  &setme1),
+    GNUNET_GETOPT_OPTION_SET_ONE ('n',
+                                  "name",
+                                  "description",
+                                  &setme2),
+    GNUNET_GETOPT_OPTION_END
+  };
 
+
+  GNUNET_log_setup ("test_program",
+                    "WARNING",
+                    NULL);
   GNUNET_assert (GNUNET_OK ==
-                 GNUNET_PROGRAM_run (7, argv, "test_program", "A test",
-                                     options1, &runner, &ok));
+                 GNUNET_PROGRAM_run (7, argvx,
+                                     "test_program",
+                                     "A test",
+                                     options1,
+                                     &runner, &ok));
 
   GNUNET_assert (GNUNET_OK ==
-                 GNUNET_PROGRAM_run (7, argv, "test_program", "A test",
-                                     options2, &runner, &ok));
+                 GNUNET_PROGRAM_run (7, argvx,
+                                     "test_program", "A test",
+                                     options2,
+                                     &runner, &ok));
   GNUNET_assert (GNUNET_OK ==
-                 GNUNET_PROGRAM_run (7, argv, "test_program", "A test",
-                                     options3, &runner, &ok));
+                 GNUNET_PROGRAM_run (7, argvx,
+                                     "test_program", "A test",
+                                     options3,
+                                     &runner, &ok));
   GNUNET_assert (GNUNET_OK ==
-                 GNUNET_PROGRAM_run (7, argv, "test_program", "A test",
-                                     options4, &runner, &ok));
+                 GNUNET_PROGRAM_run (7, argvx,
+                                     "test_program", "A test",
+                                     options4,
+                                     &runner, &ok));
 
   return ok;
 }
 
-int
-main (int argc, char *argv[])
-{
-  int ret = 0;
-
-  GNUNET_log_setup ("test_program", "WARNING", NULL);
-  ret += check ();
-
-  return ret;
-}
-
 /* end of test_program.c */
diff --git a/src/util/test_server.c b/src/util/test_server.c
deleted file mode 100644 (file)
index 8003adb..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009, 2010, 2014, 2016 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server.c
- * @brief tests for server.c
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-/**
- * TCP port to use for the server.
- */
-#define PORT 12435
-
-/**
- * Timeout to use for operations.
- */
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2)
-
-/**
- * Test message type.
- */
-#define MY_TYPE 128
-
-/**
- * Test message type.
- */
-#define MY_TYPE2 129
-
-/**
- * Handle for the server.
- */
-static struct GNUNET_SERVER_Handle *server;
-
-/**
- * Handle for the client.
- */
-static struct GNUNET_MQ_Handle *mq;
-
-/**
- * Handle of the server for the client.
- */
-static struct GNUNET_SERVER_Client *argclient;
-
-/**
- * Our configuration.
- */
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-/**
- * Number indiciating in which phase of the test we are.
- */
-static int ok;
-
-
-/**
- * Final task invoked to clean up.
- *
- * @param cls NULL
- */
-static void
-finish_up (void *cls)
-{
-  GNUNET_assert (7 == ok);
-  ok = 0;
-  GNUNET_SERVER_destroy (server);
-  GNUNET_MQ_destroy (mq);
-  GNUNET_CONFIGURATION_destroy (cfg);
-}
-
-
-/**
- * The server has received the second message, initiate clean up.
- *
- * @param cls NULL
- * @param client client we got the message from
- * @param message the message
- */
-static void
-recv_fin_cb (void *cls,
-             struct GNUNET_SERVER_Client *client,
-             const struct GNUNET_MessageHeader *message)
-{
-  GNUNET_assert (6 == ok);
-  ok = 7;
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-  GNUNET_SCHEDULER_add_now (&finish_up, NULL);
-}
-
-
-/**
- * We have received the reply from the server, check that we are at
- * the right stage and queue the next message to the server.  Cleans
- * up #argclient.
- *
- * @param cls NULL
- * @param msg message we got from the server
- */
-static void
-handle_reply (void *cls,
-              const struct GNUNET_MessageHeader *msg)
-{
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *m;
-
-  GNUNET_assert (4 == ok);
-  ok = 6;
-  env = GNUNET_MQ_msg (m,
-                       MY_TYPE2);
-  GNUNET_MQ_send (mq,
-                  env);
-}
-
-
-/**
- * Send a reply of type #MY_TYPE from the server to the client.
- * Checks that we are in the right phase and transmits the
- * reply.  Cleans up #argclient state.
- *
- * @param cls NULL
- * @param size number of bytes we are allowed to send
- * @param buf where to copy the reply
- * @return number of bytes written to @a buf
- */
-static size_t
-reply_msg (void *cls,
-           size_t size,
-           void *buf)
-{
-  struct GNUNET_MessageHeader msg;
-
-  GNUNET_assert (3 == ok);
-  ok = 4;
-  GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
-  msg.type = htons (MY_TYPE);
-  msg.size = htons (sizeof (struct GNUNET_MessageHeader));
-  GNUNET_memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader));
-  GNUNET_assert (NULL != argclient);
-  GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
-  GNUNET_SERVER_client_drop (argclient);
-  argclient = NULL;
-  return sizeof (struct GNUNET_MessageHeader);
-}
-
-
-/**
- * Function called whenever the server receives a message of
- * type #MY_TYPE.  Checks that we are at the stage where
- * we expect the first message, then sends a reply.  Stores
- * the handle to the client in #argclient.
- *
- * @param cls NULL
- * @param client client that sent the message
- * @param message the message we received
- */
-static void
-recv_cb (void *cls,
-         struct GNUNET_SERVER_Client *client,
-         const struct GNUNET_MessageHeader *message)
-{
-  GNUNET_assert (2 == ok);
-  ok = 3;
-  argclient = client;
-  GNUNET_SERVER_client_keep (argclient);
-  GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size));
-  GNUNET_assert (MY_TYPE == ntohs (message->type));
-  GNUNET_assert (NULL !=
-                 GNUNET_SERVER_notify_transmit_ready (client,
-                                                      ntohs (message->size),
-                                                      TIMEOUT,
-                                                      &reply_msg,
-                                                      NULL));
-}
-
-
-/**
- * Message handlers for the server.
- */
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
-  {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
-  {&recv_fin_cb, NULL, MY_TYPE2, sizeof (struct GNUNET_MessageHeader)},
-  {NULL, NULL, 0, 0}
-};
-
-
-/**
- * Generic error handler, called with the appropriate error code and
- * the same closure specified at the creation of the message queue.
- * Not every message queue implementation supports an error handler.
- *
- * @param cls closure with the `struct GNUNET_STATISTICS_Handle *`
- * @param error error code
- */
-static void
-mq_error_handler (void *cls,
-                  enum GNUNET_MQ_Error error)
-{
-  GNUNET_assert (0); /* should never happen */
-}
-
-
-/**
- * First task run by the scheduler.  Initializes the server and
- * a client and asks for a transmission from the client to the
- * server.
- *
- * @param cls NULL
- */
-static void
-task (void *cls)
-{
-  struct sockaddr_in sa;
-  struct sockaddr *sap[2];
-  socklen_t slens[2];
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *msg;
-  struct GNUNET_MQ_MessageHandler chandlers[] = {
-    GNUNET_MQ_hd_fixed_size (reply,
-                             MY_TYPE,
-                             struct GNUNET_MessageHeader,
-                             cls),
-    GNUNET_MQ_handler_end ()
-  };
-
-  sap[0] = (struct sockaddr *) &sa;
-  slens[0] = sizeof (sa);
-  sap[1] = NULL;
-  slens[1] = 0;
-  memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_family = AF_INET;
-  sa.sin_port = htons (PORT);
-  server = GNUNET_SERVER_create (NULL, NULL,
-                                 sap, slens,
-                                 TIMEOUT, GNUNET_NO);
-  GNUNET_assert (server != NULL);
-  GNUNET_SERVER_add_handlers (server, handlers);
-  cfg = GNUNET_CONFIGURATION_create ();
-  GNUNET_CONFIGURATION_set_value_number (cfg,
-                                         "test-server",
-                                         "PORT",
-                                         PORT);
-  GNUNET_CONFIGURATION_set_value_string (cfg,
-                                         "test-server",
-                                         "HOSTNAME",
-                                         "localhost");
-  GNUNET_CONFIGURATION_set_value_string (cfg,
-                                         "resolver",
-                                         "HOSTNAME",
-                                         "localhost");
-  mq = GNUNET_CLIENT_connect (cfg,
-                              "test-server",
-                              chandlers,
-                              &mq_error_handler,
-                              NULL);
-  GNUNET_assert (NULL != mq);
-  ok = 2;
-  env = GNUNET_MQ_msg (msg,
-                       MY_TYPE);
-  GNUNET_MQ_send (mq,
-                  env);
-}
-
-
-/**
- * Runs the test.
- *
- * @param argc length of @a argv
- * @param argv command line arguments (ignored)
- * @return 0 on success, otherwise phase of failure
- */
-int
-main (int argc, char *argv[])
-{
-  GNUNET_log_setup ("test_server",
-                    "WARNING",
-                    NULL);
-  ok = 1;
-  GNUNET_SCHEDULER_run (&task, &ok);
-  return ok;
-}
-
-/* end of test_server.c */
diff --git a/src/util/test_server_disconnect.c b/src/util/test_server_disconnect.c
deleted file mode 100644 (file)
index c3d003e..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009, 2010, 2016 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server_disconnect.c
- * @brief tests for server.c,  specifically GNUNET_SERVER_client_disconnect
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-
-#define PORT 12435
-
-#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
-
-#define MY_TYPE 128
-
-static struct GNUNET_SERVER_Handle *server;
-
-static struct GNUNET_MQ_Handle *mq;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-static int ok;
-
-
-static void
-finish_up (void *cls)
-{
-  GNUNET_assert (ok == 5);
-  ok = 0;
-  GNUNET_SERVER_destroy (server);
-  GNUNET_MQ_destroy (mq);
-  GNUNET_CONFIGURATION_destroy (cfg);
-}
-
-
-static void
-notify_disconnect (void *cls,
-                   struct GNUNET_SERVER_Client *clientarg)
-{
-  if (NULL == clientarg)
-    return;
-  GNUNET_assert (ok == 4);
-  ok = 5;
-  GNUNET_SCHEDULER_add_now (&finish_up, NULL);
-}
-
-
-static void
-server_disconnect (void *cls)
-{
-  struct GNUNET_SERVER_Client *argclient = cls;
-
-  GNUNET_assert (ok == 3);
-  ok = 4;
-  GNUNET_SERVER_client_disconnect (argclient);
-  GNUNET_SERVER_client_drop (argclient);
-}
-
-
-static void
-recv_cb (void *cls,
-        struct GNUNET_SERVER_Client *client,
-         const struct GNUNET_MessageHeader *message)
-{
-  GNUNET_assert (ok == 2);
-  ok = 3;
-  GNUNET_SERVER_client_keep (client);
-  GNUNET_SCHEDULER_add_now (&server_disconnect, client);
-  GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size));
-  GNUNET_assert (MY_TYPE == ntohs (message->type));
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
-  {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
-  {NULL, NULL, 0, 0}
-};
-
-
-static void
-task (void *cls)
-{
-  struct sockaddr_in sa;
-  struct sockaddr *sap[2];
-  socklen_t slens[2];
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *msg;
-
-  sap[0] = (struct sockaddr *) &sa;
-  slens[0] = sizeof (sa);
-  sap[1] = NULL;
-  slens[1] = 0;
-  memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_family = AF_INET;
-  sa.sin_port = htons (PORT);
-  server = GNUNET_SERVER_create (NULL, NULL, sap, slens, TIMEOUT, GNUNET_NO);
-  GNUNET_assert (server != NULL);
-  GNUNET_SERVER_add_handlers (server, handlers);
-  GNUNET_SERVER_disconnect_notify (server, &notify_disconnect, NULL);
-  cfg = GNUNET_CONFIGURATION_create ();
-  GNUNET_CONFIGURATION_set_value_number (cfg, "test-server", "PORT", PORT);
-  GNUNET_CONFIGURATION_set_value_string (cfg, "test-server", "HOSTNAME",
-                                         "localhost");
-  GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
-                                         "localhost");
-  mq = GNUNET_CLIENT_connect (cfg,
-                              "test-server",
-                              NULL,
-                              NULL,
-                              NULL);
-  GNUNET_assert (NULL != mq);
-  ok = 2;
-  env = GNUNET_MQ_msg (msg,
-                       MY_TYPE);
-  GNUNET_MQ_send (mq,
-                  env);
-}
-
-
-/**
- * Main method, starts scheduler with task1,
- * checks that "ok" is correct at the end.
- */
-static int
-check ()
-{
-  ok = 1;
-  GNUNET_SCHEDULER_run (&task, &ok);
-  return ok;
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  int ret = 0;
-
-  GNUNET_log_setup ("test_server_disconnect", "WARNING", NULL);
-  ret += check ();
-
-  return ret;
-}
-
-/* end of test_server_disconnect.c */
diff --git a/src/util/test_server_mst_interrupt.c b/src/util/test_server_mst_interrupt.c
deleted file mode 100644 (file)
index 3141a75..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009, 2010 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server_mst_interrupt.c
- * @brief test for interrupt message processing in server_mst.c
- */
-#include "platform.h"
-#include "gnunet_protocols.h"
-#include "gnunet_util_lib.h"
-
-static struct GNUNET_SERVER_MessageStreamTokenizer * mst;
-
-
-/* Callback destroying mst with data in buffer */
-static int
-mst_cb (void *cls, void *client,
-        const struct GNUNET_MessageHeader * message)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MST gave me message, destroying\n");
-  GNUNET_SERVER_mst_destroy (mst);
-  return GNUNET_SYSERR;
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  struct GNUNET_PeerIdentity id;
-  struct GNUNET_MessageHeader msg[2];
-
-  GNUNET_log_setup ("test_server_mst_interrupt", "WARNING", NULL);
-  memset (&id, 0, sizeof (id));
-  msg[0].size = htons (sizeof (msg));
-  msg[0].type = htons (sizeof (GNUNET_MESSAGE_TYPE_DUMMY));
-  mst = GNUNET_SERVER_mst_create(mst_cb, NULL);
-  GNUNET_SERVER_mst_receive (mst, &id,
-                            (const char *) &msg, 2 * sizeof (msg),
-                            GNUNET_NO, GNUNET_NO);
-  /* If we reach this line, it did not crash */
-  return 0;
-}
-
-/* end of test_server_mst_interrupt.c */
diff --git a/src/util/test_server_with_client.c b/src/util/test_server_with_client.c
deleted file mode 100644 (file)
index 63bfda0..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009, 2016 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server_with_client.c
- * @brief tests for server.c and client.c,
- *       specifically disconnect_notify,
- *       client_get_address and receive_done (resume processing)
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define PORT 22335
-
-#define MY_TYPE 128
-
-
-static struct GNUNET_SERVER_Handle *server;
-
-static struct GNUNET_MQ_Handle *mq;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-static int ok;
-
-
-static void
-send_done (void *cls)
-{
-  struct GNUNET_SERVER_Client *argclient = cls;
-
-  GNUNET_assert (ok == 3);
-  ok++;
-  GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
-}
-
-
-static void
-recv_cb (void *cls,
-         struct GNUNET_SERVER_Client *argclient,
-         const struct GNUNET_MessageHeader *message)
-{
-  void *addr;
-  size_t addrlen;
-  struct sockaddr_in sa;
-  struct sockaddr_in *have;
-
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_SERVER_client_get_address (argclient,
-                                                   &addr,
-                                                   &addrlen));
-
-  GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
-  have = addr;
-  memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_family = AF_INET;
-  sa.sin_port = have->sin_port;
-  sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-  GNUNET_assert (0 == memcmp (&sa, addr, addrlen));
-  GNUNET_free (addr);
-  switch (ok)
-  {
-  case 2:
-    ok++;
-    GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
-                                  (GNUNET_TIME_UNIT_MILLISECONDS, 50),
-                                  &send_done,
-                                  argclient);
-    break;
-  case 4:
-    ok++;
-    GNUNET_MQ_destroy (mq);
-    GNUNET_SERVER_receive_done (argclient,
-                                GNUNET_OK);
-    break;
-  default:
-    GNUNET_assert (0);
-  }
-
-}
-
-
-static void
-clean_up (void *cls)
-{
-  GNUNET_SERVER_destroy (server);
-  server = NULL;
-  GNUNET_CONFIGURATION_destroy (cfg);
-  cfg = NULL;
-}
-
-
-/**
- * Functions with this signature are called whenever a client
- * is disconnected on the network level.
- *
- * @param cls closure
- * @param client identification of the client
- */
-static void
-notify_disconnect (void *cls,
-                   struct GNUNET_SERVER_Client *client)
-{
-  if (client == NULL)
-    return;
-  GNUNET_assert (ok == 5);
-  ok = 0;
-  GNUNET_SCHEDULER_add_now (&clean_up, NULL);
-}
-
-
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
-  {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
-  {NULL, NULL, 0, 0}
-};
-
-
-static void
-task (void *cls)
-{
-  struct sockaddr_in sa;
-  struct sockaddr *sap[2];
-  socklen_t slens[2];
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *msg;
-
-  sap[0] = (struct sockaddr *) &sa;
-  slens[0] = sizeof (sa);
-  sap[1] = NULL;
-  slens[1] = 0;
-  memset (&sa, 0, sizeof (sa));
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sa.sin_len = sizeof (sa);
-#endif
-  sa.sin_family = AF_INET;
-  sa.sin_port = htons (PORT);
-  server =
-      GNUNET_SERVER_create (NULL, NULL, sap, slens,
-                            GNUNET_TIME_relative_multiply
-                            (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO);
-  GNUNET_assert (server != NULL);
-  handlers[0].callback_cls = cls;
-  GNUNET_SERVER_add_handlers (server, handlers);
-  GNUNET_SERVER_disconnect_notify (server, &notify_disconnect, cls);
-  cfg = GNUNET_CONFIGURATION_create ();
-  GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT);
-  GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", "localhost");
-  GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
-                                         "localhost");
-  mq = GNUNET_CLIENT_connect (cfg,
-                              "test",
-                              NULL,
-                              NULL,
-                              NULL);
-  GNUNET_assert (NULL != mq);
-  ok = 2;
-  env = GNUNET_MQ_msg (msg,
-                       MY_TYPE);
-  GNUNET_MQ_send (mq,
-                  env);
-  env = GNUNET_MQ_msg (msg,
-                       MY_TYPE);
-  GNUNET_MQ_send (mq,
-                  env);
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  GNUNET_log_setup ("test_server_with_client",
-                    "WARNING",
-                    NULL);
-  ok = 1;
-  GNUNET_SCHEDULER_run (&task, NULL);
-  return ok;
-}
-
-/* end of test_server_with_client.c */
diff --git a/src/util/test_server_with_client_unix.c b/src/util/test_server_with_client_unix.c
deleted file mode 100644 (file)
index 8fabbe2..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
-     This file is part of GNUnet.
-     Copyright (C) 2009, 2016 GNUnet e.V.
-
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
-
-     GNUnet is distributed in the hope that it will be useful, but
-     WITHOUT ANY WARRANTY; without even the implied warranty of
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
-*/
-/**
- * @file util/test_server_with_client_unix.c
- * @brief tests for server.c and client.c,
- *       specifically disconnect_notify,
- *       client_get_address and receive_done (resume processing)
- */
-#include "platform.h"
-#include "gnunet_util_lib.h"
-
-#define MY_TYPE 128
-
-
-static struct GNUNET_SERVER_Handle *server;
-
-static struct GNUNET_MQ_Handle *mq;
-
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-
-static int ok;
-
-
-static void
-send_done (void *cls)
-{
-  struct GNUNET_SERVER_Client *argclient = cls;
-
-  GNUNET_assert (ok == 3);
-  ok++;
-  GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
-}
-
-
-static void
-recv_cb (void *cls,
-        struct GNUNET_SERVER_Client *argclient,
-         const struct GNUNET_MessageHeader *message)
-{
-  switch (ok)
-  {
-  case 2:
-    ok++;
-    (void) GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
-                                        (GNUNET_TIME_UNIT_MILLISECONDS, 50),
-                                        &send_done,
-                                        argclient);
-    break;
-  case 4:
-    ok++;
-    GNUNET_MQ_destroy (mq);
-    GNUNET_SERVER_receive_done (argclient, GNUNET_OK);
-    break;
-  default:
-    GNUNET_assert (0);
-  }
-
-}
-
-
-static void
-clean_up (void *cls)
-{
-  GNUNET_SERVER_destroy (server);
-  server = NULL;
-  GNUNET_CONFIGURATION_destroy (cfg);
-  cfg = NULL;
-}
-
-
-/**
- * Functions with this signature are called whenever a client
- * is disconnected on the network level.
- *
- * @param cls closure
- * @param client identification of the client
- */
-static void
-notify_disconnect (void *cls,
-                  struct GNUNET_SERVER_Client *client)
-{
-  if (client == NULL)
-    return;
-  GNUNET_assert (ok == 5);
-  ok = 0;
-  (void) GNUNET_SCHEDULER_add_now (&clean_up, NULL);
-}
-
-
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
-  {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)},
-  {NULL, NULL, 0, 0}
-};
-
-
-static void
-task (void *cls)
-{
-  struct sockaddr_un un;
-  const char *unixpath = "/tmp/testsock";
-  struct sockaddr *sap[2];
-  socklen_t slens[2];
-  struct GNUNET_MQ_Envelope *env;
-  struct GNUNET_MessageHeader *msg;
-
-  memset (&un, 0, sizeof (un));
-  un.sun_family = AF_UNIX;
-  strncpy(un.sun_path, unixpath, sizeof (un.sun_path) - 1);
-#if HAVE_SOCKADDR_UN_SUN_LEN
-  un.sun_len = (u_char) sizeof (un);
-#endif
-
-  sap[0] = (struct sockaddr *) &un;
-  slens[0] = sizeof (un);
-  sap[1] = NULL;
-  slens[1] = 0;
-  server =
-      GNUNET_SERVER_create (NULL, NULL, sap, slens,
-                            GNUNET_TIME_relative_multiply
-                            (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO);
-  GNUNET_assert (server != NULL);
-  handlers[0].callback_cls = cls;
-  GNUNET_SERVER_add_handlers (server, handlers);
-  GNUNET_SERVER_disconnect_notify (server, &notify_disconnect, cls);
-  cfg = GNUNET_CONFIGURATION_create ();
-
-  GNUNET_CONFIGURATION_set_value_string (cfg, "test", "UNIXPATH", unixpath);
-  GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME",
-                                         "localhost");
-  mq = GNUNET_CLIENT_connect (cfg,
-                              "test",
-                              NULL,
-                              NULL,
-                              NULL);
-  GNUNET_assert (NULL != mq);
-  ok = 2;
-  env = GNUNET_MQ_msg (msg,
-                       MY_TYPE);
-  GNUNET_MQ_send (mq,
-                  env);
-  env = GNUNET_MQ_msg (msg,
-                       MY_TYPE);
-  GNUNET_MQ_send (mq,
-                  env);
-}
-
-
-int
-main (int argc, char *argv[])
-{
-  GNUNET_log_setup ("test_server_with_client_unix",
-                    "WARNING",
-                    NULL);
-  ok = 1;
-  GNUNET_SCHEDULER_run (&task, NULL);
-  return ok;
-}
-
-/* end of test_server_with_client_unix.c */
index d2136b42f0a8881a89a175e506e79e26ec6eda7b..1567c97ce173bd9e097939e423b39df90e2c44f3 100644 (file)
@@ -148,7 +148,7 @@ check (const char *sname)
              sname);
   global_ret = 1;
   GNUNET_assert (0 ==
-                 GNUNET_SERVICE_ruN_ (3,
+                 GNUNET_SERVICE_run_ (3,
                                      argv,
                                      sname,
                                      GNUNET_SERVICE_OPTION_NONE,
index ecc94ead006a7efd6bd1a3ea7f34f126e1a5a78a..ceb5fdcbba3ceefee3acf249c18f7d2978ec863b 100644 (file)
@@ -37,9 +37,8 @@ GNUNET_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-system-runtime/
 GNUNET_USER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-${USERHOME:-${USER:-user}}-runtime/
 
 
-# Legacy option...
-# GNUNET_TEST_HOME = ~/.gnunet/
-# GNUNET_TEST_HOME = /var/lib/gnunet/
+# Override for GNUNET_HOME used by test cases.
+# GNUNET_TEST_HOME = /tmp/foo/bar
 
 # DEFAULTCONFIG = /etc/gnunet.conf
 # If 'DEFAULTCONFIG' is not defined, the current
index 417d2eb899a0f628953e920e31d701ddec63a3fb..5c16fa349d4811ee268d09ea5a2078a6dbc8a311 100644 (file)
@@ -59,7 +59,7 @@ gnunet_service_vpn_LDADD = \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/tun/libgnunettun.la \
   $(top_builddir)/src/util/libgnunetutil.la \
-  $(top_builddir)/src/cadet/libgnunetcadetnew.la \
+  $(top_builddir)/src/cadet/libgnunetcadet.la \
   $(top_builddir)/src/regex/libgnunetregex.la \
   $(GN_LIBINTL)
 gnunet_service_vpn_CFLAGS = \
index a9596752ad06d169f0cae52902d06491003d8b9e..e74a0aa2f26ceb11f528723416909a3a08796207 100644 (file)
@@ -77,7 +77,7 @@
 static boolean privilege_testing = FALSE;
 
 /**
- * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
  */
 #define MAX_SIZE 65536
 
index 02889d65b972ee4fabba02732e0e8ad6271a202d..4ed4e079eea7a3d0bbef90491918ba51eaa52f3e 100644 (file)
@@ -53,7 +53,7 @@
 #define DEBUG GNUNET_NO
 
 /**
- * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
  */
 #define MAX_SIZE 65536
 
index aa0ea51a32085a0a6d74249973bb3640a4bb8d48..d9daaa7e217571c9bd388d9c79c02ee811ba0b6c 100644 (file)
@@ -1384,7 +1384,7 @@ create_channel (struct ChannelState *ts,
     GNUNET_MQ_handler_end()
   };
 
-  return GNUNET_CADET_channel_creatE (cadet_handle,
+  return GNUNET_CADET_channel_create (cadet_handle,
                                       ts,
                                       target,
                                       port,
@@ -1839,7 +1839,7 @@ route_packet (struct DestinationEntry *destination,
 
       mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
        payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
-      if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
       {
        GNUNET_break (0);
        return;
@@ -1864,7 +1864,7 @@ route_packet (struct DestinationEntry *destination,
 
       mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
        alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
-      if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
       {
        GNUNET_break (0);
        return;
@@ -1904,7 +1904,7 @@ route_packet (struct DestinationEntry *destination,
 
        mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
          payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
-       if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+       if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
        {
          GNUNET_break (0);
          return;
@@ -1927,7 +1927,7 @@ route_packet (struct DestinationEntry *destination,
 
        mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
          alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
-       if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+       if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
        {
          GNUNET_break (0);
          return;
@@ -1963,7 +1963,7 @@ route_packet (struct DestinationEntry *destination,
 
       mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
        payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
-      if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
       {
        GNUNET_break (0);
        return;
@@ -2038,7 +2038,7 @@ route_packet (struct DestinationEntry *destination,
       /* update length calculations, as payload_length may have changed */
       mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
        alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
-      if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
       {
        GNUNET_break (0);
        return;
@@ -2061,6 +2061,7 @@ route_packet (struct DestinationEntry *destination,
       void *payload;
       uint8_t new_type;
 
+      new_type = icmp->type;
       /* Perform ICMP protocol-translation (depending on destination AF and source AF)
         and throw away ICMP payload depending on ICMP message type */
       switch (af)
@@ -2111,8 +2112,8 @@ route_packet (struct DestinationEntry *destination,
        switch (icmp->type)
          {
          case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
-           if (destination->details.exit_destination.af == AF_INET6)
-             new_type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
+           if (destination->details.exit_destination.af == AF_INET)
+             new_type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
            /* throw away IP-payload, exit will have to make it up anyway */
            payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
            break;
@@ -2167,7 +2168,7 @@ route_packet (struct DestinationEntry *destination,
       /* update length calculations, as payload_length may have changed */
       mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
        alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
-      if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+      if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
       {
        GNUNET_break (0);
        return;
@@ -2216,12 +2217,10 @@ route_packet (struct DestinationEntry *destination,
  * and forward the packet.
  *
  * @param cls closure, NULL
- * @param client NULL
  * @param message message we got from the client (VPN channel interface)
  */
 static int
 message_token (void *cls,
-              void *client,
                const struct GNUNET_MessageHeader *message)
 {
   const struct GNUNET_TUN_Layer2PacketHeader *tun;
@@ -3067,7 +3066,7 @@ run (void *cls,
   }
   vpn_argv[6] = NULL;
 
-  cadet_handle = GNUNET_CADET_connecT (cfg_);
+  cadet_handle = GNUNET_CADET_connect (cfg_);
     // FIXME never opens ports???
   helper_handle = GNUNET_HELPER_start (GNUNET_NO,
                                       "gnunet-helper-vpn", vpn_argv,
index 2e7daf7f7291b11f396034341cdb37c0fa38bf72..0adbd5c96f7f6d4bdebb3e96b3628854c8b95926 100644 (file)
@@ -78,7 +78,7 @@ static int udp;
 /**
  * Selected level of verbosity.
  */
-static int verbosity;
+static unsigned int verbosity;
 
 /**
  * Global return value.
@@ -286,33 +286,53 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'4', "ipv4", NULL,
-     gettext_noop ("request that result should be an IPv4 address"),
-     0, &GNUNET_GETOPT_set_one, &ipv4},
-    {'6', "ipv6", NULL,
-     gettext_noop ("request that result should be an IPv6 address"),
-     0, &GNUNET_GETOPT_set_one, &ipv6},
-    {'d', "duration", "TIME",
-     gettext_noop ("how long should the mapping be valid for new tunnels?"),
-     1, &GNUNET_GETOPT_set_relative_time, &duration},
-    {'i', "ip", "IP",
-     gettext_noop ("destination IP for the tunnel"),
-     1, &GNUNET_GETOPT_set_string, &target_ip},
-    {'p', "peer", "PEERID",
-     gettext_noop ("peer offering the service we would like to access"),
-     1, &GNUNET_GETOPT_set_string, &peer_id},
-    {'s', "service", "NAME",
-     gettext_noop ("name of the service we would like to access"),
-     1, &GNUNET_GETOPT_set_string, &service_name},
-    {'t', "tcp", NULL,
-     gettext_noop ("service is offered via TCP"),
-     0, &GNUNET_GETOPT_set_one, &tcp},
-    {'u', "udp", NULL,
-     gettext_noop ("service is offered via UDP"),
-     0, &GNUNET_GETOPT_set_one, &udp},
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_OPTION_SET_ONE ('4',
+                                  "ipv4",
+                                  gettext_noop ("request that result should be an IPv4 address"),
+                                  &ipv4),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('6',
+                                  "ipv6",
+                                  gettext_noop ("request that result should be an IPv6 address"),
+                                  &ipv6),
+
+    GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('d',
+                                            "duration",
+                                            "TIME",
+                                            gettext_noop ("how long should the mapping be valid for new tunnels?"),
+                                            &duration),
+
+    GNUNET_GETOPT_OPTION_STRING ('i',
+                                 "ip",
+                                 "IP",
+                                 gettext_noop ("destination IP for the tunnel"),
+                                 &target_ip),
+
+    GNUNET_GETOPT_OPTION_STRING ('p',
+                                 "peer",
+                                 "PEERID",
+                                 gettext_noop ("peer offering the service we would like to access"),
+                                 &peer_id),
+
+    GNUNET_GETOPT_OPTION_STRING ('s', 
+                                 "service",
+                                 "NAME",
+                                 gettext_noop ("name of the service we would like to access"),
+                                 &service_name),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('t',
+                                  "tcp",
+                                  gettext_noop ("service is offered via TCP"),
+                                  &tcp),
+
+    GNUNET_GETOPT_OPTION_SET_ONE ('u',
+                                  "udp",
+                                  gettext_noop ("service is offered via UDP"),
+                                  &udp),
 
     GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
+
     GNUNET_GETOPT_OPTION_END
   };
   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))