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 are waiting for the phone to be picked up.
77 * We're in shutdown, sending hangup messages before cleaning up.
84 * A line connects a local client with a mesh tunnel (or, if it is an
85 * open line, is waiting for a mesh tunnel).
100 * Handle for the reliable tunnel (contol data)
102 struct GNUNET_MESH_Tunnel *tunnel_reliable;
105 * Handle for unreliable tunnel (audio data)
107 struct GNUNET_MESH_Tunnel *tunnel_unreliable;
110 * Transmit handle for pending audio messages
112 struct GNUNET_MESH_TransmitHandle *unreliable_mth;
115 * Message queue for control messages
117 struct GNUNET_MQ_Handle *reliable_mq;
120 * Handle to the line client.
122 struct GNUNET_SERVER_Client *client;
125 * Target of the line, if we are the caller.
127 struct GNUNET_PeerIdentity target;
135 * Remote line number.
137 uint32_t remote_line;
140 * Current status of this line.
142 enum LineStatus status;
150 static const struct GNUNET_CONFIGURATION_Handle *cfg;
153 * Notification context containing all connected clients.
155 static struct GNUNET_SERVER_NotificationContext *nc;
160 static struct GNUNET_MESH_Handle *mesh;
163 * Identity of this peer.
165 static struct GNUNET_PeerIdentity my_identity;
168 * Head of DLL of active lines.
170 static struct Line *lines_head;
173 * Tail of DLL of active lines.
175 static struct Line *lines_tail;
178 * Counter for generating local line numbers.
179 * FIXME: randomize generation in the future
180 * to eliminate information leakage.
182 static uint32_t local_line_cnt;
186 * Function to register a phone.
188 * @param cls closure, NULL
189 * @param client the client from which the message is
190 * @param message the message from the client
193 handle_client_register_message (void *cls,
194 struct GNUNET_SERVER_Client *client,
195 const struct GNUNET_MessageHeader *message)
197 const struct ClientPhoneRegisterMessage *msg;
200 msg = (struct ClientPhoneRegisterMessage *) message;
201 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
205 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
208 line = GNUNET_new (struct Line);
209 line->client = client;
210 GNUNET_SERVER_notification_context_add (nc, client);
211 GNUNET_CONTAINER_DLL_insert (lines_head,
214 line->local_line = ntohl (msg->line);
215 GNUNET_SERVER_client_set_user_context (client, line);
216 GNUNET_SERVER_receive_done (client, GNUNET_OK);
221 * Function to handle a pickup request message from the client
223 * @param cls closure, NULL
224 * @param client the client from which the message is
225 * @param message the message from the client
228 handle_client_pickup_message (void *cls,
229 struct GNUNET_SERVER_Client *client,
230 const struct GNUNET_MessageHeader *message)
232 const struct ClientPhonePickupMessage *msg;
233 struct GNUNET_MQ_Envelope *e;
234 struct MeshPhonePickupMessage *mppm;
239 msg = (struct ClientPhonePickupMessage *) message;
240 meta = (const char *) &msg[1];
241 len = ntohs (msg->header.size) - sizeof (struct ClientPhonePickupMessage);
243 ('\0' != meta[len - 1]) )
248 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
252 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
255 line->status = LS_CALLEE_CONNECTED;
256 e = GNUNET_MQ_msg_extra (mppm,
258 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP);
259 memcpy (&mppm[1], meta, len);
260 GNUNET_MQ_send (line->reliable_mq, e);
261 GNUNET_SERVER_receive_done (client, GNUNET_OK);
266 * Function to handle a hangup request message from the client
268 * @param cls closure, NULL
269 * @param client the client from which the message is
270 * @param message the message from the client
273 handle_client_hangup_message (void *cls,
274 struct GNUNET_SERVER_Client *client,
275 const struct GNUNET_MessageHeader *message)
277 const struct ClientPhoneHangupMessage *msg;
278 struct GNUNET_MQ_Envelope *e;
279 struct MeshPhoneHangupMessage *mhum;
284 msg = (struct ClientPhoneHangupMessage *) message;
285 meta = (const char *) &msg[1];
286 len = ntohs (msg->header.size) - sizeof (struct ClientPhoneHangupMessage);
288 ('\0' != meta[len - 1]) )
293 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
297 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
300 line->status = LS_CALLEE_LISTEN;
301 e = GNUNET_MQ_msg_extra (mhum,
303 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP);
304 memcpy (&mhum[1], meta, len);
305 GNUNET_MQ_send (line->reliable_mq, e);
306 GNUNET_SERVER_receive_done (client, GNUNET_OK);
311 * Function to handle call request the client
313 * @param cls closure, NULL
314 * @param client the client from which the message is
315 * @param message the message from the client
318 handle_client_call_message (void *cls,
319 struct GNUNET_SERVER_Client *client,
320 const struct GNUNET_MessageHeader *message)
322 const struct ClientCallMessage *msg;
324 struct GNUNET_MQ_Envelope *e;
325 struct MeshPhoneRingMessage *ring;
327 msg = (struct ClientCallMessage *) message;
328 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
331 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
334 line = GNUNET_new (struct Line);
335 line->target = msg->target;
336 GNUNET_CONTAINER_DLL_insert (lines_head,
339 line->remote_line = ntohl (msg->line);
340 line->status = LS_CALLER_CALLING;
341 line->tunnel_reliable = GNUNET_MESH_tunnel_create (mesh,
344 GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
347 line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
348 line->local_line = local_line_cnt++;
349 e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING);
350 ring->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
351 ring->purpose.size = htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
352 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
353 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
354 sizeof (struct GNUNET_CRYPTO_EccPublicSignKey));
355 GNUNET_CRYPTO_ecc_key_get_public_for_signature (&msg->caller_id,
357 ring->remote_line = msg->line;
358 ring->source_line = line->local_line;
359 ring->target = msg->target;
360 ring->source = my_identity;
361 ring->expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));
362 GNUNET_CRYPTO_ecc_sign (&msg->caller_id,
365 GNUNET_MQ_send (line->reliable_mq, e);
366 GNUNET_SERVER_client_set_user_context (client, line);
367 GNUNET_SERVER_receive_done (client, GNUNET_OK);
372 * Function to handle audio data from the client
374 * @param cls closure, NULL
375 * @param client the client from which the message is
376 * @param message the message from the client
379 handle_client_audio_message (void *cls,
380 struct GNUNET_SERVER_Client *client,
381 const struct GNUNET_MessageHeader *message)
383 const struct ClientAudioMessage *msg;
385 msg = (struct ClientAudioMessage *) message;
386 GNUNET_break (0); // FIXME
387 GNUNET_SERVER_receive_done (client, GNUNET_OK);
392 * Function to handle a ring message incoming over mesh
394 * @param cls closure, NULL
395 * @param tunnel the tunnel over which the message arrived
396 * @param tunnel_ctx the tunnel context, can be NULL
397 * @param message the incoming message
401 handle_mesh_ring_message (void *cls,
402 struct GNUNET_MESH_Tunnel *tunnel,
404 const struct GNUNET_MessageHeader *message)
406 const struct MeshPhoneRingMessage *msg;
408 struct GNUNET_MQ_Envelope *e;
409 struct MeshPhoneBusyMessage *busy;
410 struct ClientPhoneRingMessage cring;
412 msg = (const struct MeshPhoneRingMessage *) message;
413 if ( (msg->purpose.size != htonl (sizeof (struct GNUNET_PeerIdentity) * 2 +
414 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
415 sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
416 sizeof (struct GNUNET_CRYPTO_EccPublicSignKey))) ||
418 GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING,
424 return GNUNET_SYSERR;
426 for (line = lines_head; NULL != line; line = line->next)
427 if ( (line->local_line == ntohl (msg->remote_line)) &&
428 (LS_CALLEE_LISTEN == line->status) )
432 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
433 _("No available phone for incoming call on line %u, sending BUSY signal\n"),
434 ntohl (msg->remote_line));
435 e = GNUNET_MQ_msg (busy, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY);
436 GNUNET_MQ_send (line->reliable_mq, e);
439 line->status = LS_CALLEE_RINGING;
440 line->remote_line = ntohl (msg->source_line);
441 line->tunnel_reliable = tunnel;
442 line->reliable_mq = GNUNET_MESH_mq_create (line->tunnel_reliable);
444 cring.header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_RING);
445 cring.header.size = htons (sizeof (cring));
446 cring.reserved = htonl (0);
447 cring.caller_id = msg->caller_id;
448 GNUNET_SERVER_notification_context_unicast (nc,
457 * Function to handle a hangup message incoming over mesh
459 * @param cls closure, NULL
460 * @param tunnel the tunnel over which the message arrived
461 * @param tunnel_ctx the tunnel context, can be NULL
462 * @param message the incoming message
466 handle_mesh_hangup_message (void *cls,
467 struct GNUNET_MESH_Tunnel *tunnel,
469 const struct GNUNET_MessageHeader *message)
471 const struct MeshPhoneHangupMessage *msg;
473 msg = (const struct MeshPhoneHangupMessage *) message;
474 GNUNET_break (0); // FIXME
480 * Function to handle a pickup message incoming over mesh
482 * @param cls closure, NULL
483 * @param tunnel the tunnel over which the message arrived
484 * @param tunnel_ctx the tunnel context, can be NULL
485 * @param message the incoming message
489 handle_mesh_pickup_message (void *cls,
490 struct GNUNET_MESH_Tunnel *tunnel,
492 const struct GNUNET_MessageHeader *message)
494 const struct MeshPhonePickupMessage *msg;
495 struct Line *line = *tunnel_ctx;
497 msg = (const struct MeshPhonePickupMessage *) message;
498 GNUNET_break (0); // FIXME
501 line->tunnel_unreliable = GNUNET_MESH_tunnel_create (mesh,
504 GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
514 * Function to handle a busy message incoming over mesh
516 * @param cls closure, NULL
517 * @param tunnel the tunnel over which the message arrived
518 * @param tunnel_ctx the tunnel context, can be NULL
519 * @param message the incoming message
523 handle_mesh_busy_message (void *cls,
524 struct GNUNET_MESH_Tunnel *tunnel,
526 const struct GNUNET_MessageHeader *message)
528 const struct MeshPhoneBusyMessage *msg;
530 msg = (const struct MeshPhoneBusyMessage *) message;
531 GNUNET_break (0); // FIXME
537 * Function to handle an audio message incoming over mesh
539 * @param cls closure, NULL
540 * @param tunnel the tunnel over which the message arrived
541 * @param tunnel_ctx the tunnel context, can be NULL
542 * @param message the incoming message
546 handle_mesh_audio_message (void *cls,
547 struct GNUNET_MESH_Tunnel *tunnel,
549 const struct GNUNET_MessageHeader *message)
551 const struct MeshAudioMessage *msg;
553 msg = (const struct MeshAudioMessage *) message;
554 GNUNET_break (0); // FIXME
560 * Method called whenever another peer has added us to a tunnel
561 * the other peer initiated.
564 * @param tunnel new handle to the tunnel
565 * @param initiator peer that started the tunnel
567 * @return initial tunnel context for the tunnel (can be NULL -- that's not an error)
570 inbound_tunnel (void *cls,
571 struct GNUNET_MESH_Tunnel *tunnel,
572 const struct GNUNET_PeerIdentity *initiator,
576 GNUNET_break (0); // FIXME
577 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
578 _("Received incoming tunnel on port %d\n"), port);
584 * Function called whenever an inbound tunnel is destroyed. Should clean up
585 * any associated state.
587 * @param cls closure (set from #GNUNET_MESH_connect)
588 * @param tunnel connection to the other end (henceforth invalid)
589 * @param tunnel_ctx place where local state associated
590 * with the tunnel is stored
593 inbound_end (void *cls,
594 const struct GNUNET_MESH_Tunnel *tunnel,
597 GNUNET_break (0); // FIXME
602 * A client disconnected. Remove all of its data structure entries.
604 * @param cls closure, NULL
605 * @param client identification of the client
608 handle_client_disconnect (void *cls,
609 struct GNUNET_SERVER_Client *client)
613 line = GNUNET_SERVER_client_get_user_context (client, struct Line);
616 GNUNET_CONTAINER_DLL_remove (lines_head,
620 GNUNET_SERVER_client_set_user_context (client, NULL);
627 * @param cls closure, NULL
628 * @param tc the task context
631 do_shutdown (void *cls,
632 const struct GNUNET_SCHEDULER_TaskContext *tc)
634 GNUNET_break (0); // FIXME
637 GNUNET_MESH_disconnect (mesh);
642 GNUNET_SERVER_notification_context_destroy (nc);
649 * Main function that will be run by the scheduler.
652 * @param server server handle
653 * @param c configuration
657 struct GNUNET_SERVER_Handle *server,
658 const struct GNUNET_CONFIGURATION_Handle *c)
660 static const struct GNUNET_SERVER_MessageHandler server_handlers[] = {
661 {&handle_client_register_message, NULL,
662 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_REGISTER,
663 sizeof (struct ClientPhoneRegisterMessage)},
664 {&handle_client_pickup_message, NULL,
665 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_PICK_UP,
667 {&handle_client_hangup_message, NULL,
668 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_HANG_UP,
670 {&handle_client_call_message, NULL,
671 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_PHONE_CALL,
673 {&handle_client_audio_message, NULL,
674 GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO,
678 static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
679 {&handle_mesh_ring_message,
680 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_RING,
681 sizeof (struct MeshPhoneRingMessage)},
682 {&handle_mesh_hangup_message,
683 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_HANG_UP,
685 {&handle_mesh_pickup_message,
686 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_PICK_UP,
688 {&handle_mesh_busy_message,
689 GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_PHONE_BUSY,
690 sizeof (struct MeshPhoneBusyMessage)},
691 {&handle_mesh_audio_message, GNUNET_MESSAGE_TYPE_CONVERSATION_MESH_AUDIO,
695 static uint32_t ports[] = {
696 GNUNET_APPLICATION_TYPE_CONVERSATION_CONTROL,
697 GNUNET_APPLICATION_TYPE_CONVERSATION_AUDIO,
702 GNUNET_assert (GNUNET_OK ==
703 GNUNET_CRYPTO_get_host_identity (cfg,
705 mesh = GNUNET_MESH_connect (cfg,
715 GNUNET_SCHEDULER_shutdown ();
718 nc = GNUNET_SERVER_notification_context_create (server, 16);
719 GNUNET_SERVER_add_handlers (server, server_handlers);
720 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
721 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
728 * The main function for the conversation service.
730 * @param argc number of arguments from the command line
731 * @param argv command line arguments
732 * @return 0 ok, 1 on error
739 GNUNET_SERVICE_run (argc, argv,
741 GNUNET_SERVICE_OPTION_NONE,
742 &run, NULL)) ? 0 : 1;
745 /* end of gnunet-service-conversation.c */