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