Use Suffix Extensions in Makefiles (doc, src/{arm,dht,integration,statistics}) for...
[oweals/gnunet.git] / src / conversation / gnunet-service-conversation.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2013, 2016, 2017 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_SERVICE_Client *client;
176
177   /**
178    * Message queue for @e client.
179    */
180   struct GNUNET_MQ_Handle *mq;
181
182   /**
183    * Our open port.
184    */
185   struct GNUNET_CADET_Port *port;
186
187   /**
188    * Port number we are listening on (to verify signatures).
189    * Only valid if @e port is non-NULL.
190    */
191   struct GNUNET_HashCode line_port;
192
193   /**
194    * Generator for channel IDs.
195    */
196   uint32_t cid_gen;
197
198 };
199
200
201 /**
202  * Our configuration.
203  */
204 static const struct GNUNET_CONFIGURATION_Handle *cfg;
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   for (struct Channel *ch = line->channel_head;
230        NULL != ch;
231        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 the `struct Line` of the client from which the message is
242  * @param msg the message from the client
243  */
244 static void
245 handle_client_pickup_message (void *cls,
246                               const struct ClientPhonePickupMessage *msg)
247 {
248   struct Line *line = cls;
249   struct CadetPhonePickupMessage *mppm;
250   struct GNUNET_MQ_Envelope *env;
251   struct Channel *ch;
252
253   if (NULL == line->port)
254   {
255     /* we never opened the port, bad client! */
256     GNUNET_break_op (0);
257     GNUNET_SERVICE_client_drop (line->client);
258     return;
259   }
260   for (ch = line->channel_head; NULL != ch; ch = ch->next)
261     if (msg->cid == ch->cid)
262       break;
263   if (NULL == ch)
264   {
265     /* could have been destroyed asynchronously, ignore message */
266     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
267                 "Channel %u not found\n",
268                 msg->cid);
269     GNUNET_SERVICE_client_continue (line->client);
270     return;
271   }
272   switch (ch->status)
273   {
274   case CS_CALLEE_INIT:
275     GNUNET_break (0);
276     GNUNET_SERVICE_client_drop (line->client);
277     return;
278   case CS_CALLEE_RINGING:
279     ch->status = CS_CALLEE_CONNECTED;
280     break;
281   case CS_CALLEE_CONNECTED:
282     GNUNET_break (0);
283     GNUNET_SERVICE_client_drop (line->client);
284     return;
285   case CS_CALLEE_SHUTDOWN:
286     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
287                 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
288     break;
289   case CS_CALLER_CALLING:
290   case CS_CALLER_CONNECTED:
291   case CS_CALLER_SHUTDOWN:
292     GNUNET_break (0);
293     GNUNET_SERVICE_client_drop (line->client);
294     return;
295   }
296   GNUNET_break (CS_CALLEE_CONNECTED == ch->status);
297   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
298               "Sending PICK_UP message to cadet\n");
299   env = GNUNET_MQ_msg (mppm,
300                        GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP);
301   GNUNET_MQ_send (ch->mq,
302                   env);
303   GNUNET_SERVICE_client_continue (line->client);
304 }
305
306
307 /**
308  * Destroy a channel.
309  *
310  * @param ch channel to destroy.
311  */
312 static void
313 destroy_line_cadet_channels (struct Channel *ch)
314 {
315   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316               "Destroying cadet channels\n");
317   if (NULL != ch->channel)
318     GNUNET_CADET_channel_destroy (ch->channel);
319 }
320
321
322 /**
323  * We are done signalling shutdown to the other peer.  Close down
324  * the channel.
325  *
326  * @param cls the `struct Channel` to reset/terminate
327  */
328 static void
329 mq_done_finish_caller_shutdown (void *cls)
330 {
331   struct Channel *ch = cls;
332
333   switch (ch->status)
334   {
335   case CS_CALLEE_INIT:
336     GNUNET_break (0);
337     break;
338   case CS_CALLEE_RINGING:
339     GNUNET_break (0);
340     break;
341   case CS_CALLEE_CONNECTED:
342     GNUNET_break (0);
343     break;
344   case CS_CALLEE_SHUTDOWN:
345     destroy_line_cadet_channels (ch);
346     break;
347   case CS_CALLER_CALLING:
348     GNUNET_break (0);
349     break;
350   case CS_CALLER_CONNECTED:
351     GNUNET_break (0);
352     break;
353   case CS_CALLER_SHUTDOWN:
354     destroy_line_cadet_channels (ch);
355     break;
356   }
357 }
358
359
360 /**
361  * Function to handle a hangup request message from the client
362  *
363  * @param cls the `struct Line` the hangup is for
364  * @param msg the message from the client
365  */
366 static void
367 handle_client_hangup_message (void *cls,
368                               const struct ClientPhoneHangupMessage *msg)
369 {
370   struct Line *line = cls;
371   struct GNUNET_MQ_Envelope *e;
372   struct CadetPhoneHangupMessage *mhum;
373   struct Channel *ch;
374
375   for (ch = line->channel_head; NULL != ch; ch = ch->next)
376     if (msg->cid == ch->cid)
377       break;
378   if (NULL == ch)
379   {
380     /* could have been destroyed asynchronously, ignore message */
381     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
382                 "Channel %u not found\n",
383                 msg->cid);
384     GNUNET_SERVICE_client_continue (line->client);
385     return;
386   }
387   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
388               "Received HANGUP for channel %u which is in state %d\n",
389               msg->cid,
390               ch->status);
391   switch (ch->status)
392   {
393   case CS_CALLEE_INIT:
394     GNUNET_break (0);
395     GNUNET_SERVICE_client_drop (line->client);
396     return;
397   case CS_CALLEE_RINGING:
398     ch->status = CS_CALLEE_SHUTDOWN;
399     break;
400   case CS_CALLEE_CONNECTED:
401     ch->status = CS_CALLEE_SHUTDOWN;
402     break;
403   case CS_CALLEE_SHUTDOWN:
404     /* maybe the other peer closed asynchronously... */
405     GNUNET_SERVICE_client_continue (line->client);
406     return;
407   case CS_CALLER_CALLING:
408     ch->status = CS_CALLER_SHUTDOWN;
409     break;
410   case CS_CALLER_CONNECTED:
411     ch->status = CS_CALLER_SHUTDOWN;
412     break;
413   case CS_CALLER_SHUTDOWN:
414     /* maybe the other peer closed asynchronously... */
415     GNUNET_SERVICE_client_continue (line->client);
416     return;
417   }
418   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
419               "Sending HANG_UP message via cadet\n");
420   e = GNUNET_MQ_msg (mhum,
421                      GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP);
422   GNUNET_MQ_notify_sent (e,
423                          &mq_done_finish_caller_shutdown,
424                          ch);
425   GNUNET_MQ_send (ch->mq,
426                   e);
427   GNUNET_SERVICE_client_continue (line->client);
428 }
429
430
431 /**
432  * Function to handle a suspend request message from the client
433  *
434  * @param cls the `struct Line` the message is about
435  * @param msg the message from the client
436  */
437 static void
438 handle_client_suspend_message (void *cls,
439                                const struct ClientPhoneSuspendMessage *msg)
440 {
441   struct Line *line = cls;
442   struct GNUNET_MQ_Envelope *e;
443   struct CadetPhoneSuspendMessage *mhum;
444   struct Channel *ch;
445
446   for (ch = line->channel_head; NULL != ch; ch = ch->next)
447     if (msg->cid == ch->cid)
448       break;
449   if (NULL == ch)
450   {
451     /* could have been destroyed asynchronously, ignore message */
452     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
453                 "Channel %u not found\n",
454                 msg->cid);
455     GNUNET_SERVICE_client_continue (line->client);
456     return;
457   }
458   if (GNUNET_YES == ch->suspended_local)
459   {
460     GNUNET_break (0);
461     GNUNET_SERVICE_client_drop (line->client);
462     return;
463   }
464   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
465               "Received SUSPEND for channel %u which is in state %d\n",
466               msg->cid,
467               ch->status);
468   switch (ch->status)
469   {
470   case CS_CALLEE_INIT:
471     GNUNET_break (0);
472     GNUNET_SERVICE_client_drop (line->client);
473     return;
474   case CS_CALLEE_RINGING:
475     GNUNET_break (0);
476     GNUNET_SERVICE_client_drop (line->client);
477     return;
478   case CS_CALLEE_CONNECTED:
479     ch->suspended_local = GNUNET_YES;
480     break;
481   case CS_CALLEE_SHUTDOWN:
482     /* maybe the other peer closed asynchronously... */
483     GNUNET_SERVICE_client_continue (line->client);
484     return;
485   case CS_CALLER_CALLING:
486     GNUNET_break (0);
487     GNUNET_SERVICE_client_drop (line->client);
488     return;
489   case CS_CALLER_CONNECTED:
490     ch->suspended_local = GNUNET_YES;
491     break;
492   case CS_CALLER_SHUTDOWN:
493     /* maybe the other peer closed asynchronously... */
494     GNUNET_SERVICE_client_continue (line->client);
495     return;
496   }
497   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498               "Sending SUSPEND message via cadet\n");
499   e = GNUNET_MQ_msg (mhum,
500                      GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND);
501   GNUNET_MQ_send (ch->mq,
502                   e);
503   GNUNET_SERVICE_client_continue (line->client);
504 }
505
506
507 /**
508  * Function to handle a resume request message from the client
509  *
510  * @param cls the `struct Line` the message is about
511  * @param msg the message from the client
512  */
513 static void
514 handle_client_resume_message (void *cls,
515                               const struct ClientPhoneResumeMessage *msg)
516 {
517   struct Line *line = cls;
518   struct GNUNET_MQ_Envelope *e;
519   struct CadetPhoneResumeMessage *mhum;
520   struct Channel *ch;
521
522   for (ch = line->channel_head; NULL != ch; ch = ch->next)
523     if (msg->cid == ch->cid)
524       break;
525   if (NULL == ch)
526   {
527     /* could have been destroyed asynchronously, ignore message */
528     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529                 "Channel %u not found\n",
530                 msg->cid);
531     GNUNET_SERVICE_client_continue (line->client);
532     return;
533   }
534   if (GNUNET_YES != ch->suspended_local)
535   {
536     GNUNET_break (0);
537     GNUNET_SERVICE_client_drop (line->client);
538     return;
539   }
540   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541               "Received RESUME for channel %u which is in state %d\n",
542               msg->cid,
543               ch->status);
544   switch (ch->status)
545   {
546   case CS_CALLEE_INIT:
547     GNUNET_break (0);
548     GNUNET_SERVICE_client_drop (line->client);
549     return;
550   case CS_CALLEE_RINGING:
551     GNUNET_break (0);
552     GNUNET_SERVICE_client_drop (line->client);
553     return;
554   case CS_CALLEE_CONNECTED:
555     ch->suspended_local = GNUNET_NO;
556     break;
557   case CS_CALLEE_SHUTDOWN:
558     /* maybe the other peer closed asynchronously... */
559     GNUNET_SERVICE_client_continue (line->client);
560     return;
561   case CS_CALLER_CALLING:
562     GNUNET_break (0);
563     GNUNET_SERVICE_client_drop (line->client);
564     return;
565   case CS_CALLER_CONNECTED:
566     ch->suspended_local = GNUNET_NO;
567     break;
568   case CS_CALLER_SHUTDOWN:
569     /* maybe the other peer closed asynchronously... */
570     GNUNET_SERVICE_client_drop (line->client);
571     return;
572   }
573   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574               "Sending RESUME message via cadet\n");
575   e = GNUNET_MQ_msg (mhum,
576                      GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME);
577   GNUNET_MQ_send (ch->mq,
578                   e);
579   GNUNET_SERVICE_client_continue (line->client);
580 }
581
582
583 /**
584  * Transmission of audio data via cadet channel finished.
585  *
586  * @param cls the `struct Channel` we are transmitting for
587  */
588 static void
589 channel_audio_sent_notify (void *cls)
590 {
591   struct Channel *ch = cls;
592
593   ch->env = NULL;
594 }
595
596
597 /**
598  * Function to check audio data from the client
599  *
600  * @param cls the `struct Line` the message is about
601  * @param msg the message from the client
602  * @return #GNUNET_OK (any data is ok)
603  */
604 static int
605 check_client_audio_message (void *cls,
606                             const struct ClientAudioMessage *msg)
607 {
608   return GNUNET_OK;
609 }
610
611
612 /**
613  * Function to handle audio data from the client
614  *
615  * @param cls the `struct Line` the message is about
616  * @param msg the message from the client
617  */
618 static void
619 handle_client_audio_message (void *cls,
620                              const struct ClientAudioMessage *msg)
621 {
622   struct Line *line = cls;
623   struct CadetAudioMessage *mam;
624   struct Channel *ch;
625   size_t size;
626
627   size = ntohs (msg->header.size) - sizeof (struct ClientAudioMessage);
628   ch = find_channel_by_line (line,
629                              msg->cid);
630   if (NULL == ch)
631   {
632     /* could have been destroyed asynchronously, ignore message */
633     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634                 "Channel %u not found\n",
635                 msg->cid);
636     GNUNET_SERVICE_client_continue (line->client);
637     return;
638   }
639
640   switch (ch->status)
641   {
642   case CS_CALLEE_INIT:
643   case CS_CALLEE_RINGING:
644   case CS_CALLER_CALLING:
645     GNUNET_break (0);
646     GNUNET_SERVICE_client_drop (line->client);
647     return;
648   case CS_CALLEE_CONNECTED:
649   case CS_CALLER_CONNECTED:
650     /* common case, handled below */
651     break;
652   case CS_CALLEE_SHUTDOWN:
653   case CS_CALLER_SHUTDOWN:
654     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
655                 "Cadet audio channel in shutdown; audio data dropped\n");
656     GNUNET_SERVICE_client_continue (line->client);
657     return;
658   }
659   if (GNUNET_YES == ch->suspended_local)
660   {
661     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
662                 "This channel is suspended locally\n");
663     GNUNET_SERVICE_client_drop (line->client);
664     return;
665   }
666   if (NULL != ch->env)
667   {
668     /* NOTE: we may want to not do this and instead combine the data */
669     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
670                 "Bandwidth insufficient; dropping previous audio data segment\n");
671     GNUNET_MQ_send_cancel (ch->env);
672     ch->env = NULL;
673   }
674
675   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
676               "Received %u bytes of AUDIO data from client CID %u\n",
677               (unsigned int) size,
678               msg->cid);
679   ch->env = GNUNET_MQ_msg_extra (mam,
680                                  size,
681                                  GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
682   GNUNET_memcpy (&mam[1],
683                  &msg[1],
684                  size);
685   /* FIXME: set options for unreliable transmission */
686   GNUNET_MQ_notify_sent (ch->env,
687                          &channel_audio_sent_notify,
688                          ch);
689   GNUNET_MQ_send (ch->mq,
690                   ch->env);
691   GNUNET_SERVICE_client_continue (line->client);
692 }
693
694
695 /**
696  * Function to handle a ring message incoming over cadet
697  *
698  * @param cls closure, NULL
699  * @param msg the incoming message
700  */
701 static void
702 handle_cadet_ring_message (void *cls,
703                            const struct CadetPhoneRingMessage *msg)
704 {
705   struct Channel *ch = cls;
706   struct Line *line = ch->line;
707   struct GNUNET_MQ_Envelope *env;
708   struct ClientPhoneRingMessage *cring;
709   struct CadetPhoneRingInfoPS rs;
710
711   rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
712   rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
713   rs.line_port = line->line_port;
714   rs.target_peer = my_identity;
715   rs.expiration_time = msg->expiration_time;
716
717   if (GNUNET_OK !=
718       GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
719                                   &rs.purpose,
720                                   &msg->signature,
721                                   &msg->caller_id))
722   {
723     GNUNET_break_op (0);
724     destroy_line_cadet_channels (ch);
725     return;
726   }
727   if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (msg->expiration_time)).rel_value_us)
728   {
729     /* ancient call, replay? */
730     GNUNET_break_op (0);
731     /* Note that our reliance on time here is awkward; better would be
732        to use a more complex challenge-response protocol against
733        replay attacks.  Left for future work ;-). */
734     destroy_line_cadet_channels (ch);
735     return;
736   }
737   if (CS_CALLEE_INIT != ch->status)
738   {
739     GNUNET_break_op (0);
740     destroy_line_cadet_channels (ch);
741     return;
742   }
743   GNUNET_CADET_receive_done (ch->channel);
744   ch->status = CS_CALLEE_RINGING;
745   env = GNUNET_MQ_msg (cring,
746                        GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
747   cring->cid = ch->cid;
748   cring->caller_id = msg->caller_id;
749   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
750               "Sending RING message to client. CID is %u\n",
751               (unsigned int) ch->cid);
752   GNUNET_MQ_send (line->mq,
753                   env);
754 }
755
756
757 /**
758  * Function to handle a hangup message incoming over cadet
759  *
760  * @param cls closure, our `struct Channel *`
761  * @param message the incoming message
762  */
763 static void
764 handle_cadet_hangup_message (void *cls,
765                              const struct CadetPhoneHangupMessage *message)
766 {
767   struct Channel *ch = cls;
768   struct Line *line = ch->line;
769   struct GNUNET_MQ_Envelope *env;
770   struct ClientPhoneHangupMessage *hup;
771   enum ChannelStatus status;
772   uint32_t cid;
773
774   GNUNET_CADET_receive_done (ch->channel);
775   cid = ch->cid;
776   status = ch->status;
777   destroy_line_cadet_channels (ch);
778   switch (status)
779   {
780   case CS_CALLEE_INIT:
781     GNUNET_break_op (0);
782     return;
783   case CS_CALLEE_RINGING:
784   case CS_CALLEE_CONNECTED:
785     break;
786   case CS_CALLEE_SHUTDOWN:
787     return;
788   case CS_CALLER_CALLING:
789   case CS_CALLER_CONNECTED:
790     break;
791   case CS_CALLER_SHUTDOWN:
792     return;
793   }
794   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
795               "Sending HANG UP message to client\n");
796   env = GNUNET_MQ_msg (hup,
797                        GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
798   hup->cid = cid;
799   GNUNET_MQ_send (line->mq,
800                   env);
801 }
802
803
804 /**
805  * Function to handle a pickup message incoming over cadet
806  *
807  * @param cls closure, our `struct Channel *`
808  * @param message the incoming message
809  */
810 static void
811 handle_cadet_pickup_message (void *cls,
812                              const struct CadetPhonePickupMessage *message)
813 {
814   struct Channel *ch = cls;
815   struct Line *line = ch->line;
816   struct GNUNET_MQ_Envelope *env;
817   struct ClientPhonePickedupMessage *pick;
818
819   GNUNET_CADET_receive_done (ch->channel);
820   switch (ch->status)
821   {
822   case CS_CALLEE_INIT:
823   case CS_CALLEE_RINGING:
824   case CS_CALLEE_CONNECTED:
825     GNUNET_break_op (0);
826     destroy_line_cadet_channels (ch);
827     return;
828   case CS_CALLEE_SHUTDOWN:
829     GNUNET_break_op (0);
830     destroy_line_cadet_channels (ch);
831     return;
832   case CS_CALLER_CALLING:
833     ch->status = CS_CALLER_CONNECTED;
834     break;
835   case CS_CALLER_CONNECTED:
836     GNUNET_break_op (0);
837     return;
838   case CS_CALLER_SHUTDOWN:
839     GNUNET_break_op (0);
840     mq_done_finish_caller_shutdown (ch);
841     return;
842   }
843   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
844               "Sending PICKED UP message to client\n");
845   env = GNUNET_MQ_msg (pick,
846                        GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
847   pick->cid = ch->cid;
848   GNUNET_MQ_send (line->mq,
849                   env);
850 }
851
852
853 /**
854  * Function to handle a suspend message incoming over cadet
855  *
856  * @param cls closure, our `struct Channel *`
857  * @param message the incoming message
858  */
859 static void
860 handle_cadet_suspend_message (void *cls,
861                               const struct CadetPhoneSuspendMessage *message)
862 {
863   struct Channel *ch = cls;
864   struct Line *line = ch->line;
865   struct GNUNET_MQ_Envelope *env;
866   struct ClientPhoneSuspendMessage *suspend;
867
868   GNUNET_CADET_receive_done (ch->channel);
869   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
870               "Suspending channel CID: %u\n",
871               ch->cid);
872   switch (ch->status)
873   {
874   case CS_CALLEE_INIT:
875     GNUNET_break_op (0);
876     break;
877   case CS_CALLEE_RINGING:
878     GNUNET_break_op (0);
879     break;
880   case CS_CALLEE_CONNECTED:
881     ch->suspended_remote = GNUNET_YES;
882     break;
883   case CS_CALLEE_SHUTDOWN:
884     return;
885   case CS_CALLER_CALLING:
886     GNUNET_break_op (0);
887     break;
888   case CS_CALLER_CONNECTED:
889     ch->suspended_remote = GNUNET_YES;
890     break;
891   case CS_CALLER_SHUTDOWN:
892     return;
893   }
894   env = GNUNET_MQ_msg (suspend,
895                        GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
896   suspend->cid = ch->cid;
897   GNUNET_MQ_send (line->mq,
898                   env);
899 }
900
901
902 /**
903  * Function to handle a resume message incoming over cadet
904  *
905  * @param cls closure, our `struct Channel *`
906  * @param msg the incoming message
907  */
908 static void
909 handle_cadet_resume_message (void *cls,
910                              const struct CadetPhoneResumeMessage *msg)
911 {
912   struct Channel *ch = cls;
913   struct Line *line;
914   struct GNUNET_MQ_Envelope *env;
915   struct ClientPhoneResumeMessage *resume;
916
917   line = ch->line;
918   GNUNET_CADET_receive_done (ch->channel);
919   if (GNUNET_YES != ch->suspended_remote)
920   {
921     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
922                 "RESUME message received for non-suspended channel, dropping channel.\n");
923     destroy_line_cadet_channels (ch);
924     return;
925   }
926   switch (ch->status)
927   {
928   case CS_CALLEE_INIT:
929     GNUNET_break (0);
930     break;
931   case CS_CALLEE_RINGING:
932     GNUNET_break (0);
933     break;
934   case CS_CALLEE_CONNECTED:
935     ch->suspended_remote = GNUNET_NO;
936     break;
937   case CS_CALLEE_SHUTDOWN:
938     return;
939   case CS_CALLER_CALLING:
940     GNUNET_break (0);
941     break;
942   case CS_CALLER_CONNECTED:
943     ch->suspended_remote = GNUNET_NO;
944     break;
945   case CS_CALLER_SHUTDOWN:
946     return;
947   }
948   env = GNUNET_MQ_msg (resume,
949                        GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
950   resume->cid = ch->cid;
951   GNUNET_MQ_send (line->mq,
952                   env);
953 }
954
955
956 /**
957  * Function to check an audio message incoming over cadet
958  *
959  * @param cls closure, our `struct Channel *`
960  * @param msg the incoming message
961  * @return #GNUNET_OK (always)
962  */
963 static int
964 check_cadet_audio_message (void *cls,
965                            const struct CadetAudioMessage *msg)
966 {
967   return GNUNET_OK; /* any payload is fine */
968 }
969
970
971 /**
972  * Function to handle an audio message incoming over cadet
973  *
974  * @param cls closure, our `struct Channel *`
975  * @param msg the incoming message
976  */
977 static void
978 handle_cadet_audio_message (void *cls,
979                             const struct CadetAudioMessage *msg)
980 {
981   struct Channel *ch = cls;
982   size_t msize = ntohs (msg->header.size) - sizeof (struct CadetAudioMessage);
983   struct GNUNET_MQ_Envelope *env;
984   struct ClientAudioMessage *cam;
985
986   GNUNET_CADET_receive_done (ch->channel);
987   if ( (GNUNET_YES == ch->suspended_local) ||
988        (GNUNET_YES == ch->suspended_remote) )
989   {
990     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991                 "Received %u bytes of AUDIO data on suspended channel CID %u; dropping\n",
992                 (unsigned int) msize,
993                 ch->cid);
994     return;
995   }
996   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
997               "Forwarding %u bytes of AUDIO data to client CID %u\n",
998               (unsigned int) msize,
999               ch->cid);
1000   env = GNUNET_MQ_msg_extra (cam,
1001                              msize,
1002                              GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1003   cam->cid = ch->cid;
1004   GNUNET_memcpy (&cam[1],
1005                  &msg[1],
1006                  msize);
1007   GNUNET_MQ_send (ch->line->mq,
1008                   env);
1009 }
1010
1011
1012 /**
1013  * Function called whenever an inbound channel is destroyed.  Should clean up
1014  * any associated state.
1015  *
1016  * @param cls closure (set from #GNUNET_CADET_connect)
1017  * @param channel connection to the other end (henceforth invalid)
1018  */
1019 static void
1020 inbound_end (void *cls,
1021              const struct GNUNET_CADET_Channel *channel)
1022 {
1023   struct Channel *ch = cls;
1024   struct Line *line = ch->line;
1025   struct GNUNET_MQ_Envelope *env;
1026   struct ClientPhoneHangupMessage *hup;
1027
1028   GNUNET_assert (channel == ch->channel);
1029   ch->channel = NULL;
1030   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1031               "Channel destroyed by CADET in state %d\n",
1032               ch->status);
1033   switch (ch->status)
1034   {
1035   case CS_CALLEE_INIT:
1036   case CS_CALLEE_SHUTDOWN:
1037   case CS_CALLER_SHUTDOWN:
1038     break;
1039   case CS_CALLEE_RINGING:
1040   case CS_CALLEE_CONNECTED:
1041   case CS_CALLER_CALLING:
1042   case CS_CALLER_CONNECTED:
1043     if (NULL != line)
1044     {
1045       env = GNUNET_MQ_msg (hup,
1046                            GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1047       hup->cid = ch->cid;
1048       GNUNET_MQ_send (line->mq,
1049                       env);
1050     }
1051     break;
1052   }
1053   if (NULL != line)
1054     GNUNET_CONTAINER_DLL_remove (line->channel_head,
1055                                  line->channel_tail,
1056                                  ch);
1057   GNUNET_free (ch);
1058 }
1059
1060
1061 /**
1062  * Function to handle call request from the client
1063  *
1064  * @param cls the `struct Line` the message is about
1065  * @param msg the message from the client
1066  */
1067 static void
1068 handle_client_call_message (void *cls,
1069                             const struct ClientCallMessage *msg)
1070 {
1071   struct Line *line = cls;
1072   struct Channel *ch = GNUNET_new (struct Channel);
1073   struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1074     GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1075                              GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1076                              struct CadetPhoneHangupMessage,
1077                              ch),
1078     GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1079                              GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1080                              struct CadetPhonePickupMessage,
1081                              ch),
1082     GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1083                              GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1084                              struct CadetPhoneSuspendMessage,
1085                              ch),
1086     GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1087                              GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1088                              struct CadetPhoneResumeMessage,
1089                              ch),
1090     GNUNET_MQ_hd_var_size (cadet_audio_message,
1091                            GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1092                            struct CadetAudioMessage,
1093                            ch),
1094     GNUNET_MQ_handler_end ()
1095   };
1096   struct GNUNET_MQ_Envelope *e;
1097   struct CadetPhoneRingMessage *ring;
1098   struct CadetPhoneRingInfoPS rs;
1099
1100   line->line_port = msg->line_port;
1101   rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
1102   rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
1103   rs.line_port = line->line_port;
1104   rs.target_peer = msg->target;
1105   rs.expiration_time
1106     = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
1107   ch->line = line;
1108   GNUNET_CONTAINER_DLL_insert (line->channel_head,
1109                                line->channel_tail,
1110                                ch);
1111   ch->status = CS_CALLER_CALLING;
1112   ch->channel = GNUNET_CADET_channel_create (cadet,
1113                                              ch,
1114                                              &msg->target,
1115                                              &msg->line_port,
1116                                              GNUNET_CADET_OPTION_RELIABLE,
1117                                              NULL,
1118                                              &inbound_end,
1119                                              cadet_handlers);
1120   ch->mq = GNUNET_CADET_get_mq (ch->channel);
1121   e = GNUNET_MQ_msg (ring,
1122                      GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
1123   GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
1124                                       &ring->caller_id);
1125   ring->expiration_time = rs.expiration_time;
1126   GNUNET_assert (GNUNET_OK ==
1127                  GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
1128                                            &rs.purpose,
1129                                            &ring->signature));
1130   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131               "Sending RING message via CADET\n");
1132   GNUNET_MQ_send (ch->mq,
1133                   e);
1134   GNUNET_SERVICE_client_continue (line->client);
1135 }
1136
1137
1138 /**
1139  * Method called whenever another peer has added us to a channel
1140  * the other peer initiated.
1141  *
1142  * @param cls the `struct Line` receiving a connection
1143  * @param channel new handle to the channel
1144  * @param initiator peer that started the channel
1145  * @return initial channel context for the channel
1146  */
1147 static void *
1148 inbound_channel (void *cls,
1149                  struct GNUNET_CADET_Channel *channel,
1150                  const struct GNUNET_PeerIdentity *initiator)
1151 {
1152   struct Line *line = cls;
1153   struct Channel *ch;
1154
1155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1156               "Received incoming cadet channel on line %p\n",
1157               line);
1158   ch = GNUNET_new (struct Channel);
1159   ch->status = CS_CALLEE_INIT;
1160   ch->line = line;
1161   ch->channel = channel;
1162   ch->mq = GNUNET_CADET_get_mq (ch->channel);
1163   ch->cid = line->cid_gen++;
1164   GNUNET_CONTAINER_DLL_insert (line->channel_head,
1165                                line->channel_tail,
1166                                ch);
1167   return ch;
1168 }
1169
1170
1171 /**
1172  * A client connected.  Initialize the `struct Line` data structure.
1173  *
1174  * @param cls closure, NULL
1175  * @param client identification of the client
1176  * @param mq message queue for @a client
1177  * @return the `struct Line` for the client
1178  */
1179 static void *
1180 client_connect_cb (void *cls,
1181                    struct GNUNET_SERVICE_Client *client,
1182                    struct GNUNET_MQ_Handle *mq)
1183 {
1184   struct Line *line;
1185
1186   line = GNUNET_new (struct Line);
1187   line->client = client;
1188   line->mq = mq;
1189   return line;
1190 }
1191
1192
1193 /**
1194  * A client disconnected.  Remove all of its data structure entries.
1195  *
1196  * @param cls closure, NULL
1197  * @param client identification of the client
1198  * @param app_ctx our `struct Line *` for @a client
1199  */
1200 static void
1201 client_disconnect_cb (void *cls,
1202                       struct GNUNET_SERVICE_Client *client,
1203                       void *app_ctx)
1204 {
1205   struct Line *line = app_ctx;
1206   struct Channel *ch;
1207   struct Channel *chn;
1208
1209   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1210               "Client disconnected, closing line\n");
1211   if (NULL != line->port)
1212   {
1213     GNUNET_CADET_close_port (line->port);
1214     line->port = NULL;
1215   }
1216   for (ch = line->channel_head; NULL != ch; ch = chn)
1217   {
1218     chn = ch->next;
1219     ch->line = NULL;
1220     destroy_line_cadet_channels (ch);
1221   }
1222   GNUNET_free (line);
1223 }
1224
1225
1226 /**
1227  * Function to register a phone.
1228  *
1229  * @param cls the `struct Line` of the client from which the message is
1230  * @param msg the message from the client
1231  */
1232 static void
1233 handle_client_register_message (void *cls,
1234                                 const struct ClientPhoneRegisterMessage *msg)
1235 {
1236   struct Line *line = cls;
1237   struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
1238     GNUNET_MQ_hd_fixed_size (cadet_ring_message,
1239                              GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING,
1240                              struct CadetPhoneRingMessage,
1241                              NULL),
1242     GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1243                              GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1244                              struct CadetPhoneHangupMessage,
1245                              NULL),
1246     GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1247                              GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1248                              struct CadetPhonePickupMessage,
1249                              NULL),
1250     GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1251                              GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1252                              struct CadetPhoneSuspendMessage,
1253                              NULL),
1254     GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1255                              GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1256                              struct CadetPhoneResumeMessage,
1257                              NULL),
1258     GNUNET_MQ_hd_var_size (cadet_audio_message,
1259                            GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1260                            struct CadetAudioMessage,
1261                            NULL),
1262     GNUNET_MQ_handler_end ()
1263   };
1264
1265   line->line_port = msg->line_port;
1266   line->port = GNUNET_CADET_open_port (cadet,
1267                                        &msg->line_port,
1268                                        &inbound_channel,
1269                                        line,
1270                                        NULL,
1271                                        &inbound_end,
1272                                        cadet_handlers);
1273   if (NULL == line->port)
1274   {
1275     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1276                 _("Could not open line, port %s already in use!\n"),
1277                 GNUNET_h2s (&msg->line_port));
1278     GNUNET_SERVICE_client_drop (line->client);
1279     return;
1280   }
1281   GNUNET_SERVICE_client_continue (line->client);
1282 }
1283
1284
1285 /**
1286  * Shutdown nicely
1287  *
1288  * @param cls closure, NULL
1289  */
1290 static void
1291 do_shutdown (void *cls)
1292 {
1293   if (NULL != cadet)
1294   {
1295     GNUNET_CADET_disconnect (cadet);
1296     cadet = NULL;
1297   }
1298 }
1299
1300
1301 /**
1302  * Main function that will be run by the scheduler.
1303  *
1304  * @param cls closure
1305  * @param c configuration
1306  * @param service service handle
1307  */
1308 static void
1309 run (void *cls,
1310      const struct GNUNET_CONFIGURATION_Handle *c,
1311      struct GNUNET_SERVICE_Handle *service)
1312 {
1313   cfg = c;
1314   GNUNET_assert (GNUNET_OK ==
1315                  GNUNET_CRYPTO_get_peer_identity (cfg,
1316                                                   &my_identity));
1317   cadet = GNUNET_CADET_connect (cfg);
1318   if (NULL == cadet)
1319   {
1320     GNUNET_break (0);
1321     GNUNET_SCHEDULER_shutdown ();
1322     return;
1323   }
1324   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1325                                  NULL);
1326 }
1327
1328
1329 /**
1330  * Define "main" method using service macro.
1331  */
1332 GNUNET_SERVICE_MAIN
1333 ("conversation",
1334  GNUNET_SERVICE_OPTION_NONE,
1335  &run,
1336  &client_connect_cb,
1337  &client_disconnect_cb,
1338  NULL,
1339  GNUNET_MQ_hd_fixed_size (client_register_message,
1340                           GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1341                           struct ClientPhoneRegisterMessage,
1342                           NULL),
1343  GNUNET_MQ_hd_fixed_size (client_pickup_message,
1344                           GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1345                           struct ClientPhonePickupMessage,
1346                           NULL),
1347  GNUNET_MQ_hd_fixed_size (client_suspend_message,
1348                           GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1349                           struct ClientPhoneSuspendMessage,
1350                           NULL),
1351  GNUNET_MQ_hd_fixed_size (client_resume_message,
1352                           GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1353                           struct ClientPhoneResumeMessage,
1354                           NULL),
1355  GNUNET_MQ_hd_fixed_size (client_hangup_message,
1356                           GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1357                           struct ClientPhoneHangupMessage,
1358                           NULL),
1359  GNUNET_MQ_hd_fixed_size (client_call_message,
1360                           GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1361                           struct ClientCallMessage,
1362                           NULL),
1363  GNUNET_MQ_hd_var_size (client_audio_message,
1364                         GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1365                         struct ClientAudioMessage,
1366                         NULL),
1367  GNUNET_MQ_handler_end ());
1368
1369
1370 /* end of gnunet-service-conversation.c */