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