2 This file is part of GNUnet.
3 Copyright (C) 2013, 2016, 2017 GNUnet e.V.
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.
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.
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.
21 * @file conversation/gnunet-service-conversation.c
22 * @brief conversation service implementation
23 * @author Simon Dieterle
24 * @author Andreas Fuchs
25 * @author Christian Grothoff
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"
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.
43 #define RING_TIMEOUT GNUNET_TIME_UNIT_DAYS
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).
53 * The possible connection status
58 * We just got the connection, but no introduction yet.
63 * Our phone is ringing, waiting for the client to pick up.
73 * We're in shutdown, sending hangup messages before cleaning up.
78 * We are waiting for the phone to be picked up.
88 * We're in shutdown, sending hangup messages before cleaning up.
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.
107 struct Channel *next;
112 struct Channel *prev;
115 * Line associated with the channel.
120 * Handle for the channel.
122 struct GNUNET_CADET_Channel *channel;
125 * Message queue for control messages
127 struct GNUNET_MQ_Handle *mq;
130 * Temporary buffer for audio data in the @e mq.
132 struct GNUNET_MQ_Envelope *env;
135 * Channel identifier we use for this call with the client.
140 * Current status of this line.
142 enum ChannelStatus status;
145 * #GNUNET_YES if the channel was suspended by the other peer.
147 int8_t suspended_remote;
150 * #GNUNET_YES if the channel was suspended by the local client.
152 int8_t suspended_local;
158 * A `struct Line` connects a local client with cadet channels.
165 struct Channel *channel_head;
170 struct Channel *channel_tail;
173 * Handle to the line client.
175 struct GNUNET_SERVICE_Client *client;
178 * Message queue for @e client.
180 struct GNUNET_MQ_Handle *mq;
185 struct GNUNET_CADET_Port *port;
188 * Port number we are listening on (to verify signatures).
189 * Only valid if @e port is non-NULL.
191 struct GNUNET_HashCode line_port;
194 * Generator for channel IDs.
204 static const struct GNUNET_CONFIGURATION_Handle *cfg;
209 static struct GNUNET_CADET_Handle *cadet;
212 * Identity of this peer.
214 static struct GNUNET_PeerIdentity my_identity;
218 * Given a @a cid, find the corresponding channel given
221 * @param line a line to search
222 * @param cid what to search for
223 * @return NULL for not found
225 static struct Channel *
226 find_channel_by_line (struct Line *line,
229 for (struct Channel *ch = line->channel_head;
239 * Function to handle a pickup request message from the client
241 * @param cls the `struct Line` of the client from which the message is
242 * @param msg the message from the client
245 handle_client_pickup_message (void *cls,
246 const struct ClientPhonePickupMessage *msg)
248 struct Line *line = cls;
249 struct CadetPhonePickupMessage *mppm;
250 struct GNUNET_MQ_Envelope *env;
253 if (NULL == line->port)
255 /* we never opened the port, bad client! */
257 GNUNET_SERVICE_client_drop (line->client);
260 for (ch = line->channel_head; NULL != ch; ch = ch->next)
261 if (msg->cid == ch->cid)
265 /* could have been destroyed asynchronously, ignore message */
266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
267 "Channel %u not found\n",
269 GNUNET_SERVICE_client_continue (line->client);
276 GNUNET_SERVICE_client_drop (line->client);
278 case CS_CALLEE_RINGING:
279 ch->status = CS_CALLEE_CONNECTED;
281 case CS_CALLEE_CONNECTED:
283 GNUNET_SERVICE_client_drop (line->client);
285 case CS_CALLEE_SHUTDOWN:
286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
287 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
289 case CS_CALLER_CALLING:
290 case CS_CALLER_CONNECTED:
291 case CS_CALLER_SHUTDOWN:
293 GNUNET_SERVICE_client_drop (line->client);
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,
303 GNUNET_SERVICE_client_continue (line->client);
310 * @param ch channel to destroy.
313 destroy_line_cadet_channels (struct Channel *ch)
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Destroying cadet channels\n");
317 if (NULL != ch->channel)
318 GNUNET_CADET_channel_destroy (ch->channel);
323 * We are done signalling shutdown to the other peer. Close down
326 * @param cls the `struct Channel` to reset/terminate
329 mq_done_finish_caller_shutdown (void *cls)
331 struct Channel *ch = cls;
338 case CS_CALLEE_RINGING:
341 case CS_CALLEE_CONNECTED:
344 case CS_CALLEE_SHUTDOWN:
345 destroy_line_cadet_channels (ch);
347 case CS_CALLER_CALLING:
350 case CS_CALLER_CONNECTED:
353 case CS_CALLER_SHUTDOWN:
354 destroy_line_cadet_channels (ch);
361 * Function to handle a hangup request message from the client
363 * @param cls the `struct Line` the hangup is for
364 * @param msg the message from the client
367 handle_client_hangup_message (void *cls,
368 const struct ClientPhoneHangupMessage *msg)
370 struct Line *line = cls;
371 struct GNUNET_MQ_Envelope *e;
372 struct CadetPhoneHangupMessage *mhum;
375 for (ch = line->channel_head; NULL != ch; ch = ch->next)
376 if (msg->cid == ch->cid)
380 /* could have been destroyed asynchronously, ignore message */
381 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
382 "Channel %u not found\n",
384 GNUNET_SERVICE_client_continue (line->client);
387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
388 "Received HANGUP for channel %u which is in state %d\n",
395 GNUNET_SERVICE_client_drop (line->client);
397 case CS_CALLEE_RINGING:
398 ch->status = CS_CALLEE_SHUTDOWN;
400 case CS_CALLEE_CONNECTED:
401 ch->status = CS_CALLEE_SHUTDOWN;
403 case CS_CALLEE_SHUTDOWN:
404 /* maybe the other peer closed asynchronously... */
405 GNUNET_SERVICE_client_continue (line->client);
407 case CS_CALLER_CALLING:
408 ch->status = CS_CALLER_SHUTDOWN;
410 case CS_CALLER_CONNECTED:
411 ch->status = CS_CALLER_SHUTDOWN;
413 case CS_CALLER_SHUTDOWN:
414 /* maybe the other peer closed asynchronously... */
415 GNUNET_SERVICE_client_continue (line->client);
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,
425 GNUNET_MQ_send (ch->mq,
427 GNUNET_SERVICE_client_continue (line->client);
432 * Function to handle a suspend request message from the client
434 * @param cls the `struct Line` the message is about
435 * @param msg the message from the client
438 handle_client_suspend_message (void *cls,
439 const struct ClientPhoneSuspendMessage *msg)
441 struct Line *line = cls;
442 struct GNUNET_MQ_Envelope *e;
443 struct CadetPhoneSuspendMessage *mhum;
446 for (ch = line->channel_head; NULL != ch; ch = ch->next)
447 if (msg->cid == ch->cid)
451 /* could have been destroyed asynchronously, ignore message */
452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
453 "Channel %u not found\n",
455 GNUNET_SERVICE_client_continue (line->client);
458 if (GNUNET_YES == ch->suspended_local)
461 GNUNET_SERVICE_client_drop (line->client);
464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
465 "Received SUSPEND for channel %u which is in state %d\n",
472 GNUNET_SERVICE_client_drop (line->client);
474 case CS_CALLEE_RINGING:
476 GNUNET_SERVICE_client_drop (line->client);
478 case CS_CALLEE_CONNECTED:
479 ch->suspended_local = GNUNET_YES;
481 case CS_CALLEE_SHUTDOWN:
482 /* maybe the other peer closed asynchronously... */
483 GNUNET_SERVICE_client_continue (line->client);
485 case CS_CALLER_CALLING:
487 GNUNET_SERVICE_client_drop (line->client);
489 case CS_CALLER_CONNECTED:
490 ch->suspended_local = GNUNET_YES;
492 case CS_CALLER_SHUTDOWN:
493 /* maybe the other peer closed asynchronously... */
494 GNUNET_SERVICE_client_continue (line->client);
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,
503 GNUNET_SERVICE_client_continue (line->client);
508 * Function to handle a resume request message from the client
510 * @param cls the `struct Line` the message is about
511 * @param msg the message from the client
514 handle_client_resume_message (void *cls,
515 const struct ClientPhoneResumeMessage *msg)
517 struct Line *line = cls;
518 struct GNUNET_MQ_Envelope *e;
519 struct CadetPhoneResumeMessage *mhum;
522 for (ch = line->channel_head; NULL != ch; ch = ch->next)
523 if (msg->cid == ch->cid)
527 /* could have been destroyed asynchronously, ignore message */
528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529 "Channel %u not found\n",
531 GNUNET_SERVICE_client_continue (line->client);
534 if (GNUNET_YES != ch->suspended_local)
537 GNUNET_SERVICE_client_drop (line->client);
540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541 "Received RESUME for channel %u which is in state %d\n",
548 GNUNET_SERVICE_client_drop (line->client);
550 case CS_CALLEE_RINGING:
552 GNUNET_SERVICE_client_drop (line->client);
554 case CS_CALLEE_CONNECTED:
555 ch->suspended_local = GNUNET_NO;
557 case CS_CALLEE_SHUTDOWN:
558 /* maybe the other peer closed asynchronously... */
559 GNUNET_SERVICE_client_continue (line->client);
561 case CS_CALLER_CALLING:
563 GNUNET_SERVICE_client_drop (line->client);
565 case CS_CALLER_CONNECTED:
566 ch->suspended_local = GNUNET_NO;
568 case CS_CALLER_SHUTDOWN:
569 /* maybe the other peer closed asynchronously... */
570 GNUNET_SERVICE_client_drop (line->client);
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,
579 GNUNET_SERVICE_client_continue (line->client);
584 * Transmission of audio data via cadet channel finished.
586 * @param cls the `struct Channel` we are transmitting for
589 channel_audio_sent_notify (void *cls)
591 struct Channel *ch = cls;
598 * Function to check audio data from the client
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)
605 check_client_audio_message (void *cls,
606 const struct ClientAudioMessage *msg)
613 * Function to handle audio data from the client
615 * @param cls the `struct Line` the message is about
616 * @param msg the message from the client
619 handle_client_audio_message (void *cls,
620 const struct ClientAudioMessage *msg)
622 struct Line *line = cls;
623 struct CadetAudioMessage *mam;
627 size = ntohs (msg->header.size) - sizeof (struct ClientAudioMessage);
628 ch = find_channel_by_line (line,
632 /* could have been destroyed asynchronously, ignore message */
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "Channel %u not found\n",
636 GNUNET_SERVICE_client_continue (line->client);
643 case CS_CALLEE_RINGING:
644 case CS_CALLER_CALLING:
646 GNUNET_SERVICE_client_drop (line->client);
648 case CS_CALLEE_CONNECTED:
649 case CS_CALLER_CONNECTED:
650 /* common case, handled below */
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);
659 if (GNUNET_YES == ch->suspended_local)
661 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
662 "This channel is suspended locally\n");
663 GNUNET_SERVICE_client_drop (line->client);
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);
675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
676 "Received %u bytes of AUDIO data from client CID %u\n",
679 ch->env = GNUNET_MQ_msg_extra (mam,
681 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
682 GNUNET_memcpy (&mam[1],
685 /* FIXME: set options for unreliable transmission */
686 GNUNET_MQ_notify_sent (ch->env,
687 &channel_audio_sent_notify,
689 GNUNET_MQ_send (ch->mq,
691 GNUNET_SERVICE_client_continue (line->client);
696 * Function to handle a ring message incoming over cadet
698 * @param cls closure, NULL
699 * @param msg the incoming message
702 handle_cadet_ring_message (void *cls,
703 const struct CadetPhoneRingMessage *msg)
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;
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;
718 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
724 destroy_line_cadet_channels (ch);
727 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (msg->expiration_time)).rel_value_us)
729 /* ancient call, replay? */
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);
737 if (CS_CALLEE_INIT != ch->status)
740 destroy_line_cadet_channels (ch);
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,
758 * Function to handle a hangup message incoming over cadet
760 * @param cls closure, our `struct Channel *`
761 * @param message the incoming message
764 handle_cadet_hangup_message (void *cls,
765 const struct CadetPhoneHangupMessage *message)
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;
774 GNUNET_CADET_receive_done (ch->channel);
777 destroy_line_cadet_channels (ch);
783 case CS_CALLEE_RINGING:
784 case CS_CALLEE_CONNECTED:
786 case CS_CALLEE_SHUTDOWN:
788 case CS_CALLER_CALLING:
789 case CS_CALLER_CONNECTED:
791 case CS_CALLER_SHUTDOWN:
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);
799 GNUNET_MQ_send (line->mq,
805 * Function to handle a pickup message incoming over cadet
807 * @param cls closure, our `struct Channel *`
808 * @param message the incoming message
811 handle_cadet_pickup_message (void *cls,
812 const struct CadetPhonePickupMessage *message)
814 struct Channel *ch = cls;
815 struct Line *line = ch->line;
816 struct GNUNET_MQ_Envelope *env;
817 struct ClientPhonePickedupMessage *pick;
819 GNUNET_CADET_receive_done (ch->channel);
823 case CS_CALLEE_RINGING:
824 case CS_CALLEE_CONNECTED:
826 destroy_line_cadet_channels (ch);
828 case CS_CALLEE_SHUTDOWN:
830 destroy_line_cadet_channels (ch);
832 case CS_CALLER_CALLING:
833 ch->status = CS_CALLER_CONNECTED;
835 case CS_CALLER_CONNECTED:
838 case CS_CALLER_SHUTDOWN:
840 mq_done_finish_caller_shutdown (ch);
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);
848 GNUNET_MQ_send (line->mq,
854 * Function to handle a suspend message incoming over cadet
856 * @param cls closure, our `struct Channel *`
857 * @param message the incoming message
860 handle_cadet_suspend_message (void *cls,
861 const struct CadetPhoneSuspendMessage *message)
863 struct Channel *ch = cls;
864 struct Line *line = ch->line;
865 struct GNUNET_MQ_Envelope *env;
866 struct ClientPhoneSuspendMessage *suspend;
868 GNUNET_CADET_receive_done (ch->channel);
869 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
870 "Suspending channel CID: %u\n",
877 case CS_CALLEE_RINGING:
880 case CS_CALLEE_CONNECTED:
881 ch->suspended_remote = GNUNET_YES;
883 case CS_CALLEE_SHUTDOWN:
885 case CS_CALLER_CALLING:
888 case CS_CALLER_CONNECTED:
889 ch->suspended_remote = GNUNET_YES;
891 case CS_CALLER_SHUTDOWN:
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,
903 * Function to handle a resume message incoming over cadet
905 * @param cls closure, our `struct Channel *`
906 * @param msg the incoming message
909 handle_cadet_resume_message (void *cls,
910 const struct CadetPhoneResumeMessage *msg)
912 struct Channel *ch = cls;
914 struct GNUNET_MQ_Envelope *env;
915 struct ClientPhoneResumeMessage *resume;
918 GNUNET_CADET_receive_done (ch->channel);
919 if (GNUNET_YES != ch->suspended_remote)
921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
922 "RESUME message received for non-suspended channel, dropping channel.\n");
923 destroy_line_cadet_channels (ch);
931 case CS_CALLEE_RINGING:
934 case CS_CALLEE_CONNECTED:
935 ch->suspended_remote = GNUNET_NO;
937 case CS_CALLEE_SHUTDOWN:
939 case CS_CALLER_CALLING:
942 case CS_CALLER_CONNECTED:
943 ch->suspended_remote = GNUNET_NO;
945 case CS_CALLER_SHUTDOWN:
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,
957 * Function to check an audio message incoming over cadet
959 * @param cls closure, our `struct Channel *`
960 * @param msg the incoming message
961 * @return #GNUNET_OK (always)
964 check_cadet_audio_message (void *cls,
965 const struct CadetAudioMessage *msg)
967 return GNUNET_OK; /* any payload is fine */
972 * Function to handle an audio message incoming over cadet
974 * @param cls closure, our `struct Channel *`
975 * @param msg the incoming message
978 handle_cadet_audio_message (void *cls,
979 const struct CadetAudioMessage *msg)
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;
986 GNUNET_CADET_receive_done (ch->channel);
987 if ( (GNUNET_YES == ch->suspended_local) ||
988 (GNUNET_YES == ch->suspended_remote) )
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,
996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
997 "Forwarding %u bytes of AUDIO data to client CID %u\n",
998 (unsigned int) msize,
1000 env = GNUNET_MQ_msg_extra (cam,
1002 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1004 GNUNET_memcpy (&cam[1],
1007 GNUNET_MQ_send (ch->line->mq,
1013 * Function called whenever an inbound channel is destroyed. Should clean up
1014 * any associated state.
1016 * @param cls closure (set from #GNUNET_CADET_connect)
1017 * @param channel connection to the other end (henceforth invalid)
1020 inbound_end (void *cls,
1021 const struct GNUNET_CADET_Channel *channel)
1023 struct Channel *ch = cls;
1024 struct Line *line = ch->line;
1025 struct GNUNET_MQ_Envelope *env;
1026 struct ClientPhoneHangupMessage *hup;
1028 GNUNET_assert (channel == ch->channel);
1030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1031 "Channel destroyed by CADET in state %d\n",
1035 case CS_CALLEE_INIT:
1036 case CS_CALLEE_SHUTDOWN:
1037 case CS_CALLER_SHUTDOWN:
1039 case CS_CALLEE_RINGING:
1040 case CS_CALLEE_CONNECTED:
1041 case CS_CALLER_CALLING:
1042 case CS_CALLER_CONNECTED:
1045 env = GNUNET_MQ_msg (hup,
1046 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1048 GNUNET_MQ_send (line->mq,
1054 GNUNET_CONTAINER_DLL_remove (line->channel_head,
1062 * Function to handle call request from the client
1064 * @param cls the `struct Line` the message is about
1065 * @param msg the message from the client
1068 handle_client_call_message (void *cls,
1069 const struct ClientCallMessage *msg)
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,
1078 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1079 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1080 struct CadetPhonePickupMessage,
1082 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1083 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1084 struct CadetPhoneSuspendMessage,
1086 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1087 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1088 struct CadetPhoneResumeMessage,
1090 GNUNET_MQ_hd_var_size (cadet_audio_message,
1091 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1092 struct CadetAudioMessage,
1094 GNUNET_MQ_handler_end ()
1096 struct GNUNET_MQ_Envelope *e;
1097 struct CadetPhoneRingMessage *ring;
1098 struct CadetPhoneRingInfoPS rs;
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;
1106 = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
1108 GNUNET_CONTAINER_DLL_insert (line->channel_head,
1111 ch->status = CS_CALLER_CALLING;
1112 ch->channel = GNUNET_CADET_channel_create (cadet,
1116 GNUNET_CADET_OPTION_RELIABLE,
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,
1125 ring->expiration_time = rs.expiration_time;
1126 GNUNET_assert (GNUNET_OK ==
1127 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
1130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131 "Sending RING message via CADET\n");
1132 GNUNET_MQ_send (ch->mq,
1134 GNUNET_SERVICE_client_continue (line->client);
1139 * Method called whenever another peer has added us to a channel
1140 * the other peer initiated.
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
1148 inbound_channel (void *cls,
1149 struct GNUNET_CADET_Channel *channel,
1150 const struct GNUNET_PeerIdentity *initiator)
1152 struct Line *line = cls;
1155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1156 "Received incoming cadet channel on line %p\n",
1158 ch = GNUNET_new (struct Channel);
1159 ch->status = CS_CALLEE_INIT;
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,
1172 * A client connected. Initialize the `struct Line` data structure.
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
1180 client_connect_cb (void *cls,
1181 struct GNUNET_SERVICE_Client *client,
1182 struct GNUNET_MQ_Handle *mq)
1186 line = GNUNET_new (struct Line);
1187 line->client = client;
1194 * A client disconnected. Remove all of its data structure entries.
1196 * @param cls closure, NULL
1197 * @param client identification of the client
1198 * @param app_ctx our `struct Line *` for @a client
1201 client_disconnect_cb (void *cls,
1202 struct GNUNET_SERVICE_Client *client,
1205 struct Line *line = app_ctx;
1207 struct Channel *chn;
1209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1210 "Client disconnected, closing line\n");
1211 if (NULL != line->port)
1213 GNUNET_CADET_close_port (line->port);
1216 for (ch = line->channel_head; NULL != ch; ch = chn)
1220 destroy_line_cadet_channels (ch);
1227 * Function to register a phone.
1229 * @param cls the `struct Line` of the client from which the message is
1230 * @param msg the message from the client
1233 handle_client_register_message (void *cls,
1234 const struct ClientPhoneRegisterMessage *msg)
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,
1242 GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1243 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1244 struct CadetPhoneHangupMessage,
1246 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1247 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1248 struct CadetPhonePickupMessage,
1250 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1251 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1252 struct CadetPhoneSuspendMessage,
1254 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1255 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1256 struct CadetPhoneResumeMessage,
1258 GNUNET_MQ_hd_var_size (cadet_audio_message,
1259 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1260 struct CadetAudioMessage,
1262 GNUNET_MQ_handler_end ()
1265 line->line_port = msg->line_port;
1266 line->port = GNUNET_CADET_open_port (cadet,
1273 if (NULL == line->port)
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);
1281 GNUNET_SERVICE_client_continue (line->client);
1288 * @param cls closure, NULL
1291 do_shutdown (void *cls)
1295 GNUNET_CADET_disconnect (cadet);
1302 * Main function that will be run by the scheduler.
1304 * @param cls closure
1305 * @param c configuration
1306 * @param service service handle
1310 const struct GNUNET_CONFIGURATION_Handle *c,
1311 struct GNUNET_SERVICE_Handle *service)
1314 GNUNET_assert (GNUNET_OK ==
1315 GNUNET_CRYPTO_get_peer_identity (cfg,
1317 cadet = GNUNET_CADET_connect (cfg);
1321 GNUNET_SCHEDULER_shutdown ();
1324 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1330 * Define "main" method using service macro.
1334 GNUNET_SERVICE_OPTION_NONE,
1337 &client_disconnect_cb,
1339 GNUNET_MQ_hd_fixed_size (client_register_message,
1340 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1341 struct ClientPhoneRegisterMessage,
1343 GNUNET_MQ_hd_fixed_size (client_pickup_message,
1344 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1345 struct ClientPhonePickupMessage,
1347 GNUNET_MQ_hd_fixed_size (client_suspend_message,
1348 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1349 struct ClientPhoneSuspendMessage,
1351 GNUNET_MQ_hd_fixed_size (client_resume_message,
1352 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1353 struct ClientPhoneResumeMessage,
1355 GNUNET_MQ_hd_fixed_size (client_hangup_message,
1356 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1357 struct ClientPhoneHangupMessage,
1359 GNUNET_MQ_hd_fixed_size (client_call_message,
1360 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1361 struct ClientCallMessage,
1363 GNUNET_MQ_hd_var_size (client_audio_message,
1364 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1365 struct ClientAudioMessage,
1367 GNUNET_MQ_handler_end ());
1370 /* end of gnunet-service-conversation.c */