- doxygen
[oweals/gnunet.git] / src / mesh / gnunet-service-mesh_local.c
1 /*
2      This file is part of GNUnet.
3      (C) 2013 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 #include "platform.h"
23 #include "gnunet_util_lib.h"
24
25 #include "gnunet_statistics_service.h"
26
27 #include "mesh_enc.h"
28 #include "mesh_protocol_enc.h" // GNUNET_MESH_Data is shared
29
30 #include "gnunet-service-mesh_local.h"
31
32 #define LOG(level, ...) GNUNET_log_from(level,"mesh-loc",__VA_ARGS__)
33
34 /******************************************************************************/
35 /********************************   STRUCTS  **********************************/
36 /******************************************************************************/
37
38 /**
39  * Struct containing information about a client of the service
40  *
41  * TODO: add a list of 'waiting' ports
42  */
43 struct MeshClient
44 {
45     /**
46      * Linked list next
47      */
48   struct MeshClient *next;
49
50     /**
51      * Linked list prev
52      */
53   struct MeshClient *prev;
54
55     /**
56      * Tunnels that belong to this client, indexed by local id
57      */
58   struct GNUNET_CONTAINER_MultiHashMap32 *own_channels;
59
60     /**
61      * Tunnels this client has accepted, indexed by incoming local id
62      */
63   struct GNUNET_CONTAINER_MultiHashMap32 *incoming_channels;
64
65     /**
66      * Channel ID for the next incoming channel.
67      */
68   MESH_ChannelNumber next_chid;
69
70     /**
71      * Handle to communicate with the client
72      */
73   struct GNUNET_SERVER_Client *handle;
74
75     /**
76      * Ports that this client has declared interest in.
77      * Indexed by port, contains *Client.
78      */
79   struct GNUNET_CONTAINER_MultiHashMap32 *ports;
80
81     /**
82      * Whether the client is active or shutting down (don't send confirmations
83      * to a client that is shutting down.
84      */
85   int shutting_down;
86
87     /**
88      * ID of the client, mainly for debug messages
89      */
90   unsigned int id;
91 };
92
93 /******************************************************************************/
94 /*******************************   GLOBALS  ***********************************/
95 /******************************************************************************/
96
97 /**
98  * Global handle to the statistics service.
99  */
100 extern struct GNUNET_STATISTICS_Handle *stats;
101
102 /**
103  * Handle to server lib.
104  */
105 static struct GNUNET_SERVER_Handle *server_handle;
106
107 /**
108  * DLL with all the clients, head.
109  */
110 static struct MeshClient *clients_head;
111
112 /**
113  * DLL with all the clients, tail.
114  */
115 static struct MeshClient *clients_tail;
116
117 /**
118  * Next ID to assign to a client.
119  */
120 unsigned int next_client_id;
121
122 /**
123  * All ports clients of this peer have opened.
124  */
125 static struct GNUNET_CONTAINER_MultiHashMap32 *ports;
126
127 /**
128  * Notification context, to send messages to local clients.
129  */
130 static struct GNUNET_SERVER_NotificationContext *nc;
131
132
133 /******************************************************************************/
134 /********************************   STATIC  ***********************************/
135 /******************************************************************************/
136
137 /**
138  * Remove client's ports from the global hashmap on disconnect.
139  *
140  * @param cls Closure (unused).
141  * @param key Port.
142  * @param value Client structure.
143  *
144  * @return GNUNET_OK, keep iterating.
145  */
146 static int
147 client_release_ports (void *cls,
148                       uint32_t key,
149                       void *value)
150 {
151   int res;
152
153   res = GNUNET_CONTAINER_multihashmap32_remove (ports, key, value);
154   if (GNUNET_YES != res)
155   {
156     GNUNET_break (0);
157     LOG (GNUNET_ERROR_TYPE_WARNING,
158                 "Port %u by client %p was not registered.\n",
159                 key, value);
160   }
161   return GNUNET_OK;
162 }
163
164
165
166 /******************************************************************************/
167 /********************************  HANDLES  ***********************************/
168 /******************************************************************************/
169
170
171 /**
172  * Handler for client connection.
173  *
174  * @param cls Closure (unused).
175  * @param client Client handler.
176  */
177 static void
178 handle_client_connect (void *cls, struct GNUNET_SERVER_Client *client)
179 {
180   struct MeshClient *c;
181
182   LOG (GNUNET_ERROR_TYPE_DEBUG, "client connected: %p\n", client);
183   if (NULL == client)
184     return;
185   c = GNUNET_new (struct MeshClient);
186   c->handle = client;
187   c->id = next_client_id++; /* overflow not important: just for debug */
188   c->next_chid = GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
189   GNUNET_SERVER_client_keep (client);
190   GNUNET_SERVER_client_set_user_context (client, c);
191   GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, c);
192 }
193
194
195 /**
196  * Iterator for deleting each channel whose client endpoint disconnected.
197  *
198  * @param cls Closure (client that has disconnected).
199  * @param key The local channel id (used to access the hashmap).
200  * @param value The value stored at the key (channel to destroy).
201  *
202  * @return GNUNET_OK, keep iterating.
203  */
204 static int
205 channel_destroy_iterator (void *cls,
206                           uint32_t key,
207                           void *value)
208 {
209   struct MeshChannel *ch = value;
210   struct MeshClient *c = cls;
211
212   LOG (GNUNET_ERROR_TYPE_DEBUG,
213               " Channel %s destroy, due to client %s shutdown.\n",
214               GMCH_2s (ch), GML_2s (c));
215
216   GMCH_handle_local_destroy (ch, c);
217   return GNUNET_OK;
218 }
219
220 /**
221  * Handler for client disconnection
222  *
223  * @param cls closure
224  * @param client identification of the client; NULL
225  *        for the last call when the server is destroyed
226  */
227 static void
228 handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
229 {
230   struct MeshClient *c;
231
232   LOG (GNUNET_ERROR_TYPE_DEBUG, "client disconnected: %p\n", client);
233   if (client == NULL)
234   {
235     LOG (GNUNET_ERROR_TYPE_DEBUG, "   (SERVER DOWN)\n");
236     return;
237   }
238
239   c = GML_client_get (client);
240   if (NULL != c)
241   {
242     LOG (GNUNET_ERROR_TYPE_DEBUG, "matching client found (%u, %p)\n",
243                 c->id, c);
244     GNUNET_SERVER_client_drop (c->handle);
245     c->shutting_down = GNUNET_YES;
246     if (NULL != c->own_channels)
247     {
248       GNUNET_CONTAINER_multihashmap32_iterate (c->own_channels,
249                                                &channel_destroy_iterator, c);
250       GNUNET_CONTAINER_multihashmap32_destroy (c->own_channels);
251     }
252
253     if (NULL != c->incoming_channels)
254     {
255       GNUNET_CONTAINER_multihashmap32_iterate (c->incoming_channels,
256                                                &channel_destroy_iterator, c);
257       GNUNET_CONTAINER_multihashmap32_destroy (c->incoming_channels);
258     }
259
260     if (NULL != c->ports)
261     {
262       GNUNET_CONTAINER_multihashmap32_iterate (c->ports,
263                                                &client_release_ports, c);
264       GNUNET_CONTAINER_multihashmap32_destroy (c->ports);
265     }
266     GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, c);
267     GNUNET_STATISTICS_update (stats, "# clients", -1, GNUNET_NO);
268     LOG (GNUNET_ERROR_TYPE_DEBUG, "  client free (%p)\n", c);
269     GNUNET_free (c);
270   }
271   else
272   {
273     LOG (GNUNET_ERROR_TYPE_WARNING, " context NULL!\n");
274   }
275   LOG (GNUNET_ERROR_TYPE_DEBUG, "done!\n");
276   return;
277 }
278
279
280 /**
281  * Handler for new clients
282  *
283  * @param cls closure
284  * @param client identification of the client
285  * @param message the actual message, which includes messages the client wants
286  */
287 static void
288 handle_new_client (void *cls, struct GNUNET_SERVER_Client *client,
289                    const struct GNUNET_MessageHeader *message)
290 {
291   struct GNUNET_MESH_ClientConnect *cc_msg;
292   struct MeshClient *c;
293   unsigned int size;
294   uint32_t *p;
295   unsigned int i;
296
297   LOG (GNUNET_ERROR_TYPE_DEBUG, "new client connected %p\n", client);
298
299   /* Check data sanity */
300   size = ntohs (message->size) - sizeof (struct GNUNET_MESH_ClientConnect);
301   cc_msg = (struct GNUNET_MESH_ClientConnect *) message;
302   if (0 != (size % sizeof (uint32_t)))
303   {
304     GNUNET_break (0);
305     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
306     return;
307   }
308   size /= sizeof (uint32_t);
309
310   /* Initialize new client structure */
311   c = GNUNET_SERVER_client_get_user_context (client, struct MeshClient);
312   LOG (GNUNET_ERROR_TYPE_DEBUG, "  client id %u\n", c->id);
313   LOG (GNUNET_ERROR_TYPE_DEBUG, "  client has %u ports\n", size);
314   if (size > 0)
315   {
316     uint32_t u32;
317
318     p = (uint32_t *) &cc_msg[1];
319     c->ports = GNUNET_CONTAINER_multihashmap32_create (size);
320     for (i = 0; i < size; i++)
321     {
322       u32 = ntohl (p[i]);
323       LOG (GNUNET_ERROR_TYPE_DEBUG, "    port: %u\n", u32);
324
325       /* store in client's hashmap */
326       GNUNET_CONTAINER_multihashmap32_put (c->ports, u32, c,
327                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
328       /* store in global hashmap */
329       /* FIXME only allow one client to have the port open,
330        *       have a backup hashmap with waiting clients */
331       GNUNET_CONTAINER_multihashmap32_put (ports, u32, c,
332                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
333     }
334   }
335
336   c->own_channels = GNUNET_CONTAINER_multihashmap32_create (32);
337   c->incoming_channels = GNUNET_CONTAINER_multihashmap32_create (32);
338   GNUNET_SERVER_notification_context_add (nc, client);
339   GNUNET_STATISTICS_update (stats, "# clients", 1, GNUNET_NO);
340
341   GNUNET_SERVER_receive_done (client, GNUNET_OK);
342   LOG (GNUNET_ERROR_TYPE_DEBUG, "new client processed\n");
343 }
344
345
346 /**
347  * Handler for requests of new tunnels
348  *
349  * @param cls Closure.
350  * @param client Identification of the client.
351  * @param message The actual message.
352  */
353 static void
354 handle_channel_create (void *cls, struct GNUNET_SERVER_Client *client,
355                        const struct GNUNET_MessageHeader *message)
356 {
357   struct MeshClient *c;
358
359   LOG (GNUNET_ERROR_TYPE_DEBUG, "new channel requested\n");
360
361   /* Sanity check for client registration */
362   if (NULL == (c = GML_client_get (client)))
363   {
364     GNUNET_break (0);
365     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
366     return;
367   }
368   LOG (GNUNET_ERROR_TYPE_DEBUG, "  by client %u\n", c->id);
369
370   /* Message size sanity check */
371   if (sizeof (struct GNUNET_MESH_ChannelMessage) != ntohs (message->size))
372   {
373     GNUNET_break (0);
374     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
375     return;
376   }
377
378   if (GNUNET_OK !=
379       GMCH_handle_local_create (c,
380                                 (struct GNUNET_MESH_ChannelMessage *) message))
381   {
382     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
383     return;
384   }
385
386   GNUNET_SERVER_receive_done (client, GNUNET_OK);
387   return;
388 }
389
390
391 /**
392  * Handler for requests of deleting tunnels
393  *
394  * @param cls closure
395  * @param client identification of the client
396  * @param message the actual message
397  */
398 static void
399 handle_channel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
400                         const struct GNUNET_MessageHeader *message)
401 {
402   struct GNUNET_MESH_ChannelMessage *msg;
403   struct MeshClient *c;
404   struct MeshChannel *ch;
405   MESH_ChannelNumber chid;
406
407   LOG (GNUNET_ERROR_TYPE_DEBUG,
408               "Got a DESTROY CHANNEL from client!\n");
409
410   /* Sanity check for client registration */
411   if (NULL == (c = GML_client_get (client)))
412   {
413     GNUNET_break (0);
414     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
415     return;
416   }
417   LOG (GNUNET_ERROR_TYPE_DEBUG, "  by client %u\n", c->id);
418
419   /* Message sanity check */
420   if (sizeof (struct GNUNET_MESH_ChannelMessage) != ntohs (message->size))
421   {
422     GNUNET_break (0);
423     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
424     return;
425   }
426
427   msg = (struct GNUNET_MESH_ChannelMessage *) message;
428
429   /* Retrieve tunnel */
430   chid = ntohl (msg->channel_id);
431   ch = GML_channel_get (c, chid);
432   if (NULL == ch)
433   {
434     LOG (GNUNET_ERROR_TYPE_ERROR, "  channel %X not found\n", chid);
435     GNUNET_break (0);
436     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
437     return;
438   }
439
440   GMCH_handle_local_destroy (ch, c);
441
442   GNUNET_SERVER_receive_done (client, GNUNET_OK);
443   return;
444 }
445
446
447 /**
448  * Handler for client traffic
449  *
450  * @param cls closure
451  * @param client identification of the client
452  * @param message the actual message
453  */
454 static void
455 handle_data (void *cls, struct GNUNET_SERVER_Client *client,
456              const struct GNUNET_MessageHeader *message)
457 {
458   struct GNUNET_MESH_LocalData *msg;
459   struct MeshClient *c;
460   struct MeshChannel *ch;
461   MESH_ChannelNumber chid;
462   size_t size;
463   int fwd;
464
465   LOG (GNUNET_ERROR_TYPE_DEBUG,
466               "Got data from a client!\n");
467
468   /* Sanity check for client registration */
469   if (NULL == (c = GML_client_get (client)))
470   {
471     GNUNET_break (0);
472     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
473     return;
474   }
475   LOG (GNUNET_ERROR_TYPE_DEBUG, "  by client %u\n", c->id);
476
477   msg = (struct GNUNET_MESH_LocalData *) message;
478
479   /* Sanity check for message size */
480   size = ntohs (message->size) - sizeof (struct GNUNET_MESH_LocalData);
481   if (size < sizeof (struct GNUNET_MessageHeader))
482   {
483     GNUNET_break (0);
484     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
485     return;
486   }
487
488   /* Channel exists? */
489   chid = ntohl (msg->id);
490   fwd = chid < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
491   ch = GML_channel_get (c, chid);
492   if (NULL == ch)
493   {
494     GNUNET_break (0);
495     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
496     return;
497   }
498
499   if (GNUNET_OK !=
500       GMCH_handle_local_data (ch, c,
501                               (struct GNUNET_MessageHeader *)&msg[1], fwd))
502   {
503     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
504     return;
505   }
506
507   LOG (GNUNET_ERROR_TYPE_DEBUG, "receive done OK\n");
508   GNUNET_SERVER_receive_done (client, GNUNET_OK);
509
510   return;
511 }
512
513
514 /**
515  * Handler for client's ACKs for payload traffic.
516  *
517  * @param cls Closure (unused).
518  * @param client Identification of the client.
519  * @param message The actual message.
520  */
521 static void
522 handle_ack (void *cls, struct GNUNET_SERVER_Client *client,
523             const struct GNUNET_MessageHeader *message)
524 {
525   struct GNUNET_MESH_LocalAck *msg;
526   struct MeshChannel *ch;
527   struct MeshClient *c;
528   MESH_ChannelNumber chid;
529   int fwd;
530
531   LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a local ACK\n");
532
533   /* Sanity check for client registration */
534   if (NULL == (c = GML_client_get (client)))
535   {
536     GNUNET_break (0);
537     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
538     return;
539   }
540   LOG (GNUNET_ERROR_TYPE_DEBUG, "  by client %u\n", c->id);
541
542   msg = (struct GNUNET_MESH_LocalAck *) message;
543
544   /* Channel exists? */
545   chid = ntohl (msg->channel_id);
546   LOG (GNUNET_ERROR_TYPE_DEBUG, "  on channel %X\n", chid);
547   ch = GML_channel_get (c, chid);
548   LOG (GNUNET_ERROR_TYPE_DEBUG, "   -- ch %p\n", ch);
549   if (NULL == ch)
550   {
551     GNUNET_break (0);
552     LOG (GNUNET_ERROR_TYPE_WARNING, "Channel %X unknown.\n", chid);
553     LOG (GNUNET_ERROR_TYPE_WARNING, "  for client %u.\n", c->id);
554     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
555     return;
556   }
557
558   /* If client is root, the ACK is going FWD, therefore this is "BCK ACK". */
559   /* If client is dest, the ACK is going BCK, therefore this is "FWD ACK" */
560   fwd = chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
561
562   GMCH_handle_local_ack (ch, fwd);
563   GNUNET_SERVER_receive_done (client, GNUNET_OK);
564
565   return;
566 }
567
568
569 /*
570  * Iterator over all tunnels to send a monitoring client info about each tunnel.
571  *
572  * @param cls Closure (client handle).
573  * @param key Key (hashed tunnel ID, unused).
574  * @param value Tunnel info.
575  *
576  * @return GNUNET_YES, to keep iterating.
577  */
578 // static int
579 // monitor_all_tunnels_iterator (void *cls,
580 //                               const struct GNUNET_HashCode * key,
581 //                               void *value)
582 // {
583 //   struct GNUNET_SERVER_Client *client = cls;
584 //   struct MeshChannel *ch = value;
585 //   struct GNUNET_MESH_LocalMonitor *msg;
586 //
587 //   msg = GNUNET_malloc (sizeof(struct GNUNET_MESH_LocalMonitor));
588 //   msg->channel_id = htonl (ch->gid);
589 //   msg->header.size = htons (sizeof (struct GNUNET_MESH_LocalMonitor));
590 //   msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS);
591 //
592 //   LOG (GNUNET_ERROR_TYPE_INFO,
593 //               "*  sending info about tunnel %s\n",
594 //               GNUNET_i2s (&msg->owner));
595 //
596 //   GNUNET_SERVER_notification_context_unicast (nc, client,
597 //                                               &msg->header, GNUNET_NO);
598 //   return GNUNET_YES;
599 // }
600
601
602 /**
603  * Handler for client's MONITOR request.
604  *
605  * @param cls Closure (unused).
606  * @param client Identification of the client.
607  * @param message The actual message.
608  */
609 static void
610 handle_get_tunnels (void *cls, struct GNUNET_SERVER_Client *client,
611                     const struct GNUNET_MessageHeader *message)
612 {
613   struct MeshClient *c;
614
615   /* Sanity check for client registration */
616   if (NULL == (c = GML_client_get (client)))
617   {
618     GNUNET_break (0);
619     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
620     return;
621   }
622
623   LOG (GNUNET_ERROR_TYPE_INFO,
624               "Received get tunnels request from client %u\n",
625               c->id);
626 //   GNUNET_CONTAINER_multihashmap_iterate (tunnels,
627 //                                          monitor_all_tunnels_iterator,
628 //                                          client);
629   LOG (GNUNET_ERROR_TYPE_INFO,
630               "Get tunnels request from client %u completed\n",
631               c->id);
632   GNUNET_SERVER_receive_done (client, GNUNET_OK);
633 }
634
635
636 /**
637  * Handler for client's MONITOR_TUNNEL request.
638  *
639  * @param cls Closure (unused).
640  * @param client Identification of the client.
641  * @param message The actual message.
642  */
643 void
644 handle_show_tunnel (void *cls, struct GNUNET_SERVER_Client *client,
645                     const struct GNUNET_MessageHeader *message)
646 {
647   const struct GNUNET_MESH_LocalMonitor *msg;
648   struct GNUNET_MESH_LocalMonitor *resp;
649   struct MeshClient *c;
650   struct MeshChannel *ch;
651
652   /* Sanity check for client registration */
653   if (NULL == (c = GML_client_get (client)))
654   {
655     GNUNET_break (0);
656     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
657     return;
658   }
659
660   msg = (struct GNUNET_MESH_LocalMonitor *) message;
661   LOG (GNUNET_ERROR_TYPE_INFO,
662               "Received tunnel info request from client %u for tunnel %s[%X]\n",
663               c->id,
664               &msg->owner,
665               ntohl (msg->channel_id));
666 //   ch = channel_get (&msg->owner, ntohl (msg->channel_id));
667   ch = NULL; // FIXME
668   if (NULL == ch)
669   {
670     /* We don't know the tunnel */
671     struct GNUNET_MESH_LocalMonitor warn;
672
673     warn = *msg;
674     GNUNET_SERVER_notification_context_unicast (nc, client,
675                                                 &warn.header,
676                                                 GNUNET_NO);
677     GNUNET_SERVER_receive_done (client, GNUNET_OK);
678     return;
679   }
680
681   /* Initialize context */
682   resp = GNUNET_malloc (sizeof (struct GNUNET_MESH_LocalMonitor));
683   *resp = *msg;
684   resp->header.size = htons (sizeof (struct GNUNET_MESH_LocalMonitor));
685   GNUNET_SERVER_notification_context_unicast (nc, c->handle,
686                                               &resp->header, GNUNET_NO);
687   GNUNET_free (resp);
688
689   LOG (GNUNET_ERROR_TYPE_INFO,
690               "Monitor tunnel request from client %u completed\n",
691               c->id);
692   GNUNET_SERVER_receive_done (client, GNUNET_OK);
693 }
694
695
696 /**
697  * Functions to handle messages from clients
698  */
699 static struct GNUNET_SERVER_MessageHandler client_handlers[] = {
700   {&handle_new_client, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_CONNECT, 0},
701   {&handle_channel_create, NULL, GNUNET_MESSAGE_TYPE_MESH_CHANNEL_CREATE,
702    sizeof (struct GNUNET_MESH_ChannelMessage)},
703   {&handle_channel_destroy, NULL, GNUNET_MESSAGE_TYPE_MESH_CHANNEL_DESTROY,
704    sizeof (struct GNUNET_MESH_ChannelMessage)},
705   {&handle_data, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA, 0},
706   {&handle_ack, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK,
707    sizeof (struct GNUNET_MESH_LocalAck)},
708   {&handle_get_tunnels, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNELS,
709    sizeof (struct GNUNET_MessageHeader)},
710   {&handle_show_tunnel, NULL, GNUNET_MESSAGE_TYPE_MESH_LOCAL_INFO_TUNNEL,
711    sizeof (struct GNUNET_MESH_LocalMonitor)},
712   {NULL, NULL, 0, 0}
713 };
714
715
716
717 /******************************************************************************/
718 /********************************    API    ***********************************/
719 /******************************************************************************/
720
721 /**
722  * Initialize server subsystem.
723  *
724  * @param handle Server handle.
725  */
726 void
727 GML_init (struct GNUNET_SERVER_Handle *handle)
728 {
729   LOG (GNUNET_ERROR_TYPE_DEBUG, "init\n");
730   server_handle = handle;
731   GNUNET_SERVER_suspend (server_handle);
732   ports = GNUNET_CONTAINER_multihashmap32_create (32);
733 }
734
735
736 /**
737  * Install server (service) handlers and start listening to clients.
738  */
739 void
740 GML_start (void)
741 {
742   GNUNET_SERVER_add_handlers (server_handle, client_handlers);
743   GNUNET_SERVER_connect_notify (server_handle,  &handle_client_connect, NULL);
744   GNUNET_SERVER_disconnect_notify (server_handle, &handle_client_disconnect,
745                                    NULL);
746   nc = GNUNET_SERVER_notification_context_create (server_handle, 1);
747
748   clients_head = NULL;
749   clients_tail = NULL;
750   next_client_id = 0;
751   GNUNET_SERVER_resume (server_handle);
752 }
753
754
755 /**
756  * Shutdown server.
757  */
758 void
759 GML_shutdown (void)
760 {
761   if (nc != NULL)
762   {
763     GNUNET_SERVER_notification_context_destroy (nc);
764     nc = NULL;
765   }
766 }
767
768
769 /**
770  * Get a channel from a client.
771  *
772  * @param c Client to check.
773  * @param chid Channel ID, must be local (> 0x800...).
774  *
775  * @return non-NULL if channel exists in the clients lists
776  */
777 struct MeshChannel *
778 GML_channel_get (struct MeshClient *c, MESH_ChannelNumber chid)
779 {
780   if (0 == (chid & GNUNET_MESH_LOCAL_CHANNEL_ID_CLI))
781   {
782     GNUNET_break_op (0);
783     LOG (GNUNET_ERROR_TYPE_DEBUG, "CHID %X not a local chid\n", chid);
784     return NULL;
785   }
786   if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
787     return GNUNET_CONTAINER_multihashmap32_get (c->incoming_channels, chid);
788   return GNUNET_CONTAINER_multihashmap32_get (c->own_channels, chid);
789 }
790
791
792 /**
793  * Add a channel to a client
794  *
795  * @param client Client.
796  * @param chid Channel ID.
797  * @param ch Channel.
798  */
799 void
800 GML_channel_add (struct MeshClient *client,
801                  uint32_t chid,
802                  struct MeshChannel *ch)
803 {
804   if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_SERV)
805     GNUNET_CONTAINER_multihashmap32_put (client->incoming_channels, chid, ch,
806                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
807   else if (chid >= GNUNET_MESH_LOCAL_CHANNEL_ID_CLI)
808     GNUNET_CONTAINER_multihashmap32_put (client->own_channels, chid, ch,
809                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
810   else
811     GNUNET_break (0);
812 }
813
814
815 /**
816  * Remove a channel from a client
817  *
818  * @param client Client.
819  * @param chid Channel ID.
820  * @param ch Channel.
821  */
822 void
823 GML_channel_remove (struct MeshClient *client,
824                     uint32_t chid,
825                     struct MeshChannel *ch)
826 {
827   if (GNUNET_MESH_LOCAL_CHANNEL_ID_SERV <= chid)
828     GNUNET_CONTAINER_multihashmap32_remove (client->incoming_channels, chid, ch);
829   else if (GNUNET_MESH_LOCAL_CHANNEL_ID_CLI <= chid)
830     GNUNET_CONTAINER_multihashmap32_remove (client->own_channels, chid, ch);
831   else
832     GNUNET_break (0);
833 }
834
835
836 /**
837  * Get the tunnel's next free local channel ID.
838  *
839  * @param c Client.
840  *
841  * @return LID of a channel free to use.
842  */
843 MESH_ChannelNumber
844 GML_get_next_chid (struct MeshClient *c)
845 {
846   MESH_ChannelNumber chid;
847
848   while (NULL != GML_channel_get (c, c->next_chid))
849   {
850     LOG (GNUNET_ERROR_TYPE_DEBUG, "Channel %u exists...\n", c->next_chid);
851     c->next_chid = (c->next_chid + 1) | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
852   }
853   chid = c->next_chid;
854   c->next_chid = (c->next_chid + 1) | GNUNET_MESH_LOCAL_CHANNEL_ID_SERV;
855
856   return chid;
857 }
858
859
860 /**
861  * Check if client has registered with the service and has not disconnected
862  *
863  * @param client the client to check
864  *
865  * @return non-NULL if client exists in the global DLL
866  */
867 struct MeshClient *
868 GML_client_get (struct GNUNET_SERVER_Client *client)
869 {
870   return GNUNET_SERVER_client_get_user_context (client, struct MeshClient);
871 }
872
873 /**
874  * Find a client that has opened a port
875  *
876  * @param port Port to check.
877  *
878  * @return non-NULL if a client has the port.
879  */
880 struct MeshClient *
881 GML_client_get_by_port (uint32_t port)
882 {
883   return GNUNET_CONTAINER_multihashmap32_get (ports, port);
884 }
885
886
887 /**
888  * Deletes a channel from a client (either owner or destination).
889  *
890  * @param c Client whose tunnel to delete.
891  * @param ch Channel which should be deleted.
892  * @param id Channel ID.
893  */
894 void
895 GML_client_delete_channel (struct MeshClient *c,
896                            struct MeshChannel *ch,
897                            MESH_ChannelNumber id)
898 {
899   int res;
900
901   if (GNUNET_MESH_LOCAL_CHANNEL_ID_SERV <= id)
902   {
903     res = GNUNET_CONTAINER_multihashmap32_remove (c->incoming_channels,
904                                                   id, ch);
905     if (GNUNET_YES != res)
906       LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_channel dest KO\n");
907   }
908   else if (GNUNET_MESH_LOCAL_CHANNEL_ID_CLI <= id)
909   {
910     res = GNUNET_CONTAINER_multihashmap32_remove (c->own_channels,
911                                                   id, ch);
912     if (GNUNET_YES != res)
913       LOG (GNUNET_ERROR_TYPE_DEBUG, "client_delete_tunnel root KO\n");
914   }
915   else
916   {
917     GNUNET_break (0);
918   }
919 }
920
921 /**
922  * Build a local ACK message and send it to a local client, if needed.
923  *
924  * If the client was already allowed to send data, do nothing.
925  *
926  * @param c Client to whom send the ACK.
927  * @param id Channel ID to use
928  */
929 void
930 GML_send_ack (struct MeshClient *c, MESH_ChannelNumber id)
931 {
932   struct GNUNET_MESH_LocalAck msg;
933
934   LOG (GNUNET_ERROR_TYPE_DEBUG,
935               "send local %s ack on %X towards %p\n",
936               id < GNUNET_MESH_LOCAL_CHANNEL_ID_SERV ? "FWD" : "BCK", id, c);
937
938   msg.header.size = htons (sizeof (msg));
939   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_ACK);
940   msg.channel_id = htonl (id);
941   GNUNET_SERVER_notification_context_unicast (nc,
942                                               c->handle,
943                                               &msg.header,
944                                               GNUNET_NO);
945
946 }
947
948
949 /**
950  * Notify the client that a new incoming channel was created.
951  *
952  * @param c Client to notify.
953  * @param id Channel ID.
954  * @param port Channel's destination port.
955  * @param opt Options (bit array).
956  * @param peer Origin peer.
957  */
958 void
959 GML_send_channel_create (struct MeshClient *c,
960                          uint32_t id, uint32_t port, uint32_t opt,
961                          const struct GNUNET_PeerIdentity *peer)
962 {
963   struct GNUNET_MESH_ChannelMessage msg;
964
965   msg.header.size = htons (sizeof (msg));
966   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_CREATE);
967   msg.channel_id = htonl (id);
968   msg.port = htonl (port);
969   msg.opt = htonl (opt);
970   msg.peer = *peer;
971   GNUNET_SERVER_notification_context_unicast (nc, c->handle,
972                                               &msg.header, GNUNET_NO);
973 }
974
975
976 /**
977  * Notify a client that a channel is no longer valid.
978  *
979  * @param c Client.
980  * @param id ID of the channel that is destroyed.
981  */
982 void
983 GML_send_channel_destroy (struct MeshClient *c, uint32_t id)
984 {
985   struct GNUNET_MESH_ChannelMessage msg;
986
987   if (NULL == c)
988   {
989     GNUNET_break (0);
990     return;
991   }
992   msg.header.size = htons (sizeof (msg));
993   msg.header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_TUNNEL_DESTROY);
994   msg.channel_id = htonl (id);
995   msg.port = htonl (0);
996   memset (&msg.peer, 0, sizeof (msg.peer));
997   msg.opt = htonl (0);
998   GNUNET_SERVER_notification_context_unicast (nc, c->handle,
999                                               &msg.header, GNUNET_NO);
1000 }
1001
1002
1003 /**
1004  * Modify the mesh message ID from global to local and send to client.
1005  *
1006  * @param c Client to send to.
1007  * @param msg Message to modify and send.
1008  * @param id Channel ID to use (c can be both owner and client).
1009  */
1010 void
1011 GML_send_data (struct MeshClient *c,
1012                const struct GNUNET_MESH_Data *msg,
1013                MESH_ChannelNumber id)
1014 {
1015   struct GNUNET_MESH_LocalData *copy;
1016   uint16_t size = ntohs (msg->header.size) - sizeof (struct GNUNET_MESH_Data);
1017   char cbuf[size + sizeof (struct GNUNET_MESH_LocalData)];
1018
1019   if (size < sizeof (struct GNUNET_MessageHeader))
1020   {
1021     GNUNET_break_op (0);
1022     return;
1023   }
1024   if (NULL == c)
1025   {
1026     GNUNET_break (0);
1027     return;
1028   }
1029   copy = (struct GNUNET_MESH_LocalData *) cbuf;
1030   memcpy (&copy[1], &msg[1], size);
1031   copy->header.size = htons (sizeof (struct GNUNET_MESH_LocalData) + size);
1032   copy->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_LOCAL_DATA);
1033   copy->id = htonl (id);
1034   GNUNET_SERVER_notification_context_unicast (nc, c->handle,
1035                                               &copy->header, GNUNET_NO);
1036 }
1037
1038
1039 /**
1040  * Get the static string to represent a client.
1041  *
1042  * @param c Client.
1043  *
1044  * @return Static string for the client.
1045  */
1046 const char *
1047 GML_2s (const struct MeshClient *c)
1048 {
1049   static char buf[32];
1050
1051   sprintf (buf, "%u", c->id);
1052   return buf;
1053 }