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