gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnunet] branch master updated: NAMESTORE: Add record set blocking API


From: gnunet
Subject: [gnunet] branch master updated: NAMESTORE: Add record set blocking API
Date: Wed, 16 Mar 2022 18:54:17 +0100

This is an automated email from the git hooks/post-receive script.

martin-schanzenbach pushed a commit to branch master
in repository gnunet.

The following commit(s) were added to refs/heads/master by this push:
     new 68ac68b70 NAMESTORE: Add record set blocking API
68ac68b70 is described below

commit 68ac68b70cf7fac5367421badade9febbaea7bf2
Author: Martin Schanzenbach <schanzen@gnunet.org>
AuthorDate: Wed Mar 16 18:53:22 2022 +0100

    NAMESTORE: Add record set blocking API
    
    New API that allows the caller to reserve
    the mofification of a record set under a label.
    The record set cannot be modified by other clients
    until released.
---
 src/include/gnunet_namestore_service.h   |  55 ++++++++++++
 src/namestore/Makefile.am                |  11 +++
 src/namestore/gnunet-service-namestore.c | 141 +++++++++++++++++++++++++++++--
 src/namestore/namestore.h                |  12 ++-
 src/namestore/namestore_api.c            | 108 +++++++++++++++--------
 5 files changed, 285 insertions(+), 42 deletions(-)

diff --git a/src/include/gnunet_namestore_service.h 
b/src/include/gnunet_namestore_service.h
index 7db5e9d9e..619b81aed 100644
--- a/src/include/gnunet_namestore_service.h
+++ b/src/include/gnunet_namestore_service.h
@@ -211,6 +211,61 @@ GNUNET_NAMESTORE_records_lookup (struct 
GNUNET_NAMESTORE_Handle *h,
                                  void *rm_cls);
 
 
+/**
+ * Open a record set for editing.
+ * Retrieves an exclusive lock on this set.
+ * Must be commited using @a GNUNET_NAMESTORE_records_commit
+ *
+ * @param h handle to the namestore
+ * @param pkey private key of the zone
+ * @param label name that is being mapped
+ * @param error_cb function to call on error (i.e. disconnect or unable to get 
lock)
+ *        the handle is afterwards invalid
+ * @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_records_open (struct GNUNET_NAMESTORE_Handle *h,
+                               const struct
+                               GNUNET_IDENTITY_PrivateKey *pkey,
+                               const char *label,
+                               GNUNET_SCHEDULER_TaskCallback error_cb,
+                               void *error_cb_cls,
+                               GNUNET_NAMESTORE_RecordMonitor rm,
+                               void *rm_cls);
+
+/**
+ * Commit the record set to the namestore.
+ * Releases the lock on the record set.
+ * Use an empty array to
+ * remove all records under the given name.
+ *
+ * The continuation is called after the value has been stored in the
+ * database. Monitors may be notified asynchronously (basically with
+ * a buffer). However, if any monitor is consistently too slow to
+ * keep up with the changes, calling @a cont will be delayed until the
+ * monitors do keep up.
+ *
+ * @param h handle to the namestore
+ * @param pkey private key of the zone
+ * @param label name that is being mapped
+ * @param rd_count number of records in the 'rd' array
+ * @param rd array of records with data to store
+ * @param cont continuation to call when done
+ * @param cont_cls closure for @a cont
+ * @return handle to abort the request
+ */
+struct GNUNET_NAMESTORE_QueueEntry *
+GNUNET_NAMESTORE_records_commit (struct GNUNET_NAMESTORE_Handle *h,
+                                 const struct GNUNET_IDENTITY_PrivateKey *pkey,
+                                 const char *label,
+                                 unsigned int rd_count,
+                                 const struct GNUNET_GNSRECORD_Data *rd,
+                                 GNUNET_NAMESTORE_ContinuationWithStatus cont,
+                                 void *cont_cls);
+
 /**
  * Look for an existing PKEY delegation record for a given public key.
  * Returns at most one result to the processor.
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am
index 51708dd67..2441b864a 100644
--- a/src/namestore/Makefile.am
+++ b/src/namestore/Makefile.am
@@ -39,6 +39,7 @@ if HAVE_SQLITE
 SQLITE_PLUGIN = libgnunet_plugin_namestore_sqlite.la
 SQLITE_TESTS = test_plugin_namestore_sqlite \
  test_namestore_api_store_sqlite \
+ test_namestore_api_store_locking_sqlite \
  test_namestore_api_store_update_sqlite \
  test_namestore_api_zone_iteration_sqlite \
  test_namestore_api_remove_sqlite \
@@ -249,6 +250,16 @@ test_namestore_api_store_sqlite_LDADD = \
   $(top_builddir)/src/identity/libgnunetidentity.la \
   libgnunetnamestore.la
 
+test_namestore_api_store_locking_sqlite_SOURCES = \
+ test_namestore_api_store_locking.c
+test_namestore_api_store_locking_sqlite_LDADD = \
+  $(top_builddir)/src/testing/libgnunettesting.la \
+  $(top_builddir)/src/util/libgnunetutil.la \
+  $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
+  $(top_builddir)/src/identity/libgnunetidentity.la \
+  libgnunetnamestore.la
+
+
 test_namestore_api_store_postgres_SOURCES = \
  test_namestore_api_store.c
 test_namestore_api_store_postgres_LDADD = \
diff --git a/src/namestore/gnunet-service-namestore.c 
b/src/namestore/gnunet-service-namestore.c
index 2a3a006e8..3f679cacd 100644
--- a/src/namestore/gnunet-service-namestore.c
+++ b/src/namestore/gnunet-service-namestore.c
@@ -121,6 +121,23 @@ struct ZoneIteration
   int send_end;
 };
 
+/**
+ * Lock on a record set
+ */
+struct RecordsLock
+{
+  /* DLL */
+  struct RecordsLock *prev;
+
+  /* DLL */
+  struct RecordsLock *next;
+
+  /* Hash of the locked label */
+  struct GNUNET_HashCode label_hash;
+
+  /* Client locking the zone */
+  struct NamestoreClient *client;
+};
 
 /**
  * A namestore client
@@ -393,6 +410,16 @@ static struct StoreActivity *sa_head;
  */
 static struct StoreActivity *sa_tail;
 
+/**
+ * Head of the DLL of record set locks
+ */
+static struct RecordsLock *locks_head;
+
+/**
+ * Tail of the DLL of record set locks
+ */
+static struct RecordsLock *locks_tail;
+
 /**
  * Notification context shared by all monitors.
  */
@@ -420,6 +447,7 @@ static void
 cleanup_task (void *cls)
 {
   struct CacheOperation *cop;
+  struct RecordsLock *lock;
 
   (void) cls;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
@@ -431,6 +459,14 @@ cleanup_task (void *cls)
     GNUNET_CONTAINER_DLL_remove (cop_head, cop_tail, cop);
     GNUNET_free (cop);
   }
+  while (NULL != (lock = locks_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (locks_head,
+                                 locks_tail,
+                                 lock);
+    GNUNET_free (lock);
+  }
+
   if (NULL != namecache)
   {
     GNUNET_NAMECACHE_disconnect (namecache);
@@ -1118,6 +1154,7 @@ client_disconnect_cb (void *cls,
   struct NamestoreClient *nc = app_ctx;
   struct ZoneIteration *no;
   struct CacheOperation *cop;
+  struct RecordsLock *lock;
 
   (void) cls;
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
@@ -1168,6 +1205,15 @@ client_disconnect_cb (void *cls,
   for (cop = cop_head; NULL != cop; cop = cop->next)
     if (nc == cop->nc)
       cop->nc = NULL;
+  for (lock = locks_head; NULL != lock; lock = lock->next)
+  {
+    if (nc != lock->client)
+      continue;
+    GNUNET_CONTAINER_DLL_remove (locks_head,
+                                 locks_tail,
+                                 lock);
+    GNUNET_free (lock);
+  }
   GNUNET_free (nc);
 }
 
@@ -1361,6 +1407,7 @@ check_record_lookup (void *cls, const struct 
LabelLookupMessage *ll_msg)
   return GNUNET_OK;
 }
 
+
 /**
  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
  *
@@ -1374,13 +1421,14 @@ handle_record_lookup (void *cls, const struct 
LabelLookupMessage *ll_msg)
   struct GNUNET_MQ_Envelope *env;
   struct LabelLookupResponseMessage *llr_msg;
   struct RecordLookupContext rlc;
+  struct RecordsLock *lock;
+  struct GNUNET_HashCode label_hash;
   const char *name_tmp;
   char *res_name;
   char *conv_name;
   uint32_t name_len;
   int res;
 
-  name_len = ntohl (ll_msg->label_len);
   name_tmp = (const char *) &ll_msg[1];
   GNUNET_SERVICE_client_continue (nc->client);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1396,6 +1444,52 @@ handle_record_lookup (void *cls, const struct 
LabelLookupMessage *ll_msg)
     GNUNET_SERVICE_client_drop (nc->client);
     return;
   }
+  name_len = strlen (conv_name) + 1;
+  if (GNUNET_YES == ntohl (ll_msg->locking))
+  {
+    GNUNET_CRYPTO_hash (conv_name, strlen (conv_name), &label_hash);
+    for (lock = locks_head; NULL != lock; lock = lock->next)
+      if (0 == memcmp (&label_hash, &lock->label_hash, sizeof (label_hash)))
+        break;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Record locked: %s\n", (NULL == lock) ? "No" : "Yes");
+    if (NULL != lock)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Client holds lock: %s\n", (lock->client != nc) ? "No" : 
"Yes");
+
+      if (lock->client != nc)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                    "Lock is held by other client on `%s'\n", conv_name);
+        env =
+          GNUNET_MQ_msg_extra (llr_msg,
+                               name_len,
+                               
GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE);
+        llr_msg->gns_header.r_id = ll_msg->gns_header.r_id;
+        llr_msg->private_key = ll_msg->zone;
+        llr_msg->name_len = htons (name_len);
+        llr_msg->rd_count = htons (0);
+        llr_msg->rd_len = htons (0);
+        llr_msg->found = htons (GNUNET_SYSERR);
+        GNUNET_memcpy (&llr_msg[1], conv_name, name_len);
+        GNUNET_MQ_send (nc->mq, env);
+        GNUNET_free (conv_name);
+        return;
+      }
+    }
+    else
+    {
+      lock = GNUNET_new (struct RecordsLock);
+      lock->client = nc;
+      GNUNET_CRYPTO_hash (conv_name,
+                          strlen (conv_name),
+                          &lock->label_hash);
+      GNUNET_CONTAINER_DLL_insert (locks_head,
+                                   locks_tail,
+                                   lock);
+    }
+  }
   rlc.label = conv_name;
   rlc.found = GNUNET_NO;
   rlc.res_rd_count = 0;
@@ -1407,7 +1501,6 @@ handle_record_lookup (void *cls, const struct 
LabelLookupMessage *ll_msg)
                                       conv_name,
                                       &lookup_it,
                                       &rlc);
-  GNUNET_free (conv_name);
   env =
     GNUNET_MQ_msg_extra (llr_msg,
                          name_len + rlc.rd_ser_len,
@@ -1419,16 +1512,18 @@ handle_record_lookup (void *cls, const struct 
LabelLookupMessage *ll_msg)
   llr_msg->rd_len = htons (rlc.rd_ser_len);
   res_name = (char *) &llr_msg[1];
   if ((GNUNET_YES == rlc.found) && (GNUNET_OK == res))
-    llr_msg->found = ntohs (GNUNET_YES);
+    llr_msg->found = htons (GNUNET_YES);
   else
-    llr_msg->found = ntohs (GNUNET_NO);
-  GNUNET_memcpy (&llr_msg[1], name_tmp, name_len);
+    llr_msg->found = htons (GNUNET_NO);
+  GNUNET_memcpy (&llr_msg[1], conv_name, name_len);
   GNUNET_memcpy (&res_name[name_len], rlc.res_rd, rlc.rd_ser_len);
   GNUNET_MQ_send (nc->mq, env);
   GNUNET_free (rlc.res_rd);
+  GNUNET_free (conv_name);
 }
 
 
+
 /**
  * Checks a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
  *
@@ -1528,6 +1623,8 @@ handle_record_store (void *cls, const struct 
RecordStoreMessage *rp_msg)
   unsigned int rd_count;
   int res;
   struct StoreActivity *sa;
+  struct RecordsLock *lock;
+  struct GNUNET_HashCode label_hash;
   struct GNUNET_TIME_Absolute existing_block_exp;
   struct GNUNET_TIME_Absolute new_block_exp;
 
@@ -1552,7 +1649,8 @@ handle_record_store (void *cls, const struct 
RecordStoreMessage *rp_msg)
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   "Error normalizing name `%s'\n",
                   name_tmp);
-      send_store_response (nc, GNUNET_SYSERR, _("Error normalizing name."), 
rid);
+      send_store_response (nc, GNUNET_SYSERR, _ ("Error normalizing name."),
+                           rid);
       GNUNET_SERVICE_client_continue (nc->client);
       return;
     }
@@ -1574,11 +1672,28 @@ handle_record_store (void *cls, const struct 
RecordStoreMessage *rp_msg)
         GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, 
rd))
     {
       send_store_response (nc, GNUNET_SYSERR,
-                           _("Error deserializing records."), rid);
+                           _ ("Error deserializing records."), rid);
       GNUNET_free (conv_name);
       GNUNET_SERVICE_client_continue (nc->client);
       return;
     }
+    if (GNUNET_YES == ntohl (rp_msg->locking))
+    {
+      GNUNET_CRYPTO_hash (conv_name, strlen (conv_name), &label_hash);
+      for (lock = locks_head; NULL != lock; lock = lock->next)
+        if (0 == memcmp (&label_hash, &lock->label_hash, sizeof (label_hash)))
+          break;
+      if ((NULL == lock) ||
+          (lock->client != nc))
+      {
+        send_store_response (nc, res, _ ("Record set locked."), rid);
+        GNUNET_SERVICE_client_continue (nc->client);
+        GNUNET_free (conv_name);
+        return;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Client has lock on `%s', continuing.\n", conv_name);
+    }
 
     GNUNET_STATISTICS_update (statistics,
                               "Well-formed store requests received",
@@ -1683,11 +1798,21 @@ handle_record_store (void *cls, const struct 
RecordStoreMessage *rp_msg)
     if (GNUNET_OK != res)
     {
       /* store not successful, no need to tell monitors */
-      send_store_response (nc, res, _("Store failed"), rid);
+      send_store_response (nc, res, _ ("Store failed"), rid);
       GNUNET_SERVICE_client_continue (nc->client);
       GNUNET_free (conv_name);
       return;
     }
+    if (GNUNET_YES == ntohl (rp_msg->locking))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Releasing lock on `%s'\n", conv_name);
+      GNUNET_assert (NULL != lock);
+      GNUNET_CONTAINER_DLL_remove (locks_head,
+                                   locks_tail,
+                                   lock);
+      GNUNET_free (lock);
+    }
 
     sa = GNUNET_malloc (sizeof(struct StoreActivity)
                         + ntohs (rp_msg->gns_header.header.size));
diff --git a/src/namestore/namestore.h b/src/namestore/namestore.h
index 8391d9d74..0f3ffa837 100644
--- a/src/namestore/namestore.h
+++ b/src/namestore/namestore.h
@@ -67,6 +67,11 @@ struct RecordStoreMessage
    */
   struct GNUNET_TIME_AbsoluteNBO expire;
 
+  /**
+   * Unock the label with this request.
+   */
+  uint32_t locking GNUNET_PACKED;
+
   /**
    * Name length
    */
@@ -145,6 +150,11 @@ struct LabelLookupMessage
    */
   uint32_t label_len GNUNET_PACKED;
 
+  /**
+   * Lock the label with this lookup
+   */
+  uint32_t locking GNUNET_PACKED;
+
   /**
    * The private key of the zone to look up in
    */
@@ -185,7 +195,7 @@ struct LabelLookupResponseMessage
    * Was the label found in the database??
    * #GNUNET_YES or #GNUNET_NO
    */
-  uint16_t found GNUNET_PACKED;
+  int16_t found GNUNET_PACKED;
 
   /**
    * The private key of the authority.
diff --git a/src/namestore/namestore_api.c b/src/namestore/namestore_api.c
index 3c8caf961..a7380bbde 100644
--- a/src/namestore/namestore_api.c
+++ b/src/namestore/namestore_api.c
@@ -479,8 +479,10 @@ handle_lookup_result (void *cls, const struct 
LabelLookupResponseMessage *msg)
   size_t name_len;
   size_t rd_len;
   unsigned int rd_count;
+  int16_t found = (int16_t) ntohs (msg->found);
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Received RECORD_LOOKUP_RESULT\n");
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Received RECORD_LOOKUP_RESULT (found=%i)\n",
+        found);
   qe = find_qe (h, ntohl (msg->gns_header.r_id));
   if (NULL == qe)
     return;
@@ -488,7 +490,7 @@ handle_lookup_result (void *cls, const struct 
LabelLookupResponseMessage *msg)
   rd_count = ntohs (msg->rd_count);
   name_len = ntohs (msg->name_len);
   name = (const char *) &msg[1];
-  if (GNUNET_NO == ntohs (msg->found))
+  if (GNUNET_NO == found)
   {
     /* label was not in namestore */
     if (NULL != qe->proc)
@@ -496,6 +498,13 @@ handle_lookup_result (void *cls, const struct 
LabelLookupResponseMessage *msg)
     free_qe (qe);
     return;
   }
+  if (GNUNET_SYSERR == found)
+  {
+    if (NULL != qe->error_cb)
+      qe->error_cb (qe->error_cb_cls);
+    free_qe (qe);
+    return;
+  }
 
   rd_tmp = &name[name_len];
   {
@@ -1005,14 +1014,15 @@ warn_delay (void *cls)
 }
 
 struct GNUNET_NAMESTORE_QueueEntry *
-GNUNET_NAMESTORE_records_store (
+records_store_ (
   struct GNUNET_NAMESTORE_Handle *h,
   const struct GNUNET_IDENTITY_PrivateKey *pkey,
   const char *label,
   unsigned int rd_count,
   const struct GNUNET_GNSRECORD_Data *rd,
   GNUNET_NAMESTORE_ContinuationWithStatus cont,
-  void *cont_cls)
+  void *cont_cls,
+  int locking)
 {
   struct GNUNET_NAMESTORE_QueueEntry *qe;
   struct GNUNET_MQ_Envelope *env;
@@ -1059,6 +1069,7 @@ GNUNET_NAMESTORE_records_store (
   msg->rd_len = htons (rd_ser_len);
   msg->reserved = ntohs(0);
   msg->private_key = *pkey;
+  msg->locking = htonl (locking);
 
   name_tmp = (char *) &msg[1];
   GNUNET_memcpy (name_tmp, label, name_len);
@@ -1090,27 +1101,45 @@ GNUNET_NAMESTORE_records_store (
   return qe;
 }
 
-/**
- * Lookup an item in the namestore.
- *
- * @param h handle to the namestore
- * @param pkey private key of the zone
- * @param label name that is being mapped (at most 255 characters long)
- * @param 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_records_lookup (
+GNUNET_NAMESTORE_records_store (
+  struct GNUNET_NAMESTORE_Handle *h,
+  const struct GNUNET_IDENTITY_PrivateKey *pkey,
+  const char *label,
+  unsigned int rd_count,
+  const struct GNUNET_GNSRECORD_Data *rd,
+  GNUNET_NAMESTORE_ContinuationWithStatus cont,
+  void *cont_cls)
+{
+  return records_store_ (h, pkey, label,
+                         rd_count, rd, cont, cont_cls, GNUNET_NO);
+}
+
+struct GNUNET_NAMESTORE_QueueEntry *
+GNUNET_NAMESTORE_records_commit (
+  struct GNUNET_NAMESTORE_Handle *h,
+  const struct GNUNET_IDENTITY_PrivateKey *pkey,
+  const char *label,
+  unsigned int rd_count,
+  const struct GNUNET_GNSRECORD_Data *rd,
+  GNUNET_NAMESTORE_ContinuationWithStatus cont,
+  void *cont_cls)
+{
+  return records_store_ (h, pkey, label,
+                         rd_count, rd, cont, cont_cls, GNUNET_YES);
+}
+
+
+struct GNUNET_NAMESTORE_QueueEntry *
+records_lookup_ (
   struct GNUNET_NAMESTORE_Handle *h,
   const struct GNUNET_IDENTITY_PrivateKey *pkey,
   const char *label,
   GNUNET_SCHEDULER_TaskCallback error_cb,
   void *error_cb_cls,
   GNUNET_NAMESTORE_RecordMonitor rm,
-  void *rm_cls)
+  void *rm_cls,
+  int locking)
 {
   struct GNUNET_NAMESTORE_QueueEntry *qe;
   struct GNUNET_MQ_Envelope *env;
@@ -1138,6 +1167,7 @@ GNUNET_NAMESTORE_records_lookup (
   msg->gns_header.r_id = htonl (qe->op_id);
   msg->zone = *pkey;
   msg->label_len = htonl (label_len);
+  msg->locking = htonl (locking);
   GNUNET_memcpy (&msg[1], label, label_len);
   if (NULL == h->mq)
     qe->env = env;
@@ -1146,22 +1176,34 @@ GNUNET_NAMESTORE_records_lookup (
   return qe;
 }
 
+struct GNUNET_NAMESTORE_QueueEntry *
+GNUNET_NAMESTORE_records_lookup (
+  struct GNUNET_NAMESTORE_Handle *h,
+  const struct GNUNET_IDENTITY_PrivateKey *pkey,
+  const char *label,
+  GNUNET_SCHEDULER_TaskCallback error_cb,
+  void *error_cb_cls,
+  GNUNET_NAMESTORE_RecordMonitor rm,
+  void *rm_cls)
+{
+  return records_lookup_ (h, pkey, label,
+                          error_cb, error_cb_cls, rm, rm_cls, GNUNET_NO);
+}
+
+struct GNUNET_NAMESTORE_QueueEntry *
+GNUNET_NAMESTORE_records_open (
+  struct GNUNET_NAMESTORE_Handle *h,
+  const struct GNUNET_IDENTITY_PrivateKey *pkey,
+  const char *label,
+  GNUNET_SCHEDULER_TaskCallback error_cb,
+  void *error_cb_cls,
+  GNUNET_NAMESTORE_RecordMonitor rm,
+  void *rm_cls)
+{
+  return records_lookup_ (h, pkey, label,
+                          error_cb, error_cb_cls, rm, rm_cls, GNUNET_YES);
+}
 
-/**
- * Look for an existing PKEY delegation record for a given public key.
- * Returns at most one result to the processor.
- *
- * @param h handle to the namestore
- * @param zone public key of the zone to look up in, never NULL
- * @param value_zone public key of the target zone (value), never NULL
- * @param error_cb function to call on error (i.e. disconnect)
- * @param error_cb_cls closure for @a error_cb
- * @param proc function to call on the matching records, or with
- *        NULL (rd_count == 0) if there are no matching records
- * @param proc_cls closure for @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,

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]