From 9a8457f1bbce39b73ab7c03bc9706b10f80fbf0c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 15 Jan 2017 21:49:27 +0100 Subject: [PATCH] starting re-implementation of CADET service --- src/cadet/gnunet-service-cadet-new.c | 1302 +++++++++++++++++ src/cadet/gnunet-service-cadet-new.h | 144 ++ src/cadet/gnunet-service-cadet-new_channel.c | 1154 +++++++++++++++ src/cadet/gnunet-service-cadet-new_channel.h | 173 +++ .../gnunet-service-cadet-new_connection.c | 56 + .../gnunet-service-cadet-new_connection.h | 58 + src/cadet/gnunet-service-cadet-new_dht.c | 337 +++++ src/cadet/gnunet-service-cadet-new_dht.h | 108 ++ src/cadet/gnunet-service-cadet-new_hello.c | 142 ++ src/cadet/gnunet-service-cadet-new_hello.h | 80 + src/cadet/gnunet-service-cadet-new_paths.c | 94 ++ src/cadet/gnunet-service-cadet-new_paths.h | 83 ++ src/cadet/gnunet-service-cadet-new_peer.c | 509 +++++++ src/cadet/gnunet-service-cadet-new_peer.h | 170 +++ src/cadet/gnunet-service-cadet-new_tunnels.c | 830 +++++++++++ src/cadet/gnunet-service-cadet-new_tunnels.h | 314 ++++ 16 files changed, 5554 insertions(+) create mode 100644 src/cadet/gnunet-service-cadet-new.c create mode 100644 src/cadet/gnunet-service-cadet-new.h create mode 100644 src/cadet/gnunet-service-cadet-new_channel.c create mode 100644 src/cadet/gnunet-service-cadet-new_channel.h create mode 100644 src/cadet/gnunet-service-cadet-new_connection.c create mode 100644 src/cadet/gnunet-service-cadet-new_connection.h create mode 100644 src/cadet/gnunet-service-cadet-new_dht.c create mode 100644 src/cadet/gnunet-service-cadet-new_dht.h create mode 100644 src/cadet/gnunet-service-cadet-new_hello.c create mode 100644 src/cadet/gnunet-service-cadet-new_hello.h create mode 100644 src/cadet/gnunet-service-cadet-new_paths.c create mode 100644 src/cadet/gnunet-service-cadet-new_paths.h create mode 100644 src/cadet/gnunet-service-cadet-new_peer.c create mode 100644 src/cadet/gnunet-service-cadet-new_peer.h create mode 100644 src/cadet/gnunet-service-cadet-new_tunnels.c create mode 100644 src/cadet/gnunet-service-cadet-new_tunnels.h diff --git a/src/cadet/gnunet-service-cadet-new.c b/src/cadet/gnunet-service-cadet-new.c new file mode 100644 index 000000000..f367c4c73 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new.c @@ -0,0 +1,1302 @@ +/* + 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 */ diff --git a/src/cadet/gnunet-service-cadet-new.h b/src/cadet/gnunet-service-cadet-new.h new file mode 100644 index 000000000..f5e979ee5 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new.h @@ -0,0 +1,144 @@ + +/* + 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 diff --git a/src/cadet/gnunet-service-cadet-new_channel.c b/src/cadet/gnunet-service-cadet-new_channel.c new file mode 100644 index 000000000..00bdf569e --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_channel.c @@ -0,0 +1,1154 @@ + +/* + 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 */ diff --git a/src/cadet/gnunet-service-cadet-new_channel.h b/src/cadet/gnunet-service-cadet-new_channel.h new file mode 100644 index 000000000..5cf42a894 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_channel.h @@ -0,0 +1,173 @@ + +/* + 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 diff --git a/src/cadet/gnunet-service-cadet-new_connection.c b/src/cadet/gnunet-service-cadet-new_connection.c new file mode 100644 index 000000000..b24e4bd49 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_connection.c @@ -0,0 +1,56 @@ + +/* + 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) +{ +} diff --git a/src/cadet/gnunet-service-cadet-new_connection.h b/src/cadet/gnunet-service-cadet-new_connection.h new file mode 100644 index 000000000..7745e4fec --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_connection.h @@ -0,0 +1,58 @@ + +/* + 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 diff --git a/src/cadet/gnunet-service-cadet-new_dht.c b/src/cadet/gnunet-service-cadet-new_dht.c new file mode 100644 index 000000000..fbd8b95f1 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_dht.c @@ -0,0 +1,337 @@ +/* + 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 */ diff --git a/src/cadet/gnunet-service-cadet-new_dht.h b/src/cadet/gnunet-service-cadet-new_dht.h new file mode 100644 index 000000000..70f834de5 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_dht.h @@ -0,0 +1,108 @@ +/* + 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 */ diff --git a/src/cadet/gnunet-service-cadet-new_hello.c b/src/cadet/gnunet-service-cadet-new_hello.c new file mode 100644 index 000000000..9d4635021 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_hello.c @@ -0,0 +1,142 @@ +/* + 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 */ diff --git a/src/cadet/gnunet-service-cadet-new_hello.h b/src/cadet/gnunet-service-cadet-new_hello.h new file mode 100644 index 000000000..4291ae985 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_hello.h @@ -0,0 +1,80 @@ +/* + This file is part of GNUnet. + Copyright (C) 2014, 2017 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file cadet/gnunet-service-cadet_hello.h + * @brief cadet service; dealing with hello messages + * @author Bartlomiej Polot + * @author Christian Grothoff + * + * All functions in this file should use the prefix GCH (Gnunet Cadet Hello) + */ + +#ifndef GNUNET_SERVICE_CADET_HELLO_H +#define GNUNET_SERVICE_CADET_HELLO_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" + + +/** + * Initialize the hello subsystem. + * + * @param c Configuration. + */ +void +GCH_init (const struct GNUNET_CONFIGURATION_Handle *c); + + +/** + * Shut down the hello subsystem. + */ +void +GCH_shutdown (void); + + +/** + * Get own hello message. + * + * @return Own hello message. + */ +const struct GNUNET_HELLO_Message * +GCH_get_mine (void); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + +/* ifndef GNUNET_CADET_SERVICE_HELLO_H */ +#endif +/* end of gnunet-cadet-service_hello.h */ diff --git a/src/cadet/gnunet-service-cadet-new_paths.c b/src/cadet/gnunet-service-cadet-new_paths.c new file mode 100644 index 000000000..a338cc20e --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_paths.c @@ -0,0 +1,94 @@ + +/* + 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 */ diff --git a/src/cadet/gnunet-service-cadet-new_paths.h b/src/cadet/gnunet-service-cadet-new_paths.h new file mode 100644 index 000000000..9354c3f72 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_paths.h @@ -0,0 +1,83 @@ + +/* + 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 diff --git a/src/cadet/gnunet-service-cadet-new_peer.c b/src/cadet/gnunet-service-cadet-new_peer.c new file mode 100644 index 000000000..824936943 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_peer.c @@ -0,0 +1,509 @@ + +/* + 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 */ diff --git a/src/cadet/gnunet-service-cadet-new_peer.h b/src/cadet/gnunet-service-cadet-new_peer.h new file mode 100644 index 000000000..d76874dbc --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_peer.h @@ -0,0 +1,170 @@ + +/* + 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 diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.c b/src/cadet/gnunet-service-cadet-new_tunnels.c new file mode 100644 index 000000000..4299d5bf7 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_tunnels.c @@ -0,0 +1,830 @@ + +/* + 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 */ diff --git a/src/cadet/gnunet-service-cadet-new_tunnels.h b/src/cadet/gnunet-service-cadet-new_tunnels.h new file mode 100644 index 000000000..5e06559d5 --- /dev/null +++ b/src/cadet/gnunet-service-cadet-new_tunnels.h @@ -0,0 +1,314 @@ + +/* + 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 -- 2.25.1