X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=inline;f=src%2Fnamestore%2Fnamestore_api.c;h=55745d83d8c816ad415faba37f3c22c94cc3067f;hb=7da98cf076e9c5101244dfbbf8c3ddff045d298e;hp=ff1630b9261ac7ee9c01eb7a658f144298b97c0f;hpb=77f81b949fe89c8a316f49fc5fa75cd51c513468;p=oweals%2Fgnunet.git diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c index ff1630b92..55745d83d 100644 --- a/src/namestore/namestore_api.c +++ b/src/namestore/namestore_api.c @@ -1,21 +1,19 @@ /* This file is part of GNUnet. - (C) 2010-2013 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 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 - 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ /** @@ -33,12 +31,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, "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 @@ -60,7 +64,7 @@ struct GNUNET_NAMESTORE_QueueEntry /** * Main handle to access the namestore. */ - struct GNUNET_NAMESTORE_Handle *nsh; + struct GNUNET_NAMESTORE_Handle *h; /** * Continuation to call @@ -68,7 +72,7 @@ struct GNUNET_NAMESTORE_QueueEntry GNUNET_NAMESTORE_ContinuationWithStatus cont; /** - * Closure for 'cont'. + * Closure for @e cont. */ void *cont_cls; @@ -78,19 +82,30 @@ struct GNUNET_NAMESTORE_QueueEntry GNUNET_NAMESTORE_RecordMonitor proc; /** - * Closure for 'proc'. + * Closure for @e proc. */ void *proc_cls; /** - * Function to call with the blocks we get back; or NULL. + * Function to call on errors. + */ + GNUNET_SCHEDULER_TaskCallback error_cb; + + /** + * Closure for @e error_cb. */ - GNUNET_NAMESTORE_BlockProcessor block_proc; + void *error_cb_cls; /** - * Closure for 'block_proc'. + * Envelope of the message to send to the service, if not yet + * sent. */ - void *block_proc_cls; + 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 @@ -122,49 +137,50 @@ struct GNUNET_NAMESTORE_ZoneIterator struct GNUNET_NAMESTORE_Handle *h; /** - * The continuation to call with the results + * Function to call on completion. */ - GNUNET_NAMESTORE_RecordMonitor proc; + GNUNET_SCHEDULER_TaskCallback finish_cb; /** - * Closure for 'proc'. + * Closure for @e error_cb. */ - void* proc_cls; + void *finish_cb_cls; /** - * Private key of the zone. + * The continuation to call with the results */ - struct GNUNET_CRYPTO_EccPrivateKey zone; + GNUNET_NAMESTORE_RecordMonitor proc; /** - * The operation id this zone iteration operation has + * Closure for @e proc. */ - uint32_t op_id; - -}; + void *proc_cls; + /** + * Function to call on errors. + */ + GNUNET_SCHEDULER_TaskCallback error_cb; -/** - * Message in linked list we should send to the service. The - * actual binary message follows this struct. - */ -struct PendingMessage -{ + /** + * Closure for @e error_cb. + */ + void *error_cb_cls; /** - * Kept in a DLL. + * Envelope of the message to send to the service, if not yet + * sent. */ - struct PendingMessage *next; + struct GNUNET_MQ_Envelope *env; /** - * Kept in a DLL. + * Private key of the zone. */ - struct PendingMessage *prev; + struct GNUNET_CRYPTO_EcdsaPrivateKey zone; /** - * Size of the message. + * The operation id this zone iteration operation has */ - size_t size; + uint32_t op_id; }; @@ -181,59 +197,44 @@ struct GNUNET_NAMESTORE_Handle const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Socket (if available). - */ - struct GNUNET_CLIENT_Connection *client; - - /** - * Currently pending transmission request (or NULL). + * Connection to the service (if available). */ - struct GNUNET_CLIENT_TransmitHandle *th; - - /** - * Head of linked list of pending messages to send to the service - */ - 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; /** - * Should we reconnect to service due to some serious error? + * Delay introduced before we reconnect. */ - int reconnect; + struct GNUNET_TIME_Relative reconnect_delay; /** - * Did we start to receive yet? + * Should we reconnect to service due to some serious error? */ - int is_receiving; + int reconnect; /** * The last operation id used for a NAMESTORE operation @@ -253,142 +254,172 @@ force_reconnect (struct GNUNET_NAMESTORE_Handle *h); /** - * Handle an incoming message of type #GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK_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 - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client + * @param h namestore handle + * @param rid id to look up + * @return NULL if @a rid was not found */ -static int -handle_lookup_block_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct LookupBlockResponseMessage *msg, - size_t size) +static struct GNUNET_NAMESTORE_QueueEntry * +find_qe (struct GNUNET_NAMESTORE_Handle *h, + uint32_t rid) { - struct GNUNET_NAMESTORE_Block *block; - char buf[size + sizeof (struct GNUNET_NAMESTORE_Block) - sizeof (struct LookupBlockResponseMessage)]; + struct GNUNET_NAMESTORE_QueueEntry *qe; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s'\n", - "LOOKUP_BLOCK_RESPONSE"); - if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us) - { - /* no match found */ - if (NULL != qe->block_proc) - qe->block_proc (qe->block_proc_cls, NULL); - return GNUNET_OK; - } + for (qe = h->op_head; qe != NULL; qe = qe->next) + if (qe->op_id == rid) + return qe; + return NULL; +} - block = (struct GNUNET_NAMESTORE_Block *) buf; - block->signature = msg->signature; - block->derived_key = msg->derived_key; - block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); - block->purpose.size = htonl (size - sizeof (struct LookupBlockResponseMessage) + - sizeof (struct GNUNET_TIME_AbsoluteNBO) + - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)); - block->expiration_time = msg->expire; - memcpy (&block[1], - &msg[1], - size - sizeof (struct LookupBlockResponseMessage)); - if (GNUNET_OK != - GNUNET_NAMESTORE_block_verify (block)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (NULL != qe->block_proc) - qe->block_proc (qe->block_proc_cls, block); - else - GNUNET_break (0); - return GNUNET_OK; + +/** + * 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; + + 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_BLOCK_CACHE_RESPONSE' + * Free @a qe. * - * @param qe the respective entry in the message queue - * @param msg the message we received - * @param size the message size - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client + * @param qe entry to free + */ +static void +free_qe (struct GNUNET_NAMESTORE_QueueEntry *qe) +{ + 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); +} + + +/** + * Free @a ze. + * + * @param ze entry to free + */ +static void +free_ze (struct GNUNET_NAMESTORE_ZoneIterator *ze) +{ + 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); +} + + +/** + * 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 -handle_block_cache_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct BlockCacheResponseMessage *msg, - size_t size) +check_rd (size_t rd_len, + const void *rd_buf, + unsigned int rd_count) { - int res; + struct GNUNET_GNSRECORD_Data rd[rd_count]; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Received `%s'\n", - "BLOCK_CACHE_RESPONSE"); - res = ntohl (msg->op_result); - /* TODO: add actual error message from namestore to response... */ - if (NULL != qe->cont) - qe->cont (qe->cont_cls, res, (GNUNET_OK == res) ? NULL : _("Namestore failed to cache block")); + if (GNUNET_OK != + GNUNET_GNSRECORD_records_deserialize (rd_len, + rd_buf, + rd_count, + rd)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } return GNUNET_OK; } /** - * Handle an incoming message of type #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_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 - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client */ -static int -handle_record_store_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct RecordStoreResponseMessage* msg, - size_t size) +static void +handle_record_store_response (void *cls, + const struct RecordStoreResponseMessage *msg) { + struct GNUNET_NAMESTORE_Handle *h = cls; + struct GNUNET_NAMESTORE_QueueEntry *qe; int res; const char *emsg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Received `%s'\n", - "RECORD_STORE_RESPONSE"); - /* TODO: add actual error message from namestore to response... */ + + 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); - return GNUNET_OK; + if (NULL != qe->cont) + qe->cont (qe->cont_cls, + res, + emsg); + free_qe (qe); } /** - * Handle an incoming message of type #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT + * 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 and we did NOT notify the client + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ static int -handle_record_result (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct RecordResultMessage *msg, - size_t size) +check_lookup_result (void *cls, + const struct LabelLookupResponseMessage *msg) { const char *name; - const char *rd_tmp; size_t exp_msg_len; size_t msg_len; size_t name_len; size_t rd_len; - unsigned int rd_count; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s'\n", - "RECORD_RESULT"); + (void) cls; 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); - GNUNET_break (0 == ntohs (msg->reserved)); - exp_msg_len = sizeof (struct RecordResultMessage) + name_len + rd_len; + exp_msg_len = sizeof (*msg) + name_len + rd_len; if (msg_len != exp_msg_len) { GNUNET_break (0); @@ -401,430 +432,360 @@ handle_record_result (struct GNUNET_NAMESTORE_QueueEntry *qe, GNUNET_break (0); return GNUNET_SYSERR; } - rd_tmp = &name[name_len]; + if (GNUNET_NO == ntohs (msg->found)) { - struct GNUNET_NAMESTORE_RecordData rd[rd_count]; - - if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize(rd_len, rd_tmp, rd_count, rd)) + if (0 != ntohs (msg->rd_count)) { GNUNET_break (0); return GNUNET_SYSERR; } - 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); + return GNUNET_OK; } - return GNUNET_OK; + return check_rd (rd_len, + &name[name_len], + ntohs (msg->rd_count)); } /** - * Handle an incoming message of type #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE. + * Handle 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_NO if we notified the client about - * the error, #GNUNET_SYSERR on error and we did NOT notify the client */ -static int -handle_zone_to_name_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct ZoneToNameResponseMessage *msg, - size_t size) +static void +handle_lookup_result (void *cls, + const struct LabelLookupResponseMessage *msg) { - int res; + 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_ser_len; + size_t rd_len; unsigned int rd_count; - const char *name_tmp; - const char *rd_tmp; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s'\n", - "ZONE_TO_NAME_RESPONSE"); - res = ntohs (msg->res); - switch (res) + 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); + name = (const char *) &msg[1]; + if (GNUNET_NO == ntohs (msg->found)) { - 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"); - break; - 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]; - if ( (name_len > 0) && - ('\0' != name_tmp[name_len -1]) ) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - 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)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - /* 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! */ - return GNUNET_OK; - } - default: - GNUNET_break (0); - return GNUNET_SYSERR; + /* label was not in namestore */ + if (NULL != qe->proc) + qe->proc (qe->proc_cls, + &msg->private_key, + name, + 0, + NULL); + free_qe (qe); + return; } - /* error case, call continuation with error */ - if (NULL != qe->proc) - qe->proc (qe->proc_cls, NULL, NULL, 0, NULL); - return GNUNET_OK; -} - -/** - * Handle incoming messages for record operations - * - * @param qe the respective zone iteration handle - * @param msg the message we received - * @param type the message type in host byte order - * @param size the message size - * @return #GNUNET_OK on success, #GNUNET_NO if we notified the client about - * the error, #GNUNET_SYSERR on error and we did NOT notify the client - */ -static int -manage_record_operations (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct GNUNET_MessageHeader *msg, - uint16_t type, - size_t size) -{ - /* handle different message type */ - switch (type) + rd_tmp = &name[name_len]; { - case GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK_RESPONSE: - if (size < sizeof (struct LookupBlockResponseMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_lookup_block_response (qe, (const struct LookupBlockResponseMessage *) msg, size); - case GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE_RESPONSE: - if (size != sizeof (struct BlockCacheResponseMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_block_cache_response (qe, (const struct BlockCacheResponseMessage *) msg, size); - case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE: - if (size != sizeof (struct RecordStoreResponseMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_record_store_response (qe, (const struct RecordStoreResponseMessage *) msg, size); - case GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE: - if (size < sizeof (struct ZoneToNameResponseMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_zone_to_name_response (qe, (const struct ZoneToNameResponseMessage *) msg, size); - case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT: - if (size < sizeof (struct RecordResultMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_record_result (qe, (const struct RecordResultMessage *) msg, size); - default: - GNUNET_break (0); - return GNUNET_SYSERR; + struct GNUNET_GNSRECORD_Data rd[rd_count]; + + 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); } + free_qe (qe); } /** - * Handle a response from NAMESTORE service for a zone iteration request + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT * - * @param ze the respective iterator for this operation - * @param msg the message containing the respoonse - * @param size the message size - * @return #GNUNET_YES on success, @a ze should be kept, #GNUNET_NO on success if @a ze should - * not be kept any longer, #GNUNET_SYSERR on error (disconnect) and @a ze should be kept + * @param cls + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ static int -handle_zone_iteration_response (struct GNUNET_NAMESTORE_ZoneIterator *ze, - const struct RecordResultMessage *msg, - size_t size) +check_record_result (void *cls, + const struct RecordResultMessage *msg) { - static struct GNUNET_CRYPTO_EccPrivateKey priv_dummy; + const char *name; size_t msg_len; - size_t exp_msg_len; size_t name_len; size_t rd_len; - unsigned rd_count; - const char *name_tmp; - const char *rd_ser_tmp; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s'\n", - "ZONE_ITERATION_RESPONSE"); - msg_len = ntohs (msg->gns_header.header.size); + (void) cls; 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); - exp_msg_len = sizeof (struct RecordResultMessage) + name_len + rd_len; - if (msg_len != exp_msg_len) + if (0 != ntohs (msg->reserved)) { GNUNET_break (0); return GNUNET_SYSERR; } - if ((0 == name_len) && (0 == (memcmp (&msg->private_key, &priv_dummy, sizeof (priv_dummy))))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Zone iteration is completed!\n"); - if (NULL != ze->proc) - ze->proc (ze->proc_cls, NULL, NULL, 0, NULL); - return GNUNET_NO; - } - name_tmp = (const char *) &msg[1]; - if ((name_tmp[name_len -1] != '\0') || (name_len > MAX_NAME_LEN)) + if (msg_len != sizeof (struct RecordResultMessage) + name_len + rd_len) { GNUNET_break (0); return GNUNET_SYSERR; } - rd_ser_tmp = (const 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 (0); - return GNUNET_SYSERR; - } - if (NULL != ze->proc) - ze->proc (ze->proc_cls, &msg->private_key, name_tmp, rd_count, rd); - return GNUNET_YES; - } -} - - -/** - * Handle incoming messages for zone iterations - * - * @param ze the respective zone iteration handle - * @param msg the message we received - * @param type the message type in HBO - * @param size the message size - * @return #GNUNET_YES on success, @a ze should be kept, #GNUNET_NO on success if @a ze should - * not be kept any longer, #GNUNET_SYSERR on error (disconnect) and @a ze should be kept - */ -static int -manage_zone_operations (struct GNUNET_NAMESTORE_ZoneIterator *ze, - const struct GNUNET_MessageHeader *msg, - int type, size_t size) -{ - /* handle different message type */ - switch (type) + name = (const char *) &msg[1]; + if ( (name_len > 0) && + ('\0' != name[name_len -1]) ) { - case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT: - if (size < sizeof (struct RecordResultMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_zone_iteration_response (ze, (const struct RecordResultMessage *) msg, size); - default: 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; - const 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; - int ret; + 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)) - { - GNUNET_break_op (0); - GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, - GNUNET_TIME_UNIT_FOREVER_REL); - return; - } - gm = (const struct GNUNET_NAMESTORE_Header *) msg; - r_id = ntohl (gm->r_id); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received message type %u size %u op %u\n", - (unsigned int) type, - (unsigned int) size, - (unsigned int) r_id); - - /* Is it a record related operation ? */ - for (qe = h->op_head; qe != NULL; qe = qe->next) - if (qe->op_id == r_id) - break; - if (NULL != qe) + if ( (0 == name_len) && + (0 == (memcmp (&msg->private_key, + &priv_dummy, + sizeof (priv_dummy)))) ) { - ret = manage_record_operations (qe, msg, type, size); - if (GNUNET_OK != ret) - { - /* protocol error, need to reconnect */ - h->reconnect = GNUNET_YES; - } - if (GNUNET_SYSERR != ret) + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Zone iteration completed!\n"); + if (NULL == ze) { - /* client was notified about success or failure, clean up 'qe' */ - GNUNET_CONTAINER_DLL_remove (h->op_head, - h->op_tail, - qe); - GNUNET_free (qe); + GNUNET_break (0); + force_reconnect (h); + return; } + if (NULL != ze->finish_cb) + ze->finish_cb (ze->finish_cb_cls); + free_ze (ze); + return; } - /* Is it a zone iteration operation? */ - for (ze = h->z_head; ze != NULL; ze = ze->next) - if (ze->op_id == r_id) - break; - if (NULL != ze) + + name = (const char *) &msg[1]; + rd_tmp = &name[name_len]; { - ret = manage_zone_operations (ze, msg, type, size); - if (GNUNET_NO == ret) + struct GNUNET_GNSRECORD_Data rd[rd_count]; + + GNUNET_assert (GNUNET_OK == + GNUNET_GNSRECORD_records_deserialize(rd_len, + rd_tmp, + rd_count, + rd)); + if (0 == name_len) + name = NULL; + if (NULL != qe) { - /* end of iteration, clean up 'ze' */ - GNUNET_CONTAINER_DLL_remove (h->z_head, - h->z_tail, - ze); - GNUNET_free (ze); + 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 (GNUNET_SYSERR == ret) + if (NULL != ze) { - /* protocol error, need to reconnect */ - h->reconnect = GNUNET_YES; + if (NULL != ze->proc) + ze->proc (ze->proc_cls, + &msg->private_key, + name, + rd_count, + rd); + return; } } - if (GNUNET_YES == h->reconnect) - { - force_reconnect (h); - return; - } - GNUNET_CLIENT_receive (h->client, &process_namestore_message, h, - GNUNET_TIME_UNIT_FOREVER_REL); + GNUNET_assert (0); } /** - * 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 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 void -do_transmit (struct GNUNET_NAMESTORE_Handle *h); +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) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + name_tmp = (const char *) &msg[1]; + if ( (name_len > 0) && + ('\0' != name_tmp[name_len -1]) ) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return check_rd (rd_ser_len, + &name_tmp[name_len], + ntohs (msg->rd_count)); +} /** - * We can now transmit a message to NAMESTORE. Do it. + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE. * - * @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 + * @param cls + * @param msg the message we received */ -static size_t -transmit_message_to_namestore (void *cls, size_t size, void *buf) +static void +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; + 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; - h->th = NULL; - if ((0 == size) || (NULL == buf)) - { - force_reconnect (h); - return 0; - } - ret = 0; - cbuf = buf; - while ((NULL != (p = h->pending_head)) && (p->size <= size)) + 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) { - 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_NO == h->is_receiving) + 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]; { - h->is_receiving = GNUNET_YES; - GNUNET_CLIENT_receive (h->client, - &process_namestore_message, h, - GNUNET_TIME_UNIT_FOREVER_REL); + 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; } - GNUNET_free (p); + default: + GNUNET_break (0); + force_reconnect (h); + 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; /* transmission request already pending */ - if (NULL == (p = h->pending_head)) - return; /* transmission queue empty */ - if (NULL == h->client) - return; /* currently reconnecting */ - h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, p->size, - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_NO, &transmit_message_to_namestore, - h); + struct GNUNET_NAMESTORE_Handle *h = cls; + + (void) error; + force_reconnect (h); } @@ -836,10 +797,49 @@ do_transmit (struct GNUNET_NAMESTORE_Handle *h) static void reconnect (struct GNUNET_NAMESTORE_Handle *h) { - GNUNET_assert (NULL == h->client); - h->client = GNUNET_CLIENT_connect ("namestore", h->cfg); - GNUNET_assert (NULL != h->client); - do_transmit (h); + 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; + + 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) + { + GNUNET_MQ_send (h->mq, + qe->env); + qe->env = NULL; + } } @@ -847,14 +847,13 @@ reconnect (struct GNUNET_NAMESTORE_Handle *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); } @@ -867,11 +866,32 @@ 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->is_receiving = GNUNET_NO; - h->client = NULL; - h->reconnect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + 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); } @@ -903,8 +923,12 @@ GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) 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; } @@ -918,95 +942,65 @@ GNUNET_NAMESTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) void GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h) { - struct PendingMessage *p; struct GNUNET_NAMESTORE_QueueEntry *q; struct GNUNET_NAMESTORE_ZoneIterator *z; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); - GNUNET_assert (NULL != h); - 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); } /** - * Store an item in the namestore. If the item is already present, - * it is replaced with the new record. + * 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 block block to store - * @param cont continuation to call when done - * @param cont_cls closure for cont - * @return handle to abort the request + * @param cls a `struct GNUNET_NAMESTORE_QueueEntry *` */ -struct GNUNET_NAMESTORE_QueueEntry * -GNUNET_NAMESTORE_block_cache (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_NAMESTORE_Block *block, - GNUNET_NAMESTORE_ContinuationWithStatus cont, - void *cont_cls) +static void +warn_delay (void *cls) { - struct GNUNET_NAMESTORE_QueueEntry *qe; - struct PendingMessage *pe; - struct BlockCacheMessage *msg; - uint32_t rid; - size_t blen; - size_t msg_size; - - GNUNET_assert (NULL != h); - blen = ntohl (block->purpose.size) - sizeof (struct GNUNET_TIME_AbsoluteNBO); - rid = get_op_id (h); - qe = GNUNET_new (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); - - /* setup msg */ - msg_size = sizeof (struct BlockCacheMessage) + blen; - pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - msg = (struct BlockCacheMessage *) &pe[1]; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE); - msg->gns_header.header.size = htons (msg_size); - msg->gns_header.r_id = htonl (rid); - msg->expire = block->expiration_time; - msg->signature = block->signature; - msg->derived_key = block->derived_key; - memcpy (&msg[1], &block[1], blen); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sending `%s' message with size %u\n", - "NAMESTORE_BLOCK_CACHE", - (unsigned int) msg_size); - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); - return qe; + 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); } @@ -1018,56 +1012,63 @@ GNUNET_NAMESTORE_block_cache (struct GNUNET_NAMESTORE_Handle *h, * @param h handle to the namestore * @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 'rd' array + * @param rd_count number of records in the @a rd array * @param rd array of records with data to store * @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_records_store (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_EccPrivateKey *pkey, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, const char *label, unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, + const struct GNUNET_GNSRECORD_Data *rd, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; - struct PendingMessage *pe; + struct GNUNET_MQ_Envelope *env; char *name_tmp; char *rd_ser; - size_t rd_ser_len; - size_t msg_size; + ssize_t rd_ser_len; size_t name_len; uint32_t rid; struct RecordStoreMessage *msg; + ssize_t sret; - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != pkey); - GNUNET_assert (NULL != label); name_len = strlen (label) + 1; if (name_len > MAX_NAME_LEN) { GNUNET_break (0); return NULL; } + rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, + rd); + if (rd_ser_len < 0) + { + GNUNET_break (0); + return NULL; + } + if (rd_ser_len > UINT16_MAX) + { + GNUNET_break (0); + return NULL; + } rid = get_op_id (h); qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry); - qe->nsh = h; + 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); + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + qe); /* setup msg */ - rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); - msg_size = sizeof (struct RecordStoreMessage) + name_len + rd_ser_len; - pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - msg = (struct RecordStoreMessage *) &pe[1]; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE); - msg->gns_header.header.size = htons (msg_size); + 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 (rd_count); @@ -1076,64 +1077,138 @@ GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h, msg->private_key = *pkey; name_tmp = (char *) &msg[1]; - memcpy (name_tmp, label, name_len); + GNUNET_memcpy (name_tmp, + label, + name_len); rd_ser = &name_tmp[name_len]; - GNUNET_break (rd_ser_len == GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser)); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sending `%s' message for name `%s' with size %u\n", - "NAMESTORE_RECORD_STORE", label, msg_size); - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); + 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; } /** - * Get a result for a particular key from the namestore. The processor - * will only be called once. + * Set the desired nick name for a zone + * + * @param h handle to the namestore + * @param pkey private key of the zone + * @param nick the nick name to set + * @param cont continuation to call when done + * @param cont_cls closure for @a cont + * @return handle to abort the request + */ +struct GNUNET_NAMESTORE_QueueEntry * +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_GNSRECORD_Data rd; + + 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); +} + + +/** + * Lookup an item in the namestore. * * @param h handle to the namestore - * @param derived_hash hash of zone key combined with name to lookup - * @param proc function to call on the matching block, or with - * NULL if there is no matching block - * @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_block (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_HashCode *derived_hash, - GNUNET_NAMESTORE_BlockProcessor 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; - struct LookupBlockMessage *msg; - size_t msg_size; - uint32_t rid; + struct GNUNET_MQ_Envelope *env; + struct LabelLookupMessage *msg; + size_t label_len; + + if (1 == (label_len = strlen (label) + 1)) + { + GNUNET_break (0); + return NULL; + } - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != derived_hash); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Looking for block under %s\n", - GNUNET_h2s (derived_hash)); - rid = get_op_id(h); qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry); - qe->nsh = h; - qe->block_proc = proc; - qe->block_proc_cls = proc_cls; - qe->op_id = rid; - GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe); - - msg_size = sizeof (struct LookupBlockMessage); - pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - msg = (struct LookupBlockMessage *) &pe[1]; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK); - msg->gns_header.header.size = htons (msg_size); - msg->gns_header.r_id = htonl (rid); - msg->query = *derived_hash; - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); + 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; } @@ -1145,48 +1220,50 @@ GNUNET_NAMESTORE_lookup_block (struct GNUNET_NAMESTORE_Handle *h, * @param h handle to the namestore * @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_EccPrivateKey *zone, - const struct GNUNET_CRYPTO_EccPublicSignKey *value_zone, - GNUNET_NAMESTORE_RecordMonitor 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; - struct ZoneToNameMessage * msg; - size_t msg_size; + struct GNUNET_MQ_Envelope *env; + struct ZoneToNameMessage *msg; uint32_t rid; - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != zone); - GNUNET_assert (NULL != value_zone); rid = get_op_id(h); qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry); - qe->nsh = h; + 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); - - msg_size = sizeof (struct ZoneToNameMessage); - pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - 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; - - /* 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; } @@ -1201,46 +1278,57 @@ GNUNET_NAMESTORE_zone_to_name (struct GNUNET_NAMESTORE_Handle *h, * * @param h handle to the namestore * @param zone zone to access, NULL for all zones + * @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 @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_EccPrivateKey *zone, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, GNUNET_NAMESTORE_RecordMonitor proc, - void *proc_cls) + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls) { struct GNUNET_NAMESTORE_ZoneIterator *it; - struct PendingMessage *pe; - struct ZoneIterationStartMessage * msg; - size_t msg_size; + struct GNUNET_MQ_Envelope *env; + struct ZoneIterationStartMessage *msg; uint32_t rid; - GNUNET_assert (NULL != h); - rid = get_op_id(h); + 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; - GNUNET_CONTAINER_DLL_insert_tail (h->z_head, h->z_tail, it); - - msg_size = sizeof (struct ZoneIterationStartMessage); - pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - 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) msg->zone = *zone; - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); + if (NULL == h->mq) + it->env = env; + else + GNUNET_MQ_send (h->mq, + env); return it; } @@ -1250,27 +1338,26 @@ GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h, * 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 ZoneIterationNextMessage * msg; - struct PendingMessage *pe; - size_t msg_size; - - GNUNET_assert (NULL != it); - h = it->h; - msg_size = sizeof (struct ZoneIterationNextMessage); - pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - 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); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "ZONE_ITERATION_NEXT"); - 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); } @@ -1282,29 +1369,21 @@ GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it) void GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it) { - struct GNUNET_NAMESTORE_Handle *h; - struct PendingMessage *pe; - size_t msg_size; - struct ZoneIterationStopMessage * msg; + struct GNUNET_NAMESTORE_Handle *h = it->h; + struct GNUNET_MQ_Envelope *env; + struct ZoneIterationStopMessage *msg; - GNUNET_assert (NULL != it); - h = it->h; - GNUNET_CONTAINER_DLL_remove (h->z_head, - h->z_tail, - it); - msg_size = sizeof (struct ZoneIterationStopMessage); - pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - 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); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending `%s' message\n", - "ZONE_ITERATION_STOP"); - GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); - do_transmit(h); - GNUNET_free (it); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending ZONE_ITERATION_STOP message\n"); + if (NULL != h->mq) + { + 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); + } + free_ze (it); } @@ -1317,11 +1396,7 @@ 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 (NULL != qe); - GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); - GNUNET_free(qe); + free_qe (qe); }