--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2013, 2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new.c
+ * @brief GNUnet CADET service with encryption
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * Dictionary:
+ * - peer: other cadet instance. If there is direct connection it's a neighbor.
+ * - path: series of directly connected peer from one peer to another.
+ * - connection: path which is being used in a tunnel.
+ * - tunnel: encrypted connection to a peer, neighbor or not.
+ * - channel: logical link between two clients, on the same or different peers.
+ * have properties like reliability.
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "cadet.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_channel.h"
+#include "gnunet-service-cadet-new_connection.h"
+#include "gnunet-service-cadet-new_dht.h"
+#include "gnunet-service-cadet-new_hello.h"
+#include "gnunet-service-cadet-new_tunnels.h"
+#include "gnunet-service-cadet-new_peer.h"
+#include "gnunet-service-cadet-new_paths.h"
+
+#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
+
+
+/**
+ * Struct containing information about a client of the service
+ */
+struct CadetClient
+{
+ /**
+ * Linked list next
+ */
+ struct CadetClient *next;
+
+ /**
+ * Linked list prev
+ */
+ struct CadetClient *prev;
+
+ /**
+ * Tunnels that belong to this client, indexed by local id
+ */
+ 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_chid;
+
+ /**
+ * Handle to communicate with the client
+ */
+ struct GNUNET_MQ_Handle *mq;
+
+ /**
+ * Client handle.
+ */
+ struct GNUNET_SERVICE_Client *client;
+
+ /**
+ * Ports that this client has declared interest in.
+ * Indexed by port, contains *Client.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *ports;
+
+ /**
+ * 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;
+};
+
+/******************************************************************************/
+/*********************** GLOBAL VARIABLES ****************************/
+/******************************************************************************/
+
+/****************************** Global variables ******************************/
+
+/**
+ * Handle to the statistics service.
+ */
+struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Handle to communicate with ATS.
+ */
+struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+
+/**
+ * Local peer own ID.
+ */
+struct GNUNET_PeerIdentity my_full_id;
+
+/**
+ * Own private key.
+ */
+struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+
+/**
+ * Signal that shutdown is happening: prevent recover measures.
+ */
+int shutting_down;
+
+/**
+ * DLL with all the clients, head.
+ */
+static struct CadetClient *clients_head;
+
+/**
+ * DLL with all the clients, tail.
+ */
+static struct CadetClient *clients_tail;
+
+/**
+ * Next ID to assign to a client.
+ */
+static unsigned int next_client_id;
+
+/**
+ * All ports clients of this peer have opened.
+ */
+struct GNUNET_CONTAINER_MultiHashMap *open_ports;
+
+/**
+ * Map from ports to channels where the ports were closed at the
+ * time we got the inbound connection.
+ * Indexed by port, contains `struct CadetChannel`.
+ */
+struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
+
+/**
+ * Map from PIDs to `struct CadetPeer` entries.
+ */
+struct GNUNET_CONTAINER_MultiPeerMap *peers;
+
+
+
+/**
+ * Send a message to a client.
+ *
+ * @param c client to get the message
+ * @param env envelope with the message
+ */
+void
+GSC_send_to_client (struct CadetClient *c,
+ struct GNUNET_MQ_Envelope *env)
+{
+ GNUNET_MQ_send (c->mq,
+ env);
+}
+
+
+/**
+ * Return identifier for a client as a string.
+ *
+ * @param c client to identify
+ * @return string for debugging
+ */
+const char *
+GSC_2s (struct CadetClient *c)
+{
+ static char buf[32];
+
+ if (NULL == c)
+ return "Client(NULL)";
+ GNUNET_snprintf (buf,
+ sizeof (buf),
+ "Client(%u)",
+ c->id);
+ return buf;
+}
+
+
+/**
+ * Obtain the next LID to use for incoming connections to
+ * the given client.
+ *
+ * @param c client handle
+ */
+static struct GNUNET_CADET_ClientChannelNumber
+client_get_next_lid (struct CadetClient *c)
+{
+ struct GNUNET_CADET_ClientChannelNumber ccn = c->next_chid;
+
+ /* increment until we have a free one... */
+ while (NULL !=
+ GNUNET_CONTAINER_multihashmap32_get (c->incoming_channels,
+ ntohl (ccn.channel_of_client)))
+ {
+ ccn.channel_of_client
+ = htonl (1 + (ntohl (ccn.channel_of_client)));
+ if (ntohl (ccn.channel_of_client) >=
+ GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ ccn.channel_of_client = htonl (0);
+ }
+ c->next_chid.channel_of_client
+ = htonl (1 + (ntohl (ccn.channel_of_client)));
+ return ccn;
+}
+
+
+/**
+ * Bind incoming channel to this client, and notify client
+ * about incoming connection.
+ *
+ * @param c client to bind to
+ * @param ch channel to be bound
+ * @param dest peer that establishes the connection
+ * @param port port number
+ * @param options options
+ * @return local channel number assigned to the new client
+ */
+struct GNUNET_CADET_ClientChannelNumber
+GSC_bind (struct CadetClient *c,
+ struct CadetChannel *ch,
+ struct CadetPeer *dest,
+ const struct GNUNET_HashCode *port,
+ uint32_t options)
+{
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_ChannelCreateMessage *msg;
+ struct GNUNET_CADET_ClientChannelNumber lid;
+
+ lid = client_get_next_lid (c);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_put (c->incoming_channels,
+ ntohl (lid.channel_of_client),
+ ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
+ /* notify local client about incoming connection! */
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
+ msg->channel_id = lid;
+ msg->port = *port;
+ msg->opt = htonl (options);
+ GCP_id (dest,
+ &msg->peer);
+ GSC_send_to_client (c,
+ env);
+ return lid;
+}
+
+
+/******************************************************************************/
+/************************ 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;
+
+ if (NULL != stats)
+ {
+ GNUNET_STATISTICS_destroy (stats,
+ GNUNET_NO);
+ stats = NULL;
+ }
+ if (NULL != open_ports)
+ {
+ GNUNET_CONTAINER_multihashmap_destroy (open_ports);
+ open_ports = NULL;
+ }
+ if (NULL != loose_channels)
+ {
+ GNUNET_CONTAINER_multihashmap_destroy (loose_channels);
+ loose_channels = NULL;
+ }
+ /* All channels, connections and CORE must be down before this point. */
+ GCP_destroy_all_peers ();
+ if (NULL != peers)
+ {
+ GNUNET_CONTAINER_multipeermap_destroy (peers);
+ peers = NULL;
+ }
+ if (NULL != ats_ch)
+ {
+ GNUNET_ATS_connectivity_done (ats_ch);
+ ats_ch = NULL;
+ }
+ GCD_shutdown ();
+ GCH_shutdown ();
+ GNUNET_free_non_null (my_private_key);
+ my_private_key = NULL;
+}
+
+
+/**
+ * We had a remote connection @a value to port @a port before
+ * client @a cls opened port @a port. Bind them now.
+ *
+ * @param cls the `struct CadetClient`
+ * @param port the port
+ * @param value the `struct CadetChannel`
+ * @return #GNUNET_YES (iterate over all such channels)
+ */
+static int
+bind_loose_channel (void *cls,
+ const struct GNUNET_HashCode *port,
+ void *value)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch = value;
+
+ GCCH_bind (ch,
+ c);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (loose_channels,
+ port,
+ value));
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for port open requests.
+ *
+ * @param cls Identification of the client.
+ * @param pmsg The actual message.
+ */
+static void
+handle_port_open (void *cls,
+ const struct GNUNET_CADET_PortMessage *pmsg)
+{
+ struct CadetClient *c = cls;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Open port %s requested by client %u\n",
+ GNUNET_h2s (&pmsg->port),
+ c->id);
+ if (NULL == c->ports)
+ c->ports = GNUNET_CONTAINER_multihashmap_create (4,
+ GNUNET_NO);
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put (c->ports,
+ &pmsg->port,
+ c,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ /* 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 (open_ports,
+ &pmsg->port,
+ c,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ GNUNET_CONTAINER_multihashmap_get_multiple (loose_channels,
+ &pmsg->port,
+ &bind_loose_channel,
+ c);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for port close requests.
+ *
+ * @param cls Identification of the client.
+ * @param pmsg The actual message.
+ */
+static void
+handle_port_close (void *cls,
+ const struct GNUNET_CADET_PortMessage *pmsg)
+{
+ struct CadetClient *c = cls;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Open port %s requested by client %u\n",
+ GNUNET_h2s (&pmsg->port),
+ c->id);
+ if (GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_remove (c->ports,
+ &pmsg->port,
+ c))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (open_ports,
+ &pmsg->port,
+ c));
+
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for requests of new channels.
+ *
+ * @param cls Identification of the client.
+ * @param ccm The actual message.
+ */
+static void
+handle_channel_create (void *cls,
+ const struct GNUNET_CADET_ChannelCreateMessage *ccm)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch;
+ struct GNUNET_CADET_ClientChannelNumber chid;
+ struct CadetPeer *dst;
+
+ chid = ccm->channel_id;
+ if (ntohl (chid.channel_of_client) < GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ {
+ /* Channel ID not in allowed range. */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ ch = GNUNET_CONTAINER_multihashmap32_get (c->own_channels,
+ ntohl (chid.channel_of_client));
+ if (NULL != ch)
+ {
+ /* Channel ID already in use. Not allowed. */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+
+ dst = GCP_get (&ccm->peer,
+ GNUNET_YES);
+
+ /* Create channel */
+ ch = GCCH_channel_local_new (c,
+ chid,
+ dst,
+ &ccm->port,
+ ntohl (ccm->opt));
+ if (NULL == ch)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_put (c->own_channels,
+ ntohl (chid.channel_of_client),
+ ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "New channel %s to %s at port %s requested by client %u\n",
+ GCCH_2s (ch),
+ GNUNET_i2s (&ccm->peer),
+ GNUNET_h2s (&ccm->port),
+ c->id);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Return the map which we use for client @a c for a channel ID of @a chid
+ *
+ * @param c client to find map for
+ * @param chid chid to find map for
+ * @return applicable map we use
+ */
+static struct GNUNET_CONTAINER_MultiHashMap32 *
+get_map_by_chid (struct CadetClient *c,
+ struct GNUNET_CADET_ClientChannelNumber chid)
+{
+ return (ntohl (chid.channel_of_client) >= GNUNET_CADET_LOCAL_CHANNEL_ID_CLI)
+ ? c->own_channels
+ : c->incoming_channels;
+}
+
+
+/**
+ * Handler for requests of deleting tunnels
+ *
+ * @param cls client identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_channel_destroy (void *cls,
+ const struct GNUNET_CADET_ChannelDestroyMessage *msg)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_CADET_ClientChannelNumber chid;
+ struct GNUNET_CONTAINER_MultiHashMap32 *map;
+ struct CadetChannel *ch;
+
+ /* Retrieve tunnel */
+ chid = msg->channel_id;
+ map = get_map_by_chid (c,
+ chid);
+ ch = GNUNET_CONTAINER_multihashmap32_get (map,
+ ntohl (chid.channel_of_client));
+ if (NULL == ch)
+ {
+ /* Client attempted to destroy unknown channel */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Client %u is destroying channel %s\n",
+ c->id,
+ GCCH_2s (ch));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (map,
+ ntohl (chid.channel_of_client),
+ ch));
+ GCCH_channel_local_destroy (ch);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Check for client traffic data message is well-formed
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ * @return #GNUNET_OK if @a msg is OK, #GNUNET_SYSERR if not
+ */
+static int
+check_data (void *cls,
+ const struct GNUNET_CADET_LocalData *msg)
+{
+ const struct GNUNET_MessageHeader *payload;
+ size_t payload_size;
+ size_t payload_claimed_size;
+
+ /* Sanity check for message size */
+ payload_size = ntohs (msg->header.size) - sizeof (*msg);
+ if ( (payload_size < sizeof (struct GNUNET_MessageHeader)) ||
+ (GNUNET_CONSTANTS_MAX_CADET_MESSAGE_SIZE < payload_size) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ payload = (struct GNUNET_MessageHeader *) &msg[1];
+ payload_claimed_size = ntohs (payload->size);
+ if (payload_size != payload_claimed_size)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Handler for client traffic
+ *
+ * @param cls identification of the client
+ * @param msg the actual message
+ */
+static void
+handle_data (void *cls,
+ const struct GNUNET_CADET_LocalData *msg)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_CONTAINER_MultiHashMap32 *map;
+ struct GNUNET_CADET_ClientChannelNumber chid;
+ struct CadetChannel *ch;
+ const struct GNUNET_MessageHeader *payload;
+
+ chid = msg->id;
+ map = get_map_by_chid (c,
+ chid);
+ ch = GNUNET_CONTAINER_multihashmap32_get (map,
+ ntohl (chid.channel_of_client));
+ if (NULL == ch)
+ {
+ /* Channel does not exist! */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+
+ payload = (const struct GNUNET_MessageHeader *) &msg[1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received %u bytes payload from client %u for channel %s\n",
+ ntohs (payload->size),
+ c->id,
+ GCCH_2s (ch));
+ if (GNUNET_OK !=
+ GCCH_handle_local_data (ch,
+ payload))
+ {
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Handler for client's ACKs for payload traffic.
+ *
+ * @param cls identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_ack (void *cls,
+ const struct GNUNET_CADET_LocalAck *msg)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_CONTAINER_MultiHashMap32 *map;
+ struct GNUNET_CADET_ClientChannelNumber chid;
+ struct CadetChannel *ch;
+
+ chid = msg->channel_id;
+ map = get_map_by_chid (c,
+ chid);
+ ch = GNUNET_CONTAINER_multihashmap32_get (map,
+ ntohl (chid.channel_of_client));
+ if (NULL == ch)
+ {
+ /* Channel does not exist! */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (c->client);
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got a local ACK from client %u for channel %s\n",
+ c->id,
+ GCCH_2s (ch));
+ GCCH_handle_local_ack (ch);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all peers to send a monitoring client info about each peer.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Peer info.
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_peers_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ void *value)
+{
+ struct CadetClient *c = cls;
+ struct CadetPeer *p = value;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoPeer *msg;
+
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+ msg->destination = *peer;
+ msg->paths = htons (GCP_count_paths (p));
+ msg->tunnel = htons (NULL != GCP_get_tunnel (p,
+ GNUNET_NO));
+ GNUNET_MQ_send (c->mq,
+ env);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO PEERS request.
+ *
+ * @param cls Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_peers (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *reply;
+
+ GCP_iterate_all (&get_all_peers_iterator,
+ c);
+ env = GNUNET_MQ_msg (reply,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS);
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all paths of a peer to build an InfoPeer message.
+ * Message contains blocks of peers, first not included.
+ *
+ * @param cls message queue for transmission
+ * @param 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_MQ_Handle *mq = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *resp;
+ struct GNUNET_PeerIdentity *id;
+ uint16_t path_size;
+ unsigned int i;
+ unsigned int path_length;
+
+ path_length = GCPP_get_length (path);
+ path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
+ if (sizeof (*resp) + path_size > UINT16_MAX)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Path of %u entries is too long for info message\n",
+ path_length);
+ return GNUNET_YES;
+ }
+ env = GNUNET_MQ_msg_extra (resp,
+ path_size,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
+ id = (struct GNUNET_PeerIdentity *) &resp[1];
+
+ /* Don't copy first peer. First peer is always the local one. Last
+ * peer is always the destination (leave as 0, EOL).
+ */
+ for (i = 0; i < path_length - 1; i++)
+ GCPP_get_pid_at_offset (path,
+ i + 1,
+ &id[i]);
+ GNUNET_MQ_send (mq,
+ env);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's SHOW_PEER request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_show_peer (void *cls,
+ const struct GNUNET_CADET_LocalInfo *msg)
+{
+ struct CadetClient *c = cls;
+ struct CadetPeer *p;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *resp;
+
+ p = GCP_get (&msg->peer,
+ GNUNET_NO);
+ if (NULL != p)
+ GCP_iterate_paths (p,
+ &path_info_iterator,
+ c->mq);
+ /* Send message with 0/0 to indicate the end */
+ env = GNUNET_MQ_msg (resp,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER_END);
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all tunnels to send a monitoring client info about each tunnel.
+ *
+ * @param cls Closure ().
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value a `struct CadetPeer`
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+get_all_tunnels_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ void *value)
+{
+ struct CadetClient *c = cls;
+ struct CadetPeer *p = value;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoTunnel *msg;
+ struct CadetTunnel *t;
+
+ t = GCP_get_tunnel (p,
+ GNUNET_NO);
+ if (NULL == t)
+ return GNUNET_YES;
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+ msg->destination = *peer;
+ msg->channels = htonl (GCT_count_channels (t));
+ msg->connections = htonl (GCT_count_any_connections (t));
+ msg->cstate = htons ((uint16_t) GCT_get_cstate (t));
+ msg->estate = htons ((uint16_t) GCT_get_estate (t));
+ GNUNET_MQ_send (c->mq,
+ env);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO TUNNELS request.
+ *
+ * @param cls client Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_get_tunnels (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_MessageHeader *reply;
+
+ GCP_iterate_all (&get_all_tunnels_iterator,
+ c);
+ env = GNUNET_MQ_msg (reply,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS);
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * FIXME.
+ */
+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));
+}
+
+
+/**
+ * FIXME.
+ */
+static void
+iter_channel (void *cls,
+ struct CadetChannel *ch)
+{
+ struct GNUNET_CADET_LocalInfoTunnel *msg = cls;
+ struct GNUNET_CADET_Hash *h = (struct GNUNET_CADET_Hash *) &msg[1];
+ struct GCT_ChannelTunnelNumber *chn
+ = (struct GCT_ChannelTunnelNumber *) &h[msg->connections];
+
+ chn[msg->channels++] = GCCH_get_id (ch);
+}
+
+
+/**
+ * Handler for client's SHOW_TUNNEL request.
+ *
+ * @param cls Identification of the client.
+ * @param msg The actual message.
+ */
+static void
+handle_show_tunnel (void *cls,
+ const struct GNUNET_CADET_LocalInfo *msg)
+{
+ struct CadetClient *c = cls;
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoTunnel *resp;
+ struct CadetTunnel *t;
+ struct CadetPeer *p;
+ unsigned int ch_n;
+ unsigned int c_n;
+
+ p = GCP_get (&msg->peer,
+ GNUNET_NO);
+ t = GCP_get_tunnel (p,
+ GNUNET_NO);
+ if (NULL == t)
+ {
+ /* We don't know the tunnel */
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalInfoTunnel *warn;
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Tunnel to %s unknown\n",
+ GNUNET_i2s_full (&msg->peer));
+ env = GNUNET_MQ_msg (warn,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+ warn->destination = msg->peer;
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+ return;
+ }
+
+ /* Initialize context */
+ ch_n = GCT_count_channels (t);
+ c_n = GCT_count_any_connections (t);
+ env = GNUNET_MQ_msg_extra (resp,
+ c_n * sizeof (struct GNUNET_CADET_Hash) +
+ ch_n * sizeof (struct GCT_ChannelTunnelNumber),
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
+ resp->destination = msg->peer;
+ /* Do not reorder! #iter_channel needs counters in HBO! */
+ GCT_iterate_connections (t,
+ &iter_connection,
+ resp);
+ GCT_iterate_channels (t,
+ &iter_channel,
+ resp);
+ resp->connections = htonl (resp->connections);
+ resp->channels = htonl (resp->channels);
+ resp->cstate = htons (GCT_get_cstate (t));
+ resp->estate = htons (GCT_get_estate (t));
+ GNUNET_MQ_send (c->mq,
+ env);
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+/**
+ * Iterator over all peers to dump info for each peer.
+ *
+ * @param cls Closure (unused).
+ * @param peer Peer ID (tunnel remote peer).
+ * @param value Peer info.
+ *
+ * @return #GNUNET_YES, to keep iterating.
+ */
+static int
+show_peer_iterator (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ void *value)
+{
+ struct CadetPeer *p = value;
+ struct CadetTunnel *t;
+
+ t = GCP_get_tunnel (p,
+ GNUNET_NO);
+ if (NULL != t)
+ GCT_debug (t,
+ GNUNET_ERROR_TYPE_ERROR);
+ LOG (GNUNET_ERROR_TYPE_ERROR, "\n");
+ return GNUNET_YES;
+}
+
+
+/**
+ * Handler for client's INFO_DUMP request.
+ *
+ * @param cls Identification of the client.
+ * @param message The actual message.
+ */
+static void
+handle_info_dump (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct CadetClient *c = cls;
+
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Received dump info request from client %u\n",
+ c->id);
+
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "*************************** DUMP START ***************************\n");
+ for (struct CadetClient *ci = clients_head; NULL != ci; ci = ci->next)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Client %u (%p), handle: %p, ports: %u, own channels: %u, incoming channels: %u\n",
+ ci->id,
+ ci,
+ ci->client,
+ (NULL != c->ports)
+ ? GNUNET_CONTAINER_multihashmap_size (ci->ports)
+ : 0,
+ GNUNET_CONTAINER_multihashmap32_size (ci->own_channels),
+ GNUNET_CONTAINER_multihashmap32_size (ci->incoming_channels));
+ }
+ LOG (GNUNET_ERROR_TYPE_ERROR, "***************************\n");
+ GCP_iterate_all (&show_peer_iterator,
+ NULL);
+
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "**************************** DUMP END ****************************\n");
+
+ GNUNET_SERVICE_client_continue (c->client);
+}
+
+
+
+/**
+ * Callback called when a client connects to the service.
+ *
+ * @param cls closure for the service
+ * @param client the new client that connected to the service
+ * @param mq the message queue used to send messages to the client
+ * @return @a c
+ */
+static void *
+client_connect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *client,
+ struct GNUNET_MQ_Handle *mq)
+{
+ struct CadetClient *c;
+
+ c = GNUNET_new (struct CadetClient);
+ c->client = client;
+ c->mq = mq;
+ c->id = next_client_id++; /* overflow not important: just for debug */
+ c->own_channels
+ = GNUNET_CONTAINER_multihashmap32_create (32);
+ c->incoming_channels
+ = GNUNET_CONTAINER_multihashmap32_create (32);
+ GNUNET_CONTAINER_DLL_insert (clients_head,
+ clients_tail,
+ c);
+ GNUNET_STATISTICS_update (stats,
+ "# clients",
+ +1,
+ GNUNET_NO);
+ return c;
+}
+
+
+/**
+ * Iterator for deleting each channel whose client endpoint disconnected.
+ *
+ * @param cls Closure (client that has disconnected).
+ * @param key The local channel id (used to access the hashmap).
+ * @param value The value stored at the key (channel to destroy).
+ * @return #GNUNET_OK, keep iterating.
+ */
+static int
+own_channel_destroy_iterator (void *cls,
+ uint32_t key,
+ void *value)
+{
+ struct CadetClient *c = cls;
+ struct CadetChannel *ch = value;
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
+ key,
+ ch));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Destroying own channel %s, due to client %u shutdown.\n",
+ GCCH_2s (ch),
+ c->id);
+ GCCH_channel_local_destroy (ch);
+ 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
+incoming_channel_destroy_iterator (void *cls,
+ uint32_t key,
+ void *value)
+{
+ struct CadetChannel *ch = value;
+ struct CadetClient *c = cls;
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
+ key,
+ ch));
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Destroying incoming channel %s due to client %u shutdown.\n",
+ GCCH_2s (ch),
+ c->id);
+ GCCH_channel_incoming_destroy (ch);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Remove client's ports from the global hashmap on disconnect.
+ *
+ * @param cls Closure (unused).
+ * @param key Port.
+ * @param value the `struct CadetClient` to remove
+ * @return #GNUNET_OK, keep iterating.
+ */
+static int
+client_release_ports (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct CadetClient *c = value;
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (open_ports,
+ key,
+ value));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (c->ports,
+ key,
+ value));
+ return GNUNET_OK;
+}
+
+
+/**
+ * Callback called when a client disconnected from the service
+ *
+ * @param cls closure for the service
+ * @param client the client that disconnected
+ * @param internal_cls should be equal to @a c
+ */
+static void
+client_disconnect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *client,
+ void *internal_cls)
+{
+ struct CadetClient *c = internal_cls;
+
+ GNUNET_assert (c->client == client);
+ c->shutting_down = GNUNET_YES;
+ if (NULL != c->own_channels)
+ {
+ GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels,
+ &own_channel_destroy_iterator,
+ c);
+ GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels);
+ }
+ if (NULL != c->incoming_channels)
+ {
+ GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels,
+ &incoming_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_free (c);
+}
+
+
+/**
+ * Setup CADET internals.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_SERVICE_Handle *service)
+{
+ my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (c);
+ if (NULL == my_private_key)
+ {
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (my_private_key,
+ &my_full_id.public_key);
+ stats = GNUNET_STATISTICS_create ("cadet",
+ c);
+ GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+ NULL);
+ ats_ch = GNUNET_ATS_connectivity_init (c);
+ /* FIXME: optimize code to allow GNUNET_YES here! */
+ open_ports = GNUNET_CONTAINER_multihashmap_create (16,
+ GNUNET_NO);
+ loose_channels = GNUNET_CONTAINER_multihashmap_create (16,
+ GNUNET_NO);
+ peers = GNUNET_CONTAINER_multipeermap_create (16,
+ GNUNET_YES);
+ GCH_init (c);
+ GCD_init (c);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "CADET starting at peer %s\n",
+ GNUNET_i2s (&my_full_id));
+
+}
+
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("cadet",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ GNUNET_MQ_hd_fixed_size (port_open,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_OPEN,
+ struct GNUNET_CADET_PortMessage,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (port_close,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_PORT_CLOSE,
+ struct GNUNET_CADET_PortMessage,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (channel_create,
+ GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE,
+ struct GNUNET_CADET_ChannelCreateMessage,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (channel_destroy,
+ GNUNET_MESSAGE_TYPE_CADET_CHANNEL_DESTROY,
+ struct GNUNET_CADET_ChannelDestroyMessage,
+ NULL),
+ GNUNET_MQ_hd_var_size (data,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_DATA,
+ struct GNUNET_CADET_LocalData,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (ack,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK,
+ struct GNUNET_CADET_LocalAck,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (get_peers,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEERS,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (show_peer,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER,
+ struct GNUNET_CADET_LocalInfo,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (get_tunnels,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNELS,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (show_tunnel,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL,
+ struct GNUNET_CADET_LocalInfo,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (info_dump,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_DUMP,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_handler_end ());
+
+/* end of gnunet-service-cadet-new.c */
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new.h
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_H
+#define GNUNET_SERVICE_CADET_H
+
+/**
+ * A client to the CADET service.
+ */
+struct CadetClient;
+
+/**
+ * A peer in the GNUnet network.
+ */
+struct CadetPeer;
+
+/**
+ * Tunnel from us to another peer.
+ */
+struct CadetTunnel;
+
+/**
+ * Entry in the message queue of a `struct CadetTunnel`
+ */
+struct CadetTunnelQueueEntry;
+
+/**
+ * A path of peer in the GNUnet network.
+ */
+struct CadetPeerPath;
+
+/**
+ * Active path through the network (used by a tunnel).
+ */
+struct CadetConnection;
+
+/**
+ * Logical end-to-end conenction between clients.
+ */
+struct CadetChannel;
+
+/**
+ * Handle to the statistics service.
+ */
+extern struct GNUNET_STATISTICS_Handle *stats;
+
+/**
+ * Handle to communicate with ATS.
+ */
+extern struct GNUNET_ATS_ConnectivityHandle *ats_ch;
+
+/**
+ * Local peer own ID.
+ */
+extern struct GNUNET_PeerIdentity my_full_id;
+
+/**
+ * Own private key.
+ */
+extern struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
+
+/**
+ * All ports clients of this peer have opened.
+ */
+extern struct GNUNET_CONTAINER_MultiHashMap *open_ports;
+
+/**
+ * Map from ports to channels where the ports were closed at the
+ * time we got the inbound connection.
+ * Indexed by port, contains `struct CadetChannel`.
+ */
+extern struct GNUNET_CONTAINER_MultiHashMap *loose_channels;
+
+/**
+ * Map from PIDs to `struct CadetPeer` entries.
+ */
+extern struct GNUNET_CONTAINER_MultiPeerMap *peers;
+
+
+/**
+ * Send a message to a client.
+ *
+ * @param c client to get the message
+ * @param env envelope with the message
+ */
+void
+GSC_send_to_client (struct CadetClient *c,
+ struct GNUNET_MQ_Envelope *env);
+
+
+/**
+ * Bind incoming channel to this client, and notify client
+ * about incoming connection.
+ *
+ * @param c client to bind to
+ * @param ch channel to be bound
+ * @param dest peer that establishes the connection
+ * @param port port number
+ * @param options options
+ * @return local channel number assigned to the new client
+ */
+struct GNUNET_CADET_ClientChannelNumber
+GSC_bind (struct CadetClient *c,
+ struct CadetChannel *ch,
+ struct CadetPeer *dest,
+ const struct GNUNET_HashCode *port,
+ uint32_t options);
+
+
+/**
+ * Return identifier for a client as a string.
+ *
+ * @param c client to identify
+ * @return string for debugging
+ */
+const char *
+GSC_2s (struct CadetClient *c);
+
+
+#endif
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_channel.c
+ * @brief logical links between CADET clients
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "cadet.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_channel.h"
+#include "gnunet-service-cadet-new_connection.h"
+#include "gnunet-service-cadet-new_tunnels.h"
+#include "gnunet-service-cadet-new_peer.h"
+#include "gnunet-service-cadet-new_paths.h"
+
+#define LOG(level, ...) GNUNET_log (level,__VA_ARGS__)
+
+/**
+ * How long do we initially wait before retransmitting?
+ */
+#define CADET_INITIAL_RETRANSMIT_TIME GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 250)
+
+/**
+ * How long do we wait before dropping state about incoming
+ * connection to closed port?
+ */
+#define TIMEOUT_CLOSED_PORT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Number used to uniquely identify messages in a CADET Channel.
+ */
+struct ChannelMessageIdentifier
+{
+ /**
+ * Unique ID of the message, cycles around, in NBO.
+ */
+ uint32_t mid GNUNET_PACKED;
+};
+
+
+/**
+ * Message to create a Channel.
+ */
+struct GNUNET_CADET_ChannelCreate
+{
+ /**
+ * Type: #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Channel options.
+ */
+ uint32_t opt GNUNET_PACKED;
+
+ /**
+ * Destination port.
+ */
+ struct GNUNET_HashCode port;
+
+ /**
+ * ID of the channel
+ */
+ struct GCT_ChannelTunnelNumber gid;
+};
+
+
+
+/**
+ * Message for cadet data traffic.
+ */
+struct GNUNET_CADET_Data
+{
+ /**
+ * Type: #GNUNET_MESSAGE_TYPE_CADET_UNICAST,
+ * #GNUNET_MESSAGE_TYPE_CADET_TO_ORIGIN
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Unique ID of the payload message.
+ */
+ struct ChannelMessageIdentifier mid;
+
+ /**
+ * ID of the channel
+ */
+ struct GCT_ChannelTunnelNumber gid;
+
+ /**
+ * Payload follows
+ */
+};
+
+
+/**
+ * Message to acknowledge end-to-end data.
+ */
+struct GNUNET_CADET_DataACK
+{
+ /**
+ * Type: #GNUNET_MESSAGE_TYPE_CADET_DATA_ACK
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * ID of the channel
+ */
+ struct GCT_ChannelTunnelNumber gid;
+
+ /**
+ * Bitfield of already-received messages past @e mid.
+ * pid + 1 @ LSB
+ * pid + 64 @ MSB
+ */
+ uint64_t futures GNUNET_PACKED;
+
+ /**
+ * Last message ID received.
+ */
+ struct ChannelMessageIdentifier mid;
+};
+
+
+
+GNUNET_NETWORK_STRUCT_END
+
+
+/**
+ * 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_CREATE_SENT,
+
+ /**
+ * Connection confirmed, ready to carry traffic.
+ */
+ CADET_CHANNEL_READY
+};
+
+
+/**
+ * Info needed to retry a message in case it gets lost.
+ * Note that we DO use this structure also for unreliable
+ * messages.
+ */
+struct CadetReliableMessage
+{
+ /**
+ * Double linked list, FIFO style
+ */
+ struct CadetReliableMessage *next;
+
+ /**
+ * Double linked list, FIFO style
+ */
+ struct CadetReliableMessage *prev;
+
+ /**
+ * Which channel is this message in?
+ */
+ struct CadetChannel *ch;
+
+ /**
+ * Entry in the tunnels queue for this message, NULL if it has left
+ * the tunnel. Used to cancel transmission in case we receive an
+ * ACK in time.
+ */
+ struct CadetTunnelQueueEntry *qe;
+
+ /**
+ * How soon should we retry if we fail to get an ACK?
+ * Messages in the queue are sorted by this value.
+ */
+ struct GNUNET_TIME_Absolute next_retry;
+
+ /**
+ * How long do we wait for an ACK after transmission?
+ * Use for the back-off calculation.
+ */
+ struct GNUNET_TIME_Relative retry_delay;
+
+ /**
+ * Data message we are trying to send.
+ */
+ struct GNUNET_CADET_Data data_message;
+
+ /* followed by variable-size payload */
+};
+
+
+/**
+ * List of received out-of-order data messages.
+ */
+struct CadetOutOfOrderMessage
+{
+ /**
+ * Double linked list, FIFO style
+ */
+ struct CadetOutOfOrderMessage *next;
+
+ /**
+ * Double linked list, FIFO style
+ */
+ struct CadetOutOfOrderMessage *prev;
+
+ /**
+ * ID of the message (ACK needed to free)
+ */
+ struct ChannelMessageIdentifier mid;
+
+ /**
+ * The envelope with the payload of the out-of-order message
+ */
+ struct GNUNET_MQ_Envelope *env;
+
+};
+
+
+/**
+ * Struct containing all information regarding a channel to a remote client.
+ */
+struct CadetChannel
+{
+ /**
+ * Tunnel this channel is in.
+ */
+ struct CadetTunnel *t;
+
+ /**
+ * Last entry in the tunnel's queue relating to control messages
+ * (#GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE or
+ * #GNUNET_MESSAGE_TYPE_CADET_CHANNEL_ACK). Used to cancel
+ * transmission in case we receive updated information.
+ */
+ struct CadetTunnelQueueEntry *last_control_qe;
+
+ /**
+ * Client owner of the tunnel, if any.
+ * (Used if this channel represends the initiating end of the tunnel.)
+ */
+ struct CadetClient *owner;
+
+ /**
+ * Client destination of the tunnel, if any.
+ * (Used if this channel represents the listening end of the tunnel.)
+ */
+ struct CadetClient *dest;
+
+ /**
+ * Head of DLL of messages sent and not yet ACK'd.
+ */
+ struct CadetReliableMessage *head_sent;
+
+ /**
+ * Tail of DLL of messages sent and not yet ACK'd.
+ */
+ struct CadetReliableMessage *tail_sent;
+
+ /**
+ * Head of DLL of messages received out of order or while client was unready.
+ */
+ struct CadetOutOfOrderMessage *head_recv;
+
+ /**
+ * Tail DLL of messages received out of order or while client was unready.
+ */
+ struct CadetOutOfOrderMessage *tail_recv;
+
+ /**
+ * Task to resend/poll in case no ACK is received.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * Last time the channel was used
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /**
+ * Destination port of the channel.
+ */
+ struct GNUNET_HashCode port;
+
+ /**
+ * Counter for exponential backoff.
+ */
+ struct GNUNET_TIME_Relative retry_time;
+
+ /**
+ * How long does it usually take to get an ACK.
+ */
+ struct GNUNET_TIME_Relative expected_delay;
+
+ /**
+ * Bitfield of already-received messages past @e mid_recv.
+ */
+ uint64_t mid_futures;
+
+ /**
+ * Next MID expected for incoming traffic.
+ */
+ struct ChannelMessageIdentifier mid_recv;
+
+ /**
+ * Next MID to use for outgoing traffic.
+ */
+ struct ChannelMessageIdentifier mid_send;
+
+ /**
+ * Total (reliable) messages pending ACK for this channel.
+ */
+ unsigned int pending_messages;
+
+ /**
+ * Maximum (reliable) messages pending ACK for this channel
+ * before we throttle the client.
+ */
+ unsigned int max_pending_messages;
+
+ /**
+ * Number identifying this channel in its tunnel.
+ */
+ struct GCT_ChannelTunnelNumber gid;
+
+ /**
+ * Local tunnel number for local client owning the channel.
+ * ( >= #GNUNET_CADET_LOCAL_CHANNEL_ID_CLI or 0 )
+ */
+ struct GNUNET_CADET_ClientChannelNumber lid;
+
+ /**
+ * Channel state.
+ */
+ enum CadetChannelState state;
+
+ /**
+ * Can we send data to the client?
+ */
+ int client_ready;
+
+ /**
+ * Can the client send data to us?
+ */
+ int client_allowed;
+
+ /**
+ * Is the tunnel bufferless (minimum latency)?
+ */
+ int nobuffer;
+
+ /**
+ * Is the tunnel reliable?
+ */
+ int reliable;
+
+ /**
+ * Is the tunnel out-of-order?
+ */
+ int out_of_order;
+
+ /**
+ * Flag to signal the destruction of the channel. If this is set to
+ * #GNUNET_YES the channel will be destroyed once the queue is
+ * empty.
+ */
+ int destroy;
+
+};
+
+
+
+/**
+ * Get the static string for identification of the channel.
+ *
+ * @param ch Channel.
+ *
+ * @return Static string with the channel IDs.
+ */
+const char *
+GCCH_2s (const struct CadetChannel *ch)
+{
+ static char buf[128];
+
+ if (NULL == ch)
+ return "(NULL Channel)";
+ GNUNET_snprintf (buf,
+ sizeof (buf),
+ "%s:%s gid:%X (%X)",
+ GCT_2s (ch->t),
+ GNUNET_h2s (&ch->port),
+ ch->gid,
+ ntohl (ch->lid.channel_of_client));
+ return buf;
+}
+
+
+/**
+ * Get the channel's public ID.
+ *
+ * @param ch Channel.
+ *
+ * @return ID used to identify the channel with the remote peer.
+ */
+struct GCT_ChannelTunnelNumber
+GCCH_get_id (const struct CadetChannel *ch)
+{
+ return ch->gid;
+}
+
+
+/**
+ * Destroy the given channel.
+ *
+ * @param ch channel to destroy
+ */
+static void
+channel_destroy (struct CadetChannel *ch)
+{
+ struct CadetReliableMessage *crm;
+ struct CadetOutOfOrderMessage *com;
+
+ while (NULL != (crm = ch->head_sent))
+ {
+ GNUNET_assert (ch == crm->ch);
+ if (NULL != crm->qe)
+ {
+ GCT_send_cancel (crm->qe);
+ crm->qe = NULL;
+ }
+ GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+ ch->tail_sent,
+ crm);
+ GNUNET_free (crm);
+ }
+ while (NULL != (com = ch->head_recv))
+ {
+ GNUNET_CONTAINER_DLL_remove (ch->head_recv,
+ ch->tail_recv,
+ com);
+ GNUNET_MQ_discard (com->env);
+ GNUNET_free (com);
+ }
+ if (NULL != ch->last_control_qe)
+ {
+ GCT_send_cancel (ch->last_control_qe);
+ ch->last_control_qe = NULL;
+ }
+ if (NULL != ch->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (ch->retry_task);
+ ch->retry_task = NULL;
+ }
+ GCT_remove_channel (ch->t,
+ ch,
+ ch->gid);
+ GNUNET_free (ch);
+}
+
+
+/**
+ * Send a channel create message.
+ *
+ * @param cls Channel for which to send.
+ */
+static void
+send_create (void *cls);
+
+
+/**
+ * Function called once the tunnel confirms that we sent the
+ * create message. Delays for a bit until we retry.
+ *
+ * @param cls our `struct CadetChannel`.
+ */
+static void
+create_sent_cb (void *cls)
+{
+ struct CadetChannel *ch = cls;
+
+ ch->last_control_qe = NULL;
+ ch->retry_time = GNUNET_TIME_STD_BACKOFF (ch->retry_time);
+ ch->retry_task = GNUNET_SCHEDULER_add_delayed (ch->retry_time,
+ &send_create,
+ ch);
+}
+
+
+/**
+ * Send a channel create message.
+ *
+ * @param cls Channel for which to send.
+ */
+static void
+send_create (void *cls)
+{
+ struct CadetChannel *ch = cls;
+ struct GNUNET_CADET_ChannelCreate msgcc;
+ uint32_t options;
+
+ options = 0;
+ if (ch->nobuffer)
+ options |= GNUNET_CADET_OPTION_NOBUFFER;
+ if (ch->reliable)
+ options |= GNUNET_CADET_OPTION_RELIABLE;
+ if (ch->out_of_order)
+ options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
+ msgcc.header.size = htons (sizeof (msgcc));
+ msgcc.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_CHANNEL_CREATE);
+ msgcc.opt = htonl (options);
+ msgcc.port = ch->port;
+ msgcc.gid = ch->gid;
+ ch->state = CADET_CHANNEL_CREATE_SENT;
+ ch->last_control_qe = GCT_send (ch->t,
+ &msgcc.header,
+ &create_sent_cb,
+ ch);
+}
+
+
+/**
+ * Create a new channel.
+ *
+ * @param owner local client owning the channel
+ * @param owner_id local chid of this channel at the @a owner
+ * @param destination peer to which we should build the channel
+ * @param port desired port at @a destination
+ * @param options options for the channel
+ * @return handle to the new channel
+ */
+struct CadetChannel *
+GCCH_channel_local_new (struct CadetClient *owner,
+ struct GNUNET_CADET_ClientChannelNumber owner_id,
+ struct CadetPeer *destination,
+ const struct GNUNET_HashCode *port,
+ uint32_t options)
+{
+ struct CadetChannel *ch;
+
+ ch = GNUNET_new (struct CadetChannel);
+ ch->max_pending_messages = 32; /* FIXME: allow control via options
+ or adjust dynamically... */
+ ch->owner = owner;
+ ch->lid = owner_id;
+ ch->port = *port;
+ ch->t = GCP_get_tunnel (destination,
+ GNUNET_YES);
+ ch->gid = GCT_add_channel (ch->t,
+ ch);
+ ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
+ ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
+ ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
+ ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
+ ch->retry_task = GNUNET_SCHEDULER_add_now (&send_create,
+ ch);
+ GNUNET_STATISTICS_update (stats,
+ "# channels",
+ 1,
+ GNUNET_NO);
+ return ch;
+}
+
+
+/**
+ * We had an incoming channel to a port that is closed.
+ * It has not been opened for a while, drop it.
+ *
+ * @param cls the channel to drop
+ */
+static void
+timeout_closed_cb (void *cls)
+{
+ struct CadetChannel *ch = cls;
+
+ ch->retry_task = NULL;
+ channel_destroy (ch);
+}
+
+
+/**
+ * Create a new channel.
+ *
+ * @param t tunnel to the remote peer
+ * @param gid identifier of this channel in the tunnel
+ * @param port desired local port
+ * @param options options for the channel
+ * @return handle to the new channel
+ */
+struct CadetChannel *
+GCCH_channel_incoming_new (struct CadetTunnel *t,
+ struct GCT_ChannelTunnelNumber gid,
+ const struct GNUNET_HashCode *port,
+ uint32_t options)
+{
+ struct CadetChannel *ch;
+ struct CadetClient *c;
+
+ ch = GNUNET_new (struct CadetChannel);
+ ch->max_pending_messages = 32; /* FIXME: allow control via options
+ or adjust dynamically... */
+ ch->port = *port;
+ ch->t = t;
+ ch->gid = gid;
+ ch->retry_time = CADET_INITIAL_RETRANSMIT_TIME;
+ ch->nobuffer = (0 != (options & GNUNET_CADET_OPTION_NOBUFFER));
+ ch->reliable = (0 != (options & GNUNET_CADET_OPTION_RELIABLE));
+ ch->out_of_order = (0 != (options & GNUNET_CADET_OPTION_OUT_OF_ORDER));
+ GNUNET_STATISTICS_update (stats,
+ "# channels",
+ 1,
+ GNUNET_NO);
+
+ c = GNUNET_CONTAINER_multihashmap_get (open_ports,
+ port);
+ if (NULL == c)
+ {
+ /* port closed, wait for it to possibly open */
+ (void) GNUNET_CONTAINER_multihashmap_put (loose_channels,
+ port,
+ ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ ch->retry_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT_CLOSED_PORT,
+ &timeout_closed_cb,
+ ch);
+ }
+ else
+ {
+ GCCH_bind (ch,
+ c);
+ }
+ GNUNET_STATISTICS_update (stats,
+ "# channels",
+ 1,
+ GNUNET_NO);
+ return ch;
+}
+
+
+/**
+ * Function called once the tunnel confirms that we sent the
+ * ACK message. Just remembers it was sent, we do not expect
+ * ACKs for ACKs ;-).
+ *
+ * @param cls our `struct CadetChannel`.
+ */
+static void
+send_ack_cb (void *cls)
+{
+ struct CadetChannel *ch = cls;
+
+ ch->last_control_qe = NULL;
+}
+
+
+/**
+ * Compute and send the current ACK to the other peer.
+ *
+ * @param ch channel to send the ACK for
+ */
+static void
+send_channel_ack (struct CadetChannel *ch)
+{
+ struct GNUNET_CADET_DataACK msg;
+
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA_ACK);
+ msg.header.size = htons (sizeof (msg));
+ msg.gid = ch->gid;
+ msg.mid.mid = htonl (ntohl (ch->mid_recv.mid) - 1);
+ msg.futures = GNUNET_htonll (ch->mid_futures);
+ if (NULL != ch->last_control_qe)
+ GCT_send_cancel (ch->last_control_qe);
+ ch->last_control_qe = GCT_send (ch->t,
+ &msg.header,
+ &send_ack_cb,
+ ch);
+}
+
+
+/**
+ * Send our initial ACK to the client confirming that the
+ * connection is up.
+ *
+ * @param cls the `struct CadetChannel`
+ */
+static void
+send_connect_ack (void *cls)
+{
+ struct CadetChannel *ch = cls;
+
+ ch->retry_task = NULL;
+ send_channel_ack (ch);
+}
+
+
+/**
+ * A client is bound to the port that we have a channel
+ * open to. Send the acknowledgement for the connection
+ * request and establish the link with the client.
+ *
+ * @param ch open incoming channel
+ * @param c client listening on the respective port
+ */
+void
+GCCH_bind (struct CadetChannel *ch,
+ struct CadetClient *c)
+{
+ uint32_t options;
+
+ if (NULL != ch->retry_task)
+ {
+ /* there might be a timeout task here */
+ GNUNET_SCHEDULER_cancel (ch->retry_task);
+ ch->retry_task = NULL;
+ }
+ options = 0;
+ if (ch->nobuffer)
+ options |= GNUNET_CADET_OPTION_NOBUFFER;
+ if (ch->reliable)
+ options |= GNUNET_CADET_OPTION_RELIABLE;
+ if (ch->out_of_order)
+ options |= GNUNET_CADET_OPTION_OUT_OF_ORDER;
+ ch->dest = c;
+ ch->lid = GSC_bind (c,
+ ch,
+ GCT_get_destination (ch->t),
+ &ch->port,
+ options);
+ ch->mid_recv.mid = htonl (1); /* The CONNECT counts as message 0! */
+
+ /* notify other peer that we accepted the connection */
+ ch->retry_task = GNUNET_SCHEDULER_add_now (&send_connect_ack,
+ ch);
+}
+
+
+/**
+ * Destroy locally created channel. Called by the
+ * local client, so no need to tell the client.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_channel_local_destroy (struct CadetChannel *ch)
+{
+ if (GNUNET_YES == ch->destroy)
+ {
+ /* other end already destroyed, with the local client gone, no need
+ to finish transmissions, just destroy immediately. */
+ channel_destroy (ch);
+ return;
+ }
+ if (NULL != ch->head_sent)
+ {
+ /* allow send queue to train first */
+ ch->destroy = GNUNET_YES;
+ return;
+ }
+ /* Nothing left to do, just finish destruction */
+ channel_destroy (ch);
+}
+
+
+/**
+ * Destroy channel that was incoming. Called by the
+ * local client, so no need to tell the client.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_channel_incoming_destroy (struct CadetChannel *ch)
+{
+ if (GNUNET_YES == ch->destroy)
+ {
+ /* other end already destroyed, with the remote client gone, no need
+ to finish transmissions, just destroy immediately. */
+ channel_destroy (ch);
+ return;
+ }
+ if (NULL != ch->head_recv)
+ {
+ /* allow local client to see all data first */
+ ch->destroy = GNUNET_YES;
+ return;
+ }
+ /* Nothing left to do, just finish destruction */
+ channel_destroy (ch);
+}
+
+
+/**
+ * Function called once the tunnel has sent one of our messages.
+ * If the message is unreliable, simply frees the `crm`. If the
+ * message was reliable, calculate retransmission time and
+ * wait for ACK (or retransmit).
+ *
+ * @param cls the `struct CadetReliableMessage` that was sent
+ */
+static void
+data_sent_cb (void *cls);
+
+
+/**
+ * We need to retry a transmission, the last one took too long to
+ * be acknowledged.
+ *
+ * @param cls the `struct CadetChannel` where we need to retransmit
+ */
+static void
+retry_transmission (void *cls)
+{
+ struct CadetChannel *ch = cls;
+ struct CadetReliableMessage *crm = ch->head_sent;
+
+ GNUNET_assert (NULL == crm->qe);
+ crm->qe = GCT_send (ch->t,
+ &crm->data_message.header,
+ &data_sent_cb,
+ crm);
+}
+
+
+/**
+ * Check if we can now allow the client to transmit, and if so,
+ * let the client know about it.
+ *
+ * @param ch channel to check
+ */
+static void
+GCCH_check_allow_client (struct CadetChannel *ch)
+{
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_CADET_LocalAck *msg;
+
+ if (GNUNET_YES == ch->client_allowed)
+ return; /* client already allowed! */
+ if (CADET_CHANNEL_READY != ch->state)
+ {
+ /* destination did not yet ACK our CREATE! */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Channel %s not yet ready, throttling client until ACK.\n",
+ GCCH_2s (ch));
+ return;
+ }
+ if (ch->pending_messages > ch->max_pending_messages)
+ {
+ /* Too many messages in queue. */
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Message queue still too long on channel %s, throttling client until ACK.\n",
+ GCCH_2s (ch));
+ return;
+ }
+ if ( (NULL != ch->head_sent) &&
+ (64 <= ntohl (ch->mid_send.mid) - ntohl (ch->head_sent->data_message.mid.mid)) )
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Gap in ACKs too big on channel %s, throttling client until ACK.\n",
+ GCCH_2s (ch));
+ return;
+ }
+ ch->client_allowed = GNUNET_YES;
+
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending local ack to channel %s client\n",
+ GCCH_2s (ch));
+ env = GNUNET_MQ_msg (msg,
+ GNUNET_MESSAGE_TYPE_CADET_LOCAL_ACK);
+ msg->channel_id = ch->lid;
+ GSC_send_to_client (ch->owner ? ch->owner : ch->dest,
+ env);
+}
+
+
+/**
+ * Function called once the tunnel has sent one of our messages.
+ * If the message is unreliable, simply frees the `crm`. If the
+ * message was reliable, calculate retransmission time and
+ * wait for ACK (or retransmit).
+ *
+ * @param cls the `struct CadetReliableMessage` that was sent
+ */
+static void
+data_sent_cb (void *cls)
+{
+ struct CadetReliableMessage *crm = cls;
+ struct CadetChannel *ch = crm->ch;
+ struct CadetReliableMessage *off;
+
+ crm->qe = NULL;
+ GNUNET_CONTAINER_DLL_remove (ch->head_sent,
+ ch->tail_sent,
+ crm);
+ if (GNUNET_NO == ch->reliable)
+ {
+ GNUNET_free (crm);
+ ch->pending_messages--;
+ GCCH_check_allow_client (ch);
+ return;
+ }
+ if (0 == crm->retry_delay.rel_value_us)
+ crm->retry_delay = ch->expected_delay;
+ crm->next_retry = GNUNET_TIME_relative_to_absolute (crm->retry_delay);
+
+ /* find position for re-insertion into the DLL */
+ if ( (NULL == ch->head_sent) ||
+ (crm->next_retry.abs_value_us < ch->head_sent->next_retry.abs_value_us) )
+ {
+ /* insert at HEAD, also (re)schedule retry task! */
+ GNUNET_CONTAINER_DLL_insert (ch->head_sent,
+ ch->tail_sent,
+ crm);
+ if (NULL != ch->retry_task)
+ GNUNET_SCHEDULER_cancel (ch->retry_task);
+ ch->retry_task = GNUNET_SCHEDULER_add_delayed (crm->retry_delay,
+ &retry_transmission,
+ ch);
+ return;
+ }
+ for (off = ch->head_sent; NULL != off; off = off->next)
+ if (crm->next_retry.abs_value_us < off->next_retry.abs_value_us)
+ break;
+ if (NULL == off)
+ {
+ /* insert at tail */
+ GNUNET_CONTAINER_DLL_insert_tail (ch->head_sent,
+ ch->tail_sent,
+ crm);
+ }
+ else
+ {
+ /* insert before off */
+ GNUNET_CONTAINER_DLL_insert_after (ch->head_sent,
+ ch->tail_sent,
+ off->prev,
+ crm);
+ }
+}
+
+
+/**
+ * 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 message payload to transmit.
+ * @return #GNUNET_OK if everything goes well,
+ * #GNUNET_SYSERR in case of an error.
+ */
+int
+GCCH_handle_local_data (struct CadetChannel *ch,
+ const struct GNUNET_MessageHeader *message)
+{
+ uint16_t payload_size = ntohs (message->size);
+ struct CadetReliableMessage *crm;
+
+ if (GNUNET_NO == ch->client_allowed)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ ch->client_allowed = GNUNET_NO;
+ ch->pending_messages++;
+
+ /* Everything is correct, send the message. */
+ crm = GNUNET_malloc (sizeof (*crm) + payload_size);
+ crm->ch = ch;
+ crm->data_message.header.size = htons (sizeof (struct GNUNET_CADET_Data) + payload_size);
+ crm->data_message.header.type = htons (GNUNET_MESSAGE_TYPE_CADET_DATA);
+ ch->mid_send.mid = htonl (ntohl (ch->mid_send.mid) + 1);
+ crm->data_message.mid = ch->mid_send;
+ crm->data_message.gid = ch->gid;
+ GNUNET_memcpy (&crm[1],
+ message,
+ payload_size);
+ GNUNET_CONTAINER_DLL_insert (ch->head_sent,
+ ch->tail_sent,
+ crm);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending %u bytes from local client to channel %s\n",
+ payload_size,
+ GCCH_2s (ch));
+ crm->qe = GCT_send (ch->t,
+ &crm->data_message.header,
+ &data_sent_cb,
+ crm);
+ GCCH_check_allow_client (ch);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Try to deliver messages to the local client, if it is ready for more.
+ *
+ * @param ch channel to process
+ */
+static void
+send_client_buffered_data (struct CadetChannel *ch)
+{
+ struct CadetOutOfOrderMessage *com;
+
+ if (GNUNET_NO == ch->client_ready)
+ return; /* client not ready */
+ com = ch->head_recv;
+ if (NULL == com)
+ return; /* none pending */
+ if ( (com->mid.mid != ch->mid_recv.mid) &&
+ (GNUNET_NO == ch->out_of_order) )
+ return; /* missing next one in-order */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Passing payload message to client on channel %s\n",
+ GCCH_2s (ch));
+
+ /* all good, pass next message to client */
+ GNUNET_CONTAINER_DLL_remove (ch->head_recv,
+ ch->tail_recv,
+ com);
+ ch->mid_recv.mid = htonl (1 + ntohl (com->mid.mid));
+ ch->mid_futures >>= 1; /* equivalent to division by 2 */
+ GSC_send_to_client (ch->owner ? ch->owner : ch->dest,
+ com->env);
+ GNUNET_free (com);
+ if ( (0xFFULL == (ch->mid_futures & 0xFFULL)) &&
+ (GNUNET_YES == ch->reliable) )
+ {
+ /* The next 15 messages were also already received (0xFF), this
+ suggests that the sender may be blocked on flow control
+ urgently waiting for an ACK from us. (As we have an inherent
+ maximum of 64 bits, and 15 is getting too close for comfort.)
+ So we should send one now. */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sender on channel %s likely blocked on flow-control, sending ACK now.\n",
+ GCCH_2s (ch));
+ if (GNUNET_YES == ch->reliable)
+ send_channel_ack (ch);
+ }
+
+ if (NULL != ch->head_recv)
+ return;
+ if (GNUNET_NO == ch->destroy)
+ return;
+ channel_destroy (ch);
+}
+
+
+/**
+ * Handle ACK from client on local channel.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_handle_local_ack (struct CadetChannel *ch)
+{
+ ch->client_ready = GNUNET_YES;
+ send_client_buffered_data (ch);
+}
+
+
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-chn",__VA_ARGS__)
+
+
+/**
+ * Log channel info.
+ *
+ * @param ch Channel.
+ * @param level Debug level to use.
+ */
+void
+GCCH_debug (struct CadetChannel *ch,
+ enum GNUNET_ErrorType level)
+{
+ int do_log;
+
+ do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
+ "cadet-chn",
+ __FILE__, __FUNCTION__, __LINE__);
+ if (0 == do_log)
+ return;
+
+ if (NULL == ch)
+ {
+ LOG2 (level, "CHN *** DEBUG NULL CHANNEL ***\n");
+ return;
+ }
+ LOG2 (level,
+ "CHN Channel %s:%X (%p)\n",
+ GCT_2s (ch->t),
+ ch->gid,
+ ch);
+ if (NULL != ch->owner)
+ {
+ LOG2 (level,
+ "CHN origin %s ready %s local-id: %u\n",
+ GSC_2s (ch->owner),
+ ch->client_ready ? "YES" : "NO",
+ ntohl (ch->lid.channel_of_client));
+ }
+ if (NULL != ch->dest)
+ {
+ LOG2 (level,
+ "CHN destination %s ready %s local-id: %u\n",
+ GSC_2s (ch->dest),
+ ch->client_ready ? "YES" : "NO",
+ ntohl (ch->lid.channel_of_client));
+ }
+ LOG2 (level,
+ "CHN Message IDs recv: %d (%LLX), send: %d\n",
+ ntohl (ch->mid_recv.mid),
+ (unsigned long long) ch->mid_futures,
+ ntohl (ch->mid_send.mid));
+}
+
+
+
+/* end of gnunet-service-cadet-new_channel.c */
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_channel.h
+ * @brief GNUnet CADET service with encryption
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_CHANNEL_H
+#define GNUNET_SERVICE_CADET_CHANNEL_H
+
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_peer.h"
+
+
+/**
+ * A channel is a bidirectional connection between two CADET
+ * clients. Communiation can be reliable, unreliable, in-order
+ * or out-of-order. One client is the "local" client, this
+ * one initiated the connection. The other client is the
+ * "incoming" client, this one listened on a port to accept
+ * the connection from the "local" client.
+ */
+struct CadetChannel;
+
+
+/**
+ * Get the static string for identification of the channel.
+ *
+ * @param ch Channel.
+ *
+ * @return Static string with the channel IDs.
+ */
+const char *
+GCCH_2s (const struct CadetChannel *ch);
+
+
+/**
+ * Log channel info.
+ *
+ * @param ch Channel.
+ * @param level Debug level to use.
+ */
+void
+GCCH_debug (struct CadetChannel *ch,
+ enum GNUNET_ErrorType level);
+
+
+/**
+ * Get the channel's public ID.
+ *
+ * @param ch Channel.
+ *
+ * @return ID used to identify the channel with the remote peer.
+ */
+struct GCT_ChannelTunnelNumber
+GCCH_get_id (const struct CadetChannel *ch);
+
+
+/**
+ * Create a new channel.
+ *
+ * @param owner local client owning the channel
+ * @param owner_id local chid of this channel at the @a owner
+ * @param destination peer to which we should build the channel
+ * @param port desired port at @a destination
+ * @param options options for the channel
+ * @return handle to the new channel
+ */
+struct CadetChannel *
+GCCH_channel_local_new (struct CadetClient *owner,
+ struct GNUNET_CADET_ClientChannelNumber owner_id,
+ struct CadetPeer *destination,
+ const struct GNUNET_HashCode *port,
+ uint32_t options);
+
+
+/**
+ * A client is bound to the port that we have a channel
+ * open to. Send the acknowledgement for the connection
+ * request and establish the link with the client.
+ *
+ * @param ch open incoming channel
+ * @param c client listening on the respective port
+ */
+void
+GCCH_bind (struct CadetChannel *ch,
+ struct CadetClient *c);
+
+
+
+/**
+ * Destroy locally created channel. Called by the
+ * local client, so no need to tell the client.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_channel_local_destroy (struct CadetChannel *ch);
+
+
+/**
+ * Create a new channel.
+ *
+ * @param t tunnel to the remote peer
+ * @param gid identifier of this channel in the tunnel
+ * @param origin peer to who initiated the channel
+ * @param port desired local port
+ * @param options options for the channel
+ * @return handle to the new channel
+ */
+struct CadetChannel *
+GCCH_channel_incoming_new (struct CadetTunnel *t,
+ struct GCT_ChannelTunnelNumber gid,
+ const struct GNUNET_HashCode *port,
+ uint32_t options);
+
+
+/**
+ * Destroy channel that was incoming. Called by the
+ * local client, so no need to tell the client.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_channel_incoming_destroy (struct CadetChannel *ch);
+
+
+/**
+ * Handle data given by a client.
+ *
+ * Check whether the client is allowed to send in this tunnel, save if
+ * channel is reliable and send an ACK to the client if there is still
+ * buffer space in the tunnel.
+ *
+ * @param ch Channel.
+ * @param message payload to transmit.
+ * @return #GNUNET_OK if everything goes well,
+ * #GNUNET_SYSERR in case of an error.
+ */
+int
+GCCH_handle_local_data (struct CadetChannel *ch,
+ const struct GNUNET_MessageHeader *message);
+
+
+/**
+ * Handle ACK from client on local channel.
+ *
+ * @param ch channel to destroy
+ */
+void
+GCCH_handle_local_ack (struct CadetChannel *ch);
+
+#endif
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_connection.c
+ * @brief
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-cadet-new_connection.h"
+
+
+/**
+ * Obtain unique ID for the connection.
+ *
+ * @param cc connection.
+ * @return unique number of the connection
+ */
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc)
+{
+ GNUNET_assert (0); // FIXME
+ return NULL;
+}
+
+
+/**
+ * Log connection info.
+ *
+ * @param cc connection
+ * @param level Debug level to use.
+ */
+void
+GCC_debug (struct CadetConnection *cc,
+ enum GNUNET_ErrorType level)
+{
+}
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_connection.h
+ * @brief
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_CONNECTION_H
+#define GNUNET_SERVICE_CADET_CONNECTION_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_peer.h"
+
+
+
+/**
+ * Obtain unique ID for the connection.
+ *
+ * @param cc connection.
+ * @return unique number of the connection
+ */
+const struct GNUNET_CADET_ConnectionTunnelIdentifier *
+GCC_get_id (struct CadetConnection *cc);
+
+
+/**
+ * Log connection info.
+ *
+ * @param cc connection
+ * @param level Debug level to use.
+ */
+void
+GCC_debug (struct CadetConnection *cc,
+ enum GNUNET_ErrorType level);
+
+
+#endif
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2013, 2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+/**
+ * @file cadet/gnunet-service-cadet-new_dht.c
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_dht_service.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_dht.h"
+#include "gnunet-service-cadet-new_hello.h"
+#include "gnunet-service-cadet-new_peer.h"
+#include "gnunet-service-cadet-new_paths.h"
+
+#define LOG(level, ...) GNUNET_log_from (level,"cadet-dht",__VA_ARGS__)
+
+
+/**
+ * Handle for DHT searches.
+ */
+struct GCD_search_handle
+{
+ /**
+ * DHT_GET handle.
+ */
+ struct GNUNET_DHT_GetHandle *dhtget;
+
+ /**
+ * Provided callback to call when a path is found.
+ */
+ GCD_search_callback callback;
+
+ /**
+ * Provided closure.
+ */
+ void *cls;
+
+};
+
+
+/**
+ * Handle to use DHT.
+ */
+static struct GNUNET_DHT_Handle *dht_handle;
+
+/**
+ * How often to PUT own ID in the DHT.
+ */
+static struct GNUNET_TIME_Relative id_announce_time;
+
+/**
+ * DHT replication level, see DHT API: #GNUNET_DHT_get_start(), #GNUNET_DHT_put().
+ */
+static unsigned long long dht_replication_level;
+
+/**
+ * Task to periodically announce itself in the network.
+ */
+static struct GNUNET_SCHEDULER_Task *announce_id_task;
+
+/**
+ * Delay for the next ID announce.
+ */
+static struct GNUNET_TIME_Relative announce_delay;
+
+
+
+/**
+ * Function to process paths received for a new peer addition. The recorded
+ * paths form the initial tunnel, which can be optimized later.
+ * Called on each result obtained for the DHT search.
+ *
+ * @param cls closure
+ * @param exp when will this value expire
+ * @param key key of the result
+ * @param get_path path of the get request
+ * @param get_path_length lenght of @a get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the @a put_path
+ * @param type type of the result
+ * @param size number of bytes in data
+ * @param data pointer to the result data
+ */
+static void
+dht_get_id_handler (void *cls, struct GNUNET_TIME_Absolute exp,
+ const struct GNUNET_HashCode *key,
+ const struct GNUNET_PeerIdentity *get_path,
+ unsigned int get_path_length,
+ const struct GNUNET_PeerIdentity *put_path,
+ unsigned int put_path_length,
+ enum GNUNET_BLOCK_Type type,
+ size_t size,
+ const void *data)
+{
+ struct GCD_search_handle *h = cls;
+ const struct GNUNET_HELLO_Message *hello = data;
+ struct CadetPeerPath *p;
+ struct CadetPeer *peer;
+
+ p = GCPP_path_from_dht (get_path,
+ get_path_length,
+ put_path,
+ put_path_length);
+ h->callback (h->cls, p);
+ GCPP_path_destroy (p);
+
+ if ( (size >= sizeof (struct GNUNET_HELLO_Message)) &&
+ (ntohs (hello->header.size) == size) &&
+ (size == GNUNET_HELLO_size (hello)) )
+ {
+ peer = GCP_get (&put_path[0],
+ GNUNET_YES);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Got HELLO for %s\n",
+ GCP_2s (peer));
+ GCP_set_hello (peer,
+ hello);
+ }
+}
+
+
+/**
+ * Periodically announce self id in the DHT
+ *
+ * @param cls closure
+ */
+static void
+announce_id (void *cls)
+{
+ struct GNUNET_HashCode phash;
+ const struct GNUNET_HELLO_Message *hello;
+ size_t size;
+ struct GNUNET_TIME_Absolute expiration;
+ struct GNUNET_TIME_Relative next_put;
+
+ hello = GCH_get_mine ();
+ size = (NULL != hello) ? GNUNET_HELLO_size (hello) : 0;
+ if (0 == size)
+ {
+ expiration = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ announce_delay);
+ announce_delay = GNUNET_TIME_STD_BACKOFF (announce_delay);
+ }
+ else
+ {
+ expiration = GNUNET_HELLO_get_last_expiration (hello);
+ announce_delay = GNUNET_TIME_UNIT_SECONDS;
+ }
+
+ /* Call again in id_announce_time, unless HELLO expires first,
+ * but wait at least 1s. */
+ next_put
+ = GNUNET_TIME_absolute_get_remaining (expiration);
+ next_put
+ = GNUNET_TIME_relative_min (next_put,
+ id_announce_time);
+ next_put
+ = GNUNET_TIME_relative_max (next_put,
+ GNUNET_TIME_UNIT_SECONDS);
+ announce_id_task
+ = GNUNET_SCHEDULER_add_delayed (next_put,
+ &announce_id,
+ cls);
+ GNUNET_STATISTICS_update (stats,
+ "# DHT announce",
+ 1,
+ GNUNET_NO);
+ memset (&phash,
+ 0,
+ sizeof (phash));
+ GNUNET_memcpy (&phash,
+ &my_full_id,
+ sizeof (my_full_id));
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Announcing my HELLO (%u bytes) in the DHT\n",
+ size);
+ GNUNET_DHT_put (dht_handle, /* DHT handle */
+ &phash, /* Key to use */
+ dht_replication_level, /* Replication level */
+ GNUNET_DHT_RO_RECORD_ROUTE
+ | GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE, /* DHT options */
+ GNUNET_BLOCK_TYPE_DHT_HELLO, /* Block type */
+ size, /* Size of the data */
+ (const char *) hello, /* Data itself */
+ expiration, /* Data expiration */
+ NULL, /* Continuation */
+ NULL); /* Continuation closure */
+}
+
+
+/**
+ * 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);
+ GNUNET_break (NULL != dht_handle);
+ announce_delay = GNUNET_TIME_UNIT_SECONDS;
+ announce_id_task = GNUNET_SCHEDULER_add_now (&announce_id,
+ NULL);
+}
+
+
+/**
+ * Shut down the DHT subsystem.
+ */
+void
+GCD_shutdown (void)
+{
+ if (NULL != dht_handle)
+ {
+ GNUNET_DHT_disconnect (dht_handle);
+ dht_handle = NULL;
+ }
+ if (NULL != announce_id_task)
+ {
+ GNUNET_SCHEDULER_cancel (announce_id_task);
+ announce_id_task = NULL;
+ }
+}
+
+
+/**
+ * Search DHT for paths to @a peeR_id
+ *
+ * @param peer_id peer to search for
+ * @param callback function to call with results
+ * @param callback_cls closure for @a callback
+ * @return handle to abort search
+ */
+struct GCD_search_handle *
+GCD_search (const struct GNUNET_PeerIdentity *peer_id,
+ GCD_search_callback callback,
+ void *callback_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->callback = callback;
+ h->cls = callback_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);
+ return h;
+}
+
+
+/**
+ * Stop DHT search started with #GCD_search().
+ *
+ * @param h handle to search to stop
+ */
+void
+GCD_search_stop (struct GCD_search_handle *h)
+{
+ GNUNET_DHT_get_stop (h->dhtget);
+ GNUNET_free (h);
+}
+
+/* end of gnunet-service-cadet_dht.c */
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2013, 2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_dht.h
+ * @brief cadet service; dealing with DHT requests and results
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCD (Gnunet Cadet Dht)
+ */
+#ifndef GNUNET_SERVICE_CADET_DHT_H
+#define GNUNET_SERVICE_CADET_DHT_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+/**
+ * Handle for DHT search operation.
+ */
+struct GCD_search_handle;
+
+
+/**
+ * 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);
+
+
+/**
+ * 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);
+
+
+/**
+ * Search DHT for paths to @a peeR_id
+ *
+ * @param peer_id peer to search for
+ * @param callback function to call with results
+ * @param callback_cls closure for @a callback
+ * @return handle to abort search
+ */
+struct GCD_search_handle *
+GCD_search (const struct GNUNET_PeerIdentity *peer_id,
+ GCD_search_callback callback,
+ void *callback_cls);
+
+
+/**
+ * Stop DHT search started with #GCD_search().
+ *
+ * @param h handle to search to stop
+ */
+void
+GCD_search_stop (struct GCD_search_handle *h);
+
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_DHT_H */
+#endif
+/* end of gnunet-service-cadet_dht.h */
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2014, 2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_peerinfo_service.h"
+#include "cadet_protocol.h"
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_hello.h"
+#include "gnunet-service-cadet-new_peer.h"
+
+#define LOG(level, ...) GNUNET_log_from(level,"cadet-hll",__VA_ARGS__)
+
+/**
+ * Hello message of local peer.
+ */
+static struct GNUNET_HELLO_Message *mine;
+
+/**
+ * Handle to peerinfo service.
+ */
+static struct GNUNET_PEERINFO_Handle *peerinfo;
+
+/**
+ * Iterator context.
+ */
+static struct GNUNET_PEERINFO_NotifyContext* nc;
+
+
+/**
+ * Process each hello message received from peerinfo.
+ *
+ * @param cls Closure (unused).
+ * @param peer Identity of the peer.
+ * @param hello Hello of the peer.
+ * @param err_msg Error message.
+ */
+static void
+got_hello (void *cls,
+ const struct GNUNET_PeerIdentity *id,
+ const struct GNUNET_HELLO_Message *hello,
+ const char *err_msg)
+{
+ struct CadetPeer *peer;
+
+ if ( (NULL == id) ||
+ (NULL == hello) )
+ return;
+ if (0 == memcmp (id,
+ &my_full_id,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_free_non_null (mine);
+ mine = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (&hello->header);
+ return;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Hello for %s (%d bytes), expires on %s\n",
+ GNUNET_i2s (id),
+ GNUNET_HELLO_size (hello),
+ GNUNET_STRINGS_absolute_time_to_string (GNUNET_HELLO_get_last_expiration (hello)));
+ peer = GCP_get (id,
+ GNUNET_YES);
+ GCP_set_hello (peer,
+ hello);
+
+}
+
+
+/**
+ * Initialize the hello subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCH_init (const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ GNUNET_assert (NULL == nc);
+ peerinfo = GNUNET_PEERINFO_connect (c);
+ nc = GNUNET_PEERINFO_notify (c,
+ GNUNET_NO,
+ &got_hello,
+ NULL);
+}
+
+
+/**
+ * Shut down the hello subsystem.
+ */
+void
+GCH_shutdown ()
+{
+ if (NULL != nc)
+ {
+ GNUNET_PEERINFO_notify_cancel (nc);
+ nc = NULL;
+ }
+ if (NULL != peerinfo)
+ {
+ GNUNET_PEERINFO_disconnect (peerinfo);
+ peerinfo = NULL;
+ }
+ if (NULL != mine)
+ {
+ GNUNET_free (mine);
+ mine = NULL;
+ }
+}
+
+
+/**
+ * Get own hello message.
+ *
+ * @return Own hello message.
+ */
+const struct GNUNET_HELLO_Message *
+GCH_get_mine (void)
+{
+ return mine;
+}
+
+/* end of gnunet-service-cadet-new_hello.c */
--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2014, 2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet_hello.h
+ * @brief cadet service; dealing with hello messages
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ *
+ * All functions in this file should use the prefix GCH (Gnunet Cadet Hello)
+ */
+
+#ifndef GNUNET_SERVICE_CADET_HELLO_H
+#define GNUNET_SERVICE_CADET_HELLO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+
+
+/**
+ * Initialize the hello subsystem.
+ *
+ * @param c Configuration.
+ */
+void
+GCH_init (const struct GNUNET_CONFIGURATION_Handle *c);
+
+
+/**
+ * Shut down the hello subsystem.
+ */
+void
+GCH_shutdown (void);
+
+
+/**
+ * Get own hello message.
+ *
+ * @return Own hello message.
+ */
+const struct GNUNET_HELLO_Message *
+GCH_get_mine (void);
+
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+/* ifndef GNUNET_CADET_SERVICE_HELLO_H */
+#endif
+/* end of gnunet-cadet-service_hello.h */
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_paths.c
+ * @brief Information we track per path.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-cadet-new_paths.h"
+
+/**
+ * Create a peer path based on the result of a DHT lookup.
+ *
+ * @param get_path path of the get request
+ * @param get_path_length lenght of @a get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the @a put_path
+ * @return a path through the network
+ */
+struct CadetPeerPath *
+GCPP_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
+ unsigned int get_path_length,
+ const struct GNUNET_PeerIdentity *put_path,
+ unsigned int put_path_length)
+{
+ GNUNET_break (0);
+ return NULL;
+}
+
+
+/**
+ * Destroy a path, we no longer need it.
+ *
+ * @param p path to destroy.
+ */
+void
+GCPP_path_destroy (struct CadetPeerPath *p)
+{
+ GNUNET_assert (0);
+}
+
+
+/**
+ * Return the length of the path. Excludes one end of the
+ * path, so the loopback path has length 0.
+ *
+ * @param path path to return the length for
+ * @return number of peers on the path
+ */
+unsigned int
+GCPP_get_length (struct CadetPeerPath *path)
+{
+ GNUNET_assert (0);
+ return -1;
+}
+
+
+/**
+ * Obtain the identity of the peer at offset @a off in @a path.
+ *
+ * @param path peer path to inspect
+ * @param off offset to return, must be smaller than path length
+ * @param[out] pid where to write the pid, must not be NULL
+ */
+void
+GCPP_get_pid_at_offset (struct CadetPeerPath *path,
+ unsigned int off,
+ struct GNUNET_PeerIdentity *pid)
+{
+ GNUNET_assert (0);
+}
+
+
+/* end of gnunet-service-cadet-new_paths.c */
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_paths.h
+ * @brief Information we track per path.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_PATHS_H
+#define GNUNET_SERVICE_CADET_PATHS_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet-service-cadet-new.h"
+
+/**
+ * Create a peer path based on the result of a DHT lookup.
+ *
+ * @param get_path path of the get request
+ * @param get_path_length lenght of @a get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the @a put_path
+ * @return a path through the network
+ */
+struct CadetPeerPath *
+GCPP_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
+ unsigned int get_path_length,
+ const struct GNUNET_PeerIdentity *put_path,
+ unsigned int put_path_length);
+
+
+/**
+ * Destroy a path, we no longer need it.
+ *
+ * @param p path to destroy.
+ */
+void
+GCPP_path_destroy (struct CadetPeerPath *p);
+
+
+/**
+ * Return the length of the path. Excludes one end of the
+ * path, so the loopback path has length 0.
+ *
+ * @param path path to return the length for
+ * @return number of peers on the path
+ */
+unsigned int
+GCPP_get_length (struct CadetPeerPath *path);
+
+
+/**
+ * Obtain the identity of the peer at offset @a off in @a path.
+ *
+ * @param path peer path to inspect
+ * @param off offset to return, must be smaller than path length
+ * @param[out] pid where to write the pid, must not be NULL
+ */
+void
+GCPP_get_pid_at_offset (struct CadetPeerPath *path,
+ unsigned int off,
+ struct GNUNET_PeerIdentity *pid);
+
+
+#endif
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_peer.c
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#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 "cadet_path.h"
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_dht.h"
+#include "gnunet-service-cadet-new_peer.h"
+#include "gnunet-service-cadet-new_tunnels.h"
+
+/**
+ * How long do we wait until tearing down an idle peer?
+ */
+#define IDLE_PEER_TIMEOUT GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 5)
+
+
+/**
+ * Struct containing all information regarding a given peer
+ */
+struct CadetPeer
+{
+ /**
+ * ID of the peer
+ */
+ struct GNUNET_PeerIdentity pid;
+
+ /**
+ * Last time we heard from this peer
+ */
+ 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;
+
+ /**
+ * Task to stop the DHT search for paths to this peer
+ */
+ struct GNUNET_SCHEDULER_Task *search_delayed;
+
+ /**
+ * Task to destroy this entry.
+ */
+ struct GNUNET_SCHEDULER_Task *destroy_task;
+
+ /**
+ * Tunnel to this peer, if any.
+ */
+ struct CadetTunnel *t;
+
+ /**
+ * Connections that go through this peer; indexed by tid.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *connections;
+
+ /**
+ * Handle for core transmissions.
+ */
+ struct GNUNET_MQ_Handle *core_mq;
+
+ /**
+ * Hello message of the peer.
+ */
+ struct GNUNET_HELLO_Message *hello;
+
+ /**
+ * Handle to us offering the HELLO to the transport.
+ */
+ struct GNUNET_TRANSPORT_OfferHelloHandle *hello_offer;
+
+ /**
+ * Handle to our ATS request asking ATS to suggest an address
+ * to TRANSPORT for this peer (to establish a direct link).
+ */
+ struct GNUNET_ATS_ConnectivitySuggestHandle *connectivity_suggestion;
+
+ /**
+ * How many messages are in the queue to this peer.
+ */
+ unsigned int queue_n;
+
+ /**
+ * How many paths do we have to this peer (in the @e path_head DLL).
+ */
+ unsigned int num_paths;
+
+};
+
+
+/**
+ * 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 "PEER(NULL)";
+ return GNUNET_i2s (&peer->pid);
+}
+
+
+/**
+ * This peer is no longer be needed, clean it up now.
+ *
+ * @param cls peer to clean up
+ */
+static void
+destroy_peer (void *cls)
+{
+ struct CadetPeer *cp = cls;
+
+ cp->destroy_task = NULL;
+ GNUNET_assert (NULL == cp->t);
+ GNUNET_assert (NULL == cp->core_mq);
+ GNUNET_assert (0 == GNUNET_CONTAINER_multihashmap_size (cp->connections));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_remove (peers,
+ &cp->pid,
+ cp));
+ /* FIXME: clean up paths! */
+ /* FIXME: clean up search_h! */
+ /* FIXME: clean up search_delayed! */
+
+ GNUNET_CONTAINER_multihashmap_destroy (cp->connections);
+ GNUNET_free_non_null (cp->hello);
+ if (NULL != cp->hello_offer)
+ {
+ GNUNET_TRANSPORT_offer_hello_cancel (cp->hello_offer);
+ cp->hello_offer = NULL;
+ }
+ if (NULL != cp->connectivity_suggestion)
+ {
+ GNUNET_ATS_connectivity_suggest_cancel (cp->connectivity_suggestion);
+ cp->connectivity_suggestion = NULL;
+ }
+ GNUNET_free (cp);
+}
+
+
+/**
+ * Function called to destroy a peer now.
+ *
+ * @param cls NULL
+ * @param pid identity of the peer (unused)
+ * @param value the `struct CadetPeer` to clean up
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static int
+destroy_iterator_cb (void *cls,
+ const struct GNUNET_PeerIdentity *pid,
+ void *value)
+{
+ struct CadetPeer *cp = value;
+
+ if (NULL != cp->destroy_task)
+ GNUNET_SCHEDULER_cancel (cp->destroy_task);
+ destroy_peer (cp);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Clean up all entries about all peers.
+ * Must only be called after all tunnels, CORE-connections and
+ * connections are down.
+ */
+void
+GCP_destroy_all_peers ()
+{
+ GNUNET_CONTAINER_multipeermap_iterate (peers,
+ &destroy_iterator_cb,
+ NULL);
+}
+
+
+/**
+ * This peer may no longer be needed, consider cleaning it up.
+ *
+ * @param peer peer to clean up
+ */
+static void
+consider_peer_destroy (struct CadetPeer *peer)
+{
+ struct GNUNET_TIME_Relative exp;
+
+ if (NULL != peer->destroy_task)
+ {
+ GNUNET_SCHEDULER_cancel (peer->destroy_task);
+ peer->destroy_task = NULL;
+ }
+ if (NULL != peer->t)
+ return; /* still relevant! */
+ if (NULL != peer->core_mq)
+ return; /* still relevant! */
+ if (0 != GNUNET_CONTAINER_multihashmap_size (peer->connections))
+ return; /* still relevant! */
+ if (NULL != peer->hello)
+ {
+ /* relevant only until HELLO expires */
+ exp = GNUNET_TIME_absolute_get_remaining (GNUNET_HELLO_get_last_expiration (peer->hello));
+ peer->destroy_task = GNUNET_SCHEDULER_add_delayed (exp,
+ &destroy_peer,
+ peer);
+ return;
+ }
+ peer->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_PEER_TIMEOUT,
+ &destroy_peer,
+ peer);
+}
+
+
+/**
+ * Function called when the DHT finds a @a path to the peer (@a cls).
+ *
+ * @param cls the `struct CadetPeer`
+ * @param path the path that was found
+ */
+static void
+dht_result_cb (void *cls,
+ const struct CadetPeerPath *path)
+{
+ struct CadetPeer *peer = cls;
+
+ // FIXME: handle path!
+}
+
+
+/**
+ * This peer is now on more "active" duty, activate processes related to it.
+ *
+ * @param peer the more-active peer
+ */
+static void
+consider_peer_activate (struct CadetPeer *peer)
+{
+ uint32_t strength;
+
+ if (NULL != peer->destroy_task)
+ {
+ /* It's active, do not destory! */
+ GNUNET_SCHEDULER_cancel (peer->destroy_task);
+ peer->destroy_task = NULL;
+ }
+ if (NULL == peer->core_mq)
+ {
+ /* Lacks direct connection, try to create one by querying the DHT */
+ if ( (NULL == peer->search_h) &&
+ (DESIRED_CONNECTIONS_PER_TUNNEL < peer->num_paths) )
+ peer->search_h
+ = GCD_search (&peer->pid,
+ &dht_result_cb,
+ peer);
+ }
+ else
+ {
+ /* Have direct connection, stop DHT search if active */
+ if (NULL != peer->search_h)
+ {
+ GCD_search_stop (peer->search_h);
+ peer->search_h = NULL;
+ }
+ }
+
+ /* If we have a tunnel, our urge for connections is much bigger */
+ strength = (NULL != peer->t) ? 32 : 1;
+ if (NULL != peer->connectivity_suggestion)
+ GNUNET_ATS_connectivity_suggest_cancel (peer->connectivity_suggestion);
+ peer->connectivity_suggestion
+ = GNUNET_ATS_connectivity_suggest (ats_ch,
+ &peer->pid,
+ strength);
+}
+
+
+/**
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
+ *
+ * @param peer_id Full identity of the peer.
+ * @param create #GNUNET_YES if a new peer should be created if unknown.
+ * #GNUNET_NO to return NULL if peer is unknown.
+ * @return Existing or newly created peer structure.
+ * NULL if unknown and not requested @a create
+ */
+struct CadetPeer *
+GCP_get (const struct GNUNET_PeerIdentity *peer_id,
+ int create)
+{
+ struct CadetPeer *cp;
+
+ cp = GNUNET_CONTAINER_multipeermap_get (peers,
+ peer_id);
+ if (NULL != cp)
+ return cp;
+ if (GNUNET_NO == create)
+ return NULL;
+ cp = GNUNET_new (struct CadetPeer);
+ cp->pid = *peer_id;
+ cp->connections = GNUNET_CONTAINER_multihashmap_create (32,
+ GNUNET_YES);
+ cp->search_h = NULL; // FIXME: start search immediately!?
+ cp->connectivity_suggestion = NULL; // FIXME: request with ATS!?
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multipeermap_put (peers,
+ &cp->pid,
+ cp,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ return cp;
+}
+
+
+/**
+ * Obtain the peer identity for a `struct CadetPeer`.
+ *
+ * @param cp our peer handle
+ * @param[out] peer_id where to write the peer identity
+ */
+void
+GCP_id (struct CadetPeer *cp,
+ struct GNUNET_PeerIdentity *peer_id)
+{
+ *peer_id = cp->pid;
+}
+
+
+/**
+ * Create a peer path based on the result of a DHT lookup.
+ *
+ * @param get_path path of the get request
+ * @param get_path_length lenght of @a get_path
+ * @param put_path path of the put request
+ * @param put_path_length length of the @a put_path
+ * @return a path through the network
+ */
+struct CadetPeerPath *
+GCP_path_from_dht (const struct GNUNET_PeerIdentity *get_path,
+ unsigned int get_path_length,
+ const struct GNUNET_PeerIdentity *put_path,
+ unsigned int put_path_length)
+{
+ GNUNET_assert (0); // FIXME: implement!
+ return NULL;
+}
+
+
+/**
+ * Iterate over all known peers.
+ *
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+ void *cls)
+{
+ GNUNET_CONTAINER_multipeermap_iterate (peers,
+ iter,
+ cls);
+}
+
+
+/**
+ * Count the number of known paths toward the peer.
+ *
+ * @param peer Peer to get path info.
+ * @return Number of known paths.
+ */
+unsigned int
+GCP_count_paths (const struct CadetPeer *peer)
+{
+ return peer->num_paths;
+}
+
+
+/**
+ * Iterate over the paths to a peer.
+ *
+ * @param peer Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
+ */
+unsigned int
+GCP_iterate_paths (struct CadetPeer *peer,
+ GCP_PathIterator callback,
+ void *callback_cls)
+{
+ unsigned int ret = 0;
+
+ for (struct CadetPeerPath *path = peer->path_head;
+ NULL != path;
+ path = path->next)
+ {
+ if (GNUNET_NO ==
+ callback (callback_cls,
+ peer,
+ path))
+ return ret;
+ ret++;
+ }
+ return ret;
+}
+
+
+/**
+ * Get the tunnel towards a peer.
+ *
+ * @param peer Peer to get from.
+ * @param create #GNUNET_YES to create a tunnel if we do not have one
+ * @return Tunnel towards peer.
+ */
+struct CadetTunnel *
+GCP_get_tunnel (struct CadetPeer *peer,
+ int create)
+{
+ if (NULL == peer)
+ return NULL;
+ if ( (NULL != peer->t) ||
+ (GNUNET_NO == create) )
+ return peer->t;
+ peer->t = GCT_create_tunnel (peer);
+ consider_peer_activate (peer);
+ return peer->t;
+}
+
+
+/**
+ * We got a HELLO for a @a peer, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
+ *
+ * @param peer the peer we got a HELLO for
+ * @param hello the HELLO to remember
+ */
+void
+GCP_set_hello (struct CadetPeer *peer,
+ const struct GNUNET_HELLO_Message *hello)
+{
+ /* FIXME! */
+
+ consider_peer_destroy (peer);
+}
+
+
+/**
+ * The tunnel to the given peer no longer exists, remove it from our
+ * data structures, and possibly clean up the peer itself.
+ *
+ * @param peer the peer affected
+ * @param t the dead tunnel
+ */
+void
+GCP_drop_tunnel (struct CadetPeer *peer,
+ struct CadetTunnel *t)
+{
+ GNUNET_assert (peer->t == t);
+ peer->t = NULL;
+ consider_peer_destroy (peer);
+}
+
+
+/* end of gnunet-service-cadet-new_peer.c */
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_peer.h
+ * @brief Information we track per peer.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_PEER_H
+#define GNUNET_SERVICE_CADET_PEER_H
+
+#include "gnunet-service-cadet-new.h"
+#include "gnunet_hello_lib.h"
+
+
+/**
+ * Get the static string for a peer ID.
+ *
+ * @param peer Peer.
+ *
+ * @return Static string for it's ID.
+ */
+const char *
+GCP_2s (const struct CadetPeer *peer);
+
+
+/**
+ * Retrieve the CadetPeer stucture associated with the
+ * peer. Optionally create one and insert it in the appropriate
+ * structures if the peer is not known yet.
+ *
+ * @param peer_id Full identity of the peer.
+ * @param create #GNUNET_YES if a new peer should be created if unknown.
+ * #GNUNET_NO to return NULL if peer is unknown.
+ * @return Existing or newly created peer structure.
+ * NULL if unknown and not requested @a create
+ */
+struct CadetPeer *
+GCP_get (const struct GNUNET_PeerIdentity *peer_id,
+ int create);
+
+
+/**
+ * Obtain the peer identity for a `struct CadetPeer`.
+ *
+ * @param cp our peer handle
+ * @param[out] peer_id where to write the peer identity
+ */
+void
+GCP_id (struct CadetPeer *cp,
+ struct GNUNET_PeerIdentity *peer_id);
+
+
+/**
+ * Iterate over all known peers.
+ *
+ * @param iter Iterator.
+ * @param cls Closure for @c iter.
+ */
+void
+GCP_iterate_all (GNUNET_CONTAINER_PeerMapIterator iter,
+ void *cls);
+
+
+/**
+ * Count the number of known paths toward the peer.
+ *
+ * @param peer Peer to get path info.
+ * @return Number of known paths.
+ */
+unsigned int
+GCP_count_paths (const struct CadetPeer *peer);
+
+
+/**
+ * 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.
+ *
+ * FIXME: path argument should be redundant; remove!
+ */
+typedef int
+(*GCP_PathIterator) (void *cls,
+ struct CadetPeer *peer,
+ struct CadetPeerPath *path);
+
+
+/**
+ * Iterate over the paths to a peer.
+ *
+ * @param peer Peer to get path info.
+ * @param callback Function to call for every path.
+ * @param callback_cls Closure for @a callback.
+ * @return Number of iterated paths.
+ */
+unsigned int
+GCP_iterate_paths (struct CadetPeer *peer,
+ GCP_PathIterator callback,
+ void *callback_cls);
+
+
+/**
+ * Get the tunnel towards a peer.
+ *
+ * @param peer Peer to get from.
+ * @param create #GNUNET_YES to create a tunnel if we do not have one
+ * @return Tunnel towards peer.
+ */
+struct CadetTunnel *
+GCP_get_tunnel (struct CadetPeer *peer,
+ int create);
+
+
+/**
+ * The tunnel to the given peer no longer exists, remove it from our
+ * data structures, and possibly clean up the peer itself.
+ *
+ * @param peer the peer affected
+ * @param t the dead tunnel
+ */
+void
+GCP_drop_tunnel (struct CadetPeer *peer,
+ struct CadetTunnel *t);
+
+
+/**
+ * We got a HELLO for a @a peer, remember it, and possibly
+ * trigger adequate actions (like trying to connect).
+ *
+ * @param peer the peer we got a HELLO for
+ * @param hello the HELLO to remember
+ */
+void
+GCP_set_hello (struct CadetPeer *peer,
+ const struct GNUNET_HELLO_Message *hello);
+
+
+/**
+ * Clean up all entries about all peers.
+ * Must only be called after all tunnels, CORE-connections and
+ * connections are down.
+ */
+void
+GCP_destroy_all_peers (void);
+
+
+#endif
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2013, 2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_tunnels.c
+ * @brief Information we track per tunnel.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_signatures.h"
+#include "cadet_protocol.h"
+#include "cadet_path.h"
+#include "gnunet-service-cadet-new.h"
+#include "gnunet-service-cadet-new_channel.h"
+#include "gnunet-service-cadet-new_connection.h"
+#include "gnunet-service-cadet-new_tunnels.h"
+#include "gnunet-service-cadet-new_peer.h"
+
+
+/**
+ * How long do we wait until tearing down an idle tunnel?
+ */
+#define IDLE_DESTROY_DELAY GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 90)
+
+
+/**
+ * Struct to old keys for skipped messages while advancing the Axolotl ratchet.
+ */
+struct CadetTunnelSkippedKey
+{
+ /**
+ * DLL next.
+ */
+ struct CadetTunnelSkippedKey *next;
+
+ /**
+ * DLL prev.
+ */
+ struct CadetTunnelSkippedKey *prev;
+
+ /**
+ * When was this key stored (for timeout).
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /**
+ * Header key.
+ */
+ struct GNUNET_CRYPTO_SymmetricSessionKey HK;
+
+ /**
+ * Message key.
+ */
+ struct GNUNET_CRYPTO_SymmetricSessionKey MK;
+
+ /**
+ * Key number for a given HK.
+ */
+ unsigned int Kn;
+};
+
+
+/**
+ * Axolotl data, according to https://github.com/trevp/axolotl/wiki .
+ */
+struct CadetTunnelAxolotl
+{
+ /**
+ * A (double linked) list of stored message keys and associated header keys
+ * for "skipped" messages, i.e. messages that have not been
+ * received despite the reception of more recent messages, (head).
+ */
+ struct CadetTunnelSkippedKey *skipped_head;
+
+ /**
+ * Skipped messages' keys DLL, tail.
+ */
+ struct CadetTunnelSkippedKey *skipped_tail;
+
+ /**
+ * 32-byte root key which gets updated by DH ratchet.
+ */
+ struct GNUNET_CRYPTO_SymmetricSessionKey RK;
+
+ /**
+ * 32-byte header key (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;
+
+ /**
+ * When does this ratchet expire and a new one is triggered.
+ */
+ struct GNUNET_TIME_Absolute ratchet_expiration;
+
+ /**
+ * Number of elements in @a skipped_head <-> @a skipped_tail.
+ */
+ unsigned int skipped;
+
+ /**
+ * Message number (reset to 0 with each new ratchet, next message to send).
+ */
+ uint32_t Ns;
+
+ /**
+ * Message number (reset to 0 with each new ratchet, next message to recv).
+ */
+ uint32_t Nr;
+
+ /**
+ * Previous message numbers (# of msgs sent under prev ratchet)
+ */
+ uint32_t PNs;
+
+ /**
+ * True (#GNUNET_YES) if we have to send a new ratchet key in next msg.
+ */
+ int ratchet_flag;
+
+ /**
+ * 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;
+
+};
+
+
+/**
+ * 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 used to save messages in a non-ready tunnel to send once connected.
+ */
+struct CadetTunnelQueueEntry
+{
+ /**
+ * We are entries in a DLL
+ */
+ struct CadetTunnelQueueEntry *next;
+
+ /**
+ * We are entries in a DLL
+ */
+ struct CadetTunnelQueueEntry *prev;
+
+ /**
+ * Tunnel these messages belong in.
+ */
+ struct CadetTunnel *t;
+
+ /**
+ * Continuation to call once sent (on the channel layer).
+ */
+ GNUNET_SCHEDULER_TaskCallback cont;
+
+ /**
+ * Closure for @c cont.
+ */
+ void *cont_cls;
+
+ /**
+ * (Encrypted) message to send follows.
+ */
+ /* struct GNUNET_MessageHeader *msg; */
+};
+
+
+/**
+ * Struct containing all information regarding a tunnel to a peer.
+ */
+struct CadetTunnel
+{
+ /**
+ * Endpoint of the tunnel.
+ */
+ struct CadetPeer *peer;
+
+ /**
+ * Peer's ephemeral key, to recreate @c e_key and @c d_key when own
+ * ephemeral key changes.
+ */
+ struct GNUNET_CRYPTO_EcdhePublicKey peers_ephemeral_key;
+
+ /**
+ * Encryption ("our") key. It is only "confirmed" if kx_ctx is NULL.
+ */
+ struct GNUNET_CRYPTO_SymmetricSessionKey e_key;
+
+ /**
+ * Decryption ("their") key. It is only "confirmed" if kx_ctx is NULL.
+ */
+ struct GNUNET_CRYPTO_SymmetricSessionKey d_key;
+
+ /**
+ * Axolotl info.
+ */
+ struct CadetTunnelAxolotl ax;
+
+ /**
+ * State of the tunnel connectivity.
+ */
+ enum CadetTunnelCState cstate;
+
+ /**
+ * State of the tunnel encryption.
+ */
+ enum CadetTunnelEState estate;
+
+ /**
+ * Task to start the rekey process.
+ */
+ struct GNUNET_SCHEDULER_Task *rekey_task;
+
+ /**
+ * DLL of connections that are actively used to reach the destination peer.
+ */
+ struct CadetTConnection *connection_head;
+
+ /**
+ * DLL of connections that are actively used to reach the destination peer.
+ */
+ struct CadetTConnection *connection_tail;
+
+ /**
+ * Channels inside this tunnel. Maps
+ * `struct GCT_ChannelTunnelNumber` to a `struct CadetChannel`.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap32 *channels;
+
+ /**
+ * Channel ID for the next created channel in this tunnel.
+ */
+ struct GCT_ChannelTunnelNumber next_chid;
+
+ /**
+ * Queued messages, to transmit once tunnel gets connected.
+ */
+ struct CadetTunnelQueueEntry *tq_head;
+
+ /**
+ * Queued messages, to transmit once tunnel gets connected.
+ */
+ struct CadetTunnelQueueEntry *tq_tail;
+
+ /**
+ * Task scheduled if there are no more channels using the tunnel.
+ */
+ struct GNUNET_SCHEDULER_Task *destroy_task;
+
+ /**
+ * Task to trim connections if too many are present.
+ */
+ struct GNUNET_SCHEDULER_Task *trim_connections_task;
+
+ /**
+ * Ephemeral message in the queue (to avoid queueing more than one).
+ */
+ struct CadetConnectionQueue *ephm_hKILL;
+
+ /**
+ * Pong message in the queue.
+ */
+ struct CadetConnectionQueue *pong_hKILL;
+
+ /**
+ * Number of connections in the @e connection_head DLL.
+ */
+ unsigned int num_connections;
+
+ /**
+ * Number of entries in the @e tq_head DLL.
+ */
+ unsigned int tq_len;
+};
+
+
+/**
+ * Get the static string for the peer this tunnel is directed.
+ *
+ * @param t Tunnel.
+ *
+ * @return Static string the destination peer's ID.
+ */
+const char *
+GCT_2s (const struct CadetTunnel *t)
+{
+ static char buf[64];
+
+ if (NULL == t)
+ return "T(NULL)";
+
+ GNUNET_snprintf (buf,
+ sizeof (buf),
+ "T(%s)",
+ GCP_2s (t->peer));
+ return buf;
+}
+
+
+/**
+ * Return the peer to which this tunnel goes.
+ *
+ * @param t a tunnel
+ * @return the destination of the tunnel
+ */
+struct CadetPeer *
+GCT_get_destination (struct CadetTunnel *t)
+{
+ return t->peer;
+}
+
+
+/**
+ * Count channels of a tunnel.
+ *
+ * @param t Tunnel on which to count.
+ *
+ * @return Number of channels.
+ */
+unsigned int
+GCT_count_channels (struct CadetTunnel *t)
+{
+ return GNUNET_CONTAINER_multihashmap32_size (t->channels);
+}
+
+
+/**
+ * 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)
+{
+ return t->num_connections;
+}
+
+
+/**
+ * Get the connectivity state of a tunnel.
+ *
+ * @param t Tunnel.
+ *
+ * @return Tunnel's connectivity state.
+ */
+enum CadetTunnelCState
+GCT_get_cstate (struct CadetTunnel *t)
+{
+ 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)
+{
+ return t->estate;
+}
+
+
+/**
+ * Add a channel to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @return unique number identifying @a ch within @a t
+ */
+struct GCT_ChannelTunnelNumber
+GCT_add_channel (struct CadetTunnel *t,
+ struct CadetChannel *ch)
+{
+ struct GCT_ChannelTunnelNumber ret;
+ uint32_t chid;
+
+ chid = ntohl (t->next_chid.channel_in_tunnel);
+ while (NULL !=
+ GNUNET_CONTAINER_multihashmap32_get (t->channels,
+ chid))
+ chid++;
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_put (t->channels,
+ chid,
+ ch,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ t->next_chid.channel_in_tunnel = htonl (chid + 1);
+ ret.channel_in_tunnel = htonl (chid);
+ return ret;
+}
+
+
+/**
+ * This tunnel is no longer used, destroy it.
+ *
+ * @param cls the idle tunnel
+ */
+static void
+destroy_tunnel (void *cls)
+{
+ struct CadetTunnel *t = cls;
+
+ t->destroy_task = NULL;
+
+ // FIXME: implement!
+ GCP_drop_tunnel (t->peer,
+ t);
+ GNUNET_free (t);
+}
+
+
+/**
+ * Create a tunnel to @a destionation. Must only be called
+ * from within #GCP_get_tunnel().
+ *
+ * @param destination where to create the tunnel to
+ * @return new tunnel to @a destination
+ */
+struct CadetTunnel *
+GCT_create_tunnel (struct CadetPeer *destination)
+{
+ struct CadetTunnel *t;
+
+ t = GNUNET_new (struct CadetTunnel);
+ t->peer = destination;
+ t->channels = GNUNET_CONTAINER_multihashmap32_create (8);
+
+ return t;
+}
+
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @param gid unique number identifying @a ch within @a t
+ */
+void
+GCT_remove_channel (struct CadetTunnel *t,
+ struct CadetChannel *ch,
+ struct GCT_ChannelTunnelNumber gid)
+{
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (t->channels,
+ ntohl (gid.channel_in_tunnel),
+ ch));
+ if (0 ==
+ GNUNET_CONTAINER_multihashmap32_size (t->channels))
+ {
+ t->destroy_task = GNUNET_SCHEDULER_add_delayed (IDLE_DESTROY_DELAY,
+ &destroy_tunnel,
+ t);
+ }
+}
+
+
+/**
+ * Sends an already built message on a tunnel, encrypting it and
+ * choosing the best connection if not provided.
+ *
+ * @param message Message to send. Function modifies it.
+ * @param t Tunnel on which this message is transmitted.
+ * @param cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ * @return Handle to cancel message. NULL if @c cont is NULL.
+ */
+struct CadetTunnelQueueEntry *
+GCT_send (struct CadetTunnel *t,
+ const struct GNUNET_MessageHeader *message,
+ GNUNET_SCHEDULER_TaskCallback cont,
+ void *cont_cls)
+{
+ struct CadetTunnelQueueEntry *q;
+ uint16_t payload_size;
+
+ payload_size = ntohs (message->size);
+
+ q = GNUNET_malloc (sizeof (*q) +
+ payload_size);
+ /* FIXME: encrypt 'message' to end of 'q' */
+ q->t = t;
+ q->cont = cont;
+ q->cont_cls = cont_cls;
+ GNUNET_CONTAINER_DLL_insert_tail (t->tq_head,
+ t->tq_tail,
+ q);
+ /* FIXME: initiate transmission process! */
+ 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 entry to cancel.
+ */
+void
+GCT_send_cancel (struct CadetTunnelQueueEntry *q)
+{
+ struct CadetTunnel *t = q->t;
+
+ GNUNET_CONTAINER_DLL_remove (t->tq_head,
+ t->tq_tail,
+ q);
+ GNUNET_free (q);
+}
+
+
+/**
+ * Iterate over all connections of a tunnel.
+ *
+ * @param t Tunnel whose connections to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_connections (struct CadetTunnel *t,
+ GCT_ConnectionIterator iter,
+ void *iter_cls)
+{
+ for (struct CadetTConnection *ct = t->connection_head;
+ NULL != ct;
+ ct = ct->next)
+ iter (iter_cls,
+ ct->c);
+}
+
+
+/**
+ * Closure for #iterate_channels_cb.
+ */
+struct ChanIterCls
+{
+ /**
+ * Function to call.
+ */
+ GCT_ChannelIterator iter;
+
+ /**
+ * Closure for @e iter.
+ */
+ void *iter_cls;
+};
+
+
+/**
+ * Helper function for #GCT_iterate_channels.
+ *
+ * @param cls the `struct ChanIterCls`
+ * @param key unused
+ * @param value a `struct CadetChannel`
+ * @return #GNUNET_OK
+ */
+static int
+iterate_channels_cb (void *cls,
+ uint32_t key,
+ void *value)
+{
+ struct ChanIterCls *ctx = cls;
+ struct CadetChannel *ch = value;
+
+ ctx->iter (ctx->iter_cls,
+ ch);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Iterate over all channels of a tunnel.
+ *
+ * @param t Tunnel whose channels to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_channels (struct CadetTunnel *t,
+ GCT_ChannelIterator iter,
+ void *iter_cls)
+{
+ struct ChanIterCls ctx;
+
+ ctx.iter = iter;
+ ctx.iter_cls = iter_cls;
+ GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+ &iterate_channels_cb,
+ &ctx);
+
+}
+
+
+/**
+ * Call #GCCH_debug() on a channel.
+ *
+ * @param cls points to the log level to use
+ * @param key unused
+ * @param value the `struct CadetChannel` to dump
+ * @return #GNUNET_OK (continue iteration)
+ */
+static int
+debug_channel (void *cls,
+ uint32_t key,
+ void *value)
+{
+ const enum GNUNET_ErrorType *level = cls;
+ struct CadetChannel *ch = value;
+
+ GCCH_debug (ch, *level);
+ return GNUNET_OK;
+}
+
+
+/**
+ * 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;
+ }
+}
+
+
+/**
+ * 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_SENT:
+ return "CADET_TUNNEL_KEY_SENT";
+ case CADET_TUNNEL_KEY_PING:
+ return "CADET_TUNNEL_KEY_PING";
+ 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;
+ }
+}
+
+
+#define LOG2(level, ...) GNUNET_log_from_nocheck(level,"cadet-tun",__VA_ARGS__)
+
+
+/**
+ * Log all possible info about the tunnel state.
+ *
+ * @param t Tunnel to debug.
+ * @param level Debug level to use.
+ */
+void
+GCT_debug (const struct CadetTunnel *t,
+ enum GNUNET_ErrorType level)
+{
+ struct CadetTConnection *iter_c;
+ int do_log;
+
+ do_log = GNUNET_get_log_call_status (level & (~GNUNET_ERROR_TYPE_BULK),
+ "cadet-tun",
+ __FILE__, __FUNCTION__, __LINE__);
+ if (0 == do_log)
+ return;
+
+ LOG2 (level,
+ "TTT TUNNEL TOWARDS %s in cstate %s, estate %s tq_len: %u #cons: %u\n",
+ GCT_2s (t),
+ cstate2s (t->cstate),
+ estate2s (t->estate),
+ t->tq_len,
+ t->num_connections);
+#if DUMP_KEYS_TO_STDERR
+ ax_debug (t->ax, level);
+#endif
+ LOG2 (level,
+ "TTT channels:\n");
+ GNUNET_CONTAINER_multihashmap32_iterate (t->channels,
+ &debug_channel,
+ &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 TUNNEL END\n");
+}
+
+
+/* end of gnunet-service-cadet-new_tunnels.c */
--- /dev/null
+
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2001-2017 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file cadet/gnunet-service-cadet-new_tunnels.h
+ * @brief Information we track per tunnel.
+ * @author Bartlomiej Polot
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_CADET_TUNNELS_H
+#define GNUNET_SERVICE_CADET_TUNNELS_H
+
+
+/**
+ * How many connections would we like to have per tunnel?
+ */
+#define DESIRED_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_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_PING,
+
+ /**
+ * 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
+};
+
+
+/**
+ * Number uniquely identifying a channel within a tunnel.
+ */
+struct GCT_ChannelTunnelNumber
+{
+ uint32_t channel_in_tunnel GNUNET_PACKED;
+};
+
+
+/**
+ * Get the static string for the peer this tunnel is directed.
+ *
+ * @param t Tunnel.
+ *
+ * @return Static string the destination peer's ID.
+ */
+const char *
+GCT_2s (const struct CadetTunnel *t);
+
+
+/**
+ * Create a tunnel to @a destionation. Must only be called
+ * from within #GCP_get_tunnel().
+ *
+ * @param destination where to create the tunnel to
+ * @return new tunnel to @a destination
+ */
+struct CadetTunnel *
+GCT_create_tunnel (struct CadetPeer *destination);
+
+
+/**
+ * Return the peer to which this tunnel goes.
+ *
+ * @param t a tunnel
+ * @return the destination of the tunnel
+ */
+struct CadetPeer *
+GCT_get_destination (struct CadetTunnel *t);
+
+
+/**
+ * Add a channel to a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @return unique number identifying @a ch within @a t
+ */
+struct GCT_ChannelTunnelNumber
+GCT_add_channel (struct CadetTunnel *t,
+ struct CadetChannel *ch);
+
+
+/**
+ * Remove a channel from a tunnel.
+ *
+ * @param t Tunnel.
+ * @param ch Channel
+ * @param gid unique number identifying @a ch within @a t
+ */
+void
+GCT_remove_channel (struct CadetTunnel *t,
+ struct CadetChannel *ch,
+ struct GCT_ChannelTunnelNumber gid);
+
+
+/**
+ * Sends an already built message on a tunnel, encrypting it and
+ * choosing the best connection if not provided.
+ *
+ * @param message Message to send. Function modifies it.
+ * @param t Tunnel on which this message is transmitted.
+ * @param cont Continuation to call once message is really sent.
+ * @param cont_cls Closure for @c cont.
+ * @return Handle to cancel message. NULL if @c cont is NULL.
+ */
+struct CadetTunnelQueueEntry *
+GCT_send (struct CadetTunnel *t,
+ const struct GNUNET_MessageHeader *message,
+ GNUNET_SCHEDULER_TaskCallback cont,
+ void *cont_cls);
+
+
+/**
+ * Cancel a previously sent message while it's in the queue.
+ *
+ * ONLY can be called before the continuation given to the send
+ * function is called. Once the continuation is called, the message is
+ * no longer in the queue!
+ *
+ * @param q Handle to the queue entry to cancel.
+ */
+void
+GCT_send_cancel (struct CadetTunnelQueueEntry *q);
+
+
+/**
+ * Return the number of channels using a tunnel.
+ *
+ * @param t tunnel to count obtain the number of channels for
+ * @return number of channels using the tunnel
+ */
+unsigned int
+GCT_count_channels (struct CadetTunnel *t);
+
+
+/**
+ * Return the number of connections available for a tunnel.
+ *
+ * @param t tunnel to count obtain the number of connections for
+ * @return number of connections available for the tunnel
+ */
+unsigned int
+GCT_count_any_connections (struct CadetTunnel *t);
+
+
+/**
+ * Iterator over connections.
+ *
+ * @param cls closure
+ * @param c one of the connections
+ */
+typedef void
+(*GCT_ConnectionIterator) (void *cls,
+ struct CadetConnection *c);
+
+
+/**
+ * Iterate over all connections of a tunnel.
+ *
+ * @param t Tunnel whose connections to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_connections (struct CadetTunnel *t,
+ GCT_ConnectionIterator iter,
+ void *iter_cls);
+
+
+/**
+ * Iterator over channels.
+ *
+ * @param cls closure
+ * @param ch one of the channels
+ */
+typedef void
+(*GCT_ChannelIterator) (void *cls,
+ struct CadetChannel *ch);
+
+
+/**
+ * Iterate over all channels of a tunnel.
+ *
+ * @param t Tunnel whose channels to iterate.
+ * @param iter Iterator.
+ * @param iter_cls Closure for @c iter.
+ */
+void
+GCT_iterate_channels (struct CadetTunnel *t,
+ GCT_ChannelIterator iter,
+ void *iter_cls);
+
+
+/**
+ * Get the 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);
+
+
+/**
+ * Log all possible info about the tunnel state.
+ *
+ * @param t Tunnel to debug.
+ * @param level Debug level to use.
+ */
+void
+GCT_debug (const struct CadetTunnel *t,
+ enum GNUNET_ErrorType level);
+
+
+#endif