X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fsocial%2Fsocial_api.c;h=89843831be02164972b6c04c6877066d88156391;hb=0120859e1ea2f0591602f446d4bc054e9230c801;hp=4aed3755e33d747c2f794ad3231a7abf73762290;hpb=cab1b047ddcac497e14515fc11f097c4aac8ee27;p=oweals%2Fgnunet.git diff --git a/src/social/social_api.c b/src/social/social_api.c index 4aed3755e..89843831b 100644 --- a/src/social/social_api.c +++ b/src/social/social_api.c @@ -1,6 +1,6 @@ - /* +/* * This file is part of GNUnet - * Copyright (C) 2013 Christian Grothoff (and other contributing authors) + * Copyright (C) 2013 GNUnet e.V. * * GNUnet is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published @@ -19,9 +19,10 @@ */ /** - * @file social/social_api.c - * @brief Social service; implements social interactions using the PSYC service. * @author Gabor X Toth + * + * @file + * Social service; implements social interactions using the PSYC service. */ #include @@ -29,11 +30,6 @@ #include "platform.h" #include "gnunet_util_lib.h" -#include "gnunet_env_lib.h" -#include "gnunet_core_service.h" -#include "gnunet_identity_service.h" -#include "gnunet_namestore_service.h" -#include "gnunet_gns_service.h" #include "gnunet_psyc_service.h" #include "gnunet_psyc_util_lib.h" #include "gnunet_social_service.h" @@ -41,11 +37,15 @@ #define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__) - -static struct GNUNET_CORE_Handle *core; -static struct GNUNET_GNS_Handle *gns; -static struct GNUNET_NAMESTORE_Handle *namestore; -static struct GNUNET_PeerIdentity this_peer; +/** + * Handle for an ego. + */ +struct GNUNET_SOCIAL_Ego +{ + struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; + struct GNUNET_HashCode pub_key_hash; + char *name; +}; /** @@ -59,9 +59,9 @@ struct GNUNET_SOCIAL_Nym /** - * Handle for a place where social interactions happen. + * Handle for an application. */ -struct GNUNET_SOCIAL_Place +struct GNUNET_SOCIAL_App { /** * Configuration to use. @@ -71,27 +71,27 @@ struct GNUNET_SOCIAL_Place /** * Client connection to the service. */ - struct GNUNET_CLIENT_MANAGER_Connection *client; + struct GNUNET_MQ_Handle *mq; /** - * Transmission handle. + * Message to send on connect. */ - struct GNUNET_PSYC_TransmitHandle *tmit; + struct GNUNET_MQ_Envelope *connect_env; /** - * Receipt handle. + * Time to wait until we try to reconnect on failure. */ - struct GNUNET_PSYC_ReceiveHandle *recv; + struct GNUNET_TIME_Relative reconnect_delay; /** - * Slicer for processing incoming methods. + * Task for reconnecting when the listener fails. */ - struct GNUNET_SOCIAL_Slicer *slicer; + struct GNUNET_SCHEDULER_Task *reconnect_task; /** - * Message to send on reconnect. + * Async operations. */ - struct GNUNET_MessageHeader *connect_msg; + struct GNUNET_OP_Handle *op; /** * Function called after disconnected from the service. @@ -104,210 +104,164 @@ struct GNUNET_SOCIAL_Place void *disconnect_cls; /** - * Public key of the place. - */ - struct GNUNET_CRYPTO_EddsaPublicKey pub_key; - - /** - * Private key of the ego. + * Application ID. */ - struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key; + char *id; /** - * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)? + * Hash map of all egos. + * pub_key_hash -> struct GNUNET_SOCIAL_Ego * */ - uint8_t is_host; + struct GNUNET_CONTAINER_MultiHashMap *egos; - /** - * Is this place in the process of disconnecting from the service? - * #GNUNET_YES or #GNUNET_NO - */ - uint8_t is_disconnecting; + GNUNET_SOCIAL_AppEgoCallback ego_cb; + GNUNET_SOCIAL_AppHostPlaceCallback host_cb; + GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb; + GNUNET_SOCIAL_AppConnectedCallback connected_cb; + void *cb_cls; }; -/** - * Host handle for a place that we entered. - */ -struct GNUNET_SOCIAL_Host +struct GNUNET_SOCIAL_HostConnection { - struct GNUNET_SOCIAL_Place plc; - - struct GNUNET_CRYPTO_EddsaPrivateKey place_key; - - /** - * Receipt handle. - */ - struct GNUNET_PSYC_ReceiveHandle *recv; - - /** - * Slicer for processing incoming methods. - */ - struct GNUNET_SOCIAL_Slicer *slicer; - - GNUNET_SOCIAL_HostEnterCallback enter_cb; + struct GNUNET_SOCIAL_App *app; - GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb; + struct AppPlaceMessage plc_msg; +}; - GNUNET_SOCIAL_FarewellCallback farewell_cb; - /** - * Closure for callbacks. - */ - void *cb_cls; +struct GNUNET_SOCIAL_GuestConnection +{ + struct GNUNET_SOCIAL_App *app; - struct GNUNET_SOCIAL_Nym *notice_place_leave_nym; - struct GNUNET_ENV_Environment *notice_place_leave_env; + struct AppPlaceMessage plc_msg; }; /** - * Guest handle for place that we entered. + * Handle for a place where social interactions happen. */ -struct GNUNET_SOCIAL_Guest +struct GNUNET_SOCIAL_Place { - struct GNUNET_SOCIAL_Place plc; - /** - * Receipt handle. + * Configuration to use. */ - struct GNUNET_PSYC_ReceiveHandle *recv; + const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Slicer for processing incoming methods. + * Client connection to the service. */ - struct GNUNET_SOCIAL_Slicer *slicer; - - GNUNET_SOCIAL_GuestEnterCallback enter_cb; - - GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb; + struct GNUNET_MQ_Handle *mq; /** - * Closure for callbacks. + * Message to send on connect. */ - void *cb_cls; -}; - - -/** - * Hash map of all nyms. - * pub_key_hash -> struct GNUNET_SOCIAL_Nym * - */ -struct GNUNET_CONTAINER_MultiHashMap *nyms; + struct GNUNET_MQ_Envelope *connect_env; - -/** - * Handle for a try-and-slice instance. - */ -struct GNUNET_SOCIAL_Slicer -{ /** - * Method handlers: method_name -> SlicerMethodCallbacks + * Time to wait until we try to reconnect on failure. */ - struct GNUNET_CONTAINER_MultiHashMap *method_handlers; + struct GNUNET_TIME_Relative reconnect_delay; /** - * Modifier handlers: modifier name -> SlicerModifierCallbacks + * Task for reconnecting when the listener fails. */ - struct GNUNET_CONTAINER_MultiHashMap *modifier_handlers; + struct GNUNET_SCHEDULER_Task *reconnect_task; /** - * Currently being processed message part. + * Async operations. */ - const struct GNUNET_MessageHeader *msg; + struct GNUNET_OP_Handle *op; /** - * ID of currently being received message. + * Transmission handle. */ - uint64_t message_id; + struct GNUNET_PSYC_TransmitHandle *tmit; /** - * Method name of currently being received message. + * Slicer for processing incoming messages. */ - char *method_name; + struct GNUNET_PSYC_Slicer *slicer; + // FIXME: do we need is_disconnecing like on the psyc and multicast APIs? /** - * Name of currently processed modifier. + * Function called after disconnected from the service. */ - char *mod_name; + GNUNET_ContinuationCallback disconnect_cb; /** - * Value of currently processed modifier. + * Closure for @a disconnect_cb. */ - char *mod_value; + void *disconnect_cls; /** - * Public key of the nym the current message originates from. + * Public key of the place. */ - struct GNUNET_CRYPTO_EcdsaPublicKey nym_key; + struct GNUNET_CRYPTO_EddsaPublicKey pub_key; /** - * Size of @a method_name (including terminating \0). + * Public key of the ego. */ - uint16_t method_name_size; + struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; /** - * Size of @a modifier_name (including terminating \0). + * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)? */ - uint16_t mod_name_size; + uint8_t is_host; +}; - /** - * Size of modifier value fragment. - */ - uint16_t mod_value_size; - /** - * Full size of modifier value. - */ - uint16_t mod_full_value_size; +/** + * Host handle for a place that we entered. + */ +struct GNUNET_SOCIAL_Host +{ + struct GNUNET_SOCIAL_Place plc; /** - * Remaining bytes from the value of the current modifier. + * Slicer for processing incoming messages from guests. */ - uint16_t mod_value_remaining; + struct GNUNET_PSYC_Slicer *slicer; + + GNUNET_SOCIAL_HostEnterCallback enter_cb; + + GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb; + + GNUNET_SOCIAL_FarewellCallback farewell_cb; /** - * Operator of currently processed modifier. + * Closure for callbacks. */ - uint8_t mod_oper; + void *cb_cls; + + struct GNUNET_SOCIAL_Nym *notice_place_leave_nym; + struct GNUNET_PSYC_Environment *notice_place_leave_env; }; /** - * Callbacks for a slicer method handler. + * Guest handle for place that we entered. */ -struct SlicerMethodCallbacks +struct GNUNET_SOCIAL_Guest { - GNUNET_SOCIAL_MethodCallback method_cb; - GNUNET_SOCIAL_ModifierCallback modifier_cb; - GNUNET_SOCIAL_DataCallback data_cb; - GNUNET_SOCIAL_EndOfMessageCallback eom_cb; - void *cls; -}; + struct GNUNET_SOCIAL_Place plc; + GNUNET_SOCIAL_GuestEnterCallback enter_cb; -struct SlicerMethodRemoveClosure -{ - struct GNUNET_SOCIAL_Slicer *slicer; - struct SlicerMethodCallbacks rm_cbs; + GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb; + + /** + * Closure for callbacks. + */ + void *cb_cls; }; /** - * Callbacks for a slicer method handler. + * Hash map of all nyms. + * pub_key_hash -> struct GNUNET_SOCIAL_Nym * */ -struct SlicerModifierCallbacks -{ - GNUNET_SOCIAL_ModifierCallback modifier_cb; - void *cls; -}; - - -struct SlicerModifierRemoveClosure -{ - struct GNUNET_SOCIAL_Slicer *slicer; - struct SlicerModifierCallbacks rm_cbs; -}; +struct GNUNET_CONTAINER_MultiHashMap *nyms; /** @@ -344,9 +298,9 @@ struct GNUNET_SOCIAL_HistoryRequest uint64_t op_id; /** - * Message handler. + * Slicer for processing incoming messages. */ - struct GNUNET_PSYC_ReceiveHandle *recv; + struct GNUNET_PSYC_Slicer *slicer; /** * Function to call when the operation finished. @@ -404,6 +358,82 @@ struct GNUNET_SOCIAL_LookHandle }; +struct ZoneAddPlaceHandle +{ + GNUNET_ResultCallback result_cb; + void *result_cls; +}; + + +struct ZoneAddNymHandle +{ + GNUNET_ResultCallback result_cb; + void *result_cls; +}; + + +/*** CLEANUP / DISCONNECT ***/ + + +static void +host_cleanup (struct GNUNET_SOCIAL_Host *hst) +{ + if (NULL != hst->slicer) + { + GNUNET_PSYC_slicer_destroy (hst->slicer); + hst->slicer = NULL; + } + GNUNET_free (hst); +} + + +static void +guest_cleanup (struct GNUNET_SOCIAL_Guest *gst) +{ + GNUNET_free (gst); +} + + +static void +place_cleanup (struct GNUNET_SOCIAL_Place *plc) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "cleaning up place %p\n", + plc); + if (NULL != plc->tmit) + { + GNUNET_PSYC_transmit_destroy (plc->tmit); + plc->tmit = NULL; + } + if (NULL != plc->connect_env) + { + GNUNET_MQ_discard (plc->connect_env); + plc->connect_env = NULL; + } + if (NULL != plc->mq) + { + GNUNET_MQ_destroy (plc->mq); + plc->mq = NULL; + } + if (NULL != plc->disconnect_cb) + { + plc->disconnect_cb (plc->disconnect_cls); + plc->disconnect_cb = NULL; + } + + (GNUNET_YES == plc->is_host) + ? host_cleanup ((struct GNUNET_SOCIAL_Host *) plc) + : guest_cleanup ((struct GNUNET_SOCIAL_Guest *) plc); +} + + +static void +place_disconnect (struct GNUNET_SOCIAL_Place *plc) +{ + place_cleanup (plc); +} + + /*** NYM ***/ static struct GNUNET_SOCIAL_Nym * @@ -448,36 +478,40 @@ nym_destroy (struct GNUNET_SOCIAL_Nym *nym) static void host_recv_notice_place_leave_method (void *cls, + const struct GNUNET_PSYC_MessageHeader *msg, const struct GNUNET_PSYC_MessageMethod *meth, uint64_t message_id, - uint32_t flags, - const struct GNUNET_SOCIAL_Nym *nym, const char *method_name) { struct GNUNET_SOCIAL_Host *hst = cls; + if (0 == memcmp (&(struct GNUNET_CRYPTO_EcdsaPublicKey) {}, - &nym->pub_key, sizeof (nym->pub_key))) + &msg->slave_pub_key, sizeof (msg->slave_pub_key))) return; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&msg->slave_pub_key); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Host received method for message ID %" PRIu64 " from nym %s: %s\n", message_id, GNUNET_h2s (&nym->pub_key_hash), method_name); hst->notice_place_leave_nym = (struct GNUNET_SOCIAL_Nym *) nym; - hst->notice_place_leave_env = GNUNET_ENV_environment_create (); + hst->notice_place_leave_env = GNUNET_PSYC_env_create (); char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "_notice_place_leave: got method from nym %s (%s).\n", GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str); + GNUNET_free (str); } static void host_recv_notice_place_leave_modifier (void *cls, - const struct GNUNET_MessageHeader *msg, + const struct GNUNET_PSYC_MessageHeader *msg, + const struct GNUNET_MessageHeader *pmsg, uint64_t message_id, - enum GNUNET_ENV_Operator oper, + enum GNUNET_PSYC_Operator oper, const char *name, const void *value, uint16_t value_size, @@ -487,586 +521,134 @@ host_recv_notice_place_leave_modifier (void *cls, if (NULL == hst->notice_place_leave_env) return; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Host received modifier for _notice_place_leave message with ID %" PRIu64 ":\n" "%c%s: %.*s\n", - message_id, oper, name, value_size, value); + message_id, oper, name, value_size, (const char *) value); /* skip _nym, it's added later in eom() */ if (0 == memcmp (name, "_nym", sizeof ("_nym")) || 0 == memcmp (name, "_nym_", sizeof ("_nym_") - 1)) return; - GNUNET_ENV_environment_add (hst->notice_place_leave_env, - GNUNET_ENV_OP_SET, name, value, value_size); + GNUNET_PSYC_env_add (hst->notice_place_leave_env, + GNUNET_PSYC_OP_SET, name, value, value_size); } static void host_recv_notice_place_leave_eom (void *cls, - const struct GNUNET_MessageHeader *msg, + const struct GNUNET_PSYC_MessageHeader *msg, + const struct GNUNET_MessageHeader *pmsg, uint64_t message_id, - uint8_t cancelled) + uint8_t is_cancelled) { struct GNUNET_SOCIAL_Host *hst = cls; if (NULL == hst->notice_place_leave_env) return; char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "_notice_place_leave: got EOM from nym %s (%s).\n", GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str); + GNUNET_free (str); - if (GNUNET_YES != cancelled) + if (GNUNET_YES != is_cancelled) { if (NULL != hst->farewell_cb) hst->farewell_cb (hst->cb_cls, hst->notice_place_leave_nym, hst->notice_place_leave_env); /* announce leaving guest to place */ - GNUNET_ENV_environment_add (hst->notice_place_leave_env, GNUNET_ENV_OP_SET, - "_nym", hst->notice_place_leave_nym, - sizeof (*hst->notice_place_leave_nym)); + GNUNET_PSYC_env_add (hst->notice_place_leave_env, GNUNET_PSYC_OP_SET, + "_nym", hst->notice_place_leave_nym, + sizeof (*hst->notice_place_leave_nym)); GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", hst->notice_place_leave_env, NULL, NULL, GNUNET_SOCIAL_ANNOUNCE_NONE); nym_destroy (hst->notice_place_leave_nym); } - GNUNET_ENV_environment_destroy (hst->notice_place_leave_env); + GNUNET_PSYC_env_destroy (hst->notice_place_leave_env); hst->notice_place_leave_env = NULL; } -/*** SLICER ***/ +/*** PLACE ***/ -/** - * Call a method handler for an incoming message part. - */ -int -slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key, - void *value) -{ - struct GNUNET_SOCIAL_Slicer *slicer = cls; - const struct GNUNET_MessageHeader *msg = slicer->msg; - struct SlicerMethodCallbacks *cbs = value; - uint16_t ptype = ntohs (msg->type); - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: - { - if (NULL == cbs->method_cb) - break; - struct GNUNET_PSYC_MessageMethod * - meth = (struct GNUNET_PSYC_MessageMethod *) msg; - cbs->method_cb (cbs->cls, meth, slicer->message_id, - ntohl (meth->flags), - nym_get_or_create (&slicer->nym_key), - slicer->method_name); - break; +static int +check_place_result (void *cls, + const struct GNUNET_OperationResultMessage *res) +{ + uint16_t size = ntohs (res->header.size); + if (size < sizeof (*res)) + { /* Error, message too small. */ + GNUNET_break (0); + return GNUNET_SYSERR; } + return GNUNET_OK; +} - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - if (NULL == cbs->modifier_cb) - break; - struct GNUNET_PSYC_MessageModifier * - mod = (struct GNUNET_PSYC_MessageModifier *) msg; - cbs->modifier_cb (cbs->cls, &mod->header, slicer->message_id, - mod->oper, (const char *) &mod[1], - (const void *) &mod[1] + ntohs (mod->name_size), - ntohs (mod->header.size) - sizeof (*mod) - ntohs (mod->name_size), - ntohs (mod->value_size)); - break; - } - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - { - if (NULL == cbs->modifier_cb) - break; - cbs->modifier_cb (cbs->cls, msg, slicer->message_id, - slicer->mod_oper, slicer->mod_name, &msg[1], - ntohs (msg->size) - sizeof (*msg), - slicer->mod_full_value_size); - break; - } +static void +handle_place_result (void *cls, + const struct GNUNET_OperationResultMessage *res) +{ + struct GNUNET_SOCIAL_Place *plc = cls; - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: - { - if (NULL == cbs->data_cb) - break; - uint64_t data_offset = 0; // FIXME - cbs->data_cb (cbs->cls, msg, slicer->message_id, - data_offset, &msg[1], ntohs (msg->size) - sizeof (*msg)); - break; - } + uint16_t size = ntohs (res->header.size); + uint16_t data_size = size - sizeof (*res); + const char *data = (0 < data_size) ? (const char *) &res[1] : NULL; - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: - if (NULL == cbs->eom_cb) - break; - cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_NO); - break; + GNUNET_OP_result (plc->op, GNUNET_ntohll (res->op_id), + GNUNET_ntohll (res->result_code), + data, data_size, NULL); +} - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: - if (NULL == cbs->eom_cb) - break; - cbs->eom_cb (cbs->cls, msg, slicer->message_id, GNUNET_YES); - break; + +static int +check_app_result (void *cls, + const struct GNUNET_OperationResultMessage *res) +{ + uint16_t size = ntohs (res->header.size); + if (size < sizeof (*res)) + { /* Error, message too small. */ + GNUNET_break (0); + return GNUNET_SYSERR; } - return GNUNET_YES; + return GNUNET_OK; } -/** - * Call a method handler for an incoming message part. - */ -int -slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key, - void *value) +static void +handle_app_result (void *cls, + const struct GNUNET_OperationResultMessage *res) { - struct GNUNET_SOCIAL_Slicer *slicer = cls; - struct SlicerModifierCallbacks *cbs = value; + struct GNUNET_SOCIAL_App *app = cls; - cbs->modifier_cb (cbs->cls, slicer->msg, slicer->message_id, slicer->mod_oper, - slicer->mod_name, slicer->mod_value, - slicer->mod_value_size, slicer->mod_full_value_size); - return GNUNET_YES; + uint16_t size = ntohs (res->header.size); + uint16_t data_size = size - sizeof (*res); + const char *data = (0 < data_size) ? (const char *) &res[1] : NULL; + + GNUNET_OP_result (app->op, GNUNET_ntohll (res->op_id), + GNUNET_ntohll (res->result_code), + data, data_size, NULL); } -/** - * Process an incoming message part and call matching handlers. - * - * @param cls - * Closure. - * @param message_id - * ID of the message. - * @param flags - * Flags for the message. - * @see enum GNUNET_PSYC_MessageFlags - * @param msg - * The message part. as it arrived from the network. - */ static void -slicer_message (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, - uint64_t message_id, uint32_t flags, uint64_t fragment_offset, - const struct GNUNET_MessageHeader *msg) +op_recv_history_result (void *cls, int64_t result, + const void *err_msg, uint16_t err_msg_size) { - struct GNUNET_SOCIAL_Slicer *slicer = cls; - slicer->nym_key = *slave_key; + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received history replay result: %" PRId64 ".\n", result); - uint16_t ptype = ntohs (msg->type); - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype) - { - struct GNUNET_PSYC_MessageMethod * - meth = (struct GNUNET_PSYC_MessageMethod *) msg; - slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth); - slicer->method_name = GNUNET_malloc (slicer->method_name_size); - memcpy (slicer->method_name, &meth[1], slicer->method_name_size); - slicer->message_id = message_id; - } - else - { - GNUNET_assert (message_id == slicer->message_id); - } + struct GNUNET_SOCIAL_HistoryRequest *hist = cls; - char *nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (slave_key); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Slicer received message of type %u and size %u, " - "with ID %" PRIu64 " and method %s from %s\n", - ptype, ntohs (msg->size), message_id, slicer->method_name, nym_str); - GNUNET_free (nym_str); + if (NULL != hist->result_cb) + hist->result_cb (hist->cls, result, err_msg, err_msg_size); - slicer->msg = msg; - - /* try-and-slice modifier */ - - switch (ptype) - { - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: - { - struct GNUNET_PSYC_MessageModifier * - mod = (struct GNUNET_PSYC_MessageModifier *) msg; - slicer->mod_oper = mod->oper; - slicer->mod_name_size = ntohs (mod->name_size); - slicer->mod_name = GNUNET_malloc (slicer->mod_name_size); - memcpy (slicer->mod_name, &mod[1], slicer->mod_name_size); - slicer->mod_value = (char *) &mod[1] + slicer->mod_name_size; - slicer->mod_full_value_size = ntohs (mod->value_size); - slicer->mod_value_remaining = slicer->mod_full_value_size; - slicer->mod_value_size - = ntohs (mod->header.size) - sizeof (*mod) - slicer->mod_name_size; - } - case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: - if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT) - { - slicer->mod_value = (char *) &msg[1]; - slicer->mod_value_size = ntohs (msg->size) - sizeof (*msg); - } - slicer->mod_value_remaining -= slicer->mod_value_size; - char *name = GNUNET_malloc (slicer->mod_name_size); - memcpy (name, slicer->mod_name, slicer->mod_name_size); - do - { - struct GNUNET_HashCode key; - uint16_t name_len = strlen (name); - GNUNET_CRYPTO_hash (name, name_len, &key); - GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key, - slicer_modifier_handler_notify, - slicer); - char *p = strrchr (name, '_'); - if (NULL == p) - break; - *p = '\0'; - } while (1); - GNUNET_free (name); - } - - /* try-and-slice method */ - - char *name = GNUNET_malloc (slicer->method_name_size); - memcpy (name, slicer->method_name, slicer->method_name_size); - do - { - struct GNUNET_HashCode key; - uint16_t name_len = strlen (name); - GNUNET_CRYPTO_hash (name, name_len, &key); - GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key, - slicer_method_handler_notify, - slicer); - char *p = strrchr (name, '_'); - if (NULL == p) - break; - *p = '\0'; - } while (1); - GNUNET_free (name); - - if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype) - GNUNET_free (slicer->method_name); - - if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name) - { - GNUNET_free (slicer->mod_name); - slicer->mod_name = NULL; - slicer->mod_name_size = 0; - slicer->mod_value_size = 0; - slicer->mod_full_value_size = 0; - slicer->mod_oper = 0; - } - - slicer->msg = NULL; -} - - -/** - * Create a try-and-slice instance. - * - * A slicer processes incoming messages and notifies callbacks about matching - * methods or modifiers encountered. - * - * @return A new try-and-slice construct. - */ -struct GNUNET_SOCIAL_Slicer * -GNUNET_SOCIAL_slicer_create (void) -{ - struct GNUNET_SOCIAL_Slicer *slicer = GNUNET_malloc (sizeof (*slicer)); - slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); - return slicer; -} - - -/** - * Add a method to the try-and-slice instance. - * - * The callbacks are called for messages with a matching @a method_name prefix. - * - * @param slicer - * The try-and-slice instance to extend. - * @param method_name - * Name of the given method, use empty string to match all. - * @param method_cb - * Method handler invoked upon a matching message. - * @param modifier_cb - * Modifier handler, invoked after @a method_cb - * for each modifier in the message. - * @param data_cb - * Data handler, invoked after @a modifier_cb for each data fragment. - * @param eom_cb - * Invoked upon reaching the end of a matching message. - * @param cls - * Closure for the callbacks. - */ -void -GNUNET_SOCIAL_slicer_method_add (struct GNUNET_SOCIAL_Slicer *slicer, - const char *method_name, - GNUNET_SOCIAL_MethodCallback method_cb, - GNUNET_SOCIAL_ModifierCallback modifier_cb, - GNUNET_SOCIAL_DataCallback data_cb, - GNUNET_SOCIAL_EndOfMessageCallback eom_cb, - void *cls) -{ - struct GNUNET_HashCode key; - GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key); - - struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs)); - cbs->method_cb = method_cb; - cbs->modifier_cb = modifier_cb; - cbs->data_cb = data_cb; - cbs->eom_cb = eom_cb; - cbs->cls = cls; - - GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); -} - - -int -slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - struct SlicerMethodRemoveClosure *rm_cls = cls; - struct GNUNET_SOCIAL_Slicer *slicer = rm_cls->slicer; - struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs; - struct SlicerMethodCallbacks *cbs = value; - - if (cbs->method_cb == rm_cbs->method_cb - && cbs->modifier_cb == rm_cbs->modifier_cb - && cbs->data_cb == rm_cbs->data_cb - && cbs->eom_cb == rm_cbs->eom_cb) - { - GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs); - GNUNET_free (cbs); - return GNUNET_NO; - } - return GNUNET_YES; -} - - -/** - * Remove a registered method from the try-and-slice instance. - * - * Removes one matching handler registered with the given - * @a method_name and callbacks. - * - * @param slicer - * The try-and-slice instance. - * @param method_name - * Name of the method to remove. - * @param method_cb - * Method handler. - * @param modifier_cb - * Modifier handler. - * @param data_cb - * Data handler. - * @param eom_cb - * End of message handler. - * - * @return #GNUNET_OK if a method handler was removed, - * #GNUNET_NO if no handler matched the given method name and callbacks. - */ -int -GNUNET_SOCIAL_slicer_method_remove (struct GNUNET_SOCIAL_Slicer *slicer, - const char *method_name, - GNUNET_SOCIAL_MethodCallback method_cb, - GNUNET_SOCIAL_ModifierCallback modifier_cb, - GNUNET_SOCIAL_DataCallback data_cb, - GNUNET_SOCIAL_EndOfMessageCallback eom_cb) -{ - struct GNUNET_HashCode key; - GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key); - - struct SlicerMethodRemoveClosure rm_cls; - rm_cls.slicer = slicer; - struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs; - rm_cbs->method_cb = method_cb; - rm_cbs->modifier_cb = modifier_cb; - rm_cbs->data_cb = data_cb; - rm_cbs->eom_cb = eom_cb; - - return - (GNUNET_SYSERR - == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key, - slicer_method_remove, - &rm_cls)) - ? GNUNET_NO - : GNUNET_OK; -} - - -/** - * Watch a place for changed objects. - * - * @param slicer - * The try-and-slice instance. - * @param object_filter - * Object prefix to match. - * @param modifier_cb - * Function to call when encountering a state modifier. - * @param cls - * Closure for callback. - */ -void -GNUNET_SOCIAL_slicer_modifier_add (struct GNUNET_SOCIAL_Slicer *slicer, - const char *object_filter, - GNUNET_SOCIAL_ModifierCallback modifier_cb, - void *cls) -{ - struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs); - cbs->modifier_cb = modifier_cb; - cbs->cls = cls; - - struct GNUNET_HashCode key; - GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key); - GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); -} - - -int -slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - struct SlicerModifierRemoveClosure *rm_cls = cls; - struct GNUNET_SOCIAL_Slicer *slicer = rm_cls->slicer; - struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs; - struct SlicerModifierCallbacks *cbs = value; - - if (cbs->modifier_cb == rm_cbs->modifier_cb) - { - GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs); - GNUNET_free (cbs); - return GNUNET_NO; - } - return GNUNET_YES; -} - - -/** - * Remove a registered modifier from the try-and-slice instance. - * - * Removes one matching handler registered with the given - * @a object_filter and @a modifier_cb. - * - * @param slicer - * The try-and-slice instance. - * @param object_filter - * Object prefix to match. - * @param modifier_cb - * Function to call when encountering a state modifier changes. - */ -int -GNUNET_SOCIAL_slicer_modifier_remove (struct GNUNET_SOCIAL_Slicer *slicer, - const char *object_filter, - GNUNET_SOCIAL_ModifierCallback modifier_cb) -{ - struct GNUNET_HashCode key; - GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key); - - struct SlicerModifierRemoveClosure rm_cls; - rm_cls.slicer = slicer; - struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs; - rm_cbs->modifier_cb = modifier_cb; - - return - (GNUNET_SYSERR - == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key, - slicer_modifier_remove, - &rm_cls)) - ? GNUNET_NO - : GNUNET_OK; - } - - -int -slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value) -{ - struct SlicerMethodCallbacks *cbs = value; - GNUNET_free (cbs); - return GNUNET_YES; -} - - -/** - * Destroy a given try-and-slice instance. - * - * @param slicer - * Slicer to destroy - */ -void -GNUNET_SOCIAL_slicer_destroy (struct GNUNET_SOCIAL_Slicer *slicer) -{ - GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers, - slicer_method_free, NULL); - GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers); - GNUNET_free (slicer); -} - - -/*** PLACE ***/ - - -static void -place_send_connect_msg (struct GNUNET_SOCIAL_Place *plc) -{ - uint16_t cmsg_size = ntohs (plc->connect_msg->size); - struct GNUNET_MessageHeader * cmsg = GNUNET_malloc (cmsg_size); - memcpy (cmsg, plc->connect_msg, cmsg_size); - GNUNET_CLIENT_MANAGER_transmit_now (plc->client, cmsg); -} - - -static void -place_recv_disconnect (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_SOCIAL_Place * - plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc)); - - GNUNET_CLIENT_MANAGER_reconnect (client); - place_send_connect_msg (plc); -} - - -static void -place_recv_result (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) -{ - struct GNUNET_SOCIAL_Place * - plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc)); - - const struct GNUNET_OperationResultMessage * - res = (const struct GNUNET_OperationResultMessage *) msg; - - uint16_t size = ntohs (msg->size); - if (size < sizeof (*res)) - { /* Error, message too small. */ - GNUNET_break (0); - return; - } - - uint16_t data_size = size - sizeof (*res); - const char *data = (0 < data_size) ? (const char *) &res[1] : NULL; - GNUNET_CLIENT_MANAGER_op_result (plc->client, GNUNET_ntohll (res->op_id), - GNUNET_ntohll (res->result_code), - data, data_size); -} - - -static void -op_recv_history_result (void *cls, int64_t result, - const void *err_msg, uint16_t err_msg_size) -{ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received history replay result: %" PRId64 ".\n", result); - - struct GNUNET_SOCIAL_HistoryRequest *hist = cls; - - if (NULL != hist->result_cb) - hist->result_cb (hist->cls, result, err_msg, err_msg_size); - - GNUNET_PSYC_receive_destroy (hist->recv); - GNUNET_free (hist); -} + GNUNET_free (hist); +} static void @@ -1085,18 +667,30 @@ op_recv_state_result (void *cls, int64_t result, } -static void -place_recv_history_result (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +static int +check_place_history_result (void *cls, + const struct GNUNET_OperationResultMessage *res) { - struct GNUNET_SOCIAL_Place * - plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc)); + struct GNUNET_PSYC_MessageHeader * + pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); + uint16_t size = ntohs (res->header.size); + + if (NULL == pmsg || size < sizeof (*res) + sizeof (*pmsg)) + { /* Error, message too small. */ + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} - const struct GNUNET_OperationResultMessage * - res = (const struct GNUNET_OperationResultMessage *) msg; + +static void +handle_place_history_result (void *cls, + const struct GNUNET_OperationResultMessage *res) +{ + struct GNUNET_SOCIAL_Place *plc = cls; struct GNUNET_PSYC_MessageHeader * - pmsg = (struct GNUNET_PSYC_MessageHeader *) &res[1]; + pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); LOG (GNUNET_ERROR_TYPE_DEBUG, "%p Received historic fragment for message #%" PRIu64 ".\n", @@ -1105,9 +699,9 @@ place_recv_history_result (void *cls, GNUNET_ResultCallback result_cb = NULL; struct GNUNET_SOCIAL_HistoryRequest *hist = NULL; - if (GNUNET_YES != GNUNET_CLIENT_MANAGER_op_find (plc->client, - GNUNET_ntohll (res->op_id), - &result_cb, (void *) &hist)) + if (GNUNET_YES != GNUNET_OP_get (plc->op, + GNUNET_ntohll (res->op_id), + &result_cb, (void *) &hist, NULL)) { /* Operation not found. */ LOG (GNUNET_ERROR_TYPE_WARNING, "%p Replay operation not found for historic fragment of message #%" @@ -1116,50 +710,57 @@ place_recv_history_result (void *cls, return; } - uint16_t size = ntohs (msg->size); - if (size < sizeof (*res) + sizeof (*pmsg)) - { /* Error, message too small. */ - GNUNET_break (0); - return; + GNUNET_PSYC_slicer_message (hist->slicer, + (const struct GNUNET_PSYC_MessageHeader *) pmsg); +} + + +static int +check_place_state_result (void *cls, + const struct GNUNET_OperationResultMessage *res) +{ + const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); + if (NULL == mod) + { + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_WARNING, + "Invalid modifier in state result\n"); + return GNUNET_SYSERR; } - GNUNET_PSYC_receive_message (hist->recv, - (const struct GNUNET_PSYC_MessageHeader *) pmsg); + uint16_t size = ntohs (res->header.size); + uint16_t mod_size = ntohs (mod->size); + if (size - sizeof (*res) != mod_size) + { + GNUNET_break_op (0); + LOG (GNUNET_ERROR_TYPE_WARNING, + "Invalid modifier size in state result: %u - %u != %u\n", + ntohs (res->header.size), sizeof (*res), mod_size); + return GNUNET_SYSERR; + } + return GNUNET_OK; } static void -place_recv_state_result (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +handle_place_state_result (void *cls, + const struct GNUNET_OperationResultMessage *res) { - struct GNUNET_SOCIAL_Place * - plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc)); - - const struct GNUNET_OperationResultMessage * - res = (const struct GNUNET_OperationResultMessage *) msg; + struct GNUNET_SOCIAL_Place *plc = cls; GNUNET_ResultCallback result_cb = NULL; struct GNUNET_SOCIAL_LookHandle *look = NULL; - if (GNUNET_YES != GNUNET_CLIENT_MANAGER_op_find (plc->client, - GNUNET_ntohll (res->op_id), - &result_cb, (void *) &look)) + if (GNUNET_YES != GNUNET_OP_get (plc->op, + GNUNET_ntohll (res->op_id), + &result_cb, (void *) &look, NULL)) { /* Operation not found. */ return; } - const struct GNUNET_MessageHeader * - mod = (struct GNUNET_MessageHeader *) &res[1]; + const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); uint16_t mod_size = ntohs (mod->size); - if (ntohs (msg->size) - sizeof (*res) != mod_size) - { - GNUNET_break_op (0); - LOG (GNUNET_ERROR_TYPE_WARNING, - "Invalid modifier size in state result: %u - %u != %u\n", - ntohs (msg->size), sizeof (*res), mod_size); - return; - } + switch (ntohs (mod->type)) { case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: @@ -1169,7 +770,9 @@ place_recv_state_result (void *cls, const char *name = (const char *) &pmod[1]; uint16_t name_size = ntohs (pmod->name_size); - if ('\0' != name[name_size - 1]) + if (0 == name_size + || mod_size - sizeof (*pmod) < name_size + || '\0' != name[name_size - 1]) { GNUNET_break_op (0); LOG (GNUNET_ERROR_TYPE_WARNING, @@ -1184,7 +787,7 @@ place_recv_state_result (void *cls, { look->mod_value_remaining = look->mod_value_size; look->mod_name = GNUNET_malloc (name_size); - memcpy (look->mod_name, name, name_size); + GNUNET_memcpy (look->mod_name, name, name_size); } break; } @@ -1203,96 +806,108 @@ place_recv_state_result (void *cls, static void -place_recv_message_ack (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +handle_place_message_ack (void *cls, + const struct GNUNET_MessageHeader *msg) { - struct GNUNET_SOCIAL_Place * - plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc)); + struct GNUNET_SOCIAL_Place *plc = cls; + GNUNET_PSYC_transmit_got_ack (plc->tmit); } +static int +check_place_message (void *cls, + const struct GNUNET_PSYC_MessageHeader *pmsg) +{ + return GNUNET_OK; +} + + static void -place_recv_message (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +handle_place_message (void *cls, + const struct GNUNET_PSYC_MessageHeader *pmsg) { - struct GNUNET_SOCIAL_Place * - plc = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (*plc)); - GNUNET_PSYC_receive_message (plc->recv, - (const struct GNUNET_PSYC_MessageHeader *) msg); + struct GNUNET_SOCIAL_Place *plc = cls; + + GNUNET_PSYC_slicer_message (plc->slicer, pmsg); +} + + +static int +check_host_message (void *cls, + const struct GNUNET_PSYC_MessageHeader *pmsg) +{ + return GNUNET_OK; } static void -host_recv_message (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +handle_host_message (void *cls, + const struct GNUNET_PSYC_MessageHeader *pmsg) { - struct GNUNET_SOCIAL_Host * - hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client, sizeof (hst->plc)); - GNUNET_PSYC_receive_message (hst->recv, - (const struct GNUNET_PSYC_MessageHeader *) msg); - GNUNET_PSYC_receive_message (hst->plc.recv, - (const struct GNUNET_PSYC_MessageHeader *) msg); + struct GNUNET_SOCIAL_Host *hst = cls; + + GNUNET_PSYC_slicer_message (hst->slicer, pmsg); + GNUNET_PSYC_slicer_message (hst->plc.slicer, pmsg); } static void -host_recv_enter_ack (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +handle_host_enter_ack (void *cls, + const struct HostEnterAck *hack) { - struct GNUNET_SOCIAL_Host * - hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client, - sizeof (struct GNUNET_SOCIAL_Place)); + struct GNUNET_SOCIAL_Host *hst = cls; - struct GNUNET_PSYC_CountersResultMessage * - cres = (struct GNUNET_PSYC_CountersResultMessage *) msg; - int32_t result = ntohl (cres->result_code); + hst->plc.pub_key = hack->place_pub_key; + + int32_t result = ntohl (hack->result_code); if (NULL != hst->enter_cb) - hst->enter_cb (hst->cb_cls, result, GNUNET_ntohll (cres->max_message_id)); + hst->enter_cb (hst->cb_cls, result, &hack->place_pub_key, + GNUNET_ntohll (hack->max_message_id)); +} + + +static int +check_host_enter_request (void *cls, + const struct GNUNET_PSYC_JoinRequestMessage *req) +{ + return GNUNET_OK; } static void -host_recv_enter_request (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +handle_host_enter_request (void *cls, + const struct GNUNET_PSYC_JoinRequestMessage *req) { - struct GNUNET_SOCIAL_Host * - hst = GNUNET_CLIENT_MANAGER_get_user_context_ (client, - sizeof (struct GNUNET_SOCIAL_Place)); + struct GNUNET_SOCIAL_Host *hst = cls; + if (NULL == hst->answer_door_cb) return; const char *method_name = NULL; - struct GNUNET_ENV_Environment *env = NULL; - struct GNUNET_PSYC_MessageHeader *entry_pmsg; + struct GNUNET_PSYC_Environment *env = NULL; + struct GNUNET_PSYC_MessageHeader *entry_pmsg = NULL; const void *data = NULL; uint16_t data_size = 0; char *str; - const struct GNUNET_PSYC_JoinRequestMessage * - req = (const struct GNUNET_PSYC_JoinRequestMessage *) msg; - const struct GNUNET_PSYC_Message *entry_msg = NULL; + const struct GNUNET_PSYC_Message *join_msg = NULL; do { - if (sizeof (*req) + sizeof (*entry_msg) <= ntohs (req->header.size)) + if (sizeof (*req) + sizeof (*join_msg) <= ntohs (req->header.size)) { - entry_msg = (struct GNUNET_PSYC_Message *) &req[1]; + join_msg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (req); LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received entry_msg of type %u and size %u.\n", - ntohs (entry_msg->header.type), ntohs (entry_msg->header.size)); + "Received join_msg of type %u and size %u.\n", + ntohs (join_msg->header.type), ntohs (join_msg->header.size)); - env = GNUNET_ENV_environment_create (); - entry_pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg); + env = GNUNET_PSYC_env_create (); + entry_pmsg = GNUNET_PSYC_message_header_create_from_psyc (join_msg); if (GNUNET_OK != GNUNET_PSYC_message_parse (entry_pmsg, &method_name, env, &data, &data_size)) { GNUNET_break_op (0); - str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_key); + str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_pub_key); LOG (GNUNET_ERROR_TYPE_WARNING, "Ignoring invalid entry request from nym %s.\n", str); @@ -1301,199 +916,301 @@ host_recv_enter_request (void *cls, } } - struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_key); + struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_pub_key); hst->answer_door_cb (hst->cb_cls, nym, method_name, env, - data_size, data); + data, data_size); } while (0); if (NULL != env) - GNUNET_ENV_environment_destroy (env); - GNUNET_free (entry_pmsg); + GNUNET_PSYC_env_destroy (env); + if (NULL != entry_pmsg) + GNUNET_free (entry_pmsg); } static void -guest_recv_enter_ack (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +handle_guest_enter_ack (void *cls, + const struct GNUNET_PSYC_CountersResultMessage *cres) { - struct GNUNET_SOCIAL_Guest * - gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client, - sizeof (struct GNUNET_SOCIAL_Place)); + struct GNUNET_SOCIAL_Guest *gst = cls; - struct GNUNET_PSYC_CountersResultMessage * - cres = (struct GNUNET_PSYC_CountersResultMessage *) msg; int32_t result = ntohl (cres->result_code); if (NULL != gst->enter_cb) - gst->enter_cb (gst->cb_cls, result, GNUNET_ntohll (cres->max_message_id)); + gst->enter_cb (gst->cb_cls, result, &gst->plc.pub_key, + GNUNET_ntohll (cres->max_message_id)); +} + + +static int +check_guest_enter_decision (void *cls, + const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) +{ + return GNUNET_OK; } static void -guest_recv_join_decision (void *cls, - struct GNUNET_CLIENT_MANAGER_Connection *client, - const struct GNUNET_MessageHeader *msg) +handle_guest_enter_decision (void *cls, + const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) { - struct GNUNET_SOCIAL_Guest * - gst = GNUNET_CLIENT_MANAGER_get_user_context_ (client, - sizeof (struct GNUNET_SOCIAL_Place)); - const struct GNUNET_PSYC_JoinDecisionMessage * - dcsn = (const struct GNUNET_PSYC_JoinDecisionMessage *) msg; + struct GNUNET_SOCIAL_Guest *gst = cls; struct GNUNET_PSYC_Message *pmsg = NULL; - if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg)) - pmsg = (struct GNUNET_PSYC_Message *) &dcsn[1]; + if (ntohs (dcsn->header.size) > sizeof (*dcsn)) + pmsg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (dcsn); if (NULL != gst->entry_dcsn_cb) gst->entry_dcsn_cb (gst->cb_cls, ntohl (dcsn->is_admitted), pmsg); } -static struct GNUNET_CLIENT_MANAGER_MessageHandler host_handlers[] = +static int +check_app_ego (void *cls, + const struct AppEgoMessage *emsg) { - { host_recv_enter_ack, NULL, - GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK, - sizeof (struct GNUNET_PSYC_CountersResultMessage), GNUNET_NO }, - - { host_recv_enter_request, NULL, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST, - sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES }, - - { host_recv_message, NULL, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, - sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES }, - - { place_recv_message_ack, NULL, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, - sizeof (struct GNUNET_MessageHeader), GNUNET_NO }, - - { place_recv_history_result, NULL, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, - sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES }, - - { place_recv_state_result, NULL, - GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, - sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES }, - - { place_recv_result, NULL, - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, - sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES }, - - { place_recv_disconnect, NULL, 0, 0, GNUNET_NO }, - - { NULL, NULL, 0, 0, GNUNET_NO } -}; + return GNUNET_OK; +} -static struct GNUNET_CLIENT_MANAGER_MessageHandler guest_handlers[] = +static void +handle_app_ego (void *cls, + const struct AppEgoMessage *emsg) { - { guest_recv_enter_ack, NULL, - GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK, - sizeof (struct GNUNET_PSYC_CountersResultMessage), GNUNET_NO }, + struct GNUNET_SOCIAL_App *app = cls; - { host_recv_enter_request, NULL, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST, - sizeof (struct GNUNET_PSYC_JoinRequestMessage), GNUNET_YES }, + uint16_t name_size = ntohs (emsg->header.size) - sizeof (*emsg); - { place_recv_message, NULL, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, - sizeof (struct GNUNET_PSYC_MessageHeader), GNUNET_YES }, + struct GNUNET_HashCode ego_pub_hash; + GNUNET_CRYPTO_hash (&emsg->ego_pub_key, sizeof (emsg->ego_pub_key), + &ego_pub_hash); - { place_recv_message_ack, NULL, - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, - sizeof (struct GNUNET_MessageHeader), GNUNET_NO }, + struct GNUNET_SOCIAL_Ego * + ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash); + if (NULL == ego) + { + ego = GNUNET_malloc (sizeof (*ego)); + ego->pub_key = emsg->ego_pub_key; + ego->name = GNUNET_malloc (name_size); + GNUNET_memcpy (ego->name, &emsg[1], name_size); + } + else + { + ego->name = GNUNET_realloc (ego->name, name_size); + GNUNET_memcpy (ego->name, &emsg[1], name_size); + } - { guest_recv_join_decision, NULL, - GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, - sizeof (struct GNUNET_PSYC_JoinDecisionMessage), GNUNET_YES }, + GNUNET_CONTAINER_multihashmap_put (app->egos, &ego_pub_hash, ego, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); - { place_recv_history_result, NULL, - GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, - sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES }, + if (NULL != app->ego_cb) + app->ego_cb (app->cb_cls, ego, &ego->pub_key, ego->name); +} - { place_recv_state_result, NULL, - GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, - sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES }, - { place_recv_result, NULL, - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, - sizeof (struct GNUNET_OperationResultMessage), GNUNET_YES }, +static void +handle_app_ego_end (void *cls, + const struct GNUNET_MessageHeader *msg) +{ + //struct GNUNET_SOCIAL_App *app = cls; +} - { place_recv_disconnect, NULL, 0, 0, GNUNET_NO }, - { NULL, NULL, 0, 0, GNUNET_NO } -}; +static int +check_app_place (void *cls, + const struct AppPlaceMessage *pmsg) +{ + return GNUNET_OK; +} static void -place_cleanup (struct GNUNET_SOCIAL_Place *plc) +handle_app_place (void *cls, + const struct AppPlaceMessage *pmsg) { - if (NULL != plc->tmit) - GNUNET_PSYC_transmit_destroy (plc->tmit); - if (NULL != plc->recv) - GNUNET_PSYC_receive_destroy (plc->recv); - if (NULL != plc->connect_msg) - GNUNET_free (plc->connect_msg); - if (NULL != plc->disconnect_cb) - plc->disconnect_cb (plc->disconnect_cls); + struct GNUNET_SOCIAL_App *app = cls; + + if ((GNUNET_YES == pmsg->is_host && NULL == app->host_cb) + || (GNUNET_NO == pmsg->is_host && NULL == app->guest_cb)) + return; - if (NULL != core) + struct GNUNET_HashCode ego_pub_hash; + GNUNET_CRYPTO_hash (&pmsg->ego_pub_key, sizeof (pmsg->ego_pub_key), + &ego_pub_hash); + struct GNUNET_SOCIAL_Ego * + ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash); + if (NULL == ego) { - GNUNET_CORE_disconnect (core); - core = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failure to obtain ego %s.\n", + GNUNET_h2s (&ego_pub_hash)); + GNUNET_break (0); + return; } - if (NULL != namestore) + + if (GNUNET_YES == pmsg->is_host) { - GNUNET_NAMESTORE_disconnect (namestore); - namestore = NULL; + if (NULL != app->host_cb) { + struct GNUNET_SOCIAL_HostConnection *hconn = GNUNET_malloc (sizeof (*hconn)); + hconn->app = app; + hconn->plc_msg = *pmsg; + app->host_cb (app->cb_cls, hconn, ego, &pmsg->place_pub_key, pmsg->place_state); + GNUNET_free (hconn); + } } - if (NULL != gns) + else if (NULL != app->guest_cb) { - GNUNET_GNS_disconnect (gns); - gns = NULL; + struct GNUNET_SOCIAL_GuestConnection *gconn = GNUNET_malloc (sizeof (*gconn)); + gconn->app = app; + gconn->plc_msg = *pmsg; + app->guest_cb (app->cb_cls, gconn, ego, &pmsg->place_pub_key, pmsg->place_state); + GNUNET_free (gconn); } } static void -host_cleanup (void *cls) +handle_app_place_end (void *cls, + const struct GNUNET_MessageHeader *msg) { - struct GNUNET_SOCIAL_Host *hst = cls; - place_cleanup (&hst->plc); - GNUNET_PSYC_receive_destroy (hst->recv); - GNUNET_SOCIAL_slicer_destroy (hst->slicer); - GNUNET_free (hst); + struct GNUNET_SOCIAL_App *app = cls; + + if (NULL != app->connected_cb) + app->connected_cb (app->cb_cls); } +/** + * Handler for a #GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK message received + * from the social service. + * + * @param cls the place of type `struct GNUNET_SOCIAL_Place` + * @param msg the message received from the service + */ static void -guest_cleanup (void *cls) +handle_place_leave_ack (void *cls, + const struct GNUNET_MessageHeader *msg) { - struct GNUNET_SOCIAL_Guest *gst = cls; - place_cleanup (&gst->plc); - GNUNET_free (gst); + struct GNUNET_SOCIAL_Place *plc = cls; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s left place %p\n", + plc->is_host ? "host" : "guest", + plc); + place_disconnect (plc); } /*** HOST ***/ + +static void +host_connect (struct GNUNET_SOCIAL_Host *hst); + + +static void +host_reconnect (void *cls) +{ + host_connect (cls); +} + + +/** + * Host client disconnected from service. + * + * Reconnect after backoff period. + */ +static void +host_disconnected (void *cls, enum GNUNET_MQ_Error error) +{ + struct GNUNET_SOCIAL_Host *hst = cls; + struct GNUNET_SOCIAL_Place *plc = &hst->plc; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Host client disconnected (%d), re-connecting\n", + (int) error); + if (NULL != plc->tmit) + { + GNUNET_PSYC_transmit_destroy (plc->tmit); + plc->tmit = NULL; + } + if (NULL != plc->mq) + { + GNUNET_MQ_destroy (plc->mq); + plc->mq = NULL; + } + + plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay, + host_reconnect, + hst); + plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay); +} + + +static void +host_connect (struct GNUNET_SOCIAL_Host *hst) +{ + struct GNUNET_SOCIAL_Place *plc = &hst->plc; + + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_fixed_size (host_enter_ack, + GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK, + struct HostEnterAck, + hst), + GNUNET_MQ_hd_fixed_size (place_leave_ack, + GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK, + struct GNUNET_MessageHeader, + plc), + GNUNET_MQ_hd_var_size (host_enter_request, + GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST, + struct GNUNET_PSYC_JoinRequestMessage, + hst), + GNUNET_MQ_hd_var_size (host_message, + GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, + struct GNUNET_PSYC_MessageHeader, + hst), + GNUNET_MQ_hd_fixed_size (place_message_ack, + GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, + struct GNUNET_MessageHeader, + plc), + GNUNET_MQ_hd_var_size (place_history_result, + GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, + struct GNUNET_OperationResultMessage, + plc), + GNUNET_MQ_hd_var_size (place_state_result, + GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, + struct GNUNET_OperationResultMessage, + plc), + GNUNET_MQ_hd_var_size (place_result, + GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, + struct GNUNET_OperationResultMessage, + plc), + GNUNET_MQ_handler_end () + }; + + plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social", + handlers, host_disconnected, hst); + GNUNET_assert (NULL != plc->mq); + plc->tmit = GNUNET_PSYC_transmit_create (plc->mq); + + GNUNET_MQ_send_copy (plc->mq, plc->connect_env); +} + + /** * Enter a place as host. * * A place is created upon first entering, and it is active until permanently * left using GNUNET_SOCIAL_host_leave(). * - * @param cfg - * Configuration to contact the social service. + * @param app + * Application handle. * @param ego * Identity of the host. - * @param place_key - * Private-public key pair of the place. - * NULL for ephemeral places. * @param policy * Policy specifying entry and history restrictions for the place. * @param slicer * Slicer to handle incoming messages. + * @param enter_cb + * Function called when the place is entered and ready to use. * @param answer_door_cb * Function to handle new nyms that want to enter. * @param farewell_cb @@ -1501,14 +1218,13 @@ guest_cleanup (void *cls) * @param cls * Closure for the callbacks. * - * @return Handle for the host. + * @return Handle for the host. This handle contains the pubkey. */ struct GNUNET_SOCIAL_Host * -GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPrivateKey *place_key, +GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, enum GNUNET_PSYC_Policy policy, - struct GNUNET_SOCIAL_Slicer *slicer, + struct GNUNET_PSYC_Slicer *slicer, GNUNET_SOCIAL_HostEnterCallback enter_cb, GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, GNUNET_SOCIAL_FarewellCallback farewell_cb, @@ -1516,76 +1232,47 @@ GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, { struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst)); struct GNUNET_SOCIAL_Place *plc = &hst->plc; - struct HostEnterRequest *req = GNUNET_malloc (sizeof (*req)); - - if (NULL != place_key) - { - hst->place_key = *place_key; - } - else - { - struct GNUNET_CRYPTO_EddsaPrivateKey * - ephemeral_key = GNUNET_CRYPTO_eddsa_key_create (); - hst->place_key = *ephemeral_key; - GNUNET_CRYPTO_eddsa_key_get_public (&hst->place_key, &plc->pub_key); - GNUNET_CRYPTO_eddsa_key_clear (ephemeral_key); - GNUNET_free (ephemeral_key); - } - - req->header.size = htons (sizeof (*req)); - req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); - req->policy = policy; - req->place_key = hst->place_key; - req->host_key = plc->ego_key; - plc->connect_msg = (struct GNUNET_MessageHeader *) req; - plc->cfg = cfg; + plc->cfg = app->cfg; plc->is_host = GNUNET_YES; plc->slicer = slicer; - plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego); - GNUNET_CRYPTO_eddsa_key_get_public (place_key, &plc->pub_key); - hst->enter_cb = enter_cb; hst->answer_door_cb = answer_door_cb; hst->farewell_cb = farewell_cb; hst->cb_cls = cls; - plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", host_handlers); - GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, hst, sizeof (*plc)); + plc->op = GNUNET_OP_create (); - plc->tmit = GNUNET_PSYC_transmit_create (plc->client); - plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer); + hst->slicer = GNUNET_PSYC_slicer_create (); + GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL, + host_recv_notice_place_leave_method, + host_recv_notice_place_leave_modifier, + NULL, host_recv_notice_place_leave_eom, hst); - hst->slicer = GNUNET_SOCIAL_slicer_create (); - GNUNET_SOCIAL_slicer_method_add (hst->slicer, "_notice_place_leave", - host_recv_notice_place_leave_method, - host_recv_notice_place_leave_modifier, - NULL, host_recv_notice_place_leave_eom, hst); - hst->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, hst->slicer); + uint16_t app_id_size = strlen (app->id) + 1; + struct HostEnterRequest *hreq; + plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size, + GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); + hreq->policy = policy; + hreq->ego_pub_key = ego->pub_key; + GNUNET_memcpy (&hreq[1], app->id, app_id_size); - place_send_connect_msg (plc); + host_connect (hst); return hst; } /** - * Enter a place as host. + * Reconnect to an already entered place as host. * - * A place is created upon first entering, and it is active until permanently - * left using GNUNET_SOCIAL_host_leave(). - * - * @param cfg - * Configuration to contact the social service. - * @param ego - * Identity of the host. - * @param gns_name - * GNS name in the zone of the @a ego that contains the - * public key of the place in a PLACE record. - * @param policy - * Policy specifying entry and history restrictions for the place. + * @param hconn + * Host connection handle. + * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback() * @param slicer * Slicer to handle incoming messages. + * @param enter_cb + * Function called when the place is entered and ready to use. * @param answer_door_cb * Function to handle new nyms that want to enter. * @param farewell_cb @@ -1595,27 +1282,46 @@ GNUNET_SOCIAL_host_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, * * @return Handle for the host. */ -struct GNUNET_SOCIAL_Host * -GNUNET_SOCIAL_host_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_IDENTITY_Ego *ego, - const char *gns_name, - enum GNUNET_PSYC_Policy policy, - struct GNUNET_SOCIAL_Slicer *slicer, - GNUNET_SOCIAL_HostEnterCallback enter_cb, - GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, - GNUNET_SOCIAL_FarewellCallback farewell_cb, - void *cls) -{ - struct GNUNET_CRYPTO_EddsaPrivateKey place_key = {}; - - /* FIXME: - * 1. get public key by looking up PLACE entry under gns_name - * in the zone of the ego. - * 2. get private key from $GNUNET_DATA_HOME/social/places/PUB_KEY_HASH - */ + struct GNUNET_SOCIAL_Host * +GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn, + struct GNUNET_PSYC_Slicer *slicer, + GNUNET_SOCIAL_HostEnterCallback enter_cb, + GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, + GNUNET_SOCIAL_FarewellCallback farewell_cb, + void *cls) +{ + struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst)); + struct GNUNET_SOCIAL_Place *plc = &hst->plc; - return GNUNET_SOCIAL_host_enter (cfg, ego, &place_key, policy, slicer, - enter_cb, answer_door_cb, farewell_cb, cls); + hst->enter_cb = enter_cb; + hst->answer_door_cb = answer_door_cb; + hst->farewell_cb = farewell_cb; + hst->cb_cls = cls; + + plc->cfg = hconn->app->cfg; + plc->is_host = GNUNET_YES; + plc->slicer = slicer; + plc->pub_key = hconn->plc_msg.place_pub_key; + plc->ego_pub_key = hconn->plc_msg.ego_pub_key; + + plc->op = GNUNET_OP_create (); + + hst->slicer = GNUNET_PSYC_slicer_create (); + GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL, + host_recv_notice_place_leave_method, + host_recv_notice_place_leave_modifier, + NULL, host_recv_notice_place_leave_eom, hst); + + size_t app_id_size = strlen (hconn->app->id) + 1; + struct HostEnterRequest *hreq; + plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size, + GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); + hreq->place_pub_key = hconn->plc_msg.place_pub_key; + hreq->ego_pub_key = hconn->plc_msg.ego_pub_key; + GNUNET_memcpy (&hreq[1], hconn->app->id, app_id_size); + + host_connect (hst); + return hst; } @@ -1647,6 +1353,7 @@ GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, int is_admitted, const struct GNUNET_PSYC_Message *entry_resp) { + struct GNUNET_SOCIAL_Place *plc = &hst->plc; struct GNUNET_PSYC_JoinDecisionMessage *dcsn; uint16_t entry_resp_size = (NULL != entry_resp) ? ntohs (entry_resp->header.size) : 0; @@ -1654,16 +1361,16 @@ GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < sizeof (*dcsn) + entry_resp_size) return GNUNET_SYSERR; - dcsn = GNUNET_malloc (sizeof (*dcsn) + entry_resp_size); - dcsn->header.size = htons (sizeof (*dcsn) + entry_resp_size); - dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION); + struct GNUNET_MQ_Envelope * + env = GNUNET_MQ_msg_extra (dcsn, entry_resp_size, + GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION); dcsn->is_admitted = htonl (is_admitted); - dcsn->slave_key = nym->pub_key; + dcsn->slave_pub_key = nym->pub_key; if (0 < entry_resp_size) - memcpy (&dcsn[1], entry_resp, entry_resp_size); + GNUNET_memcpy (&dcsn[1], entry_resp, entry_resp_size); - GNUNET_CLIENT_MANAGER_transmit (hst->plc.client, &dcsn->header); + GNUNET_MQ_send (plc->mq, env); return GNUNET_OK; } @@ -1679,135 +1386,100 @@ GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, * Host of the place. * @param nym * Handle for the entity to be ejected. + * @param env + * Environment for the message or NULL. */ void GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *hst, - const struct GNUNET_SOCIAL_Nym *nym) -{ - struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create (); - GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_SET, - "_nym", &nym->pub_key, sizeof (nym->pub_key)); + const struct GNUNET_SOCIAL_Nym *nym, + struct GNUNET_PSYC_Environment *e) +{ + struct GNUNET_PSYC_Environment *env = e; + if (NULL == env) + env = GNUNET_PSYC_env_create (); + GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, + "_nym", &nym->pub_key, sizeof (nym->pub_key)); GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", env, NULL, NULL, GNUNET_SOCIAL_ANNOUNCE_NONE); + if (NULL == e) + GNUNET_PSYC_env_destroy (env); } /** - * Get the public key of a @a nym. + * Get the public key of @a ego. * - * Suitable, for example, to be used with GNUNET_NAMESTORE_zone_to_name(). - * - * @param nym - * Pseudonym to map to a cryptographic identifier. + * @param ego + * Ego. * - * @return Public key of nym. + * @return Public key of ego. */ const struct GNUNET_CRYPTO_EcdsaPublicKey * -GNUNET_SOCIAL_nym_get_key (const struct GNUNET_SOCIAL_Nym *nym) +GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego) { - return &nym->pub_key; + return &ego->pub_key; } /** - * Get the hash of the public key of a @a nym. + * Get the hash of the public key of @a ego. * - * @param nym - * Pseudonym to map to a cryptographic identifier. + * @param ego + * Ego. * - * @return Hash of the public key of nym. + * @return Hash of the public key of @a ego. */ const struct GNUNET_HashCode * -GNUNET_SOCIAL_nym_get_key_hash (const struct GNUNET_SOCIAL_Nym *nym) +GNUNET_SOCIAL_ego_get_pub_key_hash (const struct GNUNET_SOCIAL_Ego *ego) { - return &nym->pub_key_hash; + return &ego->pub_key_hash; } /** - * Obtain the private-public key pair of the hosted place. - * - * The public part is suitable for storing in GNS within a PLACE record, - * along with peer IDs to join at. + * Get the name of @a ego. * - * @param host - * Host of the place. + * @param ego + * Ego. * - * @return Private-public key pair of the hosted place. + * @return Public key of @a ego. */ -const struct GNUNET_CRYPTO_EddsaPrivateKey * -GNUNET_SOCIAL_host_get_place_key (struct GNUNET_SOCIAL_Host *hst) +const char * +GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego) { - return &hst->place_key; + return ego->name; } /** - * Connected to core service. + * Get the public key of @a nym. + * + * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym(). + * + * @param nym + * Pseudonym. + * + * @return Public key of @a nym. */ -static void -core_connected_cb (void *cls, const struct GNUNET_PeerIdentity *my_identity) +const struct GNUNET_CRYPTO_EcdsaPublicKey * +GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym) { - this_peer = *my_identity; - // FIXME + return &nym->pub_key; } /** - * Advertise the place in the GNS zone of the @e ego of the @a host. + * Get the hash of the public key of @a nym. * - * @param hst - * Host of the place. - * @param name - * The name for the PLACE record to put in the zone. - * @param peer_count - * Number of elements in the @a peers array. - * @param peers - * List of peers to put in the PLACE record to advertise - * as entry points to the place in addition to the origin. - * @param expiration_time - * Expiration time of the record, use 0 to remove the record. - * @param password - * Password used to encrypt the record or NULL to keep it cleartext. - * @param result_cb - * Function called with the result of the operation. - * @param result_cls - * Closure for @a result_cb + * @param nym + * Pseudonym. + * + * @return Hash of the public key of @a nym. */ -void -GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *hst, - const char *name, - uint32_t peer_count, - const struct GNUNET_PeerIdentity *peers, - struct GNUNET_TIME_Absolute expiration_time, - const char *password, - GNUNET_NAMESTORE_ContinuationWithStatus result_cb, - void *result_cls) +const struct GNUNET_HashCode * +GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym) { - struct GNUNET_SOCIAL_Place *plc = &hst->plc; - if (NULL == namestore) - namestore = GNUNET_NAMESTORE_connect (plc->cfg); - if (NULL == core) - core = GNUNET_CORE_connect (plc->cfg, NULL, core_connected_cb, NULL, NULL, - NULL, GNUNET_NO, NULL, GNUNET_NO, NULL); - - struct GNUNET_GNSRECORD_Data rd = { }; - rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE; - rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - rd.expiration_time = expiration_time.abs_value_us; - - struct GNUNET_GNSRECORD_PlaceData * - rec = GNUNET_malloc (sizeof (*rec) + peer_count * sizeof (*peers)); - rec->place_key = plc->pub_key; - rec->origin = this_peer; - rec->relay_count = htonl (peer_count); - memcpy (&rec[1], peers, peer_count * sizeof (*peers)); - - rd.data = rec; - rd.data_size = sizeof (*rec) + peer_count * sizeof (*peers); - - GNUNET_NAMESTORE_records_store (namestore, &hst->plc.ego_key, - name, 1, &rd, result_cb, result_cls); + return &nym->pub_key_hash; } @@ -1830,11 +1502,14 @@ GNUNET_SOCIAL_host_advertise (struct GNUNET_SOCIAL_Host *hst, struct GNUNET_SOCIAL_Announcement * GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *hst, const char *method_name, - const struct GNUNET_ENV_Environment *env, + const struct GNUNET_PSYC_Environment *env, GNUNET_PSYC_TransmitNotifyData notify_data, void *notify_data_cls, enum GNUNET_SOCIAL_AnnounceFlags flags) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "PSYC_transmit_message for host, method: %s\n", + method_name); if (GNUNET_OK == GNUNET_PSYC_transmit_message (hst->plc.tmit, method_name, env, NULL, notify_data, notify_data_cls, flags)) @@ -1887,193 +1562,267 @@ GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst) /** - * Stop hosting a place. + * Disconnect from a home. * * Invalidates host handle. * - * @param host Host leaving the place. - * @param keep_active Keep the place active after last host disconnected. + * @param hst + * The host to disconnect. */ void -GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst, - int keep_active, - GNUNET_ContinuationCallback leave_cb, - void *leave_cls) +GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst, + GNUNET_ContinuationCallback disconnect_cb, + void *cls) { struct GNUNET_SOCIAL_Place *plc = &hst->plc; - /* FIXME: send msg to service */ + plc->disconnect_cb = disconnect_cb; + plc->disconnect_cls = cls; + place_disconnect (plc); +} + - plc->is_disconnecting = GNUNET_YES; - plc->disconnect_cb = leave_cb; - plc->disconnect_cls = leave_cls; +/** + * Stop hosting the home. + * + * Sends a _notice_place_closing announcement to the home. + * Invalidates host handle. + * + * @param hst + * The host leaving. + * @param env + * Environment for the message or NULL. + * _nym is set to @e nym regardless whether an @e env is provided. + * @param disconnect_cb + * Function called after the host left the place + * and disconnected from the social service. + * @param cls + * Closure for @a disconnect_cb. + */ +void +GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst, + const struct GNUNET_PSYC_Environment *env, + GNUNET_ContinuationCallback disconnect_cb, + void *cls) +{ + struct GNUNET_MQ_Envelope *envelope; - GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES, - &host_cleanup, hst); + GNUNET_SOCIAL_host_announce (hst, "_notice_place_closing", env, NULL, NULL, + GNUNET_SOCIAL_ANNOUNCE_NONE); + hst->plc.disconnect_cb = disconnect_cb; + hst->plc.disconnect_cls = cls; + envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE); + GNUNET_MQ_send (hst->plc.mq, + envelope); } /*** GUEST ***/ -static struct GuestEnterRequest * -guest_enter_request_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_key, + +static void +guest_connect (struct GNUNET_SOCIAL_Guest *gst); + + +static void +guest_reconnect (void *cls) +{ + guest_connect (cls); +} + + +/** + * Guest client disconnected from service. + * + * Reconnect after backoff period. + */ +static void +guest_disconnected (void *cls, enum GNUNET_MQ_Error error) +{ + struct GNUNET_SOCIAL_Guest *gst = cls; + struct GNUNET_SOCIAL_Place *plc = &gst->plc; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Guest client disconnected (%d), re-connecting\n", + (int) error); + if (NULL != plc->tmit) + { + GNUNET_PSYC_transmit_destroy (plc->tmit); + plc->tmit = NULL; + } + if (NULL != plc->mq) + { + GNUNET_MQ_destroy (plc->mq); + plc->mq = NULL; + } + + plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay, + guest_reconnect, + gst); + plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay); +} + + +static void +guest_connect (struct GNUNET_SOCIAL_Guest *gst) +{ + struct GNUNET_SOCIAL_Place *plc = &gst->plc; + + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_fixed_size (guest_enter_ack, + GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK, + struct GNUNET_PSYC_CountersResultMessage, + gst), + GNUNET_MQ_hd_fixed_size (place_leave_ack, + GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK, + struct GNUNET_MessageHeader, + plc), + GNUNET_MQ_hd_var_size (guest_enter_decision, + GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, + struct GNUNET_PSYC_JoinDecisionMessage, + gst), + GNUNET_MQ_hd_var_size (place_message, + GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, + struct GNUNET_PSYC_MessageHeader, + plc), + GNUNET_MQ_hd_fixed_size (place_message_ack, + GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, + struct GNUNET_MessageHeader, + plc), + GNUNET_MQ_hd_var_size (place_history_result, + GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, + struct GNUNET_OperationResultMessage, + plc), + GNUNET_MQ_hd_var_size (place_state_result, + GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, + struct GNUNET_OperationResultMessage, + plc), + GNUNET_MQ_hd_var_size (place_result, + GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, + struct GNUNET_OperationResultMessage, + plc), + GNUNET_MQ_handler_end () + }; + + plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social", + handlers, guest_disconnected, gst); + GNUNET_assert (NULL != plc->mq); + plc->tmit = GNUNET_PSYC_transmit_create (plc->mq); + + GNUNET_MQ_send_copy (plc->mq, plc->connect_env); +} + + +static struct GNUNET_MQ_Envelope * +guest_enter_request_create (const char *app_id, + const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, const struct GNUNET_PeerIdentity *origin, size_t relay_count, const struct GNUNET_PeerIdentity *relays, const struct GNUNET_PSYC_Message *join_msg) { + uint16_t app_id_size = strlen (app_id) + 1; uint16_t join_msg_size = ntohs (join_msg->header.size); uint16_t relay_size = relay_count * sizeof (*relays); - struct GuestEnterRequest * - req = GNUNET_malloc (sizeof (*req) + relay_size + join_msg_size); + struct GuestEnterRequest *greq; + struct GNUNET_MQ_Envelope * + env = GNUNET_MQ_msg_extra (greq, app_id_size + relay_size + join_msg_size, + GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); + greq->place_pub_key = *place_pub_key; + greq->ego_pub_key = *ego_pub_key; + greq->origin = *origin; + greq->relay_count = htonl (relay_count); - req->header.size = htons (sizeof (*req) + relay_size + join_msg_size); - req->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); - req->place_key = *place_key; - req->guest_key = *guest_key; - req->origin = *origin; - req->relay_count = htonl (relay_count); + char *p = (char *) &greq[1]; + GNUNET_memcpy (p, app_id, app_id_size); + p += app_id_size; - uint16_t p = sizeof (*req); if (0 < relay_size) { - memcpy ((char *) req + p, relays, relay_size); + GNUNET_memcpy (p, relays, relay_size); p += relay_size; } - memcpy ((char *) req + p, join_msg, join_msg_size); - return req; + GNUNET_memcpy (p, join_msg, join_msg_size); + return env; } + /** * Request entry to a place as a guest. * - * @param cfg Configuration to contact the social service. - * @param ego Identity of the guest. - * @param crypto_address Public key of the place to enter. - * @param origin Peer identity of the origin of the underlying multicast group. - * @param relay_count Number of elements in the @a relays array. - * @param relays Relays for the underlying multicast group. - * @param method_name Method name for the message. - * @param env Environment containing variables for the message, or NULL. - * @param data Payload for the message to give to the enter callback. - * @param data_size Number of bytes in @a data. - * @param slicer Slicer to use for processing incoming requests from guests. + * @param app + * Application handle. + * @param ego + * Identity of the guest. + * @param place_pub_key + * Public key of the place to enter. + * @param flags + * Flags for the entry. + * @param origin + * Peer identity of the origin of the underlying multicast group. + * @param relay_count + * Number of elements in the @a relays array. + * @param relays + * Relays for the underlying multicast group. + * @param method_name + * Method name for the message. + * @param env + * Environment containing variables for the message, or NULL. + * @param data + * Payload for the message to give to the enter callback. + * @param data_size + * Number of bytes in @a data. + * @param slicer + * Slicer to use for processing incoming requests from guests. * * @return NULL on errors, otherwise handle for the guest. */ struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const struct GNUNET_CRYPTO_EddsaPublicKey *place_key, +GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, + enum GNUNET_PSYC_SlaveJoinFlags flags, const struct GNUNET_PeerIdentity *origin, uint32_t relay_count, const struct GNUNET_PeerIdentity *relays, const struct GNUNET_PSYC_Message *entry_msg, - struct GNUNET_SOCIAL_Slicer *slicer, - GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, - GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb, - void *cls) -{ - struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego); - plc->pub_key = *place_key; - plc->cfg = cfg; - plc->is_host = GNUNET_YES; - plc->slicer = slicer; - - gst->enter_cb = local_enter_cb; - gst->entry_dcsn_cb = entry_dcsn_cb; - gst->cb_cls = cls; - - plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers); - GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc)); - - plc->tmit = GNUNET_PSYC_transmit_create (plc->client); - plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer); - - struct GuestEnterRequest * - req = guest_enter_request_create (&plc->ego_key, place_key, origin, - relay_count, relays, entry_msg); - plc->connect_msg = &req->header; - place_send_connect_msg (plc); - return gst; -} - - -/** - * Result of a GNS name lookup for entering a place. - * - * @see GNUNET_SOCIAL_guest_enter_by_name - */ -static void -gns_result_guest_enter (void *cls, uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct GNUNET_SOCIAL_Guest *gst = cls; - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "%p GNS result: %u records.\n", gst, rd_count); - - const struct GNUNET_GNSRECORD_PlaceData * - rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data; - - if (0 == rd_count) - { - if (NULL != gst->enter_cb) - gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0); - return; - } - - if (rd->data_size < sizeof (*rec)) - { - GNUNET_break_op (0); - if (NULL != gst->enter_cb) - gst->enter_cb (gst->cb_cls, GNUNET_SYSERR, 0); - return; - } + struct GNUNET_PSYC_Slicer *slicer, + GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, + GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb, + void *cls) +{ + struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); + struct GNUNET_SOCIAL_Place *plc = &gst->plc; - uint16_t relay_count = ntohl (rec->relay_count); - struct GNUNET_PeerIdentity *relays = NULL; + plc->ego_pub_key = ego->pub_key; + plc->pub_key = *place_pub_key; + plc->cfg = app->cfg; + plc->is_host = GNUNET_NO; + plc->slicer = slicer; - if (0 < relay_count) - { - if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity)) - { - relays = (struct GNUNET_PeerIdentity *) &rec[1]; - } - else - { - relay_count = 0; - GNUNET_break_op (0); - } - } + plc->op = GNUNET_OP_create (); - struct GuestEnterRequest * - req = guest_enter_request_create (&plc->ego_key, &rec->place_key, - &rec->origin, relay_count, relays, - (struct GNUNET_PSYC_Message *) plc->connect_msg); - GNUNET_free (plc->connect_msg); - plc->connect_msg = &req->header; - plc->pub_key = req->place_key; + plc->connect_env + = guest_enter_request_create (app->id, &ego->pub_key, &plc->pub_key, + origin, relay_count, relays, entry_msg); - plc->tmit = GNUNET_PSYC_transmit_create (plc->client); - plc->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, plc->slicer); + gst->enter_cb = local_enter_cb; + gst->entry_dcsn_cb = entry_dcsn_cb; + gst->cb_cls = cls; - place_send_connect_msg (plc); + guest_connect (gst); + return gst; } /** * Request entry to a place by name as a guest. * - * @param cfg - * Configuration to contact the social service. + * @param app + * Application handle. * @param ego * Identity of the guest. * @param gns_name @@ -2085,7 +1834,7 @@ gns_result_guest_enter (void *cls, uint32_t rd_count, * @param password * Password to decrypt the record, or NULL for cleartext records. * @param join_msg - * Entry request message. + * Entry request message or NULL. * @param slicer * Slicer to use for processing incoming requests from guests. * @param local_enter_cb @@ -2096,11 +1845,12 @@ gns_result_guest_enter (void *cls, uint32_t rd_count, * @return NULL on errors, otherwise handle for the guest. */ struct GNUNET_SOCIAL_Guest * -GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const char *gns_name, const char *password, +GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const char *gns_name, + const char *password, const struct GNUNET_PSYC_Message *join_msg, - struct GNUNET_SOCIAL_Slicer *slicer, + struct GNUNET_PSYC_Slicer *slicer, GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb, void *cls) @@ -2108,32 +1858,165 @@ GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); struct GNUNET_SOCIAL_Place *plc = &gst->plc; - GNUNET_assert (NULL != join_msg); + if (NULL == password) + password = ""; + + uint16_t app_id_size = strlen (app->id) + 1; + uint16_t gns_name_size = strlen (gns_name) + 1; + uint16_t password_size = strlen (password) + 1; + + uint16_t join_msg_size = 0; + if (NULL != join_msg) + join_msg_size = ntohs (join_msg->header.size); + + struct GuestEnterByNameRequest *greq; + plc->connect_env + = GNUNET_MQ_msg_extra (greq, app_id_size + gns_name_size + + password_size + join_msg_size, + GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME); + + greq->ego_pub_key = ego->pub_key; + + char *p = (char *) &greq[1]; + GNUNET_memcpy (p, app->id, app_id_size); + p += app_id_size; + GNUNET_memcpy (p, gns_name, gns_name_size); + p += gns_name_size; + GNUNET_memcpy (p, password, password_size); + p += password_size; + if (NULL != join_msg) + GNUNET_memcpy (p, join_msg, join_msg_size); + + plc->ego_pub_key = ego->pub_key; + plc->cfg = app->cfg; + plc->is_host = GNUNET_NO; + plc->slicer = slicer; + + plc->op = GNUNET_OP_create (); gst->enter_cb = local_enter_cb; gst->entry_dcsn_cb = entry_decision_cb; gst->cb_cls = cls; - plc->ego_key = *GNUNET_IDENTITY_ego_get_private_key (ego); - plc->cfg = cfg; + guest_connect (gst); + return gst; +} + + +struct ReconnectContext +{ + struct GNUNET_SOCIAL_Guest *guest; + int *result; + int64_t *max_message_id; + GNUNET_SOCIAL_GuestEnterCallback enter_cb; + void *enter_cls; +}; + + +static void +guest_enter_reconnect_cb (void *cls, + int result, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, + uint64_t max_message_id) +{ + struct ReconnectContext *reconnect_ctx = cls; + + GNUNET_assert (NULL != reconnect_ctx); + reconnect_ctx->result = GNUNET_new (int); + *(reconnect_ctx->result) = result; + reconnect_ctx->max_message_id = GNUNET_new (int64_t); + *(reconnect_ctx->max_message_id) = max_message_id; +} + + +static void +guest_entry_dcsn_reconnect_cb (void *cls, + int is_admitted, + const struct GNUNET_PSYC_Message *entry_resp) +{ + struct ReconnectContext *reconnect_ctx = cls; + struct GNUNET_SOCIAL_Guest *gst = reconnect_ctx->guest; + + GNUNET_assert (NULL != reconnect_ctx); + GNUNET_assert (NULL != reconnect_ctx->result); + GNUNET_assert (NULL != reconnect_ctx->max_message_id); + if (GNUNET_YES != is_admitted) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Guest was rejected after calling " + "GNUNET_SOCIAL_guest_enter_reconnect ()\n"); + } + else if (NULL != reconnect_ctx->enter_cb) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "guest reconnected!\n"); + reconnect_ctx->enter_cb (reconnect_ctx->enter_cls, + *(reconnect_ctx->result), + &gst->plc.pub_key, + *(reconnect_ctx->max_message_id)); + } + GNUNET_free (reconnect_ctx->result); + GNUNET_free (reconnect_ctx->max_message_id); + GNUNET_free (reconnect_ctx); +} + + +/** + * Reconnect to an already entered place as guest. + * + * @param gconn + * Guest connection handle. + * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback() + * @param flags + * Flags for the entry. + * @param slicer + * Slicer to use for processing incoming requests from guests. + * @param enter_cb + * Called upon re-entering is complete. + * @param entry_decision_cb + * Called upon receiving entry decision. + * + * @return NULL on errors, otherwise handle for the guest. + */ +struct GNUNET_SOCIAL_Guest * +GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn, + enum GNUNET_PSYC_SlaveJoinFlags flags, + struct GNUNET_PSYC_Slicer *slicer, + GNUNET_SOCIAL_GuestEnterCallback enter_cb, + void *cls) +{ + struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); + struct GNUNET_SOCIAL_Place *plc = &gst->plc; + struct ReconnectContext *reconnect_ctx; + + uint16_t app_id_size = strlen (gconn->app->id) + 1; + struct GuestEnterRequest *greq; + plc->connect_env + = GNUNET_MQ_msg_extra (greq, app_id_size, + GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); + greq->ego_pub_key = gconn->plc_msg.ego_pub_key; + greq->place_pub_key = gconn->plc_msg.place_pub_key; + greq->flags = htonl (flags); + + GNUNET_memcpy (&greq[1], gconn->app->id, app_id_size); + + plc->cfg = gconn->app->cfg; plc->is_host = GNUNET_NO; plc->slicer = slicer; + plc->pub_key = gconn->plc_msg.place_pub_key; + plc->ego_pub_key = gconn->plc_msg.ego_pub_key; - uint16_t join_msg_size = ntohs (join_msg->header.size); - plc->connect_msg = GNUNET_malloc (join_msg_size); - memcpy (plc->connect_msg, join_msg, join_msg_size); - - if (NULL == gns) - gns = GNUNET_GNS_connect (cfg); + reconnect_ctx = GNUNET_new (struct ReconnectContext); + reconnect_ctx->guest = gst; + reconnect_ctx->enter_cb = enter_cb; + reconnect_ctx->enter_cls = cls; - plc->client = GNUNET_CLIENT_MANAGER_connect (cfg, "social", guest_handlers); - GNUNET_CLIENT_MANAGER_set_user_context_ (plc->client, gst, sizeof (*plc)); + plc->op = GNUNET_OP_create (); + gst->enter_cb = &guest_enter_reconnect_cb; + gst->entry_dcsn_cb = &guest_entry_dcsn_reconnect_cb; + gst->cb_cls = reconnect_ctx; - struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; - GNUNET_IDENTITY_ego_get_public_key (ego, &ego_pub_key); - GNUNET_GNS_lookup (gns, gns_name, &ego_pub_key, - GNUNET_GNSRECORD_TYPE_PLACE, GNUNET_GNS_LO_DEFAULT, - NULL, gns_result_guest_enter, gst); + guest_connect (gst); return gst; } @@ -2160,7 +2043,7 @@ GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_CONFIGURATION_Handle *cfg struct GNUNET_SOCIAL_TalkRequest * GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *gst, const char *method_name, - const struct GNUNET_ENV_Environment *env, + const struct GNUNET_PSYC_Environment *env, GNUNET_PSYC_TransmitNotifyData notify_data, void *notify_data_cls, enum GNUNET_SOCIAL_TalkFlags flags) @@ -2199,7 +2082,28 @@ GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr) void GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr) { - GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tr); + GNUNET_PSYC_transmit_cancel ( (struct GNUNET_PSYC_TransmitHandle *) tr); +} + + +/** + * Disconnect from a place. + * + * Invalidates guest handle. + * + * @param gst + * The guest to disconnect. + */ +void +GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst, + GNUNET_ContinuationCallback disconnect_cb, + void *cls) +{ + struct GNUNET_SOCIAL_Place *plc = &gst->plc; + + plc->disconnect_cb = disconnect_cb; + plc->disconnect_cls = cls; + place_disconnect (plc); } @@ -2221,28 +2125,19 @@ GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr) */ void GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst, - int keep_active, - struct GNUNET_ENV_Environment *env, - GNUNET_ContinuationCallback leave_cb, - void *leave_cls) + struct GNUNET_PSYC_Environment *env, + GNUNET_ContinuationCallback disconnect_cb, + void *cls) { - struct GNUNET_SOCIAL_Place *plc = &gst->plc; - - plc->is_disconnecting = GNUNET_YES; - plc->disconnect_cb = leave_cb; - plc->disconnect_cls = leave_cls; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Guest: leaving place.\n"); + struct GNUNET_MQ_Envelope *envelope; - if (GNUNET_NO == keep_active && NULL != plc->tmit) - { - GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL, - GNUNET_SOCIAL_TALK_NONE); - } - - GNUNET_CLIENT_MANAGER_disconnect (plc->client, GNUNET_YES, - &guest_cleanup, gst); + GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL, + GNUNET_SOCIAL_TALK_NONE); + gst->plc.disconnect_cb = disconnect_cb; + gst->plc.disconnect_cls = cls; + envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE); + GNUNET_MQ_send (gst->plc.mq, + envelope); } @@ -2262,6 +2157,67 @@ GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst) } +/** + * Obtain the public key of a place. + * + * @param plc + * Place. + * + * @return Public key of the place. + */ +const struct GNUNET_CRYPTO_EddsaPublicKey * +GNUNET_SOCIAL_place_get_pub_key (const struct GNUNET_SOCIAL_Place *plc) +{ + return &plc->pub_key; +} + + +/** + * Set message processing @a flags for a @a method_prefix. + * + * @param plc + * Place. + * @param method_prefix + * Method prefix @a flags apply to. + * @param flags + * The flags that apply to a matching @a method_prefix. + */ +void +GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc, + const char *method_prefix, + enum GNUNET_SOCIAL_MsgProcFlags flags) +{ + GNUNET_assert (NULL != method_prefix); + struct MsgProcRequest *mpreq; + uint16_t method_size = strnlen (method_prefix, + GNUNET_MAX_MESSAGE_SIZE + - sizeof (*mpreq)) + 1; + GNUNET_assert ('\0' == method_prefix[method_size - 1]); + + struct GNUNET_MQ_Envelope * + env = GNUNET_MQ_msg_extra (mpreq, method_size, + GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET); + mpreq->flags = htonl (flags); + GNUNET_memcpy (&mpreq[1], method_prefix, method_size); + + GNUNET_MQ_send (plc->mq, env); +} + + +/** + * Clear all message processing flags previously set for this place. + */ +void +GNUNET_SOCIAL_place_msg_proc_clear (struct GNUNET_SOCIAL_Place *plc) +{ + struct GNUNET_MessageHeader *req; + struct GNUNET_MQ_Envelope * + env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR); + + GNUNET_MQ_send (plc->mq, env); +} + + static struct GNUNET_SOCIAL_HistoryRequest * place_history_replay (struct GNUNET_SOCIAL_Place *plc, uint64_t start_message_id, @@ -2269,35 +2225,35 @@ place_history_replay (struct GNUNET_SOCIAL_Place *plc, uint64_t message_limit, const char *method_prefix, uint32_t flags, - struct GNUNET_SOCIAL_Slicer *slicer, + struct GNUNET_PSYC_Slicer *slicer, GNUNET_ResultCallback result_cb, void *cls) { struct GNUNET_PSYC_HistoryRequestMessage *req; struct GNUNET_SOCIAL_HistoryRequest *hist = GNUNET_malloc (sizeof (*hist)); hist->plc = plc; - hist->recv = GNUNET_PSYC_receive_create (NULL, slicer_message, slicer); + hist->slicer = slicer; hist->result_cb = result_cb; hist->cls = cls; - hist->op_id = GNUNET_CLIENT_MANAGER_op_add (plc->client, - &op_recv_history_result, hist); + hist->op_id = GNUNET_OP_add (plc->op, op_recv_history_result, hist, NULL); GNUNET_assert (NULL != method_prefix); uint16_t method_size = strnlen (method_prefix, - GNUNET_SERVER_MAX_MESSAGE_SIZE + GNUNET_MAX_MESSAGE_SIZE - sizeof (*req)) + 1; GNUNET_assert ('\0' == method_prefix[method_size - 1]); - req = GNUNET_malloc (sizeof (*req) + method_size); - req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY); - req->header.size = htons (sizeof (*req) + method_size); + + struct GNUNET_MQ_Envelope * + env = GNUNET_MQ_msg_extra (req, method_size, + GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY); req->start_message_id = GNUNET_htonll (start_message_id); req->end_message_id = GNUNET_htonll (end_message_id); req->message_limit = GNUNET_htonll (message_limit); req->flags = htonl (flags); req->op_id = GNUNET_htonll (hist->op_id); - memcpy (&req[1], method_prefix, method_size); + GNUNET_memcpy (&req[1], method_prefix, method_size); - GNUNET_CLIENT_MANAGER_transmit (plc->client, &req->header); + GNUNET_MQ_send (plc->mq, env); return hist; } @@ -2332,7 +2288,7 @@ GNUNET_SOCIAL_place_history_replay (struct GNUNET_SOCIAL_Place *plc, uint64_t end_message_id, const char *method_prefix, uint32_t flags, - struct GNUNET_SOCIAL_Slicer *slicer, + struct GNUNET_PSYC_Slicer *slicer, GNUNET_ResultCallback result_cb, void *cls) { @@ -2368,7 +2324,7 @@ GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc, uint64_t message_limit, const char *method_prefix, uint32_t flags, - struct GNUNET_SOCIAL_Slicer *slicer, + struct GNUNET_PSYC_Slicer *slicer, GNUNET_ResultCallback result_cb, void *cls) { @@ -2386,8 +2342,7 @@ GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc, void GNUNET_SOCIAL_place_history_replay_cancel (struct GNUNET_SOCIAL_HistoryRequest *hist) { - GNUNET_PSYC_receive_destroy (hist->recv); - GNUNET_CLIENT_MANAGER_op_cancel (hist->plc->client, hist->op_id); + GNUNET_OP_remove (hist->plc->op, hist->op_id); GNUNET_free (hist); } @@ -2407,19 +2362,17 @@ place_state_get (struct GNUNET_SOCIAL_Place *plc, look->var_cb = var_cb; look->result_cb = result_cb; look->cls = cls; - look->op_id = GNUNET_CLIENT_MANAGER_op_add (plc->client, - &op_recv_state_result, look); + look->op_id = GNUNET_OP_add (plc->op, &op_recv_state_result, look, NULL); GNUNET_assert (NULL != name); - size_t name_size = strnlen (name, GNUNET_SERVER_MAX_MESSAGE_SIZE + size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE - sizeof (*req)) + 1; - req = GNUNET_malloc (sizeof (*req) + name_size); - req->header.type = htons (type); - req->header.size = htons (sizeof (*req) + name_size); + struct GNUNET_MQ_Envelope * + env = GNUNET_MQ_msg_extra (req, name_size, type); req->op_id = GNUNET_htonll (look->op_id); - memcpy (&req[1], name, name_size); + GNUNET_memcpy (&req[1], name, name_size); - GNUNET_CLIENT_MANAGER_transmit (plc->client, &req->header); + GNUNET_MQ_send (plc->mq, env); return look; } @@ -2486,13 +2439,122 @@ GNUNET_SOCIAL_place_look_for (struct GNUNET_SOCIAL_Place *plc, void GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *look) { - GNUNET_CLIENT_MANAGER_op_cancel (look->plc->client, look->op_id); + GNUNET_OP_remove (look->plc->op, look->op_id); GNUNET_free (look); } +static void +op_recv_zone_add_place_result (void *cls, int64_t result, + const void *err_msg, uint16_t err_msg_size) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received zone add place result: %" PRId64 ".\n", result); + + struct ZoneAddPlaceHandle *add_plc = cls; + if (NULL != add_plc->result_cb) + add_plc->result_cb (add_plc->result_cls, result, err_msg, err_msg_size); + + GNUNET_free (add_plc); +} + + +/** + * Advertise @e place in the GNS zone of @e ego. + * + * @param app + * Application handle. + * @param ego + * Ego. + * @param place_pub_key + * Public key of place to add. + * @param name + * The name for the PLACE record to put in the zone. + * @param password + * Password used to encrypt the record or NULL to keep it cleartext. + * @param relay_count + * Number of elements in the @a relays array. + * @param relays + * List of relays to put in the PLACE record to advertise + * as entry points to the place in addition to the origin. + * @param expiration_time + * Expiration time of the record, use 0 to remove the record. + * @param result_cb + * Function called with the result of the operation. + * @param result_cls + * Closure for @a result_cb + * + * @return #GNUNET_OK if the request was sent, + * #GNUNET_SYSERR on error, e.g. the name/password is too long. + */ +int +GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const char *name, + const char *password, + const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, + const struct GNUNET_PeerIdentity *origin, + uint32_t relay_count, + const struct GNUNET_PeerIdentity *relays, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_ResultCallback result_cb, + void *result_cls) +{ + struct ZoneAddPlaceRequest *preq; + size_t name_size = strlen (name) + 1; + size_t password_size = strlen (password) + 1; + size_t relay_size = relay_count * sizeof (*relays); + size_t payload_size = name_size + password_size + relay_size; + + if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*preq) + payload_size) + return GNUNET_SYSERR; + + struct GNUNET_MQ_Envelope * + env = GNUNET_MQ_msg_extra (preq, payload_size, + GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE); + preq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us); + preq->ego_pub_key = ego->pub_key; + preq->place_pub_key = *place_pub_key; + preq->origin = *origin; + preq->relay_count = htonl (relay_count); + + char *p = (char *) &preq[1]; + GNUNET_memcpy (p, name, name_size); + p += name_size; + GNUNET_memcpy (p, password, password_size); + p += password_size; + GNUNET_memcpy (p, relays, relay_size); + + struct ZoneAddPlaceHandle * add_plc = GNUNET_malloc (sizeof (*add_plc)); + add_plc->result_cb = result_cb; + add_plc->result_cls = result_cls; + + preq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op, + op_recv_zone_add_place_result, + add_plc, NULL)); + + GNUNET_MQ_send (app->mq, env); + return GNUNET_OK; +} + + +static void +op_recv_zone_add_nym_result (void *cls, int64_t result, + const void *err_msg, uint16_t err_msg_size) +{ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received zone add nym result: %" PRId64 ".\n", result); + + struct ZoneAddNymHandle *add_nym = cls; + if (NULL != add_nym->result_cb) + add_nym->result_cb (add_nym->result_cls, result, err_msg, err_msg_size); + + GNUNET_free (add_nym); +} + + /** - * Add public key to the GNS zone of the @e ego. + * Add nym to the GNS zone of @e ego. * * @param cfg * Configuration. @@ -2500,37 +2562,265 @@ GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *look) * Ego. * @param name * The name for the PKEY record to put in the zone. - * @param pub_key - * Public key to add. + * @param nym_pub_key + * Public key of nym to add. * @param expiration_time * Expiration time of the record, use 0 to remove the record. * @param result_cb * Function called with the result of the operation. * @param result_cls * Closure for @a result_cb + * + * @return #GNUNET_OK if the request was sent, + * #GNUNET_SYSERR on error, e.g. the name is too long. + */ +int +GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app, + const struct GNUNET_SOCIAL_Ego *ego, + const char *name, + const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key, + struct GNUNET_TIME_Absolute expiration_time, + GNUNET_ResultCallback result_cb, + void *result_cls) +{ + struct ZoneAddNymRequest *nreq; + + size_t name_size = strlen (name) + 1; + if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size) + return GNUNET_SYSERR; + + struct GNUNET_MQ_Envelope * + env = GNUNET_MQ_msg_extra (nreq, name_size, + GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM); + nreq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us); + nreq->ego_pub_key = ego->pub_key; + nreq->nym_pub_key = *nym_pub_key; + GNUNET_memcpy (&nreq[1], name, name_size); + + struct ZoneAddNymHandle *add_nym = GNUNET_malloc (sizeof (*add_nym)); + add_nym->result_cb = result_cb; + add_nym->result_cls = result_cls; + + nreq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op, + op_recv_zone_add_nym_result, + add_nym, NULL)); + + GNUNET_MQ_send (app->mq, env); + return GNUNET_OK; +} + + +/*** APP ***/ + + +static void +app_connect (struct GNUNET_SOCIAL_App *app); + + +static void +app_reconnect (void *cls) +{ + app_connect (cls); +} + + +/** + * App client disconnected from service. + * + * Reconnect after backoff period. + */ +static void +app_disconnected (void *cls, enum GNUNET_MQ_Error error) +{ + struct GNUNET_SOCIAL_App *app = cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "App client disconnected (%d), re-connecting\n", + (int) error); + if (NULL != app->mq) + { + GNUNET_MQ_destroy (app->mq); + app->mq = NULL; + } + + app->reconnect_task = GNUNET_SCHEDULER_add_delayed (app->reconnect_delay, + app_reconnect, + app); + app->reconnect_delay = GNUNET_TIME_STD_BACKOFF (app->reconnect_delay); +} + + +static void +app_connect (struct GNUNET_SOCIAL_App *app) +{ + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_var_size (app_ego, + GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO, + struct AppEgoMessage, + app), + GNUNET_MQ_hd_fixed_size (app_ego_end, + GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO_END, + struct GNUNET_MessageHeader, + app), + GNUNET_MQ_hd_var_size (app_place, + GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE, + struct AppPlaceMessage, + app), + GNUNET_MQ_hd_fixed_size (app_place_end, + GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE_END, + struct GNUNET_MessageHeader, + app), + GNUNET_MQ_hd_var_size (app_result, + GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, + struct GNUNET_OperationResultMessage, + app), + GNUNET_MQ_handler_end () + }; + + app->mq = GNUNET_CLIENT_connect (app->cfg, "social", + handlers, app_disconnected, app); + GNUNET_assert (NULL != app->mq); + GNUNET_MQ_send_copy (app->mq, app->connect_env); +} + + +/** + * Connect application to the social service. + * + * The @host_place_cb and @guest_place_cb functions are + * initially called for each entered places, + * then later each time a new place is entered with the current application ID. + * + * @param cfg + * Configuration. + * @param id + * Application ID. + * @param ego_cb + * Function to notify about an available ego. + * @param host_cb + * Function to notify about a place entered as host. + * @param guest_cb + * Function to notify about a place entered as guest. + * @param cls + * Closure for the callbacks. + * + * @return Handle that can be used to stop listening. + */ +struct GNUNET_SOCIAL_App * +GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *id, + GNUNET_SOCIAL_AppEgoCallback ego_cb, + GNUNET_SOCIAL_AppHostPlaceCallback host_cb, + GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb, + GNUNET_SOCIAL_AppConnectedCallback connected_cb, + void *cls) +{ + uint16_t app_id_size = strnlen (id, GNUNET_SOCIAL_APP_MAX_ID_SIZE); + if (GNUNET_SOCIAL_APP_MAX_ID_SIZE == app_id_size) + return NULL; + app_id_size++; + + struct GNUNET_SOCIAL_App *app = GNUNET_malloc (sizeof *app); + app->cfg = cfg; + app->ego_cb = ego_cb; + app->host_cb = host_cb; + app->guest_cb = guest_cb; + app->connected_cb = connected_cb; + app->cb_cls = cls; + app->egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); + app->op = GNUNET_OP_create (); + app->id = GNUNET_malloc (app_id_size); + GNUNET_memcpy (app->id, id, app_id_size); + + struct AppConnectRequest *creq; + app->connect_env = GNUNET_MQ_msg_extra (creq, app_id_size, + GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT); + GNUNET_memcpy (&creq[1], app->id, app_id_size); + + app_connect (app); + return app; +} + + +static void +app_cleanup (struct GNUNET_SOCIAL_App *app) +{ + if (NULL != app->mq) + { + GNUNET_MQ_destroy (app->mq); + app->mq = NULL; + } + if (NULL != app->disconnect_cb) + { + app->disconnect_cb (app->disconnect_cls); + app->disconnect_cb = NULL; + } + GNUNET_free (app); +} + +/** + * Disconnect application. + * + * @param app + * Application handle. + * @param disconnect_cb + * Disconnect callback. + * @param disconnect_cls + * Disconnect closure. + */ +void +GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app, + GNUNET_ContinuationCallback disconnect_cb, + void *disconnect_cls) +{ + if (NULL == app) return; + + app->disconnect_cb = disconnect_cb; + app->disconnect_cls = disconnect_cls; + + if (NULL != app->mq) + { + struct GNUNET_MQ_Envelope *env = GNUNET_MQ_get_last_envelope (app->mq); + if (NULL != env) + { + GNUNET_MQ_notify_sent (env, (GNUNET_SCHEDULER_TaskCallback) app_cleanup, app); + } + else + { + app_cleanup (app); + } + } + else + { + app_cleanup (app); + } +} + + +/** + * Detach application from a place. + * + * Removes the place from the entered places list for this application. + * Note: this does not disconnect from the place. + * + * @see GNUNET_SOCIAL_host_disconnect() and GNUNET_SOCIAL_guest_disconnect() + * + * @param app + * Application. + * @param plc + * Place. */ void -GNUNET_SOCIAL_zone_add_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_IDENTITY_Ego *ego, - const char *name, - const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key, - struct GNUNET_TIME_Absolute expiration_time, - GNUNET_NAMESTORE_ContinuationWithStatus result_cb, - void *result_cls) -{ - if (NULL == namestore) - namestore = GNUNET_NAMESTORE_connect (cfg); - - struct GNUNET_GNSRECORD_Data rd = { }; - rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY; - rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; - rd.expiration_time = expiration_time.abs_value_us; - rd.data = pub_key; - rd.data_size = sizeof (*pub_key); - - GNUNET_NAMESTORE_records_store (namestore, - GNUNET_IDENTITY_ego_get_private_key (ego), - name, 1, &rd, result_cb, result_cls); +GNUNET_SOCIAL_app_detach (struct GNUNET_SOCIAL_App *app, + struct GNUNET_SOCIAL_Place *plc) +{ + struct AppDetachRequest *dreq; + struct GNUNET_MQ_Envelope * + env = GNUNET_MQ_msg (dreq, GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH); + dreq->place_pub_key = plc->pub_key; + dreq->ego_pub_key = plc->ego_pub_key; + + GNUNET_MQ_send (app->mq, env); }