-disable phone on reconnect
[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 client 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_EccPublicSignKey));
507   GNUNET_CRYPTO_ecc_key_get_public_for_signature (&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_ecc_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 @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   case LS_CALLEE_RINGING:
589   case LS_CALLER_CALLING:
590     GNUNET_break (0);
591     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
592     return;
593   case LS_CALLEE_CONNECTED:
594   case LS_CALLER_CONNECTED:
595     /* common case, handled below */
596     break;
597   case LS_CALLEE_SHUTDOWN:
598   case LS_CALLER_SHUTDOWN:
599     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
600                 "Mesh audio channel in shutdown; audio data dropped\n");
601     GNUNET_SERVER_receive_done (client, GNUNET_OK);
602     return;
603   }
604   if (NULL == line->tunnel_unreliable)
605   {
606     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
607                 _("Mesh audio channel not ready; audio data dropped\n"));
608     GNUNET_SERVER_receive_done (client, GNUNET_OK);    
609     return;
610   }
611   if (NULL != line->unreliable_mth)
612   {
613     /* NOTE: we may want to not do this and instead combine the data */
614     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
615                 "Dropping previous audio data segment with %u bytes\n",
616                 line->audio_size);
617     GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
618     GNUNET_free (line->audio_data);
619   }
620   line->audio_size = size;
621   line->audio_data = GNUNET_malloc (line->audio_size);
622   memcpy (line->audio_data,
623           &msg[1],
624           size);
625   line->unreliable_mth = GNUNET_MESH_notify_transmit_ready (line->tunnel_unreliable,
626                                                             GNUNET_NO,
627                                                             GNUNET_TIME_UNIT_FOREVER_REL,
628                                                             sizeof (struct MeshAudioMessage) 
629                                                             + line->audio_size,
630                                                             &transmit_line_audio,
631                                                             line);
632   GNUNET_SERVER_receive_done (client, GNUNET_OK);
633 }
634
635
636 /**
637  * We are done signalling shutdown to the other peer.  
638  * Destroy the tunnel.
639  *
640  * @param cls the `struct GNUNET_MESH_tunnel` to destroy
641  */
642 static void
643 mq_done_destroy_tunnel (void *cls)
644 {
645   struct GNUNET_MESH_Tunnel *tunnel = cls;
646   
647   GNUNET_MESH_tunnel_destroy (tunnel);
648 }
649
650
651 /**
652  * Function to handle a ring message incoming over mesh
653  *
654  * @param cls closure, NULL
655  * @param tunnel the tunnel over which the message arrived
656  * @param tunnel_ctx the tunnel context, can be NULL
657  * @param message the incoming message
658  * @return #GNUNET_OK
659  */
660 static int
661 handle_mesh_ring_message (void *cls,
662                           struct GNUNET_MESH_Tunnel *tunnel,
663                           void **tunnel_ctx,
664                           const struct GNUNET_MessageHeader *message)
665 {
666   const struct MeshPhoneRingMessage *msg;
667   struct Line *line;
668   struct GNUNET_MQ_Envelope *e;
669   struct MeshPhoneBusyMessage *busy;
670   struct ClientPhoneRingMessage cring;
671   
672   msg = (const struct MeshPhoneRingMessage *) message;
673   if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
674                                     sizeof (struct GNUNET_TIME_AbsoluteNBO) +
675                                     sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
676                                     sizeof (struct GNUNET_CRYPTO_EccPublicSignKey))) ||
677        (GNUNET_OK !=
678         GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
679                                   &msg->purpose,
680                                   &msg->signature,
681                                   &msg->caller_id)) )
682   {
683     GNUNET_break_op (0);
684     return GNUNET_SYSERR;
685   }
686   for (line = lines_head; NULL != line; line = line->next)  
687     if ( (line->local_line == ntohl (msg->remote_line)) &&
688          (LS_CALLEE_LISTEN == line->status) )
689       break;
690   if (NULL == line) 
691   {
692     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
693                 _("No available phone for incoming call on line %u, sending BUSY signal\n"),
694                 ntohl (msg->remote_line));
695     e = GNUNET_MQ_msg (busy, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY);
696     GNUNET_MQ_notify_sent (e,
697                            &mq_done_destroy_tunnel,
698                            tunnel);
699     GNUNET_MQ_send (line->reliable_mq, e);
700     GNUNET_MESH_receive_done (tunnel); /* needed? */
701     return GNUNET_OK;
702   }
703   line->status = LS_CALLEE_RINGING;
704   line->remote_line = ntohl (msg->source_line);
705   line->tunnel_reliable = tunnel;
706   line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
707   *tunnel_ctx = line;
708   cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
709   cring.header.size = htons (sizeof (cring));
710   cring.reserved = htonl (0);
711   cring.caller_id = msg->caller_id;
712   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
713               "Sending RING message to client\n");
714   GNUNET_SERVER_notification_context_unicast (nc,
715                                               line->client,
716                                               &cring.header,
717                                               GNUNET_NO);
718   GNUNET_MESH_receive_done (tunnel);
719   return GNUNET_OK;
720 }
721
722
723 /**
724  * Function to handle a hangup message incoming over mesh
725  *
726  * @param cls closure, NULL
727  * @param tunnel the tunnel over which the message arrived
728  * @param tunnel_ctx the tunnel context, can be NULL
729  * @param message the incoming message
730  * @return #GNUNET_OK
731  */
732 static int
733 handle_mesh_hangup_message (void *cls,
734                             struct GNUNET_MESH_Tunnel *tunnel,
735                             void **tunnel_ctx,
736                             const struct GNUNET_MessageHeader *message)
737 {
738   struct Line *line = *tunnel_ctx;
739   const struct MeshPhoneHangupMessage *msg;
740   const char *reason;
741   size_t len = ntohs (message->size) - sizeof (struct MeshPhoneHangupMessage);
742   char buf[len + sizeof (struct ClientPhoneHangupMessage)];
743   struct ClientPhoneHangupMessage *hup;
744   
745   msg = (const struct MeshPhoneHangupMessage *) message;
746   len = ntohs (msg->header.size) - sizeof (struct MeshPhoneHangupMessage);
747   reason = (const char *) &msg[1];
748   if ( (0 == len) ||
749        ('\0' != reason[len - 1]) )
750   {
751     reason = NULL;
752     len = 0;
753   }
754   if (NULL == line)
755   {
756     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
757                 "HANGUP message received for non-existing line, dropping tunnel.\n");
758     return GNUNET_SYSERR;
759   }
760   *tunnel_ctx = NULL;
761   switch (line->status)
762   {
763   case LS_CALLEE_LISTEN:
764     GNUNET_break (0);
765     return GNUNET_SYSERR;
766   case LS_CALLEE_RINGING:
767     line->status = LS_CALLEE_LISTEN;
768     destroy_line_mesh_tunnels (line);
769     break;
770   case LS_CALLEE_CONNECTED:
771     line->status = LS_CALLEE_LISTEN;
772     destroy_line_mesh_tunnels (line);
773     break;
774   case LS_CALLEE_SHUTDOWN:
775     line->status = LS_CALLEE_LISTEN;
776     destroy_line_mesh_tunnels (line);
777     return GNUNET_OK;
778   case LS_CALLER_CALLING:
779     line->status = LS_CALLER_SHUTDOWN;
780     mq_done_finish_caller_shutdown (line);
781     break;
782   case LS_CALLER_CONNECTED:
783     line->status = LS_CALLER_SHUTDOWN;
784     mq_done_finish_caller_shutdown (line);
785     break;
786   case LS_CALLER_SHUTDOWN:
787     mq_done_finish_caller_shutdown (line);
788     return GNUNET_OK;
789   }
790   hup = (struct ClientPhoneHangupMessage *) buf;
791   hup->header.size = sizeof (buf);
792   hup->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
793   memcpy (&hup[1], reason, len);
794   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
795               "Sending HANG UP message to client with reason `%s'\n",
796               reason);
797   GNUNET_SERVER_notification_context_unicast (nc,
798                                               line->client,
799                                               &hup->header,
800                                               GNUNET_NO);
801   GNUNET_MESH_receive_done (tunnel);
802   return GNUNET_OK;
803 }
804
805
806 /**
807  * Function to handle a pickup message incoming over mesh
808  *
809  * @param cls closure, NULL
810  * @param tunnel the tunnel over which the message arrived
811  * @param tunnel_ctx the tunnel context, can be NULL
812  * @param message the incoming message
813  * @return #GNUNET_OK
814  */
815 static int
816 handle_mesh_pickup_message (void *cls,
817                             struct GNUNET_MESH_Tunnel *tunnel,
818                             void **tunnel_ctx,
819                             const struct GNUNET_MessageHeader *message)
820 {
821   const struct MeshPhonePickupMessage *msg;
822   struct Line *line = *tunnel_ctx;
823   const char *metadata;
824   size_t len = ntohs (message->size) - sizeof (struct MeshPhonePickupMessage);
825   char buf[len + sizeof (struct ClientPhonePickupMessage)];
826   struct ClientPhonePickupMessage *pick;
827   
828   msg = (const struct MeshPhonePickupMessage *) message;
829   len = ntohs (msg->header.size) - sizeof (struct MeshPhonePickupMessage);
830   metadata = (const char *) &msg[1];
831   if ( (0 == len) ||
832        ('\0' != metadata[len - 1]) )
833   {
834     metadata = NULL;
835     len = 0;
836   }
837   if (NULL == line)
838   {
839     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
840                 "PICKUP message received for non-existing line, dropping tunnel.\n");
841     return GNUNET_SYSERR;
842   }
843   GNUNET_MESH_receive_done (tunnel);
844   switch (line->status)
845   {
846   case LS_CALLEE_LISTEN:
847     GNUNET_break (0);
848     return GNUNET_SYSERR;
849   case LS_CALLEE_RINGING:
850   case LS_CALLEE_CONNECTED:
851     GNUNET_break_op (0);
852     destroy_line_mesh_tunnels (line);
853     line->status = LS_CALLEE_LISTEN;
854     return GNUNET_SYSERR;
855   case LS_CALLEE_SHUTDOWN:
856     GNUNET_break_op (0);
857     line->status = LS_CALLEE_LISTEN;
858     destroy_line_mesh_tunnels (line);
859     break;
860   case LS_CALLER_CALLING:
861     line->status = LS_CALLER_CONNECTED;
862     break;
863   case LS_CALLER_CONNECTED:
864     GNUNET_break_op (0);
865     return GNUNET_OK;
866   case LS_CALLER_SHUTDOWN:
867     GNUNET_break_op (0);
868     mq_done_finish_caller_shutdown (line);
869     return GNUNET_SYSERR;
870   }
871   pick = (struct ClientPhonePickupMessage *) buf;
872   pick->header.size = sizeof (buf);
873   pick->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
874   memcpy (&pick[1], metadata, len);
875   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
876               "Sending PICK UP message via mesh with metadata `%s'\n",
877               metadata);
878   GNUNET_SERVER_notification_context_unicast (nc,
879                                               line->client,
880                                               &pick->header,
881                                               GNUNET_NO);
882   line->tunnel_unreliable = GNUNET_MESH_tunnel_create (mesh,
883                                                        line,
884                                                        &line->target,
885                                                        GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
886                                                        GNUNET_YES,
887                                                        GNUNET_NO);
888   return GNUNET_OK;
889 }
890
891
892 /**
893  * Function to handle a busy message incoming over mesh
894  *
895  * @param cls closure, NULL
896  * @param tunnel the tunnel over which the message arrived
897  * @param tunnel_ctx the tunnel context, can be NULL
898  * @param message the incoming message
899  * @return #GNUNET_OK
900  */
901 static int
902 handle_mesh_busy_message (void *cls,
903                           struct GNUNET_MESH_Tunnel *tunnel,
904                           void **tunnel_ctx,
905                           const struct GNUNET_MessageHeader *message)
906 {
907   struct Line *line = *tunnel_ctx;
908   struct ClientPhoneBusyMessage busy;
909
910   if (NULL == line)
911   {
912     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
913                 "HANGUP message received for non-existing line, dropping tunnel.\n");
914     return GNUNET_SYSERR;
915   }
916   busy.header.size = sizeof (busy);
917   busy.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY);
918   GNUNET_MESH_receive_done (tunnel);
919   *tunnel_ctx = NULL;
920   switch (line->status)
921   {
922   case LS_CALLEE_LISTEN:
923     GNUNET_break (0);
924     return GNUNET_SYSERR;
925   case LS_CALLEE_RINGING:
926     GNUNET_break_op (0);
927     break;
928   case LS_CALLEE_CONNECTED:
929     GNUNET_break_op (0);
930     break;
931   case LS_CALLEE_SHUTDOWN:
932     GNUNET_break_op (0);
933     break;
934   case LS_CALLER_CALLING:
935     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
936                 "Sending BUSY message to client\n");
937     GNUNET_SERVER_notification_context_unicast (nc,
938                                                 line->client,
939                                                 &busy.header,
940                                                 GNUNET_NO);
941     line->status = LS_CALLER_SHUTDOWN;
942     mq_done_finish_caller_shutdown (line);
943     break;
944   case LS_CALLER_CONNECTED:
945     GNUNET_break_op (0);
946     line->status = LS_CALLER_SHUTDOWN;
947     mq_done_finish_caller_shutdown (line);
948     break;
949   case LS_CALLER_SHUTDOWN:
950     GNUNET_break_op (0);
951     mq_done_finish_caller_shutdown (line);
952     break;
953   }
954   return GNUNET_OK;
955 }
956
957
958 /**
959  * Function to handle an audio message incoming over mesh
960  *
961  * @param cls closure, NULL
962  * @param tunnel the tunnel over which the message arrived
963  * @param tunnel_ctx the tunnel context, can be NULL
964  * @param message the incoming message
965  * @return #GNUNET_OK
966  */
967 static int
968 handle_mesh_audio_message (void *cls,
969                            struct GNUNET_MESH_Tunnel *tunnel,
970                            void **tunnel_ctx,
971                            const struct GNUNET_MessageHeader *message)
972 {
973   const struct MeshAudioMessage *msg;
974   struct Line *line = *tunnel_ctx;
975   struct GNUNET_PeerIdentity sender;
976   size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
977   char buf[msize + sizeof (struct ClientAudioMessage)];
978   struct ClientAudioMessage *cam;
979   const union GNUNET_MESH_TunnelInfo *info;
980   
981   msg = (const struct MeshAudioMessage *) message;
982   if (NULL == line)
983   {
984     info = GNUNET_MESH_tunnel_get_info (tunnel,
985                                         GNUNET_MESH_OPTION_PEER);
986     if (NULL == info)
987     {
988       GNUNET_break (0);
989       return GNUNET_OK;
990     }
991     sender = info->peer;
992     for (line = lines_head; NULL != line; line = line->next)
993       if ( (line->local_line == ntohl (msg->remote_line)) &&
994            (LS_CALLEE_CONNECTED == line->status) &&
995            (0 == memcmp (&line->target,
996                          &sender,
997                          sizeof (struct GNUNET_PeerIdentity))) &&
998            (NULL == line->tunnel_unreliable) )
999         break;
1000     if (NULL == line)
1001     {
1002       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1003                   "Received AUDIO data for non-existing line %u, dropping.\n",
1004                   ntohl (msg->remote_line));
1005       return GNUNET_SYSERR;
1006     }    
1007     line->tunnel_unreliable = tunnel;
1008     *tunnel_ctx = line;
1009   }
1010   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1011               "Forwarding %u bytes of AUDIO data to client\n",
1012               msize);
1013   cam = (struct ClientAudioMessage *) buf;
1014   cam->header.size = htons (sizeof (buf));
1015   cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1016   memcpy (&cam[1], &msg[1], msize);
1017   GNUNET_SERVER_notification_context_unicast (nc,
1018                                               line->client,
1019                                               &cam->header,
1020                                               GNUNET_YES);
1021   GNUNET_MESH_receive_done (tunnel);
1022   return GNUNET_OK;
1023 }
1024
1025
1026 /**
1027  * Method called whenever another peer has added us to a tunnel
1028  * the other peer initiated.
1029  *
1030  * @param cls closure
1031  * @param tunnel new handle to the tunnel
1032  * @param initiator peer that started the tunnel
1033  * @param port port
1034  * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
1035  */
1036 static void *
1037 inbound_tunnel (void *cls,
1038                 struct GNUNET_MESH_Tunnel *tunnel,
1039                 const struct GNUNET_PeerIdentity *initiator, 
1040                 uint32_t port)
1041 {
1042   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1043               _("Received incoming tunnel on port %u\n"), 
1044               (unsigned int) port);
1045   return NULL;
1046 }
1047
1048
1049 /**
1050  * Function called whenever an inbound tunnel is destroyed.  Should clean up
1051  * any associated state.
1052  *
1053  * @param cls closure (set from #GNUNET_MESH_connect)
1054  * @param tunnel connection to the other end (henceforth invalid)
1055  * @param tunnel_ctx place where local state associated
1056  *                   with the tunnel is stored
1057  */
1058 static void
1059 inbound_end (void *cls,
1060              const struct GNUNET_MESH_Tunnel *tunnel,
1061              void *tunnel_ctx)
1062 {
1063   struct Line *line = tunnel_ctx;
1064   struct ClientPhoneHangupMessage hup;
1065
1066   if (NULL == line)
1067     return;
1068   if (line->tunnel_unreliable == tunnel)
1069   {
1070     line->tunnel_unreliable = NULL;
1071     return;
1072   }
1073   if (line->tunnel_reliable != tunnel)
1074     return;
1075   line->tunnel_reliable = NULL;
1076   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077               "Mesh tunnel destroyed by mesh\n");
1078   hup.header.size = sizeof (hup);
1079   hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1080   switch (line->status)
1081   {
1082   case LS_CALLEE_LISTEN:
1083     GNUNET_break (0);
1084     return;
1085   case LS_CALLEE_RINGING:
1086   case LS_CALLEE_CONNECTED:
1087     GNUNET_SERVER_notification_context_unicast (nc,
1088                                                 line->client,
1089                                                 &hup.header,
1090                                                 GNUNET_NO);
1091     line->status = LS_CALLEE_LISTEN;
1092     break;
1093   case LS_CALLEE_SHUTDOWN:
1094     line->status = LS_CALLEE_LISTEN;
1095     destroy_line_mesh_tunnels (line);
1096     break;
1097   case LS_CALLER_CALLING:
1098   case LS_CALLER_CONNECTED:
1099     GNUNET_SERVER_notification_context_unicast (nc,
1100                                                 line->client,
1101                                                 &hup.header,
1102                                                 GNUNET_NO);
1103     destroy_line_mesh_tunnels (line);
1104     break;
1105   case LS_CALLER_SHUTDOWN:
1106     destroy_line_mesh_tunnels (line);
1107     break;
1108   }
1109 }
1110
1111
1112 /**
1113  * A client disconnected.  Remove all of its data structure entries.
1114  *
1115  * @param cls closure, NULL
1116  * @param client identification of the client
1117  */
1118 static void
1119 handle_client_disconnect (void *cls, 
1120                           struct GNUNET_SERVER_Client *client)
1121 {
1122   struct Line *line;
1123
1124   if (NULL == client)
1125     return;
1126   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
1127   if (NULL == line)
1128     return;
1129   GNUNET_SERVER_client_set_user_context (client, NULL);
1130   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131               "Client disconnected, closing line\n");
1132   GNUNET_CONTAINER_DLL_remove (lines_head,
1133                                lines_tail,
1134                                line);
1135   destroy_line_mesh_tunnels (line);
1136   GNUNET_free_non_null (line->audio_data);
1137   GNUNET_free (line);
1138 }
1139
1140
1141 /**
1142  * Shutdown nicely
1143  * 
1144  * @param cls closure, NULL
1145  * @param tc the task context
1146  */
1147 static void
1148 do_shutdown (void *cls,
1149              const struct GNUNET_SCHEDULER_TaskContext *tc)
1150 {
1151   if (NULL != mesh)
1152   {
1153     GNUNET_MESH_disconnect (mesh);
1154     mesh = NULL;
1155   }
1156   if (NULL != nc)
1157   {
1158     GNUNET_SERVER_notification_context_destroy (nc);
1159     nc = NULL;
1160   }
1161 }
1162
1163
1164 /**
1165  * Main function that will be run by the scheduler.
1166  *
1167  * @param cls closure
1168  * @param server server handle
1169  * @param c configuration
1170  */
1171 static void
1172 run (void *cls, 
1173      struct GNUNET_SERVER_Handle *server,
1174      const struct GNUNET_CONFIGURATION_Handle *c)
1175 {
1176   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1177     {&handle_client_register_message, NULL,
1178      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1179      sizeof (struct ClientPhoneRegisterMessage)},
1180     {&handle_client_pickup_message, NULL,
1181      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1182      0},
1183     {&handle_client_hangup_message, NULL,
1184      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1185      0},
1186     {&handle_client_call_message, NULL,
1187      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1188      0},
1189     {&handle_client_audio_message, NULL,
1190      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1191      0},
1192     {NULL, NULL, 0, 0}
1193   };
1194   static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1195     {&handle_mesh_ring_message,
1196      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
1197      sizeof (struct MeshPhoneRingMessage)},
1198     {&handle_mesh_hangup_message, 
1199      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
1200      0},
1201     {&handle_mesh_pickup_message, 
1202      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
1203      0},
1204     {&handle_mesh_busy_message, 
1205      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY,
1206      sizeof (struct MeshPhoneBusyMessage)},
1207     {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
1208      0},
1209     {NULL, 0, 0}
1210   };
1211   static uint32_t ports[] = { 
1212     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
1213     GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1214     0 
1215   };
1216
1217   cfg = c;
1218   GNUNET_assert (GNUNET_OK ==
1219                  GNUNET_CRYPTO_get_host_identity (cfg,
1220                                                   &my_identity));
1221   mesh = GNUNET_MESH_connect (cfg,
1222                               NULL,
1223                               &inbound_tunnel,
1224                               &inbound_end, 
1225                               mesh_handlers, 
1226                               ports);
1227
1228   if (NULL == mesh)
1229   {
1230     GNUNET_break (0);
1231     GNUNET_SCHEDULER_shutdown ();
1232     return;
1233   }
1234   nc = GNUNET_SERVER_notification_context_create (server, 16);
1235   GNUNET_SERVER_add_handlers (server, server_handlers);
1236   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1237   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, 
1238                                 &do_shutdown,
1239                                 NULL);
1240 }
1241
1242
1243 /**
1244  * The main function for the conversation service.
1245  *
1246  * @param argc number of arguments from the command line
1247  * @param argv command line arguments
1248  * @return 0 ok, 1 on error
1249  */
1250 int
1251 main (int argc, 
1252       char *const *argv)
1253 {
1254   return (GNUNET_OK ==
1255           GNUNET_SERVICE_run (argc, argv,
1256                               "conversation", 
1257                               GNUNET_SERVICE_OPTION_NONE,
1258                               &run, NULL)) ? 0 : 1;
1259 }
1260
1261 /* end of gnunet-service-conversation.c */