2 This file is part of GNUnet.
3 Copyright (C) 2013 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 * Our phone is ringing, waiting for the client to pick up.
68 * We're in shutdown, sending hangup messages before cleaning up.
73 * We are waiting for the phone to be picked up.
83 * We're in shutdown, sending hangup messages before cleaning up.
91 * A `struct Channel` represents a cadet channel, which is a P2P
92 * connection to another conversation service. Multiple channels can
93 * be attached the the same `struct Line`, which represents a local
94 * client. We keep them in a linked list.
102 struct Channel *next;
107 struct Channel *prev;
110 * Line associated with the channel.
115 * Handle for the reliable channel (contol data)
117 struct GNUNET_CADET_Channel *channel_reliable;
120 * Handle for unreliable channel (audio data)
122 struct GNUNET_CADET_Channel *channel_unreliable;
125 * Transmit handle for pending audio messages
127 struct GNUNET_CADET_TransmitHandle *unreliable_mth;
130 * Message queue for control messages
132 struct GNUNET_MQ_Handle *reliable_mq;
135 * Target of the line, if we are the caller.
137 struct GNUNET_PeerIdentity target;
140 * Temporary buffer for audio data.
145 * Number of bytes in @e audio_data.
150 * Channel identifier.
155 * Remote line number.
157 uint32_t remote_line;
160 * Current status of this line.
162 enum ChannelStatus status;
165 * #GNUNET_YES if the channel was suspended by the other peer.
167 int8_t suspended_remote;
170 * #GNUNET_YES if the channel was suspended by the local client.
172 int8_t suspended_local;
178 * A `struct Line` connects a local client with cadet channels.
195 struct Channel *channel_head;
200 struct Channel *channel_tail;
203 * Handle to the line client.
205 struct GNUNET_SERVER_Client *client;
208 * Generator for channel IDs.
223 static const struct GNUNET_CONFIGURATION_Handle *cfg;
226 * Notification context containing all connected clients.
228 static struct GNUNET_SERVER_NotificationContext *nc;
233 static struct GNUNET_CADET_Handle *cadet;
236 * Identity of this peer.
238 static struct GNUNET_PeerIdentity my_identity;
241 * Head of DLL of active lines.
243 static struct Line *lines_head;
246 * Tail of DLL of active lines.
248 static struct Line *lines_tail;
251 * Counter for generating local line numbers.
252 * FIXME: randomize generation in the future
253 * to eliminate information leakage.
255 static uint32_t local_line_cnt;
259 * Function to register a phone.
261 * @param cls closure, NULL
262 * @param client the client from which the message is
263 * @param message the message from the client
266 handle_client_register_message (void *cls,
267 struct GNUNET_SERVER_Client *client,
268 const struct GNUNET_MessageHeader *message)
270 const struct ClientPhoneRegisterMessage *msg;
273 msg = (const struct ClientPhoneRegisterMessage *) message;
274 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
278 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
281 line = GNUNET_new (struct Line);
282 line->client = client;
283 GNUNET_SERVER_notification_context_add (nc, client);
284 GNUNET_SERVER_client_set_user_context (client, line);
285 GNUNET_CONTAINER_DLL_insert (lines_head,
288 line->local_line = ntohl (msg->line) & (~ (1 << 31));
289 GNUNET_SERVER_receive_done (client, GNUNET_OK);
294 * Function to handle a pickup request message from the client
296 * @param cls closure, NULL
297 * @param client the client from which the message is
298 * @param message the message from the client
301 handle_client_pickup_message (void *cls,
302 struct GNUNET_SERVER_Client *client,
303 const struct GNUNET_MessageHeader *message)
305 const struct ClientPhonePickupMessage *msg;
306 struct GNUNET_MQ_Envelope *e;
307 struct CadetPhonePickupMessage *mppm;
311 msg = (const struct ClientPhonePickupMessage *) message;
312 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
316 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
319 for (ch = line->channel_head; NULL != ch; ch = ch->next)
320 if (msg->cid == ch->cid)
324 /* could have been destroyed asynchronously, ignore message */
325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
326 "Channel %u not found\n",
328 GNUNET_SERVER_receive_done (client, GNUNET_YES);
333 case CS_CALLEE_RINGING:
334 ch->status = CS_CALLEE_CONNECTED;
336 case CS_CALLEE_CONNECTED:
338 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
340 case CS_CALLEE_SHUTDOWN:
341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
344 case CS_CALLER_CALLING:
345 case CS_CALLER_CONNECTED:
346 case CS_CALLER_SHUTDOWN:
348 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
351 GNUNET_break (CS_CALLEE_CONNECTED == ch->status);
352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353 "Sending PICK_UP message to cadet\n");
354 e = GNUNET_MQ_msg (mppm,
355 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP);
356 GNUNET_MQ_send (ch->reliable_mq, e);
357 GNUNET_SERVER_receive_done (client, GNUNET_OK);
364 * @param ch channel to destroy.
367 destroy_line_cadet_channels (struct Channel *ch)
369 struct Line *line = ch->line;
370 struct GNUNET_CADET_Channel *t;
372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
373 "Destroying cadet channels\n");
374 if (NULL != ch->reliable_mq)
376 GNUNET_MQ_destroy (ch->reliable_mq);
377 ch->reliable_mq = NULL;
379 if (NULL != ch->unreliable_mth)
381 GNUNET_CADET_notify_transmit_ready_cancel (ch->unreliable_mth);
382 ch->unreliable_mth = NULL;
384 if (NULL != (t = ch->channel_unreliable))
386 ch->channel_unreliable = NULL;
387 GNUNET_CADET_channel_destroy (t);
389 if (NULL != (t = ch->channel_reliable))
391 ch->channel_reliable = NULL;
392 GNUNET_CADET_channel_destroy (t);
394 GNUNET_CONTAINER_DLL_remove (line->channel_head,
397 GNUNET_free_non_null (ch->audio_data);
403 * We are done signalling shutdown to the other peer. Close down
406 * @param cls the `struct Channel` to reset/terminate
409 mq_done_finish_caller_shutdown (void *cls)
411 struct Channel *ch = cls;
415 case CS_CALLEE_RINGING:
418 case CS_CALLEE_CONNECTED:
421 case CS_CALLEE_SHUTDOWN:
422 destroy_line_cadet_channels (ch);
424 case CS_CALLER_CALLING:
427 case CS_CALLER_CONNECTED:
430 case CS_CALLER_SHUTDOWN:
431 destroy_line_cadet_channels (ch);
438 * Function to handle a hangup request message from the client
440 * @param cls closure, NULL
441 * @param client the client from which the message is
442 * @param message the message from the client
445 handle_client_hangup_message (void *cls,
446 struct GNUNET_SERVER_Client *client,
447 const struct GNUNET_MessageHeader *message)
449 const struct ClientPhoneHangupMessage *msg;
450 struct GNUNET_MQ_Envelope *e;
451 struct CadetPhoneHangupMessage *mhum;
455 msg = (const struct ClientPhoneHangupMessage *) message;
456 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
460 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
463 for (ch = line->channel_head; NULL != ch; ch = ch->next)
464 if (msg->cid == ch->cid)
468 /* could have been destroyed asynchronously, ignore message */
469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470 "Channel %u not found\n",
472 GNUNET_SERVER_receive_done (client, GNUNET_OK);
475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476 "Received HANGUP for channel %u which is in state %d\n",
481 case CS_CALLEE_RINGING:
482 ch->status = CS_CALLEE_SHUTDOWN;
484 case CS_CALLEE_CONNECTED:
485 ch->status = CS_CALLEE_SHUTDOWN;
487 case CS_CALLEE_SHUTDOWN:
488 /* maybe the other peer closed asynchronously... */
489 GNUNET_SERVER_receive_done (client, GNUNET_OK);
491 case CS_CALLER_CALLING:
492 ch->status = CS_CALLER_SHUTDOWN;
494 case CS_CALLER_CONNECTED:
495 ch->status = CS_CALLER_SHUTDOWN;
497 case CS_CALLER_SHUTDOWN:
498 /* maybe the other peer closed asynchronously... */
499 GNUNET_SERVER_receive_done (client, GNUNET_OK);
502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
503 "Sending HANG_UP message via cadet\n");
504 e = GNUNET_MQ_msg (mhum,
505 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP);
506 GNUNET_MQ_notify_sent (e,
507 &mq_done_finish_caller_shutdown,
509 GNUNET_MQ_send (ch->reliable_mq, e);
510 GNUNET_SERVER_receive_done (client, GNUNET_OK);
515 * Function to handle a suspend request message from the client
517 * @param cls closure, NULL
518 * @param client the client from which the message is
519 * @param message the message from the client
522 handle_client_suspend_message (void *cls,
523 struct GNUNET_SERVER_Client *client,
524 const struct GNUNET_MessageHeader *message)
526 const struct ClientPhoneSuspendMessage *msg;
527 struct GNUNET_MQ_Envelope *e;
528 struct CadetPhoneSuspendMessage *mhum;
532 msg = (const struct ClientPhoneSuspendMessage *) message;
533 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
537 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
540 for (ch = line->channel_head; NULL != ch; ch = ch->next)
541 if (msg->cid == ch->cid)
545 /* could have been destroyed asynchronously, ignore message */
546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
547 "Channel %u not found\n",
549 GNUNET_SERVER_receive_done (client, GNUNET_OK);
552 if (GNUNET_YES == ch->suspended_local)
555 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
559 "Received SUSPEND for channel %u which is in state %d\n",
564 case CS_CALLEE_RINGING:
566 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
568 case CS_CALLEE_CONNECTED:
569 ch->suspended_local = GNUNET_YES;
571 case CS_CALLEE_SHUTDOWN:
572 /* maybe the other peer closed asynchronously... */
573 GNUNET_SERVER_receive_done (client, GNUNET_OK);
575 case CS_CALLER_CALLING:
577 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
579 case CS_CALLER_CONNECTED:
580 ch->suspended_local = GNUNET_YES;
582 case CS_CALLER_SHUTDOWN:
583 /* maybe the other peer closed asynchronously... */
584 GNUNET_SERVER_receive_done (client, GNUNET_OK);
587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
588 "Sending SUSPEND message via cadet\n");
589 e = GNUNET_MQ_msg (mhum,
590 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND);
591 GNUNET_MQ_send (ch->reliable_mq, e);
592 GNUNET_SERVER_receive_done (client, GNUNET_OK);
597 * Function to handle a resume request message from the client
599 * @param cls closure, NULL
600 * @param client the client from which the message is
601 * @param message the message from the client
604 handle_client_resume_message (void *cls,
605 struct GNUNET_SERVER_Client *client,
606 const struct GNUNET_MessageHeader *message)
608 const struct ClientPhoneResumeMessage *msg;
609 struct GNUNET_MQ_Envelope *e;
610 struct CadetPhoneResumeMessage *mhum;
614 msg = (const struct ClientPhoneResumeMessage *) message;
615 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
619 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
622 for (ch = line->channel_head; NULL != ch; ch = ch->next)
623 if (msg->cid == ch->cid)
627 /* could have been destroyed asynchronously, ignore message */
628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
629 "Channel %u not found\n",
631 GNUNET_SERVER_receive_done (client, GNUNET_OK);
634 if (GNUNET_YES != ch->suspended_local)
637 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
641 "Received RESUME for channel %u which is in state %d\n",
646 case CS_CALLEE_RINGING:
648 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
650 case CS_CALLEE_CONNECTED:
651 ch->suspended_local = GNUNET_NO;
653 case CS_CALLEE_SHUTDOWN:
654 /* maybe the other peer closed asynchronously... */
655 GNUNET_SERVER_receive_done (client, GNUNET_OK);
657 case CS_CALLER_CALLING:
659 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
661 case CS_CALLER_CONNECTED:
662 ch->suspended_local = GNUNET_NO;
664 case CS_CALLER_SHUTDOWN:
665 /* maybe the other peer closed asynchronously... */
666 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
670 "Sending RESUME message via cadet\n");
671 e = GNUNET_MQ_msg (mhum,
672 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME);
673 GNUNET_MQ_send (ch->reliable_mq, e);
674 GNUNET_SERVER_receive_done (client, GNUNET_OK);
679 * Function to handle call request from the client
681 * @param cls closure, NULL
682 * @param client the client from which the message is
683 * @param message the message from the client
686 handle_client_call_message (void *cls,
687 struct GNUNET_SERVER_Client *client,
688 const struct GNUNET_MessageHeader *message)
690 const struct ClientCallMessage *msg;
693 struct GNUNET_MQ_Envelope *e;
694 struct CadetPhoneRingMessage *ring;
696 msg = (const struct ClientCallMessage *) message;
697 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
701 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
704 line = GNUNET_new (struct Line);
705 line->client = client;
706 line->local_line = (local_line_cnt++) | (1 << 31);
707 GNUNET_SERVER_client_set_user_context (client, line);
708 GNUNET_SERVER_notification_context_add (nc, client);
709 GNUNET_CONTAINER_DLL_insert (lines_head,
712 ch = GNUNET_new (struct Channel);
714 GNUNET_CONTAINER_DLL_insert (line->channel_head,
717 ch->target = msg->target;
718 ch->remote_line = ntohl (msg->line);
719 ch->status = CS_CALLER_CALLING;
720 ch->channel_reliable = GNUNET_CADET_channel_create (cadet,
723 GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
724 GNUNET_CADET_OPTION_RELIABLE);
725 ch->reliable_mq = GNUNET_CADET_mq_create (ch->channel_reliable);
726 e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
727 ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
728 ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
729 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
730 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
731 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
732 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
734 ring->remote_line = msg->line;
735 ring->source_line = htonl (line->local_line);
736 ring->target = msg->target;
737 ring->source = my_identity;
738 ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
739 GNUNET_assert (GNUNET_OK ==
740 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
744 "Sending RING message via cadet\n");
745 GNUNET_MQ_send (ch->reliable_mq, e);
746 GNUNET_SERVER_receive_done (client, GNUNET_OK);
751 * Transmit audio data via unreliable cadet channel.
753 * @param cls the `struct Channel` we are transmitting for
754 * @param size number of bytes available in @a buf
755 * @param buf where to copy the data
756 * @return number of bytes copied to @a buf
759 transmit_line_audio (void *cls,
763 struct Channel *ch = cls;
764 struct CadetAudioMessage *mam = buf;
766 ch->unreliable_mth = NULL;
767 if ( (NULL == buf) ||
768 (size < sizeof (struct CadetAudioMessage) + ch->audio_size) )
770 /* eh, other error handling? */
773 mam->header.size = htons (sizeof (struct CadetAudioMessage) + ch->audio_size);
774 mam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
775 mam->remote_line = htonl (ch->remote_line);
776 mam->source_line = htonl (ch->line->local_line);
777 memcpy (&mam[1], ch->audio_data, ch->audio_size);
778 GNUNET_free (ch->audio_data);
779 ch->audio_data = NULL;
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781 "Sending %u bytes of audio data from line %u to remote line %u via cadet\n",
782 ch->audio_size, ch->line->local_line, ch->remote_line);
783 return sizeof (struct CadetAudioMessage) + ch->audio_size;
788 * Function to handle audio data from the client
790 * @param cls closure, NULL
791 * @param client the client from which the message is
792 * @param message the message from the client
795 handle_client_audio_message (void *cls,
796 struct GNUNET_SERVER_Client *client,
797 const struct GNUNET_MessageHeader *message)
799 const struct ClientAudioMessage *msg;
804 size = ntohs (message->size) - sizeof (struct ClientAudioMessage);
805 msg = (const struct ClientAudioMessage *) message;
806 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
810 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
813 for (ch = line->channel_head; NULL != ch; ch = ch->next)
814 if (msg->cid == ch->cid)
818 /* could have been destroyed asynchronously, ignore message */
819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
820 "Channel %u not found\n",
822 GNUNET_SERVER_receive_done (client, GNUNET_OK);
828 case CS_CALLEE_RINGING:
829 case CS_CALLER_CALLING:
831 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
833 case CS_CALLEE_CONNECTED:
834 case CS_CALLER_CONNECTED:
835 /* common case, handled below */
837 case CS_CALLEE_SHUTDOWN:
838 case CS_CALLER_SHUTDOWN:
839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
840 "Cadet audio channel in shutdown; audio data dropped\n");
841 GNUNET_SERVER_receive_done (client, GNUNET_OK);
844 if (GNUNET_YES == ch->suspended_local)
846 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "This channel is suspended locally\n");
847 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
850 if (NULL == ch->channel_unreliable)
852 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
853 _("Cadet audio channel not ready; audio data dropped\n"));
854 GNUNET_SERVER_receive_done (client, GNUNET_OK);
857 if (NULL != ch->unreliable_mth)
859 /* NOTE: we may want to not do this and instead combine the data */
860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
861 "Bandwidth insufficient; dropping previous audio data segment with %u bytes\n",
862 (unsigned int) ch->audio_size);
863 GNUNET_CADET_notify_transmit_ready_cancel (ch->unreliable_mth);
864 ch->unreliable_mth = NULL;
865 GNUNET_free (ch->audio_data);
866 ch->audio_data = NULL;
868 ch->audio_size = size;
869 ch->audio_data = GNUNET_malloc (ch->audio_size);
870 memcpy (ch->audio_data,
873 ch->unreliable_mth = GNUNET_CADET_notify_transmit_ready (ch->channel_unreliable,
875 GNUNET_TIME_UNIT_FOREVER_REL,
876 sizeof (struct CadetAudioMessage)
878 &transmit_line_audio,
880 GNUNET_SERVER_receive_done (client, GNUNET_OK);
885 * We are done signalling shutdown to the other peer.
886 * Destroy the channel.
888 * @param cls the `struct GNUNET_CADET_channel` to destroy
891 mq_done_destroy_channel (void *cls)
893 struct GNUNET_CADET_Channel *channel = cls;
895 GNUNET_CADET_channel_destroy (channel);
900 * Function to handle a ring message incoming over cadet
902 * @param cls closure, NULL
903 * @param channel the channel over which the message arrived
904 * @param channel_ctx the channel context, can be NULL
905 * or point to the `struct Channel`
906 * @param message the incoming message
910 handle_cadet_ring_message (void *cls,
911 struct GNUNET_CADET_Channel *channel,
913 const struct GNUNET_MessageHeader *message)
915 const struct CadetPhoneRingMessage *msg;
918 struct GNUNET_MQ_Envelope *e;
919 struct CadetPhoneHangupMessage *hang_up;
920 struct ClientPhoneRingMessage cring;
921 struct GNUNET_MQ_Handle *reliable_mq;
923 msg = (const struct CadetPhoneRingMessage *) message;
924 if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
925 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
926 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
927 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) ||
929 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
935 return GNUNET_SYSERR;
937 GNUNET_CADET_receive_done (channel); /* needed? */
938 for (line = lines_head; NULL != line; line = line->next)
939 if (line->local_line == ntohl (msg->remote_line))
943 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
944 _("No available phone for incoming call on line %u, sending HANG_UP signal\n"),
945 ntohl (msg->remote_line));
946 e = GNUNET_MQ_msg (hang_up,
947 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP);
948 GNUNET_MQ_notify_sent (e,
949 &mq_done_destroy_channel,
951 reliable_mq = GNUNET_CADET_mq_create (channel);
952 GNUNET_MQ_send (reliable_mq, e);
953 /* FIXME: do we need to clean up reliable_mq somehow/somewhere? */
956 ch = GNUNET_new (struct Channel);
958 GNUNET_CONTAINER_DLL_insert (line->channel_head,
961 ch->status = CS_CALLEE_RINGING;
962 ch->remote_line = ntohl (msg->source_line);
963 ch->channel_reliable = channel;
964 ch->reliable_mq = GNUNET_CADET_mq_create (ch->channel_reliable);
965 ch->cid = line->cid_gen++;
966 ch->target = msg->source;
968 cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
969 cring.header.size = htons (sizeof (cring));
971 cring.caller_id = msg->caller_id;
972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
973 "Sending RING message to client. CID %u:(%u, %u)\n",
974 ch->cid, ch->remote_line, line->local_line);
975 GNUNET_SERVER_notification_context_unicast (nc,
984 * Function to handle a hangup message incoming over cadet
986 * @param cls closure, NULL
987 * @param channel the channel over which the message arrived
988 * @param channel_ctx the channel context, can be NULL
989 * or point to the `struct Channel`
990 * @param message the incoming message
994 handle_cadet_hangup_message (void *cls,
995 struct GNUNET_CADET_Channel *channel,
997 const struct GNUNET_MessageHeader *message)
999 struct Channel *ch = *channel_ctx;
1001 struct ClientPhoneHangupMessage hup;
1002 enum ChannelStatus status;
1006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1007 "HANGUP message received for non-existing line, dropping channel.\n");
1008 return GNUNET_SYSERR;
1011 *channel_ctx = NULL;
1012 hup.header.size = htons (sizeof (hup));
1013 hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1015 status = ch->status;
1016 GNUNET_CADET_receive_done (channel);
1017 destroy_line_cadet_channels (ch);
1020 case CS_CALLEE_RINGING:
1021 case CS_CALLEE_CONNECTED:
1023 case CS_CALLEE_SHUTDOWN:
1025 case CS_CALLER_CALLING:
1026 case CS_CALLER_CONNECTED:
1028 case CS_CALLER_SHUTDOWN:
1031 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1032 "Sending HANG UP message to client\n");
1033 GNUNET_SERVER_notification_context_unicast (nc,
1042 * Function to handle a pickup message incoming over cadet
1044 * @param cls closure, NULL
1045 * @param channel the channel over which the message arrived
1046 * @param channel_ctx the channel context, can be NULL
1047 * or point to the `struct Channel`
1048 * @param message the incoming message
1049 * @return #GNUNET_OK if message was OK,
1050 * #GNUNET_SYSERR if message violated the protocol
1053 handle_cadet_pickup_message (void *cls,
1054 struct GNUNET_CADET_Channel *channel,
1056 const struct GNUNET_MessageHeader *message)
1058 struct Channel *ch = *channel_ctx;
1060 struct ClientPhonePickupMessage pick;
1064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1065 "PICKUP message received for non-existing channel, dropping channel.\n");
1066 return GNUNET_SYSERR;
1069 GNUNET_CADET_receive_done (channel);
1072 case CS_CALLEE_RINGING:
1073 case CS_CALLEE_CONNECTED:
1074 GNUNET_break_op (0);
1075 destroy_line_cadet_channels (ch);
1076 return GNUNET_SYSERR;
1077 case CS_CALLEE_SHUTDOWN:
1078 GNUNET_break_op (0);
1079 destroy_line_cadet_channels (ch);
1080 return GNUNET_SYSERR;
1081 case CS_CALLER_CALLING:
1082 ch->status = CS_CALLER_CONNECTED;
1084 case CS_CALLER_CONNECTED:
1085 GNUNET_break_op (0);
1087 case CS_CALLER_SHUTDOWN:
1088 GNUNET_break_op (0);
1089 mq_done_finish_caller_shutdown (ch);
1090 return GNUNET_SYSERR;
1092 pick.header.size = htons (sizeof (pick));
1093 pick.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
1095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1096 "Sending PICKED UP message to client\n");
1097 GNUNET_SERVER_notification_context_unicast (nc,
1101 ch->channel_unreliable = GNUNET_CADET_channel_create (cadet,
1104 GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1105 GNUNET_CADET_OPTION_DEFAULT);
1106 if (NULL == ch->channel_unreliable)
1115 * Function to handle a suspend message incoming over cadet
1117 * @param cls closure, NULL
1118 * @param channel the channel over which the message arrived
1119 * @param channel_ctx the channel context, can be NULL
1120 * or point to the `struct Channel`
1121 * @param message the incoming message
1122 * @return #GNUNET_OK
1125 handle_cadet_suspend_message (void *cls,
1126 struct GNUNET_CADET_Channel *channel,
1128 const struct GNUNET_MessageHeader *message)
1130 struct Channel *ch = *channel_ctx;
1132 struct ClientPhoneSuspendMessage suspend;
1136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1137 "SUSPEND message received for non-existing line, dropping channel.\n");
1138 return GNUNET_SYSERR;
1141 suspend.header.size = htons (sizeof (suspend));
1142 suspend.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
1143 suspend.cid = ch->cid;
1144 GNUNET_CADET_receive_done (channel);
1145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1146 "Suspending channel CID: %u(%u:%u)\n",
1147 ch->cid, ch->remote_line, line->local_line);
1150 case CS_CALLEE_RINGING:
1151 GNUNET_break_op (0);
1153 case CS_CALLEE_CONNECTED:
1154 ch->suspended_remote = GNUNET_YES;
1156 case CS_CALLEE_SHUTDOWN:
1158 case CS_CALLER_CALLING:
1159 GNUNET_break_op (0);
1161 case CS_CALLER_CONNECTED:
1162 ch->suspended_remote = GNUNET_YES;
1164 case CS_CALLER_SHUTDOWN:
1167 GNUNET_SERVER_notification_context_unicast (nc,
1176 * Function to handle a resume message incoming over cadet
1178 * @param cls closure, NULL
1179 * @param channel the channel over which the message arrived
1180 * @param channel_ctx the channel context, can be NULL
1181 * or point to the `struct Channel`
1182 * @param message the incoming message
1183 * @return #GNUNET_OK
1186 handle_cadet_resume_message (void *cls,
1187 struct GNUNET_CADET_Channel *channel,
1189 const struct GNUNET_MessageHeader *message)
1191 struct Channel *ch = *channel_ctx;
1193 struct ClientPhoneResumeMessage resume;
1197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1198 "RESUME message received for non-existing line, dropping channel.\n");
1199 return GNUNET_SYSERR;
1202 resume.header.size = htons (sizeof (resume));
1203 resume.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
1204 resume.cid = ch->cid;
1205 GNUNET_CADET_receive_done (channel);
1206 if (GNUNET_YES != ch->suspended_remote)
1208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1209 "RESUME message received for non-suspended channel, dropping channel.\n");
1210 return GNUNET_SYSERR;
1214 case CS_CALLEE_RINGING:
1217 case CS_CALLEE_CONNECTED:
1218 ch->suspended_remote = GNUNET_NO;
1220 case CS_CALLEE_SHUTDOWN:
1222 case CS_CALLER_CALLING:
1225 case CS_CALLER_CONNECTED:
1226 ch->suspended_remote = GNUNET_NO;
1228 case CS_CALLER_SHUTDOWN:
1231 GNUNET_SERVER_notification_context_unicast (nc,
1240 * Function to handle an audio message incoming over cadet
1242 * @param cls closure, NULL
1243 * @param channel the channel over which the message arrived
1244 * @param channel_ctx the channel context, can be NULL
1245 * or point to the `struct Channel`
1246 * @param message the incoming message
1247 * @return #GNUNET_OK
1250 handle_cadet_audio_message (void *cls,
1251 struct GNUNET_CADET_Channel *channel,
1253 const struct GNUNET_MessageHeader *message)
1255 const struct CadetAudioMessage *msg;
1256 struct Channel *ch = *channel_ctx;
1258 struct GNUNET_PeerIdentity sender;
1259 size_t msize = ntohs (message->size) - sizeof (struct CadetAudioMessage);
1260 char buf[msize + sizeof (struct ClientAudioMessage)];
1261 struct ClientAudioMessage *cam;
1262 const union GNUNET_CADET_ChannelInfo *info;
1264 msg = (const struct CadetAudioMessage *) message;
1267 info = GNUNET_CADET_channel_get_info (channel,
1268 GNUNET_CADET_OPTION_PEER);
1272 return GNUNET_SYSERR;
1274 sender = info->peer;
1275 for (line = lines_head; NULL != line; line = line->next)
1276 if (line->local_line == ntohl (msg->remote_line))
1278 for (ch = line->channel_head; NULL != ch; ch = ch->next)
1280 if ( (CS_CALLEE_CONNECTED == ch->status) &&
1281 (0 == memcmp (&ch->target,
1283 sizeof (struct GNUNET_PeerIdentity))) &&
1284 (NULL == ch->channel_unreliable) &&
1285 (ch->remote_line == ntohl (msg->source_line)) )
1292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1293 "Received %u bytes of AUDIO data for non-existing line %u, dropping.\n",
1294 msize, ntohl (msg->remote_line));
1295 return GNUNET_SYSERR;
1299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1300 "Received %u bytes of AUDIO data for unknown sender.\n",
1302 return GNUNET_SYSERR;
1304 if ((GNUNET_YES == ch->suspended_local) || (GNUNET_YES == ch->suspended_remote))
1306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1307 "Received %u bytes of AUDIO data on suspended channel CID %u:(%u:%u); dropping\n",
1308 msize, ch->cid, ch->remote_line, line->local_line);
1309 GNUNET_CADET_receive_done (channel);
1312 ch->channel_unreliable = channel;
1315 GNUNET_CADET_receive_done (channel);
1316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1317 "Forwarding %u bytes of AUDIO data to client CID %u:(%u:%u)\n",
1318 msize, ch->cid, ch->remote_line, ch->line->local_line);
1319 cam = (struct ClientAudioMessage *) buf;
1320 cam->header.size = htons (sizeof (buf));
1321 cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1323 memcpy (&cam[1], &msg[1], msize);
1324 GNUNET_SERVER_notification_context_unicast (nc,
1333 * Method called whenever another peer has added us to a channel
1334 * the other peer initiated.
1336 * @param cls closure
1337 * @param channel new handle to the channel
1338 * @param initiator peer that started the channel
1340 * @param options channel option flags
1341 * @return initial channel context for the channel;
1342 * (can be NULL -- that's not an error)
1345 inbound_channel (void *cls,
1346 struct GNUNET_CADET_Channel *channel,
1347 const struct GNUNET_PeerIdentity *initiator,
1348 uint32_t port, enum GNUNET_CADET_ChannelOption options)
1350 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1351 _("Received incoming Cadet channel on port %u\n"),
1352 (unsigned int) port);
1358 * Function called whenever an inbound channel is destroyed. Should clean up
1359 * any associated state.
1361 * @param cls closure (set from #GNUNET_CADET_connect)
1362 * @param channel connection to the other end (henceforth invalid)
1363 * @param channel_ctx place where local state associated
1364 * with the channel is stored;
1365 * may point to the `struct Channel`
1368 inbound_end (void *cls,
1369 const struct GNUNET_CADET_Channel *channel,
1372 struct Channel *ch = channel_ctx;
1374 struct ClientPhoneHangupMessage hup;
1378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1379 "Cadet channel destroyed, but channel is unknown to us\n");
1383 if (ch->channel_unreliable == channel)
1385 if (NULL != ch->unreliable_mth)
1387 GNUNET_CADET_notify_transmit_ready_cancel (ch->unreliable_mth);
1388 ch->unreliable_mth = NULL;
1390 ch->channel_unreliable = NULL;
1391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1392 "Unreliable channel destroyed\n");
1395 if (ch->channel_reliable != channel)
1397 /* recursive call, I'm the one destroying 'ch' right now */
1400 ch->channel_reliable = NULL;
1402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1403 "Cadet channel destroyed by Cadet in state %d\n",
1405 hup.header.size = htons (sizeof (hup));
1406 hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1410 case CS_CALLEE_RINGING:
1411 case CS_CALLEE_CONNECTED:
1412 GNUNET_SERVER_notification_context_unicast (nc,
1417 case CS_CALLEE_SHUTDOWN:
1419 case CS_CALLER_CALLING:
1420 case CS_CALLER_CONNECTED:
1421 GNUNET_SERVER_notification_context_unicast (nc,
1426 case CS_CALLER_SHUTDOWN:
1429 destroy_line_cadet_channels (ch);
1434 * A client disconnected. Remove all of its data structure entries.
1436 * @param cls closure, NULL
1437 * @param client identification of the client
1440 handle_client_disconnect (void *cls,
1441 struct GNUNET_SERVER_Client *client)
1447 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
1450 GNUNET_SERVER_client_set_user_context (client, NULL);
1451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1452 "Client disconnected, closing line\n");
1453 GNUNET_CONTAINER_DLL_remove (lines_head,
1456 while (NULL != line->channel_head)
1457 destroy_line_cadet_channels (line->channel_head);
1465 * @param cls closure, NULL
1468 do_shutdown (void *cls)
1473 while (NULL != (line = lines_head))
1475 while (NULL != (ch = line->channel_head))
1476 destroy_line_cadet_channels (ch);
1477 GNUNET_CONTAINER_DLL_remove (lines_head,
1480 GNUNET_SERVER_client_set_user_context (line->client, NULL);
1485 GNUNET_CADET_disconnect (cadet);
1490 GNUNET_SERVER_notification_context_destroy (nc);
1497 * Main function that will be run by the scheduler.
1499 * @param cls closure
1500 * @param server server handle
1501 * @param c configuration
1505 struct GNUNET_SERVER_Handle *server,
1506 const struct GNUNET_CONFIGURATION_Handle *c)
1508 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1509 {&handle_client_register_message, NULL,
1510 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1511 sizeof (struct ClientPhoneRegisterMessage)},
1512 {&handle_client_pickup_message, NULL,
1513 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1514 sizeof (struct ClientPhonePickupMessage) },
1515 {&handle_client_suspend_message, NULL,
1516 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND,
1517 sizeof (struct ClientPhoneSuspendMessage) },
1518 {&handle_client_resume_message, NULL,
1519 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME,
1520 sizeof (struct ClientPhoneResumeMessage) },
1521 {&handle_client_hangup_message, NULL,
1522 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1523 sizeof (struct ClientPhoneHangupMessage) },
1524 {&handle_client_call_message, NULL,
1525 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1526 sizeof (struct ClientCallMessage) },
1527 {&handle_client_audio_message, NULL,
1528 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1532 static struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
1533 {&handle_cadet_ring_message,
1534 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING,
1535 sizeof (struct CadetPhoneRingMessage)},
1536 {&handle_cadet_hangup_message,
1537 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP,
1538 sizeof (struct CadetPhoneHangupMessage)},
1539 {&handle_cadet_pickup_message,
1540 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_PICK_UP,
1541 sizeof (struct CadetPhonePickupMessage)},
1542 {&handle_cadet_suspend_message,
1543 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_SUSPEND,
1544 sizeof (struct CadetPhoneSuspendMessage)},
1545 {&handle_cadet_resume_message,
1546 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RESUME,
1547 sizeof (struct CadetPhoneResumeMessage)},
1548 {&handle_cadet_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO,
1552 static uint32_t ports[] = {
1553 GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
1554 GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1559 GNUNET_assert (GNUNET_OK ==
1560 GNUNET_CRYPTO_get_peer_identity (cfg,
1562 cadet = GNUNET_CADET_connect (cfg,
1572 GNUNET_SCHEDULER_shutdown ();
1575 nc = GNUNET_SERVER_notification_context_create (server, 16);
1576 GNUNET_SERVER_add_handlers (server, server_handlers);
1577 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1578 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1585 * The main function for the conversation service.
1587 * @param argc number of arguments from the command line
1588 * @param argv command line arguments
1589 * @return 0 ok, 1 on error
1595 return (GNUNET_OK ==
1596 GNUNET_SERVICE_run (argc, argv,
1598 GNUNET_SERVICE_OPTION_NONE,
1599 &run, NULL)) ? 0 : 1;
1602 /* end of gnunet-service-conversation.c */