This file is part of GNUnet.
Copyright (C) 2012, 2013, 2014, 2018 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.
+ Affero 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @author Christian Grothoff
*
* TODO:
+ * - "get_nick_record" is a bottleneck, introduce a cache to
+ * avoid looking it up again and again (for the same few
+ * zones that the user will typically manage!)
* - run testcases, make sure everything works!
*/
#include "platform.h"
#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+/**
+ * If a monitor takes more than 1 minute to process an event, print a warning.
+ */
+#define MONITOR_STALL_WARN_DELAY GNUNET_TIME_UNIT_MINUTES
+
+/**
+ * Size of the cache used by #get_nick_record()
+ */
+#define NC_SIZE 16
/**
* A namestore client
*/
uint32_t offset;
+ /**
+ * Number of pending cache operations triggered by this zone iteration which we
+ * need to wait for before allowing the client to continue.
+ */
+ unsigned int cache_ops;
+
+ /**
+ * Set to #GNUNET_YES if the last iteration exhausted the limit set by the
+ * client and we should send the #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END
+ * message and free the data structure once @e cache_ops is zero.
+ */
+ int send_end;
+
};
*/
struct GNUNET_SCHEDULER_Task *task;
+ /**
+ * Task to warn about slow monitors.
+ */
+ struct GNUNET_SCHEDULER_Task *sa_wait_warning;
+
+ /**
+ * Since when are we blocked on this monitor?
+ */
+ struct GNUNET_TIME_Absolute sa_waiting_start;
+
/**
* Last sequence number in the zone iteration used to address next
* result of the zone iteration in the store
struct GNUNET_NAMECACHE_QueueEntry *qe;
/**
- * Client to notify about the result.
+ * Client to notify about the result, can be NULL.
*/
struct NamestoreClient *nc;
+ /**
+ * Zone iteration to call #zone_iteration_done_client_continue()
+ * for if applicable, can be NULL.
+ */
+ struct ZoneIteration *zi;
+
/**
* Client's request ID.
*/
*/
const struct RecordStoreMessage *rsm;
- /**
- * Array of record data to store (without NICK unless this is about
- * #GNUNET_GNS_EMPTY_LABEL_AT). Length is in @e rd_count.
- */
- struct GNUNET_GNSRECORD_Data *rd;
-
/**
* Next zone monitor that still needs to be notified about this PUT.
*/
*/
char *conv_name;
+};
+
+
+/**
+ * Entry in list of cached nick resolutions.
+ */
+struct NickCache
+{
+ /**
+ * Zone the cache entry is for.
+ */
+ struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
+
/**
- * How many records do we try to store?
+ * Cached record data.
*/
- unsigned int rd_count;
+ struct GNUNET_GNSRECORD_Data *rd;
+ /**
+ * Timestamp when this cache entry was used last.
+ */
+ struct GNUNET_TIME_Absolute last_used;
};
+/**
+ * We cache nick records to reduce DB load.
+ */
+static struct NickCache nick_cache[NC_SIZE];
+
/**
* Public key of all zeros.
*/
GNUNET_CONTAINER_DLL_remove (sa_head,
sa_tail,
sa);
- GNUNET_array_grow (sa->rd,
- sa->rd_count,
- 0);
GNUNET_free (sa->conv_name);
GNUNET_free (sa);
}
* record, which (if found) is then copied to @a cls for future use.
*
* @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found)
- * @param seq sequence number of the record
+ * @param seq sequence number of the record, MUST NOT BE ZERO
* @param private_key the private key of the zone (unused)
* @param label should be #GNUNET_GNS_EMPTY_LABEL_AT
* @param rd_count number of records in @a rd
struct GNUNET_GNSRECORD_Data **res = cls;
(void) private_key;
- (void) seq;
+ GNUNET_assert (0 != seq);
if (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT))
{
GNUNET_break (0);
}
+/**
+ * Add entry to the cache for @a zone and @a nick
+ *
+ * @param zone zone key to cache under
+ * @param nick nick entry to cache
+ */
+static void
+cache_nick (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const struct GNUNET_GNSRECORD_Data *nick)
+{
+ struct NickCache *oldest;
+
+ oldest = NULL;
+ for (unsigned int i=0;i<NC_SIZE;i++)
+ {
+ struct NickCache *pos = &nick_cache[i];
+
+ if ( (NULL == oldest) ||
+ (oldest->last_used.abs_value_us >
+ pos->last_used.abs_value_us) )
+ oldest = pos;
+ if (0 == memcmp (zone,
+ &pos->zone,
+ sizeof (*zone)))
+ {
+ oldest = pos;
+ break;
+ }
+ }
+ GNUNET_free_non_null (oldest->rd);
+ oldest->zone = *zone;
+ oldest->rd = GNUNET_malloc (sizeof (*nick) +
+ nick->data_size);
+ *oldest->rd = *nick;
+ oldest->rd->data = &oldest->rd[1];
+ memcpy (&oldest->rd[1],
+ nick->data,
+ nick->data_size);
+ oldest->last_used = GNUNET_TIME_absolute_get ();
+}
+
+
/**
* Return the NICK record for the zone (if it exists).
*
struct GNUNET_GNSRECORD_Data *nick;
int res;
+ /* check cache first */
+ for (unsigned int i=0;i<NC_SIZE;i++)
+ {
+ struct NickCache *pos = &nick_cache[i];
+ if ( (NULL != pos->rd) &&
+ (0 == memcmp (zone,
+ &pos->zone,
+ sizeof (*zone))) )
+ {
+ nick = GNUNET_malloc (sizeof (*nick) +
+ pos->rd->data_size);
+ *nick = *pos->rd;
+ nick->data = &nick[1];
+ memcpy (&nick[1],
+ pos->rd->data,
+ pos->rd->data_size);
+ pos->last_used = GNUNET_TIME_absolute_get ();
+ return nick;
+ }
+ }
+
nick = NULL;
res = GSN_database->lookup_records (GSN_database->cls,
zone,
GNUNET_GNSRECORD_z2s (&pub));
return NULL;
}
+
+ /* update cache */
+ cache_nick (zone,
+ nick);
return nick;
}
uint64_t latest_expiration;
size_t req;
char *data;
- int record_offset;
size_t data_offset;
+ struct GNUNET_GNSRECORD_Data *target;
(*rdc_res) = 1 + rd2_length;
if (0 == 1 + rd2_length)
{
+ GNUNET_break (0);
(*rd_res) = NULL;
return;
}
- req = 0;
- for (unsigned int c=0; c< 1; c++)
- req += sizeof (struct GNUNET_GNSRECORD_Data) + nick_rd[c].data_size;
- for (unsigned int c=0; c< rd2_length; c++)
- req += sizeof (struct GNUNET_GNSRECORD_Data) + rd2[c].data_size;
- (*rd_res) = GNUNET_malloc (req);
- data = (char *) &(*rd_res)[1 + rd2_length];
+ req = sizeof (struct GNUNET_GNSRECORD_Data) + nick_rd->data_size;
+ for (unsigned int i=0; i<rd2_length; i++)
+ {
+ const struct GNUNET_GNSRECORD_Data *orig = &rd2[i];
+
+ if (req + sizeof (struct GNUNET_GNSRECORD_Data) + orig->data_size < req)
+ {
+ GNUNET_break (0);
+ (*rd_res) = NULL;
+ return;
+ }
+ req += sizeof (struct GNUNET_GNSRECORD_Data) + orig->data_size;
+ }
+ target = GNUNET_malloc (req);
+ (*rd_res) = target;
+ data = (char *) &target[1 + rd2_length];
data_offset = 0;
latest_expiration = 0;
- for (unsigned int c=0; c< rd2_length; c++)
+ for (unsigned int i=0;i<rd2_length;i++)
{
- if (0 != (rd2[c].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
+ const struct GNUNET_GNSRECORD_Data *orig = &rd2[i];
+
+ if (0 != (orig->flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
{
- if ((GNUNET_TIME_absolute_get().abs_value_us + rd2[c].expiration_time) >
- latest_expiration)
- latest_expiration = rd2[c].expiration_time;
+ if ((GNUNET_TIME_absolute_get().abs_value_us + orig->expiration_time) >
+ latest_expiration)
+ latest_expiration = orig->expiration_time;
}
- else if (rd2[c].expiration_time > latest_expiration)
- latest_expiration = rd2[c].expiration_time;
- (*rd_res)[c] = rd2[c];
- (*rd_res)[c].data = (void *) &data[data_offset];
- GNUNET_memcpy ((void *) (*rd_res)[c].data,
- rd2[c].data,
- rd2[c].data_size);
- data_offset += (*rd_res)[c].data_size;
+ else if (orig->expiration_time > latest_expiration)
+ latest_expiration = orig->expiration_time;
+ target[i] = *orig;
+ target[i].data = (void *) &data[data_offset];
+ GNUNET_memcpy (&data[data_offset],
+ orig->data,
+ orig->data_size);
+ data_offset += orig->data_size;
}
/* append nick */
- record_offset = rd2_length;
- (*rd_res)[record_offset] = *nick_rd;
- (*rd_res)[record_offset].expiration_time = latest_expiration;
- (*rd_res)[record_offset].data = (void *) &data[data_offset];
- GNUNET_memcpy ((void *) (*rd_res)[record_offset].data,
+ target[rd2_length] = *nick_rd;
+ target[rd2_length].expiration_time = latest_expiration;
+ target[rd2_length].data = (void *) &data[data_offset];
+ GNUNET_memcpy (&data[data_offset],
nick_rd->data,
nick_rd->data_size);
- data_offset += (*rd_res)[record_offset].data_size;
- GNUNET_assert (req == (sizeof (struct GNUNET_GNSRECORD_Data)) * (*rdc_res) + data_offset);
+ data_offset += nick_rd->data_size;
+ GNUNET_assert (req ==
+ (sizeof (struct GNUNET_GNSRECORD_Data)) * (*rdc_res) + data_offset);
}
struct GNUNET_GNSRECORD_Data *res;
unsigned int res_count;
size_t name_len;
- size_t rd_ser_len;
+ ssize_t rd_ser_len;
char *name_tmp;
char *rd_ser;
nick = get_nick_record (zone_key);
+ GNUNET_assert (-1 !=
+ GNUNET_GNSRECORD_records_get_size (rd_count,
+ rd));
+
if ( (NULL != nick) &&
(0 != strcmp (name,
GNUNET_GNS_EMPTY_LABEL_AT)))
res = (struct GNUNET_GNSRECORD_Data *) rd;
}
+ GNUNET_assert (-1 !=
+ GNUNET_GNSRECORD_records_get_size (res_count,
+ res));
+
+
name_len = strlen (name) + 1;
- rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count, res);
+ rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count,
+ res);
+ if (rd_ser_len < 0)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (nc->client);
+ return;
+ }
+ if (((size_t) rd_ser_len) >= UINT16_MAX - name_len - sizeof (*zir_msg))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (nc->client);
+ return;
+ }
env = GNUNET_MQ_msg_extra (zir_msg,
name_len + rd_ser_len,
GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
zir_msg->gns_header.r_id = htonl (request_id);
zir_msg->name_len = htons (name_len);
zir_msg->rd_count = htons (res_count);
- zir_msg->rd_len = htons (rd_ser_len);
+ zir_msg->rd_len = htons ((uint16_t) rd_ser_len);
zir_msg->private_key = *zone_key;
name_tmp = (char *) &zir_msg[1];
GNUNET_memcpy (name_tmp,
name,
name_len);
rd_ser = &name_tmp[name_len];
- GNUNET_GNSRECORD_records_serialize (res_count,
- res,
- rd_ser_len,
- rd_ser);
+ GNUNET_assert (rd_ser_len ==
+ GNUNET_GNSRECORD_records_serialize (res_count,
+ res,
+ rd_ser_len,
+ rd_ser));
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending RECORD_RESULT message with %u records\n",
res_count);
struct GNUNET_MQ_Envelope *env;
struct RecordStoreResponseMessage *rcr_msg;
+ GNUNET_assert (NULL != nc);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending RECORD_STORE_RESPONSE message\n");
GNUNET_STATISTICS_update (statistics,
}
+/**
+ * Function called once we are done with the zone iteration and
+ * allow the zone iteration client to send us more messages.
+ *
+ * @param zi zone iteration we are processing
+ */
+static void
+zone_iteration_done_client_continue (struct ZoneIteration *zi)
+{
+ struct GNUNET_MQ_Envelope *env;
+ struct GNUNET_NAMESTORE_Header *em;
+
+ GNUNET_SERVICE_client_continue (zi->nc->client);
+ if (! zi->send_end)
+ return;
+ /* send empty response to indicate end of list */
+ env = GNUNET_MQ_msg (em,
+ GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT_END);
+ em->r_id = htonl (zi->request_id);
+ GNUNET_MQ_send (zi->nc->mq,
+ env);
+
+ GNUNET_CONTAINER_DLL_remove (zi->nc->op_head,
+ zi->nc->op_tail,
+ zi);
+ GNUNET_free (zi);
+}
+
+
/**
* Cache operation complete, clean up.
*
const char *emsg)
{
struct CacheOperation *cop = cls;
+ struct ZoneIteration *zi;
if (NULL != emsg)
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
send_store_response (cop->nc,
success,
cop->rid);
+ if (NULL != (zi = cop->zi))
+ {
+ zi->cache_ops--;
+ if (0 == zi->cache_ops)
+ {
+ /* unchoke zone iteration, cache has caught up */
+ zone_iteration_done_client_continue (zi);
+ }
+ }
GNUNET_free (cop);
}
* refresh the corresponding (encrypted) block in the namecache.
*
* @param nc client responsible for the request, can be NULL
+ * @param zi zone iteration response for the request, can be NULL
* @param rid request ID of the client
* @param zone_key private key of the zone
* @param name label for the records
*/
static void
refresh_block (struct NamestoreClient *nc,
+ struct ZoneIteration *zi,
uint32_t rid,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
const char *name,
}
if (0 == res_count)
{
- send_store_response (nc,
- GNUNET_OK,
- rid);
+ if (NULL != nc)
+ send_store_response (nc,
+ GNUNET_OK,
+ rid);
return; /* no data, no need to update cache */
}
if (GNUNET_YES == disable_namecache)
"Namecache updates skipped (NC disabled)",
1,
GNUNET_NO);
- send_store_response (nc,
- GNUNET_OK,
- rid);
+ if (NULL != nc)
+ send_store_response (nc,
+ GNUNET_OK,
+ rid);
return;
}
exp_time = GNUNET_GNSRECORD_record_get_expiration_time (res_count,
GNUNET_NO);
cop = GNUNET_new (struct CacheOperation);
cop->nc = nc;
+ cop->zi = zi;
+ if (NULL != zi)
+ zi->cache_ops++;
cop->rid = rid;
GNUNET_CONTAINER_DLL_insert (cop_head,
cop_tail,
}
+/**
+ * Print a warning that one of our monitors is no longer reacting.
+ *
+ * @param cls a `struct ZoneMonitor` to warn about
+ */
+static void
+warn_monitor_slow (void *cls)
+{
+ struct ZoneMonitor *zm = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No response from monitor since %s\n",
+ GNUNET_STRINGS_absolute_time_to_string (zm->sa_waiting_start));
+ zm->sa_wait_warning = GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
+ &warn_monitor_slow,
+ zm);
+}
+
+
/**
* Continue processing the @a sa.
*
continue_store_activity (struct StoreActivity *sa)
{
const struct RecordStoreMessage *rp_msg = sa->rsm;
+ unsigned int rd_count;
+ size_t name_len;
+ size_t rd_ser_len;
+ uint32_t rid;
+ const char *name_tmp;
+ const char *rd_ser;
- for (struct ZoneMonitor *zm = sa->zm_pos;
- NULL != zm;
- zm = sa->zm_pos)
- {
- if ( (0 != memcmp (&rp_msg->private_key,
- &zm->zone,
- sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) &&
- (0 != memcmp (&zm->zone,
- &zero,
- sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) )
- sa->zm_pos = zm->next; /* not interesting to this monitor */
- if (zm->limit == zm->iteration_cnt)
- {
- zm->sa_waiting = GNUNET_YES;
- return; /* blocked on zone monitor */
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Notifying monitor about changes under label `%s'\n",
- sa->conv_name);
- zm->limit--;
- send_lookup_response (zm->nc,
- 0,
- &rp_msg->private_key,
- sa->conv_name,
- sa->rd_count,
- sa->rd);
- sa->zm_pos = zm->next;
- }
- /* great, done with the monitors, unpack (again) for refresh_block operation */
+ rid = ntohl (rp_msg->gns_header.r_id);
+ name_len = ntohs (rp_msg->name_len);
+ rd_count = ntohs (rp_msg->rd_count);
+ rd_ser_len = ntohs (rp_msg->rd_len);
+ name_tmp = (const char *) &rp_msg[1];
+ rd_ser = &name_tmp[name_len];
{
- size_t name_len;
- size_t rd_ser_len;
- uint32_t rid;
- const char *name_tmp;
- const char *rd_ser;
- unsigned int rd_count;
-
- rid = ntohl (rp_msg->gns_header.r_id);
- name_len = ntohs (rp_msg->name_len);
- rd_count = ntohs (rp_msg->rd_count);
- rd_ser_len = ntohs (rp_msg->rd_len);
- name_tmp = (const char *) &rp_msg[1];
- rd_ser = &name_tmp[name_len];
+ struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL(rd_count)];
+
+ /* We did this before, must succeed again */
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_GNSRECORD_records_deserialize (rd_ser_len,
+ rd_ser,
+ rd_count,
+ rd));
+
+ for (struct ZoneMonitor *zm = sa->zm_pos;
+ NULL != zm;
+ zm = sa->zm_pos)
{
- struct GNUNET_GNSRECORD_Data rd[rd_count];
-
- /* We did this before, must succeed again */
- GNUNET_assert (GNUNET_OK ==
- GNUNET_GNSRECORD_records_deserialize (rd_ser_len,
- rd_ser,
- rd_count,
- rd));
- refresh_block (sa->nc,
- rid,
- &rp_msg->private_key,
- sa->conv_name,
- rd_count,
- rd);
+ if ( (0 != memcmp (&rp_msg->private_key,
+ &zm->zone,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) &&
+ (0 != memcmp (&zm->zone,
+ &zero,
+ sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) )
+ {
+ sa->zm_pos = zm->next; /* not interesting to this monitor */
+ continue;
+ }
+ if (zm->limit == zm->iteration_cnt)
+ {
+ zm->sa_waiting = GNUNET_YES;
+ zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
+ if (NULL != zm->sa_wait_warning)
+ GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
+ zm->sa_wait_warning = GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
+ &warn_monitor_slow,
+ zm);
+ return; /* blocked on zone monitor */
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Notifying monitor about changes under label `%s'\n",
+ sa->conv_name);
+ zm->limit--;
+ send_lookup_response (zm->nc,
+ 0,
+ &rp_msg->private_key,
+ sa->conv_name,
+ rd_count,
+ rd);
+ sa->zm_pos = zm->next;
}
+ /* great, done with the monitors, unpack (again) for refresh_block operation */
+ refresh_block (sa->nc,
+ NULL,
+ rid,
+ &rp_msg->private_key,
+ sa->conv_name,
+ rd_count,
+ rd);
}
GNUNET_SERVICE_client_continue (sa->nc->client);
free_store_activity (sa);
GNUNET_SCHEDULER_cancel (zm->task);
zm->task = NULL;
}
+ if (NULL != zm->sa_wait_warning)
+ {
+ GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
+ zm->sa_wait_warning = NULL;
+ }
for (struct StoreActivity *sa = sa_head; NULL != sa; sa = san)
{
san = sa->next;
/**
* FIXME.
*/
- size_t rd_ser_len;
+ ssize_t rd_ser_len;
};
/**
- * FIXME.
- * @param seq sequence number of the record
+ * Function called by the namestore plugin when we are trying to lookup
+ * a record as part of #handle_record_lookup(). Merges all results into
+ * the context.
+ *
+ * @param cls closure with a `struct RecordLookupContext`
+ * @param seq unique serial number of the record, MUST NOT BE ZERO
+ * @param zone_key private key of the zone
+ * @param label name that is being mapped (at most 255 characters long)
+ * @param rd_count number of entries in @a rd array
+ * @param rd array of records with data to store
*/
static void
lookup_it (void *cls,
const struct GNUNET_GNSRECORD_Data *rd)
{
struct RecordLookupContext *rlc = cls;
- struct GNUNET_GNSRECORD_Data *rd_res;
- unsigned int rdc_res;
(void) private_key;
- (void) seq;
- if (0 == strcmp (label,
+ GNUNET_assert (0 != seq);
+ if (0 != strcmp (label,
rlc->label))
+ return;
+ rlc->found = GNUNET_YES;
+ if (0 == rd_count)
{
- rlc->found = GNUNET_YES;
- if (0 != rd_count)
+ rlc->rd_ser_len = 0;
+ rlc->res_rd_count = 0;
+ rlc->res_rd = NULL;
+ return;
+ }
+ if ( (NULL != rlc->nick) &&
+ (0 != strcmp (label,
+ GNUNET_GNS_EMPTY_LABEL_AT)) )
+ {
+ /* Merge */
+ struct GNUNET_GNSRECORD_Data *rd_res;
+ unsigned int rdc_res;
+
+ rd_res = NULL;
+ rdc_res = 0;
+ rlc->nick->flags = (rlc->nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
+ merge_with_nick_records (rlc->nick,
+ rd_count,
+ rd,
+ &rdc_res,
+ &rd_res);
+ rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rdc_res,
+ rd_res);
+ if (rlc->rd_ser_len < 0)
{
- if ( (NULL != rlc->nick) &&
- (0 != strcmp (label,
- GNUNET_GNS_EMPTY_LABEL_AT)) )
- {
- /* Merge */
- rd_res = NULL;
- rdc_res = 0;
- rlc->nick->flags = (rlc->nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
- merge_with_nick_records (rlc->nick,
- rd_count,
- rd,
- &rdc_res,
- &rd_res);
- rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rdc_res,
- rd_res);
- rlc->res_rd_count = rdc_res;
- rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
+ GNUNET_break (0);
+ GNUNET_free (rd_res);
+ rlc->found = GNUNET_NO;
+ rlc->rd_ser_len = 0;
+ return;
+ }
+ rlc->res_rd_count = rdc_res;
+ rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
+ if (rlc->rd_ser_len !=
GNUNET_GNSRECORD_records_serialize (rdc_res,
rd_res,
rlc->rd_ser_len,
- rlc->res_rd);
-
- GNUNET_free (rd_res);
- GNUNET_free (rlc->nick);
- rlc->nick = NULL;
- }
- else
- {
- rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count,
- rd);
- rlc->res_rd_count = rd_count;
- rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
+ rlc->res_rd))
+ {
+ GNUNET_break (0);
+ GNUNET_free (rlc->res_rd);
+ rlc->res_rd = NULL;
+ rlc->res_rd_count = 0;
+ rlc->rd_ser_len = 0;
+ GNUNET_free (rd_res);
+ rlc->found = GNUNET_NO;
+ return;
+ }
+ GNUNET_free (rd_res);
+ GNUNET_free (rlc->nick);
+ rlc->nick = NULL;
+ }
+ else
+ {
+ rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count,
+ rd);
+ if (rlc->rd_ser_len < 0)
+ {
+ GNUNET_break (0);
+ rlc->found = GNUNET_NO;
+ rlc->rd_ser_len = 0;
+ return;
+ }
+ rlc->res_rd_count = rd_count;
+ rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
+ if (rlc->rd_ser_len !=
GNUNET_GNSRECORD_records_serialize (rd_count,
rd,
rlc->rd_ser_len,
- rlc->res_rd);
- }
- }
- else
+ rlc->res_rd))
{
- rlc->rd_ser_len = 0;
- rlc->res_rd_count = 0;
+ GNUNET_break (0);
+ GNUNET_free (rlc->res_rd);
rlc->res_rd = NULL;
+ rlc->res_rd_count = 0;
+ rlc->rd_ser_len = 0;
+ rlc->found = GNUNET_NO;
+ return;
}
}
}
{
uint32_t name_len;
size_t src_size;
- const char *name_tmp;
(void) cls;
name_len = ntohl (ll_msg->label_len);
GNUNET_break (0);
return GNUNET_SYSERR;
}
-
- name_tmp = (const char *) &ll_msg[1];
- if ('\0' != name_tmp[name_len -1])
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
+ GNUNET_MQ_check_zero_termination (ll_msg);
return GNUNET_OK;
}
rd_ser = &name_tmp[name_len];
{
struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL(rd_count)];
- struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL(rd_count)];
- unsigned int rd_clean_off;
if (GNUNET_OK !=
GNUNET_GNSRECORD_records_deserialize (rd_ser_len,
{
/* remove "NICK" records, unless this is for the
#GNUNET_GNS_EMPTY_LABEL_AT label */
+ struct GNUNET_GNSRECORD_Data rd_clean[GNUNET_NZL(rd_count)];
+ unsigned int rd_clean_off;
+
rd_clean_off = 0;
for (unsigned int i=0;i<rd_count;i++)
{
conv_name)) ||
(GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type) )
rd_clean_off++;
+
+ if ( (0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT,
+ conv_name)) &&
+ (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) )
+ cache_nick (&rp_msg->private_key,
+ &rd[i]);
}
res = GSN_database->store_records (GSN_database->cls,
&rp_msg->private_key,
sa);
sa->nc = nc;
sa->rsm = (const struct RecordStoreMessage *) &sa[1];
- memcpy (&sa[1],
- rp_msg,
- ntohs (rp_msg->gns_header.header.size));
+ GNUNET_memcpy (&sa[1],
+ rp_msg,
+ ntohs (rp_msg->gns_header.header.size));
sa->zm_pos = monitor_head;
sa->conv_name = conv_name;
- GNUNET_array_grow (sa->rd,
- sa->rd_count,
- rd_clean_off);
- memcpy (sa->rd,
- rd_clean,
- sizeof (struct GNUNET_GNSRECORD_Data) * rd_clean_off);
continue_store_activity (sa);
}
}
* Zone to name iterator
*
* @param cls struct ZoneToNameCtx *
- * @param seq sequence number of the record
+ * @param seq sequence number of the record, MUST NOT BE ZERO
* @param zone_key the zone key
* @param name name
* @param rd_count number of records in @a rd
struct ZoneToNameResponseMessage *ztnr_msg;
int16_t res;
size_t name_len;
- size_t rd_ser_len;
+ ssize_t rd_ser_len;
size_t msg_size;
char *name_tmp;
char *rd_tmp;
- (void) seq;
+ GNUNET_assert (0 != seq);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Found result for zone-to-name lookup: `%s'\n",
name);
res = GNUNET_YES;
name_len = (NULL == name) ? 0 : strlen (name) + 1;
- rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
+ rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count,
+ rd);
+ if (rd_ser_len < 0)
+ {
+ GNUNET_break (0);
+ ztn_ctx->success = GNUNET_SYSERR;
+ return;
+ }
msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
if (msg_size >= GNUNET_MAX_MESSAGE_SIZE)
{
name,
name_len);
rd_tmp = &name_tmp[name_len];
- GNUNET_GNSRECORD_records_serialize (rd_count,
- rd,
- rd_ser_len,
- rd_tmp);
+ GNUNET_assert (rd_ser_len ==
+ GNUNET_GNSRECORD_records_serialize (rd_count,
+ rd,
+ rd_ser_len,
+ rd_tmp));
ztn_ctx->success = GNUNET_OK;
GNUNET_MQ_send (ztn_ctx->nc->mq,
env);
* Process results for zone iteration from database
*
* @param cls struct ZoneIterationProcResult
- * @param seq sequence number of the record
+ * @param seq sequence number of the record, MUST NOT BE ZERO
* @param zone_key the zone key
* @param name name
* @param rd_count number of records for this name
struct ZoneIterationProcResult *proc = cls;
int do_refresh_block;
+ GNUNET_assert (0 != seq);
if ( (NULL == zone_key) &&
(NULL == name) )
{
proc->limit--;
proc->zi->seq = seq;
send_lookup_response (proc->zi->nc,
- proc->zi->request_id,
- zone_key,
- name,
- rd_count,
- rd);
+ proc->zi->request_id,
+ zone_key,
+ name,
+ rd_count,
+ rd);
+
+
do_refresh_block = GNUNET_NO;
for (unsigned int i=0;i<rd_count;i++)
if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
}
if (GNUNET_YES == do_refresh_block)
refresh_block (NULL,
- 0,
+ proc->zi,
+ 0,
zone_key,
name,
rd_count,
uint64_t limit)
{
struct ZoneIterationProcResult proc;
- struct GNUNET_MQ_Envelope *env;
- struct RecordResultMessage *rrm;
struct GNUNET_TIME_Absolute start;
struct GNUNET_TIME_Relative duration;
duration.rel_value_us,
GNUNET_NO);
if (0 == proc.limit)
- {
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Returned %llu results, more results available\n",
- (unsigned long long) limit);
- return; /* more results later after we get the
- #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message */
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Completed iteration after %llu/%llu results\n",
- (unsigned long long) (limit - proc.limit),
- (unsigned long long) limit);
- /* send empty response to indicate end of list */
- env = GNUNET_MQ_msg (rrm,
- GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
- rrm->gns_header.r_id = htonl (zi->request_id);
- GNUNET_MQ_send (zi->nc->mq,
- env);
- GNUNET_CONTAINER_DLL_remove (zi->nc->op_head,
- zi->nc->op_tail,
- zi);
- GNUNET_free (zi);
+ (unsigned long long) limit);
+ zi->send_end = (0 != proc.limit);
+ if (0 == zi->cache_ops)
+ zone_iteration_done_client_continue (zi);
}
*/
static void
handle_iteration_start (void *cls,
- const struct ZoneIterationStartMessage *zis_msg)
+ const struct ZoneIterationStartMessage *zis_msg)
{
struct NamestoreClient *nc = cls;
struct ZoneIteration *zi;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received ZONE_ITERATION_START message\n");
+ "Received ZONE_ITERATION_START message\n");
zi = GNUNET_new (struct ZoneIteration);
zi->request_id = ntohl (zis_msg->gns_header.r_id);
zi->offset = 0;
zi->zone = zis_msg->zone;
GNUNET_CONTAINER_DLL_insert (nc->op_head,
- nc->op_tail,
- zi);
+ nc->op_tail,
+ zi);
run_zone_iteration_round (zi,
1);
- GNUNET_SERVICE_client_continue (nc->client);
}
*/
static void
handle_iteration_stop (void *cls,
- const struct ZoneIterationStopMessage *zis_msg)
+ const struct ZoneIterationStopMessage *zis_msg)
{
struct NamestoreClient *nc = cls;
struct ZoneIteration *zi;
uint32_t rid;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received ZONE_ITERATION_STOP message\n");
+ "Received ZONE_ITERATION_STOP message\n");
rid = ntohl (zis_msg->gns_header.r_id);
for (zi = nc->op_head; NULL != zi; zi = zi->next)
if (zi->request_id == rid)
return;
}
GNUNET_CONTAINER_DLL_remove (nc->op_head,
- nc->op_tail,
- zi);
+ nc->op_tail,
+ zi);
GNUNET_free (zi);
GNUNET_SERVICE_client_continue (nc->client);
}
*/
static void
handle_iteration_next (void *cls,
- const struct ZoneIterationNextMessage *zis_msg)
+ const struct ZoneIterationNextMessage *zis_msg)
{
struct NamestoreClient *nc = cls;
struct ZoneIteration *zi;
}
run_zone_iteration_round (zi,
limit);
- GNUNET_SERVICE_client_continue (nc->client);
}
sa = sn;
}
if (zm->limit > zm->iteration_cnt)
+ {
zm->sa_waiting = GNUNET_NO;
+ if (NULL != zm->sa_wait_warning)
+ {
+ GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
+ zm->sa_wait_warning = NULL;
+ }
+ }
+ else if (GNUNET_YES == zm->sa_waiting)
+ {
+ zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
+ if (NULL != zm->sa_wait_warning)
+ GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
+ zm->sa_wait_warning = GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
+ &warn_monitor_slow,
+ zm);
+ }
}
struct GNUNET_MessageHeader *sync;
env = GNUNET_MQ_msg (sync,
- GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
+ GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
GNUNET_MQ_send (zm->nc->mq,
- env);
+ env);
/* mark iteration done */
zm->in_first_iteration = GNUNET_NO;
zm->iteration_cnt = 0;
* A #GNUNET_NAMESTORE_RecordIterator for monitors.
*
* @param cls a 'struct ZoneMonitor *' with information about the monitor
- * @param seq sequence number of the record
+ * @param seq sequence number of the record, MUST NOT BE ZERO
* @param zone_key zone key of the zone
* @param name name
* @param rd_count number of records in @a rd
*/
static void
monitor_iterate_cb (void *cls,
- uint64_t seq,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
- const char *name,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
+ uint64_t seq,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+ const char *name,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
{
struct ZoneMonitor *zm = cls;
+ GNUNET_assert (0 != seq);
zm->seq = seq;
- if (NULL == name)
- {
- /* finished with iteration */
- monitor_sync (zm);
- return;
- }
+ GNUNET_assert (NULL != name);
GNUNET_STATISTICS_update (statistics,
"Monitor notifications sent",
1,
zm->limit--;
zm->iteration_cnt--;
send_lookup_response (zm->nc,
- 0,
- zone_key,
- name,
- rd_count,
- rd);
+ 0,
+ zone_key,
+ name,
+ rd_count,
+ rd);
if ( (0 == zm->iteration_cnt) &&
(0 != zm->limit) )
{
*/
static void
handle_monitor_start (void *cls,
- const struct ZoneMonitorStartMessage *zis_msg)
+ const struct ZoneMonitorStartMessage *zis_msg)
{
struct NamestoreClient *nc = cls;
struct ZoneMonitor *zm;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received ZONE_MONITOR_START message\n");
+ "Received ZONE_MONITOR_START message\n");
zm = GNUNET_new (struct ZoneMonitor);
zm->nc = nc;
zm->zone = zis_msg->zone;
zm->limit = 1;
zm->in_first_iteration = (GNUNET_YES == ntohl (zis_msg->iterate_first));
GNUNET_CONTAINER_DLL_insert (monitor_head,
- monitor_tail,
- zm);
+ monitor_tail,
+ zm);
GNUNET_SERVICE_client_mark_monitor (nc->client);
GNUNET_SERVICE_client_continue (nc->client);
GNUNET_notification_context_add (monitor_nc,
- nc->mq);
+ nc->mq);
if (zm->in_first_iteration)
zm->task = GNUNET_SCHEDULER_add_now (&monitor_iteration_next,
- zm);
+ zm);
else
monitor_sync (zm);
}
zm->iteration_cnt = zm->limit; /* use it all */
ret = GSN_database->iterate_records (GSN_database->cls,
(0 == memcmp (&zm->zone,
- &zero,
- sizeof (zero)))
+ &zero,
+ sizeof (zero)))
? NULL
: &zm->zone,
- zm->seq,
+ zm->seq,
zm->iteration_cnt,
- &monitor_iterate_cb,
- zm);
+ &monitor_iterate_cb,
+ zm);
if (GNUNET_SYSERR == ret)
{
GNUNET_SERVICE_client_drop (zm->nc->client);
inc = GNUNET_ntohll (nm->limit);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received ZONE_MONITOR_NEXT message with limit %llu\n",
+ "Received ZONE_MONITOR_NEXT message with limit %llu\n",
(unsigned long long) inc);
for (zm = monitor_head; NULL != zm; zm = zm->next)
if (zm->nc == nc)
GNUNET_assert (zm->iteration_cnt <= zm->limit);
if ( (zm->limit > zm->iteration_cnt) &&
(zm->sa_waiting) )
+ {
monitor_unblock (zm);
+ }
+ else if (GNUNET_YES == zm->sa_waiting)
+ {
+ if (NULL != zm->sa_wait_warning)
+ GNUNET_SCHEDULER_cancel (zm->sa_wait_warning);
+ zm->sa_waiting_start = GNUNET_TIME_absolute_get ();
+ zm->sa_wait_warning = GNUNET_SCHEDULER_add_delayed (MONITOR_STALL_WARN_DELAY,
+ &warn_monitor_slow,
+ zm);
+ }
}
(void) cls;
(void) service;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Starting namestore service\n");
+ "Starting namestore service\n");
cache_keys = GNUNET_CONFIGURATION_get_value_yesno (cfg,
"namestore",
"CACHE_KEYS");
disable_namecache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
- "namecache",
- "DISABLE");
+ "namecache",
+ "DISABLE");
GSN_cfg = cfg;
monitor_nc = GNUNET_notification_context_create (1);
if (GNUNET_YES != disable_namecache)
statistics = GNUNET_STATISTICS_create ("namestore",
cfg);
GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
- NULL);
+ NULL);
if (NULL == GSN_database)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Could not load database backend `%s'\n",
- db_lib_name);
+ "Could not load database backend `%s'\n",
+ db_lib_name);
GNUNET_SCHEDULER_shutdown ();
return;
}
&client_disconnect_cb,
NULL,
GNUNET_MQ_hd_var_size (record_store,
- GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE,
- struct RecordStoreMessage,
- NULL),
+ GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE,
+ struct RecordStoreMessage,
+ NULL),
GNUNET_MQ_hd_var_size (record_lookup,
- GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP,
- struct LabelLookupMessage,
- NULL),
+ GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP,
+ struct LabelLookupMessage,
+ NULL),
GNUNET_MQ_hd_fixed_size (zone_to_name,
- GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME,
- struct ZoneToNameMessage,
- NULL),
+ GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME,
+ struct ZoneToNameMessage,
+ NULL),
GNUNET_MQ_hd_fixed_size (iteration_start,
- GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START,
- struct ZoneIterationStartMessage,
- NULL),
+ GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START,
+ struct ZoneIterationStartMessage,
+ NULL),
GNUNET_MQ_hd_fixed_size (iteration_next,
- GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT,
- struct ZoneIterationNextMessage,
- NULL),
+ GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT,
+ struct ZoneIterationNextMessage,
+ NULL),
GNUNET_MQ_hd_fixed_size (iteration_stop,
- GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP,
- struct ZoneIterationStopMessage,
- NULL),
+ GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP,
+ struct ZoneIterationStopMessage,
+ NULL),
GNUNET_MQ_hd_fixed_size (monitor_start,
- GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START,
- struct ZoneMonitorStartMessage,
- NULL),
+ GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START,
+ struct ZoneMonitorStartMessage,
+ NULL),
GNUNET_MQ_hd_fixed_size (monitor_next,
- GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT,
- struct ZoneMonitorNextMessage,
- NULL),
+ GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT,
+ struct ZoneMonitorNextMessage,
+ NULL),
GNUNET_MQ_handler_end ());