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