2 This file is part of GNUnet.
3 (C) 2001 - 2011 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file mesh/gnunet-service-mesh.c
23 * @brief GNUnet MESH service
24 * @author Bartlomiej Polot
29 * - MESH NETWORK HANDLER HELPERS
30 * - MESH NETWORK HANDLES
31 * - MESH LOCAL HANDLER HELPERS
32 * - MESH LOCAL HANDLES
33 * - PERIODIC FUNCTIONS
34 * - MAIN FUNCTIONS (main & run)
37 * - error reporting (CREATE/CHANGE/ADD/DEL?) -- new message!
38 * - partial disconnect reporting -- same as error reporting?
39 * - add vs create? change vs. keep-alive? same msg or different ones? -- thinking...
40 * - speed requirement specification (change?) in mesh API -- API call
41 * - add ping message (connection confirmation, others?)
45 #include "gnunet_common.h"
46 #include "gnunet_util_lib.h"
47 #include "gnunet_peer_lib.h"
48 #include "gnunet_core_service.h"
49 #include "gnunet_protocols.h"
52 #include "mesh_protocol.h"
53 #include "gnunet_dht_service.h"
55 #define REFRESH_PATH_TIME GNUNET_TIME_relative_multiply(\
56 GNUNET_TIME_UNIT_SECONDS,\
60 /******************************************************************************/
61 /************************ DATA STRUCTURES ****************************/
62 /******************************************************************************/
65 * Information regarding a path
73 struct MeshPath *next;
74 struct MeshPath *prev;
77 * Whether the path is serving traffic in a tunnel or is a backup
82 * List of all the peers that form the path from origin to target
84 GNUNET_PEER_Id *peers;
87 * Number of peers (hops) in the path
94 * All the states a peer participating in a tunnel can be in.
99 * Path to the peer not known yet
104 * Request sent, not yet answered.
109 * Peer connected and ready to accept data
114 * Peer connected previosly but not responding
116 MESH_PEER_RECONNECTING
121 * Struct containing all information regarding a given peer
131 * Is the peer reachable? Is the peer even connected?
133 enum MeshPeerState state;
136 * Last time we heard from this peer
138 struct GNUNET_TIME_Absolute last_contact;
141 * Number of attempts to reconnect so far
143 int n_reconnect_attempts;
146 * Paths to reach the peer
148 struct MeshPath *path;
149 struct MeshPath *path_tail;
152 * Handle to stop the DHT search for a path to this peer
154 struct GNUNET_DHT_GetHandle *dhtget;
159 * Data scheduled to transmit (to local client or remote peer)
166 struct MeshQueue *next;
167 struct MeshQueue *prev;
170 * Target of the data (NULL if target is client)
172 struct MeshPeerInfo *peer;
175 * Client to send the data to (NULL if target is peer)
177 struct MeshClient *client;
180 * Size of the message to transmit
185 * How old is the data?
187 struct GNUNET_TIME_Absolute timestamp;
192 struct GNUNET_MessageHeader *data;
196 * Globally unique tunnel identification (owner + number)
197 * DO NOT USE OVER THE NETWORK
199 struct MESH_TunnelID {
201 * Node that owns the tunnel
206 * Tunnel number to differentiate all the tunnels owned by the node oid
207 * ( tid < GNUNET_MESH_LOCAL_TUNNEL_ID_MARK )
209 MESH_TunnelNumber tid;
213 struct MeshClient; /* FWD declaration */
215 * Struct containing all information regarding a tunnel
216 * For an intermediate node the improtant info used will be:
217 * - id Tunnel unique identification
218 * - paths[0] To know where to send it next
219 * - metainfo: ready, speeds, accounting
226 struct MESH_TunnelID id;
229 * Local tunnel number ( >= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK or 0 )
231 MESH_TunnelNumber local_tid;
234 * Last time the tunnel was used
236 struct GNUNET_TIME_Absolute timestamp;
239 * Peers in the tunnelindexed by PeerIdentity (MeshPeerInfo)
241 struct GNUNET_CONTAINER_MultiHashMap* peers;
244 * Number of peers that are connected and potentially ready to receive data
246 unsigned int peers_ready;
249 * Number of peers that have been added to the tunnel
251 unsigned int peers_total;
255 * Client owner of the tunnel, if any
257 struct MeshClient *client;
260 * Messages ready to transmit
262 struct MeshQueue *queue_head;
263 struct MeshQueue *queue_tail;
268 * Struct containing information about a client of the service
275 struct MeshClient *next;
276 struct MeshClient *prev;
279 * Tunnels that belong to this client, indexed by local id
281 struct GNUNET_CONTAINER_MultiHashMap* tunnels;
284 * Handle to communicate with the client
286 struct GNUNET_SERVER_Client *handle;
289 * Applications that this client has claimed to provide
291 GNUNET_MESH_ApplicationType *apps;
292 unsigned int app_counter;
295 * Messages that this client has declared interest in
298 unsigned int type_counter;
302 /******************************************************************************/
303 /*********************** GLOBAL VARIABLES ****************************/
304 /******************************************************************************/
309 static struct MeshClient *clients;
310 static struct MeshClient *clients_tail;
313 * Tunnels known, indexed by MESH_TunnelID (MeshTunnel)
315 static struct GNUNET_CONTAINER_MultiHashMap *tunnels;
318 * Peers known, indexed by PeerIdentity (MeshPeerInfo)
320 static struct GNUNET_CONTAINER_MultiHashMap *peers;
323 * Handle to communicate with core
325 static struct GNUNET_CORE_Handle *core_handle;
330 static struct GNUNET_DHT_Handle *dht_handle;
333 * Local peer own ID (memory efficient handle)
335 static GNUNET_PEER_Id myid;
338 * Tunnel ID for the next created tunnel (global tunnel number)
340 static MESH_TunnelNumber next_tid;
342 /******************************************************************************/
343 /****************** GENERAL HELPER FUNCTIONS ************************/
344 /******************************************************************************/
347 * Retrieve the MeshPeerInfo stucture associated with the peer, create one
348 * and inster it in the appropiate structures if the peer is not known yet.
349 * @param peer Identity of the peer
350 * @return Existing or newly created peer info
352 static struct MeshPeerInfo *
353 get_peer_info (const struct GNUNET_PeerIdentity *peer)
355 struct MeshPeerInfo * peer_info;
357 peer_info = GNUNET_CONTAINER_multihashmap_get(peers,
359 if (NULL == peer_info) {
360 peer_info = (struct MeshPeerInfo *)
361 GNUNET_malloc(sizeof(struct MeshPeerInfo));
362 GNUNET_CONTAINER_multihashmap_put(peers,
365 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
366 peer_info->id = GNUNET_PEER_intern(peer);
367 peer_info->state = MESH_PEER_SEARCHING;
374 * Find the first peer whom to send a packet to go down this path
375 * @param path The path to use
376 * @return short id of the next peer, myid in case of local delivery,
377 * or 0 in case of error
379 static GNUNET_PEER_Id
380 get_first_hop (struct MeshPath *path)
384 while (NULL != path) {
385 if (path->in_use) break;
389 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
390 "tried to get the next hop from an invalid path\n");
394 for (i = 0; i < path->length; i++) {
395 if (path->peers[i] == myid) {
396 if (i < path->length - 1) {
397 return path->peers[i+1];
408 * Get the cost of the path.
409 * @param path The path to analyze
410 * @return Number of hops to reach destination, UINT_MAX in case the peer is not
414 get_path_cost(struct MeshPath *path)
418 if (NULL == path) return UINT_MAX;
419 for (i = 0; i < path->length; i++) {
420 if (path->peers[i] == myid) {
421 return path->length - i;
429 * Add the path to the peer and update the path used to reach it in case this
431 * @param peer_info Destination peer to add the path to.
432 * @param path New path to add. Last peer must be the peer in arg 1.
435 add_path_to_peer(struct MeshPeerInfo *peer_info, struct MeshPath *path)
438 unsigned int new_cost;
439 unsigned int best_cost;
440 struct MeshPath *aux;
441 struct MeshPath *best;
443 if (NULL == peer_info || NULL == path) return;
445 new_cost = get_path_cost(path);
446 best_cost = UINT_MAX;
448 for (aux = peer_info->path; aux != NULL; aux = aux->next) {
449 if ((i = get_path_cost(aux)) < best_cost) {
454 if (best_cost < new_cost) {
456 GNUNET_CONTAINER_DLL_insert_tail(peer_info->path,
457 peer_info->path_tail,
460 if (NULL != best) best->in_use = 0;
462 GNUNET_CONTAINER_DLL_insert(peer_info->path,
463 peer_info->path_tail,
471 * Add the path to the peer and update the path used to reach it in case this
472 * is the shortest. The path is given in reverse, the destination peer is
473 * path[0]. The function modifies the path, inverting it to use the origin as
475 * @param peer_info Destination peer to add the path to.
476 * @param path New path to add. First peer must be the peer in arg 1.
479 add_path_to_origin(struct MeshPeerInfo *peer_info, struct MeshPath *path)
484 for (i = 0; i < path->length/2; i++) {
485 aux = path->peers[i];
486 path->peers[i] = path->peers[path->length - i - 1];
487 path->peers[path->length - i - 1] = aux;
489 add_path_to_peer(peer_info, path);
494 * Check if client has registered with the service and has not disconnected
495 * @param client the client to check
496 * @return non-NULL if client exists in the global DLL
498 static struct MeshClient *
499 retrieve_client (struct GNUNET_SERVER_Client *client)
501 struct MeshClient *c;
505 if (c->handle == client) return c;
513 * Checks if a given client has subscribed to certain message type
514 * @param message_type Type of message to check
515 * @param c Client to check
516 * @return GNUNET_YES or GNUNET_NO, depending on subscription status
519 is_client_subscribed(uint16_t message_type, struct MeshClient *c)
523 for (i = 0; i < c->type_counter; i++) {
524 if (c->types[i] == message_type) return GNUNET_YES;
531 * Search for a tunnel among the tunnels for a client
532 * @param client the client whose tunnels to search in
533 * @param tid the local id of the tunnel
534 * @return tunnel handler, NULL if doesn't exist
536 static struct MeshTunnel *
537 retrieve_tunnel_by_local_id (struct MeshClient *c, MESH_TunnelNumber tid)
539 GNUNET_HashCode hash;
541 GNUNET_CRYPTO_hash(&tid, sizeof(MESH_TunnelNumber), &hash);
542 return GNUNET_CONTAINER_multihashmap_get(c->tunnels, &hash);
546 * Search for a tunnel by global ID using PEER_ID
547 * @param pi owner of the tunnel
548 * @param tid global tunnel number
549 * @return tunnel handler, NULL if doesn't exist
551 static struct MeshTunnel *
552 retrieve_tunnel_by_pi (GNUNET_PEER_Id pi, MESH_TunnelNumber tid)
554 struct MESH_TunnelID id;
555 GNUNET_HashCode hash;
560 GNUNET_CRYPTO_hash(&id, sizeof(struct MESH_TunnelID), &hash);
561 return GNUNET_CONTAINER_multihashmap_get(tunnels, &hash);
567 * Search for a tunnel by global ID using full PeerIdentities
568 * @param oid owner of the tunnel
569 * @param tid global tunnel number
570 * @return tunnel handler, NULL if doesn't exist
572 static struct MeshTunnel *
573 retrieve_tunnel (struct GNUNET_PeerIdentity *oid, MESH_TunnelNumber tid)
575 return retrieve_tunnel_by_pi(GNUNET_PEER_search(oid), tid);
580 * Destroy the path and free any allocated resources linked to it
581 * @param t tunnel the path belongs to
582 * @param p the path to destroy
583 * @return GNUNET_OK on success
586 destroy_path(struct MeshPath *p)
588 GNUNET_PEER_decrement_rcs(p->peers, p->length);
589 GNUNET_free(p->peers);
596 * Destroy the peer_info and free any allocated resources linked to it
597 * @param t tunnel the path belongs to
598 * @param pi the peer_info to destroy
599 * @return GNUNET_OK on success
602 destroy_peer_info(struct MeshPeerInfo *pi)
604 GNUNET_HashCode hash;
605 struct GNUNET_PeerIdentity id;
607 GNUNET_PEER_resolve(pi->id, &id);
608 GNUNET_PEER_change_rc(pi->id, -1);
609 GNUNET_CRYPTO_hash(&id, sizeof(struct GNUNET_PeerIdentity), &hash);
611 GNUNET_CONTAINER_multihashmap_remove(peers, &hash, pi);
619 * Destroy the tunnel and free any allocated resources linked to it
620 * @param c client the tunnel belongs to
621 * @param t the tunnel to destroy
622 * @return GNUNET_OK on success
625 destroy_tunnel(struct MeshTunnel *t)
627 struct MeshClient *c;
628 GNUNET_HashCode hash;
631 if (NULL == t) return GNUNET_OK;
635 GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
636 if(GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove(tunnels, &hash, t)) {
640 GNUNET_CRYPTO_hash(&t->local_tid, sizeof(MESH_TunnelNumber), &hash);
642 GNUNET_CONTAINER_multihashmap_remove(c->tunnels, &hash, t))
650 /******************************************************************************/
651 /**************** MESH NETWORK HANDLER HELPERS ***********************/
652 /******************************************************************************/
655 * Function called to notify a client about the socket
656 * being ready to queue more data. "buf" will be
657 * NULL and "size" zero if the socket was closed for
658 * writing in the meantime.
661 * @param size number of bytes available in buf
662 * @param buf where the callee should write the message
663 * @return number of bytes written to buf
666 send_core_create_path_for_peer (void *cls, size_t size, void *buf)
668 struct MeshPeerInfo *peer_info = cls;
669 struct GNUNET_MESH_ManipulatePath *msg;
671 struct GNUNET_PeerIdentity *peer_ptr;
672 struct GNUNET_PeerIdentity id;
676 if (0 == size && NULL == buf) {
677 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Retransmitting create path\n");
678 GNUNET_PEER_resolve(get_first_hop(peer_info->path), &id);
679 GNUNET_CORE_notify_transmit_ready(core_handle,
682 GNUNET_TIME_UNIT_FOREVER_REL,
684 sizeof(struct GNUNET_MESH_ManipulatePath)
685 + (peer_info->path->length
686 * sizeof (struct GNUNET_PeerIdentity)),
687 &send_core_create_path_for_peer,
698 if (p == NULL) return 0; // TODO Notify ERROR Path not found
700 size_needed = sizeof(struct GNUNET_MESH_ManipulatePath)
701 + p->length * sizeof(struct GNUNET_PeerIdentity);
702 if (size < size_needed) {
703 // TODO retry? cancel?
707 msg = (struct GNUNET_MESH_ManipulatePath *) buf;
708 msg->header.size = htons(size_needed);
709 msg->header.type = htons(GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE);
711 peer_ptr = (struct GNUNET_PeerIdentity *) &msg[1];
712 for (i = 0; i < p->length; i++) {
713 GNUNET_PEER_resolve(p->peers[i], peer_ptr++);
716 peer_info->state = MESH_PEER_WAITING;
723 * There are several options to send a "data to origin" or similar packet.
724 * The core callback function needs to know at least: ID of tunnel and the
725 * data itself, so one parameter (cls) is not enough.
726 * 1. Build the message inside the original funtction, call core_ntfy_trnsmt_rdy
727 * passing the created message as cls
728 * - # memcpy: 2 (function X: to message struct, callback: from cls to buf)
729 * - Very messy, original function becomes huge and ugly
730 * (see "handle_mesh_path_create" for example)
731 * 2. Create a helper function to build the packet, then call
732 * core_ntfy_trnsmt_rdy with message as cls.
733 * - # memcpy: 2 (in helper function data->msg and in callback cls->buf)
734 * 3- Define new container, pass container with pointers
735 * - # memcpy = 1 (in callback, cls->buf)
736 * - Noise: extra containers defined per type of message
738 struct info_for_data_to_origin
740 struct MESH_TunnelID *origin;
746 * Function called to notify a client about the socket
747 * being ready to queue more data. "buf" will be
748 * NULL and "size" zero if the socket was closed for
749 * writing in the meantime.
751 * @param cls closure (info_for_data_to_origin with all info to build packet)
752 * @param size number of bytes available in buf
753 * @param buf where the callee should write the message
754 * @return number of bytes written to buf
757 send_core_data_to_origin (void *cls, size_t size, void *buf)
759 struct info_for_data_to_origin *info = cls;
760 struct GNUNET_MESH_DataMessageToOrigin *msg = buf;
763 GNUNET_assert(NULL != info);
764 total_size = sizeof(struct GNUNET_MESH_DataMessageToOrigin) + info->size;
765 GNUNET_assert(total_size < (uint16_t) -1); /* FIXME */
767 if (total_size > size) {
768 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
769 "not enough buffer to send data to origin\n");
772 msg->header.size = htons(total_size);
773 msg->header.type = htons(GNUNET_MESSAGE_TYPE_DATA_MESSAGE_TO_ORIGIN);
774 GNUNET_PEER_resolve(info->origin->oid, &msg->oid);
775 msg->tid = htonl(info->origin->tid);
776 if (0 != info->size && NULL != info->data) {
777 memcpy(&msg[1], info->data, info->size);
784 * Function called to notify a client about the socket
785 * being ready to queue more data. "buf" will be
786 * NULL and "size" zero if the socket was closed for
787 * writing in the meantime.
789 * @param cls closure (data itself)
790 * @param size number of bytes available in buf
791 * @param buf where the callee should write the message
792 * @return number of bytes written to buf
795 send_core_data_raw (void *cls, size_t size, void *buf)
797 struct GNUNET_MessageHeader *msg = cls;
800 GNUNET_assert(NULL != msg);
801 total_size = ntohs(msg->size);
803 if (total_size > size) {
804 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
805 "not enough buffer to send data futher\n");
808 memcpy(msg, buf, total_size);
815 * Function called to notify a client about the socket
816 * being ready to queue more data. "buf" will be
817 * NULL and "size" zero if the socket was closed for
818 * writing in the meantime.
820 * @param cls closure (data itself)
821 * @param size number of bytes available in buf
822 * @param buf where the callee should write the message
823 * @return number of bytes written to buf
826 send_core_data_multicast (void *cls, size_t size, void *buf)
828 struct GNUNET_MESH_DataMessageFromOrigin *msg = cls;
831 GNUNET_assert(NULL != msg);
832 total_size = ntohs(msg->header.size);
834 if (total_size > size) {
835 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
836 "not enough buffer to send data futher\n");
839 memcpy(msg, buf, total_size);
845 * Function called to notify a client about the socket
846 * being ready to queue more data. "buf" will be
847 * NULL and "size" zero if the socket was closed for
848 * writing in the meantime.
850 * @param cls closure (data itself)
851 * @param size number of bytes available in buf
852 * @param buf where the callee should write the message
853 * @return number of bytes written to buf
856 send_core_data_to_peer (void *cls, size_t size, void *buf)
858 struct info_for_data_to_origin *info = cls;
859 struct GNUNET_MESH_DataMessageToOrigin *msg = buf;
862 GNUNET_assert(NULL != info);
863 total_size = sizeof(struct GNUNET_MESH_DataMessageToOrigin) + info->size;
864 /* FIXME better constant? short >= 16 bits, not == 16 bits... */
865 GNUNET_assert(total_size < USHRT_MAX);
867 if (total_size > size) {
868 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
869 "not enough buffer to send data to origin\n");
872 msg->header.size = htons(total_size);
873 msg->header.type = htons(GNUNET_MESSAGE_TYPE_DATA_MESSAGE_TO_ORIGIN);
874 GNUNET_PEER_resolve(info->origin->oid, &msg->oid);
875 msg->tid = htonl(info->origin->tid);
876 if (0 != info->size && NULL != info->data) {
877 memcpy(&msg[1], info->data, info->size);
885 * Send another peer a notification to destroy a tunnel
886 * @param cls The tunnel to destroy
887 * @param size Size in the buffer
888 * @param buf Memory where to put the data to transmit
889 * @return Size of data put in buffer
892 send_p2p_tunnel_destroy(void *cls, size_t size, void *buf)
894 struct MeshTunnel *t = cls;
895 struct MeshClient *c;
896 struct GNUNET_MESH_TunnelMessage *msg;
900 msg->header.type = htons(GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY); /*FIXME*/
901 msg->header.size = htons(sizeof(struct GNUNET_MESH_TunnelMessage));
902 msg->tunnel_id = htonl(t->id.tid);
904 destroy_tunnel(c, t);
905 return sizeof(struct GNUNET_MESH_TunnelMessage);
911 * Function called to notify a client about the socket
912 * begin ready to queue more data. "buf" will be
913 * NULL and "size" zero if the socket was closed for
914 * writing in the meantime.
917 * @param size number of bytes available in buf
918 * @param buf where the callee should write the message
919 * @return number of bytes written to buf
922 send_client_raw (void *cls, size_t size, void *buf)
924 GNUNET_MessageHeader *msg = cls;
927 msg_size = ntohs(msg->size);
928 if (msg_size > size) {
929 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
930 "deliver to client failed: buffer too small\n");
933 memcpy(buf, cls, msg_size);
939 * Iterator over hash map peer entries to resend a data packet to all peers
942 * @param cls closure (original message)
943 * @param key current key code (peer id hash)
944 * @param value value in the hash map (peer_info)
945 * @return GNUNET_YES if we should continue to iterate, GNUNET_NO if not.
947 static int iterate_resend_multicast (void *cls,
948 const GNUNET_HashCode * key,
951 struct GNUNET_MESH_DataMessageMulticast *msg = cls;
952 struct GNUNET_PeerIdentity id;
953 struct MeshPeerInfo *peer_info = value;
955 if (peer_info->id == myid) {
956 // TODO retransmit to interested clients
959 GNUNET_PEER_resolve(get_first_hop(peer_info->path), &id);
960 GNUNET_CORE_notify_transmit_ready(core_handle,
963 GNUNET_TIME_UNIT_FOREVER_REL,
965 ntohs(msg->header.size),
972 /******************************************************************************/
973 /******************** MESH NETWORK HANDLERS **************************/
974 /******************************************************************************/
978 * Core handler for path creation
979 * struct GNUNET_CORE_MessageHandler
982 * @param message message
983 * @param peer peer identity this notification is about
984 * @param atsi performance data
985 * @return GNUNET_OK to keep the connection open,
986 * GNUNET_SYSERR to close it (signal serious error)
990 handle_mesh_path_create (void *cls,
991 const struct GNUNET_PeerIdentity *peer,
992 const struct GNUNET_MessageHeader *message,
993 const struct GNUNET_TRANSPORT_ATS_Information
996 unsigned int own_pos;
999 MESH_TunnelNumber tid;
1000 struct GNUNET_MESH_ManipulatePath *msg;
1001 struct GNUNET_PeerIdentity *pi;
1002 struct GNUNET_PeerIdentity id;
1003 GNUNET_HashCode hash;
1004 struct MeshPath *path;
1005 struct MeshPeerInfo *dest_peer_info;
1006 struct MeshPeerInfo *orig_peer_info;
1007 struct MeshTunnel *t;
1010 size = ntohs(message->size);
1011 if (size < sizeof(struct GNUNET_MESH_ManipulatePath)) {
1012 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1013 "received create path message too short\n");
1017 size -= sizeof(struct GNUNET_MESH_ManipulatePath);
1018 if (size < 2 * sizeof(struct GNUNET_PeerIdentity)) {
1019 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1020 "create path message lacks enough peers\n");
1023 if (size % sizeof(struct GNUNET_PeerIdentity)) {
1024 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1025 "create path message of wrong size\n");
1028 msg = (struct GNUNET_MESH_ManipulatePath *) message;
1029 size /= sizeof(struct GNUNET_PeerIdentity);
1031 tid = ntohl(msg->tid);
1032 pi = (struct GNUNET_PeerIdentity *) &msg[1];
1033 t = retrieve_tunnel(pi, tid);
1036 t = GNUNET_malloc(sizeof(struct MeshTunnel));
1037 t->id.oid = GNUNET_PEER_intern(pi);
1041 t->peers = GNUNET_CONTAINER_multihashmap_create(32);
1043 GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
1045 GNUNET_CONTAINER_multihashmap_put(tunnels,
1048 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1050 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1051 "create path: could not store tunnel in hashmap\n");
1056 dest_peer_info = GNUNET_CONTAINER_multihashmap_get(peers,
1057 &pi[size - 1].hashPubKey);
1058 if (NULL == dest_peer_info) {
1059 dest_peer_info = GNUNET_malloc(sizeof(struct MeshPeerInfo));
1060 dest_peer_info->id = GNUNET_PEER_intern(&pi[size - 1]);
1061 dest_peer_info->state = MESH_PEER_WAITING;
1062 GNUNET_CONTAINER_multihashmap_put(peers,
1063 &pi[size - 1].hashPubKey,
1065 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1067 orig_peer_info = GNUNET_CONTAINER_multihashmap_get(peers, &pi->hashPubKey);
1068 if (NULL == orig_peer_info) {
1069 orig_peer_info = GNUNET_malloc(sizeof(struct MeshPeerInfo));
1070 orig_peer_info->id = GNUNET_PEER_intern(pi);
1071 orig_peer_info->state = MESH_PEER_WAITING;
1072 GNUNET_CONTAINER_multihashmap_put(peers,
1075 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1079 path = GNUNET_malloc(sizeof(struct MeshPath));
1080 path->length = size;
1081 path->peers = GNUNET_malloc(size * sizeof(GNUNET_PEER_Id));
1083 for (i = 0; i < size; i++) {
1084 path->peers[i] = GNUNET_PEER_intern(&pi[i]);
1085 if (path->peers[i] == myid) own_pos = i;
1087 if (own_pos == 0) { /* cannot be self, must be 'not found' */
1088 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1089 "create path: self not found in path through self\n");
1091 /* FIXME error. destroy tunnel? leave for timeout? */
1094 if (own_pos == size - 1) { /* it is for us! */
1095 add_path_to_origin(orig_peer_info, path); /* inverts path! */
1096 GNUNET_PEER_resolve(get_first_hop(path), &id); /* path is inverted :) */
1098 * is it allowed/desired to declare variables this way?
1099 * (style, best practices, etc)
1100 * This variable is short lived and completely irrelevant for the rest
1103 struct info_for_data_to_origin *info =
1104 GNUNET_malloc(sizeof(struct info_for_data_to_origin));
1105 info->origin = &t->id;
1108 GNUNET_CORE_notify_transmit_ready(core_handle,
1111 GNUNET_TIME_UNIT_FOREVER_REL,
1113 sizeof(struct GNUNET_MessageHeader),
1114 &send_core_data_to_origin,
1117 add_path_to_peer(dest_peer_info, path);
1118 GNUNET_PEER_resolve(get_first_hop(path), &id);
1119 GNUNET_CORE_notify_transmit_ready(core_handle,
1122 GNUNET_TIME_UNIT_FOREVER_REL,
1124 sizeof(struct GNUNET_MessageHeader),
1125 &send_core_create_path_for_peer,
1133 * Core handler for mesh network traffic going from the origin to a peer
1135 * @param cls closure
1136 * @param message message
1137 * @param peer peer identity this notification is about
1138 * @param atsi performance data
1139 * @return GNUNET_OK to keep the connection open,
1140 * GNUNET_SYSERR to close it (signal serious error)
1143 handle_mesh_data_unicast (void *cls,
1144 const struct GNUNET_PeerIdentity *peer,
1145 const struct GNUNET_MessageHeader *message,
1146 const struct GNUNET_TRANSPORT_ATS_Information
1149 struct GNUNET_MESH_DataMessageFromOrigin *msg;
1150 struct GNUNET_PeerIdentity id;
1151 struct MeshTunnel *t;
1152 struct MeshPeerInfo *pi;
1153 struct MeshClient *c;
1155 uint16_t payload_type;
1157 size = ntohs(message->size);
1158 if (size < sizeof(struct GNUNET_MESH_DataMessageFromOrigin)) {
1159 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1160 "got data from origin packet: too short\n");
1161 return GNUNET_OK; // FIXME maybe SYSERR? peer misbehaving?
1163 msg = (struct GNUNET_MESH_DataMessageFromOrigin *) message;
1164 t = retrieve_tunnel(&msg->oid, ntohl(msg->tid));
1166 /* TODO: are we so nice that we try to send it to OID anyway? We *could*
1167 * know how to reach it, from the global peer hashmap
1171 pi = GNUNET_CONTAINER_multihashmap_get(t->peers,
1172 &msg->destination.hashPubKey);
1174 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1175 "got invalid data from origin packet: wrong destination\n");
1176 /* TODO are we so nice to try to deliver it anyway? maybe we missed
1177 * a Create_Path packet that added the peer but we have it in the
1178 * _global_ peer pool anyway...
1182 if (pi->id == myid) {
1183 payload_type = ntohs(msg[1].header.type);
1184 for (c = clients; NULL != c; c = c->next) {
1185 if (is_client_subscribed(payload_type, c)) {
1186 GNUNET_SERVER_notify_transmit_ready(c,
1187 size - sizeof(struct GNUNET_MESH_DataMessageFromOrigin),
1188 GNUNET_TIME_UNIT_FOREVER_REL,
1195 GNUNET_PEER_resolve(get_first_hop(pi->path), &id);
1196 GNUNET_CORE_notify_transmit_ready(core_handle,
1199 GNUNET_TIME_UNIT_FOREVER_REL,
1202 &send_core_data_raw,
1209 * Core handler for mesh network traffic going from the origin to all peers
1211 * @param cls closure
1212 * @param message message
1213 * @param peer peer identity this notification is about
1214 * @param atsi performance data
1215 * @return GNUNET_OK to keep the connection open,
1216 * GNUNET_SYSERR to close it (signal serious error)
1219 handle_mesh_data_multicast (void *cls,
1220 const struct GNUNET_PeerIdentity *peer,
1221 const struct GNUNET_MessageHeader *message,
1222 const struct GNUNET_TRANSPORT_ATS_Information
1225 struct GNUNET_MESH_DataMessageMulticast *msg;
1226 struct MeshTunnel *t;
1229 size = ntohs(message->size);
1230 if (size < sizeof(struct GNUNET_MESH_DataMessageMulticast)) {
1231 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1232 "got multicast packet: too short\n");
1233 return GNUNET_OK; // FIXME maybe SYSERR? peer misbehaving?
1235 msg = (struct GNUNET_MESH_DataMessageMulticast *) message;
1236 t = retrieve_tunnel(&msg->oid, ntohl(msg->tid));
1242 GNUNET_CONTAINER_multihashmap_iterate(t->peers,
1243 &iterate_resend_multicast,
1251 * Core handler for mesh network traffic
1253 * @param cls closure
1254 * @param message message
1255 * @param peer peer identity this notification is about
1256 * @param atsi performance data
1257 * @return GNUNET_OK to keep the connection open,
1258 * GNUNET_SYSERR to close it (signal serious error)
1261 handle_mesh_data_to_orig (void *cls,
1262 const struct GNUNET_PeerIdentity *peer,
1263 const struct GNUNET_MessageHeader *message,
1264 const struct GNUNET_TRANSPORT_ATS_Information
1267 struct GNUNET_MESH_DataMessageToOrigin *msg;
1268 struct GNUNET_PeerIdentity id;
1269 struct MeshTunnel *t;
1270 struct MeshPeerInfo *peer_info;
1273 size = ntohs(message->size);
1274 if (size < sizeof(struct GNUNET_MESH_DataMessageToOrigin)) {
1275 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1276 "got invalid data to origin packet: too short\n");
1277 return GNUNET_OK; // FIXME maybe SYSERR? peer misbehaving?
1279 msg = (struct GNUNET_MESH_DataMessageToOrigin *) message;
1280 t = retrieve_tunnel(&msg->oid, ntohl(msg->tid));
1283 /* TODO: are we so nice that we try to send it to OID anyway? We *could*
1284 * know how to reach it, from the global peer hashmap
1289 if (t->id.oid == myid) {
1290 if (NULL == t->client) {
1291 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
1292 "got data packet for ownerless tunnel\n");
1295 // TODO retransmit to client owner
1298 peer_info = get_peer_info(&msg->oid);
1299 if (NULL == peer_info) {
1300 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1301 "unknown origin of tunnel\n");
1304 GNUNET_PEER_resolve(get_first_hop(peer_info->path), &id);
1305 GNUNET_CORE_notify_transmit_ready(core_handle,
1308 GNUNET_TIME_UNIT_FOREVER_REL,
1311 &send_core_data_raw,
1319 * Functions to handle messages from core
1321 static struct GNUNET_CORE_MessageHandler core_handlers[] = {
1322 {&handle_mesh_path_create, GNUNET_MESSAGE_TYPE_MESH_PATH_CREATE, 0},
1323 {&handle_mesh_data_unicast, GNUNET_MESSAGE_TYPE_DATA_MESSAGE_FROM_ORIGIN, 0},
1324 {&handle_mesh_data_multicast, GNUNET_MESSAGE_TYPE_DATA_MULTICAST, 0},
1325 {&handle_mesh_data_to_orig, GNUNET_MESSAGE_TYPE_DATA_MESSAGE_TO_ORIGIN, 0},
1331 /******************************************************************************/
1332 /**************** MESH LOCAL HANDLER HELPERS ***********************/
1333 /******************************************************************************/
1336 * delete_tunnel_entry: iterator for deleting each tunnel that belongs to a
1337 * client when the client disconnects.
1338 * @param cls closure (client that is disconnecting)
1339 * @param key the hash of the local tunnel id (used to access the hashmap)
1340 * @param value the value stored at the key (tunnel to destroy)
1341 * @return GNUNET_OK on success
1344 delete_tunnel_entry (void *cls, const GNUNET_HashCode * key, void *value) {
1346 r = destroy_tunnel((struct MeshTunnel *) value);
1352 * notify_client_connection_failure: notify a client that the connection to the
1353 * requested remote peer is not possible (for instance, no route found)
1354 * Function called when the socket is ready to queue more data. "buf" will be
1355 * NULL and "size" zero if the socket was closed for writing in the meantime.
1357 * @param cls closure
1358 * @param size number of bytes available in buf
1359 * @param buf where the callee should write the message
1360 * @return number of bytes written to buf
1363 notify_client_connection_failure (void *cls, size_t size, void *buf)
1366 struct MeshPeerInfo *peer_info;
1367 struct GNUNET_MESH_PeerControl *msg;
1368 struct GNUNET_PeerIdentity id;
1370 if (0 == size && NULL == buf) {
1371 // TODO retry? cancel?
1375 size_needed = sizeof(struct GNUNET_MESH_PeerControl);
1376 peer_info = (struct MeshPeerInfo *) cls;
1377 msg = (struct GNUNET_MESH_PeerControl *) buf;
1378 msg->header.size = htons(sizeof(struct GNUNET_MESH_PeerControl));
1379 msg->header.type = htons(GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED);
1380 // msg->tunnel_id = htonl(peer_info->t->tid);
1381 GNUNET_PEER_resolve(peer_info->id, &id);
1382 memcpy(&msg->peer, &id, sizeof(struct GNUNET_PeerIdentity));
1390 * Send keepalive packets for a peer
1396 path_refresh (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1398 struct MeshPeerInfo *peer_info = cls;
1399 struct GNUNET_PeerIdentity id;
1401 if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN) return;
1402 GNUNET_PEER_resolve(get_first_hop(peer_info->path), &id);
1403 GNUNET_CORE_notify_transmit_ready(core_handle,
1406 GNUNET_TIME_UNIT_FOREVER_REL,
1408 sizeof(struct GNUNET_MESH_ManipulatePath)
1409 + (peer_info->path->length
1410 * sizeof (struct GNUNET_PeerIdentity)),
1411 &send_core_create_path_for_peer,
1419 * Function to process paths received for a new peer addition. The recorded
1420 * paths form the initial tunnel, which can be optimized later.
1421 * Called on each result obtained for the DHT search.
1423 * @param cls closure
1424 * @param exp when will this value expire
1425 * @param key key of the result
1426 * @param get_path NULL-terminated array of pointers
1427 * to the peers on reverse GET path (or NULL if not recorded)
1428 * @param put_path NULL-terminated array of pointers
1429 * to the peers on the PUT path (or NULL if not recorded)
1430 * @param type type of the result
1431 * @param size number of bytes in data
1432 * @param data pointer to the result data
1435 dht_get_response_handler(void *cls,
1436 struct GNUNET_TIME_Absolute exp,
1437 const GNUNET_HashCode * key,
1438 const struct GNUNET_PeerIdentity * const *get_path,
1439 const struct GNUNET_PeerIdentity * const *put_path,
1440 enum GNUNET_BLOCK_Type type,
1444 struct MeshPeerInfo *peer_info = cls;
1446 struct GNUNET_PeerIdentity pi;
1449 if ((NULL == get_path || NULL == put_path) && NULL == peer_info->path) {
1450 // Find ourselves some alternate initial path to the destination: retry
1451 GNUNET_DHT_get_stop(peer_info->dhtget);
1452 GNUNET_PEER_resolve(peer_info->id, &pi);
1453 peer_info->dhtget = GNUNET_DHT_get_start(dht_handle,
1454 GNUNET_TIME_UNIT_FOREVER_REL,
1455 GNUNET_BLOCK_TYPE_ANY,
1457 4, /* replication level */
1458 GNUNET_DHT_RO_RECORD_ROUTE,
1459 NULL, /* bloom filter */
1462 0, /* xquery bits */
1463 dht_get_response_handler,
1467 p = GNUNET_malloc(sizeof(struct MeshPath));
1468 for (i = 0; get_path[i] != NULL; i++);
1469 for (i--; i >= 0; i--) {
1470 p->peers = GNUNET_realloc(p->peers,
1471 sizeof(GNUNET_PEER_Id) * (p->length + 1));
1472 p->peers[p->length] = GNUNET_PEER_intern(get_path[i]);
1475 for (i = 0; put_path[i] != NULL; i++);
1476 for (i--; i >= 0; i--) {
1477 p->peers = GNUNET_realloc(p->peers,
1478 sizeof(GNUNET_PEER_Id) * (p->length + 1));
1479 p->peers[p->length] = GNUNET_PEER_intern(put_path[i]);
1482 add_path_to_peer(peer_info, p);
1483 GNUNET_CORE_notify_transmit_ready(core_handle,
1486 GNUNET_TIME_UNIT_FOREVER_REL,
1488 sizeof(struct GNUNET_MESH_ManipulatePath)
1490 * sizeof (struct GNUNET_PeerIdentity)),
1491 &send_core_create_path_for_peer,
1493 GNUNET_SCHEDULER_add_delayed(REFRESH_PATH_TIME, &path_refresh, peer_info);
1498 /******************************************************************************/
1499 /********************* MESH LOCAL HANDLES **************************/
1500 /******************************************************************************/
1504 * Handler for client disconnection
1506 * @param cls closure
1507 * @param client identification of the client; NULL
1508 * for the last call when the server is destroyed
1511 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
1513 struct MeshClient *c;
1514 struct MeshClient *next;
1516 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1517 "client disconnected\n");
1520 if (c->handle == client) {
1521 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1522 " matching client found, cleaning\n");
1523 GNUNET_CONTAINER_multihashmap_iterate(c->tunnels,
1524 &delete_tunnel_entry,
1526 GNUNET_CONTAINER_multihashmap_destroy(c->tunnels);
1527 if(0 != c->app_counter) GNUNET_free (c->apps);
1528 if(0 != c->type_counter) GNUNET_free (c->types);
1529 GNUNET_CONTAINER_DLL_remove(clients, clients_tail, c);
1534 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1535 " ... searching\n");
1539 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1546 * Handler for new clients
1548 * @param cls closure
1549 * @param client identification of the client
1550 * @param message the actual message, which includes messages the client wants
1553 handle_local_new_client (void *cls,
1554 struct GNUNET_SERVER_Client *client,
1555 const struct GNUNET_MessageHeader *message)
1557 struct GNUNET_MESH_ClientConnect *cc_msg;
1558 struct MeshClient *c;
1563 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "new client connected\n");
1564 /* Check data sanity */
1565 size = ntohs(message->size) - sizeof(struct GNUNET_MESH_ClientConnect);
1566 cc_msg = (struct GNUNET_MESH_ClientConnect *) message;
1567 types = ntohs(cc_msg->types);
1568 apps = ntohs(cc_msg->applications);
1570 types * sizeof(uint16_t) + apps * sizeof(GNUNET_MESH_ApplicationType))
1573 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1577 /* Create new client structure */
1578 c = GNUNET_malloc(sizeof(struct MeshClient));
1581 c->type_counter = types;
1582 c->types = GNUNET_malloc(types * sizeof(uint16_t));
1583 memcpy(c->types, &message[1], types * sizeof(uint16_t));
1586 c->app_counter = apps;
1587 c->apps = GNUNET_malloc(apps * sizeof(GNUNET_MESH_ApplicationType));
1589 &message[1] + types * sizeof(uint16_t),
1590 apps * sizeof(GNUNET_MESH_ApplicationType));
1592 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1593 " client has %u+%u subscriptions\n",
1597 GNUNET_CONTAINER_DLL_insert(clients, clients_tail, c);
1598 c->tunnels = GNUNET_CONTAINER_multihashmap_create(32);
1600 GNUNET_SERVER_receive_done(client, GNUNET_OK);
1606 * Handler for requests of new tunnels
1608 * @param cls closure
1609 * @param client identification of the client
1610 * @param message the actual message
1613 handle_local_tunnel_create (void *cls,
1614 struct GNUNET_SERVER_Client *client,
1615 const struct GNUNET_MessageHeader *message)
1617 struct GNUNET_MESH_TunnelMessage *t_msg;
1618 struct MeshTunnel *t;
1619 struct MeshClient *c;
1620 GNUNET_HashCode hash;
1622 /* Sanity check for client registration */
1623 if (NULL == (c = retrieve_client(client))) {
1625 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1629 /* Message sanity check */
1630 if (sizeof(struct GNUNET_MESH_TunnelMessage) != ntohs(message->size)) {
1632 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1636 t_msg = (struct GNUNET_MESH_TunnelMessage *) message;
1637 /* Sanity check for tunnel numbering */
1638 if (0 == (ntohl(t_msg->tunnel_id) & GNUNET_MESH_LOCAL_TUNNEL_ID_MARK)) {
1640 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1643 /* Sanity check for duplicate tunnel IDs */
1644 if(NULL != retrieve_tunnel_by_local_id(c, ntohl(t_msg->tunnel_id))) {
1646 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1650 t = GNUNET_malloc(sizeof(struct MeshTunnel));
1651 while (NULL != retrieve_tunnel_by_pi(myid, next_tid))
1652 next_tid = (next_tid + 1) % GNUNET_MESH_LOCAL_TUNNEL_ID_MARK;
1653 t->id.tid = next_tid++;
1655 t->local_tid = ntohl(t_msg->tunnel_id);
1657 t->peers = GNUNET_CONTAINER_multihashmap_create(32);
1659 GNUNET_CRYPTO_hash(&t->local_tid, sizeof(MESH_TunnelNumber), &hash);
1661 GNUNET_CONTAINER_multihashmap_put(c->tunnels, &hash, t,
1662 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1665 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1669 GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
1671 GNUNET_CONTAINER_multihashmap_put(tunnels, &hash, t,
1672 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1675 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1679 GNUNET_SERVER_receive_done(client, GNUNET_OK);
1685 * Handler for requests of deleting tunnels
1687 * @param cls closure
1688 * @param client identification of the client
1689 * @param message the actual message
1692 handle_local_tunnel_destroy (void *cls,
1693 struct GNUNET_SERVER_Client *client,
1694 const struct GNUNET_MessageHeader *message)
1696 struct GNUNET_MESH_TunnelMessage *tunnel_msg;
1697 struct MeshClient *c;
1698 struct MeshTunnel *t;
1699 MESH_TunnelNumber tid;
1700 GNUNET_HashCode hash;
1703 /* Sanity check for client registration */
1704 if (NULL == (c = retrieve_client(client))) {
1706 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1709 /* Message sanity check */
1710 if (sizeof(struct GNUNET_MESH_TunnelMessage) != ntohs(message->size)) {
1712 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1716 tunnel_msg = (struct GNUNET_MESH_TunnelMessage *) message;
1718 /* Retrieve tunnel */
1719 tid = ntohl(tunnel_msg->tunnel_id);
1721 /* Remove from local id hashmap */
1722 GNUNET_CRYPTO_hash(&tid, sizeof(MESH_TunnelNumber), &hash);
1723 t = GNUNET_CONTAINER_multihashmap_get(c->tunnels, &hash);
1724 GNUNET_CONTAINER_multihashmap_remove(c->tunnels, &hash, t);
1726 /* Remove from global id hashmap */
1727 GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
1728 GNUNET_CONTAINER_multihashmap_remove(tunnels, &hash, t);
1730 // notify_tunnel_destroy(t);
1731 GNUNET_SERVER_receive_done(client, GNUNET_OK);
1737 * Handler for connection requests to new peers
1739 * @param cls closure
1740 * @param client identification of the client
1741 * @param message the actual message (PeerControl)
1744 handle_local_connect_add (void *cls,
1745 struct GNUNET_SERVER_Client *client,
1746 const struct GNUNET_MessageHeader *message)
1748 struct GNUNET_MESH_PeerControl *peer_msg;
1749 struct MeshClient *c;
1750 struct MeshTunnel *t;
1751 MESH_TunnelNumber tid;
1752 struct MeshPeerInfo *peer_info;
1755 /* Sanity check for client registration */
1756 if (NULL == (c = retrieve_client(client))) {
1758 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1762 peer_msg = (struct GNUNET_MESH_PeerControl *)message;
1763 /* Sanity check for message size */
1764 if (sizeof(struct GNUNET_MESH_PeerControl)
1765 != ntohs(peer_msg->header.size))
1768 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1772 /* Tunnel exists? */
1773 tid = ntohl(peer_msg->tunnel_id);
1774 t = retrieve_tunnel_by_local_id(c, tid);
1777 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1781 /* Does client own tunnel? */
1782 if (t->client->handle != client) {
1784 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1789 peer_info = get_peer_info(&peer_msg->peer);
1791 /* Start DHT search if needed */
1792 if(MESH_PEER_READY != peer_info->state && NULL == peer_info->dhtget) {
1793 peer_info->dhtget = GNUNET_DHT_get_start(dht_handle,
1794 GNUNET_TIME_UNIT_FOREVER_REL,
1795 GNUNET_BLOCK_TYPE_ANY,
1796 &peer_msg->peer.hashPubKey,
1797 4, /* replication level */
1798 GNUNET_DHT_RO_RECORD_ROUTE,
1799 NULL, /* bloom filter */
1802 0, /* xquery bits */
1803 dht_get_response_handler,
1807 GNUNET_SERVER_receive_done(client, GNUNET_OK);
1813 * Handler for disconnection requests of peers in a tunnel
1815 * @param cls closure
1816 * @param client identification of the client
1817 * @param message the actual message (PeerControl)
1820 handle_local_connect_del (void *cls,
1821 struct GNUNET_SERVER_Client *client,
1822 const struct GNUNET_MessageHeader *message)
1824 struct GNUNET_MESH_PeerControl *peer_msg;
1825 struct MeshClient *c;
1826 struct MeshTunnel *t;
1827 MESH_TunnelNumber tid;
1829 /* Sanity check for client registration */
1830 if (NULL == (c = retrieve_client(client))) {
1832 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1835 peer_msg = (struct GNUNET_MESH_PeerControl *)message;
1836 /* Sanity check for message size */
1837 if (sizeof(struct GNUNET_MESH_PeerControl)
1838 != ntohs(peer_msg->header.size))
1841 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1845 /* Tunnel exists? */
1846 tid = ntohl(peer_msg->tunnel_id);
1847 t = retrieve_tunnel_by_local_id(c, tid);
1850 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1854 /* Does client own tunnel? */
1855 if (t->client->handle != client) {
1857 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1861 /* Ok, delete peer from tunnel */
1862 GNUNET_CONTAINER_multihashmap_remove_all(t->peers,
1863 &peer_msg->peer.hashPubKey);
1865 GNUNET_SERVER_receive_done(client, GNUNET_OK);
1871 * Handler for connection requests to new peers by type
1873 * @param cls closure
1874 * @param client identification of the client
1875 * @param message the actual message (ConnectPeerByType)
1878 handle_local_connect_by_type (void *cls,
1879 struct GNUNET_SERVER_Client *client,
1880 const struct GNUNET_MessageHeader *message)
1882 struct GNUNET_MESH_ConnectPeerByType *connect_msg;
1883 MESH_TunnelNumber tid;
1884 GNUNET_MESH_ApplicationType application;
1885 struct MeshClient *c;
1886 struct MeshTunnel *t;
1888 /* Sanity check for client registration */
1889 if (NULL == (c = retrieve_client(client))) {
1891 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1895 connect_msg = (struct GNUNET_MESH_ConnectPeerByType *)message;
1896 /* Sanity check for message size */
1897 if (sizeof(struct GNUNET_MESH_PeerControl) !=
1898 ntohs(connect_msg->header.size))
1901 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1905 /* Tunnel exists? */
1906 tid = ntohl(connect_msg->tunnel_id);
1907 t = retrieve_tunnel_by_local_id(c, tid);
1910 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1914 /* Does client own tunnel? */
1915 if (t->client->handle != client) {
1917 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1921 /* Ok, lets find a peer offering the service */
1922 application = ntohl(connect_msg->type);
1923 application++; // FIXME silence warnings
1925 GNUNET_SERVER_receive_done(client, GNUNET_OK);
1931 * Handler for client traffic directed to one peer
1933 * @param cls closure
1934 * @param client identification of the client
1935 * @param message the actual message
1938 handle_local_network_traffic (void *cls,
1939 struct GNUNET_SERVER_Client *client,
1940 const struct GNUNET_MessageHeader *message)
1942 struct MeshClient *c;
1943 struct MeshTunnel *t;
1944 struct MeshPeerInfo *pi;
1945 struct GNUNET_MESH_Data *data_msg;
1946 struct GNUNET_PeerIdentity next_hop;
1947 MESH_TunnelNumber tid;
1949 /* Sanity check for client registration */
1950 if (NULL == (c = retrieve_client(client))) {
1952 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1955 data_msg = (struct GNUNET_MESH_Data *)message;
1956 /* Sanity check for message size */
1957 if (sizeof(struct GNUNET_MESH_PeerControl) !=
1958 ntohs(data_msg->header.size))
1961 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1965 /* Tunnel exists? */
1966 tid = ntohl(data_msg->tunnel_id);
1967 t = retrieve_tunnel_by_local_id(c, tid);
1970 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1974 /* Is it a local tunnel? Then, does client own the tunnel? */
1975 if (t->client->handle != NULL && t->client->handle != client) {
1977 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1981 pi = GNUNET_CONTAINER_multihashmap_get(t->peers,
1982 &data_msg->peer_id.hashPubKey);
1983 /* Is the selected peer in the tunnel? */
1986 * Are we SO nice that we automatically try to add him to the tunnel?
1989 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
1992 GNUNET_PEER_resolve(get_first_hop(pi->path), &next_hop);
1993 GNUNET_CORE_notify_transmit_ready(core_handle,
1996 GNUNET_TIME_UNIT_FOREVER_REL,
1998 /* FIXME re-check types */
1999 message->size - sizeof(struct GNUNET_MESH_Data)
2000 + sizeof(struct GNUNET_MESH_DataMessageFromOrigin),
2001 &send_core_data_to_origin, /* FIXME re-check */
2004 GNUNET_SERVER_receive_done(client, GNUNET_OK); /* FIXME not yet */
2009 * Handler for client traffic directed to all peers in a tunnel
2011 * @param cls closure
2012 * @param client identification of the client
2013 * @param message the actual message
2016 handle_local_network_traffic_bcast (void *cls,
2017 struct GNUNET_SERVER_Client *client,
2018 const struct GNUNET_MessageHeader *message)
2020 struct MeshClient *c;
2021 struct MeshTunnel *t;
2022 struct GNUNET_MESH_DataBroadcast *data_msg;
2023 MESH_TunnelNumber tid;
2025 /* Sanity check for client registration */
2026 if (NULL == (c = retrieve_client(client))) {
2028 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
2031 data_msg = (struct GNUNET_MESH_DataBroadcast *)message;
2032 /* Sanity check for message size */
2033 if (sizeof(struct GNUNET_MESH_PeerControl)
2034 != ntohs(data_msg->header.size))
2037 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
2041 /* Tunnel exists? */
2042 tid = ntohl(data_msg->tunnel_id);
2043 t = retrieve_tunnel_by_local_id(c, tid);
2046 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
2050 /* Does client own tunnel? */
2051 if (t->client->handle != client) {
2053 GNUNET_SERVER_receive_done(client, GNUNET_SYSERR);
2059 GNUNET_SERVER_receive_done(client, GNUNET_OK);
2064 * Functions to handle messages from clients
2066 static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = {
2067 {&handle_local_new_client, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT, 0},
2068 {&handle_local_tunnel_create, NULL,
2069 GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE,
2070 sizeof(struct GNUNET_MESH_TunnelMessage)},
2071 {&handle_local_tunnel_destroy, NULL,
2072 GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY,
2073 sizeof(struct GNUNET_MESH_TunnelMessage)},
2074 {&handle_local_connect_add, NULL,
2075 GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_ADD,
2076 sizeof(struct GNUNET_MESH_PeerControl)},
2077 {&handle_local_connect_del, NULL,
2078 GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_DEL,
2079 sizeof(struct GNUNET_MESH_PeerControl)},
2080 {&handle_local_connect_by_type, NULL,
2081 GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT_PEER_BY_TYPE,
2082 sizeof(struct GNUNET_MESH_ConnectPeerByType)},
2083 {&handle_local_network_traffic, NULL,
2084 GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA, 0},
2085 {&handle_local_network_traffic_bcast, NULL,
2086 GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA_BROADCAST, 0},
2092 * To be called on core init/fail.
2094 * @param cls service closure
2095 * @param server handle to the server for this service
2096 * @param identity the public identity of this peer
2097 * @param publicKey the public key of this peer
2100 core_init (void *cls,
2101 struct GNUNET_CORE_Handle *server,
2102 const struct GNUNET_PeerIdentity *identity,
2103 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
2105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2107 core_handle = server;
2108 myid = GNUNET_PEER_intern(identity);
2113 * Method called whenever a given peer connects.
2115 * @param cls closure
2116 * @param peer peer identity this notification is about
2117 * @param atsi performance data for the connection
2120 core_connect (void *cls,
2121 const struct GNUNET_PeerIdentity *peer,
2122 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
2124 // GNUNET_PEER_Id pid;
2125 struct MeshPeerInfo *peer_info;
2126 struct MeshPath *path;
2128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2129 "Peer connected\n");
2130 peer_info = get_peer_info(peer);
2131 if (myid == peer_info->id) {
2132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2135 path = GNUNET_malloc(sizeof(struct MeshPath));
2137 path->peers = GNUNET_malloc(sizeof(GNUNET_PEER_Id) * 2);
2138 path->peers[0] = myid;
2139 path->peers[1] = peer_info->id;
2140 add_path_to_peer(peer_info, path);
2145 * Method called whenever a peer disconnects.
2147 * @param cls closure
2148 * @param peer peer identity this notification is about
2151 core_disconnect (void *cls,
2153 GNUNET_PeerIdentity *peer)
2156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2157 "Peer disconnected\n");
2158 pid = GNUNET_PEER_search(peer);
2160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2167 /******************************************************************************/
2168 /************************ MAIN FUNCTIONS ****************************/
2169 /******************************************************************************/
2172 * Task run during shutdown.
2178 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2182 if (core_handle != NULL) {
2183 GNUNET_CORE_disconnect (core_handle);
2186 if (dht_handle != NULL) {
2187 GNUNET_DHT_disconnect (dht_handle);
2190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2195 * Process mesh requests.
2197 * @param cls closure
2198 * @param server the initialized server
2199 * @param c configuration to use
2203 struct GNUNET_SERVER_Handle *server,
2204 const struct GNUNET_CONFIGURATION_Handle *c)
2206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2207 "starting to run\n");
2208 GNUNET_SERVER_add_handlers (server, plugin_handlers);
2209 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
2210 core_handle = GNUNET_CORE_connect (c, /* Main configuration */
2212 NULL, /* Closure passed to MESH functions */
2213 &core_init, /* Call core_init once connected */
2214 &core_connect, /* Handle connects */
2215 &core_disconnect, /* remove peers on disconnects */
2216 NULL, /* Do we care about "status" updates? */
2217 NULL, /* Don't notify about all incoming messages */
2218 GNUNET_NO, /* For header only in notification */
2219 NULL, /* Don't notify about all outbound messages */
2220 GNUNET_NO, /* For header-only out notification */
2221 core_handlers); /* Register these handlers */
2222 if (core_handle == NULL) {
2225 dht_handle = GNUNET_DHT_connect(c, 64);
2226 if (dht_handle == NULL) {
2231 tunnels = GNUNET_CONTAINER_multihashmap_create(32);
2232 peers = GNUNET_CONTAINER_multihashmap_create(32);
2234 clients_tail = NULL;
2236 /* Scheduled the task to clean up when shutdown is called */
2237 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
2238 &shutdown_task, NULL);
2240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2245 * The main function for the mesh service.
2247 * @param argc number of arguments from the command line
2248 * @param argv command line arguments
2249 * @return 0 ok, 1 on error
2252 main (int argc, char *const *argv)
2257 GNUNET_SERVICE_run (argc,
2260 GNUNET_SERVICE_OPTION_NONE,
2261 &run, NULL)) ? 0 : 1;
2262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,