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