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 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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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);
308 * Channel went down, notify client and free data
311 * @param ch channel that went down
314 clean_up_channel (struct Channel *ch)
316 struct Line *line = ch->line;
317 struct GNUNET_MQ_Envelope *env;
318 struct ClientPhoneHangupMessage *hup;
323 case CS_CALLEE_SHUTDOWN:
324 case CS_CALLER_SHUTDOWN:
326 case CS_CALLEE_RINGING:
327 case CS_CALLEE_CONNECTED:
328 case CS_CALLER_CALLING:
329 case CS_CALLER_CONNECTED:
332 env = GNUNET_MQ_msg (hup,
333 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
335 GNUNET_MQ_send (line->mq,
341 GNUNET_CONTAINER_DLL_remove (line->channel_head,
351 * @param ch channel to destroy.
354 destroy_line_cadet_channels (struct Channel *ch)
356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
357 "Destroying cadet channels\n");
358 if (NULL != ch->channel)
360 GNUNET_CADET_channel_destroy (ch->channel);
363 clean_up_channel (ch);
368 * We are done signalling shutdown to the other peer. Close down
371 * @param cls the `struct Channel` to reset/terminate
374 mq_done_finish_caller_shutdown (void *cls)
376 struct Channel *ch = cls;
383 case CS_CALLEE_RINGING:
386 case CS_CALLEE_CONNECTED:
389 case CS_CALLEE_SHUTDOWN:
390 destroy_line_cadet_channels (ch);
392 case CS_CALLER_CALLING:
395 case CS_CALLER_CONNECTED:
398 case CS_CALLER_SHUTDOWN:
399 destroy_line_cadet_channels (ch);
406 * Function to handle a hangup request message from the client
408 * @param cls the `struct Line` the hangup is for
409 * @param msg the message from the client
412 handle_client_hangup_message (void *cls,
413 const struct ClientPhoneHangupMessage *msg)
415 struct Line *line = cls;
416 struct GNUNET_MQ_Envelope *e;
417 struct CadetPhoneHangupMessage *mhum;
420 for (ch = line->channel_head; NULL != ch; ch = ch->next)
421 if (msg->cid == ch->cid)
425 /* could have been destroyed asynchronously, ignore message */
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "Channel %u not found\n",
429 GNUNET_SERVICE_client_continue (line->client);
432 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
433 "Received HANGUP for channel %u which is in state %d\n",
440 GNUNET_SERVICE_client_drop (line->client);
442 case CS_CALLEE_RINGING:
443 ch->status = CS_CALLEE_SHUTDOWN;
445 case CS_CALLEE_CONNECTED:
446 ch->status = CS_CALLEE_SHUTDOWN;
448 case CS_CALLEE_SHUTDOWN:
449 /* maybe the other peer closed asynchronously... */
450 GNUNET_SERVICE_client_continue (line->client);
452 case CS_CALLER_CALLING:
453 ch->status = CS_CALLER_SHUTDOWN;
455 case CS_CALLER_CONNECTED:
456 ch->status = CS_CALLER_SHUTDOWN;
458 case CS_CALLER_SHUTDOWN:
459 /* maybe the other peer closed asynchronously... */
460 GNUNET_SERVICE_client_continue (line->client);
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,
470 GNUNET_MQ_send (ch->mq,
472 GNUNET_SERVICE_client_continue (line->client);
477 * Function to handle a suspend request message from the client
479 * @param cls the `struct Line` the message is about
480 * @param msg the message from the client
483 handle_client_suspend_message (void *cls,
484 const struct ClientPhoneSuspendMessage *msg)
486 struct Line *line = cls;
487 struct GNUNET_MQ_Envelope *e;
488 struct CadetPhoneSuspendMessage *mhum;
491 for (ch = line->channel_head; NULL != ch; ch = ch->next)
492 if (msg->cid == ch->cid)
496 /* could have been destroyed asynchronously, ignore message */
497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498 "Channel %u not found\n",
500 GNUNET_SERVICE_client_continue (line->client);
503 if (GNUNET_YES == ch->suspended_local)
506 GNUNET_SERVICE_client_drop (line->client);
509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510 "Received SUSPEND for channel %u which is in state %d\n",
517 GNUNET_SERVICE_client_drop (line->client);
519 case CS_CALLEE_RINGING:
521 GNUNET_SERVICE_client_drop (line->client);
523 case CS_CALLEE_CONNECTED:
524 ch->suspended_local = GNUNET_YES;
526 case CS_CALLEE_SHUTDOWN:
527 /* maybe the other peer closed asynchronously... */
528 GNUNET_SERVICE_client_continue (line->client);
530 case CS_CALLER_CALLING:
532 GNUNET_SERVICE_client_drop (line->client);
534 case CS_CALLER_CONNECTED:
535 ch->suspended_local = GNUNET_YES;
537 case CS_CALLER_SHUTDOWN:
538 /* maybe the other peer closed asynchronously... */
539 GNUNET_SERVICE_client_continue (line->client);
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,
548 GNUNET_SERVICE_client_continue (line->client);
553 * Function to handle a resume request message from the client
555 * @param cls the `struct Line` the message is about
556 * @param msg the message from the client
559 handle_client_resume_message (void *cls,
560 const struct ClientPhoneResumeMessage *msg)
562 struct Line *line = cls;
563 struct GNUNET_MQ_Envelope *e;
564 struct CadetPhoneResumeMessage *mhum;
567 for (ch = line->channel_head; NULL != ch; ch = ch->next)
568 if (msg->cid == ch->cid)
572 /* could have been destroyed asynchronously, ignore message */
573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
574 "Channel %u not found\n",
576 GNUNET_SERVICE_client_continue (line->client);
579 if (GNUNET_YES != ch->suspended_local)
582 GNUNET_SERVICE_client_drop (line->client);
585 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
586 "Received RESUME for channel %u which is in state %d\n",
593 GNUNET_SERVICE_client_drop (line->client);
595 case CS_CALLEE_RINGING:
597 GNUNET_SERVICE_client_drop (line->client);
599 case CS_CALLEE_CONNECTED:
600 ch->suspended_local = GNUNET_NO;
602 case CS_CALLEE_SHUTDOWN:
603 /* maybe the other peer closed asynchronously... */
604 GNUNET_SERVICE_client_continue (line->client);
606 case CS_CALLER_CALLING:
608 GNUNET_SERVICE_client_drop (line->client);
610 case CS_CALLER_CONNECTED:
611 ch->suspended_local = GNUNET_NO;
613 case CS_CALLER_SHUTDOWN:
614 /* maybe the other peer closed asynchronously... */
615 GNUNET_SERVICE_client_drop (line->client);
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,
624 GNUNET_SERVICE_client_continue (line->client);
629 * Transmission of audio data via cadet channel finished.
631 * @param cls the `struct Channel` we are transmitting for
634 channel_audio_sent_notify (void *cls)
636 struct Channel *ch = cls;
643 * Function to check audio data from the client
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)
650 check_client_audio_message (void *cls,
651 const struct ClientAudioMessage *msg)
660 * Function to handle audio data from the client
662 * @param cls the `struct Line` the message is about
663 * @param msg the message from the client
666 handle_client_audio_message (void *cls,
667 const struct ClientAudioMessage *msg)
669 struct Line *line = cls;
670 struct CadetAudioMessage *mam;
674 size = ntohs (msg->header.size) - sizeof (struct ClientAudioMessage);
675 ch = find_channel_by_line (line,
679 /* could have been destroyed asynchronously, ignore message */
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681 "Channel %u not found\n",
683 GNUNET_SERVICE_client_continue (line->client);
690 case CS_CALLEE_RINGING:
691 case CS_CALLER_CALLING:
693 GNUNET_SERVICE_client_drop (line->client);
695 case CS_CALLEE_CONNECTED:
696 case CS_CALLER_CONNECTED:
697 /* common case, handled below */
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);
706 if (GNUNET_YES == ch->suspended_local)
708 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
709 "This channel is suspended locally\n");
710 GNUNET_SERVICE_client_drop (line->client);
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);
722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723 "Received %u bytes of AUDIO data from client CID %u\n",
726 ch->env = GNUNET_MQ_msg_extra (mam,
728 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
729 GNUNET_memcpy (&mam[1],
732 /* FIXME: set options for unreliable transmission */
733 GNUNET_MQ_notify_sent (ch->env,
734 &channel_audio_sent_notify,
736 GNUNET_MQ_send (ch->mq,
738 GNUNET_SERVICE_client_continue (line->client);
743 * Function to handle a ring message incoming over cadet
745 * @param cls closure, NULL
746 * @param msg the incoming message
749 handle_cadet_ring_message (void *cls,
750 const struct CadetPhoneRingMessage *msg)
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;
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;
765 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
771 destroy_line_cadet_channels (ch);
774 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (msg->expiration_time)).rel_value_us)
776 /* ancient call, replay? */
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);
784 if (CS_CALLEE_INIT != ch->status)
787 destroy_line_cadet_channels (ch);
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,
805 * Function to handle a hangup message incoming over cadet
807 * @param cls closure, our `struct Channel *`
808 * @param message the incoming message
811 handle_cadet_hangup_message (void *cls,
812 const struct CadetPhoneHangupMessage *message)
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;
822 GNUNET_CADET_receive_done (ch->channel);
825 destroy_line_cadet_channels (ch);
831 case CS_CALLEE_RINGING:
832 case CS_CALLEE_CONNECTED:
834 case CS_CALLEE_SHUTDOWN:
836 case CS_CALLER_CALLING:
837 case CS_CALLER_CONNECTED:
839 case CS_CALLER_SHUTDOWN:
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);
847 GNUNET_MQ_send (line->mq,
853 * Function to handle a pickup message incoming over cadet
855 * @param cls closure, our `struct Channel *`
856 * @param message the incoming message
859 handle_cadet_pickup_message (void *cls,
860 const struct CadetPhonePickupMessage *message)
862 struct Channel *ch = cls;
863 struct Line *line = ch->line;
864 struct GNUNET_MQ_Envelope *env;
865 struct ClientPhonePickedupMessage *pick;
868 GNUNET_CADET_receive_done (ch->channel);
872 case CS_CALLEE_RINGING:
873 case CS_CALLEE_CONNECTED:
875 destroy_line_cadet_channels (ch);
877 case CS_CALLEE_SHUTDOWN:
879 destroy_line_cadet_channels (ch);
881 case CS_CALLER_CALLING:
882 ch->status = CS_CALLER_CONNECTED;
884 case CS_CALLER_CONNECTED:
887 case CS_CALLER_SHUTDOWN:
889 mq_done_finish_caller_shutdown (ch);
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);
897 GNUNET_MQ_send (line->mq,
903 * Function to handle a suspend message incoming over cadet
905 * @param cls closure, our `struct Channel *`
906 * @param message the incoming message
909 handle_cadet_suspend_message (void *cls,
910 const struct CadetPhoneSuspendMessage *message)
912 struct Channel *ch = cls;
913 struct Line *line = ch->line;
914 struct GNUNET_MQ_Envelope *env;
915 struct ClientPhoneSuspendMessage *suspend;
918 GNUNET_CADET_receive_done (ch->channel);
919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
920 "Suspending channel CID: %u\n",
927 case CS_CALLEE_RINGING:
930 case CS_CALLEE_CONNECTED:
931 ch->suspended_remote = GNUNET_YES;
933 case CS_CALLEE_SHUTDOWN:
935 case CS_CALLER_CALLING:
938 case CS_CALLER_CONNECTED:
939 ch->suspended_remote = GNUNET_YES;
941 case CS_CALLER_SHUTDOWN:
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,
953 * Function to handle a resume message incoming over cadet
955 * @param cls closure, our `struct Channel *`
956 * @param msg the incoming message
959 handle_cadet_resume_message (void *cls,
960 const struct CadetPhoneResumeMessage *msg)
962 struct Channel *ch = cls;
964 struct GNUNET_MQ_Envelope *env;
965 struct ClientPhoneResumeMessage *resume;
969 GNUNET_CADET_receive_done (ch->channel);
970 if (GNUNET_YES != ch->suspended_remote)
972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
973 "RESUME message received for non-suspended channel, dropping channel.\n");
974 destroy_line_cadet_channels (ch);
982 case CS_CALLEE_RINGING:
985 case CS_CALLEE_CONNECTED:
986 ch->suspended_remote = GNUNET_NO;
988 case CS_CALLEE_SHUTDOWN:
990 case CS_CALLER_CALLING:
993 case CS_CALLER_CONNECTED:
994 ch->suspended_remote = GNUNET_NO;
996 case CS_CALLER_SHUTDOWN:
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,
1008 * Function to check an audio message incoming over cadet
1010 * @param cls closure, our `struct Channel *`
1011 * @param msg the incoming message
1012 * @return #GNUNET_OK (always)
1015 check_cadet_audio_message (void *cls,
1016 const struct CadetAudioMessage *msg)
1020 return GNUNET_OK; /* any payload is fine */
1025 * Function to handle an audio message incoming over cadet
1027 * @param cls closure, our `struct Channel *`
1028 * @param msg the incoming message
1031 handle_cadet_audio_message (void *cls,
1032 const struct CadetAudioMessage *msg)
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;
1039 GNUNET_CADET_receive_done (ch->channel);
1040 if ( (GNUNET_YES == ch->suspended_local) ||
1041 (GNUNET_YES == ch->suspended_remote) )
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,
1049 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1050 "Forwarding %u bytes of AUDIO data to client CID %u\n",
1051 (unsigned int) msize,
1053 env = GNUNET_MQ_msg_extra (cam,
1055 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1057 GNUNET_memcpy (&cam[1],
1060 GNUNET_MQ_send (ch->line->mq,
1066 * Function called whenever an inbound channel is destroyed. Should clean up
1067 * any associated state.
1069 * @param cls closure (set from #GNUNET_CADET_connect)
1070 * @param channel connection to the other end (henceforth invalid)
1073 inbound_end (void *cls,
1074 const struct GNUNET_CADET_Channel *channel)
1076 struct Channel *ch = cls;
1078 GNUNET_assert (channel == ch->channel);
1080 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1081 "Channel destroyed by CADET in state %d\n",
1083 clean_up_channel (ch);
1088 * Function to handle call request from the client
1090 * @param cls the `struct Line` the message is about
1091 * @param msg the message from the client
1094 handle_client_call_message (void *cls,
1095 const struct ClientCallMessage *msg)
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,
1104 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1105 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1106 struct CadetPhonePickupMessage,
1108 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1109 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1110 struct CadetPhoneSuspendMessage,
1112 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1113 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1114 struct CadetPhoneResumeMessage,
1116 GNUNET_MQ_hd_var_size (cadet_audio_message,
1117 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1118 struct CadetAudioMessage,
1120 GNUNET_MQ_handler_end ()
1122 struct GNUNET_MQ_Envelope *e;
1123 struct CadetPhoneRingMessage *ring;
1124 struct CadetPhoneRingInfoPS rs;
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;
1132 = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
1134 GNUNET_CONTAINER_DLL_insert (line->channel_head,
1137 ch->status = CS_CALLER_CALLING;
1138 ch->channel = GNUNET_CADET_channel_create (cadet,
1142 GNUNET_CADET_OPTION_RELIABLE,
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,
1151 ring->expiration_time = rs.expiration_time;
1152 GNUNET_assert (GNUNET_OK ==
1153 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
1156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157 "Sending RING message via CADET\n");
1158 GNUNET_MQ_send (ch->mq,
1160 GNUNET_SERVICE_client_continue (line->client);
1165 * Method called whenever another peer has added us to a channel
1166 * the other peer initiated.
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
1174 inbound_channel (void *cls,
1175 struct GNUNET_CADET_Channel *channel,
1176 const struct GNUNET_PeerIdentity *initiator)
1178 struct Line *line = cls;
1182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1183 "Received incoming cadet channel on line %p\n",
1185 ch = GNUNET_new (struct Channel);
1186 ch->status = CS_CALLEE_INIT;
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,
1199 * A client connected. Initialize the `struct Line` data structure.
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
1207 client_connect_cb (void *cls,
1208 struct GNUNET_SERVICE_Client *client,
1209 struct GNUNET_MQ_Handle *mq)
1214 line = GNUNET_new (struct Line);
1215 line->client = client;
1222 * A client disconnected. Remove all of its data structure entries.
1224 * @param cls closure, NULL
1225 * @param client identification of the client
1226 * @param app_ctx our `struct Line *` for @a client
1229 client_disconnect_cb (void *cls,
1230 struct GNUNET_SERVICE_Client *client,
1233 struct Line *line = app_ctx;
1234 struct Channel *chn;
1238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1239 "Client disconnected, closing line\n");
1240 if (NULL != line->port)
1242 GNUNET_CADET_close_port (line->port);
1245 for (struct Channel *ch = line->channel_head; NULL != ch; ch = chn)
1249 destroy_line_cadet_channels (ch);
1256 * Function to register a phone.
1258 * @param cls the `struct Line` of the client from which the message is
1259 * @param msg the message from the client
1262 handle_client_register_message (void *cls,
1263 const struct ClientPhoneRegisterMessage *msg)
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,
1271 GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1272 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1273 struct CadetPhoneHangupMessage,
1275 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1276 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1277 struct CadetPhonePickupMessage,
1279 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1280 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1281 struct CadetPhoneSuspendMessage,
1283 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1284 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1285 struct CadetPhoneResumeMessage,
1287 GNUNET_MQ_hd_var_size (cadet_audio_message,
1288 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1289 struct CadetAudioMessage,
1291 GNUNET_MQ_handler_end ()
1294 line->line_port = msg->line_port;
1295 line->port = GNUNET_CADET_open_port (cadet,
1302 if (NULL == line->port)
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);
1310 GNUNET_SERVICE_client_continue (line->client);
1317 * @param cls closure, NULL
1320 do_shutdown (void *cls)
1325 GNUNET_CADET_disconnect (cadet);
1332 * Main function that will be run by the scheduler.
1334 * @param cls closure
1335 * @param c configuration
1336 * @param service service handle
1340 const struct GNUNET_CONFIGURATION_Handle *c,
1341 struct GNUNET_SERVICE_Handle *service)
1346 GNUNET_assert (GNUNET_OK ==
1347 GNUNET_CRYPTO_get_peer_identity (cfg,
1349 cadet = GNUNET_CADET_connect (cfg);
1353 GNUNET_SCHEDULER_shutdown ();
1356 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1362 * Define "main" method using service macro.
1366 GNUNET_SERVICE_OPTION_NONE,
1369 &client_disconnect_cb,
1371 GNUNET_MQ_hd_fixed_size (client_register_message,
1372 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1373 struct ClientPhoneRegisterMessage,
1375 GNUNET_MQ_hd_fixed_size (client_pickup_message,
1376 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1377 struct ClientPhonePickupMessage,
1379 GNUNET_MQ_hd_fixed_size (client_suspend_message,
1380 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1381 struct ClientPhoneSuspendMessage,
1383 GNUNET_MQ_hd_fixed_size (client_resume_message,
1384 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1385 struct ClientPhoneResumeMessage,
1387 GNUNET_MQ_hd_fixed_size (client_hangup_message,
1388 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1389 struct ClientPhoneHangupMessage,
1391 GNUNET_MQ_hd_fixed_size (client_call_message,
1392 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1393 struct ClientCallMessage,
1395 GNUNET_MQ_hd_var_size (client_audio_message,
1396 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1397 struct ClientAudioMessage,
1399 GNUNET_MQ_handler_end ());
1402 /* end of gnunet-service-conversation.c */