- fix state selection
[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     GNUNET_SERVER_receive_done (client, GNUNET_YES);
329     return;
330   }
331   switch (ch->status)
332   {
333   case CS_CALLEE_RINGING:
334     ch->status = CS_CALLEE_CONNECTED;
335     break;
336   case CS_CALLEE_CONNECTED:
337     GNUNET_break (0);
338     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
339     return;
340   case CS_CALLEE_SHUTDOWN:
341     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342                 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
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     GNUNET_SERVER_receive_done (client, GNUNET_OK);
487     return;
488   case CS_CALLER_CALLING:
489     ch->status = CS_CALLER_SHUTDOWN;
490     break;
491   case CS_CALLER_CONNECTED:
492     ch->status = CS_CALLER_SHUTDOWN;
493     break;
494   case CS_CALLER_SHUTDOWN:
495     /* maybe the other peer closed asynchronously... */
496     GNUNET_SERVER_receive_done (client, GNUNET_OK);
497     return;
498   }
499   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
500               "Sending HANG_UP message via mesh\n");
501   e = GNUNET_MQ_msg (mhum,
502                      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
503   GNUNET_MQ_notify_sent (e,
504                          &mq_done_finish_caller_shutdown,
505                          ch);
506   GNUNET_MQ_send (ch->reliable_mq, e);
507   GNUNET_SERVER_receive_done (client, GNUNET_OK);
508 }
509
510
511 /**
512  * Function to handle a suspend request message from the client
513  *
514  * @param cls closure, NULL
515  * @param client the client from which the message is
516  * @param message the message from the client
517  */
518 static void
519 handle_client_suspend_message (void *cls,
520                                struct GNUNET_SERVER_Client *client,
521                                const struct GNUNET_MessageHeader *message)
522 {
523   const struct ClientPhoneSuspendMessage *msg;
524   struct GNUNET_MQ_Envelope *e;
525   struct MeshPhoneSuspendMessage *mhum;
526   struct Line *line;
527   struct Channel *ch;
528
529   msg = (const struct ClientPhoneSuspendMessage *) message;
530   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
531   if (NULL == line)
532   {
533     GNUNET_break (0);
534     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
535     return;
536   }
537   for (ch = line->channel_head; NULL != ch; ch = ch->next)
538     if (msg->cid == ch->cid)
539       break;
540   if (NULL == ch)
541   {
542     /* could have been destroyed asynchronously, ignore message */
543     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
544                 "Channel %u not found\n",
545                 msg->cid);
546     GNUNET_SERVER_receive_done (client, GNUNET_OK);
547     return;
548   }
549   if (GNUNET_YES == ch->suspended_local)
550   {
551     GNUNET_break (0);
552     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
553     return;
554   }
555   switch (ch->status)
556   {
557   case CS_CALLEE_RINGING:
558     GNUNET_break (0);
559     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
560     return;
561   case CS_CALLEE_CONNECTED:
562     ch->suspended_local = GNUNET_YES;
563     break;
564   case CS_CALLEE_SHUTDOWN:
565     /* maybe the other peer closed asynchronously... */
566     GNUNET_SERVER_receive_done (client, GNUNET_OK);
567     return;
568   case CS_CALLER_CALLING:
569     GNUNET_break (0);
570     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
571     return;
572   case CS_CALLER_CONNECTED:
573     ch->suspended_local = GNUNET_YES;
574     break;
575   case CS_CALLER_SHUTDOWN:
576     /* maybe the other peer closed asynchronously... */
577     GNUNET_SERVER_receive_done (client, GNUNET_OK);
578     return;
579   }
580   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
581               "Sending SUSPEND message via mesh\n");
582   e = GNUNET_MQ_msg (mhum,
583                      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_SUSPEND);
584   GNUNET_MQ_send (ch->reliable_mq, e);
585   GNUNET_SERVER_receive_done (client, GNUNET_OK);
586 }
587
588
589 /**
590  * Function to handle a resume request message from the client
591  *
592  * @param cls closure, NULL
593  * @param client the client from which the message is
594  * @param message the message from the client
595  */
596 static void
597 handle_client_resume_message (void *cls,
598                               struct GNUNET_SERVER_Client *client,
599                               const struct GNUNET_MessageHeader *message)
600 {
601   const struct ClientPhoneResumeMessage *msg;
602   struct GNUNET_MQ_Envelope *e;
603   struct MeshPhoneResumeMessage *mhum;
604   struct Line *line;
605   struct Channel *ch;
606
607   msg = (const struct ClientPhoneResumeMessage *) message;
608   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
609   if (NULL == line)
610   {
611     GNUNET_break (0);
612     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
613     return;
614   }
615   for (ch = line->channel_head; NULL != ch; ch = ch->next)
616     if (msg->cid == ch->cid)
617       break;
618   if (NULL == ch)
619   {
620     /* could have been destroyed asynchronously, ignore message */
621     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
622                 "Channel %u not found\n",
623                 msg->cid);
624     GNUNET_SERVER_receive_done (client, GNUNET_OK);
625     return;
626   }
627   if (GNUNET_YES != ch->suspended_local)
628   {
629     GNUNET_break (0);
630     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
631     return;
632   }
633   switch (ch->status)
634   {
635   case CS_CALLEE_RINGING:
636     GNUNET_break (0);
637     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
638     return;
639   case CS_CALLEE_CONNECTED:
640     ch->suspended_local = GNUNET_NO;
641     break;
642   case CS_CALLEE_SHUTDOWN:
643     /* maybe the other peer closed asynchronously... */
644     GNUNET_SERVER_receive_done (client, GNUNET_OK);
645     return;
646   case CS_CALLER_CALLING:
647     GNUNET_break (0);
648     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
649     return;
650   case CS_CALLER_CONNECTED:
651     ch->suspended_local = GNUNET_NO;
652     break;
653   case CS_CALLER_SHUTDOWN:
654     /* maybe the other peer closed asynchronously... */
655     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
656     return;
657   }
658   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659               "Sending RESUME message via mesh\n");
660   e = GNUNET_MQ_msg (mhum,
661                      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RESUME);
662   GNUNET_MQ_send (ch->reliable_mq, e);
663   GNUNET_SERVER_receive_done (client, GNUNET_OK);
664 }
665
666
667 /**
668  * Function to handle call request from the client
669  *
670  * @param cls closure, NULL
671  * @param client the client from which the message is
672  * @param message the message from the client
673  */
674 static void
675 handle_client_call_message (void *cls,
676                             struct GNUNET_SERVER_Client *client,
677                             const struct GNUNET_MessageHeader *message)
678 {
679   const struct ClientCallMessage *msg;
680   struct Line *line;
681   struct Channel *ch;
682   struct GNUNET_MQ_Envelope *e;
683   struct MeshPhoneRingMessage *ring;
684
685   msg = (const struct ClientCallMessage *) message;
686   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
687   if (NULL != line)
688   {
689     GNUNET_break (0);
690     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
691     return;
692   }
693   line = GNUNET_new (struct Line);
694   line->client = client;
695   line->local_line = (local_line_cnt++) | (1 << 31);
696   GNUNET_SERVER_client_set_user_context (client, line);
697   GNUNET_SERVER_notification_context_add (nc, client);
698   GNUNET_CONTAINER_DLL_insert (lines_head,
699                                lines_tail,
700                                line);
701   ch = GNUNET_new (struct Channel);
702   ch->line = line;
703   GNUNET_CONTAINER_DLL_insert (line->channel_head,
704                                line->channel_tail,
705                                ch);
706   ch->target = msg->target;
707   ch->remote_line = ntohl (msg->line);
708   ch->status = CS_CALLER_CALLING;
709   ch->channel_reliable = GNUNET_MESH_channel_create (mesh,
710                                                      ch,
711                                                      &msg->target,
712                                                      GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
713                                                      GNUNET_MESH_OPTION_RELIABLE);
714   ch->reliable_mq = GNUNET_MESH_mq_create (ch->channel_reliable);
715   e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
716   ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
717   ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
718                               sizeof (struct GNUNET_TIME_AbsoluteNBO) +
719                               sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
720                               sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
721   GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
722                                       &ring->caller_id);
723   ring->remote_line = msg->line;
724   ring->source_line = htonl (line->local_line);
725   ring->target = msg->target;
726   ring->source = my_identity;
727   ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
728   GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
729                             &ring->purpose,
730                             &ring->signature);
731   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
732               "Sending RING message via mesh\n");
733   GNUNET_MQ_send (ch->reliable_mq, e);
734   GNUNET_SERVER_receive_done (client, GNUNET_OK);
735 }
736
737
738 /**
739  * Transmit audio data via unreliable mesh channel.
740  *
741  * @param cls the `struct Channel` we are transmitting for
742  * @param size number of bytes available in @a buf
743  * @param buf where to copy the data
744  * @return number of bytes copied to @a buf
745  */
746 static size_t
747 transmit_line_audio (void *cls,
748                      size_t size,
749                      void *buf)
750 {
751   struct Channel *ch = cls;
752   struct MeshAudioMessage *mam = buf;
753
754   ch->unreliable_mth = NULL;
755   if ( (NULL == buf) ||
756        (size < sizeof (struct MeshAudioMessage) + ch->audio_size) )
757     {
758     /* eh, other error handling? */
759     return 0;
760   }
761   mam->header.size = htons (sizeof (struct MeshAudioMessage) + ch->audio_size);
762   mam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO);
763   mam->remote_line = htonl (ch->remote_line);
764   mam->source_line = htonl (ch->line->local_line);
765   memcpy (&mam[1], ch->audio_data, ch->audio_size);
766   GNUNET_free (ch->audio_data);
767   ch->audio_data = NULL;
768   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769               "Sending %u bytes of audio data from line %u to remote line %u via mesh\n",
770               ch->audio_size, ch->line->local_line, ch->remote_line);
771   return sizeof (struct MeshAudioMessage) + ch->audio_size;
772 }
773
774
775 /**
776  * Function to handle audio data from the client
777  *
778  * @param cls closure, NULL
779  * @param client the client from which the message is
780  * @param message the message from the client
781  */
782 static void
783 handle_client_audio_message (void *cls,
784                              struct GNUNET_SERVER_Client *client,
785                              const struct GNUNET_MessageHeader *message)
786 {
787   const struct ClientAudioMessage *msg;
788   struct Line *line;
789   struct Channel *ch;
790   size_t size;
791
792   size = ntohs (message->size) - sizeof (struct ClientAudioMessage);
793   msg = (const struct ClientAudioMessage *) message;
794   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
795   if (NULL == line)
796   {
797     GNUNET_break (0);
798     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
799     return;
800   }
801   for (ch = line->channel_head; NULL != ch; ch = ch->next)
802     if (msg->cid == ch->cid)
803       break;
804   if (NULL == ch)
805   {
806     /* could have been destroyed asynchronously, ignore message */
807     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
808                 "Channel %u not found\n",
809                 msg->cid);
810     GNUNET_SERVER_receive_done (client, GNUNET_OK);
811     return;
812   }
813
814   switch (ch->status)
815   {
816   case CS_CALLEE_RINGING:
817   case CS_CALLER_CALLING:
818     GNUNET_break (0);
819     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
820     return;
821   case CS_CALLEE_CONNECTED:
822   case CS_CALLER_CONNECTED:
823     /* common case, handled below */
824     break;
825   case CS_CALLEE_SHUTDOWN:
826   case CS_CALLER_SHUTDOWN:
827     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
828                 "Mesh audio channel in shutdown; audio data dropped\n");
829     GNUNET_SERVER_receive_done (client, GNUNET_OK);
830     return;
831   }
832   if (GNUNET_YES == ch->suspended_local)
833   {
834     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "This channel is suspended locally\n");
835     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
836     return;
837   }
838   if (NULL == ch->channel_unreliable)
839   {
840     GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
841                 _("Mesh audio channel not ready; audio data dropped\n"));
842     GNUNET_SERVER_receive_done (client, GNUNET_OK);
843     return;
844   }
845   if (NULL != ch->unreliable_mth)
846   {
847     /* NOTE: we may want to not do this and instead combine the data */
848     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849                 "Bandwidth insufficient; dropping previous audio data segment with %u bytes\n",
850                 (unsigned int) ch->audio_size);
851     GNUNET_MESH_notify_transmit_ready_cancel (ch->unreliable_mth);
852     ch->unreliable_mth = NULL;
853     GNUNET_free (ch->audio_data);
854     ch->audio_data = NULL;
855   }
856   ch->audio_size = size;
857   ch->audio_data = GNUNET_malloc (ch->audio_size);
858   memcpy (ch->audio_data,
859           &msg[1],
860           size);
861   ch->unreliable_mth = GNUNET_MESH_notify_transmit_ready (ch->channel_unreliable,
862                                                           GNUNET_NO,
863                                                           GNUNET_TIME_UNIT_FOREVER_REL,
864                                                           sizeof (struct MeshAudioMessage)
865                                                           + ch->audio_size,
866                                                           &transmit_line_audio,
867                                                           ch);
868   GNUNET_SERVER_receive_done (client, GNUNET_OK);
869 }
870
871
872 /**
873  * We are done signalling shutdown to the other peer.
874  * Destroy the channel.
875  *
876  * @param cls the `struct GNUNET_MESH_channel` to destroy
877  */
878 static void
879 mq_done_destroy_channel (void *cls)
880 {
881   struct GNUNET_MESH_Channel *channel = cls;
882
883   GNUNET_MESH_channel_destroy (channel);
884 }
885
886
887 /**
888  * Function to handle a ring message incoming over mesh
889  *
890  * @param cls closure, NULL
891  * @param channel the channel over which the message arrived
892  * @param channel_ctx the channel context, can be NULL
893  *                    or point to the `struct Channel`
894  * @param message the incoming message
895  * @return #GNUNET_OK
896  */
897 static int
898 handle_mesh_ring_message (void *cls,
899                           struct GNUNET_MESH_Channel *channel,
900                           void **channel_ctx,
901                           const struct GNUNET_MessageHeader *message)
902 {
903   const struct MeshPhoneRingMessage *msg;
904   struct Line *line;
905   struct Channel *ch;
906   struct GNUNET_MQ_Envelope *e;
907   struct MeshPhoneHangupMessage *hang_up;
908   struct ClientPhoneRingMessage cring;
909   struct GNUNET_MQ_Handle *reliable_mq;
910
911   msg = (const struct MeshPhoneRingMessage *) message;
912   if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
913                                     sizeof (struct GNUNET_TIME_AbsoluteNBO) +
914                                     sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
915                                     sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) ||
916        (GNUNET_OK !=
917         GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
918                                   &msg->purpose,
919                                   &msg->signature,
920                                   &msg->caller_id)) )
921   {
922     GNUNET_break_op (0);
923     return GNUNET_SYSERR;
924   }
925   for (line = lines_head; NULL != line; line = line->next)
926     if (line->local_line == ntohl (msg->remote_line))
927       break;
928   if (NULL == line)
929   {
930     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
931                 _("No available phone for incoming call on line %u, sending HANG_UP signal\n"),
932                 ntohl (msg->remote_line));
933     e = GNUNET_MQ_msg (hang_up,
934                        GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
935     GNUNET_MQ_notify_sent (e,
936                            &mq_done_destroy_channel,
937                            channel);
938     reliable_mq = GNUNET_MESH_mq_create (channel);
939     GNUNET_MQ_send (reliable_mq, e);
940     /* FIXME: do we need to clean up reliable_mq somehow/somewhere? */
941     GNUNET_MESH_receive_done (channel); /* needed? */
942     return GNUNET_OK;
943   }
944   ch = GNUNET_new (struct Channel);
945   ch->line = line;
946   GNUNET_CONTAINER_DLL_insert (line->channel_head,
947                                line->channel_tail,
948                                ch);
949   ch->status = CS_CALLEE_RINGING;
950   ch->remote_line = ntohl (msg->source_line);
951   ch->channel_reliable = channel;
952   ch->reliable_mq = GNUNET_MESH_mq_create (ch->channel_reliable);
953   ch->cid = line->cid_gen++;
954   ch->target = msg->source;
955   *channel_ctx = ch;
956   cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
957   cring.header.size = htons (sizeof (cring));
958   cring.cid = ch->cid;
959   cring.caller_id = msg->caller_id;
960   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
961               "Sending RING message to client. CID %u:(%u, %u)\n", 
962               ch->cid, ch->remote_line, line->local_line);
963   GNUNET_SERVER_notification_context_unicast (nc,
964                                               line->client,
965                                               &cring.header,
966                                               GNUNET_NO);
967   GNUNET_MESH_receive_done (channel);
968   return GNUNET_OK;
969 }
970
971
972 /**
973  * Function to handle a hangup message incoming over mesh
974  *
975  * @param cls closure, NULL
976  * @param channel the channel over which the message arrived
977  * @param channel_ctx the channel context, can be NULL
978  *                    or point to the `struct Channel`
979  * @param message the incoming message
980  * @return #GNUNET_OK
981  */
982 static int
983 handle_mesh_hangup_message (void *cls,
984                             struct GNUNET_MESH_Channel *channel,
985                             void **channel_ctx,
986                             const struct GNUNET_MessageHeader *message)
987 {
988   struct Channel *ch = *channel_ctx;
989   struct Line *line;
990   struct ClientPhoneHangupMessage hup;
991   enum ChannelStatus status;
992
993   if (NULL == ch)
994   {
995     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
996                 "HANGUP message received for non-existing line, dropping channel.\n");
997     return GNUNET_SYSERR;
998   }
999   line = ch->line;
1000   *channel_ctx = NULL;
1001   hup.header.size = htons (sizeof (hup));
1002   hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1003   hup.cid = ch->cid;
1004   status = ch->status;
1005   GNUNET_MESH_receive_done (channel);
1006   destroy_line_mesh_channels (ch);
1007   switch (status)
1008   {
1009   case CS_CALLEE_RINGING:
1010   case CS_CALLEE_CONNECTED:
1011     break;
1012   case CS_CALLEE_SHUTDOWN:
1013     return GNUNET_OK;
1014   case CS_CALLER_CALLING:
1015   case CS_CALLER_CONNECTED:
1016     break;
1017   case CS_CALLER_SHUTDOWN:
1018     return GNUNET_OK;
1019   }
1020   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1021               "Sending HANG UP message to client\n");
1022   GNUNET_SERVER_notification_context_unicast (nc,
1023                                               line->client,
1024                                               &hup.header,
1025                                               GNUNET_NO);
1026   return GNUNET_OK;
1027 }
1028
1029
1030 /**
1031  * Function to handle a pickup message incoming over mesh
1032  *
1033  * @param cls closure, NULL
1034  * @param channel the channel over which the message arrived
1035  * @param channel_ctx the channel context, can be NULL
1036  *                    or point to the `struct Channel`
1037  * @param message the incoming message
1038  * @return #GNUNET_OK
1039  */
1040 static int
1041 handle_mesh_pickup_message (void *cls,
1042                             struct GNUNET_MESH_Channel *channel,
1043                             void **channel_ctx,
1044                             const struct GNUNET_MessageHeader *message)
1045 {
1046   struct Channel *ch = *channel_ctx;
1047   struct Line *line;
1048   struct ClientPhonePickupMessage pick;
1049
1050   if (NULL == ch)
1051   {
1052     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1053                 "PICKUP message received for non-existing channel, dropping channel.\n");
1054     return GNUNET_SYSERR;
1055   }
1056   line = ch->line;
1057   GNUNET_MESH_receive_done (channel);
1058   switch (ch->status)
1059   {
1060   case CS_CALLEE_RINGING:
1061   case CS_CALLEE_CONNECTED:
1062     GNUNET_break_op (0);
1063     destroy_line_mesh_channels (ch);
1064     return GNUNET_SYSERR;
1065   case CS_CALLEE_SHUTDOWN:
1066     GNUNET_break_op (0);
1067     destroy_line_mesh_channels (ch);
1068     break;
1069   case CS_CALLER_CALLING:
1070     ch->status = CS_CALLER_CONNECTED;
1071     break;
1072   case CS_CALLER_CONNECTED:
1073     GNUNET_break_op (0);
1074     return GNUNET_OK;
1075   case CS_CALLER_SHUTDOWN:
1076     GNUNET_break_op (0);
1077     mq_done_finish_caller_shutdown (ch);
1078     return GNUNET_SYSERR;
1079   }
1080   pick.header.size = htons (sizeof (pick));
1081   pick.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
1082   pick.cid = ch->cid;
1083   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1084               "Sending PICKED UP message to client\n");
1085   GNUNET_SERVER_notification_context_unicast (nc,
1086                                               line->client,
1087                                               &pick.header,
1088                                               GNUNET_NO);
1089   ch->channel_unreliable = GNUNET_MESH_channel_create (mesh,
1090                                                        ch,
1091                                                        &ch->target,
1092                                                        GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1093                                                        GNUNET_MESH_OPTION_DEFAULT);
1094   if (NULL == ch->channel_unreliable)
1095   {
1096     GNUNET_break (0);
1097   }
1098   return GNUNET_OK;
1099 }
1100
1101
1102 /**
1103  * Function to handle a suspend message incoming over mesh
1104  *
1105  * @param cls closure, NULL
1106  * @param channel the channel over which the message arrived
1107  * @param channel_ctx the channel context, can be NULL
1108  *                    or point to the `struct Channel`
1109  * @param message the incoming message
1110  * @return #GNUNET_OK
1111  */
1112 static int
1113 handle_mesh_suspend_message (void *cls,
1114                              struct GNUNET_MESH_Channel *channel,
1115                              void **channel_ctx,
1116                              const struct GNUNET_MessageHeader *message)
1117 {
1118   struct Channel *ch = *channel_ctx;
1119   struct Line *line;
1120   struct ClientPhoneSuspendMessage suspend;
1121
1122   if (NULL == ch)
1123   {
1124     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125                 "SUSPEND message received for non-existing line, dropping channel.\n");
1126     return GNUNET_SYSERR;
1127   }
1128   line = ch->line;
1129   suspend.header.size = htons (sizeof (suspend));
1130   suspend.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
1131   suspend.cid = ch->cid;
1132   GNUNET_MESH_receive_done (channel);
1133   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1134               "Suspending channel CID: %u(%u:%u)\n",
1135               ch->cid, ch->remote_line, line->local_line);
1136   switch (ch->status)
1137   {
1138   case CS_CALLEE_RINGING:
1139     GNUNET_break_op (0);
1140     break;
1141   case CS_CALLEE_CONNECTED:
1142     ch->suspended_remote = GNUNET_YES;
1143     break;
1144   case CS_CALLEE_SHUTDOWN:
1145     return GNUNET_OK;
1146   case CS_CALLER_CALLING:
1147     GNUNET_break_op (0);
1148     break;
1149   case CS_CALLER_CONNECTED:
1150     ch->suspended_remote = GNUNET_YES;
1151     break;
1152   case CS_CALLER_SHUTDOWN:
1153     return GNUNET_OK;
1154   }
1155   GNUNET_SERVER_notification_context_unicast (nc,
1156                                               line->client,
1157                                               &suspend.header,
1158                                               GNUNET_NO);
1159   return GNUNET_OK;
1160 }
1161
1162
1163 /**
1164  * Function to handle a resume message incoming over mesh
1165  *
1166  * @param cls closure, NULL
1167  * @param channel the channel over which the message arrived
1168  * @param channel_ctx the channel context, can be NULL
1169  *                    or point to the `struct Channel`
1170  * @param message the incoming message
1171  * @return #GNUNET_OK
1172  */
1173 static int
1174 handle_mesh_resume_message (void *cls,
1175                              struct GNUNET_MESH_Channel *channel,
1176                              void **channel_ctx,
1177                              const struct GNUNET_MessageHeader *message)
1178 {
1179   struct Channel *ch = *channel_ctx;
1180   struct Line *line;
1181   struct ClientPhoneResumeMessage resume;
1182
1183   if (NULL == ch)
1184   {
1185     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1186                 "RESUME message received for non-existing line, dropping channel.\n");
1187     return GNUNET_SYSERR;
1188   }
1189   line = ch->line;
1190   resume.header.size = htons (sizeof (resume));
1191   resume.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
1192   resume.cid = ch->cid;
1193   GNUNET_MESH_receive_done (channel);
1194   if (GNUNET_YES != ch->suspended_remote)
1195   {
1196     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1197                 "RESUME message received for non-suspended channel, dropping channel.\n");
1198     return GNUNET_SYSERR;
1199   }
1200   switch (ch->status)
1201   {
1202   case CS_CALLEE_RINGING:
1203     GNUNET_break (0);
1204     break;
1205   case CS_CALLEE_CONNECTED:
1206     ch->suspended_remote = GNUNET_NO;
1207     break;
1208   case CS_CALLEE_SHUTDOWN:
1209     return GNUNET_OK;
1210   case CS_CALLER_CALLING:
1211     GNUNET_break (0);
1212     break;
1213   case CS_CALLER_CONNECTED:
1214     ch->suspended_remote = GNUNET_NO;
1215     break;
1216   case CS_CALLER_SHUTDOWN:
1217     return GNUNET_OK;
1218   }
1219   GNUNET_SERVER_notification_context_unicast (nc,
1220                                               line->client,
1221                                               &resume.header,
1222                                               GNUNET_NO);
1223   return GNUNET_OK;
1224 }
1225
1226
1227 /**
1228  * Function to handle an audio message incoming over mesh
1229  *
1230  * @param cls closure, NULL
1231  * @param channel the channel over which the message arrived
1232  * @param channel_ctx the channel context, can be NULL
1233  *                    or point to the `struct Channel`
1234  * @param message the incoming message
1235  * @return #GNUNET_OK
1236  */
1237 static int
1238 handle_mesh_audio_message (void *cls,
1239                            struct GNUNET_MESH_Channel *channel,
1240                            void **channel_ctx,
1241                            const struct GNUNET_MessageHeader *message)
1242 {
1243   const struct MeshAudioMessage *msg;
1244   struct Channel *ch = *channel_ctx;
1245   struct Line *line;
1246   struct GNUNET_PeerIdentity sender;
1247   size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
1248   char buf[msize + sizeof (struct ClientAudioMessage)];
1249   struct ClientAudioMessage *cam;
1250   const union GNUNET_MESH_ChannelInfo *info;
1251
1252   msg = (const struct MeshAudioMessage *) message;
1253   if (NULL == ch)
1254   {
1255     info = GNUNET_MESH_channel_get_info (channel,
1256                                          GNUNET_MESH_OPTION_PEER);
1257     if (NULL == info)
1258     {
1259       GNUNET_break (0);
1260       return GNUNET_OK;
1261     }
1262     sender = info->peer;
1263     for (line = lines_head; NULL != line; line = line->next)
1264       if (line->local_line == ntohl (msg->remote_line))
1265       {
1266         for (ch = line->channel_head; NULL != ch; ch = ch->next)
1267         {
1268           if ( (CS_CALLEE_CONNECTED == ch->status) &&
1269                (0 == memcmp (&ch->target,
1270                              &sender,
1271                              sizeof (struct GNUNET_PeerIdentity))) &&
1272                (NULL == ch->channel_unreliable) &&
1273                (ch->remote_line == ntohl (msg->source_line)) )
1274             break;
1275         }
1276         break;
1277       }
1278     if (NULL == line)
1279     {
1280       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1281                   "Received %u bytes of AUDIO data for non-existing line %u, dropping.\n",
1282                   msize, ntohl (msg->remote_line));
1283       return GNUNET_SYSERR;
1284     }
1285     if (NULL == ch)
1286     {
1287       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1288                   "Received %u bytes of AUDIO data for unknown sender.\n",
1289                   msize);
1290       return GNUNET_SYSERR;
1291     }
1292     if ((GNUNET_YES == ch->suspended_local) || (GNUNET_YES == ch->suspended_remote))
1293     {
1294       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1295                   "Received %u bytes of AUDIO data on suspended channel CID %u:(%u:%u); dropping\n",
1296                   msize, ch->cid, ch->remote_line, line->local_line);
1297       return GNUNET_OK;
1298     }
1299     ch->channel_unreliable = channel;
1300     *channel_ctx = ch;
1301   }
1302   GNUNET_break (ch->line->local_line == ntohl (msg->remote_line));
1303   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1304               "Forwarding %u bytes of AUDIO data to client CID %u:(%u:%u)\n",
1305               msize, ch->cid, ch->remote_line, ch->line->local_line);
1306   cam = (struct ClientAudioMessage *) buf;
1307   cam->header.size = htons (sizeof (buf));
1308   cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1309   cam->cid = ch->cid;
1310   memcpy (&cam[1], &msg[1], msize);
1311   GNUNET_SERVER_notification_context_unicast (nc,
1312                                               ch->line->client,
1313                                               &cam->header,
1314                                               GNUNET_YES);
1315   GNUNET_MESH_receive_done (channel);
1316   return GNUNET_OK;
1317 }
1318
1319
1320 /**
1321  * Method called whenever another peer has added us to a channel
1322  * the other peer initiated.
1323  *
1324  * @param cls closure
1325  * @param channel new handle to the channel
1326  * @param initiator peer that started the channel
1327  * @param port port
1328  * @param options channel option flags
1329  * @return initial channel context for the channel;
1330  *         (can be NULL -- that's not an error)
1331  */
1332 static void *
1333 inbound_channel (void *cls,
1334                 struct GNUNET_MESH_Channel *channel,
1335                 const struct GNUNET_PeerIdentity *initiator,
1336                 uint32_t port, enum GNUNET_MESH_ChannelOption options)
1337 {
1338   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1339               _("Received incoming channel on port %u\n"),
1340               (unsigned int) port);
1341   return NULL;
1342 }
1343
1344
1345 /**
1346  * Function called whenever an inbound channel is destroyed.  Should clean up
1347  * any associated state.
1348  *
1349  * @param cls closure (set from #GNUNET_MESH_connect)
1350  * @param channel connection to the other end (henceforth invalid)
1351  * @param channel_ctx place where local state associated
1352  *                   with the channel is stored;
1353  *                   may point to the `struct Channel`
1354  */
1355 static void
1356 inbound_end (void *cls,
1357              const struct GNUNET_MESH_Channel *channel,
1358              void *channel_ctx)
1359 {
1360   struct Channel *ch = channel_ctx;
1361   struct Line *line;
1362   struct ClientPhoneHangupMessage hup;
1363
1364   if (NULL == ch)
1365   {
1366     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1367                 "Mesh channel destroyed, but channel is unknown to us\n");
1368     return;
1369   }
1370   line = ch->line;
1371   if (ch->channel_unreliable == channel)
1372   {
1373     if (NULL != ch->unreliable_mth)
1374     {
1375       GNUNET_MESH_notify_transmit_ready_cancel (ch->unreliable_mth);
1376       ch->unreliable_mth = NULL;
1377     }
1378     ch->channel_unreliable = NULL;
1379     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1380                 "Unreliable channel destroyed\n");
1381     return;
1382   }
1383   if (ch->channel_reliable != channel)
1384   {
1385     /* recursive call, I'm the one destroying 'ch' right now */
1386     return;
1387   }
1388   ch->channel_reliable = NULL;
1389
1390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1391               "Mesh channel destroyed by mesh in state %d\n",
1392               ch->status);
1393   hup.header.size = htons (sizeof (hup));
1394   hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1395   hup.cid = ch->cid;
1396   switch (ch->status)
1397   {
1398   case CS_CALLEE_RINGING:
1399   case CS_CALLEE_CONNECTED:
1400     GNUNET_SERVER_notification_context_unicast (nc,
1401                                                 line->client,
1402                                                 &hup.header,
1403                                                 GNUNET_NO);
1404     break;
1405   case CS_CALLEE_SHUTDOWN:
1406     break;
1407   case CS_CALLER_CALLING:
1408   case CS_CALLER_CONNECTED:
1409     GNUNET_SERVER_notification_context_unicast (nc,
1410                                                 line->client,
1411                                                 &hup.header,
1412                                                 GNUNET_NO);
1413     break;
1414   case CS_CALLER_SHUTDOWN:
1415     break;
1416   }
1417   destroy_line_mesh_channels (ch);
1418 }
1419
1420
1421 /**
1422  * A client disconnected.  Remove all of its data structure entries.
1423  *
1424  * @param cls closure, NULL
1425  * @param client identification of the client
1426  */
1427 static void
1428 handle_client_disconnect (void *cls,
1429                           struct GNUNET_SERVER_Client *client)
1430 {
1431   struct Line *line;
1432
1433   if (NULL == client)
1434     return;
1435   line = GNUNET_SERVER_client_get_user_context (client, struct Line);
1436   if (NULL == line)
1437     return;
1438   GNUNET_SERVER_client_set_user_context (client, (void *)NULL);
1439   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1440               "Client disconnected, closing line\n");
1441   GNUNET_CONTAINER_DLL_remove (lines_head,
1442                                lines_tail,
1443                                line);
1444   while (NULL != line->channel_head)
1445     destroy_line_mesh_channels (line->channel_head);
1446   GNUNET_free (line);
1447 }
1448
1449
1450 /**
1451  * Shutdown nicely
1452  *
1453  * @param cls closure, NULL
1454  * @param tc the task context
1455  */
1456 static void
1457 do_shutdown (void *cls,
1458              const struct GNUNET_SCHEDULER_TaskContext *tc)
1459 {
1460   struct Line *line;
1461   struct Channel *ch;
1462
1463   while (NULL != (line = lines_head))
1464   {
1465     while (NULL != (ch = line->channel_head))
1466       destroy_line_mesh_channels (ch);
1467     GNUNET_CONTAINER_DLL_remove (lines_head,
1468                                  lines_tail,
1469                                  line);
1470     GNUNET_SERVER_client_set_user_context (line->client, (void *) NULL);
1471     GNUNET_free (line);
1472   }
1473   if (NULL != mesh)
1474   {
1475     GNUNET_MESH_disconnect (mesh);
1476     mesh = NULL;
1477   }
1478   if (NULL != nc)
1479   {
1480     GNUNET_SERVER_notification_context_destroy (nc);
1481     nc = NULL;
1482   }
1483 }
1484
1485
1486 /**
1487  * Main function that will be run by the scheduler.
1488  *
1489  * @param cls closure
1490  * @param server server handle
1491  * @param c configuration
1492  */
1493 static void
1494 run (void *cls,
1495      struct GNUNET_SERVER_Handle *server,
1496      const struct GNUNET_CONFIGURATION_Handle *c)
1497 {
1498   static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1499     {&handle_client_register_message, NULL,
1500      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1501      sizeof (struct ClientPhoneRegisterMessage)},
1502     {&handle_client_pickup_message, NULL,
1503      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1504      sizeof (struct ClientPhonePickupMessage) },
1505     {&handle_client_suspend_message, NULL,
1506      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1507      sizeof (struct ClientPhoneSuspendMessage) },
1508     {&handle_client_resume_message, NULL,
1509      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1510      sizeof (struct ClientPhoneResumeMessage) },
1511     {&handle_client_hangup_message, NULL,
1512      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1513      sizeof (struct ClientPhoneHangupMessage) },
1514     {&handle_client_call_message, NULL,
1515      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1516      sizeof (struct ClientCallMessage) },
1517     {&handle_client_audio_message, NULL,
1518      GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1519      0},
1520     {NULL, NULL, 0, 0}
1521   };
1522   static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1523     {&handle_mesh_ring_message,
1524      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
1525      sizeof (struct MeshPhoneRingMessage)},
1526     {&handle_mesh_hangup_message,
1527      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
1528      sizeof (struct MeshPhoneHangupMessage)},
1529     {&handle_mesh_pickup_message,
1530      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
1531      sizeof (struct MeshPhonePickupMessage)},
1532     {&handle_mesh_suspend_message,
1533      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_SUSPEND,
1534      sizeof (struct MeshPhoneSuspendMessage)},
1535     {&handle_mesh_resume_message,
1536      GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RESUME,
1537      sizeof (struct MeshPhoneResumeMessage)},
1538     {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
1539      0},
1540     {NULL, 0, 0}
1541   };
1542   static uint32_t ports[] = {
1543     GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
1544     GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1545     0
1546   };
1547
1548   cfg = c;
1549   GNUNET_assert (GNUNET_OK ==
1550                  GNUNET_CRYPTO_get_peer_identity (cfg,
1551                                                   &my_identity));
1552   mesh = GNUNET_MESH_connect (cfg,
1553                               NULL,
1554                               &inbound_channel,
1555                               &inbound_end,
1556                               mesh_handlers,
1557                               ports);
1558
1559   if (NULL == mesh)
1560   {
1561     GNUNET_break (0);
1562     GNUNET_SCHEDULER_shutdown ();
1563     return;
1564   }
1565   nc = GNUNET_SERVER_notification_context_create (server, 16);
1566   GNUNET_SERVER_add_handlers (server, server_handlers);
1567   GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1568   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1569                                 &do_shutdown,
1570                                 NULL);
1571 }
1572
1573
1574 /**
1575  * The main function for the conversation service.
1576  *
1577  * @param argc number of arguments from the command line
1578  * @param argv command line arguments
1579  * @return 0 ok, 1 on error
1580  */
1581 int
1582 main (int argc,
1583       char *const *argv)
1584 {
1585   return (GNUNET_OK ==
1586           GNUNET_SERVICE_run (argc, argv,
1587                               "conversation",
1588                               GNUNET_SERVICE_OPTION_NONE,
1589                               &run, NULL)) ? 0 : 1;
1590 }
1591
1592 /* end of gnunet-service-conversation.c */