-handle audio in mesh
[oweals/gnunet.git] / src / conversation / gnunet-service-conversation-new.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  * @file conversation/gnunet-service-conversation.c
22  * @brief conversation service implementation
23  * @author Simon Dieterle
24  * @author Andreas Fuchs
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_applications.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_signatures.h"
33 #include "gnunet_mesh_service.h"
34 #include "gnunet_conversation_service.h"
35 #include "conversation.h"
36
37
38 /**
39  * How long is our signature on a call valid?  Needs to be long enough for time zone
40  * differences and network latency to not matter.  No strong need for it to be short,
41  * but we simply like all signatures to eventually expire.
42  */
43 #define RING_TIMEOUT GNUNET_TIME_UNIT_DAYS
44
45
46 /**
47  * The possible connection status
48  */
49 enum LineStatus
50 {
51   /**
52    * We are waiting for incoming calls.
53    */
54   LS_CALLEE_LISTEN,
55
56   /**
57    * Our phone is ringing, waiting for the client to pick up.
58    */
59   LS_CALLEE_RINGING,
60
61   /**
62    * We are talking!
63    */
64   LS_CALLEE_CONNECTED,
65
66   /**
67    * We're in shutdown, sending hangup messages before cleaning up.
68    */
69   LS_CALLEE_SHUTDOWN,
70
71   /**
72    * We are waiting for the phone to be picked up.
73    */
74   LS_CALLER_CALLING,
75
76   /**
77    * We are talking!
78    */
79   LS_CALLER_CONNECTED,
80
81   /**
82    * We're in shutdown, sending hangup messages before cleaning up.
83    */
84   LS_CALLER_SHUTDOWN
85 };
86
87
88 /**
89  * A line connects a local client with a mesh tunnel (or, if it is an
90  * open line, is waiting for a mesh tunnel).
91  */
92 struct Line
93 {
94   /**
95    * Kept in a DLL.
96    */
97   struct Line *next;
98
99   /**
100    * Kept in a DLL.
101    */
102   struct Line *prev;
103
104   /**
105    * Handle for the reliable tunnel (contol data)
106    */
107   struct GNUNET_MESH_Tunnel *tunnel_reliable;
108   
109   /**
110    * Handle for unreliable tunnel (audio data)
111    */
112   struct GNUNET_MESH_Tunnel *tunnel_unreliable;
113
114   /**
115    * Transmit handle for pending audio messages
116    */
117   struct GNUNET_MESH_TransmitHandle *unreliable_mth;
118
119   /**
120    * Message queue for control messages
121    */
122   struct GNUNET_MQ_Handle *reliable_mq;
123
124   /**
125    * Handle to the line client.
126    */
127   struct GNUNET_SERVER_Client *client;
128
129   /**
130    * Target of the line, if we are the caller.
131    */
132   struct GNUNET_PeerIdentity target;
133
134   /**
135    * Our line number.
136    */
137   uint32_t local_line;
138
139   /**
140    * Remote line number.
141    */
142   uint32_t remote_line;
143
144   /**
145    * Current status of this line.
146    */ 
147   enum LineStatus status;
148
149 };
150
151
152 /**
153  * Our configuration.
154  */
155 static const struct GNUNET_CONFIGURATION_Handle *cfg;
156
157 /**
158  * Notification context containing all connected clients.
159  */
160 static struct GNUNET_SERVER_NotificationContext *nc;
161
162 /**
163  * Handle for mesh
164  */
165 static struct GNUNET_MESH_Handle *mesh;
166
167 /**
168  * Identity of this peer.
169  */
170 static struct GNUNET_PeerIdentity my_identity;
171
172 /**
173  * Head of DLL of active lines.
174  */
175 static struct Line *lines_head;
176
177 /**
178  * Tail of DLL of active lines.
179  */
180 static struct Line *lines_tail;
181
182 /**
183  * Counter for generating local line numbers.
184  * FIXME: randomize generation in the future
185  * to eliminate information leakage.
186  */
187 static uint32_t local_line_cnt;
188
189
190 /**
191  * Function to register a phone.
192  *
193  * @param cls closure, NULL
194  * @param client the client from which the message is
195  * @param message the message from the client
196  */
197 static void
198 handle_client_register_message (void *cls,
199                                 struct GNUNET_SERVER_Client *client,
200                                 const struct GNUNET_MessageHeader *message)
201 {
202   const struct ClientPhoneRegisterMessage *msg;
203   struct Line *line;
204
205   msg = (struct ClientPhoneRegisterMessage *) message;
206   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
207   if (NULL != line)
208   {
209     GNUNET_break (0);
210     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
211     return;
212   }
213   line = GNUNET_new (struct Line);
214   line->client = client;
215   GNUNET_SERVER_notification_context_add (nc, client);
216   GNUNET_CONTAINER_DLL_insert (lines_head,
217                                lines_tail,
218                                line);
219   line->local_line = ntohl (msg->line);
220   GNUNET_SERVER_client_set_user_context (client, line);
221   GNUNET_SERVER_receive_done (client, GNUNET_OK);
222 }
223
224
225 /**
226  * Function to handle a pickup request message from the client
227  *
228  * @param cls closure, NULL
229  * @param client the client from which the message is
230  * @param message the message from the client
231  */
232 static void
233 handle_client_pickup_message (void *cls,
234                               struct GNUNET_SERVER_Client *client,
235                               const struct GNUNET_MessageHeader *message)
236 {
237   const struct ClientPhonePickupMessage *msg;
238   struct GNUNET_MQ_Envelope *e;
239   struct MeshPhonePickupMessage *mppm;
240   const char *meta;
241   struct Line *line;
242   size_t len;
243
244   msg = (struct ClientPhonePickupMessage *) message;
245   meta = (const char *) &msg[1];
246   len = ntohs (msg->header.size) - sizeof (struct ClientPhonePickupMessage);
247   if ( (0 == len) ||
248        ('\0' != meta[len - 1]) )
249   {
250     meta = NULL;
251     len = 0;
252   }
253   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
254   if (NULL == line)
255   {
256     GNUNET_break (0);
257     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
258     return;
259   }
260   switch (line->status)
261   {
262   case LS_CALLEE_LISTEN:
263     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
264                 "Ignoring client's PICKUP message, caller has HUNG UP already\n");
265     GNUNET_SERVER_receive_done (client, GNUNET_OK);
266     break;
267   case LS_CALLEE_RINGING:
268     line->status = LS_CALLEE_CONNECTED;
269     break;
270   case LS_CALLEE_CONNECTED:
271     GNUNET_break (0);
272     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
273     return;
274   case LS_CALLEE_SHUTDOWN:
275     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
276                 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
277     GNUNET_SERVER_receive_done (client, GNUNET_OK);
278     break;
279   case LS_CALLER_CALLING:
280   case LS_CALLER_CONNECTED:
281   case LS_CALLER_SHUTDOWN:
282     GNUNET_break (0);
283     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
284     return;
285   }
286   line->status = LS_CALLEE_CONNECTED;
287   e = GNUNET_MQ_msg_extra (mppm,
288                            len,
289                            GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP);
290   memcpy (&mppm[1], meta, len);
291   GNUNET_MQ_send (line->reliable_mq, e);
292   GNUNET_SERVER_receive_done (client, GNUNET_OK);
293 }
294
295
296 /**
297  * Destroy the mesh tunnels of a line.
298  *
299  * @param line line to shutdown tunnels of
300  */
301 static void
302 destroy_line_mesh_tunnels (struct Line *line)
303 {
304   if (NULL != line->reliable_mq)
305   {
306     GNUNET_MQ_destroy (line->reliable_mq);
307     line->reliable_mq = NULL;
308   }
309   if (NULL != line->tunnel_unreliable)
310   {
311     GNUNET_MESH_tunnel_destroy (line->tunnel_unreliable);
312     line->tunnel_unreliable = NULL;
313   }
314   if (NULL != line->tunnel_reliable)
315   {
316     GNUNET_MESH_tunnel_destroy (line->tunnel_reliable);
317     line->tunnel_reliable = NULL;
318   }
319 }
320
321
322 /**
323  * We are done signalling shutdown to the other peer.  Close down
324  * (or reset) the line.
325  *
326  * @param cls the `struct Line` to reset/terminate
327  */
328 static void
329 mq_done_finish_caller_shutdown (void *cls)
330 {
331   struct Line *line = cls;
332
333   switch (line->status)
334   {
335   case LS_CALLEE_LISTEN:
336     GNUNET_break (0);
337     break;
338   case LS_CALLEE_RINGING:
339     GNUNET_break (0);
340     break;
341   case LS_CALLEE_CONNECTED:
342     GNUNET_break (0);
343     break;
344   case LS_CALLEE_SHUTDOWN:
345     line->status = LS_CALLEE_LISTEN;
346     destroy_line_mesh_tunnels (line);
347     return;
348   case LS_CALLER_CALLING:
349     line->status = LS_CALLER_SHUTDOWN;
350     break;
351   case LS_CALLER_CONNECTED:
352     line->status = LS_CALLER_SHUTDOWN;
353     break;
354   case LS_CALLER_SHUTDOWN:
355     destroy_line_mesh_tunnels (line);
356     GNUNET_CONTAINER_DLL_remove (lines_head,
357                                  lines_tail,
358                                  line);
359     GNUNET_free (line);
360     break;
361   }  
362 }
363
364
365 /**
366  * Function to handle a hangup request message from the client
367  *
368  * @param cls closure, NULL
369  * @param client the client from which the message is
370  * @param message the message from the client
371  */
372 static void
373 handle_client_hangup_message (void *cls,
374                               struct GNUNET_SERVER_Client *client,
375                               const struct GNUNET_MessageHeader *message)
376 {
377   const struct ClientPhoneHangupMessage *msg;
378   struct GNUNET_MQ_Envelope *e;
379   struct MeshPhoneHangupMessage *mhum;
380   const char *meta;
381   struct Line *line;
382   size_t len;
383
384   msg = (struct ClientPhoneHangupMessage *) message;
385   meta = (const char *) &msg[1];
386   len = ntohs (msg->header.size) - sizeof (struct ClientPhoneHangupMessage);
387   if ( (0 == len) ||
388        ('\0' != meta[len - 1]) )
389   {
390     meta = NULL;
391     len = 0;
392   }
393   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
394   if (NULL == line)
395   {
396     GNUNET_break (0);
397     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
398     return;
399   }
400   switch (line->status)
401   {
402   case LS_CALLEE_LISTEN:
403     GNUNET_break (0);
404     GNUNET_SERVER_receive_done (client, GNUNET_OK);
405     return;
406   case LS_CALLEE_RINGING:
407     line->status = LS_CALLEE_SHUTDOWN;
408     break;
409   case LS_CALLEE_CONNECTED:
410     line->status = LS_CALLEE_SHUTDOWN;
411     break;
412   case LS_CALLEE_SHUTDOWN:
413     GNUNET_break (0);
414     GNUNET_SERVER_receive_done (client, GNUNET_OK);
415     return;
416   case LS_CALLER_CALLING:
417     line->status = LS_CALLER_SHUTDOWN;
418     break;
419   case LS_CALLER_CONNECTED:
420     line->status = LS_CALLER_SHUTDOWN;
421     break;
422   case LS_CALLER_SHUTDOWN:
423     GNUNET_break (0);
424     GNUNET_SERVER_receive_done (client, GNUNET_OK);
425     return;
426   }
427   e = GNUNET_MQ_msg_extra (mhum,
428                            len,
429                            GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
430   memcpy (&mhum[1], meta, len);
431   GNUNET_MQ_notify_sent (e,
432                          &mq_done_finish_caller_shutdown,
433                          line);
434   GNUNET_MQ_send (line->reliable_mq, e);
435   GNUNET_SERVER_receive_done (client, GNUNET_OK);
436 }
437
438
439 /**
440  * Function to handle call request the client
441  *
442  * @param cls closure, NULL
443  * @param client the client from which the message is
444  * @param message the message from the client
445  */
446 static void
447 handle_client_call_message (void *cls,
448                             struct GNUNET_SERVER_Client *client,
449                             const struct GNUNET_MessageHeader *message)
450 {
451   const struct ClientCallMessage *msg;
452   struct Line *line;
453   struct GNUNET_MQ_Envelope *e;
454   struct MeshPhoneRingMessage *ring;
455
456   msg = (struct ClientCallMessage *) message;
457   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
458   if (NULL != line)
459   {
460     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
461     return;
462   }
463   line = GNUNET_new (struct Line);
464   line->target = msg->target;
465   GNUNET_CONTAINER_DLL_insert (lines_head,
466                                lines_tail,
467                                line);
468   line->remote_line = ntohl (msg->line);
469   line->status = LS_CALLER_CALLING;
470   line->tunnel_reliable = GNUNET_MESH_tunnel_create (mesh,
471                                                      line,
472                                                      &msg->target,
473                                                      GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
474                                                      GNUNET_NO,
475                                                      GNUNET_YES);
476   line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
477   line->local_line = local_line_cnt++;
478   e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
479   ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
480   ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
481                               sizeof (struct GNUNET_TIME_AbsoluteNBO) +
482                               sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
483                               sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
484   GNUNET_CRYPTO_ecc_key_get_public_for_signature (&msg->caller_id,
485                                                   &ring->caller_id);
486   ring->remote_line = msg->line;
487   ring->source_line = line->local_line;
488   ring->target = msg->target;
489   ring->source = my_identity;
490   ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
491   GNUNET_CRYPTO_ecc_sign (&msg->caller_id,
492                           &ring->purpose,
493                           &ring->signature);
494   GNUNET_MQ_send (line->reliable_mq, e);
495   GNUNET_SERVER_client_set_user_context (client, line);
496   GNUNET_SERVER_receive_done (client, GNUNET_OK);
497 }
498
499
500 /**
501  * Function to handle audio data from the client
502  *
503  * @param cls closure, NULL
504  * @param client the client from which the message is
505  * @param message the message from the client
506  */
507 static void
508 handle_client_audio_message (void *cls,
509                              struct GNUNET_SERVER_Client *client,
510                              const struct GNUNET_MessageHeader *message)
511 {
512   const struct ClientAudioMessage *msg;
513
514   msg = (struct ClientAudioMessage *) message;
515   GNUNET_break (0); // FIXME
516   GNUNET_SERVER_receive_done (client, GNUNET_OK);
517 }
518
519
520 /**
521  * We are done signalling shutdown to the other peer.  
522  * Destroy the tunnel.
523  *
524  * @param cls the `struct GNUNET_MESH_tunnel` to destroy
525  */
526 static void
527 mq_done_destroy_tunnel (void *cls)
528 {
529   struct GNUNET_MESH_Tunnel *tunnel = cls;
530   
531   GNUNET_MESH_tunnel_destroy (tunnel);
532 }
533
534
535 /**
536  * Function to handle a ring message incoming over mesh
537  *
538  * @param cls closure, NULL
539  * @param tunnel the tunnel over which the message arrived
540  * @param tunnel_ctx the tunnel context, can be NULL
541  * @param message the incoming message
542  * @return #GNUNET_OK
543  */
544 static int
545 handle_mesh_ring_message (void *cls,
546                           struct GNUNET_MESH_Tunnel *tunnel,
547                           void **tunnel_ctx,
548                           const struct GNUNET_MessageHeader *message)
549 {
550   const struct MeshPhoneRingMessage *msg;
551   struct Line *line;
552   struct GNUNET_MQ_Envelope *e;
553   struct MeshPhoneBusyMessage *busy;
554   struct ClientPhoneRingMessage cring;
555   
556   msg = (const struct MeshPhoneRingMessage *) message;
557   if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
558                                     sizeof (struct GNUNET_TIME_AbsoluteNBO) +
559                                     sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
560                                     sizeof (struct GNUNET_CRYPTO_EccPublicSignKey))) ||
561        (GNUNET_OK !=
562         GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
563                                   &msg->purpose,
564                                   &msg->signature,
565                                   &msg->caller_id)) )
566   {
567     GNUNET_break_op (0);
568     return GNUNET_SYSERR;
569   }
570   for (line = lines_head; NULL != line; line = line->next)  
571     if ( (line->local_line == ntohl (msg->remote_line)) &&
572          (LS_CALLEE_LISTEN == line->status) )
573       break;
574   if (NULL == line) 
575   {
576     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
577                 _("No available phone for incoming call on line %u, sending BUSY signal\n"),
578                 ntohl (msg->remote_line));
579     e = GNUNET_MQ_msg (busy, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY);
580     GNUNET_MQ_notify_sent (e,
581                            &mq_done_destroy_tunnel,
582                            tunnel);
583     GNUNET_MQ_send (line->reliable_mq, e);
584     GNUNET_MESH_receive_done (tunnel); /* needed? */
585     return GNUNET_OK;
586   }
587   line->status = LS_CALLEE_RINGING;
588   line->remote_line = ntohl (msg->source_line);
589   line->tunnel_reliable = tunnel;
590   line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
591   *tunnel_ctx = line;
592   cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
593   cring.header.size = htons (sizeof (cring));
594   cring.reserved = htonl (0);
595   cring.caller_id = msg->caller_id;
596   GNUNET_SERVER_notification_context_unicast (nc,
597                                               line->client,
598                                               &cring.header,
599                                               GNUNET_NO);
600   GNUNET_MESH_receive_done (tunnel);
601   return GNUNET_OK;
602 }
603
604
605 /**
606  * Function to handle a hangup message incoming over mesh
607  *
608  * @param cls closure, NULL
609  * @param tunnel the tunnel over which the message arrived
610  * @param tunnel_ctx the tunnel context, can be NULL
611  * @param message the incoming message
612  * @return #GNUNET_OK
613  */
614 static int
615 handle_mesh_hangup_message (void *cls,
616                             struct GNUNET_MESH_Tunnel *tunnel,
617                             void **tunnel_ctx,
618                             const struct GNUNET_MessageHeader *message)
619 {
620   struct Line *line = *tunnel_ctx;
621   const struct MeshPhoneHangupMessage *msg;
622   const char *reason;
623   size_t len = ntohs (message->size) - sizeof (struct MeshPhoneHangupMessage);
624   char buf[len + sizeof (struct ClientPhoneHangupMessage)];
625   struct ClientPhoneHangupMessage *hup;
626   
627   msg = (const struct MeshPhoneHangupMessage *) message;
628   len = ntohs (msg->header.size) - sizeof (struct MeshPhoneHangupMessage);
629   reason = (const char *) &msg[1];
630   if ( (0 == len) ||
631        ('\0' != reason[len - 1]) )
632   {
633     reason = NULL;
634     len = 0;
635   }
636   if (NULL == line)
637   {
638     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
639                 "HANGUP message received for non-existing line, dropping tunnel.\n");
640     return GNUNET_SYSERR;
641   }
642   *tunnel_ctx = NULL;
643   switch (line->status)
644   {
645   case LS_CALLEE_LISTEN:
646     GNUNET_break (0);
647     return GNUNET_SYSERR;
648   case LS_CALLEE_RINGING:
649     line->status = LS_CALLEE_LISTEN;
650     destroy_line_mesh_tunnels (line);
651     break;
652   case LS_CALLEE_CONNECTED:
653     line->status = LS_CALLEE_LISTEN;
654     destroy_line_mesh_tunnels (line);
655     break;
656   case LS_CALLEE_SHUTDOWN:
657     line->status = LS_CALLEE_LISTEN;
658     destroy_line_mesh_tunnels (line);
659     return GNUNET_OK;
660   case LS_CALLER_CALLING:
661     line->status = LS_CALLER_SHUTDOWN;
662     mq_done_finish_caller_shutdown (line);
663     break;
664   case LS_CALLER_CONNECTED:
665     line->status = LS_CALLER_SHUTDOWN;
666     mq_done_finish_caller_shutdown (line);
667     break;
668   case LS_CALLER_SHUTDOWN:
669     mq_done_finish_caller_shutdown (line);
670     return GNUNET_OK;
671   }
672   hup = (struct ClientPhoneHangupMessage *) buf;
673   hup->header.size = sizeof (buf);
674   hup->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
675   memcpy (&hup[1], reason, len);
676   GNUNET_SERVER_notification_context_unicast (nc,
677                                               line->client,
678                                               &hup->header,
679                                               GNUNET_NO);
680   GNUNET_MESH_receive_done (tunnel);
681   return GNUNET_OK;
682 }
683
684
685 /**
686  * Function to handle a pickup message incoming over mesh
687  *
688  * @param cls closure, NULL
689  * @param tunnel the tunnel over which the message arrived
690  * @param tunnel_ctx the tunnel context, can be NULL
691  * @param message the incoming message
692  * @return #GNUNET_OK
693  */
694 static int
695 handle_mesh_pickup_message (void *cls,
696                             struct GNUNET_MESH_Tunnel *tunnel,
697                             void **tunnel_ctx,
698                             const struct GNUNET_MessageHeader *message)
699 {
700   const struct MeshPhonePickupMessage *msg;
701   struct Line *line = *tunnel_ctx;
702   const char *metadata;
703   size_t len = ntohs (message->size) - sizeof (struct MeshPhonePickupMessage);
704   char buf[len + sizeof (struct ClientPhonePickupMessage)];
705   struct ClientPhonePickupMessage *pick;
706   
707   msg = (const struct MeshPhonePickupMessage *) message;
708   len = ntohs (msg->header.size) - sizeof (struct MeshPhonePickupMessage);
709   metadata = (const char *) &msg[1];
710   if ( (0 == len) ||
711        ('\0' != metadata[len - 1]) )
712   {
713     metadata = NULL;
714     len = 0;
715   }
716   if (NULL == line)
717   {
718     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
719                 "PICKUP message received for non-existing line, dropping tunnel.\n");
720     return GNUNET_SYSERR;
721   }
722   GNUNET_MESH_receive_done (tunnel);
723   switch (line->status)
724   {
725   case LS_CALLEE_LISTEN:
726     GNUNET_break (0);
727     return GNUNET_SYSERR;
728   case LS_CALLEE_RINGING:
729   case LS_CALLEE_CONNECTED:
730     GNUNET_break_op (0);
731     destroy_line_mesh_tunnels (line);
732     line->status = LS_CALLEE_LISTEN;
733     return GNUNET_SYSERR;
734   case LS_CALLEE_SHUTDOWN:
735     GNUNET_break_op (0);
736     line->status = LS_CALLEE_LISTEN;
737     destroy_line_mesh_tunnels (line);
738     break;
739   case LS_CALLER_CALLING:
740     line->status = LS_CALLER_CONNECTED;
741     break;
742   case LS_CALLER_CONNECTED:
743     GNUNET_break_op (0);
744     return GNUNET_OK;
745   case LS_CALLER_SHUTDOWN:
746     GNUNET_break_op (0);
747     mq_done_finish_caller_shutdown (line);
748     return GNUNET_SYSERR;
749   }
750   pick = (struct ClientPhonePickupMessage *) buf;
751   pick->header.size = sizeof (buf);
752   pick->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
753   memcpy (&pick[1], metadata, len);
754   GNUNET_SERVER_notification_context_unicast (nc,
755                                               line->client,
756                                               &pick->header,
757                                               GNUNET_NO);
758   line->tunnel_unreliable = GNUNET_MESH_tunnel_create (mesh,
759                                                        line,
760                                                        &line->target,
761                                                        GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
762                                                        GNUNET_YES,
763                                                        GNUNET_NO);
764   return GNUNET_OK;
765 }
766
767
768 /**
769  * Function to handle a busy message incoming over mesh
770  *
771  * @param cls closure, NULL
772  * @param tunnel the tunnel over which the message arrived
773  * @param tunnel_ctx the tunnel context, can be NULL
774  * @param message the incoming message
775  * @return #GNUNET_OK
776  */
777 static int
778 handle_mesh_busy_message (void *cls,
779                           struct GNUNET_MESH_Tunnel *tunnel,
780                           void **tunnel_ctx,
781                           const struct GNUNET_MessageHeader *message)
782 {
783   struct Line *line = *tunnel_ctx;
784   struct ClientPhoneBusyMessage busy;
785
786   if (NULL == line)
787   {
788     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
789                 "HANGUP message received for non-existing line, dropping tunnel.\n");
790     return GNUNET_SYSERR;
791   }
792   busy.header.size = sizeof (busy);
793   busy.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY);
794   GNUNET_SERVER_notification_context_unicast (nc,
795                                               line->client,
796                                               &busy.header,
797                                               GNUNET_NO);
798   GNUNET_MESH_receive_done (tunnel);
799   *tunnel_ctx = NULL;
800   switch (line->status)
801   {
802   case LS_CALLEE_LISTEN:
803     GNUNET_break (0);
804     return GNUNET_SYSERR;
805   case LS_CALLEE_RINGING:
806     GNUNET_break_op (0);
807     break;
808   case LS_CALLEE_CONNECTED:
809     GNUNET_break_op (0);
810     break;
811   case LS_CALLEE_SHUTDOWN:
812     GNUNET_break_op (0);
813     break;
814   case LS_CALLER_CALLING:
815     line->status = LS_CALLER_SHUTDOWN;
816     mq_done_finish_caller_shutdown (line);
817     break;
818   case LS_CALLER_CONNECTED:
819     line->status = LS_CALLER_SHUTDOWN;
820     mq_done_finish_caller_shutdown (line);
821     break;
822   case LS_CALLER_SHUTDOWN:
823     mq_done_finish_caller_shutdown (line);
824     break;
825   }
826   return GNUNET_OK;
827 }
828
829
830 /**
831  * Function to handle an audio message incoming over mesh
832  *
833  * @param cls closure, NULL
834  * @param tunnel the tunnel over which the message arrived
835  * @param tunnel_ctx the tunnel context, can be NULL
836  * @param message the incoming message
837  * @return #GNUNET_OK
838  */
839 static int
840 handle_mesh_audio_message (void *cls,
841                            struct GNUNET_MESH_Tunnel *tunnel,
842                            void **tunnel_ctx,
843                            const struct GNUNET_MessageHeader *message)
844 {
845   const struct MeshAudioMessage *msg;
846   struct Line *line = *tunnel_ctx;
847   struct GNUNET_PeerIdentity sender;
848   size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
849   char buf[msize + sizeof (struct ClientAudioMessage)];
850   struct ClientAudioMessage *cam;
851   
852   msg = (const struct MeshAudioMessage *) message;
853   if (NULL == line)
854   {
855     sender = *GNUNET_MESH_tunnel_get_info (tunnel,
856                                            GNUNET_MESH_OPTION_PEER)->peer;
857     for (line = lines_head; NULL != line; line = line->next)
858       if ( (line->local_line == ntohl (msg->remote_line)) &&
859            (LS_CALLEE_CONNECTED == line->status) &&
860            (0 == memcmp (&line->target,
861                          &sender,
862                          sizeof (struct GNUNET_PeerIdentity))) &&
863            (NULL == line->tunnel_unreliable) )
864         break;
865     if (NULL == line)
866     {
867       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
868                   "Received AUDIO data for non-existing line %u, dropping.\n",
869                   ntohl (msg->remote_line));
870       return GNUNET_SYSERR;
871     }
872     line->tunnel_unreliable = tunnel;
873     *tunnel_ctx = line;
874   }
875   cam = (struct ClientAudioMessage *) buf;
876   cam->header.size = htons (sizeof (buf));
877   cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
878   memcpy (&cam[1], &msg[1], msize);
879   GNUNET_SERVER_notification_context_unicast (nc,
880                                               line->client,
881                                               &cam->header,
882                                               GNUNET_YES);
883   GNUNET_MESH_receive_done (tunnel);
884   return GNUNET_OK;
885 }
886
887
888 /**
889  * Method called whenever another peer has added us to a tunnel
890  * the other peer initiated.
891  *
892  * @param cls closure
893  * @param tunnel new handle to the tunnel
894  * @param initiator peer that started the tunnel
895  * @param port port
896  * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
897  */
898 static void *
899 inbound_tunnel (void *cls,
900                 struct GNUNET_MESH_Tunnel *tunnel,
901                 const struct GNUNET_PeerIdentity *initiator, 
902                 uint32_t port)
903 {
904   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
905               _("Received incoming tunnel on port %d\n"), 
906               port);
907   return NULL;
908 }
909
910
911 /**
912  * Function called whenever an inbound tunnel is destroyed.  Should clean up
913  * any associated state.
914  *
915  * @param cls closure (set from #GNUNET_MESH_connect)
916  * @param tunnel connection to the other end (henceforth invalid)
917  * @param tunnel_ctx place where local state associated
918  *                   with the tunnel is stored
919  */
920 static void
921 inbound_end (void *cls,
922              const struct GNUNET_MESH_Tunnel *tunnel,
923              void *tunnel_ctx)
924 {
925   struct Line *line = tunnel_ctx;
926   struct ClientPhoneHangupMessage hup;
927
928   if (NULL == line)
929     return;
930   if (line->tunnel_unreliable == tunnel)
931   {
932     line->tunnel_unreliable = NULL;
933     return;
934   }
935   hup.header.size = sizeof (hup);
936   hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
937   switch (line->status)
938   {
939   case LS_CALLEE_LISTEN:
940     GNUNET_break (0);
941     return;
942   case LS_CALLEE_RINGING:
943   case LS_CALLEE_CONNECTED:
944     GNUNET_SERVER_notification_context_unicast (nc,
945                                                 line->client,
946                                                 &hup.header,
947                                                 GNUNET_NO);
948     line->status = LS_CALLEE_LISTEN;
949     break;
950   case LS_CALLEE_SHUTDOWN:
951     line->status = LS_CALLEE_LISTEN;
952     destroy_line_mesh_tunnels (line);
953     break;
954   case LS_CALLER_CALLING:
955   case LS_CALLER_CONNECTED:
956     GNUNET_SERVER_notification_context_unicast (nc,
957                                                 line->client,
958                                                 &hup.header,
959                                                 GNUNET_NO);
960     destroy_line_mesh_tunnels (line);
961     GNUNET_CONTAINER_DLL_remove (lines_head,
962                                  lines_tail,
963                                  line);
964     GNUNET_free (line);
965     break;
966   case LS_CALLER_SHUTDOWN:
967     destroy_line_mesh_tunnels (line);
968     GNUNET_CONTAINER_DLL_remove (lines_head,
969                                  lines_tail,
970                                  line);
971     GNUNET_free (line);
972     break;
973   }
974 }
975
976
977 /**
978  * A client disconnected.  Remove all of its data structure entries.
979  *
980  * @param cls closure, NULL
981  * @param client identification of the client
982  */
983 static void
984 handle_client_disconnect (void *cls, 
985                           struct GNUNET_SERVER_Client *client)
986 {
987   struct Line *line;
988
989   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
990   if (NULL == line)
991     return;
992   GNUNET_CONTAINER_DLL_remove (lines_head,
993                                lines_tail,
994                                line);
995   GNUNET_free (line);
996   GNUNET_SERVER_client_set_user_context (client, NULL);
997 }
998
999
1000 /**
1001  * Shutdown nicely
1002  * 
1003  * @param cls closure, NULL
1004  * @param tc the task context
1005  */
1006 static void
1007 do_shutdown (void *cls,
1008              const struct GNUNET_SCHEDULER_TaskContext *tc)
1009 {
1010   if (NULL != mesh)
1011   {
1012     GNUNET_MESH_disconnect (mesh);
1013     mesh = NULL;
1014   }
1015   if (NULL != nc)
1016   {
1017     GNUNET_SERVER_notification_context_destroy (nc);
1018     nc = NULL;
1019   }
1020 }
1021
1022
1023 /**
1024  * Main function that will be run by the scheduler.
1025  *
1026  * @param cls closure
1027  * @param server server handle
1028  * @param c configuration
1029  */
1030 static void
1031 run (void *cls, 
1032      struct GNUNET_SERVER_Handle *server,
1033      const struct GNUNET_CONFIGURATION_Handle *c)
1034 {
1035   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1036     {&handle_client_register_message, NULL,
1037      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1038      sizeof (struct ClientPhoneRegisterMessage)},
1039     {&handle_client_pickup_message, NULL,
1040      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1041      0},
1042     {&handle_client_hangup_message, NULL,
1043      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1044      0},
1045     {&handle_client_call_message, NULL,
1046      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1047      0},
1048     {&handle_client_audio_message, NULL,
1049      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1050      0},
1051     {NULL, NULL, 0, 0}
1052   };
1053   static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1054     {&handle_mesh_ring_message,
1055      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
1056      sizeof (struct MeshPhoneRingMessage)},
1057     {&handle_mesh_hangup_message, 
1058      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
1059      0},
1060     {&handle_mesh_pickup_message, 
1061      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
1062      0},
1063     {&handle_mesh_busy_message, 
1064      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY,
1065      sizeof (struct MeshPhoneBusyMessage)},
1066     {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
1067      0},
1068     {NULL, 0, 0}
1069   };
1070   static uint32_t ports[] = { 
1071     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
1072     GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1073     0 
1074   };
1075
1076   cfg = c;
1077   GNUNET_assert (GNUNET_OK ==
1078                  GNUNET_CRYPTO_get_host_identity (cfg,
1079                                                   &my_identity));
1080   mesh = GNUNET_MESH_connect (cfg,
1081                               NULL,
1082                               &inbound_tunnel,
1083                               &inbound_end, 
1084                               mesh_handlers, 
1085                               ports);
1086
1087   if (NULL == mesh)
1088   {
1089     GNUNET_break (0);
1090     GNUNET_SCHEDULER_shutdown ();
1091     return;
1092   }
1093   nc = GNUNET_SERVER_notification_context_create (server, 16);
1094   GNUNET_SERVER_add_handlers (server, server_handlers);
1095   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1096   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, 
1097                                 &do_shutdown,
1098                                 NULL);
1099 }
1100
1101
1102 /**
1103  * The main function for the conversation service.
1104  *
1105  * @param argc number of arguments from the command line
1106  * @param argv command line arguments
1107  * @return 0 ok, 1 on error
1108  */
1109 int
1110 main (int argc, 
1111       char *const *argv)
1112 {
1113   return (GNUNET_OK ==
1114           GNUNET_SERVICE_run (argc, argv,
1115                               "conversation", 
1116                               GNUNET_SERVICE_OPTION_NONE,
1117                               &run, NULL)) ? 0 : 1;
1118 }
1119
1120 /* end of gnunet-service-conversation.c */