/** * Retrieve latest values of counters for a channel master. * * The current value of counters are needed when a channel master is restarted, * so that it can continue incrementing the counters from their last value. * * @param h * Handle for the PSYCstore. * @param channel_key * Public key that identifies the channel. * @param ccb * Callback to call with the result. * @param ccb_cls * Closure for the @a ccb callback. * * @return Handle that can be used to cancel the operation. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_counters_get (struct GNUNET_PSYCSTORE_Handle *h, struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, GNUNET_PSYCSTORE_CountersCallback ccb, void *ccb_cls) { struct OperationRequest *req; struct GNUNET_PSYCSTORE_OperationHandle * op = GNUNET_malloc (sizeof (*op) + sizeof (*req)); op->h = h; op->data_cb = ccb; op->cls = ccb_cls; req = (struct OperationRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_COUNTERS_GET); req->header.size = htons (sizeof (*req)); req->channel_key = *channel_key; op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); return op; }
/** * Apply modifiers of a message to the current channel state. * * An error is returned if there are missing messages containing state * operations before the current one. * * @param h * Handle for the PSYCstore. * @param channel_key * The channel we are interested in. * @param message_id * ID of the message that contains the @a modifiers. * @param state_delta * Value of the _state_delta PSYC header variable of the message. * @param rcb * Callback to call with the result of the operation. * @param rcb_cls * Closure for the @a rcb callback. * * @return Handle that can be used to cancel the operation. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_state_modify (struct GNUNET_PSYCSTORE_Handle *h, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, uint64_t message_id, uint64_t state_delta, GNUNET_PSYCSTORE_ResultCallback rcb, void *rcb_cls) { struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; struct StateModifyRequest *req; op = GNUNET_malloc (sizeof (*op) + sizeof (*req)); op->h = h; op->res_cb = rcb; op->cls = rcb_cls; req = (struct StateModifyRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY); req->header.size = htons (sizeof (*req)); req->channel_key = *channel_key; req->message_id = GNUNET_htonll (message_id); req->state_delta = GNUNET_htonll (state_delta); op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); return op; /* FIXME: only the last operation is returned, * operation_cancel() should be able to cancel all of them. */ }
/** * Cancel a PSYCstore operation. Note that the operation MAY still * be executed; this merely cancels the continuation; if the request * was already transmitted, the service may still choose to complete * the operation. * * @param op Operation to cancel. */ void GNUNET_PSYCSTORE_operation_cancel (struct GNUNET_PSYCSTORE_OperationHandle *op) { struct GNUNET_PSYCSTORE_Handle *h = op->h; if (h->transmit_head != NULL && (h->transmit_head != op || NULL == h->client)) { /* request not active, can simply remove */ GNUNET_CONTAINER_DLL_remove (h->transmit_head, h->transmit_tail, op); GNUNET_free (op); return; } if (NULL != h->th) { /* request active but not yet with service, can still abort */ GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; GNUNET_CONTAINER_DLL_remove (h->transmit_head, h->transmit_tail, op); GNUNET_free (op); transmit_next (h); return; } /* request active with service, simply ensure continuations are not called */ op->res_cb = NULL; op->data_cb = NULL; }
/** * Retrieve all state variables for a channel with the given prefix. * * @param h * Handle for the PSYCstore. * @param channel_key * The channel we are interested in. * @param name_prefix * Prefix of state variable names to match. * @param scb * Callback to return matching state variables. * @param rcb * Callback to call with the result of the operation. * @param cls * Closure for the callbacks. * * @return Handle that can be used to cancel the operation. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_state_get_prefix (struct GNUNET_PSYCSTORE_Handle *h, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, const char *name_prefix, GNUNET_PSYCSTORE_StateCallback scb, GNUNET_PSYCSTORE_ResultCallback rcb, void *cls) { size_t name_size = strlen (name_prefix) + 1; struct OperationRequest *req; struct GNUNET_PSYCSTORE_OperationHandle * op = GNUNET_malloc (sizeof (*op) + sizeof (*req) + name_size); op->h = h; op->data_cb = (DataCallback) scb; op->res_cb = rcb; op->cls = cls; req = (struct OperationRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET_PREFIX); req->header.size = htons (sizeof (*req) + name_size); req->channel_key = *channel_key; memcpy (&req[1], name_prefix, name_size); op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); return op; }
/** * Test if a member was admitted to the channel at the given message ID. * * This is useful when relaying and replaying messages to check if a particular * slave has access to the message fragment with a given group generation. It * is also used when handling join requests to determine whether the slave is * currently admitted to the channel. * * @param h * Handle for the PSYCstore. * @param channel_key * The channel we are interested in. * @param slave_key * Public key of slave whose membership to check. * @param message_id * Message ID for which to do the membership test. * @param group_generation * Group generation of the fragment of the message to test. * It has relevance if the message consists of multiple fragments with * different group generations. * @param rcb * Callback to call with the test result. * @param rcb_cls * Closure for the callback. * * @return Operation handle that can be used to cancel the operation. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_membership_test (struct GNUNET_PSYCSTORE_Handle *h, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, uint64_t message_id, uint64_t group_generation, GNUNET_PSYCSTORE_ResultCallback rcb, void *rcb_cls) { struct MembershipTestRequest *req; struct GNUNET_PSYCSTORE_OperationHandle * op = GNUNET_malloc (sizeof (*op) + sizeof (*req)); op->h = h; op->res_cb = rcb; op->cls = rcb_cls; req = (struct MembershipTestRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST); req->header.size = htons (sizeof (*req)); req->channel_key = *channel_key; req->slave_key = *slave_key; req->message_id = GNUNET_htonll (message_id); req->group_generation = GNUNET_htonll (group_generation); op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); return op; }
/** * Store a message fragment sent to a channel. * * @param h Handle for the PSYCstore. * @param channel_key The channel the message belongs to. * @param message Message to store. * @param psycstore_flags Flags indicating whether the PSYC message contains * state modifiers. * @param rcb Callback to call with the result of the operation. * @param rcb_cls Closure for the callback. * * @return Handle that can be used to cancel the operation. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_fragment_store (struct GNUNET_PSYCSTORE_Handle *h, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, const struct GNUNET_MULTICAST_MessageHeader *msg, enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags, GNUNET_PSYCSTORE_ResultCallback rcb, void *rcb_cls) { uint16_t size = ntohs (msg->header.size); struct FragmentStoreRequest *req; struct GNUNET_PSYCSTORE_OperationHandle * op = GNUNET_malloc (sizeof (*op) + sizeof (*req) + size); op->h = h; op->res_cb = rcb; op->cls = rcb_cls; req = (struct FragmentStoreRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE); req->header.size = htons (sizeof (*req) + size); req->channel_key = *channel_key; req->psycstore_flags = htonl (psycstore_flags); memcpy (&req[1], msg, size); op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); return op; }
/** * Try again to connect to the identity service. * * @param cls handle to the identity service. * @param tc scheduler context */ static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_IDENTITY_Handle *h = cls; struct GNUNET_IDENTITY_Operation *op; struct GNUNET_MessageHeader msg; h->reconnect_task = NULL; LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to identity service.\n"); GNUNET_assert (NULL == h->client); h->client = GNUNET_CLIENT_connect ("identity", h->cfg); GNUNET_assert (NULL != h->client); if ( (NULL == h->op_head) || (GNUNET_MESSAGE_TYPE_IDENTITY_START != ntohs (h->op_head->msg->type)) ) { op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + sizeof (struct GNUNET_MessageHeader)); op->h = h; op->msg = (const struct GNUNET_MessageHeader *) &op[1]; msg.size = htons (sizeof (msg)); msg.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_START); memcpy (&op[1], &msg, sizeof (msg)); GNUNET_CONTAINER_DLL_insert (h->op_head, h->op_tail, op); } transmit_next (h); GNUNET_assert (NULL != h->th); }
/** * Update signed values of state variables in the state store. * * @param h * Handle for the PSYCstore. * @param channel_key * The channel we are interested in. * @param message_id * Message ID that contained the state @a hash. * @param hash * Hash of the serialized full state. * @param rcb * Callback to call with the result of the operation. * @param rcb_cls * Closure for the callback. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_state_hash_update (struct GNUNET_PSYCSTORE_Handle *h, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, uint64_t message_id, const struct GNUNET_HashCode *hash, GNUNET_PSYCSTORE_ResultCallback rcb, void *rcb_cls) { struct StateHashUpdateRequest *req; struct GNUNET_PSYCSTORE_OperationHandle * op = GNUNET_malloc (sizeof (*op) + sizeof (*req)); op->h = h; op->res_cb = rcb; op->cls = rcb_cls; req = (struct StateHashUpdateRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_RESET); req->header.size = htons (sizeof (*req)); req->channel_key = *channel_key; req->hash = *hash; op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); return op; }
/** * Try again to connect to the PSYCstore service. * * @param cls Handle to the PSYCstore service. * @param tc Scheduler context. */ static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_PSYCSTORE_Handle *h = cls; h->reconnect_task = NULL; LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to PSYCstore service.\n"); GNUNET_assert (NULL == h->client); h->client = GNUNET_CLIENT_connect ("psycstore", h->cfg); GNUNET_assert (NULL != h->client); transmit_next (h); }
/** * Store synchronized state. * * @param h * Handle for the PSYCstore. * @param channel_key * The channel we are interested in. * @param max_state_message_id * ID of the last stateful message before @a state_hash_message_id. * @param state_hash_message_id * ID of the message that contains the state_hash PSYC header variable. * @param modifier_count * Number of elements in the @a modifiers array. * @param modifiers * Full state to store. * @param rcb * Callback to call with the result of the operation. * @param rcb_cls * Closure for the callback. * * @return Handle that can be used to cancel the operation. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_state_sync (struct GNUNET_PSYCSTORE_Handle *h, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, uint64_t max_state_message_id, uint64_t state_hash_message_id, size_t modifier_count, const struct GNUNET_PSYC_Modifier *modifiers, GNUNET_PSYCSTORE_ResultCallback rcb, void *rcb_cls) { struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; size_t i; for (i = 0; i < modifier_count; i++) { struct StateSyncRequest *req; uint16_t name_size = strlen (modifiers[i].name) + 1; op = GNUNET_malloc (sizeof (*op) + sizeof (*req) + name_size + modifiers[i].value_size); op->h = h; op->res_cb = rcb; op->cls = rcb_cls; req = (struct StateSyncRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC); req->header.size = htons (sizeof (*req) + name_size + modifiers[i].value_size); req->channel_key = *channel_key; req->max_state_message_id = GNUNET_htonll (max_state_message_id); req->state_hash_message_id = GNUNET_htonll (state_hash_message_id); req->name_size = htons (name_size); req->flags = (0 == i) ? STATE_OP_FIRST : (modifier_count - 1 == i) ? STATE_OP_LAST : 0; memcpy (&req[1], modifiers[i].name, name_size); memcpy ((char *) &req[1] + name_size, modifiers[i].value, modifiers[i].value_size); op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); } return op; }
/** * Retrieve all fragments of messages in a message ID range. * * @param h * Handle for the PSYCstore. * @param channel_key * The channel we are interested in. * @param slave_key * The slave requesting the message. * If not NULL, a membership test is performed first * and the message is only returned if the slave has access to it. * @param first_message_id * First message ID to retrieve. * @param last_message_id * Last consecutive message ID to retrieve. * @param fragment_limit * Maximum number of fragments to retrieve. * @param method_prefix * Retrieve only messages with a matching method prefix. * @todo Implement method_prefix query. * @param fragment_cb * Callback to call with the retrieved fragments. * @param result_cb * Callback to call with the result of the operation. * @param cls * Closure for the callbacks. * * @return Handle that can be used to cancel the operation. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, uint64_t first_message_id, uint64_t last_message_id, uint64_t fragment_limit, const char *method_prefix, GNUNET_PSYCSTORE_FragmentCallback fragment_cb, GNUNET_PSYCSTORE_ResultCallback rcb, void *cls) { struct MessageGetRequest *req; if (NULL == method_prefix) method_prefix = ""; uint16_t method_size = strnlen (method_prefix, GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*req)) + 1; struct GNUNET_PSYCSTORE_OperationHandle * op = GNUNET_malloc (sizeof (*op) + sizeof (*req)); op->h = h; op->data_cb = (DataCallback) fragment_cb; op->res_cb = rcb; op->cls = cls; req = (struct MessageGetRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET); req->header.size = htons (sizeof (*req) + method_size); req->channel_key = *channel_key; req->first_message_id = GNUNET_htonll (first_message_id); req->last_message_id = GNUNET_htonll (last_message_id); req->fragment_limit = GNUNET_htonll (fragment_limit); if (NULL != slave_key) { req->slave_key = *slave_key; req->do_membership_test = GNUNET_YES; } memcpy (&req[1], method_prefix, method_size); ((char *) &req[1])[method_size - 1] = '\0'; op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); return op; }
/** * Store join/leave events for a PSYC channel in order to be able to answer * membership test queries later. * * @param h * Handle for the PSYCstore. * @param channel_key * The channel where the event happened. * @param slave_key * Public key of joining/leaving slave. * @param did_join * #GNUNET_YES on join, #GNUNET_NO on part. * @param announced_at * ID of the message that announced the membership change. * @param effective_since * Message ID this membership change is in effect since. * For joins it is <= announced_at, for parts it is always 0. * @param group_generation * In case of a part, the last group generation the slave has access to. * It has relevance when a larger message have fragments with different * group generations. * @param rcb * Callback to call with the result of the storage operation. * @param rcb_cls * Closure for the callback. * * @return Operation handle that can be used to cancel the operation. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_membership_store (struct GNUNET_PSYCSTORE_Handle *h, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, int did_join, uint64_t announced_at, uint64_t effective_since, uint64_t group_generation, GNUNET_PSYCSTORE_ResultCallback rcb, void *rcb_cls) { GNUNET_assert (NULL != h); GNUNET_assert (NULL != channel_key); GNUNET_assert (NULL != slave_key); GNUNET_assert (GNUNET_YES == did_join || GNUNET_NO == did_join); GNUNET_assert (did_join ? effective_since <= announced_at : effective_since == 0); struct MembershipStoreRequest *req; struct GNUNET_PSYCSTORE_OperationHandle * op = GNUNET_malloc (sizeof (*op) + sizeof (*req)); op->h = h; op->res_cb = rcb; op->cls = rcb_cls; req = (struct MembershipStoreRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE); req->header.size = htons (sizeof (*req)); req->channel_key = *channel_key; req->slave_key = *slave_key; req->did_join = did_join; req->announced_at = GNUNET_htonll (announced_at); req->effective_since = GNUNET_htonll (effective_since); req->group_generation = GNUNET_htonll (group_generation); op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); return op; }
/** * Renames an existing identity. * * @param id identity service to use * @param old_name old name * @param new_name desired new name * @param cb function to call with the result (will only be called once) * @param cb_cls closure for @a cb * @return handle to abort the operation */ struct GNUNET_IDENTITY_Operation * GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *id, const char *old_name, const char *new_name, GNUNET_IDENTITY_Continuation cb, void *cb_cls) { struct GNUNET_IDENTITY_Operation *op; struct GNUNET_IDENTITY_RenameMessage *grm; size_t slen_old; size_t slen_new; char *dst; slen_old = strlen (old_name) + 1; slen_new = strlen (new_name) + 1; if ( (slen_old >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (slen_old + slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_RenameMessage)) ) { GNUNET_break (0); return NULL; } op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + sizeof (struct GNUNET_IDENTITY_RenameMessage) + slen_old + slen_new); op->h = id; op->cont = cb; op->cls = cb_cls; grm = (struct GNUNET_IDENTITY_RenameMessage *) &op[1]; grm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_RENAME); grm->header.size = htons (sizeof (struct GNUNET_IDENTITY_RenameMessage) + slen_old + slen_new); grm->old_name_len = htons (slen_old); grm->new_name_len = htons (slen_new); dst = (char *) &grm[1]; memcpy (dst, old_name, slen_old); memcpy (&dst[slen_old], new_name, slen_new); op->msg = &grm->header; GNUNET_CONTAINER_DLL_insert_tail (id->op_head, id->op_tail, op); if (NULL == id->th) transmit_next (id); return op; }
/** * Create a new identity with the given name. * * @param id identity service to use * @param name desired name * @param cont function to call with the result (will only be called once) * @param cont_cls closure for @a cont * @return handle to abort the operation */ struct GNUNET_IDENTITY_Operation * GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *id, const char *name, GNUNET_IDENTITY_Continuation cont, void *cont_cls) { struct GNUNET_IDENTITY_Operation *op; struct GNUNET_IDENTITY_CreateRequestMessage *crm; struct GNUNET_CRYPTO_EcdsaPrivateKey *pk; size_t slen; slen = strlen (name) + 1; pk = GNUNET_CRYPTO_ecdsa_key_create (); if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_CreateRequestMessage)) { GNUNET_break (0); GNUNET_free (pk); return NULL; } op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) + slen); op->h = id; op->cont = cont; op->cls = cont_cls; crm = (struct GNUNET_IDENTITY_CreateRequestMessage *) &op[1]; crm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_CREATE); crm->header.size = htons (sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) + slen); crm->name_len = htons (slen); crm->reserved = htons (0); crm->private_key = *pk; memcpy (&crm[1], name, slen); op->msg = &crm->header; GNUNET_CONTAINER_DLL_insert_tail (id->op_head, id->op_tail, op); if (NULL == id->th) transmit_next (id); GNUNET_free (pk); return op; }
/** * Transmit next message to service. * * @param cls The 'struct GNUNET_PSYCSTORE_Handle'. * @param size Number of bytes available in buf. * @param buf Where to copy the message. * @return Number of bytes copied to buf. */ static size_t send_next_message (void *cls, size_t size, void *buf) { struct GNUNET_PSYCSTORE_Handle *h = cls; struct GNUNET_PSYCSTORE_OperationHandle *op = h->transmit_head; size_t ret; h->th = NULL; if (NULL == op) return 0; ret = ntohs (op->msg->size); if (ret > size) { reschedule_connect (h); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %d to PSYCstore service. ID: %" PRIu64 "\n", ntohs (op->msg->type), op->op_id); memcpy (buf, op->msg, ret); GNUNET_CONTAINER_DLL_remove (h->transmit_head, h->transmit_tail, op); if (NULL == op->res_cb && NULL == op->data_cb) { GNUNET_free (op); } else { GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); } if (NULL != h->transmit_head) transmit_next (h); if (GNUNET_NO == h->in_receive) { h->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); } return ret; }
/** * Transmit next message to service. * * @param cls the `struct GNUNET_IDENTITY_Handle`. * @param size number of bytes available in @a buf * @param buf where to copy the message * @return number of bytes copied to buf */ static size_t send_next_message (void *cls, size_t size, void *buf) { struct GNUNET_IDENTITY_Handle *h = cls; struct GNUNET_IDENTITY_Operation *op = h->op_head; size_t ret; h->th = NULL; if (NULL == op) return 0; ret = ntohs (op->msg->size); if (ret > size) { reschedule_connect (h); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %d to identity service\n", ntohs (op->msg->type)); memcpy (buf, op->msg, ret); if ( (NULL == op->cont) && (NULL == op->cb) ) { GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); GNUNET_free (op); transmit_next (h); } if (GNUNET_NO == h->in_receive) { h->in_receive = GNUNET_YES; GNUNET_CLIENT_receive (h->client, &message_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); } return ret; }
/** * Retrieve message fragments by fragment ID range. * * @param h * Handle for the PSYCstore. * @param channel_key * The channel we are interested in. * @param slave_key * The slave requesting the fragment. If not NULL, a membership test is * performed first and the fragment is only returned if the slave has * access to it. * @param first_fragment_id * First fragment ID to retrieve. * Use 0 to get the latest message fragment. * @param last_fragment_id * Last consecutive fragment ID to retrieve. * Use 0 to get the latest message fragment. * @param fragment_limit * Maximum number of fragments to retrieve. * @param fragment_cb * Callback to call with the retrieved fragments. * @param rcb * Callback to call with the result of the operation. * @param cls * Closure for the callbacks. * * @return Handle that can be used to cancel the operation. */ struct GNUNET_PSYCSTORE_OperationHandle * GNUNET_PSYCSTORE_fragment_get (struct GNUNET_PSYCSTORE_Handle *h, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, uint64_t first_fragment_id, uint64_t last_fragment_id, GNUNET_PSYCSTORE_FragmentCallback fragment_cb, GNUNET_PSYCSTORE_ResultCallback rcb, void *cls) { struct FragmentGetRequest *req; struct GNUNET_PSYCSTORE_OperationHandle * op = GNUNET_malloc (sizeof (*op) + sizeof (*req)); op->h = h; op->data_cb = (DataCallback) fragment_cb; op->res_cb = rcb; op->cls = cls; req = (struct FragmentGetRequest *) &op[1]; op->msg = (struct GNUNET_MessageHeader *) req; req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET); req->header.size = htons (sizeof (*req)); req->channel_key = *channel_key; req->first_fragment_id = GNUNET_htonll (first_fragment_id); req->last_fragment_id = GNUNET_htonll (last_fragment_id); if (NULL != slave_key) { req->slave_key = *slave_key; req->do_membership_test = GNUNET_YES; } op->op_id = get_next_op_id (h); req->op_id = GNUNET_htonll (op->op_id); GNUNET_CONTAINER_DLL_insert_tail (h->transmit_head, h->transmit_tail, op); transmit_next (h); return op; }
/** * Set the preferred/default identity for a service. * * @param id identity service to inform * @param service_name for which service is an identity set * @param ego new default identity to be set for this service * @param cont function to call once the operation finished * @param cont_cls closure for @a cont * @return handle to abort the operation */ struct GNUNET_IDENTITY_Operation * GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *id, const char *service_name, struct GNUNET_IDENTITY_Ego *ego, GNUNET_IDENTITY_Continuation cont, void *cont_cls) { struct GNUNET_IDENTITY_Operation *op; struct GNUNET_IDENTITY_SetDefaultMessage *sdm; size_t slen; slen = strlen (service_name) + 1; if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_SetDefaultMessage)) { GNUNET_break (0); return NULL; } op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) + slen); op->h = id; op->cont = cont; op->cls = cont_cls; sdm = (struct GNUNET_IDENTITY_SetDefaultMessage *) &op[1]; sdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT); sdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) + slen); sdm->name_len = htons (slen); sdm->reserved = htons (0); sdm->private_key = *ego->pk; memcpy (&sdm[1], service_name, slen); op->msg = &sdm->header; GNUNET_CONTAINER_DLL_insert_tail (id->op_head, id->op_tail, op); if (NULL == id->th) transmit_next (id); return op; }
/** * Delete an existing identity. * * @param id identity service to use * @param name name of the identity to delete * @param cb function to call with the result (will only be called once) * @param cb_cls closure for @a cb * @return handle to abort the operation */ struct GNUNET_IDENTITY_Operation * GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *id, const char *name, GNUNET_IDENTITY_Continuation cb, void *cb_cls) { struct GNUNET_IDENTITY_Operation *op; struct GNUNET_IDENTITY_DeleteMessage *gdm; size_t slen; slen = strlen (name) + 1; if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GNUNET_IDENTITY_DeleteMessage)) { GNUNET_break (0); return NULL; } op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + sizeof (struct GNUNET_IDENTITY_DeleteMessage) + slen); op->h = id; op->cont = cb; op->cls = cb_cls; gdm = (struct GNUNET_IDENTITY_DeleteMessage *) &op[1]; gdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_DELETE); gdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_DeleteMessage) + slen); gdm->name_len = htons (slen); gdm->reserved = htons (0); memcpy (&gdm[1], name, slen); op->msg = &gdm->header; GNUNET_CONTAINER_DLL_insert_tail (id->op_head, id->op_tail, op); if (NULL == id->th) transmit_next (id); return op; }
/** * Cancel an identity operation. Note that the operation MAY still * be executed; this merely cancels the continuation; if the request * was already transmitted, the service may still choose to complete * the operation. * * @param op operation to cancel */ void GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op) { struct GNUNET_IDENTITY_Handle *h = op->h; if ( (h->op_head != op) || (NULL == h->client) ) { /* request not active, can simply remove */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client aborted non-head operation, simply removing it\n"); GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); GNUNET_free (op); return; } if (NULL != h->th) { /* request active but not yet with service, can still abort */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client aborted head operation prior to transmission, aborting it\n"); GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); h->th = NULL; GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); GNUNET_free (op); transmit_next (h); return; } /* request active with service, simply ensure continuations are not called */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client aborted active request, NULLing continuation\n"); op->cont = NULL; op->cb = NULL; }