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