2 This file is part of GNUnet.
3 (C) 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/mesh_api_new.c
23 * @brief mesh api: client implementation of mesh service
24 * @author Bartlomiej Polot
31 * - API CALL DEFINITIONS
38 #if 0 /* keep Emacsens' auto-indent happy */
45 #include "gnunet_common.h"
46 #include "gnunet_client_lib.h"
47 #include "gnunet_util_lib.h"
48 #include "gnunet_peer_lib.h"
49 #include "gnunet_mesh_service_new.h"
51 #include "mesh_protocol.h"
53 /******************************************************************************/
54 /************************ DATA STRUCTURES ****************************/
55 /******************************************************************************/
58 * Opaque handle to the service.
60 struct GNUNET_MESH_Handle
63 * Handle to the server connection, to send messages later
65 struct GNUNET_CLIENT_Connection *client;
68 * Set of handlers used for processing incoming messages in the tunnels
70 const struct GNUNET_MESH_MessageHandler *message_handlers;
74 * Set of applications that should be claimed to be offered at this node.
75 * Note that this is just informative, the appropiate handlers must be
76 * registered independently and the mapping is up to the developer of the
79 const GNUNET_MESH_ApplicationType *applications;
83 * Double linked list of the tunnels this client is connected to.
85 struct GNUNET_MESH_Tunnel *tunnels_head;
86 struct GNUNET_MESH_Tunnel *tunnels_tail;
89 * tid of the next tunnel to create (to avoid reusing IDs often)
91 MESH_TunnelNumber next_tid;
94 * Callback for tunnel disconnection
96 GNUNET_MESH_TunnelEndHandler *cleaner;
99 * Handle to cancel pending transmissions in case of disconnection
101 struct GNUNET_CLIENT_TransmitHandle *th;
104 * Closure for all the handlers given by the client
110 * Opaque handle to a tunnel.
112 struct GNUNET_MESH_Tunnel
118 struct GNUNET_MESH_Tunnel *next;
119 struct GNUNET_MESH_Tunnel *prev;
122 * Local ID of the tunnel
124 MESH_TunnelNumber tid;
127 * Owner of the tunnel
129 GNUNET_PEER_Id owner;
132 * Callback to execute when peers connect to the tunnel
134 GNUNET_MESH_TunnelConnectHandler connect_handler;
137 * Callback to execute when peers disconnect to the tunnel
139 GNUNET_MESH_TunnelDisconnectHandler disconnect_handler;
142 * All peers added to the tunnel
144 GNUNET_PEER_Id *peers;
147 * Closure for the connect/disconnect handlers
152 * Handle to the mesh this tunnel belongs to
154 struct GNUNET_MESH_Handle *mesh;
157 struct GNUNET_MESH_TransmitHandle
162 /******************************************************************************/
163 /*********************** AUXILIARY FUNCTIONS *************************/
164 /******************************************************************************/
167 * Get the tunnel handler for the tunnel specified by id from the given handle
168 * @param h Mesh handle
169 * @param tid ID of the wanted tunnel
170 * @return handle to the required tunnel or NULL if not found
172 static struct GNUNET_MESH_Tunnel *
173 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid)
175 struct GNUNET_MESH_Tunnel *t;
188 /******************************************************************************/
189 /************************ SEND CALLBACKS ****************************/
190 /******************************************************************************/
194 * Function called to send a connect message to the service, specifying the
195 * types and applications that the client is interested in.
196 * "buf" will be NULL and "size" zero if the socket was closed for writing in
199 * @param cls closure, the mesh handle
200 * @param size number of bytes available in buf
201 * @param buf where the callee should write the connect message
202 * @return number of bytes written to buf
205 send_connect_packet (void *cls, size_t size, void *buf)
207 struct GNUNET_MESH_Handle *h = cls;
208 struct GNUNET_MESH_ClientConnect *msg;
211 GNUNET_MESH_ApplicationType *apps;
215 if (0 == size || buf == NULL)
217 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
218 "Send connect packet: buffer size 0 or buffer invalid\n");
219 // FIXME: disconnect, reconnect, retry!
222 if (sizeof (struct GNUNET_MessageHeader) > size)
224 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
225 "Send connect packet: buffer size too small\n");
226 // FIXME: disconnect, reconnect, retry!
229 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
230 "Send connect packet: %lu bytes buffer\n", size);
231 msg = (struct GNUNET_MESH_ClientConnect *) buf;
232 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
234 for (ntypes = 0, types = NULL; ntypes < h->n_handlers; ntypes++)
236 types = GNUNET_realloc (types, sizeof (uint16_t) * (ntypes + 1));
237 types[ntypes] = h->message_handlers[ntypes].type;
240 for (napps = 0, apps = NULL; napps < h->n_applications; napps++)
242 apps = GNUNET_realloc (apps,
243 sizeof (GNUNET_MESH_ApplicationType) * (napps + 1));
244 apps[napps] = h->applications[napps];
247 msg->header.size = htons (sizeof (struct GNUNET_MESH_ClientConnect) +
248 sizeof (uint16_t) * ntypes +
249 sizeof (GNUNET_MESH_ApplicationType) * napps);
251 memcpy (&msg[1], types, sizeof (uint16_t) * ntypes);
252 memcpy (&msg[1] + sizeof (uint16_t) * ntypes,
253 apps, sizeof (GNUNET_MESH_ApplicationType) * napps);
254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
255 "Sent %lu bytes long message %d types and %d apps\n",
256 ntohs (msg->header.size), ntypes, napps);
257 msg->applications = htons (napps);
258 msg->types = htons (ntypes);
260 return ntohs (msg->header.size);
265 * Function called to send a create tunnel message, specifying the tunnel
266 * number chosen by the client.
267 * "buf" will be NULL and "size" zero if the socket was closed for
268 * writing in the meantime.
270 * @param cls closure, the tunnel handle
271 * @param size number of bytes available in buf
272 * @param buf where the callee should write the create tunnel message
273 * @return number of bytes written to buf
276 send_tunnel_create_packet (void *cls, size_t size, void *buf)
278 struct GNUNET_MESH_Tunnel *t = cls;
279 struct GNUNET_MESH_Handle *h;
280 struct GNUNET_MESH_TunnelMessage *msg;
284 if (0 == size || buf == NULL)
286 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
287 "Send connect packet: buffer size 0 or buffer invalid\n");
288 // FIXME: disconnect, reconnect, retry!
291 if (sizeof (struct GNUNET_MessageHeader) > size)
293 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
294 "Send connect packet: buffer size too small\n");
295 // FIXME: disconnect, reconnect, retry!
298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299 "Send connect packet: %lu bytes buffer\n", size);
300 msg = (struct GNUNET_MESH_TunnelMessage *) buf;
301 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
303 msg->header.size = htons (sizeof (struct GNUNET_MESH_TunnelMessage));
304 msg->tunnel_id = htonl (t->tid);
306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307 "Sent %lu bytes long message\n", ntohs (msg->header.size));
309 return ntohs (msg->header.size);
313 /******************************************************************************/
314 /*********************** RECEIVE HANDLERS ****************************/
315 /******************************************************************************/
318 * Process the new tunnel notification and add it to the tunnels in the handle
320 * @param h The mesh handle
321 * @param msg A message with the details of the new incoming tunnel
324 process_tunnel_create (struct GNUNET_MESH_Handle *h,
325 const struct GNUNET_MESH_TunnelMessage *msg)
327 struct GNUNET_MESH_Tunnel *t;
328 MESH_TunnelNumber tid;
330 tid = ntohl (msg->tunnel_id);
331 if (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK)
333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
334 "MESH: received an incoming tunnel with tid in local range (%X)\n",
337 return; //FIXME abort? reconnect?
339 t = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
349 * Process the new peer event and notify the upper level of it
351 * @param h The mesh handle
352 * @param msg A message with the details of the peer event
355 process_peer_event (struct GNUNET_MESH_Handle *h,
356 const struct GNUNET_MESH_PeerControl *msg)
358 struct GNUNET_MESH_Tunnel *t;
361 size = ntohs (msg->header.size);
362 if (size != sizeof (struct GNUNET_MESH_PeerControl))
367 t = retrieve_tunnel (h, ntohl (msg->tunnel_id));
373 if (GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED == msg->header.type)
375 if (NULL != t->connect_handler)
377 t->connect_handler (t->cls, &msg->peer, NULL); /* FIXME atsi */
382 if (NULL != t->disconnect_handler)
384 t->disconnect_handler (t->cls, &msg->peer);
391 * Process the incoming data packets
393 * @param h The mesh handle
394 * @param msh A message encapsulating the data
397 process_incoming_data (struct GNUNET_MESH_Handle *h,
398 const struct GNUNET_MessageHeader *message)
400 const struct GNUNET_MessageHeader *payload;
401 const struct GNUNET_MESH_MessageHandler *handler;
402 const struct GNUNET_PeerIdentity *peer;
403 struct GNUNET_MESH_Unicast *ucast;
404 struct GNUNET_MESH_Multicast *mcast;
405 struct GNUNET_MESH_ToOrigin *to_orig;
406 struct GNUNET_MESH_Tunnel *t;
410 type = ntohs (message->type);
413 case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
414 ucast = (struct GNUNET_MESH_Unicast *) message;
415 t = retrieve_tunnel (h, ntohl (ucast->tid));
416 payload = (struct GNUNET_MessageHeader *) &ucast[1];
419 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
420 mcast = (struct GNUNET_MESH_Multicast *) message;
421 t = retrieve_tunnel (h, ntohl (mcast->tid));
422 payload = (struct GNUNET_MessageHeader *) &mcast[1];
425 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
426 to_orig = (struct GNUNET_MESH_ToOrigin *) message;
427 t = retrieve_tunnel (h, ntohl (to_orig->tid));
428 payload = (struct GNUNET_MessageHeader *) &to_orig[1];
429 peer = &to_orig->sender;
440 for (i = 0; i < h->n_handlers; i++)
442 handler = &h->message_handlers[i];
443 if (handler->type == type)
445 if (GNUNET_OK == handler->callback (h->cls, t, NULL, /* FIXME ctx */
446 peer, payload, NULL)) /* FIXME atsi */
448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
449 "MESH: callback completed successfully\n");
453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
454 "MESH: callback caused disconnection\n");
455 GNUNET_MESH_disconnect (h);
464 * Function to process all messages received from the service
467 * @param msg message received, NULL on timeout or fatal error
470 msg_received (void *cls, const struct GNUNET_MessageHeader *msg)
472 struct GNUNET_MESH_Handle *h = cls;
480 switch (ntohs (msg->type))
482 /* Notify of a new incoming tunnel */
483 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
484 process_tunnel_create (h, (struct GNUNET_MESH_TunnelMessage *) msg);
486 /* Notify of a new peer or a peer disconnect in the tunnel */
487 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED:
488 case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED:
489 process_peer_event (h, (struct GNUNET_MESH_PeerControl *) msg);
491 /* Notify of a new data packet in the tunnel */
492 case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
493 case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
494 case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
495 process_incoming_data (h, msg);
497 /* We shouldn't get any other packages, log and ignore */
499 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
500 "MESH: unsolicited message form service (type %d)\n",
504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "received a message from mesh\n");
505 GNUNET_CLIENT_receive (h->client,
506 &msg_received, h, GNUNET_TIME_UNIT_FOREVER_REL);
510 /******************************************************************************/
511 /********************** API CALL DEFINITIONS *************************/
512 /******************************************************************************/
515 * Connect to the mesh service.
517 * @param cfg configuration to use
518 * @param cls closure for the various callbacks that follow
519 * (including handlers in the handlers array)
520 * @param cleaner function called when an *inbound* tunnel is destroyed
521 * @param handlers callbacks for messages we care about, NULL-terminated
522 * note that the mesh is allowed to drop notifications about
523 * inbound messages if the client does not process them fast
524 * enough (for this notification type, a bounded queue is used)
525 * @param stypes Application Types the client claims to offer
526 * @return handle to the mesh service
527 * NULL on error (in this case, init is never called)
529 struct GNUNET_MESH_Handle *
530 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
532 GNUNET_MESH_TunnelEndHandler cleaner,
533 const struct GNUNET_MESH_MessageHandler *handlers,
534 const GNUNET_MESH_ApplicationType *stypes)
536 struct GNUNET_MESH_Handle *h;
539 h = GNUNET_malloc (sizeof (struct GNUNET_MESH_Handle));
541 h->cleaner = cleaner;
542 h->client = GNUNET_CLIENT_connect ("mesh", cfg);
543 GNUNET_CLIENT_receive (h->client,
544 &msg_received, h, GNUNET_TIME_UNIT_FOREVER_REL);
545 if (h->client == NULL)
552 h->message_handlers = handlers;
553 h->applications = stypes;
554 h->next_tid = 0x80000000;
556 for (h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++) ;
557 for (h->n_applications = 0; stypes[h->n_applications]; h->n_applications++) ;
559 size = sizeof (struct GNUNET_MESH_ClientConnect);
560 size += h->n_handlers * sizeof (uint16_t);
561 size += h->n_applications * sizeof (GNUNET_MESH_ApplicationType);
563 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
565 GNUNET_TIME_UNIT_FOREVER_REL,
567 &send_connect_packet,
575 * Disconnect from the mesh service.
577 * @param handle connection to mesh to disconnect
580 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle)
582 if (NULL != handle->th)
584 GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
586 if (NULL != handle->client)
588 GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
590 GNUNET_free (handle);
595 * Create a new tunnel (we're initiator and will be allowed to add/remove peers
598 * @param h mesh handle
599 * @param connect_handler function to call when peers are actually connected
600 * @param disconnect_handler function to call when peers are disconnected
601 * @param handler_cls closure for connect/disconnect handlers
603 struct GNUNET_MESH_Tunnel *
604 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h,
605 GNUNET_MESH_TunnelConnectHandler
607 GNUNET_MESH_TunnelDisconnectHandler
608 disconnect_handler, void *handler_cls)
610 struct GNUNET_MESH_Tunnel *tunnel;
612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MESH: Creating new tunnel\n");
613 tunnel = GNUNET_malloc (sizeof (struct GNUNET_MESH_Tunnel));
615 tunnel->connect_handler = connect_handler;
616 tunnel->disconnect_handler = disconnect_handler;
617 tunnel->cls = handler_cls;
619 tunnel->tid = h->next_tid++;
620 h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK; // keep in range
622 h->th = GNUNET_CLIENT_notify_transmit_ready (h->client,
624 GNUNET_MESH_TunnelMessage),
625 GNUNET_TIME_UNIT_FOREVER_REL,
627 &send_tunnel_create_packet,
635 * Request that a peer should be added to the tunnel. The existing
636 * connect handler will be called ONCE with either success or failure.
638 * @param tunnel handle to existing tunnel
639 * @param timeout how long to try to establish a connection
640 * @param peer peer to add
643 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
644 struct GNUNET_TIME_Relative timeout,
645 const struct GNUNET_PeerIdentity *peer)
647 static GNUNET_PEER_Id peer_id;
649 peer_id = GNUNET_PEER_intern (peer);
651 /* FIXME ACTUALLY DO STUFF */
652 tunnel->peers = &peer_id;
653 tunnel->connect_handler (tunnel->cls, peer, NULL);
659 * Request that a peer should be removed from the tunnel. The existing
660 * disconnect handler will be called ONCE if we were connected.
662 * @param tunnel handle to existing tunnel
663 * @param peer peer to remove
666 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
667 const struct GNUNET_PeerIdentity *peer)
669 /* FIXME ACTUALLY DO STUFF */
670 tunnel->peers = NULL;
671 tunnel->disconnect_handler (tunnel->cls, peer);
677 * Request that the mesh should try to connect to a peer supporting the given
680 * @param tunnel handle to existing tunnel
681 * @param timeout how long to try to establish a connection
682 * @param app_type application type that must be supported by the peer (MESH
683 * should discover peer in proximity handling this type)
686 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
687 struct GNUNET_TIME_Relative timeout,
688 GNUNET_MESH_ApplicationType app_type)
695 * Ask the mesh to call "notify" once it is ready to transmit the
696 * given number of bytes to the specified "target". If we are not yet
697 * connected to the specified peer, a call to this function will cause
698 * us to try to establish a connection.
700 * @param tunnel tunnel to use for transmission
701 * @param cork is corking allowed for this transmission?
702 * @param priority how important is the message?
703 * @param maxdelay how long can the message wait?
704 * @param target destination for the message,
705 * NULL for multicast to all tunnel targets
706 * @param notify_size how many bytes of buffer space does notify want?
707 * @param notify function to call when buffer space is available;
708 * will be called with NULL on timeout or if the overall queue
709 * for this peer is larger than queue_size and this is currently
710 * the message with the lowest priority
711 * @param notify_cls closure for notify
712 * @return non-NULL if the notify callback was queued,
713 * NULL if we can not even queue the request (insufficient
714 * memory); if NULL is returned, "notify" will NOT be called.
716 struct GNUNET_MESH_TransmitHandle *
717 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel,
720 struct GNUNET_TIME_Relative maxdelay,
721 const struct GNUNET_PeerIdentity *target,
723 GNUNET_CONNECTION_TransmitReadyNotify
724 notify, void *notify_cls)
726 struct GNUNET_MESH_TransmitHandle *handle;
728 handle = GNUNET_malloc (sizeof (struct GNUNET_MESH_TransmitHandle));
734 #if 0 /* keep Emacsens' auto-indent happy */