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.
22 * @file conversation/conversation_api.c
23 * @brief API for conversation
24 * @author Simon Dieterle
25 * @author Andreas Fuchs
29 * - AUXILIARY FUNCTIONS
32 * - API CALL DEFINITIONS
37 #include "gnunet_util_lib.h"
38 #include "gnunet_dnsparser_lib.h"
39 #include "gnunet_gns_service.h"
40 #include "gnunet_protocols.h"
41 #include "conversation.h"
42 #include "gnunet_conversation_service.h"
44 #define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
46 /******************************************************************************/
47 /************************ DATA STRUCTURES ****************************/
48 /******************************************************************************/
50 enum GNUNET_CONVERSATION_CallType
57 * Information about a call
59 struct GNUNET_CONVERSATION_CallInformation
63 * Peer interacting with
65 struct GNUNET_PeerIdentity peer;
68 * Type of call (incoming or outgoing)
73 * Shows if the call ist fully established
79 * Opaque handle to the service.
81 struct GNUNET_CONVERSATION_Handle
87 const struct GNUNET_CONFIGURATION_Handle *cfg;
90 * Handle to the server connection, to send messages later
92 struct GNUNET_CLIENT_Connection *client;
97 struct GNUNET_GNS_Handle *gns;
102 struct GNUNET_NAMESTORE_Handle *namestore;
110 * Callback for incoming calls
112 GNUNET_CONVERSATION_CallHandler *call_handler;
115 * Callback for rejected calls
117 GNUNET_CONVERSATION_RejectHandler *reject_handler;
120 * Callback for notifications
122 GNUNET_CONVERSATION_NotificationHandler *notification_handler;
125 * Callback for missed calls
127 GNUNET_CONVERSATION_MissedCallHandler *missed_call_handler;
130 * The pointer to the call
132 struct GNUNET_CONVERSATION_CallInformation *call;
135 /******************************************************************************/
136 /*********************** AUXILIARY FUNCTIONS *************************/
137 /******************************************************************************/
140 * Initialize the conversation txt record in GNS
143 setup_gns_txt (struct GNUNET_CONVERSATION_Handle *handle)
145 struct GNUNET_CRYPTO_EccPublicSignKey zone_pkey;
146 struct GNUNET_CRYPTO_EccPrivateKey *zone_key;
147 struct GNUNET_CRYPTO_EccPrivateKey *peer_key;
148 struct GNUNET_NAMESTORE_RecordData rd;
149 struct GNUNET_PeerIdentity peer;
154 rd.expiration_time = UINT64_MAX;
157 GNUNET_CONFIGURATION_get_value_filename (handle->cfg, "gns", "ZONEKEY",
160 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
165 GNUNET_CONFIGURATION_get_value_filename (handle->cfg, "PEER",
166 "PRIVATE_KEY", &peer_keyfile))
168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
172 zone_key = GNUNET_CRYPTO_ecc_key_create_from_file (zone_keyfile);
173 GNUNET_CRYPTO_ecc_key_get_public_for_signature (zone_key, &zone_pkey);
174 peer_key = GNUNET_CRYPTO_ecc_key_create_from_file (peer_keyfile);
175 GNUNET_CRYPTO_ecc_key_get_public_for_signature (peer_key,
177 const char *h = GNUNET_i2s_full (&peer);
179 rd.data_size = strlen (h) + 1;
181 rd.record_type = GNUNET_DNSPARSER_TYPE_TXT;
182 rd.flags = GNUNET_NAMESTORE_RF_NONE;
184 /* FIXME: continuation? return value? */
185 GNUNET_NAMESTORE_records_store (handle->namestore,
193 * Callback for checking the conversation txt gns record
200 check_gns_cb (void *cls, uint32_t rd_count,
201 const struct GNUNET_NAMESTORE_RecordData *rd)
203 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
211 h->txt_record_set = GNUNET_YES;
217 * Check if the gns txt record for conversation exits
220 check_gns (struct GNUNET_CONVERSATION_Handle *h)
222 GNUNET_GNS_lookup (h->gns, "conversation.gns",
223 NULL /* FIXME_ZONE */,
224 GNUNET_DNSPARSER_TYPE_TXT,
231 /******************************************************************************/
232 /*********************** RECEIVE HANDLERS ****************************/
233 /******************************************************************************/
236 * Function to process all messages received from the service
239 * @param msg message received, NULL on timeout or fatal error
242 receive_message_cb (void *cls,
243 const struct GNUNET_MessageHeader *msg)
245 struct GNUNET_CONVERSATION_Handle *h = cls;
246 struct ServerClientSessionInitiateMessage *imsg;
247 struct ServerClientSessionRejectMessage *rmsg;
248 struct GNUNET_CONVERSATION_MissedCallNotification *missed_calls;
252 switch (ntohs (msg->type))
254 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_ACCEPT:
255 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
256 _("%s has accepted your call.\n"),
257 GNUNET_i2s_full (&(h->call->peer)));
259 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_CALL_ACCEPTED,
261 h->call->type = CALLEE;
265 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_REJECT:
266 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
267 _("%s has rejected your call.\n"),
268 GNUNET_i2s_full (&(h->call->peer)));
270 rmsg = (struct ServerClientSessionRejectMessage *) msg;
271 h->reject_handler (NULL, h, ntohs (rmsg->reason), &(h->call->peer));
272 GNUNET_free (h->call);
277 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_TERMINATE:
278 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
279 _("%s has terminated the call.\n"),
280 GNUNET_i2s_full (&(h->call->peer)));
282 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_CALL_TERMINATED,
284 GNUNET_free (h->call);
289 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_INITIATE:
290 imsg = (struct ServerClientSessionInitiateMessage *) msg;
292 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%s wants to call you.\n"),
293 GNUNET_i2s_full (&(imsg->peer)));
296 (struct GNUNET_CONVERSATION_CallInformation *)
297 GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_CallInformation));
298 memcpy (&(h->call->peer), &(imsg->peer),
299 sizeof (struct GNUNET_PeerIdentity));
300 h->call_handler (NULL, h, &(h->call->peer));
301 h->call->type = CALLEE;
305 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_MISSED_CALL:
307 (struct GNUNET_CONVERSATION_MissedCallNotification *) (msg +
310 GNUNET_MessageHeader)));
311 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
312 _("You &d have missed a calls.\n"),
313 missed_calls->number);
314 h->missed_call_handler (NULL, h, missed_calls);
317 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SERVICE_BLOCKED:
318 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("The service is blocked.\n"));
319 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_SERVICE_BLOCKED,
323 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_PEER_NOT_CONNECTED:
324 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
325 _("The peer you are calling is not connected.\n"));
326 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_NO_PEER, NULL);
329 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_NO_ANSWER:
330 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
331 _("The peer you are calling does not answer.\n"));
332 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_NO_ANSWER,
336 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_ERROR:
337 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Generic error occured.\n"));
341 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
342 _("Got unknown message type.\n"));
348 GNUNET_CLIENT_receive (h->client, &receive_message_cb, h,
349 GNUNET_TIME_UNIT_FOREVER_REL);
352 /******************************************************************************/
353 /************************ SEND FUNCTIONS ****************************/
354 /******************************************************************************/
357 * Function called to send a session initiate message to the service.
358 * "buf" will be NULL and "size" zero if the socket was closed for writing in
361 * @param cls closure, NULL
362 * @param size number of bytes available in buf
363 * @param buf where the callee should write the initiate message
364 * @return number of bytes written to buf
367 transmit_session_initiate_message (void *cls, size_t size, void *buf)
370 struct ClientServerSessionInitiateMessage *msg;
371 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
373 msg_size = sizeof (struct ClientServerSessionInitiateMessage);
375 GNUNET_assert (size >= msg_size);
377 msg->header.size = htons (msg_size);
378 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_INITIATE);
379 memcpy (&msg->peer, &(h->call->peer), sizeof (struct GNUNET_PeerIdentity));
381 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
383 ("Sending ClientServerSessionInitiateMessage to the service for peer: %s\n"),
384 GNUNET_i2s_full (&(h->call->peer)));
386 h->call->type = CALLER;
392 * Function called to send a session accept message to the service.
393 * "buf" will be NULL and "size" zero if the socket was closed for writing in
396 * @param cls closure, NULL
397 * @param size number of bytes available in buf
398 * @param buf where the callee should write the accept message
399 * @return number of bytes written to buf
402 transmit_session_accept_message (void *cls, size_t size, void *buf)
405 struct ClientServerSessionAcceptMessage *msg;
406 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
408 msg_size = sizeof (struct ClientServerSessionAcceptMessage);
410 GNUNET_assert (size >= msg_size);
412 msg->header.size = htons (msg_size);
413 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_ACCEPT);
415 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
417 ("Sending ClienServerSessionAcceptMessage to the service for peer: %s\n"),
418 GNUNET_i2s_full (&(h->call->peer)));
420 h->call->established = GNUNET_YES;
426 * Function called to send a session reject message to the service.
427 * "buf" will be NULL and "size" zero if the socket was closed for writing in
430 * @param cls closure, NULL
431 * @param size number of bytes available in buf
432 * @param buf where the callee should write the reject message
433 * @return number of bytes written to buf
436 transmit_session_reject_message (void *cls, size_t size, void *buf)
439 struct ClientServerSessionRejectMessage *msg;
440 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
442 msg_size = sizeof (struct ClientServerSessionRejectMessage);
444 GNUNET_assert (size >= msg_size);
446 msg->header.size = htons (msg_size);
447 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_REJECT);
448 msg->reason = htons (GNUNET_CONVERSATION_REJECT_REASON_NOT_WANTED);
450 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
452 ("Sending ClientServerSessionRejectMessage to the service for peer: %s\n"),
453 GNUNET_i2s_full (&(h->call->peer)));
455 GNUNET_free (h->call);
462 * Function called to send a session terminate message to the service.
463 * "buf" will be NULL and "size" zero if the socket was closed for writing in
466 * @param cls closure, NULL
467 * @param size number of bytes available in buf
468 * @param buf where the callee should write the terminate message
469 * @return number of bytes written to buf
472 transmit_session_terminate_message (void *cls, size_t size, void *buf)
475 struct ClientServerSessionTerminateMessage *msg;
476 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
478 msg_size = sizeof (struct ClientServerSessionTerminateMessage);
480 GNUNET_assert (size >= msg_size);
482 msg->header.size = htons (msg_size);
483 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_TERMINATE);
485 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
487 ("Sending ClientServerSessionTerminateMessage to the service for peer: %s\n"),
488 GNUNET_i2s_full (&(h->call->peer)));
490 GNUNET_free (h->call);
497 * Auxiliary function to call a peer.
499 * @param h conversation handle
503 initiate_call (struct GNUNET_CONVERSATION_Handle *h, struct GNUNET_PeerIdentity peer)
506 (struct GNUNET_CONVERSATION_CallInformation *)
507 GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_CallInformation));
508 memcpy (&(h->call->peer), &peer, sizeof (struct GNUNET_PeerIdentity));
510 GNUNET_CLIENT_notify_transmit_ready (h->client,
512 ClientServerSessionInitiateMessage),
513 MAX_TRANSMIT_DELAY, GNUNET_YES,
514 &transmit_session_initiate_message, h);
520 * Auxiliary function to accept a call.
522 * @param h conversation handle
525 accept_call (struct GNUNET_CONVERSATION_Handle *h)
527 GNUNET_CLIENT_notify_transmit_ready (h->client,
529 ClientServerSessionAcceptMessage),
530 MAX_TRANSMIT_DELAY, GNUNET_YES,
531 &transmit_session_accept_message, h);
536 * Auxiliary function to reject a call.
538 * @param h conversation handle
541 reject_call (struct GNUNET_CONVERSATION_Handle *h)
543 GNUNET_CLIENT_notify_transmit_ready (h->client,
545 ClientServerSessionRejectMessage),
546 MAX_TRANSMIT_DELAY, GNUNET_YES,
547 &transmit_session_reject_message, h);
552 * Auxiliary function to terminate a call.
554 * @param h conversation handle
557 terminate_call (struct GNUNET_CONVERSATION_Handle *h)
559 GNUNET_CLIENT_notify_transmit_ready (h->client,
561 ClientServerSessionTerminateMessage),
562 MAX_TRANSMIT_DELAY, GNUNET_YES,
563 &transmit_session_terminate_message,
572 gns_call_cb (void *cls, uint32_t rd_count,
573 const struct GNUNET_NAMESTORE_RecordData *rd)
575 struct GNUNET_CONVERSATION_Handle *handle = cls;
576 struct GNUNET_PeerIdentity peer;
579 for (i=0;i<rd_count;i++)
581 switch (rd[i].record_type)
583 case GNUNET_DNSPARSER_TYPE_TXT: /* FIXME: use fresh record type for voide... */
585 GNUNET_CRYPTO_ecc_public_sign_key_from_string (rd[i].data,
592 initiate_call (handle, peer);
598 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
600 handle->notification_handler (NULL, handle,
601 GNUNET_CONVERSATION_NT_NO_PEER,
610 gns_lookup_and_call (struct GNUNET_CONVERSATION_Handle *h, const char *callee)
612 char domain[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
616 strcpy (pos, "conversation");
617 pos += strlen ("conversation");
620 strcpy (pos, callee);
621 pos += strlen (callee);
623 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Lookup for %s\n", domain);
625 GNUNET_GNS_lookup (h->gns,
627 NULL /* FIXME: ZONE! */,
628 GNUNET_DNSPARSER_TYPE_TXT,
635 /******************************************************************************/
636 /********************** API CALL DEFINITIONS *************************/
637 /******************************************************************************/
639 struct GNUNET_CONVERSATION_Handle *
640 GNUNET_CONVERSATION_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
642 GNUNET_CONVERSATION_CallHandler call_handler,
643 GNUNET_CONVERSATION_RejectHandler reject_handler,
644 GNUNET_CONVERSATION_NotificationHandler notification_handler,
645 GNUNET_CONVERSATION_MissedCallHandler missed_call_handler)
647 struct GNUNET_CONVERSATION_Handle *h;
649 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
650 "GNUNET_CONVERSATION_connect()\n");
651 h = GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_Handle));
654 h->call_handler = call_handler;
655 h->reject_handler = reject_handler;
656 h->notification_handler = notification_handler;
657 h->missed_call_handler = missed_call_handler;
659 if (NULL == (h->client = GNUNET_CLIENT_connect ("conversation", cfg)))
661 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access CONVERSATION service\n");
668 if (NULL == (h->gns = GNUNET_GNS_connect (cfg)))
670 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access GNS service\n");
672 GNUNET_CLIENT_disconnect (h->client);
678 if (NULL == (h->namestore = GNUNET_NAMESTORE_connect (cfg)))
680 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
681 "Could not access NAMESTORE service\n");
683 GNUNET_CLIENT_disconnect (h->client);
684 GNUNET_GNS_disconnect (h->gns);
691 GNUNET_CLIENT_receive (h->client, &receive_message_cb, h,
692 GNUNET_TIME_UNIT_FOREVER_REL);
699 GNUNET_CONVERSATION_disconnect (struct GNUNET_CONVERSATION_Handle *handle)
701 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CONVERSATION DISCONNECT\n");
703 GNUNET_CLIENT_disconnect (handle->client);
704 GNUNET_GNS_disconnect (handle->gns);
706 GNUNET_free (handle);
712 GNUNET_CONVERSATION_call (struct GNUNET_CONVERSATION_Handle *h,
716 struct GNUNET_PeerIdentity peer;
718 if (NULL == h || NULL == h->client)
721 if (GNUNET_YES == doGnsLookup)
723 gns_lookup_and_call (h, callee);
727 GNUNET_CRYPTO_ecc_public_sign_key_from_string (callee,
731 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
732 _("`%s' is not a valid public key\n"),
734 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_NO_PEER, NULL);
737 initiate_call (h, peer);
742 GNUNET_CONVERSATION_hangup (struct GNUNET_CONVERSATION_Handle *h)
744 if (NULL == h || NULL == h->client)
752 GNUNET_CONVERSATION_accept (struct GNUNET_CONVERSATION_Handle *h)
754 if (NULL == h || NULL == h->client)
762 GNUNET_CONVERSATION_reject (struct GNUNET_CONVERSATION_Handle *h)
764 if (NULL == h || NULL == h->client)
770 /* end of conversation_api.c */