123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2020--2021 GNUnet e.V.
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- 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
- Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @author Tobias Frisch
- * @file src/messenger/gnunet-service-messenger_handle.c
- * @brief GNUnet MESSENGER service
- */
- #include "gnunet-service-messenger_handle.h"
- #include "gnunet-service-messenger.h"
- #include "gnunet-service-messenger_message_kind.h"
- #include "messenger_api_util.h"
- struct GNUNET_MESSENGER_SrvHandle*
- create_handle (struct GNUNET_MESSENGER_Service *service,
- struct GNUNET_MQ_Handle *mq)
- {
- GNUNET_assert((service) && (mq));
- struct GNUNET_MESSENGER_SrvHandle *handle = GNUNET_new(struct GNUNET_MESSENGER_SrvHandle);
- handle->service = service;
- handle->mq = mq;
- handle->name = NULL;
- handle->ego = NULL;
- handle->member_ids = GNUNET_CONTAINER_multihashmap_create (8, GNUNET_NO);
- return handle;
- }
- int
- iterate_free_member_ids (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
- {
- GNUNET_free(value);
- return GNUNET_YES;
- }
- void
- destroy_handle (struct GNUNET_MESSENGER_SrvHandle *handle)
- {
- GNUNET_assert(handle);
- if (handle->service->dir)
- save_handle_configuration (handle);
- if (handle->name)
- GNUNET_free(handle->name);
- GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_free_member_ids, NULL);
- GNUNET_CONTAINER_multihashmap_destroy (handle->member_ids);
- GNUNET_free(handle);
- }
- void
- get_handle_data_subdir (const struct GNUNET_MESSENGER_SrvHandle *handle,
- const char *name,
- char **dir)
- {
- GNUNET_assert((handle) && (dir));
- if (name)
- GNUNET_asprintf (dir, "%s%s%c%s%c", handle->service->dir, "identities",
- DIR_SEPARATOR, name, DIR_SEPARATOR);
- else
- GNUNET_asprintf (dir, "%s%s%c", handle->service->dir, "anonymous",
- DIR_SEPARATOR);
- }
- static int
- create_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *key)
- {
- GNUNET_assert((handle) && (key));
- struct GNUNET_ShortHashCode *random_id = GNUNET_new(struct GNUNET_ShortHashCode);
- if (!random_id)
- return GNUNET_NO;
- generate_free_member_id (random_id, NULL);
- if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->member_ids, key, random_id,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
- {
- GNUNET_free(random_id);
- return GNUNET_NO;
- }
- GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Created a new member id (%s) for room: %s\n", GNUNET_sh2s (random_id),
- GNUNET_h2s (key));
- return GNUNET_YES;
- }
- const struct GNUNET_ShortHashCode*
- get_handle_member_id (const struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *key)
- {
- GNUNET_assert((handle) && (key));
- return GNUNET_CONTAINER_multihashmap_get (handle->member_ids, key);
- }
- int
- change_handle_member_id (struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *key,
- const struct GNUNET_ShortHashCode *unique_id)
- {
- GNUNET_assert((handle) && (key) && (unique_id));
- struct GNUNET_ShortHashCode *member_id = GNUNET_CONTAINER_multihashmap_get (handle->member_ids, key);
- if (!member_id)
- {
- member_id = GNUNET_new(struct GNUNET_ShortHashCode);
- GNUNET_memcpy(member_id, unique_id, sizeof(*member_id));
- if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (handle->member_ids, key, member_id,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST))
- {
- GNUNET_free(member_id);
- return GNUNET_SYSERR;
- }
- }
- if (0 == GNUNET_memcmp(unique_id, member_id))
- goto send_message_to_client;
- GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Change a member id (%s) for room (%s).\n", GNUNET_sh2s (member_id),
- GNUNET_h2s (key));
- GNUNET_memcpy(member_id, unique_id, sizeof(*unique_id));
- GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Member id changed to (%s).\n", GNUNET_sh2s (unique_id));
- struct GNUNET_MESSENGER_MemberMessage *msg;
- struct GNUNET_MQ_Envelope *env;
- send_message_to_client:
- env = GNUNET_MQ_msg(msg, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_MEMBER_ID);
- GNUNET_memcpy(&(msg->key), key, sizeof(*key));
- GNUNET_memcpy(&(msg->id), member_id, sizeof(*member_id));
- GNUNET_MQ_send (handle->mq, env);
- return GNUNET_OK;
- }
- static void
- change_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle,
- const char *name)
- {
- GNUNET_assert(handle);
- if (handle->name)
- GNUNET_free(handle->name);
- handle->name = name ? GNUNET_strdup(name) : NULL;
- const uint16_t name_len = handle->name ? strlen (handle->name) : 0;
- struct GNUNET_MESSENGER_NameMessage *msg;
- struct GNUNET_MQ_Envelope *env;
- env = GNUNET_MQ_msg_extra(msg, name_len + 1, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_NAME);
- char *extra = ((char*) msg) + sizeof(*msg);
- if (name_len)
- GNUNET_memcpy(extra, handle->name, name_len);
- extra[name_len] = '\0';
- GNUNET_MQ_send (handle->mq, env);
- }
- static void
- change_handle_ego (struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_MESSENGER_Ego *ego)
- {
- GNUNET_assert(handle);
- handle->ego = ego;
- ego = get_handle_ego (handle);
- const uint16_t length = GNUNET_IDENTITY_key_get_length(&(ego->pub));
- struct GNUNET_MESSENGER_KeyMessage *msg;
- struct GNUNET_MQ_Envelope *env;
- env = GNUNET_MQ_msg_extra(msg, length, GNUNET_MESSAGE_TYPE_MESSENGER_CONNECTION_GET_KEY);
- char *extra = ((char*) msg) + sizeof(*msg);
- if (GNUNET_IDENTITY_write_key_to_buffer(&(ego->pub), extra, length) < 0)
- GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Could not write key to buffer.\n");
- GNUNET_MQ_send (handle->mq, env);
- }
- struct GNUNET_MESSENGER_MessageHandle
- {
- struct GNUNET_MESSENGER_SrvHandle *handle;
- struct GNUNET_MESSENGER_Message *message;
- };
- static int
- iterate_send_message (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
- {
- struct GNUNET_MESSENGER_MessageHandle *msg_handle = cls;
- send_handle_message (msg_handle->handle, key, msg_handle->message);
- return GNUNET_YES;
- }
- void
- set_handle_ego (struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_MESSENGER_Ego *ego)
- {
- GNUNET_assert((handle) && (ego));
- struct GNUNET_MESSENGER_MessageHandle msg_handle;
- msg_handle.handle = handle;
- msg_handle.message = create_message_key (&(ego->priv));
- GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_send_message, &msg_handle);
- destroy_message (msg_handle.message);
- change_handle_ego (handle, ego);
- }
- const struct GNUNET_MESSENGER_Ego*
- get_handle_ego (const struct GNUNET_MESSENGER_SrvHandle *handle)
- {
- GNUNET_assert(handle);
- static struct GNUNET_MESSENGER_Ego anonymous;
- static int read_keys = 0;
- if (handle->ego)
- return handle->ego;
- if (!read_keys)
- {
- struct GNUNET_IDENTITY_Ego *ego = GNUNET_IDENTITY_ego_get_anonymous ();
- GNUNET_memcpy(&(anonymous.priv), GNUNET_IDENTITY_ego_get_private_key (ego), sizeof(anonymous.priv));
- GNUNET_IDENTITY_ego_get_public_key (ego, &(anonymous.pub));
- read_keys = 1;
- }
- return &anonymous;
- }
- static void
- callback_setup_handle_name (void *cls,
- const char *name,
- const struct GNUNET_MESSENGER_Ego *ego)
- {
- struct GNUNET_MESSENGER_SrvHandle *handle = cls;
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Setting up handle...\n");
- change_handle_name (handle, name);
- change_handle_ego (handle, ego);
- if (handle->service->dir)
- load_handle_configuration (handle);
- }
- void
- setup_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle,
- const char *name)
- {
- GNUNET_assert(handle);
- struct GNUNET_MESSENGER_EgoStore *store = get_service_ego_store(handle->service);
- lookup_store_ego (store, name, callback_setup_handle_name, handle);
- }
- static void
- callback_update_handle (void *cls,
- const char *name,
- const struct GNUNET_MESSENGER_Ego *ego)
- {
- struct GNUNET_MESSENGER_SrvHandle *handle = cls;
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Updating handle...\n");
- struct GNUNET_MESSENGER_EgoStore *store = get_service_ego_store(handle->service);
- if (!ego)
- create_store_ego(store, handle->name, handle);
- else
- change_handle_ego (handle, ego);
- }
- void
- update_handle (struct GNUNET_MESSENGER_SrvHandle *handle)
- {
- GNUNET_assert(handle);
- if (!handle->name)
- {
- GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Updating handle failed: Name is required!\n");
- return;
- }
- struct GNUNET_MESSENGER_EgoStore *store = get_service_ego_store(handle->service);
- lookup_store_ego (store, handle->name, callback_update_handle, handle);
- }
- static void
- callback_set_handle_name (void *cls,
- const char *name,
- const struct GNUNET_MESSENGER_Ego *ego)
- {
- struct GNUNET_MESSENGER_SrvHandle *handle = cls;
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Renaming handle...\n");
- if (ego)
- {
- GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Renaming handle failed: Name is occupied! (%s)\n", name);
- return;
- }
- struct GNUNET_MESSENGER_EgoStore *store = get_service_ego_store(handle->service);
- int rename_ego_in_store = handle->ego? GNUNET_YES : GNUNET_NO;
- char *old_dir;
- get_handle_data_subdir (handle, handle->name, &old_dir);
- char *new_dir;
- get_handle_data_subdir (handle, name, &new_dir);
- int result = 0;
- if (GNUNET_YES == GNUNET_DISK_directory_test (old_dir, GNUNET_YES))
- {
- GNUNET_DISK_directory_create_for_file (new_dir);
- result = rename (old_dir, new_dir);
- }
- else if (GNUNET_YES == GNUNET_DISK_directory_test (new_dir, GNUNET_NO))
- result = -1;
- if (0 == result)
- {
- struct GNUNET_MESSENGER_MessageHandle msg_handle;
- msg_handle.handle = handle;
- msg_handle.message = create_message_name (name);
- GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_send_message, &msg_handle);
- destroy_message (msg_handle.message);
- change_handle_name (handle, name);
- }
- else
- rename_ego_in_store = GNUNET_NO;
- GNUNET_free(old_dir);
- GNUNET_free(new_dir);
- if (GNUNET_YES == rename_ego_in_store)
- rename_store_ego(store, handle->name, name);
- }
- void
- set_handle_name (struct GNUNET_MESSENGER_SrvHandle *handle,
- const char *name)
- {
- GNUNET_assert(handle);
- if (!name)
- {
- if (handle->ego)
- GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Renaming handle failed: Name is required!\n");
- else
- change_handle_name (handle, name);
- return;
- }
- struct GNUNET_MESSENGER_EgoStore *store = get_service_ego_store(handle->service);
- lookup_store_ego (store, name, callback_set_handle_name, handle);
- }
- int
- open_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *key)
- {
- GNUNET_assert((handle) && (key));
- if ((!get_handle_member_id (handle, key)) && (GNUNET_YES != create_handle_member_id (handle, key)))
- return GNUNET_NO;
- return open_service_room (handle->service, handle, key);
- }
- int
- entry_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_PeerIdentity *door,
- const struct GNUNET_HashCode *key)
- {
- GNUNET_assert((handle) && (door) && (key));
- if ((!get_handle_member_id (handle, key)) && (GNUNET_YES != create_handle_member_id (handle, key)))
- return GNUNET_NO;
- return entry_service_room (handle->service, handle, door, key);
- }
- int
- close_handle_room (struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *key)
- {
- GNUNET_assert((handle) && (key));
- if (!get_handle_member_id (handle, key))
- return GNUNET_NO;
- return close_service_room (handle->service, handle, key);
- }
- int
- send_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *key,
- const struct GNUNET_MESSENGER_Message *message)
- {
- GNUNET_assert((handle) && (key) && (message));
- const struct GNUNET_ShortHashCode *id = get_handle_member_id (handle, key);
- if (!id)
- {
- GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "It is required to be a member of a room to send messages!\n");
- return GNUNET_NO;
- }
- struct GNUNET_MESSENGER_SrvRoom *room = get_service_room (handle->service, key);
- if (!room)
- {
- GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "The room (%s) is unknown!\n", GNUNET_h2s (key));
- return GNUNET_NO;
- }
- struct GNUNET_MESSENGER_Message *msg = copy_message(message);
- GNUNET_memcpy(&(msg->header.sender_id), id, sizeof(*id));
- return send_room_message (room, handle, msg);
- }
- static const struct GNUNET_HashCode*
- get_next_member_session_contect(const struct GNUNET_MESSENGER_MemberSession *session)
- {
- if (session->next)
- return get_next_member_session_contect (session->next);
- else
- return get_member_session_context(session);
- }
- static const struct GNUNET_MESSENGER_MemberSession*
- get_handle_member_session (struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *key)
- {
- GNUNET_assert((handle) && (key) && (handle->service));
- const struct GNUNET_ShortHashCode *id = get_handle_member_id(handle, key);
- struct GNUNET_MESSENGER_SrvRoom *room = get_service_room(handle->service, key);
- if ((!id) || (!room))
- return NULL;
- struct GNUNET_MESSENGER_MemberStore *store = get_room_member_store(room);
- struct GNUNET_MESSENGER_Member *member = get_store_member(store, id);
- const struct GNUNET_MESSENGER_Ego *ego = get_handle_ego(handle);
- if (!ego)
- return NULL;
- return get_member_session(member, &(ego->pub));
- }
- void
- notify_handle_message (struct GNUNET_MESSENGER_SrvHandle *handle,
- const struct GNUNET_HashCode *key,
- const struct GNUNET_MESSENGER_MemberSession *session,
- const struct GNUNET_MESSENGER_Message *message,
- const struct GNUNET_HashCode *hash)
- {
- GNUNET_assert((handle) && (key) && (session) && (message) && (hash));
- if ((!handle->mq) || (!get_handle_member_id (handle, key)))
- {
- GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Notifying client about message requires membership!\n");
- return;
- }
- const struct GNUNET_IDENTITY_PublicKey *pubkey = get_contact_key(session->contact);
- struct GNUNET_HashCode sender;
- GNUNET_CRYPTO_hash(pubkey, sizeof(*pubkey), &sender);
- const struct GNUNET_HashCode *context = get_next_member_session_contect (session);
- GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Notifying client about message: %s\n", GNUNET_h2s (hash));
- struct GNUNET_MESSENGER_Message *private_message = NULL;
- if (GNUNET_MESSENGER_KIND_PRIVATE == message->header.kind)
- {
- private_message = copy_message(message);
- if (GNUNET_YES != decrypt_message(private_message, &(get_handle_ego(handle)->priv)))
- {
- destroy_message(private_message);
- private_message = NULL;
- }
- else
- message = private_message;
- }
- struct GNUNET_MESSENGER_RecvMessage *msg;
- struct GNUNET_MQ_Envelope *env;
- uint16_t length = get_message_size (message, GNUNET_YES);
- env = GNUNET_MQ_msg_extra(msg, length, GNUNET_MESSAGE_TYPE_MESSENGER_ROOM_RECV_MESSAGE);
- GNUNET_memcpy(&(msg->key), key, sizeof(msg->key));
- GNUNET_memcpy(&(msg->sender), &sender, sizeof(msg->sender));
- GNUNET_memcpy(&(msg->context), context, sizeof(msg->context));
- GNUNET_memcpy(&(msg->hash), hash, sizeof(msg->hash));
- msg->flags = (uint32_t) GNUNET_MESSENGER_FLAG_NONE;
- if (get_handle_member_session(handle, key) == session)
- msg->flags |= (uint32_t) GNUNET_MESSENGER_FLAG_SENT;
- if (private_message)
- msg->flags |= (uint32_t) GNUNET_MESSENGER_FLAG_PRIVATE;
- char *buffer = ((char*) msg) + sizeof(*msg);
- encode_message (message, length, buffer, GNUNET_YES);
- if (private_message)
- destroy_message(private_message);
- GNUNET_MQ_send (handle->mq, env);
- }
- static int
- callback_scan_for_rooms (void *cls,
- const char *filename)
- {
- struct GNUNET_MESSENGER_SrvHandle *handle = cls;
- struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
- if ((GNUNET_YES == GNUNET_DISK_file_test (filename)) && (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, filename)))
- {
- struct GNUNET_HashCode key;
- struct GNUNET_ShortHashCode member_id;
- if ((GNUNET_OK == GNUNET_CONFIGURATION_get_data (cfg, "room", "key", &key, sizeof(key))) &&
- (GNUNET_OK == GNUNET_CONFIGURATION_get_data (cfg, "room", "member_id", &member_id, sizeof(member_id))))
- change_handle_member_id (handle, &key, &member_id);
- }
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_OK;
- }
- void
- load_handle_configuration (struct GNUNET_MESSENGER_SrvHandle *handle)
- {
- GNUNET_assert(handle);
- char *id_dir;
- get_handle_data_subdir (handle, handle->name, &id_dir);
- if (GNUNET_YES == GNUNET_DISK_directory_test (id_dir, GNUNET_YES))
- {
- char *scan_dir;
- GNUNET_asprintf (&scan_dir, "%s%s%c", id_dir, "rooms", DIR_SEPARATOR);
- if (GNUNET_OK == GNUNET_DISK_directory_test (scan_dir, GNUNET_YES))
- GNUNET_DISK_directory_scan (scan_dir, callback_scan_for_rooms, handle);
- GNUNET_free(scan_dir);
- }
- GNUNET_free(id_dir);
- }
- static int
- iterate_save_rooms (void *cls,
- const struct GNUNET_HashCode *key,
- void *value)
- {
- struct GNUNET_MESSENGER_SrvHandle *handle = cls;
- struct GNUNET_ShortHashCode *member_id = value;
- char *id_dir;
- get_handle_data_subdir (handle, handle->name, &id_dir);
- char *filename;
- GNUNET_asprintf (&filename, "%s%s%c%s.cfg", id_dir, "rooms", DIR_SEPARATOR, GNUNET_h2s (key));
- GNUNET_free(id_dir);
- struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
- char *key_data = GNUNET_STRINGS_data_to_string_alloc (key, sizeof(*key));
- if (key_data)
- {
- GNUNET_CONFIGURATION_set_value_string (cfg, "room", "key", key_data);
- GNUNET_free(key_data);
- }
- char *member_id_data = GNUNET_STRINGS_data_to_string_alloc (member_id, sizeof(*member_id));
- if (member_id_data)
- {
- GNUNET_CONFIGURATION_set_value_string (cfg, "room", "member_id", member_id_data);
- GNUNET_free(member_id_data);
- }
- GNUNET_CONFIGURATION_write (cfg, filename);
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free(filename);
- return GNUNET_YES;
- }
- void
- save_handle_configuration (struct GNUNET_MESSENGER_SrvHandle *handle)
- {
- GNUNET_assert(handle);
- char *id_dir;
- get_handle_data_subdir (handle, handle->name, &id_dir);
- if ((GNUNET_YES == GNUNET_DISK_directory_test (id_dir, GNUNET_NO)) || (GNUNET_OK
- == GNUNET_DISK_directory_create (id_dir)))
- {
- char *save_dir;
- GNUNET_asprintf (&save_dir, "%s%s%c", id_dir, "rooms", DIR_SEPARATOR);
- if ((GNUNET_YES == GNUNET_DISK_directory_test (save_dir, GNUNET_NO)) ||
- (GNUNET_OK == GNUNET_DISK_directory_create (save_dir)))
- GNUNET_CONTAINER_multihashmap_iterate (handle->member_ids, iterate_save_rooms, handle);
- GNUNET_free(save_dir);
- }
- GNUNET_free(id_dir);
- }
|