/* This file is part of GNUnet. Copyright (C) 2016 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file reclaim/reclaim_api.c * @brief api to interact with the reclaim service * @author Martin Schanzenbach */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_constants.h" #include "gnunet_mq_lib.h" #include "gnunet_protocols.h" #include "gnunet_reclaim_lib.h" #include "gnunet_reclaim_service.h" #include "reclaim.h" #define LOG(kind, ...) GNUNET_log_from (kind, "reclaim-api", __VA_ARGS__) /** * Handle for an operation with the service. */ struct GNUNET_RECLAIM_Operation { /** * Main handle. */ struct GNUNET_RECLAIM_Handle *h; /** * We keep operations in a DLL. */ struct GNUNET_RECLAIM_Operation *next; /** * We keep operations in a DLL. */ struct GNUNET_RECLAIM_Operation *prev; /** * Message to send to the service. * Allocated at the end of this struct. */ const struct GNUNET_MessageHeader *msg; /** * Continuation to invoke after attribute store call */ GNUNET_RECLAIM_ContinuationWithStatus as_cb; /** * Attribute result callback */ GNUNET_RECLAIM_AttributeResult ar_cb; /** * Attribute result callback */ GNUNET_RECLAIM_AttributeTicketResult atr_cb; /** * Credential result callback */ GNUNET_RECLAIM_CredentialResult at_cb; /** * Revocation result callback */ GNUNET_RECLAIM_ContinuationWithStatus rvk_cb; /** * Ticket result callback */ GNUNET_RECLAIM_TicketCallback tr_cb; /** * Ticket issue result callback */ GNUNET_RECLAIM_IssueTicketCallback ti_cb; /** * Envelope with the message for this queue entry. */ struct GNUNET_MQ_Envelope *env; /** * request id */ uint32_t r_id; /** * Closure for @e cont or @e cb. */ void *cls; }; /** * Handle for a ticket iterator operation */ struct GNUNET_RECLAIM_TicketIterator { /** * Kept in a DLL. */ struct GNUNET_RECLAIM_TicketIterator *next; /** * Kept in a DLL. */ struct GNUNET_RECLAIM_TicketIterator *prev; /** * Main handle to access the idp. */ struct GNUNET_RECLAIM_Handle *h; /** * Function to call on completion. */ GNUNET_SCHEDULER_TaskCallback finish_cb; /** * Closure for @e finish_cb. */ void *finish_cb_cls; /** * The continuation to call with the results */ GNUNET_RECLAIM_TicketCallback tr_cb; /** * Closure for @e tr_cb. */ void *cls; /** * Function to call on errors. */ GNUNET_SCHEDULER_TaskCallback error_cb; /** * Closure for @e error_cb. */ void *error_cb_cls; /** * Envelope of the message to send to the service, if not yet * sent. */ struct GNUNET_MQ_Envelope *env; /** * The operation id this zone iteration operation has */ uint32_t r_id; }; /** * Handle for a attribute iterator operation */ struct GNUNET_RECLAIM_AttributeIterator { /** * Kept in a DLL. */ struct GNUNET_RECLAIM_AttributeIterator *next; /** * Kept in a DLL. */ struct GNUNET_RECLAIM_AttributeIterator *prev; /** * Main handle to access the service. */ struct GNUNET_RECLAIM_Handle *h; /** * Function to call on completion. */ GNUNET_SCHEDULER_TaskCallback finish_cb; /** * Closure for @e finish_cb. */ void *finish_cb_cls; /** * The continuation to call with the results */ GNUNET_RECLAIM_AttributeResult proc; /** * Closure for @e proc. */ void *proc_cls; /** * Function to call on errors. */ GNUNET_SCHEDULER_TaskCallback error_cb; /** * Closure for @e error_cb. */ void *error_cb_cls; /** * Envelope of the message to send to the service, if not yet * sent. */ struct GNUNET_MQ_Envelope *env; /** * Private key of the zone. */ struct GNUNET_IDENTITY_PrivateKey identity; /** * The operation id this zone iteration operation has */ uint32_t r_id; }; /** * Handle for a credential iterator operation */ struct GNUNET_RECLAIM_CredentialIterator { /** * Kept in a DLL. */ struct GNUNET_RECLAIM_CredentialIterator *next; /** * Kept in a DLL. */ struct GNUNET_RECLAIM_CredentialIterator *prev; /** * Main handle to access the service. */ struct GNUNET_RECLAIM_Handle *h; /** * Function to call on completion. */ GNUNET_SCHEDULER_TaskCallback finish_cb; /** * Closure for @e finish_cb. */ void *finish_cb_cls; /** * The continuation to call with the results */ GNUNET_RECLAIM_CredentialResult proc; /** * Closure for @e proc. */ void *proc_cls; /** * Function to call on errors. */ GNUNET_SCHEDULER_TaskCallback error_cb; /** * Closure for @e error_cb. */ void *error_cb_cls; /** * Envelope of the message to send to the service, if not yet * sent. */ struct GNUNET_MQ_Envelope *env; /** * Private key of the zone. */ struct GNUNET_IDENTITY_PrivateKey identity; /** * The operation id this zone iteration operation has */ uint32_t r_id; }; /** * Handle to the service. */ struct GNUNET_RECLAIM_Handle { /** * Configuration to use. */ const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Socket (if available). */ struct GNUNET_CLIENT_Connection *client; /** * Closure for 'cb'. */ void *cb_cls; /** * Head of active operations. */ struct GNUNET_RECLAIM_Operation *op_head; /** * Tail of active operations. */ struct GNUNET_RECLAIM_Operation *op_tail; /** * Head of active iterations */ struct GNUNET_RECLAIM_AttributeIterator *it_head; /** * Tail of active iterations */ struct GNUNET_RECLAIM_AttributeIterator *it_tail; /** * Head of active iterations */ struct GNUNET_RECLAIM_CredentialIterator *ait_head; /** * Tail of active iterations */ struct GNUNET_RECLAIM_CredentialIterator *ait_tail; /** * Head of active iterations */ struct GNUNET_RECLAIM_TicketIterator *ticket_it_head; /** * Tail of active iterations */ struct GNUNET_RECLAIM_TicketIterator *ticket_it_tail; /** * Currently pending transmission request, or NULL for none. */ struct GNUNET_CLIENT_TransmitHandle *th; /** * Task doing exponential back-off trying to reconnect. */ struct GNUNET_SCHEDULER_Task *reconnect_task; /** * Time for next connect retry. */ struct GNUNET_TIME_Relative reconnect_backoff; /** * Connection to service (if available). */ struct GNUNET_MQ_Handle *mq; /** * Request Id generator. Incremented by one for each request. */ uint32_t r_id_gen; /** * Are we polling for incoming messages right now? */ int in_receive; }; /** * Try again to connect to the service. * * @param h handle to the reclaim service. */ static void reconnect (struct GNUNET_RECLAIM_Handle *h); /** * Reconnect * * @param cls the handle */ static void reconnect_task (void *cls) { struct GNUNET_RECLAIM_Handle *handle = cls; handle->reconnect_task = NULL; reconnect (handle); } /** * Disconnect from service and then reconnect. * * @param handle our service */ static void force_reconnect (struct GNUNET_RECLAIM_Handle *handle) { GNUNET_MQ_destroy (handle->mq); handle->mq = NULL; handle->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff); handle->reconnect_task = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff, &reconnect_task, handle); } /** * Free @a it. * * @param it entry to free */ static void free_it (struct GNUNET_RECLAIM_AttributeIterator *it) { struct GNUNET_RECLAIM_Handle *h = it->h; GNUNET_CONTAINER_DLL_remove (h->it_head, h->it_tail, it); if (NULL != it->env) GNUNET_MQ_discard (it->env); GNUNET_free (it); } /** * Free @a it. * * @param ait entry to free */ static void free_ait (struct GNUNET_RECLAIM_CredentialIterator *ait) { struct GNUNET_RECLAIM_Handle *h = ait->h; GNUNET_CONTAINER_DLL_remove (h->ait_head, h->ait_tail, ait); if (NULL != ait->env) GNUNET_MQ_discard (ait->env); GNUNET_free (ait); } /** * Free @a op * * @param op the operation to free */ static void free_op (struct GNUNET_RECLAIM_Operation *op) { if (NULL == op) return; if (NULL != op->env) GNUNET_MQ_discard (op->env); GNUNET_free (op); } /** * Generic error handler, called with the appropriate error code and * the same closure specified at the creation of the message queue. * Not every message queue implementation supports an error handler. * * @param cls closure with the `struct GNUNET_GNS_Handle *` * @param error error code */ static void mq_error_handler (void *cls, enum GNUNET_MQ_Error error) { struct GNUNET_RECLAIM_Handle *handle = cls; force_reconnect (handle); } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE * * @param cls * @param msg the message we received */ static void handle_success_response (void *cls, const struct SuccessResultMessage *msg) { struct GNUNET_RECLAIM_Handle *h = cls; struct GNUNET_RECLAIM_Operation *op; uint32_t r_id = ntohl (msg->id); int res; const char *emsg; for (op = h->op_head; NULL != op; op = op->next) if (op->r_id == r_id) break; if (NULL == op) return; res = ntohl (msg->op_result); LOG (GNUNET_ERROR_TYPE_DEBUG, "Received SUCCESS_RESPONSE with result %d\n", res); /* TODO: add actual error message to response... */ if (GNUNET_SYSERR == res) emsg = _ ("failed to store record\n"); else emsg = NULL; if (NULL != op->as_cb) op->as_cb (op->cls, res, emsg); GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); free_op (op); } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT * * @param cls * @param msg the message we received * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ static int check_consume_ticket_result (void *cls, const struct ConsumeTicketResultMessage *msg) { size_t msg_len; size_t attrs_len; size_t pl_len; size_t key_len; msg_len = ntohs (msg->header.size); attrs_len = ntohl (msg->attrs_len); key_len = ntohl (msg->key_len); pl_len = ntohl (msg->presentations_len); if (msg_len != sizeof(*msg) + attrs_len + pl_len + key_len) { GNUNET_break (0); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT * * @param cls * @param msg the message we received */ static void handle_consume_ticket_result (void *cls, const struct ConsumeTicketResultMessage *msg) { struct GNUNET_IDENTITY_PublicKey identity; struct GNUNET_RECLAIM_Handle *h = cls; struct GNUNET_RECLAIM_Operation *op; size_t attrs_len; size_t pl_len; size_t key_len; size_t read; uint32_t r_id = ntohl (msg->id); char *read_ptr; attrs_len = ntohl (msg->attrs_len); key_len = ntohl (msg->key_len); pl_len = ntohl (msg->presentations_len); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing ticket result.\n"); for (op = h->op_head; NULL != op; op = op->next) if (op->r_id == r_id) break; if (NULL == op) return; { struct GNUNET_RECLAIM_AttributeList *attrs; struct GNUNET_RECLAIM_AttributeListEntry *le; struct GNUNET_RECLAIM_PresentationList *pl; struct GNUNET_RECLAIM_PresentationListEntry *ple; read_ptr = (char *) &msg[1]; GNUNET_assert (GNUNET_SYSERR != GNUNET_IDENTITY_read_public_key_from_buffer (read_ptr, key_len, &identity, &read)); read_ptr += read; attrs = GNUNET_RECLAIM_attribute_list_deserialize (read_ptr, attrs_len); read_ptr += attrs_len; pl = GNUNET_RECLAIM_presentation_list_deserialize (read_ptr, pl_len); if (NULL != op->atr_cb) { if (NULL == attrs) { op->atr_cb (op->cls, &identity, NULL, NULL); } else { for (le = attrs->list_head; NULL != le; le = le->next) { if (GNUNET_NO == GNUNET_RECLAIM_id_is_zero (&le->attribute->credential)) { for (ple = pl->list_head; NULL != ple; ple = ple->next) { if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (&le->attribute->credential, &ple->presentation->credential_id)) { op->atr_cb (op->cls, &identity, le->attribute, ple->presentation); break; } } } else // No credentials { op->atr_cb (op->cls, &identity, le->attribute, NULL); } } } op->atr_cb (op->cls, NULL, NULL, NULL); } if (NULL != attrs) GNUNET_RECLAIM_attribute_list_destroy (attrs); if (NULL != pl) GNUNET_RECLAIM_presentation_list_destroy (pl); GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); free_op (op); return; } GNUNET_assert (0); } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT * * @param cls * @param msg the message we received * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ static int check_attribute_result (void *cls, const struct AttributeResultMessage *msg) { size_t msg_len; size_t attr_len; size_t key_len; msg_len = ntohs (msg->header.size); attr_len = ntohl (msg->attr_len); key_len = ntohl (msg->pkey_len); if (msg_len != sizeof(*msg) + attr_len + key_len) { GNUNET_break (0); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT * * @param cls * @param msg the message we received */ static void handle_attribute_result (void *cls, const struct AttributeResultMessage *msg) { static struct GNUNET_IDENTITY_PublicKey identity; struct GNUNET_RECLAIM_Handle *h = cls; struct GNUNET_RECLAIM_AttributeIterator *it; struct GNUNET_RECLAIM_Operation *op; size_t attr_len; size_t key_len; size_t read; uint32_t r_id = ntohl (msg->id); char *buf; attr_len = ntohl (msg->attr_len); key_len = ntohl (msg->pkey_len); LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing attribute result.\n"); for (it = h->it_head; NULL != it; it = it->next) if (it->r_id == r_id) break; for (op = h->op_head; NULL != op; op = op->next) if (op->r_id == r_id) break; if ((NULL == it) && (NULL == op)) return; buf = (char *) &msg[1]; if (0 == key_len) { if ((NULL == it) && (NULL == op)) { GNUNET_break (0); force_reconnect (h); return; } if (NULL != it) { if (NULL != it->finish_cb) it->finish_cb (it->finish_cb_cls); free_it (it); } if (NULL != op) { if (NULL != op->ar_cb) op->ar_cb (op->cls, NULL, NULL); GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); free_op (op); } return; } { struct GNUNET_RECLAIM_Attribute *attr; GNUNET_assert (GNUNET_SYSERR != GNUNET_IDENTITY_read_public_key_from_buffer (buf, key_len, &identity, &read)); buf += read; GNUNET_RECLAIM_attribute_deserialize (buf, attr_len, &attr); if (NULL != it) { if (NULL != it->proc) it->proc (it->proc_cls, &identity, attr); } else if (NULL != op) { if (NULL != op->ar_cb) op->ar_cb (op->cls, &identity, attr); } GNUNET_free (attr); return; } GNUNET_assert (0); } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_credential_RESULT * * @param cls * @param msg the message we received * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ static int check_credential_result (void *cls, const struct CredentialResultMessage *msg) { size_t msg_len; size_t cred_len; size_t key_len; msg_len = ntohs (msg->header.size); cred_len = ntohl (msg->credential_len); key_len = ntohl (msg->key_len); if (msg_len != sizeof(*msg) + cred_len + key_len) { GNUNET_break (0); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_credential_RESULT * * @param cls * @param msg the message we received */ static void handle_credential_result (void *cls, const struct CredentialResultMessage *msg) { struct GNUNET_IDENTITY_PublicKey identity; struct GNUNET_RECLAIM_Handle *h = cls; struct GNUNET_RECLAIM_CredentialIterator *it; struct GNUNET_RECLAIM_Operation *op; size_t att_len; size_t key_len; size_t read; uint32_t r_id = ntohl (msg->id); char *buf; key_len = ntohl (msg->key_len); att_len = ntohl (msg->credential_len); LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing credential result.\n"); for (it = h->ait_head; NULL != it; it = it->next) if (it->r_id == r_id) break; for (op = h->op_head; NULL != op; op = op->next) if (op->r_id == r_id) break; if ((NULL == it) && (NULL == op)) return; buf = (char *) &msg[1]; if (0 < key_len) { GNUNET_assert (GNUNET_SYSERR != GNUNET_IDENTITY_read_public_key_from_buffer (buf, key_len, &identity, &read)); buf += read; } if (0 == key_len) { if ((NULL == it) && (NULL == op)) { GNUNET_break (0); force_reconnect (h); return; } if (NULL != it) { if (NULL != it->finish_cb) it->finish_cb (it->finish_cb_cls); free_ait (it); } if (NULL != op) { if (NULL != op->at_cb) op->at_cb (op->cls, NULL, NULL); GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); free_op (op); } return; } { struct GNUNET_RECLAIM_Credential *att; att = GNUNET_RECLAIM_credential_deserialize (buf, att_len); if (NULL != it) { if (NULL != it->proc) it->proc (it->proc_cls, &identity, att); } else if (NULL != op) { if (NULL != op->at_cb) op->at_cb (op->cls, &identity, att); } GNUNET_free (att); return; } GNUNET_assert (0); } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT * * @param cls * @param msg the message we received * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ static int check_ticket_result (void *cls, const struct TicketResultMessage *msg) { size_t msg_len; size_t pres_len; size_t tkt_len; msg_len = ntohs (msg->header.size); pres_len = ntohl (msg->presentations_len); tkt_len = ntohl (msg->tkt_len); if (msg_len != sizeof(*msg) + pres_len + tkt_len) { GNUNET_break (0); return GNUNET_SYSERR; } return GNUNET_OK; } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT * * @param cls * @param msg the message we received */ static void handle_ticket_result (void *cls, const struct TicketResultMessage *msg) { struct GNUNET_RECLAIM_Handle *handle = cls; struct GNUNET_RECLAIM_Operation *op; struct GNUNET_RECLAIM_TicketIterator *it; struct GNUNET_RECLAIM_PresentationList *presentation; uint32_t r_id = ntohl (msg->id); struct GNUNET_RECLAIM_Ticket ticket; size_t pres_len; size_t tkt_len; size_t tb_read; char *buf; tkt_len = ntohl (msg->tkt_len); pres_len = ntohl (msg->presentations_len); for (op = handle->op_head; NULL != op; op = op->next) if (op->r_id == r_id) break; for (it = handle->ticket_it_head; NULL != it; it = it->next) if (it->r_id == r_id) break; if ((NULL == op) && (NULL == it)) return; buf = (char*) &msg[1]; GNUNET_assert (GNUNET_SYSERR != GNUNET_RECLAIM_read_ticket_from_buffer (buf, tkt_len, &ticket, &tb_read)); buf += tb_read; if (NULL != op) { if (0 < pres_len) presentation = GNUNET_RECLAIM_presentation_list_deserialize ( buf, pres_len); GNUNET_CONTAINER_DLL_remove (handle->op_head, handle->op_tail, op); if (0 == tb_read) { if (NULL != op->ti_cb) op->ti_cb (op->cls, NULL, NULL); } else { if (NULL != op->ti_cb) op->ti_cb (op->cls, &ticket, (0 < pres_len) ? presentation : NULL); } if (0 < pres_len) GNUNET_RECLAIM_presentation_list_destroy (presentation); free_op (op); return; } else if (NULL != it) { if (0 == tkt_len) { GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head, handle->ticket_it_tail, it); it->finish_cb (it->finish_cb_cls); GNUNET_free (it); } else { if (NULL != it->tr_cb) it->tr_cb (it->cls, &ticket); } return; } GNUNET_break (0); } /** * Handle an incoming message of type * #GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT * * @param cls * @param msg the message we received */ static void handle_revoke_ticket_result (void *cls, const struct RevokeTicketResultMessage *msg) { struct GNUNET_RECLAIM_Handle *h = cls; struct GNUNET_RECLAIM_Operation *op; uint32_t r_id = ntohl (msg->id); int32_t success; LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing revocation result.\n"); for (op = h->op_head; NULL != op; op = op->next) if (op->r_id == r_id) break; if (NULL == op) return; success = ntohl (msg->success); { if (NULL != op->rvk_cb) { op->rvk_cb (op->cls, success, NULL); } GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); free_op (op); return; } GNUNET_assert (0); } /** * Try again to connect to the service. * * @param h handle to the reclaim service. */ static void reconnect (struct GNUNET_RECLAIM_Handle *h) { struct GNUNET_MQ_MessageHandler handlers[] = { GNUNET_MQ_hd_fixed_size (success_response, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE, struct SuccessResultMessage, h), GNUNET_MQ_hd_var_size (attribute_result, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT, struct AttributeResultMessage, h), GNUNET_MQ_hd_var_size (credential_result, GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_RESULT, struct CredentialResultMessage, h), GNUNET_MQ_hd_var_size (ticket_result, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT, struct TicketResultMessage, h), GNUNET_MQ_hd_var_size (consume_ticket_result, GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT, struct ConsumeTicketResultMessage, h), GNUNET_MQ_hd_fixed_size (revoke_ticket_result, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT, struct RevokeTicketResultMessage, h), GNUNET_MQ_handler_end () }; struct GNUNET_RECLAIM_Operation *op; GNUNET_assert (NULL == h->mq); LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to reclaim service.\n"); h->mq = GNUNET_CLIENT_connect (h->cfg, "reclaim", handlers, &mq_error_handler, h); if (NULL == h->mq) return; for (op = h->op_head; NULL != op; op = op->next) GNUNET_MQ_send_copy (h->mq, op->env); } /** * Connect to the reclaim service. * * @param cfg the configuration to use * @return handle to use */ struct GNUNET_RECLAIM_Handle * GNUNET_RECLAIM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_RECLAIM_Handle *h; h = GNUNET_new (struct GNUNET_RECLAIM_Handle); h->cfg = cfg; reconnect (h); if (NULL == h->mq) { GNUNET_free (h); return NULL; } return h; } void GNUNET_RECLAIM_cancel (struct GNUNET_RECLAIM_Operation *op) { struct GNUNET_RECLAIM_Handle *h = op->h; GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op); free_op (op); } /** * Disconnect from service * * @param h handle to destroy */ void GNUNET_RECLAIM_disconnect (struct GNUNET_RECLAIM_Handle *h) { GNUNET_assert (NULL != h); if (NULL != h->mq) { GNUNET_MQ_destroy (h->mq); h->mq = NULL; } if (NULL != h->reconnect_task) { GNUNET_SCHEDULER_cancel (h->reconnect_task); h->reconnect_task = NULL; } GNUNET_assert (NULL == h->op_head); GNUNET_free (h); } struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_attribute_store ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *pkey, const struct GNUNET_RECLAIM_Attribute *attr, const struct GNUNET_TIME_Relative *exp_interval, GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_RECLAIM_Operation *op; struct AttributeStoreMessage *sam; size_t attr_len; size_t key_len; ssize_t written; char *buf; op = GNUNET_new (struct GNUNET_RECLAIM_Operation); op->h = h; op->as_cb = cont; op->cls = cont_cls; op->r_id = h->r_id_gen++; GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); key_len = GNUNET_IDENTITY_private_key_get_length (pkey); attr_len = GNUNET_RECLAIM_attribute_serialize_get_size (attr); op->env = GNUNET_MQ_msg_extra (sam, attr_len + key_len, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE); sam->key_len = htonl (key_len); buf = (char *) &sam[1]; written = GNUNET_IDENTITY_write_private_key_to_buffer (pkey, buf, key_len); GNUNET_assert (0 < written); buf += written; sam->id = htonl (op->r_id); sam->exp = GNUNET_htonll (exp_interval->rel_value_us); GNUNET_RECLAIM_attribute_serialize (attr, buf); sam->attr_len = htons (attr_len); if (NULL != h->mq) GNUNET_MQ_send_copy (h->mq, op->env); return op; } struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_attribute_delete ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *pkey, const struct GNUNET_RECLAIM_Attribute *attr, GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_RECLAIM_Operation *op; struct AttributeDeleteMessage *dam; size_t attr_len; size_t key_len; ssize_t written; char *buf; op = GNUNET_new (struct GNUNET_RECLAIM_Operation); op->h = h; op->as_cb = cont; op->cls = cont_cls; op->r_id = h->r_id_gen++; GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); key_len = GNUNET_IDENTITY_private_key_get_length (pkey); attr_len = GNUNET_RECLAIM_attribute_serialize_get_size (attr); op->env = GNUNET_MQ_msg_extra (dam, attr_len + key_len, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE); dam->key_len = htonl (key_len); buf = (char *) &dam[1]; written = GNUNET_IDENTITY_write_private_key_to_buffer (pkey, buf, key_len); GNUNET_assert (0 < written); buf += written; dam->id = htonl (op->r_id); GNUNET_RECLAIM_attribute_serialize (attr, buf); dam->attr_len = htons (attr_len); if (NULL != h->mq) GNUNET_MQ_send_copy (h->mq, op->env); return op; } struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_credential_store ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *pkey, const struct GNUNET_RECLAIM_Credential *credential, const struct GNUNET_TIME_Relative *exp_interval, GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_RECLAIM_Operation *op; struct AttributeStoreMessage *sam; size_t attr_len; size_t key_len; ssize_t written; char *buf; op = GNUNET_new (struct GNUNET_RECLAIM_Operation); op->h = h; op->as_cb = cont; op->cls = cont_cls; op->r_id = h->r_id_gen++; key_len = GNUNET_IDENTITY_private_key_get_length (pkey); GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); attr_len = GNUNET_RECLAIM_credential_serialize_get_size (credential); op->env = GNUNET_MQ_msg_extra (sam, attr_len + key_len, GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_STORE); sam->key_len = htonl (key_len); buf = (char *) &sam[1]; written = GNUNET_IDENTITY_write_private_key_to_buffer (pkey, buf, key_len); GNUNET_assert (0 <= written); buf += written; sam->id = htonl (op->r_id); sam->exp = GNUNET_htonll (exp_interval->rel_value_us); GNUNET_RECLAIM_credential_serialize (credential, buf); sam->attr_len = htons (attr_len); if (NULL != h->mq) GNUNET_MQ_send_copy (h->mq, op->env); return op; } struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_credential_delete ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *pkey, const struct GNUNET_RECLAIM_Credential *attr, GNUNET_RECLAIM_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_RECLAIM_Operation *op; struct AttributeDeleteMessage *dam; size_t attr_len; size_t key_len; ssize_t written; char *buf; op = GNUNET_new (struct GNUNET_RECLAIM_Operation); op->h = h; op->as_cb = cont; op->cls = cont_cls; op->r_id = h->r_id_gen++; key_len = GNUNET_IDENTITY_private_key_get_length (pkey); GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); attr_len = GNUNET_RECLAIM_credential_serialize_get_size (attr); op->env = GNUNET_MQ_msg_extra (dam, attr_len + key_len, GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_DELETE); dam->key_len = htonl (key_len); buf = (char *) &dam[1]; written = GNUNET_IDENTITY_write_private_key_to_buffer (pkey, buf, key_len); GNUNET_assert (0 <= written); buf += written; dam->id = htonl (op->r_id); GNUNET_RECLAIM_credential_serialize (attr, buf); dam->attr_len = htons (attr_len); if (NULL != h->mq) GNUNET_MQ_send_copy (h->mq, op->env); return op; } struct GNUNET_RECLAIM_AttributeIterator * GNUNET_RECLAIM_get_attributes_start ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *identity, GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls, GNUNET_RECLAIM_AttributeResult proc, void *proc_cls, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls) { struct GNUNET_RECLAIM_AttributeIterator *it; struct GNUNET_MQ_Envelope *env; struct AttributeIterationStartMessage *msg; uint32_t rid; size_t key_len; rid = h->r_id_gen++; it = GNUNET_new (struct GNUNET_RECLAIM_AttributeIterator); it->h = h; it->error_cb = error_cb; it->error_cb_cls = error_cb_cls; it->finish_cb = finish_cb; it->finish_cb_cls = finish_cb_cls; it->proc = proc; it->proc_cls = proc_cls; it->r_id = rid; it->identity = *identity; key_len = GNUNET_IDENTITY_private_key_get_length (identity); GNUNET_CONTAINER_DLL_insert_tail (h->it_head, h->it_tail, it); env = GNUNET_MQ_msg_extra (msg, key_len, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START); msg->id = htonl (rid); msg->key_len = htonl (key_len); GNUNET_IDENTITY_write_private_key_to_buffer (identity, &msg[1], key_len); if (NULL == h->mq) it->env = env; else GNUNET_MQ_send (h->mq, env); return it; } void GNUNET_RECLAIM_get_attributes_next (struct GNUNET_RECLAIM_AttributeIterator *it) { struct GNUNET_RECLAIM_Handle *h = it->h; struct AttributeIterationNextMessage *msg; struct GNUNET_MQ_Envelope *env; env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT); msg->id = htonl (it->r_id); GNUNET_MQ_send (h->mq, env); } void GNUNET_RECLAIM_get_attributes_stop (struct GNUNET_RECLAIM_AttributeIterator *it) { struct GNUNET_RECLAIM_Handle *h = it->h; struct GNUNET_MQ_Envelope *env; struct AttributeIterationStopMessage *msg; if (NULL != h->mq) { env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP); msg->id = htonl (it->r_id); GNUNET_MQ_send (h->mq, env); } free_it (it); } struct GNUNET_RECLAIM_CredentialIterator * GNUNET_RECLAIM_get_credentials_start ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *identity, GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls, GNUNET_RECLAIM_CredentialResult proc, void *proc_cls, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls) { struct GNUNET_RECLAIM_CredentialIterator *ait; struct GNUNET_MQ_Envelope *env; struct CredentialIterationStartMessage *msg; uint32_t rid; size_t key_len; rid = h->r_id_gen++; ait = GNUNET_new (struct GNUNET_RECLAIM_CredentialIterator); ait->h = h; ait->error_cb = error_cb; ait->error_cb_cls = error_cb_cls; ait->finish_cb = finish_cb; ait->finish_cb_cls = finish_cb_cls; ait->proc = proc; ait->proc_cls = proc_cls; ait->r_id = rid; ait->identity = *identity; key_len = GNUNET_IDENTITY_private_key_get_length (identity); GNUNET_CONTAINER_DLL_insert_tail (h->ait_head, h->ait_tail, ait); env = GNUNET_MQ_msg_extra (msg, key_len, GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_ITERATION_START); msg->id = htonl (rid); msg->key_len = htonl (key_len); GNUNET_IDENTITY_write_private_key_to_buffer (identity, &msg[1], key_len); if (NULL == h->mq) ait->env = env; else GNUNET_MQ_send (h->mq, env); return ait; } void GNUNET_RECLAIM_get_credentials_next (struct GNUNET_RECLAIM_CredentialIterator *ait) { struct GNUNET_RECLAIM_Handle *h = ait->h; struct CredentialIterationNextMessage *msg; struct GNUNET_MQ_Envelope *env; env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_ITERATION_NEXT); msg->id = htonl (ait->r_id); GNUNET_MQ_send (h->mq, env); } void GNUNET_RECLAIM_get_credentials_stop (struct GNUNET_RECLAIM_CredentialIterator *ait) { struct GNUNET_RECLAIM_Handle *h = ait->h; struct GNUNET_MQ_Envelope *env; struct CredentialIterationStopMessage *msg; if (NULL != h->mq) { env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_CREDENTIAL_ITERATION_STOP); msg->id = htonl (ait->r_id); GNUNET_MQ_send (h->mq, env); } free_ait (ait); } struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_issue ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *iss, const struct GNUNET_IDENTITY_PublicKey *rp, const struct GNUNET_RECLAIM_AttributeList *attrs, GNUNET_RECLAIM_IssueTicketCallback cb, void *cb_cls) { struct GNUNET_RECLAIM_Operation *op; struct IssueTicketMessage *tim; size_t attr_len; size_t key_len; size_t rpk_len; ssize_t written; char *buf; op = GNUNET_new (struct GNUNET_RECLAIM_Operation); op->h = h; op->ti_cb = cb; op->cls = cb_cls; op->r_id = h->r_id_gen++; key_len = GNUNET_IDENTITY_private_key_get_length (iss); rpk_len = GNUNET_IDENTITY_public_key_get_length (rp); GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); attr_len = GNUNET_RECLAIM_attribute_list_serialize_get_size (attrs); op->env = GNUNET_MQ_msg_extra (tim, attr_len + key_len + rpk_len, GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET); tim->key_len = htonl (key_len); tim->pkey_len = htonl (rpk_len); buf = (char *) &tim[1]; written = GNUNET_IDENTITY_write_private_key_to_buffer (iss, buf, key_len); GNUNET_assert (0 <= written); buf += written; written = GNUNET_IDENTITY_write_public_key_to_buffer (rp, buf, rpk_len); GNUNET_assert (0 <= written); buf += written; tim->id = htonl (op->r_id); GNUNET_RECLAIM_attribute_list_serialize (attrs, buf); tim->attr_len = htons (attr_len); if (NULL != h->mq) GNUNET_MQ_send_copy (h->mq, op->env); return op; } /** * Consumes an issued ticket. The ticket is persisted * and used to retrieve identity information from the issuer * * @param h the reclaim to use * @param identity the identity that is the subject of the issued ticket (the * relying party) * @param ticket the issued ticket to consume * @param cb the callback to call * @param cb_cls the callback closure * @return handle to abort the operation */ struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_consume ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *identity, const struct GNUNET_RECLAIM_Ticket *ticket, GNUNET_RECLAIM_AttributeTicketResult cb, void *cb_cls) { struct GNUNET_RECLAIM_Operation *op; struct ConsumeTicketMessage *ctm; size_t key_len; size_t tkt_len; char *buf; op = GNUNET_new (struct GNUNET_RECLAIM_Operation); op->h = h; op->atr_cb = cb; op->cls = cb_cls; op->r_id = h->r_id_gen++; key_len = GNUNET_IDENTITY_private_key_get_length (identity); tkt_len = GNUNET_RECLAIM_ticket_serialize_get_size (ticket); GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); op->env = GNUNET_MQ_msg_extra (ctm, key_len + tkt_len, GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET); ctm->key_len = htonl (key_len); buf = (char*) &ctm[1]; GNUNET_IDENTITY_write_private_key_to_buffer (identity, buf, key_len); buf += key_len; ctm->tkt_len = htonl (tkt_len); GNUNET_RECLAIM_write_ticket_to_buffer (ticket, buf, tkt_len); ctm->id = htonl (op->r_id); if (NULL != h->mq) GNUNET_MQ_send_copy (h->mq, op->env); else reconnect (h); return op; } struct GNUNET_RECLAIM_TicketIterator * GNUNET_RECLAIM_ticket_iteration_start ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *identity, GNUNET_SCHEDULER_TaskCallback error_cb, void *error_cb_cls, GNUNET_RECLAIM_TicketCallback proc, void *proc_cls, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls) { struct GNUNET_RECLAIM_TicketIterator *it; struct GNUNET_MQ_Envelope *env; struct TicketIterationStartMessage *msg; uint32_t rid; size_t key_len; rid = h->r_id_gen++; it = GNUNET_new (struct GNUNET_RECLAIM_TicketIterator); it->h = h; it->error_cb = error_cb; it->error_cb_cls = error_cb_cls; it->finish_cb = finish_cb; it->finish_cb_cls = finish_cb_cls; it->tr_cb = proc; it->cls = proc_cls; it->r_id = rid; key_len = GNUNET_IDENTITY_private_key_get_length (identity); GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, h->ticket_it_tail, it); env = GNUNET_MQ_msg_extra (msg, key_len, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START); msg->id = htonl (rid); msg->key_len = htonl (key_len); GNUNET_IDENTITY_write_private_key_to_buffer (identity, &msg[1], key_len); if (NULL == h->mq) it->env = env; else GNUNET_MQ_send (h->mq, env); return it; } /** * Calls the ticket processor specified in * #GNUNET_RECLAIM_ticket_iteration_start for the next record. * * @param it the iterator */ void GNUNET_RECLAIM_ticket_iteration_next (struct GNUNET_RECLAIM_TicketIterator *it) { struct GNUNET_RECLAIM_Handle *h = it->h; struct TicketIterationNextMessage *msg; struct GNUNET_MQ_Envelope *env; env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT); msg->id = htonl (it->r_id); GNUNET_MQ_send (h->mq, env); } /** * Stops iteration and releases the handle for further calls. Must * be called on any iteration that has not yet completed prior to calling * #GNUNET_RECLAIM_disconnect. * * @param it the iterator */ void GNUNET_RECLAIM_ticket_iteration_stop (struct GNUNET_RECLAIM_TicketIterator *it) { struct GNUNET_RECLAIM_Handle *h = it->h; struct GNUNET_MQ_Envelope *env; struct TicketIterationStopMessage *msg; if (NULL != h->mq) { env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP); msg->id = htonl (it->r_id); GNUNET_MQ_send (h->mq, env); } GNUNET_free (it); } /** * Revoked an issued ticket. The relying party will be unable to retrieve * attributes. Other issued tickets remain unaffected. * This includes tickets issued to other relying parties as well as to * other tickets issued to the audience specified in this ticket. * * @param h the identity provider to use * @param identity the issuing identity * @param ticket the ticket to revoke * @param cb the callback * @param cb_cls the callback closure * @return handle to abort the operation */ struct GNUNET_RECLAIM_Operation * GNUNET_RECLAIM_ticket_revoke ( struct GNUNET_RECLAIM_Handle *h, const struct GNUNET_IDENTITY_PrivateKey *identity, const struct GNUNET_RECLAIM_Ticket *ticket, GNUNET_RECLAIM_ContinuationWithStatus cb, void *cb_cls) { struct GNUNET_RECLAIM_Operation *op; struct RevokeTicketMessage *msg; uint32_t rid; size_t key_len; size_t tkt_len; ssize_t written; char *buf; rid = h->r_id_gen++; op = GNUNET_new (struct GNUNET_RECLAIM_Operation); op->h = h; op->rvk_cb = cb; op->cls = cb_cls; op->r_id = rid; GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op); key_len = GNUNET_IDENTITY_private_key_get_length (identity); tkt_len = GNUNET_RECLAIM_ticket_serialize_get_size (ticket); op->env = GNUNET_MQ_msg_extra (msg, key_len + tkt_len, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET); msg->id = htonl (rid); msg->key_len = htonl (key_len); msg->tkt_len = htonl (tkt_len); buf = (char*) &msg[1]; written = GNUNET_IDENTITY_write_private_key_to_buffer (identity, buf, key_len); GNUNET_assert (0 <= written); buf += written; GNUNET_RECLAIM_write_ticket_to_buffer (ticket, buf, tkt_len); if (NULL != h->mq) { GNUNET_MQ_send (h->mq, op->env); op->env = NULL; } return op; } size_t GNUNET_RECLAIM_ticket_serialize_get_size (const struct GNUNET_RECLAIM_Ticket *tkt) { size_t size = sizeof (tkt->rnd); size += GNUNET_IDENTITY_public_key_get_length (&tkt->identity); size += GNUNET_IDENTITY_public_key_get_length (&tkt->audience); return size; } enum GNUNET_GenericReturnValue GNUNET_RECLAIM_read_ticket_from_buffer (const void *buffer, size_t len, struct GNUNET_RECLAIM_Ticket *tkt, size_t *tb_read) { const char *tmp = buffer; size_t read = 0; size_t left = len; if (GNUNET_SYSERR == GNUNET_IDENTITY_read_public_key_from_buffer (tmp, left, &tkt->identity, &read)) return GNUNET_SYSERR; left -= read; tmp += read; if (GNUNET_SYSERR == GNUNET_IDENTITY_read_public_key_from_buffer (tmp, left, &tkt->audience, &read)) return GNUNET_SYSERR; left -= read; tmp += read; if (left < sizeof (tkt->rnd)) return GNUNET_SYSERR; memcpy (&tkt->rnd, tmp, sizeof (tkt->rnd)); *tb_read = tmp - (char*) buffer + sizeof (tkt->rnd); return GNUNET_OK; } ssize_t GNUNET_RECLAIM_write_ticket_to_buffer (const struct GNUNET_RECLAIM_Ticket *tkt, void *buffer, size_t len) { char *tmp = buffer; size_t left = len; ssize_t written = 0; written = GNUNET_IDENTITY_write_public_key_to_buffer (&tkt->identity, buffer, left); if (0 > written) return written; left -= written; tmp += written; written = GNUNET_IDENTITY_write_public_key_to_buffer (&tkt->audience, tmp, left); if (0 > written) return written; left -= written; tmp += written; if (left < sizeof (tkt->rnd)) return -1; memcpy (tmp, &tkt->rnd, sizeof (tkt->rnd)); return tmp - (char*) buffer + sizeof (tkt->rnd); } /* end of reclaim_api.c */