-only run tests if we actually had pulse/opus
[oweals/gnunet.git] / src / conversation / gnunet-service-conversation.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    * Temporary buffer for audio data.
136    */
137   void *audio_data;
138
139   /**
140    * Number of bytes in @e audio_data.
141    */
142   size_t audio_size;
143
144   /**
145    * Our line number.
146    */
147   uint32_t local_line;
148
149   /**
150    * Remote line number.
151    */
152   uint32_t remote_line;
153
154   /**
155    * Current status of this line.
156    */
157   enum LineStatus status;
158
159 };
160
161
162 /**
163  * Our configuration.
164  */
165 static const struct GNUNET_CONFIGURATION_Handle *cfg;
166
167 /**
168  * Notification context containing all connected clients.
169  */
170 static struct GNUNET_SERVER_NotificationContext *nc;
171
172 /**
173  * Handle for mesh
174  */
175 static struct GNUNET_MESH_Handle *mesh;
176
177 /**
178  * Identity of this peer.
179  */
180 static struct GNUNET_PeerIdentity my_identity;
181
182 /**
183  * Head of DLL of active lines.
184  */
185 static struct Line *lines_head;
186
187 /**
188  * Tail of DLL of active lines.
189  */
190 static struct Line *lines_tail;
191
192 /**
193  * Counter for generating local line numbers.
194  * FIXME: randomize generation in the future
195  * to eliminate information leakage.
196  */
197 static uint32_t local_line_cnt;
198
199
200 /**
201  * Function to register a phone.
202  *
203  * @param cls closure, NULL
204  * @param client the client from which the message is
205  * @param message the message from the client
206  */
207 static void
208 handle_client_register_message (void *cls,
209                                 struct GNUNET_SERVER_Client *client,
210                                 const struct GNUNET_MessageHeader *message)
211 {
212   const struct ClientPhoneRegisterMessage *msg;
213   struct Line *line;
214
215   msg = (struct ClientPhoneRegisterMessage *) message;
216   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
217   if (NULL != line)
218   {
219     GNUNET_break (0);
220     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
221     return;
222   }
223   line = GNUNET_new (struct Line);
224   line->client = client;
225   GNUNET_SERVER_notification_context_add (nc, client);
226   GNUNET_SERVER_client_set_user_context (client, line);
227   GNUNET_CONTAINER_DLL_insert (lines_head,
228                                lines_tail,
229                                line);
230   line->local_line = ntohl (msg->line);
231   GNUNET_SERVER_receive_done (client, GNUNET_OK);
232 }
233
234
235 /**
236  * Function to handle a pickup request message from the client
237  *
238  * @param cls closure, NULL
239  * @param client the client from which the message is
240  * @param message the message from the client
241  */
242 static void
243 handle_client_pickup_message (void *cls,
244                               struct GNUNET_SERVER_Client *client,
245                               const struct GNUNET_MessageHeader *message)
246 {
247   const struct ClientPhonePickupMessage *msg;
248   struct GNUNET_MQ_Envelope *e;
249   struct MeshPhonePickupMessage *mppm;
250   const char *meta;
251   struct Line *line;
252   size_t len;
253
254   msg = (struct ClientPhonePickupMessage *) message;
255   meta = (const char *) &msg[1];
256   len = ntohs (msg->header.size) - sizeof (struct ClientPhonePickupMessage);
257   if ( (0 == len) ||
258        ('\0' != meta[len - 1]) )
259   {
260     meta = NULL;
261     len = 0;
262   }
263   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
264   if (NULL == line)
265   {
266     GNUNET_break (0);
267     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
268     return;
269   }
270   switch (line->status)
271   {
272   case LS_CALLEE_LISTEN:
273     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
274                 "Ignoring client's PICKUP message, caller has HUNG UP already\n");
275     GNUNET_SERVER_receive_done (client, GNUNET_OK);
276     break;
277   case LS_CALLEE_RINGING:
278     line->status = LS_CALLEE_CONNECTED;
279     break;
280   case LS_CALLEE_CONNECTED:
281     GNUNET_break (0);
282     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
283     return;
284   case LS_CALLEE_SHUTDOWN:
285     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
286                 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
287     GNUNET_SERVER_receive_done (client, GNUNET_OK);
288     break;
289   case LS_CALLER_CALLING:
290   case LS_CALLER_CONNECTED:
291   case LS_CALLER_SHUTDOWN:
292     GNUNET_break (0);
293     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
294     return;
295   }
296   line->status = LS_CALLEE_CONNECTED;
297   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
298               "Sending PICK_UP message to mesh with meta data `%s'\n",
299               meta);
300   e = GNUNET_MQ_msg_extra (mppm,
301                            len,
302                            GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP);
303   memcpy (&mppm[1], meta, len);
304   GNUNET_MQ_send (line->reliable_mq, e);
305   GNUNET_SERVER_receive_done (client, GNUNET_OK);
306 }
307
308
309 /**
310  * Destroy the mesh tunnels of a line.
311  *
312  * @param line line to shutdown tunnels of
313  */
314 static void
315 destroy_line_mesh_tunnels (struct Line *line)
316 {
317   struct GNUNET_MESH_Tunnel *t;
318
319   if (NULL != line->reliable_mq)
320   {
321     GNUNET_MQ_destroy (line->reliable_mq);
322     line->reliable_mq = NULL;
323   }
324   if (NULL != line->unreliable_mth)
325   {
326     GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
327     line->unreliable_mth = NULL;
328   }
329   if (NULL != (t = line->tunnel_unreliable))
330   {
331     line->tunnel_unreliable = NULL;
332     GNUNET_MESH_tunnel_destroy (t);
333   }
334   if (NULL != (t = line->tunnel_reliable))
335   {
336     line->tunnel_reliable = NULL;
337     GNUNET_MESH_tunnel_destroy (t);
338   }
339 }
340
341
342 /**
343  * We are done signalling shutdown to the other peer.  Close down
344  * (or reset) the line.
345  *
346  * @param cls the `struct Line` to reset/terminate
347  */
348 static void
349 mq_done_finish_caller_shutdown (void *cls)
350 {
351   struct Line *line = cls;
352
353   switch (line->status)
354   {
355   case LS_CALLEE_LISTEN:
356     GNUNET_break (0);
357     break;
358   case LS_CALLEE_RINGING:
359     GNUNET_break (0);
360     break;
361   case LS_CALLEE_CONNECTED:
362     GNUNET_break (0);
363     break;
364   case LS_CALLEE_SHUTDOWN:
365     line->status = LS_CALLEE_LISTEN;
366     destroy_line_mesh_tunnels (line);
367     return;
368   case LS_CALLER_CALLING:
369     line->status = LS_CALLER_SHUTDOWN;
370     break;
371   case LS_CALLER_CONNECTED:
372     line->status = LS_CALLER_SHUTDOWN;
373     break;
374   case LS_CALLER_SHUTDOWN:
375     destroy_line_mesh_tunnels (line);
376     break;
377   }
378 }
379
380
381 /**
382  * Function to handle a hangup request message from the client
383  *
384  * @param cls closure, NULL
385  * @param client the client from which the message is
386  * @param message the message from the client
387  */
388 static void
389 handle_client_hangup_message (void *cls,
390                               struct GNUNET_SERVER_Client *client,
391                               const struct GNUNET_MessageHeader *message)
392 {
393   const struct ClientPhoneHangupMessage *msg;
394   struct GNUNET_MQ_Envelope *e;
395   struct MeshPhoneHangupMessage *mhum;
396   const char *meta;
397   struct Line *line;
398   size_t len;
399
400   msg = (struct ClientPhoneHangupMessage *) message;
401   meta = (const char *) &msg[1];
402   len = ntohs (msg->header.size) - sizeof (struct ClientPhoneHangupMessage);
403   if ( (0 == len) ||
404        ('\0' != meta[len - 1]) )
405   {
406     meta = NULL;
407     len = 0;
408   }
409   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
410   if (NULL == line)
411   {
412     GNUNET_break (0);
413     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
414     return;
415   }
416   switch (line->status)
417   {
418   case LS_CALLEE_LISTEN:
419     GNUNET_break (0);
420     GNUNET_SERVER_receive_done (client, GNUNET_OK);
421     return;
422   case LS_CALLEE_RINGING:
423     line->status = LS_CALLEE_SHUTDOWN;
424     break;
425   case LS_CALLEE_CONNECTED:
426     line->status = LS_CALLEE_SHUTDOWN;
427     break;
428   case LS_CALLEE_SHUTDOWN:
429     GNUNET_break (0);
430     GNUNET_SERVER_receive_done (client, GNUNET_OK);
431     return;
432   case LS_CALLER_CALLING:
433     line->status = LS_CALLER_SHUTDOWN;
434     break;
435   case LS_CALLER_CONNECTED:
436     line->status = LS_CALLER_SHUTDOWN;
437     break;
438   case LS_CALLER_SHUTDOWN:
439     GNUNET_break (0);
440     GNUNET_SERVER_receive_done (client, GNUNET_OK);
441     return;
442   }
443   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444               "Sending HANG_UP message via mesh with meta data `%s'\n",
445               meta);
446   e = GNUNET_MQ_msg_extra (mhum,
447                            len,
448                            GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
449   memcpy (&mhum[1], meta, len);
450   GNUNET_MQ_notify_sent (e,
451                          &mq_done_finish_caller_shutdown,
452                          line);
453   GNUNET_MQ_send (line->reliable_mq, e);
454   GNUNET_SERVER_receive_done (client, GNUNET_OK);
455 }
456
457
458 /**
459  * Function to handle call request the client
460  *
461  * @param cls closure, NULL
462  * @param client the client from which the message is
463  * @param message the message from the client
464  */
465 static void
466 handle_client_call_message (void *cls,
467                             struct GNUNET_SERVER_Client *client,
468                             const struct GNUNET_MessageHeader *message)
469 {
470   const struct ClientCallMessage *msg;
471   struct Line *line;
472   struct GNUNET_MQ_Envelope *e;
473   struct MeshPhoneRingMessage *ring;
474
475   msg = (struct ClientCallMessage *) message;
476   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
477   if (NULL != line)
478   {
479     GNUNET_break (0);
480     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
481     return;
482   }
483   line = GNUNET_new (struct Line);
484   line->client = client;
485   GNUNET_SERVER_client_set_user_context (client, line);
486   GNUNET_SERVER_notification_context_add (nc, client);
487   line->target = msg->target;
488   GNUNET_CONTAINER_DLL_insert (lines_head,
489                                lines_tail,
490                                line);
491   line->remote_line = ntohl (msg->line);
492   line->status = LS_CALLER_CALLING;
493   line->tunnel_reliable = GNUNET_MESH_tunnel_create (mesh,
494                                                      line,
495                                                      &msg->target,
496                                                      GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
497                                                      GNUNET_NO,
498                                                      GNUNET_YES);
499   line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
500   line->local_line = local_line_cnt++;
501   e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
502   ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
503   ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
504                               sizeof (struct GNUNET_TIME_AbsoluteNBO) +
505                               sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
506                               sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
507   GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
508                                                   &ring->caller_id);
509   ring->remote_line = msg->line;
510   ring->source_line = line->local_line;
511   ring->target = msg->target;
512   ring->source = my_identity;
513   ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
514   GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
515                           &ring->purpose,
516                           &ring->signature);
517   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518               "Sending RING message via mesh\n");
519   GNUNET_MQ_send (line->reliable_mq, e);
520   GNUNET_SERVER_receive_done (client, GNUNET_OK);
521 }
522
523
524 /**
525  * Transmit audio data via unreliable mesh channel.
526  *
527  * @param cls the `struct Line` we are transmitting for
528  * @param size number of bytes available in @a buf
529  * @param buf where to copy the data
530  * @return number of bytes copied to @a buf
531  */
532 static size_t
533 transmit_line_audio (void *cls,
534                      size_t size,
535                      void *buf)
536 {
537   struct Line *line = cls;
538   struct MeshAudioMessage *mam = buf;
539
540   line->unreliable_mth = NULL;
541   if ( (NULL == buf) ||
542        (size < sizeof (struct MeshAudioMessage) + line->audio_size) )
543     {
544     /* eh, other error handling? */
545     return 0;
546   }
547   mam->header.size = htons (sizeof (struct MeshAudioMessage) + line->audio_size);
548   mam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO);
549   mam->remote_line = htonl (line->remote_line);
550   memcpy (&mam[1], line->audio_data, line->audio_size);
551   GNUNET_free (line->audio_data);
552   line->audio_data = NULL;
553   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
554               "Sending %u bytes of audio data via mesh\n",
555               line->audio_size);
556   return sizeof (struct MeshAudioMessage) + line->audio_size;
557 }
558
559
560 /**
561  * Function to handle audio data from the client
562  *
563  * @param cls closure, NULL
564  * @param client the client from which the message is
565  * @param message the message from the client
566  */
567 static void
568 handle_client_audio_message (void *cls,
569                              struct GNUNET_SERVER_Client *client,
570                              const struct GNUNET_MessageHeader *message)
571 {
572   const struct ClientAudioMessage *msg;
573   struct Line *line;
574   size_t size;
575
576   size = ntohs (message->size) - sizeof (struct ClientAudioMessage);
577   msg = (struct ClientAudioMessage *) message;
578   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
579   if (NULL == line)
580   {
581     GNUNET_break (0);
582     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
583     return;
584   }
585   switch (line->status)
586   {
587   case LS_CALLEE_LISTEN:
588     /* could be OK if the line just was closed by the other side */
589     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
590                 "Audio data dropped, channel is down\n");
591     GNUNET_SERVER_receive_done (client, GNUNET_OK);
592     break;
593   case LS_CALLEE_RINGING:
594   case LS_CALLER_CALLING:
595     GNUNET_break (0);
596     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
597     return;
598   case LS_CALLEE_CONNECTED:
599   case LS_CALLER_CONNECTED:
600     /* common case, handled below */
601     break;
602   case LS_CALLEE_SHUTDOWN:
603   case LS_CALLER_SHUTDOWN:
604     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
605                 "Mesh audio channel in shutdown; audio data dropped\n");
606     GNUNET_SERVER_receive_done (client, GNUNET_OK);
607     return;
608   }
609   if (NULL == line->tunnel_unreliable)
610   {
611     GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
612                 _("Mesh audio channel not ready; audio data dropped\n"));
613     GNUNET_SERVER_receive_done (client, GNUNET_OK);
614     return;
615   }
616   if (NULL != line->unreliable_mth)
617   {
618     /* NOTE: we may want to not do this and instead combine the data */
619     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
620                 "Bandwidth insufficient; dropping previous audio data segment with %u bytes\n",
621                 (unsigned int) line->audio_size);
622     GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
623     line->unreliable_mth = NULL;
624     GNUNET_free (line->audio_data);
625     line->audio_data = NULL;
626   }
627   line->audio_size = size;
628   line->audio_data = GNUNET_malloc (line->audio_size);
629   memcpy (line->audio_data,
630           &msg[1],
631           size);
632   line->unreliable_mth = GNUNET_MESH_notify_transmit_ready (line->tunnel_unreliable,
633                                                             GNUNET_NO,
634                                                             GNUNET_TIME_UNIT_FOREVER_REL,
635                                                             sizeof (struct MeshAudioMessage)
636                                                             + line->audio_size,
637                                                             &transmit_line_audio,
638                                                             line);
639   GNUNET_SERVER_receive_done (client, GNUNET_OK);
640 }
641
642
643 /**
644  * We are done signalling shutdown to the other peer.
645  * Destroy the tunnel.
646  *
647  * @param cls the `struct GNUNET_MESH_tunnel` to destroy
648  */
649 static void
650 mq_done_destroy_tunnel (void *cls)
651 {
652   struct GNUNET_MESH_Tunnel *tunnel = cls;
653
654   GNUNET_MESH_tunnel_destroy (tunnel);
655 }
656
657
658 /**
659  * Function to handle a ring message incoming over mesh
660  *
661  * @param cls closure, NULL
662  * @param tunnel the tunnel over which the message arrived
663  * @param tunnel_ctx the tunnel context, can be NULL
664  * @param message the incoming message
665  * @return #GNUNET_OK
666  */
667 static int
668 handle_mesh_ring_message (void *cls,
669                           struct GNUNET_MESH_Tunnel *tunnel,
670                           void **tunnel_ctx,
671                           const struct GNUNET_MessageHeader *message)
672 {
673   const struct MeshPhoneRingMessage *msg;
674   struct Line *line;
675   struct GNUNET_MQ_Envelope *e;
676   struct MeshPhoneBusyMessage *busy;
677   struct ClientPhoneRingMessage cring;
678
679   msg = (const struct MeshPhoneRingMessage *) message;
680   if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
681                                     sizeof (struct GNUNET_TIME_AbsoluteNBO) +
682                                     sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
683                                     sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) ||
684        (GNUNET_OK !=
685         GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
686                                   &msg->purpose,
687                                   &msg->signature,
688                                   &msg->caller_id)) )
689   {
690     GNUNET_break_op (0);
691     return GNUNET_SYSERR;
692   }
693   for (line = lines_head; NULL != line; line = line->next)
694     if ( (line->local_line == ntohl (msg->remote_line)) &&
695          (LS_CALLEE_LISTEN == line->status) )
696       break;
697   if (NULL == line)
698   {
699     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
700                 _("No available phone for incoming call on line %u, sending BUSY signal\n"),
701                 ntohl (msg->remote_line));
702     e = GNUNET_MQ_msg (busy, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY);
703     GNUNET_MQ_notify_sent (e,
704                            &mq_done_destroy_tunnel,
705                            tunnel);
706     GNUNET_MQ_send (line->reliable_mq, e);
707     GNUNET_MESH_receive_done (tunnel); /* needed? */
708     return GNUNET_OK;
709   }
710   line->status = LS_CALLEE_RINGING;
711   line->remote_line = ntohl (msg->source_line);
712   line->tunnel_reliable = tunnel;
713   line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
714   *tunnel_ctx = line;
715   cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
716   cring.header.size = htons (sizeof (cring));
717   cring.reserved = htonl (0);
718   cring.caller_id = msg->caller_id;
719   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720               "Sending RING message to client\n");
721   GNUNET_SERVER_notification_context_unicast (nc,
722                                               line->client,
723                                               &cring.header,
724                                               GNUNET_NO);
725   GNUNET_MESH_receive_done (tunnel);
726   return GNUNET_OK;
727 }
728
729
730 /**
731  * Function to handle a hangup message incoming over mesh
732  *
733  * @param cls closure, NULL
734  * @param tunnel the tunnel over which the message arrived
735  * @param tunnel_ctx the tunnel context, can be NULL
736  * @param message the incoming message
737  * @return #GNUNET_OK
738  */
739 static int
740 handle_mesh_hangup_message (void *cls,
741                             struct GNUNET_MESH_Tunnel *tunnel,
742                             void **tunnel_ctx,
743                             const struct GNUNET_MessageHeader *message)
744 {
745   struct Line *line = *tunnel_ctx;
746   const struct MeshPhoneHangupMessage *msg;
747   const char *reason;
748   size_t len = ntohs (message->size) - sizeof (struct MeshPhoneHangupMessage);
749   char buf[len + sizeof (struct ClientPhoneHangupMessage)];
750   struct ClientPhoneHangupMessage *hup;
751
752   msg = (const struct MeshPhoneHangupMessage *) message;
753   len = ntohs (msg->header.size) - sizeof (struct MeshPhoneHangupMessage);
754   reason = (const char *) &msg[1];
755   if ( (0 == len) ||
756        ('\0' != reason[len - 1]) )
757   {
758     reason = NULL;
759     len = 0;
760   }
761   if (NULL == line)
762   {
763     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
764                 "HANGUP message received for non-existing line, dropping tunnel.\n");
765     return GNUNET_SYSERR;
766   }
767   *tunnel_ctx = NULL;
768   switch (line->status)
769   {
770   case LS_CALLEE_LISTEN:
771     GNUNET_break (0);
772     return GNUNET_SYSERR;
773   case LS_CALLEE_RINGING:
774     line->status = LS_CALLEE_LISTEN;
775     destroy_line_mesh_tunnels (line);
776     break;
777   case LS_CALLEE_CONNECTED:
778     line->status = LS_CALLEE_LISTEN;
779     destroy_line_mesh_tunnels (line);
780     break;
781   case LS_CALLEE_SHUTDOWN:
782     line->status = LS_CALLEE_LISTEN;
783     destroy_line_mesh_tunnels (line);
784     return GNUNET_OK;
785   case LS_CALLER_CALLING:
786     line->status = LS_CALLER_SHUTDOWN;
787     mq_done_finish_caller_shutdown (line);
788     break;
789   case LS_CALLER_CONNECTED:
790     line->status = LS_CALLER_SHUTDOWN;
791     mq_done_finish_caller_shutdown (line);
792     break;
793   case LS_CALLER_SHUTDOWN:
794     mq_done_finish_caller_shutdown (line);
795     return GNUNET_OK;
796   }
797   hup = (struct ClientPhoneHangupMessage *) buf;
798   hup->header.size = sizeof (buf);
799   hup->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
800   memcpy (&hup[1], reason, len);
801   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
802               "Sending HANG UP message to client with reason `%s'\n",
803               reason);
804   GNUNET_SERVER_notification_context_unicast (nc,
805                                               line->client,
806                                               &hup->header,
807                                               GNUNET_NO);
808   GNUNET_MESH_receive_done (tunnel);
809   return GNUNET_OK;
810 }
811
812
813 /**
814  * Function to handle a pickup message incoming over mesh
815  *
816  * @param cls closure, NULL
817  * @param tunnel the tunnel over which the message arrived
818  * @param tunnel_ctx the tunnel context, can be NULL
819  * @param message the incoming message
820  * @return #GNUNET_OK
821  */
822 static int
823 handle_mesh_pickup_message (void *cls,
824                             struct GNUNET_MESH_Tunnel *tunnel,
825                             void **tunnel_ctx,
826                             const struct GNUNET_MessageHeader *message)
827 {
828   const struct MeshPhonePickupMessage *msg;
829   struct Line *line = *tunnel_ctx;
830   const char *metadata;
831   size_t len = ntohs (message->size) - sizeof (struct MeshPhonePickupMessage);
832   char buf[len + sizeof (struct ClientPhonePickupMessage)];
833   struct ClientPhonePickupMessage *pick;
834
835   msg = (const struct MeshPhonePickupMessage *) message;
836   len = ntohs (msg->header.size) - sizeof (struct MeshPhonePickupMessage);
837   metadata = (const char *) &msg[1];
838   if ( (0 == len) ||
839        ('\0' != metadata[len - 1]) )
840   {
841     metadata = NULL;
842     len = 0;
843   }
844   if (NULL == line)
845   {
846     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
847                 "PICKUP message received for non-existing line, dropping tunnel.\n");
848     return GNUNET_SYSERR;
849   }
850   GNUNET_MESH_receive_done (tunnel);
851   switch (line->status)
852   {
853   case LS_CALLEE_LISTEN:
854     GNUNET_break (0);
855     return GNUNET_SYSERR;
856   case LS_CALLEE_RINGING:
857   case LS_CALLEE_CONNECTED:
858     GNUNET_break_op (0);
859     destroy_line_mesh_tunnels (line);
860     line->status = LS_CALLEE_LISTEN;
861     return GNUNET_SYSERR;
862   case LS_CALLEE_SHUTDOWN:
863     GNUNET_break_op (0);
864     line->status = LS_CALLEE_LISTEN;
865     destroy_line_mesh_tunnels (line);
866     break;
867   case LS_CALLER_CALLING:
868     line->status = LS_CALLER_CONNECTED;
869     break;
870   case LS_CALLER_CONNECTED:
871     GNUNET_break_op (0);
872     return GNUNET_OK;
873   case LS_CALLER_SHUTDOWN:
874     GNUNET_break_op (0);
875     mq_done_finish_caller_shutdown (line);
876     return GNUNET_SYSERR;
877   }
878   pick = (struct ClientPhonePickupMessage *) buf;
879   pick->header.size = sizeof (buf);
880   pick->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
881   memcpy (&pick[1], metadata, len);
882   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
883               "Sending PICKED UP message to client with metadata `%s'\n",
884               metadata);
885   GNUNET_SERVER_notification_context_unicast (nc,
886                                               line->client,
887                                               &pick->header,
888                                               GNUNET_NO);
889   line->tunnel_unreliable = GNUNET_MESH_tunnel_create (mesh,
890                                                        line,
891                                                        &line->target,
892                                                        GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
893                                                        GNUNET_YES,
894                                                        GNUNET_NO);
895   if (NULL == line->tunnel_unreliable)
896   {
897     GNUNET_break (0);
898   }
899   return GNUNET_OK;
900 }
901
902
903 /**
904  * Function to handle a busy message incoming over mesh
905  *
906  * @param cls closure, NULL
907  * @param tunnel the tunnel over which the message arrived
908  * @param tunnel_ctx the tunnel context, can be NULL
909  * @param message the incoming message
910  * @return #GNUNET_OK
911  */
912 static int
913 handle_mesh_busy_message (void *cls,
914                           struct GNUNET_MESH_Tunnel *tunnel,
915                           void **tunnel_ctx,
916                           const struct GNUNET_MessageHeader *message)
917 {
918   struct Line *line = *tunnel_ctx;
919   struct ClientPhoneBusyMessage busy;
920
921   if (NULL == line)
922   {
923     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924                 "HANGUP message received for non-existing line, dropping tunnel.\n");
925     return GNUNET_SYSERR;
926   }
927   busy.header.size = sizeof (busy);
928   busy.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY);
929   GNUNET_MESH_receive_done (tunnel);
930   *tunnel_ctx = NULL;
931   switch (line->status)
932   {
933   case LS_CALLEE_LISTEN:
934     GNUNET_break (0);
935     return GNUNET_SYSERR;
936   case LS_CALLEE_RINGING:
937     GNUNET_break_op (0);
938     break;
939   case LS_CALLEE_CONNECTED:
940     GNUNET_break_op (0);
941     break;
942   case LS_CALLEE_SHUTDOWN:
943     GNUNET_break_op (0);
944     break;
945   case LS_CALLER_CALLING:
946     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
947                 "Sending BUSY message to client\n");
948     GNUNET_SERVER_notification_context_unicast (nc,
949                                                 line->client,
950                                                 &busy.header,
951                                                 GNUNET_NO);
952     line->status = LS_CALLER_SHUTDOWN;
953     mq_done_finish_caller_shutdown (line);
954     break;
955   case LS_CALLER_CONNECTED:
956     GNUNET_break_op (0);
957     line->status = LS_CALLER_SHUTDOWN;
958     mq_done_finish_caller_shutdown (line);
959     break;
960   case LS_CALLER_SHUTDOWN:
961     GNUNET_break_op (0);
962     mq_done_finish_caller_shutdown (line);
963     break;
964   }
965   return GNUNET_OK;
966 }
967
968
969 /**
970  * Function to handle an audio message incoming over mesh
971  *
972  * @param cls closure, NULL
973  * @param tunnel the tunnel over which the message arrived
974  * @param tunnel_ctx the tunnel context, can be NULL
975  * @param message the incoming message
976  * @return #GNUNET_OK
977  */
978 static int
979 handle_mesh_audio_message (void *cls,
980                            struct GNUNET_MESH_Tunnel *tunnel,
981                            void **tunnel_ctx,
982                            const struct GNUNET_MessageHeader *message)
983 {
984   const struct MeshAudioMessage *msg;
985   struct Line *line = *tunnel_ctx;
986   struct GNUNET_PeerIdentity sender;
987   size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
988   char buf[msize + sizeof (struct ClientAudioMessage)];
989   struct ClientAudioMessage *cam;
990   const union GNUNET_MESH_TunnelInfo *info;
991
992   msg = (const struct MeshAudioMessage *) message;
993   if (NULL == line)
994   {
995     info = GNUNET_MESH_tunnel_get_info (tunnel,
996                                         GNUNET_MESH_OPTION_PEER);
997     if (NULL == info)
998     {
999       GNUNET_break (0);
1000       return GNUNET_OK;
1001     }
1002     sender = info->peer;
1003     for (line = lines_head; NULL != line; line = line->next)
1004       if ( (line->local_line == ntohl (msg->remote_line)) &&
1005            (LS_CALLEE_CONNECTED == line->status) &&
1006            (0 == memcmp (&line->target,
1007                          &sender,
1008                          sizeof (struct GNUNET_PeerIdentity))) &&
1009            (NULL == line->tunnel_unreliable) )
1010         break;
1011     if (NULL == line)
1012     {
1013       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1014                   "Received AUDIO data for non-existing line %u, dropping.\n",
1015                   ntohl (msg->remote_line));
1016       return GNUNET_SYSERR;
1017     }
1018     line->tunnel_unreliable = tunnel;
1019     *tunnel_ctx = line;
1020   }
1021   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1022               "Forwarding %u bytes of AUDIO data to client\n",
1023               msize);
1024   cam = (struct ClientAudioMessage *) buf;
1025   cam->header.size = htons (sizeof (buf));
1026   cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1027   memcpy (&cam[1], &msg[1], msize);
1028   GNUNET_SERVER_notification_context_unicast (nc,
1029                                               line->client,
1030                                               &cam->header,
1031                                               GNUNET_YES);
1032   GNUNET_MESH_receive_done (tunnel);
1033   return GNUNET_OK;
1034 }
1035
1036
1037 /**
1038  * Method called whenever another peer has added us to a tunnel
1039  * the other peer initiated.
1040  *
1041  * @param cls closure
1042  * @param tunnel new handle to the tunnel
1043  * @param initiator peer that started the tunnel
1044  * @param port port
1045  * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
1046  */
1047 static void *
1048 inbound_tunnel (void *cls,
1049                 struct GNUNET_MESH_Tunnel *tunnel,
1050                 const struct GNUNET_PeerIdentity *initiator,
1051                 uint32_t port)
1052 {
1053   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1054               _("Received incoming tunnel on port %u\n"),
1055               (unsigned int) port);
1056   return NULL;
1057 }
1058
1059
1060 /**
1061  * Function called whenever an inbound tunnel is destroyed.  Should clean up
1062  * any associated state.
1063  *
1064  * @param cls closure (set from #GNUNET_MESH_connect)
1065  * @param tunnel connection to the other end (henceforth invalid)
1066  * @param tunnel_ctx place where local state associated
1067  *                   with the tunnel is stored
1068  */
1069 static void
1070 inbound_end (void *cls,
1071              const struct GNUNET_MESH_Tunnel *tunnel,
1072              void *tunnel_ctx)
1073 {
1074   struct Line *line = tunnel_ctx;
1075   struct ClientPhoneHangupMessage hup;
1076
1077   if (NULL == line)
1078     return;
1079   if (line->tunnel_unreliable == tunnel)
1080   {
1081     if (NULL != line->unreliable_mth)
1082     {
1083       GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
1084       line->unreliable_mth = NULL;
1085     }
1086     line->tunnel_unreliable = NULL;
1087     return;
1088   }
1089   if (line->tunnel_reliable != tunnel)
1090     return;
1091   line->tunnel_reliable = NULL;
1092
1093   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094               "Mesh tunnel destroyed by mesh\n");
1095   hup.header.size = sizeof (hup);
1096   hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1097   switch (line->status)
1098   {
1099   case LS_CALLEE_LISTEN:
1100     GNUNET_break (0);
1101     break;
1102   case LS_CALLEE_RINGING:
1103   case LS_CALLEE_CONNECTED:
1104     GNUNET_SERVER_notification_context_unicast (nc,
1105                                                 line->client,
1106                                                 &hup.header,
1107                                                 GNUNET_NO);
1108     line->status = LS_CALLEE_LISTEN;
1109     break;
1110   case LS_CALLEE_SHUTDOWN:
1111     line->status = LS_CALLEE_LISTEN;
1112     break;
1113   case LS_CALLER_CALLING:
1114   case LS_CALLER_CONNECTED:
1115     GNUNET_SERVER_notification_context_unicast (nc,
1116                                                 line->client,
1117                                                 &hup.header,
1118                                                 GNUNET_NO);
1119     break;
1120   case LS_CALLER_SHUTDOWN:
1121     break;
1122   }
1123   destroy_line_mesh_tunnels (line);
1124 }
1125
1126
1127 /**
1128  * A client disconnected.  Remove all of its data structure entries.
1129  *
1130  * @param cls closure, NULL
1131  * @param client identification of the client
1132  */
1133 static void
1134 handle_client_disconnect (void *cls,
1135                           struct GNUNET_SERVER_Client *client)
1136 {
1137   struct Line *line;
1138
1139   if (NULL == client)
1140     return;
1141   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
1142   if (NULL == line)
1143     return;
1144   GNUNET_SERVER_client_set_user_context (client, (void *)NULL);
1145   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1146               "Client disconnected, closing line\n");
1147   GNUNET_CONTAINER_DLL_remove (lines_head,
1148                                lines_tail,
1149                                line);
1150   destroy_line_mesh_tunnels (line);
1151   GNUNET_free_non_null (line->audio_data);
1152   GNUNET_free (line);
1153 }
1154
1155
1156 /**
1157  * Shutdown nicely
1158  *
1159  * @param cls closure, NULL
1160  * @param tc the task context
1161  */
1162 static void
1163 do_shutdown (void *cls,
1164              const struct GNUNET_SCHEDULER_TaskContext *tc)
1165 {
1166   if (NULL != mesh)
1167   {
1168     GNUNET_MESH_disconnect (mesh);
1169     mesh = NULL;
1170   }
1171   if (NULL != nc)
1172   {
1173     GNUNET_SERVER_notification_context_destroy (nc);
1174     nc = NULL;
1175   }
1176 }
1177
1178
1179 /**
1180  * Main function that will be run by the scheduler.
1181  *
1182  * @param cls closure
1183  * @param server server handle
1184  * @param c configuration
1185  */
1186 static void
1187 run (void *cls,
1188      struct GNUNET_SERVER_Handle *server,
1189      const struct GNUNET_CONFIGURATION_Handle *c)
1190 {
1191   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1192     {&handle_client_register_message, NULL,
1193      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1194      sizeof (struct ClientPhoneRegisterMessage)},
1195     {&handle_client_pickup_message, NULL,
1196      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1197      0},
1198     {&handle_client_hangup_message, NULL,
1199      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1200      0},
1201     {&handle_client_call_message, NULL,
1202      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1203      0},
1204     {&handle_client_audio_message, NULL,
1205      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1206      0},
1207     {NULL, NULL, 0, 0}
1208   };
1209   static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1210     {&handle_mesh_ring_message,
1211      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
1212      sizeof (struct MeshPhoneRingMessage)},
1213     {&handle_mesh_hangup_message,
1214      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
1215      0},
1216     {&handle_mesh_pickup_message,
1217      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
1218      0},
1219     {&handle_mesh_busy_message,
1220      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY,
1221      sizeof (struct MeshPhoneBusyMessage)},
1222     {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
1223      0},
1224     {NULL, 0, 0}
1225   };
1226   static uint32_t ports[] = {
1227     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
1228     GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1229     0
1230   };
1231
1232   cfg = c;
1233   GNUNET_assert (GNUNET_OK ==
1234                  GNUNET_CRYPTO_get_peer_identity (cfg,
1235                                                   &my_identity));
1236   mesh = GNUNET_MESH_connect (cfg,
1237                               NULL,
1238                               &inbound_tunnel,
1239                               &inbound_end,
1240                               mesh_handlers,
1241                               ports);
1242
1243   if (NULL == mesh)
1244   {
1245     GNUNET_break (0);
1246     GNUNET_SCHEDULER_shutdown ();
1247     return;
1248   }
1249   nc = GNUNET_SERVER_notification_context_create (server, 16);
1250   GNUNET_SERVER_add_handlers (server, server_handlers);
1251   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1252   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1253                                 &do_shutdown,
1254                                 NULL);
1255 }
1256
1257
1258 /**
1259  * The main function for the conversation service.
1260  *
1261  * @param argc number of arguments from the command line
1262  * @param argv command line arguments
1263  * @return 0 ok, 1 on error
1264  */
1265 int
1266 main (int argc,
1267       char *const *argv)
1268 {
1269   return (GNUNET_OK ==
1270           GNUNET_SERVICE_run (argc, argv,
1271                               "conversation",
1272                               GNUNET_SERVICE_OPTION_NONE,
1273                               &run, NULL)) ? 0 : 1;
1274 }
1275
1276 /* end of gnunet-service-conversation.c */