-fix mesh tunnel destruction
[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     /* 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_EccPublicSignKey))) ||
684        (GNUNET_OK !=
685         GNUNET_CRYPTO_ecc_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 PICK UP message via mesh 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   return GNUNET_OK;
896 }
897
898
899 /**
900  * Function to handle a busy message incoming over mesh
901  *
902  * @param cls closure, NULL
903  * @param tunnel the tunnel over which the message arrived
904  * @param tunnel_ctx the tunnel context, can be NULL
905  * @param message the incoming message
906  * @return #GNUNET_OK
907  */
908 static int
909 handle_mesh_busy_message (void *cls,
910                           struct GNUNET_MESH_Tunnel *tunnel,
911                           void **tunnel_ctx,
912                           const struct GNUNET_MessageHeader *message)
913 {
914   struct Line *line = *tunnel_ctx;
915   struct ClientPhoneBusyMessage busy;
916
917   if (NULL == line)
918   {
919     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920                 "HANGUP message received for non-existing line, dropping tunnel.\n");
921     return GNUNET_SYSERR;
922   }
923   busy.header.size = sizeof (busy);
924   busy.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY);
925   GNUNET_MESH_receive_done (tunnel);
926   *tunnel_ctx = NULL;
927   switch (line->status)
928   {
929   case LS_CALLEE_LISTEN:
930     GNUNET_break (0);
931     return GNUNET_SYSERR;
932   case LS_CALLEE_RINGING:
933     GNUNET_break_op (0);
934     break;
935   case LS_CALLEE_CONNECTED:
936     GNUNET_break_op (0);
937     break;
938   case LS_CALLEE_SHUTDOWN:
939     GNUNET_break_op (0);
940     break;
941   case LS_CALLER_CALLING:
942     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
943                 "Sending BUSY message to client\n");
944     GNUNET_SERVER_notification_context_unicast (nc,
945                                                 line->client,
946                                                 &busy.header,
947                                                 GNUNET_NO);
948     line->status = LS_CALLER_SHUTDOWN;
949     mq_done_finish_caller_shutdown (line);
950     break;
951   case LS_CALLER_CONNECTED:
952     GNUNET_break_op (0);
953     line->status = LS_CALLER_SHUTDOWN;
954     mq_done_finish_caller_shutdown (line);
955     break;
956   case LS_CALLER_SHUTDOWN:
957     GNUNET_break_op (0);
958     mq_done_finish_caller_shutdown (line);
959     break;
960   }
961   return GNUNET_OK;
962 }
963
964
965 /**
966  * Function to handle an audio message incoming over mesh
967  *
968  * @param cls closure, NULL
969  * @param tunnel the tunnel over which the message arrived
970  * @param tunnel_ctx the tunnel context, can be NULL
971  * @param message the incoming message
972  * @return #GNUNET_OK
973  */
974 static int
975 handle_mesh_audio_message (void *cls,
976                            struct GNUNET_MESH_Tunnel *tunnel,
977                            void **tunnel_ctx,
978                            const struct GNUNET_MessageHeader *message)
979 {
980   const struct MeshAudioMessage *msg;
981   struct Line *line = *tunnel_ctx;
982   struct GNUNET_PeerIdentity sender;
983   size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
984   char buf[msize + sizeof (struct ClientAudioMessage)];
985   struct ClientAudioMessage *cam;
986   const union GNUNET_MESH_TunnelInfo *info;
987   
988   msg = (const struct MeshAudioMessage *) message;
989   if (NULL == line)
990   {
991     info = GNUNET_MESH_tunnel_get_info (tunnel,
992                                         GNUNET_MESH_OPTION_PEER);
993     if (NULL == info)
994     {
995       GNUNET_break (0);
996       return GNUNET_OK;
997     }
998     sender = info->peer;
999     for (line = lines_head; NULL != line; line = line->next)
1000       if ( (line->local_line == ntohl (msg->remote_line)) &&
1001            (LS_CALLEE_CONNECTED == line->status) &&
1002            (0 == memcmp (&line->target,
1003                          &sender,
1004                          sizeof (struct GNUNET_PeerIdentity))) &&
1005            (NULL == line->tunnel_unreliable) )
1006         break;
1007     if (NULL == line)
1008     {
1009       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1010                   "Received AUDIO data for non-existing line %u, dropping.\n",
1011                   ntohl (msg->remote_line));
1012       return GNUNET_SYSERR;
1013     }    
1014     line->tunnel_unreliable = tunnel;
1015     *tunnel_ctx = line;
1016   }
1017   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1018               "Forwarding %u bytes of AUDIO data to client\n",
1019               msize);
1020   cam = (struct ClientAudioMessage *) buf;
1021   cam->header.size = htons (sizeof (buf));
1022   cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1023   memcpy (&cam[1], &msg[1], msize);
1024   GNUNET_SERVER_notification_context_unicast (nc,
1025                                               line->client,
1026                                               &cam->header,
1027                                               GNUNET_YES);
1028   GNUNET_MESH_receive_done (tunnel);
1029   return GNUNET_OK;
1030 }
1031
1032
1033 /**
1034  * Method called whenever another peer has added us to a tunnel
1035  * the other peer initiated.
1036  *
1037  * @param cls closure
1038  * @param tunnel new handle to the tunnel
1039  * @param initiator peer that started the tunnel
1040  * @param port port
1041  * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
1042  */
1043 static void *
1044 inbound_tunnel (void *cls,
1045                 struct GNUNET_MESH_Tunnel *tunnel,
1046                 const struct GNUNET_PeerIdentity *initiator, 
1047                 uint32_t port)
1048 {
1049   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1050               _("Received incoming tunnel on port %u\n"), 
1051               (unsigned int) port);
1052   return NULL;
1053 }
1054
1055
1056 /**
1057  * Function called whenever an inbound tunnel is destroyed.  Should clean up
1058  * any associated state.
1059  *
1060  * @param cls closure (set from #GNUNET_MESH_connect)
1061  * @param tunnel connection to the other end (henceforth invalid)
1062  * @param tunnel_ctx place where local state associated
1063  *                   with the tunnel is stored
1064  */
1065 static void
1066 inbound_end (void *cls,
1067              const struct GNUNET_MESH_Tunnel *tunnel,
1068              void *tunnel_ctx)
1069 {
1070   struct Line *line = tunnel_ctx;
1071   struct ClientPhoneHangupMessage hup;
1072
1073   if (NULL == line)
1074     return;
1075   if (line->tunnel_unreliable == tunnel)
1076   {
1077     if (NULL != line->unreliable_mth)
1078     {
1079       GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
1080       line->unreliable_mth = NULL;
1081     }
1082     line->tunnel_unreliable = NULL;
1083     return;
1084   }
1085   if (line->tunnel_reliable != tunnel)
1086     return;
1087   line->tunnel_reliable = NULL;
1088
1089   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1090               "Mesh tunnel destroyed by mesh\n");
1091   hup.header.size = sizeof (hup);
1092   hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1093   switch (line->status)
1094   {
1095   case LS_CALLEE_LISTEN:
1096     GNUNET_break (0);
1097     break;
1098   case LS_CALLEE_RINGING:
1099   case LS_CALLEE_CONNECTED:
1100     GNUNET_SERVER_notification_context_unicast (nc,
1101                                                 line->client,
1102                                                 &hup.header,
1103                                                 GNUNET_NO);
1104     line->status = LS_CALLEE_LISTEN;
1105     break;
1106   case LS_CALLEE_SHUTDOWN:
1107     line->status = LS_CALLEE_LISTEN;
1108     break;
1109   case LS_CALLER_CALLING:
1110   case LS_CALLER_CONNECTED:
1111     GNUNET_SERVER_notification_context_unicast (nc,
1112                                                 line->client,
1113                                                 &hup.header,
1114                                                 GNUNET_NO);
1115     break;
1116   case LS_CALLER_SHUTDOWN:
1117     break;
1118   }
1119   destroy_line_mesh_tunnels (line);
1120 }
1121
1122
1123 /**
1124  * A client disconnected.  Remove all of its data structure entries.
1125  *
1126  * @param cls closure, NULL
1127  * @param client identification of the client
1128  */
1129 static void
1130 handle_client_disconnect (void *cls, 
1131                           struct GNUNET_SERVER_Client *client)
1132 {
1133   struct Line *line;
1134
1135   if (NULL == client)
1136     return;
1137   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
1138   if (NULL == line)
1139     return;
1140   GNUNET_SERVER_client_set_user_context (client, NULL);
1141   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1142               "Client disconnected, closing line\n");
1143   GNUNET_CONTAINER_DLL_remove (lines_head,
1144                                lines_tail,
1145                                line);
1146   destroy_line_mesh_tunnels (line);
1147   GNUNET_free_non_null (line->audio_data);
1148   GNUNET_free (line);
1149 }
1150
1151
1152 /**
1153  * Shutdown nicely
1154  * 
1155  * @param cls closure, NULL
1156  * @param tc the task context
1157  */
1158 static void
1159 do_shutdown (void *cls,
1160              const struct GNUNET_SCHEDULER_TaskContext *tc)
1161 {
1162   if (NULL != mesh)
1163   {
1164     GNUNET_MESH_disconnect (mesh);
1165     mesh = NULL;
1166   }
1167   if (NULL != nc)
1168   {
1169     GNUNET_SERVER_notification_context_destroy (nc);
1170     nc = NULL;
1171   }
1172 }
1173
1174
1175 /**
1176  * Main function that will be run by the scheduler.
1177  *
1178  * @param cls closure
1179  * @param server server handle
1180  * @param c configuration
1181  */
1182 static void
1183 run (void *cls, 
1184      struct GNUNET_SERVER_Handle *server,
1185      const struct GNUNET_CONFIGURATION_Handle *c)
1186 {
1187   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1188     {&handle_client_register_message, NULL,
1189      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1190      sizeof (struct ClientPhoneRegisterMessage)},
1191     {&handle_client_pickup_message, NULL,
1192      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1193      0},
1194     {&handle_client_hangup_message, NULL,
1195      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1196      0},
1197     {&handle_client_call_message, NULL,
1198      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1199      0},
1200     {&handle_client_audio_message, NULL,
1201      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1202      0},
1203     {NULL, NULL, 0, 0}
1204   };
1205   static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1206     {&handle_mesh_ring_message,
1207      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
1208      sizeof (struct MeshPhoneRingMessage)},
1209     {&handle_mesh_hangup_message, 
1210      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
1211      0},
1212     {&handle_mesh_pickup_message, 
1213      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
1214      0},
1215     {&handle_mesh_busy_message, 
1216      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY,
1217      sizeof (struct MeshPhoneBusyMessage)},
1218     {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
1219      0},
1220     {NULL, 0, 0}
1221   };
1222   static uint32_t ports[] = { 
1223     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
1224     GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1225     0 
1226   };
1227
1228   cfg = c;
1229   GNUNET_assert (GNUNET_OK ==
1230                  GNUNET_CRYPTO_get_host_identity (cfg,
1231                                                   &my_identity));
1232   mesh = GNUNET_MESH_connect (cfg,
1233                               NULL,
1234                               &inbound_tunnel,
1235                               &inbound_end, 
1236                               mesh_handlers, 
1237                               ports);
1238
1239   if (NULL == mesh)
1240   {
1241     GNUNET_break (0);
1242     GNUNET_SCHEDULER_shutdown ();
1243     return;
1244   }
1245   nc = GNUNET_SERVER_notification_context_create (server, 16);
1246   GNUNET_SERVER_add_handlers (server, server_handlers);
1247   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1248   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, 
1249                                 &do_shutdown,
1250                                 NULL);
1251 }
1252
1253
1254 /**
1255  * The main function for the conversation service.
1256  *
1257  * @param argc number of arguments from the command line
1258  * @param argv command line arguments
1259  * @return 0 ok, 1 on error
1260  */
1261 int
1262 main (int argc, 
1263       char *const *argv)
1264 {
1265   return (GNUNET_OK ==
1266           GNUNET_SERVICE_run (argc, argv,
1267                               "conversation", 
1268                               GNUNET_SERVICE_OPTION_NONE,
1269                               &run, NULL)) ? 0 : 1;
1270 }
1271
1272 /* end of gnunet-service-conversation.c */