2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, 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_mesh_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 * The possible connection status
52 * We are waiting for incoming calls.
57 * Our phone is ringing, waiting for the client to pick up.
67 * We're in shutdown, sending hangup messages before cleaning up.
72 * We are waiting for the phone to be picked up.
82 * We're in shutdown, sending hangup messages before cleaning up.
89 * A line connects a local client with a mesh channel (or, if it is an
90 * open line, is waiting for a mesh channel).
105 * Handle for the reliable channel (contol data)
107 struct GNUNET_MESH_Channel *channel_reliable;
110 * Handle for unreliable channel (audio data)
112 struct GNUNET_MESH_Channel *channel_unreliable;
115 * Transmit handle for pending audio messages
117 struct GNUNET_MESH_TransmitHandle *unreliable_mth;
120 * Message queue for control messages
122 struct GNUNET_MQ_Handle *reliable_mq;
125 * Handle to the line client.
127 struct GNUNET_SERVER_Client *client;
130 * Target of the line, if we are the caller.
132 struct GNUNET_PeerIdentity target;
135 * Temporary buffer for audio data.
140 * Number of bytes in @e audio_data.
150 * Remote line number.
152 uint32_t remote_line;
155 * Current status of this line.
157 enum LineStatus status;
165 static const struct GNUNET_CONFIGURATION_Handle *cfg;
168 * Notification context containing all connected clients.
170 static struct GNUNET_SERVER_NotificationContext *nc;
175 static struct GNUNET_MESH_Handle *mesh;
178 * Identity of this peer.
180 static struct GNUNET_PeerIdentity my_identity;
183 * Head of DLL of active lines.
185 static struct Line *lines_head;
188 * Tail of DLL of active lines.
190 static struct Line *lines_tail;
193 * Counter for generating local line numbers.
194 * FIXME: randomize generation in the future
195 * to eliminate information leakage.
197 static uint32_t local_line_cnt;
201 * Function to register a phone.
203 * @param cls closure, NULL
204 * @param client the client from which the message is
205 * @param message the message from the client
208 handle_client_register_message (void *cls,
209 struct GNUNET_SERVER_Client *client,
210 const struct GNUNET_MessageHeader *message)
212 const struct ClientPhoneRegisterMessage *msg;
215 msg = (struct ClientPhoneRegisterMessage *) message;
216 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
220 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
223 line = GNUNET_new (struct Line);
224 line->client = client;
225 GNUNET_SERVER_notification_context_add (nc, client);
226 GNUNET_SERVER_client_set_user_context (client, line);
227 GNUNET_CONTAINER_DLL_insert (lines_head,
230 line->local_line = ntohl (msg->line);
231 GNUNET_SERVER_receive_done (client, GNUNET_OK);
236 * Function to handle a pickup request message from the client
238 * @param cls closure, NULL
239 * @param client the client from which the message is
240 * @param message the message from the client
243 handle_client_pickup_message (void *cls,
244 struct GNUNET_SERVER_Client *client,
245 const struct GNUNET_MessageHeader *message)
247 const struct ClientPhonePickupMessage *msg;
248 struct GNUNET_MQ_Envelope *e;
249 struct MeshPhonePickupMessage *mppm;
254 msg = (struct ClientPhonePickupMessage *) message;
255 meta = (const char *) &msg[1];
256 len = ntohs (msg->header.size) - sizeof (struct ClientPhonePickupMessage);
258 ('\0' != meta[len - 1]) )
263 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
267 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
270 switch (line->status)
272 case LS_CALLEE_LISTEN:
273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
274 "Ignoring client's PICKUP message, caller has HUNG UP already\n");
275 GNUNET_SERVER_receive_done (client, GNUNET_OK);
277 case LS_CALLEE_RINGING:
278 line->status = LS_CALLEE_CONNECTED;
280 case LS_CALLEE_CONNECTED:
282 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
284 case LS_CALLEE_SHUTDOWN:
285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
286 "Ignoring client's PICKUP message, line is in SHUTDOWN\n");
287 GNUNET_SERVER_receive_done (client, GNUNET_OK);
289 case LS_CALLER_CALLING:
290 case LS_CALLER_CONNECTED:
291 case LS_CALLER_SHUTDOWN:
293 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
296 line->status = LS_CALLEE_CONNECTED;
297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
298 "Sending PICK_UP message to mesh with meta data `%s'\n",
300 e = GNUNET_MQ_msg_extra (mppm,
302 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP);
303 memcpy (&mppm[1], meta, len);
304 GNUNET_MQ_send (line->reliable_mq, e);
305 GNUNET_SERVER_receive_done (client, GNUNET_OK);
310 * Destroy the mesh channels of a line.
312 * @param line line to shutdown channels of
315 destroy_line_mesh_channels (struct Line *line)
317 struct GNUNET_MESH_Channel *t;
319 if (NULL != line->reliable_mq)
321 GNUNET_MQ_destroy (line->reliable_mq);
322 line->reliable_mq = NULL;
324 if (NULL != line->unreliable_mth)
326 GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
327 line->unreliable_mth = NULL;
329 if (NULL != (t = line->channel_unreliable))
331 line->channel_unreliable = NULL;
332 GNUNET_MESH_channel_destroy (t);
334 if (NULL != (t = line->channel_reliable))
336 line->channel_reliable = NULL;
337 GNUNET_MESH_channel_destroy (t);
343 * We are done signalling shutdown to the other peer. Close down
344 * (or reset) the line.
346 * @param cls the `struct Line` to reset/terminate
349 mq_done_finish_caller_shutdown (void *cls)
351 struct Line *line = cls;
353 switch (line->status)
355 case LS_CALLEE_LISTEN:
358 case LS_CALLEE_RINGING:
361 case LS_CALLEE_CONNECTED:
364 case LS_CALLEE_SHUTDOWN:
365 line->status = LS_CALLEE_LISTEN;
366 destroy_line_mesh_channels (line);
368 case LS_CALLER_CALLING:
369 line->status = LS_CALLER_SHUTDOWN;
371 case LS_CALLER_CONNECTED:
372 line->status = LS_CALLER_SHUTDOWN;
374 case LS_CALLER_SHUTDOWN:
375 destroy_line_mesh_channels (line);
382 * Function to handle a hangup request message from the client
384 * @param cls closure, NULL
385 * @param client the client from which the message is
386 * @param message the message from the client
389 handle_client_hangup_message (void *cls,
390 struct GNUNET_SERVER_Client *client,
391 const struct GNUNET_MessageHeader *message)
393 const struct ClientPhoneHangupMessage *msg;
394 struct GNUNET_MQ_Envelope *e;
395 struct MeshPhoneHangupMessage *mhum;
400 msg = (struct ClientPhoneHangupMessage *) message;
401 meta = (const char *) &msg[1];
402 len = ntohs (msg->header.size) - sizeof (struct ClientPhoneHangupMessage);
404 ('\0' != meta[len - 1]) )
409 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
413 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
416 switch (line->status)
418 case LS_CALLEE_LISTEN:
420 GNUNET_SERVER_receive_done (client, GNUNET_OK);
422 case LS_CALLEE_RINGING:
423 line->status = LS_CALLEE_SHUTDOWN;
425 case LS_CALLEE_CONNECTED:
426 line->status = LS_CALLEE_SHUTDOWN;
428 case LS_CALLEE_SHUTDOWN:
430 GNUNET_SERVER_receive_done (client, GNUNET_OK);
432 case LS_CALLER_CALLING:
433 line->status = LS_CALLER_SHUTDOWN;
435 case LS_CALLER_CONNECTED:
436 line->status = LS_CALLER_SHUTDOWN;
438 case LS_CALLER_SHUTDOWN:
440 GNUNET_SERVER_receive_done (client, GNUNET_OK);
443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 "Sending HANG_UP message via mesh with meta data `%s'\n",
446 e = GNUNET_MQ_msg_extra (mhum,
448 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
449 memcpy (&mhum[1], meta, len);
450 GNUNET_MQ_notify_sent (e,
451 &mq_done_finish_caller_shutdown,
453 GNUNET_MQ_send (line->reliable_mq, e);
454 GNUNET_SERVER_receive_done (client, GNUNET_OK);
459 * Function to handle call request the client
461 * @param cls closure, NULL
462 * @param client the client from which the message is
463 * @param message the message from the client
466 handle_client_call_message (void *cls,
467 struct GNUNET_SERVER_Client *client,
468 const struct GNUNET_MessageHeader *message)
470 const struct ClientCallMessage *msg;
472 struct GNUNET_MQ_Envelope *e;
473 struct MeshPhoneRingMessage *ring;
475 msg = (struct ClientCallMessage *) message;
476 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
480 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
483 line = GNUNET_new (struct Line);
484 line->client = client;
485 GNUNET_SERVER_client_set_user_context (client, line);
486 GNUNET_SERVER_notification_context_add (nc, client);
487 line->target = msg->target;
488 GNUNET_CONTAINER_DLL_insert (lines_head,
491 line->remote_line = ntohl (msg->line);
492 line->status = LS_CALLER_CALLING;
493 line->channel_reliable = GNUNET_MESH_channel_create (mesh,
496 GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
499 line->reliable_mq = GNUNET_MESH_mq_create (line->channel_reliable);
500 line->local_line = local_line_cnt++;
501 e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
502 ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
503 ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
504 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
505 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
506 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
507 GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
509 ring->remote_line = msg->line;
510 ring->source_line = line->local_line;
511 ring->target = msg->target;
512 ring->source = my_identity;
513 ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
514 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518 "Sending RING message via mesh\n");
519 GNUNET_MQ_send (line->reliable_mq, e);
520 GNUNET_SERVER_receive_done (client, GNUNET_OK);
525 * Transmit audio data via unreliable mesh channel.
527 * @param cls the `struct Line` we are transmitting for
528 * @param size number of bytes available in @a buf
529 * @param buf where to copy the data
530 * @return number of bytes copied to @a buf
533 transmit_line_audio (void *cls,
537 struct Line *line = cls;
538 struct MeshAudioMessage *mam = buf;
540 line->unreliable_mth = NULL;
541 if ( (NULL == buf) ||
542 (size < sizeof (struct MeshAudioMessage) + line->audio_size) )
544 /* eh, other error handling? */
547 mam->header.size = htons (sizeof (struct MeshAudioMessage) + line->audio_size);
548 mam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO);
549 mam->remote_line = htonl (line->remote_line);
550 memcpy (&mam[1], line->audio_data, line->audio_size);
551 GNUNET_free (line->audio_data);
552 line->audio_data = NULL;
553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
554 "Sending %u bytes of audio data via mesh\n",
556 return sizeof (struct MeshAudioMessage) + line->audio_size;
561 * Function to handle audio data from the client
563 * @param cls closure, NULL
564 * @param client the client from which the message is
565 * @param message the message from the client
568 handle_client_audio_message (void *cls,
569 struct GNUNET_SERVER_Client *client,
570 const struct GNUNET_MessageHeader *message)
572 const struct ClientAudioMessage *msg;
576 size = ntohs (message->size) - sizeof (struct ClientAudioMessage);
577 msg = (struct ClientAudioMessage *) message;
578 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
582 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
585 switch (line->status)
587 case LS_CALLEE_LISTEN:
588 /* could be OK if the line just was closed by the other side */
589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
590 "Audio data dropped, channel is down\n");
591 GNUNET_SERVER_receive_done (client, GNUNET_OK);
593 case LS_CALLEE_RINGING:
594 case LS_CALLER_CALLING:
596 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
598 case LS_CALLEE_CONNECTED:
599 case LS_CALLER_CONNECTED:
600 /* common case, handled below */
602 case LS_CALLEE_SHUTDOWN:
603 case LS_CALLER_SHUTDOWN:
604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
605 "Mesh audio channel in shutdown; audio data dropped\n");
606 GNUNET_SERVER_receive_done (client, GNUNET_OK);
609 if (NULL == line->channel_unreliable)
611 GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
612 _("Mesh audio channel not ready; audio data dropped\n"));
613 GNUNET_SERVER_receive_done (client, GNUNET_OK);
616 if (NULL != line->unreliable_mth)
618 /* NOTE: we may want to not do this and instead combine the data */
619 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
620 "Bandwidth insufficient; dropping previous audio data segment with %u bytes\n",
621 (unsigned int) line->audio_size);
622 GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
623 line->unreliable_mth = NULL;
624 GNUNET_free (line->audio_data);
625 line->audio_data = NULL;
627 line->audio_size = size;
628 line->audio_data = GNUNET_malloc (line->audio_size);
629 memcpy (line->audio_data,
632 line->unreliable_mth = GNUNET_MESH_notify_transmit_ready (line->channel_unreliable,
634 GNUNET_TIME_UNIT_FOREVER_REL,
635 sizeof (struct MeshAudioMessage)
637 &transmit_line_audio,
639 GNUNET_SERVER_receive_done (client, GNUNET_OK);
644 * We are done signalling shutdown to the other peer.
645 * Destroy the channel.
647 * @param cls the `struct GNUNET_MESH_channel` to destroy
650 mq_done_destroy_channel (void *cls)
652 struct GNUNET_MESH_Channel *channel = cls;
654 GNUNET_MESH_channel_destroy (channel);
659 * Function to handle a ring message incoming over mesh
661 * @param cls closure, NULL
662 * @param channel the channel over which the message arrived
663 * @param channel_ctx the channel context, can be NULL
664 * @param message the incoming message
668 handle_mesh_ring_message (void *cls,
669 struct GNUNET_MESH_Channel *channel,
671 const struct GNUNET_MessageHeader *message)
673 const struct MeshPhoneRingMessage *msg;
675 struct GNUNET_MQ_Envelope *e;
676 struct MeshPhoneHangupMessage *hang_up;
677 struct ClientPhoneRingMessage cring;
679 msg = (const struct MeshPhoneRingMessage *) message;
680 if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
681 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
682 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
683 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) ||
685 GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
691 return GNUNET_SYSERR;
693 for (line = lines_head; NULL != line; line = line->next)
694 if ( (line->local_line == ntohl (msg->remote_line)) &&
695 (LS_CALLEE_LISTEN == line->status) )
699 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
700 _("No available phone for incoming call on line %u, sending HANG_UP signal\n"),
701 ntohl (msg->remote_line));
702 e = GNUNET_MQ_msg (hang_up, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
703 GNUNET_MQ_notify_sent (e,
704 &mq_done_destroy_channel,
706 GNUNET_MQ_send (line->reliable_mq, e);
707 GNUNET_MESH_receive_done (channel); /* needed? */
710 line->status = LS_CALLEE_RINGING;
711 line->remote_line = ntohl (msg->source_line);
712 line->channel_reliable = channel;
713 line->reliable_mq = GNUNET_MESH_mq_create (line->channel_reliable);
715 cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
716 cring.header.size = htons (sizeof (cring));
717 cring.cid = htonl (0 /* FIXME */);
718 cring.caller_id = msg->caller_id;
719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720 "Sending RING message to client\n");
721 GNUNET_SERVER_notification_context_unicast (nc,
725 GNUNET_MESH_receive_done (channel);
731 * Function to handle a hangup message incoming over mesh
733 * @param cls closure, NULL
734 * @param channel the channel over which the message arrived
735 * @param channel_ctx the channel context, can be NULL
736 * @param message the incoming message
740 handle_mesh_hangup_message (void *cls,
741 struct GNUNET_MESH_Channel *channel,
743 const struct GNUNET_MessageHeader *message)
745 struct Line *line = *channel_ctx;
746 const struct MeshPhoneHangupMessage *msg;
748 size_t len = ntohs (message->size) - sizeof (struct MeshPhoneHangupMessage);
749 char buf[len + sizeof (struct ClientPhoneHangupMessage)];
750 struct ClientPhoneHangupMessage *hup;
752 msg = (const struct MeshPhoneHangupMessage *) message;
753 len = ntohs (msg->header.size) - sizeof (struct MeshPhoneHangupMessage);
754 reason = (const char *) &msg[1];
756 ('\0' != reason[len - 1]) )
763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
764 "HANGUP message received for non-existing line, dropping channel.\n");
765 return GNUNET_SYSERR;
768 switch (line->status)
770 case LS_CALLEE_LISTEN:
772 return GNUNET_SYSERR;
773 case LS_CALLEE_RINGING:
774 line->status = LS_CALLEE_LISTEN;
775 destroy_line_mesh_channels (line);
777 case LS_CALLEE_CONNECTED:
778 line->status = LS_CALLEE_LISTEN;
779 destroy_line_mesh_channels (line);
781 case LS_CALLEE_SHUTDOWN:
782 line->status = LS_CALLEE_LISTEN;
783 destroy_line_mesh_channels (line);
785 case LS_CALLER_CALLING:
786 line->status = LS_CALLER_SHUTDOWN;
787 mq_done_finish_caller_shutdown (line);
789 case LS_CALLER_CONNECTED:
790 line->status = LS_CALLER_SHUTDOWN;
791 mq_done_finish_caller_shutdown (line);
793 case LS_CALLER_SHUTDOWN:
794 mq_done_finish_caller_shutdown (line);
797 hup = (struct ClientPhoneHangupMessage *) buf;
798 hup->header.size = sizeof (buf);
799 hup->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
800 memcpy (&hup[1], reason, len);
801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
802 "Sending HANG UP message to client with reason `%s'\n",
804 GNUNET_SERVER_notification_context_unicast (nc,
808 GNUNET_MESH_receive_done (channel);
814 * Function to handle a pickup message incoming over mesh
816 * @param cls closure, NULL
817 * @param channel the channel over which the message arrived
818 * @param channel_ctx the channel context, can be NULL
819 * @param message the incoming message
823 handle_mesh_pickup_message (void *cls,
824 struct GNUNET_MESH_Channel *channel,
826 const struct GNUNET_MessageHeader *message)
828 const struct MeshPhonePickupMessage *msg;
829 struct Line *line = *channel_ctx;
830 const char *metadata;
831 size_t len = ntohs (message->size) - sizeof (struct MeshPhonePickupMessage);
832 char buf[len + sizeof (struct ClientPhonePickupMessage)];
833 struct ClientPhonePickupMessage *pick;
835 msg = (const struct MeshPhonePickupMessage *) message;
836 len = ntohs (msg->header.size) - sizeof (struct MeshPhonePickupMessage);
837 metadata = (const char *) &msg[1];
839 ('\0' != metadata[len - 1]) )
846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
847 "PICKUP message received for non-existing line, dropping channel.\n");
848 return GNUNET_SYSERR;
850 GNUNET_MESH_receive_done (channel);
851 switch (line->status)
853 case LS_CALLEE_LISTEN:
855 return GNUNET_SYSERR;
856 case LS_CALLEE_RINGING:
857 case LS_CALLEE_CONNECTED:
859 destroy_line_mesh_channels (line);
860 line->status = LS_CALLEE_LISTEN;
861 return GNUNET_SYSERR;
862 case LS_CALLEE_SHUTDOWN:
864 line->status = LS_CALLEE_LISTEN;
865 destroy_line_mesh_channels (line);
867 case LS_CALLER_CALLING:
868 line->status = LS_CALLER_CONNECTED;
870 case LS_CALLER_CONNECTED:
873 case LS_CALLER_SHUTDOWN:
875 mq_done_finish_caller_shutdown (line);
876 return GNUNET_SYSERR;
878 pick = (struct ClientPhonePickupMessage *) buf;
879 pick->header.size = sizeof (buf);
880 pick->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICKED_UP);
881 memcpy (&pick[1], metadata, len);
882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
883 "Sending PICKED UP message to client with metadata `%s'\n",
885 GNUNET_SERVER_notification_context_unicast (nc,
889 line->channel_unreliable = GNUNET_MESH_channel_create (mesh,
892 GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
895 if (NULL == line->channel_unreliable)
904 * Function to handle a suspend message incoming over mesh
906 * @param cls closure, NULL
907 * @param channel the channel over which the message arrived
908 * @param channel_ctx the channel context, can be NULL
909 * @param message the incoming message
913 handle_mesh_suspend_message (void *cls,
914 struct GNUNET_MESH_Channel *channel,
916 const struct GNUNET_MessageHeader *message)
918 struct Line *line = *channel_ctx;
919 struct ClientPhoneSuspendMessage suspend;
923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924 "SUSPEND message received for non-existing line, dropping channel.\n");
925 return GNUNET_SYSERR;
927 suspend.header.size = sizeof (suspend);
928 suspend.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_SUSPEND);
929 suspend.cid = htonl (0 /* FIXME */);
930 GNUNET_MESH_receive_done (channel);
932 switch (line->status)
934 case LS_CALLEE_LISTEN:
936 return GNUNET_SYSERR;
937 case LS_CALLEE_RINGING:
940 case LS_CALLEE_CONNECTED:
943 case LS_CALLEE_SHUTDOWN:
946 case LS_CALLER_CALLING:
947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
948 "Sending SUSPEND message to client\n");
949 GNUNET_SERVER_notification_context_unicast (nc,
953 line->status = LS_CALLER_SHUTDOWN;
954 mq_done_finish_caller_shutdown (line);
956 case LS_CALLER_CONNECTED:
958 line->status = LS_CALLER_SHUTDOWN;
959 mq_done_finish_caller_shutdown (line);
961 case LS_CALLER_SHUTDOWN:
963 mq_done_finish_caller_shutdown (line);
971 * Function to handle a resume message incoming over mesh
973 * @param cls closure, NULL
974 * @param channel the channel over which the message arrived
975 * @param channel_ctx the channel context, can be NULL
976 * @param message the incoming message
980 handle_mesh_resume_message (void *cls,
981 struct GNUNET_MESH_Channel *channel,
983 const struct GNUNET_MessageHeader *message)
985 struct Line *line = *channel_ctx;
986 struct ClientPhoneResumeMessage resume;
990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991 "RESUME message received for non-existing line, dropping channel.\n");
992 return GNUNET_SYSERR;
994 resume.header.size = sizeof (resume);
995 resume.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RESUME);
996 resume.cid = htonl (0 /* FIXME */);
997 GNUNET_MESH_receive_done (channel);
999 switch (line->status)
1001 case LS_CALLEE_LISTEN:
1003 return GNUNET_SYSERR;
1004 case LS_CALLEE_RINGING:
1005 GNUNET_break_op (0);
1007 case LS_CALLEE_CONNECTED:
1008 GNUNET_break_op (0);
1010 case LS_CALLEE_SHUTDOWN:
1011 GNUNET_break_op (0);
1013 case LS_CALLER_CALLING:
1014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1015 "Sending SUSPEND message to client\n");
1016 GNUNET_SERVER_notification_context_unicast (nc,
1020 line->status = LS_CALLER_SHUTDOWN;
1021 mq_done_finish_caller_shutdown (line);
1023 case LS_CALLER_CONNECTED:
1024 GNUNET_break_op (0);
1025 line->status = LS_CALLER_SHUTDOWN;
1026 mq_done_finish_caller_shutdown (line);
1028 case LS_CALLER_SHUTDOWN:
1029 GNUNET_break_op (0);
1030 mq_done_finish_caller_shutdown (line);
1038 * Function to handle an audio message incoming over mesh
1040 * @param cls closure, NULL
1041 * @param channel the channel over which the message arrived
1042 * @param channel_ctx the channel context, can be NULL
1043 * @param message the incoming message
1044 * @return #GNUNET_OK
1047 handle_mesh_audio_message (void *cls,
1048 struct GNUNET_MESH_Channel *channel,
1050 const struct GNUNET_MessageHeader *message)
1052 const struct MeshAudioMessage *msg;
1053 struct Line *line = *channel_ctx;
1054 struct GNUNET_PeerIdentity sender;
1055 size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
1056 char buf[msize + sizeof (struct ClientAudioMessage)];
1057 struct ClientAudioMessage *cam;
1058 const union GNUNET_MESH_ChannelInfo *info;
1060 msg = (const struct MeshAudioMessage *) message;
1063 info = GNUNET_MESH_channel_get_info (channel,
1064 GNUNET_MESH_OPTION_PEER);
1070 sender = *(info->peer);
1071 for (line = lines_head; NULL != line; line = line->next)
1072 if ( (line->local_line == ntohl (msg->remote_line)) &&
1073 (LS_CALLEE_CONNECTED == line->status) &&
1074 (0 == memcmp (&line->target,
1076 sizeof (struct GNUNET_PeerIdentity))) &&
1077 (NULL == line->channel_unreliable) )
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1082 "Received AUDIO data for non-existing line %u, dropping.\n",
1083 ntohl (msg->remote_line));
1084 return GNUNET_SYSERR;
1086 line->channel_unreliable = channel;
1087 *channel_ctx = line;
1089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1090 "Forwarding %u bytes of AUDIO data to client\n",
1092 cam = (struct ClientAudioMessage *) buf;
1093 cam->header.size = htons (sizeof (buf));
1094 cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
1095 memcpy (&cam[1], &msg[1], msize);
1096 GNUNET_SERVER_notification_context_unicast (nc,
1100 GNUNET_MESH_receive_done (channel);
1106 * Method called whenever another peer has added us to a channel
1107 * the other peer initiated.
1109 * @param cls closure
1110 * @param channel new handle to the channel
1111 * @param initiator peer that started the channel
1113 * @return initial channel context for the channel (can be NULL -- that's not an error)
1116 inbound_channel (void *cls,
1117 struct GNUNET_MESH_Channel *channel,
1118 const struct GNUNET_PeerIdentity *initiator,
1121 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1122 _("Received incoming channel on port %u\n"),
1123 (unsigned int) port);
1129 * Function called whenever an inbound channel is destroyed. Should clean up
1130 * any associated state.
1132 * @param cls closure (set from #GNUNET_MESH_connect)
1133 * @param channel connection to the other end (henceforth invalid)
1134 * @param channel_ctx place where local state associated
1135 * with the channel is stored
1138 inbound_end (void *cls,
1139 const struct GNUNET_MESH_Channel *channel,
1142 struct Line *line = channel_ctx;
1143 struct ClientPhoneHangupMessage hup;
1147 if (line->channel_unreliable == channel)
1149 if (NULL != line->unreliable_mth)
1151 GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
1152 line->unreliable_mth = NULL;
1154 line->channel_unreliable = NULL;
1157 if (line->channel_reliable != channel)
1159 line->channel_reliable = NULL;
1161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1162 "Mesh channel destroyed by mesh\n");
1163 hup.header.size = sizeof (hup);
1164 hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1165 switch (line->status)
1167 case LS_CALLEE_LISTEN:
1170 case LS_CALLEE_RINGING:
1171 case LS_CALLEE_CONNECTED:
1172 GNUNET_SERVER_notification_context_unicast (nc,
1176 line->status = LS_CALLEE_LISTEN;
1178 case LS_CALLEE_SHUTDOWN:
1179 line->status = LS_CALLEE_LISTEN;
1181 case LS_CALLER_CALLING:
1182 case LS_CALLER_CONNECTED:
1183 GNUNET_SERVER_notification_context_unicast (nc,
1188 case LS_CALLER_SHUTDOWN:
1191 destroy_line_mesh_channels (line);
1196 * A client disconnected. Remove all of its data structure entries.
1198 * @param cls closure, NULL
1199 * @param client identification of the client
1202 handle_client_disconnect (void *cls,
1203 struct GNUNET_SERVER_Client *client)
1209 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
1212 GNUNET_SERVER_client_set_user_context (client, (void *)NULL);
1213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1214 "Client disconnected, closing line\n");
1215 GNUNET_CONTAINER_DLL_remove (lines_head,
1218 destroy_line_mesh_channels (line);
1219 GNUNET_free_non_null (line->audio_data);
1227 * @param cls closure, NULL
1228 * @param tc the task context
1231 do_shutdown (void *cls,
1232 const struct GNUNET_SCHEDULER_TaskContext *tc)
1236 GNUNET_MESH_disconnect (mesh);
1241 GNUNET_SERVER_notification_context_destroy (nc);
1248 * Main function that will be run by the scheduler.
1250 * @param cls closure
1251 * @param server server handle
1252 * @param c configuration
1256 struct GNUNET_SERVER_Handle *server,
1257 const struct GNUNET_CONFIGURATION_Handle *c)
1259 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1260 {&handle_client_register_message, NULL,
1261 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1262 sizeof (struct ClientPhoneRegisterMessage)},
1263 {&handle_client_pickup_message, NULL,
1264 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1266 {&handle_client_hangup_message, NULL,
1267 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1269 {&handle_client_call_message, NULL,
1270 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1272 {&handle_client_audio_message, NULL,
1273 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1277 static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1278 {&handle_mesh_ring_message,
1279 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
1280 sizeof (struct MeshPhoneRingMessage)},
1281 {&handle_mesh_hangup_message,
1282 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
1284 {&handle_mesh_pickup_message,
1285 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
1287 {&handle_mesh_suspend_message,
1288 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_SUSPEND,
1289 sizeof (struct MeshPhoneSuspendMessage)},
1290 {&handle_mesh_resume_message,
1291 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RESUME,
1292 sizeof (struct MeshPhoneResumeMessage)},
1293 {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
1297 static uint32_t ports[] = {
1298 GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
1299 GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1304 GNUNET_assert (GNUNET_OK ==
1305 GNUNET_CRYPTO_get_peer_identity (cfg,
1307 mesh = GNUNET_MESH_connect (cfg,
1317 GNUNET_SCHEDULER_shutdown ();
1320 nc = GNUNET_SERVER_notification_context_create (server, 16);
1321 GNUNET_SERVER_add_handlers (server, server_handlers);
1322 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1323 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1330 * The main function for the conversation service.
1332 * @param argc number of arguments from the command line
1333 * @param argv command line arguments
1334 * @return 0 ok, 1 on error
1340 return (GNUNET_OK ==
1341 GNUNET_SERVICE_run (argc, argv,
1343 GNUNET_SERVICE_OPTION_NONE,
1344 &run, NULL)) ? 0 : 1;
1347 /* end of gnunet-service-conversation.c */