From 3ec2b451f938398eb4d2f92603f0659c26f6675c Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Wed, 28 Sep 2022 14:05:01 +0900 Subject: NAMESTORE: Allow service-side record set filtering. Fixes #7193 This commit enables zone iteration APIs which allow you to set a record set filter to determine which records should be returned or not. In particular filtering of private records and maintenance records (TOMBSTONE) for zonemaster. --- src/gnsrecord/gnsrecord_misc.c | 27 +--- src/include/gnunet_gnsrecord_lib.h | 57 ++++---- src/include/gnunet_namestore_service.h | 112 +++++++++++++++- src/namestore/gnunet-service-namestore.c | 144 +++++++++++++++------ src/namestore/namestore.h | 28 ++++ src/namestore/namestore_api.c | 83 ++++++++---- src/namestore/namestore_api_monitor.c | 76 +++++++---- src/zonemaster/gnunet-service-zonemaster-monitor.c | 50 +++---- src/zonemaster/gnunet-service-zonemaster.c | 51 +++----- 9 files changed, 416 insertions(+), 212 deletions(-) diff --git a/src/gnsrecord/gnsrecord_misc.c b/src/gnsrecord/gnsrecord_misc.c index 5e3bbdb8c..880fc68c6 100644 --- a/src/gnsrecord/gnsrecord_misc.c +++ b/src/gnsrecord/gnsrecord_misc.c @@ -421,7 +421,7 @@ GNUNET_GNSRECORD_normalize_record_set (const char *label, rd_public, unsigned int *rd_count_public, struct GNUNET_TIME_Absolute *expiry, - int include_private, + enum GNUNET_GNSRECORD_Filter filter, char **emsg) { struct GNUNET_TIME_Absolute now; @@ -539,7 +539,7 @@ GNUNET_GNSRECORD_normalize_record_set (const char *label, /* Ignore private records for public record set */ - if ((GNUNET_NO == include_private) && + if ((0 != (filter & GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE)) && (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE))) continue; /* Skip expired records */ @@ -561,27 +561,4 @@ GNUNET_GNSRECORD_normalize_record_set (const char *label, } -enum GNUNET_GenericReturnValue -GNUNET_GNSRECORD_convert_records_for_export (const char *label, - const struct - GNUNET_GNSRECORD_Data *rd, - unsigned int rd_count, - struct GNUNET_GNSRECORD_Data * - rd_public, - unsigned int *rd_count_public, - struct GNUNET_TIME_Absolute *expiry, - char **emsg) -{ - return GNUNET_GNSRECORD_normalize_record_set (label, - rd, - rd_count, - rd_public, - rd_count_public, - expiry, - GNUNET_NO, - emsg); - -} - - /* end of gnsrecord_misc.c */ diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h index 1ff348b71..21fb610f3 100644 --- a/src/include/gnunet_gnsrecord_lib.h +++ b/src/include/gnunet_gnsrecord_lib.h @@ -124,6 +124,35 @@ enum GNUNET_GNSRECORD_Flags #define GNUNET_GNSRECORD_RF_RCMP_FLAGS (GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION) }; +/** + * Filter for GNUNET_GNSRECORD_normalize_record_set(). + */ +enum GNUNET_GNSRECORD_Filter +{ + /** + * No filter flags set. + * Private and public records are returned, + * maintenance records (TOMBSTONE etc) are not. + */ + GNUNET_GNSRECORD_FILTER_NONE = 0, + + /** + * Include maintenance records (TOMBSTONE etc). + */ + GNUNET_GNSRECORD_FILTER_INCLUDE_MAINTENANCE = 1, + + /** + * Filter private records + */ + GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE = 2, + + /** + * Filter public records. + * FIXME: Not implemented + */ + //GNUNET_NAMESTORE_FILTER_OMIT_PUBLIC = 4, +}; + /** * A GNS record. @@ -725,7 +754,7 @@ GNUNET_GNSRECORD_is_critical (uint32_t type); * @param rd_public where to write the converted records * @param rd_public_count number of records written to @a rd_public * @param min_expiry the minimum expiration of this set - * @param include_private GNUNET_YES if private records should be included. + * @param filter the record set filter, see GNUNET_GNSRECORD_Filter. * @param emsg the error message if something went wrong * @return GNUNET_OK if set could be normalized and is consistent */ @@ -736,34 +765,10 @@ GNUNET_GNSRECORD_normalize_record_set (const char *label, struct GNUNET_GNSRECORD_Data *rd_public, unsigned int *rd_count_public, struct GNUNET_TIME_Absolute *min_expiry, - int include_private, + enum GNUNET_GNSRECORD_Filter filter, char **emsg); -/** - * Convert namestore records from the internal format to that - * suitable for publication (removes private records). - * - * @param label the label under which this set is (supposed to be) published. - * @param rd input records - * @param rd_count size of the @a rd and @a rd_public arrays - * @param rd_public where to write the converted records - * @param rd_public_count number of records written to @a rd_public - * @param expiry the expiration of the block - * @param emsg the error message if something went wrong - * @return GNUNET_OK if set is consistent and can be exported - */ -enum GNUNET_GenericReturnValue -GNUNET_GNSRECORD_convert_records_for_export (const char *label, - const struct - GNUNET_GNSRECORD_Data *rd, - unsigned int rd_count, - struct GNUNET_GNSRECORD_Data * - rd_public, - unsigned int *rd_count_public, - struct GNUNET_TIME_Absolute *expiry, - char **emsg); - /** * Check label for invalid characters. * diff --git a/src/include/gnunet_namestore_service.h b/src/include/gnunet_namestore_service.h index 0788bc8b4..dc6aeaa69 100644 --- a/src/include/gnunet_namestore_service.h +++ b/src/include/gnunet_namestore_service.h @@ -198,6 +198,27 @@ typedef void unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd); +/** + * Process a record set that was stored in the namestore. + * The record set expiration value takes existing TOMBSTONE records + * into account even if those are not returned. + * + * @param cls closure + * @param zone private key of the zone + * @param label label of the records + * @param rd_count number of entries in @a rd array, 0 if label was deleted + * @param rd array of records with data to store + * @param expiry the expiration of this record set. + */ +typedef void +(*GNUNET_NAMESTORE_RecordSetMonitor) (void *cls, + const struct + GNUNET_IDENTITY_PrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd, + struct GNUNET_TIME_Absolute expiry); + /** * Lookup an item in the namestore. @@ -265,6 +286,9 @@ GNUNET_NAMESTORE_cancel (struct GNUNET_NAMESTORE_QueueEntry *qe); /** + * @deprecated since 0.16.7 will be replaced in 0.18 + * @see GNUNET_NAMESTORE_zone_iteration_start2() + * * Starts a new zone iteration (used to periodically PUT all of our * records into our DHT). This MUST lock the `struct GNUNET_NAMESTORE_Handle` * for any other calls than #GNUNET_NAMESTORE_zone_iterator_next() and @@ -300,6 +324,44 @@ GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h, GNUNET_SCHEDULER_TaskCallback finish_cb, void *finish_cb_cls); +/** + * Starts a new zone iteration (used to periodically PUT all of our + * 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. + * + * On error (disconnect), @a error_cb will be invoked. + * On normal completion, @a finish_cb proc will be + * invoked. + * + * @param h handle to the namestore + * @param zone zone to access, NULL for all zones + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @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) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @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_start2 (struct GNUNET_NAMESTORE_Handle *h, + const struct + GNUNET_IDENTITY_PrivateKey *zone, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_NAMESTORE_RecordSetMonitor proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls, + enum GNUNET_GNSRECORD_Filter filter); + + /** * Calls the record processor specified in #GNUNET_NAMESTORE_zone_iteration_start @@ -332,6 +394,9 @@ struct GNUNET_NAMESTORE_ZoneMonitor; /** + * @deprecated since 0.16.7 will be replaced in 0.18 + * @see GNUNET_NAMESTORE_zone_monitor_start2() + * * Begin monitoring a zone for changes. Will first call the @a * monitor function on all existing records in the selected zone(s) if * @a iterate_first is #GNUNET_YES. In any case, we will then call @a @@ -370,6 +435,47 @@ GNUNET_NAMESTORE_zone_monitor_start ( GNUNET_SCHEDULER_TaskCallback sync_cb, void *sync_cb_cls); +/** + * Begin monitoring a zone for changes. Will first call the @a + * monitor function on all existing records in the selected zone(s) if + * @a iterate_first is #GNUNET_YES. In any case, we will then call @a + * sync_cb, and then afterwards call the @a monitor whenever a record + * changes. If the namestore disconnects, the @a error_cb function is + * called with a disconnect event. Once the connection is + * re-established, the process begins from the start (depending on @a + * iterate_first, we will again first do all existing records, then @a + * sync, then updates). + * + * @param cfg configuration to use to connect to namestore + * @param zone zone to monitor, NULL for all zones + * @param iterate_first #GNUNET_YES to first iterate over all existing records, + * #GNUNET_NO to only return changes that happen from now on + * @param error_cb function to call on error (i.e. disconnect); note that + * unlike the other error callbacks in this API, a call to this + * function does NOT destroy the monitor handle, it merely signals + * that monitoring is down. You need to still explicitly call + * #GNUNET_NAMESTORE_zone_monitor_stop(). + * @param error_cb_cls closure for @a error_cb + * @param monitor function to call on zone changes, with an initial limit of 1 + * @param monitor_cls closure for @a monitor + * @param sync_cb function called when we're in sync with the namestore + * @param sync_cb_cls closure for @a sync_cb + * @param filter the record set filter to use + * @return handle to stop monitoring + */ +struct GNUNET_NAMESTORE_ZoneMonitor * +GNUNET_NAMESTORE_zone_monitor_start2 ( + const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_IDENTITY_PrivateKey *zone, + int iterate_first, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_NAMESTORE_RecordSetMonitor monitor, + void *monitor_cls, + GNUNET_SCHEDULER_TaskCallback sync_cb, + void *sync_cb_cls, + enum GNUNET_GNSRECORD_Filter filter); + /** * Calls the monitor processor specified in #GNUNET_NAMESTORE_zone_monitor_start @@ -435,9 +541,9 @@ GNUNET_NAMESTORE_transaction_begin (struct GNUNET_NAMESTORE_Handle *h, */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_transaction_rollback (struct GNUNET_NAMESTORE_Handle *h, - GNUNET_NAMESTORE_ContinuationWithStatus - cont, - void *cont_cls); + GNUNET_NAMESTORE_ContinuationWithStatus + cont, + void *cont_cls); /** * Commit a namestore transaction. * Saves all actions performed since #GNUNET_NAMESTORE_transaction_begin diff --git a/src/namestore/gnunet-service-namestore.c b/src/namestore/gnunet-service-namestore.c index 1bfcec76b..0a3dfea25 100644 --- a/src/namestore/gnunet-service-namestore.c +++ b/src/namestore/gnunet-service-namestore.c @@ -84,6 +84,11 @@ struct ZoneIteration */ struct GNUNET_IDENTITY_PrivateKey zone; + /** + * The record set filter + */ + enum GNUNET_GNSRECORD_Filter filter; + /** * Last sequence number in the zone iteration used to address next * result of the zone iteration in the store @@ -180,6 +185,11 @@ struct ZoneMonitor */ struct GNUNET_IDENTITY_PrivateKey zone; + /** + * The record set filter + */ + enum GNUNET_GNSRECORD_Filter filter; + /** * Task active during initial iteration. */ @@ -717,38 +727,63 @@ merge_with_nick_records (const struct GNUNET_GNSRECORD_Data *nick_rd, * @param name name * @param rd_count number of records in @a rd * @param rd array of records + * @param filter record set filter */ static void -send_lookup_response (struct NamestoreClient *nc, - uint32_t request_id, - const struct GNUNET_IDENTITY_PrivateKey *zone_key, - const char *name, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) +send_lookup_response_with_filter (struct NamestoreClient *nc, + uint32_t request_id, + const struct + GNUNET_IDENTITY_PrivateKey *zone_key, + const char *name, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd, + enum GNUNET_GNSRECORD_Filter filter) { struct GNUNET_MQ_Envelope *env; struct RecordResultMessage *zir_msg; struct GNUNET_GNSRECORD_Data *nick; struct GNUNET_GNSRECORD_Data *res; + struct GNUNET_GNSRECORD_Data rd_nf[rd_count]; + struct GNUNET_TIME_Absolute block_exp = GNUNET_TIME_UNIT_ZERO_ABS;; unsigned int res_count; + unsigned int rd_nf_count; size_t name_len; ssize_t rd_ser_len; char *name_tmp; char *rd_ser; + char *emsg; nick = get_nick_record (nc, zone_key); GNUNET_assert (-1 != GNUNET_GNSRECORD_records_get_size (rd_count, rd)); + if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (name, + rd, + rd_count, + rd_nf, + &rd_nf_count, + &block_exp, + filter, + &emsg)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg); + GNUNET_free (emsg); + GNUNET_assert (0); + } + + /** + * FIXME if we ever support GNUNET_NAMESTORE_OMIT_PUBLIC, + * we need to omit adding this public record here + */ if ((NULL != nick) && (0 != strcmp (name, GNUNET_GNS_EMPTY_LABEL_AT))) { nick->flags = (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE; - merge_with_nick_records (nick, rd_count, rd, &res_count, &res); + merge_with_nick_records (nick, rd_nf_count, rd_nf, &res_count, &res); } else { - res_count = rd_count; - res = (struct GNUNET_GNSRECORD_Data *) rd; + res_count = rd_nf_count; + res = (struct GNUNET_GNSRECORD_Data *) rd_nf; } if (NULL != nick) GNUNET_free (nick); @@ -782,6 +817,7 @@ send_lookup_response (struct NamestoreClient *nc, zir_msg->rd_count = htons (res_count); zir_msg->rd_len = htons ((uint16_t) rd_ser_len); zir_msg->private_key = *zone_key; + zir_msg->expire = GNUNET_TIME_absolute_hton (block_exp); name_tmp = (char *) &zir_msg[1]; GNUNET_memcpy (name_tmp, name, name_len); rd_ser = &name_tmp[name_len]; @@ -796,10 +832,33 @@ send_lookup_response (struct NamestoreClient *nc, 1, GNUNET_NO); GNUNET_MQ_send (nc->mq, env); - if (rd != res) + if (rd_nf != res) GNUNET_free (res); } +/** + * Generate a `struct LookupNameResponseMessage` and send it to the + * given client using the given notification context. + * + * @param nc client to unicast to + * @param request_id request ID to use + * @param zone_key zone key of the zone + * @param name name + * @param rd_count number of records in @a rd + * @param rd array of records + */ +static void +send_lookup_response (struct NamestoreClient *nc, + uint32_t request_id, + const struct + GNUNET_IDENTITY_PrivateKey *zone_key, + const char *name, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + send_lookup_response_with_filter (nc, request_id, zone_key, name, + rd_count, rd, GNUNET_GNSRECORD_FILTER_NONE); +} /** * Send response to the store request to the client. @@ -995,7 +1054,7 @@ refresh_block (struct NamestoreClient *nc, cop->nc = nc; cop->zi = zi; if (NULL != zi) - zi->cache_ops ++; + zi->cache_ops++; cop->rid = rid; GNUNET_CONTAINER_DLL_insert (cop_head, cop_tail, cop); cop->qe = GNUNET_NAMECACHE_block_cache (namecache, @@ -1081,12 +1140,13 @@ continue_store_activity (struct StoreActivity *sa) "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); + send_lookup_response_with_filter (zm->nc, + 0, + &rp_msg->private_key, + sa->conv_name, + rd_count, + rd, + zm->filter); sa->zm_pos = zm->next; } /* great, done with the monitors, unpack (again) for refresh_block operation */ @@ -1454,7 +1514,7 @@ handle_record_lookup (void *cls, const struct LabelLookupMessage *ll_msg) if (GNUNET_YES == rlc.found) llr_msg->found = htons (GNUNET_YES); else if (GNUNET_SYSERR == res) - llr_msg->found = htons (GNUNET_SYSERR); + llr_msg->found = htons (GNUNET_SYSERR); else llr_msg->found = htons (GNUNET_NO); GNUNET_memcpy (&llr_msg[1], conv_name, name_len); @@ -1531,13 +1591,15 @@ get_block_exp_existing (void *cls, unsigned int rd_pub_count; char *emsg; - if (GNUNET_OK != GNUNET_GNSRECORD_convert_records_for_export (label, - rd, - rd_count, - rd_pub, - &rd_pub_count, - exp, - &emsg)) + if (GNUNET_OK != + GNUNET_GNSRECORD_normalize_record_set (label, + rd, + rd_count, + rd_pub, + &rd_pub_count, + exp, + GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE, + &emsg)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg); @@ -1673,14 +1735,15 @@ handle_record_store (void *cls, const struct RecordStoreMessage *rp_msg) have_nick = GNUNET_YES; } } - if (GNUNET_OK != GNUNET_GNSRECORD_normalize_record_set (conv_name, - rd_clean, - rd_clean_off, - rd_nf, - &rd_nf_count, - &new_block_exp, - GNUNET_YES, - &emsg)) + if (GNUNET_OK != + GNUNET_GNSRECORD_normalize_record_set (conv_name, + rd_clean, + rd_clean_off, + rd_nf, + &rd_nf_count, + &new_block_exp, + GNUNET_GNSRECORD_FILTER_NONE, + &emsg)) { send_store_response (nc, GNUNET_SYSERR, emsg, rid); GNUNET_free (emsg); @@ -1991,12 +2054,13 @@ zone_iterate_proc (void *cls, } proc->limit--; proc->zi->seq = seq; - send_lookup_response (proc->zi->nc, - proc->zi->request_id, - zone_key, - name, - rd_count, - rd); + send_lookup_response_with_filter (proc->zi->nc, + proc->zi->request_id, + zone_key, + name, + rd_count, + rd, + proc->zi->filter); do_refresh_block = GNUNET_NO; @@ -2077,6 +2141,7 @@ handle_iteration_start (void *cls, "Received ZONE_ITERATION_START message\n"); zi = GNUNET_new (struct ZoneIteration); zi->request_id = ntohl (zis_msg->gns_header.r_id); + zi->filter = ntohs (zis_msg->filter); zi->offset = 0; zi->nc = nc; zi->zone = zis_msg->zone; @@ -2281,6 +2346,7 @@ handle_monitor_start (void *cls, const struct ZoneMonitorStartMessage *zis_msg) zm->nc = nc; zm->zone = zis_msg->zone; zm->limit = 1; + zm->filter = ntohs (zis_msg->filter); zm->in_first_iteration = (GNUNET_YES == ntohl (zis_msg->iterate_first)); GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm); GNUNET_SERVICE_client_mark_monitor (nc->client); diff --git a/src/namestore/namestore.h b/src/namestore/namestore.h index 8aaba180f..ad02ffb48 100644 --- a/src/namestore/namestore.h +++ b/src/namestore/namestore.h @@ -279,6 +279,12 @@ struct RecordResultMessage */ struct GNUNET_NAMESTORE_Header gns_header; + /** + * Expiration time if the record result (if any). + * Takes TOMBSTONEs into account. + */ + struct GNUNET_TIME_AbsoluteNBO expire; + /** * Name length */ @@ -375,6 +381,17 @@ struct ZoneMonitorStartMessage */ uint32_t iterate_first GNUNET_PACKED; + /** + * Record set filter control flags. + * See GNUNET_NAMESTORE_Filter enum. + */ + uint16_t filter; + + /** + * Reserved for alignment + */ + uint16_t reserved; + /** * Zone key. */ @@ -420,6 +437,17 @@ struct ZoneIterationStartMessage * Zone key. All zeros for "all zones". */ struct GNUNET_IDENTITY_PrivateKey zone; + + /** + * Record set filter control flags. + * See GNUNET_NAMESTORE_Filter enum. + */ + uint16_t filter; + + /** + * Reserved for alignment + */ + uint16_t reserved; }; diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c index 71d969022..51ee25acf 100644 --- a/src/namestore/namestore_api.c +++ b/src/namestore/namestore_api.c @@ -82,6 +82,11 @@ struct GNUNET_NAMESTORE_QueueEntry */ GNUNET_NAMESTORE_RecordMonitor proc; + /** + * Function to call with the records we get back; or NULL. + */ + GNUNET_NAMESTORE_RecordSetMonitor proc2; + /** * Closure for @e proc. */ @@ -150,6 +155,11 @@ struct GNUNET_NAMESTORE_ZoneIterator */ GNUNET_NAMESTORE_RecordMonitor proc; + /** + * The continuation to call with the results + */ + GNUNET_NAMESTORE_RecordSetMonitor proc2; + /** * Closure for @e proc. */ @@ -630,6 +640,9 @@ handle_record_result (void *cls, const struct RecordResultMessage *msg) { if (NULL != ze->proc) ze->proc (ze->proc_cls, &msg->private_key, name, rd_count, rd); + if (NULL != ze->proc2) + ze->proc2 (ze->proc_cls, &msg->private_key, name, + rd_count, rd, GNUNET_TIME_absolute_ntoh (msg->expire)); return; } } @@ -1272,25 +1285,6 @@ GNUNET_NAMESTORE_zone_to_name ( } -/** - * Starts a new zone iteration (used to periodically PUT all of our - * 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. - * - * @param h handle to the namestore - * @param zone zone to access, NULL for all zones - * @param error_cb function to call on error (i.e. disconnect) - * @param error_cb_cls closure for @a error_cb - * @param proc function to call on each name from the zone; it - * will be called repeatedly with a value (if available) - * @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, @@ -1332,15 +1326,50 @@ GNUNET_NAMESTORE_zone_iteration_start ( return it; } +struct GNUNET_NAMESTORE_ZoneIterator * +GNUNET_NAMESTORE_zone_iteration_start2 ( + struct GNUNET_NAMESTORE_Handle *h, + const struct GNUNET_IDENTITY_PrivateKey *zone, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_NAMESTORE_RecordSetMonitor proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls, + enum GNUNET_GNSRECORD_Filter filter) +{ + struct GNUNET_NAMESTORE_ZoneIterator *it; + struct GNUNET_MQ_Envelope *env; + struct ZoneIterationStartMessage *msg; + uint32_t rid; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending ZONE_ITERATION_START message\n"); + rid = get_op_id (h); + it = GNUNET_new (struct GNUNET_NAMESTORE_ZoneIterator); + it->h = h; + it->error_cb = error_cb; + it->error_cb_cls = error_cb_cls; + it->finish_cb = finish_cb; + it->finish_cb_cls = finish_cb_cls; + it->proc2 = proc; + it->proc_cls = proc_cls; + it->op_id = rid; + if (NULL != zone) + it->zone = *zone; + GNUNET_CONTAINER_DLL_insert_tail (h->z_head, h->z_tail, it); + env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START); + msg->gns_header.r_id = htonl (rid); + msg->filter = htons ((uint16_t) filter); + if (NULL != zone) + msg->zone = *zone; + if (NULL == h->mq) + it->env = env; + else + GNUNET_MQ_send (h->mq, env); + return it; +} + -/** - * 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, uint64_t limit) diff --git a/src/namestore/namestore_api_monitor.c b/src/namestore/namestore_api_monitor.c index 6670e54ce..968d7ed58 100644 --- a/src/namestore/namestore_api_monitor.c +++ b/src/namestore/namestore_api_monitor.c @@ -64,6 +64,16 @@ struct GNUNET_NAMESTORE_ZoneMonitor */ GNUNET_NAMESTORE_RecordMonitor monitor; + /** + * Function to call on events. + */ + GNUNET_NAMESTORE_RecordSetMonitor monitor2; + + /** + * Record set filter for this monitor + */ + enum GNUNET_GNSRECORD_Filter filter; + /** * Closure for @e monitor. */ @@ -213,7 +223,11 @@ handle_result (void *cls, const struct RecordResultMessage *lrm) GNUNET_assert ( GNUNET_OK == GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd)); - zm->monitor (zm->monitor_cls, &lrm->private_key, name_tmp, rd_count, rd); + if (NULL != zm->monitor2) + zm->monitor2 (zm->monitor_cls, &lrm->private_key, name_tmp, + rd_count, rd, GNUNET_TIME_absolute_ntoh (lrm->expire)); + else + zm->monitor (zm->monitor_cls, &lrm->private_key, name_tmp, rd_count, rd); } } @@ -272,33 +286,11 @@ reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm) env = GNUNET_MQ_msg (sm, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START); sm->iterate_first = htonl (zm->iterate_first); sm->zone = zm->zone; + sm->filter = htons ((uint16_t) zm->filter); GNUNET_MQ_send (zm->mq, env); } -/** - * Begin monitoring a zone for changes. If @a iterate_first is set, - * we Will first call the @a monitor function on all existing records - * in the selected zone(s). In any case, we will call @a sync and - * afterwards call @a monitor whenever a record changes. - * - * @param cfg configuration to use to connect to namestore - * @param zone zone to monitor - * @param iterate_first #GNUNET_YES to first iterate over all existing records, - * #GNUNET_NO to only return changes that happen from now - * on - * @param error_cb function to call on error (i.e. disconnect); note that - * unlike the other error callbacks in this API, a call to this - * function does NOT destroy the monitor handle, it merely signals - * that monitoring is down. You need to still explicitly call - * #GNUNET_NAMESTORE_zone_monitor_stop(). - * @param error_cb_cls closure for @a error_cb - * @param monitor function to call on zone changes - * @param monitor_cls closure for @a monitor - * @param sync_cb function called when we're in sync with the namestore - * @param cls closure for @a sync_cb - * @return handle to stop monitoring - */ struct GNUNET_NAMESTORE_ZoneMonitor * GNUNET_NAMESTORE_zone_monitor_start ( const struct GNUNET_CONFIGURATION_Handle *cfg, @@ -333,6 +325,42 @@ GNUNET_NAMESTORE_zone_monitor_start ( return zm; } +struct GNUNET_NAMESTORE_ZoneMonitor * +GNUNET_NAMESTORE_zone_monitor_start2 ( + const struct GNUNET_CONFIGURATION_Handle *cfg, + const struct GNUNET_IDENTITY_PrivateKey *zone, + int iterate_first, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_NAMESTORE_RecordSetMonitor monitor, + void *monitor_cls, + GNUNET_SCHEDULER_TaskCallback sync_cb, + void *sync_cb_cls, + enum GNUNET_GNSRECORD_Filter filter) +{ + struct GNUNET_NAMESTORE_ZoneMonitor *zm; + + zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor); + if (NULL != zone) + zm->zone = *zone; + zm->iterate_first = iterate_first; + zm->error_cb = error_cb; + zm->error_cb_cls = error_cb_cls; + zm->monitor2 = monitor; + zm->monitor_cls = monitor_cls; + zm->sync_cb = sync_cb; + zm->sync_cb_cls = sync_cb_cls; + zm->cfg = cfg; + zm->filter = filter; + reconnect (zm); + if (NULL == zm->mq) + { + GNUNET_free (zm); + return NULL; + } + return zm; +} + /** * Calls the monitor processor specified in #GNUNET_NAMESTORE_zone_monitor_start diff --git a/src/zonemaster/gnunet-service-zonemaster-monitor.c b/src/zonemaster/gnunet-service-zonemaster-monitor.c index 748a0f342..08749bede 100644 --- a/src/zonemaster/gnunet-service-zonemaster-monitor.c +++ b/src/zonemaster/gnunet-service-zonemaster-monitor.c @@ -273,19 +273,17 @@ perform_dht_put (const struct GNUNET_IDENTITY_PrivateKey *key, * @param label label of the records; NULL on disconnect * @param rd_count number of entries in @a rd array, 0 if label was deleted * @param rd array of records with data to store + * @param expire expiration of this record set */ static void handle_monitor_event (void *cls, const struct GNUNET_IDENTITY_PrivateKey *zone, const char *label, unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) + const struct GNUNET_GNSRECORD_Data *rd, + struct GNUNET_TIME_Absolute expire) { - struct GNUNET_GNSRECORD_Data rd_public[rd_count]; - unsigned int rd_public_count; struct DhtPutActivity *ma; - struct GNUNET_TIME_Absolute expire; - char *emsg; (void) cls; GNUNET_STATISTICS_update (statistics, @@ -296,24 +294,7 @@ handle_monitor_event (void *cls, "Received %u records for label `%s' via namestore monitor\n", rd_count, label); - /* filter out records that are not public, and convert to - absolute expiration time. */ - if (GNUNET_OK != GNUNET_GNSRECORD_convert_records_for_export (label, - rd, - rd_count, - rd_public, - &rd_public_count, - &expire, - &emsg)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Zonemaster-monitor failed: %s\n", emsg); - GNUNET_free (emsg); - GNUNET_NAMESTORE_zone_monitor_next (zmon, - 1); - return; /* nothing to do */ - } - if (0 == rd_public_count) + if (0 == rd_count) { GNUNET_NAMESTORE_zone_monitor_next (zmon, 1); @@ -323,8 +304,8 @@ handle_monitor_event (void *cls, ma->start_date = GNUNET_TIME_absolute_get (); ma->ph = perform_dht_put (zone, label, - rd_public, - rd_public_count, + rd, + rd_count, expire, ma); if (NULL == ma->ph) @@ -427,15 +408,16 @@ run (void *cls, /* Schedule periodic put for our records. */ statistics = GNUNET_STATISTICS_create ("zonemaster-mon", c); - zmon = GNUNET_NAMESTORE_zone_monitor_start (c, - NULL, - GNUNET_NO, - &handle_monitor_error, - NULL, - &handle_monitor_event, - NULL, - NULL /* sync_cb */, - NULL); + zmon = GNUNET_NAMESTORE_zone_monitor_start2 (c, + NULL, + GNUNET_NO, + &handle_monitor_error, + NULL, + &handle_monitor_event, + NULL, + NULL /* sync_cb */, + NULL, + GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE); GNUNET_NAMESTORE_zone_monitor_next (zmon, NAMESTORE_QUEUE_LIMIT - 1); GNUNET_break (NULL != zmon); diff --git a/src/zonemaster/gnunet-service-zonemaster.c b/src/zonemaster/gnunet-service-zonemaster.c index c6b86bf71..dba1b24ce 100644 --- a/src/zonemaster/gnunet-service-zonemaster.c +++ b/src/zonemaster/gnunet-service-zonemaster.c @@ -683,46 +683,28 @@ put_gns_record (void *cls, const struct GNUNET_IDENTITY_PrivateKey *key, const char *label, unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) + const struct GNUNET_GNSRECORD_Data *rd, + struct GNUNET_TIME_Absolute expire) { - struct GNUNET_GNSRECORD_Data rd_public[rd_count]; - unsigned int rd_public_count; struct DhtPutActivity *ma; - struct GNUNET_TIME_Absolute expire; - char *emsg; (void) cls; ns_iteration_left--; - if (GNUNET_OK != GNUNET_GNSRECORD_convert_records_for_export (label, - rd, - rd_count, - rd_public, - &rd_public_count, - &expire, - &emsg)) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Record set inconsistent, moving to next record set: %s\n", - emsg); - GNUNET_free (emsg); - check_zone_namestore_next (); - return; - } - if (0 == rd_public_count) + if (0 == rd_count) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record set empty, moving to next record set\n"); check_zone_namestore_next (); return; } - for (unsigned int i = 0; i < rd_public_count; i++) + for (unsigned int i = 0; i < rd_count; i++) { - if (0 != (rd_public[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) + if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) { /* GNUNET_GNSRECORD_block_create will convert to absolute time; we just need to adjust our iteration frequency */ min_relative_record_time.rel_value_us = - GNUNET_MIN (rd_public[i].expiration_time, + GNUNET_MIN (rd[i].expiration_time, min_relative_record_time.rel_value_us); } } @@ -736,8 +718,8 @@ put_gns_record (void *cls, ma->start_date = GNUNET_TIME_absolute_get (); ma->ph = perform_dht_put (key, label, - rd_public, - rd_public_count, + rd, + rd_count, expire, ma); put_cnt++; @@ -793,14 +775,15 @@ publish_zone_dht_start (void *cls) GNUNET_assert (NULL == namestore_iter); ns_iteration_left = 1; namestore_iter - = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle, - NULL, /* All zones */ - &zone_iteration_error, - NULL, - &put_gns_record, - NULL, - &zone_iteration_finished, - NULL); + = GNUNET_NAMESTORE_zone_iteration_start2 (namestore_handle, + NULL, /* All zones */ + &zone_iteration_error, + NULL, + &put_gns_record, + NULL, + &zone_iteration_finished, + NULL, + GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE); GNUNET_assert (NULL != namestore_iter); } -- cgit v1.2.3