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;
218 * Check if the gns txt record for conversation exits
221 check_gns (struct GNUNET_CONVERSATION_Handle *h)
223 GNUNET_GNS_lookup (h->gns, "conversation.gads",
224 NULL /* FIXME_ZONE */,
225 GNUNET_DNSPARSER_TYPE_TXT,
233 /******************************************************************************/
234 /*********************** RECEIVE HANDLERS ****************************/
235 /******************************************************************************/
238 * Function to process all messages received from the service
241 * @param msg message received, NULL on timeout or fatal error
244 receive_message_cb (void *cls, const struct GNUNET_MessageHeader *msg)
246 struct GNUNET_CONVERSATION_Handle *h = cls;
247 struct ServerClientSessionInitiateMessage *imsg;
248 struct ServerClientSessionRejectMessage *rmsg;
249 struct GNUNET_CONVERSATION_MissedCallNotification *missed_calls;
253 switch (ntohs (msg->type))
255 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_ACCEPT:
256 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
257 _("%s has accepted your call.\n"),
258 GNUNET_i2s_full (&(h->call->peer)));
260 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_CALL_ACCEPTED,
262 h->call->type = CALLEE;
266 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_REJECT:
267 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
268 _("%s has rejected your call.\n"),
269 GNUNET_i2s_full (&(h->call->peer)));
271 rmsg = (struct ServerClientSessionRejectMessage *) msg;
272 h->reject_handler (NULL, h, ntohs (rmsg->reason), &(h->call->peer));
273 GNUNET_free (h->call);
278 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_TERMINATE:
279 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
280 _("%s has terminated the call.\n"),
281 GNUNET_i2s_full (&(h->call->peer)));
283 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_CALL_TERMINATED,
285 GNUNET_free (h->call);
290 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SESSION_INITIATE:
291 imsg = (struct ServerClientSessionInitiateMessage *) msg;
293 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("%s wants to call you.\n"),
294 GNUNET_i2s_full (&(imsg->peer)));
297 (struct GNUNET_CONVERSATION_CallInformation *)
298 GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_CallInformation));
299 memcpy (&(h->call->peer), &(imsg->peer),
300 sizeof (struct GNUNET_PeerIdentity));
301 h->call_handler (NULL, h, &(h->call->peer));
302 h->call->type = CALLEE;
306 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_MISSED_CALL:
308 (struct GNUNET_CONVERSATION_MissedCallNotification *) (msg +
311 GNUNET_MessageHeader)));
312 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
313 _("You &d have missed a calls.\n"),
314 missed_calls->number);
315 h->missed_call_handler (NULL, h, missed_calls);
318 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_SERVICE_BLOCKED:
319 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("The service is blocked.\n"));
320 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_SERVICE_BLOCKED,
324 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_PEER_NOT_CONNECTED:
325 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
326 _("The peer you are calling is not connected.\n"));
327 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_NO_PEER, NULL);
330 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_NO_ANSWER:
331 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
332 _("The peer you are calling does not answer.\n"));
333 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_NO_ANSWER,
337 case GNUNET_MESSAGE_TYPE_CONVERSATION_SC_ERROR:
338 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Generic error occured.\n"));
342 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
343 _("Got unknown message type.\n"));
349 GNUNET_CLIENT_receive (h->client, &receive_message_cb, h,
350 GNUNET_TIME_UNIT_FOREVER_REL);
353 /******************************************************************************/
354 /************************ SEND FUNCTIONS ****************************/
355 /******************************************************************************/
358 * Function called to send a session initiate message to the service.
359 * "buf" will be NULL and "size" zero if the socket was closed for writing in
362 * @param cls closure, NULL
363 * @param size number of bytes available in buf
364 * @param buf where the callee should write the initiate message
365 * @return number of bytes written to buf
368 transmit_session_initiate_message (void *cls, size_t size, void *buf)
371 struct ClientServerSessionInitiateMessage *msg;
372 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
374 msg_size = sizeof (struct ClientServerSessionInitiateMessage);
376 GNUNET_assert (size >= msg_size);
378 msg->header.size = htons (msg_size);
379 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_INITIATE);
380 memcpy (&msg->peer, &(h->call->peer), sizeof (struct GNUNET_PeerIdentity));
382 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
384 ("Sending ClientServerSessionInitiateMessage to the service for peer: %s\n"),
385 GNUNET_i2s_full (&(h->call->peer)));
387 h->call->type = CALLER;
393 * Function called to send a session accept message to the service.
394 * "buf" will be NULL and "size" zero if the socket was closed for writing in
397 * @param cls closure, NULL
398 * @param size number of bytes available in buf
399 * @param buf where the callee should write the accept message
400 * @return number of bytes written to buf
403 transmit_session_accept_message (void *cls, size_t size, void *buf)
406 struct ClientServerSessionAcceptMessage *msg;
407 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
409 msg_size = sizeof (struct ClientServerSessionAcceptMessage);
411 GNUNET_assert (size >= msg_size);
413 msg->header.size = htons (msg_size);
414 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_ACCEPT);
416 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
418 ("Sending ClienServerSessionAcceptMessage to the service for peer: %s\n"),
419 GNUNET_i2s_full (&(h->call->peer)));
421 h->call->established = GNUNET_YES;
427 * Function called to send a session reject message to the service.
428 * "buf" will be NULL and "size" zero if the socket was closed for writing in
431 * @param cls closure, NULL
432 * @param size number of bytes available in buf
433 * @param buf where the callee should write the reject message
434 * @return number of bytes written to buf
437 transmit_session_reject_message (void *cls, size_t size, void *buf)
440 struct ClientServerSessionRejectMessage *msg;
441 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
443 msg_size = sizeof (struct ClientServerSessionRejectMessage);
445 GNUNET_assert (size >= msg_size);
447 msg->header.size = htons (msg_size);
448 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_REJECT);
449 msg->reason = htons (GNUNET_CONVERSATION_REJECT_REASON_NOT_WANTED);
451 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
453 ("Sending ClientServerSessionRejectMessage to the service for peer: %s\n"),
454 GNUNET_i2s_full (&(h->call->peer)));
456 GNUNET_free (h->call);
463 * Function called to send a session terminate message to the service.
464 * "buf" will be NULL and "size" zero if the socket was closed for writing in
467 * @param cls closure, NULL
468 * @param size number of bytes available in buf
469 * @param buf where the callee should write the terminate message
470 * @return number of bytes written to buf
473 transmit_session_terminate_message (void *cls, size_t size, void *buf)
476 struct ClientServerSessionTerminateMessage *msg;
477 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
479 msg_size = sizeof (struct ClientServerSessionTerminateMessage);
481 GNUNET_assert (size >= msg_size);
483 msg->header.size = htons (msg_size);
484 msg->header.type = htons (GNUNET_MESSAGE_TYPE_CONVERSATION_CS_SESSION_TERMINATE);
486 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
488 ("Sending ClientServerSessionTerminateMessage to the service for peer: %s\n"),
489 GNUNET_i2s_full (&(h->call->peer)));
491 GNUNET_free (h->call);
498 * Auxiliary function to call a peer.
500 * @param h conversation handle
504 initiate_call (struct GNUNET_CONVERSATION_Handle *h, struct GNUNET_PeerIdentity peer)
507 (struct GNUNET_CONVERSATION_CallInformation *)
508 GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_CallInformation));
509 memcpy (&(h->call->peer), &peer, sizeof (struct GNUNET_PeerIdentity));
511 GNUNET_CLIENT_notify_transmit_ready (h->client,
513 ClientServerSessionInitiateMessage),
514 MAX_TRANSMIT_DELAY, GNUNET_YES,
515 &transmit_session_initiate_message, h);
521 * Auxiliary function to accept a call.
523 * @param h conversation handle
526 accept_call (struct GNUNET_CONVERSATION_Handle *h)
528 GNUNET_CLIENT_notify_transmit_ready (h->client,
530 ClientServerSessionAcceptMessage),
531 MAX_TRANSMIT_DELAY, GNUNET_YES,
532 &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);
551 * Auxiliary function to terminate a call.
553 * @param h conversation handle
556 terminate_call (struct GNUNET_CONVERSATION_Handle *h)
558 GNUNET_CLIENT_notify_transmit_ready (h->client,
560 ClientServerSessionTerminateMessage),
561 MAX_TRANSMIT_DELAY, GNUNET_YES,
562 &transmit_session_terminate_message,
570 gns_call_cb (void *cls, uint32_t rd_count,
571 const struct GNUNET_NAMESTORE_RecordData *rd)
573 struct GNUNET_CONVERSATION_Handle *handle = cls;
574 struct GNUNET_PeerIdentity peer;
577 for (i=0;i<rd_count;i++)
579 switch (rd[i].record_type)
581 case GNUNET_DNSPARSER_TYPE_TXT: /* FIXME: use fresh record type for voide... */
583 GNUNET_CRYPTO_ecc_public_sign_key_from_string (rd[i].data,
590 initiate_call (handle, peer);
596 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
598 handle->notification_handler (NULL, handle,
599 GNUNET_CONVERSATION_NT_NO_PEER,
608 gns_lookup_and_call (struct GNUNET_CONVERSATION_Handle *h, const char *callee)
610 char domain[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
614 strcpy (pos, "conversation");
615 pos += strlen ("conversation");
618 strcpy (pos, callee);
619 pos += strlen (callee);
621 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Lookup for %s\n", domain);
623 GNUNET_GNS_lookup (h->gns,
625 NULL /* FIXME: ZONE! */,
626 GNUNET_DNSPARSER_TYPE_TXT,
633 /******************************************************************************/
634 /********************** API CALL DEFINITIONS *************************/
635 /******************************************************************************/
637 struct GNUNET_CONVERSATION_Handle *
638 GNUNET_CONVERSATION_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
639 GNUNET_CONVERSATION_CallHandler * call_handler,
640 GNUNET_CONVERSATION_RejectHandler * reject_handler,
641 GNUNET_CONVERSATION_NotificationHandler * notification_handler,
642 GNUNET_CONVERSATION_MissedCallHandler * missed_call_handler)
644 struct GNUNET_CONVERSATION_Handle *h;
646 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNUNET_CONVERSATION_connect()\n");
647 h = GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_Handle));
650 h->call_handler = call_handler;
651 h->reject_handler = reject_handler;
652 h->notification_handler = notification_handler;
653 h->missed_call_handler = missed_call_handler;
655 if (NULL == (h->client = GNUNET_CLIENT_connect ("conversation", cfg)))
657 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access CONVERSATION service\n");
664 if (NULL == (h->gns = GNUNET_GNS_connect (cfg)))
666 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access GNS service\n");
668 GNUNET_CLIENT_disconnect (h->client);
674 if (NULL == (h->namestore = GNUNET_NAMESTORE_connect (cfg)))
676 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
677 "Could not access NAMESTORE service\n");
679 GNUNET_CLIENT_disconnect (h->client);
680 GNUNET_GNS_disconnect (h->gns);
687 GNUNET_CLIENT_receive (h->client, &receive_message_cb, h,
688 GNUNET_TIME_UNIT_FOREVER_REL);
694 GNUNET_CONVERSATION_disconnect (struct GNUNET_CONVERSATION_Handle *handle)
696 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CONVERSATION DISCONNECT\n");
698 GNUNET_CLIENT_disconnect (handle->client);
699 GNUNET_GNS_disconnect (handle->gns);
701 GNUNET_free (handle);
707 GNUNET_CONVERSATION_call (struct GNUNET_CONVERSATION_Handle *h,
711 struct GNUNET_PeerIdentity peer;
713 if (NULL == h || NULL == h->client)
716 if (GNUNET_YES == doGnsLookup)
718 gns_lookup_and_call (h, callee);
722 GNUNET_CRYPTO_ecc_public_sign_key_from_string (callee,
726 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
727 _("`%s' is not a valid public key\n"),
729 h->notification_handler (NULL, h, GNUNET_CONVERSATION_NT_NO_PEER, NULL);
732 initiate_call (h, peer);
736 GNUNET_CONVERSATION_hangup (struct GNUNET_CONVERSATION_Handle *h)
738 if (NULL == h || NULL == h->client)
745 GNUNET_CONVERSATION_accept (struct GNUNET_CONVERSATION_Handle *h)
747 if (NULL == h || NULL == h->client)
754 GNUNET_CONVERSATION_reject (struct GNUNET_CONVERSATION_Handle *h)
756 if (NULL == h || NULL == h->client)
762 /* end of conversation_api.c */