* @brief GNUnet MESH service
* @author Bartlomiej Polot
*
+ * STRUCTURE:
+ * - DATA STRUCTURES
+ * - GLOBAL VARIABLES
+ * - MESH NETWORK HANDLER HELPERS
+ * - MESH NETWORK HANDLES
+ * - MESH LOCAL HANDLER HELPERS
+ * - MESH LOCAL HANDLES
+ * - PERIODIC FUNCTIONS
+ * - MAIN FUNCTIONS (main & run)
+ *
* TODO:
- * - soft stateing (keep-alive (CHANGE?) / timeout / disconnect) -- not a message issue
* - error reporting (CREATE/CHANGE/ADD/DEL?) -- new message!
* - partial disconnect reporting -- same as error reporting?
* - add vs create? change vs. keep-alive? same msg or different ones? -- thinking...
* - speed requirement specification (change?) in mesh API -- API call
+ * - add ping message (connection confirmation, others?)
*/
#include "platform.h"
#include "gnunet_common.h"
#include "gnunet_util_lib.h"
+#include "gnunet_peer_lib.h"
#include "gnunet_core_service.h"
#include "gnunet_protocols.h"
+
#include "mesh.h"
+#include "mesh_protocol.h"
+#include "gnunet_dht_service.h"
+
+#define REFRESH_PATH_TIME GNUNET_TIME_relative_multiply(\
+ GNUNET_TIME_UNIT_SECONDS,\
+ 300)
/******************************************************************************/
-/******************** MESH NETWORK MESSAGES **************************/
+/************************ DATA STRUCTURES ****************************/
/******************************************************************************/
/**
- * Message for mesh path management
+ * Information regarding a path
*/
-struct GNUNET_MESH_ManipulatePath
+struct MeshPath
{
+
/**
- * Type: GNUNET_MESSAGE_TYPE_MESH_PATH_[CREATE|CHANGE|ADD|DEL]
- *
- * Size: sizeof(struct GNUNET_MESH_ManipulatePath) + path_length * sizeof (struct GNUNET_PeerIdentity)
+ * Linked list
*/
- struct GNUNET_MessageHeader header;
+ struct MeshPath *next;
+ struct MeshPath *prev;
/**
- * Id of the tunnel this path belongs to, unique in conjunction with the origin.
+ * Whether the path is serving traffic in a tunnel or is a backup
*/
- uint32_t tid GNUNET_PACKED;
+ int in_use;
/**
- * Information about speed requirements. If the tunnel cannot sustain the
- * minimum bandwidth, packets are to be dropped.
+ * List of all the peers that form the path from origin to target
*/
- uint32_t speed_min GNUNET_PACKED;
+ GNUNET_PEER_Id *peers;
/**
- * path_length structs defining the *whole* path from the origin [0] to the
- * final destination [path_length-1].
+ * Number of peers (hops) in the path
*/
- // struct GNUNET_PeerIdentity peers[path_length];
+ unsigned int length;
};
+
/**
- * Message for mesh data traffic to all tunnel targets.
+ * All the states a peer participating in a tunnel can be in.
*/
-struct GNUNET_MESH_OriginMulticast
+enum MeshPeerState
{
/**
- * Type: GNUNET_MESSAGE_TYPE_DATA_MULTICAST
+ * Path to the peer not known yet
*/
- struct GNUNET_MessageHeader header;
+ MESH_PEER_SEARCHING,
/**
- * TID of the tunnel
- */
- uint32_t tid GNUNET_PACKED;
-
- /**
- * OID of the tunnel
+ * Request sent, not yet answered.
*/
- struct GNUNET_PeerIdentity oid;
+ MESH_PEER_WAITING,
/**
- * FIXME: Some form of authentication
+ * Peer connected and ready to accept data
*/
- // uint32_t token;
+ MESH_PEER_READY,
/**
- * Payload follows
+ * Peer connected previosly but not responding
*/
+ MESH_PEER_RECONNECTING
};
/**
- * Message for mesh data traffic to a particular destination from origin.
+ * Struct containing all information regarding a given peer
*/
-struct GNUNET_MESH_DataMessageFromOrigin
+struct MeshPeerInfo
{
/**
- * Type: GNUNET_MESSAGE_TYPE_DATA_MESSAGE_FROM_ORIGIN
+ * ID of the peer
*/
- struct GNUNET_MessageHeader header;
+ GNUNET_PEER_Id id;
/**
- * TID of the tunnel
+ * Is the peer reachable? Is the peer even connected?
*/
- uint32_t tid GNUNET_PACKED;
+ enum MeshPeerState state;
/**
- * OID of the tunnel
+ * Last time we heard from this peer
*/
- struct GNUNET_PeerIdentity oid;
+ struct GNUNET_TIME_Absolute last_contact;
/**
- * Destination.
+ * Number of attempts to reconnect so far
*/
- struct GNUNET_PeerIdentity destination;
+ int n_reconnect_attempts;
/**
- * FIXME: Some form of authentication
+ * Paths to reach the peer
*/
- // uint32_t token;
+ struct MeshPath *path;
+ struct MeshPath *path_tail;
/**
- * Payload follows
+ * Handle to stop the DHT search for a path to this peer
*/
+ struct GNUNET_DHT_GetHandle *dhtget;
};
/**
- * Message for mesh data traffic from a tunnel participant to origin.
+ * Data scheduled to transmit (to local client or remote peer)
*/
-struct GNUNET_MESH_DataMessageToOrigin
+struct MeshQueue
{
/**
- * Type: GNUNET_MESSAGE_TYPE_DATA_MESSAGE_TO_ORIGIN
+ * Double linked list
*/
- struct GNUNET_MessageHeader header;
+ struct MeshQueue *next;
+ struct MeshQueue *prev;
/**
- * TID of the tunnel
+ * Target of the data (NULL if target is client)
*/
- uint32_t tid GNUNET_PACKED;
+ struct MeshPeerInfo *peer;
/**
- * OID of the tunnel
+ * Client to send the data to (NULL if target is peer)
*/
- struct GNUNET_PeerIdentity oid;
+ struct MeshClient *client;
/**
- * Sender of the message.
+ * Size of the message to transmit
*/
- struct GNUNET_PeerIdentity sender;
+ unsigned int size;
/**
- * FIXME: Some form of authentication
+ * How old is the data?
*/
- // uint32_t token;
+ struct GNUNET_TIME_Absolute timestamp;
/**
- * Payload follows
+ * Data itself
*/
+ struct GNUNET_MessageHeader *data;
};
/**
- * Message for mesh flow control
+ * Globally unique tunnel identification (owner + number)
+ * DO NOT USE OVER THE NETWORK
*/
-struct GNUNET_MESH_SpeedNotify
-{
- /**
- * Type: GNUNET_MESSAGE_TYPE_DATA_SPEED_NOTIFY
- */
- struct GNUNET_MessageHeader header;
-
- /**
- * TID of the tunnel
- */
- uint32_t tid GNUNET_PACKED;
-
+struct MESH_TunnelID {
/**
- * OID of the tunnel
+ * Node that owns the tunnel
*/
- struct GNUNET_PeerIdentity oid;
+ GNUNET_PEER_Id oid;
/**
- * Slowest link down the path (above minimum speed requirement).
+ * Tunnel number to differentiate all the tunnels owned by the node oid
+ * ( tid < GNUNET_MESH_LOCAL_TUNNEL_ID_MARK )
*/
- uint32_t speed_min;
-
+ MESH_TunnelNumber tid;
};
-/******************************************************************************/
-/************************ DATA STRUCTURES ****************************/
-/******************************************************************************/
+struct MeshClient; /* FWD declaration */
/**
- * All the states a peer participating in a tunnel can be in.
+ * Struct containing all information regarding a tunnel
+ * For an intermediate node the improtant info used will be:
+ * - id Tunnel unique identification
+ * - paths[0] To know where to send it next
+ * - metainfo: ready, speeds, accounting
*/
-enum PeerState
+struct MeshTunnel
{
/**
- * Request sent, not yet answered.
+ * Tunnel ID
*/
- MESH_PEER_WAITING,
+ struct MESH_TunnelID id;
/**
- * Peer connected and ready to accept data
+ * Local tunnel number ( >= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK or 0 )
*/
- MESH_PEER_READY,
+ MESH_TunnelNumber local_tid;
/**
- * Peer connected previosly but not responding
+ * Last time the tunnel was used
*/
- MESH_PEER_UNAVAILABLE,
+ struct GNUNET_TIME_Absolute timestamp;
/**
- * Peer requested but not ever connected
+ * Peers in the tunnelindexed by PeerIdentity (MeshPeerInfo)
*/
- MESH_PEER_UNREACHABLE
-};
+ struct GNUNET_CONTAINER_MultiHashMap* peers;
-/**
- * Struct containing all information regarding a given peer
- */
-struct PeerInfo
-{
/**
- * ID of the peer
+ * Number of peers that are connected and potentially ready to receive data
*/
- struct GNUNET_PeerIdentity id;
+ unsigned int peers_ready;
/**
- * Is the peer reachable? Is the peer even connected?
+ * Number of peers that have been added to the tunnel
*/
- enum PeerState state;
+ unsigned int peers_total;
+
/**
- * Who to send the data to
+ * Client owner of the tunnel, if any
*/
- uint32_t first_hop;
+ struct MeshClient *client;
/**
- * Max data rate to this peer
+ * Messages ready to transmit
*/
- uint32_t max_speed;
+ struct MeshQueue *queue_head;
+ struct MeshQueue *queue_tail;
+
};
/**
- * Information regarding a path
+ * Struct containing information about a client of the service
*/
-struct Path
+struct MeshClient
{
/**
- * Id of the path, in case it's needed
+ * Linked list
*/
- uint32_t id;
+ struct MeshClient *next;
+ struct MeshClient *prev;
/**
- * Whether the path is serving traffic in a tunnel or is a backup
+ * Tunnels that belong to this client, indexed by local id
*/
- int in_use;
+ struct GNUNET_CONTAINER_MultiHashMap* tunnels;
/**
- * List of all the peers that form the path from origin to target
+ * Handle to communicate with the client
*/
- struct PeerInfo *peers;
-};
+ struct GNUNET_SERVER_Client *handle;
-/**
- * Struct containing all information regarding a tunnel
- * For an intermediate node the improtant info used will be:
- * - OID \ To identify
- * - TID / the tunnel
- * - paths[0] | To know where to send it next
- * - metainfo: ready, speeds, accounting
- * For an end node more fields will be needed (client-handling)
- */
-struct MESH_tunnel
-{
/**
- * Origin ID: Node that created the tunnel
+ * Applications that this client has claimed to provide
*/
- struct GNUNET_PeerIdentity oid;
+ GNUNET_MESH_ApplicationType *apps;
+ unsigned int app_counter;
/**
- * Tunnel number (unique for a given oid)
+ * Messages that this client has declared interest in
*/
- uint32_t tid;
+ uint16_t *types;
+ unsigned int type_counter;
- /**
- * Whether the tunnel is in state to transmit data
- */
- int ready;
+};
- /**
- * Minimal speed for this tunnel in kb/s
- */
- uint32_t speed_min;
+/******************************************************************************/
+/*********************** GLOBAL VARIABLES ****************************/
+/******************************************************************************/
- /**
- * Maximal speed for this tunnel in kb/s
- */
- uint32_t speed_max;
+/**
+ * All the clients
+ */
+static struct MeshClient *clients;
+static struct MeshClient *clients_tail;
- /**
- * Last time the tunnel was used
- */
- struct GNUNET_TIME_Absolute timestamp;
+/**
+ * Tunnels known, indexed by MESH_TunnelID (MeshTunnel)
+ */
+struct GNUNET_CONTAINER_MultiHashMap *tunnels;
- /**
- * Peers in the tunnel, for future optimizations
- */
- struct PeerInfo *peers;
+/**
+ * Peers known, indexed by PeerIdentity (MeshPeerInfo)
+ */
+struct GNUNET_CONTAINER_MultiHashMap *peers;
- /**
- * Paths (used and backup)
- */
- struct Path *paths;
+/**
+ * Handle to communicate with core
+ */
+static struct GNUNET_CORE_Handle *core_handle;
- /**
- * Messages ready to transmit
- */
- struct GNUNET_MessageHeader *msg_out;
+/**
+ * Handle to use DHT
+ */
+static struct GNUNET_DHT_Handle *dht_handle;
- /**
- * Messages received and not processed
- */
- struct GNUNET_MessageHeader *msg_in;
+/**
+ * Local peer own ID (memory efficient handle)
+ */
+static GNUNET_PEER_Id myid;
- /**
- * FIXME Clients. Is anyone to be notified for traffic here?
- */
-};
+/**
+ * Tunnel ID for the next created tunnel (global tunnel number)
+ */
+static MESH_TunnelNumber next_tid;
+
+/******************************************************************************/
+/****************** GENERAL HELPER FUNCTIONS ************************/
+/******************************************************************************/
/**
- * So, I'm an endpoint. Why am I receiveing traffic?
- * Who is interested in this? How to communicate with them?
+ * Retrieve the MeshPeerInfo stucture associated with the peer, create one
+ * and inster it in the appropiate structures if the peer is not known yet.
+ * @param peer Identity of the peer
+ * @return Existing or newly created peer info
*/
-struct Clients
+static struct MeshPeerInfo *
+get_peer_info (const struct GNUNET_PeerIdentity *peer)
{
- /**
- * FIXME add structures needed to handle client connections
- */
- int fixme;
-};
+ struct MeshPeerInfo * peer_info;
+
+ peer_info = GNUNET_CONTAINER_multihashmap_get(peers,
+ &peer->hashPubKey);
+ if (NULL == peer_info) {
+ peer_info = (struct MeshPeerInfo *)
+ GNUNET_malloc(sizeof(struct MeshPeerInfo));
+ GNUNET_CONTAINER_multihashmap_put(peers,
+ &peer->hashPubKey,
+ peer_info,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+ peer_info->id = GNUNET_PEER_intern(peer);
+ peer_info->state = MESH_PEER_SEARCHING;
+ }
+
+ return peer_info;
+}
+
+/**
+ * Find the first peer whom to send a packet to go down this path
+ * @param path The path to use
+ * @return short id of the next peer, myid in case of local delivery,
+ * or 0 in case of error
+ */
+static GNUNET_PEER_Id
+get_first_hop (struct MeshPath *path)
+{
+ unsigned int i;
+
+ if (NULL == path) return 0;
+ if (path->in_use == 0) return 0;
+
+ for (i = 0; i < path->length; i++) {
+ if (path->peers[i] == myid) {
+ if (i < path->length - 1) {
+ return path->peers[i+1];
+ } else {
+ return myid;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Get the cost of the path.
+ * @param path The path to analyze
+ * @return Number of hops to reach destination, UINT_MAX in case the peer is not
+ * in the path
+ */
+static unsigned int
+get_path_cost(struct MeshPath *path)
+{
+ unsigned int i;
+
+ if (NULL == path) return UINT_MAX;
+ for (i = 0; i < path->length; i++) {
+ if (path->peers[i] == myid) {
+ return path->length - i;
+ }
+ }
+ return UINT_MAX;
+}
+
+
+/**
+ * Add the path to the peer and update the path used to reach it in case this
+ * is the shortest.
+ * @param peer_info Destination peer to add the path to.
+ * @param path New path to add. Last peer must be the peer in arg 1.
+ */
+static void
+add_path_to_peer(struct MeshPeerInfo *peer_info, struct MeshPath *path)
+{
+ unsigned int i;
+ unsigned int new_cost;
+ unsigned int best_cost;
+ struct MeshPath *aux;
+ struct MeshPath *best;
+
+ if (NULL == peer_info || NULL == path) return;
+
+ new_cost = get_path_cost(path);
+ best_cost = UINT_MAX;
+ best = NULL;
+ for (aux = peer_info->path; aux != NULL; aux = aux->next) {
+ if ((i = get_path_cost(aux)) < best_cost) {
+ best = aux;
+ best_cost = i;
+ }
+ }
+ if (best_cost < new_cost) {
+ path->in_use = 0;
+ GNUNET_CONTAINER_DLL_insert_tail(peer_info->path,
+ peer_info->path_tail,
+ path);
+ } else {
+ if (NULL != best) best->in_use = 0;
+ path->in_use = 1;
+ GNUNET_CONTAINER_DLL_insert(peer_info->path,
+ peer_info->path_tail,
+ path);
+ }
+ return;
+}
+
+
+/**
+ * Check if client has registered with the service and has not disconnected
+ * @param client the client to check
+ * @return non-NULL if client exists in the global DLL
+ */
+static struct MeshClient *
+retrieve_client (struct GNUNET_SERVER_Client *client)
+{
+ struct MeshClient *c;
+
+ c = clients;
+ while (NULL != c) {
+ if (c->handle == client) return c;
+ c = c->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * Search for a tunnel among the tunnels for a client
+ * @param client the client whose tunnels to search in
+ * @param tid the local id of the tunnel
+ * @return tunnel handler, NULL if doesn't exist
+ */
+static struct MeshTunnel *
+retrieve_tunnel_by_local_id (struct MeshClient *c, MESH_TunnelNumber tid)
+{
+ GNUNET_HashCode hash;
+
+ GNUNET_CRYPTO_hash(&tid, sizeof(MESH_TunnelNumber), &hash);
+ return GNUNET_CONTAINER_multihashmap_get(c->tunnels, &hash);
+}
+
+/**
+ * Search for a tunnel by global ID using PEER_ID
+ * @param pi owner of the tunnel
+ * @param tid global tunnel number
+ * @return tunnel handler, NULL if doesn't exist
+ */
+static struct MeshTunnel *
+retrieve_tunnel_by_pi (GNUNET_PEER_Id pi, MESH_TunnelNumber tid)
+{
+ struct MESH_TunnelID id;
+ GNUNET_HashCode hash;
+
+ id.oid = pi;
+ id.tid = tid;
+
+ GNUNET_CRYPTO_hash(&id, sizeof(struct MESH_TunnelID), &hash);
+ return GNUNET_CONTAINER_multihashmap_get(tunnels, &hash);
+}
+
+
+
+/**
+ * Search for a tunnel by global ID using full PeerIdentities
+ * @param oid owner of the tunnel
+ * @param tid global tunnel number
+ * @return tunnel handler, NULL if doesn't exist
+ */
+static struct MeshTunnel *
+retrieve_tunnel (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid)
+{
+ GNUNET_PEER_Id pi;
+
+ pi = GNUNET_PEER_intern(oid);
+ GNUNET_PEER_change_rc(pi, -1);
+ return retrieve_tunnel_by_pi(pi, tid);
+}
+
+
+/**
+ * Destroy the path and free any allocated resources linked to it
+ * @param t tunnel the path belongs to
+ * @param p the path to destroy
+ * @return GNUNET_OK on success
+ */
+static int
+destroy_path(struct MeshPath *p)
+{
+ GNUNET_PEER_decrement_rcs(p->peers, p->length);
+ GNUNET_free(p->peers);
+ GNUNET_free(p);
+ return GNUNET_OK;
+}
+
+#if LATER
+/**
+ * Destroy the peer_info and free any allocated resources linked to it
+ * @param t tunnel the path belongs to
+ * @param pi the peer_info to destroy
+ * @return GNUNET_OK on success
+ */
+static int
+destroy_peer_info(struct MeshPeerInfo *pi)
+{
+ GNUNET_HashCode hash;
+ struct GNUNET_PeerIdentity id;
+
+ GNUNET_PEER_resolve(pi->id, &id);
+ GNUNET_PEER_change_rc(pi->id, -1);
+ GNUNET_CRYPTO_hash(&id, sizeof(struct GNUNET_PeerIdentity), &hash);
+
+ GNUNET_CONTAINER_multihashmap_remove(peers, &hash, pi);
+ GNUNET_free(pi);
+ return GNUNET_OK;
+}
+#endif
+
+
+/**
+ * Destroy the tunnel and free any allocated resources linked to it
+ * @param c client the tunnel belongs to
+ * @param t the tunnel to destroy
+ * @return GNUNET_OK on success
+ */
+static int
+destroy_tunnel(struct MeshTunnel *t)
+{
+// struct MeshPath *path;
+ struct MeshClient *c;
+ GNUNET_HashCode hash;
+ int r;
+ if (NULL == t) return GNUNET_OK;
+
+ c = t->client;
+
+ GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
+ if(GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove(tunnels, &hash, t)) {
+ r = GNUNET_SYSERR;
+ }
+
+ GNUNET_CRYPTO_hash(&t->local_tid, sizeof(MESH_TunnelNumber), &hash);
+ if(GNUNET_YES !=
+ GNUNET_CONTAINER_multihashmap_remove(c->tunnels, &hash, t))
+ {
+ r = GNUNET_SYSERR;
+ }
+ GNUNET_free(t);
+ return r;
+}
+
+/******************************************************************************/
+/**************** MESH NETWORK HANDLER HELPERS ***********************/
+/******************************************************************************/
+
+/**
+ * Function called to notify a client about the socket
+ * being ready to queue more data. "buf" will be
+ * NULL and "size" zero if the socket was closed for
+ * writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+send_core_create_path_for_peer (void *cls, size_t size, void *buf)
+{
+ struct MeshPeerInfo *peer_info = cls;
+ struct GNUNET_MESH_ManipulatePath *msg;
+ struct MeshPath *p;
+ struct GNUNET_PeerIdentity *peer_ptr;
+ struct GNUNET_PeerIdentity id;
+ size_t size_needed;
+ int i;
+
+ if (0 == size && NULL == buf) {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Retransmitting create path\n");
+ GNUNET_PEER_resolve(get_first_hop(peer_info->path), &id);
+ GNUNET_CORE_notify_transmit_ready(core_handle,
+ 0,
+ 0,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &id,
+ sizeof(struct GNUNET_MESH_ManipulatePath)
+ + (peer_info->path->length
+ * sizeof (struct GNUNET_PeerIdentity)),
+ &send_core_create_path_for_peer,
+ peer_info);
+ return 0;
+ }
+ p = peer_info->path;
+ while (NULL != p) {
+ if (p->in_use) {
+ break;
+ }
+ p = p->next;
+ }
+ if (p == NULL) return 0; // TODO Notify ERROR Path not found
+
+ size_needed = sizeof(struct GNUNET_MESH_ManipulatePath)
+ + p->length * sizeof(struct GNUNET_PeerIdentity);
+ if (size < size_needed) {
+ // TODO retry? cancel?
+ return 0;
+ }
+
+ msg = (struct GNUNET_MESH_ManipulatePath *) buf;
+ msg->header.size = htons(size_needed);
+ msg->header.type = htons(GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE);
+
+ peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1];
+ for (i = 0; i < p->length; i++) {
+ GNUNET_PEER_resolve(p->peers[i], peer_ptr++);
+ }
+
+ peer_info->state = MESH_PEER_WAITING; // TODO maybe already ready?
+
+ return size_needed;
+}
+
+#if LATER
+/**
+ * Send another peer a notification to destroy a tunnel
+ * @param cls The tunnel to destroy
+ * @param size Size in the buffer
+ * @param buf Memory where to put the data to transmit
+ * @return Size of data put in buffer
+ */
+static size_t
+send_p2p_tunnel_destroy(void *cls, size_t size, void *buf)
+{
+ struct MeshTunnel *t = cls;
+ struct MeshClient *c;
+ struct GNUNET_MESH_TunnelMessage *msg;
+
+ c = t->client;
+ msg = buf;
+ msg->header.type = htons(GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); /*FIXME*/
+ msg->header.size = htons(sizeof(struct GNUNET_MESH_TunnelMessage));
+ msg->tunnel_id = htonl(t->id.tid);
+
+ destroy_tunnel(c, t);
+ return sizeof(struct GNUNET_MESH_TunnelMessage);
+}
+#endif
/******************************************************************************/
/******************** MESH NETWORK HANDLERS **************************/
/******************************************************************************/
+
/**
* Core handler for path creation
* struct GNUNET_CORE_MessageHandler
const struct GNUNET_TRANSPORT_ATS_Information
*atsi)
{
- /* Extract path */
- /* Find origin & self */
- /* Search for origin in local tunnels */
- /* Create tunnel / add path */
- /* Retransmit to next link in chain, if any (core_notify + callback) */
+ unsigned int own_pos;
+ uint16_t size;
+ uint16_t i;
+ MESH_TunnelNumber tid;
+ struct GNUNET_MESH_ManipulatePath *msg;
+ struct GNUNET_PeerIdentity *pi;
+ GNUNET_HashCode hash;
+ struct MeshPath *path;
+ struct MeshPeerInfo *peer_info;
+ struct MeshTunnel *t;
+
+
+ size = ntohs(message->size);
+ if (size < sizeof(struct GNUNET_MESH_ManipulatePath)) {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "received create path message too short\n");
+ return GNUNET_OK;
+ }
+
+ size -= sizeof(struct GNUNET_MESH_ManipulatePath);
+ if (size < 2 * sizeof(struct GNUNET_PeerIdentity)) {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "create path message lacks enough peers\n");
+ return GNUNET_OK;
+ }
+ if (size % sizeof(struct GNUNET_PeerIdentity)) {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "create path message of wrong size\n");
+ return GNUNET_OK;
+ }
+ msg = (struct GNUNET_MESH_ManipulatePath *) message;
+ size /= sizeof(struct GNUNET_PeerIdentity);
+
+ tid = ntohl(msg->tid);
+ pi = (struct GNUNET_PeerIdentity *) &msg[1];
+ t = retrieve_tunnel(pi, tid);
+
+ if (NULL == t) {
+ t = GNUNET_malloc(sizeof(struct MeshTunnel));
+ t->id.oid = GNUNET_PEER_intern(pi);
+ t->id.tid = tid;
+ t->local_tid = 0;
+ t->client = NULL;
+ t->peers = GNUNET_CONTAINER_multihashmap_create(32);
+
+ GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put(tunnels,
+ &hash,
+ t,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "create path: could not store tunnel in hashmap\n");
+ return GNUNET_OK;
+ }
+
+ }
+ peer_info = GNUNET_CONTAINER_multihashmap_get(peers,
+ &pi[size - 1].hashPubKey);
+ if (NULL == peer_info) {
+ peer_info = GNUNET_malloc(sizeof(struct MeshPeerInfo));
+ peer_info->id = GNUNET_PEER_intern(&pi[size - 1]);
+ peer_info->state = MESH_PEER_WAITING;
+ GNUNET_CONTAINER_multihashmap_put(peers,
+ &pi[size - 1].hashPubKey,
+ peer_info,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+ }
+
+ path = GNUNET_malloc(sizeof(struct MeshPath));
+ path->length = size;
+ path->peers = GNUNET_malloc(size * sizeof(GNUNET_PEER_Id));
+ own_pos = 0;
+ for (i = 0; i < size; i++) {
+ path->peers[i] = GNUNET_PEER_intern(&pi[i]);
+ if (path->peers[i] == myid) own_pos = i;
+ }
+ if (own_pos == 0) { /* cannot be self, must be 'not found' */
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "create path: self not found in path through self\n");
+ destroy_path(path);
+ /* FIXME destroy tunnel? leave for timeout? */
+ return 0;
+ }
+ if (own_pos == size - 1) { /* it is for us! */
+ destroy_path(path); /* not needed anymore */
+ /* TODO: send ack? new meesage type? */
+ } else {
+ add_path_to_peer(peer_info, path);
+ /* TODO: Retransmit to next link in chain, if any (core_notify + callback) */
+ }
return GNUNET_OK;
}
+
/**
* Core handler for mesh network traffic
*
const struct GNUNET_TRANSPORT_ATS_Information
*atsi)
{
- if(GNUNET_MESSAGE_TYPE_MESH_DATA_GO == ntohs(message->type)) {
+ if (GNUNET_MESSAGE_TYPE_MESH_DATA_GO == ntohs(message->type)) {
/* Retransmit to next in path of tunnel identified by message */
return GNUNET_OK;
} else { /* GNUNET_MESSAGE_TYPE_MESH_DATA_BACK */
}
}
+
/**
* Functions to handle messages from core
*/
+/******************************************************************************/
+/**************** MESH LOCAL HANDLER HELPERS ***********************/
+/******************************************************************************/
+
+/**
+ * delete_tunnel_entry: iterator for deleting each tunnel that belongs to a
+ * client when the client disconnects.
+ * @param cls closure (client that is disconnecting)
+ * @param key the hash of the local tunnel id (used to access the hashmap)
+ * @param value the value stored at the key (tunnel to destroy)
+ * @return GNUNET_OK on success
+ */
+static int
+delete_tunnel_entry (void *cls, const GNUNET_HashCode * key, void *value) {
+ int r;
+ r = destroy_tunnel((struct MeshTunnel *) value);
+ return r;
+}
+
+#if LATER
+/**
+ * notify_client_connection_failure: notify a client that the connection to the
+ * requested remote peer is not possible (for instance, no route found)
+ * Function called when the socket is ready to queue more data. "buf" will be
+ * NULL and "size" zero if the socket was closed for writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+notify_client_connection_failure (void *cls, size_t size, void *buf)
+{
+ int size_needed;
+ struct MeshPeerInfo *peer_info;
+ struct GNUNET_MESH_PeerControl *msg;
+ struct GNUNET_PeerIdentity id;
+
+ if (0 == size && NULL == buf) {
+ // TODO retry? cancel?
+ return 0;
+ }
+
+ size_needed = sizeof(struct GNUNET_MESH_PeerControl);
+ peer_info = (struct MeshPeerInfo *) cls;
+ msg = (struct GNUNET_MESH_PeerControl *) buf;
+ msg->header.size = htons(sizeof(struct GNUNET_MESH_PeerControl));
+ msg->header.type = htons(GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED);
+// msg->tunnel_id = htonl(peer_info->t->tid);
+ GNUNET_PEER_resolve(peer_info->id, &id);
+ memcpy(&msg->peer, &id, sizeof(struct GNUNET_PeerIdentity));
+
+ return size_needed;
+}
+#endif
+
+
+/**
+ * Send keepalive packets for a peer
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+path_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct MeshPeerInfo *peer_info = cls;
+ struct GNUNET_PeerIdentity id;
+
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) return;
+ GNUNET_PEER_resolve(get_first_hop(peer_info->path), &id);
+ GNUNET_CORE_notify_transmit_ready(core_handle,
+ 0,
+ 0,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &id,
+ sizeof(struct GNUNET_MESH_ManipulatePath)
+ + (peer_info->path->length
+ * sizeof (struct GNUNET_PeerIdentity)),
+ &send_core_create_path_for_peer,
+ peer_info);
+
+ return;
+}
+
+
+/**
+ * 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 NULL-terminated array of pointers
+ * to the peers on reverse GET path (or NULL if not recorded)
+ * @param put_path NULL-terminated array of pointers
+ * to the peers on the PUT path (or NULL if not recorded)
+ * @param type type of the result
+ * @param size number of bytes in data
+ * @param data pointer to the result data
+ */
+static void
+dht_get_response_handler(void *cls,
+ struct GNUNET_TIME_Absolute exp,
+ const GNUNET_HashCode * key,
+ const struct GNUNET_PeerIdentity * const *get_path,
+ const struct GNUNET_PeerIdentity * const *put_path,
+ enum GNUNET_BLOCK_Type type,
+ size_t size,
+ const void *data)
+{
+ struct MeshPeerInfo *peer_info = cls;
+ struct MeshPath *p;
+ struct GNUNET_PeerIdentity pi;
+ int i;
+
+ if ((NULL == get_path || NULL == put_path) && NULL == peer_info->path) {
+ // Find ourselves some alternate initial path to the destination: retry
+ GNUNET_DHT_get_stop(peer_info->dhtget);
+ GNUNET_PEER_resolve(peer_info->id, &pi);
+ peer_info->dhtget = GNUNET_DHT_get_start(dht_handle,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_BLOCK_TYPE_ANY,
+ &pi.hashPubKey,
+ 4, /* replication level */
+ GNUNET_DHT_RO_RECORD_ROUTE,
+ NULL, /* bloom filter */
+ 0, /* mutator */
+ NULL, /* xquery */
+ 0, /* xquery bits */
+ dht_get_response_handler,
+ (void *)peer_info);
+ }
+
+ p = GNUNET_malloc(sizeof(struct MeshPath));
+ for (i = 0; get_path[i] != NULL; i++);
+ for (i--; i >= 0; i--) {
+ p->peers = GNUNET_realloc(p->peers,
+ sizeof(GNUNET_PEER_Id) * (p->length + 1));
+ p->peers[p->length] = GNUNET_PEER_intern(get_path[i]);
+ p->length++;
+ }
+ for (i = 0; put_path[i] != NULL; i++);
+ for (i--; i >= 0; i--) {
+ p->peers = GNUNET_realloc(p->peers,
+ sizeof(GNUNET_PEER_Id) * (p->length + 1));
+ p->peers[p->length] = GNUNET_PEER_intern(put_path[i]);
+ p->length++;
+ }
+ add_path_to_peer(peer_info, p);
+ GNUNET_CORE_notify_transmit_ready(core_handle,
+ 0,
+ 0,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ get_path[1],
+ sizeof(struct GNUNET_MESH_ManipulatePath)
+ + (p->length
+ * sizeof (struct GNUNET_PeerIdentity)),
+ &send_core_create_path_for_peer,
+ peer_info);
+ GNUNET_SCHEDULER_add_delayed(REFRESH_PATH_TIME, &path_refresh, peer_info);
+ return;
+}
+
+
/******************************************************************************/
/********************* MESH LOCAL HANDLES **************************/
/******************************************************************************/
+
/**
* Handler for client disconnection
*
static void
handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
{
- /* Remove client from list, delete all timers and queues associated */
+ struct MeshClient *c;
+ struct MeshClient *next;
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+ "client disconnected\n");
+ c = clients;
+ while (NULL != c) {
+ if (c->handle == client) {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+ " matching client found, cleaning\n");
+ GNUNET_CONTAINER_multihashmap_iterate(c->tunnels,
+ &delete_tunnel_entry,
+ c);
+ GNUNET_CONTAINER_multihashmap_destroy(c->tunnels);
+ if(0 != c->app_counter) GNUNET_free (c->apps);
+ if(0 != c->type_counter) GNUNET_free (c->types);
+ GNUNET_CONTAINER_DLL_remove(clients, clients_tail, c);
+ next = c->next;
+ GNUNET_free (c);
+ c = next;
+ } else {
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+ " ... searching\n");
+ c = c->next;
+ }
+ }
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+ " done!\n");
return;
}
+
/**
* Handler for new clients
*
struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
+ struct GNUNET_MESH_ClientConnect *cc_msg;
+ struct MeshClient *c;
+ unsigned int size;
+ uint16_t types;
+ uint16_t apps;
+
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "new client connected\n");
+ /* Check data sanity */
+ size = ntohs(message->size) - sizeof(struct GNUNET_MESH_ClientConnect);
+ cc_msg = (struct GNUNET_MESH_ClientConnect *) message;
+ types = ntohs(cc_msg->types);
+ apps = ntohs(cc_msg->applications);
+ if (size !=
+ types * sizeof(uint16_t) + apps * sizeof(GNUNET_MESH_ApplicationType))
+ {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Create new client structure */
+ c = GNUNET_malloc(sizeof(struct MeshClient));
+ c->handle = client;
+ if (types != 0) {
+ c->type_counter = types;
+ c->types = GNUNET_malloc(types * sizeof(uint16_t));
+ memcpy(c->types, &message[1], types * sizeof(uint16_t));
+ }
+ if (apps != 0) {
+ c->app_counter = apps;
+ c->apps = GNUNET_malloc(apps * sizeof(GNUNET_MESH_ApplicationType));
+ memcpy(c->apps,
+ &message[1] + types * sizeof(uint16_t),
+ apps * sizeof(GNUNET_MESH_ApplicationType));
+ }
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+ " client has %u+%u subscriptions\n",
+ c->type_counter,
+ c->app_counter);
+
+ GNUNET_CONTAINER_DLL_insert(clients, clients_tail, c);
+ c->tunnels = GNUNET_CONTAINER_multihashmap_create(32);
+
+ GNUNET_SERVER_receive_done(client, GNUNET_OK);
+
+}
+
+
+/**
+ * Handler for requests of new tunnels
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_local_tunnel_create (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_MESH_TunnelMessage *t_msg;
+ struct MeshTunnel *t;
+ struct MeshClient *c;
+ GNUNET_HashCode hash;
+
+ /* Sanity check for client registration */
+ if (NULL == (c = retrieve_client(client))) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Message sanity check */
+ if (sizeof(struct GNUNET_MESH_TunnelMessage) != ntohs(message->size)) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ t_msg = (struct GNUNET_MESH_TunnelMessage *) message;
+ /* Sanity check for tunnel numbering */
+ if (0 == (ntohl(t_msg->tunnel_id) & GNUNET_MESH_LOCAL_TUNNEL_ID_MARK)) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+ /* Sanity check for duplicate tunnel IDs */
+ if(NULL != retrieve_tunnel_by_local_id(c, ntohl(t_msg->tunnel_id))) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ t = GNUNET_malloc(sizeof(struct MeshTunnel));
+ while (NULL != retrieve_tunnel_by_pi(myid, next_tid))
+ next_tid = (next_tid + 1) % GNUNET_MESH_LOCAL_TUNNEL_ID_MARK;
+ t->id.tid = next_tid++;
+ t->id.oid = myid;
+ t->local_tid = ntohl(t_msg->tunnel_id);
+ t->client = c;
+ t->peers = GNUNET_CONTAINER_multihashmap_create(32);
+
+ GNUNET_CRYPTO_hash(&t->local_tid, sizeof(MESH_TunnelNumber), &hash);
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put(c->tunnels, &hash, t,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put(tunnels, &hash, t,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ GNUNET_SERVER_receive_done(client, GNUNET_OK);
return;
}
+
/**
- * Handler for connection requests
+ * Handler for requests of deleting tunnels
*
* @param cls closure
* @param client identification of the client
* @param message the actual message
*/
static void
-handle_local_connect (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader *message)
+handle_local_tunnel_destroy (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_MESH_TunnelMessage *tunnel_msg;
+ struct MeshClient *c;
+ struct MeshTunnel *t;
+ MESH_TunnelNumber tid;
+ GNUNET_HashCode hash;
+
+
+ /* Sanity check for client registration */
+ if (NULL == (c = retrieve_client(client))) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+ /* Message sanity check */
+ if (sizeof(struct GNUNET_MESH_TunnelMessage) != ntohs(message->size)) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ tunnel_msg = (struct GNUNET_MESH_TunnelMessage *) message;
+
+ /* Retrieve tunnel */
+ tid = ntohl(tunnel_msg->tunnel_id);
+
+ /* Remove from local id hashmap */
+ GNUNET_CRYPTO_hash(&tid, sizeof(MESH_TunnelNumber), &hash);
+ t = GNUNET_CONTAINER_multihashmap_get(c->tunnels, &hash);
+ GNUNET_CONTAINER_multihashmap_remove(c->tunnels, &hash, t);
+
+ /* Remove from global id hashmap */
+ GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
+ GNUNET_CONTAINER_multihashmap_remove(tunnels, &hash, t);
+
+// notify_tunnel_destroy(t);
+ GNUNET_SERVER_receive_done(client, GNUNET_OK);
+ return;
+}
+
+
+/**
+ * Handler for connection requests to new peers
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message (PeerControl)
+ */
+static void
+handle_local_connect_add (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_MESH_PeerControl *peer_msg;
+ struct MeshClient *c;
+ struct MeshTunnel *t;
+ MESH_TunnelNumber tid;
+ struct MeshPeerInfo *peer_info;
+
+
+ /* Sanity check for client registration */
+ if (NULL == (c = retrieve_client(client))) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ peer_msg = (struct GNUNET_MESH_PeerControl *)message;
+ /* Sanity check for message size */
+ if (sizeof(struct GNUNET_MESH_PeerControl)
+ != ntohs(peer_msg->header.size))
+ {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Tunnel exists? */
+ tid = ntohl(peer_msg->tunnel_id);
+ t = retrieve_tunnel_by_local_id(c, tid);
+ if (NULL == t) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Does client own tunnel? */
+ if (t->client->handle != client) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ t->peers_total++;
+ peer_info = get_peer_info(&peer_msg->peer);
+
+ /* Start DHT search if needed */
+ if(MESH_PEER_READY != peer_info->state && NULL == peer_info->dhtget) {
+ peer_info->dhtget = GNUNET_DHT_get_start(dht_handle,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_BLOCK_TYPE_ANY,
+ &peer_msg->peer.hashPubKey,
+ 4, /* replication level */
+ GNUNET_DHT_RO_RECORD_ROUTE,
+ NULL, /* bloom filter */
+ 0, /* mutator */
+ NULL, /* xquery */
+ 0, /* xquery bits */
+ dht_get_response_handler,
+ (void *)peer_info);
+ }
+
+ GNUNET_SERVER_receive_done(client, GNUNET_OK);
+ return;
+}
+
+
+/**
+ * Handler for disconnection requests of peers in a tunnel
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message (PeerControl)
+ */
+static void
+handle_local_connect_del (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
{
+ struct GNUNET_MESH_PeerControl *peer_msg;
+ struct MeshClient *c;
+ struct MeshTunnel *t;
+ MESH_TunnelNumber tid;
+ GNUNET_PEER_Id peer_id;
+
+ /* Sanity check for client registration */
+ if (NULL == (c = retrieve_client(client))) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+ peer_msg = (struct GNUNET_MESH_PeerControl *)message;
+ /* Sanity check for message size */
+ if (sizeof(struct GNUNET_MESH_PeerControl)
+ != ntohs(peer_msg->header.size))
+ {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Tunnel exists? */
+ tid = ntohl(peer_msg->tunnel_id);
+ t = retrieve_tunnel_by_local_id(c, tid);
+ if (NULL == t) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Does client own tunnel? */
+ if (t->client->handle != client) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Ok, delete peer from tunnel */
+ peer_id = GNUNET_PEER_intern(&peer_msg->peer);
+
+ /* FIXME Delete paths */
+ /* FIXME Delete peer info */
+
+ GNUNET_PEER_change_rc(peer_id, -1);
+
+ GNUNET_SERVER_receive_done(client, GNUNET_OK);
+ return;
+}
+
+
+/**
+ * Handler for connection requests to new peers by type
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message (ConnectPeerByType)
+ */
+static void
+handle_local_connect_by_type (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct GNUNET_MESH_ConnectPeerByType *connect_msg;
+ MESH_TunnelNumber tid;
+ GNUNET_MESH_ApplicationType application;
+ struct MeshClient *c;
+ struct MeshTunnel *t;
+
+ /* Sanity check for client registration */
+ if (NULL == (c = retrieve_client(client))) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ connect_msg = (struct GNUNET_MESH_ConnectPeerByType *)message;
+ /* Sanity check for message size */
+ if (sizeof(struct GNUNET_MESH_PeerControl) !=
+ ntohs(connect_msg->header.size))
+ {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Tunnel exists? */
+ tid = ntohl(connect_msg->tunnel_id);
+ t = retrieve_tunnel_by_local_id(c, tid);
+ if (NULL == t) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Does client own tunnel? */
+ if (t->client->handle != client) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Ok, lets find a peer offering the service */
+ application = ntohl(connect_msg->type);
+ application++; // FIXME silence warnings
+
+ GNUNET_SERVER_receive_done(client, GNUNET_OK);
return;
}
+
/**
- * Handler for client traffic
+ * Handler for client traffic directed to one peer
*
* @param cls closure
* @param client identification of the client
struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
+ struct MeshClient *c;
+ struct MeshTunnel *t;
+ struct GNUNET_MESH_Data *data_msg;
+ MESH_TunnelNumber tid;
+
+ /* Sanity check for client registration */
+ if (NULL == (c = retrieve_client(client))) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+ data_msg = (struct GNUNET_MESH_Data *)message;
+ /* Sanity check for message size */
+ if (sizeof(struct GNUNET_MESH_PeerControl) !=
+ ntohs(data_msg->header.size))
+ {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Tunnel exists? */
+ tid = ntohl(data_msg->tunnel_id);
+ t = retrieve_tunnel_by_local_id(c, tid);
+ if (NULL == t) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Does client own tunnel? */
+ if (t->client->handle != client) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* TODO */
+
+ GNUNET_SERVER_receive_done(client, GNUNET_OK);
return;
}
/**
- * Functions to handle messages from clients
+ * Handler for client traffic directed to all peers in a tunnel
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
*/
-/* MESSAGES DEFINED:
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT 272
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ANY 273
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ALL 274
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ADD 275
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_DEL 276
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE 277
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_CANCEL 278
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_TRANSMIT_READY 279
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATED 280
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROYED 281
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA 282
-#define GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA_BROADCAST 283
+static void
+handle_local_network_traffic_bcast (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct MeshClient *c;
+ struct MeshTunnel *t;
+ struct GNUNET_MESH_DataBroadcast *data_msg;
+ MESH_TunnelNumber tid;
+
+ /* Sanity check for client registration */
+ if (NULL == (c = retrieve_client(client))) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+ data_msg = (struct GNUNET_MESH_DataBroadcast *)message;
+ /* Sanity check for message size */
+ if (sizeof(struct GNUNET_MESH_PeerControl)
+ != ntohs(data_msg->header.size))
+ {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Tunnel exists? */
+ tid = ntohl(data_msg->tunnel_id);
+ t = retrieve_tunnel_by_local_id(c, tid);
+ if (NULL == t) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* Does client own tunnel? */
+ if (t->client->handle != client) {
+ GNUNET_break(0);
+ GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
+ return;
+ }
+
+ /* TODO */
+
+ GNUNET_SERVER_receive_done(client, GNUNET_OK);
+ return;
+}
+
+/**
+ * Functions to handle messages from clients
*/
static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
{&handle_local_new_client, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT, 0},
- {&handle_local_connect, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ANY, 0},
- {&handle_local_connect, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ALL, 0},
- {&handle_local_connect, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ADD, 0},
- {&handle_local_connect, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_DEL, 0},
- {&handle_local_connect, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE, sizeof(struct GNUNET_MESH_ConnectPeerByType)},
- {&handle_local_connect, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_CANCEL, sizeof(struct GNUNET_MESH_Control)},
- {&handle_local_network_traffic, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_TRANSMIT_READY, sizeof(struct GNUNET_MESH_Control)},
- {&handle_local_network_traffic, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA, 0}, /* FIXME needed? */
- {&handle_local_network_traffic, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA_BROADCAST, 0}, /* FIXME needed? */
+ {&handle_local_tunnel_create, NULL,
+ GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE,
+ sizeof(struct GNUNET_MESH_TunnelMessage)},
+ {&handle_local_tunnel_destroy, NULL,
+ GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY,
+ sizeof(struct GNUNET_MESH_TunnelMessage)},
+ {&handle_local_connect_add, NULL,
+ GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ADD,
+ sizeof(struct GNUNET_MESH_PeerControl)},
+ {&handle_local_connect_del, NULL,
+ GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_DEL,
+ sizeof(struct GNUNET_MESH_PeerControl)},
+ {&handle_local_connect_by_type, NULL,
+ GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE,
+ sizeof(struct GNUNET_MESH_ConnectPeerByType)},
+ {&handle_local_network_traffic, NULL,
+ GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA, 0},
+ {&handle_local_network_traffic_bcast, NULL,
+ GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA_BROADCAST, 0},
{NULL, NULL, 0, 0}
};
const struct GNUNET_PeerIdentity *identity,
const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Core init\n");
+ core_handle = server;
+ myid = GNUNET_PEER_intern(identity);
return;
}
const struct GNUNET_PeerIdentity *peer,
const struct GNUNET_TRANSPORT_ATS_Information *atsi)
{
+// GNUNET_PEER_Id pid;
+ struct MeshPeerInfo *peer_info;
+ struct MeshPath *path;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer connected\n");
+ peer_info = get_peer_info(peer);
+ if (myid == peer_info->id) {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " (self)\n");
+ }
+ path = GNUNET_malloc(sizeof(struct MeshPath));
+ path->length = 2;
+ path->peers = GNUNET_malloc(sizeof(GNUNET_PEER_Id) * 2);
+ path->peers[0] = myid;
+ path->peers[1] = peer_info->id;
+ add_path_to_peer(peer_info, path);
return;
}
const struct
GNUNET_PeerIdentity *peer)
{
+ GNUNET_PEER_Id pid;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer disconnected\n");
+ pid = GNUNET_PEER_intern(peer);
+ GNUNET_PEER_change_rc(pid, -1);
+ if (myid == pid) {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ " (self)\n");
+ }
return;
}
+
+/******************************************************************************/
+/************************ MAIN FUNCTIONS ****************************/
+/******************************************************************************/
+
/**
- * Process mesh requests. FIXME NON FUNCTIONAL, SKELETON
+ * Task run during shutdown.
+ *
+ * @param cls unused
+ * @param tc unused
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "shutting down\n");
+ if (core_handle != NULL) {
+ GNUNET_CORE_disconnect (core_handle);
+ core_handle = NULL;
+ }
+ if (dht_handle != NULL) {
+ GNUNET_DHT_disconnect (dht_handle);
+ dht_handle = NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "shut down\n");
+}
+
+/**
+ * Process mesh requests.
*
* @param cls closure
* @param server the initialized server
struct GNUNET_SERVER_Handle *server,
const struct GNUNET_CONFIGURATION_Handle *c)
{
- struct GNUNET_CORE_Handle *core;
-
- GNUNET_SERVER_add_handlers (server, plugin_handlers);
- GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
- core = GNUNET_CORE_connect (c, /* Main configuration */
- 32, /* queue size */
- NULL, /* Closure passed to MESH functions */
- &core_init, /* Call core_init once connected */
- &core_connect, /* Handle connects */
- &core_disconnect, /* remove peers on disconnects */
- NULL, /* Do we care about "status" updates? */
- NULL, /* Don't want notified about all incoming messages */
- GNUNET_NO, /* For header only inbound notification */
- NULL, /* Don't want notified about all outbound messages */
- GNUNET_NO, /* For header only outbound notification */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "starting to run\n");
+ GNUNET_SERVER_add_handlers (server, plugin_handlers);
+ GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
+ core_handle = GNUNET_CORE_connect (c, /* Main configuration */
+ 1, /* queue size */
+ NULL, /* Closure passed to MESH functions */
+ &core_init, /* Call core_init once connected */
+ &core_connect, /* Handle connects */
+ &core_disconnect, /* remove peers on disconnects */
+ NULL, /* Do we care about "status" updates? */
+ NULL, /* Don't notify about all incoming messages */
+ GNUNET_NO, /* For header only in notification */
+ NULL, /* Don't notify about all outbound messages */
+ GNUNET_NO, /* For header-only out notification */
core_handlers); /* Register these handlers */
+ if (core_handle == NULL) {
+ GNUNET_break(0);
+ }
+ dht_handle = GNUNET_DHT_connect(c, 64);
+ if (dht_handle == NULL) {
+ GNUNET_break(0);
+ }
+ next_tid = 0;
- if (core == NULL)
- return;
+ tunnels = GNUNET_CONTAINER_multihashmap_create(32);
+ peers = GNUNET_CONTAINER_multihashmap_create(32);
+ clients = NULL;
+ clients_tail = NULL;
+
+ /* Scheduled the task to clean up when shutdown is called */
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &shutdown_task, NULL);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "end if run()\n");
}
/**
int
main (int argc, char *const *argv)
{
- int ret;
-
- ret = (GNUNET_OK ==
- GNUNET_SERVICE_run (argc,
- argv,
- "mesh",
- GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
- return ret;
-}
\ No newline at end of file
+ int ret;
+
+ ret = (GNUNET_OK ==
+ GNUNET_SERVICE_run (argc,
+ argv,
+ "mesh",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run, NULL)) ? 0 : 1;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "end of main()\n");
+ return ret;
+}