Change client <-> service traffic
[oweals/gnunet.git] / src / mesh / mesh_api_new.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
22  * @file mesh/mesh_api_new.c
23  * @brief mesh api: client implementation of mesh service
24  * @author Bartlomiej Polot
25  * 
26  * STRUCTURE:
27  * - CONSTANTS
28  * - DATA STRUCTURES
29  * - SEND CALLBACKS
30  * - RECEIVE HANDLERS
31  * - API CALL DEFINITIONS
32  */
33
34 #ifdef __cplusplus
35
36 extern "C"
37 {
38 #if 0                           /* keep Emacsens' auto-indent happy */
39 }
40 #endif
41 #endif
42
43
44 #include "platform.h"
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"
50 #include "mesh.h"
51 #include "mesh_protocol.h"
52
53 /******************************************************************************/
54 /************************      DATA STRUCTURES     ****************************/
55 /******************************************************************************/
56
57 /**
58  * Opaque handle to the service.
59  */
60 struct GNUNET_MESH_Handle {
61     /**
62      * Handle to the server connection, to send messages later
63      */
64     struct GNUNET_CLIENT_Connection             *client;
65
66     /**
67      * Set of handlers used for processing incoming messages in the tunnels
68      */
69     const struct GNUNET_MESH_MessageHandler     *message_handlers;
70     int                                         n_handlers;
71
72     /**
73      * Set of applications that should be claimed to be offered at this node.
74      * Note that this is just informative, the appropiate handlers must be
75      * registered independently and the mapping is up to the developer of the
76      * client application.
77      */
78     const GNUNET_MESH_ApplicationType           *applications;
79     int                                         n_applications;
80
81     /**
82      * Double linked list of the tunnels this client is connected to.
83      */
84     struct GNUNET_MESH_Tunnel                   *tunnels_head;
85     struct GNUNET_MESH_Tunnel                   *tunnels_tail;
86
87     /**
88      * tid of the next tunnel to create (to avoid reusing IDs often)
89      */
90     MESH_TunnelNumber                               next_tid;
91
92     /**
93      * Callback for tunnel disconnection
94      */
95     GNUNET_MESH_TunnelEndHandler                *cleaner;
96
97     /**
98      * Handle to cancel pending transmissions in case of disconnection
99      */
100     struct GNUNET_CLIENT_TransmitHandle         *th;
101
102     /**
103      * Closure for all the handlers given by the client
104      */
105     void                                        *cls;
106 };
107
108 /**
109  * Opaque handle to a tunnel.
110  */
111 struct GNUNET_MESH_Tunnel {
112
113     /**
114      * DLL
115      */
116     struct GNUNET_MESH_Tunnel                   *next;
117     struct GNUNET_MESH_Tunnel                   *prev;
118
119     /**
120      * Local ID of the tunnel
121      */
122     MESH_TunnelNumber                           tid;
123
124     /**
125      * Owner of the tunnel
126      */
127     GNUNET_PEER_Id                              owner;
128
129     /**
130      * Callback to execute when peers connect to the tunnel
131      */
132     GNUNET_MESH_TunnelConnectHandler            connect_handler;
133
134     /**
135      * Callback to execute when peers disconnect to the tunnel
136      */
137     GNUNET_MESH_TunnelDisconnectHandler         disconnect_handler;
138
139     /**
140      * All peers added to the tunnel
141      */
142     GNUNET_PEER_Id                              *peers;
143
144     /**
145      * Closure for the connect/disconnect handlers
146      */
147     void                                        *cls;
148
149     /**
150      * Handle to the mesh this tunnel belongs to
151      */
152     struct GNUNET_MESH_Handle                   *mesh;
153 };
154
155 struct GNUNET_MESH_TransmitHandle {
156     // TODO
157 };
158
159 /******************************************************************************/
160 /***********************     AUXILIARY FUNCTIONS      *************************/
161 /******************************************************************************/
162
163 /**
164  * Get the tunnel handler for the tunnel specified by id from the given handle
165  * @param h Mesh handle
166  * @param tid ID of the wanted tunnel
167  * @return handle to the required tunnel or NULL if not found
168  */
169 static struct GNUNET_MESH_Tunnel *
170 retrieve_tunnel (struct GNUNET_MESH_Handle *h, MESH_TunnelNumber tid) 
171 {
172     struct GNUNET_MESH_Tunnel           *t;
173
174     t = h->tunnels_head;
175     while (t != NULL) {
176         if (t->tid == tid) return t;
177         t = t->next;
178     }
179     return NULL;
180 }
181
182
183 /******************************************************************************/
184 /************************       SEND CALLBACKS     ****************************/
185 /******************************************************************************/
186
187
188 /**
189  * Function called to send a connect message to the service, specifying the
190  * types and applications that the client is interested in.
191  * "buf" will be NULL and "size" zero if the socket was closed for writing in
192  * the meantime.
193  *
194  * @param cls closure, the mesh handle
195  * @param size number of bytes available in buf
196  * @param buf where the callee should write the connect message
197  * @return number of bytes written to buf
198  */
199 static size_t 
200 send_connect_packet (void *cls, size_t size, void *buf)
201 {
202     struct GNUNET_MESH_Handle           *h = cls;
203     struct GNUNET_MESH_ClientConnect    *msg;
204     uint16_t                            *types;
205     uint16_t                            ntypes;
206     GNUNET_MESH_ApplicationType         *apps;
207     uint16_t                            napps;
208
209     h->th = NULL;
210     if (0 == size || buf == NULL) {
211         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
212                     "Send connect packet: buffer size 0 or buffer invalid\n");
213         // FIXME: disconnect, reconnect, retry!
214         return 0;
215     }
216     if (sizeof(struct GNUNET_MessageHeader) > size) {
217         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
218                     "Send connect packet: buffer size too small\n");
219         // FIXME: disconnect, reconnect, retry!
220         return 0;
221     }
222     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
223                 "Send connect packet: %lu bytes buffer\n",
224                 size);
225     msg = (struct GNUNET_MESH_ClientConnect *) buf;
226     msg->header.type = htons(GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
227
228     for (ntypes = 0, types = NULL; ntypes < h->n_handlers; ntypes++) {
229         types = GNUNET_realloc(types, sizeof(uint16_t) * (ntypes + 1));
230         types[ntypes] = h->message_handlers[ntypes].type;
231     }
232
233     for(napps = 0, apps = NULL; napps < h->n_applications; napps++) {
234         apps = GNUNET_realloc(apps,
235                               sizeof(GNUNET_MESH_ApplicationType) *
236                                 (napps + 1));
237         apps[napps] = h->applications[napps];
238     }
239
240     msg->header.size = htons(sizeof(struct GNUNET_MESH_ClientConnect) +
241                              sizeof(uint16_t) * ntypes +
242                              sizeof(GNUNET_MESH_ApplicationType) * napps);
243
244     memcpy(&msg[1], types, sizeof(uint16_t) * ntypes);
245     memcpy(&msg[1] + sizeof(uint16_t) * ntypes,
246            apps,
247            sizeof(GNUNET_MESH_ApplicationType) * napps);
248     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
249                 "Sent %lu bytes long message %d types and %d apps\n",
250                 ntohs(msg->header.size),
251                 ntypes,
252                 napps
253                );
254     msg->applications = htons(napps);
255     msg->types = htons(ntypes);
256
257     return ntohs(msg->header.size);
258 }
259
260
261 /**
262  * Function called to send a create tunnel message, specifying the tunnel
263  * number chosen by the client.
264  * "buf" will be NULL and "size" zero if the socket was closed for
265  * writing in the meantime.
266  *
267  * @param cls closure, the tunnel handle
268  * @param size number of bytes available in buf
269  * @param buf where the callee should write the create tunnel message
270  * @return number of bytes written to buf
271  */
272 static size_t 
273 send_tunnel_create_packet (void *cls, size_t size, void *buf)
274 {
275     struct GNUNET_MESH_Tunnel           *t = cls;
276     struct GNUNET_MESH_Handle           *h;
277     struct GNUNET_MESH_TunnelMessage    *msg;
278
279     h = t->mesh;
280     h->th = NULL;
281     if (0 == size || buf == NULL) {
282         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
283                     "Send connect packet: buffer size 0 or buffer invalid\n");
284         // FIXME: disconnect, reconnect, retry!
285         return 0;
286     }
287     if (sizeof(struct GNUNET_MessageHeader) > size) {
288         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
289                     "Send connect packet: buffer size too small\n");
290         // FIXME: disconnect, reconnect, retry!
291         return 0;
292     }
293     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
294                 "Send connect packet: %lu bytes buffer\n",
295                 size);
296     msg = (struct GNUNET_MESH_TunnelMessage *) buf;
297     msg->header.type = htons(GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT);
298
299     msg->header.size = htons(sizeof(struct GNUNET_MESH_TunnelMessage));
300     msg->tunnel_id = htonl(t->tid);
301
302     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
303                 "Sent %lu bytes long message\n",
304                 ntohs(msg->header.size));
305
306     return ntohs(msg->header.size);
307 }
308
309
310 /******************************************************************************/
311 /***********************      RECEIVE HANDLERS     ****************************/
312 /******************************************************************************/
313
314 /**
315  * Process the new tunnel notification and add it to the tunnels in the handle
316  * 
317  * @param h     The mesh handle
318  * @param msg   A message with the details of the new incoming tunnel
319  */
320 static void
321 process_tunnel_create(struct GNUNET_MESH_Handle *h, 
322                       const struct GNUNET_MESH_TunnelMessage *msg)
323 {
324     struct GNUNET_MESH_Tunnel                   *t;
325     MESH_TunnelNumber                               tid;
326
327     tid = ntohl(msg->tunnel_id);
328     if (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK) {
329         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
330             "MESH: received an incoming tunnel with tid in local range (%X)\n",
331             tid);
332         GNUNET_break_op(0);
333         return; //FIXME abort? reconnect?
334     }
335     t = GNUNET_malloc(sizeof(struct GNUNET_MESH_Tunnel));
336     t->cls = h->cls;
337     t->connect_handler = NULL;
338     t->disconnect_handler = NULL;
339     t->mesh = h;
340     t->tid = tid;
341
342     return;
343 }
344
345
346 /**
347  * Process the incoming data packets
348  * 
349  * @param h     The mesh handle
350  * @param msh   A message encapsulating the data
351  */
352 static void
353 process_incoming_data(struct GNUNET_MESH_Handle *h,
354                       const struct GNUNET_MessageHeader *message)
355 {
356     const struct GNUNET_MessageHeader           *payload;
357     const struct GNUNET_MESH_MessageHandler     *handler;
358     struct GNUNET_MESH_Unicast                  *ucast;
359     struct GNUNET_MESH_Tunnel                   *t;
360     uint16_t                                    type;
361     int                                         i;
362
363     type = ntohs(message->type);
364     switch (type) {
365         case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
366             ucast = message;
367             t = retrieve_tunnel(h, ntohl(ucast->tid));
368             
369     }
370     for (i = 0; i < h->n_handlers; i++) {
371         handler = &h->message_handlers[i];
372         if (handler->type == type) {
373             /* FIXME */
374             if (GNUNET_OK == handler->callback (h->cls,
375                                                 t,
376                                                 NULL,
377                                                 NULL,
378                                                 NULL,
379                                                 NULL))
380             {
381                 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
382                             "MESH: callback completed successfully\n");
383             } else {
384                 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
385                             "MESH: callback caused disconnection\n");
386                 GNUNET_MESH_disconnect(h);
387             }
388         }
389     }
390     return;
391 }
392
393
394 /**
395  * Function to process all messages received from the service
396  *
397  * @param cls closure
398  * @param msg message received, NULL on timeout or fatal error
399  */
400 static void
401 msg_received (void *cls, const struct GNUNET_MessageHeader * msg)
402 {
403     struct GNUNET_MESH_Handle                   *h = cls;
404
405     if (msg == NULL) {
406         GNUNET_break_op(0);
407         return;
408     }
409
410     switch (ntohs(msg->type)) {
411         /* Notify of a new incoming tunnel */
412         case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
413             process_tunnel_create(h, (struct GNUNET_MESH_TunnelMessage *)msg);
414             break;
415         /* Notify of a new peer in the tunnel */
416         case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED:
417             break;
418         /* Notify of a peer leaving the tunnel */
419         case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED:
420             break;
421         /* Notify of a new data packet in the tunnel */
422         case GNUNET_MESSAGE_TYPE_MESH_UNICAST:
423         case GNUNET_MESSAGE_TYPE_MESH_MULTICAST:
424         case GNUNET_MESSAGE_TYPE_MESH_TO_ORIGIN:
425             process_incoming_data(h, msg);
426             break;
427         /* We shouldn't get any other packages, log and ignore */
428         default:
429             GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
430                         "MESH: unsolicited message form service (type %d)\n",
431                         ntohs(msg->type));
432     }
433
434     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
435                "received a message from mesh\n");
436     GNUNET_CLIENT_receive (h->client,
437                         &msg_received,
438                         h, 
439                         GNUNET_TIME_UNIT_FOREVER_REL);
440     return;
441 }
442
443 /******************************************************************************/
444 /**********************      API CALL DEFINITIONS     *************************/
445 /******************************************************************************/
446
447 /**
448  * Connect to the mesh service.
449  *
450  * @param cfg configuration to use
451  * @param cls closure for the various callbacks that follow
452  *            (including handlers in the handlers array)
453  * @param cleaner function called when an *inbound* tunnel is destroyed
454  * @param handlers callbacks for messages we care about, NULL-terminated
455  *                 note that the mesh is allowed to drop notifications about
456  *                 inbound messages if the client does not process them fast
457  *                 enough (for this notification type, a bounded queue is used)
458  * @param stypes Application Types the client claims to offer
459  * @return handle to the mesh service 
460  *         NULL on error (in this case, init is never called)
461  */
462 struct GNUNET_MESH_Handle *
463 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
464                      void *cls,
465                      GNUNET_MESH_TunnelEndHandler cleaner,
466                      const struct GNUNET_MESH_MessageHandler *handlers,
467                      const GNUNET_MESH_ApplicationType *stypes) 
468 {
469     struct GNUNET_MESH_Handle           *h;
470     size_t                              size;
471
472     h = GNUNET_malloc(sizeof(struct GNUNET_MESH_Handle));
473
474     h->cleaner = cleaner;
475     h->client = GNUNET_CLIENT_connect("mesh", cfg);
476     GNUNET_CLIENT_receive (h->client,
477                          &msg_received,
478                          h, 
479                          GNUNET_TIME_UNIT_FOREVER_REL);
480     if(h->client == NULL) {
481         GNUNET_free(h);
482         return NULL;
483     }
484
485     h->cls = cls;
486     h->message_handlers = handlers;
487     h->applications = stypes;
488     h->next_tid = 0x80000000;
489
490     for(h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++);
491     for(h->n_applications = 0; stypes[h->n_applications]; h->n_applications++);
492
493     size = sizeof(struct GNUNET_MESH_ClientConnect);
494     size += h->n_handlers * sizeof(uint16_t);
495     size += h->n_applications * sizeof(GNUNET_MESH_ApplicationType);
496
497     h->th = GNUNET_CLIENT_notify_transmit_ready(h->client,
498                                                 size,
499                                                 GNUNET_TIME_UNIT_FOREVER_REL,
500                                                 GNUNET_YES,
501                                                 &send_connect_packet,
502                                                 (void *)h);
503
504     return h;
505 }
506
507
508 /**
509  * Disconnect from the mesh service.
510  *
511  * @param handle connection to mesh to disconnect
512  */
513 void 
514 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle) 
515 {
516     if (NULL != handle->th) {
517         GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
518     }
519     if (NULL != handle->client) {
520         GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
521     }
522     GNUNET_free(handle);
523 }
524
525
526 /**
527  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
528  * and to broadcast).
529  *
530  * @param h mesh handle
531  * @param connect_handler function to call when peers are actually connected
532  * @param disconnect_handler function to call when peers are disconnected
533  * @param handler_cls closure for connect/disconnect handlers
534  */
535 struct GNUNET_MESH_Tunnel *
536 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h,
537                            GNUNET_MESH_TunnelConnectHandler
538                            connect_handler,
539                            GNUNET_MESH_TunnelDisconnectHandler
540                            disconnect_handler,
541                            void *handler_cls)
542 {
543     struct GNUNET_MESH_Tunnel           *tunnel;
544
545     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
546                "MESH: Creating new tunnel\n");
547     tunnel = GNUNET_malloc(sizeof(struct GNUNET_MESH_Tunnel));
548
549     tunnel->connect_handler = connect_handler;
550     tunnel->disconnect_handler = disconnect_handler;
551     tunnel->cls = handler_cls;
552     tunnel->mesh = h;
553     tunnel->tid = h->next_tid++;
554     h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK; // keep in range
555
556     h->th = GNUNET_CLIENT_notify_transmit_ready(h->client,
557                                     sizeof(struct GNUNET_MESH_TunnelMessage),
558                                     GNUNET_TIME_UNIT_FOREVER_REL,
559                                     GNUNET_YES,
560                                     &send_tunnel_create_packet,
561                                     (void *)tunnel);
562
563     return tunnel;
564 }
565
566
567 /**
568  * Request that a peer should be added to the tunnel.  The existing
569  * connect handler will be called ONCE with either success or failure.
570  *
571  * @param tunnel handle to existing tunnel
572  * @param timeout how long to try to establish a connection
573  * @param peer peer to add
574  */
575 void
576 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
577                                       struct GNUNET_TIME_Relative timeout,
578                                       const struct GNUNET_PeerIdentity *peer)
579 {
580     static GNUNET_PEER_Id       peer_id;
581
582     peer_id = GNUNET_PEER_intern(peer);
583
584     /* FIXME ACTUALLY DO STUFF */
585     tunnel->peers = &peer_id;
586     tunnel->connect_handler(tunnel->cls, peer, NULL);
587     return;
588 }
589
590
591 /**
592  * Request that a peer should be removed from the tunnel.  The existing
593  * disconnect handler will be called ONCE if we were connected.
594  *
595  * @param tunnel handle to existing tunnel
596  * @param peer peer to remove
597  */
598 void
599 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
600                                       const struct GNUNET_PeerIdentity *peer)
601 {
602     /* FIXME ACTUALLY DO STUFF */
603     tunnel->peers = NULL;
604     tunnel->disconnect_handler(tunnel->cls, peer);
605     return;
606 }
607
608
609 /**
610  * Request that the mesh should try to connect to a peer supporting the given
611  * message type.
612  *
613  * @param tunnel handle to existing tunnel
614  * @param timeout how long to try to establish a connection
615  * @param app_type application type that must be supported by the peer (MESH
616  *                 should discover peer in proximity handling this type)
617  */
618 void
619 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
620                                           struct GNUNET_TIME_Relative timeout,
621                                           GNUNET_MESH_ApplicationType
622                                           app_type)
623 {
624     return;
625 }
626
627
628 /**
629  * Ask the mesh to call "notify" once it is ready to transmit the
630  * given number of bytes to the specified "target".  If we are not yet
631  * connected to the specified peer, a call to this function will cause
632  * us to try to establish a connection.
633  *
634  * @param tunnel tunnel to use for transmission
635  * @param cork is corking allowed for this transmission?
636  * @param priority how important is the message?
637  * @param maxdelay how long can the message wait?
638  * @param target destination for the message,
639  *               NULL for multicast to all tunnel targets 
640  * @param notify_size how many bytes of buffer space does notify want?
641  * @param notify function to call when buffer space is available;
642  *        will be called with NULL on timeout or if the overall queue
643  *        for this peer is larger than queue_size and this is currently
644  *        the message with the lowest priority
645  * @param notify_cls closure for notify
646  * @return non-NULL if the notify callback was queued,
647  *         NULL if we can not even queue the request (insufficient
648  *         memory); if NULL is returned, "notify" will NOT be called.
649  */
650 struct GNUNET_MESH_TransmitHandle *
651 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel,
652                                    int cork,
653                                    uint32_t priority,
654                                    struct GNUNET_TIME_Relative maxdelay,
655                                    const struct GNUNET_PeerIdentity *target,
656                                    size_t notify_size,
657                                    GNUNET_CONNECTION_TransmitReadyNotify
658                                    notify,
659                                    void *notify_cls)
660 {
661     struct GNUNET_MESH_TransmitHandle   *handle;
662
663     handle = GNUNET_malloc(sizeof(struct GNUNET_MESH_TransmitHandle));
664
665     return handle;
666 }
667
668
669 #if 0                           /* keep Emacsens' auto-indent happy */
670 {
671 #endif
672 #ifdef __cplusplus
673 }
674 #endif