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.
95 * A `struct Channel` represents a cadet channel, which is a P2P
96 * connection to another conversation service. Multiple channels can
97 * be attached the the same `struct Line`, which represents a local
98 * client. We keep them in a linked list.
105 struct Channel *next;
110 struct Channel *prev;
113 * Line associated with the channel.
118 * Handle for the channel.
120 struct GNUNET_CADET_Channel *channel;
123 * Message queue for control messages
125 struct GNUNET_MQ_Handle *mq;
128 * Temporary buffer for audio data in the @e mq.
130 struct GNUNET_MQ_Envelope *env;
133 * Channel identifier we use for this call with the client.
138 * Current status of this line.
140 enum ChannelStatus status;
143 * #GNUNET_YES if the channel was suspended by the other peer.
145 int8_t suspended_remote;
148 * #GNUNET_YES if the channel was suspended by the local client.
150 int8_t suspended_local;
155 * A `struct Line` connects a local client with cadet channels.
162 struct Channel *channel_head;
167 struct Channel *channel_tail;
170 * Handle to the line client.
172 struct GNUNET_SERVICE_Client *client;
175 * Message queue for @e client.
177 struct GNUNET_MQ_Handle *mq;
182 struct GNUNET_CADET_Port *port;
185 * Port number we are listening on (to verify signatures).
186 * Only valid if @e port is non-NULL.
188 struct GNUNET_HashCode line_port;
191 * Generator for channel IDs.
200 static const struct GNUNET_CONFIGURATION_Handle *cfg;
205 static struct GNUNET_CADET_Handle *cadet;
208 * Identity of this peer.
210 static struct GNUNET_PeerIdentity my_identity;
214 * Given a @a cid, find the corresponding channel given
217 * @param line a line to search
218 * @param cid what to search for
219 * @return NULL for not found
221 static struct Channel *
222 find_channel_by_line (struct Line *line, uint32_t cid)
224 for (struct Channel *ch = line->channel_head; NULL != ch; ch = ch->next)
232 * Function to handle a pickup request message from the client
234 * @param cls the `struct Line` of the client from which the message is
235 * @param msg the message from the client
238 handle_client_pickup_message (void *cls,
239 const struct ClientPhonePickupMessage *msg)
241 struct Line *line = cls;
242 struct CadetPhonePickupMessage *mppm;
243 struct GNUNET_MQ_Envelope *env;
246 if (NULL == line->port)
248 /* we never opened the port, bad client! */
250 GNUNET_SERVICE_client_drop (line->client);
253 for (ch = line->channel_head; NULL != ch; ch = ch->next)
254 if (msg->cid == ch->cid)
258 /* could have been destroyed asynchronously, ignore message */
259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
260 GNUNET_SERVICE_client_continue (line->client);
267 GNUNET_SERVICE_client_drop (line->client);
270 case CS_CALLEE_RINGING:
271 ch->status = CS_CALLEE_CONNECTED;
274 case CS_CALLEE_CONNECTED:
276 GNUNET_SERVICE_client_drop (line->client);
279 case CS_CALLEE_SHUTDOWN:
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
284 case CS_CALLER_CALLING:
285 case CS_CALLER_CONNECTED:
286 case CS_CALLER_SHUTDOWN:
288 GNUNET_SERVICE_client_drop (line->client);
291 GNUNET_break (CS_CALLEE_CONNECTED == ch->status);
292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending PICK_UP message to cadet\n");
294 GNUNET_MQ_msg (mppm, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP);
295 GNUNET_MQ_send (ch->mq, env);
296 GNUNET_SERVICE_client_continue (line->client);
301 * Channel went down, notify client and free data
304 * @param ch channel that went down
307 clean_up_channel (struct Channel *ch)
309 struct Line *line = ch->line;
310 struct GNUNET_MQ_Envelope *env;
311 struct ClientPhoneHangupMessage *hup;
316 case CS_CALLEE_SHUTDOWN:
317 case CS_CALLER_SHUTDOWN:
320 case CS_CALLEE_RINGING:
321 case CS_CALLEE_CONNECTED:
322 case CS_CALLER_CALLING:
323 case CS_CALLER_CONNECTED:
327 GNUNET_MQ_msg (hup, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
329 GNUNET_MQ_send (line->mq, env);
334 GNUNET_CONTAINER_DLL_remove (line->channel_head, line->channel_tail, ch);
342 * @param ch channel to destroy.
345 destroy_line_cadet_channels (struct Channel *ch)
347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Destroying cadet channels\n");
348 if (NULL != ch->channel)
350 GNUNET_CADET_channel_destroy (ch->channel);
353 clean_up_channel (ch);
358 * We are done signalling shutdown to the other peer. Close down
361 * @param cls the `struct Channel` to reset/terminate
364 mq_done_finish_caller_shutdown (void *cls)
366 struct Channel *ch = cls;
374 case CS_CALLEE_RINGING:
378 case CS_CALLEE_CONNECTED:
382 case CS_CALLEE_SHUTDOWN:
383 destroy_line_cadet_channels (ch);
386 case CS_CALLER_CALLING:
390 case CS_CALLER_CONNECTED:
394 case CS_CALLER_SHUTDOWN:
395 destroy_line_cadet_channels (ch);
402 * Function to handle a hangup request message from the client
404 * @param cls the `struct Line` the hangup is for
405 * @param msg the message from the client
408 handle_client_hangup_message (void *cls,
409 const struct ClientPhoneHangupMessage *msg)
411 struct Line *line = cls;
412 struct GNUNET_MQ_Envelope *e;
413 struct CadetPhoneHangupMessage *mhum;
416 for (ch = line->channel_head; NULL != ch; ch = ch->next)
417 if (msg->cid == ch->cid)
421 /* could have been destroyed asynchronously, ignore message */
422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
423 GNUNET_SERVICE_client_continue (line->client);
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "Received HANGUP for channel %u which is in state %d\n",
434 GNUNET_SERVICE_client_drop (line->client);
437 case CS_CALLEE_RINGING:
438 ch->status = CS_CALLEE_SHUTDOWN;
441 case CS_CALLEE_CONNECTED:
442 ch->status = CS_CALLEE_SHUTDOWN;
445 case CS_CALLEE_SHUTDOWN:
446 /* maybe the other peer closed asynchronously... */
447 GNUNET_SERVICE_client_continue (line->client);
450 case CS_CALLER_CALLING:
451 ch->status = CS_CALLER_SHUTDOWN;
454 case CS_CALLER_CONNECTED:
455 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, "Sending HANG_UP message via cadet\n");
465 GNUNET_MQ_msg (mhum, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP);
466 GNUNET_MQ_notify_sent (e, &mq_done_finish_caller_shutdown, ch);
467 GNUNET_MQ_send (ch->mq, e);
468 GNUNET_SERVICE_client_continue (line->client);
473 * Function to handle a suspend request message from the client
475 * @param cls the `struct Line` the message is about
476 * @param msg the message from the client
479 handle_client_suspend_message (void *cls,
480 const struct ClientPhoneSuspendMessage *msg)
482 struct Line *line = cls;
483 struct GNUNET_MQ_Envelope *e;
484 struct CadetPhoneSuspendMessage *mhum;
487 for (ch = line->channel_head; NULL != ch; ch = ch->next)
488 if (msg->cid == ch->cid)
492 /* could have been destroyed asynchronously, ignore message */
493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
494 GNUNET_SERVICE_client_continue (line->client);
497 if (GNUNET_YES == ch->suspended_local)
500 GNUNET_SERVICE_client_drop (line->client);
503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504 "Received SUSPEND for channel %u which is in state %d\n",
511 GNUNET_SERVICE_client_drop (line->client);
514 case CS_CALLEE_RINGING:
516 GNUNET_SERVICE_client_drop (line->client);
519 case CS_CALLEE_CONNECTED:
520 ch->suspended_local = GNUNET_YES;
523 case CS_CALLEE_SHUTDOWN:
524 /* maybe the other peer closed asynchronously... */
525 GNUNET_SERVICE_client_continue (line->client);
528 case CS_CALLER_CALLING:
530 GNUNET_SERVICE_client_drop (line->client);
533 case CS_CALLER_CONNECTED:
534 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, "Sending SUSPEND message via cadet\n");
544 GNUNET_MQ_msg (mhum, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND);
545 GNUNET_MQ_send (ch->mq, e);
546 GNUNET_SERVICE_client_continue (line->client);
551 * Function to handle a resume request message from the client
553 * @param cls the `struct Line` the message is about
554 * @param msg the message from the client
557 handle_client_resume_message (void *cls,
558 const struct ClientPhoneResumeMessage *msg)
560 struct Line *line = cls;
561 struct GNUNET_MQ_Envelope *e;
562 struct CadetPhoneResumeMessage *mhum;
565 for (ch = line->channel_head; NULL != ch; ch = ch->next)
566 if (msg->cid == ch->cid)
570 /* could have been destroyed asynchronously, ignore message */
571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
572 GNUNET_SERVICE_client_continue (line->client);
575 if (GNUNET_YES != ch->suspended_local)
578 GNUNET_SERVICE_client_drop (line->client);
581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
582 "Received RESUME for channel %u which is in state %d\n",
589 GNUNET_SERVICE_client_drop (line->client);
592 case CS_CALLEE_RINGING:
594 GNUNET_SERVICE_client_drop (line->client);
597 case CS_CALLEE_CONNECTED:
598 ch->suspended_local = GNUNET_NO;
601 case CS_CALLEE_SHUTDOWN:
602 /* maybe the other peer closed asynchronously... */
603 GNUNET_SERVICE_client_continue (line->client);
606 case CS_CALLER_CALLING:
608 GNUNET_SERVICE_client_drop (line->client);
611 case CS_CALLER_CONNECTED:
612 ch->suspended_local = GNUNET_NO;
615 case CS_CALLER_SHUTDOWN:
616 /* maybe the other peer closed asynchronously... */
617 GNUNET_SERVICE_client_drop (line->client);
620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending RESUME message via cadet\n");
621 e = GNUNET_MQ_msg (mhum, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME);
622 GNUNET_MQ_send (ch->mq, e);
623 GNUNET_SERVICE_client_continue (line->client);
628 * Transmission of audio data via cadet channel finished.
630 * @param cls the `struct Channel` we are transmitting for
633 channel_audio_sent_notify (void *cls)
635 struct Channel *ch = cls;
642 * Function to check audio data from the client
644 * @param cls the `struct Line` the message is about
645 * @param msg the message from the client
646 * @return #GNUNET_OK (any data is ok)
649 check_client_audio_message (void *cls, const struct ClientAudioMessage *msg)
658 * Function to handle audio data from the client
660 * @param cls the `struct Line` the message is about
661 * @param msg the message from the client
664 handle_client_audio_message (void *cls, const struct ClientAudioMessage *msg)
666 struct Line *line = cls;
667 struct CadetAudioMessage *mam;
671 size = ntohs (msg->header.size) - sizeof(struct ClientAudioMessage);
672 ch = find_channel_by_line (line, msg->cid);
675 /* could have been destroyed asynchronously, ignore message */
676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Channel %u not found\n", msg->cid);
677 GNUNET_SERVICE_client_continue (line->client);
684 case CS_CALLEE_RINGING:
685 case CS_CALLER_CALLING:
687 GNUNET_SERVICE_client_drop (line->client);
690 case CS_CALLEE_CONNECTED:
691 case CS_CALLER_CONNECTED:
692 /* common case, handled below */
695 case CS_CALLEE_SHUTDOWN:
696 case CS_CALLER_SHUTDOWN:
697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
698 "Cadet audio channel in shutdown; audio data dropped\n");
699 GNUNET_SERVICE_client_continue (line->client);
702 if (GNUNET_YES == ch->suspended_local)
704 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
705 "This channel is suspended locally\n");
706 GNUNET_SERVICE_client_drop (line->client);
711 /* NOTE: we may want to not do this and instead combine the data */
712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
713 "Bandwidth insufficient; dropping previous audio data segment\n");
714 GNUNET_MQ_send_cancel (ch->env);
718 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
719 "Received %u bytes of AUDIO data from client CID %u\n",
722 ch->env = GNUNET_MQ_msg_extra (mam,
724 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
725 GNUNET_memcpy (&mam[1], &msg[1], size);
726 /* FIXME: set options for unreliable transmission */
727 GNUNET_MQ_notify_sent (ch->env, &channel_audio_sent_notify, ch);
728 GNUNET_MQ_send (ch->mq, ch->env);
729 GNUNET_SERVICE_client_continue (line->client);
734 * Function to handle a ring message incoming over cadet
736 * @param cls closure, NULL
737 * @param msg the incoming message
740 handle_cadet_ring_message (void *cls, const struct CadetPhoneRingMessage *msg)
742 struct Channel *ch = cls;
743 struct Line *line = ch->line;
744 struct GNUNET_MQ_Envelope *env;
745 struct ClientPhoneRingMessage *cring;
746 struct CadetPhoneRingInfoPS rs;
748 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
749 rs.purpose.size = htonl (sizeof(struct CadetPhoneRingInfoPS));
750 rs.line_port = line->line_port;
751 rs.target_peer = my_identity;
752 rs.expiration_time = msg->expiration_time;
755 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
761 destroy_line_cadet_channels (ch);
764 if (0 == GNUNET_TIME_absolute_get_remaining (
765 GNUNET_TIME_absolute_ntoh (msg->expiration_time))
768 /* ancient call, replay? */
770 /* Note that our reliance on time here is awkward; better would be
771 to use a more complex challenge-response protocol against
772 replay attacks. Left for future work ;-). */
773 destroy_line_cadet_channels (ch);
776 if (CS_CALLEE_INIT != ch->status)
779 destroy_line_cadet_channels (ch);
782 GNUNET_CADET_receive_done (ch->channel);
783 ch->status = CS_CALLEE_RINGING;
784 env = GNUNET_MQ_msg (cring, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
785 cring->cid = ch->cid;
786 cring->caller_id = msg->caller_id;
787 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
788 "Sending RING message to client. CID is %u\n",
789 (unsigned int) ch->cid);
790 GNUNET_MQ_send (line->mq, env);
795 * Function to handle a hangup message incoming over cadet
797 * @param cls closure, our `struct Channel *`
798 * @param message the incoming message
801 handle_cadet_hangup_message (void *cls,
802 const struct CadetPhoneHangupMessage *message)
804 struct Channel *ch = cls;
805 struct Line *line = ch->line;
806 struct GNUNET_MQ_Envelope *env;
807 struct ClientPhoneHangupMessage *hup;
808 enum ChannelStatus status;
812 GNUNET_CADET_receive_done (ch->channel);
815 destroy_line_cadet_channels (ch);
822 case CS_CALLEE_RINGING:
823 case CS_CALLEE_CONNECTED:
826 case CS_CALLEE_SHUTDOWN:
829 case CS_CALLER_CALLING:
830 case CS_CALLER_CONNECTED:
833 case CS_CALLER_SHUTDOWN:
836 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending HANG UP message to client\n");
837 env = GNUNET_MQ_msg (hup, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
839 GNUNET_MQ_send (line->mq, env);
844 * Function to handle a pickup message incoming over cadet
846 * @param cls closure, our `struct Channel *`
847 * @param message the incoming message
850 handle_cadet_pickup_message (void *cls,
851 const struct CadetPhonePickupMessage *message)
853 struct Channel *ch = cls;
854 struct Line *line = ch->line;
855 struct GNUNET_MQ_Envelope *env;
856 struct ClientPhonePickedupMessage *pick;
859 GNUNET_CADET_receive_done (ch->channel);
863 case CS_CALLEE_RINGING:
864 case CS_CALLEE_CONNECTED:
866 destroy_line_cadet_channels (ch);
869 case CS_CALLEE_SHUTDOWN:
871 destroy_line_cadet_channels (ch);
874 case CS_CALLER_CALLING:
875 ch->status = CS_CALLER_CONNECTED;
878 case CS_CALLER_CONNECTED:
882 case CS_CALLER_SHUTDOWN:
884 mq_done_finish_caller_shutdown (ch);
887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending PICKED UP message to client\n");
889 GNUNET_MQ_msg (pick, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
891 GNUNET_MQ_send (line->mq, env);
896 * Function to handle a suspend message incoming over cadet
898 * @param cls closure, our `struct Channel *`
899 * @param message the incoming message
902 handle_cadet_suspend_message (void *cls,
903 const struct CadetPhoneSuspendMessage *message)
905 struct Channel *ch = cls;
906 struct Line *line = ch->line;
907 struct GNUNET_MQ_Envelope *env;
908 struct ClientPhoneSuspendMessage *suspend;
911 GNUNET_CADET_receive_done (ch->channel);
912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Suspending channel CID: %u\n", ch->cid);
919 case CS_CALLEE_RINGING:
923 case CS_CALLEE_CONNECTED:
924 ch->suspended_remote = GNUNET_YES;
927 case CS_CALLEE_SHUTDOWN:
930 case CS_CALLER_CALLING:
934 case CS_CALLER_CONNECTED:
935 ch->suspended_remote = GNUNET_YES;
938 case CS_CALLER_SHUTDOWN:
942 GNUNET_MQ_msg (suspend, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
943 suspend->cid = ch->cid;
944 GNUNET_MQ_send (line->mq, env);
949 * Function to handle a resume message incoming over cadet
951 * @param cls closure, our `struct Channel *`
952 * @param msg the incoming message
955 handle_cadet_resume_message (void *cls,
956 const struct CadetPhoneResumeMessage *msg)
958 struct Channel *ch = cls;
960 struct GNUNET_MQ_Envelope *env;
961 struct ClientPhoneResumeMessage *resume;
965 GNUNET_CADET_receive_done (ch->channel);
966 if (GNUNET_YES != ch->suspended_remote)
969 GNUNET_ERROR_TYPE_DEBUG,
970 "RESUME message received for non-suspended channel, dropping channel.\n");
971 destroy_line_cadet_channels (ch);
980 case CS_CALLEE_RINGING:
984 case CS_CALLEE_CONNECTED:
985 ch->suspended_remote = GNUNET_NO;
988 case CS_CALLEE_SHUTDOWN:
991 case CS_CALLER_CALLING:
995 case CS_CALLER_CONNECTED:
996 ch->suspended_remote = GNUNET_NO;
999 case CS_CALLER_SHUTDOWN:
1003 GNUNET_MQ_msg (resume, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
1004 resume->cid = ch->cid;
1005 GNUNET_MQ_send (line->mq, env);
1010 * Function to check an audio message incoming over cadet
1012 * @param cls closure, our `struct Channel *`
1013 * @param msg the incoming message
1014 * @return #GNUNET_OK (always)
1017 check_cadet_audio_message (void *cls, const struct CadetAudioMessage *msg)
1021 return GNUNET_OK; /* any payload is fine */
1026 * Function to handle an audio message incoming over cadet
1028 * @param cls closure, our `struct Channel *`
1029 * @param msg the incoming message
1032 handle_cadet_audio_message (void *cls, 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))
1044 GNUNET_ERROR_TYPE_DEBUG,
1045 "Received %u bytes of AUDIO data on suspended channel CID %u; dropping\n",
1046 (unsigned int) msize,
1050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051 "Forwarding %u bytes of AUDIO data to client CID %u\n",
1052 (unsigned int) msize,
1055 GNUNET_MQ_msg_extra (cam, msize, GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1057 GNUNET_memcpy (&cam[1], &msg[1], msize);
1058 GNUNET_MQ_send (ch->line->mq, env);
1063 * Function called whenever an inbound channel is destroyed. Should clean up
1064 * any associated state.
1066 * @param cls closure (set from #GNUNET_CADET_connect)
1067 * @param channel connection to the other end (henceforth invalid)
1070 inbound_end (void *cls, const struct GNUNET_CADET_Channel *channel)
1072 struct Channel *ch = cls;
1074 GNUNET_assert (channel == ch->channel);
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077 "Channel destroyed by CADET in state %d\n",
1079 clean_up_channel (ch);
1084 * Function to handle call request from the client
1086 * @param cls the `struct Line` the message is about
1087 * @param msg the message from the client
1090 handle_client_call_message (void *cls, const struct ClientCallMessage *msg)
1092 struct Line *line = cls;
1093 struct Channel *ch = GNUNET_new (struct Channel);
1094 struct GNUNET_MQ_MessageHandler cadet_handlers[] =
1095 { GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1096 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1097 struct CadetPhoneHangupMessage,
1099 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1100 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1101 struct CadetPhonePickupMessage,
1103 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1104 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1105 struct CadetPhoneSuspendMessage,
1107 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1108 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1109 struct CadetPhoneResumeMessage,
1111 GNUNET_MQ_hd_var_size (cadet_audio_message,
1112 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1113 struct CadetAudioMessage,
1115 GNUNET_MQ_handler_end () };
1116 struct GNUNET_MQ_Envelope *e;
1117 struct CadetPhoneRingMessage *ring;
1118 struct CadetPhoneRingInfoPS rs;
1120 line->line_port = msg->line_port;
1121 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
1122 rs.purpose.size = htonl (sizeof(struct CadetPhoneRingInfoPS));
1123 rs.line_port = line->line_port;
1124 rs.target_peer = msg->target;
1125 rs.expiration_time =
1126 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
1128 GNUNET_CONTAINER_DLL_insert (line->channel_head, line->channel_tail, ch);
1129 ch->status = CS_CALLER_CALLING;
1130 ch->channel = GNUNET_CADET_channel_create (cadet,
1137 ch->mq = GNUNET_CADET_get_mq (ch->channel);
1138 e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
1139 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id, &ring->caller_id);
1140 ring->expiration_time = rs.expiration_time;
1141 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
1144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending RING message via CADET\n");
1145 GNUNET_MQ_send (ch->mq, e);
1146 GNUNET_SERVICE_client_continue (line->client);
1151 * Method called whenever another peer has added us to a channel
1152 * the other peer initiated.
1154 * @param cls the `struct Line` receiving a connection
1155 * @param channel new handle to the channel
1156 * @param initiator peer that started the channel
1157 * @return initial channel context for the channel
1160 inbound_channel (void *cls,
1161 struct GNUNET_CADET_Channel *channel,
1162 const struct GNUNET_PeerIdentity *initiator)
1164 struct Line *line = cls;
1168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1169 "Received incoming cadet channel on line %p\n",
1171 ch = GNUNET_new (struct Channel);
1172 ch->status = CS_CALLEE_INIT;
1174 ch->channel = channel;
1175 ch->mq = GNUNET_CADET_get_mq (ch->channel);
1176 ch->cid = line->cid_gen++;
1177 GNUNET_CONTAINER_DLL_insert (line->channel_head, line->channel_tail, ch);
1183 * A client connected. Initialize the `struct Line` data structure.
1185 * @param cls closure, NULL
1186 * @param client identification of the client
1187 * @param mq message queue for @a client
1188 * @return the `struct Line` for the client
1191 client_connect_cb (void *cls,
1192 struct GNUNET_SERVICE_Client *client,
1193 struct GNUNET_MQ_Handle *mq)
1198 line = GNUNET_new (struct Line);
1199 line->client = client;
1206 * A client disconnected. Remove all of its data structure entries.
1208 * @param cls closure, NULL
1209 * @param client identification of the client
1210 * @param app_ctx our `struct Line *` for @a client
1213 client_disconnect_cb (void *cls,
1214 struct GNUNET_SERVICE_Client *client,
1217 struct Line *line = app_ctx;
1218 struct Channel *chn;
1222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected, closing line\n");
1223 if (NULL != line->port)
1225 GNUNET_CADET_close_port (line->port);
1228 for (struct Channel *ch = line->channel_head; NULL != ch; ch = chn)
1232 destroy_line_cadet_channels (ch);
1239 * Function to register a phone.
1241 * @param cls the `struct Line` of the client from which the message is
1242 * @param msg the message from the client
1245 handle_client_register_message (void *cls,
1246 const struct ClientPhoneRegisterMessage *msg)
1248 struct Line *line = cls;
1249 struct GNUNET_MQ_MessageHandler cadet_handlers[] =
1250 { GNUNET_MQ_hd_fixed_size (cadet_ring_message,
1251 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING,
1252 struct CadetPhoneRingMessage,
1254 GNUNET_MQ_hd_fixed_size (cadet_hangup_message,
1255 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1256 struct CadetPhoneHangupMessage,
1258 GNUNET_MQ_hd_fixed_size (cadet_pickup_message,
1259 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1260 struct CadetPhonePickupMessage,
1262 GNUNET_MQ_hd_fixed_size (cadet_suspend_message,
1263 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1264 struct CadetPhoneSuspendMessage,
1266 GNUNET_MQ_hd_fixed_size (cadet_resume_message,
1267 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1268 struct CadetPhoneResumeMessage,
1270 GNUNET_MQ_hd_var_size (cadet_audio_message,
1271 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1272 struct CadetAudioMessage,
1274 GNUNET_MQ_handler_end () };
1276 line->line_port = msg->line_port;
1277 line->port = GNUNET_CADET_open_port (cadet,
1284 if (NULL == line->port)
1286 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1287 _ ("Could not open line, port %s already in use!\n"),
1288 GNUNET_h2s (&msg->line_port));
1289 GNUNET_SERVICE_client_drop (line->client);
1292 GNUNET_SERVICE_client_continue (line->client);
1299 * @param cls closure, NULL
1302 do_shutdown (void *cls)
1307 GNUNET_CADET_disconnect (cadet);
1314 * Main function that will be run by the scheduler.
1316 * @param cls closure
1317 * @param c configuration
1318 * @param service service handle
1322 const struct GNUNET_CONFIGURATION_Handle *c,
1323 struct GNUNET_SERVICE_Handle *service)
1328 GNUNET_assert (GNUNET_OK ==
1329 GNUNET_CRYPTO_get_peer_identity (cfg, &my_identity));
1330 cadet = GNUNET_CADET_connect (cfg);
1334 GNUNET_SCHEDULER_shutdown ();
1337 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1342 * Define "main" method using service macro.
1344 GNUNET_SERVICE_MAIN (
1346 GNUNET_SERVICE_OPTION_NONE,
1349 &client_disconnect_cb,
1351 GNUNET_MQ_hd_fixed_size (client_register_message,
1352 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1353 struct ClientPhoneRegisterMessage,
1355 GNUNET_MQ_hd_fixed_size (client_pickup_message,
1356 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1357 struct ClientPhonePickupMessage,
1359 GNUNET_MQ_hd_fixed_size (client_suspend_message,
1360 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1361 struct ClientPhoneSuspendMessage,
1363 GNUNET_MQ_hd_fixed_size (client_resume_message,
1364 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1365 struct ClientPhoneResumeMessage,
1367 GNUNET_MQ_hd_fixed_size (client_hangup_message,
1368 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1369 struct ClientPhoneHangupMessage,
1371 GNUNET_MQ_hd_fixed_size (client_call_message,
1372 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1373 struct ClientCallMessage,
1375 GNUNET_MQ_hd_var_size (client_audio_message,
1376 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1377 struct ClientAudioMessage,
1379 GNUNET_MQ_handler_end ());
1382 /* end of gnunet-service-conversation.c */