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