2 This file is part of GNUnet.
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 2, 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_conversation.h"
41 #include "gnunet_conversation_service.h"
43 #define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
45 /******************************************************************************/
46 /************************ DATA STRUCTURES ****************************/
47 /******************************************************************************/
49 enum GNUNET_CONVERSATION_CallType
56 * Information about a call
58 struct GNUNET_CONVERSATION_CallInformation
62 * Peer interacting with
64 struct GNUNET_PeerIdentity peer;
67 * Type of call (incoming or outgoing)
72 * Shows if the call ist fully established
78 * Opaque handle to the service.
80 struct GNUNET_CONVERSATION_Handle
86 const struct GNUNET_CONFIGURATION_Handle *cfg;
89 * Handle to the server connection, to send messages later
91 struct GNUNET_CLIENT_Connection *client;
96 struct GNUNET_GNS_Handle *gns;
101 struct GNUNET_NAMESTORE_Handle *namestore;
109 * Callback for incoming calls
111 GNUNET_CONVERSATION_CallHandler *call_handler;
114 * Callback for rejected calls
116 GNUNET_CONVERSATION_RejectHandler *reject_handler;
119 * Callback for notifications
121 GNUNET_CONVERSATION_NotificationHandler *notification_handler;
124 * Callback for missed calls
126 GNUNET_CONVERSATION_MissedCallHandler *missed_call_handler;
129 * The pointer to the call
131 struct GNUNET_CONVERSATION_CallInformation *call;
134 /******************************************************************************/
135 /*********************** AUXILIARY FUNCTIONS *************************/
136 /******************************************************************************/
139 * Initialize the conversation txt record in GNS
142 setup_gns_txt (struct GNUNET_CONVERSATION_Handle *handle)
144 struct GNUNET_CRYPTO_EccPublicSignKey zone_pkey;
145 struct GNUNET_CRYPTO_EccPrivateKey *zone_key;
146 struct GNUNET_CRYPTO_EccPrivateKey *peer_key;
147 struct GNUNET_NAMESTORE_RecordData rd;
148 struct GNUNET_PeerIdentity peer;
153 rd.expiration_time = UINT64_MAX;
156 GNUNET_CONFIGURATION_get_value_filename (handle->cfg, "gns", "ZONEKEY",
159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
164 GNUNET_CONFIGURATION_get_value_filename (handle->cfg, "PEER",
165 "PRIVATE_KEY", &peer_keyfile))
167 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
171 zone_key = GNUNET_CRYPTO_ecc_key_create_from_file (zone_keyfile);
172 GNUNET_CRYPTO_ecc_key_get_public_for_signature (zone_key, &zone_pkey);
173 peer_key = GNUNET_CRYPTO_ecc_key_create_from_file (peer_keyfile);
174 GNUNET_CRYPTO_ecc_key_get_public_for_signature (peer_key,
176 const char *h = GNUNET_i2s_full (&peer);
178 rd.data_size = strlen (h) + 1;
180 rd.record_type = GNUNET_DNSPARSER_TYPE_TXT;
181 rd.flags = GNUNET_NAMESTORE_RF_NONE;
183 /* FIXME: continuation? return value? */
184 GNUNET_NAMESTORE_records_store (handle->namestore,
192 * Callback for checking the conversation txt gns record
199 check_gns_cb (void *cls, uint32_t rd_count,
200 const struct GNUNET_NAMESTORE_RecordData *rd)
202 struct GNUNET_CONVERSATION_Handle *h = (struct GNUNET_CONVERSATION_Handle *) cls;
210 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.gads",
223 NULL /* FIXME_ZONE */,
224 GNUNET_DNSPARSER_TYPE_TXT,
232 /******************************************************************************/
233 /*********************** RECEIVE HANDLERS ****************************/
234 /******************************************************************************/
237 * Function to process all messages received from the service
240 * @param msg message received, NULL on timeout or fatal error
243 receive_message_cb (void *cls, 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, NotificationType_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, NotificationType_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, NotificationType_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, NotificationType_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, NotificationType_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 (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);
535 * Auxiliary function to reject a call.
537 * @param h conversation handle
540 reject_call (struct GNUNET_CONVERSATION_Handle *h)
542 GNUNET_CLIENT_notify_transmit_ready (h->client,
544 ClientServerSessionRejectMessage),
545 MAX_TRANSMIT_DELAY, GNUNET_YES,
546 &transmit_session_reject_message, h);
550 * Auxiliary function to terminate a call.
552 * @param h conversation handle
555 terminate_call (struct GNUNET_CONVERSATION_Handle *h)
557 GNUNET_CLIENT_notify_transmit_ready (h->client,
559 ClientServerSessionTerminateMessage),
560 MAX_TRANSMIT_DELAY, GNUNET_YES,
561 &transmit_session_terminate_message,
569 gns_call_cb (void *cls, uint32_t rd_count,
570 const struct GNUNET_NAMESTORE_RecordData *rd)
572 struct GNUNET_CONVERSATION_Handle *handle = cls;
573 struct GNUNET_PeerIdentity peer;
576 for (i=0;i<rd_count;i++)
578 switch (rd[i].record_type)
580 case GNUNET_DNSPARSER_TYPE_TXT: /* FIXME: use fresh record type for voide... */
582 GNUNET_CRYPTO_ecc_public_sign_key_from_string (rd[i].data,
589 initiate_call (handle, peer);
595 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
597 handle->notification_handler (NULL, handle,
598 NotificationType_NO_PEER,
607 gns_lookup_and_call (struct GNUNET_CONVERSATION_Handle *h, const char *callee)
609 char domain[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
613 strcpy (pos, "conversation");
614 pos += strlen ("conversation");
617 strcpy (pos, callee);
618 pos += strlen (callee);
620 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Lookup for %s\n", domain);
622 GNUNET_GNS_lookup (h->gns,
624 NULL /* FIXME: ZONE! */,
625 GNUNET_DNSPARSER_TYPE_TXT,
632 /******************************************************************************/
633 /********************** API CALL DEFINITIONS *************************/
634 /******************************************************************************/
636 struct GNUNET_CONVERSATION_Handle *
637 GNUNET_CONVERSATION_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, void *cls,
638 GNUNET_CONVERSATION_CallHandler * call_handler,
639 GNUNET_CONVERSATION_RejectHandler * reject_handler,
640 GNUNET_CONVERSATION_NotificationHandler * notification_handler,
641 GNUNET_CONVERSATION_MissedCallHandler * missed_call_handler)
643 struct GNUNET_CONVERSATION_Handle *h;
645 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "GNUNET_CONVERSATION_connect()\n");
646 h = GNUNET_malloc (sizeof (struct GNUNET_CONVERSATION_Handle));
649 h->call_handler = call_handler;
650 h->reject_handler = reject_handler;
651 h->notification_handler = notification_handler;
652 h->missed_call_handler = missed_call_handler;
654 if (NULL == (h->client = GNUNET_CLIENT_connect ("conversation", cfg)))
656 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access CONVERSATION service\n");
663 if (NULL == (h->gns = GNUNET_GNS_connect (cfg)))
665 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not access GNS service\n");
667 GNUNET_CLIENT_disconnect (h->client);
673 if (NULL == (h->namestore = GNUNET_NAMESTORE_connect (cfg)))
675 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
676 "Could not access NAMESTORE service\n");
678 GNUNET_CLIENT_disconnect (h->client);
679 GNUNET_GNS_disconnect (h->gns);
686 GNUNET_CLIENT_receive (h->client, &receive_message_cb, h,
687 GNUNET_TIME_UNIT_FOREVER_REL);
693 GNUNET_CONVERSATION_disconnect (struct GNUNET_CONVERSATION_Handle *handle)
695 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "CONVERSATION DISCONNECT\n");
697 GNUNET_CLIENT_disconnect (handle->client);
698 GNUNET_GNS_disconnect (handle->gns);
700 GNUNET_free (handle);
706 GNUNET_CONVERSATION_call (struct GNUNET_CONVERSATION_Handle *h,
710 struct GNUNET_PeerIdentity peer;
712 if (NULL == h || NULL == h->client)
715 if (GNUNET_YES == doGnsLookup)
717 gns_lookup_and_call (h, callee);
721 GNUNET_CRYPTO_ecc_public_sign_key_from_string (callee,
725 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
726 _("`%s' is not a valid public key\n"),
728 h->notification_handler (NULL, h, NotificationType_NO_PEER, NULL);
731 initiate_call (h, peer);
735 GNUNET_CONVERSATION_hangup (struct GNUNET_CONVERSATION_Handle *h)
737 if (NULL == h || NULL == h->client)
744 GNUNET_CONVERSATION_accept (struct GNUNET_CONVERSATION_Handle *h)
746 if (NULL == h || NULL == h->client)
753 GNUNET_CONVERSATION_reject (struct GNUNET_CONVERSATION_Handle *h)
755 if (NULL == h || NULL == h->client)
761 /* end of conversation_api.c */