X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fnamestore%2Fnamestore_api.c;h=c0a3e0cdd1843836869b69660d9e1ccc0c57019d;hb=cbd60b5e56aac2d6711e299086383f83357794f8;hp=168ae1f1c97955358cf7c7d0917188af1638e8b1;hpb=e0d8d7ff0b129f9d8110e810856399971406773d;p=oweals%2Fgnunet.git diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c index 168ae1f1c..c0a3e0cdd 100644 --- a/src/namestore/namestore_api.c +++ b/src/namestore/namestore_api.c @@ -1,21 +1,16 @@ /* This file is part of GNUnet. - (C) 2009, 2010 Christian Grothoff (and other contributing authors) + Copyright (C) 2010-2013, 2016 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 - by the Free Software Foundation; either version 3, or (at your - option) any later version. + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation, either version 3 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 - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Affero General Public License for more details. */ /** @@ -23,6 +18,7 @@ * @brief API to access the NAMESTORE service * @author Martin Schanzenbach * @author Matthias Wachs + * @author Christian Grothoff */ #include "platform.h" @@ -32,11 +28,18 @@ #include "gnunet_dnsparser_lib.h" #include "gnunet_arm_service.h" #include "gnunet_signatures.h" +#include "gnunet_gns_service.h" #include "gnunet_namestore_service.h" #include "namestore.h" -#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) +#define LOG(kind,...) GNUNET_log_from (kind, "namestore-api",__VA_ARGS__) + +/** + * We grant the namestore up to 1 minute of latency, if it is slower than + * that, store queries will fail. + */ +#define NAMESTORE_DELAY_TOLERANCE GNUNET_TIME_UNIT_MINUTES /** * An QueueEntry used to store information for a pending @@ -58,7 +61,7 @@ struct GNUNET_NAMESTORE_QueueEntry /** * Main handle to access the namestore. */ - struct GNUNET_NAMESTORE_Handle *nsh; + struct GNUNET_NAMESTORE_Handle *h; /** * Continuation to call @@ -66,20 +69,41 @@ struct GNUNET_NAMESTORE_QueueEntry GNUNET_NAMESTORE_ContinuationWithStatus cont; /** - * Closure for 'cont'. + * Closure for @e cont. */ void *cont_cls; /** * Function to call with the records we get back; or NULL. */ - GNUNET_NAMESTORE_RecordProcessor proc; + GNUNET_NAMESTORE_RecordMonitor proc; /** - * Closure for '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; + + /** + * Task scheduled to warn us if the namestore is way too slow. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + /** * The operation id this zone iteration operation has */ @@ -110,62 +134,51 @@ struct GNUNET_NAMESTORE_ZoneIterator struct GNUNET_NAMESTORE_Handle *h; /** - * The continuation to call with the results + * Function to call on completion. */ - GNUNET_NAMESTORE_RecordProcessor proc; + GNUNET_SCHEDULER_TaskCallback finish_cb; /** - * Closure for 'proc'. + * Closure for @e error_cb. */ - void* proc_cls; + void *finish_cb_cls; /** - * If this iterator iterates over a specific zone this value contains the - * short hash of the zone + * The continuation to call with the results */ - struct GNUNET_CRYPTO_ShortHashCode zone; + GNUNET_NAMESTORE_RecordMonitor proc; /** - * The operation id this zone iteration operation has + * Closure for @e proc. */ - uint32_t op_id; + void *proc_cls; /** - * GNUNET_YES if this iterator iterates over a specific zone - * GNUNET_NO if this iterator iterates over all zones - * - * Zone is stored GNUNET_CRYPTO_ShortHashCode 'zone'; + * Function to call on errors. */ - int has_zone; -}; - - -/** - * Message in linked list we should send to the service. The - * actual binary message follows this struct. - */ -struct PendingMessage -{ + GNUNET_SCHEDULER_TaskCallback error_cb; /** - * Kept in a DLL. + * Closure for @e error_cb. */ - struct PendingMessage *next; + void *error_cb_cls; /** - * Kept in a DLL. + * Envelope of the message to send to the service, if not yet + * sent. */ - struct PendingMessage *prev; + struct GNUNET_MQ_Envelope *env; /** - * Size of the message. + * Private key of the zone. */ - size_t size; + struct GNUNET_CRYPTO_EcdsaPrivateKey zone; /** - * Is this the 'START' message? + * The operation id this zone iteration operation has */ - int is_init; + uint32_t op_id; + }; @@ -181,49 +194,39 @@ struct GNUNET_NAMESTORE_Handle const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Socket (if available). - */ - struct GNUNET_CLIENT_Connection *client; - - /** - * Currently pending transmission request (or NULL). - */ - struct GNUNET_CLIENT_TransmitHandle *th; - - /** - * Head of linked list of pending messages to send to the service + * Connection to the service (if available). */ - struct PendingMessage * pending_head; - - /** - * Tail of linked list of pending messages to send to the service - */ - struct PendingMessage * pending_tail; + struct GNUNET_MQ_Handle *mq; /** * Head of pending namestore queue entries */ - struct GNUNET_NAMESTORE_QueueEntry * op_head; + struct GNUNET_NAMESTORE_QueueEntry *op_head; /** * Tail of pending namestore queue entries */ - struct GNUNET_NAMESTORE_QueueEntry * op_tail; + struct GNUNET_NAMESTORE_QueueEntry *op_tail; /** * Head of pending namestore zone iterator entries */ - struct GNUNET_NAMESTORE_ZoneIterator * z_head; + struct GNUNET_NAMESTORE_ZoneIterator *z_head; /** * Tail of pending namestore zone iterator entries */ - struct GNUNET_NAMESTORE_ZoneIterator * z_tail; + struct GNUNET_NAMESTORE_ZoneIterator *z_tail; /** * Reconnect task */ - GNUNET_SCHEDULER_TaskIdentifier reconnect_task; + struct GNUNET_SCHEDULER_Task *reconnect_task; + + /** + * Delay introduced before we reconnect. + */ + struct GNUNET_TIME_Relative reconnect_delay; /** * Should we reconnect to service due to some serious error? @@ -248,657 +251,538 @@ force_reconnect (struct GNUNET_NAMESTORE_Handle *h); /** - * Handle an incoming message of type 'GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE' + * Find the queue entry that matches the @a rid * - * @param qe the respective entry in the message queue - * @param msg the message we received - * @param size the message size + * @param h namestore handle + * @param rid id to look up + * @return NULL if @a rid was not found */ -static void -handle_lookup_name_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - struct LookupNameResponseMessage * msg, - size_t size) +static struct GNUNET_NAMESTORE_QueueEntry * +find_qe (struct GNUNET_NAMESTORE_Handle *h, + uint32_t rid) { - struct GNUNET_NAMESTORE_Handle *h = qe->nsh; - char *name; - char * rd_tmp; - struct GNUNET_CRYPTO_RsaSignature *signature = NULL; - struct GNUNET_TIME_Absolute expire; - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key_tmp; - size_t exp_msg_len; - size_t msg_len = 0; - size_t name_len = 0; - size_t rd_len = 0; - int contains_sig = GNUNET_NO; - int rd_count = 0; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", - "LOOKUP_NAME_RESPONSE"); - /* Operation done, remove */ - GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); - rd_len = ntohs (msg->rd_len); - rd_count = ntohs (msg->rd_count); - msg_len = ntohs (msg->gns_header.header.size); - name_len = ntohs (msg->name_len); - contains_sig = ntohs (msg->contains_sig); - expire = GNUNET_TIME_absolute_ntoh(msg->expire); - - exp_msg_len = sizeof (struct LookupNameResponseMessage) + - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + - name_len + rd_len; - - if (msg_len != exp_msg_len) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message size describes with `%u' bytes but calculated size is %u bytes \n", - msg_len, exp_msg_len); - GNUNET_break_op (0); - return; - } + struct GNUNET_NAMESTORE_QueueEntry *qe; - name = (char *) &msg[1]; - if (name_len > 0) - { - GNUNET_assert ('\0' == name[name_len -1]); - GNUNET_assert ((name_len - 1) == strlen(name)); - } - rd_tmp = &name[name_len]; + for (qe = h->op_head; qe != NULL; qe = qe->next) + if (qe->op_id == rid) + return qe; + return NULL; +} - /* deserialize records */ - { - struct GNUNET_NAMESTORE_RecordData rd[rd_count]; - if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize(rd_len, rd_tmp, rd_count, rd)) - { - GNUNET_break_op (0); - return; - } +/** + * Find the zone iteration entry that matches the @a rid + * + * @param h namestore handle + * @param rid id to look up + * @return NULL if @a rid was not found + */ +static struct GNUNET_NAMESTORE_ZoneIterator * +find_zi (struct GNUNET_NAMESTORE_Handle *h, + uint32_t rid) +{ + struct GNUNET_NAMESTORE_ZoneIterator *ze; - /* reset values if values not contained */ - if (GNUNET_NO == contains_sig) - signature = NULL; - else - signature = &msg->signature; - if (0 == name_len) - name = NULL; - - if (NULL != name) - public_key_tmp = &msg->public_key; - else - public_key_tmp = NULL; - - if (NULL != qe->proc) - qe->proc (qe->proc_cls, public_key_tmp, expire, name, rd_count, (rd_count > 0) ? rd : NULL, signature); - } - GNUNET_free (qe); + for (ze = h->z_head; ze != NULL; ze = ze->next) + if (ze->op_id == rid) + return ze; + return NULL; } /** - * Handle an incoming message of type 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE' + * Free @a qe. * - * @param qe the respective entry in the message queue - * @param msg the message we received - * @param size the message size + * @param qe entry to free */ static void -handle_record_put_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - struct RecordPutResponseMessage* msg, - size_t size) +free_qe (struct GNUNET_NAMESTORE_QueueEntry *qe) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", - "RECORD_PUT_RESPONSE"); - - struct GNUNET_NAMESTORE_Handle *h = qe->nsh; - /* Operation done, remove */ - GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); - - int res = ntohl (msg->op_result); - - if (res == GNUNET_OK) - { - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, res, _("Namestore added record successfully")); - } - - } - else if (res == GNUNET_SYSERR) - { - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, res, _("Namestore failed to add record")); - } - } - else - { - GNUNET_break_op (0); - return; - } - + struct GNUNET_NAMESTORE_Handle *h = qe->h; + + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + qe); + if (NULL != qe->env) + GNUNET_MQ_discard (qe->env); + if (NULL != qe->timeout_task) + GNUNET_SCHEDULER_cancel (qe->timeout_task); GNUNET_free (qe); } /** - * Handle an incoming message of type 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE' + * Free @a ze. * - * @param qe the respective entry in the message queue - * @param msg the message we received - * @param size the message size + * @param ze entry to free */ static void -handle_record_create_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - struct RecordCreateResponseMessage* msg, - size_t size) +free_ze (struct GNUNET_NAMESTORE_ZoneIterator *ze) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", - "RECORD_CREATE_RESPONSE"); + struct GNUNET_NAMESTORE_Handle *h = ze->h; + + GNUNET_CONTAINER_DLL_remove (h->z_head, + h->z_tail, + ze); + if (NULL != ze->env) + GNUNET_MQ_discard (ze->env); + GNUNET_free (ze); +} - struct GNUNET_NAMESTORE_Handle *h = qe->nsh; - /* Operation done, remove */ - GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); - int res = ntohl (msg->op_result); - if (res == GNUNET_YES) - { - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, res, _("Namestore added record successfully")); - } +/** + * Check that @a rd_buf of lenght @a rd_len contains + * @a rd_count records. + * + * @param rd_len length of @a rd_buf + * @param rd_buf buffer with serialized records + * @param rd_count number of records expected + * @return #GNUNET_OK if @a rd_buf is well-formed + */ +static int +check_rd (size_t rd_len, + const void *rd_buf, + unsigned int rd_count) +{ + struct GNUNET_GNSRECORD_Data rd[rd_count]; - } - else if (res == GNUNET_NO) - { - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, res, _("Namestore record already existed")); - } - } - else + if (GNUNET_OK != + GNUNET_GNSRECORD_records_deserialize (rd_len, + rd_buf, + rd_count, + rd)) { - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, GNUNET_SYSERR, _("Namestore failed to add record\n")); - } + GNUNET_break (0); + return GNUNET_SYSERR; } - - GNUNET_free (qe); + return GNUNET_OK; } /** - * Handle an incoming message of type 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE' + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE * - * @param qe the respective entry in the message queue + * @param cls * @param msg the message we received - * @param size the message size */ static void -handle_record_remove_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - struct RecordRemoveResponseMessage* msg, - size_t size) +handle_record_store_response (void *cls, + const struct RecordStoreResponseMessage *msg) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", - "RECORD_REMOVE_RESPONSE"); - - struct GNUNET_NAMESTORE_Handle *h = qe->nsh; - /* Operation done, remove */ - GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); - - int res = ntohl (msg->op_result); - /** - * result: - * 0 : successful - * 1 : No records for entry - * 2 : Could not find record to remove - * 3 : Failed to create new signature - * 4 : Failed to put new set of records in database - */ - switch (res) { - case 0: - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, GNUNET_YES, _("Namestore removed record successfully")); - } - - break; - case 1: - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, GNUNET_NO, _("No records for entry")); - } - - break; - case 2: - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, GNUNET_NO, _("Could not find record to remove")); - } - - break; - case 3: - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, GNUNET_SYSERR, _("Failed to create new signature")); - } - - break; - case 4: - if (qe->cont != NULL) - { - qe->cont (qe->cont_cls, GNUNET_SYSERR, _("Failed to put new set of records in database")); - } - break; - default: - GNUNET_break_op (0); - break; - } - - GNUNET_free (qe); + struct GNUNET_NAMESTORE_Handle *h = cls; + struct GNUNET_NAMESTORE_QueueEntry *qe; + int res; + const char *emsg; + + qe = find_qe (h, + ntohl (msg->gns_header.r_id)); + res = ntohl (msg->op_result); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received RECORD_STORE_RESPONSE with result %d\n", + res); + /* TODO: add actual error message from namestore to response... */ + if (GNUNET_SYSERR == res) + emsg = _("Namestore failed to store record\n"); + else + emsg = NULL; + if (NULL != qe->cont) + qe->cont (qe->cont_cls, + res, + emsg); + free_qe (qe); } /** - * Handle an incoming message of type 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE' + * Check validity of an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE * - * @param qe the respective entry in the message queue + * @param cls * @param msg the message we received - * @param size the message size + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ -static void -handle_zone_to_name_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - struct ZoneToNameResponseMessage* msg, - size_t size) +static int +check_lookup_result (void *cls, + const struct LabelLookupResponseMessage *msg) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", - "ZONE_TO_NAME_RESPONSE"); - - struct GNUNET_NAMESTORE_Handle *h = qe->nsh; - /* Operation done, remove */ - GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); - - int res = ntohs (msg->res); - - struct GNUNET_TIME_Absolute expire; + const char *name; + size_t exp_msg_len; + size_t msg_len; size_t name_len; - size_t rd_ser_len; - unsigned int rd_count; + size_t rd_len; - char * name_tmp; - char * rd_tmp; - - if (res == GNUNET_SYSERR) + (void) cls; + rd_len = ntohs (msg->rd_len); + msg_len = ntohs (msg->gns_header.header.size); + name_len = ntohs (msg->name_len); + exp_msg_len = sizeof (*msg) + name_len + rd_len; + if (msg_len != exp_msg_len) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "An error occured during zone to name operation\n"); - if (qe->proc != NULL) - qe->proc (qe->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL, 0, NULL, NULL); + GNUNET_break (0); + return GNUNET_SYSERR; } - else if (res == GNUNET_NO) + name = (const char *) &msg[1]; + if ( (name_len > 0) && + ('\0' != name[name_len -1]) ) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore has no result for zone to name mapping \n"); - if (qe->proc != NULL) - qe->proc (qe->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL, 0, NULL, NULL); + GNUNET_break (0); + return GNUNET_SYSERR; } - else if (res == GNUNET_YES) + if (GNUNET_NO == ntohs (msg->found)) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Namestore has result for zone to name mapping \n"); - - name_len = ntohs (msg->name_len); - rd_count = ntohs (msg->rd_count); - rd_ser_len = ntohs (msg->rd_len); - expire = GNUNET_TIME_absolute_ntoh(msg->expire); - - name_tmp = (char *) &msg[1]; - if (name_len > 0) - { - GNUNET_assert ('\0' == name_tmp[name_len -1]); - GNUNET_assert (name_len -1 == strlen(name_tmp)); - } - rd_tmp = &name_tmp[name_len]; - - struct GNUNET_NAMESTORE_RecordData rd[rd_count]; - if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_tmp, rd_count, rd)) + if (0 != ntohs (msg->rd_count)) { - GNUNET_break_op (0); - return; + GNUNET_break (0); + return GNUNET_SYSERR; } - - if (qe->proc != NULL) - qe->proc (qe->proc_cls, &msg->zone_key, expire, name_tmp, rd_count, rd, &msg->signature); + return GNUNET_OK; } - else - GNUNET_break_op (0); - - GNUNET_free (qe); + return check_rd (rd_len, + &name[name_len], + ntohs (msg->rd_count)); } /** - * Handle incoming messages for record operations + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE * - * @param ze the respective zone iteration handle + * @param cls * @param msg the message we received - * @param type the message type in HBO - * @param size the message size */ static void -manage_record_operations (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct GNUNET_MessageHeader *msg, - int type, size_t size) +handle_lookup_result (void *cls, + const struct LabelLookupResponseMessage *msg) { + struct GNUNET_NAMESTORE_Handle *h = cls; + struct GNUNET_NAMESTORE_QueueEntry *qe; + const char *name; + const char *rd_tmp; + size_t name_len; + size_t rd_len; + unsigned int rd_count; - /* handle different message type */ - switch (type) { - case GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE: - if (size < sizeof (struct LookupNameResponseMessage)) - { - GNUNET_break_op (0); - break; - } - handle_lookup_name_response (qe, (struct LookupNameResponseMessage *) msg, size); - break; - case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE: - if (size != sizeof (struct RecordPutResponseMessage)) - { - GNUNET_break_op (0); - break; - } - handle_record_put_response (qe, (struct RecordPutResponseMessage *) msg, size); - break; - case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE: - if (size != sizeof (struct RecordCreateResponseMessage)) - { - GNUNET_break_op (0); - break; - } - handle_record_create_response (qe, (struct RecordCreateResponseMessage *) msg, size); - break; - case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE: - if (size != sizeof (struct RecordRemoveResponseMessage)) - { - GNUNET_break_op (0); - break; - } - handle_record_remove_response (qe, (struct RecordRemoveResponseMessage *) msg, size); - break; - case GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE: - if (size < sizeof (struct ZoneToNameResponseMessage)) - { - GNUNET_break_op (0); - break; - } - handle_zone_to_name_response (qe, (struct ZoneToNameResponseMessage *) msg, size); - break; - default: - GNUNET_break_op (0); - break; - } -} - - -/** - * Handle a response from NAMESTORE service for a zone iteration request - * - * @param ze the respective iterator for this operation - * @param msg the message containing the respoonse - * @param size the message size - */ -static void -handle_zone_iteration_response (struct GNUNET_NAMESTORE_ZoneIterator *ze, - struct ZoneIterationResponseMessage *msg, - size_t size) -{ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' \n", - "ZONE_ITERATION_RESPONSE"); - - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubdummy; - size_t msg_len = 0; - size_t exp_msg_len = 0; - size_t name_len = 0; - size_t rd_len = 0; - unsigned rd_count = 0; - - char *name_tmp; - char *rd_ser_tmp; - struct GNUNET_TIME_Absolute expire; - - msg_len = ntohs (msg->gns_header.header.size); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received RECORD_LOOKUP_RESULT\n"); + qe = find_qe (h, + ntohl (msg->gns_header.r_id)); + if (NULL == qe) + return; rd_len = ntohs (msg->rd_len); rd_count = ntohs (msg->rd_count); name_len = ntohs (msg->name_len); - expire = GNUNET_TIME_absolute_ntoh (msg->expire); - - exp_msg_len = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_len; - if (msg_len != exp_msg_len) + name = (const char *) &msg[1]; + if (GNUNET_NO == ntohs (msg->found)) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message size describes with `%u' bytes but calculated size is %u bytes \n", - msg_len, exp_msg_len); - GNUNET_break_op (0); - return; - } - if (0 != ntohs (msg->reserved)) - { - GNUNET_break_op (0); + /* label was not in namestore */ + if (NULL != qe->proc) + qe->proc (qe->proc_cls, + &msg->private_key, + name, + 0, + NULL); + free_qe (qe); return; } - memset (&pubdummy, '\0', sizeof (pubdummy)); - if ((0 == name_len) && (0 == (memcmp (&msg->public_key, &pubdummy, sizeof (pubdummy))))) + rd_tmp = &name[name_len]; { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration is completed!\n"); - - GNUNET_CONTAINER_DLL_remove(ze->h->z_head, ze->h->z_tail, ze); - - if (ze->proc != NULL) - ze->proc(ze->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL , 0, NULL, NULL); - - GNUNET_free (ze); - return; - } + struct GNUNET_GNSRECORD_Data rd[rd_count]; - name_tmp = (char *) &msg[1]; - if ((name_tmp[name_len -1] != '\0') || (name_len > 256)) - { - GNUNET_break_op (0); - return; - } - rd_ser_tmp = (char *) &name_tmp[name_len]; - struct GNUNET_NAMESTORE_RecordData rd[rd_count]; - if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd)) - { - GNUNET_break_op (0); - return; + GNUNET_assert (GNUNET_OK == + GNUNET_GNSRECORD_records_deserialize (rd_len, + rd_tmp, + rd_count, + rd)); + if (0 == name_len) + name = NULL; + if (NULL != qe->proc) + qe->proc (qe->proc_cls, + &msg->private_key, + name, + rd_count, + (rd_count > 0) ? rd : NULL); } - - if (ze->proc != NULL) - ze->proc(ze->proc_cls, &msg->public_key, expire, name_tmp, rd_count, rd, &msg->signature); + free_qe (qe); } /** - * Handle incoming messages for zone iterations + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT * - * @param ze the respective zone iteration handle + * @param cls * @param msg the message we received - * @param type the message type in HBO - * @param size the message size + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ -static void -manage_zone_operations (struct GNUNET_NAMESTORE_ZoneIterator *ze, - const struct GNUNET_MessageHeader *msg, - int type, size_t size) +static int +check_record_result (void *cls, + const struct RecordResultMessage *msg) { + const char *name; + size_t msg_len; + size_t name_len; + size_t rd_len; - /* handle different message type */ - switch (type) { - case GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE: - if (size < sizeof (struct ZoneIterationResponseMessage)) - { - GNUNET_break_op (0); - break; - } - handle_zone_iteration_response (ze, (struct ZoneIterationResponseMessage *) msg, size); - break; - default: - GNUNET_break_op (0); - break; + (void) cls; + rd_len = ntohs (msg->rd_len); + msg_len = ntohs (msg->gns_header.header.size); + name_len = ntohs (msg->name_len); + if (0 != ntohs (msg->reserved)) + { + GNUNET_break (0); + return GNUNET_SYSERR; } + if (msg_len != sizeof (struct RecordResultMessage) + name_len + rd_len) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + name = (const char *) &msg[1]; + if ( (name_len > 0) && + ('\0' != name[name_len -1]) ) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return check_rd (rd_len, + &name[name_len], + ntohs (msg->rd_count)); } /** - * Type of a function to call when we receive a message - * from the service. + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT * - * @param cls the 'struct GNUNET_NAMESTORE_SchedulingHandle' - * @param msg message received, NULL on timeout or fatal error + * @param cls + * @param msg the message we received */ static void -process_namestore_message (void *cls, const struct GNUNET_MessageHeader *msg) +handle_record_result (void *cls, + const struct RecordResultMessage *msg) { + static struct GNUNET_CRYPTO_EcdsaPrivateKey priv_dummy; struct GNUNET_NAMESTORE_Handle *h = cls; - struct GNUNET_NAMESTORE_Header * gm; struct GNUNET_NAMESTORE_QueueEntry *qe; struct GNUNET_NAMESTORE_ZoneIterator *ze; - uint16_t size; - uint16_t type; - uint32_t r_id = UINT32_MAX; + const char *name; + const char *rd_tmp; + size_t name_len; + size_t rd_len; + unsigned int rd_count; - if (NULL == msg) + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received RECORD_RESULT\n"); + rd_len = ntohs (msg->rd_len); + rd_count = ntohs (msg->rd_count); + name_len = ntohs (msg->name_len); + ze = find_zi (h, + ntohl (msg->gns_header.r_id)); + qe = find_qe (h, + ntohl (msg->gns_header.r_id)); + if ( (NULL == ze) && + (NULL == qe) ) + return; /* rid not found */ + if ( (NULL != ze) && + (NULL != qe) ) { + GNUNET_break (0); /* rid ambigous */ force_reconnect (h); return; } - - size = ntohs (msg->size); - type = ntohs (msg->type); - - if (size < sizeof (struct GNUNET_NAMESTORE_Header)) + if ( (0 == name_len) && + (0 == (memcmp (&msg->private_key, + &priv_dummy, + sizeof (priv_dummy)))) ) { - GNUNET_break_op (0); - GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, - GNUNET_TIME_UNIT_FOREVER_REL); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Zone iteration completed!\n"); + if (NULL == ze) + { + GNUNET_break (0); + force_reconnect (h); + return; + } + if (NULL != ze->finish_cb) + ze->finish_cb (ze->finish_cb_cls); + free_ze (ze); return; } - gm = (struct GNUNET_NAMESTORE_Header *) msg; - r_id = ntohl (gm->r_id); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message type %i size %i op %u\n", type, size, r_id); - - /* Find matching operation */ - if (r_id > h->last_op_id_used) + name = (const char *) &msg[1]; + rd_tmp = &name[name_len]; { - /* No matching pending operation found */ - GNUNET_break_op (0); - GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, - GNUNET_TIME_UNIT_FOREVER_REL); - return; - } + struct GNUNET_GNSRECORD_Data rd[rd_count]; - /* Is it a record related operation ? */ - for (qe = h->op_head; qe != NULL; qe = qe->next) - { - if (qe->op_id == r_id) - break; - } - if (qe != NULL) - { - manage_record_operations (qe, msg, type, size); + GNUNET_assert (GNUNET_OK == + GNUNET_GNSRECORD_records_deserialize(rd_len, + rd_tmp, + rd_count, + rd)); + if (0 == name_len) + name = NULL; + if (NULL != qe) + { + if (NULL != qe->proc) + qe->proc (qe->proc_cls, + &msg->private_key, + name, + rd_count, + (rd_count > 0) ? rd : NULL); + free_qe (qe); + return; + } + if (NULL != ze) + { + if (NULL != ze->proc) + ze->proc (ze->proc_cls, + &msg->private_key, + name, + rd_count, + rd); + return; + } } + GNUNET_assert (0); +} - /* Is it a zone iteration operation ? */ - for (ze = h->z_head; ze != NULL; ze = ze->next) + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE. + * + * @param qe the respective entry in the message queue + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR if message malformed + */ +static int +check_zone_to_name_response (void *cls, + const struct ZoneToNameResponseMessage *msg) +{ + size_t name_len; + size_t rd_ser_len; + const char *name_tmp; + + (void) cls; + if (GNUNET_OK != ntohs (msg->res)) + return GNUNET_OK; + name_len = ntohs (msg->name_len); + rd_ser_len = ntohs (msg->rd_len); + if (ntohs (msg->gns_header.header.size) != + sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len) { - if (ze->op_id == r_id) - break; + GNUNET_break (0); + return GNUNET_SYSERR; } - if (ze != NULL) + name_tmp = (const char *) &msg[1]; + if ( (name_len > 0) && + ('\0' != name_tmp[name_len -1]) ) { - manage_zone_operations (ze, msg, type, size); + GNUNET_break (0); + return GNUNET_SYSERR; } - - GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, - GNUNET_TIME_UNIT_FOREVER_REL); - - if (GNUNET_YES == h->reconnect) - force_reconnect (h); - + return check_rd (rd_ser_len, + &name_tmp[name_len], + ntohs (msg->rd_count)); } /** - * Transmit messages from the message queue to the service - * (if there are any, and if we are not already trying). + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE. * - * @param h handle to use + * @param cls + * @param msg the message we received */ static void -do_transmit (struct GNUNET_NAMESTORE_Handle *h); - - -/** - * We can now transmit a message to NAMESTORE. Do it. - * - * @param cls the 'struct GNUNET_NAMESTORE_Handle' - * @param size number of bytes we can transmit - * @param buf where to copy the messages - * @return number of bytes copied into buf - */ -static size_t -transmit_message_to_namestore (void *cls, size_t size, void *buf) +handle_zone_to_name_response (void *cls, + const struct ZoneToNameResponseMessage *msg) { struct GNUNET_NAMESTORE_Handle *h = cls; - struct PendingMessage *p; - size_t ret; - char *cbuf; - - h->th = NULL; - if ((size == 0) || (buf == NULL)) + struct GNUNET_NAMESTORE_QueueEntry *qe; + int res; + size_t name_len; + size_t rd_ser_len; + unsigned int rd_count; + const char *name_tmp; + const char *rd_tmp; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received ZONE_TO_NAME_RESPONSE\n"); + qe = find_qe (h, + ntohl (msg->gns_header.r_id)); + res = ntohs (msg->res); + switch (res) { + case GNUNET_SYSERR: + LOG (GNUNET_ERROR_TYPE_DEBUG, + "An error occured during zone to name operation\n"); + break; + case GNUNET_NO: + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Namestore has no result for zone to name mapping \n"); + if (NULL != qe->proc) + qe->proc (qe->proc_cls, &msg->zone, NULL, 0, NULL); + free_qe (qe); + return; + case GNUNET_YES: + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Namestore has result for zone to name mapping \n"); + name_len = ntohs (msg->name_len); + rd_count = ntohs (msg->rd_count); + rd_ser_len = ntohs (msg->rd_len); + name_tmp = (const char *) &msg[1]; + rd_tmp = &name_tmp[name_len]; + { + struct GNUNET_GNSRECORD_Data rd[rd_count]; + + GNUNET_assert (GNUNET_OK == + GNUNET_GNSRECORD_records_deserialize (rd_ser_len, + rd_tmp, + rd_count, + rd)); + /* normal end, call continuation with result */ + if (NULL != qe->proc) + qe->proc (qe->proc_cls, + &msg->zone, + name_tmp, + rd_count, + rd); + /* return is important here: break would call continuation with error! */ + free_qe (qe); + return; + } + default: + GNUNET_break (0); force_reconnect (h); - return 0; - } - ret = 0; - cbuf = buf; - while ((NULL != (p = h->pending_head)) && (p->size <= size)) - { - memcpy (&cbuf[ret], &p[1], p->size); - ret += p->size; - size -= p->size; - GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p); - if (GNUNET_YES == p->is_init) - GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, - GNUNET_TIME_UNIT_FOREVER_REL); - GNUNET_free (p); + return; } - do_transmit (h); - return ret; + /* error case, call continuation with error */ + if (NULL != qe->error_cb) + qe->error_cb (qe->error_cb_cls); + free_qe (qe); } + /** - * Transmit messages from the message queue to the service - * (if there are any, and if we are not already trying). + * 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 h handle to use + * @param cls closure with the `struct GNUNET_NAMESTORE_Handle *` + * @param error error code */ static void -do_transmit (struct GNUNET_NAMESTORE_Handle *h) +mq_error_handler (void *cls, + enum GNUNET_MQ_Error error) { - struct PendingMessage *p; - - if (NULL != h->th) - return; - if (NULL == (p = h->pending_head)) - return; - if (NULL == h->client) - return; /* currently reconnecting */ + struct GNUNET_NAMESTORE_Handle *h = cls; - h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, p->size, - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_NO, &transmit_message_to_namestore, - h); + (void) error; + force_reconnect (h); } @@ -910,39 +794,63 @@ do_transmit (struct GNUNET_NAMESTORE_Handle *h) static void reconnect (struct GNUNET_NAMESTORE_Handle *h) { - struct PendingMessage *p; - struct StartMessage *init; - - GNUNET_assert (NULL == h->client); - h->client = GNUNET_CLIENT_connect ("namestore", h->cfg); - GNUNET_assert (NULL != h->client); + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_fixed_size (record_store_response, + GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE, + struct RecordStoreResponseMessage, + h), + GNUNET_MQ_hd_var_size (zone_to_name_response, + GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE, + struct ZoneToNameResponseMessage, + h), + GNUNET_MQ_hd_var_size (record_result, + GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT, + struct RecordResultMessage, + h), + GNUNET_MQ_hd_var_size (lookup_result, + GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE, + struct LabelLookupResponseMessage, + h), + GNUNET_MQ_handler_end () + }; + struct GNUNET_NAMESTORE_ZoneIterator *it; + struct GNUNET_NAMESTORE_QueueEntry *qe; - if ((NULL == (p = h->pending_head)) || (GNUNET_YES != p->is_init)) + GNUNET_assert (NULL == h->mq); + h->mq = GNUNET_CLIENT_connect (h->cfg, + "namestore", + handlers, + &mq_error_handler, + h); + if (NULL == h->mq) + return; + /* re-transmit pending requests that waited for a reconnect... */ + for (it = h->z_head; NULL != it; it = it->next) + { + GNUNET_MQ_send (h->mq, + it->env); + it->env = NULL; + } + for (qe = h->op_head; NULL != qe; qe = qe->next) { - p = GNUNET_malloc (sizeof (struct PendingMessage) + - sizeof (struct StartMessage)); - p->size = sizeof (struct StartMessage); - p->is_init = GNUNET_YES; - init = (struct StartMessage *) &p[1]; - init->header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_START); - init->header.size = htons (sizeof (struct StartMessage)); - GNUNET_CONTAINER_DLL_insert (h->pending_head, h->pending_tail, p); + GNUNET_MQ_send (h->mq, + qe->env); + qe->env = NULL; } - do_transmit (h); } + /** * Re-establish the connection to the service. * * @param cls handle to use to re-connect. - * @param tc scheduler context */ static void -reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +reconnect_task (void *cls) { struct GNUNET_NAMESTORE_Handle *h = cls; - h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + h->reconnect_task = NULL; reconnect (h); } @@ -955,26 +863,47 @@ reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static void force_reconnect (struct GNUNET_NAMESTORE_Handle *h) { - h->reconnect = GNUNET_NO; - GNUNET_CLIENT_disconnect (h->client); - h->client = NULL; - h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, - &reconnect_task, - h); + struct GNUNET_NAMESTORE_ZoneIterator *ze; + struct GNUNET_NAMESTORE_QueueEntry *qe; + + GNUNET_MQ_destroy (h->mq); + h->mq = NULL; + while (NULL != (ze = h->z_head)) + { + if (NULL != ze->error_cb) + ze->error_cb (ze->error_cb_cls); + free_ze (ze); + } + while (NULL != (qe = h->op_head)) + { + if (NULL != qe->error_cb) + qe->error_cb (qe->error_cb_cls); + if (NULL != qe->cont) + qe->cont (qe->cont_cls, + GNUNET_SYSERR, + "failure in communication with namestore service"); + free_qe (qe); + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Reconnecting to namestore\n"); + h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay); + h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, + &reconnect_task, + h); } /** - * Get an unused operation id to distinguish between namestore requests + * Get a fresh operation id to distinguish between namestore requests + * * @param h the namestore handle - * @return operation id + * @return next operation id to use */ static uint32_t get_op_id (struct GNUNET_NAMESTORE_Handle *h) { - uint32_t op_id = h->last_op_id_used; - h->last_op_id_used ++; - return op_id; + return h->last_op_id_used++; } @@ -989,492 +918,294 @@ GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_NAMESTORE_Handle *h; - h = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Handle)); + h = GNUNET_new (struct GNUNET_NAMESTORE_Handle); h->cfg = cfg; - h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h); - h->last_op_id_used = 0; + reconnect (h); + if (NULL == h->mq) + { + GNUNET_free (h); + return NULL; + } return h; } -static void -clean_up_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) +/** + * Disconnect from the namestore service (and free associated + * resources). + * + * @param h handle to the namestore + */ +void +GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h) { - struct PendingMessage *p; struct GNUNET_NAMESTORE_QueueEntry *q; struct GNUNET_NAMESTORE_ZoneIterator *z; - struct GNUNET_NAMESTORE_Handle *h = cls; - GNUNET_assert (h != NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - while (NULL != (p = h->pending_head)) - { - GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p); - GNUNET_free (p); - } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + GNUNET_break (NULL == h->op_head); while (NULL != (q = h->op_head)) { - GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q); + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + q); GNUNET_free (q); } - + GNUNET_break (NULL == h->z_head); while (NULL != (z = h->z_head)) { - GNUNET_CONTAINER_DLL_remove (h->z_head, h->z_tail, z); + GNUNET_CONTAINER_DLL_remove (h->z_head, + h->z_tail, + z); GNUNET_free (z); } - - if (NULL != h->client) + if (NULL != h->mq) { - GNUNET_CLIENT_disconnect (h->client); - h->client = NULL; + GNUNET_MQ_destroy (h->mq); + h->mq = NULL; } - if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task) + if (NULL != h->reconnect_task) { GNUNET_SCHEDULER_cancel (h->reconnect_task); - h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + h->reconnect_task = NULL; } - GNUNET_free(h); - h = NULL; + GNUNET_free (h); } /** - * Disconnect from the namestore service (and free associated - * resources). + * Task launched to warn the user that the namestore is + * excessively slow and that a query was thus dropped. * - * @param h handle to the namestore - * @param drop set to GNUNET_YES to delete all data in namestore (!) + * @param cls a `struct GNUNET_NAMESTORE_QueueEntry *` */ -void -GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h, int drop) +static void +warn_delay (void *cls) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from namestore service\n"); - GNUNET_SCHEDULER_add_now (&clean_up_task, h); + struct GNUNET_NAMESTORE_QueueEntry *qe = cls; + + qe->timeout_task = NULL; + LOG (GNUNET_ERROR_TYPE_WARNING, + "Did not receive response from namestore after %s!\n", + GNUNET_STRINGS_relative_time_to_string (NAMESTORE_DELAY_TOLERANCE, + GNUNET_YES)); + if (NULL != qe->cont) + { + qe->cont (qe->cont_cls, + GNUNET_SYSERR, + "timeout"); + qe->cont = NULL; + } + GNUNET_NAMESTORE_cancel (qe); } /** * Store an item in the namestore. If the item is already present, - * the expiration time is updated to the max of the existing time and - * the new time. This API is used when we cache signatures from other - * authorities. + * it is replaced with the new record. Use an empty array to + * remove all records under the given name. * * @param h handle to the namestore - * @param zone_key public key of the zone - * @param name name that is being mapped (at most 255 characters long) - * @param freshness when does the corresponding block in the DHT expire (until - * when should we never do a DHT lookup for the same name again)? - * @param rd_count number of entries in 'rd' array + * @param pkey private key of the zone + * @param label name that is being mapped (at most 255 characters long) + * @param rd_count number of records in the @a rd array * @param rd array of records with data to store - * @param signature signature for all the records in the zone under the given name * @param cont continuation to call when done - * @param cont_cls closure for cont + * @param cont_cls closure for @a cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * -GNUNET_NAMESTORE_record_put (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, - const char *name, - struct GNUNET_TIME_Absolute freshness, - unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, - const struct GNUNET_CRYPTO_RsaSignature *signature, - GNUNET_NAMESTORE_ContinuationWithStatus cont, - void *cont_cls) +GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; - struct PendingMessage *pe; - - /* pointer to elements */ - char * rd_tmp; - char * name_tmp; - - size_t msg_size = 0; - size_t name_len = 0; - size_t rd_ser_len = 0; - uint32_t rid = 0; - - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != zone_key); - GNUNET_assert (NULL != name); - GNUNET_assert (NULL != rd); - GNUNET_assert (NULL != signature); + struct GNUNET_MQ_Envelope *env; + char *name_tmp; + char *rd_ser; + ssize_t rd_ser_len; + size_t name_len; + uint32_t rid; + struct RecordStoreMessage *msg; + ssize_t sret; - name_len = strlen(name) + 1; - if (name_len > 256) + name_len = strlen (label) + 1; + if (name_len > MAX_NAME_LEN) { GNUNET_break (0); return NULL; } - - rid = get_op_id(h); - qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); - qe->nsh = h; - qe->cont = cont; - qe->cont_cls = cont_cls; - qe->op_id = rid; - GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); - - /* set msg_size*/ - rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); - char rd_ser[rd_ser_len]; - GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); - - struct RecordPutMessage * msg; - msg_size = sizeof (struct RecordPutMessage) + name_len + rd_ser_len; - - /* create msg here */ - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct RecordPutMessage *) &pe[1]; - name_tmp = (char *) &msg[1]; - rd_tmp = &name_tmp[name_len]; - - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT); - msg->gns_header.header.size = htons (msg_size); - msg->gns_header.r_id = htonl (rid); - msg->signature = *signature; - msg->name_len = htons (name_len); - msg->expire = GNUNET_TIME_absolute_hton (freshness); - msg->rd_len = htons (rd_ser_len); - msg->rd_count = htons (rd_count); - - msg->public_key = *zone_key; - memcpy (name_tmp, name, name_len); - memcpy (rd_tmp, rd_ser, rd_ser_len); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_PUT", name, msg_size); - - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); - - return qe; -} - - -/** - * Check if a signature is valid. This API is used by the GNS Block - * to validate signatures received from the network. - * - * @param public_key public key of the zone - * @param expire block expiration - * @param name name that is being mapped (at most 255 characters long) - * @param rd_count number of entries in 'rd' array - * @param rd array of records with data to store - * @param signature signature for all the records in the zone under the given name - * @return GNUNET_OK if the signature is valid - */ -int -GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const struct GNUNET_TIME_Absolute expire, - const char *name, - unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, - const struct GNUNET_CRYPTO_RsaSignature *signature) -{ - int res = GNUNET_SYSERR; - size_t rd_ser_len = 0; - size_t name_len = 0; - char * name_tmp; - char * rd_tmp; - struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose; - struct GNUNET_TIME_AbsoluteNBO *expire_tmp; - struct GNUNET_TIME_AbsoluteNBO expire_nbo = GNUNET_TIME_absolute_hton(expire); - - GNUNET_assert (public_key != NULL); - GNUNET_assert (name != NULL); - GNUNET_assert (rd != NULL); - GNUNET_assert (signature != NULL); - - - rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); - char rd_ser[rd_ser_len]; - GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); - - name_len = strlen (name) + 1; - if (name_len > 256) + rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, + rd); + if (rd_ser_len < 0) { GNUNET_break (0); - return GNUNET_SYSERR; + return NULL; } - - sig_purpose = GNUNET_malloc(sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len); - sig_purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)+ rd_ser_len + name_len); - sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); - expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; - name_tmp = (char *) &expire_tmp[1]; - rd_tmp = &name_tmp[name_len]; - memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); - memcpy (name_tmp, name, name_len); - memcpy (rd_tmp, rd_ser, rd_ser_len); - - res = GNUNET_CRYPTO_rsa_verify(GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, sig_purpose, signature, public_key); - - GNUNET_free (sig_purpose); - - return res; -} - -/** - * Store an item in the namestore. If the item is already present, - * the expiration time is updated to the max of the existing time and - * the new time. This API is used by the authority of a zone. - * - * @param h handle to the namestore - * @param pkey private key of the zone - * @param name name that is being mapped (at most 255 characters long) - * @param rd record data to store - * @param cont continuation to call when done - * @param cont_cls closure for cont - * @return handle to abort the request - */ -struct GNUNET_NAMESTORE_QueueEntry * -GNUNET_NAMESTORE_record_create (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, - const char *name, - const struct GNUNET_NAMESTORE_RecordData *rd, - GNUNET_NAMESTORE_ContinuationWithStatus cont, - void *cont_cls) -{ - struct GNUNET_NAMESTORE_QueueEntry *qe; - struct PendingMessage *pe; - char * name_tmp; - char * pkey_tmp; - char * rd_tmp; - size_t rd_ser_len = 0; - size_t msg_size = 0; - size_t name_len = 0; - size_t key_len = 0; - uint32_t rid = 0; - - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != pkey); - GNUNET_assert (NULL != name); - GNUNET_assert (NULL != rd); - - name_len = strlen(name) + 1; - if (name_len > 256) + if (rd_ser_len > UINT16_MAX) { GNUNET_break (0); return NULL; } - - rid = get_op_id(h); - qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); - qe->nsh = h; + rid = get_op_id (h); + qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry); + qe->h = h; qe->cont = cont; qe->cont_cls = cont_cls; qe->op_id = rid; - GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); - - /* set msg_size*/ - struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * pkey_enc = GNUNET_CRYPTO_rsa_encode_key (pkey); - GNUNET_assert (pkey_enc != NULL); - key_len = ntohs (pkey_enc->len); - - rd_ser_len = GNUNET_NAMESTORE_records_get_size(1, rd); - char rd_ser[rd_ser_len]; - GNUNET_NAMESTORE_records_serialize(1, rd, rd_ser_len, rd_ser); - - struct RecordCreateMessage * msg; - msg_size = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len; - - /* create msg here */ - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct RecordCreateMessage *) &pe[1]; - - pkey_tmp = (char *) &msg[1]; - name_tmp = &pkey_tmp[key_len]; - rd_tmp = &name_tmp[name_len]; - - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE); - msg->gns_header.header.size = htons (msg_size); + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + qe); + + /* setup msg */ + env = GNUNET_MQ_msg_extra (msg, + name_len + rd_ser_len, + GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE); msg->gns_header.r_id = htonl (rid); msg->name_len = htons (name_len); - msg->rd_count = htons (1); + msg->rd_count = htons (rd_count); msg->rd_len = htons (rd_ser_len); - msg->pkey_len = htons (key_len); - msg->expire = GNUNET_TIME_absolute_hton(GNUNET_TIME_UNIT_FOREVER_ABS); - memcpy (pkey_tmp, pkey_enc, key_len); - memcpy (name_tmp, name, name_len); - memcpy (rd_tmp, rd_ser, rd_ser_len); - GNUNET_free (pkey_enc); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_CREATE", name, msg_size); + msg->reserved = htons (0); + msg->private_key = *pkey; - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); + name_tmp = (char *) &msg[1]; + GNUNET_memcpy (name_tmp, + label, + name_len); + rd_ser = &name_tmp[name_len]; + sret = GNUNET_GNSRECORD_records_serialize (rd_count, + rd, + rd_ser_len, + rd_ser); + if ( (0 > sret) || + (sret != rd_ser_len) ) + { + GNUNET_break (0); + GNUNET_free (env); + return NULL; + } + GNUNET_assert (rd_ser_len == (size_t) sret); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending NAMESTORE_RECORD_STORE message for name `%s' with %u records\n", + label, + rd_count); + qe->timeout_task = GNUNET_SCHEDULER_add_delayed (NAMESTORE_DELAY_TOLERANCE, + &warn_delay, + qe); + if (NULL == h->mq) + { + qe->env = env; + LOG (GNUNET_ERROR_TYPE_WARNING, + "Delaying NAMESTORE_RECORD_STORE message as namestore is not ready!\n"); + } + else + { + GNUNET_MQ_send (h->mq, + env); + } return qe; } /** - * Explicitly remove some content from the database. The - * "cont"inuation will be called with status "GNUNET_OK" if content - * was removed, "GNUNET_NO" if no matching entry was found and - * "GNUNET_SYSERR" on all other types of errors. - * This API is used by the authority of a zone. + * Set the desired nick name for a zone * * @param h handle to the namestore * @param pkey private key of the zone - * @param name name that is being mapped (at most 255 characters long) - * @param rd record data, remove specific record, NULL to remove the name and all records + * @param nick the nick name to set * @param cont continuation to call when done - * @param cont_cls closure for cont + * @param cont_cls closure for @a cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * -GNUNET_NAMESTORE_record_remove (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, - const char *name, - const struct GNUNET_NAMESTORE_RecordData *rd, - GNUNET_NAMESTORE_ContinuationWithStatus cont, - void *cont_cls) +GNUNET_NAMESTORE_set_nick (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const char *nick, + GNUNET_NAMESTORE_ContinuationWithStatus cont, + void *cont_cls) { - struct GNUNET_NAMESTORE_QueueEntry *qe; - struct PendingMessage *pe; - char *pkey_tmp; - char *rd_tmp; - char *name_tmp; - size_t rd_ser_len = 0; - size_t msg_size = 0; - size_t name_len = 0; - size_t key_len = 0; - uint32_t rid = 0; - uint16_t rd_count = 1; - - GNUNET_assert (NULL != h); - - rid = get_op_id(h); - qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); - qe->nsh = h; - qe->cont = cont; - qe->cont_cls = cont_cls; - qe->op_id = rid; - GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); - - /* set msg_size*/ - struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * pkey_enc = GNUNET_CRYPTO_rsa_encode_key (pkey); - GNUNET_assert (pkey_enc != NULL); - key_len = ntohs (pkey_enc->len); - - if (NULL == rd) - rd_count = 0; - else - rd_count = 1; - rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); - char rd_ser[rd_ser_len]; - GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser); - - name_len = strlen (name) + 1; - - struct RecordRemoveMessage * msg; - msg_size = sizeof (struct RecordRemoveMessage) + key_len + name_len + rd_ser_len; - - /* create msg here */ - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct RecordRemoveMessage *) &pe[1]; - - pkey_tmp = (char *) &msg[1]; - name_tmp = &pkey_tmp[key_len]; - rd_tmp = &name_tmp[name_len]; + struct GNUNET_GNSRECORD_Data rd; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE); - msg->gns_header.header.size = htons (msg_size); - msg->gns_header.r_id = htonl (rid); - msg->name_len = htons (name_len); - msg->rd_len = htons (rd_ser_len); - msg->rd_count = htons (rd_count); - msg->pkey_len = htons (key_len); - memcpy (pkey_tmp, pkey_enc, key_len); - memcpy (name_tmp, name, name_len); - memcpy (rd_tmp, rd_ser, rd_ser_len); - - GNUNET_free (pkey_enc); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_REMOVE", name, msg_size); - - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); - return qe; + if (NULL == h->mq) + return NULL; + memset (&rd, 0, sizeof (rd)); + rd.data = nick; + rd.data_size = strlen (nick) +1; + rd.record_type = GNUNET_GNSRECORD_TYPE_NICK; + rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us; + rd.flags |= GNUNET_GNSRECORD_RF_PRIVATE; + return GNUNET_NAMESTORE_records_store (h, + pkey, + GNUNET_GNS_EMPTY_LABEL_AT, + 1, + &rd, + cont, + cont_cls); } /** - * Get a result for a particular key from the namestore. The processor - * will only be called once. + * Lookup an item in the namestore. * * @param h handle to the namestore - * @param zone zone to look up a record from - * @param name name to look up - * @param record_type desired record type, 0 for all - * @param proc function to call on the matching records, or with - * NULL (rd_count == 0) if there are no matching records - * @param proc_cls closure for proc - * @return a handle that can be used to - * cancel + * @param pkey private key of the zone + * @param label name that is being mapped (at most 255 characters long) + * @param error_cb function to call on error (i.e. disconnect) + * @param error_cb_cls closure for @a error_cb + * @param rm function to call with the result (with 0 records if we don't have that label) + * @param rm_cls closure for @a rm + * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * -GNUNET_NAMESTORE_lookup_record (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_ShortHashCode *zone, - const char *name, - uint32_t record_type, - GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls) +GNUNET_NAMESTORE_records_lookup (struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const char *label, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_NAMESTORE_RecordMonitor rm, + void *rm_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; - struct PendingMessage *pe; - size_t msg_size = 0; - size_t name_len = 0; - uint32_t rid = 0; - - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != zone); - GNUNET_assert (NULL != name); + struct GNUNET_MQ_Envelope *env; + struct LabelLookupMessage *msg; + size_t label_len; - name_len = strlen (name) + 1; - if ((name_len == 0) || (name_len > 256)) + if (1 == (label_len = strlen (label) + 1)) { GNUNET_break (0); return NULL; } - rid = get_op_id(h); - qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); - qe->nsh = h; - qe->proc = proc; - qe->proc_cls = proc_cls; - qe->op_id = rid; - GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); - - /* set msg_size*/ - msg_size = sizeof (struct LookupNameMessage) + name_len; - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - - /* create msg here */ - struct LookupNameMessage * msg; - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct LookupNameMessage *) &pe[1]; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME); - msg->gns_header.header.size = htons (msg_size); - msg->gns_header.r_id = htonl (rid); - msg->record_type = htonl (record_type); - msg->name_len = htonl (name_len); - msg->zone = *zone; - memcpy (&msg[1], name, name_len); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s'\n", "NAMESTORE_LOOKUP_NAME", name); - - /* transmit message */ - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); - + qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry); + qe->h = h; + qe->error_cb = error_cb; + qe->error_cb_cls = error_cb_cls; + qe->proc = rm; + qe->proc_cls = rm_cls; + qe->op_id = get_op_id(h); + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + qe); + + env = GNUNET_MQ_msg_extra (msg, + label_len, + GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP); + msg->gns_header.r_id = htonl (qe->op_id); + msg->zone = *pkey; + msg->label_len = htonl (label_len); + GNUNET_memcpy (&msg[1], + label, + label_len); + if (NULL == h->mq) + qe->env = env; + else + GNUNET_MQ_send (h->mq, + env); return qe; } @@ -1484,195 +1215,146 @@ GNUNET_NAMESTORE_lookup_record (struct GNUNET_NAMESTORE_Handle *h, * Returns at most one result to the processor. * * @param h handle to the namestore - * @param zone hash of public key of the zone to look up in, never NULL - * @param value_zone hash of the public key of the target zone (value), never NULL + * @param zone public key of the zone to look up in, never NULL + * @param value_zone public key of the target zone (value), never NULL + * @param error_cb function to call on error (i.e. disconnect) + * @param error_cb_cls closure for @a error_cb * @param proc function to call on the matching records, or with * NULL (rd_count == 0) if there are no matching records - * @param proc_cls closure for proc + * @param proc_cls closure for @a proc * @return a handle that can be used to * cancel */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_zone_to_name (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_ShortHashCode *zone, - const struct GNUNET_CRYPTO_ShortHashCode *value_zone, - GNUNET_NAMESTORE_RecordProcessor proc, void *proc_cls) + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const struct GNUNET_CRYPTO_EcdsaPublicKey *value_zone, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_NAMESTORE_RecordMonitor proc, + void *proc_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; - struct PendingMessage *pe; - size_t msg_size = 0; - uint32_t rid = 0; - - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != zone); - GNUNET_assert (NULL != value_zone); + struct GNUNET_MQ_Envelope *env; + struct ZoneToNameMessage *msg; + uint32_t rid; rid = get_op_id(h); - qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); - qe->nsh = h; + qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry); + qe->h = h; + qe->error_cb = error_cb; + qe->error_cb_cls = error_cb_cls; qe->proc = proc; qe->proc_cls = proc_cls; qe->op_id = rid; - GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); - - /* set msg_size*/ - msg_size = sizeof (struct ZoneToNameMessage); - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - - /* create msg here */ - struct ZoneToNameMessage * msg; - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct ZoneToNameMessage *) &pe[1]; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME); - msg->gns_header.header.size = htons (msg_size); + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + qe); + + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME); msg->gns_header.r_id = htonl (rid); msg->zone = *zone; msg->value_zone = *value_zone; - - char * z_tmp = GNUNET_strdup (GNUNET_short_h2s (zone)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for zone `%s' in zone `%s'\n", - "NAMESTORE_ZONE_TO_NAME", - z_tmp, - GNUNET_short_h2s (value_zone)); - GNUNET_free (z_tmp); - - /* transmit message */ - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); - + if (NULL == h->mq) + qe->env = env; + else + GNUNET_MQ_send (h->mq, + env); return qe; } - /** * Starts a new zone iteration (used to periodically PUT all of our - * records into our DHT). This MUST lock the GNUNET_NAMESTORE_Handle - * for any other calls than GNUNET_NAMESTORE_zone_iterator_next and - * GNUNET_NAMESTORE_zone_iteration_stop. "proc" will be called once + * records into our DHT). This MUST lock the struct GNUNET_NAMESTORE_Handle + * for any other calls than #GNUNET_NAMESTORE_zone_iterator_next and + * #GNUNET_NAMESTORE_zone_iteration_stop. @a proc will be called once * immediately, and then again after - * "GNUNET_NAMESTORE_zone_iterator_next" is invoked. + * #GNUNET_NAMESTORE_zone_iterator_next is invoked. * * @param h handle to the namestore * @param zone zone to access, NULL for all zones - * @param must_have_flags flags that must be set for the record to be returned - * @param must_not_have_flags flags that must NOT be set for the record to be returned + * @param error_cb function to call on error (i.e. disconnect) + * @param error_cb_cls closure for @a error_cb * @param proc function to call on each name from the zone; it * will be called repeatedly with a value (if available) - * and always once at the end with a name of NULL. - * @param proc_cls closure for proc + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * @param finish_cb_cls closure for @a finish_cb * @return an iterator handle to use for iteration */ struct GNUNET_NAMESTORE_ZoneIterator * GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_ShortHashCode *zone, - enum GNUNET_NAMESTORE_RecordFlags must_have_flags, - enum GNUNET_NAMESTORE_RecordFlags must_not_have_flags, - GNUNET_NAMESTORE_RecordProcessor proc, - void *proc_cls) + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_NAMESTORE_RecordMonitor proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls) { struct GNUNET_NAMESTORE_ZoneIterator *it; - struct PendingMessage *pe; - size_t msg_size = 0; - uint32_t rid = 0; - - GNUNET_assert (NULL != h); - rid = get_op_id(h); - it = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIterator)); + struct GNUNET_MQ_Envelope *env; + struct ZoneIterationStartMessage *msg; + uint32_t rid; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending ZONE_ITERATION_START message\n"); + rid = get_op_id (h); + it = GNUNET_new (struct GNUNET_NAMESTORE_ZoneIterator); 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->op_id = rid; - if (NULL != zone) - { it->zone = *zone; - it->has_zone = GNUNET_YES; - } - else - { - memset (&it->zone, '\0', sizeof (it->zone)); - it->has_zone = GNUNET_NO; - } - GNUNET_CONTAINER_DLL_insert_tail(h->z_head, h->z_tail, it); - - /* set msg_size*/ - msg_size = sizeof (struct ZoneIterationStartMessage); - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - - /* create msg here */ - struct ZoneIterationStartMessage * msg; - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct ZoneIterationStartMessage *) &pe[1]; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START); - msg->gns_header.header.size = htons (msg_size); + GNUNET_CONTAINER_DLL_insert_tail (h->z_head, + h->z_tail, + it); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START); msg->gns_header.r_id = htonl (rid); if (NULL != zone) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for zone `%s'\n", "ZONE_ITERATION_START", GNUNET_short_h2s(zone)); msg->zone = *zone; - } + if (NULL == h->mq) + it->env = env; else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for all zones\n", "ZONE_ITERATION_START"); - memset (&msg->zone, '\0', sizeof (msg->zone)); - } - msg->must_have_flags = ntohs (must_have_flags); - msg->must_not_have_flags = ntohs (must_not_have_flags); - - /* transmit message */ - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); - + GNUNET_MQ_send (h->mq, + env); return it; } /** - * Calls the record processor specified in GNUNET_NAMESTORE_zone_iteration_start + * Calls the record processor specified in #GNUNET_NAMESTORE_zone_iteration_start * for the next record. * * @param it the iterator + * @param limit number of records to return to the iterator in one shot + * (before #GNUNET_NAMESTORE_zone_iterator_next is to be called again) */ void -GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it) +GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it, + uint64_t limit) { - struct GNUNET_NAMESTORE_Handle *h; - struct PendingMessage *pe; - size_t msg_size = 0; - - GNUNET_assert (NULL != it); - h = it->h; - struct GNUNET_NAMESTORE_ZoneIterator *tmp = it->h->z_head; - - while (tmp != NULL) - { - if (tmp == it) - break; - tmp = tmp->next; - } - GNUNET_assert (NULL != tmp); - - /* set msg_size*/ - msg_size = sizeof (struct ZoneIterationNextMessage); - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - - /* create msg here */ - struct ZoneIterationNextMessage * msg; - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct ZoneIterationNextMessage *) &pe[1]; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT); - msg->gns_header.header.size = htons (msg_size); + struct GNUNET_NAMESTORE_Handle *h = it->h; + struct ZoneIterationNextMessage *msg; + struct GNUNET_MQ_Envelope *env; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending ZONE_ITERATION_NEXT message with limit %llu\n", + (unsigned long long) limit); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT); msg->gns_header.r_id = htonl (it->op_id); - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "ZONE_ITERATION_NEXT"); - - /* transmit message */ - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); + msg->limit = GNUNET_htonll (limit); + GNUNET_MQ_send (h->mq, + env); } @@ -1684,41 +1366,21 @@ GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it) void GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it) { - GNUNET_assert (NULL != it); - struct PendingMessage *pe; - size_t msg_size = 0; struct GNUNET_NAMESTORE_Handle *h = it->h; - struct GNUNET_NAMESTORE_ZoneIterator *tmp = it->h->z_head; + struct GNUNET_MQ_Envelope *env; + struct ZoneIterationStopMessage *msg; - while (tmp != NULL) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending ZONE_ITERATION_STOP message\n"); + if (NULL != h->mq) { - if (tmp == it) - break; - tmp = tmp->next; + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP); + msg->gns_header.r_id = htonl (it->op_id); + GNUNET_MQ_send (h->mq, + env); } - GNUNET_assert (NULL != tmp); - - /* set msg_size*/ - msg_size = sizeof (struct ZoneIterationStopMessage); - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - - /* create msg here */ - struct ZoneIterationStopMessage * msg; - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct ZoneIterationStopMessage *) &pe[1]; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP); - msg->gns_header.header.size = htons (msg_size); - msg->gns_header.r_id = htonl (it->op_id); - - if (GNUNET_YES == it->has_zone) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for zone `%s'\n", "ZONE_ITERATION_STOP", GNUNET_short_h2s(&it->zone)); - else - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for all zones\n", "ZONE_ITERATION_STOP"); - - /* transmit message */ - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); + free_ze (it); } @@ -1731,11 +1393,8 @@ GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it) void GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe) { - struct GNUNET_NAMESTORE_Handle *h = qe->nsh; - - GNUNET_assert (qe != NULL); - GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); - GNUNET_free(qe); + free_qe (qe); } + /* end of namestore_api.c */