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 tunnel (or, if it is an
90 * open line, is waiting for a mesh tunnel).
105 * Handle for the reliable tunnel (contol data)
107 struct GNUNET_MESH_Tunnel *tunnel_reliable;
110 * Handle for unreliable tunnel (audio data)
112 struct GNUNET_MESH_Tunnel *tunnel_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 e = GNUNET_MQ_msg_extra (mppm,
299 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP);
300 memcpy (&mppm[1], meta, len);
301 GNUNET_MQ_send (line->reliable_mq, e);
302 GNUNET_SERVER_receive_done (client, GNUNET_OK);
307 * Destroy the mesh tunnels of a line.
309 * @param line line to shutdown tunnels of
312 destroy_line_mesh_tunnels (struct Line *line)
314 if (NULL != line->reliable_mq)
316 GNUNET_MQ_destroy (line->reliable_mq);
317 line->reliable_mq = NULL;
319 if (NULL != line->unreliable_mth)
321 GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
322 line->unreliable_mth = NULL;
324 if (NULL != line->tunnel_unreliable)
326 GNUNET_MESH_tunnel_destroy (line->tunnel_unreliable);
327 line->tunnel_unreliable = NULL;
329 if (NULL != line->tunnel_reliable)
331 GNUNET_MESH_tunnel_destroy (line->tunnel_reliable);
332 line->tunnel_reliable = NULL;
338 * We are done signalling shutdown to the other peer. Close down
339 * (or reset) the line.
341 * @param cls the `struct Line` to reset/terminate
344 mq_done_finish_caller_shutdown (void *cls)
346 struct Line *line = cls;
348 switch (line->status)
350 case LS_CALLEE_LISTEN:
353 case LS_CALLEE_RINGING:
356 case LS_CALLEE_CONNECTED:
359 case LS_CALLEE_SHUTDOWN:
360 line->status = LS_CALLEE_LISTEN;
361 destroy_line_mesh_tunnels (line);
363 case LS_CALLER_CALLING:
364 line->status = LS_CALLER_SHUTDOWN;
366 case LS_CALLER_CONNECTED:
367 line->status = LS_CALLER_SHUTDOWN;
369 case LS_CALLER_SHUTDOWN:
370 destroy_line_mesh_tunnels (line);
371 GNUNET_CONTAINER_DLL_remove (lines_head,
374 GNUNET_free_non_null (line->audio_data);
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 e = GNUNET_MQ_msg_extra (mhum,
445 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
446 memcpy (&mhum[1], meta, len);
447 GNUNET_MQ_notify_sent (e,
448 &mq_done_finish_caller_shutdown,
450 GNUNET_MQ_send (line->reliable_mq, e);
451 GNUNET_SERVER_receive_done (client, GNUNET_OK);
456 * Function to handle call request the client
458 * @param cls closure, NULL
459 * @param client the client from which the message is
460 * @param message the message from the client
463 handle_client_call_message (void *cls,
464 struct GNUNET_SERVER_Client *client,
465 const struct GNUNET_MessageHeader *message)
467 const struct ClientCallMessage *msg;
469 struct GNUNET_MQ_Envelope *e;
470 struct MeshPhoneRingMessage *ring;
472 msg = (struct ClientCallMessage *) message;
473 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
477 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
480 line = GNUNET_new (struct Line);
481 line->client = client;
482 GNUNET_SERVER_client_set_user_context (client, line);
483 GNUNET_SERVER_notification_context_add (nc, client);
484 line->target = msg->target;
485 GNUNET_CONTAINER_DLL_insert (lines_head,
488 line->remote_line = ntohl (msg->line);
489 line->status = LS_CALLER_CALLING;
490 line->tunnel_reliable = GNUNET_MESH_tunnel_create (mesh,
493 GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
496 line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
497 line->local_line = local_line_cnt++;
498 e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
499 ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
500 ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
501 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
502 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
503 sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
504 GNUNET_CRYPTO_ecc_key_get_public_for_signature (&msg->caller_id,
506 ring->remote_line = msg->line;
507 ring->source_line = line->local_line;
508 ring->target = msg->target;
509 ring->source = my_identity;
510 ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
511 GNUNET_CRYPTO_ecc_sign (&msg->caller_id,
514 GNUNET_MQ_send (line->reliable_mq, e);
515 GNUNET_SERVER_receive_done (client, GNUNET_OK);
520 * Transmit audio data via unreliable mesh channel.
522 * @param cls the `struct Line` we are transmitting for
523 * @param size number of bytes available in @a buf
524 * @param buf where to copy the data
525 * @return number of bytes copied to @buf
528 transmit_line_audio (void *cls,
532 struct Line *line = cls;
533 struct MeshAudioMessage *mam = buf;
535 line->unreliable_mth = NULL;
536 if ( (NULL == buf) ||
537 (size < sizeof (struct MeshAudioMessage) + line->audio_size) )
539 /* eh, other error handling? */
542 mam->header.size = htons (sizeof (struct MeshAudioMessage) + line->audio_size);
543 mam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO);
544 mam->remote_line = htonl (line->remote_line);
545 memcpy (&mam[1], line->audio_data, line->audio_size);
546 GNUNET_free (line->audio_data);
547 line->audio_data = NULL;
548 return sizeof (struct MeshAudioMessage) + line->audio_size;
553 * Function to handle audio data from the client
555 * @param cls closure, NULL
556 * @param client the client from which the message is
557 * @param message the message from the client
560 handle_client_audio_message (void *cls,
561 struct GNUNET_SERVER_Client *client,
562 const struct GNUNET_MessageHeader *message)
564 const struct ClientAudioMessage *msg;
568 size = ntohs (message->size) - sizeof (struct ClientAudioMessage);
569 msg = (struct ClientAudioMessage *) message;
570 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
574 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
577 switch (line->status)
579 case LS_CALLEE_LISTEN:
580 case LS_CALLEE_RINGING:
581 case LS_CALLER_CALLING:
583 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
585 case LS_CALLEE_CONNECTED:
586 case LS_CALLER_CONNECTED:
587 /* common case, handled below */
589 case LS_CALLEE_SHUTDOWN:
590 case LS_CALLER_SHUTDOWN:
591 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592 "Mesh audio channel in shutdown; audio data dropped\n");
593 GNUNET_SERVER_receive_done (client, GNUNET_OK);
596 if (NULL == line->tunnel_unreliable)
598 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
599 _("Mesh audio channel not ready; audio data dropped\n"));
600 GNUNET_SERVER_receive_done (client, GNUNET_OK);
603 if (NULL != line->unreliable_mth)
605 /* NOTE: we may want to not do this and instead combine the data */
606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
607 "Dropping previous audio data segment with %u bytes\n",
609 GNUNET_MESH_notify_transmit_ready_cancel (line->unreliable_mth);
610 GNUNET_free (line->audio_data);
612 line->audio_size = size;
613 line->audio_data = GNUNET_malloc (line->audio_size);
614 memcpy (line->audio_data,
617 line->unreliable_mth = GNUNET_MESH_notify_transmit_ready (line->tunnel_unreliable,
619 GNUNET_TIME_UNIT_FOREVER_REL,
620 sizeof (struct MeshAudioMessage)
622 &transmit_line_audio,
624 GNUNET_SERVER_receive_done (client, GNUNET_OK);
629 * We are done signalling shutdown to the other peer.
630 * Destroy the tunnel.
632 * @param cls the `struct GNUNET_MESH_tunnel` to destroy
635 mq_done_destroy_tunnel (void *cls)
637 struct GNUNET_MESH_Tunnel *tunnel = cls;
639 GNUNET_MESH_tunnel_destroy (tunnel);
644 * Function to handle a ring message incoming over mesh
646 * @param cls closure, NULL
647 * @param tunnel the tunnel over which the message arrived
648 * @param tunnel_ctx the tunnel context, can be NULL
649 * @param message the incoming message
653 handle_mesh_ring_message (void *cls,
654 struct GNUNET_MESH_Tunnel *tunnel,
656 const struct GNUNET_MessageHeader *message)
658 const struct MeshPhoneRingMessage *msg;
660 struct GNUNET_MQ_Envelope *e;
661 struct MeshPhoneBusyMessage *busy;
662 struct ClientPhoneRingMessage cring;
664 msg = (const struct MeshPhoneRingMessage *) message;
665 if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
666 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
667 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
668 sizeof (struct GNUNET_CRYPTO_EccPublicSignKey))) ||
670 GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
676 return GNUNET_SYSERR;
678 for (line = lines_head; NULL != line; line = line->next)
679 if ( (line->local_line == ntohl (msg->remote_line)) &&
680 (LS_CALLEE_LISTEN == line->status) )
684 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
685 _("No available phone for incoming call on line %u, sending BUSY signal\n"),
686 ntohl (msg->remote_line));
687 e = GNUNET_MQ_msg (busy, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY);
688 GNUNET_MQ_notify_sent (e,
689 &mq_done_destroy_tunnel,
691 GNUNET_MQ_send (line->reliable_mq, e);
692 GNUNET_MESH_receive_done (tunnel); /* needed? */
695 line->status = LS_CALLEE_RINGING;
696 line->remote_line = ntohl (msg->source_line);
697 line->tunnel_reliable = tunnel;
698 line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
700 cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
701 cring.header.size = htons (sizeof (cring));
702 cring.reserved = htonl (0);
703 cring.caller_id = msg->caller_id;
704 GNUNET_SERVER_notification_context_unicast (nc,
708 GNUNET_MESH_receive_done (tunnel);
714 * Function to handle a hangup message incoming over mesh
716 * @param cls closure, NULL
717 * @param tunnel the tunnel over which the message arrived
718 * @param tunnel_ctx the tunnel context, can be NULL
719 * @param message the incoming message
723 handle_mesh_hangup_message (void *cls,
724 struct GNUNET_MESH_Tunnel *tunnel,
726 const struct GNUNET_MessageHeader *message)
728 struct Line *line = *tunnel_ctx;
729 const struct MeshPhoneHangupMessage *msg;
731 size_t len = ntohs (message->size) - sizeof (struct MeshPhoneHangupMessage);
732 char buf[len + sizeof (struct ClientPhoneHangupMessage)];
733 struct ClientPhoneHangupMessage *hup;
735 msg = (const struct MeshPhoneHangupMessage *) message;
736 len = ntohs (msg->header.size) - sizeof (struct MeshPhoneHangupMessage);
737 reason = (const char *) &msg[1];
739 ('\0' != reason[len - 1]) )
746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
747 "HANGUP message received for non-existing line, dropping tunnel.\n");
748 return GNUNET_SYSERR;
751 switch (line->status)
753 case LS_CALLEE_LISTEN:
755 return GNUNET_SYSERR;
756 case LS_CALLEE_RINGING:
757 line->status = LS_CALLEE_LISTEN;
758 destroy_line_mesh_tunnels (line);
760 case LS_CALLEE_CONNECTED:
761 line->status = LS_CALLEE_LISTEN;
762 destroy_line_mesh_tunnels (line);
764 case LS_CALLEE_SHUTDOWN:
765 line->status = LS_CALLEE_LISTEN;
766 destroy_line_mesh_tunnels (line);
768 case LS_CALLER_CALLING:
769 line->status = LS_CALLER_SHUTDOWN;
770 mq_done_finish_caller_shutdown (line);
772 case LS_CALLER_CONNECTED:
773 line->status = LS_CALLER_SHUTDOWN;
774 mq_done_finish_caller_shutdown (line);
776 case LS_CALLER_SHUTDOWN:
777 mq_done_finish_caller_shutdown (line);
780 hup = (struct ClientPhoneHangupMessage *) buf;
781 hup->header.size = sizeof (buf);
782 hup->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
783 memcpy (&hup[1], reason, len);
784 GNUNET_SERVER_notification_context_unicast (nc,
788 GNUNET_MESH_receive_done (tunnel);
794 * Function to handle a pickup message incoming over mesh
796 * @param cls closure, NULL
797 * @param tunnel the tunnel over which the message arrived
798 * @param tunnel_ctx the tunnel context, can be NULL
799 * @param message the incoming message
803 handle_mesh_pickup_message (void *cls,
804 struct GNUNET_MESH_Tunnel *tunnel,
806 const struct GNUNET_MessageHeader *message)
808 const struct MeshPhonePickupMessage *msg;
809 struct Line *line = *tunnel_ctx;
810 const char *metadata;
811 size_t len = ntohs (message->size) - sizeof (struct MeshPhonePickupMessage);
812 char buf[len + sizeof (struct ClientPhonePickupMessage)];
813 struct ClientPhonePickupMessage *pick;
815 msg = (const struct MeshPhonePickupMessage *) message;
816 len = ntohs (msg->header.size) - sizeof (struct MeshPhonePickupMessage);
817 metadata = (const char *) &msg[1];
819 ('\0' != metadata[len - 1]) )
826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
827 "PICKUP message received for non-existing line, dropping tunnel.\n");
828 return GNUNET_SYSERR;
830 GNUNET_MESH_receive_done (tunnel);
831 switch (line->status)
833 case LS_CALLEE_LISTEN:
835 return GNUNET_SYSERR;
836 case LS_CALLEE_RINGING:
837 case LS_CALLEE_CONNECTED:
839 destroy_line_mesh_tunnels (line);
840 line->status = LS_CALLEE_LISTEN;
841 return GNUNET_SYSERR;
842 case LS_CALLEE_SHUTDOWN:
844 line->status = LS_CALLEE_LISTEN;
845 destroy_line_mesh_tunnels (line);
847 case LS_CALLER_CALLING:
848 line->status = LS_CALLER_CONNECTED;
850 case LS_CALLER_CONNECTED:
853 case LS_CALLER_SHUTDOWN:
855 mq_done_finish_caller_shutdown (line);
856 return GNUNET_SYSERR;
858 pick = (struct ClientPhonePickupMessage *) buf;
859 pick->header.size = sizeof (buf);
860 pick->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP);
861 memcpy (&pick[1], metadata, len);
862 GNUNET_SERVER_notification_context_unicast (nc,
866 line->tunnel_unreliable = GNUNET_MESH_tunnel_create (mesh,
869 GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
877 * Function to handle a busy message incoming over mesh
879 * @param cls closure, NULL
880 * @param tunnel the tunnel over which the message arrived
881 * @param tunnel_ctx the tunnel context, can be NULL
882 * @param message the incoming message
886 handle_mesh_busy_message (void *cls,
887 struct GNUNET_MESH_Tunnel *tunnel,
889 const struct GNUNET_MessageHeader *message)
891 struct Line *line = *tunnel_ctx;
892 struct ClientPhoneBusyMessage busy;
896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
897 "HANGUP message received for non-existing line, dropping tunnel.\n");
898 return GNUNET_SYSERR;
900 busy.header.size = sizeof (busy);
901 busy.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_BUSY);
902 GNUNET_SERVER_notification_context_unicast (nc,
906 GNUNET_MESH_receive_done (tunnel);
908 switch (line->status)
910 case LS_CALLEE_LISTEN:
912 return GNUNET_SYSERR;
913 case LS_CALLEE_RINGING:
916 case LS_CALLEE_CONNECTED:
919 case LS_CALLEE_SHUTDOWN:
922 case LS_CALLER_CALLING:
923 line->status = LS_CALLER_SHUTDOWN;
924 mq_done_finish_caller_shutdown (line);
926 case LS_CALLER_CONNECTED:
927 line->status = LS_CALLER_SHUTDOWN;
928 mq_done_finish_caller_shutdown (line);
930 case LS_CALLER_SHUTDOWN:
931 mq_done_finish_caller_shutdown (line);
939 * Function to handle an audio message incoming over mesh
941 * @param cls closure, NULL
942 * @param tunnel the tunnel over which the message arrived
943 * @param tunnel_ctx the tunnel context, can be NULL
944 * @param message the incoming message
948 handle_mesh_audio_message (void *cls,
949 struct GNUNET_MESH_Tunnel *tunnel,
951 const struct GNUNET_MessageHeader *message)
953 const struct MeshAudioMessage *msg;
954 struct Line *line = *tunnel_ctx;
955 struct GNUNET_PeerIdentity sender;
956 size_t msize = ntohs (message->size) - sizeof (struct MeshAudioMessage);
957 char buf[msize + sizeof (struct ClientAudioMessage)];
958 struct ClientAudioMessage *cam;
960 msg = (const struct MeshAudioMessage *) message;
963 sender = *GNUNET_MESH_tunnel_get_info (tunnel,
964 GNUNET_MESH_OPTION_PEER)->peer;
965 for (line = lines_head; NULL != line; line = line->next)
966 if ( (line->local_line == ntohl (msg->remote_line)) &&
967 (LS_CALLEE_CONNECTED == line->status) &&
968 (0 == memcmp (&line->target,
970 sizeof (struct GNUNET_PeerIdentity))) &&
971 (NULL == line->tunnel_unreliable) )
975 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
976 "Received AUDIO data for non-existing line %u, dropping.\n",
977 ntohl (msg->remote_line));
978 return GNUNET_SYSERR;
980 line->tunnel_unreliable = tunnel;
983 cam = (struct ClientAudioMessage *) buf;
984 cam->header.size = htons (sizeof (buf));
985 cam->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
986 memcpy (&cam[1], &msg[1], msize);
987 GNUNET_SERVER_notification_context_unicast (nc,
991 GNUNET_MESH_receive_done (tunnel);
997 * Method called whenever another peer has added us to a tunnel
998 * the other peer initiated.
1000 * @param cls closure
1001 * @param tunnel new handle to the tunnel
1002 * @param initiator peer that started the tunnel
1004 * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
1007 inbound_tunnel (void *cls,
1008 struct GNUNET_MESH_Tunnel *tunnel,
1009 const struct GNUNET_PeerIdentity *initiator,
1012 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1013 _("Received incoming tunnel on port %d\n"),
1020 * Function called whenever an inbound tunnel is destroyed. Should clean up
1021 * any associated state.
1023 * @param cls closure (set from #GNUNET_MESH_connect)
1024 * @param tunnel connection to the other end (henceforth invalid)
1025 * @param tunnel_ctx place where local state associated
1026 * with the tunnel is stored
1029 inbound_end (void *cls,
1030 const struct GNUNET_MESH_Tunnel *tunnel,
1033 struct Line *line = tunnel_ctx;
1034 struct ClientPhoneHangupMessage hup;
1038 if (line->tunnel_unreliable == tunnel)
1040 line->tunnel_unreliable = NULL;
1043 hup.header.size = sizeof (hup);
1044 hup.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP);
1045 switch (line->status)
1047 case LS_CALLEE_LISTEN:
1050 case LS_CALLEE_RINGING:
1051 case LS_CALLEE_CONNECTED:
1052 GNUNET_SERVER_notification_context_unicast (nc,
1056 line->status = LS_CALLEE_LISTEN;
1058 case LS_CALLEE_SHUTDOWN:
1059 line->status = LS_CALLEE_LISTEN;
1060 destroy_line_mesh_tunnels (line);
1062 case LS_CALLER_CALLING:
1063 case LS_CALLER_CONNECTED:
1064 GNUNET_SERVER_notification_context_unicast (nc,
1068 destroy_line_mesh_tunnels (line);
1069 GNUNET_CONTAINER_DLL_remove (lines_head,
1072 GNUNET_free_non_null (line->audio_data);
1075 case LS_CALLER_SHUTDOWN:
1076 destroy_line_mesh_tunnels (line);
1077 GNUNET_CONTAINER_DLL_remove (lines_head,
1087 * A client disconnected. Remove all of its data structure entries.
1089 * @param cls closure, NULL
1090 * @param client identification of the client
1093 handle_client_disconnect (void *cls,
1094 struct GNUNET_SERVER_Client *client)
1098 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
1101 GNUNET_CONTAINER_DLL_remove (lines_head,
1105 GNUNET_SERVER_client_set_user_context (client, NULL);
1112 * @param cls closure, NULL
1113 * @param tc the task context
1116 do_shutdown (void *cls,
1117 const struct GNUNET_SCHEDULER_TaskContext *tc)
1121 GNUNET_MESH_disconnect (mesh);
1126 GNUNET_SERVER_notification_context_destroy (nc);
1133 * Main function that will be run by the scheduler.
1135 * @param cls closure
1136 * @param server server handle
1137 * @param c configuration
1141 struct GNUNET_SERVER_Handle *server,
1142 const struct GNUNET_CONFIGURATION_Handle *c)
1144 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
1145 {&handle_client_register_message, NULL,
1146 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
1147 sizeof (struct ClientPhoneRegisterMessage)},
1148 {&handle_client_pickup_message, NULL,
1149 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
1151 {&handle_client_hangup_message, NULL,
1152 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
1154 {&handle_client_call_message, NULL,
1155 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
1157 {&handle_client_audio_message, NULL,
1158 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
1162 static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1163 {&handle_mesh_ring_message,
1164 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
1165 sizeof (struct MeshPhoneRingMessage)},
1166 {&handle_mesh_hangup_message,
1167 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
1169 {&handle_mesh_pickup_message,
1170 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
1172 {&handle_mesh_busy_message,
1173 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY,
1174 sizeof (struct MeshPhoneBusyMessage)},
1175 {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
1179 static uint32_t ports[] = {
1180 GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
1181 GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
1186 GNUNET_assert (GNUNET_OK ==
1187 GNUNET_CRYPTO_get_host_identity (cfg,
1189 mesh = GNUNET_MESH_connect (cfg,
1199 GNUNET_SCHEDULER_shutdown ();
1202 nc = GNUNET_SERVER_notification_context_create (server, 16);
1203 GNUNET_SERVER_add_handlers (server, server_handlers);
1204 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1205 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1212 * The main function for the conversation service.
1214 * @param argc number of arguments from the command line
1215 * @param argv command line arguments
1216 * @return 0 ok, 1 on error
1222 return (GNUNET_OK ==
1223 GNUNET_SERVICE_run (argc, argv,
1225 GNUNET_SERVICE_OPTION_NONE,
1226 &run, NULL)) ? 0 : 1;
1229 /* end of gnunet-service-conversation.c */