2 This file is part of GNUnet.
3 Copyright (C) 2013, 2016 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,
231 for (ch = line->channel_head; NULL != ch; ch = ch->next)
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");
319 GNUNET_MQ_destroy (ch->mq);
322 if (NULL != ch->channel)
323 GNUNET_CADET_channel_destroy (ch->channel);
328 * We are done signalling shutdown to the other peer. Close down
331 * @param cls the `struct Channel` to reset/terminate
334 mq_done_finish_caller_shutdown (void *cls)
336 struct Channel *ch = cls;
343 case CS_CALLEE_RINGING:
346 case CS_CALLEE_CONNECTED:
349 case CS_CALLEE_SHUTDOWN:
350 destroy_line_cadet_channels (ch);
352 case CS_CALLER_CALLING:
355 case CS_CALLER_CONNECTED:
358 case CS_CALLER_SHUTDOWN:
359 destroy_line_cadet_channels (ch);
366 * Function to handle a hangup request message from the client
368 * @param cls the `struct Line` the hangup is for
369 * @param msg the message from the client
372 handle_client_hangup_message (void *cls,
373 const struct ClientPhoneHangupMessage *msg)
375 struct Line *line = cls;
376 struct GNUNET_MQ_Envelope *e;
377 struct CadetPhoneHangupMessage *mhum;
380 for (ch = line->channel_head; NULL != ch; ch = ch->next)
381 if (msg->cid == ch->cid)
385 /* could have been destroyed asynchronously, ignore message */
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387 "Channel %u not found\n",
389 GNUNET_SERVICE_client_continue (line->client);
392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
393 "Received HANGUP for channel %u which is in state %d\n",
400 GNUNET_SERVICE_client_drop (line->client);
402 case CS_CALLEE_RINGING:
403 ch->status = CS_CALLEE_SHUTDOWN;
405 case CS_CALLEE_CONNECTED:
406 ch->status = CS_CALLEE_SHUTDOWN;
408 case CS_CALLEE_SHUTDOWN:
409 /* maybe the other peer closed asynchronously... */
410 GNUNET_SERVICE_client_continue (line->client);
412 case CS_CALLER_CALLING:
413 ch->status = CS_CALLER_SHUTDOWN;
415 case CS_CALLER_CONNECTED:
416 ch->status = CS_CALLER_SHUTDOWN;
418 case CS_CALLER_SHUTDOWN:
419 /* maybe the other peer closed asynchronously... */
420 GNUNET_SERVICE_client_continue (line->client);
423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424 "Sending HANG_UP message via cadet\n");
425 e = GNUNET_MQ_msg (mhum,
426 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP);
427 GNUNET_MQ_notify_sent (e,
428 &mq_done_finish_caller_shutdown,
430 GNUNET_MQ_send (ch->mq,
432 GNUNET_SERVICE_client_continue (line->client);
437 * Function to handle a suspend request message from the client
439 * @param cls the `struct Line` the message is about
440 * @param msg the message from the client
443 handle_client_suspend_message (void *cls,
444 const struct ClientPhoneSuspendMessage *msg)
446 struct Line *line = cls;
447 struct GNUNET_MQ_Envelope *e;
448 struct CadetPhoneSuspendMessage *mhum;
451 for (ch = line->channel_head; NULL != ch; ch = ch->next)
452 if (msg->cid == ch->cid)
456 /* could have been destroyed asynchronously, ignore message */
457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 "Channel %u not found\n",
460 GNUNET_SERVICE_client_continue (line->client);
463 if (GNUNET_YES == ch->suspended_local)
466 GNUNET_SERVICE_client_drop (line->client);
469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470 "Received SUSPEND for channel %u which is in state %d\n",
477 GNUNET_SERVICE_client_drop (line->client);
479 case CS_CALLEE_RINGING:
481 GNUNET_SERVICE_client_drop (line->client);
483 case CS_CALLEE_CONNECTED:
484 ch->suspended_local = GNUNET_YES;
486 case CS_CALLEE_SHUTDOWN:
487 /* maybe the other peer closed asynchronously... */
488 GNUNET_SERVICE_client_continue (line->client);
490 case CS_CALLER_CALLING:
492 GNUNET_SERVICE_client_drop (line->client);
494 case CS_CALLER_CONNECTED:
495 ch->suspended_local = GNUNET_YES;
497 case CS_CALLER_SHUTDOWN:
498 /* maybe the other peer closed asynchronously... */
499 GNUNET_SERVICE_client_continue (line->client);
502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
503 "Sending SUSPEND message via cadet\n");
504 e = GNUNET_MQ_msg (mhum,
505 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND);
506 GNUNET_MQ_send (ch->mq,
508 GNUNET_SERVICE_client_continue (line->client);
513 * Function to handle a resume request message from the client
515 * @param cls the `struct Line` the message is about
516 * @param msg the message from the client
519 handle_client_resume_message (void *cls,
520 const struct ClientPhoneResumeMessage *msg)
522 struct Line *line = cls;
523 struct GNUNET_MQ_Envelope *e;
524 struct CadetPhoneResumeMessage *mhum;
527 for (ch = line->channel_head; NULL != ch; ch = ch->next)
528 if (msg->cid == ch->cid)
532 /* could have been destroyed asynchronously, ignore message */
533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
534 "Channel %u not found\n",
536 GNUNET_SERVICE_client_continue (line->client);
539 if (GNUNET_YES != ch->suspended_local)
542 GNUNET_SERVICE_client_drop (line->client);
545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
546 "Received RESUME for channel %u which is in state %d\n",
553 GNUNET_SERVICE_client_drop (line->client);
555 case CS_CALLEE_RINGING:
557 GNUNET_SERVICE_client_drop (line->client);
559 case CS_CALLEE_CONNECTED:
560 ch->suspended_local = GNUNET_NO;
562 case CS_CALLEE_SHUTDOWN:
563 /* maybe the other peer closed asynchronously... */
564 GNUNET_SERVICE_client_continue (line->client);
566 case CS_CALLER_CALLING:
568 GNUNET_SERVICE_client_drop (line->client);
570 case CS_CALLER_CONNECTED:
571 ch->suspended_local = GNUNET_NO;
573 case CS_CALLER_SHUTDOWN:
574 /* maybe the other peer closed asynchronously... */
575 GNUNET_SERVICE_client_drop (line->client);
578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
579 "Sending RESUME message via cadet\n");
580 e = GNUNET_MQ_msg (mhum,
581 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME);
582 GNUNET_MQ_send (ch->mq,
584 GNUNET_SERVICE_client_continue (line->client);
589 * Function to handle call request from the client
591 * @param cls the `struct Line` the message is about
592 * @param msg the message from the client
595 handle_client_call_message (void *cls,
596 const struct ClientCallMessage *msg)
598 struct Line *line = cls;
600 struct GNUNET_MQ_Envelope *e;
601 struct CadetPhoneRingMessage *ring;
602 struct CadetPhoneRingInfoPS rs;
604 line->line_port = msg->line_port;
605 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
606 rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
607 rs.line_port = line->line_port;
608 rs.target_peer = msg->target;
610 = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
612 ch = GNUNET_new (struct Channel);
614 GNUNET_CONTAINER_DLL_insert (line->channel_head,
617 ch->status = CS_CALLER_CALLING;
618 ch->channel = GNUNET_CADET_channel_create (cadet,
622 GNUNET_CADET_OPTION_RELIABLE);
623 ch->mq = GNUNET_CADET_mq_create (ch->channel);
624 e = GNUNET_MQ_msg (ring,
625 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
626 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
628 ring->expiration_time = rs.expiration_time;
629 GNUNET_assert (GNUNET_OK ==
630 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
633 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
634 "Sending RING message via CADET\n");
635 GNUNET_MQ_send (ch->mq,
637 GNUNET_SERVICE_client_continue (line->client);
642 * Transmission of audio data via cadet channel finished.
644 * @param cls the `struct Channel` we are transmitting for
647 channel_audio_sent_notify (void *cls)
649 struct Channel *ch = cls;
656 * Function to check audio data from the client
658 * @param cls the `struct Line` the message is about
659 * @param msg the message from the client
660 * @return #GNUNET_OK (any data is ok)
663 check_client_audio_message (void *cls,
664 const struct ClientAudioMessage *msg)
671 * Function to handle audio data from the client
673 * @param cls the `struct Line` the message is about
674 * @param msg the message from the client
677 handle_client_audio_message (void *cls,
678 const struct ClientAudioMessage *msg)
680 struct Line *line = cls;
681 struct ClientAudioMessage *mam;
685 size = ntohs (msg->header.size) - sizeof (struct ClientAudioMessage);
686 ch = find_channel_by_line (line,
690 /* could have been destroyed asynchronously, ignore message */
691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
692 "Channel %u not found\n",
694 GNUNET_SERVICE_client_continue (line->client);
701 case CS_CALLEE_RINGING:
702 case CS_CALLER_CALLING:
704 GNUNET_SERVICE_client_drop (line->client);
706 case CS_CALLEE_CONNECTED:
707 case CS_CALLER_CONNECTED:
708 /* common case, handled below */
710 case CS_CALLEE_SHUTDOWN:
711 case CS_CALLER_SHUTDOWN:
712 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
713 "Cadet audio channel in shutdown; audio data dropped\n");
714 GNUNET_SERVICE_client_continue (line->client);
717 if (GNUNET_YES == ch->suspended_local)
719 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
720 "This channel is suspended locally\n");
721 GNUNET_SERVICE_client_drop (line->client);
726 /* NOTE: we may want to not do this and instead combine the data */
727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
728 "Bandwidth insufficient; dropping previous audio data segment\n");
729 GNUNET_MQ_send_cancel (ch->env);
733 ch->env = GNUNET_MQ_msg_extra (mam,
735 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
736 GNUNET_memcpy (&mam[1],
739 /* FIXME: set options for unreliable transmission */
740 GNUNET_MQ_notify_sent (ch->env,
741 &channel_audio_sent_notify,
743 GNUNET_MQ_send (ch->mq,
745 GNUNET_SERVICE_client_continue (line->client);
750 * Function to handle a ring message incoming over cadet
752 * @param cls closure, NULL
753 * @param channel the channel over which the message arrived
754 * @param channel_ctx the channel context, can be NULL
755 * or point to the `struct Channel`
756 * @param message the incoming message
760 handle_cadet_ring_message (void *cls,
761 struct GNUNET_CADET_Channel *channel,
763 const struct GNUNET_MessageHeader *message)
765 struct Channel *ch = *channel_ctx;
766 struct Line *line = ch->line;
767 const struct CadetPhoneRingMessage *msg;
768 struct GNUNET_MQ_Envelope *env;
769 struct ClientPhoneRingMessage *cring;
770 struct CadetPhoneRingInfoPS rs;
772 msg = (const struct CadetPhoneRingMessage *) message;
773 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
774 rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
775 rs.line_port = line->line_port;
776 rs.target_peer = my_identity;
777 rs.expiration_time = msg->expiration_time;
780 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
786 return GNUNET_SYSERR;
788 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (msg->expiration_time)).rel_value_us)
790 /* ancient call, replay? */
792 /* Note that our reliance on time here is awkward; better would be
793 to use a more complex challenge-response protocol against
794 replay attacks. Left for future work ;-). */
795 return GNUNET_SYSERR;
797 if (CS_CALLEE_INIT != ch->status)
800 return GNUNET_SYSERR;
802 GNUNET_CADET_receive_done (channel);
803 ch->status = CS_CALLEE_RINGING;
804 env = GNUNET_MQ_msg (cring,
805 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
806 cring->cid = ch->cid;
807 cring->caller_id = msg->caller_id;
808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
809 "Sending RING message to client. CID is %u\n",
810 (unsigned int) ch->cid);
811 GNUNET_MQ_send (line->mq,
818 * Function to handle a hangup message incoming over cadet
820 * @param cls closure, NULL
821 * @param channel the channel over which the message arrived
822 * @param channel_ctx the channel context, can be NULL
823 * or point to the `struct Channel`
824 * @param message the incoming message
828 handle_cadet_hangup_message (void *cls,
829 struct GNUNET_CADET_Channel *channel,
831 const struct GNUNET_MessageHeader *message)
833 struct Channel *ch = *channel_ctx;
834 struct Line *line = ch->line;
835 struct GNUNET_MQ_Envelope *env;
836 struct ClientPhoneHangupMessage *hup;
837 enum ChannelStatus status;
840 GNUNET_CADET_receive_done (channel);
843 destroy_line_cadet_channels (ch);
849 case CS_CALLEE_RINGING:
850 case CS_CALLEE_CONNECTED:
852 case CS_CALLEE_SHUTDOWN:
854 case CS_CALLER_CALLING:
855 case CS_CALLER_CONNECTED:
857 case CS_CALLER_SHUTDOWN:
860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
861 "Sending HANG UP message to client\n");
862 env = GNUNET_MQ_msg (hup,
863 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
865 GNUNET_MQ_send (line->mq,
872 * Function to handle a pickup message incoming over cadet
874 * @param cls closure, NULL
875 * @param channel the channel over which the message arrived
876 * @param channel_ctx the channel context, can be NULL
877 * or point to the `struct Channel`
878 * @param message the incoming message
879 * @return #GNUNET_OK if message was OK,
880 * #GNUNET_SYSERR if message violated the protocol
883 handle_cadet_pickup_message (void *cls,
884 struct GNUNET_CADET_Channel *channel,
886 const struct GNUNET_MessageHeader *message)
888 struct Channel *ch = *channel_ctx;
889 struct Line *line = ch->line;
890 struct GNUNET_MQ_Envelope *env;
891 struct ClientPhonePickedupMessage *pick;
893 GNUNET_CADET_receive_done (channel);
897 case CS_CALLEE_RINGING:
898 case CS_CALLEE_CONNECTED:
900 destroy_line_cadet_channels (ch);
901 return GNUNET_SYSERR;
902 case CS_CALLEE_SHUTDOWN:
904 destroy_line_cadet_channels (ch);
905 return GNUNET_SYSERR;
906 case CS_CALLER_CALLING:
907 ch->status = CS_CALLER_CONNECTED;
909 case CS_CALLER_CONNECTED:
912 case CS_CALLER_SHUTDOWN:
914 mq_done_finish_caller_shutdown (ch);
915 return GNUNET_SYSERR;
917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
918 "Sending PICKED UP message to client\n");
919 env = GNUNET_MQ_msg (pick,
920 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
922 GNUNET_MQ_send (line->mq,
929 * Function to handle a suspend message incoming over cadet
931 * @param cls closure, NULL
932 * @param channel the channel over which the message arrived
933 * @param channel_ctx the channel context, can be NULL
934 * or point to the `struct Channel`
935 * @param message the incoming message
939 handle_cadet_suspend_message (void *cls,
940 struct GNUNET_CADET_Channel *channel,
942 const struct GNUNET_MessageHeader *message)
944 struct Channel *ch = *channel_ctx;
945 struct Line *line = ch->line;
946 struct GNUNET_MQ_Envelope *env;
947 struct ClientPhoneSuspendMessage *suspend;
949 GNUNET_CADET_receive_done (channel);
950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
951 "Suspending channel CID: %u\n",
958 case CS_CALLEE_RINGING:
961 case CS_CALLEE_CONNECTED:
962 ch->suspended_remote = GNUNET_YES;
964 case CS_CALLEE_SHUTDOWN:
966 case CS_CALLER_CALLING:
969 case CS_CALLER_CONNECTED:
970 ch->suspended_remote = GNUNET_YES;
972 case CS_CALLER_SHUTDOWN:
975 env = GNUNET_MQ_msg (suspend,
976 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
977 suspend->cid = ch->cid;
978 GNUNET_MQ_send (line->mq,
985 * Function to handle a resume message incoming over cadet
987 * @param cls closure, NULL
988 * @param channel the channel over which the message arrived
989 * @param channel_ctx the channel context, can be NULL
990 * or point to the `struct Channel`
991 * @param message the incoming message
995 handle_cadet_resume_message (void *cls,
996 struct GNUNET_CADET_Channel *channel,
998 const struct GNUNET_MessageHeader *message)
1000 struct Channel *ch = *channel_ctx;
1002 struct GNUNET_MQ_Envelope *env;
1003 struct ClientPhoneResumeMessage *resume;
1007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1008 "RESUME message received for non-existing line, dropping channel.\n");
1009 return GNUNET_SYSERR;
1012 GNUNET_CADET_receive_done (channel);
1013 if (GNUNET_YES != ch->suspended_remote)
1015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1016 "RESUME message received for non-suspended channel, dropping channel.\n");
1017 return GNUNET_SYSERR;
1021 case CS_CALLEE_INIT:
1024 case CS_CALLEE_RINGING:
1027 case CS_CALLEE_CONNECTED:
1028 ch->suspended_remote = GNUNET_NO;
1030 case CS_CALLEE_SHUTDOWN:
1032 case CS_CALLER_CALLING:
1035 case CS_CALLER_CONNECTED:
1036 ch->suspended_remote = GNUNET_NO;
1038 case CS_CALLER_SHUTDOWN:
1041 env = GNUNET_MQ_msg (resume,
1042 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
1043 resume->cid = ch->cid;
1044 GNUNET_MQ_send (line->mq,
1051 * Function to handle an audio message incoming over cadet
1053 * @param cls closure, NULL
1054 * @param channel the channel over which the message arrived
1055 * @param channel_ctx the channel context, can be NULL
1056 * or point to the `struct Channel`
1057 * @param message the incoming message
1058 * @return #GNUNET_OK
1061 handle_cadet_audio_message (void *cls,
1062 struct GNUNET_CADET_Channel *channel,
1064 const struct GNUNET_MessageHeader *message)
1066 struct Channel *ch = *channel_ctx;
1067 const struct CadetAudioMessage *msg;
1068 size_t msize = ntohs (message->size) - sizeof (struct CadetAudioMessage);
1069 struct GNUNET_MQ_Envelope *env;
1070 struct ClientAudioMessage *cam;
1072 msg = (const struct CadetAudioMessage *) message;
1073 GNUNET_CADET_receive_done (channel);
1074 if ( (GNUNET_YES == ch->suspended_local) ||
1075 (GNUNET_YES == ch->suspended_remote) )
1077 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1078 "Received %u bytes of AUDIO data on suspended channel CID %u; dropping\n",
1079 (unsigned int) msize,
1083 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1084 "Forwarding %u bytes of AUDIO data to client CID %u\n",
1085 (unsigned int) msize,
1087 env = GNUNET_MQ_msg_extra (cam,
1089 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1091 GNUNET_memcpy (&cam[1],
1094 GNUNET_MQ_send (ch->line->mq,
1101 * Method called whenever another peer has added us to a channel
1102 * the other peer initiated.
1104 * @param cls the `struct Line` receiving a connection
1105 * @param channel new handle to the channel
1106 * @param initiator peer that started the channel
1108 * @param options channel option flags
1109 * @return initial channel context for the channel
1112 inbound_channel (void *cls,
1113 struct GNUNET_CADET_Channel *channel,
1114 const struct GNUNET_PeerIdentity *initiator,
1115 const struct GNUNET_HashCode *port,
1116 enum GNUNET_CADET_ChannelOption options)
1118 struct Line *line = cls;
1121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1122 "Received incoming cadet channel on line %p\n",
1124 ch = GNUNET_new (struct Channel);
1125 ch->status = CS_CALLEE_INIT;
1127 ch->channel = channel;
1128 ch->mq = GNUNET_CADET_mq_create (ch->channel);
1129 ch->cid = line->cid_gen++;
1130 GNUNET_CONTAINER_DLL_insert (line->channel_head,
1138 * Function called whenever an inbound channel is destroyed. Should clean up
1139 * any associated state.
1141 * @param cls closure (set from #GNUNET_CADET_connect)
1142 * @param channel connection to the other end (henceforth invalid)
1143 * @param channel_ctx place where local state associated
1144 * with the channel is stored;
1145 * may point to the `struct Channel`
1148 inbound_end (void *cls,
1149 const struct GNUNET_CADET_Channel *channel,
1152 struct Channel *ch = channel_ctx;
1154 struct GNUNET_MQ_Envelope *env;
1155 struct ClientPhoneHangupMessage *hup;
1163 GNUNET_assert (channel == ch->channel);
1165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1166 "Channel destroyed by CADET in state %d\n",
1170 case CS_CALLEE_INIT:
1171 case CS_CALLEE_SHUTDOWN:
1172 case CS_CALLER_SHUTDOWN:
1174 case CS_CALLEE_RINGING:
1175 case CS_CALLEE_CONNECTED:
1176 case CS_CALLER_CALLING:
1177 case CS_CALLER_CONNECTED:
1180 env = GNUNET_MQ_msg (hup,
1181 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1183 GNUNET_MQ_send (line->mq,
1188 destroy_line_cadet_channels (ch);
1190 GNUNET_CONTAINER_DLL_remove (line->channel_head,
1198 * A client connected. Initialize the `struct Line` data structure.
1200 * @param cls closure, NULL
1201 * @param client identification of the client
1202 * @param mq message queue for @a client
1203 * @return the `struct Line` for the client
1206 client_connect_cb (void *cls,
1207 struct GNUNET_SERVICE_Client *client,
1208 struct GNUNET_MQ_Handle *mq)
1212 line = GNUNET_new (struct Line);
1213 line->client = client;
1220 * A client disconnected. Remove all of its data structure entries.
1222 * @param cls closure, NULL
1223 * @param client identification of the client
1224 * @param app_ctx our `struct Line *` for @a client
1227 client_disconnect_cb (void *cls,
1228 struct GNUNET_SERVICE_Client *client,
1231 struct Line *line = app_ctx;
1233 struct Channel *chn;
1235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1236 "Client disconnected, closing line\n");
1237 if (NULL != line->port)
1239 GNUNET_CADET_close_port (line->port);
1242 for (ch = line->channel_head; NULL != ch; ch = chn)
1246 destroy_line_cadet_channels (ch);
1253 * Function to register a phone.
1255 * @param cls the `struct Line` of the client from which the message is
1256 * @param msg the message from the client
1259 handle_client_register_message (void *cls,
1260 const struct ClientPhoneRegisterMessage *msg)
1262 struct Line *line = cls;
1264 line->line_port = msg->line_port;
1265 line->port = GNUNET_CADET_open_port (cadet,
1269 GNUNET_SERVICE_client_continue (line->client);
1276 * @param cls closure, NULL
1279 do_shutdown (void *cls)
1283 GNUNET_CADET_disconnect (cadet);
1290 * Main function that will be run by the scheduler.
1292 * @param cls closure
1293 * @param c configuration
1294 * @param service service handle
1298 const struct GNUNET_CONFIGURATION_Handle *c,
1299 struct GNUNET_SERVICE_Handle *service)
1301 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1302 {&handle_cadet_ring_message,
1303 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING,
1304 sizeof (struct CadetPhoneRingMessage)},
1305 {&handle_cadet_hangup_message,
1306 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1307 sizeof (struct CadetPhoneHangupMessage)},
1308 {&handle_cadet_pickup_message,
1309 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1310 sizeof (struct CadetPhonePickupMessage)},
1311 {&handle_cadet_suspend_message,
1312 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1313 sizeof (struct CadetPhoneSuspendMessage)},
1314 {&handle_cadet_resume_message,
1315 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1316 sizeof (struct CadetPhoneResumeMessage)},
1317 {&handle_cadet_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1323 GNUNET_assert (GNUNET_OK ==
1324 GNUNET_CRYPTO_get_peer_identity (cfg,
1326 cadet = GNUNET_CADET_connect (cfg,
1333 GNUNET_SCHEDULER_shutdown ();
1336 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1343 * Define "main" method using service macro.
1347 GNUNET_SERVICE_OPTION_NONE,
1350 &client_disconnect_cb,
1352 GNUNET_MQ_hd_fixed_size (client_register_message,
1353 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1354 struct ClientPhoneRegisterMessage,
1356 GNUNET_MQ_hd_fixed_size (client_pickup_message,
1357 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1358 struct ClientPhonePickupMessage,
1360 GNUNET_MQ_hd_fixed_size (client_suspend_message,
1361 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1362 struct ClientPhoneSuspendMessage,
1364 GNUNET_MQ_hd_fixed_size (client_resume_message,
1365 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1366 struct ClientPhoneResumeMessage,
1368 GNUNET_MQ_hd_fixed_size (client_hangup_message,
1369 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1370 struct ClientPhoneHangupMessage,
1372 GNUNET_MQ_hd_fixed_size (client_call_message,
1373 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1374 struct ClientCallMessage,
1376 GNUNET_MQ_hd_var_size (client_audio_message,
1377 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1378 struct ClientAudioMessage,
1380 GNUNET_MQ_handler_end ());
1383 /* end of gnunet-service-conversation.c */