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