Use better condition
[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 /**************************       CONSTANTS      ******************************/
54 /******************************************************************************/
55
56 #define GNUNET_MESH_LOCAL_TUNNEL_ID_MARK 0x80000000
57
58 /******************************************************************************/
59 /************************      DATA STRUCTURES     ****************************/
60 /******************************************************************************/
61
62 /**
63  * Opaque handle to the service.
64  */
65 struct GNUNET_MESH_Handle {
66     /**
67      * Handle to the server connection, to send messages later
68      */
69     struct GNUNET_CLIENT_Connection             *client;
70
71     /**
72      * Set of handlers used for processing incoming messages in the tunnels
73      */
74     const struct GNUNET_MESH_MessageHandler     *message_handlers;
75     int                                         n_handlers;
76
77     /**
78      * Set of applications that should be claimed to be offered at this node.
79      * Note that this is just informative, the appropiate handlers must be
80      * registered independently and the mapping is up to the developer of the
81      * client application.
82      */
83     const GNUNET_MESH_ApplicationType           *applications;
84     int                                         n_applications;
85
86     /**
87      * Double linked list of the tunnels this client is connected to.
88      */
89     struct GNUNET_MESH_Tunnel                   *tunnels_head;
90     struct GNUNET_MESH_Tunnel                   *tunnels_tail;
91
92     /**
93      * tid of the next tunnel to create (to avoid reusing IDs often)
94      */
95     MESH_TunnelID                               next_tid;
96
97     /**
98      * Callback for tunnel disconnection
99      */
100     GNUNET_MESH_TunnelEndHandler                *cleaner;
101
102     /**
103      * Handle to cancel pending transmissions in case of disconnection
104      */
105     struct GNUNET_CLIENT_TransmitHandle         *th;
106
107     /**
108      * Closure for all the handlers given by the client
109      */
110     void                                        *cls;
111 };
112
113 /**
114  * Opaque handle to a tunnel.
115  */
116 struct GNUNET_MESH_Tunnel {
117
118     /**
119      * DLL
120      */
121     struct GNUNET_MESH_Tunnel                   *next;
122     struct GNUNET_MESH_Tunnel                   *prev;
123
124     /**
125      * Local ID of the tunnel
126      */
127     MESH_TunnelID                               tid;
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_TunnelID 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 msh   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_TunnelID                               tid;
326
327     tid = ntohl(msg->tunnel_id);
328     if (tid >= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK) {
329         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
330             "MESH: received an incoming tunnel with tid in local range (%X)\n",
331             tid);
332         return; //FIXME abort? reconnect?
333     }
334     t = GNUNET_malloc(sizeof(struct GNUNET_MESH_Tunnel));
335     t->cls = h->cls;
336     t->connect_handler = NULL;
337     t->disconnect_handler = NULL;
338     t->mesh = h;
339     t->tid = tid;
340
341     return;
342 }
343
344
345 /**
346  * Process the incoming data packets
347  * 
348  * @param h     The mesh handle
349  * @param msh   A message encapsulating the data
350  */
351 static void
352 process_incoming_data(struct GNUNET_MESH_Handle *h, 
353                       const struct GNUNET_MESH_Data *msg)
354 {
355     const struct GNUNET_MESH_Data               *payload;
356     const struct GNUNET_MESH_MessageHandler     *handler;
357     struct GNUNET_MESH_Tunnel                   *t;
358     uint16_t                                    type;
359     int                                         i;
360
361     t = retrieve_tunnel(h, ntohl(msg->tunnel_id));
362
363     payload = (struct GNUNET_MESH_Data *) &msg[1];
364     type = ntohs(payload->header.type);
365     for (i = 0; i < h->n_handlers; i++) {
366         handler = &h->message_handlers[i];
367         if (handler->type == type) {
368             /* FIXME */
369             if (GNUNET_OK == handler->callback (h->cls,
370                                                 t,
371                                                 NULL,
372                                                 NULL,
373                                                 NULL,
374                                                 NULL))
375             {
376                 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
377                             "MESH: callback completed successfully\n");
378             } else {
379                 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
380                             "MESH: callback caused disconnection\n");
381                 GNUNET_MESH_disconnect(h);
382             }
383         }
384     }
385     return;
386 }
387
388
389 /**
390  * Function to process all messages received from the service
391  *
392  * @param cls closure
393  * @param msg message received, NULL on timeout or fatal error
394  */
395 static void
396 msg_received (void *cls, const struct GNUNET_MessageHeader * msg)
397 {
398     struct GNUNET_MESH_Handle                   *h = cls;
399
400     if (msg == NULL) {
401         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
402                "received a NULL message from mesh\n");
403         return;
404     }
405
406     switch (ntohs(msg->type)) {
407         /* Notify of a new incoming tunnel */
408         case GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE:
409             process_tunnel_create(h, (struct GNUNET_MESH_TunnelMessage *)msg);
410             break;
411         /* Notify of a new peer in the tunnel */
412         case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_CONNECTED:
413             break;
414         /* Notify of a peer leaving the tunnel */
415         case GNUNET_MESSAGE_TYPE_MESH_LOCAL_PEER_DISCONNECTED:
416             break;
417         /* Notify of a new data packet in the tunnel */
418         case GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA:
419             process_incoming_data(h, (struct GNUNET_MESH_Data *)msg);
420             break;
421         /* We shouldn't get any other packages, log and ignore */
422         default:
423             GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
424                         "MESH: unsolicited message form service (type %d)\n",
425                         ntohs(msg->type));
426     }
427
428     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
429                "received a message from mesh\n");
430     GNUNET_CLIENT_receive (h->client,
431                         &msg_received,
432                         h, 
433                         GNUNET_TIME_UNIT_FOREVER_REL);
434     return;
435 }
436
437 /******************************************************************************/
438 /**********************      API CALL DEFINITIONS     *************************/
439 /******************************************************************************/
440
441 /**
442  * Connect to the mesh service.
443  *
444  * @param cfg configuration to use
445  * @param cls closure for the various callbacks that follow
446  *            (including handlers in the handlers array)
447  * @param cleaner function called when an *inbound* tunnel is destroyed
448  * @param handlers callbacks for messages we care about, NULL-terminated
449  *                 note that the mesh is allowed to drop notifications about
450  *                 inbound messages if the client does not process them fast
451  *                 enough (for this notification type, a bounded queue is used)
452  * @param stypes Application Types the client claims to offer
453  * @return handle to the mesh service 
454  *         NULL on error (in this case, init is never called)
455  */
456 struct GNUNET_MESH_Handle *
457 GNUNET_MESH_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
458                      void *cls,
459                      GNUNET_MESH_TunnelEndHandler cleaner,
460                      const struct GNUNET_MESH_MessageHandler *handlers,
461                      const GNUNET_MESH_ApplicationType *stypes) 
462 {
463     struct GNUNET_MESH_Handle           *h;
464     size_t                              size;
465
466     h = GNUNET_malloc(sizeof(struct GNUNET_MESH_Handle));
467
468     h->cleaner = cleaner;
469     h->client = GNUNET_CLIENT_connect("mesh", cfg);
470     GNUNET_CLIENT_receive (h->client,
471                          &msg_received,
472                          h, 
473                          GNUNET_TIME_UNIT_FOREVER_REL);
474     if(h->client == NULL) {
475         GNUNET_free(h);
476         return NULL;
477     }
478
479     h->cls = cls;
480     h->message_handlers = handlers;
481     h->applications = stypes;
482     h->next_tid = 0x80000000;
483
484     for(h->n_handlers = 0; handlers[h->n_handlers].type; h->n_handlers++);
485     for(h->n_applications = 0; stypes[h->n_applications]; h->n_applications++);
486
487     size = sizeof(struct GNUNET_MESH_ClientConnect);
488     size += h->n_handlers * sizeof(uint16_t);
489     size += h->n_applications * sizeof(GNUNET_MESH_ApplicationType);
490
491     h->th = GNUNET_CLIENT_notify_transmit_ready(h->client,
492                                                 size,
493                                                 GNUNET_TIME_UNIT_FOREVER_REL,
494                                                 GNUNET_YES,
495                                                 &send_connect_packet,
496                                                 (void *)h);
497
498     return h;
499 }
500
501
502 /**
503  * Disconnect from the mesh service.
504  *
505  * @param handle connection to mesh to disconnect
506  */
507 void 
508 GNUNET_MESH_disconnect (struct GNUNET_MESH_Handle *handle) 
509 {
510     if (NULL != handle->th) {
511         GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th);
512     }
513     if (NULL != handle->client) {
514         GNUNET_CLIENT_disconnect (handle->client, GNUNET_NO);
515     }
516     GNUNET_free(handle);
517 }
518
519
520 /**
521  * Create a new tunnel (we're initiator and will be allowed to add/remove peers
522  * and to broadcast).
523  *
524  * @param h mesh handle
525  * @param connect_handler function to call when peers are actually connected
526  * @param disconnect_handler function to call when peers are disconnected
527  * @param handler_cls closure for connect/disconnect handlers
528  */
529 struct GNUNET_MESH_Tunnel *
530 GNUNET_MESH_tunnel_create (struct GNUNET_MESH_Handle *h,
531                            GNUNET_MESH_TunnelConnectHandler
532                            connect_handler,
533                            GNUNET_MESH_TunnelDisconnectHandler
534                            disconnect_handler,
535                            void *handler_cls)
536 {
537     struct GNUNET_MESH_Tunnel           *tunnel;
538
539     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
540                "MESH: Creating new tunnel\n");
541     tunnel = GNUNET_malloc(sizeof(struct GNUNET_MESH_Tunnel));
542
543     tunnel->connect_handler = connect_handler;
544     tunnel->disconnect_handler = disconnect_handler;
545     tunnel->cls = handler_cls;
546     tunnel->mesh = h;
547     tunnel->tid = h->next_tid++;
548     h->next_tid |= GNUNET_MESH_LOCAL_TUNNEL_ID_MARK; // keep in range
549
550     h->th = GNUNET_CLIENT_notify_transmit_ready(h->client,
551                                     sizeof(struct GNUNET_MESH_TunnelMessage),
552                                     GNUNET_TIME_UNIT_FOREVER_REL,
553                                     GNUNET_YES,
554                                     &send_tunnel_create_packet,
555                                     (void *)tunnel);
556
557     return tunnel;
558 }
559
560
561 /**
562  * Request that a peer should be added to the tunnel.  The existing
563  * connect handler will be called ONCE with either success or failure.
564  *
565  * @param tunnel handle to existing tunnel
566  * @param timeout how long to try to establish a connection
567  * @param peer peer to add
568  */
569 void
570 GNUNET_MESH_peer_request_connect_add (struct GNUNET_MESH_Tunnel *tunnel,
571                                       struct GNUNET_TIME_Relative timeout,
572                                       const struct GNUNET_PeerIdentity *peer)
573 {
574     static GNUNET_PEER_Id       peer_id;
575
576     peer_id = GNUNET_PEER_intern(peer);
577
578     /* FIXME ACTUALLY DO STUFF */
579     tunnel->peers = &peer_id;
580     tunnel->connect_handler(tunnel->cls, peer, NULL);
581     return;
582 }
583
584
585 /**
586  * Request that a peer should be removed from the tunnel.  The existing
587  * disconnect handler will be called ONCE if we were connected.
588  *
589  * @param tunnel handle to existing tunnel
590  * @param peer peer to remove
591  */
592 void
593 GNUNET_MESH_peer_request_connect_del (struct GNUNET_MESH_Tunnel *tunnel,
594                                       const struct GNUNET_PeerIdentity *peer)
595 {
596     /* FIXME ACTUALLY DO STUFF */
597     tunnel->peers = NULL;
598     tunnel->disconnect_handler(tunnel->cls, peer);
599     return;
600 }
601
602
603 /**
604  * Request that the mesh should try to connect to a peer supporting the given
605  * message type.
606  *
607  * @param tunnel handle to existing tunnel
608  * @param timeout how long to try to establish a connection
609  * @param app_type application type that must be supported by the peer (MESH
610  *                 should discover peer in proximity handling this type)
611  */
612 void
613 GNUNET_MESH_peer_request_connect_by_type (struct GNUNET_MESH_Tunnel *tunnel,
614                                           struct GNUNET_TIME_Relative timeout,
615                                           GNUNET_MESH_ApplicationType
616                                           app_type)
617 {
618     return;
619 }
620
621
622 /**
623  * Ask the mesh to call "notify" once it is ready to transmit the
624  * given number of bytes to the specified "target".  If we are not yet
625  * connected to the specified peer, a call to this function will cause
626  * us to try to establish a connection.
627  *
628  * @param tunnel tunnel to use for transmission
629  * @param cork is corking allowed for this transmission?
630  * @param priority how important is the message?
631  * @param maxdelay how long can the message wait?
632  * @param target destination for the message,
633  *               NULL for multicast to all tunnel targets 
634  * @param notify_size how many bytes of buffer space does notify want?
635  * @param notify function to call when buffer space is available;
636  *        will be called with NULL on timeout or if the overall queue
637  *        for this peer is larger than queue_size and this is currently
638  *        the message with the lowest priority
639  * @param notify_cls closure for notify
640  * @return non-NULL if the notify callback was queued,
641  *         NULL if we can not even queue the request (insufficient
642  *         memory); if NULL is returned, "notify" will NOT be called.
643  */
644 struct GNUNET_MESH_TransmitHandle *
645 GNUNET_MESH_notify_transmit_ready (struct GNUNET_MESH_Tunnel *tunnel,
646                                    int cork,
647                                    uint32_t priority,
648                                    struct GNUNET_TIME_Relative maxdelay,
649                                    const struct GNUNET_PeerIdentity *target,
650                                    size_t notify_size,
651                                    GNUNET_CONNECTION_TransmitReadyNotify
652                                    notify,
653                                    void *notify_cls)
654 {
655     struct GNUNET_MESH_TransmitHandle   *handle;
656
657     handle = GNUNET_malloc(sizeof(struct GNUNET_MESH_TransmitHandle));
658
659     return handle;
660 }
661
662
663 #if 0                           /* keep Emacsens' auto-indent happy */
664 {
665 #endif
666 #ifdef __cplusplus
667 }
668 #endif