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_SERVER_Client *client;
180 struct GNUNET_CADET_Port *port;
183 * Port number we are listening on (to verify signatures).
184 * Only valid if @e port is non-NULL.
186 struct GNUNET_HashCode line_port;
189 * Generator for channel IDs.
199 static const struct GNUNET_CONFIGURATION_Handle *cfg;
202 * Notification context containing all connected clients.
204 static struct GNUNET_SERVER_NotificationContext *nc;
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 closure, NULL
242 * @param client the client from which the message is
243 * @param message the message from the client
246 handle_client_pickup_message (void *cls,
247 struct GNUNET_SERVER_Client *client,
248 const struct GNUNET_MessageHeader *message)
250 const struct ClientPhonePickupMessage *msg;
251 struct GNUNET_MQ_Envelope *e;
252 struct CadetPhonePickupMessage *mppm;
256 msg = (const struct ClientPhonePickupMessage *) message;
257 line = GNUNET_SERVER_client_get_user_context (client,
262 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
265 for (ch = line->channel_head; NULL != ch; ch = ch->next)
266 if (msg->cid == ch->cid)
270 /* could have been destroyed asynchronously, ignore message */
271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
272 "Channel %u not found\n",
274 GNUNET_SERVER_receive_done (client,
282 GNUNET_SERVER_receive_done (client,
285 case CS_CALLEE_RINGING:
286 ch->status = CS_CALLEE_CONNECTED;
288 case CS_CALLEE_CONNECTED:
290 GNUNET_SERVER_receive_done (client,
293 case CS_CALLEE_SHUTDOWN:
294 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
297 case CS_CALLER_CALLING:
298 case CS_CALLER_CONNECTED:
299 case CS_CALLER_SHUTDOWN:
301 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
304 GNUNET_break (CS_CALLEE_CONNECTED == ch->status);
305 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
306 "Sending PICK_UP message to cadet\n");
307 e = GNUNET_MQ_msg (mppm,
308 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP);
309 GNUNET_MQ_send (ch->mq, e);
310 GNUNET_SERVER_receive_done (client,
318 * @param ch channel to destroy.
321 destroy_line_cadet_channels (struct Channel *ch)
323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
324 "Destroying cadet channels\n");
327 GNUNET_MQ_destroy (ch->mq);
330 if (NULL != ch->channel)
331 GNUNET_CADET_channel_destroy (ch->channel);
336 * We are done signalling shutdown to the other peer. Close down
339 * @param cls the `struct Channel` to reset/terminate
342 mq_done_finish_caller_shutdown (void *cls)
344 struct Channel *ch = cls;
351 case CS_CALLEE_RINGING:
354 case CS_CALLEE_CONNECTED:
357 case CS_CALLEE_SHUTDOWN:
358 destroy_line_cadet_channels (ch);
360 case CS_CALLER_CALLING:
363 case CS_CALLER_CONNECTED:
366 case CS_CALLER_SHUTDOWN:
367 destroy_line_cadet_channels (ch);
374 * Function to handle a hangup request message from the client
376 * @param cls closure, NULL
377 * @param client the client from which the message is
378 * @param message the message from the client
381 handle_client_hangup_message (void *cls,
382 struct GNUNET_SERVER_Client *client,
383 const struct GNUNET_MessageHeader *message)
385 const struct ClientPhoneHangupMessage *msg;
386 struct GNUNET_MQ_Envelope *e;
387 struct CadetPhoneHangupMessage *mhum;
391 msg = (const struct ClientPhoneHangupMessage *) message;
392 line = GNUNET_SERVER_client_get_user_context (client,
397 GNUNET_SERVER_receive_done (client,
401 for (ch = line->channel_head; NULL != ch; ch = ch->next)
402 if (msg->cid == ch->cid)
406 /* could have been destroyed asynchronously, ignore message */
407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408 "Channel %u not found\n",
410 GNUNET_SERVER_receive_done (client,
414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
415 "Received HANGUP for channel %u which is in state %d\n",
422 GNUNET_SERVER_receive_done (client,
425 case CS_CALLEE_RINGING:
426 ch->status = CS_CALLEE_SHUTDOWN;
428 case CS_CALLEE_CONNECTED:
429 ch->status = CS_CALLEE_SHUTDOWN;
431 case CS_CALLEE_SHUTDOWN:
432 /* maybe the other peer closed asynchronously... */
433 GNUNET_SERVER_receive_done (client,
436 case CS_CALLER_CALLING:
437 ch->status = CS_CALLER_SHUTDOWN;
439 case CS_CALLER_CONNECTED:
440 ch->status = CS_CALLER_SHUTDOWN;
442 case CS_CALLER_SHUTDOWN:
443 /* maybe the other peer closed asynchronously... */
444 GNUNET_SERVER_receive_done (client, GNUNET_OK);
447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448 "Sending HANG_UP message via cadet\n");
449 e = GNUNET_MQ_msg (mhum,
450 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP);
451 GNUNET_MQ_notify_sent (e,
452 &mq_done_finish_caller_shutdown,
454 GNUNET_MQ_send (ch->mq,
456 GNUNET_SERVER_receive_done (client,
462 * Function to handle a suspend request message from the client
464 * @param cls closure, NULL
465 * @param client the client from which the message is
466 * @param message the message from the client
469 handle_client_suspend_message (void *cls,
470 struct GNUNET_SERVER_Client *client,
471 const struct GNUNET_MessageHeader *message)
473 const struct ClientPhoneSuspendMessage *msg;
474 struct GNUNET_MQ_Envelope *e;
475 struct CadetPhoneSuspendMessage *mhum;
479 msg = (const struct ClientPhoneSuspendMessage *) message;
480 line = GNUNET_SERVER_client_get_user_context (client,
485 GNUNET_SERVER_receive_done (client,
489 for (ch = line->channel_head; NULL != ch; ch = ch->next)
490 if (msg->cid == ch->cid)
494 /* could have been destroyed asynchronously, ignore message */
495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
496 "Channel %u not found\n",
498 GNUNET_SERVER_receive_done (client,
502 if (GNUNET_YES == ch->suspended_local)
505 GNUNET_SERVER_receive_done (client,
509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
510 "Received SUSPEND for channel %u which is in state %d\n",
517 GNUNET_SERVER_receive_done (client,
520 case CS_CALLEE_RINGING:
522 GNUNET_SERVER_receive_done (client,
525 case CS_CALLEE_CONNECTED:
526 ch->suspended_local = GNUNET_YES;
528 case CS_CALLEE_SHUTDOWN:
529 /* maybe the other peer closed asynchronously... */
530 GNUNET_SERVER_receive_done (client,
533 case CS_CALLER_CALLING:
535 GNUNET_SERVER_receive_done (client,
538 case CS_CALLER_CONNECTED:
539 ch->suspended_local = GNUNET_YES;
541 case CS_CALLER_SHUTDOWN:
542 /* maybe the other peer closed asynchronously... */
543 GNUNET_SERVER_receive_done (client,
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
548 "Sending SUSPEND message via cadet\n");
549 e = GNUNET_MQ_msg (mhum,
550 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND);
551 GNUNET_MQ_send (ch->mq,
553 GNUNET_SERVER_receive_done (client,
559 * Function to handle a resume request message from the client
561 * @param cls closure, NULL
562 * @param client the client from which the message is
563 * @param message the message from the client
566 handle_client_resume_message (void *cls,
567 struct GNUNET_SERVER_Client *client,
568 const struct GNUNET_MessageHeader *message)
570 const struct ClientPhoneResumeMessage *msg;
571 struct GNUNET_MQ_Envelope *e;
572 struct CadetPhoneResumeMessage *mhum;
576 msg = (const struct ClientPhoneResumeMessage *) message;
577 line = GNUNET_SERVER_client_get_user_context (client,
582 GNUNET_SERVER_receive_done (client,
586 for (ch = line->channel_head; NULL != ch; ch = ch->next)
587 if (msg->cid == ch->cid)
591 /* could have been destroyed asynchronously, ignore message */
592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
593 "Channel %u not found\n",
595 GNUNET_SERVER_receive_done (client,
599 if (GNUNET_YES != ch->suspended_local)
602 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "Received RESUME for channel %u which is in state %d\n",
613 GNUNET_SERVER_receive_done (client,
616 case CS_CALLEE_RINGING:
618 GNUNET_SERVER_receive_done (client,
621 case CS_CALLEE_CONNECTED:
622 ch->suspended_local = GNUNET_NO;
624 case CS_CALLEE_SHUTDOWN:
625 /* maybe the other peer closed asynchronously... */
626 GNUNET_SERVER_receive_done (client,
629 case CS_CALLER_CALLING:
631 GNUNET_SERVER_receive_done (client,
634 case CS_CALLER_CONNECTED:
635 ch->suspended_local = GNUNET_NO;
637 case CS_CALLER_SHUTDOWN:
638 /* maybe the other peer closed asynchronously... */
639 GNUNET_SERVER_receive_done (client,
643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
644 "Sending RESUME message via cadet\n");
645 e = GNUNET_MQ_msg (mhum,
646 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME);
647 GNUNET_MQ_send (ch->mq,
649 GNUNET_SERVER_receive_done (client,
655 * Function to handle call request from the client
657 * @param cls closure, NULL
658 * @param client the client from which the message is
659 * @param message the message from the client
662 handle_client_call_message (void *cls,
663 struct GNUNET_SERVER_Client *client,
664 const struct GNUNET_MessageHeader *message)
666 const struct ClientCallMessage *msg;
669 struct GNUNET_MQ_Envelope *e;
670 struct CadetPhoneRingMessage *ring;
671 struct CadetPhoneRingInfoPS rs;
673 msg = (const struct ClientCallMessage *) message;
674 line = GNUNET_SERVER_client_get_user_context (client,
679 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
682 line = GNUNET_new (struct Line);
683 line->client = client;
684 line->line_port = msg->line_port;
685 GNUNET_SERVER_client_set_user_context (client,
687 GNUNET_SERVER_notification_context_add (nc,
689 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
690 rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
691 rs.line_port = line->line_port;
692 rs.target_peer = msg->target;
694 = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
696 ch = GNUNET_new (struct Channel);
698 GNUNET_CONTAINER_DLL_insert (line->channel_head,
701 ch->status = CS_CALLER_CALLING;
702 ch->channel = GNUNET_CADET_channel_create (cadet,
706 GNUNET_CADET_OPTION_RELIABLE);
707 ch->mq = GNUNET_CADET_mq_create (ch->channel);
708 e = GNUNET_MQ_msg (ring,
709 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
710 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
712 ring->expiration_time = rs.expiration_time;
713 GNUNET_assert (GNUNET_OK ==
714 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
718 "Sending RING message via CADET\n");
719 GNUNET_MQ_send (ch->mq,
721 GNUNET_SERVER_receive_done (client,
727 * Transmission of audio data via cadet channel finished.
729 * @param cls the `struct Channel` we are transmitting for
732 channel_audio_sent_notify (void *cls)
734 struct Channel *ch = cls;
741 * Function to handle audio data from the client
743 * @param cls closure, NULL
744 * @param client the client from which the message is
745 * @param message the message from the client
748 handle_client_audio_message (void *cls,
749 struct GNUNET_SERVER_Client *client,
750 const struct GNUNET_MessageHeader *message)
752 const struct ClientAudioMessage *msg;
753 struct ClientAudioMessage *mam;
758 size = ntohs (message->size) - sizeof (struct ClientAudioMessage);
759 msg = (const struct ClientAudioMessage *) message;
760 line = GNUNET_SERVER_client_get_user_context (client,
765 GNUNET_SERVER_receive_done (client,
769 ch = find_channel_by_line (line,
773 /* could have been destroyed asynchronously, ignore message */
774 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775 "Channel %u not found\n",
777 GNUNET_SERVER_receive_done (client,
785 case CS_CALLEE_RINGING:
786 case CS_CALLER_CALLING:
788 GNUNET_SERVER_receive_done (client,
791 case CS_CALLEE_CONNECTED:
792 case CS_CALLER_CONNECTED:
793 /* common case, handled below */
795 case CS_CALLEE_SHUTDOWN:
796 case CS_CALLER_SHUTDOWN:
797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
798 "Cadet audio channel in shutdown; audio data dropped\n");
799 GNUNET_SERVER_receive_done (client,
803 if (GNUNET_YES == ch->suspended_local)
805 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
806 "This channel is suspended locally\n");
807 GNUNET_SERVER_receive_done (client,
813 /* NOTE: we may want to not do this and instead combine the data */
814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
815 "Bandwidth insufficient; dropping previous audio data segment\n");
816 GNUNET_MQ_send_cancel (ch->env);
820 ch->env = GNUNET_MQ_msg_extra (mam,
822 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
823 GNUNET_memcpy (&mam[1],
826 /* FIXME: set options for unreliable transmission */
827 GNUNET_MQ_notify_sent (ch->env,
828 &channel_audio_sent_notify,
830 GNUNET_MQ_send (ch->mq,
832 GNUNET_SERVER_receive_done (client,
838 * Function to handle a ring message incoming over cadet
840 * @param cls closure, NULL
841 * @param channel the channel over which the message arrived
842 * @param channel_ctx the channel context, can be NULL
843 * or point to the `struct Channel`
844 * @param message the incoming message
848 handle_cadet_ring_message (void *cls,
849 struct GNUNET_CADET_Channel *channel,
851 const struct GNUNET_MessageHeader *message)
853 struct Channel *ch = *channel_ctx;
854 struct Line *line = ch->line;
855 const struct CadetPhoneRingMessage *msg;
856 struct ClientPhoneRingMessage cring;
857 struct CadetPhoneRingInfoPS rs;
859 msg = (const struct CadetPhoneRingMessage *) message;
860 rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
861 rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
862 rs.line_port = line->line_port;
863 rs.target_peer = my_identity;
864 rs.expiration_time = msg->expiration_time;
867 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
873 return GNUNET_SYSERR;
875 if (0 == GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (msg->expiration_time)).rel_value_us)
877 /* ancient call, replay? */
879 /* Note that our reliance on time here is awkward; better would be
880 to use a more complex challenge-response protocol against
881 replay attacks. Left for future work ;-). */
882 return GNUNET_SYSERR;
884 if (CS_CALLEE_INIT != ch->status)
887 return GNUNET_SYSERR;
889 GNUNET_CADET_receive_done (channel);
890 ch->status = CS_CALLEE_RINGING;
891 cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
892 cring.header.size = htons (sizeof (cring));
894 cring.caller_id = msg->caller_id;
895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
896 "Sending RING message to client. CID is %u\n",
897 (unsigned int) ch->cid);
898 GNUNET_SERVER_notification_context_unicast (nc,
907 * Function to handle a hangup message incoming over cadet
909 * @param cls closure, NULL
910 * @param channel the channel over which the message arrived
911 * @param channel_ctx the channel context, can be NULL
912 * or point to the `struct Channel`
913 * @param message the incoming message
917 handle_cadet_hangup_message (void *cls,
918 struct GNUNET_CADET_Channel *channel,
920 const struct GNUNET_MessageHeader *message)
922 struct Channel *ch = *channel_ctx;
923 struct Line *line = ch->line;
924 struct ClientPhoneHangupMessage hup;
925 enum ChannelStatus status;
927 GNUNET_CADET_receive_done (channel);
928 hup.header.size = htons (sizeof (hup));
929 hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
932 destroy_line_cadet_channels (ch);
938 case CS_CALLEE_RINGING:
939 case CS_CALLEE_CONNECTED:
941 case CS_CALLEE_SHUTDOWN:
943 case CS_CALLER_CALLING:
944 case CS_CALLER_CONNECTED:
946 case CS_CALLER_SHUTDOWN:
949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
950 "Sending HANG UP message to client\n");
951 GNUNET_SERVER_notification_context_unicast (nc,
960 * Function to handle a pickup message incoming over cadet
962 * @param cls closure, NULL
963 * @param channel the channel over which the message arrived
964 * @param channel_ctx the channel context, can be NULL
965 * or point to the `struct Channel`
966 * @param message the incoming message
967 * @return #GNUNET_OK if message was OK,
968 * #GNUNET_SYSERR if message violated the protocol
971 handle_cadet_pickup_message (void *cls,
972 struct GNUNET_CADET_Channel *channel,
974 const struct GNUNET_MessageHeader *message)
976 struct Channel *ch = *channel_ctx;
977 struct Line *line = ch->line;
978 struct ClientPhonePickedupMessage pick;
980 GNUNET_CADET_receive_done (channel);
984 case CS_CALLEE_RINGING:
985 case CS_CALLEE_CONNECTED:
987 destroy_line_cadet_channels (ch);
988 return GNUNET_SYSERR;
989 case CS_CALLEE_SHUTDOWN:
991 destroy_line_cadet_channels (ch);
992 return GNUNET_SYSERR;
993 case CS_CALLER_CALLING:
994 ch->status = CS_CALLER_CONNECTED;
996 case CS_CALLER_CONNECTED:
999 case CS_CALLER_SHUTDOWN:
1000 GNUNET_break_op (0);
1001 mq_done_finish_caller_shutdown (ch);
1002 return GNUNET_SYSERR;
1004 pick.header.size = htons (sizeof (pick));
1005 pick.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
1007 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1008 "Sending PICKED UP message to client\n");
1009 GNUNET_SERVER_notification_context_unicast (nc,
1018 * Function to handle a suspend message incoming over cadet
1020 * @param cls closure, NULL
1021 * @param channel the channel over which the message arrived
1022 * @param channel_ctx the channel context, can be NULL
1023 * or point to the `struct Channel`
1024 * @param message the incoming message
1025 * @return #GNUNET_OK
1028 handle_cadet_suspend_message (void *cls,
1029 struct GNUNET_CADET_Channel *channel,
1031 const struct GNUNET_MessageHeader *message)
1033 struct Channel *ch = *channel_ctx;
1034 struct Line *line = ch->line;
1035 struct ClientPhoneSuspendMessage suspend;
1037 GNUNET_CADET_receive_done (channel);
1038 suspend.header.size = htons (sizeof (suspend));
1039 suspend.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
1040 suspend.cid = ch->cid;
1041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1042 "Suspending channel CID: %u\n",
1046 case CS_CALLEE_INIT:
1047 GNUNET_break_op (0);
1049 case CS_CALLEE_RINGING:
1050 GNUNET_break_op (0);
1052 case CS_CALLEE_CONNECTED:
1053 ch->suspended_remote = GNUNET_YES;
1055 case CS_CALLEE_SHUTDOWN:
1057 case CS_CALLER_CALLING:
1058 GNUNET_break_op (0);
1060 case CS_CALLER_CONNECTED:
1061 ch->suspended_remote = GNUNET_YES;
1063 case CS_CALLER_SHUTDOWN:
1066 GNUNET_SERVER_notification_context_unicast (nc,
1075 * Function to handle a resume message incoming over cadet
1077 * @param cls closure, NULL
1078 * @param channel the channel over which the message arrived
1079 * @param channel_ctx the channel context, can be NULL
1080 * or point to the `struct Channel`
1081 * @param message the incoming message
1082 * @return #GNUNET_OK
1085 handle_cadet_resume_message (void *cls,
1086 struct GNUNET_CADET_Channel *channel,
1088 const struct GNUNET_MessageHeader *message)
1090 struct Channel *ch = *channel_ctx;
1092 struct ClientPhoneResumeMessage resume;
1096 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1097 "RESUME message received for non-existing line, dropping channel.\n");
1098 return GNUNET_SYSERR;
1101 resume.header.size = htons (sizeof (resume));
1102 resume.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
1103 resume.cid = ch->cid;
1104 GNUNET_CADET_receive_done (channel);
1105 if (GNUNET_YES != ch->suspended_remote)
1107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108 "RESUME message received for non-suspended channel, dropping channel.\n");
1109 return GNUNET_SYSERR;
1113 case CS_CALLEE_INIT:
1116 case CS_CALLEE_RINGING:
1119 case CS_CALLEE_CONNECTED:
1120 ch->suspended_remote = GNUNET_NO;
1122 case CS_CALLEE_SHUTDOWN:
1124 case CS_CALLER_CALLING:
1127 case CS_CALLER_CONNECTED:
1128 ch->suspended_remote = GNUNET_NO;
1130 case CS_CALLER_SHUTDOWN:
1133 GNUNET_SERVER_notification_context_unicast (nc,
1142 * Function to handle an audio message incoming over cadet
1144 * @param cls closure, NULL
1145 * @param channel the channel over which the message arrived
1146 * @param channel_ctx the channel context, can be NULL
1147 * or point to the `struct Channel`
1148 * @param message the incoming message
1149 * @return #GNUNET_OK
1152 handle_cadet_audio_message (void *cls,
1153 struct GNUNET_CADET_Channel *channel,
1155 const struct GNUNET_MessageHeader *message)
1157 struct Channel *ch = *channel_ctx;
1158 const struct CadetAudioMessage *msg;
1159 size_t msize = ntohs (message->size) - sizeof (struct CadetAudioMessage);
1160 char buf[msize + sizeof (struct ClientAudioMessage)] GNUNET_ALIGN;
1161 struct ClientAudioMessage *cam;
1163 msg = (const struct CadetAudioMessage *) message;
1164 GNUNET_CADET_receive_done (channel);
1165 if ( (GNUNET_YES == ch->suspended_local) ||
1166 (GNUNET_YES == ch->suspended_remote) )
1168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1169 "Received %u bytes of AUDIO data on suspended channel CID %u; dropping\n",
1170 (unsigned int) msize,
1174 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1175 "Forwarding %u bytes of AUDIO data to client CID %u\n",
1176 (unsigned int) msize,
1178 cam = (struct ClientAudioMessage *) buf;
1179 cam->header.size = htons (sizeof (buf));
1180 cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1182 GNUNET_memcpy (&cam[1],
1185 GNUNET_SERVER_notification_context_unicast (nc,
1194 * Method called whenever another peer has added us to a channel
1195 * the other peer initiated.
1197 * @param cls the `struct Line` receiving a connection
1198 * @param channel new handle to the channel
1199 * @param initiator peer that started the channel
1201 * @param options channel option flags
1202 * @return initial channel context for the channel
1205 inbound_channel (void *cls,
1206 struct GNUNET_CADET_Channel *channel,
1207 const struct GNUNET_PeerIdentity *initiator,
1208 const struct GNUNET_HashCode *port,
1209 enum GNUNET_CADET_ChannelOption options)
1211 struct Line *line = cls;
1214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1215 "Received incoming cadet channel on line %p\n",
1217 ch = GNUNET_new (struct Channel);
1218 ch->status = CS_CALLEE_INIT;
1220 ch->channel = channel;
1221 ch->mq = GNUNET_CADET_mq_create (ch->channel);
1222 ch->cid = line->cid_gen++;
1223 GNUNET_CONTAINER_DLL_insert (line->channel_head,
1231 * Function called whenever an inbound channel is destroyed. Should clean up
1232 * any associated state.
1234 * @param cls closure (set from #GNUNET_CADET_connect)
1235 * @param channel connection to the other end (henceforth invalid)
1236 * @param channel_ctx place where local state associated
1237 * with the channel is stored;
1238 * may point to the `struct Channel`
1241 inbound_end (void *cls,
1242 const struct GNUNET_CADET_Channel *channel,
1245 struct Channel *ch = channel_ctx;
1247 struct ClientPhoneHangupMessage hup;
1255 GNUNET_assert (channel == ch->channel);
1257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1258 "Channel destroyed by CADET in state %d\n",
1260 hup.header.size = htons (sizeof (hup));
1261 hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1265 case CS_CALLEE_INIT:
1267 case CS_CALLEE_RINGING:
1268 case CS_CALLEE_CONNECTED:
1270 GNUNET_SERVER_notification_context_unicast (nc,
1275 case CS_CALLEE_SHUTDOWN:
1277 case CS_CALLER_CALLING:
1278 case CS_CALLER_CONNECTED:
1280 GNUNET_SERVER_notification_context_unicast (nc,
1285 case CS_CALLER_SHUTDOWN:
1288 destroy_line_cadet_channels (ch);
1290 GNUNET_CONTAINER_DLL_remove (line->channel_head,
1298 * A client disconnected. Remove all of its data structure entries.
1300 * @param cls closure, NULL
1301 * @param client identification of the client
1304 handle_client_disconnect (void *cls,
1305 struct GNUNET_SERVER_Client *client)
1309 struct Channel *chn;
1313 line = GNUNET_SERVER_client_get_user_context (client,
1317 GNUNET_SERVER_client_set_user_context (client,
1319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1320 "Client disconnected, closing line\n");
1321 if (NULL != line->port)
1323 GNUNET_CADET_close_port (line->port);
1326 for (ch = line->channel_head; NULL != ch; ch = chn)
1330 destroy_line_cadet_channels (ch);
1337 * Function to register a phone.
1339 * @param cls closure, NULL
1340 * @param client the client from which the message is
1341 * @param message the message from the client
1344 handle_client_register_message (void *cls,
1345 struct GNUNET_SERVER_Client *client,
1346 const struct GNUNET_MessageHeader *message)
1348 const struct ClientPhoneRegisterMessage *msg;
1351 msg = (const struct ClientPhoneRegisterMessage *) message;
1352 line = GNUNET_SERVER_client_get_user_context (client,
1357 GNUNET_SERVER_receive_done (client,
1361 line = GNUNET_new (struct Line);
1362 line->client = client;
1363 GNUNET_SERVER_notification_context_add (nc,
1365 GNUNET_SERVER_client_set_user_context (client,
1367 line->line_port = msg->line_port;
1368 line->port = GNUNET_CADET_open_port (cadet,
1372 GNUNET_SERVER_receive_done (client,
1380 * @param cls closure, NULL
1383 do_shutdown (void *cls)
1387 GNUNET_CADET_disconnect (cadet);
1392 GNUNET_SERVER_notification_context_destroy (nc);
1399 * Main function that will be run by the scheduler.
1401 * @param cls closure
1402 * @param server server handle
1403 * @param c configuration
1407 struct GNUNET_SERVER_Handle *server,
1408 const struct GNUNET_CONFIGURATION_Handle *c)
1410 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1411 {&handle_client_register_message, NULL,
1412 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1413 sizeof (struct ClientPhoneRegisterMessage)},
1414 {&handle_client_pickup_message, NULL,
1415 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1416 sizeof (struct ClientPhonePickupMessage) },
1417 {&handle_client_suspend_message, NULL,
1418 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1419 sizeof (struct ClientPhoneSuspendMessage) },
1420 {&handle_client_resume_message, NULL,
1421 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1422 sizeof (struct ClientPhoneResumeMessage) },
1423 {&handle_client_hangup_message, NULL,
1424 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1425 sizeof (struct ClientPhoneHangupMessage) },
1426 {&handle_client_call_message, NULL,
1427 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1428 sizeof (struct ClientCallMessage) },
1429 {&handle_client_audio_message, NULL,
1430 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1434 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1435 {&handle_cadet_ring_message,
1436 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING,
1437 sizeof (struct CadetPhoneRingMessage)},
1438 {&handle_cadet_hangup_message,
1439 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1440 sizeof (struct CadetPhoneHangupMessage)},
1441 {&handle_cadet_pickup_message,
1442 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1443 sizeof (struct CadetPhonePickupMessage)},
1444 {&handle_cadet_suspend_message,
1445 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1446 sizeof (struct CadetPhoneSuspendMessage)},
1447 {&handle_cadet_resume_message,
1448 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1449 sizeof (struct CadetPhoneResumeMessage)},
1450 {&handle_cadet_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1456 GNUNET_assert (GNUNET_OK ==
1457 GNUNET_CRYPTO_get_peer_identity (cfg,
1459 cadet = GNUNET_CADET_connect (cfg,
1466 GNUNET_SCHEDULER_shutdown ();
1469 nc = GNUNET_SERVER_notification_context_create (server,
1471 GNUNET_SERVER_add_handlers (server,
1473 GNUNET_SERVER_disconnect_notify (server,
1474 &handle_client_disconnect,
1476 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1482 * The main function for the conversation service.
1484 * @param argc number of arguments from the command line
1485 * @param argv command line arguments
1486 * @return 0 ok, 1 on error
1492 return (GNUNET_OK ==
1493 GNUNET_SERVICE_run (argc, argv,
1495 GNUNET_SERVICE_OPTION_NONE,
1496 &run, NULL)) ? 0 : 1;
1499 /* end of gnunet-service-conversation.c */