From bcf3298c5eb79dd98bfc8ccf58793703aac70f49 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 11 Mar 2017 12:53:18 +0100 Subject: [PATCH] remove old CADET service code --- src/cadet/Makefile.am | 26 +- src/cadet/gnunet-service-cadet.c | 184 - src/cadet/gnunet-service-cadet_channel.c | 2562 ------------- src/cadet/gnunet-service-cadet_channel.h | 363 -- src/cadet/gnunet-service-cadet_connection.c | 3713 ------------------- src/cadet/gnunet-service-cadet_connection.h | 576 --- src/cadet/gnunet-service-cadet_dht.c | 424 --- src/cadet/gnunet-service-cadet_dht.h | 93 - src/cadet/gnunet-service-cadet_hello.c | 200 - src/cadet/gnunet-service-cadet_hello.h | 79 - src/cadet/gnunet-service-cadet_local.c | 1553 -------- src/cadet/gnunet-service-cadet_local.h | 234 -- src/cadet/gnunet-service-cadet_peer.c | 2209 ----------- src/cadet/gnunet-service-cadet_peer.h | 483 --- src/cadet/gnunet-service-cadet_tunnel.c | 3501 ----------------- src/cadet/gnunet-service-cadet_tunnel.h | 616 --- 16 files changed, 1 insertion(+), 16815 deletions(-) delete mode 100644 src/cadet/gnunet-service-cadet.c delete mode 100644 src/cadet/gnunet-service-cadet_channel.c delete mode 100644 src/cadet/gnunet-service-cadet_channel.h delete mode 100644 src/cadet/gnunet-service-cadet_connection.c delete mode 100644 src/cadet/gnunet-service-cadet_connection.h delete mode 100644 src/cadet/gnunet-service-cadet_dht.c delete mode 100644 src/cadet/gnunet-service-cadet_dht.h delete mode 100644 src/cadet/gnunet-service-cadet_hello.c delete mode 100644 src/cadet/gnunet-service-cadet_hello.h delete mode 100644 src/cadet/gnunet-service-cadet_local.c delete mode 100644 src/cadet/gnunet-service-cadet_local.h delete mode 100644 src/cadet/gnunet-service-cadet_peer.c delete mode 100644 src/cadet/gnunet-service-cadet_peer.h delete mode 100644 src/cadet/gnunet-service-cadet_tunnel.c delete mode 100644 src/cadet/gnunet-service-cadet_tunnel.h diff --git a/src/cadet/Makefile.am b/src/cadet/Makefile.am index b52079b2e..518646664 100644 --- a/src/cadet/Makefile.am +++ b/src/cadet/Makefile.am @@ -22,7 +22,6 @@ plugindir = $(libdir)/gnunet AM_CLFAGS = -g libexec_PROGRAMS = \ - gnunet-service-cadet \ gnunet-service-cadet-new \ $(EXP_LIBEXEC) @@ -81,31 +80,8 @@ gnunet_service_cadet_new_LDADD = \ $(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_channel.c gnunet-service-cadet_channel.h \ - gnunet-service-cadet_local.c gnunet-service-cadet_local.h \ - gnunet-service-cadet_peer.c gnunet-service-cadet_peer.h \ - gnunet-service-cadet_dht.c gnunet-service-cadet_dht.h \ - gnunet-service-cadet_hello.c gnunet-service-cadet_hello.h \ - cadet_path.c cadet_path.h \ - cadet_common.c \ - gnunet-service-cadet.c -gnunet_service_cadet_CFLAGS = $(AM_CFLAGS) -gnunet_service_cadet_LDADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/transport/libgnunettransport.la \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/ats/libgnunetats.la \ - $(top_builddir)/src/dht/libgnunetdht.la \ - $(top_builddir)/src/statistics/libgnunetstatistics.la \ - $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ - $(top_builddir)/src/hello/libgnunethello.la \ - $(top_builddir)/src/block/libgnunetblock.la if LINUX - gnunet_service_cadet_LDFLAGS = -lrt + gnunet_service_cadet_new_LDFLAGS = -lrt endif diff --git a/src/cadet/gnunet-service-cadet.c b/src/cadet/gnunet-service-cadet.c deleted file mode 100644 index 3a07f0ee5..000000000 --- a/src/cadet/gnunet-service-cadet.c +++ /dev/null @@ -1,184 +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/gnunet-service-cadet.c - * @brief GNUnet CADET service with encryption - * @author Bartlomiej Polot - * - * FIXME in progress: - * - rekey - reliability interaction - * - channel retransmit timing - * - * TODO: - * - relay corking down to core - * - set ttl relative to path length - * TODO END - * - * Dictionary: - * - peer: other cadet instance. If there is direct connection it's a neighbor. - * - tunnel: encrypted connection to a peer, neighbor or not. - * - channel: connection between two clients, on the same or different peers. - * have properties like reliability. - * - path: series of directly connected peer from one peer to another. - * - connection: path which is being used in a tunnel. - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "cadet.h" -#include "gnunet_statistics_service.h" - -#include "gnunet-service-cadet_local.h" -#include "gnunet-service-cadet_channel.h" -#include "gnunet-service-cadet_connection.h" -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_dht.h" -#include "gnunet-service-cadet_peer.h" -#include "gnunet-service-cadet_hello.h" - - -/******************************************************************************/ -/*********************** GLOBAL VARIABLES ****************************/ -/******************************************************************************/ - -/****************************** Global variables ******************************/ - -/** - * Handle to the statistics service. - */ -struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -GNUNET_PEER_Id myid; - -/** - * Local peer own ID (full value). - */ -struct GNUNET_PeerIdentity my_full_id; - - -/** - * Signal that shutdown is happening: prevent recover measures. - */ -int shutting_down; - -/*************************** Static global variables **************************/ - -/** - * Own private key. - */ -static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; - - -/******************************************************************************/ -/************************ MAIN FUNCTIONS ****************************/ -/******************************************************************************/ - -/** - * Task run during shutdown. - * - * @param cls unused - */ -static void -shutdown_task (void *cls) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "shutting down\n"); - - shutting_down = GNUNET_YES; - - 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"); -} - - -/** - * Process cadet requests. - * - * @param cls closure - * @param server the initialized server - * @param c configuration to use - */ -static void -run (void *cls, struct GNUNET_SERVER_Handle *server, - const struct GNUNET_CONFIGURATION_Handle *c) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "starting to run\n"); - - stats = GNUNET_STATISTICS_create ("cadet", c); - - /* Scheduled the task to clean up when shutdown is called */ - GNUNET_SCHEDULER_add_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 */ - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cadet service running\n"); -} - - -/** - * The main function for the cadet service. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, char *const *argv) -{ - int r; - - shutting_down = GNUNET_NO; - r = GNUNET_SERVICE_run (argc, argv, "cadet", GNUNET_SERVICE_OPTION_NONE, &run, - NULL); - GNUNET_free (my_private_key); - - if (GNUNET_OK != r) - { - FPRINTF (stderr, "GNUNET_SERVICE_run for CADET has failed!\n"); - return 1; - } - - return 0; -} diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c deleted file mode 100644 index 7b7c6e57c..000000000 --- a/src/cadet/gnunet-service-cadet_channel.c +++ /dev/null @@ -1,2562 +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" - -#include "gnunet-service-cadet_channel.h" -#include "gnunet-service-cadet_local.h" -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_peer.h" - -#define LOG(level, ...) GNUNET_log_from(level,"cadet-chn",__VA_ARGS__) -#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__) - -#define CADET_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(\ - GNUNET_TIME_UNIT_MILLISECONDS, 250) -#define CADET_RETRANSMIT_MARGIN 4 - - -/** - * All the states a connection can be in. - */ -enum CadetChannelState -{ - /** - * Uninitialized status, should never appear in operation. - */ - CADET_CHANNEL_NEW, - - /** - * Connection create message sent, waiting for ACK. - */ - CADET_CHANNEL_SENT, - - /** - * Connection confirmed, ready to carry traffic. - */ - CADET_CHANNEL_READY -}; - - -/** - * Info holder for channel messages in queues. - */ -struct CadetChannelQueue -{ - /** - * Tunnel Queue. - */ - struct CadetTunnelQueue *tq; - - /** - * Message type (DATA/DATA_ACK) - */ - uint16_t type; - - /** - * Message copy (for DATAs, to start retransmission timer) - */ - struct CadetReliableMessage *copy; - - /** - * Reliability (for DATA_ACKs, to access rel->ack_q) - */ - struct CadetChannelReliability *rel; -}; - - -/** - * Info needed to retry a message in case it gets lost. - */ -struct CadetReliableMessage -{ - /** - * Double linked list, FIFO style - */ - struct CadetReliableMessage *next; - struct CadetReliableMessage *prev; - - /** - * Type of message (payload, channel management). - */ - int16_t type; - - /** - * Tunnel Reliability queue this message is in. - */ - struct CadetChannelReliability *rel; - - /** - * ID of the message (ACK needed to free) - */ - uint32_t mid; - - /** - * Tunnel Queue. - */ - struct CadetChannelQueue *chq; - - /** - * When was this message issued (to calculate ACK delay) - */ - struct GNUNET_TIME_Absolute timestamp; - - /* struct GNUNET_CADET_ChannelAppDataMessage with payload */ -}; - - -/** - * Info about the traffic state for a client in a channel. - */ -struct CadetChannelReliability -{ - /** - * Channel this is about. - */ - struct CadetChannel *ch; - - /** - * DLL of messages sent and not yet ACK'd. - */ - struct CadetReliableMessage *head_sent; - struct CadetReliableMessage *tail_sent; - - /** - * DLL of messages received out of order. - */ - struct CadetReliableMessage *head_recv; - struct CadetReliableMessage *tail_recv; - - /** - * Messages received. - */ - unsigned int n_recv; - - /** - * Next MID to use for outgoing traffic. - */ - uint32_t mid_send; - - /** - * Next MID expected for incoming traffic. - */ - uint32_t mid_recv; - - /** - * Handle for queued unique data CREATE, DATA_ACK. - */ - struct CadetChannelQueue *uniq; - - /** - * Can we send data to the client? - */ - int client_ready; - - /** - * Can the client send data to us? - */ - int client_allowed; - - /** - * Task to resend/poll in case no ACK is received. - */ - struct GNUNET_SCHEDULER_Task * retry_task; - - /** - * Counter for exponential backoff. - */ - struct GNUNET_TIME_Relative retry_timer; - - /** - * How long does it usually take to get an ACK. - */ - struct GNUNET_TIME_Relative expected_delay; -}; - - -/** - * Struct containing all information regarding a channel to a remote client. - */ -struct CadetChannel -{ - /** - * Tunnel this channel is in. - */ - struct CadetTunnel *t; - - /** - * Destination port of the channel. - */ - struct GNUNET_HashCode port; - - /** - * Global channel number ( < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) - */ - struct GNUNET_CADET_ChannelTunnelNumber gid; - - /** - * Local tunnel number for root (owner) client. - * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 ) - */ - struct GNUNET_CADET_ClientChannelNumber lid_root; - - /** - * Local tunnel number for local destination clients (incoming number) - * ( >= GNUNET_CADET_LOCAL_CHANNEL_ID_SERV or 0). - */ - struct GNUNET_CADET_ClientChannelNumber lid_dest; - - /** - * Channel state. - */ - enum CadetChannelState state; - - /** - * Is the tunnel bufferless (minimum latency)? - */ - int nobuffer; - - /** - * Is the tunnel reliable? - */ - int reliable; - - /** - * Last time the channel was used - */ - struct GNUNET_TIME_Absolute timestamp; - - /** - * Client owner of the tunnel, if any - */ - struct CadetClient *root; - - /** - * Client destination of the tunnel, if any. - */ - struct CadetClient *dest; - - /** - * Flag to signal the destruction of the channel. - * If this is set to #GNUNET_YES the channel will be destroyed - * when the queue is empty. - */ - int destroy; - - /** - * Total (reliable) messages pending ACK for this channel. - */ - unsigned int pending_messages; - - /** - * Reliability data. - * Only present (non-NULL) at the owner of a tunnel. - */ - struct CadetChannelReliability *root_rel; - - /** - * Reliability data. - * Only present (non-NULL) at the destination of a tunnel. - */ - struct CadetChannelReliability *dest_rel; - -}; - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -extern GNUNET_PEER_Id myid; - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - - -/** - * Destroy a reliable message after it has been acknowledged, either by - * direct mid ACK or bitfield. Updates the appropriate data structures and - * timers and frees all memory. - * - * @param copy Message that is no longer needed: remote peer got it. - * @param update_time Is the timing information relevant? - * If this message is ACK in a batch the timing information - * is skewed by the retransmission, count only for the - * retransmitted message. - * - * @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. - * - * @param ch Channel for which to send. - */ -static void -send_create (struct CadetChannel *ch); - -/** - * Confirm we got a channel create, FWD ack. - * - * @param ch The channel to confirm. - * @param fwd Should we send a FWD ACK? (going dest->root) - */ -static void -send_ack (struct CadetChannel *ch, int fwd); - - - -/** - * Test if the channel is loopback: both root and dest are on the local peer. - * - * @param ch Channel to test. - * - * @return #GNUNET_YES if channel is loopback, #GNUNET_NO otherwise. - */ -static int -is_loopback (const struct CadetChannel *ch) -{ - if (NULL != ch->t) - return GCT_is_loopback (ch->t); - - return (NULL != ch->root && NULL != ch->dest); -} - - -/** - * Save a copy of the data message for later retransmission. - * - * @param msg Message to copy. - * @param mid Message ID. - * @param rel Reliability data for retransmission. - */ -static struct CadetReliableMessage * -copy_message (const struct GNUNET_CADET_ChannelAppDataMessage *msg, uint32_t mid, - struct CadetChannelReliability *rel) -{ - struct CadetReliableMessage *copy; - uint16_t size; - - size = ntohs (msg->header.size); - copy = GNUNET_malloc (sizeof (*copy) + size); - copy->mid = mid; - copy->rel = rel; - copy->type = GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA; - GNUNET_memcpy (©[1], msg, size); - - return copy; -} - -/** - * We have received a message out of order, or the client is not ready. - * Buffer it until we receive an ACK from the client or the missing - * message from the channel. - * - * @param msg Message to buffer (MUST be of type CADET_DATA). - * @param rel Reliability data to the corresponding direction. - */ -static void -add_buffered_data (const struct GNUNET_CADET_ChannelAppDataMessage *msg, - struct CadetChannelReliability *rel) -{ - struct CadetReliableMessage *copy; - struct CadetReliableMessage *prev; - uint32_t mid; - - mid = ntohl (msg->mid); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "add_buffered_data 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) - { - 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)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " bingo!\n"); - copy = copy_message (msg, mid, rel); - GNUNET_CONTAINER_DLL_insert_before (rel->head_recv, rel->tail_recv, - prev, copy); - return; - } - } - copy = copy_message (msg, mid, rel); - LOG (GNUNET_ERROR_TYPE_DEBUG, " insert at tail! (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"); -} - - -/** - * Add a destination client to a channel, initializing all data structures - * in the channel and the client. - * - * @param ch Channel to which add the destination. - * @param c Client which to add to the channel. - */ -static void -add_destination (struct CadetChannel *ch, struct CadetClient *c) -{ - if (NULL != ch->dest) - { - GNUNET_break (0); - return; - } - - /* Assign local id as destination */ - ch->lid_dest = GML_get_next_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; -} - - -/** - * Set options in a channel, extracted from a bit flag field. - * - * @param ch Channel to set options to. - * @param options Bit array in host byte order. - */ -static void -channel_set_options (struct CadetChannel *ch, uint32_t options) -{ - ch->nobuffer = (options & GNUNET_CADET_OPTION_NOBUFFER) != 0 ? - GNUNET_YES : GNUNET_NO; - ch->reliable = (options & GNUNET_CADET_OPTION_RELIABLE) != 0 ? - GNUNET_YES : GNUNET_NO; -} - - -/** - * Get a bit flag field with the options of a channel. - * - * @param ch Channel to get options from. - * - * @return Bit array in host byte order. - */ -static uint32_t -channel_get_options (struct CadetChannel *ch) -{ - uint32_t options; - - options = 0; - if (ch->nobuffer) - options |= GNUNET_CADET_OPTION_NOBUFFER; - if (ch->reliable) - options |= GNUNET_CADET_OPTION_RELIABLE; - - return options; -} - - -/** - * Notify a client that the channel is no longer valid. - * - * @param ch Channel that is destroyed. - * @param local_only Should we avoid sending it to other peers? - */ -static void -send_destroy (struct CadetChannel *ch, int local_only) -{ - struct GNUNET_CADET_ChannelManageMessage msg; - - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); - msg.header.size = htons (sizeof (msg)); - msg.ctn = ch->gid; - - /* If root is not NULL, notify. - * If it's NULL, check lid_root. When a local destroy comes in, root - * is set to NULL but lid_root is left untouched. In this case, do nothing, - * the client is the one who requested the channel to be destroyed. - */ - if (NULL != ch->root) - GML_send_channel_destroy (ch->root, ch->lid_root); - else if (0 == ch->lid_root.channel_of_client && GNUNET_NO == local_only) - GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_NO, NULL); - - if (NULL != ch->dest) - GML_send_channel_destroy (ch->dest, ch->lid_dest); - else if (0 == ch->lid_dest.channel_of_client && GNUNET_NO == local_only) - GCCH_send_prebuilt_message (&msg.header, ch, GNUNET_YES, NULL); -} - - -/** - * Notify the destination client that a new incoming channel was created. - * - * @param ch Channel that was created. - */ -static void -send_client_create (struct CadetChannel *ch) -{ - uint32_t opt; - - if (NULL == ch->dest) - return; - - opt = 0; - opt |= GNUNET_YES == ch->reliable ? GNUNET_CADET_OPTION_RELIABLE : 0; - opt |= GNUNET_YES == ch->nobuffer ? GNUNET_CADET_OPTION_NOBUFFER : 0; - GML_send_channel_create (ch->dest, - ch->lid_dest, - &ch->port, - opt, - GCT_get_destination (ch->t)); - -} - - -/** - * Send data to a client. - * - * If the client is ready, send directly, otherwise buffer while listening - * for a local ACK. - * - * @param ch Channel - * @param msg Message. - * @param fwd Is this a fwd (root->dest) message? - */ -static void -send_client_data (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelAppDataMessage *msg, - int fwd) -{ - if (fwd) - { - 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); - } - 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); - } -} - - -/** - * Send a buffered message to the client, for in order delivery or - * as result of client ACK. - * - * @param ch Channel on which to empty the message buffer. - * @param c Client to send to. - * @param fwd Is this to send FWD data?. - */ -static void -send_client_buffered_data (struct CadetChannel *ch, - struct CadetClient *c, - int fwd) -{ - struct CadetReliableMessage *copy; - struct CadetChannelReliability *rel; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "send_buffered_data\n"); - rel = fwd ? ch->dest_rel : ch->root_rel; - if (GNUNET_NO == rel->client_ready) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "client not ready\n"); - return; - } - - copy = rel->head_recv; - /* We never buffer channel management messages */ - if (NULL != copy) - { - if (copy->mid == rel->mid_recv || GNUNET_NO == ch->reliable) - { - struct GNUNET_CADET_ChannelAppDataMessage *msg = (struct GNUNET_CADET_ChannelAppDataMessage *) ©[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"); -} - - -/** - * Allow a client to send more data. - * - * In case the client was already allowed to send data, do nothing. - * - * @param ch Channel. - * @param fwd Is this a FWD ACK? (FWD ACKs are sent to root) - */ -static void -send_client_ack (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel = fwd ? ch->root_rel : ch->dest_rel; - struct CadetClient *c = fwd ? ch->root : ch->dest; - - if (NULL == c) - { - GNUNET_break (GNUNET_NO != ch->destroy); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, - " sending %s ack to client on channel %s\n", - 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); -} - - -/** - * We haven't received an ACK after a certain time: restransmit the message. - * - * @param cls Closure (CadetChannelReliability with the message to restransmit) - */ -static void -channel_retransmit_message (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 *) ©[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); - - GCCH_send_prebuilt_message (&payload->header, ch, fwd, copy); - GNUNET_STATISTICS_update (stats, "# data retransmitted", 1, GNUNET_NO); -} - - -/** - * We haven't received an Channel ACK after a certain time: resend the CREATE. - * - * @param cls Closure (CadetChannelReliability of the channel to recreate) - */ -static void -channel_recreate (void *cls) -{ - struct CadetChannelReliability *rel = cls; - - rel->retry_task = NULL; - LOG (GNUNET_ERROR_TYPE_DEBUG, "RE-CREATE\n"); - GNUNET_STATISTICS_update (stats, - "# data retransmitted", 1, GNUNET_NO); - - if (rel == rel->ch->root_rel) - { - send_create (rel->ch); - } - else if (rel == rel->ch->dest_rel) - { - send_ack (rel->ch, GNUNET_YES); - } - else - { - GNUNET_break (0); - } -} - - -/** - * Message has been sent: start retransmission timer. - * - * @param cls Closure (queue structure). - * @param t Tunnel. - * @param q Queue handler (no longer valid). - * @param type Type of message. - * @param size Size of the message. - */ -static void -ch_message_sent (void *cls, - struct CadetTunnel *t, - struct CadetTunnelQueue *q, - uint16_t type, size_t size) -{ - struct CadetChannelQueue *chq = cls; - struct CadetReliableMessage *copy = chq->copy; - struct CadetChannelReliability *rel; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "channel_message_sent callback %s\n", - GC_m2s (chq->type)); - - switch (chq->type) - { - 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); - } - - 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); -} - - -/** - * Confirm we got a channel create or FWD ack. - * - * @param ch The channel to confirm. - * @param fwd Should we send a FWD ACK? (going dest->root) - */ -static void -send_ack (struct CadetChannel *ch, int fwd) -{ - struct GNUNET_CADET_ChannelManageMessage msg; - - 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); -} - - -/** - * Send a message and don't keep any info about it: we won't need to cancel it - * or resend it. - * - * @param msg Header of the message to fire away. - * @param ch Channel on which the message should go. - * @param force Is this a forced (undroppable) message? - */ -static void -fire_and_forget (const struct GNUNET_MessageHeader *msg, - struct CadetChannel *ch, - int force) -{ - GNUNET_break (NULL == - GCT_send_prebuilt_message (msg, ch->t, NULL, - force, NULL, NULL)); -} - - -/** - * Notify that a channel create didn't succeed. - * - * @param ch The channel to reject. - */ -static void -send_nack (struct CadetChannel *ch) -{ - struct GNUNET_CADET_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", - GCCH_2s (ch)); - - 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) - { - 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); - } - for (copy = rel->head_sent; NULL != copy; copy = next) - { - next = copy->next; - GNUNET_CONTAINER_DLL_remove (rel->head_sent, rel->tail_sent, copy); - LOG (GNUNET_ERROR_TYPE_DEBUG, " COPYFREE 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); - } - if (NULL != rel->uniq && NULL != rel->uniq->tq) - { - GCT_cancel (rel->uniq->tq); - /* ch_message_sent is called freeing uniq */ - } - if (NULL != rel->retry_task) - { - GNUNET_SCHEDULER_cancel (rel->retry_task); - rel->retry_task = NULL; - } - GNUNET_free (rel); -} - - -/** - * Mark future messages as ACK'd. - * - * @param rel Reliability data. - * @param msg DataACK message with a bitfield of future ACK'd messages. - * - * @return How many messages have been freed. - */ -static unsigned int -channel_rel_free_sent (struct CadetChannelReliability *rel, - const struct GNUNET_CADET_ChannelDataAckMessage *msg) -{ - 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++) - { - 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) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "run out of copies...\n"); - return r; - } - - /* Did we overshoot the target? (previously freed, it's ok) */ - if (GC_is_pid_bigger (copy->mid, target)) - { - 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; - } - - /* Now copy->mid == target, free it */ - next = copy->next; - GNUNET_break (GNUNET_YES != rel_message_free (copy, GNUNET_YES)); - r++; - copy = next; - } - 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. - * - * @return #GNUNET_YES if channel was destroyed as a result of the call, - * #GNUNET_NO otherwise. - */ -static int -rel_message_free (struct CadetReliableMessage *copy, int update_time) -{ - struct CadetChannelReliability *rel; - struct GNUNET_TIME_Relative time; - - rel = copy->rel; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Freeing %u\n", copy->mid); - if (GNUNET_YES == update_time) - { - time = GNUNET_TIME_absolute_get_duration (copy->timestamp); - if (0 == rel->expected_delay.rel_value_us) - rel->expected_delay = time; - else - { - rel->expected_delay.rel_value_us *= 7; - rel->expected_delay.rel_value_us += time.rel_value_us; - rel->expected_delay.rel_value_us /= 8; - } - LOG (GNUNET_ERROR_TYPE_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; - } - 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); - return GNUNET_YES; - } - return GNUNET_NO; -} - - -/** - * Channel was ACK'd by remote peer, mark as ready and cancel retransmission. - * - * @param ch Channel to mark as ready. - * @param fwd Was the ACK message a FWD ACK? (dest->root, SYNACK) - */ -static void -channel_confirm (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel; - enum CadetChannelState oldstate; - - rel = fwd ? ch->root_rel : ch->dest_rel; - if (NULL == rel) - { - GNUNET_break (GNUNET_NO != ch->destroy); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " channel confirm %s %s\n", - GC_f2s (fwd), GCCH_2s (ch)); - oldstate = ch->state; - ch->state = CADET_CHANNEL_READY; - - if (CADET_CHANNEL_READY != oldstate || GNUNET_YES == is_loopback (ch)) - { - rel->client_ready = GNUNET_YES; - rel->expected_delay = rel->retry_timer; - LOG (GNUNET_ERROR_TYPE_DEBUG, " 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) - { - GNUNET_SCHEDULER_cancel (rel->retry_task); - rel->retry_task = NULL; - } - else if (NULL != rel->uniq) - { - GCT_cancel (rel->uniq->tq); - /* ch_message_sent will free and NULL uniq */ - } - else if (GNUNET_NO == is_loopback (ch)) - { - /* We SHOULD have been trying to retransmit this! */ - GNUNET_break (0); - } - } - - /* In case of a FWD ACK (SYNACK) send a BCK ACK (ACK). */ - if (GNUNET_YES == fwd) - send_ack (ch, GNUNET_NO); -} - - -/** - * Save a copy to retransmit in case it gets lost. - * - * Initializes all needed callbacks and timers. - * - * @param ch Channel this message goes on. - * @param msg Message to copy. - * @param fwd Is this fwd traffic? - */ -static struct CadetReliableMessage * -channel_save_copy (struct CadetChannel *ch, - const struct GNUNET_MessageHeader *msg, - int fwd) -{ - struct CadetChannelReliability *rel; - struct CadetReliableMessage *copy; - uint32_t mid; - uint16_t type; - uint16_t size; - - rel = fwd ? ch->root_rel : ch->dest_rel; - mid = rel->mid_send - 1; - type = ntohs (msg->type); - size = ntohs (msg->size); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "save MID %u %s\n", mid, GC_m2s (type)); - copy = GNUNET_malloc (sizeof (struct CadetReliableMessage) + size); - LOG (GNUNET_ERROR_TYPE_DEBUG, " at %p\n", copy); - copy->mid = mid; - copy->rel = rel; - copy->type = type; - GNUNET_memcpy (©[1], msg, size); - GNUNET_CONTAINER_DLL_insert_tail (rel->head_sent, rel->tail_sent, copy); - ch->pending_messages++; - - return copy; -} - - -/** - * Create a new channel. - * - * @param t Tunnel this channel is in. - * @param owner Client that owns the channel, NULL for foreign channels. - * @param lid_root Local ID for root client. - * - * @return A new initialized channel. NULL on error. - */ -static struct CadetChannel * -channel_new (struct CadetTunnel *t, - struct CadetClient *owner, - struct GNUNET_CADET_ClientChannelNumber lid_root) -{ - struct CadetChannel *ch; - - ch = GNUNET_new (struct CadetChannel); - ch->root = owner; - ch->lid_root = lid_root; - ch->t = t; - - GNUNET_STATISTICS_update (stats, "# channels", 1, GNUNET_NO); - - if (NULL != owner) - { - ch->gid = GCT_get_next_ctn (t); - GML_channel_add (owner, lid_root, ch); - } - GCT_add_channel (t, ch); - - return ch; -} - - -/** - * Handle a loopback message: call the appropriate handler for the message type. - * - * @param ch Channel this message is on. - * @param msgh Message header. - * @param fwd Is this FWD traffic? - */ -void -handle_loopback (struct CadetChannel *ch, - const struct GNUNET_MessageHeader *msgh, - int fwd) -{ - uint16_t type; - - type = ntohs (msgh->type); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Loopback %s %s message!\n", - GC_f2s (fwd), GC_m2s (type)); - - switch (type) - { - 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); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "end-to-end message not known (%u)\n", - ntohs (msgh->type)); - } -} - - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Destroy a channel and free all resources. - * - * @param ch Channel to destroy. - */ -void -GCCH_destroy (struct CadetChannel *ch) -{ - struct CadetClient *c; - struct CadetTunnel *t; - - if (NULL == ch) - return; - if (2 == ch->destroy) - return; /* recursive call */ - ch->destroy = 2; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying channel %s:%u\n", - GCT_2s (ch->t), ch->gid); - GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG); - - c = ch->root; - if (NULL != c) - { - GML_channel_remove (c, ch->lid_root, ch); - } - - c = ch->dest; - if (NULL != c) - { - GML_channel_remove (c, ch->lid_dest, ch); - } - - channel_rel_free_all (ch->root_rel); - channel_rel_free_all (ch->dest_rel); - - t = ch->t; - GCT_remove_channel (t, ch); - GNUNET_STATISTICS_update (stats, "# channels", -1, GNUNET_NO); - - GNUNET_free (ch); - GCT_destroy_if_empty (t); -} - - -/** - * Get the channel's public ID. - * - * @param ch Channel. - * - * @return ID used to identify the channel with the remote peer. - */ -struct GNUNET_CADET_ChannelTunnelNumber -GCCH_get_id (const struct CadetChannel *ch) -{ - return ch->gid; -} - - -/** - * Get the channel tunnel. - * - * @param ch Channel to get the tunnel from. - * - * @return tunnel of the channel. - */ -struct CadetTunnel * -GCCH_get_tunnel (const struct CadetChannel *ch) -{ - return ch->t; -} - - -/** - * Get free buffer space towards the client on a specific channel. - * - * @param ch Channel. - * @param fwd Is query about FWD traffic? - * - * @return Free buffer space [0 - 64] - */ -unsigned int -GCCH_get_buffer (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel; - - rel = fwd ? ch->dest_rel : ch->root_rel; - LOG (GNUNET_ERROR_TYPE_DEBUG, " get buffer, channel %s\n", GCCH_2s (ch)); - GCCH_debug (ch, GNUNET_ERROR_TYPE_DEBUG); - /* If rel is NULL it means that the end is not yet created, - * most probably is a loopback channel at the point of sending - * the ChannelCreate to itself. - */ - if (NULL == rel) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " rel is NULL: max\n"); - return 64; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " n_recv %d\n", rel->n_recv); - return (64 - rel->n_recv); -} - - -/** - * Get flow control status of end point: is client allow to send? - * - * @param ch Channel. - * @param fwd Is query about FWD traffic? (Request root status). - * - * @return #GNUNET_YES if client is allowed to send us data. - */ -int -GCCH_get_allowed (struct CadetChannel *ch, int fwd) -{ - struct CadetChannelReliability *rel; - - rel = fwd ? ch->root_rel : ch->dest_rel; - - if (NULL == rel) - { - /* Probably shutting down: root/dest NULL'ed to mark disconnection */ - GNUNET_break (GNUNET_NO != ch->destroy); - return 0; - } - - return rel->client_allowed; -} - - -/** - * 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; -} - - -/** - * 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) -{ - struct CadetClient *c; - - c = fwd ? ch->dest : ch->root; - return NULL != c; -} - - -/** - * Send an end-to-end ACK message for the most recent in-sequence payload. - * - * If channel is not reliable, do nothing. - * - * @param ch Channel this is about. - * @param fwd Is for FWD traffic? (ACK dest->owner) - */ -void -GCCH_send_data_ack (struct CadetChannel *ch, int fwd) -{ - struct GNUNET_CADET_ChannelDataAckMessage msg; - struct CadetChannelReliability *rel; - struct CadetReliableMessage *copy; - unsigned int delta; - uint64_t mask; - uint32_t ack; - - if (GNUNET_NO == ch->reliable) - return; - - rel = fwd ? ch->dest_rel : ch->root_rel; - ack = rel->mid_recv - 1; - - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK); - msg.header.size = htons (sizeof (msg)); - msg.ctn = ch->gid; - msg.mid = htonl (ack); - - msg.futures = 0LL; - for (copy = rel->head_recv; NULL != copy; copy = copy->next) - { - if (copy->type != GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA) - { - 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); - } - - 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) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " channel not ready yet!\n"); - return; - } - - if (GNUNET_YES == ch->reliable) - { - rel = fwd ? ch->root_rel : ch->dest_rel; - if (NULL == rel) - { - GNUNET_break (GNUNET_NO != ch->destroy); - return; - } - if (NULL != rel->head_sent) - { - if (64 <= rel->mid_send - rel->head_sent->mid) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " too big MID gap! Wait for ACK.\n"); - return; - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " gap ok: %u - %u\n", - rel->head_sent->mid, rel->mid_send); - 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 - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " head sent is NULL\n"); - } - } - - 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) - { - 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); - - } -} - - -/** - * 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; - } - 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. - * - * @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) -{ - 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; - } - - 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)) - { - 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 - { - /* FIXME change to a tunnel API, eliminate ch <-> peer connection */ - GCP_connect (peer); - } - - /* 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) - { - GNUNET_break (GNUNET_NO != ch->destroy); - return; - } - - if (CADET_CHANNEL_READY != ch->state) - { - if (GNUNET_NO == fwd) - { - /* If we are the root, this means the other peer has sent traffic before - * receiving our ACK. Even if the SYNACK goes missing, no traffic should - * be sent before the ACK. - */ - GNUNET_break_op (0); - return; - } - /* If we are the dest, this means that the SYNACK got to the root but - * the ACK went missing. Treat this as an ACK. - */ - channel_confirm (ch, GNUNET_NO); - } - - 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) - { - /* 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); - } - } - else - { - /* Tunnel is unreliable: send to clients directly */ - /* FIXME: accept Out Of Order traffic */ - rel->mid_recv = mid + 1; - send_client_data (ch, msg, fwd); - } - } - else - { - GNUNET_STATISTICS_update (stats, "# duplicate MID", 1, GNUNET_NO); - if (GC_is_pid_bigger (rel->mid_recv, mid)) - { - 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); - } - 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"); - } - - } - } - - GCCH_send_data_ack (ch, fwd); -} - - -/** - * Handler for cadet network traffic end-to-end ACKs. - * - * @param ch Channel on which we got this message. - * @param msg Data message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GCCH_handle_data_ack (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelDataAckMessage *msg, - int fwd) -{ - struct CadetChannelReliability *rel; - struct CadetReliableMessage *copy; - struct CadetReliableMessage *next; - uint32_t ack; - int work; - - /* If this is a remote (non-loopback) channel, find 'fwd'. */ - if (GNUNET_SYSERR == fwd) - { - if (is_loopback (ch)) - { - /* It is a loopback channel after all... */ - GNUNET_break (0); - return; - } - /* Inverted: if message came 'FWD' is a 'BCK ACK'. */ - fwd = (NULL != ch->dest) ? GNUNET_NO : GNUNET_YES; - } - - ack = ntohl (msg->mid); - LOG (GNUNET_ERROR_TYPE_INFO, - "<== %s (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; - 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) - { - if (GC_is_pid_bigger (copy->mid, ack)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " head %u, out!\n", copy->mid); - if (0 < channel_rel_free_sent (rel, msg)) - work = GNUNET_YES; - break; - } - work = GNUNET_YES; - LOG (GNUNET_ERROR_TYPE_DEBUG, " id %u\n", copy->mid); - next = copy->next; - if (GNUNET_YES == rel_message_free (copy, GNUNET_YES)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " channel destoyed\n"); - return; - } - } - - /* ACK client if needed and possible */ - GCCH_allow_client (ch, fwd); - - /* If some message was free'd, update the retransmission delay */ - if (GNUNET_YES == work) - { - if (NULL != rel->retry_task) - { - 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); - } - } - 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 - } - } -} - - -/** - * 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 - { - new_channel = GNUNET_NO; - } - 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); - - return 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); -} - - -/** - * Handler for channel ack messages. - * - * @param ch Channel. - * @param msg Message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -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) - */ -void -GCCH_handle_destroy (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelManageMessage *msg, - int fwd) -{ - 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; - } - - 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) */ - 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)) - { - handle_loopback (ch, message, fwd); - return; - } - - switch (type) - { - 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); - } -} - - -/** - * 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; -} diff --git a/src/cadet/gnunet-service-cadet_channel.h b/src/cadet/gnunet-service-cadet_channel.h deleted file mode 100644 index 9d4893269..000000000 --- a/src/cadet/gnunet-service-cadet_channel.h +++ /dev/null @@ -1,363 +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_channel.h - * @brief cadet service; dealing with end-to-end channels - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMCH (Gnunet Cadet CHannel) - */ - -#ifndef GNUNET_SERVICE_CADET_CHANNEL_H -#define GNUNET_SERVICE_CADET_CHANNEL_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" - -#include "cadet_protocol.h" -#include "cadet.h" - -/** - * Struct containing all information regarding a channel to a remote client. - */ -struct CadetChannel; - - -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_local.h" - - -/** - * Destroy a channel and free all resources. - * - * @param ch Channel to destroy. - */ -void -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. - */ -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); - - -/** - * 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); - - -/** - * 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); - - -/** - * 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); - -/** - * 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) - */ -void -GCCH_send_data_ack (struct CadetChannel *ch, int fwd); - -/** - * Notify the destination client that a new incoming channel was created. - * - * @param ch Channel that was created. - */ -void -GCCH_send_create (struct CadetChannel *ch); - -/** - * Allow a client to send us more data, in case it was choked. - * - * @param ch Channel. - * @param fwd Is this about FWD traffic? (Root client). - */ -void -GCCH_allow_client (struct CadetChannel *ch, int fwd); - -/** - * 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. - * - * Mark client as ready and send him any buffered data we could have for him. - * - * @param ch Channel. - * @param fwd Is this a "FWD ACK"? (FWD ACKs are sent by root and go BCK) - */ -void -GCCH_handle_local_ack (struct CadetChannel *ch, int fwd); - -/** - * Handle data given by a client. - * - * Check whether the client is allowed to send in this tunnel, save if channel - * is reliable and send an ACK to the client if there is still buffer space - * in the tunnel. - * - * @param ch Channel. - * @param c Client which sent the data. - * @param 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? - */ -void -GCCH_handle_local_destroy (struct CadetChannel *ch, - struct CadetClient *c, - int is_root); - - -/** - * Handle a channel create requested by a client. - * - * Create the channel and the tunnel in case this was the first0 channel. - * - * @param c Client that requested the creation (will be the root). - * @param msg Create Channel message. - * - * @return #GNUNET_OK if everything went fine, #GNUNET_SYSERR otherwise. - */ -int -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); - - -/** - * Handler for cadet network traffic end-to-end ACKs. - * - * @param ch Channel on which we got this message. - * @param msg Data message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GCCH_handle_data_ack (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelDataAckMessage *msg, - int fwd); - - -/** - * Handler for channel create messages. - * - * Does not have fwd parameter because it's always 'FWD': channel is incoming. - * - * @param t Tunnel this channel will be in. - * @param msg Channel crate message. - */ -struct CadetChannel * -GCCH_handle_create (struct CadetTunnel *t, - const struct GNUNET_CADET_ChannelOpenMessage *msg); - - -/** - * 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); - - -/** - * Handler for channel ack messages. - * - * @param ch Channel this channel is to be created in. - * @param msg Message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GCCH_handle_ack (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelManageMessage *msg, - int fwd); - - -/** - * Handler for channel destroy messages. - * - * @param ch Channel this channel is to be destroyed of. - * @param msg Message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -void -GCCH_handle_destroy (struct CadetChannel *ch, - const struct GNUNET_CADET_ChannelManageMessage *msg, - int fwd); - - -/** - * Sends an already built message on a channel. - * - * If the channel is on a loopback tunnel, notifies the appropriate destination - * client locally. - * - * On a normal channel passes the message to the tunnel for encryption and - * sending on a connection. - * - * This function DOES NOT save the message for retransmission. - * - * @param message Message to send. Function makes a copy of it. - * @param ch Channel on which this message is transmitted. - * @param fwd Is this a fwd message? - * @param existing_copy This is a retransmission, don't save a copy. - */ -void -GCCH_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct CadetChannel *ch, int fwd, - void *existing_copy); - - -/** - * Get the static string for identification of the channel. - * - * @param ch Channel.i - * - * @return Static string with the channel IDs. - */ -const char * -GCCH_2s (const struct CadetChannel *ch); - - - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_SERVICE_CADET_CHANNEL_H */ -#endif -/* end of gnunet-service-cadet_channel.h */ diff --git a/src/cadet/gnunet-service-cadet_connection.c b/src/cadet/gnunet-service-cadet_connection.c deleted file mode 100644 index 2d5087f81..000000000 --- a/src/cadet/gnunet-service-cadet_connection.c +++ /dev/null @@ -1,3713 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2001-2015 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_connection.c - * @brief GNUnet CADET service connection handling - * @author Bartlomiej Polot - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_statistics_service.h" -#include "cadet_path.h" -#include "cadet_protocol.h" -#include "cadet.h" -#include "gnunet-service-cadet_connection.h" -#include "gnunet-service-cadet_peer.h" -#include "gnunet-service-cadet_tunnel.h" - - -/** - * 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; -}; - - -/** - * Struct to encapsulate all the Flow Control information to a peer to which - * we are directly connected (on a core level). - */ -struct CadetFlowControl -{ - /** - * Connection this controls. - */ - struct CadetConnection *c; - - 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). - */ - struct CadetConnectionQueue *poll_msg; - - /** - * Queued poll message, to cancel if not necessary anymore (got ACK). - */ - struct CadetConnectionQueue *ack_msg; -}; - -/** - * Keep a record of the last messages sent on this connection. - */ -struct CadetConnectionPerformance -{ - /** - * Circular buffer for storing measurements. - */ - double usecsperbyte[AVG_MSGS]; - - /** - * Running average of @c usecsperbyte. - */ - double avg; - - /** - * How many values of @c usecsperbyte are valid. - */ - uint16_t size; - - /** - * Index of the next "free" position in @c usecsperbyte. - */ - uint16_t idx; -}; - - -/** - * Struct containing all information regarding a connection to a peer. - */ -struct CadetConnection -{ - /** - * Tunnel this connection is part of. - */ - struct CadetTunnel *t; - - /** - * Flow control information for traffic fwd. - */ - struct CadetFlowControl fwd_fc; - - /** - * Flow control information for traffic bck. - */ - struct CadetFlowControl bck_fc; - - /** - * Measure connection performance on the endpoint. - */ - struct CadetConnectionPerformance *perf; - - /** - * ID of the connection. - */ - struct GNUNET_CADET_ConnectionTunnelIdentifier id; - - /** - * Path being used for the tunnel. At the origin of the connection - * it's a pointer to the destination's path pool, otherwise just a copy. - */ - struct CadetPeerPath *path; - - /** - * Task to keep the used paths alive at the owner, - * time tunnel out on all the other peers. - */ - struct GNUNET_SCHEDULER_Task *fwd_maintenance_task; - - /** - * Task to keep the used paths alive at the destination, - * time tunnel out on all the other peers. - */ - struct GNUNET_SCHEDULER_Task *bck_maintenance_task; - - /** - * Queue handle for maintainance traffic. One handle for FWD and BCK since - * one peer never needs to maintain both directions (no loopback connections). - */ - struct CadetPeerQueue *maintenance_q; - - /** - * Should equal #get_next_hop(), or NULL if that peer disconnected. - */ - struct CadetPeer *next_peer; - - /** - * Should equal #get_prev_hop(), or NULL if that peer disconnected. - */ - struct CadetPeer *prev_peer; - - /** - * State of the connection. - */ - enum CadetConnectionState state; - - /** - * Position of the local peer in the path. - */ - unsigned int own_pos; - - /** - * Pending message count. - */ - unsigned int pending_messages; - - /** - * Destroy flag: - * - if 0, connection in use. - * - if 1, destroy on last message. - * - if 2, connection is being destroyed don't re-enter. - */ - int destroy; - - /** - * 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. - */ - int was_removed; - - /** - * Counter to do exponential backoff when creating a connection (max 64). - */ - unsigned short create_retry; - - /** - * Task to check if connection has duplicates. - */ - struct GNUNET_SCHEDULER_Task *check_duplicates_task; -}; - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -extern GNUNET_PEER_Id myid; - -/** - * Local peer own ID (full value). - */ -extern struct GNUNET_PeerIdentity my_full_id; - -/** - * Connections known, indexed by cid (CadetConnection). - */ -static struct GNUNET_CONTAINER_MultiShortmap *connections; - -/** - * How many connections are we willing to maintain. - * Local connections are always allowed, - * even if there are more connections than max. - */ -static unsigned long long max_connections; - -/** - * How many messages *in total* are we willing to queue, divide by number of - * connections to get connection queue size. - */ -static unsigned long long max_msgs_queue; - -/** - * How often to send path keepalives. Paths timeout after 4 missed. - */ -static struct GNUNET_TIME_Relative refresh_connection_time; - -/** - * How often to send path create / ACKs. - */ -static struct GNUNET_TIME_Relative create_connection_time; - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - - - -#if 0 // avoid compiler warning for unused static function -static void -fc_debug (struct CadetFlowControl *fc) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, " IN: %u/%u\n", - ntohl (fc->last_pid_recv.pid), - ntohl (fc->last_ack_sent.pid)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " OUT: %u/%u\n", - fc->last_pid_sent, fc->last_ack_recv); - LOG (GNUNET_ERROR_TYPE_DEBUG, " QUEUE: %u/%u\n", - fc->queue_n, fc->queue_max); -} - -static void -connection_debug (struct CadetConnection *c) -{ - if (NULL == c) - { - LOG (GNUNET_ERROR_TYPE_INFO, "DEBUG NULL CONNECTION\n"); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s:%X\n", - peer2s (c->t->peer), GCC_2s (c)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " state: %u, pending msgs: %u\n", - c->state, c->pending_messages); - LOG (GNUNET_ERROR_TYPE_DEBUG, " FWD FC\n"); - fc_debug (&c->fwd_fc); - LOG (GNUNET_ERROR_TYPE_DEBUG, " BCK FC\n"); - fc_debug (&c->bck_fc); -} -#endif - - -/** - * Schedule next keepalive task, taking in consideration - * the connection state and number of retries. - * - * @param c Connection for which to schedule the next keepalive. - * @param fwd Direction for the next keepalive. - */ -static void -schedule_next_keepalive (struct CadetConnection *c, int fwd); - - -/** - * Resets the connection timeout task, some other message has done the - * task's job. - * - For the first peer on the direction this means to send - * a keepalive or a path confirmation message (either create or ACK). - * - For all other peers, this means to destroy the connection, - * due to lack of activity. - * Starts the timeout if no timeout was running (connection just created). - * - * @param c Connection whose timeout to reset. - * @param fwd Is this forward? - */ -static void -connection_reset_timeout (struct CadetConnection *c, int fwd); - - -/** - * Get string description for tunnel state. Reentrant. - * - * @param s Tunnel state. - * - * @return String representation. - */ -static const char * -GCC_state2s (enum CadetConnectionState s) -{ - switch (s) - { - case CADET_CONNECTION_NEW: - return "CADET_CONNECTION_NEW"; - case CADET_CONNECTION_SENT: - return "CADET_CONNECTION_SENT"; - case CADET_CONNECTION_ACK: - return "CADET_CONNECTION_ACK"; - case CADET_CONNECTION_READY: - return "CADET_CONNECTION_READY"; - case CADET_CONNECTION_DESTROYED: - return "CADET_CONNECTION_DESTROYED"; - case CADET_CONNECTION_BROKEN: - return "CADET_CONNECTION_BROKEN"; - default: - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_ERROR, " conn state %u unknown!\n", s); - return "CADET_CONNECTION_STATE_ERROR"; - } -} - - -/** - * Initialize a Flow Control structure to the initial state. - * - * @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); - - -/** - * 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); - - return fwd; -} - - -/** - * Handler for key exchange traffic (Axolotl KX). - * - * @param peer Message sender (neighbor). - * @param msg Message itself. - */ -void -GCC_handle_kx (struct CadetPeer *peer, - const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) -{ - 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 (); -} - - -/** - * Handler for encrypted cadet network traffic (channel mgmt, data). - * - * @param peer Message sender (neighbor). - * @param msg Message itself. - */ -void -GCC_handle_encrypted (struct CadetPeer *peer, - const struct GNUNET_CADET_TunnelEncryptedMessage *msg) -{ - static struct CadetEncryptedMessageIdentifier zero; - const struct GNUNET_CADET_ConnectionTunnelIdentifier* cid; - struct CadetConnection *c; - struct CadetEncryptedMessageIdentifier pid; - int fwd; - - GCC_check_connections (); - cid = &msg->cid; - pid = msg->cemi; - log_message (&msg->header, peer, cid); - - c = connection_get (cid); - fwd = check_message (&msg->header, - cid, - c, - peer, - pid); - - /* If something went wrong, discard message. */ - if (GNUNET_SYSERR == fwd) - { - GCC_check_connections (); - return; - } - - /* Is this message for us? */ - if (GCC_is_terminal (c, fwd)) - { - GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO); - - if (NULL == c->t) - { - 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 (); -} - - -/** - * Initialize the connections subsystem - * - * @param c Configuration handle. - */ -void -GCC_init (const struct GNUNET_CONFIGURATION_Handle *c) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_MSGS_QUEUE", - &max_msgs_queue)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "CADET", "MAX_MSGS_QUEUE", "MISSING"); - GNUNET_SCHEDULER_shutdown (); - return; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, "CADET", "MAX_CONNECTIONS", - &max_connections)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "CADET", "MAX_CONNECTIONS", "MISSING"); - GNUNET_SCHEDULER_shutdown (); - return; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (c, "CADET", "REFRESH_CONNECTION_TIME", - &refresh_connection_time)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "CADET", "REFRESH_CONNECTION_TIME", "MISSING"); - GNUNET_SCHEDULER_shutdown (); - return; - } - create_connection_time = GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, - refresh_connection_time); - connections = GNUNET_CONTAINER_multishortmap_create (1024, - GNUNET_YES); -} - - -/** - * Destroy each connection on shutdown. - * - * @param cls Closure (unused). - * @param key Current key code (CID, unused). - * @param value Value in the hash map (`struct CadetConnection`) - * - * @return #GNUNET_YES, because we should continue to iterate - */ -static int -shutdown_iterator (void *cls, - const struct GNUNET_ShortHashCode *key, - void *value) -{ - struct CadetConnection *c = value; - - c->state = CADET_CONNECTION_DESTROYED; - GCC_destroy (c); - return GNUNET_YES; -} - - -/** - * Shut down the connections subsystem. - */ -void -GCC_shutdown (void) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connections\n"); - GCC_check_connections (); - GNUNET_CONTAINER_multishortmap_iterate (connections, - &shutdown_iterator, - NULL); - GNUNET_CONTAINER_multishortmap_destroy (connections); - connections = NULL; -} - - -/** - * Create a connection. - * - * @param cid Connection ID (either created locally or imposed remotely). - * @param t Tunnel this connection belongs to (or NULL for transit connections); - * @param path Path this connection has to use (copy is made). - * @param own_pos Own position in the @c path path. - * - * @return Newly created connection. - * NULL in case of error: own id not in path, wrong neighbors, ... -*/ -struct CadetConnection * -GCC_new (const struct GNUNET_CADET_ConnectionTunnelIdentifier *cid, - struct CadetTunnel *t, - struct CadetPeerPath *path, - unsigned int own_pos) -{ - struct CadetConnection *c; - struct CadetPeerPath *cpath; - - GCC_check_connections (); - cpath = path_duplicate (path); - GNUNET_assert (NULL != cpath); - c = GNUNET_new (struct CadetConnection); - c->id = *cid; - 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 (0 == own_pos) - { - /* We were the origin of this request, this means we have invalid - * info about the paths to reach the destination. We must invalidate - * the *original* path to avoid trying it again in the next minute. - */ - if (2 < path->length) - path_invalidate (path); - else - { - GNUNET_break (0); - GCT_debug(t, GNUNET_ERROR_TYPE_WARNING); - } - c->t = NULL; - } - path_destroy (c->path); - c->path = NULL; - GCC_destroy (c); - return NULL; - } - LOG (GNUNET_ERROR_TYPE_INFO, "New connection %s\n", GCC_2s (c)); - GCC_check_connections (); - return c; -} - - -/** - * Connection is no longer needed: destroy it. - * - * Cancels all pending traffic (including possible DESTROY messages), all - * maintenance tasks and removes the connection from neighbor peers and tunnel. - * - * @param c Connection to destroy. - */ -void -GCC_destroy (struct CadetConnection *c) -{ - GCC_check_connections (); - if (NULL == c) - { - GNUNET_break (0); - return; - } - - if (2 == c->destroy) /* cancel queues -> GCP_queue_cancel -> q_destroy -> */ - return; /* -> message_sent -> GCC_destroy. Don't loop. */ - c->destroy = 2; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "destroying connection %s\n", - GCC_2s (c)); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " fc's f: %p, b: %p\n", - &c->fwd_fc, &c->bck_fc); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " fc tasks f: %u, b: %u\n", - c->fwd_fc.poll_task, - c->bck_fc.poll_task); - - /* Cancel all traffic */ - if (NULL != c->path) - { - connection_cancel_queues (c, GNUNET_YES); - connection_cancel_queues (c, GNUNET_NO); - if (NULL != c->maintenance_q) - { - GCP_send_cancel (c->maintenance_q); - c->maintenance_q = NULL; - } - } - unregister_neighbors (c); - path_destroy (c->path); - c->path = NULL; - - /* Delete from tunnel */ - if (NULL != c->t) - GCT_remove_connection (c->t, c); - - if (NULL != c->check_duplicates_task) - GNUNET_SCHEDULER_cancel (c->check_duplicates_task); - if (NULL != c->fwd_maintenance_task) - GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task); - if (NULL != c->bck_maintenance_task) - GNUNET_SCHEDULER_cancel (c->bck_maintenance_task); - - if (GNUNET_NO == c->was_removed) - { - GNUNET_break (GNUNET_YES == - GNUNET_CONTAINER_multishortmap_remove (connections, - &c->id.connection_of_tunnel, - c)); - } - GNUNET_STATISTICS_update (stats, - "# connections", - -1, - GNUNET_NO); - GNUNET_free (c); - GCC_check_connections (); -} - - -/** - * Get the connection ID. - * - * @param c Connection to get the ID from. - * - * @return ID of the connection. - */ -const struct GNUNET_CADET_ConnectionTunnelIdentifier * -GCC_get_id (const struct CadetConnection *c) -{ - return &c->id; -} - - -/** - * Get the connection path. - * - * @param c Connection to get the path from. - * - * @return path used by the connection. - */ -const struct CadetPeerPath * -GCC_get_path (const struct CadetConnection *c) -{ - if (GNUNET_NO == c->destroy) - return c->path; - return NULL; -} - - -/** - * Get the connection state. - * - * @param c Connection to get the state from. - * - * @return state of the connection. - */ -enum CadetConnectionState -GCC_get_state (const struct CadetConnection *c) -{ - return c->state; -} - -/** - * Get the connection tunnel. - * - * @param c Connection to get the tunnel from. - * - * @return tunnel of the connection. - */ -struct CadetTunnel * -GCC_get_tunnel (const struct CadetConnection *c) -{ - return c->t; -} - - -/** - * Get free buffer space in a connection. - * - * @param c Connection. - * @param fwd Is query about FWD traffic? - * - * @return Free buffer space [0 - max_msgs_queue/max_connections] - */ -unsigned int -GCC_get_buffer (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - - LOG (GNUNET_ERROR_TYPE_DEBUG, " Get %s buffer on %s: %u - %u\n", - GC_f2s (fwd), GCC_2s (c), fc->queue_max, fc->queue_n); - GCC_debug (c, GNUNET_ERROR_TYPE_DEBUG); - - return (fc->queue_max - fc->queue_n); -} - - -/** - * Get how many messages have we allowed to send to us from a direction. - * - * @param c Connection. - * @param fwd Are we asking about traffic from FWD (BCK messages)? - * - * @return last_ack_sent - last_pid_recv - */ -unsigned int -GCC_get_allowed (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - if ( (CADET_CONNECTION_READY != c->state) || - GC_is_pid_bigger (ntohl (fc->last_pid_recv.pid), - ntohl (fc->last_ack_sent.pid)) ) - { - return 0; - } - return (ntohl (fc->last_ack_sent.pid) - ntohl (fc->last_pid_recv.pid)); -} - - -/** - * Get messages queued in a connection. - * - * @param c Connection. - * @param fwd Is query about FWD traffic? - * - * @return Number of messages queued. - */ -unsigned int -GCC_get_qn (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - - return fc->queue_n; -} - - -/** - * Get next PID to use. - * - * @param c Connection. - * @param fwd Is query about FWD traffic? - * @return Next PID to use. - */ -struct CadetEncryptedMessageIdentifier -GCC_get_pid (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - struct CadetEncryptedMessageIdentifier pid; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - pid = fc->next_pid; - fc->next_pid.pid = htonl (1 + ntohl (pid.pid)); - return pid; -} - - -/** - * Allow the connection to advertise a buffer of the given size. - * - * The connection will send an @c fwd ACK message (so: in direction !fwd) - * allowing up to last_pid_recv + buffer. - * - * @param c Connection. - * @param buffer How many more messages the connection can accept. - * @param fwd Is this about FWD traffic? (The ack will go dest->root). - */ -void -GCC_allow (struct CadetConnection *c, unsigned int buffer, int fwd) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, " allowing %s %u messages %s\n", - GCC_2s (c), buffer, GC_f2s (fwd)); - send_ack (c, buffer, fwd, GNUNET_NO); -} - - -/** - * Notify other peers on a connection of a broken link. Mark connections - * to destroy after all traffic has been sent. - * - * @param c Connection on which there has been a disconnection. - * @param peer Peer that disconnected. - */ -void -GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer) -{ - struct CadetFlowControl *fc; - char peer_name[16]; - int fwd; - - GCC_check_connections (); - strncpy (peer_name, GCP_2s (peer), 16); - peer_name[15] = '\0'; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "shutting down %s, %s disconnected\n", - GCC_2s (c), peer_name); - - invalidate_paths (c, peer); - - fwd = is_fwd (c, peer); - if (GNUNET_SYSERR == fwd) - { - GNUNET_break (0); - return; - } - if ( (GNUNET_YES == GCC_is_terminal (c, fwd)) || - (GNUNET_NO != c->destroy) ) - { - /* Local shutdown, or other peer already down (hence 'c->destroy'); - so there is no one to notify about this, just clean up. */ - GCC_destroy (c); - GCC_check_connections (); - return; - } - /* Mark FlowControl towards the peer as unavaliable. */ - fc = fwd ? &c->bck_fc : &c->fwd_fc; - fc->queue_max = 0; - - send_broken (c, &my_full_id, GCP_get_id (peer), fwd); - - /* Connection will have at least one pending message - * (the one we just scheduled), so delay destruction - * and remove from map so we don't use accidentally. */ - mark_destroyed (c); - GNUNET_assert (GNUNET_NO == c->was_removed); - c->was_removed = GNUNET_YES; - GNUNET_break (GNUNET_YES == - GNUNET_CONTAINER_multishortmap_remove (connections, - &c->id.connection_of_tunnel, - c)); - /* Cancel queue in the direction that just died. */ - connection_cancel_queues (c, ! fwd); - GCC_stop_poll (c, ! fwd); - unregister_neighbors (c); - GCC_check_connections (); -} - - -/** - * Is this peer the first one on the connection? - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * - * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal. - */ -int -GCC_is_origin (struct CadetConnection *c, int fwd) -{ - if (!fwd && c->path->length - 1 == c->own_pos ) - return GNUNET_YES; - if (fwd && 0 == c->own_pos) - return GNUNET_YES; - return GNUNET_NO; -} - - -/** - * Is this peer the last one on the connection? - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * Note that the ROOT is the terminal for BCK traffic! - * - * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. - */ -int -GCC_is_terminal (struct CadetConnection *c, int fwd) -{ - return GCC_is_origin (c, ! fwd); -} - - -/** - * See if we are allowed to send by the next hop in the given direction. - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * - * @return #GNUNET_YES in case it's OK to send. - */ -int -GCC_is_sendable (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - " checking sendability of %s traffic on %s\n", - GC_f2s (fwd), GCC_2s (c)); - if (NULL == c) - { - GNUNET_break (0); - return GNUNET_YES; - } - fc = fwd ? &c->fwd_fc : &c->bck_fc; - LOG (GNUNET_ERROR_TYPE_DEBUG, - " last ack recv: %u, last pid sent: %u\n", - ntohl (fc->last_ack_recv.pid), - ntohl (fc->last_pid_sent.pid)); - if (GC_is_pid_bigger (ntohl (fc->last_ack_recv.pid), - ntohl (fc->last_pid_sent.pid))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " sendable\n"); - return GNUNET_YES; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " not sendable\n"); - return GNUNET_NO; -} - - -/** - * Check if this connection is a direct one (never trim a direct connection). - * - * @param c Connection. - * - * @return #GNUNET_YES in case it's a direct connection, #GNUNET_NO otherwise. - */ -int -GCC_is_direct (struct CadetConnection *c) -{ - return (c->path->length == 2) ? GNUNET_YES : GNUNET_NO; -} - - -/** - * Sends a completely built message on a connection, properly registering - * all used resources. - * - * @param message Message to send. - * @param payload_type Type of payload, in case the message is encrypted. - * 0 for restransmissions (when type is no longer known) - * UINT16_MAX when not applicable. - * @param payload_id ID of the payload (PID, ACK, ...). - * @param c Connection on which this message is transmitted. - * @param fwd Is this a fwd message? - * @param force Force the connection to accept the message (buffer overfill). - * @param cont Continuation called once message is sent. Can be NULL. - * @param cont_cls Closure for @c cont. - * - * @return Handle to cancel the message before it's sent. - * NULL on error. - * Invalid on @c cont call. - */ -struct CadetConnectionQueue * -GCC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - uint16_t payload_type, - struct CadetEncryptedMessageIdentifier payload_id, - struct CadetConnection *c, int fwd, int force, - GCC_sent cont, void *cont_cls) -{ - struct CadetFlowControl *fc; - struct CadetConnectionQueue *q; - uint16_t size; - uint16_t type; - - size = ntohs (message->size); - type = ntohs (message->type); - - GCC_check_connections (); - fc = fwd ? &c->fwd_fc : &c->bck_fc; - if (0 == fc->queue_max) - { - GNUNET_break (0); - return NULL; - } - - LOG (GNUNET_ERROR_TYPE_INFO, - "--> %s (%s %4u) on conn %s (%p) %s [%5u]\n", - GC_m2s (type), GC_m2s (payload_type), payload_id, GCC_2s (c), c, - GC_f2s(fwd), size); - switch (type) - { - case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED: - LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u, PIDsnt: %u, ACKrcv: %u\n", - fc, - fc->queue_n, - ntohl (fc->last_pid_sent.pid), - ntohl (fc->last_ack_recv.pid)); - if (GNUNET_NO == force) - { - fc->queue_n++; - } - break; - - case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX: - /* nothing to do here */ - break; - - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK: - /* Should've only be used for restransmissions. */ - GNUNET_break (0 == payload_type); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK: - case GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY: - case GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN: - GNUNET_assert (GNUNET_YES == force); - break; - - default: - GNUNET_break (0); - 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 */ - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %s %u\n", - GCC_2s (c), c->pending_messages); - c->pending_messages++; - - q = GNUNET_new (struct CadetConnectionQueue); - q->cont = cont; - q->cont_cls = cont_cls; - q->forced = force; - GNUNET_CONTAINER_DLL_insert (fc->q_head, fc->q_tail, q); - q->peer_q = GCP_send (get_hop (c, fwd), - message, - payload_type, - payload_id, - c, - fwd, - &conn_message_sent, q); - if (NULL == q->peer_q) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "dropping msg on %s, NULL q\n", GCC_2s (c)); - GNUNET_CONTAINER_DLL_remove (fc->q_head, fc->q_tail, q); - GNUNET_free (q); - GCC_check_connections (); - return NULL; - } - GCC_check_connections (); - return q; -} - - -/** - * Cancel a previously sent message while it's in the queue. - * - * ONLY can be called before the continuation given to the send function - * is called. Once the continuation is called, the message is no longer in the - * queue. - * - * @param q Handle to the queue. - */ -void -GCC_cancel (struct CadetConnectionQueue *q) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "! GCC cancel message\n"); - - /* send_cancel calls message_sent, which calls q->cont and frees q */ - GCP_send_cancel (q->peer_q); - GCC_check_connections (); -} - - -/** - * Sends a CREATE CONNECTION message for a path to a peer. - * Changes the connection and tunnel states if necessary. - * - * @param c Connection to create. - */ -void -GCC_send_create (struct CadetConnection *c) -{ - static struct CadetEncryptedMessageIdentifier zero; - enum CadetTunnelCState state; - size_t size; - - GCC_check_connections (); - size = sizeof (struct GNUNET_CADET_ConnectionCreateMessage); - size += c->path->length * sizeof (struct GNUNET_PeerIdentity); - { - /* Allocate message on the stack */ - unsigned char cbuf[size]; - struct GNUNET_CADET_ConnectionCreateMessage *msg; - struct GNUNET_PeerIdentity *peers; - - - msg = (struct GNUNET_CADET_ConnectionCreateMessage *) cbuf; - msg->header.size = htons (size); - msg->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE); - msg->options = htonl (0); - msg->cid = *GCC_get_id (c); - peers = (struct GNUNET_PeerIdentity *) &msg[1]; - for (int i = 0; i < c->path->length; i++) - { - GNUNET_PEER_resolve (c->path->peers[i], peers++); - } - GNUNET_assert (NULL == c->maintenance_q); - c->maintenance_q = GCP_send (get_next_hop (c), - &msg->header, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, - zero, - c, GNUNET_YES, - &conn_message_sent, NULL); - } - - LOG (GNUNET_ERROR_TYPE_INFO, "==> %s %19s on conn %s (%p) FWD [%5u]\n", - GC_m2s (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE), "", - GCC_2s (c), c, size); - LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n", - c, c->pending_messages); - c->pending_messages++; - - state = GCT_get_cstate (c->t); - if (CADET_TUNNEL_SEARCHING == state || CADET_TUNNEL_NEW == state) - GCT_change_cstate (c->t, CADET_TUNNEL_WAITING); - if (CADET_CONNECTION_NEW == c->state) - connection_change_state (c, CADET_CONNECTION_SENT); - GCC_check_connections (); -} - - -/** - * Send an ACK on the appropriate connection/channel, depending on - * the direction and the position of the peer. - * - * @param c Which connection to send the hop-by-hop ACK. - * @param fwd Is this a fwd ACK? (will go dest->root). - * @param force Send the ACK even if suboptimal (e.g. requested by POLL). - */ -void -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; - } - - /* 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 (); -} - - -/** - * 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) -{ - static struct CadetEncryptedMessageIdentifier zero; - struct GNUNET_CADET_ConnectionDestroyMessage msg; - - if (GNUNET_YES == c->destroy) - return; - GCC_check_connections (); - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY); - msg.cid = c->id; - msg.reserved = htonl (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " sending connection destroy for connection %s\n", - GCC_2s (c)); - - if (GNUNET_NO == GCC_is_terminal (c, GNUNET_YES)) - (void) GCC_send_prebuilt_message (&msg.header, - UINT16_MAX, - zero, - c, - GNUNET_YES, GNUNET_YES, NULL, NULL); - if (GNUNET_NO == GCC_is_terminal (c, GNUNET_NO)) - (void) GCC_send_prebuilt_message (&msg.header, - UINT16_MAX, - zero, - c, - GNUNET_NO, GNUNET_YES, NULL, NULL); - mark_destroyed (c); - GCC_check_connections (); -} - - -/** - * @brief Start a polling timer for the connection. - * - * When a neighbor does not accept more traffic on the connection it could be - * caused by a simple congestion or by a lost ACK. Polling enables to check - * for the lastest ACK status for a connection. - * - * @param c Connection. - * @param fwd Should we poll in the FWD direction? - */ -void -GCC_start_poll (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL %s requested\n", - GC_f2s (fwd)); - if (NULL != fc->poll_task || NULL != fc->poll_msg) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL already in progress (t: %p, m: %p)\n", - fc->poll_task, fc->poll_msg); - return; - } - if (0 == fc->queue_max) - { - /* Should not be needed, traffic should've been cancelled. */ - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, " POLL not possible, peer disconnected\n"); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "POLL started on request\n"); - fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time, &send_poll, fc); -} - - -/** - * @brief Stop polling a connection for ACKs. - * - * Once we have enough ACKs for future traffic, polls are no longer necessary. - * - * @param c Connection. - * @param fwd Should we stop the poll in the FWD direction? - */ -void -GCC_stop_poll (struct CadetConnection *c, int fwd) -{ - struct CadetFlowControl *fc; - - fc = fwd ? &c->fwd_fc : &c->bck_fc; - if (NULL != fc->poll_task) - { - GNUNET_SCHEDULER_cancel (fc->poll_task); - fc->poll_task = NULL; - } - if (NULL != fc->poll_msg) - { - GCC_cancel (fc->poll_msg); - fc->poll_msg = NULL; - } -} - - -/** - * Get a (static) string for a connection. - * - * @param c Connection. - */ -const char * -GCC_2s (const struct CadetConnection *c) -{ - if (NULL == c) - return "NULL"; - - if (NULL != c->t) - { - static char buf[128]; - - SPRINTF (buf, "%s (->%s)", - GNUNET_sh2s (&GCC_get_id (c)->connection_of_tunnel), - GCT_2s (c->t)); - return buf; - } - return GNUNET_sh2s (&c->id.connection_of_tunnel); -} - - -/** - * Log all possible info about the connection state. - * - * @param c Connection to debug. - * @param level Debug level to use. - */ -void -GCC_debug (const struct CadetConnection *c, 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) - { - LOG2 (level, "CCC DEBUG NULL CONNECTION\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"); -} diff --git a/src/cadet/gnunet-service-cadet_connection.h b/src/cadet/gnunet-service-cadet_connection.h deleted file mode 100644 index 307cb42c2..000000000 --- a/src/cadet/gnunet-service-cadet_connection.h +++ /dev/null @@ -1,576 +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_connection.h - * @brief cadet service; dealing with connections - * @author Bartlomiej Polot - * - * All functions in this file use the prefix GCC (GNUnet Cadet Connection) - */ - -#ifndef GNUNET_SERVICE_CADET_CONNECTION_H -#define GNUNET_SERVICE_CADET_CONNECTION_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "gnunet_util_lib.h" - - -/** - * All the states a connection can be in. - */ -enum CadetConnectionState -{ - /** - * Uninitialized status, should never appear in operation. - */ - CADET_CONNECTION_NEW, - - /** - * Connection create message sent, waiting for ACK. - */ - CADET_CONNECTION_SENT, - - /** - * Connection ACK sent, waiting for ACK. - */ - CADET_CONNECTION_ACK, - - /** - * Connection confirmed, ready to carry traffic. - */ - CADET_CONNECTION_READY, - - /** - * Connection to be destroyed, just waiting to empty queues. - */ - CADET_CONNECTION_DESTROYED, - - /** - * 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_peer.h" - - -/** - * Check invariants for all connections using #check_neighbours(). - */ -void -GCC_check_connections (void); - - -/** - * Callback called when a queued message is sent. - * - * @param cls Closure. - * @param c Connection this message was on. - * @param type Type of message sent. - * @param fwd Was this a FWD going message? - * @param size Size of the message. - */ -typedef void -(*GCC_sent) (void *cls, - struct CadetConnection *c, - struct CadetConnectionQueue *q, - uint16_t type, - int fwd, - size_t size); - - -/** - * 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); - - -/** - * 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); - - -/** - * 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); - -/** - * 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. - * - * @param peer Message sender (neighbor). - * @param msg Message itself. - */ -void -GCC_handle_ack (struct CadetPeer *peer, - const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg); - -/** - * 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). - * - * @param peer Message sender (neighbor). - * @param msg Message itself. - */ -void -GCC_handle_kx (struct CadetPeer *peer, - const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg); - -/** - * Handler for encrypted cadet network traffic (channel mgmt, data). - * - * @param peer Message sender (neighbor). - * @param msg Message itself. - */ -void -GCC_handle_encrypted (struct CadetPeer *peer, - const struct GNUNET_CADET_TunnelEncryptedMessage *msg); - -/** - * 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. - * - * @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 (void *cls, const struct GNUNET_PeerIdentity *peer, - struct GNUNET_MessageHeader *message); - -/** - * Core handler for cadet keepalives. - * - * @param cls closure - * @param message message - * @param peer peer identity this notification is about - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - * - * TODO: Check who we got this from, to validate route. - */ -int -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. - * - * @param c Which connection to send the hop-by-hop ACK. - * @param fwd Is this a fwd ACK? (will go dest->root). - * @param force Send the ACK even if suboptimal (e.g. requested by POLL). - */ -void -GCC_send_ack (struct CadetConnection *c, int fwd, int force); - -/** - * Initialize the connections subsystem - * - * @param c Configuration handle. - */ -void -GCC_init (const struct GNUNET_CONFIGURATION_Handle *c); - -/** - * Shut down the connections subsystem. - */ -void -GCC_shutdown (void); - -/** - * 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. - * - * @param c Connection to destroy. - */ -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); - - -/** - * Get the connection path. - * - * @param c Connection to get the path from. - * - * @return path used by the connection. - */ -const struct CadetPeerPath * -GCC_get_path (const struct CadetConnection *c); - -/** - * 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); - -/** - * 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); - -/** - * 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); - -/** - * 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); - -/** - * 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); - -/** - * 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. - * - * @param cls Closure (connection for which to send the keepalive). - * @param tc Notification context. - */ -void -GCC_fwd_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - -/** - * Send BCK keepalive packets for a connection. - * - * @param cls Closure (connection for which to send the keepalive). - * @param tc Notification context. - */ -void -GCC_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); - - -/** - * Notify other peers on a connection of a broken link. Mark connections - * to destroy after all traffic has been sent. - * - * @param c Connection on which there has been a disconnection. - * @param peer Peer that disconnected. - */ -void -GCC_neighbor_disconnected (struct CadetConnection *c, struct CadetPeer *peer); - -/** - * Is this peer the first one on the connection? - * - * @param c Connection. - * @param fwd Is this about fwd traffic? - * - * @return #GNUNET_YES if origin, #GNUNET_NO if relay/terminal. - */ -int -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! - * - * @return #GNUNET_YES if terminal, #GNUNET_NO if relay/origin. - */ -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); - -/** - * 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. - * - * ONLY can be called before the continuation given to the send function - * is called. Once the continuation is called, the message is no longer in the - * queue. - * - * @param q Handle to the queue. - */ -void -GCC_cancel (struct CadetConnectionQueue *q); - -/** - * 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. - * - * @param connection Connection to create. - */ -void -GCC_send_create (struct CadetConnection *connection); - -/** - * Send a message to all peers in this connection that the connection - * is no longer valid. - * - * If some peer should not receive the message, it should be zero'ed out - * before calling this function. - * - * @param c The connection whose peers to notify. - */ -void -GCC_send_destroy (struct CadetConnection *c); - -/** - * @brief Start a polling timer for the connection. - * - * When a neighbor does not accept more traffic on the connection it could be - * caused by a simple congestion or by a lost ACK. Polling enables to check - * for the lastest ACK status for a connection. - * - * @param c Connection. - * @param fwd Should we poll in the FWD direction? - */ -void -GCC_start_poll (struct CadetConnection *c, int fwd); - - -/** - * @brief Stop polling a connection for ACKs. - * - * Once we have enough ACKs for future traffic, polls are no longer necessary. - * - * @param c Connection. - * @param fwd Should we stop the poll in the FWD direction? - */ -void -GCC_stop_poll (struct CadetConnection *c, int fwd); - -/** - * Get a (static) string for a connection. - * - * @param c Connection. - */ -const char * -GCC_2s (const struct CadetConnection *c); - -/** - * Log all possible info about the connection state. - * - * @param c Connection to debug. - * @param level Debug level to use. - */ -void -GCC_debug (const struct CadetConnection *c, 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_dht.c b/src/cadet/gnunet-service-cadet_dht.c deleted file mode 100644 index 22673b167..000000000 --- a/src/cadet/gnunet-service-cadet_dht.c +++ /dev/null @@ -1,424 +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_dht_service.h" -#include "gnunet_statistics_service.h" - -#include "cadet_path.h" -#include "gnunet-service-cadet_dht.h" -#include "gnunet-service-cadet_peer.h" -#include "gnunet-service-cadet_hello.h" - -#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__) - - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - -/** - * Handle for DHT searches. - */ -struct GCD_search_handle -{ - /** - * DHT_GET 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. - */ -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; - -/** - * 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 - * 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) -{ - struct GCD_search_handle *h = cls; - struct GNUNET_HELLO_Message *hello; - struct CadetPeerPath *p; - struct CadetPeer *peer; - char *s; - - p = path_build_from_dht (get_path, get_path_length, - put_path, put_path_length); - if (NULL == p) - { - GNUNET_break_op (0); - return; - } - - 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); -} - - -/** - * 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; - - 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) ) - { - /* 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); - } - else - { - expiration = GNUNET_HELLO_get_last_expiration (hello); - 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); -} - -/** - * 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, - */ -int -stop_get (void *cls, - uint32_t key, - void *value) -{ - struct GCD_search_handle *h = value; - - GCD_search_stop (h); - return GNUNET_YES; -} - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize the DHT subsystem. - * - * @param c Configuration. - */ -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", - "DHT_REPLICATION_LEVEL", - &dht_replication_level)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, "CADET", - "DHT_REPLICATION_LEVEL", "USING DEFAULT"); - dht_replication_level = 3; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (c, "CADET", "ID_ANNOUNCE_TIME", - &id_announce_time)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "CADET", - "ID_ANNOUNCE_TIME", "MISSING"); - GNUNET_SCHEDULER_shutdown (); - return; - } - - dht_handle = GNUNET_DHT_connect (c, 64); - if (NULL == dht_handle) - { - GNUNET_break (0); - } - - announce_delay = GNUNET_TIME_UNIT_SECONDS; - announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id, NULL); - get_requests = GNUNET_CONTAINER_multihashmap32_create (32); -} - - -/** - * Shut down the DHT subsystem. - */ -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) - { - GNUNET_DHT_disconnect (dht_handle); - dht_handle = NULL; - } - if (NULL != announce_id_task) - { - GNUNET_SCHEDULER_cancel (announce_id_task); - announce_id_task = NULL; - } -} - -struct GCD_search_handle * -GCD_search (const struct GNUNET_PeerIdentity *peer_id, - GCD_search_callback callback, void *cls) -{ - 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)); - 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 */ - dht_replication_level, /* replication level */ - GNUNET_DHT_RO_RECORD_ROUTE | - GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, - NULL, /* xquery */ - 0, /* xquery bits */ - &dht_get_id_handler, - h); - GNUNET_CONTAINER_multihashmap32_put (get_requests, - h->peer_id, - h, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); - return h; -} - - -void -GCD_search_stop (struct GCD_search_handle *h) -{ - GNUNET_break (GNUNET_OK == - GNUNET_CONTAINER_multihashmap32_remove (get_requests, - h->peer_id, h)); - GNUNET_DHT_get_stop (h->dhtget); - GNUNET_free (h); -} diff --git a/src/cadet/gnunet-service-cadet_dht.h b/src/cadet/gnunet-service-cadet_dht.h deleted file mode 100644 index b70dfe975..000000000 --- a/src/cadet/gnunet-service-cadet_dht.h +++ /dev/null @@ -1,93 +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_dht.h - * @brief cadet service; dealing with DHT requests and results - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMD (Gnunet Cadet Dht) - */ - -#ifndef GNUNET_SERVICE_CADET_DHT_H -#define GNUNET_SERVICE_CADET_DHT_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" - -struct 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! - */ -typedef void -(*GCD_search_callback) (void *cls, - const struct CadetPeerPath *path); - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * 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); - - -struct GCD_search_handle * -GCD_search (const struct GNUNET_PeerIdentity *peer_id, - GCD_search_callback callback, void *cls); - - -void -GCD_search_stop (struct GCD_search_handle *h); - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */ -#endif -/* end of gnunet-cadet-service_LOCAL.h */ diff --git a/src/cadet/gnunet-service-cadet_hello.c b/src/cadet/gnunet-service-cadet_hello.c deleted file mode 100644 index 3c63f3551..000000000 --- a/src/cadet/gnunet-service-cadet_hello.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2014 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 "gnunet_peerinfo_service.h" - -#include "cadet_protocol.h" -#include "cadet_path.h" - -#include "gnunet-service-cadet_hello.h" -#include "gnunet-service-cadet_peer.h" - -#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__) - - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -extern GNUNET_PEER_Id myid; - -/** - * Local peer own ID (full value). - */ -extern struct GNUNET_PeerIdentity my_full_id; - - -/** - * Don't try to recover tunnels if shutting down. - */ -extern int shutting_down; - - -/** - * Hello message of local peer. - */ -const struct GNUNET_HELLO_Message *mine; - -/** - * Handle to peerinfo service. - */ -static struct GNUNET_PEERINFO_Handle *peerinfo; - -/** - * Iterator context. - */ -struct GNUNET_PEERINFO_NotifyContext* nc; - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - -/** - * Process each hello message received from peerinfo. - * - * @param cls Closure (unused). - * @param peer Identity of the peer. - * @param hello Hello of the peer. - * @param err_msg Error message. - */ -static void -got_hello (void *cls, const struct GNUNET_PeerIdentity *id, - const struct GNUNET_HELLO_Message *hello, - const char *err_msg) -{ - struct CadetPeer *peer; - - if (NULL == id || NULL == hello) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " hello with id %p and msg %p\n", id, hello); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " hello for %s (%d bytes), expires on %s\n", - GNUNET_i2s (id), GNUNET_HELLO_size (hello), - GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration(hello))); - peer = GCP_get (id, GNUNET_YES); - GCP_set_hello (peer, hello); - - if (GCP_get_short_id (peer) == myid) - mine = GCP_get_hello (peer); -} - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize the hello subsystem. - * - * @param c Configuration. - */ -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); -} - - -/** - * Shut down the hello subsystem. - */ -void -GCH_shutdown () -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down channels\n"); - if (NULL != nc) - { - GNUNET_PEERINFO_notify_cancel (nc); - nc = NULL; - } - if (NULL != peerinfo) - { - GNUNET_PEERINFO_disconnect (peerinfo); - peerinfo = NULL; - } -} - - -/** - * Get own hello message. - * - * @return Own hello message. - */ -const struct GNUNET_HELLO_Message * -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)"; -} - - diff --git a/src/cadet/gnunet-service-cadet_hello.h b/src/cadet/gnunet-service-cadet_hello.h deleted file mode 100644 index 34121e1e0..000000000 --- a/src/cadet/gnunet-service-cadet_hello.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2014 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 - * - * All functions in this file should use the prefix GMH (Gnunet Cadet Hello) - */ - -#ifndef GNUNET_SERVICE_CADET_HELLO_H -#define GNUNET_SERVICE_CADET_HELLO_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_hello_lib.h" - - -/** - * Initialize the hello subsystem. - * - * @param c Configuration. - */ -void -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_local.c b/src/cadet/gnunet-service-cadet_local.c deleted file mode 100644 index dea6681df..000000000 --- a/src/cadet/gnunet-service-cadet_local.c +++ /dev/null @@ -1,1553 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2013 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - - -#include "platform.h" -#include "gnunet_util_lib.h" - -#include "gnunet_statistics_service.h" - -#include "cadet.h" -#include "cadet_protocol.h" /* GNUNET_CADET_Data is shared */ - -#include "gnunet-service-cadet_local.h" -#include "gnunet-service-cadet_channel.h" - -/* INFO DEBUG */ -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_peer.h" - -#define LOG(level, ...) GNUNET_log_from(level,"cadet-loc",__VA_ARGS__) - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - -/** - * Struct containing information about a client of the service - * - * TODO: add a list of 'waiting' ports - */ -struct CadetClient -{ - /** - * Linked list next - */ - struct CadetClient *next; - - /** - * Linked list prev - */ - struct CadetClient *prev; - - /** - * Tunnels that belong to this client, indexed by local id - */ - struct GNUNET_CONTAINER_MultiHashMap32 *own_channels; - - /** - * Tunnels this client has accepted, indexed by incoming local id - */ - struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels; - - /** - * Channel ID for the next incoming channel. - */ - struct GNUNET_CADET_ClientChannelNumber next_ccn; - - /** - * Handle to communicate with the client - */ - struct GNUNET_SERVER_Client *handle; - - /** - * Ports that this client has declared interest in. - * Indexed by port, contains *Client. - */ - struct GNUNET_CONTAINER_MultiHashMap *ports; - - /** - * Whether the client is active or shutting down (don't send confirmations - * to a client that is shutting down. - */ - int shutting_down; - - /** - * ID of the client, mainly for debug messages - */ - unsigned int id; -}; - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Handle to server lib. - */ -static struct GNUNET_SERVER_Handle *server_handle; - -/** - * DLL with all the clients, head. - */ -static struct CadetClient *clients_head; - -/** - * DLL with all the clients, tail. - */ -static struct CadetClient *clients_tail; - -/** - * Next ID to assign to a client. - */ -unsigned int next_client_id; - -/** - * All ports clients of this peer have opened. - */ -static struct GNUNET_CONTAINER_MultiHashMap *ports; - -/** - * Notification context, to send messages to local clients. - */ -static struct GNUNET_SERVER_NotificationContext *nc; - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - -/** - * Remove client's ports from the global hashmap on disconnect. - * - * @param cls Closure (unused). - * @param key Port. - * @param value Client structure. - * - * @return #GNUNET_OK, keep iterating. - */ -static int -client_release_ports (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - int res; - - res = GNUNET_CONTAINER_multihashmap_remove (ports, key, value); - if (GNUNET_YES != res) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_WARNING, - "Port %s by client %p was not registered.\n", - GNUNET_h2s (key), value); - } - return GNUNET_OK; -} - - -/** - * Iterator for deleting each channel whose client endpoint disconnected. - * - * @param cls Closure (client that has disconnected). - * @param key The local channel id (used to access the hashmap). - * @param value The value stored at the key (channel to destroy). - * - * @return #GNUNET_OK, keep iterating. - */ -static int -channel_destroy_iterator (void *cls, - uint32_t key, - void *value) -{ - struct CadetChannel *ch = value; - struct CadetClient *c = cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - " Channel %s destroy, due to client %s shutdown.\n", - GCCH_2s (ch), GML_2s (c)); - - GCCH_handle_local_destroy (ch, - c, - key < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); - return GNUNET_OK; -} - - -/** - * Unregister data and free memory for a client. - * - * @param c Client to destroy. No longer valid after call. - */ -static void -client_destroy (struct CadetClient *c) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, " client destroy: %p/%u\n", c, c->id); - GNUNET_SERVER_client_drop (c->handle); - c->shutting_down = GNUNET_YES; - - if (NULL != c->own_channels) - { - GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels, - &channel_destroy_iterator, c); - GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels); - } - if (NULL != c->incoming_channels) - { - GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels, - &channel_destroy_iterator, c); - GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels); - } - if (NULL != c->ports) - { - GNUNET_CONTAINER_multihashmap_iterate (c->ports, - &client_release_ports, c); - GNUNET_CONTAINER_multihashmap_destroy (c->ports); - } - - GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c); - GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO); - GNUNET_SERVER_client_set_user_context (c->handle, NULL); - GNUNET_free (c); -} - - -/** - * Create a client record, register data and initialize memory. - * - * @param client Client's handle. - */ -static struct CadetClient * -client_new (struct GNUNET_SERVER_Client *client) -{ - struct CadetClient *c; - - GNUNET_SERVER_client_keep (client); - GNUNET_SERVER_notification_context_add (nc, client); - - c = GNUNET_new (struct CadetClient); - c->handle = client; - c->id = next_client_id++; /* overflow not important: just for debug */ - - c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32); - c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32); - - GNUNET_SERVER_client_set_user_context (client, c); - GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c); - GNUNET_STATISTICS_update (stats, "# clients", +1, GNUNET_NO); - - LOG (GNUNET_ERROR_TYPE_DEBUG, " client created: %p/%u\n", c, c->id); - - return c; -} - - -/******************************************************************************/ -/******************************** HANDLES ***********************************/ -/******************************************************************************/ - -/** - * Handler for client connection. - * - * @param cls Closure (unused). - * @param client Client handler. - */ -static void -handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client); - if (NULL == client) - return; - - (void) client_new (client); -} - - -/** - * Handler for client disconnection - * - * @param cls closure - * @param client identification of the client; NULL - * for the last call when the server is destroyed - */ -static void -handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) -{ - struct CadetClient *c; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected: %p\n", client); - - c = GML_client_get (client); - if (NULL != c) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n", - c->id, c); - client_destroy (c); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " disconnecting client's context NULL\n"); - } - return; -} - - -/** - * Handler for port open requests. - * - * @param cls Closure. - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_port_open (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct CadetClient *c; - struct GNUNET_CADET_PortMessage *pmsg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "open port requested\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); - - /* Message size sanity check */ - if (sizeof (struct GNUNET_CADET_PortMessage) != ntohs (message->size)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - pmsg = (struct GNUNET_CADET_PortMessage *) message; - if (NULL == c->ports) - { - c->ports = GNUNET_CONTAINER_multihashmap_create (4, GNUNET_NO); - } - /* store in client's hashmap */ - if (GNUNET_OK != - GNUNET_CONTAINER_multihashmap_put (c->ports, &pmsg->port, c, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - /* store in global hashmap */ - /* FIXME only allow one client to have the port open, - * have a backup hashmap with waiting clients */ - GNUNET_CONTAINER_multihashmap_put (ports, &pmsg->port, c, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); - - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Handler for port close requests. - * - * @param cls Closure. - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_port_close (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct CadetClient *c; - struct GNUNET_CADET_PortMessage *pmsg; - int removed; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "close port requested\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); - - /* Message size sanity check */ - if (sizeof (struct GNUNET_CADET_PortMessage) != ntohs (message->size)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - pmsg = (struct GNUNET_CADET_PortMessage *) message; - removed = GNUNET_CONTAINER_multihashmap_remove (c->ports, &pmsg->port, c); - GNUNET_break_op (GNUNET_YES == removed); - removed = GNUNET_CONTAINER_multihashmap_remove (ports, &pmsg->port, c); - GNUNET_break_op (GNUNET_YES == removed); - - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Handler for requests of new channels. - * - * @param cls Closure. - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct CadetClient *c; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); - - /* Message size sanity check */ - if (sizeof (struct GNUNET_CADET_LocalChannelCreateMessage) - != ntohs (message->size)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - if (GNUNET_OK != - GCCH_handle_local_create (c, - (struct GNUNET_CADET_LocalChannelCreateMessage *) - message)) - { - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Handler for requests of deleting tunnels - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -static void -handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_CADET_LocalChannelDestroyMessage *msg; - struct CadetClient *c; - struct CadetChannel *ch; - struct GNUNET_CADET_ClientChannelNumber ccn; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a DESTROY CHANNEL from client!\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); - - /* Message sanity check */ - if (sizeof (struct GNUNET_CADET_LocalChannelDestroyMessage) - != ntohs (message->size)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - msg = (const struct GNUNET_CADET_LocalChannelDestroyMessage *) message; - - /* Retrieve tunnel */ - ccn = msg->ccn; - ch = GML_channel_get (c, ccn); - - LOG (GNUNET_ERROR_TYPE_INFO, "Client %u is destroying channel %X\n", - c->id, ccn); - - if (NULL == ch) - { - LOG (GNUNET_ERROR_TYPE_WARNING, " channel %X not found\n", ccn); - GNUNET_STATISTICS_update (stats, - "# client destroy messages on unknown channel", - 1, GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - - GCCH_handle_local_destroy (ch, - c, - ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); - - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Handler for client traffic - * - * @param cls closure - * @param client identification of the client - * @param message the actual message - */ -static void -handle_data (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_MessageHeader *payload; - struct GNUNET_CADET_LocalData *msg; - struct CadetClient *c; - struct CadetChannel *ch; - struct GNUNET_CADET_ClientChannelNumber ccn; - size_t message_size; - size_t payload_size; - size_t payload_claimed_size; - int fwd; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Got data from a client\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - /* Sanity check for message size */ - message_size = ntohs (message->size); - if (sizeof (struct GNUNET_CADET_LocalData) - + sizeof (struct GNUNET_MessageHeader) > message_size - || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < message_size) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - /* Sanity check for payload size */ - payload_size = message_size - sizeof (struct GNUNET_CADET_LocalData); - msg = (struct GNUNET_CADET_LocalData *) message; - payload = (struct GNUNET_MessageHeader *) &msg[1]; - payload_claimed_size = ntohs (payload->size); - if (sizeof (struct GNUNET_MessageHeader) > payload_claimed_size - || GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_claimed_size - || payload_claimed_size > payload_size) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "client claims to send %u bytes in %u payload\n", - payload_claimed_size, payload_size); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - ccn = msg->ccn; - LOG (GNUNET_ERROR_TYPE_DEBUG, " %u bytes (%u payload) by client %u\n", - payload_size, payload_claimed_size, c->id); - - /* Channel exists? */ - fwd = ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; - ch = GML_channel_get (c, ccn); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, - "# client data messages on unknown channel", - 1, GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - - if (GNUNET_OK != GCCH_handle_local_data (ch, c, fwd, payload, payload_size)) - { - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n"); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - - return; -} - - -/** - * Handler for client's ACKs for payload traffic. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_ack (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct GNUNET_CADET_LocalAck *msg; - struct CadetChannel *ch; - struct CadetClient *c; - struct GNUNET_CADET_ClientChannelNumber ccn; - int fwd; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "\n"); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n"); - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " by client %u\n", c->id); - - msg = (struct GNUNET_CADET_LocalAck *) message; - - /* Channel exists? */ - ccn = msg->ccn; - LOG (GNUNET_ERROR_TYPE_DEBUG, " on channel %X\n", - ntohl (ccn.channel_of_client)); - ch = GML_channel_get (c, ccn); - LOG (GNUNET_ERROR_TYPE_DEBUG, " -- ch %p\n", ch); - if (NULL == ch) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Channel %X unknown.\n", - ntohl (ccn.channel_of_client)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " for client %u.\n", c->id); - GNUNET_STATISTICS_update (stats, - "# client ack messages on unknown channel", - 1, GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - - /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */ - /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */ - fwd = ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; - - GCCH_handle_local_ack (ch, fwd); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Iterator over all peers to send a monitoring client info about each peer. - * - * @param cls Closure (). - * @param peer Peer ID (tunnel remote peer). - * @param value Peer info. - * - * @return #GNUNET_YES, to keep iterating. - */ -static int -get_all_peers_iterator (void *cls, - const struct GNUNET_PeerIdentity * peer, - void *value) -{ - struct GNUNET_SERVER_Client *client = cls; - struct CadetPeer *p = value; - struct GNUNET_CADET_LocalInfoPeer msg; - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); - msg.destination = *peer; - msg.paths = htons (GCP_count_paths (p)); - msg.tunnel = htons (NULL != GCP_get_tunnel (p)); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about peer %s\n", - GNUNET_i2s (peer)); - - GNUNET_SERVER_notification_context_unicast (nc, client, - &msg.header, GNUNET_NO); - return GNUNET_YES; -} - - -/** - * Iterator over all peers to dump info for each peer. - * - * @param cls Closure (unused). - * @param peer Peer ID (tunnel remote peer). - * @param value Peer info. - * - * @return #GNUNET_YES, to keep iterating. - */ -static int -show_peer_iterator (void *cls, - const struct GNUNET_PeerIdentity * peer, - void *value) -{ - struct CadetPeer *p = value; - struct CadetTunnel *t; - - t = GCP_get_tunnel (p); - if (NULL != t) - GCT_debug (t, GNUNET_ERROR_TYPE_ERROR); - - LOG (GNUNET_ERROR_TYPE_ERROR, "\n"); - - return GNUNET_YES; -} - - -/** - * Iterator over all paths of a peer to build an InfoPeer message. - * - * Message contains blocks of peers, first not included. - * - * @param cls Closure (message to build). - * @param peer Peer this path is towards. - * @param path Path itself - * @return #GNUNET_YES if should keep iterating. - * #GNUNET_NO otherwise. - */ -static int -path_info_iterator (void *cls, - struct CadetPeer *peer, - struct CadetPeerPath *path) -{ - struct GNUNET_CADET_LocalInfoPeer *resp = cls; - struct GNUNET_PeerIdentity *id; - uint16_t msg_size; - uint16_t path_size; - unsigned int i; - - msg_size = ntohs (resp->header.size); - path_size = sizeof (struct GNUNET_PeerIdentity) * (path->length - 1); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Info Path %u\n", path->length); - if (msg_size + path_size > UINT16_MAX) - { - LOG (GNUNET_ERROR_TYPE_WARNING, "path too long for info message\n"); - return GNUNET_NO; - } - - i = msg_size - sizeof (struct GNUNET_CADET_LocalInfoPeer); - i = i / sizeof (struct GNUNET_PeerIdentity); - - /* Set id to the address of the first free peer slot. */ - id = (struct GNUNET_PeerIdentity *) &resp[1]; - id = &id[i]; - - /* Don't copy first peers. - * First peer is always the local one. - * Last peer is always the destination (leave as 0, EOL). - */ - for (i = 0; i < path->length - 1; i++) - { - GNUNET_PEER_resolve (path->peers[i + 1], &id[i]); - LOG (GNUNET_ERROR_TYPE_DEBUG, " %s\n", GNUNET_i2s (&id[i])); - } - - resp->header.size = htons (msg_size + path_size); - - return GNUNET_YES; -} - - -/** - * Handler for client's INFO PEERS request. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_get_peers (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct CadetClient *c; - struct GNUNET_MessageHeader reply; - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received get peers request from client %u (%p)\n", - c->id, client); - - GCP_iterate_all (get_all_peers_iterator, client); - reply.size = htons (sizeof (reply)); - reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS); - GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Get peers request from client %u completed\n", c->id); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Handler for client's SHOW_PEER request. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -void -handle_show_peer (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_CADET_LocalInfo *msg; - struct GNUNET_CADET_LocalInfoPeer *resp; - struct CadetPeer *p; - struct CadetClient *c; - unsigned char cbuf[64 * 1024]; - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - msg = (struct GNUNET_CADET_LocalInfo *) message; - resp = (struct GNUNET_CADET_LocalInfoPeer *) cbuf; - LOG (GNUNET_ERROR_TYPE_INFO, - "Received peer info request from client %u for peer %s\n", - c->id, GNUNET_i2s_full (&msg->peer)); - - resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER); - resp->header.size = htons (sizeof (struct GNUNET_CADET_LocalInfoPeer)); - resp->destination = msg->peer; - p = GCP_get (&msg->peer, GNUNET_NO); - if (NULL == p) - { - /* We don't know the peer */ - - LOG (GNUNET_ERROR_TYPE_INFO, "Peer %s unknown\n", - GNUNET_i2s_full (&msg->peer)); - resp->paths = htons (0); - resp->tunnel = htons (NULL != GCP_get_tunnel (p)); - - GNUNET_SERVER_notification_context_unicast (nc, client, - &resp->header, - GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - - resp->paths = htons (GCP_count_paths (p)); - resp->tunnel = htons (NULL != GCP_get_tunnel (p)); - GCP_iterate_paths (p, &path_info_iterator, resp); - - GNUNET_SERVER_notification_context_unicast (nc, c->handle, - &resp->header, GNUNET_NO); - - LOG (GNUNET_ERROR_TYPE_INFO, "Show peer from client %u completed.\n", c->id); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Iterator over all tunnels to send a monitoring client info about each tunnel. - * - * @param cls Closure (). - * @param peer Peer ID (tunnel remote peer). - * @param value Tunnel info. - * - * @return #GNUNET_YES, to keep iterating. - */ -static int -get_all_tunnels_iterator (void *cls, - const struct GNUNET_PeerIdentity * peer, - void *value) -{ - struct GNUNET_SERVER_Client *client = cls; - struct CadetTunnel *t = value; - struct GNUNET_CADET_LocalInfoTunnel msg; - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); - msg.destination = *peer; - msg.channels = htonl (GCT_count_channels (t)); - msg.connections = htonl (GCT_count_any_connections (t)); - msg.cstate = htons ((uint16_t) GCT_get_cstate (t)); - msg.estate = htons ((uint16_t) GCT_get_estate (t)); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "sending info about tunnel ->%s\n", - GNUNET_i2s (peer)); - - GNUNET_SERVER_notification_context_unicast (nc, client, - &msg.header, GNUNET_NO); - return GNUNET_YES; -} - - -/** - * Handler for client's INFO TUNNELS request. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -static void -handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct CadetClient *c; - struct GNUNET_MessageHeader reply; - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received get tunnels request from client %u (%p)\n", - c->id, client); - - GCT_iterate_all (get_all_tunnels_iterator, client); - reply.size = htons (sizeof (reply)); - reply.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS); - GNUNET_SERVER_notification_context_unicast (nc, client, &reply, GNUNET_NO); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Get tunnels request from client %u completed\n", c->id); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -static void -iter_connection (void *cls, struct CadetConnection *c) -{ - struct GNUNET_CADET_LocalInfoTunnel *msg = cls; - struct GNUNET_CADET_ConnectionTunnelIdentifier *h; - - h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1]; - h[msg->connections] = *(GCC_get_id (c)); - msg->connections++; -} - -static void -iter_channel (void *cls, struct CadetChannel *ch) -{ - struct GNUNET_CADET_LocalInfoTunnel *msg = cls; - struct GNUNET_CADET_ConnectionTunnelIdentifier *h = (struct GNUNET_CADET_ConnectionTunnelIdentifier *) &msg[1]; - struct GNUNET_CADET_ChannelTunnelNumber *chn = (struct GNUNET_CADET_ChannelTunnelNumber *) &h[msg->connections]; - - chn[msg->channels] = GCCH_get_id (ch); - msg->channels++; -} - - -/** - * Handler for client's SHOW_TUNNEL request. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -void -handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_CADET_LocalInfo *msg; - struct GNUNET_CADET_LocalInfoTunnel *resp; - struct CadetClient *c; - struct CadetTunnel *t; - unsigned int ch_n; - unsigned int c_n; - size_t size; - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - msg = (struct GNUNET_CADET_LocalInfo *) message; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received tunnel info request from client %u for tunnel %s\n", - c->id, GNUNET_i2s_full(&msg->peer)); - - t = GCP_get_tunnel (GCP_get (&msg->peer, GNUNET_NO)); - if (NULL == t) - { - /* We don't know the tunnel */ - struct GNUNET_CADET_LocalInfoTunnel warn; - - LOG (GNUNET_ERROR_TYPE_INFO, "Tunnel %s unknown %u\n", - GNUNET_i2s_full(&msg->peer), sizeof (warn)); - warn.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); - warn.header.size = htons (sizeof (warn)); - warn.destination = msg->peer; - warn.channels = htonl (0); - warn.connections = htonl (0); - warn.cstate = htons (0); - warn.estate = htons (0); - - GNUNET_SERVER_notification_context_unicast (nc, client, - &warn.header, - GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - return; - } - - /* Initialize context */ - ch_n = GCT_count_channels (t); - c_n = GCT_count_any_connections (t); - - size = sizeof (struct GNUNET_CADET_LocalInfoTunnel); - size += c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier); - size += ch_n * sizeof (struct GNUNET_CADET_ChannelTunnelNumber); - - resp = GNUNET_malloc (size); - resp->header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL); - resp->header.size = htons (size); - resp->destination = msg->peer; - /* Do not interleave with iterators, iter_channel needs conn in HBO */ - GCT_iterate_connections (t, &iter_connection, resp); - GCT_iterate_channels (t, &iter_channel, resp); - resp->connections = htonl (resp->connections); - resp->channels = htonl (resp->channels); - /* Do not interleave end */ - resp->cstate = htons (GCT_get_cstate (t)); - resp->estate = htons (GCT_get_estate (t)); - GNUNET_SERVER_notification_context_unicast (nc, c->handle, - &resp->header, GNUNET_NO); - GNUNET_free (resp); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Show tunnel request from client %u completed. %u conn, %u ch\n", - c->id, c_n, ch_n); - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Handler for client's INFO_DUMP request. - * - * @param cls Closure (unused). - * @param client Identification of the client. - * @param message The actual message. - */ -void -handle_info_dump (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - struct CadetClient *c; - - /* Sanity check for client registration */ - if (NULL == (c = GML_client_get (client))) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - - LOG (GNUNET_ERROR_TYPE_INFO, "Received dump info request from client %u\n", - c->id); - LOG (GNUNET_ERROR_TYPE_ERROR, - "*************************** DUMP START ***************************\n"); - - for (c = clients_head; NULL != c; c = c->next) - { - LOG (GNUNET_ERROR_TYPE_ERROR, "Client %u (%p), handle: %p\n", - c->id, c, c->handle); - if (NULL != c->ports) - LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u ports registered\n", - GNUNET_CONTAINER_multihashmap_size (c->ports)); - else - LOG (GNUNET_ERROR_TYPE_ERROR, "\t no ports registered\n"); - LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u own channles\n", - GNUNET_CONTAINER_multihashmap32_size (c->own_channels)); - LOG (GNUNET_ERROR_TYPE_ERROR, "\t%3u incoming channles\n", - GNUNET_CONTAINER_multihashmap32_size (c->incoming_channels)); - } - LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n"); - GCP_iterate_all (&show_peer_iterator, NULL); - - LOG (GNUNET_ERROR_TYPE_ERROR, - "**************************** DUMP END ****************************\n"); - - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Functions to handle messages from clients - */ -static struct GNUNET_SERVER_MessageHandler client_handlers[] = { - {&handle_port_open, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN, - sizeof (struct GNUNET_CADET_PortMessage)}, - {&handle_port_close, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE, - sizeof (struct GNUNET_CADET_PortMessage)}, - {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE, - sizeof (struct GNUNET_CADET_LocalChannelCreateMessage)}, - {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY, - sizeof (struct GNUNET_CADET_LocalChannelDestroyMessage)}, - {&handle_data, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA, 0}, - {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK, - sizeof (struct GNUNET_CADET_LocalAck)}, - {&handle_get_peers, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS, - sizeof (struct GNUNET_MessageHeader)}, - {&handle_show_peer, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER, - sizeof (struct GNUNET_CADET_LocalInfo)}, - {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS, - sizeof (struct GNUNET_MessageHeader)}, - {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL, - sizeof (struct GNUNET_CADET_LocalInfo)}, - {&handle_info_dump, NULL, GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP, - sizeof (struct GNUNET_MessageHeader)}, - {NULL, NULL, 0, 0} -}; - - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize server subsystem. - * - * @param handle Server handle. - */ -void -GML_init (struct GNUNET_SERVER_Handle *handle) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); - server_handle = handle; - GNUNET_SERVER_suspend (server_handle); - ports = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO); -} - - -/** - * Install server (service) handlers and start listening to clients. - */ -void -GML_start (void) -{ - GNUNET_SERVER_add_handlers (server_handle, client_handlers); - GNUNET_SERVER_connect_notify (server_handle, &handle_client_connect, NULL); - GNUNET_SERVER_disconnect_notify (server_handle, &handle_client_disconnect, - NULL); - nc = GNUNET_SERVER_notification_context_create (server_handle, 1); - - clients_head = NULL; - clients_tail = NULL; - next_client_id = 0; - GNUNET_SERVER_resume (server_handle); -} - - -/** - * Shutdown server. - */ -void -GML_shutdown (void) -{ - struct CadetClient *c; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down local\n"); - - for (c = clients_head; NULL != clients_head; c = clients_head) - client_destroy (c); - - if (nc != NULL) - { - GNUNET_SERVER_notification_context_destroy (nc); - nc = NULL; - } - -} - - -/** - * Get a channel from a client. - * - * @param c Client to check. - * @param ccn Channel ID, must be local (> 0x800...). - * - * @return non-NULL if channel exists in the clients lists - */ -struct CadetChannel * -GML_channel_get (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber ccn) -{ - struct GNUNET_CONTAINER_MultiHashMap32 *map; - - if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) - map = c->own_channels; - else - map = c->incoming_channels; - - if (NULL == map) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Client %s does no t have a valid map for CCN %X\n", - GML_2s (c), ccn); - return NULL; - } - return GNUNET_CONTAINER_multihashmap32_get (map, - ccn.channel_of_client); -} - - -/** - * Add a channel to a client - * - * @param client Client. - * @param ccn Channel ID. - * @param ch Channel. - */ -void -GML_channel_add (struct CadetClient *client, - struct GNUNET_CADET_ClientChannelNumber ccn, - struct CadetChannel *ch) -{ - if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) - GNUNET_CONTAINER_multihashmap32_put (client->own_channels, - ccn.channel_of_client, - ch, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); - else - GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels, - ccn.channel_of_client, - ch, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); -} - - -/** - * Remove a channel from a client. - * - * @param client Client. - * @param ccn Channel ID. - * @param ch Channel. - */ -void -GML_channel_remove (struct CadetClient *client, - struct GNUNET_CADET_ClientChannelNumber ccn, - struct CadetChannel *ch) -{ - if (ntohl (ccn.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) - GNUNET_CONTAINER_multihashmap32_remove (client->own_channels, - ccn.channel_of_client, - ch); - else - GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels, - ccn.channel_of_client, - ch); -} - - -/** - * Get the tunnel's next free local channel ID. - * - * @param c Client. - * - * @return LID of a channel free to use. - */ -struct GNUNET_CADET_ClientChannelNumber -GML_get_next_ccn (struct CadetClient *c) -{ - struct GNUNET_CADET_ClientChannelNumber ccn; - - while (NULL != GML_channel_get (c, - c->next_ccn)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Channel %u exists...\n", - c->next_ccn); - c->next_ccn.channel_of_client - = htonl (1 + (ntohl (c->next_ccn.channel_of_client))); - if (ntohl (c->next_ccn.channel_of_client) >= - GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) - c->next_ccn.channel_of_client = htonl (0); - } - ccn = c->next_ccn; - c->next_ccn.channel_of_client - = htonl (1 + (ntohl (c->next_ccn.channel_of_client))); - - return ccn; -} - - -/** - * Check if client has registered with the service and has not disconnected - * - * @param client the client to check - * - * @return non-NULL if client exists in the global DLL - */ -struct CadetClient * -GML_client_get (struct GNUNET_SERVER_Client *client) -{ - if (NULL == client) - return NULL; - return GNUNET_SERVER_client_get_user_context (client, - struct CadetClient); -} - - -/** - * Find a client that has opened a port - * - * @param port Port to check. - * - * @return non-NULL if a client has the port. - */ -struct CadetClient * -GML_client_get_by_port (const struct GNUNET_HashCode *port) -{ - return GNUNET_CONTAINER_multihashmap_get (ports, port); -} - - -/** - * Deletes a channel from a client (either owner or destination). - * - * @param c Client whose tunnel to delete. - * @param ch Channel which should be deleted. - * @param id Channel ID. - */ -void -GML_client_delete_channel (struct CadetClient *c, - struct CadetChannel *ch, - struct GNUNET_CADET_ClientChannelNumber id) -{ - int res; - - if (ntohl (id.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI) - { - res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels, - id.channel_of_client, - ch); - if (GNUNET_YES != res) - LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n"); - } - else - { - res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels, - id.channel_of_client, - ch); - if (GNUNET_YES != res) - LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n"); - } -} - -/** - * Build a local ACK message and send it to a local client, if needed. - * - * If the client was already allowed to send data, do nothing. - * - * @param c Client to whom send the ACK. - * @param ccn Channel ID to use - */ -void -GML_send_ack (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber ccn) -{ - struct GNUNET_CADET_LocalAck msg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "send local %s ack on %X towards %p\n", - ntohl (ccn.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI - ? "FWD" : "BCK", - ntohl (ccn.channel_of_client), - c); - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK); - msg.ccn = ccn; - GNUNET_SERVER_notification_context_unicast (nc, - c->handle, - &msg.header, - GNUNET_NO); - -} - - - -/** - * Notify the client that a new incoming channel was created. - * - * @param c Client to notify. - * @param ccn Channel ID. - * @param port Channel's destination port. - * @param opt Options (bit array). - * @param peer Origin peer. - */ -void -GML_send_channel_create (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber ccn, - const struct GNUNET_HashCode *port, - uint32_t opt, - const struct GNUNET_PeerIdentity *peer) -{ - struct GNUNET_CADET_LocalChannelCreateMessage msg; - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_CREATE); - msg.ccn = ccn; - msg.port = *port; - msg.opt = htonl (opt); - msg.peer = *peer; - GNUNET_SERVER_notification_context_unicast (nc, c->handle, - &msg.header, GNUNET_NO); -} - - -/** - * Build a local channel NACK message and send it to a local client. - * - * @param c Client to whom send the NACK. - * @param ccn Channel ID to use - */ -void -GML_send_channel_nack (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber ccn) -{ - struct GNUNET_CADET_LocalAck msg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "send local nack on %X towards %p\n", - ntohl (ccn.channel_of_client), - c); - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED); - msg.ccn = ccn; - GNUNET_SERVER_notification_context_unicast (nc, - c->handle, - &msg.header, - GNUNET_NO); - -} - -/** - * Notify a client that a channel is no longer valid. - * - * @param c Client. - * @param ccn ID of the channel that is destroyed. - */ -void -GML_send_channel_destroy (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber ccn) -{ - struct GNUNET_CADET_LocalChannelDestroyMessage msg; - - if (NULL == c) - { - GNUNET_break (0); - return; - } - if (GNUNET_YES == c->shutting_down) - return; - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_LOCAL_CHANNEL_DESTROY); - msg.ccn = ccn; - GNUNET_SERVER_notification_context_unicast (nc, c->handle, - &msg.header, GNUNET_NO); -} - - -/** - * Modify the cadet message ID from global to local and send to client. - * - * @param c Client to send to. - * @param msg Message to modify and send. - * @param ccn Channel ID to use (c can be both owner and client). - */ -void -GML_send_data (struct CadetClient *c, - const struct GNUNET_CADET_ChannelAppDataMessage *msg, - struct GNUNET_CADET_ClientChannelNumber ccn) -{ - struct GNUNET_CADET_LocalData *copy; - uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_CADET_ChannelAppDataMessage); - char cbuf[size + sizeof (struct GNUNET_CADET_LocalData)]; - - if (size < sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break_op (0); - return; - } - if (NULL == c) - { - GNUNET_break (0); - return; - } - copy = (struct GNUNET_CADET_LocalData *) cbuf; - GNUNET_memcpy (©[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, - ©->header, GNUNET_NO); -} - - -/** - * Get the static string to represent a client. - * - * @param c Client. - * - * @return Static string for the client. - */ -const char * -GML_2s (const struct CadetClient *c) -{ - static char buf[32]; - - SPRINTF (buf, "%u", c->id); - return buf; -} diff --git a/src/cadet/gnunet-service-cadet_local.h b/src/cadet/gnunet-service-cadet_local.h deleted file mode 100644 index 113c2f489..000000000 --- a/src/cadet/gnunet-service-cadet_local.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2013 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file cadet/gnunet-service-cadet_local.h - * @brief cadet service; dealing with local clients - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GML (Gnunet Cadet Local) - */ - -#ifndef GNUNET_SERVICE_CADET_LOCAL_H -#define GNUNET_SERVICE_CADET_LOCAL_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" - -/** - * Struct containing information about a client of the service - */ -struct CadetClient; - -#include "gnunet-service-cadet_channel.h" - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize server subsystem. - * - * @param handle Server handle. - */ -void -GML_init (struct GNUNET_SERVER_Handle *handle); - -/** - * Install server (service) handlers and start listening to clients. - */ -void -GML_start (void); - -/** - * Shutdown server. - */ -void -GML_shutdown (void); - -/** - * Get a channel from a client. - * - * @param c Client to check. - * @param ccn Channel ID, must be local (> 0x800...). - * - * @return non-NULL if channel exists in the clients lists - */ -struct CadetChannel * -GML_channel_get (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber ccn); - -/** - * Add a channel to a client - * - * @param client Client. - * @param ccn Channel ID. - * @param ch Channel. - */ -void -GML_channel_add (struct CadetClient *client, - struct GNUNET_CADET_ClientChannelNumber ccn, - struct CadetChannel *ch); - -/** - * Remove a channel from a client - * - * @param client Client. - * @param ccn Channel ID. - * @param ch Channel. - */ -void -GML_channel_remove (struct CadetClient *client, - struct GNUNET_CADET_ClientChannelNumber ccn, - struct CadetChannel *ch); - -/** - * Get the tunnel's next free local channel ID. - * - * @param c Client. - * - * @return LID of a channel free to use. - */ -struct GNUNET_CADET_ClientChannelNumber -GML_get_next_ccn (struct CadetClient *c); - -/** - * Check if client has registered with the service and has not disconnected - * - * @param client the client to check - * - * @return non-NULL if client exists in the global DLL - */ -struct CadetClient * -GML_client_get (struct GNUNET_SERVER_Client *client); - -/** - * Find a client that has opened a port - * - * @param port Port to check. - * - * @return non-NULL if a client has the port. - */ -struct CadetClient * -GML_client_get_by_port (const struct GNUNET_HashCode *port); - -/** - * Deletes a tunnel from a client (either owner or destination). - * - * @param c Client whose tunnel to delete. - * @param ch Channel which should be deleted. - * @param id Channel ID. - */ -void -GML_client_delete_channel (struct CadetClient *c, - struct CadetChannel *ch, - struct GNUNET_CADET_ClientChannelNumber id); - -/** - * Build a local ACK message and send it to a local client, if needed. - * - * If the client was already allowed to send data, do nothing. - * - * @param c Client to whom send the ACK. - * @param id Channel ID to use - */ -void -GML_send_ack (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber id); - -/** - * Notify the appropriate client that a new incoming channel was created. - * - * @param c Client to notify. - * @param id Channel ID. - * @param port Channel's destination port. - * @param opt Options (bit array). - * @param peer Origin peer. - */ -void -GML_send_channel_create (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber id, - const struct GNUNET_HashCode *port, - uint32_t opt, - const struct GNUNET_PeerIdentity *peer); - -/** - * Build a local channel NACK message and send it to a local client. - * - * @param c Client to whom send the NACK. - * @param id Channel ID to use - */ -void -GML_send_channel_nack (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber id); - - -/** - * Notify a client that a channel is no longer valid. - * - * @param c Client. - * @param id ID of the channel that is destroyed. - */ -void -GML_send_channel_destroy (struct CadetClient *c, - struct GNUNET_CADET_ClientChannelNumber id); - - -/** - * Modify the cadet message ID from global to local and send to client. - * - * @param c Client to send to. - * @param msg Message to modify and send. - * @param id Channel ID to use (c can be both owner and client). - */ -void -GML_send_data (struct CadetClient *c, - const struct GNUNET_CADET_ChannelAppDataMessage *msg, - struct GNUNET_CADET_ClientChannelNumber id); - -/** - * Get the static string to represent a client. - * - * @param c Client. - * - * @return Static string for the client. - */ -const char * -GML_2s (const struct CadetClient *c); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_CADET_SERVICE_LOCAL_H */ -#endif -/* end of gnunet-cadet-service_LOCAL.h */ diff --git a/src/cadet/gnunet-service-cadet_peer.c b/src/cadet/gnunet-service-cadet_peer.c deleted file mode 100644 index fa3f2be80..000000000 --- a/src/cadet/gnunet-service-cadet_peer.c +++ /dev/null @@ -1,2209 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2013, 2015 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_peer.c - * @brief GNUnet CADET service connection handling - * @author Bartlomiej Polot - */ -#include "platform.h" -#include "gnunet_util_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" - -#define LOG(level, ...) GNUNET_log_from (level,"cadet-p2p",__VA_ARGS__) -#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-p2p",__VA_ARGS__) - - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - -/** - * Information about a queued message on the peer level. - */ -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; -}; - - -/** - * Struct containing all information regarding a given 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; - -}; - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (full value). - */ -extern struct GNUNET_PeerIdentity my_full_id; - -/** - * Local peer own ID (short) - */ -extern GNUNET_PEER_Id myid; - -/** - * Peers known, indexed by PeerIdentity, values of type `struct CadetPeer`. - */ -static struct GNUNET_CONTAINER_MultiPeerMap *peers; - -/** - * How many peers do we want to remember? - */ -static unsigned long long max_peers; - -/** - * Percentage of messages that will be dropped (for test purposes only). - */ -static unsigned long long drop_percent; - -/** - * Handle to communicate with CORE. - */ -static struct GNUNET_CORE_Handle *core_handle; - -/** - * Our configuration; - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Handle to communicate with ATS. - */ -static struct GNUNET_ATS_ConnectivityHandle *ats_ch; - -/** - * Shutdown falg. - */ -static int in_shutdown; - - -/******************************************************************************/ -/***************************** CORE HELPERS *********************************/ -/******************************************************************************/ - - -/** - * Iterator to notify all connections of a broken link. Mark connections - * to destroy after all traffic has been sent. - * - * @param cls Closure (disconnected peer). - * @param key Current key code (peer id). - * @param value Value in the hash map (connection). - * - * @return #GNUNET_YES to continue to iterate. - */ -static int -notify_broken (void *cls, - const struct GNUNET_ShortHashCode *key, - void *value) -{ - struct CadetPeer *peer = cls; - struct CadetConnection *c = value; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Notifying %s due to %s disconnect\n", - GCC_2s (c), GCP_2s (peer)); - GCC_neighbor_disconnected (c, peer); - return GNUNET_YES; -} - - -/** - * Remove the direct path to the peer. - * - * @param peer Peer to remove the direct path from. - */ -static struct CadetPeerPath * -pop_direct_path (struct CadetPeer *peer) -{ - struct CadetPeerPath *iter; - - for (iter = peer->path_head; NULL != iter; iter = iter->next) - { - if (2 >= iter->length) - { - GNUNET_CONTAINER_DLL_remove (peer->path_head, - peer->path_tail, - iter); - return iter; - } - } - return NULL; -} - -/** - * Call the continuation after a message has been sent or dropped. - * - * This funcion removes the message from the queue. - * - * @param q Queue handle. - * @param sent #GNUNET_YES if was sent to CORE, #GNUNET_NO if dropped. - */ -static void -call_peer_cont (struct CadetPeerQueue *q, int sent); - - -/******************************************************************************/ -/***************************** CORE CALLBACKS *********************************/ -/******************************************************************************/ - - -/** - * Method called whenever a given peer connects. - * - * @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). - */ -static void * -core_connect_handler (void *cls, - const struct GNUNET_PeerIdentity *peer, - struct GNUNET_MQ_Handle *mq) -{ - struct CadetPeer *neighbor; - struct CadetPeerPath *path; - char own_id[16]; - - GCC_check_connections (); - GNUNET_snprintf (own_id, - sizeof (own_id), - "%s", - GNUNET_i2s (&my_full_id)); - - /* Save a path to the neighbor */ - neighbor = GCP_get (peer, GNUNET_YES); - if (myid == neighbor->id) - { - LOG (GNUNET_ERROR_TYPE_INFO, - "CONNECTED %s (self)\n", - own_id); - path = path_new (1); - } - else - { - LOG (GNUNET_ERROR_TYPE_INFO, - "CONNECTED %s <= %s\n", - own_id, - GNUNET_i2s (peer)); - path = path_new (2); - path->peers[1] = neighbor->id; - GNUNET_PEER_change_rc (neighbor->id, 1); - GNUNET_assert (NULL == neighbor->core_mq); - neighbor->core_mq = mq; - } - path->peers[0] = myid; - GNUNET_PEER_change_rc (myid, 1); - GCP_add_path (neighbor, path, GNUNET_YES); - - /* Create the connections hashmap */ - GNUNET_assert (NULL == neighbor->connections); - neighbor->connections = GNUNET_CONTAINER_multishortmap_create (16, - GNUNET_YES); - GNUNET_STATISTICS_update (stats, - "# peers", - 1, - GNUNET_NO); - - if ( (NULL != GCP_get_tunnel (neighbor)) && - (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, peer)) ) - { - GCP_connect (neighbor); - } - GCC_check_connections (); - - return neighbor; -} - - -/** - * Method called whenever a peer disconnects. - * - * @param cls Core closure (unused). - * @param peer Peer identity this notification is about. - * @param internal_cls Internal closure (CadetPeer struct). - */ -static void -core_disconnect_handler (void *cls, - const struct GNUNET_PeerIdentity *peer, - void *internal_cls) -{ - struct CadetPeer *p = internal_cls; - struct CadetPeerPath *direct_path; - char own_id[16]; - - GCC_check_connections (); - strncpy (own_id, GNUNET_i2s (&my_full_id), 16); - own_id[15] = '\0'; - if (myid == p->id) - { - LOG (GNUNET_ERROR_TYPE_INFO, - "DISCONNECTED %s (self)\n", - own_id); - } - else - { - 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, - ¬ify_broken, - p); - GNUNET_CONTAINER_multishortmap_destroy (p->connections); - p->connections = NULL; - } - GNUNET_STATISTICS_update (stats, - "# peers", - -1, - GNUNET_NO); - path_destroy (direct_path); - GCC_check_connections (); -} - - -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ - -/** - * Check if the create_connection message has the appropriate size. - * - * @param cls Closure (unused). - * @param msg Message to check. - * - * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise. - */ -static int -check_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg) -{ - uint16_t size; - - size = ntohs (msg->header.size); - if (size < sizeof (*msg)) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - return GNUNET_YES; -} - -/** - * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE - * - * @param cls Closure (CadetPeer for neighbor that sent the message). - * @param msg Message itself. - */ -static void -handle_create (void *cls, const struct GNUNET_CADET_ConnectionCreateMessage *msg) -{ - struct CadetPeer *peer = cls; - GCC_handle_create (peer, msg); -} - - -/** - * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK - * - * @param cls Closure (CadetPeer for neighbor that sent the message). - * @param msg Message itself. - */ -static void -handle_confirm (void *cls, const struct GNUNET_CADET_ConnectionCreateAckMessage *msg) -{ - struct CadetPeer *peer = cls; - GCC_handle_confirm (peer, msg); -} - - -/** - * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN - * - * @param cls Closure (CadetPeer for neighbor that sent the message). - * @param msg Message itself. - */ -static void -handle_broken (void *cls, const struct GNUNET_CADET_ConnectionBrokenMessage *msg) -{ - struct CadetPeer *peer = cls; - GCC_handle_broken (peer, msg); -} - - -/** - * 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_destroy (void *cls, const struct GNUNET_CADET_ConnectionDestroyMessage *msg) -{ - struct CadetPeer *peer = cls; - GCC_handle_destroy (peer, msg); -} - - -/** - * Handle for #GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK - * - * @param cls Closure (CadetPeer for neighbor that sent the message). - * @param msg Message itself. - */ -static void -handle_ack (void *cls, const struct GNUNET_CADET_ConnectionEncryptedAckMessage *msg) -{ - struct CadetPeer *peer = cls; - GCC_handle_ack (peer, msg); -} - - -/** - * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL - * - * @param cls Closure (CadetPeer for neighbor that sent the message). - * @param msg Message itself. - */ -static void -handle_poll (void *cls, const struct GNUNET_CADET_ConnectionHopByHopPollMessage *msg) -{ - struct CadetPeer *peer = cls; - GCC_handle_poll (peer, msg); -} - - -/** - * 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_kx (void *cls, const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) -{ - struct CadetPeer *peer = cls; - GCC_handle_kx (peer, msg); -} - - -/** - * Check if the encrypted message has the appropriate size. - * - * @param cls Closure (unused). - * @param msg Message to check. - * - * @return #GNUNET_YES if size is correct, #GNUNET_NO otherwise. - */ -static int -check_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg) -{ - uint16_t size; - uint16_t minimum_size; - - size = ntohs (msg->header.size); - minimum_size = sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) - + sizeof (struct GNUNET_MessageHeader); - - if (size < minimum_size) - { - GNUNET_break_op (0); - return GNUNET_NO; - } - return GNUNET_YES; -} - -/** - * Handle for #GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED. - * - * @param cls Closure (CadetPeer for neighbor that sent the message). - * @param msg Message itself. - */ -static void -handle_encrypted (void *cls, const struct GNUNET_CADET_TunnelEncryptedMessage *msg) -{ - struct CadetPeer *peer = cls; - GCC_handle_encrypted (peer, msg); -} - - -/** - * To be called on core init/fail. - * - * @param cls Closure (config) - * @param identity The public identity of this peer. - */ -static void -core_init_notify (void *cls, - const struct GNUNET_PeerIdentity *identity); - - -static void -connect_to_core (const struct GNUNET_CONFIGURATION_Handle *c) -{ - struct GNUNET_MQ_MessageHandler core_handlers[] = { - GNUNET_MQ_hd_var_size (create, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE, - struct GNUNET_CADET_ConnectionCreateMessage, - NULL), - GNUNET_MQ_hd_fixed_size (confirm, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_CREATE_ACK, - struct GNUNET_CADET_ConnectionCreateAckMessage, - NULL), - GNUNET_MQ_hd_fixed_size (broken, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_BROKEN, - struct GNUNET_CADET_ConnectionBrokenMessage, - NULL), - GNUNET_MQ_hd_fixed_size (destroy, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_DESTROY, - struct GNUNET_CADET_ConnectionDestroyMessage, - NULL), - GNUNET_MQ_hd_fixed_size (ack, - GNUNET_MESSAGE_TYPE_CADET_CONNECTION_HOP_BY_HOP_ENCRYPTED_ACK, - struct GNUNET_CADET_ConnectionEncryptedAckMessage, - NULL), - GNUNET_MQ_hd_fixed_size (poll, - GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED_POLL, - struct GNUNET_CADET_ConnectionHopByHopPollMessage, - NULL), - GNUNET_MQ_hd_fixed_size (kx, - GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX, - struct GNUNET_CADET_TunnelKeyExchangeMessage, - NULL), - GNUNET_MQ_hd_var_size (encrypted, - GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED, - struct GNUNET_CADET_TunnelEncryptedMessage, - NULL), - GNUNET_MQ_handler_end () - }; - core_handle = GNUNET_CORE_connect (c, NULL, - &core_init_notify, - &core_connect_handler, - &core_disconnect_handler, - core_handlers); -} - -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ -/******************************************************************************/ - -/** - * To be called on core init/fail. - * - * @param cls Closure (config) - * @param identity The public identity of this peer. - */ -static void -core_init_notify (void *cls, - const struct GNUNET_PeerIdentity *core_identity) -{ - const struct GNUNET_CONFIGURATION_Handle *c = cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Core init\n"); - if (0 != memcmp (core_identity, &my_full_id, sizeof (my_full_id))) - { - LOG (GNUNET_ERROR_TYPE_ERROR, _("Wrong CORE service\n")); - LOG (GNUNET_ERROR_TYPE_ERROR, " core id %s\n", GNUNET_i2s (core_identity)); - LOG (GNUNET_ERROR_TYPE_ERROR, " my id %s\n", GNUNET_i2s (&my_full_id)); - GNUNET_CORE_disconnect (core_handle); - connect_to_core (c); - return; - } - GML_start (); -} - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - - -/** - * Get priority for a queued message. - * - * @param q Queued message - * - * @return CORE priority to use. - * - * FIXME make static - * FIXME use when sending - */ -enum GNUNET_CORE_Priority -get_priority (struct CadetPeerQueue *q) -{ - enum GNUNET_CORE_Priority low; - enum GNUNET_CORE_Priority high; - - if (NULL == q) - { - GNUNET_break (0); - return GNUNET_CORE_PRIO_BACKGROUND; - } - - /* Relayed traffic has lower priority, our own traffic has higher */ - if (NULL == q->c || GNUNET_NO == GCC_is_origin (q->c, q->c_fwd)) - { - low = GNUNET_CORE_PRIO_BEST_EFFORT; - high = GNUNET_CORE_PRIO_URGENT; - } - else - { - low = GNUNET_CORE_PRIO_URGENT; - high = GNUNET_CORE_PRIO_CRITICAL_CONTROL; - } - - /* Bulky payload has lower priority, control traffic has higher. */ - if (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED == q->type) - return low; - return high; -} - - -/** - * Cancel all messages queued to CORE MQ towards this peer. - * - * @param peer Peer towards which to cancel all messages. - */ -static void -cancel_queued_messages (struct CadetPeer *peer) -{ - while (NULL != peer->q_head) - { - struct CadetPeerQueue *q; - - q = peer->q_head; - call_peer_cont (q, GNUNET_NO); - GNUNET_free (q); - } -} - - -/** - * Destroy the peer_info and free any allocated resources linked to it - * - * @param peer The peer_info to destroy. - * @return #GNUNET_OK on success - */ -static int -peer_destroy (struct CadetPeer *peer) -{ - struct GNUNET_PeerIdentity id; - struct CadetPeerPath *p; - struct CadetPeerPath *nextp; - - GNUNET_PEER_resolve (peer->id, &id); - GNUNET_PEER_change_rc (peer->id, -1); - - LOG (GNUNET_ERROR_TYPE_INFO, - "destroying peer %s\n", - GNUNET_i2s (&id)); - - if (GNUNET_YES != - GNUNET_CONTAINER_multipeermap_remove (peers, &id, peer)) - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_WARNING, " peer not in peermap!!\n"); - } - GCP_stop_search (peer); - p = peer->path_head; - while (NULL != p) - { - nextp = p->next; - GNUNET_CONTAINER_DLL_remove (peer->path_head, - peer->path_tail, - p); - path_destroy (p); - p = nextp; - } - if (NULL != peer->tunnel) - GCT_destroy_empty (peer->tunnel); - if (NULL != peer->connections) - { - GNUNET_assert (0 == GNUNET_CONTAINER_multishortmap_size (peer->connections)); - GNUNET_CONTAINER_multishortmap_destroy (peer->connections); - peer->connections = NULL; - } - if (NULL != peer->hello_offer) - { - GNUNET_TRANSPORT_offer_hello_cancel (peer->hello_offer); - peer->hello_offer = NULL; - } - if (NULL != peer->connectivity_suggestion) - { - GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion); - peer->connectivity_suggestion = NULL; - } - cancel_queued_messages (peer); - - GNUNET_free_non_null (peer->hello); - GNUNET_free (peer); - return GNUNET_OK; -} - - -/** - * Iterator over peer hash map entries to destroy the peer during in_shutdown. - * - * @param cls closure - * @param key current key code - * @param value value in the hash map - * @return #GNUNET_YES if we should continue to iterate, - * #GNUNET_NO if not. - */ -static int -shutdown_peer (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - 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; -} - - -/** - * Check if peer is searching for a path (either active or delayed search). - * - * @param peer Peer to check - * @return #GNUNET_YES if there is a search active. - * #GNUNET_NO otherwise. - */ -static int -is_searching (const struct CadetPeer *peer) -{ - return ( (NULL == peer->search_h) && - (NULL == peer->search_delayed) ) ? - GNUNET_NO : GNUNET_YES; -} - - -/** - * @brief Start a search for a peer. - * - * @param cls Closure (Peer to search for). - */ -static void -delayed_search (void *cls) -{ - struct CadetPeer *peer = cls; - - peer->search_delayed = NULL; - GCC_check_connections (); - GCP_start_search (peer); - GCC_check_connections (); -} - - -/** - * Returns if peer is used (has a tunnel or is neighbor). - * - * @param peer Peer to check. - * @return #GNUNET_YES if peer is in use. - */ -static int -peer_is_used (struct CadetPeer *peer) -{ - struct CadetPeerPath *p; - - if (NULL != peer->tunnel) - return GNUNET_YES; - - for (p = peer->path_head; NULL != p; p = p->next) - { - if (p->length < 3) - return GNUNET_YES; - } - return GNUNET_NO; -} - - -/** - * Iterator over all the peers to get the oldest timestamp. - * - * @param cls Closure (unsued). - * @param key ID of the peer. - * @param value Peer_Info of the peer. - */ -static int -peer_get_oldest (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct CadetPeer *p = value; - struct GNUNET_TIME_Absolute *abs = cls; - - /* Don't count active peers */ - if (GNUNET_YES == peer_is_used (p)) - return GNUNET_YES; - - if (abs->abs_value_us < p->last_contact.abs_value_us) - abs->abs_value_us = p->last_contact.abs_value_us; - - return GNUNET_YES; -} - - -/** - * Iterator over all the peers to remove the oldest entry. - * - * @param cls Closure (unsued). - * @param key ID of the peer. - * @param value Peer_Info of the peer. - */ -static int -peer_timeout (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct CadetPeer *p = value; - struct GNUNET_TIME_Absolute *abs = cls; - - LOG (GNUNET_ERROR_TYPE_WARNING, - "peer %s timeout\n", GNUNET_i2s (key)); - - if (p->last_contact.abs_value_us == abs->abs_value_us && - GNUNET_NO == peer_is_used (p)) - { - peer_destroy (p); - return GNUNET_NO; - } - return GNUNET_YES; -} - - -/** - * Delete oldest unused peer. - */ -static void -peer_delete_oldest (void) -{ - struct GNUNET_TIME_Absolute abs; - - abs = GNUNET_TIME_UNIT_FOREVER_ABS; - - GNUNET_CONTAINER_multipeermap_iterate (peers, - &peer_get_oldest, - &abs); - GNUNET_CONTAINER_multipeermap_iterate (peers, - &peer_timeout, - &abs); -} - - -/** - * Choose the best (yet unused) path towards a peer, - * considering the tunnel properties. - * - * @param peer The destination peer. - * @return Best current known path towards the peer, if any. - */ -static struct CadetPeerPath * -peer_get_best_path (const struct CadetPeer *peer) -{ - struct CadetPeerPath *best_p; - struct CadetPeerPath *p; - unsigned int best_cost; - unsigned int cost; - - best_cost = UINT_MAX; - best_p = NULL; - for (p = peer->path_head; NULL != p; p = p->next) - { - if (GNUNET_NO == path_is_valid (p)) - continue; /* Don't use invalid paths. */ - if (GNUNET_YES == 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. - */ -static void -call_peer_cont (struct CadetPeerQueue *q, int sent) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, " core mq just sent %s\n", GC_m2s (q->type)); - if (NULL != q->cont) - { - struct GNUNET_TIME_Relative wait_time; - - wait_time = GNUNET_TIME_absolute_get_duration (q->queue_timestamp); - LOG (GNUNET_ERROR_TYPE_DEBUG, - " calling callback on %s after %s\n", - GCC_2s (q->c), - GNUNET_STRINGS_relative_time_to_string (wait_time, GNUNET_NO)); - q->cont (q->cont_cls, - q->c, q->c_fwd, sent, - q->type, - q->payload_type, - q->payload_id, - q->size, wait_time); - q->cont = NULL; - } - GNUNET_CONTAINER_DLL_remove (q->peer->q_head, q->peer->q_tail, q); -} - - -/** - * Function called by MQ when a message is sent to CORE. - * - * @param cls Closure (queue handle). - */ -static void -mq_sent (void *cls) -{ - struct CadetPeerQueue *q = cls; - - if (GNUNET_NO == q->management_traffic) - { - q->peer->queue_n--; - } - 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); -} - - -/** - * @brief Send a message to another peer (using CORE). - * - * @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). - */ -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) -{ - 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; -} - - -/** - * 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) - { - GNUNET_SCHEDULER_cancel (q->drop_task); - q->drop_task = NULL; - GNUNET_MQ_discard (q->env); - } - else - { - GNUNET_MQ_send_cancel (q->env); - } - 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; -} - - -/** - * Retrieve the CadetPeer stucture associated with the - * peer. Optionally create one and insert it in the appropriate - * structures if the peer is not known yet. - * - * @param peer Short identity of the peer. - * @param create #GNUNET_YES if a new peer should be created if unknown. - * #GNUNET_NO otherwise. - * - * @return Existing or newly created peer structure. - * NULL if unknown and not requested @a create - */ -struct CadetPeer * -GCP_get_short (const GNUNET_PEER_Id peer, int create) -{ - return GCP_get (GNUNET_PEER_resolve2 (peer), create); -} - - -/** - * Function called once #GNUNET_TRANSPORT_offer_hello() is done. - * Marks the operation as finished. - * - * @param cls Closure (our `struct CadetPeer`). - */ -static void -hello_offer_done (void *cls) -{ - struct CadetPeer *peer = cls; - - peer->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. - * - * @param peer Peer to connect to. - */ -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) -{ - 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)); -} - - -/** - * 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)); -} - - -/** - * Start the DHT search for new paths towards the peer: we don't have - * enough good connections. - * - * @param peer Destination peer. - */ -void -GCP_start_search (struct CadetPeer *peer) -{ - 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 (); -} - - -/** - * Stop the DHT search for new paths towards the peer: we already have - * enough good connections. - * - * @param peer Destination peer. - */ -void -GCP_stop_search (struct CadetPeer *peer) -{ - GCC_check_connections (); - if (NULL != peer->search_h) - { - GCD_search_stop (peer->search_h); - peer->search_h = NULL; - } - if (NULL != peer->search_delayed) - { - 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) -{ - return GNUNET_PEER_resolve2 (peer->id); -} - - -/** - * Get the Short ID of a peer. - * - * @param peer Peer to get from. - * - * @return Short ID of peer. - */ -GNUNET_PEER_Id -GCP_get_short_id (const struct CadetPeer *peer) -{ - return peer->id; -} - - -/** - * 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; -} - - -/** - * Set the hello message. - * - * @param peer Peer whose message to set. - * @param hello Hello message. - */ -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) - { - size = GNUNET_HELLO_size (hello); - peer->hello = GNUNET_malloc (size); - GNUNET_memcpy (peer->hello, hello, size); - } - else - { - peer->hello = GNUNET_HELLO_merge (old, hello); - GNUNET_free (old); - } - GCC_check_connections (); -} - - -/** - * 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; - } - 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; -} - - -/** - * Iterate all known peers. - * - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, - void *cls) -{ - GCC_check_connections (); - GNUNET_CONTAINER_multipeermap_iterate (peers, - iter, - cls); - GCC_check_connections (); -} - - -/** - * 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 */ diff --git a/src/cadet/gnunet-service-cadet_peer.h b/src/cadet/gnunet-service-cadet_peer.h deleted file mode 100644 index 1e206e10f..000000000 --- a/src/cadet/gnunet-service-cadet_peer.h +++ /dev/null @@ -1,483 +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_peer.h - * @brief cadet service; dealing with remote peers - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMP (Gnunet Cadet Peer) - */ - -#ifndef GNUNET_SERVICE_CADET_PEER_H -#define GNUNET_SERVICE_CADET_PEER_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" -#include "cadet_path.h" - -/** - * Struct containing all information regarding a given peer - */ -struct CadetPeer; - -/** - * 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. - * - * @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 c Configuration. - */ -void -GCP_init (const struct GNUNET_CONFIGURATION_Handle *c); - -/** - * Shut down the peer subsystem. - */ -void -GCP_shutdown (void); - - -/** - * 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); - - -/** - * Retrieve the CadetPeer stucture associated with the peer. Optionally create - * one and insert it in the appropriate structures if the peer is not known yet. - * - * @param peer Short identity of the peer. - * @param create #GNUNET_YES if a new peer should be created if unknown. - * #GNUNET_NO otherwise. - * - * @return Existing or newly created peer structure. - * NULL if unknown and not requested @a create - */ -struct CadetPeer * -GCP_get_short (const GNUNET_PEER_Id peer, int create); - - -/** - * 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). - * - * @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. - */ -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); - -/** - * 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. - * - * @param peer Peer. - * @param t Tunnel. - */ -void -GCP_set_tunnel (struct CadetPeer *peer, struct CadetTunnel *t); - - -/** - * Check whether there is a direct (core level) connection to peer. - * - * @param peer Peer to check. - * - * @return #GNUNET_YES if there is a direct connection. - */ -int -GCP_is_neighbor (const struct CadetPeer *peer); - - -/** - * Create and initialize a new tunnel towards a peer, in case it has none. - * - * Does not generate any traffic, just creates the local data structures. - * - * @param peer Peer towards which to create the tunnel. - */ -void -GCP_add_tunnel (struct CadetPeer *peer); - - -/** - * Add a connection to a neighboring peer. - * - * Store that the peer is the first hop of the connection in one - * direction and that on peer disconnect the connection must be - * notified and destroyed, for it will no longer be valid. - * - * @param peer Peer to add connection to. - * @param c Connection to add. - * @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); - - -/** - * Add the path to the peer and update the path used to reach it in case this - * is the shortest. - * - * @param peer Destination peer to add the path to. - * @param path New path to add. Last peer must be the peer in arg 1. - * Path will be either used of freed if already known. - * @param trusted Do we trust that this path is real? - * - * @return path if path was taken, pointer to existing duplicate if exists - * NULL on error. - */ -struct CadetPeerPath * -GCP_add_path (struct CadetPeer *peer, - struct CadetPeerPath *p, - int trusted); - - -/** - * Add the path to the origin peer and update the path used to reach it in case - * this is the shortest. - * The path is given in peer_info -> destination, therefore we turn the path - * upside down first. - * - * @param peer Peer to add the path to, being the origin of the path. - * @param path New path to add after being inversed. - * Path will be either used or freed. - * @param trusted Do we trust that this path is real? - * - * @return path if path was taken, pointer to existing duplicate if exists - * NULL on error. - */ -struct CadetPeerPath * -GCP_add_path_to_origin (struct CadetPeer *peer, - struct CadetPeerPath *path, - int trusted); - -/** - * Adds a path to the info of all the peers in the path - * - * @param p Path to process. - * @param confirmed Whether we know if the path works or not. - */ -void -GCP_add_path_to_all (const struct CadetPeerPath *p, int confirmed); - - -/** - * Remove any path to the peer that has the extact same peers as the one given. - * - * @param peer Peer to remove the path from. - * @param path Path to remove. Is always destroyed . - */ -void -GCP_remove_path (struct CadetPeer *peer, - struct CadetPeerPath *path); - - -/** - * 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); - - -/** - * 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); - - -/** - * Start the DHT search for new paths towards the peer: we don't have - * enough good connections. - * - * @param peer Destination peer. - */ -void -GCP_start_search (struct CadetPeer *peer); - - -/** - * Stop the DHT search for new paths towards the peer: we already have - * enough good connections. - * - * @param peer Destination peer. - */ -void -GCP_stop_search (struct CadetPeer *peer); - - -/** - * Get the Full ID of a peer. - * - * @param peer Peer to get from. - * - * @return Full ID of peer. - */ -const struct GNUNET_PeerIdentity * -GCP_get_id (const struct CadetPeer *peer); - - -/** - * Get the Short ID of a peer. - * - * @param peer Peer to get from. - * - * @return Short ID of peer. - */ -GNUNET_PEER_Id -GCP_get_short_id (const struct CadetPeer *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); - - -/** - * Set the hello message. - * - * @param peer Peer whose message to set. - * @param hello Hello message. - */ -void -GCP_set_hello (struct CadetPeer *peer, - const struct GNUNET_HELLO_Message *hello); - - -/** - * Get the hello message. - * - * @param peer Peer whose message to get. - * - * @return Hello message. - */ -struct GNUNET_HELLO_Message * -GCP_get_hello (struct CadetPeer *peer); - - -/** - * Try to connect to a peer on TRANSPORT level. - * - * @param peer Peer to whom to connect. - */ -void -GCP_try_connect (struct CadetPeer *peer); - -/** - * Notify a peer that a link between two other peers is broken. If any path - * used that link, eliminate it. - * - * @param peer Peer affected by the change. - * @param peer1 Peer whose link is broken. - * @param peer2 Peer whose link is broken. - */ -void -GCP_notify_broken_link (struct CadetPeer *peer, - const struct GNUNET_PeerIdentity *peer1, - const struct GNUNET_PeerIdentity *peer2); - - -/** - * Count the number of known paths toward the peer. - * - * @param peer Peer to get path info. - * - * @return Number of known paths. - */ -unsigned int -GCP_count_paths (const struct CadetPeer *peer); - -/** - * 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); - - -/** - * Iterate all known peers. - * - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, - void *cls); - - -/** - * Get the static string for a peer ID. - * - * @param peer Peer. - * - * @return Static string for it's ID. - */ -const char * -GCP_2s (const struct CadetPeer *peer); - - -/** - * Log all kinds of info about a peer. - * - * @param peer Peer. - */ -void -GCP_debug (const struct CadetPeer *p, - enum GNUNET_ErrorType level); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_CADET_SERVICE_PEER_H */ -#endif -/* end of gnunet-cadet-service_peer.h */ diff --git a/src/cadet/gnunet-service-cadet_tunnel.c b/src/cadet/gnunet-service-cadet_tunnel.c deleted file mode 100644 index a94e8f4ff..000000000 --- a/src/cadet/gnunet-service-cadet_tunnel.c +++ /dev/null @@ -1,3501 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2013, 2017 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -/** - * @file cadet/gnunet-service-cadet_tunnel.c - * @brief logical links between CADET clients - * @author Bartlomiej Polot - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_signatures.h" -#include "gnunet_statistics_service.h" -#include "cadet_protocol.h" -#include "cadet_path.h" -#include "gnunet-service-cadet_tunnel.h" -#include "gnunet-service-cadet_connection.h" -#include "gnunet-service-cadet_channel.h" -#include "gnunet-service-cadet_peer.h" - -#define LOG(level, ...) GNUNET_log_from(level,"cadet-tun",__VA_ARGS__) -#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__) - -#define REKEY_WAIT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5) - -#if !defined(GNUNET_CULL_LOGGING) - #define DUMP_KEYS_TO_STDERR GNUNET_YES -#else - #define DUMP_KEYS_TO_STDERR GNUNET_NO -#endif - -#define MIN_TUNNEL_BUFFER 8 -#define MAX_TUNNEL_BUFFER 64 -#define MAX_SKIPPED_KEYS 64 -#define MAX_KEY_GAP 256 -#define AX_HEADER_SIZE (sizeof (uint32_t) * 2\ - + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)) - -/******************************************************************************/ -/******************************** STRUCTS **********************************/ -/******************************************************************************/ - -struct CadetTChannel -{ - struct CadetTChannel *next; - struct CadetTChannel *prev; - struct CadetChannel *ch; -}; - - -/** - * Entry in list of connections used by tunnel, with metadata. - */ -struct CadetTConnection -{ - /** - * Next in DLL. - */ - struct CadetTConnection *next; - - /** - * Prev in DLL. - */ - struct CadetTConnection *prev; - - /** - * Connection handle. - */ - struct CadetConnection *c; - - /** - * Creation time, to keep oldest connection alive. - */ - struct GNUNET_TIME_Absolute created; - - /** - * Connection throughput, to keep fastest connection alive. - */ - uint32_t throughput; -}; - - -/** - * Struct to old keys for skipped messages while advancing the Axolotl ratchet. - */ -struct CadetTunnelSkippedKey -{ - /** - * DLL next. - */ - struct CadetTunnelSkippedKey *next; - - /** - * DLL prev. - */ - struct CadetTunnelSkippedKey *prev; - - /** - * When was this key stored (for timeout). - */ - struct GNUNET_TIME_Absolute timestamp; - - /** - * Header key. - */ - struct GNUNET_CRYPTO_SymmetricSessionKey HK; - - /** - * Message key. - */ - struct GNUNET_CRYPTO_SymmetricSessionKey MK; - - /** - * Key number for a given HK. - */ - unsigned int Kn; -}; - - -/** - * Axolotl data, according to https://github.com/trevp/axolotl/wiki . - */ -struct CadetTunnelAxolotl -{ - /** - * A (double linked) list of stored message keys and associated header keys - * for "skipped" messages, i.e. messages that have not been - * received despite the reception of more recent messages, (head). - */ - struct CadetTunnelSkippedKey *skipped_head; - - /** - * Skipped messages' keys DLL, tail. - */ - struct CadetTunnelSkippedKey *skipped_tail; - - /** - * Elements in @a skipped_head <-> @a skipped_tail. - */ - unsigned int skipped; - - /** - * 32-byte root key which gets updated by DH ratchet. - */ - struct GNUNET_CRYPTO_SymmetricSessionKey RK; - - /** - * 32-byte header key (send). - */ - struct GNUNET_CRYPTO_SymmetricSessionKey HKs; - - /** - * 32-byte header key (recv) - */ - struct GNUNET_CRYPTO_SymmetricSessionKey HKr; - - /** - * 32-byte next header key (send). - */ - struct GNUNET_CRYPTO_SymmetricSessionKey NHKs; - - /** - * 32-byte next header key (recv). - */ - struct GNUNET_CRYPTO_SymmetricSessionKey NHKr; - - /** - * 32-byte chain keys (used for forward-secrecy updating, send). - */ - struct GNUNET_CRYPTO_SymmetricSessionKey CKs; - - /** - * 32-byte chain keys (used for forward-secrecy updating, recv). - */ - struct GNUNET_CRYPTO_SymmetricSessionKey CKr; - - /** - * ECDH for key exchange (A0 / B0). - */ - struct GNUNET_CRYPTO_EcdhePrivateKey *kx_0; - - /** - * ECDH Ratchet key (send). - */ - struct GNUNET_CRYPTO_EcdhePrivateKey *DHRs; - - /** - * ECDH Ratchet key (recv). - */ - struct GNUNET_CRYPTO_EcdhePublicKey DHRr; - - /** - * Message number (reset to 0 with each new ratchet, next message to send). - */ - uint32_t Ns; - - /** - * Message number (reset to 0 with each new ratchet, next message to recv). - */ - uint32_t Nr; - - /** - * Previous message numbers (# of msgs sent under prev ratchet) - */ - uint32_t PNs; - - /** - * True (#GNUNET_YES) if we have to send a new ratchet key in next msg. - */ - int ratchet_flag; - - /** - * Number of messages recieved since our last ratchet advance. - * - If this counter = 0, we cannot send a new ratchet key in next msg. - * - If this counter > 0, we can (but don't yet have to) send a new key. - */ - unsigned int ratchet_allowed; - - /** - * Number of messages recieved since our last ratchet advance. - * - If this counter = 0, we cannot send a new ratchet key in next msg. - * - If this counter > 0, we can (but don't yet have to) send a new key. - */ - unsigned int ratchet_counter; - - /** - * When does this ratchet expire and a new one is triggered. - */ - struct GNUNET_TIME_Absolute ratchet_expiration; -}; - - -/** - * Struct containing all information regarding a tunnel to a peer. - */ -struct CadetTunnel -{ - /** - * Endpoint of the tunnel. - */ - struct CadetPeer *peer; - - /** - * Axolotl info. - */ - struct CadetTunnelAxolotl *ax; - - /** - * State of the tunnel connectivity. - */ - enum CadetTunnelCState cstate; - - /** - * State of the tunnel encryption. - */ - enum CadetTunnelEState estate; - - /** - * Peer's ephemeral key, to recreate @c e_key and @c d_key when own ephemeral - * key changes. - */ - struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key; - - /** - * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL. - */ - struct GNUNET_CRYPTO_SymmetricSessionKey e_key; - - /** - * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL. - */ - struct GNUNET_CRYPTO_SymmetricSessionKey d_key; - - /** - * Task to start the rekey process. - */ - struct GNUNET_SCHEDULER_Task *rekey_task; - - /** - * Paths that are actively used to reach the destination peer. - */ - struct CadetTConnection *connection_head; - struct CadetTConnection *connection_tail; - - /** - * Next connection number. - */ - uint32_t next_cid; - - /** - * Channels inside this tunnel. - */ - struct CadetTChannel *channel_head; - struct CadetTChannel *channel_tail; - - /** - * Channel ID for the next created channel. - */ - struct GNUNET_CADET_ChannelTunnelNumber next_ctn; - - /** - * Destroy flag: if true, destroy on last message. - */ - struct GNUNET_SCHEDULER_Task * destroy_task; - - /** - * Queued messages, to transmit once tunnel gets connected. - */ - struct CadetTunnelDelayed *tq_head; - struct CadetTunnelDelayed *tq_tail; - - /** - * Task to trim connections if too many are present. - */ - struct GNUNET_SCHEDULER_Task * trim_connections_task; - - /** - * Ephemeral message in the queue (to avoid queueing more than one). - */ - struct CadetConnectionQueue *ephm_h; - - /** - * Pong message in the queue. - */ - struct CadetConnectionQueue *pong_h; -}; - - -/** - * Struct used to save messages in a non-ready tunnel to send once connected. - */ -struct CadetTunnelDelayed -{ - /** - * DLL - */ - struct CadetTunnelDelayed *next; - struct CadetTunnelDelayed *prev; - - /** - * Tunnel. - */ - struct CadetTunnel *t; - - /** - * Tunnel queue given to the channel to cancel request. Update on send_queued. - */ - struct CadetTunnelQueue *tq; - - /** - * Message to send. - */ - /* struct GNUNET_MessageHeader *msg; */ -}; - - -/** - * Handle for messages queued but not yet sent. - */ -struct CadetTunnelQueue -{ - /** - * Connection queue handle, to cancel if necessary. - */ - struct CadetConnectionQueue *cq; - - /** - * Handle in case message hasn't been given to a connection yet. - */ - struct CadetTunnelDelayed *tqd; - - /** - * Continuation to call once sent. - */ - GCT_sent cont; - - /** - * Closure for @c cont. - */ - void *cont_cls; -}; - - -/******************************************************************************/ -/******************************* GLOBALS ***********************************/ -/******************************************************************************/ - -/** - * Global handle to the statistics service. - */ -extern struct GNUNET_STATISTICS_Handle *stats; - -/** - * Local peer own ID (memory efficient handle). - */ -extern GNUNET_PEER_Id myid; - -/** - * Local peer own ID (full value). - */ -extern struct GNUNET_PeerIdentity my_full_id; - - -/** - * Don't try to recover tunnels if shutting down. - */ -extern int shutting_down; - - -/** - * Set of all tunnels, in order to trigger a new exchange on rekey. - * Indexed by peer's ID. - */ -static struct GNUNET_CONTAINER_MultiPeerMap *tunnels; - -/** - * Own Peer ID private key. - */ -const static struct GNUNET_CRYPTO_EddsaPrivateKey *id_key; - - -/******************************** AXOLOTL ************************************/ - -/** - * How many messages are needed to trigger a ratchet advance. - */ -static unsigned long long ratchet_messages; - -/** - * How long until we trigger a ratched advance. - */ -static struct GNUNET_TIME_Relative ratchet_time; - - -/******************************************************************************/ -/******************************** STATIC ***********************************/ -/******************************************************************************/ - -/** - * Get string description for tunnel connectivity state. - * - * @param cs Tunnel state. - * - * @return String representation. - */ -static const char * -cstate2s (enum CadetTunnelCState cs) -{ - static char buf[32]; - - switch (cs) - { - case CADET_TUNNEL_NEW: - return "CADET_TUNNEL_NEW"; - case CADET_TUNNEL_SEARCHING: - return "CADET_TUNNEL_SEARCHING"; - case CADET_TUNNEL_WAITING: - return "CADET_TUNNEL_WAITING"; - case CADET_TUNNEL_READY: - return "CADET_TUNNEL_READY"; - case CADET_TUNNEL_SHUTDOWN: - return "CADET_TUNNEL_SHUTDOWN"; - default: - SPRINTF (buf, "%u (UNKNOWN STATE)", cs); - return buf; - } - return ""; -} - - -/** - * Get string description for tunnel encryption state. - * - * @param es Tunnel state. - * - * @return String representation. - */ -static const char * -estate2s (enum CadetTunnelEState es) -{ - static char buf[32]; - - switch (es) - { - case CADET_TUNNEL_KEY_UNINITIALIZED: - return "CADET_TUNNEL_KEY_UNINITIALIZED"; - case CADET_TUNNEL_KEY_AX_SENT: - return "CADET_TUNNEL_KEY_AX_SENT"; - case CADET_TUNNEL_KEY_AX_AUTH_SENT: - return "CADET_TUNNEL_KEY_AX_AUTH_SENT"; - case CADET_TUNNEL_KEY_OK: - return "CADET_TUNNEL_KEY_OK"; - case CADET_TUNNEL_KEY_REKEY: - return "CADET_TUNNEL_KEY_REKEY"; - default: - SPRINTF (buf, "%u (UNKNOWN STATE)", es); - return buf; - } - return ""; -} - - -/** - * @brief Check if tunnel is ready to send traffic. - * - * Tunnel must be connected and with encryption correctly set up. - * - * @param t Tunnel to check. - * - * @return #GNUNET_YES if ready, #GNUNET_NO otherwise - */ -static int -is_ready (struct CadetTunnel *t) -{ - int ready; - int conn_ok; - int enc_ok; - - conn_ok = CADET_TUNNEL_READY == t->cstate; - enc_ok = CADET_TUNNEL_KEY_OK == t->estate - || CADET_TUNNEL_KEY_REKEY == t->estate - || CADET_TUNNEL_KEY_AX_AUTH_SENT == t->estate; - ready = conn_ok && enc_ok; - ready = ready || GCT_is_loopback (t); - return ready; -} - - -/** - * Get the channel's buffer. ONLY FOR NON-LOOPBACK CHANNELS!! - * - * @param tch Tunnel's channel handle. - * - * @return Amount of messages the channel can still buffer towards the client. - */ -static unsigned int -get_channel_buffer (const struct CadetTChannel *tch) -{ - int fwd; - - /* If channel is incoming, is terminal in the FWD direction and fwd is YES */ - fwd = GCCH_is_terminal (tch->ch, GNUNET_YES); - - return GCCH_get_buffer (tch->ch, fwd); -} - - -/** - * Get the channel's allowance status. - * - * @param tch Tunnel's channel handle. - * - * @return #GNUNET_YES if we allowed the client to send data to us. - */ -static int -get_channel_allowed (const struct CadetTChannel *tch) -{ - int fwd; - - /* If channel is outgoing, is origin in the FWD direction and fwd is YES */ - fwd = GCCH_is_origin (tch->ch, GNUNET_YES); - - return GCCH_get_allowed (tch->ch, fwd); -} - - -/** - * Get the connection's buffer. - * - * @param tc Tunnel's connection handle. - * - * @return Amount of messages the connection can still buffer. - */ -static unsigned int -get_connection_buffer (const struct CadetTConnection *tc) -{ - int fwd; - - /* If connection is outgoing, is origin in the FWD direction and fwd is YES */ - fwd = GCC_is_origin (tc->c, GNUNET_YES); - - return GCC_get_buffer (tc->c, fwd); -} - - -/** - * Get the connection's allowance. - * - * @param tc Tunnel's connection handle. - * - * @return Amount of messages we have allowed the next peer to send us. - */ -static unsigned int -get_connection_allowed (const struct CadetTConnection *tc) -{ - int fwd; - - /* If connection is outgoing, is origin in the FWD direction and fwd is YES */ - fwd = GCC_is_origin (tc->c, GNUNET_YES); - - return GCC_get_allowed (tc->c, fwd); -} - - -/** - * Create a new Axolotl ephemeral (ratchet) key. - * - * @param t Tunnel. - */ -static void -new_ephemeral (struct CadetTunnel *t) -{ - GNUNET_free_non_null (t->ax->DHRs); - t->ax->DHRs = GNUNET_CRYPTO_ecdhe_key_create(); - #if DUMP_KEYS_TO_STDERR - { - struct GNUNET_CRYPTO_EcdhePublicKey pub; - GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &pub); - LOG (GNUNET_ERROR_TYPE_DEBUG, " new DHRs generated: pub %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub)); - } - #endif -} - - -/** - * Calculate HMAC. - * - * @param plaintext Content to HMAC. - * @param size Size of @c plaintext. - * @param iv Initialization vector for the message. - * @param key Key to use. - * @param hmac[out] Destination to store the HMAC. - */ -static void -t_hmac (const void *plaintext, size_t size, - uint32_t iv, const struct GNUNET_CRYPTO_SymmetricSessionKey *key, - struct GNUNET_ShortHashCode *hmac) -{ - static const char ctx[] = "cadet authentication key"; - struct GNUNET_CRYPTO_AuthKey auth_key; - struct GNUNET_HashCode hash; - -#if DUMP_KEYS_TO_STDERR - LOG (GNUNET_ERROR_TYPE_INFO, " HMAC %u bytes with key %s\n", size, - GNUNET_i2s ((struct GNUNET_PeerIdentity *) key)); -#endif - GNUNET_CRYPTO_hmac_derive_key (&auth_key, key, - &iv, sizeof (iv), - key, sizeof (*key), - ctx, sizeof (ctx), - NULL); - /* Two step: CADET_Hash is only 256 bits, HashCode is 512. */ - GNUNET_CRYPTO_hmac (&auth_key, plaintext, size, &hash); - GNUNET_memcpy (hmac, &hash, sizeof (*hmac)); -} - - -/** - * Perform a HMAC. - * - * @param key Key to use. - * @param hash[out] Resulting HMAC. - * @param source Source key material (data to HMAC). - * @param len Length of @a source. - */ -static void -t_ax_hmac_hash (struct GNUNET_CRYPTO_SymmetricSessionKey *key, - struct GNUNET_HashCode *hash, - void *source, unsigned int len) -{ - static const char ctx[] = "axolotl HMAC-HASH"; - struct GNUNET_CRYPTO_AuthKey auth_key; - - GNUNET_CRYPTO_hmac_derive_key (&auth_key, key, - ctx, sizeof (ctx), - NULL); - GNUNET_CRYPTO_hmac (&auth_key, source, len, hash); -} - - -/** - * Derive a key from a HMAC-HASH. - * - * @param key Key to use for the HMAC. - * @param out Key to generate. - * @param source Source key material (data to HMAC). - * @param len Length of @a source. - */ -static void -t_hmac_derive_key (struct GNUNET_CRYPTO_SymmetricSessionKey *key, - struct GNUNET_CRYPTO_SymmetricSessionKey *out, - void *source, unsigned int len) -{ - static const char ctx[] = "axolotl derive key"; - struct GNUNET_HashCode h; - - t_ax_hmac_hash (key, &h, source, len); - GNUNET_CRYPTO_kdf (out, sizeof (*out), ctx, sizeof (ctx), - &h, sizeof (h), NULL); -} - - -/** - * Encrypt data with the axolotl tunnel key. - * - * @param t Tunnel whose key to use. - * @param dst Destination for the encrypted data. - * @param src Source of the plaintext. Can overlap with @c dst. - * @param size Size of the plaintext. - * - * @return Size of the encrypted data. - */ -static int -t_ax_encrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size) -{ - struct GNUNET_CRYPTO_SymmetricSessionKey MK; - struct GNUNET_CRYPTO_SymmetricInitializationVector iv; - struct CadetTunnelAxolotl *ax; - size_t out_size; - - CADET_TIMING_START; - - ax = t->ax; - ax->ratchet_counter++; - if (GNUNET_YES == ax->ratchet_allowed - && (ratchet_messages <= ax->ratchet_counter - || 0 == GNUNET_TIME_absolute_get_remaining (ax->ratchet_expiration).rel_value_us)) - { - ax->ratchet_flag = GNUNET_YES; - } - - if (GNUNET_YES == ax->ratchet_flag) - { - /* Advance ratchet */ - struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; - struct GNUNET_HashCode dh; - struct GNUNET_HashCode hmac; - static const char ctx[] = "axolotl ratchet"; - - new_ephemeral (t); - ax->HKs = ax->NHKs; - - /* RK, NHKs, CKs = KDF( HMAC-HASH(RK, DH(DHRs, DHRr)) ) */ - GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, &ax->DHRr, &dh); - t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh)); - GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx), - &hmac, sizeof (hmac), NULL); - ax->RK = keys[0]; - ax->NHKs = keys[1]; - ax->CKs = keys[2]; - - ax->PNs = ax->Ns; - ax->Ns = 0; - ax->ratchet_flag = GNUNET_NO; - ax->ratchet_allowed = GNUNET_NO; - ax->ratchet_counter = 0; - ax->ratchet_expiration = - GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time); - } - - t_hmac_derive_key (&ax->CKs, &MK, "0", 1); - GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL); - - #if DUMP_KEYS_TO_STDERR - LOG (GNUNET_ERROR_TYPE_DEBUG, " CKs: %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs)); - LOG (GNUNET_ERROR_TYPE_INFO, " AX_ENC with key %u: %s\n", ax->Ns, - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK)); - #endif - - out_size = GNUNET_CRYPTO_symmetric_encrypt (src, size, &MK, &iv, dst); - t_hmac_derive_key (&ax->CKs, &ax->CKs, "1", 1); - - CADET_TIMING_END; - - return out_size; -} - - -/** - * Decrypt data with the axolotl tunnel key. - * - * @param t Tunnel whose key to use. - * @param dst Destination for the decrypted data. - * @param src Source of the ciphertext. Can overlap with @c dst. - * @param size Size of the ciphertext. - * - * @return Size of the decrypted data. - */ -static int -t_ax_decrypt (struct CadetTunnel *t, void *dst, const void *src, size_t size) -{ - struct GNUNET_CRYPTO_SymmetricSessionKey MK; - struct GNUNET_CRYPTO_SymmetricInitializationVector iv; - struct CadetTunnelAxolotl *ax; - size_t out_size; - - CADET_TIMING_START; - - ax = t->ax; - - t_hmac_derive_key (&ax->CKr, &MK, "0", 1); - GNUNET_CRYPTO_symmetric_derive_iv (&iv, &MK, NULL, 0, NULL); - - #if DUMP_KEYS_TO_STDERR - LOG (GNUNET_ERROR_TYPE_DEBUG, " CKr: %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr)); - LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC with key %u: %s\n", ax->Nr, - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &MK)); - #endif - - GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); - out_size = GNUNET_CRYPTO_symmetric_decrypt (src, size, &MK, &iv, dst); - GNUNET_assert (out_size == size); - - t_hmac_derive_key (&ax->CKr, &ax->CKr, "1", 1); - - CADET_TIMING_END; - - return out_size; -} - - -/** - * Encrypt header with the axolotl header key. - * - * @param t Tunnel whose key to use. - * @param msg Message whose header to encrypt. - */ -static void -t_h_encrypt (struct CadetTunnel *t, struct GNUNET_CADET_TunnelEncryptedMessage *msg) -{ - struct GNUNET_CRYPTO_SymmetricInitializationVector iv; - struct CadetTunnelAxolotl *ax; - size_t out_size; - - CADET_TIMING_START; - ax = t->ax; - GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKs, NULL, 0, NULL); - - #if DUMP_KEYS_TO_STDERR - LOG (GNUNET_ERROR_TYPE_INFO, " AX_ENC_H with key %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs)); - #endif - - out_size = GNUNET_CRYPTO_symmetric_encrypt (&msg->Ns, AX_HEADER_SIZE, - &ax->HKs, &iv, &msg->Ns); - - GNUNET_assert (AX_HEADER_SIZE == out_size); - CADET_TIMING_END; -} - - -/** - * Decrypt header with the current axolotl header key. - * - * @param t Tunnel whose current ax HK to use. - * @param src Message whose header to decrypt. - * @param dst Where to decrypt header to. - */ -static void -t_h_decrypt (struct CadetTunnel *t, const struct GNUNET_CADET_TunnelEncryptedMessage *src, - struct GNUNET_CADET_TunnelEncryptedMessage *dst) -{ - struct GNUNET_CRYPTO_SymmetricInitializationVector iv; - struct CadetTunnelAxolotl *ax; - size_t out_size; - - CADET_TIMING_START; - - ax = t->ax; - GNUNET_CRYPTO_symmetric_derive_iv (&iv, &ax->HKr, NULL, 0, NULL); - - #if DUMP_KEYS_TO_STDERR - LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC_H with key %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr)); - #endif - - out_size = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE, - &ax->HKr, &iv, &dst->Ns); - - GNUNET_assert (AX_HEADER_SIZE == out_size); - - CADET_TIMING_END; -} - - -/** - * Decrypt and verify data with the appropriate tunnel key and verify that the - * data has not been altered since it was sent by the remote peer. - * - * @param t Tunnel whose key to use. - * @param dst Destination for the plaintext. - * @param src Source of the message. Can overlap with @c dst. - * @param size Size of the message. - * - * @return Size of the decrypted data, -1 if an error was encountered. - */ -static int -try_old_ax_keys (struct CadetTunnel *t, void *dst, - const struct GNUNET_CADET_TunnelEncryptedMessage *src, size_t size) -{ - struct CadetTunnelSkippedKey *key; - struct GNUNET_ShortHashCode *hmac; - struct GNUNET_CRYPTO_SymmetricInitializationVector iv; - struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header; - struct GNUNET_CRYPTO_SymmetricSessionKey *valid_HK; - size_t esize; - size_t res; - size_t len; - unsigned int N; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying old keys\n"); - hmac = &plaintext_header.hmac; - esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage); - - /* Find a correct Header Key */ - for (key = t->ax->skipped_head; NULL != key; key = key->next) - { - #if DUMP_KEYS_TO_STDERR - LOG (GNUNET_ERROR_TYPE_DEBUG, " Trying hmac with key %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK)); - #endif - t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &key->HK, hmac); - if (0 == memcmp (hmac, &src->hmac, sizeof (*hmac))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " hmac correct\n"); - valid_HK = &key->HK; - break; - } - } - if (NULL == key) - return -1; - - /* Should've been checked in -cadet_connection.c handle_cadet_encrypted. */ - GNUNET_assert (size > sizeof (struct GNUNET_CADET_TunnelEncryptedMessage)); - len = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage); - GNUNET_assert (len >= sizeof (struct GNUNET_MessageHeader)); - - /* Decrypt header */ - GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->HK, NULL, 0, NULL); - res = GNUNET_CRYPTO_symmetric_decrypt (&src->Ns, AX_HEADER_SIZE, - &key->HK, &iv, &plaintext_header.Ns); - GNUNET_assert (AX_HEADER_SIZE == res); - LOG (GNUNET_ERROR_TYPE_DEBUG, " Message %u, previous: %u\n", - ntohl (plaintext_header.Ns), ntohl (plaintext_header.PNs)); - - /* Find the correct Message Key */ - N = ntohl (plaintext_header.Ns); - while (NULL != key && N != key->Kn) - key = key->next; - if (NULL == key || 0 != memcmp (&key->HK, valid_HK, sizeof (*valid_HK))) - return -1; - - #if DUMP_KEYS_TO_STDERR - LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC_H with skipped key %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->HK)); - LOG (GNUNET_ERROR_TYPE_INFO, " AX_DEC with skipped key %u: %s\n", - key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK)); - #endif - - /* Decrypt payload */ - GNUNET_CRYPTO_symmetric_derive_iv (&iv, &key->MK, NULL, 0, NULL); - res = GNUNET_CRYPTO_symmetric_decrypt (&src[1], len, &key->MK, &iv, dst); - - /* Remove key */ - GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key); - t->ax->skipped--; - GNUNET_free (key); /* GNUNET_free overwrites memory with 0xbaadf00d */ - - return res; -} - - -/** - * Delete a key from the list of skipped keys. - * - * @param t Tunnel to delete from. - * @param HKr Header Key to use. - */ -static void -store_skipped_key (struct CadetTunnel *t, - const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr) -{ - struct CadetTunnelSkippedKey *key; - - key = GNUNET_new (struct CadetTunnelSkippedKey); - key->timestamp = GNUNET_TIME_absolute_get (); - key->Kn = t->ax->Nr; - key->HK = t->ax->HKr; - t_hmac_derive_key (&t->ax->CKr, &key->MK, "0", 1); - #if DUMP_KEYS_TO_STDERR - LOG (GNUNET_ERROR_TYPE_DEBUG, " storing MK for Nr %u: %s\n", - key->Kn, GNUNET_i2s ((struct GNUNET_PeerIdentity *) &key->MK)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " for CKr: %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &t->ax->CKr)); - #endif - t_hmac_derive_key (&t->ax->CKr, &t->ax->CKr, "1", 1); - GNUNET_CONTAINER_DLL_insert (t->ax->skipped_head, t->ax->skipped_tail, key); - t->ax->Nr++; - t->ax->skipped++; -} - - -/** - * Delete a key from the list of skipped keys. - * - * @param t Tunnel to delete from. - * @param key Key to delete. - */ -static void -delete_skipped_key (struct CadetTunnel *t, struct CadetTunnelSkippedKey *key) -{ - GNUNET_CONTAINER_DLL_remove (t->ax->skipped_head, t->ax->skipped_tail, key); - GNUNET_free (key); - t->ax->skipped--; -} - - -/** - * Stage skipped AX keys and calculate the message key. - * - * Stores each HK and MK for skipped messages. - * - * @param t Tunnel where to stage the keys. - * @param HKr Header key. - * @param Np Received meesage number. - * - * @return GNUNET_OK if keys were stored. - * GNUNET_SYSERR if an error ocurred (Np not expected). - */ -static int -store_ax_keys (struct CadetTunnel *t, - const struct GNUNET_CRYPTO_SymmetricSessionKey *HKr, - uint32_t Np) -{ - int gap; - - - gap = Np - t->ax->Nr; - LOG (GNUNET_ERROR_TYPE_INFO, "Storing keys [%u, %u)\n", t->ax->Nr, Np); - if (MAX_KEY_GAP < gap) - { - /* Avoid DoS (forcing peer to do 2*33 chain HMAC operations) */ - /* TODO: start new key exchange on return */ - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_WARNING, "Got message %u, expected %u+\n", - Np, t->ax->Nr); - return GNUNET_SYSERR; - } - if (0 > gap) - { - /* Delayed message: don't store keys, flag to try old keys. */ - return GNUNET_SYSERR; - } - - while (t->ax->Nr < Np) - store_skipped_key (t, HKr); - - while (t->ax->skipped > MAX_SKIPPED_KEYS) - delete_skipped_key (t, t->ax->skipped_tail); - - return GNUNET_OK; -} - - -/** - * Decrypt and verify data with the appropriate tunnel key and verify that the - * data has not been altered since it was sent by the remote peer. - * - * @param t Tunnel whose key to use. - * @param dst Destination for the plaintext. - * @param src Source of the message. Can overlap with @c dst. - * @param size Size of the message. - * - * @return Size of the decrypted data, -1 if an error was encountered. - */ -static int -t_ax_decrypt_and_validate (struct CadetTunnel *t, void *dst, - const struct GNUNET_CADET_TunnelEncryptedMessage *src, - size_t size) -{ - struct CadetTunnelAxolotl *ax; - struct GNUNET_ShortHashCode msg_hmac; - struct GNUNET_HashCode hmac; - struct GNUNET_CADET_TunnelEncryptedMessage plaintext_header; - uint32_t Np; - uint32_t PNp; - size_t esize; /* Size of encryped payload */ - size_t osize; /* Size of output (decrypted payload) */ - - esize = size - sizeof (struct GNUNET_CADET_TunnelEncryptedMessage); - ax = t->ax; - if (NULL == ax) - return -1; - - /* Try current HK */ - t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->HKr, &msg_hmac); - if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac))) - { - static const char ctx[] = "axolotl ratchet"; - struct GNUNET_CRYPTO_SymmetricSessionKey keys[3]; /* RKp, NHKp, CKp */ - struct GNUNET_CRYPTO_SymmetricSessionKey HK; - struct GNUNET_HashCode dh; - struct GNUNET_CRYPTO_EcdhePublicKey *DHRp; - - /* Try Next HK */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " trying next HK\n"); - t_hmac (&src->Ns, AX_HEADER_SIZE + esize, 0, &ax->NHKr, &msg_hmac); - if (0 != memcmp (&msg_hmac, &src->hmac, sizeof (msg_hmac))) - { - /* Try the skipped keys, if that fails, we're out of luck. */ - return try_old_ax_keys (t, dst, src, size); - } - LOG (GNUNET_ERROR_TYPE_INFO, "next HK worked\n"); - - HK = ax->HKr; - ax->HKr = ax->NHKr; - t_h_decrypt (t, src, &plaintext_header); - Np = ntohl (plaintext_header.Ns); - PNp = ntohl (plaintext_header.PNs); - DHRp = &plaintext_header.DHRs; - store_ax_keys (t, &HK, PNp); - - /* RKp, NHKp, CKp = KDF (HMAC-HASH (RK, DH (DHRp, DHRs))) */ - GNUNET_CRYPTO_ecc_ecdh (ax->DHRs, DHRp, &dh); - t_ax_hmac_hash (&ax->RK, &hmac, &dh, sizeof (dh)); - GNUNET_CRYPTO_kdf (keys, sizeof (keys), ctx, sizeof (ctx), - &hmac, sizeof (hmac), NULL); - - /* Commit "purported" keys */ - ax->RK = keys[0]; - ax->NHKr = keys[1]; - ax->CKr = keys[2]; - ax->DHRr = *DHRp; - ax->Nr = 0; - ax->ratchet_allowed = GNUNET_YES; - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "current HK\n"); - t_h_decrypt (t, src, &plaintext_header); - Np = ntohl (plaintext_header.Ns); - PNp = ntohl (plaintext_header.PNs); - } - LOG (GNUNET_ERROR_TYPE_INFO, " got AX Nr %u\n", Np); - if (Np != ax->Nr) - if (GNUNET_OK != store_ax_keys (t, &ax->HKr, Np)) - /* Try the skipped keys, if that fails, we're out of luck. */ - return try_old_ax_keys (t, dst, src, size); - - osize = t_ax_decrypt (t, dst, &src[1], esize); - ax->Nr = Np + 1; - - if (osize != esize) - { - GNUNET_break_op (0); - return -1; - } - - return osize; -} - - -/** - * Pick a connection on which send the next data message. - * - * @param t Tunnel on which to send the message. - * - * @return The connection on which to send the next message. - */ -static struct CadetConnection * -tunnel_get_connection (struct CadetTunnel *t) -{ - struct CadetTConnection *iter; - struct CadetConnection *best; - unsigned int qn; - unsigned int lowest_q; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "tunnel_get_connection %s\n", GCT_2s (t)); - best = NULL; - lowest_q = UINT_MAX; - for (iter = t->connection_head; NULL != iter; iter = iter->next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s: %u\n", - GCC_2s (iter->c), GCC_get_state (iter->c)); - if (CADET_CONNECTION_READY == GCC_get_state (iter->c)) - { - qn = GCC_get_qn (iter->c, GCC_is_origin (iter->c, GNUNET_YES)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " q_n %u, \n", qn); - if (qn < lowest_q) - { - best = iter->c; - lowest_q = qn; - } - } - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " selected: connection %s\n", GCC_2s (best)); - return best; -} - - -/** - * Callback called when a queued message is sent. - * - * Calculates the average time and connection packet tracking. - * - * @param cls Closure (TunnelQueue handle). - * @param c Connection this message was on. - * @param q Connection queue handle (unused). - * @param type Type of message sent. - * @param fwd Was this a FWD going message? - * @param size Size of the message. - */ -static void -tun_message_sent (void *cls, - struct CadetConnection *c, - struct CadetConnectionQueue *q, - uint16_t type, int fwd, size_t size) -{ - struct CadetTunnelQueue *qt = cls; - struct CadetTunnel *t; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "tun_message_sent\n"); - - GNUNET_assert (NULL != qt->cont); - t = NULL == c ? NULL : GCC_get_tunnel (c); - qt->cont (qt->cont_cls, t, qt, type, size); - GNUNET_free (qt); -} - - -static unsigned int -count_queued_data (const struct CadetTunnel *t) -{ - struct CadetTunnelDelayed *iter; - unsigned int count; - - for (count = 0, iter = t->tq_head; iter != NULL; iter = iter->next) - count++; - - return count; -} - -/** - * Delete a queued message: either was sent or the channel was destroyed - * before the tunnel's key exchange had a chance to finish. - * - * @param tqd Delayed queue handle. - */ -static void -unqueue_data (struct CadetTunnelDelayed *tqd) -{ - GNUNET_CONTAINER_DLL_remove (tqd->t->tq_head, tqd->t->tq_tail, tqd); - GNUNET_free (tqd); -} - - -/** - * Cache a message to be sent once tunnel is online. - * - * @param t Tunnel to hold the message. - * @param msg Message itself (copy will be made). - */ -static struct CadetTunnelDelayed * -queue_data (struct CadetTunnel *t, const struct GNUNET_MessageHeader *msg) -{ - struct CadetTunnelDelayed *tqd; - uint16_t size = ntohs (msg->size); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "queue data on Tunnel %s\n", GCT_2s (t)); - - GNUNET_assert (GNUNET_NO == is_ready (t)); - - tqd = GNUNET_malloc (sizeof (struct CadetTunnelDelayed) + size); - - tqd->t = t; - GNUNET_memcpy (&tqd[1], msg, size); - GNUNET_CONTAINER_DLL_insert_tail (t->tq_head, t->tq_tail, tqd); - return tqd; -} - - -/** - * Sends an already built message on a tunnel, encrypting it and - * choosing the best connection. - * - * @param message Message to send. Function modifies it. - * @param t Tunnel on which this message is transmitted. - * @param c Connection to use (autoselect if NULL). - * @param force Force the tunnel to take the message (buffer overfill). - * @param cont Continuation to call once message is really sent. - * @param cont_cls Closure for @c cont. - * @param existing_q In case this a transmission of previously queued data, - * this should be TunnelQueue given to the client. - * Otherwise, NULL. - * @return Handle to cancel message. - * NULL if @c cont is NULL or an error happens and message is dropped. - */ -static struct CadetTunnelQueue * -send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct CadetTunnel *t, - struct CadetConnection *c, - int force, - GCT_sent cont, - void *cont_cls, - struct CadetTunnelQueue *existing_q) -{ - struct GNUNET_MessageHeader *msg; - struct GNUNET_CADET_TunnelEncryptedMessage *ax_msg; - struct CadetTunnelQueue *tq; - size_t size = ntohs (message->size); - char cbuf[sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size] GNUNET_ALIGN; - size_t esize; - uint16_t type; - int fwd; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "GMT Send on Tunnel %s\n", GCT_2s (t)); - - if (GNUNET_NO == is_ready (t)) - { - struct CadetTunnelDelayed *tqd; - /* A non null existing_q indicates sending of queued data. - * Should only happen after tunnel becomes ready. - */ - GNUNET_assert (NULL == existing_q); - tqd = queue_data (t, message); - if (NULL == cont) - return NULL; - tq = GNUNET_new (struct CadetTunnelQueue); - tq->tqd = tqd; - tqd->tq = tq; - tq->cont = cont; - tq->cont_cls = cont_cls; - return tq; - } - - GNUNET_assert (GNUNET_NO == GCT_is_loopback (t)); - - ax_msg = (struct GNUNET_CADET_TunnelEncryptedMessage *) cbuf; - msg = &ax_msg->header; - msg->size = htons (sizeof (struct GNUNET_CADET_TunnelEncryptedMessage) + size); - msg->type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_ENCRYPTED); - esize = t_ax_encrypt (t, &ax_msg[1], message, size); - ax_msg->Ns = htonl (t->ax->Ns++); - ax_msg->PNs = htonl (t->ax->PNs); - GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &ax_msg->DHRs); - t_h_encrypt (t, ax_msg); - t_hmac (&ax_msg->Ns, AX_HEADER_SIZE + esize, 0, &t->ax->HKs, &ax_msg->hmac); - GNUNET_assert (esize == size); - - if (NULL == c) - c = tunnel_get_connection (t); - if (NULL == c) - { - /* Why is tunnel 'ready'? Should have been queued! */ - if (NULL != t->destroy_task) - { - GNUNET_break (0); - GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); - } - return NULL; /* Drop... */ - } - fwd = GCC_is_origin (c, GNUNET_YES); - ax_msg->cid = *GCC_get_id (c); - ax_msg->cemi = GCC_get_pid (c, fwd); - - type = htons (message->type); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sending message of type %s with CEMI %u and CID %s\n", - GC_m2s (type), - htonl (ax_msg->cemi.pid), - GNUNET_sh2s (&ax_msg->cid.connection_of_tunnel)); - - if (NULL == cont) - { - (void) GCC_send_prebuilt_message (msg, - type, - ax_msg->cemi, - c, - fwd, - force, NULL, NULL); - return NULL; - } - if (NULL == existing_q) - { - tq = GNUNET_new (struct CadetTunnelQueue); /* FIXME valgrind: leak*/ - } - else - { - tq = existing_q; - tq->tqd = NULL; - } - tq->cont = cont; - tq->cont_cls = cont_cls; - tq->cq = GCC_send_prebuilt_message (msg, - type, - ax_msg->cemi, - c, - fwd, - force, - &tun_message_sent, tq); - GNUNET_assert (NULL != tq->cq); - - return tq; -} - - -/** - * Send all cached messages that we can, tunnel is online. - * - * @param t Tunnel that holds the messages. Cannot be loopback. - */ -static void -send_queued_data (struct CadetTunnel *t) -{ - struct CadetTunnelDelayed *tqd; - struct CadetTunnelDelayed *next; - unsigned int room; - - LOG (GNUNET_ERROR_TYPE_INFO, "Send queued data, tunnel %s\n", GCT_2s (t)); - - if (GCT_is_loopback (t)) - { - GNUNET_break (0); - return; - } - - if (GNUNET_NO == is_ready (t)) - { - LOG (GNUNET_ERROR_TYPE_WARNING, " not ready yet: %s/%s\n", - estate2s (t->estate), cstate2s (t->cstate)); - return; - } - - room = GCT_get_connections_buffer (t); - LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer space: %u\n", room); - LOG (GNUNET_ERROR_TYPE_DEBUG, " tq head: %p\n", t->tq_head); - for (tqd = t->tq_head; NULL != tqd && room > 0; tqd = next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " sending queued data\n"); - next = tqd->next; - room--; - send_prebuilt_message ((struct GNUNET_MessageHeader *) &tqd[1], - tqd->t, NULL, GNUNET_YES, - NULL != tqd->tq ? tqd->tq->cont : NULL, - NULL != tqd->tq ? tqd->tq->cont_cls : NULL, - tqd->tq); - unqueue_data (tqd); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_send_queued_data end\n", GCP_2s (t->peer)); -} - - -/** - * @brief Resend the KX until we complete the handshake. - * - * @param cls Closure (tunnel). - */ -static void -kx_resend (void *cls) -{ - struct CadetTunnel *t = cls; - - t->rekey_task = NULL; - if (CADET_TUNNEL_KEY_OK == t->estate) - { - /* Should have been canceled on estate change */ - GNUNET_break (0); - return; - } - - GCT_send_kx (t, CADET_TUNNEL_KEY_AX_SENT >= t->estate); -} - - -/** - * Callback called when a queued message is sent. - * - * @param cls Closure. - * @param c Connection this message was on. - * @param type Type of message sent. - * @param fwd Was this a FWD going message? - * @param size Size of the message. - */ -static void -ephm_sent (void *cls, - struct CadetConnection *c, - struct CadetConnectionQueue *q, - uint16_t type, int fwd, size_t size) -{ - struct CadetTunnel *t = cls; - LOG (GNUNET_ERROR_TYPE_DEBUG, "ephemeral sent %s\n", GC_m2s (type)); - - t->ephm_h = NULL; - - if (CADET_TUNNEL_KEY_OK == t->estate) - return; - - if (NULL != t->rekey_task) - { - GNUNET_break (0); - GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); - GNUNET_SCHEDULER_cancel (t->rekey_task); - } - t->rekey_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &kx_resend, t); - -} - - -/** - * Called only on shutdown, destroy every tunnel. - * - * @param cls Closure (unused). - * @param key Current public key. - * @param value Value in the hash map (tunnel). - * - * @return #GNUNET_YES, so we should continue to iterate, - */ -static int -destroy_iterator (void *cls, - const struct GNUNET_PeerIdentity *key, - void *value) -{ - struct CadetTunnel *t = value; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "GCT_shutdown destroying tunnel at %p\n", t); - GCT_destroy (t); - return GNUNET_YES; -} - - -/** - * Notify remote peer that we don't know a channel he is talking about, - * probably CHANNEL_DESTROY was missed. - * - * @param t Tunnel on which to notify. - * @param gid ID of the channel. - */ -static void -send_channel_destroy (struct CadetTunnel *t, - struct GNUNET_CADET_ChannelTunnelNumber gid) -{ - struct GNUNET_CADET_ChannelManageMessage msg; - - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY); - msg.header.size = htons (sizeof (msg)); - msg.ctn = gid; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "WARNING destroying unknown channel %u on tunnel %s\n", - ntohl (gid.cn), - GCT_2s (t)); - send_prebuilt_message (&msg.header, t, NULL, GNUNET_YES, NULL, NULL, NULL); -} - - -/** - * Demultiplex data per channel and call appropriate channel handler. - * - * @param t Tunnel on which the data came. - * @param msg Data message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_data (struct CadetTunnel *t, - const struct GNUNET_CADET_ChannelAppDataMessage *msg, - int fwd) -{ - struct CadetChannel *ch; - char buf[128]; - size_t size; - uint16_t type; - - /* Check size */ - size = ntohs (msg->header.size); - if (size < - sizeof (struct GNUNET_CADET_ChannelAppDataMessage) + - sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break (0); - return; - } - type = ntohs (msg[1].header.type); - LOG (GNUNET_ERROR_TYPE_DEBUG, " payload of type %s\n", GC_m2s (type)); - SPRINTF (buf, "# received payload of type %hu", type); - GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO); - - - /* Check channel */ - ch = GCT_get_channel (t, msg->ctn); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, - "# data on unknown channel", - 1, - GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "channel 0x%X unknown\n", - ntohl (msg->ctn.cn)); - send_channel_destroy (t, msg->ctn); - return; - } - - GCCH_handle_data (ch, msg, fwd); -} - - -/** - * Demultiplex data ACKs per channel and update appropriate channel buffer info. - * - * @param t Tunnel on which the DATA ACK came. - * @param msg DATA ACK message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_data_ack (struct CadetTunnel *t, - const struct GNUNET_CADET_ChannelDataAckMessage *msg, - int fwd) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_ChannelDataAckMessage)) - { - GNUNET_break (0); - return; - } - - /* Check channel */ - ch = GCT_get_channel (t, msg->ctn); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, "# data ack on unknown channel", - 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING channel %u unknown\n", - ntohl (msg->ctn.cn)); - return; - } - - GCCH_handle_data_ack (ch, msg, fwd); -} - - -/** - * Handle channel create. - * - * @param t Tunnel on which the message came. - * @param msg ChannelCreate message. - */ -static void -handle_ch_create (struct CadetTunnel *t, - const struct GNUNET_CADET_ChannelOpenMessage *msg) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_ChannelOpenMessage)) - { - GNUNET_break_op (0); - return; - } - - /* Check channel */ - ch = GCT_get_channel (t, msg->ctn); - if (NULL != ch && ! GCT_is_loopback (t)) - { - /* Probably a retransmission, safe to ignore */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists...\n"); - } - ch = GCCH_handle_create (t, msg); - if (NULL != ch) - GCT_add_channel (t, ch); -} - - - -/** - * Handle channel NACK: check correctness and call channel handler for NACKs. - * - * @param t Tunnel on which the NACK came. - * @param msg NACK message. - */ -static void -handle_ch_nack (struct CadetTunnel *t, - const struct GNUNET_CADET_ChannelManageMessage *msg) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage)) - { - GNUNET_break (0); - return; - } - - /* Check channel */ - ch = GCT_get_channel (t, msg->ctn); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, "# channel NACK on unknown channel", - 1, GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "WARNING channel %u unknown\n", - ntohl (msg->ctn.cn)); - return; - } - - GCCH_handle_nack (ch); -} - - -/** - * Handle a CHANNEL ACK (SYNACK/ACK). - * - * @param t Tunnel on which the CHANNEL ACK came. - * @param msg CHANNEL ACK message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_ch_ack (struct CadetTunnel *t, - const struct GNUNET_CADET_ChannelManageMessage *msg, - int fwd) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage)) - { - GNUNET_break (0); - return; - } - - /* Check channel */ - ch = GCT_get_channel (t, msg->ctn); - if (NULL == ch) - { - GNUNET_STATISTICS_update (stats, - "# channel ack on unknown channel", - 1, - GNUNET_NO); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "WARNING channel %u unknown\n", - ntohl (msg->ctn.cn)); - return; - } - - GCCH_handle_ack (ch, msg, fwd); -} - - -/** - * Handle a channel destruction message. - * - * @param t Tunnel on which the message came. - * @param msg Channel destroy message. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_ch_destroy (struct CadetTunnel *t, - const struct GNUNET_CADET_ChannelManageMessage *msg, - int fwd) -{ - struct CadetChannel *ch; - size_t size; - - /* Check size */ - size = ntohs (msg->header.size); - if (size != sizeof (struct GNUNET_CADET_ChannelManageMessage)) - { - GNUNET_break (0); - return; - } - - /* Check channel */ - ch = GCT_get_channel (t, msg->ctn); - if (NULL == ch) - { - /* Probably a retransmission, safe to ignore */ - return; - } - - GCCH_handle_destroy (ch, msg, fwd); -} - - -/** - * Free Axolotl data. - * - * @param t Tunnel. - */ -static void -destroy_ax (struct CadetTunnel *t) -{ - if (NULL == t->ax) - return; - - GNUNET_free_non_null (t->ax->DHRs); - GNUNET_free_non_null (t->ax->kx_0); - while (NULL != t->ax->skipped_head) - delete_skipped_key (t, t->ax->skipped_head); - GNUNET_assert (0 == t->ax->skipped); - - GNUNET_free (t->ax); - t->ax = NULL; - - if (NULL != t->rekey_task) - { - GNUNET_SCHEDULER_cancel (t->rekey_task); - t->rekey_task = NULL; - } - if (NULL != t->ephm_h) - { - GCC_cancel (t->ephm_h); - t->ephm_h = NULL; - } -} - - -/** - * Demultiplex by message type and call appropriate handler for a message - * towards a channel of a local tunnel. - * - * @param t Tunnel this message came on. - * @param msgh Message header. - * @param fwd Is this message fwd? This only is meaningful in loopback channels. - * #GNUNET_YES if message is FWD on the respective channel (loopback) - * #GNUNET_NO if message is BCK on the respective channel (loopback) - * #GNUNET_SYSERR if message on a one-ended channel (remote) - */ -static void -handle_decrypted (struct CadetTunnel *t, - const struct GNUNET_MessageHeader *msgh, - int fwd) -{ - uint16_t type; - char buf[256]; - - type = ntohs (msgh->type); - LOG (GNUNET_ERROR_TYPE_DEBUG, "<-- %s on %s\n", GC_m2s (type), GCT_2s (t)); - SPRINTF (buf, "# received encrypted of type %hu (%s)", type, GC_m2s (type)); - GNUNET_STATISTICS_update (stats, buf, 1, GNUNET_NO); - - switch (type) - { - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE: - /* Do nothing, connection aleady got updated. */ - GNUNET_STATISTICS_update (stats, "# keepalives received", 1, GNUNET_NO); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA: - /* Don't send hop ACK, wait for client to ACK */ - handle_data (t, (struct GNUNET_CADET_ChannelAppDataMessage *) msgh, fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_APP_DATA_ACK: - handle_data_ack (t, (struct GNUNET_CADET_ChannelDataAckMessage *) msgh, fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN: - handle_ch_create (t, (struct GNUNET_CADET_ChannelOpenMessage *) msgh); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_NACK_DEPRECATED: - handle_ch_nack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_OPEN_ACK: - handle_ch_ack (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd); - break; - - case GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY: - handle_ch_destroy (t, (struct GNUNET_CADET_ChannelManageMessage *) msgh, fwd); - break; - - default: - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_WARNING, - "end-to-end message not known (%u)\n", - ntohs (msgh->type)); - GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); - } -} - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Decrypt and process an encrypted message. - * - * Calls the appropriate handler for a message in a channel of a local tunnel. - * - * @param t Tunnel this message came on. - * @param msg Message header. - */ -void -GCT_handle_encrypted (struct CadetTunnel *t, - const struct GNUNET_CADET_TunnelEncryptedMessage *msg) -{ - uint16_t size = ntohs (msg->header.size); - char cbuf [size]; - int decrypted_size; - const struct GNUNET_MessageHeader *msgh; - unsigned int off; - - GNUNET_STATISTICS_update (stats, "# received encrypted", 1, GNUNET_NO); - - decrypted_size = t_ax_decrypt_and_validate (t, cbuf, msg, size); - - if (-1 == decrypted_size) - { - GNUNET_STATISTICS_update (stats, "# unable to decrypt", 1, GNUNET_NO); - if (CADET_TUNNEL_KEY_AX_AUTH_SENT <= t->estate) - { - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_WARNING, "Wrong crypto, tunnel %s\n", GCT_2s (t)); - GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); - } - return; - } - GCT_change_estate (t, CADET_TUNNEL_KEY_OK); - - /* FIXME: this is bad, as the structs returned from - this loop may be unaligned, see util's MST for - how to do this right. */ - off = 0; - while (off + sizeof (struct GNUNET_MessageHeader) <= decrypted_size) - { - uint16_t msize; - - msgh = (const struct GNUNET_MessageHeader *) &cbuf[off]; - msize = ntohs (msgh->size); - if (msize < sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break_op (0); - return; - } - if (off + msize < decrypted_size) - { - GNUNET_break_op (0); - return; - } - handle_decrypted (t, msgh, GNUNET_SYSERR); - off += msize; - } -} - - -/** - * Handle a Key eXchange message. - * - * @param t Tunnel on which the message came. - * @param msg KX message itself. - */ -void -GCT_handle_kx (struct CadetTunnel *t, - const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg) -{ - struct CadetTunnelAxolotl *ax; - struct GNUNET_HashCode key_material[3]; - struct GNUNET_CRYPTO_SymmetricSessionKey keys[5]; - const char salt[] = "CADET Axolotl salt"; - const struct GNUNET_PeerIdentity *pid; - int am_I_alice; - - CADET_TIMING_START; - - LOG (GNUNET_ERROR_TYPE_INFO, "<== { KX} on %s\n", GCT_2s (t)); - - if (NULL == t->ax) - { - /* Something is wrong if ax is NULL. Whose fault it is? */ - return; - } - ax = t->ax; - - pid = GCT_get_destination (t); - if (0 > GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid)) - am_I_alice = GNUNET_YES; - else if (0 < GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, pid)) - am_I_alice = GNUNET_NO; - else - { - GNUNET_break_op (0); - return; - } - - if (0 != (GNUNET_CADET_KX_FLAG_FORCE_REPLY & ntohl (msg->flags))) - { - if (NULL != t->rekey_task) - { - GNUNET_SCHEDULER_cancel (t->rekey_task); - t->rekey_task = NULL; - } - GCT_send_kx (t, GNUNET_NO); - } - - if (0 == memcmp (&ax->DHRr, &msg->ratchet_key, sizeof(msg->ratchet_key))) - { - LOG (GNUNET_ERROR_TYPE_INFO, " known ratchet key, exit\n"); - return; - } - - LOG (GNUNET_ERROR_TYPE_INFO, " is Alice? %s\n", am_I_alice ? "YES" : "NO"); - - ax->DHRr = msg->ratchet_key; - - /* ECDH A B0 */ - if (GNUNET_YES == am_I_alice) - { - GNUNET_CRYPTO_eddsa_ecdh (id_key, /* A */ - &msg->ephemeral_key, /* B0 */ - &key_material[0]); - } - else - { - GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* B0 */ - &pid->public_key, /* A */ - &key_material[0]); - } - - /* ECDH A0 B */ - if (GNUNET_YES == am_I_alice) - { - GNUNET_CRYPTO_ecdh_eddsa (ax->kx_0, /* A0 */ - &pid->public_key, /* B */ - &key_material[1]); - } - else - { - GNUNET_CRYPTO_eddsa_ecdh (id_key, /* A */ - &msg->ephemeral_key, /* B0 */ - &key_material[1]); - - - } - - /* ECDH A0 B0 */ - /* (This is the triple-DH, we could probably safely skip this, - as A0/B0 are already in the key material.) */ - GNUNET_CRYPTO_ecc_ecdh (ax->kx_0, /* A0 or B0 */ - &msg->ephemeral_key, /* B0 or A0 */ - &key_material[2]); - - #if DUMP_KEYS_TO_STDERR - { - unsigned int i; - for (i = 0; i < 3; i++) - LOG (GNUNET_ERROR_TYPE_INFO, "km[%u]: %s\n", - i, GNUNET_h2s (&key_material[i])); - } - #endif - - /* KDF */ - GNUNET_CRYPTO_kdf (keys, sizeof (keys), - salt, sizeof (salt), - &key_material, sizeof (key_material), NULL); - - if (0 == memcmp (&ax->RK, &keys[0], sizeof(ax->RK))) - { - LOG (GNUNET_ERROR_TYPE_INFO, " known handshake key, exit\n"); - return; - } - ax->RK = keys[0]; - if (GNUNET_YES == am_I_alice) - { - ax->HKr = keys[1]; - ax->NHKs = keys[2]; - ax->NHKr = keys[3]; - ax->CKr = keys[4]; - ax->ratchet_flag = GNUNET_YES; - } - else - { - ax->HKs = keys[1]; - ax->NHKr = keys[2]; - ax->NHKs = keys[3]; - ax->CKs = keys[4]; - ax->ratchet_flag = GNUNET_NO; - ax->ratchet_allowed = GNUNET_NO; - ax->ratchet_counter = 0; - ax->ratchet_expiration = - GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(), ratchet_time); - } - ax->PNs = 0; - ax->Nr = 0; - ax->Ns = 0; - - GCT_change_estate (t, CADET_TUNNEL_KEY_AX_AUTH_SENT); - send_queued_data (t); - - CADET_TIMING_END; -} - -/** - * Initialize the tunnel subsystem. - * - * @param c Configuration handle. - * @param key ECC private key, to derive all other keys and do crypto. - */ -void -GCT_init (const struct GNUNET_CONFIGURATION_Handle *c, - const struct GNUNET_CRYPTO_EddsaPrivateKey *key) -{ - unsigned int expected_overhead; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n"); - - expected_overhead = 0; - expected_overhead += sizeof (struct GNUNET_CADET_TunnelEncryptedMessage); - expected_overhead += sizeof (struct GNUNET_CADET_ChannelAppDataMessage); - expected_overhead += sizeof (struct GNUNET_CADET_ConnectionEncryptedAckMessage); - GNUNET_assert (GNUNET_CONSTANTS_CADET_P2P_OVERHEAD == expected_overhead); - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, - "CADET", - "RATCHET_MESSAGES", - &ratchet_messages)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, - "CADET", - "RATCHET_MESSAGES", - "USING DEFAULT"); - ratchet_messages = 64; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (c, - "CADET", - "RATCHET_TIME", - &ratchet_time)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, - "CADET", "RATCHET_TIME", "USING DEFAULT"); - ratchet_time = GNUNET_TIME_UNIT_HOURS; - } - - - id_key = key; - tunnels = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); -} - - -/** - * Shut down the tunnel subsystem. - */ -void -GCT_shutdown (void) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down tunnels\n"); - GNUNET_CONTAINER_multipeermap_iterate (tunnels, &destroy_iterator, NULL); - GNUNET_CONTAINER_multipeermap_destroy (tunnels); -} - - -/** - * Create a tunnel. - * - * @param destination Peer this tunnel is towards. - */ -struct CadetTunnel * -GCT_new (struct CadetPeer *destination) -{ - struct CadetTunnel *t; - - t = GNUNET_new (struct CadetTunnel); - t->next_ctn.cn = 0; - t->peer = destination; - - if (GNUNET_OK != - GNUNET_CONTAINER_multipeermap_put (tunnels, GCP_get_id (destination), t, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) - { - GNUNET_break (0); - GNUNET_free (t); - return NULL; - } - t->ax = GNUNET_new (struct CadetTunnelAxolotl); - new_ephemeral (t); - t->ax->kx_0 = GNUNET_CRYPTO_ecdhe_key_create (); - return t; -} - - -/** - * Change the tunnel's connection state. - * - * @param t Tunnel whose connection state to change. - * @param cstate New connection state. - */ -void -GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate) -{ - if (NULL == t) - return; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s cstate %s => %s\n", - GCP_2s (t->peer), cstate2s (t->cstate), cstate2s (cstate)); - if (myid != GCP_get_short_id (t->peer) && - CADET_TUNNEL_READY != t->cstate && - CADET_TUNNEL_READY == cstate) - { - t->cstate = cstate; - if (CADET_TUNNEL_KEY_OK == t->estate) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered send queued data\n"); - send_queued_data (t); - } - else if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered KX\n"); - GCT_send_kx (t, GNUNET_NO); - } - else - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "estate %s\n", estate2s (t->estate)); - } - } - t->cstate = cstate; - - if (CADET_TUNNEL_READY == cstate - && CONNECTIONS_PER_TUNNEL <= GCT_count_connections (t)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate triggered stop dht\n"); - GCP_stop_search (t->peer); - } -} - - -/** - * Change the tunnel encryption state. - * - * If the encryption state changes to OK, stop the rekey task. - * - * @param t Tunnel whose encryption state to change, or NULL. - * @param state New encryption state. - */ -void -GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state) -{ - enum CadetTunnelEState old; - - if (NULL == t) - return; - - old = t->estate; - t->estate = state; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate was %s\n", - GCP_2s (t->peer), estate2s (old)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s estate is now %s\n", - GCP_2s (t->peer), estate2s (t->estate)); - - if (CADET_TUNNEL_KEY_OK != old && CADET_TUNNEL_KEY_OK == t->estate) - { - if (NULL != t->rekey_task) - { - GNUNET_SCHEDULER_cancel (t->rekey_task); - t->rekey_task = NULL; - } - /* Send queued data if tunnel is not loopback */ - if (myid != GCP_get_short_id (t->peer)) - send_queued_data (t); - } -} - - -/** - * @brief Check if tunnel has too many connections, and remove one if necessary. - * - * Currently this means the newest connection, unless it is a direct one. - * Implemented as a task to avoid freeing a connection that is in the middle - * of being created/processed. - * - * @param cls Closure (Tunnel to check). - */ -static void -trim_connections (void *cls) -{ - struct CadetTunnel *t = cls; - - t->trim_connections_task = NULL; - if (GCT_count_connections (t) > 2 * CONNECTIONS_PER_TUNNEL) - { - struct CadetTConnection *iter; - struct CadetTConnection *c; - - for (c = iter = t->connection_head; NULL != iter; iter = iter->next) - { - if ((iter->created.abs_value_us > c->created.abs_value_us) - && GNUNET_NO == GCC_is_direct (iter->c)) - { - c = iter; - } - } - if (NULL != c) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Too many connections on tunnel %s\n", - GCT_2s (t)); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Destroying connection %s\n", - GCC_2s (c->c)); - GCC_destroy (c->c); - } - else - { - GNUNET_break (0); - } - } -} - - -/** - * Add a connection to a tunnel. - * - * @param t Tunnel. - * @param c Connection. - */ -void -GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c) -{ - struct CadetTConnection *aux; - - GNUNET_assert (NULL != c); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "add connection %s\n", GCC_2s (c)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " to tunnel %s\n", GCT_2s (t)); - for (aux = t->connection_head; aux != NULL; aux = aux->next) - if (aux->c == c) - return; - - aux = GNUNET_new (struct CadetTConnection); - aux->c = c; - aux->created = GNUNET_TIME_absolute_get (); - - GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, aux); - - if (CADET_TUNNEL_SEARCHING == t->cstate) - GCT_change_cstate (t, CADET_TUNNEL_WAITING); - - if (NULL != t->trim_connections_task) - t->trim_connections_task = GNUNET_SCHEDULER_add_now (&trim_connections, t); -} - - -/** - * Remove a connection from a tunnel. - * - * @param t Tunnel. - * @param c Connection. - */ -void -GCT_remove_connection (struct CadetTunnel *t, - struct CadetConnection *c) -{ - struct CadetTConnection *aux; - struct CadetTConnection *next; - unsigned int conns; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing connection %s from tunnel %s\n", - GCC_2s (c), GCT_2s (t)); - for (aux = t->connection_head; aux != NULL; aux = next) - { - next = aux->next; - if (aux->c == c) - { - GNUNET_CONTAINER_DLL_remove (t->connection_head, t->connection_tail, aux); - GNUNET_free (aux); - } - } - - conns = GCT_count_connections (t); - if (0 == conns - && NULL == t->destroy_task - && CADET_TUNNEL_SHUTDOWN != t->cstate - && GNUNET_NO == shutting_down) - { - if (0 == GCT_count_any_connections (t)) - GCT_change_cstate (t, CADET_TUNNEL_SEARCHING); - else - GCT_change_cstate (t, CADET_TUNNEL_WAITING); - } - - /* Start new connections if needed */ - if (CONNECTIONS_PER_TUNNEL > conns - && CADET_TUNNEL_SHUTDOWN != t->cstate - && GNUNET_NO == shutting_down) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " too few connections, getting new ones\n"); - GCP_connect (t->peer); /* Will change cstate to WAITING when possible */ - return; - } - - /* If not marked as ready, no change is needed */ - if (CADET_TUNNEL_READY != t->cstate) - return; - - /* Check if any connection is ready to maintain cstate */ - for (aux = t->connection_head; aux != NULL; aux = aux->next) - if (CADET_CONNECTION_READY == GCC_get_state (aux->c)) - return; -} - - -/** - * Add a channel to a tunnel. - * - * @param t Tunnel. - * @param ch Channel. - */ -void -GCT_add_channel (struct CadetTunnel *t, - struct CadetChannel *ch) -{ - struct CadetTChannel *aux; - - GNUNET_assert (NULL != ch); - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding channel %p to tunnel %p\n", ch, t); - - for (aux = t->channel_head; aux != NULL; aux = aux->next) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " already there %p\n", aux->ch); - if (aux->ch == ch) - return; - } - - aux = GNUNET_new (struct CadetTChannel); - aux->ch = ch; - LOG (GNUNET_ERROR_TYPE_DEBUG, - " adding %p to %p\n", aux, t->channel_head); - GNUNET_CONTAINER_DLL_insert_tail (t->channel_head, - t->channel_tail, - aux); - - if (NULL != t->destroy_task) - { - GNUNET_SCHEDULER_cancel (t->destroy_task); - t->destroy_task = NULL; - LOG (GNUNET_ERROR_TYPE_DEBUG, " undo destroy!\n"); - } -} - - -/** - * Remove a channel from a tunnel. - * - * @param t Tunnel. - * @param ch Channel. - */ -void -GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch) -{ - struct CadetTChannel *aux; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Removing channel %p from tunnel %p\n", ch, t); - for (aux = t->channel_head; aux != NULL; aux = aux->next) - { - if (aux->ch == ch) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, " found! %s\n", GCCH_2s (ch)); - GNUNET_CONTAINER_DLL_remove (t->channel_head, - t->channel_tail, - aux); - GNUNET_free (aux); - return; - } - } -} - - -/** - * Search for a channel by global ID. - * - * @param t Tunnel containing the channel. - * @param ctn Public channel number. - * - * @return channel handler, NULL if doesn't exist - */ -struct CadetChannel * -GCT_get_channel (struct CadetTunnel *t, - struct GNUNET_CADET_ChannelTunnelNumber ctn) -{ - struct CadetTChannel *iter; - - if (NULL == t) - return NULL; - - for (iter = t->channel_head; NULL != iter; iter = iter->next) - { - if (GCCH_get_id (iter->ch).cn == ctn.cn) - break; - } - - return NULL == iter ? NULL : iter->ch; -} - - -/** - * @brief Destroy a tunnel and free all resources. - * - * Should only be called a while after the tunnel has been marked as destroyed, - * in case there is a new channel added to the same peer shortly after marking - * the tunnel. This way we avoid a new public key handshake. - * - * @param cls Closure (tunnel to destroy). - */ -static void -delayed_destroy (void *cls) -{ - struct CadetTunnel *t = cls; - struct CadetTConnection *iter; - - t->destroy_task = NULL; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "delayed destroying tunnel %p\n", - t); - t->cstate = CADET_TUNNEL_SHUTDOWN; - for (iter = t->connection_head; NULL != iter; iter = iter->next) - { - GCC_send_destroy (iter->c); - } - GCT_destroy (t); -} - - -/** - * Tunnel is empty: destroy it. - * - * Notifies all connections about the destruction. - * - * @param t Tunnel to destroy. - */ -void -GCT_destroy_empty (struct CadetTunnel *t) -{ - if (GNUNET_YES == shutting_down) - return; /* Will be destroyed immediately anyway */ - - if (NULL != t->destroy_task) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Tunnel %s is already scheduled for destruction. Tunnel debug dump:\n", - GCT_2s (t)); - GCT_debug (t, GNUNET_ERROR_TYPE_WARNING); - GNUNET_break (0); - /* should never happen, tunnel can only become empty once, and the - * task identifier should be NO_TASK (cleaned when the tunnel was created - * or became un-empty) - */ - return; - } - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s empty: scheduling destruction\n", - GCT_2s (t)); - - // FIXME make delay a config option - t->destroy_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, - &delayed_destroy, t); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduled destroy of %p as %p\n", - t, t->destroy_task); -} - - -/** - * Destroy tunnel if empty (no more channels). - * - * @param t Tunnel to destroy if empty. - */ -void -GCT_destroy_if_empty (struct CadetTunnel *t) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel %s destroy if empty\n", GCT_2s (t)); - if (0 < GCT_count_channels (t)) - return; - - GCT_destroy_empty (t); -} - - -/** - * Destroy the tunnel. - * - * This function does not generate any warning traffic to clients or peers. - * - * Tasks: - * Cancel messages belonging to this tunnel queued to neighbors. - * Free any allocated resources linked to the tunnel. - * - * @param t The tunnel to destroy. - */ -void -GCT_destroy (struct CadetTunnel *t) -{ - struct CadetTConnection *iter_c; - struct CadetTConnection *next_c; - struct CadetTChannel *iter_ch; - struct CadetTChannel *next_ch; - unsigned int keepalives_queued; - - if (NULL == t) - return; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "destroying tunnel %s\n", - GCP_2s (t->peer)); - GNUNET_break (GNUNET_YES == - GNUNET_CONTAINER_multipeermap_remove (tunnels, - GCP_get_id (t->peer), t)); - - for (iter_c = t->connection_head; NULL != iter_c; iter_c = next_c) - { - next_c = iter_c->next; - GCC_destroy (iter_c->c); - } - for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = next_ch) - { - next_ch = iter_ch->next; - GCCH_destroy (iter_ch->ch); - /* Should only happen on shutdown, but it's ok. */ - } - keepalives_queued = 0; - while (NULL != t->tq_head) - { - /* Should have been cleaned by destuction of channel. */ - struct GNUNET_MessageHeader *mh; - uint16_t type; - - mh = (struct GNUNET_MessageHeader *) &t->tq_head[1]; - type = ntohs (mh->type); - if (0 == keepalives_queued && GNUNET_MESSAGE_TYPE_CADET_CHANNEL_KEEPALIVE == type) - { - keepalives_queued = 1; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "one keepalive left behind on tunnel shutdown\n"); - } - else if (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY == type) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "tunnel destroyed before a CHANNEL_DESTROY was sent to peer\n"); - } - else - { - GNUNET_break (0); - LOG (GNUNET_ERROR_TYPE_ERROR, - "message left behind on tunnel shutdown: %s\n", - GC_m2s (type)); - } - unqueue_data (t->tq_head); - } - - - if (NULL != t->destroy_task) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "cancelling dest: %p\n", - t->destroy_task); - GNUNET_SCHEDULER_cancel (t->destroy_task); - t->destroy_task = NULL; - } - - if (NULL != t->trim_connections_task) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "cancelling trim: %p\n", - t->trim_connections_task); - GNUNET_SCHEDULER_cancel (t->trim_connections_task); - t->trim_connections_task = NULL; - } - - GNUNET_STATISTICS_update (stats, "# tunnels", -1, GNUNET_NO); - GCP_set_tunnel (t->peer, NULL); - - if (NULL != t->rekey_task) - { - GNUNET_SCHEDULER_cancel (t->rekey_task); - t->rekey_task = NULL; - } - if (NULL != t->ax) - destroy_ax (t); - - GNUNET_free (t); -} - - -/** - * @brief Use the given path for the tunnel. - * Update the next and prev hops (and RCs). - * (Re)start the path refresh in case the tunnel is locally owned. - * - * @param t Tunnel to update. - * @param p Path to use. - * - * @return Connection created. - */ -struct CadetConnection * -GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *path) -{ - struct CadetConnection *c; - struct GNUNET_CADET_ConnectionTunnelIdentifier cid; - unsigned int own_pos; - - if (NULL == t || NULL == path) - { - GNUNET_break (0); - return NULL; - } - - if (CADET_TUNNEL_SHUTDOWN == t->cstate) - { - GNUNET_break (0); - return NULL; - } - - for (own_pos = 0; own_pos < path->length; own_pos++) - { - if (path->peers[own_pos] == myid) - break; - } - if (own_pos >= path->length) - { - GNUNET_break_op (0); - return NULL; - } - - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &cid, sizeof (cid)); - c = GCC_new (&cid, t, path, own_pos); - if (NULL == c) - { - /* Path was flawed */ - return NULL; - } - GCT_add_connection (t, c); - return c; -} - - -/** - * Count all created connections of a tunnel. Not necessarily ready connections! - * - * @param t Tunnel on which to count. - * - * @return Number of connections created, either being established or ready. - */ -unsigned int -GCT_count_any_connections (struct CadetTunnel *t) -{ - struct CadetTConnection *iter; - unsigned int count; - - if (NULL == t) - return 0; - - for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next) - count++; - - return count; -} - - -/** - * Count established (ready) connections of a tunnel. - * - * @param t Tunnel on which to count. - * - * @return Number of connections. - */ -unsigned int -GCT_count_connections (struct CadetTunnel *t) -{ - struct CadetTConnection *iter; - unsigned int count; - - if (NULL == t) - return 0; - - for (count = 0, iter = t->connection_head; NULL != iter; iter = iter->next) - if (CADET_CONNECTION_READY == GCC_get_state (iter->c)) - count++; - - return count; -} - - -/** - * Count channels of a tunnel. - * - * @param t Tunnel on which to count. - * - * @return Number of channels. - */ -unsigned int -GCT_count_channels (struct CadetTunnel *t) -{ - struct CadetTChannel *iter; - unsigned int count; - - for (count = 0, iter = t->channel_head; - NULL != iter; - iter = iter->next, count++) /* skip */; - - return count; -} - - -/** - * Get the connectivity state of a tunnel. - * - * @param t Tunnel. - * - * @return Tunnel's connectivity state. - */ -enum CadetTunnelCState -GCT_get_cstate (struct CadetTunnel *t) -{ - if (NULL == t) - { - GNUNET_assert (0); - return (enum CadetTunnelCState) -1; - } - return t->cstate; -} - - -/** - * Get the encryption state of a tunnel. - * - * @param t Tunnel. - * - * @return Tunnel's encryption state. - */ -enum CadetTunnelEState -GCT_get_estate (struct CadetTunnel *t) -{ - if (NULL == t) - { - GNUNET_break (0); - return (enum CadetTunnelEState) -1; - } - return t->estate; -} - -/** - * Get the maximum buffer space for a tunnel towards a local client. - * - * @param t Tunnel. - * - * @return Biggest buffer space offered by any channel in the tunnel. - */ -unsigned int -GCT_get_channels_buffer (struct CadetTunnel *t) -{ - struct CadetTChannel *iter; - unsigned int buffer; - unsigned int ch_buf; - - if (NULL == t->channel_head) - { - /* Probably getting buffer for a channel create/handshake. */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " no channels, allow max\n"); - return MIN_TUNNEL_BUFFER; - } - - buffer = 0; - for (iter = t->channel_head; NULL != iter; iter = iter->next) - { - ch_buf = get_channel_buffer (iter); - if (ch_buf > buffer) - buffer = ch_buf; - } - if (MIN_TUNNEL_BUFFER > buffer) - return MIN_TUNNEL_BUFFER; - - if (MAX_TUNNEL_BUFFER < buffer) - { - GNUNET_break (0); - return MAX_TUNNEL_BUFFER; - } - return buffer; -} - - -/** - * Get the total buffer space for a tunnel for P2P traffic. - * - * @param t Tunnel. - * - * @return Buffer space offered by all connections in the tunnel. - */ -unsigned int -GCT_get_connections_buffer (struct CadetTunnel *t) -{ - struct CadetTConnection *iter; - unsigned int buffer; - - if (GNUNET_NO == is_ready (t)) - { - if (count_queued_data (t) >= 3) - return 0; - else - return 1; - } - - buffer = 0; - for (iter = t->connection_head; NULL != iter; iter = iter->next) - { - if (GCC_get_state (iter->c) != CADET_CONNECTION_READY) - { - continue; - } - buffer += get_connection_buffer (iter); - } - - return buffer; -} - - -/** - * Get the tunnel's destination. - * - * @param t Tunnel. - * - * @return ID of the destination peer. - */ -const struct GNUNET_PeerIdentity * -GCT_get_destination (struct CadetTunnel *t) -{ - return GCP_get_id (t->peer); -} - - -/** - * Get the tunnel's next free global channel ID. - * - * @param t Tunnel. - * - * @return GID of a channel free to use. - */ -struct GNUNET_CADET_ChannelTunnelNumber -GCT_get_next_ctn (struct CadetTunnel *t) -{ - struct GNUNET_CADET_ChannelTunnelNumber ctn; - struct GNUNET_CADET_ChannelTunnelNumber mask; - int result; - - /* Set bit 30 depending on the ID relationship. Bit 31 is always 0 for GID. - * If our ID is bigger or loopback tunnel, start at 0, bit 30 = 0 - * If peer's ID is bigger, start at 0x4... bit 30 = 1 - */ - result = GNUNET_CRYPTO_cmp_peer_identity (&my_full_id, GCP_get_id (t->peer)); - if (0 > result) - mask.cn = htonl (0x40000000); - else - mask.cn = 0x0; - t->next_ctn.cn |= mask.cn; - - while (NULL != GCT_get_channel (t, t->next_ctn)) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Channel %u exists...\n", - t->next_ctn.cn); - t->next_ctn.cn = htonl ((ntohl (t->next_ctn.cn) + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI); - t->next_ctn.cn |= mask.cn; - } - ctn = t->next_ctn; - t->next_ctn.cn = (t->next_ctn.cn + 1) & ~GNUNET_CADET_LOCAL_CHANNEL_ID_CLI; - t->next_ctn.cn |= mask.cn; - - return ctn; -} - - -/** - * Send ACK on one or more channels due to buffer in connections. - * - * @param t Channel which has some free buffer space. - */ -void -GCT_unchoke_channels (struct CadetTunnel *t) -{ - struct CadetTChannel *iter; - unsigned int buffer; - unsigned int channels = GCT_count_channels (t); - unsigned int choked_n; - struct CadetChannel *choked[channels]; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "GCT_unchoke_channels on %s\n", GCT_2s (t)); - LOG (GNUNET_ERROR_TYPE_DEBUG, " head: %p\n", t->channel_head); - if (NULL != t->channel_head) - LOG (GNUNET_ERROR_TYPE_DEBUG, " head ch: %p\n", t->channel_head->ch); - - if (NULL != t->tq_head) - send_queued_data (t); - - /* Get buffer space */ - buffer = GCT_get_connections_buffer (t); - if (0 == buffer) - { - return; - } - - /* Count and remember choked channels */ - choked_n = 0; - for (iter = t->channel_head; NULL != iter; iter = iter->next) - { - if (GNUNET_NO == get_channel_allowed (iter)) - { - choked[choked_n++] = iter->ch; - } - } - - /* Unchoke random channels */ - while (0 < buffer && 0 < choked_n) - { - unsigned int r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - choked_n); - GCCH_allow_client (choked[r], GCCH_is_origin (choked[r], GNUNET_YES)); - choked_n--; - buffer--; - choked[r] = choked[choked_n]; - } -} - - -/** - * Send ACK on one or more connections due to buffer space to the client. - * - * Iterates all connections of the tunnel and sends ACKs appropriately. - * - * @param t Tunnel. - */ -void -GCT_send_connection_acks (struct CadetTunnel *t) -{ - struct CadetTConnection *iter; - uint32_t allowed; - uint32_t to_allow; - uint32_t allow_per_connection; - unsigned int cs; - unsigned int buffer; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Tunnel send connection ACKs on %s\n", - GCT_2s (t)); - - if (NULL == t) - { - GNUNET_break (0); - return; - } - - if (CADET_TUNNEL_READY != t->cstate) - return; - - buffer = GCT_get_channels_buffer (t); - LOG (GNUNET_ERROR_TYPE_DEBUG, " buffer %u\n", buffer); - - /* Count connections, how many messages are already allowed */ - cs = GCT_count_connections (t); - for (allowed = 0, iter = t->connection_head; NULL != iter; iter = iter->next) - { - allowed += get_connection_allowed (iter); - } - LOG (GNUNET_ERROR_TYPE_DEBUG, " allowed %u\n", allowed); - - /* Make sure there is no overflow */ - if (allowed > buffer) - return; - - /* Authorize connections to send more data */ - to_allow = buffer - allowed; - - for (iter = t->connection_head; - NULL != iter && to_allow > 0; - iter = iter->next) - { - if (CADET_CONNECTION_READY != GCC_get_state (iter->c) - || get_connection_allowed (iter) > 64 / 3) - { - continue; - } - GNUNET_assert(cs != 0); - allow_per_connection = to_allow/cs; - to_allow -= allow_per_connection; - cs--; - GCC_allow (iter->c, allow_per_connection, - GCC_is_origin (iter->c, GNUNET_NO)); - } - - if (0 != to_allow) - { - /* Since we don't allow if it's allowed to send 64/3, this can happen. */ - LOG (GNUNET_ERROR_TYPE_DEBUG, " reminding to_allow: %u\n", to_allow); - } -} - - -/** - * Cancel a previously sent message while it's in the queue. - * - * ONLY can be called before the continuation given to the send function - * is called. Once the continuation is called, the message is no longer in the - * queue. - * - * @param q Handle to the queue. - */ -void -GCT_cancel (struct CadetTunnelQueue *q) -{ - if (NULL != q->cq) - { - GNUNET_assert (NULL == q->tqd); - GCC_cancel (q->cq); - /* tun_message_sent() will be called and free q */ - } - else if (NULL != q->tqd) - { - unqueue_data (q->tqd); - q->tqd = NULL; - if (NULL != q->cont) - q->cont (q->cont_cls, NULL, q, 0, 0); - GNUNET_free (q); - } - else - { - GNUNET_break (0); - } -} - - -/** - * Check if the tunnel has queued traffic. - * - * @param t Tunnel to check. - * - * @return #GNUNET_YES if there is queued traffic - * #GNUNET_NO otherwise - */ -int -GCT_has_queued_traffic (struct CadetTunnel *t) -{ - return (NULL != t->tq_head) ? GNUNET_YES : GNUNET_NO; -} - - -/** - * Sends an already built message on a tunnel, encrypting it and - * choosing the best connection if not provided. - * - * @param message Message to send. Function modifies it. - * @param t Tunnel on which this message is transmitted. - * @param c Connection to use (autoselect if NULL). - * @param force Force the tunnel to take the message (buffer overfill). - * @param cont Continuation to call once message is really sent. - * @param cont_cls Closure for @c cont. - * - * @return Handle to cancel message. NULL if @c cont is NULL. - */ -struct CadetTunnelQueue * -GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct CadetTunnel *t, - struct CadetConnection *c, - int force, GCT_sent cont, void *cont_cls) -{ - return send_prebuilt_message (message, t, c, force, cont, cont_cls, NULL); -} - - -/** - * Send a KX message. - * - * @param t Tunnel on which to send it. - * @param force_reply Force the other peer to reply with a KX message. - */ -void -GCT_send_kx (struct CadetTunnel *t, int force_reply) -{ - static struct CadetEncryptedMessageIdentifier zero; - struct CadetConnection *c; - struct GNUNET_CADET_TunnelKeyExchangeMessage msg; - enum GNUNET_CADET_KX_Flags flags; - - LOG (GNUNET_ERROR_TYPE_INFO, "==> { KX} on %s\n", GCT_2s (t)); - if (NULL != t->ephm_h) - { - LOG (GNUNET_ERROR_TYPE_INFO, " already queued, nop\n"); - return; - } - GNUNET_assert (GNUNET_NO == GCT_is_loopback (t)); - - c = tunnel_get_connection (t); - if (NULL == c) - { - if (NULL == t->destroy_task && CADET_TUNNEL_READY == t->cstate) - { - GNUNET_break (0); - GCT_debug (t, GNUNET_ERROR_TYPE_ERROR); - } - return; - } - - msg.header.size = htons (sizeof (msg)); - msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_TUNNEL_KX); - flags = GNUNET_CADET_KX_FLAG_NONE; - if (GNUNET_YES == force_reply) - flags |= GNUNET_CADET_KX_FLAG_FORCE_REPLY; - msg.flags = htonl (flags); - msg.cid = *GCC_get_id (c); - GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->kx_0, &msg.ephemeral_key); - GNUNET_CRYPTO_ecdhe_key_get_public (t->ax->DHRs, &msg.ratchet_key); - - t->ephm_h = GCC_send_prebuilt_message (&msg.header, - UINT16_MAX, - zero, - c, - GCC_is_origin (c, GNUNET_YES), - GNUNET_YES, &ephm_sent, t); - if (CADET_TUNNEL_KEY_UNINITIALIZED == t->estate) - GCT_change_estate (t, CADET_TUNNEL_KEY_AX_SENT); -} - - -/** - * Is the tunnel directed towards the local peer? - * - * @param t Tunnel. - * - * @return #GNUNET_YES if it is loopback. - */ -int -GCT_is_loopback (const struct CadetTunnel *t) -{ - return (myid == GCP_get_short_id (t->peer)); -} - - -/** - * Is the tunnel this path already? - * - * @param t Tunnel. - * @param p Path. - * - * @return #GNUNET_YES a connection uses this path. - */ -int -GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p) -{ - struct CadetTConnection *iter; - - for (iter = t->connection_head; NULL != iter; iter = iter->next) - if (path_equivalent (GCC_get_path (iter->c), p)) - return GNUNET_YES; - - return GNUNET_NO; -} - - -/** - * Get a cost of a path for a tunnel considering existing connections. - * - * @param t Tunnel. - * @param path Candidate path. - * - * @return Cost of the path (path length + number of overlapping nodes) - */ -unsigned int -GCT_get_path_cost (const struct CadetTunnel *t, - const struct CadetPeerPath *path) -{ - struct CadetTConnection *iter; - const struct CadetPeerPath *aux; - unsigned int overlap; - unsigned int i; - unsigned int j; - - if (NULL == path) - return 0; - - overlap = 0; - GNUNET_assert (NULL != t); - - for (i = 0; i < path->length; i++) - { - for (iter = t->connection_head; NULL != iter; iter = iter->next) - { - aux = GCC_get_path (iter->c); - if (NULL == aux) - continue; - - for (j = 0; j < aux->length; j++) - { - if (path->peers[i] == aux->peers[j]) - { - overlap++; - break; - } - } - } - } - return path->length + overlap; -} - - -/** - * Get the static string for the peer this tunnel is directed. - * - * @param t Tunnel. - * - * @return Static string the destination peer's ID. - */ -const char * -GCT_2s (const struct CadetTunnel *t) -{ - if (NULL == t) - return "(NULL)"; - - return GCP_2s (t->peer); -} - - -/******************************************************************************/ -/***************************** INFO/DEBUG *******************************/ -/******************************************************************************/ - -static void -ax_debug (const struct CadetTunnelAxolotl *ax, enum GNUNET_ErrorType level) -{ - struct GNUNET_CRYPTO_EcdhePublicKey pub; - struct CadetTunnelSkippedKey *iter; - - LOG2 (level, "TTT RK \t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->RK)); - - LOG2 (level, "TTT HKs \t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKs)); - LOG2 (level, "TTT HKr \t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->HKr)); - LOG2 (level, "TTT NHKs\t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKs)); - LOG2 (level, "TTT NHKr\t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->NHKr)); - - LOG2 (level, "TTT CKs \t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKs)); - LOG2 (level, "TTT CKr \t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->CKr)); - - GNUNET_CRYPTO_ecdhe_key_get_public (ax->DHRs, &pub); - LOG2 (level, "TTT DHRs\t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &pub)); - LOG2 (level, "TTT DHRr\t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &ax->DHRr)); - - LOG2 (level, "TTT Nr\t %u\tNs\t%u\n", ax->Nr, ax->Ns); - LOG2 (level, "TTT PNs\t %u\tSkipped\t%u\n", ax->PNs, ax->skipped); - LOG2 (level, "TTT Ratchet\t%u\n", ax->ratchet_flag); - - for (iter = ax->skipped_head; NULL != iter; iter = iter->next) - { - LOG2 (level, "TTT HK\t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->HK)); - LOG2 (level, "TTT MK\t %s\n", - GNUNET_i2s ((struct GNUNET_PeerIdentity *) &iter->MK)); - } -} - -/** - * Log all possible info about the tunnel state. - * - * @param t Tunnel to debug. - * @param level Debug level to use. - */ -void -GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level) -{ - struct CadetTChannel *iter_ch; - struct CadetTConnection *iter_c; - int do_log; - - do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK), - "cadet-tun", - __FILE__, __FUNCTION__, __LINE__); - if (0 == do_log) - return; - - LOG2 (level, "TTT DEBUG TUNNEL TOWARDS %s\n", GCT_2s (t)); - LOG2 (level, "TTT cstate %s, estate %s\n", - cstate2s (t->cstate), estate2s (t->estate)); -#if DUMP_KEYS_TO_STDERR - ax_debug (t->ax, level); -#endif - LOG2 (level, "TTT tq_head %p, tq_tail %p\n", t->tq_head, t->tq_tail); - LOG2 (level, "TTT destroy %p\n", t->destroy_task); - LOG2 (level, "TTT channels:\n"); - for (iter_ch = t->channel_head; NULL != iter_ch; iter_ch = iter_ch->next) - { - GCCH_debug (iter_ch->ch, level); - } - - LOG2 (level, "TTT connections:\n"); - for (iter_c = t->connection_head; NULL != iter_c; iter_c = iter_c->next) - { - GCC_debug (iter_c->c, level); - } - - LOG2 (level, "TTT DEBUG TUNNEL END\n"); -} - - -/** - * Iterate all tunnels. - * - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls) -{ - GNUNET_CONTAINER_multipeermap_iterate (tunnels, iter, cls); -} - - -/** - * Count all tunnels. - * - * @return Number of tunnels to remote peers kept by this peer. - */ -unsigned int -GCT_count_all (void) -{ - return GNUNET_CONTAINER_multipeermap_size (tunnels); -} - - -/** - * Iterate all connections of a tunnel. - * - * @param t Tunnel whose connections to iterate. - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GCT_iterate_connections (struct CadetTunnel *t, GCT_conn_iter iter, void *cls) -{ - struct CadetTConnection *ct; - - for (ct = t->connection_head; NULL != ct; ct = ct->next) - iter (cls, ct->c); -} - - -/** - * Iterate all channels of a tunnel. - * - * @param t Tunnel whose channels to iterate. - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GCT_iterate_channels (struct CadetTunnel *t, GCT_chan_iter iter, void *cls) -{ - struct CadetTChannel *cht; - - for (cht = t->channel_head; NULL != cht; cht = cht->next) - iter (cls, cht->ch); -} diff --git a/src/cadet/gnunet-service-cadet_tunnel.h b/src/cadet/gnunet-service-cadet_tunnel.h deleted file mode 100644 index 1b56a0632..000000000 --- a/src/cadet/gnunet-service-cadet_tunnel.h +++ /dev/null @@ -1,616 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2013 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file cadet/gnunet-service-cadet_tunnel.h - * @brief cadet service; dealing with tunnels and crypto - * @author Bartlomiej Polot - * - * All functions in this file should use the prefix GMT (Gnunet Cadet Tunnel) - */ - -#ifndef GNUNET_SERVICE_CADET_TUNNEL_H -#define GNUNET_SERVICE_CADET_TUNNEL_H - -#ifdef __cplusplus -extern "C" -{ -#if 0 /* keep Emacsens' auto-indent happy */ -} -#endif -#endif - -#include "platform.h" -#include "gnunet_util_lib.h" - -#define CONNECTIONS_PER_TUNNEL 3 - -/** - * All the connectivity states a tunnel can be in. - */ -enum CadetTunnelCState -{ - /** - * Uninitialized status, should never appear in operation. - */ - CADET_TUNNEL_NEW, - - /** - * No path to the peer known yet. - */ - CADET_TUNNEL_SEARCHING, - - /** - * Request sent, not yet answered. - */ - CADET_TUNNEL_WAITING, - - /** - * Peer connected and ready to accept data. - */ - CADET_TUNNEL_READY, - - /** - * Tunnel being shut down, don't try to keep it alive. - */ - CADET_TUNNEL_SHUTDOWN -}; - - -/** - * All the encryption states a tunnel can be in. - */ -enum CadetTunnelEState -{ - /** - * Uninitialized status, should never appear in operation. - */ - CADET_TUNNEL_KEY_UNINITIALIZED, - - /** - * Ephemeral key sent, waiting for peer's key. - */ - CADET_TUNNEL_KEY_AX_SENT, - - /** - * In OTR: New ephemeral key and ping sent, waiting for pong. - * - * This means that we DO have the peer's ephemeral key, otherwise the - * state would be KEY_SENT. We DO NOT have a valid session key (either no - * previous key or previous key expired). - * - * - * In Axolotl: Key sent and received but no deciphered traffic yet. - * - * This means that we can send traffic (otherwise we would never complete - * the handshake), but we don't have complete confirmation. Since the first - * traffic MUST be a complete channel creation 3-way handshake, no payload - * will be sent before confirmation. - */ - CADET_TUNNEL_KEY_AX_AUTH_SENT, - - /** - * Handshake completed: session key available. - */ - CADET_TUNNEL_KEY_OK, - - /** - * New ephemeral key and ping sent, waiting for pong. Unlike KEY_PING, - * we still have a valid session key and therefore we *can* still send - * traffic on the tunnel. - */ - CADET_TUNNEL_KEY_REKEY -}; - -/** - * Struct containing all information regarding a given peer - */ -struct CadetTunnel; - - -#include "gnunet-service-cadet_channel.h" -#include "gnunet-service-cadet_connection.h" -#include "gnunet-service-cadet_peer.h" - -/** - * Handle for messages queued but not yet sent. - */ -struct CadetTunnelQueue; - -/** - * Callback called when a queued message is sent. - * - * @param cls Closure. - * @param t Tunnel this message was on. - * @param type Type of message sent. - * @param size Size of the message. - */ -typedef void -(*GCT_sent) (void *cls, - struct CadetTunnel *t, - struct CadetTunnelQueue *q, - uint16_t type, size_t size); - -typedef void -(*GCT_conn_iter) (void *cls, struct CadetConnection *c); - - -typedef void -(*GCT_chan_iter) (void *cls, struct CadetChannel *ch); - - -/******************************************************************************/ -/******************************** API ***********************************/ -/******************************************************************************/ - -/** - * Initialize tunnel subsystem. - * - * @param c Configuration handle. - * @param key ECC private key, to derive all other keys and do crypto. - */ -void -GCT_init (const struct GNUNET_CONFIGURATION_Handle *c, - const struct GNUNET_CRYPTO_EddsaPrivateKey *key); - - -/** - * Shut down the tunnel subsystem. - */ -void -GCT_shutdown (void); - - -/** - * Create a tunnel. - * - * @param destination Peer this tunnel is towards. - */ -struct CadetTunnel * -GCT_new (struct CadetPeer *destination); - - -/** - * Tunnel is empty: destroy it. - * - * Notifies all connections about the destruction. - * - * @param t Tunnel to destroy. - */ -void -GCT_destroy_empty (struct CadetTunnel *t); - - -/** - * Destroy tunnel if empty (no more channels). - * - * @param t Tunnel to destroy if empty. - */ -void -GCT_destroy_if_empty (struct CadetTunnel *t); - - -/** - * Destroy the tunnel. - * - * This function does not generate any warning traffic to clients or peers. - * - * Tasks: - * Cancel messages belonging to this tunnel queued to neighbors. - * Free any allocated resources linked to the tunnel. - * - * @param t The tunnel to destroy. - */ -void -GCT_destroy (struct CadetTunnel *t); - - -/** - * Change the tunnel's connection state. - * - * @param t Tunnel whose connection state to change. - * @param cstate New connection state. - */ -void -GCT_change_cstate (struct CadetTunnel* t, enum CadetTunnelCState cstate); - - -/** - * Change the tunnel encryption state. - * - * @param t Tunnel whose encryption state to change. - * @param state New encryption state. - */ -void -GCT_change_estate (struct CadetTunnel* t, enum CadetTunnelEState state); - - -/** - * Add a connection to a tunnel. - * - * @param t Tunnel. - * @param c Connection. - */ -void -GCT_add_connection (struct CadetTunnel *t, struct CadetConnection *c); - - -/** - * Remove a connection from a tunnel. - * - * @param t Tunnel. - * @param c Connection. - */ -void -GCT_remove_connection (struct CadetTunnel *t, struct CadetConnection *c); - - -/** - * Add a channel to a tunnel. - * - * @param t Tunnel. - * @param ch Channel. - */ -void -GCT_add_channel (struct CadetTunnel *t, struct CadetChannel *ch); - - -/** - * Remove a channel from a tunnel. - * - * @param t Tunnel. - * @param ch Channel. - */ -void -GCT_remove_channel (struct CadetTunnel *t, struct CadetChannel *ch); - - -/** - * Search for a channel by global ID. - * - * @param t Tunnel containing the channel. - * @param ctn Public channel number. - * - * @return channel handler, NULL if doesn't exist - */ -struct CadetChannel * -GCT_get_channel (struct CadetTunnel *t, struct GNUNET_CADET_ChannelTunnelNumber ctn); - - -/** - * Decrypt and process an encrypted message. - * - * Calls the appropriate handler for a message in a channel of a local tunnel. - * - * @param t Tunnel this message came on. - * @param msg Message header. - */ -void -GCT_handle_encrypted (struct CadetTunnel *t, - const struct GNUNET_CADET_TunnelEncryptedMessage *msg); - - -/** - * Handle a Key eXchange message. - * - * @param t Tunnel on which the message came. - * @param msg KX message itself. - */ -void -GCT_handle_kx (struct CadetTunnel *t, - const struct GNUNET_CADET_TunnelKeyExchangeMessage *msg); - - -/** - * @brief Use the given path for the tunnel. - * Update the next and prev hops (and RCs). - * (Re)start the path refresh in case the tunnel is locally owned. - * - * @param t Tunnel to update. - * @param p Path to use. - * - * @return Connection created. - */ -struct CadetConnection * -GCT_use_path (struct CadetTunnel *t, struct CadetPeerPath *p); - - -/** - * Count all created connections of a tunnel. Not necessarily ready connections! - * - * @param t Tunnel on which to count. - * - * @return Number of connections created, either being established or ready. - */ -unsigned int -GCT_count_any_connections (struct CadetTunnel *t); - - -/** - * Count established (ready) connections of a tunnel. - * - * @param t Tunnel on which to count. - * - * @return Number of connections. - */ -unsigned int -GCT_count_connections (struct CadetTunnel *t); - - -/** - * Count channels of a tunnel. - * - * @param t Tunnel on which to count. - * - * @return Number of channels. - */ -unsigned int -GCT_count_channels (struct CadetTunnel *t); - - -/** - * Get the connectivity state of a tunnel. - * - * @param t Tunnel. - * - * @return Tunnel's connectivity state. - */ -enum CadetTunnelCState -GCT_get_cstate (struct CadetTunnel *t); - - -/** - * Get the encryption state of a tunnel. - * - * @param t Tunnel. - * - * @return Tunnel's encryption state. - */ -enum CadetTunnelEState -GCT_get_estate (struct CadetTunnel *t); - - -/** - * Get the maximum buffer space for a tunnel towards a local client. - * - * @param t Tunnel. - * - * @return Biggest buffer space offered by any channel in the tunnel. - */ -unsigned int -GCT_get_channels_buffer (struct CadetTunnel *t); - - -/** - * Get the total buffer space for a tunnel for P2P traffic. - * - * @param t Tunnel. - * - * @return Buffer space offered by all connections in the tunnel. - */ -unsigned int -GCT_get_connections_buffer (struct CadetTunnel *t); - - -/** - * Get the tunnel's destination. - * - * @param t Tunnel. - * - * @return ID of the destination peer. - */ -const struct GNUNET_PeerIdentity * -GCT_get_destination (struct CadetTunnel *t); - - -/** - * Get the tunnel's next free Channel ID. - * - * @param t Tunnel. - * - * @return ID of a channel free to use. - */ -struct GNUNET_CADET_ChannelTunnelNumber -GCT_get_next_ctn (struct CadetTunnel *t); - - -/** - * Send ACK on one or more channels due to buffer in connections. - * - * @param t Channel which has some free buffer space. - */ -void -GCT_unchoke_channels (struct CadetTunnel *t); - - -/** - * Send ACK on one or more connections due to buffer space to the client. - * - * Iterates all connections of the tunnel and sends ACKs appropriately. - * - * @param t Tunnel which has some free buffer space. - */ -void -GCT_send_connection_acks (struct CadetTunnel *t); - - -/** - * Cancel a previously sent message while it's in the queue. - * - * ONLY can be called before the continuation given to the send function - * is called. Once the continuation is called, the message is no longer in the - * queue. - * - * @param q Handle to the queue. - */ -void -GCT_cancel (struct CadetTunnelQueue *q); - - -/** - * Check if the tunnel has queued traffic. - * - * @param t Tunnel to check. - * - * @return #GNUNET_YES if there is queued traffic - * #GNUNET_NO otherwise - */ -int -GCT_has_queued_traffic (struct CadetTunnel *t); - -/** - * Sends an already built message on a tunnel, encrypting it and - * choosing the best connection. - * - * @param message Message to send. Function modifies it. - * @param t Tunnel on which this message is transmitted. - * @param c Connection to use (autoselect if NULL). - * @param force Force the tunnel to take the message (buffer overfill). - * @param cont Continuation to call once message is really sent. - * @param cont_cls Closure for @c cont. - * - * @return Handle to cancel message. NULL if @c cont is NULL. - */ -struct CadetTunnelQueue * -GCT_send_prebuilt_message (const struct GNUNET_MessageHeader *message, - struct CadetTunnel *t, struct CadetConnection *c, - int force, GCT_sent cont, void *cont_cls); - - -/** - * Send a KX message. - * - * @param t Tunnel on which to send it. - * @param force_reply Force the other peer to reply with a KX message. - */ -void -GCT_send_kx (struct CadetTunnel *t, int force_reply); - - -/** - * Is the tunnel directed towards the local peer? - * - * @param t Tunnel. - * - * @return #GNUNET_YES if it is loopback. - */ -int -GCT_is_loopback (const struct CadetTunnel *t); - - -/** - * Is the tunnel using this path already? - * - * @param t Tunnel. - * @param p Path. - * - * @return #GNUNET_YES a connection uses this path. - */ -int -GCT_is_path_used (const struct CadetTunnel *t, const struct CadetPeerPath *p); - - -/** - * Get a cost of a path for a tunnel considering existing connections. - * - * @param t Tunnel. - * @param path Candidate path. - * - * @return Cost of the path (path length + number of overlapping nodes) - */ -unsigned int -GCT_get_path_cost (const struct CadetTunnel *t, - const struct CadetPeerPath *path); - - -/** - * Get the static string for the peer this tunnel is directed. - * - * @param t Tunnel. - * - * @return Static string the destination peer's ID. - */ -const char * -GCT_2s (const struct CadetTunnel *t); - - -/** - * Log all possible info about the tunnel state. - * - * @param t Tunnel to debug. - * @param level Debug level to use. - */ -void -GCT_debug (const struct CadetTunnel *t, enum GNUNET_ErrorType level); - - -/** - * Iterate all tunnels. - * - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GCT_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter, void *cls); - - -/** - * Count all tunnels. - * - * @return Number of tunnels to remote peers kept by this peer. - */ -unsigned int -GCT_count_all (void); - - -/** - * Iterate all connections of a tunnel. - * - * @param t Tunnel whose connections to iterate. - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GCT_iterate_connections (struct CadetTunnel *t, GCT_conn_iter iter, void *cls); - - -/** - * Iterate all channels of a tunnel. - * - * @param t Tunnel whose channels to iterate. - * @param iter Iterator. - * @param cls Closure for @c iter. - */ -void -GCT_iterate_channels (struct CadetTunnel *t, - GCT_chan_iter iter, - void *cls); - - -#if 0 /* keep Emacsens' auto-indent happy */ -{ -#endif -#ifdef __cplusplus -} -#endif - -/* ifndef GNUNET_CADET_SERVICE_TUNNEL_H */ -#endif -/* end of gnunet-cadet-service_tunnel.h */ -- 2.25.1