- extend mesh audio messag to contain source line number. This is needed to find...
[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  * A line connects a local client with a mesh channel (or, if it is an
48  * open line, is waiting for a mesh channel).
49  */
50 struct Line;
51
52 /**
53  * The possible connection status
54  */
55 enum ChannelStatus
56 {
57   /**
58    * Our phone is ringing, waiting for the client to pick up.
59    */
60   CS_CALLEE_RINGING,
61
62   /**
63    * We are talking!
64    */
65   CS_CALLEE_CONNECTED,
66
67   /**
68    * We're in shutdown, sending hangup messages before cleaning up.
69    */
70   CS_CALLEE_SHUTDOWN,
71
72   /**
73    * We are waiting for the phone to be picked up.
74    */
75   CS_CALLER_CALLING,
76
77   /**
78    * We are talking!
79    */
80   CS_CALLER_CONNECTED,
81
82   /**
83    * We're in shutdown, sending hangup messages before cleaning up.
84    */
85   CS_CALLER_SHUTDOWN
86
87 };
88
89
90 /**
91  * A `struct Channel` represents a mesh channel, which is a P2P
92  * connection to another conversation service.  Multiple channels can
93  * be attached the the same `struct Line`, which represents a local
94  * client.  We keep them in a linked list.
95  */
96 struct Channel
97 {
98
99   /**
100    * This is a DLL.
101    */
102   struct Channel *next;
103
104   /**
105    * This is a DLL.
106    */
107   struct Channel *prev;
108
109   /**
110    * Line associated with the channel.
111    */
112   struct Line *line;
113
114   /**
115    * Handle for the reliable channel (contol data)
116    */
117   struct GNUNET_MESH_Channel *channel_reliable;
118
119   /**
120    * Handle for unreliable channel (audio data)
121    */
122   struct GNUNET_MESH_Channel *channel_unreliable;
123
124   /**
125    * Transmit handle for pending audio messages
126    */
127   struct GNUNET_MESH_TransmitHandle *unreliable_mth;
128
129   /**
130    * Message queue for control messages
131    */
132   struct GNUNET_MQ_Handle *reliable_mq;
133
134   /**
135    * Target of the line, if we are the caller.
136    */
137   struct GNUNET_PeerIdentity target;
138
139   /**
140    * Temporary buffer for audio data.
141    */
142   void *audio_data;
143
144   /**
145    * Number of bytes in @e audio_data.
146    */
147   size_t audio_size;
148
149   /**
150    * Channel identifier.
151    */
152   uint32_t cid;
153
154   /**
155    * Remote line number.
156    */
157   uint32_t remote_line;
158
159   /**
160    * Current status of this line.
161    */
162   enum ChannelStatus status;
163
164   /**
165    * #GNUNET_YES if the channel was suspended by the other peer.
166    */
167   int8_t suspended_remote;
168
169   /**
170    * #GNUNET_YES if the channel was suspended by the local client.
171    */
172   int8_t suspended_local;
173
174 };
175
176
177 /**
178  * A `struct Line` connects a local client with mesh channels.
179  */
180 struct Line
181 {
182   /**
183    * Kept in a DLL.
184    */
185   struct Line *next;
186
187   /**
188    * Kept in a DLL.
189    */
190   struct Line *prev;
191
192   /**
193    * This is a DLL.
194    */
195   struct Channel *channel_head;
196
197   /**
198    * This is a DLL.
199    */
200   struct Channel *channel_tail;
201
202   /**
203    * Handle to the line client.
204    */
205   struct GNUNET_SERVER_Client *client;
206
207   /**
208    * Generator for channel IDs.
209    */
210   uint32_t cid_gen;
211
212   /**
213    * Our line number.
214    */
215   uint32_t local_line;
216
217 };
218
219
220 /**
221  * Our configuration.
222  */
223 static const struct GNUNET_CONFIGURATION_Handle *cfg;
224
225 /**
226  * Notification context containing all connected clients.
227  */
228 static struct GNUNET_SERVER_NotificationContext *nc;
229
230 /**
231  * Handle for mesh
232  */
233 static struct GNUNET_MESH_Handle *mesh;
234
235 /**
236  * Identity of this peer.
237  */
238 static struct GNUNET_PeerIdentity my_identity;
239
240 /**
241  * Head of DLL of active lines.
242  */
243 static struct Line *lines_head;
244
245 /**
246  * Tail of DLL of active lines.
247  */
248 static struct Line *lines_tail;
249
250 /**
251  * Counter for generating local line numbers.
252  * FIXME: randomize generation in the future
253  * to eliminate information leakage.
254  */
255 static uint32_t local_line_cnt;
256
257
258 /**
259  * Function to register a phone.
260  *
261  * @param cls closure, NULL
262  * @param client the client from which the message is
263  * @param message the message from the client
264  */
265 static void
266 handle_client_register_message (void *cls,
267                                 struct GNUNET_SERVER_Client *client,
268                                 const struct GNUNET_MessageHeader *message)
269 {
270   const struct ClientPhoneRegisterMessage *msg;
271   struct Line *line;
272
273   msg = (const struct ClientPhoneRegisterMessage *) message;
274   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
275   if (NULL != line)
276   {
277     GNUNET_break (0);
278     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
279     return;
280   }
281   line = GNUNET_new (struct Line);
282   line->client = client;
283   GNUNET_SERVER_notification_context_add (nc, client);
284   GNUNET_SERVER_client_set_user_context (client, line);
285   GNUNET_CONTAINER_DLL_insert (lines_head,
286                                lines_tail,
287                                line);
288   line->local_line = ntohl (msg->line) & (~ (1 << 31));
289   GNUNET_SERVER_receive_done (client, GNUNET_OK);
290 }
291
292
293 /**
294  * Function to handle a pickup request message from the client
295  *
296  * @param cls closure, NULL
297  * @param client the client from which the message is
298  * @param message the message from the client
299  */
300 static void
301 handle_client_pickup_message (void *cls,
302                               struct GNUNET_SERVER_Client *client,
303                               const struct GNUNET_MessageHeader *message)
304 {
305   const struct ClientPhonePickupMessage *msg;
306   struct GNUNET_MQ_Envelope *e;
307   struct MeshPhonePickupMessage *mppm;
308   struct Line *line;
309   struct Channel *ch;
310
311   msg = (const struct ClientPhonePickupMessage *) message;
312   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
313   if (NULL == line)
314   {
315     GNUNET_break (0);
316     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
317     return;
318   }
319   for (ch = line->channel_head; NULL != ch; ch = ch->next)
320     if (msg->cid == ch->cid)
321       break;
322   if (NULL == ch)
323   {
324     /* could have been destroyed asynchronously, ignore message */
325     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
326                 "Channel %u not found\n",
327                 msg->cid);
328     return;
329   }
330   switch (ch->status)
331   {
332   case CS_CALLEE_RINGING:
333     ch->status = CS_CALLEE_CONNECTED;
334     break;
335   case CS_CALLEE_CONNECTED:
336     GNUNET_break (0);
337     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
338     return;
339   case CS_CALLEE_SHUTDOWN:
340     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341                 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
342     GNUNET_SERVER_receive_done (client, GNUNET_OK);
343     break;
344   case CS_CALLER_CALLING:
345   case CS_CALLER_CONNECTED:
346   case CS_CALLER_SHUTDOWN:
347     GNUNET_break (0);
348     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
349     return;
350   }
351   GNUNET_break (CS_CALLEE_CONNECTED == ch->status);
352   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353               "Sending PICK_UP message to mesh\n");
354   e = GNUNET_MQ_msg (mppm,
355                      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP);
356   GNUNET_MQ_send (ch->reliable_mq, e);
357   GNUNET_SERVER_receive_done (client, GNUNET_OK);
358 }
359
360
361 /**
362  * Destroy a channel.
363  *
364  * @param ch channel to destroy.
365  */
366 static void
367 destroy_line_mesh_channels (struct Channel *ch)
368 {
369   struct Line *line = ch->line;
370   struct GNUNET_MESH_Channel *t;
371
372   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
373               "Destroying mesh channels\n");
374   if (NULL != ch->reliable_mq)
375   {
376     GNUNET_MQ_destroy (ch->reliable_mq);
377     ch->reliable_mq = NULL;
378   }
379   if (NULL != ch->unreliable_mth)
380   {
381     GNUNET_MESH_notify_transmit_ready_cancel (ch->unreliable_mth);
382     ch->unreliable_mth = NULL;
383   }
384   if (NULL != (t = ch->channel_unreliable))
385   {
386     ch->channel_unreliable = NULL;
387     GNUNET_MESH_channel_destroy (t);
388   }
389   if (NULL != (t = ch->channel_reliable))
390   {
391     ch->channel_reliable = NULL;
392     GNUNET_MESH_channel_destroy (t);
393   }
394   GNUNET_CONTAINER_DLL_remove (line->channel_head,
395                                line->channel_tail,
396                                ch);
397   GNUNET_free_non_null (ch->audio_data);
398   GNUNET_free (ch);
399 }
400
401
402 /**
403  * We are done signalling shutdown to the other peer.  Close down
404  * the channel.
405  *
406  * @param cls the `struct Channel` to reset/terminate
407  */
408 static void
409 mq_done_finish_caller_shutdown (void *cls)
410 {
411   struct Channel *ch = cls;
412
413   switch (ch->status)
414   {
415   case CS_CALLEE_RINGING:
416     GNUNET_break (0);
417     break;
418   case CS_CALLEE_CONNECTED:
419     GNUNET_break (0);
420     break;
421   case CS_CALLEE_SHUTDOWN:
422     destroy_line_mesh_channels (ch);
423     break;
424   case CS_CALLER_CALLING:
425     GNUNET_break (0);
426     break;
427   case CS_CALLER_CONNECTED:
428     GNUNET_break (0);
429     break;
430   case CS_CALLER_SHUTDOWN:
431     destroy_line_mesh_channels (ch);
432     break;
433   }
434 }
435
436
437 /**
438  * Function to handle a hangup request message from the client
439  *
440  * @param cls closure, NULL
441  * @param client the client from which the message is
442  * @param message the message from the client
443  */
444 static void
445 handle_client_hangup_message (void *cls,
446                               struct GNUNET_SERVER_Client *client,
447                               const struct GNUNET_MessageHeader *message)
448 {
449   const struct ClientPhoneHangupMessage *msg;
450   struct GNUNET_MQ_Envelope *e;
451   struct MeshPhoneHangupMessage *mhum;
452   struct Line *line;
453   struct Channel *ch;
454
455   msg = (const struct ClientPhoneHangupMessage *) message;
456   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
457   if (NULL == line)
458   {
459     GNUNET_break (0);
460     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
461     return;
462   }
463   for (ch = line->channel_head; NULL != ch; ch = ch->next)
464     if (msg->cid == ch->cid)
465       break;
466   if (NULL == ch)
467   {
468     /* could have been destroyed asynchronously, ignore message */
469     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470                 "Channel %u not found\n",
471                 msg->cid);
472     GNUNET_SERVER_receive_done (client, GNUNET_OK);
473     return;
474   }
475
476   switch (ch->status)
477   {
478   case CS_CALLEE_RINGING:
479     ch->status = CS_CALLEE_SHUTDOWN;
480     break;
481   case CS_CALLEE_CONNECTED:
482     ch->status = CS_CALLEE_SHUTDOWN;
483     break;
484   case CS_CALLEE_SHUTDOWN:
485     /* maybe the other peer closed asynchronously... */
486     return;
487   case CS_CALLER_CALLING:
488     ch->status = CS_CALLER_SHUTDOWN;
489     break;
490   case CS_CALLER_CONNECTED:
491     ch->status = CS_CALLER_SHUTDOWN;
492     break;
493   case CS_CALLER_SHUTDOWN:
494     /* maybe the other peer closed asynchronously... */
495     return;
496   }
497   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498               "Sending HANG_UP message via mesh\n");
499   e = GNUNET_MQ_msg (mhum,
500                      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
501   GNUNET_MQ_notify_sent (e,
502                          &mq_done_finish_caller_shutdown,
503                          ch);
504   GNUNET_MQ_send (ch->reliable_mq, e);
505   GNUNET_SERVER_receive_done (client, GNUNET_OK);
506 }
507
508
509 /**
510  * Function to handle a suspend request message from the client
511  *
512  * @param cls closure, NULL
513  * @param client the client from which the message is
514  * @param message the message from the client
515  */
516 static void
517 handle_client_suspend_message (void *cls,
518                                struct GNUNET_SERVER_Client *client,
519                                const struct GNUNET_MessageHeader *message)
520 {
521   const struct ClientPhoneSuspendMessage *msg;
522   struct GNUNET_MQ_Envelope *e;
523   struct MeshPhoneSuspendMessage *mhum;
524   struct Line *line;
525   struct Channel *ch;
526
527   msg = (const struct ClientPhoneSuspendMessage *) message;
528   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
529   if (NULL == line)
530   {
531     GNUNET_break (0);
532     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
533     return;
534   }
535   for (ch = line->channel_head; NULL != ch; ch = ch->next)
536     if (msg->cid == ch->cid)
537       break;
538   if (NULL == ch)
539   {
540     /* could have been destroyed asynchronously, ignore message */
541     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
542                 "Channel %u not found\n",
543                 msg->cid);
544     return;
545   }
546   if (GNUNET_YES == ch->suspended_local)
547   {
548     GNUNET_break (0);
549     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
550     return;
551   }
552   switch (ch->status)
553   {
554   case CS_CALLEE_RINGING:
555     GNUNET_break (0);
556     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
557     return;
558   case CS_CALLEE_CONNECTED:
559     ch->suspended_local = GNUNET_YES;
560     break;
561   case CS_CALLEE_SHUTDOWN:
562     /* maybe the other peer closed asynchronously... */
563     return;
564   case CS_CALLER_CALLING:
565     GNUNET_break (0);
566     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
567     return;
568   case CS_CALLER_CONNECTED:
569     ch->suspended_local = GNUNET_YES;
570     break;
571   case CS_CALLER_SHUTDOWN:
572     /* maybe the other peer closed asynchronously... */
573     return;
574   }
575   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576               "Sending SUSPEND message via mesh\n");
577   e = GNUNET_MQ_msg (mhum,
578                      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_SUSPEND);
579   GNUNET_MQ_send (ch->reliable_mq, e);
580   GNUNET_SERVER_receive_done (client, GNUNET_OK);
581 }
582
583
584 /**
585  * Function to handle a resume request message from the client
586  *
587  * @param cls closure, NULL
588  * @param client the client from which the message is
589  * @param message the message from the client
590  */
591 static void
592 handle_client_resume_message (void *cls,
593                               struct GNUNET_SERVER_Client *client,
594                               const struct GNUNET_MessageHeader *message)
595 {
596   const struct ClientPhoneResumeMessage *msg;
597   struct GNUNET_MQ_Envelope *e;
598   struct MeshPhoneResumeMessage *mhum;
599   struct Line *line;
600   struct Channel *ch;
601
602   msg = (const struct ClientPhoneResumeMessage *) message;
603   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
604   if (NULL == line)
605   {
606     GNUNET_break (0);
607     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
608     return;
609   }
610   for (ch = line->channel_head; NULL != ch; ch = ch->next)
611     if (msg->cid == ch->cid)
612       break;
613   if (NULL == ch)
614   {
615     /* could have been destroyed asynchronously, ignore message */
616     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
617                 "Channel %u not found\n",
618                 msg->cid);
619     return;
620   }
621   if (GNUNET_YES != ch->suspended_local)
622   {
623     GNUNET_break (0);
624     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
625     return;
626   }
627   switch (ch->status)
628   {
629   case CS_CALLEE_RINGING:
630     GNUNET_break (0);
631     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
632     return;
633   case CS_CALLEE_CONNECTED:
634     ch->suspended_local = GNUNET_NO;
635     break;
636   case CS_CALLEE_SHUTDOWN:
637     /* maybe the other peer closed asynchronously... */
638     return;
639   case CS_CALLER_CALLING:
640     GNUNET_break (0);
641     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
642     return;
643   case CS_CALLER_CONNECTED:
644     ch->suspended_local = GNUNET_NO;
645     break;
646   case CS_CALLER_SHUTDOWN:
647     /* maybe the other peer closed asynchronously... */
648     return;
649   }
650   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651               "Sending RESUME message via mesh\n");
652   e = GNUNET_MQ_msg (mhum,
653                      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RESUME);
654   GNUNET_MQ_send (ch->reliable_mq, e);
655   GNUNET_SERVER_receive_done (client, GNUNET_OK);
656 }
657
658
659 /**
660  * Function to handle call request from the client
661  *
662  * @param cls closure, NULL
663  * @param client the client from which the message is
664  * @param message the message from the client
665  */
666 static void
667 handle_client_call_message (void *cls,
668                             struct GNUNET_SERVER_Client *client,
669                             const struct GNUNET_MessageHeader *message)
670 {
671   const struct ClientCallMessage *msg;
672   struct Line *line;
673   struct Channel *ch;
674   struct GNUNET_MQ_Envelope *e;
675   struct MeshPhoneRingMessage *ring;
676
677   msg = (const struct ClientCallMessage *) message;
678   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
679   if (NULL != line)
680   {
681     GNUNET_break (0);
682     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
683     return;
684   }
685   line = GNUNET_new (struct Line);
686   line->client = client;
687   line->local_line = (local_line_cnt++) | (1 << 31);
688   GNUNET_SERVER_client_set_user_context (client, line);
689   GNUNET_SERVER_notification_context_add (nc, client);
690   GNUNET_CONTAINER_DLL_insert (lines_head,
691                                lines_tail,
692                                line);
693   ch = GNUNET_new (struct Channel);
694   ch->line = line;
695   GNUNET_CONTAINER_DLL_insert (line->channel_head,
696                                line->channel_tail,
697                                ch);
698   ch->target = msg->target;
699   ch->remote_line = ntohl (msg->line);
700   ch->status = CS_CALLER_CALLING;
701   ch->channel_reliable = GNUNET_MESH_channel_create (mesh,
702                                                      ch,
703                                                      &msg->target,
704                                                      GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
705                                                      GNUNET_MESH_OPTION_RELIABLE);
706   ch->reliable_mq = GNUNET_MESH_mq_create (ch->channel_reliable);
707   e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
708   ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
709   ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
710                               sizeof (struct GNUNET_TIME_AbsoluteNBO) +
711                               sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
712                               sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
713   GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
714                                       &ring->caller_id);
715   ring->remote_line = msg->line;
716   ring->source_line = htonl (line->local_line);
717   ring->target = msg->target;
718   ring->source = my_identity;
719   ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
720   GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
721                             &ring->purpose,
722                             &ring->signature);
723   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
724               "Sending RING message via mesh\n");
725   GNUNET_MQ_send (ch->reliable_mq, e);
726   GNUNET_SERVER_receive_done (client, GNUNET_OK);
727 }
728
729
730 /**
731  * Transmit audio data via unreliable mesh channel.
732  *
733  * @param cls the `struct Channel` we are transmitting for
734  * @param size number of bytes available in @a buf
735  * @param buf where to copy the data
736  * @return number of bytes copied to @a buf
737  */
738 static size_t
739 transmit_line_audio (void *cls,
740                      size_t size,
741                      void *buf)
742 {
743   struct Channel *ch = cls;
744   struct MeshAudioMessage *mam = buf;
745
746   ch->unreliable_mth = NULL;
747   if ( (NULL == buf) ||
748        (size < sizeof (struct MeshAudioMessage) + ch->audio_size) )
749     {
750     /* eh, other error handling? */
751     return 0;
752   }
753   mam->header.size = htons (sizeof (struct MeshAudioMessage) + ch->audio_size);
754   mam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO);
755   mam->remote_line = htonl (ch->remote_line);
756   mam->source_line = htonl (ch->line->local_line);
757   memcpy (&mam[1], ch->audio_data, ch->audio_size);
758   GNUNET_free (ch->audio_data);
759   ch->audio_data = NULL;
760   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
761               "Sending %u bytes of audio data from line %u to remote line %u via mesh\n",
762               ch->audio_size, ch->line->local_line, ch->remote_line);
763   return sizeof (struct MeshAudioMessage) + ch->audio_size;
764 }
765
766
767 /**
768  * Function to handle audio data from the client
769  *
770  * @param cls closure, NULL
771  * @param client the client from which the message is
772  * @param message the message from the client
773  */
774 static void
775 handle_client_audio_message (void *cls,
776                              struct GNUNET_SERVER_Client *client,
777                              const struct GNUNET_MessageHeader *message)
778 {
779   const struct ClientAudioMessage *msg;
780   struct Line *line;
781   struct Channel *ch;
782   size_t size;
783
784   size = ntohs (message->size) - sizeof (struct ClientAudioMessage);
785   msg = (const struct ClientAudioMessage *) message;
786   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
787   if (NULL == line)
788   {
789     GNUNET_break (0);
790     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
791     return;
792   }
793   for (ch = line->channel_head; NULL != ch; ch = ch->next)
794     if (msg->cid == ch->cid)
795       break;
796   if (NULL == ch)
797   {
798     /* could have been destroyed asynchronously, ignore message */
799     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
800                 "Channel %u not found\n",
801                 msg->cid);
802     return;
803   }
804
805   switch (ch->status)
806   {
807   case CS_CALLEE_RINGING:
808   case CS_CALLER_CALLING:
809     GNUNET_break (0);
810     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
811     return;
812   case CS_CALLEE_CONNECTED:
813   case CS_CALLER_CONNECTED:
814     /* common case, handled below */
815     break;
816   case CS_CALLEE_SHUTDOWN:
817   case CS_CALLER_SHUTDOWN:
818     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
819                 "Mesh audio channel in shutdown; audio data dropped\n");
820     GNUNET_SERVER_receive_done (client, GNUNET_OK);
821     return;
822   }
823   if (GNUNET_YES == ch->suspended_local)
824   {
825     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "This channel is suspended locally\n");
826     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
827     return;
828   }
829   if (NULL == ch->channel_unreliable)
830   {
831     GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
832                 _("Mesh audio channel not ready; audio data dropped\n"));
833     GNUNET_SERVER_receive_done (client, GNUNET_OK);
834     return;
835   }
836   if (NULL != ch->unreliable_mth)
837   {
838     /* NOTE: we may want to not do this and instead combine the data */
839     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
840                 "Bandwidth insufficient; dropping previous audio data segment with %u bytes\n",
841                 (unsigned int) ch->audio_size);
842     GNUNET_MESH_notify_transmit_ready_cancel (ch->unreliable_mth);
843     ch->unreliable_mth = NULL;
844     GNUNET_free (ch->audio_data);
845     ch->audio_data = NULL;
846   }
847   ch->audio_size = size;
848   ch->audio_data = GNUNET_malloc (ch->audio_size);
849   memcpy (ch->audio_data,
850           &msg[1],
851           size);
852   ch->unreliable_mth = GNUNET_MESH_notify_transmit_ready (ch->channel_unreliable,
853                                                           GNUNET_NO,
854                                                           GNUNET_TIME_UNIT_FOREVER_REL,
855                                                           sizeof (struct MeshAudioMessage)
856                                                           + ch->audio_size,
857                                                           &transmit_line_audio,
858                                                           ch);
859   GNUNET_SERVER_receive_done (client, GNUNET_OK);
860 }
861
862
863 /**
864  * We are done signalling shutdown to the other peer.
865  * Destroy the channel.
866  *
867  * @param cls the `struct GNUNET_MESH_channel` to destroy
868  */
869 static void
870 mq_done_destroy_channel (void *cls)
871 {
872   struct GNUNET_MESH_Channel *channel = cls;
873
874   GNUNET_MESH_channel_destroy (channel);
875 }
876
877
878 /**
879  * Function to handle a ring message incoming over mesh
880  *
881  * @param cls closure, NULL
882  * @param channel the channel over which the message arrived
883  * @param channel_ctx the channel context, can be NULL
884  *                    or point to the `struct Channel`
885  * @param message the incoming message
886  * @return #GNUNET_OK
887  */
888 static int
889 handle_mesh_ring_message (void *cls,
890                           struct GNUNET_MESH_Channel *channel,
891                           void **channel_ctx,
892                           const struct GNUNET_MessageHeader *message)
893 {
894   const struct MeshPhoneRingMessage *msg;
895   struct Line *line;
896   struct Channel *ch;
897   struct GNUNET_MQ_Envelope *e;
898   struct MeshPhoneHangupMessage *hang_up;
899   struct ClientPhoneRingMessage cring;
900   struct GNUNET_MQ_Handle *reliable_mq;
901
902   msg = (const struct MeshPhoneRingMessage *) message;
903   if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
904                                     sizeof (struct GNUNET_TIME_AbsoluteNBO) +
905                                     sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
906                                     sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) ||
907        (GNUNET_OK !=
908         GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
909                                   &msg->purpose,
910                                   &msg->signature,
911                                   &msg->caller_id)) )
912   {
913     GNUNET_break_op (0);
914     return GNUNET_SYSERR;
915   }
916   for (line = lines_head; NULL != line; line = line->next)
917     if (line->local_line == ntohl (msg->remote_line))
918       break;
919   if (NULL == line)
920   {
921     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
922                 _("No available phone for incoming call on line %u, sending HANG_UP signal\n"),
923                 ntohl (msg->remote_line));
924     e = GNUNET_MQ_msg (hang_up,
925                        GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
926     GNUNET_MQ_notify_sent (e,
927                            &mq_done_destroy_channel,
928                            channel);
929     reliable_mq = GNUNET_MESH_mq_create (channel);
930     GNUNET_MQ_send (reliable_mq, e);
931     /* FIXME: do we need to clean up reliable_mq somehow/somewhere? */
932     GNUNET_MESH_receive_done (channel); /* needed? */
933     return GNUNET_OK;
934   }
935   ch = GNUNET_new (struct Channel);
936   ch->line = line;
937   GNUNET_CONTAINER_DLL_insert (line->channel_head,
938                                line->channel_tail,
939                                ch);
940   ch->status = CS_CALLEE_RINGING;
941   ch->remote_line = ntohl (msg->source_line);
942   ch->channel_reliable = channel;
943   ch->reliable_mq = GNUNET_MESH_mq_create (ch->channel_reliable);
944   ch->cid = line->cid_gen++;
945   ch->target = msg->source;
946   *channel_ctx = ch;
947   cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
948   cring.header.size = htons (sizeof (cring));
949   cring.cid = ch->cid;
950   cring.caller_id = msg->caller_id;
951   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
952               "Sending RING message to client. CID %u:(%u, %u)\n", 
953               ch->cid, ch->remote_line, line->local_line);
954   GNUNET_SERVER_notification_context_unicast (nc,
955                                               line->client,
956                                               &cring.header,
957                                               GNUNET_NO);
958   GNUNET_MESH_receive_done (channel);
959   return GNUNET_OK;
960 }
961
962
963 /**
964  * Function to handle a hangup message incoming over mesh
965  *
966  * @param cls closure, NULL
967  * @param channel the channel over which the message arrived
968  * @param channel_ctx the channel context, can be NULL
969  *                    or point to the `struct Channel`
970  * @param message the incoming message
971  * @return #GNUNET_OK
972  */
973 static int
974 handle_mesh_hangup_message (void *cls,
975                             struct GNUNET_MESH_Channel *channel,
976                             void **channel_ctx,
977                             const struct GNUNET_MessageHeader *message)
978 {
979   struct Channel *ch = *channel_ctx;
980   struct Line *line;
981   struct ClientPhoneHangupMessage hup;
982   enum ChannelStatus status;
983
984   if (NULL == ch)
985   {
986     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
987                 "HANGUP message received for non-existing line, dropping channel.\n");
988     return GNUNET_SYSERR;
989   }
990   line = ch->line;
991   *channel_ctx = NULL;
992   hup.header.size = htons (sizeof (hup));
993   hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
994   hup.cid = ch->cid;
995   status = ch->status;
996   GNUNET_MESH_receive_done (channel);
997   destroy_line_mesh_channels (ch);
998   switch (status)
999   {
1000   case CS_CALLEE_RINGING:
1001   case CS_CALLEE_CONNECTED:
1002     break;
1003   case CS_CALLEE_SHUTDOWN:
1004     return GNUNET_OK;
1005   case CS_CALLER_CALLING:
1006   case CS_CALLER_CONNECTED:
1007     break;
1008   case CS_CALLER_SHUTDOWN:
1009     return GNUNET_OK;
1010   }
1011   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1012               "Sending HANG UP message to client\n");
1013   GNUNET_SERVER_notification_context_unicast (nc,
1014                                               line->client,
1015                                               &hup.header,
1016                                               GNUNET_NO);
1017   return GNUNET_OK;
1018 }
1019
1020
1021 /**
1022  * Function to handle a pickup message incoming over mesh
1023  *
1024  * @param cls closure, NULL
1025  * @param channel the channel over which the message arrived
1026  * @param channel_ctx the channel context, can be NULL
1027  *                    or point to the `struct Channel`
1028  * @param message the incoming message
1029  * @return #GNUNET_OK
1030  */
1031 static int
1032 handle_mesh_pickup_message (void *cls,
1033                             struct GNUNET_MESH_Channel *channel,
1034                             void **channel_ctx,
1035                             const struct GNUNET_MessageHeader *message)
1036 {
1037   struct Channel *ch = *channel_ctx;
1038   struct Line *line;
1039   struct ClientPhonePickupMessage pick;
1040
1041   if (NULL == ch)
1042   {
1043     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1044                 "PICKUP message received for non-existing channel, dropping channel.\n");
1045     return GNUNET_SYSERR;
1046   }
1047   line = ch->line;
1048   GNUNET_MESH_receive_done (channel);
1049   switch (ch->status)
1050   {
1051   case CS_CALLEE_RINGING:
1052   case CS_CALLEE_CONNECTED:
1053     GNUNET_break_op (0);
1054     destroy_line_mesh_channels (ch);
1055     return GNUNET_SYSERR;
1056   case CS_CALLEE_SHUTDOWN:
1057     GNUNET_break_op (0);
1058     destroy_line_mesh_channels (ch);
1059     break;
1060   case CS_CALLER_CALLING:
1061     ch->status = CS_CALLER_CONNECTED;
1062     break;
1063   case CS_CALLER_CONNECTED:
1064     GNUNET_break_op (0);
1065     return GNUNET_OK;
1066   case CS_CALLER_SHUTDOWN:
1067     GNUNET_break_op (0);
1068     mq_done_finish_caller_shutdown (ch);
1069     return GNUNET_SYSERR;
1070   }
1071   pick.header.size = htons (sizeof (pick));
1072   pick.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
1073   pick.cid = ch->cid;
1074   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1075               "Sending PICKED UP message to client\n");
1076   GNUNET_SERVER_notification_context_unicast (nc,
1077                                               line->client,
1078                                               &pick.header,
1079                                               GNUNET_NO);
1080   ch->channel_unreliable = GNUNET_MESH_channel_create (mesh,
1081                                                        ch,
1082                                                        &ch->target,
1083                                                        GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1084                                                        GNUNET_MESH_OPTION_DEFAULT);
1085   if (NULL == ch->channel_unreliable)
1086   {
1087     GNUNET_break (0);
1088   }
1089   return GNUNET_OK;
1090 }
1091
1092
1093 /**
1094  * Function to handle a suspend message incoming over mesh
1095  *
1096  * @param cls closure, NULL
1097  * @param channel the channel over which the message arrived
1098  * @param channel_ctx the channel context, can be NULL
1099  *                    or point to the `struct Channel`
1100  * @param message the incoming message
1101  * @return #GNUNET_OK
1102  */
1103 static int
1104 handle_mesh_suspend_message (void *cls,
1105                              struct GNUNET_MESH_Channel *channel,
1106                              void **channel_ctx,
1107                              const struct GNUNET_MessageHeader *message)
1108 {
1109   struct Channel *ch = *channel_ctx;
1110   struct Line *line;
1111   struct ClientPhoneSuspendMessage suspend;
1112
1113   if (NULL == ch)
1114   {
1115     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1116                 "SUSPEND message received for non-existing line, dropping channel.\n");
1117     return GNUNET_SYSERR;
1118   }
1119   line = ch->line;
1120   suspend.header.size = htons (sizeof (suspend));
1121   suspend.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
1122   suspend.cid = ch->cid;
1123   GNUNET_MESH_receive_done (channel);
1124   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125               "Suspending channel CID: %u(%u:%u)\n",
1126               ch->cid, ch->remote_line, line->local_line);
1127   switch (ch->status)
1128   {
1129   case CS_CALLEE_RINGING:
1130     GNUNET_break_op (0);
1131     break;
1132   case CS_CALLEE_CONNECTED:
1133     ch->suspended_remote = GNUNET_YES;
1134     break;
1135   case CS_CALLEE_SHUTDOWN:
1136     return GNUNET_OK;
1137   case CS_CALLER_CALLING:
1138     GNUNET_break_op (0);
1139     break;
1140   case CS_CALLER_CONNECTED:
1141     ch->suspended_remote = GNUNET_YES;
1142     break;
1143   case CS_CALLER_SHUTDOWN:
1144     return GNUNET_OK;
1145   }
1146   GNUNET_SERVER_notification_context_unicast (nc,
1147                                               line->client,
1148                                               &suspend.header,
1149                                               GNUNET_NO);
1150   return GNUNET_OK;
1151 }
1152
1153
1154 /**
1155  * Function to handle a resume message incoming over mesh
1156  *
1157  * @param cls closure, NULL
1158  * @param channel the channel over which the message arrived
1159  * @param channel_ctx the channel context, can be NULL
1160  *                    or point to the `struct Channel`
1161  * @param message the incoming message
1162  * @return #GNUNET_OK
1163  */
1164 static int
1165 handle_mesh_resume_message (void *cls,
1166                              struct GNUNET_MESH_Channel *channel,
1167                              void **channel_ctx,
1168                              const struct GNUNET_MessageHeader *message)
1169 {
1170   struct Channel *ch = *channel_ctx;
1171   struct Line *line;
1172   struct ClientPhoneResumeMessage resume;
1173
1174   if (NULL == ch)
1175   {
1176     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1177                 "RESUME message received for non-existing line, dropping channel.\n");
1178     return GNUNET_SYSERR;
1179   }
1180   line = ch->line;
1181   resume.header.size = htons (sizeof (resume));
1182   resume.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
1183   resume.cid = ch->cid;
1184   GNUNET_MESH_receive_done (channel);
1185   if (GNUNET_YES != ch->suspended_remote)
1186   {
1187     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1188                 "RESUME message received for non-suspended channel, dropping channel.\n");
1189     return GNUNET_SYSERR;
1190   }
1191   switch (ch->status)
1192   {
1193   case CS_CALLEE_RINGING:
1194     GNUNET_break (0);
1195     break;
1196   case CS_CALLEE_CONNECTED:
1197     ch->suspended_remote = GNUNET_NO;
1198     break;
1199   case CS_CALLEE_SHUTDOWN:
1200     return GNUNET_OK;
1201   case CS_CALLER_CALLING:
1202     GNUNET_break (0);
1203     break;
1204   case CS_CALLER_CONNECTED:
1205     ch->suspended_remote = GNUNET_NO;
1206     break;
1207   case CS_CALLER_SHUTDOWN:
1208     return GNUNET_OK;
1209   }
1210   GNUNET_SERVER_notification_context_unicast (nc,
1211                                               line->client,
1212                                               &resume.header,
1213                                               GNUNET_NO);
1214   return GNUNET_OK;
1215 }
1216
1217
1218 /**
1219  * Function to handle an audio message incoming over mesh
1220  *
1221  * @param cls closure, NULL
1222  * @param channel the channel over which the message arrived
1223  * @param channel_ctx the channel context, can be NULL
1224  *                    or point to the `struct Channel`
1225  * @param message the incoming message
1226  * @return #GNUNET_OK
1227  */
1228 static int
1229 handle_mesh_audio_message (void *cls,
1230                            struct GNUNET_MESH_Channel *channel,
1231                            void **channel_ctx,
1232                            const struct GNUNET_MessageHeader *message)
1233 {
1234   const struct MeshAudioMessage *msg;
1235   struct Channel *ch = *channel_ctx;
1236   struct Line *line;
1237   struct GNUNET_PeerIdentity sender;
1238   size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
1239   char buf[msize + sizeof (struct ClientAudioMessage)];
1240   struct ClientAudioMessage *cam;
1241   const union GNUNET_MESH_ChannelInfo *info;
1242
1243   msg = (const struct MeshAudioMessage *) message;
1244   if (NULL == ch)
1245   {
1246     info = GNUNET_MESH_channel_get_info (channel,
1247                                          GNUNET_MESH_OPTION_PEER);
1248     if (NULL == info)
1249     {
1250       GNUNET_break (0);
1251       return GNUNET_OK;
1252     }
1253     sender = info->peer;
1254     for (line = lines_head; NULL != line; line = line->next)
1255       if (line->local_line == ntohl (msg->remote_line))
1256       {
1257         for (ch = line->channel_head; NULL != ch; ch = ch->next)
1258         {
1259           if ( (CS_CALLEE_CONNECTED == ch->status) &&
1260                (0 == memcmp (&ch->target,
1261                              &sender,
1262                              sizeof (struct GNUNET_PeerIdentity))) &&
1263                (NULL == ch->channel_unreliable) &&
1264                (ch->remote_line == ntohl (msg->source_line)) )
1265             break;
1266         }
1267         break;
1268       }
1269     if (NULL == line)
1270     {
1271       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1272                   "Received %u bytes of AUDIO data for non-existing line %u, dropping.\n",
1273                   msize, ntohl (msg->remote_line));
1274       return GNUNET_SYSERR;
1275     }
1276     if (NULL == ch)
1277     {
1278       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1279                   "Received %u bytes of AUDIO data for unknown sender.\n",
1280                   msize);
1281       return GNUNET_SYSERR;
1282     }
1283     if ((GNUNET_YES == ch->suspended_local) || (GNUNET_YES == ch->suspended_remote))
1284     {
1285       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1286                   "Received %u bytes of AUDIO data on suspended channel CID %u:(%u:%u); dropping\n",
1287                   msize, ch->cid, ch->remote_line, line->local_line);
1288       return GNUNET_OK;
1289     }
1290     ch->channel_unreliable = channel;
1291     *channel_ctx = ch;
1292   }
1293   GNUNET_break (ch->line->local_line == ntohl (msg->remote_line));
1294   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1295               "Forwarding %u bytes of AUDIO data to client CID %u:(%u:%u)\n",
1296               msize, ch->cid, ch->remote_line, ch->line->local_line);
1297   cam = (struct ClientAudioMessage *) buf;
1298   cam->header.size = htons (sizeof (buf));
1299   cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1300   cam->cid = ch->cid;
1301   memcpy (&cam[1], &msg[1], msize);
1302   GNUNET_SERVER_notification_context_unicast (nc,
1303                                               ch->line->client,
1304                                               &cam->header,
1305                                               GNUNET_YES);
1306   GNUNET_MESH_receive_done (channel);
1307   return GNUNET_OK;
1308 }
1309
1310
1311 /**
1312  * Method called whenever another peer has added us to a channel
1313  * the other peer initiated.
1314  *
1315  * @param cls closure
1316  * @param channel new handle to the channel
1317  * @param initiator peer that started the channel
1318  * @param port port
1319  * @param options channel option flags
1320  * @return initial channel context for the channel;
1321  *         (can be NULL -- that's not an error)
1322  */
1323 static void *
1324 inbound_channel (void *cls,
1325                 struct GNUNET_MESH_Channel *channel,
1326                 const struct GNUNET_PeerIdentity *initiator,
1327                 uint32_t port, enum GNUNET_MESH_ChannelOption options)
1328 {
1329   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1330               _("Received incoming channel on port %u\n"),
1331               (unsigned int) port);
1332   return NULL;
1333 }
1334
1335
1336 /**
1337  * Function called whenever an inbound channel is destroyed.  Should clean up
1338  * any associated state.
1339  *
1340  * @param cls closure (set from #GNUNET_MESH_connect)
1341  * @param channel connection to the other end (henceforth invalid)
1342  * @param channel_ctx place where local state associated
1343  *                   with the channel is stored;
1344  *                   may point to the `struct Channel`
1345  */
1346 static void
1347 inbound_end (void *cls,
1348              const struct GNUNET_MESH_Channel *channel,
1349              void *channel_ctx)
1350 {
1351   struct Channel *ch = channel_ctx;
1352   struct Line *line;
1353   struct ClientPhoneHangupMessage hup;
1354
1355   if (NULL == ch)
1356   {
1357     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1358                 "Mesh channel destroyed, but channel is unknown to us\n");
1359     return;
1360   }
1361   line = ch->line;
1362   if (ch->channel_unreliable == channel)
1363   {
1364     if (NULL != ch->unreliable_mth)
1365     {
1366       GNUNET_MESH_notify_transmit_ready_cancel (ch->unreliable_mth);
1367       ch->unreliable_mth = NULL;
1368     }
1369     ch->channel_unreliable = NULL;
1370     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1371                 "Unreliable channel destroyed\n");
1372     return;
1373   }
1374   if (ch->channel_reliable != channel)
1375   {
1376     /* recursive call, I'm the one destroying 'ch' right now */
1377     return;
1378   }
1379   ch->channel_reliable = NULL;
1380
1381   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1382               "Mesh channel destroyed by mesh in state %d\n",
1383               ch->status);
1384   hup.header.size = htons (sizeof (hup));
1385   hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1386   hup.cid = ch->cid;
1387   switch (ch->status)
1388   {
1389   case CS_CALLEE_RINGING:
1390   case CS_CALLEE_CONNECTED:
1391     GNUNET_SERVER_notification_context_unicast (nc,
1392                                                 line->client,
1393                                                 &hup.header,
1394                                                 GNUNET_NO);
1395     break;
1396   case CS_CALLEE_SHUTDOWN:
1397     break;
1398   case CS_CALLER_CALLING:
1399   case CS_CALLER_CONNECTED:
1400     GNUNET_SERVER_notification_context_unicast (nc,
1401                                                 line->client,
1402                                                 &hup.header,
1403                                                 GNUNET_NO);
1404     break;
1405   case CS_CALLER_SHUTDOWN:
1406     break;
1407   }
1408   destroy_line_mesh_channels (ch);
1409 }
1410
1411
1412 /**
1413  * A client disconnected.  Remove all of its data structure entries.
1414  *
1415  * @param cls closure, NULL
1416  * @param client identification of the client
1417  */
1418 static void
1419 handle_client_disconnect (void *cls,
1420                           struct GNUNET_SERVER_Client *client)
1421 {
1422   struct Line *line;
1423
1424   if (NULL == client)
1425     return;
1426   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
1427   if (NULL == line)
1428     return;
1429   GNUNET_SERVER_client_set_user_context (client, (void *)NULL);
1430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1431               "Client disconnected, closing line\n");
1432   GNUNET_CONTAINER_DLL_remove (lines_head,
1433                                lines_tail,
1434                                line);
1435   while (NULL != line->channel_head)
1436     destroy_line_mesh_channels (line->channel_head);
1437   GNUNET_free (line);
1438 }
1439
1440
1441 /**
1442  * Shutdown nicely
1443  *
1444  * @param cls closure, NULL
1445  * @param tc the task context
1446  */
1447 static void
1448 do_shutdown (void *cls,
1449              const struct GNUNET_SCHEDULER_TaskContext *tc)
1450 {
1451   struct Line *line;
1452   struct Channel *ch;
1453
1454   while (NULL != (line = lines_head))
1455   {
1456     while (NULL != (ch = line->channel_head))
1457       destroy_line_mesh_channels (ch);
1458     GNUNET_CONTAINER_DLL_remove (lines_head,
1459                                  lines_tail,
1460                                  line);
1461     GNUNET_SERVER_client_set_user_context (line->client, (void *) NULL);
1462     GNUNET_free (line);
1463   }
1464   if (NULL != mesh)
1465   {
1466     GNUNET_MESH_disconnect (mesh);
1467     mesh = NULL;
1468   }
1469   if (NULL != nc)
1470   {
1471     GNUNET_SERVER_notification_context_destroy (nc);
1472     nc = NULL;
1473   }
1474 }
1475
1476
1477 /**
1478  * Main function that will be run by the scheduler.
1479  *
1480  * @param cls closure
1481  * @param server server handle
1482  * @param c configuration
1483  */
1484 static void
1485 run (void *cls,
1486      struct GNUNET_SERVER_Handle *server,
1487      const struct GNUNET_CONFIGURATION_Handle *c)
1488 {
1489   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1490     {&handle_client_register_message, NULL,
1491      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1492      sizeof (struct ClientPhoneRegisterMessage)},
1493     {&handle_client_pickup_message, NULL,
1494      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1495      sizeof (struct ClientPhonePickupMessage) },
1496     {&handle_client_suspend_message, NULL,
1497      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1498      sizeof (struct ClientPhoneSuspendMessage) },
1499     {&handle_client_resume_message, NULL,
1500      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1501      sizeof (struct ClientPhoneResumeMessage) },
1502     {&handle_client_hangup_message, NULL,
1503      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1504      sizeof (struct ClientPhoneHangupMessage) },
1505     {&handle_client_call_message, NULL,
1506      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1507      sizeof (struct ClientCallMessage) },
1508     {&handle_client_audio_message, NULL,
1509      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1510      0},
1511     {NULL, NULL, 0, 0}
1512   };
1513   static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1514     {&handle_mesh_ring_message,
1515      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
1516      sizeof (struct MeshPhoneRingMessage)},
1517     {&handle_mesh_hangup_message,
1518      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
1519      sizeof (struct MeshPhoneHangupMessage)},
1520     {&handle_mesh_pickup_message,
1521      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
1522      sizeof (struct MeshPhonePickupMessage)},
1523     {&handle_mesh_suspend_message,
1524      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_SUSPEND,
1525      sizeof (struct MeshPhoneSuspendMessage)},
1526     {&handle_mesh_resume_message,
1527      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RESUME,
1528      sizeof (struct MeshPhoneResumeMessage)},
1529     {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
1530      0},
1531     {NULL, 0, 0}
1532   };
1533   static uint32_t ports[] = {
1534     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
1535     GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1536     0
1537   };
1538
1539   cfg = c;
1540   GNUNET_assert (GNUNET_OK ==
1541                  GNUNET_CRYPTO_get_peer_identity (cfg,
1542                                                   &my_identity));
1543   mesh = GNUNET_MESH_connect (cfg,
1544                               NULL,
1545                               &inbound_channel,
1546                               &inbound_end,
1547                               mesh_handlers,
1548                               ports);
1549
1550   if (NULL == mesh)
1551   {
1552     GNUNET_break (0);
1553     GNUNET_SCHEDULER_shutdown ();
1554     return;
1555   }
1556   nc = GNUNET_SERVER_notification_context_create (server, 16);
1557   GNUNET_SERVER_add_handlers (server, server_handlers);
1558   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1559   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1560                                 &do_shutdown,
1561                                 NULL);
1562 }
1563
1564
1565 /**
1566  * The main function for the conversation service.
1567  *
1568  * @param argc number of arguments from the command line
1569  * @param argv command line arguments
1570  * @return 0 ok, 1 on error
1571  */
1572 int
1573 main (int argc,
1574       char *const *argv)
1575 {
1576   return (GNUNET_OK ==
1577           GNUNET_SERVICE_run (argc, argv,
1578                               "conversation",
1579                               GNUNET_SERVICE_OPTION_NONE,
1580                               &run, NULL)) ? 0 : 1;
1581 }
1582
1583 /* end of gnunet-service-conversation.c */