gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

commit 1bdbb8bc0cec3650843daf5eb559ed46e9a69fd7
parent 022002438e4047d235a688cfd9da7b63ab990103
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 29 May 2013 08:19:14 +0000

-removing chat from build

Diffstat:
Mconfigure.ac | 2--
Dsrc/chat/Makefile.am | 137-------------------------------------------------------------------------------
Dsrc/chat/chat.c | 822-------------------------------------------------------------------------------
Dsrc/chat/chat.conf.in | 21---------------------
Dsrc/chat/chat.h | 485-------------------------------------------------------------------------------
Dsrc/chat/gnunet-chat.c | 750-------------------------------------------------------------------------------
Dsrc/chat/gnunet-service-chat.c | 1713-------------------------------------------------------------------------------
Dsrc/chat/test_chat.c | 556-------------------------------------------------------------------------------
Dsrc/chat/test_chat_data.conf | 55-------------------------------------------------------
Dsrc/chat/test_chat_peer1.conf | 92-------------------------------------------------------------------------------
Dsrc/chat/test_chat_peer2.conf | 94-------------------------------------------------------------------------------
Dsrc/chat/test_chat_peer3.conf | 93-------------------------------------------------------------------------------
Dsrc/chat/test_chat_private.c | 640-------------------------------------------------------------------------------
13 files changed, 0 insertions(+), 5460 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -1223,8 +1223,6 @@ src/ats/Makefile src/ats/ats.conf src/ats-tool/Makefile src/block/Makefile -src/chat/Makefile -src/chat/chat.conf src/core/Makefile src/core/core.conf src/consensus/Makefile diff --git a/src/chat/Makefile.am b/src/chat/Makefile.am @@ -1,137 +0,0 @@ -INCLUDES = -I$(top_srcdir)/src/include - -pkgcfgdir= $(pkgdatadir)/config.d/ - -libexecdir= $(pkglibdir)/libexec/ - -pkgcfg_DATA = \ - chat.conf - -if MINGW - WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols -endif - -if USE_COVERAGE - AM_CFLAGS = -fprofile-arcs -ftest-coverage -endif - -lib_LTLIBRARIES = libgnunetchat.la - -libgnunetchat_la_SOURCES = \ - chat.c chat.h - -libgnunetchat_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/fs/libgnunetfs.la - -libgnunetchat_la_DEPENDENCIES = \ - $(top_builddir)/src/fs/libgnunetfs.la - -libgnunetchat_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) $(WINFLAGS) \ - -version-info 0:0:0 - -libexec_PROGRAMS = \ - gnunet-service-chat - -bin_PROGRAMS = \ - gnunet-chat - -gnunet_service_chat_SOURCES = \ - gnunet-service-chat.c -gnunet_service_chat_LDADD = \ - $(top_builddir)/src/core/libgnunetcore.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) - -gnunet_chat_SOURCES = \ - gnunet-chat.c -gnunet_chat_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/fs/libgnunetfs.la \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(GN_LIBINTL) -gnunet_chat_DEPENDENCIES = \ - libgnunetchat.la - -check_PROGRAMS = \ - test_chat \ - test_chat_acknowledgement \ - test_chat_anonymous \ - test_chat_authentication \ - test_chat_p2p \ - test_chat_acknowledgement_p2p \ - test_chat_anonymous_p2p \ - test_chat_authentication_p2p \ - test_chat_private \ - test_chat_private_p2p - -if ENABLE_TEST_RUN -TESTS = $(check_PROGRAMS) -endif - -test_chat_SOURCES = \ - test_chat.c -test_chat_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_chat_acknowledgement_SOURCES = \ - test_chat.c -test_chat_acknowledgement_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_chat_anonymous_SOURCES = \ - test_chat.c -test_chat_anonymous_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_chat_authentication_SOURCES = \ - test_chat.c -test_chat_authentication_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_chat_p2p_SOURCES = \ - test_chat.c -test_chat_p2p_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_chat_acknowledgement_p2p_SOURCES = \ - test_chat.c -test_chat_acknowledgement_p2p_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_chat_anonymous_p2p_SOURCES = \ - test_chat.c -test_chat_anonymous_p2p_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_chat_authentication_p2p_SOURCES = \ - test_chat.c -test_chat_authentication_p2p_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_chat_private_SOURCES = \ - test_chat_private.c -test_chat_private_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -test_chat_private_p2p_SOURCES = \ - test_chat_private.c -test_chat_private_p2p_LDADD = \ - $(top_builddir)/src/chat/libgnunetchat.la \ - $(top_builddir)/src/util/libgnunetutil.la - -EXTRA_DIST = \ - test_chat_data.conf \ - test_chat_peer1.conf \ - test_chat_peer2.conf \ - test_chat_peer3.conf diff --git a/src/chat/chat.c b/src/chat/chat.c @@ -1,822 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2008, 2011 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file chat/chat.c - * @brief convenience API for sending and receiving chat messages - * @author Christian Grothoff - * @author Nathan Evans - * @author Vitaly Minko - */ - -#include "platform.h" -#include "gnunet_constants.h" -#include "gnunet_protocols.h" -#include "gnunet_signatures.h" -#include "gnunet_fs_service.h" -#include "chat.h" - -#define DEBUG_CHAT GNUNET_EXTRA_LOGGING -#define NICK_IDENTITY_PREFIX ".chat_identity_" - - -/** - * Handle for a chat room. - */ -struct GNUNET_CHAT_Room -{ - struct GNUNET_CLIENT_Connection *client; - - const struct GNUNET_CONFIGURATION_Handle *cfg; - - struct GNUNET_CONTAINER_MetaData *member_info; - - char *room_name; - - struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; - - struct MemberList *members; - - int is_joined; - - GNUNET_CHAT_JoinCallback join_callback; - - void *join_callback_cls; - - GNUNET_CHAT_MessageCallback message_callback; - - void *message_callback_cls; - - GNUNET_CHAT_MemberListCallback member_list_callback; - - void *member_list_callback_cls; - - GNUNET_CHAT_MessageConfirmation confirmation_callback; - - void *confirmation_cls; - - uint32_t sequence_number; - - uint32_t msg_options; - -}; - -/** - * Linked list of members in the chat room. - */ -struct MemberList -{ - struct MemberList *next; - - /** - * Description of the member. - */ - struct GNUNET_CONTAINER_MetaData *meta; - - /** - * Member ID (pseudonym). - */ - struct GNUNET_HashCode id; - -}; - -/** - * Context for transmitting a send-message request. - */ -struct GNUNET_CHAT_SendMessageContext -{ - /** - * Handle for the chat room. - */ - struct GNUNET_CHAT_Room *chat_room; - - /** - * Message that we're sending. - */ - char *message; - - /** - * Options for the message. - */ - enum GNUNET_CHAT_MsgOptions options; - - /** - * Receiver of the message. NULL to send to everyone in the room. - */ - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *receiver; - - /** - * Sequence id of the message. - */ - uint32_t sequence_number; - -}; - -/** - * Context for transmitting a confirmation receipt. - */ -struct GNUNET_CHAT_SendReceiptContext -{ - /** - * Handle for the chat room. - */ - struct GNUNET_CHAT_Room *chat_room; - - /** - * The original message that we're going to acknowledge. - */ - struct ReceiveNotificationMessage *received_msg; - -}; - -/** - * Ask client to send a join request. - */ -static int -rejoin_room (struct GNUNET_CHAT_Room *chat_room); - - -/** - * Transmit a confirmation receipt to the chat service. - * - * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendReceiptContext' - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf - */ -static size_t -transmit_acknowledge_request (void *cls, size_t size, void *buf) -{ - struct GNUNET_CHAT_SendReceiptContext *src = cls; - struct ConfirmationReceiptMessage *receipt; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key; - uint16_t msg_len; - size_t msg_size; - - if (NULL == buf) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Could not transmit confirmation receipt\n")); - return 0; - } -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmitting confirmation receipt to the service\n"); -#endif - msg_size = sizeof (struct ConfirmationReceiptMessage); - GNUNET_assert (size >= msg_size); - receipt = buf; - receipt->header.size = htons (msg_size); - receipt->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT); - receipt->reserved = htonl (0); - receipt->sequence_number = src->received_msg->sequence_number; - receipt->reserved2 = htonl (0); - receipt->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); - GNUNET_CRYPTO_rsa_key_get_public (src->chat_room->my_private_key, &pub_key); - GNUNET_CRYPTO_hash (&pub_key, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &receipt->target); - receipt->author = src->received_msg->sender; - receipt->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT); - receipt->purpose.size = - htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - - sizeof (uint32_t) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); - msg_len = - ntohs (src->received_msg->header.size) - - sizeof (struct ReceiveNotificationMessage); - GNUNET_CRYPTO_hash (&src->received_msg[1], msg_len, &receipt->content); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (src->chat_room->my_private_key, - &receipt->purpose, - &receipt->signature)); - GNUNET_free (src->received_msg); - GNUNET_free (src); - return msg_size; -} - - -/** - * Handles messages received from the service. Calls the proper client - * callback. - */ -static void -process_result (struct GNUNET_CHAT_Room *room, - const struct GNUNET_MessageHeader *reply) -{ - struct LeaveNotificationMessage *leave_msg; - struct JoinNotificationMessage *join_msg; - struct ReceiveNotificationMessage *received_msg; - struct ConfirmationReceiptMessage *receipt; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; - struct GNUNET_HashCode id; - const struct GNUNET_HashCode *sender; - struct GNUNET_CONTAINER_MetaData *meta; - struct GNUNET_CHAT_SendReceiptContext *src; - struct MemberList *pos; - struct MemberList *prev; - struct GNUNET_CRYPTO_AesSessionKey key; - char decrypted_msg[MAX_MESSAGE_LENGTH]; - uint16_t size; - uint16_t meta_len; - uint16_t msg_len; - char *message_content; - - size = ntohs (reply->size); - switch (ntohs (reply->type)) - { - case GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION: -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a join notification\n"); -#endif - if (size < sizeof (struct JoinNotificationMessage)) - { - GNUNET_break (0); - return; - } - join_msg = (struct JoinNotificationMessage *) reply; - meta_len = size - sizeof (struct JoinNotificationMessage); - meta = - GNUNET_CONTAINER_meta_data_deserialize ((const char *) &join_msg[1], - meta_len); - if (NULL == meta) - { - GNUNET_break (0); - return; - } - pos = GNUNET_malloc (sizeof (struct MemberList)); - pos->meta = meta; - GNUNET_CRYPTO_hash (&join_msg->public_key, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &pos->id); - GNUNET_FS_pseudonym_add (room->cfg, &pos->id, meta); - pos->next = room->members; - room->members = pos; - if (GNUNET_NO == room->is_joined) - { - GNUNET_CRYPTO_rsa_key_get_public (room->my_private_key, &pkey); - if (0 == - memcmp (&join_msg->public_key, &pkey, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded))) - { - room->join_callback (room->join_callback_cls); - room->is_joined = GNUNET_YES; - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("The current user must be the the first one joined\n")); - GNUNET_break (0); - return; - } - } - else - room->member_list_callback (room->member_list_callback_cls, meta, - &join_msg->public_key, - ntohl (join_msg->msg_options)); - break; - case GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION: -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a leave notification\n"); -#endif - if (size < sizeof (struct LeaveNotificationMessage)) - { - GNUNET_break (0); - return; - } - leave_msg = (struct LeaveNotificationMessage *) reply; - room->member_list_callback (room->member_list_callback_cls, NULL, - &leave_msg->user, GNUNET_CHAT_MSG_OPTION_NONE); - GNUNET_CRYPTO_hash (&leave_msg->user, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &id); - prev = NULL; - pos = room->members; - while ((NULL != pos) && - (0 != memcmp (&pos->id, &id, sizeof (struct GNUNET_HashCode)))) - { - prev = pos; - pos = pos->next; - } - GNUNET_assert (NULL != pos); - if (NULL == prev) - room->members = pos->next; - else - prev->next = pos->next; - GNUNET_CONTAINER_meta_data_destroy (pos->meta); - GNUNET_free (pos); - break; - case GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION: -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message notification\n"); -#endif - if (size <= sizeof (struct ReceiveNotificationMessage)) - { - GNUNET_break (0); - return; - } - received_msg = (struct ReceiveNotificationMessage *) reply; - if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ACKNOWLEDGED)) - { - src = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendReceiptContext)); - src->chat_room = room; - src->received_msg = GNUNET_memdup (received_msg, size); - GNUNET_CLIENT_notify_transmit_ready (room->client, - sizeof (struct - ConfirmationReceiptMessage), - GNUNET_CONSTANTS_SERVICE_TIMEOUT, - GNUNET_YES, - &transmit_acknowledge_request, src); - } - msg_len = size - sizeof (struct ReceiveNotificationMessage); - if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_PRIVATE)) - { - if (-1 == - GNUNET_CRYPTO_rsa_decrypt (room->my_private_key, - &received_msg->encrypted_key, &key, - sizeof (struct - GNUNET_CRYPTO_AesSessionKey))) - { - GNUNET_break (0); - return; - } - msg_len = - GNUNET_CRYPTO_aes_decrypt (&received_msg[1], msg_len, &key, - (const struct - GNUNET_CRYPTO_AesInitializationVector *) - INITVALUE, decrypted_msg); - message_content = decrypted_msg; - } - else - { - message_content = GNUNET_malloc (msg_len + 1); - memcpy (message_content, &received_msg[1], msg_len); - } - message_content[msg_len] = '\0'; - if (0 != (ntohl (received_msg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)) - { - sender = NULL; - meta = NULL; - } - else - { - pos = room->members; - while ((NULL != pos) && - (0 != - memcmp (&pos->id, &received_msg->sender, - sizeof (struct GNUNET_HashCode)))) - pos = pos->next; - GNUNET_assert (NULL != pos); - sender = &received_msg->sender; - meta = pos->meta; - } - room->message_callback (room->message_callback_cls, room, sender, meta, - message_content, - GNUNET_TIME_absolute_ntoh (received_msg->timestamp), - ntohl (received_msg->msg_options)); - if (message_content != decrypted_msg) - GNUNET_free (message_content); - break; - case GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION: -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a confirmation receipt\n"); -#endif - if (size < sizeof (struct ConfirmationReceiptMessage)) - { - GNUNET_break (0); - return; - } - receipt = (struct ConfirmationReceiptMessage *) reply; - if (NULL != room->confirmation_callback) - room->confirmation_callback (room->confirmation_cls, room, - ntohl (receipt->sequence_number), - GNUNET_TIME_absolute_ntoh - (receipt->timestamp), &receipt->target); - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unknown message type: '%u'\n"), - ntohs (reply->type)); - GNUNET_break_op (0); - break; - } -} - - -/** - * Listen for incoming messages on this chat room. Also, support servers going - * away/coming back (i.e. rejoin chat room to keep server state up to date). - * - * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' - * @param msg message received, NULL on timeout or fatal error - */ -static void -receive_results (void *cls, const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_CHAT_Room *chat_room = cls; - -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got a message from the service\n"); -#endif - if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & GNUNET_SCHEDULER_get_reason ())) - return; - if (NULL == msg) - { - GNUNET_break (0); - rejoin_room (chat_room); - return; - } - process_result (chat_room, msg); - if (NULL == chat_room->client) - return; /* fatal error */ - /* continue receiving */ - GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, - GNUNET_TIME_UNIT_FOREVER_REL); -} - - -/** - * Read existing private key from file or create a new one if it does not exist - * yet. - * Returns the private key on success, NULL on error. - */ -static struct GNUNET_CRYPTO_RsaPrivateKey * -init_private_key (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *nick_name) -{ - char *home; - char *keyfile; - struct GNUNET_CRYPTO_RsaPrivateKey *privKey; - -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initializing private key\n"); -#endif - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, "chat", "HOME", &home)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "chat", "HOME"); - return NULL; - } - GNUNET_DISK_directory_create (home); - if (GNUNET_YES != GNUNET_DISK_directory_test (home, GNUNET_YES)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to access chat home directory `%s'\n"), home); - GNUNET_free (home); - return NULL; - } - /* read or create private key */ - keyfile = - GNUNET_malloc (strlen (home) + strlen (NICK_IDENTITY_PREFIX) + - strlen (nick_name) + 2); - strcpy (keyfile, home); - GNUNET_free (home); - if (keyfile[strlen (keyfile) - 1] != DIR_SEPARATOR) - strcat (keyfile, DIR_SEPARATOR_STR); - strcat (keyfile, NICK_IDENTITY_PREFIX); - strcat (keyfile, nick_name); - privKey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); - if (NULL == privKey) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to create/open key in file `%s'\n"), keyfile); - } - GNUNET_free (keyfile); - return privKey; -} - - -/** - * Transmit a join request to the chat service. - * - * @param cls closure, pointer to the 'struct GNUNET_CHAT_Room' - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf - */ -static size_t -transmit_join_request (void *cls, size_t size, void *buf) -{ - struct GNUNET_CHAT_Room *chat_room = cls; - struct JoinRequestMessage *join_msg; - char *room; - char *meta; - size_t room_len; - ssize_t meta_len; - size_t size_of_join; - - if (NULL == buf) - { -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Could not transmit join request, retrying...\n"); -#endif - rejoin_room (chat_room); - return 0; - } -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmitting join request to the service\n"); -#endif - room_len = strlen (chat_room->room_name); - meta_len = - GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info); - size_of_join = sizeof (struct JoinRequestMessage) + meta_len + room_len; - GNUNET_assert (size >= size_of_join); - join_msg = buf; - join_msg->header.size = htons (size); - join_msg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST); - join_msg->msg_options = htonl (chat_room->msg_options); - join_msg->room_name_len = htons (room_len); - join_msg->reserved = htons (0); - join_msg->reserved2 = htonl (0); - GNUNET_CRYPTO_rsa_key_get_public (chat_room->my_private_key, - &join_msg->public_key); - room = (char *) &join_msg[1]; - memcpy (room, chat_room->room_name, room_len); - meta = &room[room_len]; - if (GNUNET_SYSERR == - GNUNET_CONTAINER_meta_data_serialize (chat_room->member_info, &meta, - meta_len, - GNUNET_CONTAINER_META_DATA_SERIALIZE_FULL)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not serialize metadata\n")); - return 0; - } - GNUNET_CLIENT_receive (chat_room->client, &receive_results, chat_room, - GNUNET_TIME_UNIT_FOREVER_REL); - return size_of_join; -} - - -/** - * Ask to send a join request. - */ -static int -rejoin_room (struct GNUNET_CHAT_Room *chat_room) -{ - size_t size_of_join; - - size_of_join = - sizeof (struct JoinRequestMessage) + - GNUNET_CONTAINER_meta_data_get_serialized_size (chat_room->member_info) + - strlen (chat_room->room_name); - if (NULL == - GNUNET_CLIENT_notify_transmit_ready (chat_room->client, size_of_join, - GNUNET_CONSTANTS_SERVICE_TIMEOUT, - GNUNET_YES, &transmit_join_request, - chat_room)) - return GNUNET_SYSERR; - return GNUNET_OK; -} - - -/** - * Leave a chat room. - */ -void -GNUNET_CHAT_leave_room (struct GNUNET_CHAT_Room *chat_room) -{ - struct MemberList *pos; - -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Leaving the room '%s'\n", - chat_room->room_name); -#endif - GNUNET_CLIENT_disconnect (chat_room->client); - GNUNET_free (chat_room->room_name); - GNUNET_CONTAINER_meta_data_destroy (chat_room->member_info); - GNUNET_CRYPTO_rsa_key_free (chat_room->my_private_key); - while (NULL != chat_room->members) - { - pos = chat_room->members; - chat_room->members = pos->next; - GNUNET_CONTAINER_meta_data_destroy (pos->meta); - GNUNET_free (pos); - } - GNUNET_free (chat_room); -} - - -/** - * Join a chat room. - * - * @param cfg configuration - * @param nick_name nickname of the user joining (used to - * determine which public key to use); - * the nickname should probably also - * be used in the member_info (as "EXTRACTOR_TITLE") - * @param member_info information about the joining member - * @param room_name name of the room - * @param msg_options message options of the joining user - * @param joinCallback function to call on successful join - * @param join_cls closure for joinCallback - * @param messageCallback which function to call if a message has - * been received? - * @param message_cls argument to callback - * @param memberCallback which function to call for join/leave notifications - * @param member_cls argument to callback - * @param confirmationCallback which function to call for confirmations (maybe NULL) - * @param confirmation_cls argument to callback - * @param me member ID (pseudonym) - * @return NULL on error - */ -struct GNUNET_CHAT_Room * -GNUNET_CHAT_join_room (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *nick_name, - struct GNUNET_CONTAINER_MetaData *member_info, - const char *room_name, - enum GNUNET_CHAT_MsgOptions msg_options, - GNUNET_CHAT_JoinCallback joinCallback, void *join_cls, - GNUNET_CHAT_MessageCallback messageCallback, - void *message_cls, - GNUNET_CHAT_MemberListCallback memberCallback, - void *member_cls, - GNUNET_CHAT_MessageConfirmation confirmationCallback, - void *confirmation_cls, struct GNUNET_HashCode * me) -{ - struct GNUNET_CHAT_Room *chat_room; - struct GNUNET_CRYPTO_RsaPrivateKey *priv_key; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key; - struct GNUNET_CLIENT_Connection *client; - -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Joining the room '%s'\n", room_name); -#endif - priv_key = init_private_key (cfg, nick_name); - if (NULL == priv_key) - return NULL; - GNUNET_CRYPTO_rsa_key_get_public (priv_key, &pub_key); - GNUNET_CRYPTO_hash (&pub_key, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - me); - GNUNET_FS_pseudonym_add (cfg, me, member_info); - client = GNUNET_CLIENT_connect ("chat", cfg); - if (NULL == client) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Failed to connect to the chat service\n")); - return NULL; - } - if (NULL == joinCallback) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Undefined mandatory parameter: joinCallback\n")); - return NULL; - } - if (NULL == messageCallback) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Undefined mandatory parameter: messageCallback\n")); - return NULL; - } - if (NULL == memberCallback) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Undefined mandatory parameter: memberCallback\n")); - return NULL; - } - chat_room = GNUNET_malloc (sizeof (struct GNUNET_CHAT_Room)); - chat_room->msg_options = msg_options; - chat_room->room_name = GNUNET_strdup (room_name); - chat_room->member_info = GNUNET_CONTAINER_meta_data_duplicate (member_info); - chat_room->my_private_key = priv_key; - chat_room->is_joined = GNUNET_NO; - chat_room->join_callback = joinCallback; - chat_room->join_callback_cls = join_cls; - chat_room->message_callback = messageCallback; - chat_room->message_callback_cls = message_cls; - chat_room->member_list_callback = memberCallback; - chat_room->member_list_callback_cls = member_cls; - chat_room->confirmation_callback = confirmationCallback; - chat_room->confirmation_cls = confirmation_cls; - chat_room->cfg = cfg; - chat_room->client = client; - chat_room->members = NULL; - if (GNUNET_SYSERR == rejoin_room (chat_room)) - { - GNUNET_CHAT_leave_room (chat_room); - return NULL; - } - return chat_room; -} - - -/** - * Transmit a send-message request to the chat service. - * - * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendMessageContext' - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf - */ -static size_t -transmit_send_request (void *cls, size_t size, void *buf) -{ - struct GNUNET_CHAT_SendMessageContext *smc = cls; - struct TransmitRequestMessage *msg_to_send; - size_t msg_size; - - if (NULL == buf) - { -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit a chat message\n"); -#endif - return 0; - } -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmitting a chat message to the service\n"); -#endif - msg_size = strlen (smc->message) + sizeof (struct TransmitRequestMessage); - GNUNET_assert (size >= msg_size); - msg_to_send = buf; - msg_to_send->header.size = htons (msg_size); - msg_to_send->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST); - msg_to_send->msg_options = htonl (smc->options); - msg_to_send->sequence_number = htonl (smc->sequence_number); - msg_to_send->timestamp = - GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); - msg_to_send->reserved = htonl (0); - if (NULL == smc->receiver) - memset (&msg_to_send->target, 0, sizeof (struct GNUNET_HashCode)); - else - GNUNET_CRYPTO_hash (smc->receiver, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &msg_to_send->target); - memcpy (&msg_to_send[1], smc->message, strlen (smc->message)); - /** - * Client don't encode private messages since public keys of other members are - * stored on the service side. - */ - if (smc->options & GNUNET_CHAT_MSG_AUTHENTICATED) - { - msg_to_send->purpose.purpose = - htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE); - msg_to_send->purpose.size = - htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - - sizeof (struct GNUNET_CRYPTO_RsaSignature)); - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_rsa_sign (smc->chat_room->my_private_key, - &msg_to_send->purpose, - &msg_to_send->signature)); - } - GNUNET_free (smc->message); - GNUNET_free (smc); - return msg_size; -} - - -/** - * Send a message. - * - * @param room handle for the chat room - * @param message message to be sent - * @param options options for the message - * @param receiver use NULL to send to everyone in the room - * @param sequence_number where to write the sequence id of the message - */ -void -GNUNET_CHAT_send_message (struct GNUNET_CHAT_Room *room, const char *message, - enum GNUNET_CHAT_MsgOptions options, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded - *receiver, uint32_t * sequence_number) -{ - size_t msg_size; - struct GNUNET_CHAT_SendMessageContext *smc; - -#if DEBUG_CHAT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending a message\n"); -#endif - room->sequence_number++; - if (NULL != sequence_number) - *sequence_number = room->sequence_number; - smc = GNUNET_malloc (sizeof (struct GNUNET_CHAT_SendMessageContext)); - smc->chat_room = room; - smc->message = GNUNET_strdup (message); - smc->options = options; - smc->receiver = receiver; - smc->sequence_number = room->sequence_number; - msg_size = strlen (message) + sizeof (struct TransmitRequestMessage); - GNUNET_CLIENT_notify_transmit_ready (room->client, msg_size, - GNUNET_CONSTANTS_SERVICE_TIMEOUT, - GNUNET_YES, &transmit_send_request, smc); -} - -/* end of chat.c */ diff --git a/src/chat/chat.conf.in b/src/chat/chat.conf.in @@ -1,21 +0,0 @@ -[chat] -AUTOSTART = YES -@UNIXONLY@ PORT = 2090 -HOSTNAME = localhost -HOME = $SERVICEHOME -BINARY = gnunet-service-chat -ACCEPT_FROM = 127.0.0.1; -ACCEPT_FROM6 = ::1; -UNIXPATH = /tmp/gnunet-service-chat.sock -UNIX_MATCH_UID = NO -UNIX_MATCH_GID = YES -# DISABLE_SOCKET_FORWARDING = NO -# USERNAME = -# MAXBUF = -# TIMEOUT = -# DISABLEV6 = -# BINDTO = -# REJECT_FROM = -# REJECT_FROM6 = -# PREFIX = - diff --git a/src/chat/chat.h b/src/chat/chat.h @@ -1,485 +0,0 @@ -/* - This file is part of GNUnet - (C) 2008, 2011 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file chat/chat.h - * @brief support for chat - * @author Christian Grothoff - * @author Nathan Evans - * @author Vitaly Minko - */ - -#ifndef CHAT_H -#define CHAT_H - -#include "gnunet_chat_service.h" - -/** - * Constant IV since we generate a new session key per each message. - */ -#define INITVALUE "InitializationVectorValue" - - -/** - * Client-service messages - */ - -GNUNET_NETWORK_STRUCT_BEGIN - -/** - * Notification sent by service to client indicating that we've received a chat - * message. After this struct, the remaining bytes are the actual text message. - * If the mesasge is private, then the text is encrypted, otherwise it's - * plaintext. - */ -struct ReceiveNotificationMessage -{ - /** - * Message type will be GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION - */ - struct GNUNET_MessageHeader header; - - /** - * Message options, see GNUNET_CHAT_MsgOptions. - */ - uint32_t msg_options GNUNET_PACKED; - - /** - * Sequence number of the message (unique per sender). - */ - uint32_t sequence_number GNUNET_PACKED; - - /** - * For alignment (should be zero). - */ - uint32_t reserved GNUNET_PACKED; - - /** - * Timestamp of the message. - */ - struct GNUNET_TIME_AbsoluteNBO timestamp; - - /** - * Hash of the public key of the pseudonym of the sender of the message. - * Should be all zeros for anonymous. - */ - struct GNUNET_HashCode sender; - - /** - * The encrypted session key. - */ - struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; - -}; - - -/** - * Request sent by client to transmit a chat message to another room members. - * After this struct, the remaining bytes are the actual message in plaintext. - * Private messages are encrypted on the service side. - */ -struct TransmitRequestMessage -{ - /** - * Message type will be GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST - */ - struct GNUNET_MessageHeader header; - - /** - * For alignment (should be zero). - */ - uint32_t reserved GNUNET_PACKED; - - /** - * Signature confirming receipt. Signature covers everything from header - * through content. - */ - struct GNUNET_CRYPTO_RsaSignature signature; - - /** - * What is being signed and why? - */ - struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; - - /** - * Desired message options, see GNUNET_CHAT_MsgOptions. - */ - uint32_t msg_options GNUNET_PACKED; - - /** - * Sequence number of the message (unique per sender). - */ - uint32_t sequence_number GNUNET_PACKED; - - /** - * Timestamp of the message. - */ - struct GNUNET_TIME_AbsoluteNBO timestamp; - - /** - * Who should receive this message? Set to all zeros for "everyone". - */ - struct GNUNET_HashCode target; - -}; - - -/** - * Receipt sent from a message receiver to the service to confirm delivery of - * a chat message and from the service to sender of the original message to - * acknowledge delivery. - */ -struct ConfirmationReceiptMessage -{ - /** - * Message type will be - * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT when sending from client, - * GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION when sending to client. - */ - struct GNUNET_MessageHeader header; - - /** - * For alignment (should be zero). - */ - uint32_t reserved GNUNET_PACKED; - - /** - * Signature confirming receipt. Signature covers everything from header - * through content. - */ - struct GNUNET_CRYPTO_RsaSignature signature; - - /** - * What is being signed and why? - */ - struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; - - /** - * Sequence number of the original message. - */ - uint32_t sequence_number GNUNET_PACKED; - - /** - * For alignment (should be zero). - */ - uint32_t reserved2 GNUNET_PACKED; - - /** - * Time of receipt. - */ - struct GNUNET_TIME_AbsoluteNBO timestamp; - - /** - * Who is confirming the receipt? - */ - struct GNUNET_HashCode target; - - /** - * Who is the author of the chat message? - */ - struct GNUNET_HashCode author; - - /** - * Hash of the (possibly encrypted) content. - */ - struct GNUNET_HashCode content; - -}; - - -/** - * Message send from client to daemon to join a chat room. - * This struct is followed by the room name and then - * the serialized ECRS meta data describing the new member. - */ -struct JoinRequestMessage -{ - /** - * Message type will be GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST - */ - struct GNUNET_MessageHeader header; - - /** - * Options. Set all options that this client is willing to receive. - * For example, if the client does not want to receive anonymous or - * OTR messages but is willing to generate acknowledgements and - * receive private messages, this should be set to - * GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. - */ - uint32_t msg_options GNUNET_PACKED; - - /** - * Length of the room name. - */ - uint16_t room_name_len GNUNET_PACKED; - - /** - * For alignment (should be zero). - */ - uint16_t reserved GNUNET_PACKED; - uint32_t reserved2 GNUNET_PACKED; - - /** - * Public key of the joining member. - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; - -}; - - -/** - * Message send by server to client to indicate joining of another room member. - * This struct is followed by the serialized ECRS MetaData describing the new - * member. - */ -struct JoinNotificationMessage -{ - /** - * Message type will be GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION - */ - struct GNUNET_MessageHeader header; - - /** - * Options. Set to all options that the new user is willing to - * process. For example, if the client does not want to receive - * anonymous or OTR messages but is willing to generate - * acknowledgements and receive private messages, this should be set - * to GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. - */ - uint32_t msg_options GNUNET_PACKED; - - /** - * Public key of the new user. - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; - -}; - - -/** - * Message send by server to client to indicate leaving of another room member. - */ -struct LeaveNotificationMessage -{ - /** - * Message type will be GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION - */ - struct GNUNET_MessageHeader header; - - /** - * Reserved (for alignment). - */ - uint32_t reserved GNUNET_PACKED; - - /** - * Who is leaving? - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded user; - -}; - - -/** - * Peer-to-peer messages - */ - -/** - * Message send by one peer to another to indicate joining of another room - * member. This struct is followed by the room name and then the serialized - * ECRS MetaData describing the new member. - */ -struct P2PJoinNotificationMessage -{ - /** - * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION - */ - struct GNUNET_MessageHeader header; - - /** - * Options. Set all options that this client is willing to receive. - * For example, if the client does not want to receive anonymous or - * OTR messages but is willing to generate acknowledgements and - * receive private messages, this should be set to - * GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED. - */ - uint32_t msg_options GNUNET_PACKED; - - /** - * Length of the room name. - */ - uint16_t room_name_len GNUNET_PACKED; - - /** - * Reserved (should be zero). - */ - uint16_t reserved GNUNET_PACKED; - uint32_t reserved2 GNUNET_PACKED; - - /** - * Public key of the joining member. - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; - -}; - - -/** - * Message send by one peer to another to indicate leaving of another room - * member. - */ -struct P2PLeaveNotificationMessage -{ - /** - * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION - */ - struct GNUNET_MessageHeader header; - - /** - * Reserved (for alignment). - */ - uint32_t reserved GNUNET_PACKED; - - /** - * Who is leaving? - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded user; - -}; - - -/** - * Message send by one peer to another to indicate receiving of a chat message. - * This struct is followed by the room name (only if the message is anonymous) - * and then the remaining bytes are the actual text message. If the mesasge is - * private, then the text is encrypted, otherwise it's plaintext. - */ -struct P2PReceiveNotificationMessage -{ - /** - * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION - */ - struct GNUNET_MessageHeader header; - - /** - * Message options, see GNUNET_CHAT_MsgOptions. - */ - uint32_t msg_options GNUNET_PACKED; - - /** - * Sequence number of the message (unique per sender). - */ - uint32_t sequence_number GNUNET_PACKED; - - /** - * Length of the room name. This is only used for anonymous messages. - */ - uint16_t room_name_len GNUNET_PACKED; - - /** - * Reserved (for alignment). - */ - uint16_t reserved GNUNET_PACKED; - - /** - * Timestamp of the message. - */ - struct GNUNET_TIME_AbsoluteNBO timestamp; - - /** - * Hash of the public key of the pseudonym of the sender of the message - * Should be all zeros for anonymous. - */ - struct GNUNET_HashCode sender; - - /** - * Who should receive this message? Set to all zeros for "everyone". - */ - struct GNUNET_HashCode target; - - /** - * The encrypted session key. - */ - struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key; - -}; - - -/** - * Receipt sent from one peer to another to confirm delivery of a chat message. - */ -struct P2PConfirmationReceiptMessage -{ - /** - * Message type will be GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT - */ - struct GNUNET_MessageHeader header; - - /** - * For alignment (should be zero). - */ - uint32_t reserved GNUNET_PACKED; - - /** - * Signature confirming receipt. Signature covers everything from header - * through content. - */ - struct GNUNET_CRYPTO_RsaSignature signature; - - /** - * What is being signed and why? - */ - struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; - - /** - * Sequence number of the original message. - */ - uint32_t msg_sequence_number GNUNET_PACKED; - - /** - * Sequence number of the receipt. - */ - uint32_t sequence_number GNUNET_PACKED; - - /** - * Time of receipt. - */ - struct GNUNET_TIME_AbsoluteNBO timestamp; - - /** - * Who is confirming the receipt? - */ - struct GNUNET_HashCode target; - - /** - * Who is the author of the chat message? - */ - struct GNUNET_HashCode author; - - /** - * Hash of the (possibly encrypted) content. - */ - struct GNUNET_HashCode content; - -}; -GNUNET_NETWORK_STRUCT_END - -#endif - -/* end of chat.h */ diff --git a/src/chat/gnunet-chat.c b/src/chat/gnunet-chat.c @@ -1,750 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2007, 2008, 2011 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file chat/gnunet-chat.c - * @brief Minimal chat command line tool - * @author Christian Grothoff - * @author Nathan Evans - * @author Vitaly Minko - */ - -#include "platform.h" -#include "gnunet_getopt_lib.h" -#include "gnunet_program_lib.h" -#include "gnunet_chat_service.h" -#include "gnunet_fs_service.h" -#include <fcntl.h> - -static int ret; - -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -static char *nickname; - -static char *room_name; - -static struct GNUNET_CONTAINER_MetaData *meta; - -static struct GNUNET_CHAT_Room *room; - -static GNUNET_SCHEDULER_TaskIdentifier handle_cmd_task; - -typedef int (*ActionFunction)(const char *argumetns, const void *xtra); - -struct ChatCommand -{ - const char *command; - ActionFunction Action; - const char *helptext; -}; - -struct UserList -{ - struct UserList *next; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey; - int ignored; -}; - -static struct UserList *users; - -static void -free_user_list () -{ - struct UserList *next; - - while (NULL != users) - { - next = users->next; - GNUNET_free (users); - users = next; - } -} - -static int -do_help (const char *args, const void *xtra); - - -/** - * Callback used for notification that we have joined the room. - * - * @param cls closure - * @return GNUNET_OK - */ -static int -join_cb (void *cls) -{ - FPRINTF (stdout, "%s", _("Joined\n")); - return GNUNET_OK; -} - - -/** - * Callback used for notification about incoming messages. - * - * @param cls closure, NULL - * @param room in which room was the message received? - * @param sender what is the ID of the sender? (maybe NULL) - * @param member_info information about the joining member - * @param message the message text - * @param timestamp time when the member joined - * @param options options for the message - * @return GNUNET_OK to accept the message now, GNUNET_NO to - * accept (but user is away), GNUNET_SYSERR to signal denied delivery - */ -static int -receive_cb (void *cls, struct GNUNET_CHAT_Room *room, - const struct GNUNET_HashCode * sender, - const struct GNUNET_CONTAINER_MetaData *member_info, - const char *message, struct GNUNET_TIME_Absolute timestamp, - enum GNUNET_CHAT_MsgOptions options) -{ - char *non_unique_nick; - char *nick; - int nick_is_a_dup; - const char *timestr; - const char *fmt; - - if (NULL == sender) - nick = GNUNET_strdup (_("anonymous")); - else - { - if (GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, - sender, NULL, NULL, &non_unique_nick, &nick_is_a_dup) - || (nick_is_a_dup == GNUNET_YES)) - { - GNUNET_free (non_unique_nick); - non_unique_nick = GNUNET_strdup (_("anonymous")); - } - nick = GNUNET_FS_pseudonym_name_uniquify (cfg, sender, non_unique_nick, NULL); - GNUNET_free (non_unique_nick); - } - - fmt = NULL; - switch ((int) options) - { - case GNUNET_CHAT_MSG_OPTION_NONE: - case GNUNET_CHAT_MSG_ANONYMOUS: - fmt = _("(%s) `%s' said: %s\n"); - break; - case GNUNET_CHAT_MSG_PRIVATE: - fmt = _("(%s) `%s' said to you: %s\n"); - break; - case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ANONYMOUS: - fmt = _("(%s) `%s' said to you: %s\n"); - break; - case GNUNET_CHAT_MSG_AUTHENTICATED: - fmt = _("(%s) `%s' said for sure: %s\n"); - break; - case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_AUTHENTICATED: - fmt = _("(%s) `%s' said to you for sure: %s\n"); - break; - case GNUNET_CHAT_MSG_ACKNOWLEDGED: - fmt = _("(%s) `%s' was confirmed that you received: %s\n"); - break; - case GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: - fmt = _("(%s) `%s' was confirmed that you and only you received: %s\n"); - break; - case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_ACKNOWLEDGED: - fmt = _("(%s) `%s' was confirmed that you received from him or her: %s\n"); - break; - case GNUNET_CHAT_MSG_AUTHENTICATED | GNUNET_CHAT_MSG_PRIVATE | GNUNET_CHAT_MSG_ACKNOWLEDGED: - fmt = - _ - ("(%s) `%s' was confirmed that you and only you received from him or her: %s\n"); - break; - case GNUNET_CHAT_MSG_OFF_THE_RECORD: - fmt = _("(%s) `%s' said off the record: %s\n"); - break; - default: - fmt = _("(%s) <%s> said using an unknown message type: %s\n"); - break; - } - timestr = GNUNET_STRINGS_absolute_time_to_string (timestamp); - FPRINTF (stdout, fmt, timestr, nick, message); - GNUNET_free (nick); - return GNUNET_OK; -} - - -/** - * Callback used for message delivery confirmations. - * - * @param cls closure, NULL - * @param room in which room was the message received? - * @param orig_seq_number sequence number of the original message - * @param timestamp when was the message received? - * @param receiver who is confirming the receipt? - * @return GNUNET_OK to continue, GNUNET_SYSERR to refuse processing further - * confirmations from anyone for this message - */ -static int -confirmation_cb (void *cls, struct GNUNET_CHAT_Room *room, - uint32_t orig_seq_number, - struct GNUNET_TIME_Absolute timestamp, - const struct GNUNET_HashCode * receiver) -{ - char *nick; - char *unique_nick; - int nick_is_a_dup; - - if (GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, - receiver, NULL, NULL, &nick, &nick_is_a_dup) - || (nick_is_a_dup == GNUNET_YES)) - { - GNUNET_free (nick); - nick = GNUNET_strdup (_("anonymous")); - } - unique_nick = GNUNET_FS_pseudonym_name_uniquify (cfg, receiver, nick, NULL); - GNUNET_free (nick); - FPRINTF (stdout, _("'%s' acknowledged message #%d\n"), unique_nick, orig_seq_number); - GNUNET_free (unique_nick); - return GNUNET_OK; -} - - -/** - * Callback used for notification that another room member has joined or left. - * - * @param cls closure (not used) - * @param member_info will be non-null if the member is joining, NULL if he is - * leaving - * @param member_id hash of public key of the user (for unique identification) - * @param options what types of messages is this member willing to receive? - * @return GNUNET_OK - */ -static int -member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, - enum GNUNET_CHAT_MsgOptions options) -{ - char *nick; - char *non_unique_nick; - int nick_is_a_dup; - struct GNUNET_HashCode id; - struct UserList *pos; - struct UserList *prev; - - GNUNET_CRYPTO_hash (member_id, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &id); - if (GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, - &id, NULL, NULL, &non_unique_nick, &nick_is_a_dup) - || (nick_is_a_dup == GNUNET_YES)) - { - GNUNET_free (non_unique_nick); - non_unique_nick = GNUNET_strdup (_("anonymous")); - } - nick = GNUNET_FS_pseudonym_name_uniquify (cfg, &id, non_unique_nick, NULL); - GNUNET_free (non_unique_nick); - - FPRINTF (stdout, - member_info != - NULL ? _("`%s' entered the room\n") : _("`%s' left the room\n"), - nick); - GNUNET_free (nick); - if (NULL != member_info) - { - /* user joining */ - pos = GNUNET_malloc (sizeof (struct UserList)); - pos->next = users; - pos->pkey = *member_id; - pos->ignored = GNUNET_NO; - users = pos; - } - else - { - /* user leaving */ - prev = NULL; - pos = users; - while ((NULL != pos) && - (0 != - memcmp (&pos->pkey, member_id, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))) - { - prev = pos; - pos = pos->next; - } - if (NULL == pos) - { - GNUNET_break (0); - } - else - { - if (NULL == prev) - users = pos->next; - else - prev->next = pos->next; - GNUNET_free (pos); - } - } - return GNUNET_OK; -} - - -static int -do_join (const char *arg, const void *xtra) -{ - char *my_name; - int my_name_is_a_dup; - struct GNUNET_HashCode me; - - if (arg[0] == '#') - arg++; /* ignore first hash */ - GNUNET_CHAT_leave_room (room); - free_user_list (); - GNUNET_free (room_name); - room_name = GNUNET_strdup (arg); - room = - GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, - &receive_cb, NULL, &member_list_cb, NULL, - &confirmation_cb, NULL, &me); - if (NULL == room) - { - FPRINTF (stdout, "%s", _("Could not change username\n")); - return GNUNET_SYSERR; - } - if ((GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, - &me, NULL, NULL, &my_name, &my_name_is_a_dup)) || - (my_name_is_a_dup == GNUNET_YES)) - { - GNUNET_free (my_name); - my_name = GNUNET_strdup (_("anonymous")); - } - /* Don't uniquify our own name - other people will have a different - * suffix for our own name anyway. - */ - FPRINTF (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, - my_name); - GNUNET_free (my_name); - return GNUNET_OK; -} - - -static int -do_nick (const char *msg, const void *xtra) -{ - char *my_name; - int my_name_is_a_dup; - struct GNUNET_HashCode me; - - GNUNET_CHAT_leave_room (room); - free_user_list (); - GNUNET_free (nickname); - GNUNET_CONTAINER_meta_data_destroy (meta); - nickname = GNUNET_strdup (msg); - meta = GNUNET_CONTAINER_meta_data_create (); - GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>", EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METAFORMAT_UTF8, "text/plain", - nickname, strlen (nickname) + 1); - room = - GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, - &receive_cb, NULL, &member_list_cb, NULL, - &confirmation_cb, NULL, &me); - if (NULL == room) - { - FPRINTF (stdout, "%s", _("Could not change username\n")); - return GNUNET_SYSERR; - } - if ((GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, - &me, NULL, NULL, &my_name, &my_name_is_a_dup)) || - (my_name_is_a_dup == GNUNET_YES)) - { - GNUNET_free (my_name); - my_name = GNUNET_strdup (_("anonymous")); - } - FPRINTF (stdout, _("Changed username to `%s'\n"), my_name); - GNUNET_free (my_name); - return GNUNET_OK; -} - - -static int -do_names (const char *msg, const void *xtra) -{ - char *name; - char *unique_name; - int name_is_a_dup; - struct UserList *pos; - struct GNUNET_HashCode pid; - - FPRINTF (stdout, _("Users in room `%s': "), room_name); - pos = users; - while (NULL != pos) - { - GNUNET_CRYPTO_hash (&pos->pkey, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &pid); - if (GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, - &pid, NULL, NULL, &name, &name_is_a_dup) - || (name_is_a_dup == GNUNET_YES)) - { - GNUNET_free (name); - name = GNUNET_strdup (_("anonymous")); - } - unique_name = GNUNET_FS_pseudonym_name_uniquify (cfg, &pid, name, NULL); - GNUNET_free (name); - FPRINTF (stdout, "`%s' ", unique_name); - GNUNET_free (unique_name); - pos = pos->next; - } - FPRINTF (stdout, "%s", "\n"); - return GNUNET_OK; -} - - -static int -do_send (const char *msg, const void *xtra) -{ - uint32_t seq; - - GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_OPTION_NONE, NULL, &seq); - return GNUNET_OK; -} - - -static int -do_send_pm (const char *msg, const void *xtra) -{ - char *user; - struct GNUNET_HashCode uid; - struct GNUNET_HashCode pid; - uint32_t seq; - struct UserList *pos; - - if (NULL == strstr (msg, " ")) - { - FPRINTF (stderr, "%s", _("Syntax: /msg USERNAME MESSAGE")); - return GNUNET_OK; - } - user = GNUNET_strdup (msg); - strstr (user, " ")[0] = '\0'; - msg += strlen (user) + 1; - if (GNUNET_OK != GNUNET_FS_pseudonym_name_to_id (cfg, user, &uid)) - { - FPRINTF (stderr, - _("Unknown user `%s'. Make sure you specify its numeric suffix, if any.\n"), - user); - GNUNET_free (user); - return GNUNET_OK; - } - pos = users; - while (NULL != pos) - { - GNUNET_CRYPTO_hash (&pos->pkey, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &pid); - if (0 == memcmp (&pid, &uid, sizeof (struct GNUNET_HashCode))) - break; - pos = pos->next; - } - if (NULL == pos) - { - FPRINTF (stderr, _("User `%s' is currently not in the room!\n"), user); - GNUNET_free (user); - return GNUNET_OK; - } - GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_PRIVATE, &pos->pkey, - &seq); - GNUNET_free (user); - return GNUNET_OK; -} - - -static int -do_send_sig (const char *msg, const void *xtra) -{ - uint32_t seq; - - GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_AUTHENTICATED, NULL, - &seq); - return GNUNET_OK; -} - - -static int -do_send_ack (const char *msg, const void *xtra) -{ - uint32_t seq; - - GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_ACKNOWLEDGED, NULL, - &seq); - return GNUNET_OK; -} - - -static int -do_send_anonymous (const char *msg, const void *xtra) -{ - uint32_t seq; - - GNUNET_CHAT_send_message (room, msg, GNUNET_CHAT_MSG_ANONYMOUS, NULL, &seq); - return GNUNET_OK; -} - - -static int -do_quit (const char *args, const void *xtra) -{ - return GNUNET_SYSERR; -} - - -static int -do_unknown (const char *msg, const void *xtra) -{ - FPRINTF (stderr, _("Unknown command `%s'\n"), msg); - return GNUNET_OK; -} - - -/** - * List of supported IRC commands. The order matters! - */ -static struct ChatCommand commands[] = { - {"/join ", &do_join, - gettext_noop - ("Use `/join #roomname' to join a chat room. Joining a room will cause you" - " to leave the current room")}, - {"/nick ", &do_nick, - gettext_noop - ("Use `/nick nickname' to change your nickname. This will cause you to" - " leave the current room and immediately rejoin it with the new name.")}, - {"/msg ", &do_send_pm, - gettext_noop - ("Use `/msg nickname message' to send a private message to the specified" - " user")}, - {"/notice ", &do_send_pm, - gettext_noop ("The `/notice' command is an alias for `/msg'")}, - {"/query ", &do_send_pm, - gettext_noop ("The `/query' command is an alias for `/msg'")}, - {"/sig ", &do_send_sig, - gettext_noop ("Use `/sig message' to send a signed public message")}, - {"/ack ", &do_send_ack, - gettext_noop - ("Use `/ack message' to require signed acknowledgment of the message")}, - {"/anonymous ", &do_send_anonymous, - gettext_noop - ("Use `/anonymous message' to send a public anonymous message")}, - {"/anon ", &do_send_anonymous, - gettext_noop ("The `/anon' command is an alias for `/anonymous'")}, - {"/quit", &do_quit, - gettext_noop ("Use `/quit' to terminate gnunet-chat")}, - {"/leave", &do_quit, - gettext_noop ("The `/leave' command is an alias for `/quit'")}, - {"/names", &do_names, - gettext_noop - ("Use `/names' to list all of the current members in the chat room")}, - {"/help", &do_help, - gettext_noop ("Use `/help command' to get help for a specific command")}, - /* Add standard commands: - * /whois (print metadata), - * /ignore (set flag, check on receive!) */ - /* the following three commands must be last! */ - {"/", &do_unknown, NULL}, - {"", &do_send, NULL}, - {NULL, NULL, NULL}, -}; - - -static int -do_help (const char *args, const void *xtra) -{ - int i; - - i = 0; - while ((NULL != args) && (0 != strlen (args)) && - (commands[i].Action != &do_help)) - { - if (0 == strncasecmp (&args[1], &commands[i].command[1], strlen (args) - 1)) - { - FPRINTF (stdout, "%s\n", gettext (commands[i].helptext)); - return GNUNET_OK; - } - i++; - } - i = 0; - FPRINTF (stdout, "%s", "Available commands:"); - while (commands[i].Action != &do_help) - { - FPRINTF (stdout, " %s", gettext (commands[i].command)); - i++; - } - FPRINTF (stdout, "%s", "\n"); - FPRINTF (stdout, "%s\n", gettext (commands[i].helptext)); - return GNUNET_OK; -} - - -static void -do_stop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_CHAT_leave_room (room); - if (handle_cmd_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (handle_cmd_task); - handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; - } - free_user_list (); - GNUNET_CONTAINER_meta_data_destroy (meta); - GNUNET_free (room_name); - GNUNET_free (nickname); -} - - -void -handle_command (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - char message[MAX_MESSAGE_LENGTH + 1]; - int i; - - /* read message from command line and handle it */ - memset (message, 0, MAX_MESSAGE_LENGTH + 1); - if (NULL == fgets (message, MAX_MESSAGE_LENGTH, stdin)) - goto next; - if (strlen (message) == 0) - goto next; - if (message[strlen (message) - 1] == '\n') - message[strlen (message) - 1] = '\0'; - if (strlen (message) == 0) - goto next; - i = 0; - while ((NULL != commands[i].command) && - (0 != - strncasecmp (commands[i].command, message, - strlen (commands[i].command)))) - i++; - if (GNUNET_OK != - commands[i].Action (&message[strlen (commands[i].command)], NULL)) - goto out; - -next: - handle_cmd_task = - GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 100), - GNUNET_SCHEDULER_PRIORITY_UI, - &handle_command, NULL); - return; - -out: - handle_cmd_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Main function that will be run by the scheduler. - * - * @param cls closure, NULL - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param c configuration - */ -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *c) -{ - struct GNUNET_HashCode me; - char *my_name; - int my_name_is_a_dup; - - cfg = c; - /* check arguments */ - if (NULL == nickname) - { - FPRINTF (stderr, "%s", _("You must specify a nickname\n")); - ret = -1; - return; - } - if (NULL == room_name) - room_name = GNUNET_strdup ("gnunet"); - meta = GNUNET_CONTAINER_meta_data_create (); - GNUNET_CONTAINER_meta_data_insert (meta, "<gnunet>", EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METAFORMAT_UTF8, "text/plain", - nickname, strlen (nickname) + 1); - room = - GNUNET_CHAT_join_room (cfg, nickname, meta, room_name, -1, &join_cb, NULL, - &receive_cb, NULL, &member_list_cb, NULL, - &confirmation_cb, NULL, &me); - if (NULL == room) - { - FPRINTF (stderr, _("Failed to join room `%s'\n"), room_name); - GNUNET_free (room_name); - GNUNET_free (nickname); - GNUNET_CONTAINER_meta_data_destroy (meta); - ret = -1; - return; - } - if ((GNUNET_OK != GNUNET_FS_pseudonym_get_info (cfg, - &me, NULL, NULL, &my_name, &my_name_is_a_dup)) || - (my_name_is_a_dup == GNUNET_YES)) - { - GNUNET_free (my_name); - my_name = GNUNET_strdup (_("anonymous")); - } - FPRINTF (stdout, _("Joining room `%s' as user `%s'...\n"), room_name, - my_name); - GNUNET_free (my_name); - handle_cmd_task = - GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_UI, - &handle_command, NULL); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &do_stop_task, - NULL); -} - - -/** - * The main function to chat via GNUnet. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, char *const *argv) -{ - int flags; - - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - {'n', "nick", "NAME", - gettext_noop ("set the nickname to use (required)"), - 1, &GNUNET_GETOPT_set_string, &nickname}, - {'r', "room", "NAME", - gettext_noop ("set the chat room to join"), - 1, &GNUNET_GETOPT_set_string, &room_name}, - GNUNET_GETOPT_OPTION_END - }; - -#ifndef WINDOWS - flags = fcntl (0, F_GETFL, 0); - flags |= O_NONBLOCK; - fcntl (0, F_SETFL, flags); -#endif - - if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) - return 2; - - return (GNUNET_OK == - GNUNET_PROGRAM_run (argc, argv, "gnunet-chat", - gettext_noop ("Join a chat on GNUnet."), options, - &run, NULL)) ? ret : 1; -} - -/* end of gnunet-chat.c */ diff --git a/src/chat/gnunet-service-chat.c b/src/chat/gnunet-service-chat.c @@ -1,1713 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2009, 2011 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file chat/gnunet-service-chat.c - * @brief service providing chat functionality - * @author Christian Grothoff - * @author Vitaly Minko - */ - -#include "platform.h" -#include "gnunet_core_service.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_protocols.h" -#include "gnunet_service_lib.h" -#include "gnunet_signatures.h" -#include "chat.h" - -#define DEBUG_CHAT_SERVICE GNUNET_EXTRA_LOGGING -#define MAX_TRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) -#define EXPECTED_NEIGHBOUR_COUNT 16 -#define MAX_ANONYMOUS_MSG_LIST_LENGTH 16 - - -/** - * Linked list of our current clients. - */ -struct ChatClient -{ - struct ChatClient *next; - - /** - * Handle for a chat client (NULL for external clients). - */ - struct GNUNET_SERVER_Client *client; - - /** - * Public key of the client. - */ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key; - - /** - * Name of the room which the client is in. - */ - char *room; - - /** - * Serialized metadata of the client. - */ - char *member_info; - - /** - * Hash of the public key (for convenience). - */ - struct GNUNET_HashCode id; - - /** - * Options which the client is willing to receive. - */ - uint32_t msg_options; - - /** - * Length of serialized metadata in member_info. - */ - uint16_t meta_len; - - /** - * Sequence number of the last message sent by the client. - */ - uint32_t msg_sequence_number; - - /** - * Sequence number of the last receipt sent by the client. - * Used to discard already processed receipts. - */ - uint32_t rcpt_sequence_number; - -}; - -/** - * Information about a peer that we are connected to. - * We track data that is useful for determining which - * peers should receive our requests. - */ -struct ConnectedPeer -{ - /** - * The peer's identity. - */ - GNUNET_PEER_Id pid; -}; - -/** - * Linked list of recent anonymous messages. - */ -struct AnonymousMessage -{ - struct AnonymousMessage *next; - - /** - * Hash of the message. - */ - struct GNUNET_HashCode hash; - -}; - - -/** - * Handle to the core service (NULL until we've connected to it). - */ -static struct GNUNET_CORE_Handle *core; - -/** - * Our configuration. - */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * The identity of this host. - */ -static struct GNUNET_PeerIdentity me; - -/** - * Head of the list of current clients. - */ -static struct ChatClient *client_list_head = NULL; - -/** - * Notification context containing all connected clients. - */ -struct GNUNET_SERVER_NotificationContext *nc = NULL; - -/** - * Head of the list of recent anonymous messages. - */ -static struct AnonymousMessage *anonymous_list_head = NULL; - -/** - * Map of peer identifiers to "struct ConnectedPeer" (for that peer). - */ -static struct GNUNET_CONTAINER_MultiHashMap *connected_peers; - - -static void -remember_anonymous_message (const struct P2PReceiveNotificationMessage - *p2p_rnmsg) -{ - static struct GNUNET_HashCode hash; - struct AnonymousMessage *anon_msg; - struct AnonymousMessage *prev; - int anon_list_len; - - GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash); - anon_msg = GNUNET_malloc (sizeof (struct AnonymousMessage)); - anon_msg->hash = hash; - anon_msg->next = anonymous_list_head; - anonymous_list_head = anon_msg; - anon_list_len = 1; - prev = NULL; - while ((NULL != anon_msg->next)) - { - prev = anon_msg; - anon_msg = anon_msg->next; - anon_list_len++; - } - if (anon_list_len == MAX_ANONYMOUS_MSG_LIST_LENGTH) - { - GNUNET_free (anon_msg); - if (NULL != prev) - prev->next = NULL; - } -} - - -static int -lookup_anonymous_message (const struct P2PReceiveNotificationMessage *p2p_rnmsg) -{ - static struct GNUNET_HashCode hash; - struct AnonymousMessage *anon_msg; - - GNUNET_CRYPTO_hash (p2p_rnmsg, ntohs (p2p_rnmsg->header.size), &hash); - anon_msg = anonymous_list_head; - while ((NULL != anon_msg) && - (0 != memcmp (&anon_msg->hash, &hash, sizeof (struct GNUNET_HashCode)))) - anon_msg = anon_msg->next; - return (NULL != anon_msg); -} - - -/** - * Transmit a message notification to the peer. - * - * @param cls closure, pointer to the 'struct P2PReceiveNotificationMessage' - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf - */ -static size_t -transmit_message_notification_to_peer (void *cls, size_t size, void *buf) -{ - struct P2PReceiveNotificationMessage *my_msg = cls; - struct P2PReceiveNotificationMessage *m = buf; - size_t msg_size; - -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmitting P2P message notification\n"); -#endif - if (buf == NULL) - { - /* client disconnected */ -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Buffer is NULL, dropping the message\n"); -#endif - return 0; - } - msg_size = ntohs (my_msg->header.size); - GNUNET_assert (size >= msg_size); - memcpy (m, my_msg, msg_size); - GNUNET_free (my_msg); - return msg_size; -} - - -/** - * Ask to send a message notification to the peer. - */ -static int -send_message_noficiation (void *cls, const struct GNUNET_HashCode * key, void *value) -{ - struct P2PReceiveNotificationMessage *msg = cls; - struct ConnectedPeer *cp = value; - struct GNUNET_PeerIdentity pid; - struct P2PReceiveNotificationMessage *my_msg; - - GNUNET_PEER_resolve (cp->pid, &pid); -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message notification to `%s'\n", - GNUNET_i2s (&pid)); -#endif - my_msg = GNUNET_memdup (msg, ntohs (msg->header.size)); - if (NULL == - GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY, - &pid, ntohs (msg->header.size), - &transmit_message_notification_to_peer, - my_msg)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Failed to queue a message notification\n")); - return GNUNET_YES; -} - - -/** - * A client sent a chat message. Encrypt the message text if the message is - * private. Send the message to local room members and to all connected peers. - * - * @param cls closure, NULL - * @param client identification of the client - * @param message the actual message - */ -static void -handle_transmit_request (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - static struct GNUNET_HashCode all_zeros; - const struct TransmitRequestMessage *trmsg; - struct ReceiveNotificationMessage *rnmsg; - struct P2PReceiveNotificationMessage *p2p_rnmsg; - struct ChatClient *pos; - struct ChatClient *target; - struct GNUNET_CRYPTO_AesSessionKey key; - char encrypted_msg[MAX_MESSAGE_LENGTH]; - const char *room; - size_t room_len; - int msg_len; - int is_priv; - int is_anon; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a chat message\n"); - if (ntohs (message->size) <= sizeof (struct TransmitRequestMessage)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - trmsg = (const struct TransmitRequestMessage *) message; - msg_len = ntohs (trmsg->header.size) - sizeof (struct TransmitRequestMessage); - is_priv = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_PRIVATE)); - if (is_priv) - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting the message text\n"); -#endif - GNUNET_CRYPTO_aes_create_session_key (&key); - msg_len = - GNUNET_CRYPTO_aes_encrypt (&trmsg[1], msg_len, &key, - (const struct - GNUNET_CRYPTO_AesInitializationVector *) - INITVALUE, encrypted_msg); - if (-1 == msg_len) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not encrypt the message text\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - } - rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len); - rnmsg->header.size = - htons (sizeof (struct ReceiveNotificationMessage) + msg_len); - rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); - rnmsg->msg_options = trmsg->msg_options; - rnmsg->timestamp = trmsg->timestamp; - pos = client_list_head; - while ((NULL != pos) && (pos->client != client)) - pos = pos->next; - if (NULL == pos) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "The client is not a member of a chat room. Client has to " - "join a chat room first\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - GNUNET_free (rnmsg); - return; - } - room = pos->room; - pos->msg_sequence_number = ntohl (trmsg->sequence_number); - is_anon = (0 != (ntohl (trmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)); - if (is_anon) - { - memset (&rnmsg->sender, 0, sizeof (struct GNUNET_HashCode)); - rnmsg->sequence_number = 0; - } - else - { - rnmsg->sender = pos->id; - rnmsg->sequence_number = trmsg->sequence_number; - } - if (is_priv) - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Encrypting the session key using the public key of '%s'\n", - GNUNET_h2s (&trmsg->target)); -#endif - if (0 == memcmp (&all_zeros, &trmsg->target, sizeof (struct GNUNET_HashCode))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Malformed message: private, but no target\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - GNUNET_free (rnmsg); - return; - } - memcpy (&rnmsg[1], encrypted_msg, msg_len); - target = client_list_head; - while ((NULL != target) && - (0 != - memcmp (&target->id, &trmsg->target, sizeof (struct GNUNET_HashCode)))) - target = target->next; - if (NULL == target) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unknown target of the private message\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - GNUNET_free (rnmsg); - return; - } - if (GNUNET_SYSERR == - GNUNET_CRYPTO_rsa_encrypt (&key, - sizeof (struct GNUNET_CRYPTO_AesSessionKey), - &target->public_key, &rnmsg->encrypted_key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Could not encrypt the session key\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - GNUNET_free (rnmsg); - return; - } - } - else - { - memcpy (&rnmsg[1], &trmsg[1], msg_len); - } - pos = client_list_head; -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending message to local room members\n"); -#endif - while (NULL != pos) - { - if ((0 == strcmp (room, pos->room)) && (NULL != pos->client) && - (pos->client != client)) - { - if (((!is_priv) || - (0 == memcmp (&trmsg->target, &pos->id, sizeof (struct GNUNET_HashCode)))) - && (0 == (ntohl (trmsg->msg_options) & (~pos->msg_options)))) - { - GNUNET_SERVER_notification_context_unicast (nc, pos->client, - &rnmsg->header, GNUNET_NO); - } - } - pos = pos->next; - } -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Broadcasting message to neighbour peers\n"); -#endif - if (is_anon) - { - room_len = strlen (room); - p2p_rnmsg = - GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len + - room_len); - p2p_rnmsg->header.size = - htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len + - room_len); - p2p_rnmsg->room_name_len = htons (room_len); - memcpy ((char *) &p2p_rnmsg[1], room, room_len); - memcpy ((char *) &p2p_rnmsg[1] + room_len, &trmsg[1], msg_len); - } - else - { - p2p_rnmsg = - GNUNET_malloc (sizeof (struct P2PReceiveNotificationMessage) + msg_len); - p2p_rnmsg->header.size = - htons (sizeof (struct P2PReceiveNotificationMessage) + msg_len); - if (is_priv) - { - memcpy (&p2p_rnmsg[1], encrypted_msg, msg_len); - memcpy (&p2p_rnmsg->encrypted_key, &rnmsg->encrypted_key, - sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); - } - else - memcpy (&p2p_rnmsg[1], &trmsg[1], msg_len); - } - p2p_rnmsg->header.type = - htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION); - p2p_rnmsg->msg_options = trmsg->msg_options; - p2p_rnmsg->sequence_number = trmsg->sequence_number; - p2p_rnmsg->timestamp = trmsg->timestamp; - p2p_rnmsg->reserved = htons (0); - p2p_rnmsg->sender = rnmsg->sender; - p2p_rnmsg->target = trmsg->target; - if (is_anon) - remember_anonymous_message (p2p_rnmsg); - GNUNET_CONTAINER_multihashmap_iterate (connected_peers, - &send_message_noficiation, p2p_rnmsg); - GNUNET_free (p2p_rnmsg); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - GNUNET_free (rnmsg); -} - - -/** - * Transmit a join notification to the peer. - * - * @param cls closure, pointer to the 'struct ChatClient' - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf - */ -static size_t -transmit_join_notification_to_peer (void *cls, size_t size, void *buf) -{ - struct ChatClient *entry = cls; - struct P2PJoinNotificationMessage *m = buf; - size_t room_len; - size_t meta_len; - size_t msg_size; - char *roomptr; - -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P join notification\n"); -#endif - room_len = strlen (entry->room); - meta_len = entry->meta_len; - msg_size = sizeof (struct P2PJoinNotificationMessage) + meta_len + room_len; - GNUNET_assert (size >= msg_size); - GNUNET_assert (NULL != buf); - m = buf; - m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION); - m->header.size = htons (msg_size); - m->msg_options = htonl (entry->msg_options); - m->room_name_len = htons (room_len); - m->reserved = htons (0); - m->reserved2 = htonl (0); - m->public_key = entry->public_key; - roomptr = (char *) &m[1]; - memcpy (roomptr, entry->room, room_len); - if (meta_len > 0) - memcpy (&roomptr[room_len], entry->member_info, meta_len); - return msg_size; -} - - -/** - * Ask to send a join notification to the peer. - */ -static int -send_join_noficiation (void *cls, const struct GNUNET_HashCode * key, void *value) -{ - struct ChatClient *entry = cls; - struct ConnectedPeer *cp = value; - struct GNUNET_PeerIdentity pid; - size_t msg_size; - - GNUNET_PEER_resolve (cp->pid, &pid); -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending join notification to `%s'\n", - GNUNET_i2s (&pid)); -#endif - msg_size = - sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) + - entry->meta_len; - if (NULL == - GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, MAX_TRANSMIT_DELAY, - &pid, msg_size, - &transmit_join_notification_to_peer, - entry)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Failed to queue a join notification\n")); - return GNUNET_YES; -} - - -/** - * A client asked for entering a chat room. Add the new member to the list of - * clients and notify remaining room members. - * - * @param cls closure, NULL - * @param client identification of the client - * @param message the actual message - */ -static void -handle_join_request (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct JoinRequestMessage *jrmsg; - char *room_name; - const char *roomptr; - uint16_t header_size; - uint16_t meta_len; - uint16_t room_name_len; - struct ChatClient *new_entry; - struct ChatClient *entry; - struct JoinNotificationMessage *jnmsg; - struct JoinNotificationMessage *entry_jnmsg; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a join request\n"); - if (ntohs (message->size) <= sizeof (struct JoinRequestMessage)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - jrmsg = (const struct JoinRequestMessage *) message; - header_size = ntohs (jrmsg->header.size); - room_name_len = ntohs (jrmsg->room_name_len); - if (header_size - sizeof (struct JoinRequestMessage) <= room_name_len) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Malformed message: wrong length of the room name\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - meta_len = header_size - sizeof (struct JoinRequestMessage) - room_name_len; - roomptr = (const char *) &jrmsg[1]; - room_name = GNUNET_malloc (room_name_len + 1); - memcpy (room_name, roomptr, room_name_len); - room_name[room_name_len] = '\0'; - new_entry = GNUNET_malloc (sizeof (struct ChatClient)); - memset (new_entry, 0, sizeof (struct ChatClient)); - new_entry->client = client; - new_entry->room = room_name; - new_entry->public_key = jrmsg->public_key; - new_entry->meta_len = meta_len; - if (meta_len > 0) - { - new_entry->member_info = GNUNET_malloc (meta_len); - memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len); - } - else - new_entry->member_info = NULL; - GNUNET_CRYPTO_hash (&new_entry->public_key, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &new_entry->id); - new_entry->msg_options = ntohl (jrmsg->msg_options); - new_entry->next = client_list_head; - client_list_head = new_entry; -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Synchronizing room members between local clients\n"); -#endif - jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len); - jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); - jnmsg->header.size = - htons (sizeof (struct JoinNotificationMessage) + meta_len); - jnmsg->msg_options = jrmsg->msg_options; - jnmsg->public_key = new_entry->public_key; - memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len); - GNUNET_SERVER_notification_context_add (nc, client); - entry = client_list_head; - while (NULL != entry) - { - if (0 == strcmp (room_name, entry->room)) - { - if (NULL != entry->client) - GNUNET_SERVER_notification_context_unicast (nc, entry->client, - &jnmsg->header, GNUNET_NO); - if (entry->client != client) - { - entry_jnmsg = - GNUNET_malloc (sizeof (struct JoinNotificationMessage) + - entry->meta_len); - entry_jnmsg->header.type = - htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); - entry_jnmsg->header.size = - htons (sizeof (struct JoinNotificationMessage) + entry->meta_len); - entry_jnmsg->msg_options = entry->msg_options; - entry_jnmsg->public_key = entry->public_key; - memcpy (&entry_jnmsg[1], entry->member_info, entry->meta_len); - GNUNET_SERVER_notification_context_unicast (nc, client, - &entry_jnmsg->header, - GNUNET_NO); - GNUNET_free (entry_jnmsg); - } - } - entry = entry->next; - } -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Broadcasting join notification to neighbour peers\n"); -#endif - GNUNET_CONTAINER_multihashmap_iterate (connected_peers, - &send_join_noficiation, new_entry); - GNUNET_SERVER_receive_done (client, GNUNET_OK); - GNUNET_free (jnmsg); -} - -/** - * Transmit a confirmation receipt to the peer. - * - * @param cls closure, pointer to the 'struct P2PConfirmationReceiptMessage' - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf - */ -static size_t -transmit_confirmation_receipt_to_peer (void *cls, size_t size, void *buf) -{ - struct P2PConfirmationReceiptMessage *receipt = cls; - size_t msg_size; - -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transmitting P2P confirmation receipt to '%s'\n", - GNUNET_h2s (&receipt->target)); -#endif - if (buf == NULL) - { - /* client disconnected */ -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Buffer is NULL, dropping the message\n"); -#endif - return 0; - } - msg_size = sizeof (struct P2PConfirmationReceiptMessage); - GNUNET_assert (size >= msg_size); - memcpy (buf, receipt, msg_size); - GNUNET_free (receipt); - return msg_size; -} - - -/** - * Ask to send a confirmation receipt to the peer. - */ -static int -send_confirmation_receipt (void *cls, const struct GNUNET_HashCode * key, void *value) -{ - struct P2PConfirmationReceiptMessage *receipt = cls; - struct ConnectedPeer *cp = value; - struct GNUNET_PeerIdentity pid; - struct P2PConfirmationReceiptMessage *my_receipt; - size_t msg_size; - - GNUNET_PEER_resolve (cp->pid, &pid); -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending confirmation receipt to `%s'\n", - GNUNET_i2s (&pid)); -#endif - msg_size = sizeof (struct P2PConfirmationReceiptMessage); - my_receipt = - GNUNET_memdup (receipt, sizeof (struct P2PConfirmationReceiptMessage)); - if (NULL == - GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, - MAX_TRANSMIT_DELAY, &pid, msg_size, - &transmit_confirmation_receipt_to_peer, - my_receipt)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Failed to queue a confirmation receipt\n")); - return GNUNET_YES; -} - - -/** - * A client sent a confirmation receipt. Broadcast the receipt to all connected - * peers if the author of the original message is a local client. Otherwise - * check the signature and notify the user if the signature is valid. - * - * @param cls closure, NULL - * @param client identification of the client - * @param message the actual message - */ -static void -handle_acknowledge_request (void *cls, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) -{ - const struct ConfirmationReceiptMessage *receipt; - struct ConfirmationReceiptMessage *crmsg; - struct P2PConfirmationReceiptMessage *p2p_crmsg; - struct ChatClient *target; - struct ChatClient *author; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client sent a confirmation receipt\n"); - receipt = (const struct ConfirmationReceiptMessage *) message; - author = client_list_head; - while ((NULL != author) && - (0 != - memcmp (&receipt->author, &author->id, sizeof (struct GNUNET_HashCode)))) - author = author->next; - if (NULL == author) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unknown author of the original message\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - target = client_list_head; - while ((NULL != target) && - (0 != - memcmp (&receipt->target, &target->id, sizeof (struct GNUNET_HashCode)))) - target = target->next; - if (NULL == target) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unknown target of the confirmation receipt\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } - if (NULL == author->client) - { - target->rcpt_sequence_number++; -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Broadcasting %s's receipt #%u to neighbour peers\n", - GNUNET_h2s (&target->id), target->rcpt_sequence_number); -#endif - p2p_crmsg = GNUNET_malloc (sizeof (struct P2PConfirmationReceiptMessage)); - p2p_crmsg->header.size = - htons (sizeof (struct P2PConfirmationReceiptMessage)); - p2p_crmsg->header.type = - htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT); - p2p_crmsg->reserved = htonl (0); - p2p_crmsg->signature = receipt->signature; - p2p_crmsg->purpose = receipt->purpose; - p2p_crmsg->msg_sequence_number = receipt->sequence_number; - p2p_crmsg->timestamp = receipt->timestamp; - p2p_crmsg->target = receipt->target; - p2p_crmsg->author = receipt->author; - p2p_crmsg->content = receipt->content; - p2p_crmsg->sequence_number = htonl (target->rcpt_sequence_number); - GNUNET_CONTAINER_multihashmap_iterate (connected_peers, - &send_confirmation_receipt, - p2p_crmsg); - GNUNET_free (p2p_crmsg); - } - else - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Verifying signature of the receipt\n"); -#endif - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT, - &receipt->purpose, &receipt->signature, - &target->public_key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid signature of the receipt\n"); - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending receipt to the client which sent the original message\n"); -#endif - crmsg = GNUNET_memdup (receipt, sizeof (struct ConfirmationReceiptMessage)); - crmsg->header.type = - htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION); - GNUNET_SERVER_notification_context_unicast (nc, author->client, - &crmsg->header, GNUNET_NO); - GNUNET_free (crmsg); - } - GNUNET_SERVER_receive_done (client, GNUNET_OK); -} - - -/** - * Transmit a leave notification to the peer. - * - * @param cls closure, pointer to the - * 'struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded' - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf - */ -static size_t -transmit_leave_notification_to_peer (void *cls, size_t size, void *buf) -{ - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key = cls; - struct P2PLeaveNotificationMessage *m = buf; - size_t msg_size; - -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P leave notification\n"); -#endif - if (buf == NULL) - { - /* client disconnected */ -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Buffer is NULL, dropping the message\n"); -#endif - return 0; - } - msg_size = sizeof (struct P2PLeaveNotificationMessage); - GNUNET_assert (size >= msg_size); - m = buf; - m->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION); - m->header.size = htons (msg_size); - m->reserved = htonl (0); - m->user = *public_key; - GNUNET_free (public_key); - return msg_size; -} - - -/** - * Ask to send a leave notification to the peer. - */ -static int -send_leave_noficiation (void *cls, const struct GNUNET_HashCode * key, void *value) -{ - struct ChatClient *entry = cls; - struct ConnectedPeer *cp = value; - struct GNUNET_PeerIdentity pid; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key; - size_t msg_size; - - GNUNET_PEER_resolve (cp->pid, &pid); -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending leave notification to `%s'\n", - GNUNET_i2s (&pid)); -#endif - msg_size = sizeof (struct P2PLeaveNotificationMessage); - public_key = - GNUNET_memdup (&entry->public_key, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - if (NULL == - GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, - MAX_TRANSMIT_DELAY, &pid, msg_size, - &transmit_leave_notification_to_peer, - public_key)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Failed to queue a leave notification\n")); - return GNUNET_YES; -} - - -/** - * A client disconnected. Remove all of its data structure entries and notify - * remaining room members. - * - * @param cls closure, NULL - * @param client identification of the client - */ -static void -handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) -{ - struct ChatClient *entry; - struct ChatClient *pos; - struct ChatClient *prev; - struct LeaveNotificationMessage lnmsg; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client disconnected\n"); - pos = client_list_head; - prev = NULL; - while ((NULL != pos) && (pos->client != client)) - { - prev = pos; - pos = pos->next; - } - if (NULL == pos) - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "No such client. There is nothing to do\n"); -#endif - return; - } - if (NULL == prev) - client_list_head = pos->next; - else - prev->next = pos->next; - entry = client_list_head; -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Notifying local room members that the client has disconnected\n"); -#endif - lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage)); - lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION); - lnmsg.reserved = htonl (0); - lnmsg.user = pos->public_key; - while (NULL != entry) - { - if ((0 == strcmp (pos->room, entry->room)) && (NULL != entry->client)) - { - GNUNET_SERVER_notification_context_unicast (nc, entry->client, - &lnmsg.header, GNUNET_NO); - } - entry = entry->next; - } -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Broadcasting leave notification to neighbour peers\n"); -#endif - GNUNET_CONTAINER_multihashmap_iterate (connected_peers, - &send_leave_noficiation, pos); - GNUNET_free (pos->room); - GNUNET_free_non_null (pos->member_info); - GNUNET_free (pos); -} - - -/** - * Handle P2P join notification. - * - * @param cls closure, always NULL - * @param other the other peer involved - * @param message the actual message - - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -handle_p2p_join_notification (void *cls, - const struct GNUNET_PeerIdentity *other, - const struct GNUNET_MessageHeader *message) -{ - const struct P2PJoinNotificationMessage *p2p_jnmsg; - char *room_name; - const char *roomptr; - uint16_t header_size; - uint16_t meta_len; - uint16_t room_name_len; - struct ChatClient *new_entry; - struct ChatClient *entry; - struct JoinNotificationMessage *jnmsg; - struct GNUNET_HashCode id; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P join notification\n"); - if (ntohs (message->size) <= sizeof (struct P2PJoinNotificationMessage)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - p2p_jnmsg = (const struct P2PJoinNotificationMessage *) message; - header_size = ntohs (p2p_jnmsg->header.size); - room_name_len = ntohs (p2p_jnmsg->room_name_len); - if (header_size - sizeof (struct P2PJoinNotificationMessage) <= room_name_len) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Malformed message: wrong length of the room name\n"); - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_CRYPTO_hash (&p2p_jnmsg->public_key, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &id); - entry = client_list_head; - while (NULL != entry) - { - if (0 == memcmp (&entry->id, &id, sizeof (struct GNUNET_HashCode))) - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "The client has already joined. There is nothing to do\n"); -#endif - return GNUNET_OK; - } - entry = entry->next; - } - meta_len = - header_size - sizeof (struct P2PJoinNotificationMessage) - room_name_len; - roomptr = (const char *) &p2p_jnmsg[1]; - room_name = GNUNET_malloc (room_name_len + 1); - memcpy (room_name, roomptr, room_name_len); - room_name[room_name_len] = '\0'; - new_entry = GNUNET_malloc (sizeof (struct ChatClient)); - memset (new_entry, 0, sizeof (struct ChatClient)); - new_entry->id = id; - new_entry->client = NULL; - new_entry->room = room_name; - new_entry->public_key = p2p_jnmsg->public_key; - new_entry->meta_len = meta_len; - if (meta_len > 0) - { - new_entry->member_info = GNUNET_malloc (meta_len); - memcpy (new_entry->member_info, &roomptr[room_name_len], meta_len); - } - else - new_entry->member_info = NULL; - new_entry->msg_options = ntohl (p2p_jnmsg->msg_options); - new_entry->next = client_list_head; - client_list_head = new_entry; -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Notifying local room members that we have a new client\n"); -#endif - jnmsg = GNUNET_malloc (sizeof (struct JoinNotificationMessage) + meta_len); - jnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_JOIN_NOTIFICATION); - jnmsg->header.size = - htons (sizeof (struct JoinNotificationMessage) + meta_len); - jnmsg->msg_options = p2p_jnmsg->msg_options; - jnmsg->public_key = new_entry->public_key; - memcpy (&jnmsg[1], &roomptr[room_name_len], meta_len); - entry = client_list_head; - while (NULL != entry) - { - if ((0 == strcmp (room_name, entry->room)) && (NULL != entry->client)) - { - GNUNET_SERVER_notification_context_unicast (nc, entry->client, - &jnmsg->header, GNUNET_NO); - } - entry = entry->next; - } -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Broadcasting join notification to neighbour peers\n"); -#endif - GNUNET_CONTAINER_multihashmap_iterate (connected_peers, - &send_join_noficiation, new_entry); - GNUNET_free (jnmsg); - return GNUNET_OK; -} - - -/** - * Handle P2P leave notification. - * - * @param cls closure, always NULL - * @param other the other peer involved - * @param message the actual message - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -handle_p2p_leave_notification (void *cls, - const struct GNUNET_PeerIdentity *other, - const struct GNUNET_MessageHeader *message) -{ - const struct P2PLeaveNotificationMessage *p2p_lnmsg; - struct GNUNET_HashCode id; - struct ChatClient *pos; - struct ChatClient *prev; - struct ChatClient *entry; - struct LeaveNotificationMessage lnmsg; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P leave notification\n"); - p2p_lnmsg = (const struct P2PLeaveNotificationMessage *) message; - GNUNET_CRYPTO_hash (&p2p_lnmsg->user, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &id); - pos = client_list_head; - prev = NULL; - while (NULL != pos) - { - if (0 == memcmp (&pos->id, &id, sizeof (struct GNUNET_HashCode))) - break; - prev = pos; - pos = pos->next; - } - if (NULL == pos) - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "No such client. There is nothing to do\n"); -#endif - return GNUNET_OK; - } - if (NULL == prev) - client_list_head = pos->next; - else - prev->next = pos->next; -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Notifying local room members that the client has gone away\n"); -#endif - lnmsg.header.size = htons (sizeof (struct LeaveNotificationMessage)); - lnmsg.header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_LEAVE_NOTIFICATION); - lnmsg.reserved = htonl (0); - lnmsg.user = pos->public_key; - entry = client_list_head; - while (NULL != entry) - { - if (0 == strcmp (pos->room, entry->room) && (NULL != entry->client)) - { - GNUNET_SERVER_notification_context_unicast (nc, entry->client, - &lnmsg.header, GNUNET_NO); - } - entry = entry->next; - } -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Broadcasting leave notification to neighbour peers\n"); -#endif - GNUNET_CONTAINER_multihashmap_iterate (connected_peers, - &send_leave_noficiation, pos); - GNUNET_free (pos->room); - GNUNET_free_non_null (pos->member_info); - GNUNET_free (pos); - return GNUNET_OK; -} - - -/** - * Handle P2P message notification. - * - * @param cls closure, always NULL - * @param other the other peer involved - * @param message the actual message - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -handle_p2p_message_notification (void *cls, - const struct GNUNET_PeerIdentity *other, - const struct GNUNET_MessageHeader *message) -{ - const struct P2PReceiveNotificationMessage *p2p_rnmsg; - struct P2PReceiveNotificationMessage *my_p2p_rnmsg; - struct ReceiveNotificationMessage *rnmsg; - struct ChatClient *sender; - struct ChatClient *pos; - static struct GNUNET_HashCode all_zeros; - int is_priv; - int is_anon; - uint16_t msg_len; - uint16_t room_name_len; - char *room_name = NULL; - char *text; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P message notification\n"); - if (ntohs (message->size) <= sizeof (struct P2PReceiveNotificationMessage)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed message: wrong size\n"); - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - p2p_rnmsg = (const struct P2PReceiveNotificationMessage *) message; - msg_len = - ntohs (p2p_rnmsg->header.size) - - sizeof (struct P2PReceiveNotificationMessage); - - is_anon = (0 != (ntohl (p2p_rnmsg->msg_options) & GNUNET_CHAT_MSG_ANONYMOUS)); - if (is_anon) - { - room_name_len = ntohs (p2p_rnmsg->room_name_len); - if (msg_len <= room_name_len) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Malformed message: wrong length of the room name\n"); - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - msg_len -= room_name_len; - if (lookup_anonymous_message (p2p_rnmsg)) - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "This anonymous message has already been handled."); -#endif - return GNUNET_OK; - } - remember_anonymous_message (p2p_rnmsg); - room_name = GNUNET_malloc (room_name_len + 1); - memcpy (room_name, (char *) &p2p_rnmsg[1], room_name_len); - room_name[room_name_len] = '\0'; - text = (char *) &p2p_rnmsg[1] + room_name_len; - } - else - { - sender = client_list_head; - while ((NULL != sender) && - (0 != - memcmp (&sender->id, &p2p_rnmsg->sender, sizeof (struct GNUNET_HashCode)))) - sender = sender->next; - if (NULL == sender) - { - /* not an error since the sender may have left before we got the - * message */ -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Unknown source. Rejecting the message\n"); -#endif - return GNUNET_OK; - } - if (sender->msg_sequence_number >= ntohl (p2p_rnmsg->sequence_number)) - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "This message has already been handled." - " Sequence numbers (msg/sender): %u/%u\n", - ntohl (p2p_rnmsg->sequence_number), - sender->msg_sequence_number); -#endif - return GNUNET_OK; - } - sender->msg_sequence_number = ntohl (p2p_rnmsg->sequence_number); - room_name = sender->room; - text = (char *) &p2p_rnmsg[1]; - } - -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending message to local room members\n"); -#endif - rnmsg = GNUNET_malloc (sizeof (struct ReceiveNotificationMessage) + msg_len); - rnmsg->header.size = - htons (sizeof (struct ReceiveNotificationMessage) + msg_len); - rnmsg->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_MESSAGE_NOTIFICATION); - rnmsg->msg_options = p2p_rnmsg->msg_options; - rnmsg->sequence_number = p2p_rnmsg->sequence_number; - rnmsg->reserved = htonl (0); - rnmsg->timestamp = p2p_rnmsg->timestamp; - is_priv = - (0 != memcmp (&all_zeros, &p2p_rnmsg->target, sizeof (struct GNUNET_HashCode))); - if (is_priv) - memcpy (&rnmsg->encrypted_key, &p2p_rnmsg->encrypted_key, - sizeof (struct GNUNET_CRYPTO_RsaEncryptedData)); - rnmsg->sender = p2p_rnmsg->sender; - memcpy (&rnmsg[1], text, msg_len); - pos = client_list_head; - while (NULL != pos) - { - if ((0 == strcmp (room_name, pos->room)) && (NULL != pos->client)) - { - if (((!is_priv) || - (0 == - memcmp (&p2p_rnmsg->target, &pos->id, sizeof (struct GNUNET_HashCode)))) && - (0 == (ntohl (p2p_rnmsg->msg_options) & (~pos->msg_options)))) - { - GNUNET_SERVER_notification_context_unicast (nc, pos->client, - &rnmsg->header, GNUNET_NO); - } - } - pos = pos->next; - } - if (is_anon) - GNUNET_free (room_name); -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Broadcasting message notification to neighbour peers\n"); -#endif - my_p2p_rnmsg = GNUNET_memdup (p2p_rnmsg, ntohs (p2p_rnmsg->header.size)); - GNUNET_CONTAINER_multihashmap_iterate (connected_peers, - &send_message_noficiation, - my_p2p_rnmsg); - GNUNET_free (rnmsg); - return GNUNET_OK; -} - - -/** - * Handle P2P sync request. - * - * @param cls closure, always NULL - * @param other the other peer involved - * @param message the actual message - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -handle_p2p_sync_request (void *cls, const struct GNUNET_PeerIdentity *other, - const struct GNUNET_MessageHeader *message) -{ - struct ChatClient *entry; - struct GNUNET_CORE_TransmitHandle *th; - size_t msg_size; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P sync request\n"); -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Notifying the requester of all known clients\n"); -#endif - entry = client_list_head; - while (NULL != entry) - { - msg_size = - sizeof (struct P2PJoinNotificationMessage) + strlen (entry->room) + - entry->meta_len; - th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_NO, 1, - MAX_TRANSMIT_DELAY, other, msg_size, - &transmit_join_notification_to_peer, - entry); - GNUNET_assert (NULL != th); - entry = entry->next; - } - return GNUNET_OK; -} - - -/** - * Handle P2P confirmation receipt. - * - * @param cls closure, always NULL - * @param other the other peer involved - * @param message the actual message - * @return GNUNET_OK to keep the connection open, - * GNUNET_SYSERR to close it (signal serious error) - */ -static int -handle_p2p_confirmation_receipt (void *cls, - const struct GNUNET_PeerIdentity *other, - const struct GNUNET_MessageHeader *message) -{ - const struct P2PConfirmationReceiptMessage *p2p_crmsg; - struct P2PConfirmationReceiptMessage *my_p2p_crmsg; - struct ConfirmationReceiptMessage *crmsg; - struct ChatClient *target; - struct ChatClient *author; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got P2P confirmation receipt\n"); - p2p_crmsg = (const struct P2PConfirmationReceiptMessage *) message; - target = client_list_head; - while ((NULL != target) && - (0 != - memcmp (&target->id, &p2p_crmsg->target, sizeof (struct GNUNET_HashCode)))) - target = target->next; - if (NULL == target) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unknown source of the receipt. Rejecting the message\n"); - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (target->rcpt_sequence_number >= ntohl (p2p_crmsg->sequence_number)) - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "This receipt has already been handled." - " Sequence numbers (msg/sender): %u/%u\n", - ntohl (p2p_crmsg->sequence_number), - target->rcpt_sequence_number); -#endif - return GNUNET_OK; - } - target->rcpt_sequence_number = ntohl (p2p_crmsg->sequence_number); - author = client_list_head; - while ((NULL != author) && - (0 != - memcmp (&author->id, &p2p_crmsg->author, sizeof (struct GNUNET_HashCode)))) - author = author->next; - if (NULL == author) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unknown addressee. Rejecting the receipt\n"); - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - if (NULL == author->client) - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "The author of the original message is not a local client." - " Broadcasting receipt to neighbour peers\n"); -#endif - my_p2p_crmsg = - GNUNET_memdup (p2p_crmsg, - sizeof (struct P2PConfirmationReceiptMessage)); - GNUNET_CONTAINER_multihashmap_iterate (connected_peers, - &send_confirmation_receipt, - my_p2p_crmsg); - GNUNET_free (my_p2p_crmsg); - } - else - { -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "The author of the original message is a local client." - " Verifying signature of the receipt\n"); -#endif - crmsg = GNUNET_malloc (sizeof (struct ConfirmationReceiptMessage)); - crmsg->header.size = htons (sizeof (struct ConfirmationReceiptMessage)); - crmsg->header.type = - htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_NOTIFICATION); - crmsg->signature = p2p_crmsg->signature; - crmsg->purpose = p2p_crmsg->purpose; - crmsg->sequence_number = p2p_crmsg->msg_sequence_number; - crmsg->reserved2 = 0; - crmsg->timestamp = p2p_crmsg->timestamp; - crmsg->target = p2p_crmsg->target; - crmsg->author = p2p_crmsg->author; - crmsg->content = p2p_crmsg->content; - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT, - &crmsg->purpose, &crmsg->signature, - &target->public_key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid signature of the receipt\n"); - GNUNET_break_op (0); - return GNUNET_SYSERR; - } -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "The author of the original message is a local client." - " Sending receipt to the client\n"); -#endif - GNUNET_SERVER_notification_context_unicast (nc, author->client, - &crmsg->header, GNUNET_NO); - GNUNET_free (crmsg); - } - return GNUNET_OK; -} - - -/** - * Transmit a sync request to the peer. - * - * @param cls closure, NULL - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf - */ -static size_t -transmit_sync_request_to_peer (void *cls, size_t size, void *buf) -{ - struct GNUNET_MessageHeader *m = buf; - size_t msg_size; - -#if DEBUG_CHAT_SERVICE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting P2P sync request\n"); -#endif - msg_size = sizeof (struct GNUNET_MessageHeader); - GNUNET_assert (size >= msg_size); - GNUNET_assert (NULL != buf); - m = buf; - m->type = htons (GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST); - m->size = htons (msg_size); - return msg_size; -} - - -/** - * Method called whenever a peer connects. - * - * @param cls closure - * @param peer peer identity this notification is about - */ -static void -peer_connect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) -{ - struct ConnectedPeer *cp; - struct GNUNET_CORE_TransmitHandle *th; - - if (0 == memcmp (peer, &me, sizeof (struct GNUNET_PeerIdentity))) - return; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer connected: %s\n", - GNUNET_i2s (peer)); - th = GNUNET_CORE_notify_transmit_ready (core, GNUNET_YES, 1, - MAX_TRANSMIT_DELAY, peer, - sizeof (struct GNUNET_MessageHeader), - &transmit_sync_request_to_peer, NULL); - GNUNET_assert (NULL != th); - cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey); - if (NULL != cp) - { - GNUNET_break (0); - return; - } - cp = GNUNET_malloc (sizeof (struct ConnectedPeer)); - cp->pid = GNUNET_PEER_intern (peer); - GNUNET_break (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (connected_peers, - &peer->hashPubKey, cp, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); -} - - -/** - * Iterator to free peer entries. - * - * @param cls closure, unused - * @param key current key code - * @param value value in the hash map (peer entry) - * @return GNUNET_YES (we should continue to iterate) - */ -static int -clean_peer (void *cls, const struct GNUNET_HashCode * key, void *value) -{ - struct ConnectedPeer *cp; - const struct GNUNET_PeerIdentity *peer = - (const struct GNUNET_PeerIdentity *) key; - - cp = GNUNET_CONTAINER_multihashmap_get (connected_peers, &peer->hashPubKey); - if (cp == NULL) - return GNUNET_YES; - GNUNET_break (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (connected_peers, - &peer->hashPubKey, cp)); - GNUNET_PEER_change_rc (cp->pid, -1); - GNUNET_free (cp); - return GNUNET_YES; -} - - -/** - * Method called whenever a peer disconnects. - * - * @param cls closure, not used - * @param peer peer identity this notification is about - */ -static void -peer_disconnect_handler (void *cls, const struct GNUNET_PeerIdentity *peer) -{ - - if (0 == memcmp (peer, &me, sizeof (struct GNUNET_PeerIdentity))) - return; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peer disconnected: %s\n", - GNUNET_i2s (peer)); - clean_peer (NULL, (const struct GNUNET_HashCode *) peer, NULL); -} - - -/** - * Task run during shutdown. - * - * @param cls unused - * @param tc unused - */ -static void -cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct AnonymousMessage *next_msg; - struct ChatClient *next_client; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Cleaning up\n"); - if (NULL != core) - { - GNUNET_CORE_disconnect (core); - core = NULL; - } - if (NULL != nc) - { - GNUNET_SERVER_notification_context_destroy (nc); - nc = NULL; - } - while (NULL != client_list_head) - { - next_client = client_list_head->next; - GNUNET_free (client_list_head->room); - GNUNET_free_non_null (client_list_head->member_info); - GNUNET_free (client_list_head); - client_list_head = next_client; - } - while (NULL != anonymous_list_head) - { - next_msg = anonymous_list_head->next; - GNUNET_free (anonymous_list_head); - anonymous_list_head = next_msg; - } - GNUNET_CONTAINER_multihashmap_iterate (connected_peers, &clean_peer, NULL); - GNUNET_CONTAINER_multihashmap_destroy (connected_peers); - connected_peers = NULL; -} - - -/** - * To be called on core init/fail. - * - * @param cls closure, NULL - * @param server handle to the server for this service - * @param my_identity the public identity of this peer - */ -static void -core_init (void *cls, struct GNUNET_CORE_Handle *server, - const struct GNUNET_PeerIdentity *my_identity) -{ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Core initialized\n"); - me = *my_identity; -} - - -/** - * Process chat requests. - * - * @param cls closure, NULL - * @param server the initialized server - * @param c configuration to use - */ -static void -run (void *cls, struct GNUNET_SERVER_Handle *server, - const struct GNUNET_CONFIGURATION_Handle *c) -{ - static const struct GNUNET_SERVER_MessageHandler handlers[] = { - {&handle_join_request, NULL, - GNUNET_MESSAGE_TYPE_CHAT_JOIN_REQUEST, 0}, - {&handle_transmit_request, NULL, - GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST, 0}, - {&handle_acknowledge_request, NULL, - GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT, - sizeof (struct ConfirmationReceiptMessage)}, - {NULL, NULL, 0, 0} - }; - static const struct GNUNET_CORE_MessageHandler p2p_handlers[] = { - {&handle_p2p_join_notification, - GNUNET_MESSAGE_TYPE_CHAT_P2P_JOIN_NOTIFICATION, 0}, - {&handle_p2p_leave_notification, - GNUNET_MESSAGE_TYPE_CHAT_P2P_LEAVE_NOTIFICATION, - sizeof (struct P2PLeaveNotificationMessage)}, - {&handle_p2p_message_notification, - GNUNET_MESSAGE_TYPE_CHAT_P2P_MESSAGE_NOTIFICATION, 0}, - {&handle_p2p_sync_request, - GNUNET_MESSAGE_TYPE_CHAT_P2P_SYNC_REQUEST, - sizeof (struct GNUNET_MessageHeader)}, - {&handle_p2p_confirmation_receipt, - GNUNET_MESSAGE_TYPE_CHAT_P2P_CONFIRMATION_RECEIPT, - sizeof (struct P2PConfirmationReceiptMessage)}, - {NULL, 0, 0} - }; - - GNUNET_log_setup ("gnunet-service-chat", -#if DEBUG_CHAT_SERVICE - "DEBUG", -#else - "WARNING", -#endif - NULL); - cfg = c; - nc = GNUNET_SERVER_notification_context_create (server, 16); - connected_peers = - GNUNET_CONTAINER_multihashmap_create (EXPECTED_NEIGHBOUR_COUNT, GNUNET_NO); - GNUNET_SERVER_add_handlers (server, handlers); - core = - GNUNET_CORE_connect (cfg, NULL, &core_init, - &peer_connect_handler, &peer_disconnect_handler, - NULL, GNUNET_NO, NULL, GNUNET_NO, p2p_handlers); - GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, - NULL); -} - - -/** - * The main function for the chat service. - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, char *const *argv) -{ - return (GNUNET_OK == - GNUNET_SERVICE_run (argc, argv, "chat", GNUNET_SERVICE_OPTION_NONE, - &run, NULL)) ? 0 : 1; -} - -/* end of gnunet-service-chat.c */ diff --git a/src/chat/test_chat.c b/src/chat/test_chat.c @@ -1,556 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2005, 2006, 2007, 2008, 2011 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file chat/test_chat.c - * @brief base test case for the chat library - * @author Christian Grothoff - * @author Nathan Evans - * @author Vitaly Minko - * - * This test case serves as a base for simple chatting, anonymous chatting, - * authenticated chatting and acknowledgements test cases. Based on the - * executable being run the correct test case will be performed. Private - * chatting is covered by a separate test case since it requires 3 users. - */ - -#include "platform.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_util_lib.h" -#include "gnunet_arm_service.h" -#include "gnunet_chat_service.h" - -/** - * How long until we give up on passing the test? - */ -#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) - -struct PeerContext -{ - struct GNUNET_CONFIGURATION_Handle *cfg; - struct GNUNET_OS_Process *arm_proc; -}; - -struct Wanted -{ - struct GNUNET_CONTAINER_MetaData *meta; - - struct GNUNET_HashCode *sender; - - char *msg; - - const char *me; - - enum GNUNET_CHAT_MsgOptions opt; - - uint32_t sequence_number; - - struct GNUNET_TIME_Absolute timestamp; - - GNUNET_SCHEDULER_Task next_task; - - void *next_task_cls; - -}; - -static struct PeerContext p1; - -static struct PeerContext p2; - -static struct GNUNET_HashCode alice; - -static struct GNUNET_HashCode bob; - -static struct GNUNET_CHAT_Room *alice_room; - -static struct GNUNET_CHAT_Room *bob_room; - -static struct GNUNET_CONTAINER_MetaData *alice_meta; - -static struct GNUNET_CONTAINER_MetaData *bob_meta; - -static struct Wanted alice_wanted; - -static struct Wanted bob_wanted; - -static GNUNET_SCHEDULER_TaskIdentifier kill_task; - -static GNUNET_SCHEDULER_TaskIdentifier wait_task; - -static int err; - -static int is_ready; - -static int is_p2p; - -static int is_ackn; - -static int is_anon; - -static int is_auth; - - -static void -setup_peer (struct PeerContext *p, const char *cfgname) -{ - char *binary; - - binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); - p->cfg = GNUNET_CONFIGURATION_create (); - p->arm_proc = - GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, binary, - "gnunet-service-arm", - "-c", cfgname, NULL); - GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); - GNUNET_free (binary); -} - - -static void -stop_arm (struct PeerContext *p) -{ - if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); - if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", - GNUNET_OS_process_get_pid (p->arm_proc)); - GNUNET_OS_process_destroy (p->arm_proc); - p->arm_proc = NULL; - GNUNET_CONFIGURATION_destroy (p->cfg); -} - - -static void -abort_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if (alice_room != NULL) - { - GNUNET_CHAT_leave_room (alice_room); - alice_room = NULL; - } - if (bob_room != NULL) - { - GNUNET_CHAT_leave_room (bob_room); - bob_room = NULL; - } - err = 1; -} - - -static void -timeout_kill (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - fprintf (stderr, - "Timed out, stopping the test.\n"); - kill_task = GNUNET_SCHEDULER_NO_TASK; - if (wait_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (wait_task); - wait_task = GNUNET_SCHEDULER_NO_TASK; - } - GNUNET_SCHEDULER_add_continuation (&abort_test, NULL, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); -} - - -static int -join_cb (void *cls) -{ - struct Wanted *want = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%s has joined\n", want->me); - if (NULL != want->next_task) - GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); - return GNUNET_OK; -} - - -static int -member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, - enum GNUNET_CHAT_MsgOptions options) -{ - struct Wanted *want = cls; - struct GNUNET_HashCode sender; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%s - told that %s has %s\n", want->me, - member_info == - NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (member_info, - EXTRACTOR_METATYPE_TITLE), - member_info == NULL ? "left" : "joined"); - GNUNET_CRYPTO_hash (member_id, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &sender); - if ((0 == memcmp (&sender, want->sender, sizeof (struct GNUNET_HashCode))) && - (((member_info == NULL) && (want->meta == NULL)) || - ((member_info != NULL) && (want->meta != NULL) && - (GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta)))) && - (options == want->opt)) - { - if (NULL != want->next_task) - GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); - } - else - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (&abort_test, NULL); - } - return GNUNET_OK; -} - - -static int -receive_cb (void *cls, struct GNUNET_CHAT_Room *room, - const struct GNUNET_HashCode * sender, - const struct GNUNET_CONTAINER_MetaData *meta, const char *message, - struct GNUNET_TIME_Absolute timestamp, - enum GNUNET_CHAT_MsgOptions options) -{ - struct Wanted *want = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - - "%s - told that %s said %s\n", want->me, - meta == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (meta, - EXTRACTOR_METATYPE_TITLE), - message); - if ((0 == strcmp (message, want->msg)) && - (((sender == NULL) && (want->sender == NULL)) || - ((sender != NULL) && (want->sender != NULL) && - (0 == memcmp (sender, want->sender, sizeof (struct GNUNET_HashCode))))) && - (GNUNET_CONTAINER_meta_data_test_equal (meta, want->meta)) && - (options == want->opt) && - /* Not == since the library sets the actual timestamp, so it may be - * slightly greater - */ - (timestamp.abs_value >= want->timestamp.abs_value)) - { - if (NULL != want->next_task) - GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); - } - else - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (&abort_test, NULL); - } - return GNUNET_OK; -} - - -static int -confirmation_cb (void *cls, struct GNUNET_CHAT_Room *room, - uint32_t orig_seq_number, - struct GNUNET_TIME_Absolute timestamp, - const struct GNUNET_HashCode * receiver) -{ - struct Wanted *want = cls; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "%s - told that %s acknowledged message #%d\n", want->me, - GNUNET_CONTAINER_meta_data_get_by_type (want->meta, - EXTRACTOR_METATYPE_TITLE), - orig_seq_number); - if ((0 == memcmp (receiver, want->sender, sizeof (struct GNUNET_HashCode))) && - (orig_seq_number == want->sequence_number) && - (timestamp.abs_value >= want->timestamp.abs_value)) - { - if (NULL != want->next_task) - GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); - } - else - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (&abort_test, NULL); - } - return GNUNET_OK; -} - - -static void -wait_until_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_SCHEDULER_Task task = cls; - - if (is_ready) - { - wait_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (task, NULL); - } - else - wait_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 50), - &wait_until_ready, task); -} - - -static void -disconnect_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Alice is leaving.\n"); - if (is_p2p) - stop_arm (&p2); - GNUNET_CHAT_leave_room (alice_room); - alice_room = NULL; - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; -} - - -static void -disconnect_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Bob is leaving.\n"); - alice_wanted.meta = NULL; - alice_wanted.sender = &bob; - alice_wanted.msg = NULL; - alice_wanted.opt = 0; - alice_wanted.next_task = &disconnect_alice; - alice_wanted.next_task_cls = NULL; - GNUNET_CHAT_leave_room (bob_room); - bob_room = NULL; -} - - -static void -set_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - is_ready = GNUNET_YES; -} - - -static void -send_to_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Bob says 'Hi!'\n"); - alice_wanted.meta = bob_meta; - alice_wanted.sender = &bob; - alice_wanted.msg = "Hi Alice!"; - alice_wanted.opt = GNUNET_CHAT_MSG_OPTION_NONE; - alice_wanted.timestamp = GNUNET_TIME_absolute_get (); - alice_wanted.next_task = &disconnect_bob; - alice_wanted.next_task_cls = NULL; - GNUNET_CHAT_send_message (bob_room, "Hi Alice!", GNUNET_CHAT_MSG_OPTION_NONE, - NULL, NULL); -} - - -static void -send_to_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - enum GNUNET_CHAT_MsgOptions options; - uint32_t *seq = NULL; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Alice says 'Hi!'\n"); - if (is_ackn) - { - options = GNUNET_CHAT_MSG_ACKNOWLEDGED; - alice_wanted.meta = bob_meta; - alice_wanted.sender = &bob; - alice_wanted.timestamp = GNUNET_TIME_absolute_get (); - alice_wanted.next_task = &disconnect_bob; - alice_wanted.next_task_cls = NULL; - bob_wanted.meta = alice_meta; - bob_wanted.sender = &alice; - bob_wanted.next_task = NULL; - seq = &(alice_wanted.sequence_number); - } - else if (is_anon) - { - options = GNUNET_CHAT_MSG_ANONYMOUS; - bob_wanted.meta = NULL; - bob_wanted.sender = NULL; - bob_wanted.next_task = &disconnect_bob; - } - else if (is_auth) - { - options = GNUNET_CHAT_MSG_AUTHENTICATED; - bob_wanted.meta = alice_meta; - bob_wanted.sender = &alice; - bob_wanted.next_task = &disconnect_bob; - } - else - { - options = GNUNET_CHAT_MSG_OPTION_NONE; - bob_wanted.meta = alice_meta; - bob_wanted.sender = &alice; - bob_wanted.next_task = &send_to_alice; - } - bob_wanted.msg = "Hi Bob!"; - bob_wanted.opt = options; - bob_wanted.timestamp = GNUNET_TIME_absolute_get (); - bob_wanted.next_task_cls = NULL; - GNUNET_CHAT_send_message (alice_room, "Hi Bob!", options, NULL, seq); -} - - -static void -prepare_for_alice_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - bob_wanted.meta = alice_meta; - bob_wanted.sender = &alice; - bob_wanted.msg = NULL; - bob_wanted.opt = -1; - bob_wanted.next_task = &set_ready; - bob_wanted.next_task_cls = NULL; -} - - -static void -join_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Bob joining\n"); - alice_wanted.meta = bob_meta; - alice_wanted.sender = &bob; - alice_wanted.msg = NULL; - alice_wanted.opt = -1; - alice_wanted.next_task = &wait_until_ready; - alice_wanted.next_task_cls = &send_to_bob; - bob_wanted.next_task = &prepare_for_alice_task; - bob_wanted.next_task_cls = NULL; - is_ready = GNUNET_NO; - bob_room = - GNUNET_CHAT_join_room (is_p2p ? p2.cfg : p1.cfg, "bob", bob_meta, "test", - -1, &join_cb, &bob_wanted, &receive_cb, - &bob_wanted, &member_list_cb, &bob_wanted, - &confirmation_cb, &bob_wanted, &bob); - if (NULL == bob_room) - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_CHAT_leave_room (alice_room); - alice_room = NULL; - err = 1; - } -} - - -static void -join_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Alice joining\n"); - alice_wanted.next_task = &join_bob_task; - alice_wanted.next_task_cls = NULL; - alice_room = - GNUNET_CHAT_join_room (p1.cfg, "alice", alice_meta, "test", -1, &join_cb, - &alice_wanted, &receive_cb, &alice_wanted, - &member_list_cb, &alice_wanted, &confirmation_cb, - &alice_wanted, &alice); - if (NULL == alice_room) - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - err = 1; - } -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - if (is_p2p) - { - setup_peer (&p1, "test_chat_peer1.conf"); - setup_peer (&p2, "test_chat_peer2.conf"); - } - else - setup_peer (&p1, "test_chat_data.conf"); - - memset (&alice_wanted, 0, sizeof (struct Wanted)); - memset (&bob_wanted, 0, sizeof (struct Wanted)); - alice_wanted.me = "Alice"; - bob_wanted.me = "Bob"; - alice_meta = GNUNET_CONTAINER_meta_data_create (); - GNUNET_CONTAINER_meta_data_insert (alice_meta, "<gnunet>", - EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METAFORMAT_UTF8, "text/plain", - "Alice", strlen ("Alice") + 1); - bob_meta = GNUNET_CONTAINER_meta_data_create (); - GNUNET_CONTAINER_meta_data_insert (bob_meta, "<gnunet>", - EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METAFORMAT_UTF8, "text/plain", - "Bob", strlen ("Bob") + 1); - kill_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &timeout_kill, NULL); - GNUNET_SCHEDULER_add_now (&join_alice_task, NULL); -} - - -int -main (int argc, char *argv[]) -{ - char *const argvx[] = { - "test-chat", - "-c", - "test_chat_data.conf", - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - - GNUNET_log_setup ("test_chat", - "WARNING", - NULL); - if (strstr (argv[0], "p2p") != NULL) - { - is_p2p = GNUNET_YES; - } - if (strstr (argv[0], "acknowledgment") != NULL) - { - is_ackn = GNUNET_YES; - } - else if (strstr (argv[0], "anonymous") != NULL) - { - is_anon = GNUNET_YES; - } - else if (strstr (argv[0], "authentication") != NULL) - { - is_auth = GNUNET_YES; - } - GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, - "test-chat", "nohelp", options, &run, NULL); - stop_arm (&p1); - GNUNET_CONTAINER_meta_data_destroy (alice_meta); - GNUNET_CONTAINER_meta_data_destroy (bob_meta); - if (is_p2p) - { - GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-1/"); - GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-2/"); - } - else - GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat/"); - return err; -} - -/* end of test_chat.c */ diff --git a/src/chat/test_chat_data.conf b/src/chat/test_chat_data.conf @@ -1,55 +0,0 @@ -[PATHS] -SERVICEHOME = /tmp/gnunet-test-chat/ - -[gnunetd] -HOSTKEY = $SERVICEHOME/.hostkey - -[resolver] -PORT = 42464 -HOSTNAME = localhost - -[transport] -PORT = 42465 -PLUGINS = - -[arm] -PORT = 42466 -HOSTNAME = localhost -DEFAULTSERVICES = core chat - -[peerinfo] -PORT = 42469 -HOSTNAME = localhost - -[core] -PORT = 42470 -HOSTNAME = localhost - -[chat] -PORT = 42471 -HOSTNAME = localhost -HOME = $SERVICEHOME -BINARY = gnunet-service-chat - -[testing] -WEAKRANDOM = YES - -[nat] -DISABLEV6 = YES -BINDTO = 127.0.0.1 -ENABLE_UPNP = NO -BEHIND_NAT = NO -ALLOW_NAT = NO -INTERNAL_ADDRESS = 127.0.0.1 -EXTERNAL_ADDRESS = 127.0.0.1 - -[dns] -AUTOSTART = NO - -[consensus] -AUTOSTART = NO - -[nse] -AUTOSTART = NO - - diff --git a/src/chat/test_chat_peer1.conf b/src/chat/test_chat_peer1.conf @@ -1,92 +0,0 @@ -[PATHS] -SERVICEHOME = /tmp/gnunet-test-chat-peer-1/ - -[gnunetd] -HOSTKEY = $SERVICEHOME/.hostkey - -[hostlist] -HTTPPORT = 31000 -OPTIONS = -p - -[resolver] -PORT = 31001 -HOSTNAME = localhost -UNIXPATH = /tmp/gnunet-chat-p1-service-resolver.sock - -[transport] -PORT = 31002 -UNIXPATH = /tmp/gnunet-chat-p1-service-transport.sock -PLUGINS = tcp -#BINARY = /home/grothoff/bin/gnunet-service-transport -#PREFIX = valgrind - -[transport-tcp] -PORT = 31003 - -[arm] -PORT = 31004 -UNIXPATH = /tmp/gnunet-chat-p1-service-arm.sock -HOSTNAME = localhost -DEFAULTSERVICES = resolver transport core topology hostlist statistics chat - -[core] -PORT = 31005 -UNIXPATH = /tmp/gnunet-chat-p1-service-core.sock -HOSTNAME = localhost - -[topology] -MINIMUM-FRIENDS = 0 -FRIENDS-ONLY = NO -AUTOCONNECT = YES -TARGET-CONNECTION-COUNT = 16 -FRIENDS = $SERVICEHOME/friends -BINARY = gnunet-daemon-topology - -[peerinfo] -PORT = 31006 -UNIXPATH = /tmp/gnunet-chat-p1-service-peerinfo.sock -HOSTNAME = localhost - -[statistics] -PORT = 31007 -HOSTNAME = localhost -UNIXPATH = /tmp/gnunet-chat-p1-service-statistics.sock - -[chat] -PORT = 31008 -HOSTNAME = localhost -HOME = $SERVICEHOME -BINARY = gnunet-service-chat - -[testing] -WEAKRANDOM = YES - -[fs] -AUTOSTART = NO - -[datastore] -AUTOSTART = NO - -[dht] -AUTOSTART = NO - -[mesh] -AUTOSTART = NO -[nat] -DISABLEV6 = YES -BINDTO = 127.0.0.1 -ENABLE_UPNP = NO -BEHIND_NAT = NO -ALLOW_NAT = NO -INTERNAL_ADDRESS = 127.0.0.1 -EXTERNAL_ADDRESS = 127.0.0.1 - -[dns] -AUTOSTART = NO - -[nse] -AUTOSTART = NO - -[ats] -PORT = 31971 -UNIXPATH = /tmp/gnunet-chat-p1-service-ats.sock diff --git a/src/chat/test_chat_peer2.conf b/src/chat/test_chat_peer2.conf @@ -1,94 +0,0 @@ -[PATHS] -SERVICEHOME = /tmp/gnunet-test-chat-peer-2/ - -[gnunetd] -HOSTKEY = $SERVICEHOME/.hostkey - -[hostlist] -SERVERS = http://localhost:31000/ -OPTIONS = -b - -[resolver] -PORT = 32001 -HOSTNAME = localhost -UNIXPATH = /tmp/gnunet-chat-p2-service-resolver.sock - -[transport] -PORT = 32002 -UNIXPATH = /tmp/gnunet-chat-p2-service-transport.sock -PLUGINS = tcp -#BINARY = /home/grothoff/bin/gnunet-service-transport -#PREFIX = valgrind - -[transport-tcp] -PORT = 32003 - -[arm] -PORT = 32004 -UNIXPATH = /tmp/gnunet-chat-p2-service-arm.sock -HOSTNAME = localhost -DEFAULTSERVICES = resolver transport core topology hostlist statistics chat - -[core] -PORT = 32005 -UNIXPATH = /tmp/gnunet-chat-p2-service-core.sock -HOSTNAME = localhost - -[topology] -MINIMUM-FRIENDS = 0 -FRIENDS-ONLY = NO -AUTOCONNECT = YES -TARGET-CONNECTION-COUNT = 16 -FRIENDS = $SERVICEHOME/friends -BINARY = gnunet-daemon-topology - -[peerinfo] -PORT = 32006 -UNIXPATH = /tmp/gnunet-chat-p2-service-peerinfo.sock -HOSTNAME = localhost - -[statistics] -PORT = 32007 -HOSTNAME = localhost -UNIXPATH = /tmp/gnunet-chat-p2-service-statistics.sock - -[chat] -PORT = 32008 -HOSTNAME = localhost -HOME = $SERVICEHOME -BINARY = gnunet-service-chat - -[testing] -WEAKRANDOM = YES - -[fs] -AUTOSTART = NO - -[datastore] -AUTOSTART = NO - -[dht] -AUTOSTART = NO - -[mesh] -AUTOSTART = NO - -[nat] -DISABLEV6 = YES -BINDTO = 127.0.0.1 -ENABLE_UPNP = NO -BEHIND_NAT = NO -ALLOW_NAT = NO -INTERNAL_ADDRESS = 127.0.0.1 -EXTERNAL_ADDRESS = 127.0.0.1 - -[dns] -AUTOSTART = NO - -[nse] -AUTOSTART = NO - -[ats] -PORT = 32971 -UNIXPATH = /tmp/gnunet-chat-p2-service-ats.sock - diff --git a/src/chat/test_chat_peer3.conf b/src/chat/test_chat_peer3.conf @@ -1,93 +0,0 @@ -[PATHS] -SERVICEHOME = /tmp/gnunet-test-chat-peer-3/ - -[gnunetd] -HOSTKEY = $SERVICEHOME/.hostkey - -[hostlist] -SERVERS = http://localhost:31000/ -OPTIONS = -b - -[resolver] -PORT = 33001 -HOSTNAME = localhost -UNIXPATH = /tmp/gnunet-chat-p3-service-resolver.sock - -[transport] -PORT = 33002 -UNIXPATH = /tmp/gnunet-chat-p3-service-transport.sock -PLUGINS = tcp -#BINARY = /home/grothoff/bin/gnunet-service-transport -#PREFIX = valgrind - -[transport-tcp] -PORT = 33003 - -[arm] -PORT = 33004 -UNIXPATH = /tmp/gnunet-chat-p3-service-arm.sock -HOSTNAME = localhost -DEFAULTSERVICES = resolver transport core topology hostlist statistics chat - -[core] -PORT = 33005 -UNIXPATH = /tmp/gnunet-chat-p3-service-core.sock -HOSTNAME = localhost - -[topology] -MINIMUM-FRIENDS = 0 -FRIENDS-ONLY = NO -AUTOCONNECT = YES -TARGET-CONNECTION-COUNT = 16 -FRIENDS = $SERVICEHOME/friends -BINARY = gnunet-daemon-topology - -[peerinfo] -PORT = 33006 -UNIXPATH = /tmp/gnunet-chat-p3-service-peerinfo.sock -HOSTNAME = localhost - -[statistics] -PORT = 33007 -HOSTNAME = localhost -UNIXPATH = /tmp/gnunet-chat-p3-service-statistics.sock - -[chat] -PORT = 33008 -HOSTNAME = localhost -HOME = $SERVICEHOME -BINARY = gnunet-service-chat - -[testing] -WEAKRANDOM = YES - -[fs] -AUTOSTART = NO - -[datastore] -AUTOSTART = NO - -[dht] -AUTOSTART = NO - -[mesh] -AUTOSTART = NO - -[nat] -DISABLEV6 = YES -BINDTO = 127.0.0.1 -ENABLE_UPNP = NO -BEHIND_NAT = NO -ALLOW_NAT = NO -INTERNAL_ADDRESS = 127.0.0.1 -EXTERNAL_ADDRESS = 127.0.0.1 - -[dns] -AUTOSTART = NO - - - -[nse] -AUTOSTART = NO - - diff --git a/src/chat/test_chat_private.c b/src/chat/test_chat_private.c @@ -1,640 +0,0 @@ -/* - This file is part of GNUnet. - (C) 2011 Christian Grothoff (and other contributing authors) - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. -*/ - -/** - * @file chat/test_chat_private.c - * @brief testcase for private chatting - * @author Vitaly Minko - */ - -#include "platform.h" -#include "gnunet_crypto_lib.h" -#include "gnunet_util_lib.h" -#include "gnunet_arm_service.h" -#include "gnunet_chat_service.h" - -#define VERBOSE GNUNET_NO - -/** - * How long until we give up on passing the test? - */ -#define KILL_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60) - -/** - * How long until we give up on receiving somebody else's private message? - */ -#define PM_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) - -struct PeerContext -{ - struct GNUNET_CONFIGURATION_Handle *cfg; - struct GNUNET_OS_Process *arm_proc; -}; - -struct Wanted -{ - struct GNUNET_CONTAINER_MetaData *meta; - - struct GNUNET_HashCode *sender; - - /** - * Alternative meta/sender is used when we expect join/leave notification - * from two peers and don't know which one will come first. - */ - struct GNUNET_CONTAINER_MetaData *meta2; - - struct GNUNET_HashCode *sender2; - - char *msg; - - const char *me; - - enum GNUNET_CHAT_MsgOptions opt; - - struct GNUNET_TIME_Absolute timestamp; - - GNUNET_SCHEDULER_Task next_task; - - void *next_task_cls; - -}; - -static struct PeerContext p1; - -static struct PeerContext p2; - -static struct PeerContext p3; - -static struct GNUNET_HashCode alice; - -static struct GNUNET_HashCode bob; - -static struct GNUNET_HashCode carol; - -static struct GNUNET_CHAT_Room *alice_room; - -static struct GNUNET_CHAT_Room *bob_room; - -static struct GNUNET_CHAT_Room *carol_room; - -static struct GNUNET_CONTAINER_MetaData *alice_meta; - -static struct GNUNET_CONTAINER_MetaData *bob_meta; - -static struct GNUNET_CONTAINER_MetaData *carol_meta; - -static struct Wanted alice_wanted; - -static struct Wanted bob_wanted; - -static struct Wanted carol_wanted; - -static GNUNET_SCHEDULER_TaskIdentifier kill_task; - -static GNUNET_SCHEDULER_TaskIdentifier finish_task; - -static GNUNET_SCHEDULER_TaskIdentifier wait_task; - -static int err; - -static int alice_ready; - -static int bob_ready; - -static int is_p2p; - -static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *bob_public_key; - - -static void -setup_peer (struct PeerContext *p, const char *cfgname) -{ - char *binary; - - binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); - p->cfg = GNUNET_CONFIGURATION_create (); - p->arm_proc = - GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, binary, - "gnunet-service-arm", - "-c", cfgname, NULL); - GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); - GNUNET_free (binary); -} - - -static void -stop_arm (struct PeerContext *p) -{ - if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM)) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); - if (GNUNET_OS_process_wait (p->arm_proc) != GNUNET_OK) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM process %u stopped\n", - GNUNET_OS_process_get_pid (p->arm_proc)); - GNUNET_OS_process_destroy (p->arm_proc); - p->arm_proc = NULL; - GNUNET_CONFIGURATION_destroy (p->cfg); -} - - -static void -abort_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - if (alice_room != NULL) - { - GNUNET_CHAT_leave_room (alice_room); - alice_room = NULL; - } - if (bob_room != NULL) - { - GNUNET_CHAT_leave_room (bob_room); - bob_room = NULL; - } - if (carol_room != NULL) - { - GNUNET_CHAT_leave_room (carol_room); - carol_room = NULL; - } - err = 1; -} - - -static void -timeout_kill (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ -#if VERBOSE - printf ("Timed out, stopping the test.\n"); -#endif - kill_task = GNUNET_SCHEDULER_NO_TASK; - if (wait_task != GNUNET_SCHEDULER_NO_TASK) - { - GNUNET_SCHEDULER_cancel (wait_task); - wait_task = GNUNET_SCHEDULER_NO_TASK; - } - GNUNET_SCHEDULER_add_continuation (&abort_test, NULL, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); -} - - -static int -join_cb (void *cls) -{ - struct Wanted *want = cls; - -#if VERBOSE - printf ("%s has joined\n", want->me); -#endif - if (NULL != want->next_task) - GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); - return GNUNET_OK; -} - - -static int -member_list_cb (void *cls, const struct GNUNET_CONTAINER_MetaData *member_info, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *member_id, - enum GNUNET_CHAT_MsgOptions options) -{ - struct Wanted *want = cls; - struct GNUNET_HashCode sender; - -#if VERBOSE - printf ("%s - told that %s has %s\n", want->me, - member_info == - NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (member_info, - EXTRACTOR_METATYPE_TITLE), - member_info == NULL ? "left" : "joined"); -#endif - GNUNET_CRYPTO_hash (member_id, - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), - &sender); - /* entertain both primary and an alternative sender/meta */ - if (((0 == memcmp (&sender, want->sender, sizeof (struct GNUNET_HashCode))) || - ((want->sender2 != NULL) && - (0 == memcmp (&sender, want->sender2, sizeof (struct GNUNET_HashCode))))) && - (((member_info == NULL) && (want->meta == NULL)) || - ((member_info != NULL) && - (((want->meta != NULL) && - GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta)) || - ((want->meta2 != NULL) && - GNUNET_CONTAINER_meta_data_test_equal (member_info, want->meta2))))) - && (options == want->opt)) - { - /* remember Bob's public key, we need it to send private message */ - if (NULL == bob_public_key && - (0 == memcmp (&bob, want->sender, sizeof (struct GNUNET_HashCode)))) - bob_public_key = - GNUNET_memdup (member_id, - sizeof (struct - GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); - if (want->sender2 != NULL) - { - /* flush alternative sender */ - if (0 == memcmp (&sender, want->sender, sizeof (struct GNUNET_HashCode))) - { - want->sender = want->sender2; - want->meta = want->meta2; - } - want->sender2 = NULL; - want->meta2 = NULL; - } - else if (NULL != want->next_task) - GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); - } - else - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (&abort_test, NULL); - } - return GNUNET_OK; -} - - -static int -receive_cb (void *cls, struct GNUNET_CHAT_Room *room, - const struct GNUNET_HashCode * sender, - const struct GNUNET_CONTAINER_MetaData *meta, const char *message, - struct GNUNET_TIME_Absolute timestamp, - enum GNUNET_CHAT_MsgOptions options) -{ - struct Wanted *want = cls; - -#if VERBOSE - printf ("%s - told that %s said '%s'\n", want->me, - meta == NULL ? NULL : GNUNET_CONTAINER_meta_data_get_by_type (meta, - EXTRACTOR_METATYPE_TITLE), - message); -#endif - - if ((want->msg != NULL) && (0 == strcmp (message, want->msg)) && - (((sender == NULL) && (want->sender == NULL)) || - ((sender != NULL) && (want->sender != NULL) && - (0 == memcmp (sender, want->sender, sizeof (struct GNUNET_HashCode))))) && - (GNUNET_CONTAINER_meta_data_test_equal (meta, want->meta)) && - (options == want->opt) && - /* Not == since the library sets the actual timestamp, so it may be - * slightly greater - */ - (timestamp.abs_value >= want->timestamp.abs_value)) - { - if (NULL != want->next_task) - GNUNET_SCHEDULER_add_now (want->next_task, want->next_task_cls); - } - else - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_cancel (finish_task); - finish_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (&abort_test, NULL); - } - return GNUNET_OK; -} - - -static void -wait_until_all_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - GNUNET_SCHEDULER_Task task = cls; - -#if VERBOSE - printf ("Waiting...\n"); -#endif - if (alice_ready && bob_ready) - { - wait_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_SCHEDULER_add_now (task, NULL); - } - else - wait_task = - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 5000), - &wait_until_all_ready, task); -} - - -static void -set_alice_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - alice_ready = GNUNET_YES; -} - - -static void -set_bob_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - bob_ready = GNUNET_YES; -} - - -static void -disconnect_alice (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ -#if VERBOSE - printf ("Alice is leaving.\n"); -#endif - if (is_p2p) - stop_arm (&p2); - GNUNET_CHAT_leave_room (alice_room); - alice_room = NULL; - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; -} - - -static void -disconnect_bob (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ -#if VERBOSE - printf ("Bod is leaving.\n"); -#endif - if (is_p2p) - stop_arm (&p3); - alice_wanted.meta = NULL; - alice_wanted.sender = &bob; - alice_wanted.msg = NULL; - alice_wanted.opt = 0; - alice_wanted.next_task = &disconnect_alice; - alice_wanted.next_task_cls = NULL; - GNUNET_CHAT_leave_room (bob_room); - bob_room = NULL; -} - - -static void -disconnect_carol (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ -#if VERBOSE - printf ("Carol is leaving.\n"); -#endif - alice_wanted.meta = NULL; - alice_wanted.sender = &carol; - alice_wanted.msg = NULL; - alice_wanted.opt = 0; - alice_wanted.next_task = &set_alice_ready; - alice_wanted.next_task_cls = NULL; - alice_ready = GNUNET_NO; - bob_wanted.meta = NULL; - bob_wanted.sender = &carol; - bob_wanted.msg = NULL; - bob_wanted.opt = 0; - bob_wanted.next_task = &wait_until_all_ready; - bob_wanted.next_task_cls = &disconnect_bob; - bob_ready = GNUNET_YES; - GNUNET_CHAT_leave_room (carol_room); - carol_room = NULL; -} - - -static void -send_from_alice_to_bob (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - uint32_t seq; - -#if VERBOSE - printf ("Alice says 'Hi!' to Bob\n"); -#endif - alice_ready = GNUNET_YES; - bob_ready = GNUNET_NO; - bob_wanted.meta = alice_meta; - bob_wanted.sender = &alice; - bob_wanted.msg = "Hi Bob!"; - bob_wanted.opt = GNUNET_CHAT_MSG_PRIVATE; - bob_wanted.next_task = &set_bob_ready; - bob_wanted.next_task_cls = NULL; - /* Carol should not receive this message */ - carol_wanted.meta = NULL; - carol_wanted.sender = NULL; - carol_wanted.msg = NULL; - carol_wanted.opt = 0; - carol_wanted.next_task = NULL; - carol_wanted.next_task_cls = NULL; - GNUNET_CHAT_send_message (alice_room, "Hi Bob!", GNUNET_CHAT_MSG_PRIVATE, - bob_public_key, &seq); - finish_task = - GNUNET_SCHEDULER_add_delayed (PM_TIMEOUT, &wait_until_all_ready, - &disconnect_carol); -} - - -static void -prepare_bob_for_alice_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - bob_wanted.meta = alice_meta; - bob_wanted.sender = &alice; - bob_wanted.msg = NULL; - bob_wanted.opt = -1; - bob_wanted.next_task = &set_bob_ready; - bob_wanted.next_task_cls = NULL; -} - - -static void -prepare_carol_for_alice_and_bob_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext - *tc) -{ - carol_wanted.meta = alice_meta; - carol_wanted.sender = &alice; - /* set alternative meta/sender since we don't know from which peer - * notification will come first */ - carol_wanted.meta2 = bob_meta; - carol_wanted.sender2 = &bob; - carol_wanted.msg = NULL; - carol_wanted.opt = -1; - carol_wanted.next_task = &wait_until_all_ready; - carol_wanted.next_task_cls = &send_from_alice_to_bob; -} - - -static void -join_carol_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ -#if VERBOSE - printf ("Carol joining\n"); -#endif - alice_wanted.meta = carol_meta; - alice_wanted.sender = &carol; - alice_wanted.msg = NULL; - alice_wanted.opt = -1; - alice_wanted.next_task = &set_alice_ready; - alice_wanted.next_task_cls = NULL; - alice_ready = GNUNET_NO; - bob_wanted.meta = carol_meta; - bob_wanted.sender = &carol; - bob_wanted.msg = NULL; - bob_wanted.opt = -1; - bob_wanted.next_task = &set_bob_ready; - bob_wanted.next_task_cls = NULL; - bob_ready = GNUNET_NO; - carol_wanted.next_task = &prepare_carol_for_alice_and_bob_task; - carol_wanted.next_task_cls = NULL; - carol_room = - GNUNET_CHAT_join_room (is_p2p ? p3.cfg : p1.cfg, "carol", carol_meta, - "test", -1, &join_cb, &carol_wanted, &receive_cb, - &carol_wanted, &member_list_cb, &carol_wanted, - NULL, NULL, &carol); - if (NULL == carol_room) - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_CHAT_leave_room (alice_room); - alice_room = NULL; - GNUNET_CHAT_leave_room (bob_room); - bob_room = NULL; - err = 1; - } -} - - -static void -join_bob_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ -#if VERBOSE - printf ("Bob joining\n"); -#endif - alice_wanted.meta = bob_meta; - alice_wanted.sender = &bob; - alice_wanted.msg = NULL; - alice_wanted.opt = -1; - alice_wanted.next_task = &wait_until_all_ready; - alice_wanted.next_task_cls = &join_carol_task; - alice_ready = GNUNET_YES; - bob_wanted.next_task = &prepare_bob_for_alice_task; - bob_wanted.next_task_cls = NULL; - bob_ready = GNUNET_NO; - bob_room = - GNUNET_CHAT_join_room (is_p2p ? p2.cfg : p1.cfg, "bob", bob_meta, "test", - -1, &join_cb, &bob_wanted, &receive_cb, - &bob_wanted, &member_list_cb, &bob_wanted, NULL, - NULL, &bob); - if (NULL == bob_room) - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - GNUNET_CHAT_leave_room (alice_room); - alice_room = NULL; - err = 1; - } -} - - -static void -join_alice_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) -{ -#if VERBOSE - printf ("Alice joining\n"); -#endif - alice_wanted.next_task = &join_bob_task; - alice_wanted.next_task_cls = NULL; - alice_room = - GNUNET_CHAT_join_room (p1.cfg, "alice", alice_meta, "test", -1, &join_cb, - &alice_wanted, &receive_cb, &alice_wanted, - &member_list_cb, &alice_wanted, NULL, NULL, - &alice); - if (NULL == alice_room) - { - GNUNET_SCHEDULER_cancel (kill_task); - kill_task = GNUNET_SCHEDULER_NO_TASK; - err = 1; - } -} - - -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - if (is_p2p) - { - setup_peer (&p1, "test_chat_peer1.conf"); - setup_peer (&p2, "test_chat_peer2.conf"); - setup_peer (&p3, "test_chat_peer3.conf"); - } - else - setup_peer (&p1, "test_chat_data.conf"); - - memset (&alice_wanted, 0, sizeof (struct Wanted)); - memset (&bob_wanted, 0, sizeof (struct Wanted)); - memset (&carol_wanted, 0, sizeof (struct Wanted)); - alice_wanted.me = "Alice"; - bob_wanted.me = "Bob"; - carol_wanted.me = "Carol"; - alice_meta = GNUNET_CONTAINER_meta_data_create (); - GNUNET_CONTAINER_meta_data_insert (alice_meta, "<gnunet>", - EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METAFORMAT_UTF8, "text/plain", - "Alice", strlen ("Alice") + 1); - bob_meta = GNUNET_CONTAINER_meta_data_create (); - GNUNET_CONTAINER_meta_data_insert (bob_meta, "<gnunet>", - EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METAFORMAT_UTF8, "text/plain", - "Bob", strlen ("Bob") + 1); - carol_meta = GNUNET_CONTAINER_meta_data_create (); - GNUNET_CONTAINER_meta_data_insert (carol_meta, "<gnunet>", - EXTRACTOR_METATYPE_TITLE, - EXTRACTOR_METAFORMAT_UTF8, "text/plain", - "Carol", strlen ("Carol") + 1); - kill_task = GNUNET_SCHEDULER_add_delayed (KILL_TIMEOUT, &timeout_kill, NULL); - GNUNET_SCHEDULER_add_now (&join_alice_task, NULL); -} - - -int -main (int argc, char *argv[]) -{ - char *const argvx[] = { - "test-chat", - "-c", - "test_chat_data.conf", - NULL - }; - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - - GNUNET_log_setup ("test_chat", - "WARNING", - NULL); - if (strstr (argv[0], "p2p") != NULL) - { - is_p2p = GNUNET_YES; - } - GNUNET_PROGRAM_run ((sizeof (argvx) / sizeof (char *)) - 1, argvx, - "test-chat", "nohelp", options, &run, NULL); - stop_arm (&p1); - GNUNET_CONTAINER_meta_data_destroy (alice_meta); - GNUNET_CONTAINER_meta_data_destroy (bob_meta); - GNUNET_CONTAINER_meta_data_destroy (carol_meta); - if (is_p2p) - { - GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-1/"); - GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-2/"); - GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat-peer-3/"); - } - else - GNUNET_DISK_directory_remove ("/tmp/gnunet-test-chat/"); - return err; -} - -/* end of test_chat_private.c */