X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fnamestore%2Fnamestore_api.c;h=55745d83d8c816ad415faba37f3c22c94cc3067f;hb=7da98cf076e9c5101244dfbbf8c3ddff045d298e;hp=3447dda446c0990107c227f12d69359b5103b5c4;hpb=de17ce8c248ed8d2334736e7c0013d55475625f1;p=oweals%2Fgnunet.git diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c index 3447dda44..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, 2011, 2012 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, "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 @@ -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,20 +72,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 */ @@ -112,62 +137,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; + }; @@ -183,49 +197,39 @@ struct GNUNET_NAMESTORE_Handle const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Socket (if available). + * Connection to the service (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 - */ - 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? @@ -250,596 +254,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 - * @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_name_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct LookupNameResponseMessage * msg, - size_t size) +static struct GNUNET_NAMESTORE_QueueEntry * +find_qe (struct GNUNET_NAMESTORE_Handle *h, + uint32_t rid) { - const char *name; - const char * rd_tmp; - const struct GNUNET_CRYPTO_RsaSignature *signature; - struct GNUNET_TIME_Absolute expire; - const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key_tmp; - size_t exp_msg_len; - size_t msg_len; - size_t name_len; - size_t rd_len; - int contains_sig; - int rd_count; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Received `%s'\n", "LOOKUP_NAME_RESPONSE"); - 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_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; - } - rd_tmp = &name[name_len]; - { - struct GNUNET_NAMESTORE_RecordData rd[rd_count]; + struct GNUNET_NAMESTORE_QueueEntry *qe; - if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize(rd_len, rd_tmp, rd_count, rd)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - 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); - } - return GNUNET_OK; + for (qe = h->op_head; qe != NULL; qe = qe->next) + if (qe->op_id == rid) + return qe; + return NULL; } /** - * Handle an incoming message of type 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE' + * Find the zone iteration 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_record_put_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct RecordPutResponseMessage* msg, - size_t size) +static struct GNUNET_NAMESTORE_ZoneIterator * +find_zi (struct GNUNET_NAMESTORE_Handle *h, + uint32_t rid) { - int res; + struct GNUNET_NAMESTORE_ZoneIterator *ze; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Received `%s'\n", - "RECORD_PUT_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 add record")); - return GNUNET_OK; + 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_CREATE_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 int -handle_record_create_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct RecordCreateResponseMessage* msg, - size_t size) +static void +free_qe (struct GNUNET_NAMESTORE_QueueEntry *qe) { - int res; - const char *emsg; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Received `%s'\n", - "RECORD_CREATE_RESPONSE"); - /* TODO: add actual error message from namestore to response... */ - res = ntohl (msg->op_result); - if (GNUNET_SYSERR == res) - emsg = _("Namestore failed to add record\n"); - else - emsg = NULL; - if (NULL != qe->cont) - qe->cont (qe->cont_cls, res, emsg); - return GNUNET_OK; + 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_REMOVE_RESPONSE' + * Free @a ze. * - * @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 ze entry to free */ -static int -handle_record_remove_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct RecordRemoveResponseMessage* msg, - size_t size) +static void +free_ze (struct GNUNET_NAMESTORE_ZoneIterator *ze) { - int res; - int ret; - const char *emsg; + struct GNUNET_NAMESTORE_Handle *h = ze->h; - /* Operation done, remove */ - LOG (GNUNET_ERROR_TYPE_DEBUG, "Received `%s'\n", - "RECORD_REMOVE_RESPONSE"); - /* - * results: - * 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 - */ - res = ntohl (msg->op_result); - switch (res) - { - case 0: - ret = GNUNET_OK; - emsg = NULL; - break; - case 1: - ret = GNUNET_NO; - emsg = NULL; - break; - case 2: - ret = GNUNET_NO; - emsg = NULL; - break; - case 3: - ret = GNUNET_SYSERR; - emsg = _("Failed to create new signature"); - break; - case 4: - ret = GNUNET_SYSERR; - emsg = _("Failed to put new set of records in database"); - break; - default: - GNUNET_break (0); - ret = GNUNET_SYSERR; - emsg = _("Protocol error"); - if (NULL != qe->cont) - qe->cont (qe->cont_cls, GNUNET_SYSERR, _("Protocol error")); - return GNUNET_NO; - } - if (NULL != qe->cont) - qe->cont (qe->cont_cls, ret, emsg); - return GNUNET_OK; + GNUNET_CONTAINER_DLL_remove (h->z_head, + h->z_tail, + ze); + if (NULL != ze->env) + GNUNET_MQ_discard (ze->env); + GNUNET_free (ze); } /** - * Handle an incoming message of type 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE' + * Check that @a rd_buf of lenght @a rd_len contains + * @a rd_count records. * - * @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_NO if we notified the client about - * the error, GNUNET_SYSERR on error and we did NOT notify the client + * @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_zone_to_name_response (struct GNUNET_NAMESTORE_QueueEntry *qe, - const struct ZoneToNameResponseMessage* msg, - size_t size) +check_rd (size_t rd_len, + const void *rd_buf, + unsigned int rd_count) { - int res; - struct GNUNET_TIME_Absolute expire; - size_t name_len; - size_t rd_ser_len; - unsigned int rd_count; - const char * name_tmp; - const char * rd_tmp; + struct GNUNET_GNSRECORD_Data rd[rd_count]; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s'\n", - "ZONE_TO_NAME_RESPONSE"); - res = ntohs (msg->res); - switch (res) + if (GNUNET_OK != + GNUNET_GNSRECORD_records_deserialize (rd_len, + rd_buf, + rd_count, + rd)) { - 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); - expire = GNUNET_TIME_absolute_ntoh(msg->expire); - 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_key, expire, name_tmp, rd_count, rd, &msg->signature); - /* return is important here: break would call continuation with error! */ - return GNUNET_OK; - } - default: GNUNET_break (0); return GNUNET_SYSERR; } - /* error case, call continuation with error */ - if (NULL != qe->proc) - qe->proc (qe->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL, 0, NULL, NULL); return GNUNET_OK; } /** - * Handle incoming messages for record operations + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE * - * @param qe 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_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) +static void +handle_record_store_response (void *cls, + const struct RecordStoreResponseMessage *msg) { - /* handle different message type */ - switch (type) - { - case GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE: - if (size < sizeof (struct LookupNameResponseMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_lookup_name_response (qe, (const struct LookupNameResponseMessage *) msg, size); - case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE: - if (size != sizeof (struct RecordPutResponseMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_record_put_response (qe, (const struct RecordPutResponseMessage *) msg, size); - case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE: - if (size != sizeof (struct RecordCreateResponseMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_record_create_response (qe, (const struct RecordCreateResponseMessage *) msg, size); - case GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE: - if (size != sizeof (struct RecordRemoveResponseMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_record_remove_response (qe, (const struct RecordRemoveResponseMessage *) 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); - default: - GNUNET_break (0); - return GNUNET_SYSERR; - } + 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 a response from NAMESTORE service for a zone iteration request + * Check validity of an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE * - * @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, 'ze' should be kept, GNUNET_NO on success if 'ze' should - * not be kept any longer, GNUNET_SYSERR on error (disconnect) and '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 ZoneIterationResponseMessage *msg, - size_t size) +check_lookup_result (void *cls, + const struct LabelLookupResponseMessage *msg) { - struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubdummy; - size_t msg_len; + const char *name; size_t exp_msg_len; + size_t msg_len; size_t name_len; size_t rd_len; - unsigned rd_count; - const char *name_tmp; - const char *rd_ser_tmp; - struct GNUNET_TIME_Absolute expire; - 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); - expire = GNUNET_TIME_absolute_ntoh (msg->expire); - exp_msg_len = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_len; + exp_msg_len = sizeof (*msg) + name_len + rd_len; if (msg_len != exp_msg_len) { GNUNET_break (0); return GNUNET_SYSERR; } - GNUNET_break (0 == ntohs (msg->reserved)); - memset (&pubdummy, '\0', sizeof (pubdummy)); - if ((0 == name_len) && (0 == (memcmp (&msg->public_key, &pubdummy, sizeof (pubdummy))))) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration is completed!\n"); - if (NULL != ze->proc) - ze->proc(ze->proc_cls, NULL, GNUNET_TIME_UNIT_ZERO_ABS, NULL , 0, NULL, NULL); - return GNUNET_NO; - } - name_tmp = (const char *) &msg[1]; - if ((name_tmp[name_len -1] != '\0') || (name_len > MAX_NAME_LEN)) + name = (const char *) &msg[1]; + if ( (name_len > 0) && + ('\0' != name[name_len -1]) ) { GNUNET_break (0); return GNUNET_SYSERR; } - rd_ser_tmp = (const char *) &name_tmp[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_ser_tmp, rd_count, rd)) + if (0 != ntohs (msg->rd_count)) { GNUNET_break (0); return GNUNET_SYSERR; } - if (NULL != ze->proc) - ze->proc(ze->proc_cls, &msg->public_key, expire, name_tmp, rd_count, rd, &msg->signature); - return GNUNET_YES; + 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_RECORD_LOOKUP_RESPONSE + * + * @param cls + * @param msg the message we received + */ +static void +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; + + 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)) + { + /* label was not in namestore */ + if (NULL != qe->proc) + qe->proc (qe->proc_cls, + &msg->private_key, + name, + 0, + NULL); + free_qe (qe); + return; } + + rd_tmp = &name[name_len]; + { + 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 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_YES on success, 'ze' should be kept, GNUNET_NO on success if 'ze' should - * not be kept any longer, GNUNET_SYSERR on error (disconnect) and 'ze' should be kept + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ static int -manage_zone_operations (struct GNUNET_NAMESTORE_ZoneIterator *ze, - const struct GNUNET_MessageHeader *msg, - int type, size_t size) +check_record_result (void *cls, + const struct RecordResultMessage *msg) { - /* handle different message type */ - switch (type) + const char *name; + size_t msg_len; + size_t name_len; + size_t rd_len; + + (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) { - case GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE: - if (size < sizeof (struct ZoneIterationResponseMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return handle_zone_iteration_response (ze, (const struct ZoneIterationResponseMessage *) msg, size); - default: 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; - 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)) + 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); - 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) - { - 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)) + 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; /* 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); } @@ -851,24 +797,49 @@ do_transmit (struct GNUNET_NAMESTORE_Handle *h) static void reconnect (struct GNUNET_NAMESTORE_Handle *h) { - struct PendingMessage *p; - struct StartMessage *init; + 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->client); - h->client = GNUNET_CLIENT_connect ("namestore", h->cfg); - GNUNET_assert (NULL != h->client); - 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); } @@ -876,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); } @@ -896,10 +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->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); } @@ -929,10 +921,14 @@ 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; } @@ -946,446 +942,273 @@ 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, - * 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. - * - * @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 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 - * @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) -{ - struct GNUNET_NAMESTORE_QueueEntry *qe; - struct PendingMessage *pe; - struct RecordPutMessage * msg; - char * rd_ser; - char * name_tmp; - size_t msg_size; - size_t name_len; - size_t rd_ser_len; - uint32_t rid; - - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != zone_key); - GNUNET_assert (NULL != name); - GNUNET_assert (NULL != rd); - GNUNET_assert (NULL != signature); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Storing %u records under name `%s'\n", - rd_count, - name); - name_len = strlen(name) + 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); - - /* setup msg */ - rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); - msg_size = sizeof (struct RecordPutMessage) + name_len + rd_ser_len; - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct RecordPutMessage *) &pe[1]; - 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; - name_tmp = (char *) &msg[1]; - memcpy (name_tmp, name, name_len); - rd_ser = &name_tmp[name_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_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. + * Task launched to warn the user that the namestore is + * excessively slow and that a query was thus dropped. * - * @param public_key public key of the zone - * @param freshness 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 + * @param cls a `struct GNUNET_NAMESTORE_QueueEntry *` */ -int -GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, - const struct GNUNET_TIME_Absolute freshness, - const char *name, - unsigned int rd_count, - const struct GNUNET_NAMESTORE_RecordData *rd, - const struct GNUNET_CRYPTO_RsaSignature *signature) +static void +warn_delay (void *cls) { - size_t rd_ser_len; - size_t name_len; - char * name_tmp; - char * rd_ser; - struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose; - struct GNUNET_TIME_AbsoluteNBO *expire_tmp; - struct GNUNET_TIME_AbsoluteNBO expire_nbo = GNUNET_TIME_absolute_hton (freshness); - uint32_t sig_len; - - GNUNET_assert (NULL != public_key); - GNUNET_assert (NULL != name); - GNUNET_assert (NULL != rd); - GNUNET_assert (NULL != signature); - name_len = strlen (name) + 1; - if (name_len > MAX_NAME_LEN) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); - sig_len = sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len; + 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) { - char sig_buf[sig_len] GNUNET_ALIGN; - - sig_purpose = (struct GNUNET_CRYPTO_RsaSignaturePurpose *) sig_buf; - sig_purpose->size = htonl (sig_len); - sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); - expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; - memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); - name_tmp = (char *) &expire_tmp[1]; - memcpy (name_tmp, name, name_len); - rd_ser = &name_tmp[name_len]; - GNUNET_assert (rd_ser_len == - GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser)); - return GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, sig_purpose, signature, public_key); + 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 by the authority of a zone. + * 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 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 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 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_create (struct GNUNET_NAMESTORE_Handle *h, - const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, - const char *name, - const struct GNUNET_NAMESTORE_RecordData *rd, +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; - char * name_tmp; - char * pkey_tmp; - char * rd_ser; - size_t rd_ser_len; - size_t msg_size; + struct GNUNET_MQ_Envelope *env; + char *name_tmp; + char *rd_ser; + ssize_t rd_ser_len; size_t name_len; - size_t key_len; uint32_t rid; - struct RecordCreateMessage * msg; - struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * pkey_enc; + struct RecordStoreMessage *msg; + ssize_t sret; - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != pkey); - GNUNET_assert (NULL != name); - GNUNET_assert (NULL != rd); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Creating record of type %u under name `%s'\n", - rd->record_type, - name); - name_len = strlen(name) + 1; + 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; + 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->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); - - pkey_enc = GNUNET_CRYPTO_rsa_encode_key (pkey); - GNUNET_assert (NULL != pkey_enc); + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + qe); /* setup msg */ - key_len = ntohs (pkey_enc->len); - rd_ser_len = GNUNET_NAMESTORE_records_get_size(1, rd); - msg_size = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len; - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct RecordCreateMessage *) &pe[1]; - msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE); - 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 (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); - pkey_tmp = (char *) &msg[1]; - memcpy (pkey_tmp, pkey_enc, key_len); - name_tmp = &pkey_tmp[key_len]; - memcpy (name_tmp, name, name_len); - rd_ser = &name_tmp[name_len]; - GNUNET_NAMESTORE_records_serialize(1, rd, rd_ser_len, rd_ser); - - GNUNET_free (pkey_enc); + msg->reserved = htons (0); + msg->private_key = *pkey; - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sending `%s' message for name `%s' with size %u\n", - "NAMESTORE_RECORD_CREATE", name, msg_size); - 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 GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * pkey_enc; - struct PendingMessage *pe; - struct RecordRemoveMessage * msg; - char *pkey_tmp; - char *rd_ser; - char *name_tmp; - size_t rd_ser_len; - size_t msg_size; - size_t name_len; - size_t key_len; - uint32_t rid; - uint16_t rd_count; - - GNUNET_assert (NULL != h); - if (NULL != rd) - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Removing record of type %u under name `%s'\n", - rd->record_type, - name); - else - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Removing all records under name `%s'\n", - name); - 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); - - pkey_enc = GNUNET_CRYPTO_rsa_encode_key (pkey); - GNUNET_assert (NULL != pkey_enc); - key_len = ntohs (pkey_enc->len); - - rd_count = (NULL == rd) ? 0 : 1; - rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); - name_len = strlen (name) + 1; - msg_size = sizeof (struct RecordRemoveMessage) + key_len + name_len + rd_ser_len; - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - pe->size = msg_size; - pe->is_init = GNUNET_NO; - msg = (struct RecordRemoveMessage *) &pe[1]; - 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); - pkey_tmp = (char *) &msg[1]; - memcpy (pkey_tmp, pkey_enc, key_len); - name_tmp = &pkey_tmp[key_len]; - memcpy (name_tmp, name, name_len); - rd_ser = &name_tmp[name_len]; - GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser); - - GNUNET_free (pkey_enc); + struct GNUNET_GNSRECORD_Data rd; - 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; - struct LookupNameMessage * msg; - size_t msg_size; - size_t name_len; - uint32_t rid; + struct GNUNET_MQ_Envelope *env; + struct LabelLookupMessage *msg; + size_t label_len; - GNUNET_assert (NULL != h); - GNUNET_assert (NULL != zone); - GNUNET_assert (NULL != name); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Looking for record of type %u under name `%s'\n", - record_type, - name); - name_len = strlen (name) + 1; - if ((name_len == 0) || (name_len > MAX_NAME_LEN)) + 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); - - msg_size = sizeof (struct LookupNameMessage) + name_len; - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - 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); - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sending `%s' message for name `%s'\n", "NAMESTORE_LOOKUP_NAME", name); - 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; } @@ -1395,162 +1218,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; - 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_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); - - msg_size = sizeof (struct ZoneToNameMessage); - pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); - 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; - - /* 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; - 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); - it = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIterator)); + 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); - - msg_size = sizeof (struct ZoneIterationStartMessage); - pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); - 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) - { - 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 - { - 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); - 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 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; - 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); - 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); } @@ -1562,33 +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; - 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"); - 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); } @@ -1601,11 +1396,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 (NULL != qe); - GNUNET_CONTAINER_DLL_remove(h->op_head, h->op_tail, qe); - GNUNET_free(qe); + free_qe (qe); } + /* end of namestore_api.c */