obsolete due to alpine policy
[oweals/gnunet.git] / src / reclaim / gnunet-service-reclaim_tickets.c
index 9a595447d8bdc23265205e6ad1710f0ae64dbb71..57c9e2167dd0039e6affe392408446ed9e0ddceb 100644 (file)
@@ -16,7 +16,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
    SPDX-License-Identifier: AGPL3.0-or-later
  */
+ */
 
 /**
  * @author Martin Schanzenbach
 #include <inttypes.h>
 #include "gnunet-service-reclaim_tickets.h"
 
+
+/**
+ * FIXME: the defaul ticket iteration interval should probably
+ * be the minimim attribute expiration.
+ */
 #define DEFAULT_TICKET_REFRESH_INTERVAL GNUNET_TIME_UNIT_HOURS
 
+/**
+ * Handle for a parallel GNS lookup job
+ * (Declaration further below)
+ */
 struct ParallelLookup;
 
 
@@ -59,6 +68,9 @@ struct TicketReference
 };
 
 
+/**
+ * Handle to a consume operation
+ */
 struct RECLAIM_TICKETS_ConsumeHandle
 {
   /**
@@ -117,6 +129,7 @@ struct RECLAIM_TICKETS_ConsumeHandle
   void *cb_cls;
 };
 
+
 /**
  * Handle for a parallel GNS lookup job
  */
@@ -169,6 +182,11 @@ struct TicketIssueHandle
    */
   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
 
+  /**
+   * Namestore Iterator
+   */
+  struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
+
   /**
    * Callback
    */
@@ -180,6 +198,7 @@ struct TicketIssueHandle
   void *cb_cls;
 };
 
+
 /**
  * Ticket iterator
  */
@@ -292,28 +311,25 @@ struct RECLAIM_TICKETS_RevokeHandle
   struct TicketRecordsEntry *tickets_to_update_tail;
 };
 
+
 /**
  * Ticket expiration interval
  */
 static struct GNUNET_TIME_Relative ticket_refresh_interval;
 
+
 /* Namestore handle */
 static struct GNUNET_NAMESTORE_Handle *nsh;
 
+
 /* GNS handle */
 static struct GNUNET_GNS_Handle *gns;
 
+
 /* Handle to the statistics service */
 static struct GNUNET_STATISTICS_Handle *stats;
 
-static void
-move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
 
-static void
-move_attrs_cont (void *cls)
-{
-  move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *) cls);
-}
 
 /**
  * Cleanup revoke handle
@@ -325,6 +341,7 @@ cleanup_rvk (struct RECLAIM_TICKETS_RevokeHandle *rh)
 {
   struct RevokedAttributeEntry *ae;
   struct TicketRecordsEntry *le;
+
   if (NULL != rh->ns_qe)
     GNUNET_NAMESTORE_cancel (rh->ns_qe);
   if (NULL != rh->ns_it)
@@ -348,108 +365,120 @@ cleanup_rvk (struct RECLAIM_TICKETS_RevokeHandle *rh)
   GNUNET_free (rh);
 }
 
+
+/**
+ * For each ticket, store new, updated attribute references
+ * (Implementation further below)
+ *
+ * @param cls handle to the operation
+ */
 static void
-del_attr_finished (void *cls, int32_t success, const char *emsg)
+process_tickets (void *cls);
+
+
+/**
+ * Finished storing updated attribute references.
+ * Abort on error, else continue processing tickets
+ *
+ * @param cls handle to the operation
+ * @param success result of namestore operation
+ * @param emsg (NULL on success)
+ */
+static void
+ticket_processed (void *cls, int32_t success, const char *emsg)
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
+
   rvk->ns_qe = NULL;
-  if (GNUNET_SYSERR == success)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Error removing attribute: %s\n",
-                emsg);
-    rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
-    cleanup_rvk (rvk);
-    return;
-  }
-  rvk->move_attr = rvk->move_attr->next;
-  GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
+  GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
 }
 
+
+/**
+ * For each ticket, store new, updated attribute references
+ *
+ * @param cls handle to the operation
+ */
 static void
-move_attr_finished (void *cls, int32_t success, const char *emsg)
+process_tickets (void *cls)
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
-  char *label;
-  rvk->ns_qe = NULL;
-  if (GNUNET_SYSERR == success)
+  struct TicketRecordsEntry *le;
+  struct RevokedAttributeEntry *ae;
+
+  if (NULL == rvk->tickets_to_update_head)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Finished updatding tickets, success\n");
+    rvk->cb (rvk->cb_cls, GNUNET_OK);
+    cleanup_rvk (rvk);
+    return;
+  }
+  le = rvk->tickets_to_update_head;
+  GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
+                               rvk->tickets_to_update_tail,
+                               le);
+  struct GNUNET_GNSRECORD_Data rd[le->rd_count];
+  if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
+                                                         le->data,
+                                                         le->rd_count,
+                                                         rd))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Unable to deserialize ticket record(s)\n");
     rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
     cleanup_rvk (rvk);
     return;
   }
-  label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
-                                               sizeof (uint64_t));
-  GNUNET_assert (NULL != label);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
+  for (int i = 0; i < le->rd_count; i++)
+  {
+    if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
+      continue;
+    for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
+    {
+      if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(uint64_t)))
+        continue;
+      rd[i].data = &ae->new_id;
+    }
+  }
   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
                                                &rvk->identity,
-                                               label,
-                                               0,
-                                               NULL,
-                                               &del_attr_finished,
+                                               le->label,
+                                               le->rd_count,
+                                               rd,
+                                               &ticket_processed,
                                                rvk);
-  GNUNET_free (label);
+  GNUNET_free (le->label);
+  GNUNET_free (le->data);
+  GNUNET_free (le);
 }
 
 
+/**
+ * Done collecting tickets. Start processing.
+ *
+ * @param cls handle to the operation
+ */
 static void
-rvk_move_attr_cb (void *cls,
-                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
-                  const char *label,
-                  unsigned int rd_count,
-                  const struct GNUNET_GNSRECORD_Data *rd)
+rvk_ticket_update_finished (void *cls)
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
-  struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
-  struct GNUNET_GNSRECORD_Data new_rd;
-  struct RevokedAttributeEntry *le;
-  char *new_label;
-  char *attr_data;
-  rvk->ns_qe = NULL;
-  if (0 == rd_count)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "The attribute %s no longer exists!\n",
-                label);
-    le = rvk->move_attr;
-    rvk->move_attr = le->next;
-    GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
-    GNUNET_free (le);
-    GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
-    return;
-  }
-  /** find a new place for this attribute **/
-  rvk->move_attr->new_id =
-    GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
-  new_rd = *rd;
-  claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Attribute to update: Name=%s, ID=%" PRIu64 "\n",
-              claim->name,
-              claim->id);
-  claim->id = rvk->move_attr->new_id;
-  new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim);
-  attr_data = GNUNET_malloc (rd->data_size);
-  new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data);
-  new_rd.data = attr_data;
-  new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
-                                                   sizeof (uint64_t));
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
-  rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
-                                               &rvk->identity,
-                                               new_label,
-                                               1,
-                                               &new_rd,
-                                               &move_attr_finished,
-                                               rvk);
-  GNUNET_free (new_label);
-  GNUNET_free (claim);
-  GNUNET_free (attr_data);
+
+  rvk->ns_it = NULL;
+  GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
 }
 
 
+/**
+ * We need to update all other tickets with the new attribute IDs.
+ * We first collect them all. Processing after.
+ *
+ * @param cls handle to the operation
+ * @param zone ticket issuer private key
+ * @param label ticket rnd
+ * @param rd_cound size of record set
+ * @param rd record set
+ */
 static void
 rvk_ticket_update (void *cls,
                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
@@ -469,7 +498,7 @@ rvk_ticket_update (void *cls,
       continue;
     for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
     {
-      if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
+      if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(uint64_t)))
         continue;
       has_changed = GNUNET_YES;
       break;
@@ -493,106 +522,209 @@ rvk_ticket_update (void *cls,
 }
 
 
+/**
+ * Error iterating namestore. Abort.
+ *
+ * @param cls handle to the operation
+ */
 static void
-process_tickets (void *cls);
+rvk_ns_iter_err (void *cls)
+{
+  struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
 
+  rvk->ns_it = NULL;
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Namestore error on revocation (id=%" PRIu64 "\n",
+              rvk->move_attr->old_id);
+  rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
+  cleanup_rvk (rvk);
+}
 
+
+/**
+ * Error storing new attribute in namestore. Abort
+ *
+ * @param cls handle to the operation
+ */
 static void
-ticket_processed (void *cls, int32_t success, const char *emsg)
+rvk_ns_err (void *cls)
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
+
   rvk->ns_qe = NULL;
-  GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+              "Namestore error on revocation (id=%" PRIu64 "\n",
+              rvk->move_attr->old_id);
+  rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
+  cleanup_rvk (rvk);
 }
 
+
+/**
+ * We change every attribute ID of the ticket attributes we
+ * want to revoke.
+ * When we are done, we need to update any other ticket which
+ * included references to any of the changed attributes.
+ * (Implementation further below)
+ *
+ * @param rvk handle to the operation
+ */
 static void
-process_tickets (void *cls)
+move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
+
+
+/**
+ * Delayed continuation for move_attrs
+ *
+ * @param cls handle to the operation.
+ */
+static void
+move_attrs_cont (void *cls)
 {
-  struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
-  struct TicketRecordsEntry *le;
-  struct RevokedAttributeEntry *ae;
-  if (NULL == rvk->tickets_to_update_head)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Finished updatding tickets, success\n");
-    rvk->cb (rvk->cb_cls, GNUNET_OK);
-    cleanup_rvk (rvk);
-    return;
-  }
-  le = rvk->tickets_to_update_head;
-  GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
-                               rvk->tickets_to_update_tail,
-                               le);
-  struct GNUNET_GNSRECORD_Data rd[le->rd_count];
-  if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
-                                                         le->data,
-                                                         le->rd_count,
-                                                         rd))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                "Unable to deserialize ticket record(s)\n");
-    rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
-    cleanup_rvk (rvk);
-    return;
-  }
-  for (int i = 0; i < le->rd_count; i++)
-  {
-    if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
-      continue;
-    for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
-    {
-      if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
-        continue;
-      rd[i].data = &ae->new_id;
-    }
-  }
-  rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
-                                               &rvk->identity,
-                                               le->label,
-                                               le->rd_count,
-                                               rd,
-                                               &ticket_processed,
-                                               rvk);
-  GNUNET_free (le->label);
-  GNUNET_free (le->data);
-  GNUNET_free (le);
+  move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *) cls);
 }
 
+
+/**
+ * Done deleting the old record. Abort on error.
+ * Else, continue updating attribute IDs.
+ *
+ * @param cls handle to the operation
+ * @param success result of the namestore operation
+ * @param emsg error message (NULL on success)
+ */
 static void
-rvk_ticket_update_finished (void *cls)
+del_attr_finished (void *cls, int32_t success, const char *emsg)
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
-  rvk->ns_it = NULL;
-  GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
+
+  rvk->ns_qe = NULL;
+  if (GNUNET_SYSERR == success)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                "Error removing attribute: %s\n",
+                emsg);
+    rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
+    cleanup_rvk (rvk);
+    return;
+  }
+  rvk->move_attr = rvk->move_attr->next;
+  GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
 }
 
 
+/**
+ * Updated an attribute ID.
+ * Abort on error if namestore operation failed.
+ * Else, we have to delete the old record.
+ *
+ * @param cls handle to the operation
+ * @param success result of the store operation
+ * @param emsg error message (NULL on success)
+ */
 static void
-rvk_ns_iter_err (void *cls)
+move_attr_finished (void *cls, int32_t success, const char *emsg)
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
-  rvk->ns_it = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              "Namestore error on revocation (id=%" PRIu64 "\n",
-              rvk->move_attr->old_id);
-  rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
-  cleanup_rvk (rvk);
+  char *label;
+
+  rvk->ns_qe = NULL;
+  if (GNUNET_SYSERR == success)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
+    rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
+    cleanup_rvk (rvk);
+    return;
+  }
+  label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
+                                               sizeof(uint64_t));
+  GNUNET_assert (NULL != label);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
+  rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
+                                               &rvk->identity,
+                                               label,
+                                               0,
+                                               NULL,
+                                               &del_attr_finished,
+                                               rvk);
+  GNUNET_free (label);
 }
 
 
+/**
+ * Got the referenced attribute. Updating the ID
+ *
+ * @param cls handle to the operation
+ * @param zone issuer identity
+ * @param label attribute ID
+ * @param rd_count size of record set (should be 1)
+ * @param rd record set (the attribute)
+ */
 static void
-rvk_ns_err (void *cls)
+rvk_move_attr_cb (void *cls,
+                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+                  const char *label,
+                  unsigned int rd_count,
+                  const struct GNUNET_GNSRECORD_Data *rd)
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
+  struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
+  struct GNUNET_GNSRECORD_Data new_rd;
+  struct RevokedAttributeEntry *le;
+  char *new_label;
+  char *attr_data;
+
   rvk->ns_qe = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              "Namestore error on revocation (id=%" PRIu64 "\n",
-              rvk->move_attr->old_id);
-  rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
-  cleanup_rvk (rvk);
+  if (0 == rd_count)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "The attribute %s no longer exists!\n",
+                label);
+    le = rvk->move_attr;
+    rvk->move_attr = le->next;
+    GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
+    GNUNET_free (le);
+    GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
+    return;
+  }
+  /** find a new place for this attribute **/
+  rvk->move_attr->new_id =
+    GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
+  new_rd = *rd;
+  claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Attribute to update: Name=%s, ID=%" PRIu64 "\n",
+              claim->name,
+              claim->id);
+  claim->id = rvk->move_attr->new_id;
+  new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim);
+  attr_data = GNUNET_malloc (rd->data_size);
+  new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data);
+  new_rd.data = attr_data;
+  new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
+                                                   sizeof(uint64_t));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
+  rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
+                                               &rvk->identity,
+                                               new_label,
+                                               1,
+                                               &new_rd,
+                                               &move_attr_finished,
+                                               rvk);
+  GNUNET_free (new_label);
+  GNUNET_free (claim);
+  GNUNET_free (attr_data);
 }
 
 
+/**
+ * We change every attribute ID of the ticket attributes we
+ * want to revoke.
+ * When we are done, we need to update any other ticket which
+ * included references to any of the changed attributes.
+ *
+ * @param rvk handle to the operation
+ */
 static void
 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
 {
@@ -613,7 +745,7 @@ move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
     return;
   }
   label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
-                                               sizeof (uint64_t));
+                                               sizeof(uint64_t));
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving attribute %s\n", label);
 
   rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
@@ -627,10 +759,22 @@ move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
 }
 
 
+/**
+ * Finished deleting ticket and attribute references.
+ * Abort on failure.
+ * Else, we start changing every attribute ID in the
+ * found attribute references so that access is no longer
+ * possible.
+ *
+ * @param cls handle to the operation
+ * @param success Namestore operation return value
+ * @param emsg error message (NULL on success)
+ */
 static void
 remove_ticket_cont (void *cls, int32_t success, const char *emsg)
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
+
   rvk->ns_qe = NULL;
   if (GNUNET_SYSERR == success)
   {
@@ -653,6 +797,16 @@ remove_ticket_cont (void *cls, int32_t success, const char *emsg)
 }
 
 
+/**
+ * We found the attribute references.
+ * Store them for later and remove the record set.
+ *
+ * @param cls handle to the operation
+ * @param zone the issuer key
+ * @param label ticket rnd
+ * @param rd_cound size of record set
+ * @param rd record set
+ */
 static void
 revoke_attrs_cb (void *cls,
                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
@@ -663,7 +817,12 @@ revoke_attrs_cb (void *cls,
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
   struct RevokedAttributeEntry *le;
+
   rvk->ns_qe = NULL;
+  /**
+   * Temporarily store attribute references.
+   * We need it later.
+   */
   for (int i = 0; i < rd_count; i++)
   {
     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
@@ -674,7 +833,7 @@ revoke_attrs_cb (void *cls,
     rvk->ticket_attrs++;
   }
 
-  /** Now, remove ticket **/
+  /** Remove attribute references **/
   rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
                                                &rvk->identity,
                                                label,
@@ -685,15 +844,32 @@ revoke_attrs_cb (void *cls,
 }
 
 
+/**
+ * Failed to query namestore. Abort operation
+ *
+ * @param cls handle to the operation
+ */
 static void
 rvk_attrs_err_cb (void *cls)
 {
   struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
+
   rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
   cleanup_rvk (rvk);
 }
 
 
+/**
+ * Revoke a ticket.
+ * We start by looking up attribute references in order
+ * to change attribute IDs.
+ *
+ * @param ticket ticket to revoke
+ * @param identity private key of issuer
+ * @param cb revocation status callback
+ * @param cb_cls callback closure
+ * @return handle to the operation
+ */
 struct RECLAIM_TICKETS_RevokeHandle *
 RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
@@ -710,7 +886,7 @@ RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
   rvk->ticket = *ticket;
   GNUNET_CRYPTO_ecdsa_key_get_public (&rvk->identity, &rvk->ticket.identity);
   /** Get shared attributes **/
-  label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
+  label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(uint64_t));
   GNUNET_assert (NULL != label);
   rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
                                                 identity,
@@ -719,27 +895,38 @@ RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
                                                 rvk,
                                                 &revoke_attrs_cb,
                                                 rvk);
+  GNUNET_free (label);
   return rvk;
 }
 
 
+/**
+ * Cancel a revocation.
+ *
+ * @param rh handle to the operation
+ */
 void
 RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
 {
+  GNUNET_assert (NULL != rh);
   cleanup_rvk (rh);
 }
+
+
 /*******************************
- * Ticket consume
- *******************************/
+* Ticket consume
+*******************************/
 
 /**
  * Cleanup ticket consume handle
+ *
  * @param cth the handle to clean up
  */
 static void
 cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
 {
   struct ParallelLookup *lu;
+
   if (NULL != cth->lookup_request)
     GNUNET_GNS_lookup_cancel (cth->lookup_request);
   if (NULL != cth->kill_task)
@@ -761,6 +948,13 @@ cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
 }
 
 
+/**
+ * We found an attribute record.
+ *
+ * @param cls handle to the operation
+ * @param rd_cound size of record set
+ * @param rd record set
+ */
 static void
 process_parallel_lookup_result (void *cls,
                                 uint32_t rd_count,
@@ -769,6 +963,7 @@ process_parallel_lookup_result (void *cls,
   struct ParallelLookup *parallel_lookup = cls;
   struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
+
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Parallel lookup finished (count=%u)\n",
               rd_count);
@@ -782,14 +977,14 @@ process_parallel_lookup_result (void *cls,
                             "attribute_lookup_time_total",
                             GNUNET_TIME_absolute_get_duration (
                               parallel_lookup->lookup_start_time)
-                              .rel_value_us,
+                            .rel_value_us,
                             GNUNET_YES);
   GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
 
 
   GNUNET_free (parallel_lookup);
   if (1 != rd_count)
-    GNUNET_break (0); // TODO
+    GNUNET_break (0); // FIXME: We should never find this.
   if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR)
   {
     attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
@@ -799,15 +994,21 @@ process_parallel_lookup_result (void *cls,
                                  cth->attrs->list_tail,
                                  attr_le);
   }
+
   if (NULL != cth->parallel_lookups_head)
     return; // Wait for more
-  /* Else we are done */
 
+  /* Else we are done */
   cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
   cleanup_cth (cth);
 }
 
 
+/**
+ * Cancel the lookups for attribute records
+ *
+ * @param cls handle to the operation
+ */
 static void
 abort_parallel_lookups (void *cls)
 {
@@ -831,6 +1032,15 @@ abort_parallel_lookups (void *cls)
 }
 
 
+/**
+ * GNS result with attribute references.
+ * For each result, we start a (parallel) lookup of the actual
+ * attribute record under the referenced label.
+ *
+ * @param cls handle to the operation
+ * @param rd_cound size of the record set
+ * @param rd record set
+ */
 static void
 lookup_authz_cb (void *cls,
                  uint32_t rd_count,
@@ -846,7 +1056,7 @@ lookup_authz_cb (void *cls,
                             "reclaim_authz_lookup_time_total",
                             GNUNET_TIME_absolute_get_duration (
                               cth->lookup_start_time)
-                              .rel_value_us,
+                            .rel_value_us,
                             GNUNET_YES);
   GNUNET_STATISTICS_update (stats,
                             "reclaim_authz_lookups_count",
@@ -875,6 +1085,10 @@ lookup_authz_cb (void *cls,
                                  cth->parallel_lookups_tail,
                                  parallel_lookup);
   }
+  /**
+   * We started lookups. Add a timeout task.
+   * FIXME: Really needed here?
+   */
   if (NULL != cth->parallel_lookups_head)
   {
     cth->kill_task = GNUNET_SCHEDULER_add_delayed (
@@ -883,11 +1097,25 @@ lookup_authz_cb (void *cls,
       cth);
     return;
   }
+  /**
+   * No references found, return empty attribute list
+   */
   cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
   cleanup_cth (cth);
 }
 
 
+/**
+ * Consume a ticket.
+ * We first looking attribute references under the label
+ * ticket.rnd in GNS.
+ *
+ * @param id the audience of the ticket
+ * @param ticket the ticket to consume
+ * @param cb callback to call with attributes of ticket
+ * @param cb_cls callback closure
+ * @return handle to the operation
+ */
 struct RECLAIM_TICKETS_ConsumeHandle *
 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
                          const struct GNUNET_RECLAIM_Ticket *ticket,
@@ -896,6 +1124,7 @@ RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
 {
   struct RECLAIM_TICKETS_ConsumeHandle *cth;
   char *label;
+
   cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
 
   cth->identity = *id;
@@ -905,7 +1134,7 @@ RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
   cth->cb = cb;
   cth->cb_cls = cb_cls;
   label =
-    GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof (uint64_t));
+    GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof(uint64_t));
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Looking for AuthZ info under %s\n",
               label);
@@ -922,6 +1151,12 @@ RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
   return cth;
 }
 
+
+/**
+ * Cancel a consume operation
+ *
+ * @param cth the operation to cancel
+ */
 void
 RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
 {
@@ -931,8 +1166,8 @@ RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
 
 
 /*******************************
- * Ticket issue
- *******************************/
+* Ticket issue
+*******************************/
 
 /**
  * Cleanup ticket consume handle
@@ -947,6 +1182,14 @@ cleanup_issue_handle (struct TicketIssueHandle *handle)
 }
 
 
+/**
+ * Store finished, abort on error.
+ * Else, return new ticket to caller.
+ *
+ * @param cls handle to the operation
+ * @param success store operation result
+ * @param emsg error message (or NULL on success)
+ */
 static void
 store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
 {
@@ -966,6 +1209,13 @@ store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
 }
 
 
+/**
+ * Issue a new ticket.
+ * We store references to attribute record labels and the ticket itself
+ * under the label base64(ticket.rnd).
+ *
+ * @param ih handle to the operation containing relevant metadata
+ */
 static void
 issue_ticket (struct TicketIssueHandle *ih)
 {
@@ -979,27 +1229,30 @@ issue_ticket (struct TicketIssueHandle *ih)
     list_len++;
 
   attrs_record =
-    GNUNET_malloc (list_len * sizeof (struct GNUNET_GNSRECORD_Data));
+    GNUNET_malloc (list_len * sizeof(struct GNUNET_GNSRECORD_Data));
   i = 0;
   for (le = ih->attrs->list_head; NULL != le; le = le->next)
   {
     attrs_record[i].data = &le->claim->id;
-    attrs_record[i].data_size = sizeof (le->claim->id);
-    //FIXME: Should this be the attribute expiration time or ticket refresh intv
+    attrs_record[i].data_size = sizeof(le->claim->id);
+    /**
+     * FIXME: Should this be the attribute expiration time or ticket
+     * refresh interval? Probably min(attrs.expiration)
+     */
     attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
     attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
     attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
     i++;
   }
   attrs_record[i].data = &ih->ticket;
-  attrs_record[i].data_size = sizeof (struct GNUNET_RECLAIM_Ticket);
+  attrs_record[i].data_size = sizeof(struct GNUNET_RECLAIM_Ticket);
   attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
   attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
   attrs_record[i].flags =
     GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
 
   label =
-    GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof (uint64_t));
+    GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof(uint64_t));
   // Publish record
   ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
                                               &ih->identity,
@@ -1012,7 +1265,143 @@ issue_ticket (struct TicketIssueHandle *ih)
   GNUNET_free (label);
 }
 
+/*************************************************
+* Ticket iteration (finding a specific ticket)
+*************************************************/
+
+
+/**
+ * Namestore error on issue. Abort.
+ *
+ * @param cls handle to the operation
+ */
+static void
+filter_tickets_error_cb (void *cls)
+{
+  struct TicketIssueHandle *tih = cls;
+
+  tih->ns_it = NULL;
+  tih->cb (tih->cb_cls,
+           &tih->ticket,
+           GNUNET_SYSERR,
+           "Error storing AuthZ ticket in GNS");
+  cleanup_issue_handle (tih);
+}
+
+
+/**
+ * Iterator over records.
+ * Check if any previously issued ticket already
+ * matches what we need to prevent duplicates and
+ * improve resolution synergy.
+ *
+ * @param cls handle to the operation
+ * @param zone issuer identity
+ * @param label ticket rnd
+ * @param rd_count size of record set
+ * @param rd record set
+ */
+static void
+filter_tickets_cb (void *cls,
+                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+                   const char *label,
+                   unsigned int rd_count,
+                   const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct TicketIssueHandle *tih = cls;
+  struct GNUNET_RECLAIM_Ticket *ticket = NULL;
+
+  // figure out the number of requested attributes
+  struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
+  unsigned int attr_cnt = 0;
+
+  for (le = tih->attrs->list_head; NULL != le; le = le->next)
+    attr_cnt++;
+
+  // ticket search
+  unsigned int found_attrs_cnt = 0;
+
+  for (int i = 0; i < rd_count; i++)
+  {
+    // found ticket
+    if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET == rd[i].record_type)
+    {
+      ticket = (struct GNUNET_RECLAIM_Ticket *) rd[i].data;
+      // cmp audience
+      if (0 == memcmp (&tih->ticket.audience,
+                       &ticket->audience,
+                       sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
+      {
+        tih->ticket = *ticket;
+        continue;
+      }
+      ticket = NULL;
+    }
+
+    // cmp requested attributes with ticket attributes
+    if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
+      continue;
+    for (le = tih->attrs->list_head; NULL != le; le = le->next)
+    {
+      // cmp attr_ref id with requested attr id
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  " %" PRIu64 "\n  %" PRIu64 "\n",
+                  *((uint64_t *) rd[i].data),
+                  le->claim->id);
+
+
+      if (0 == memcmp (rd[i].data, &le->claim->id, sizeof(uint64_t)))
+        found_attrs_cnt++;
+    }
+  }
+
+  /**
+   * If we found a matching ticket, return that to the caller and
+   * we are done.
+   */
+  if ((attr_cnt == found_attrs_cnt)&&(NULL != ticket))
+  {
+    GNUNET_NAMESTORE_zone_iteration_stop (tih->ns_it);
+    tih->cb (tih->cb_cls, &tih->ticket, GNUNET_OK, NULL);
+    cleanup_issue_handle (tih);
+    return;
+  }
+
+  // ticket not found in current record, checking next record set
+  GNUNET_NAMESTORE_zone_iterator_next (tih->ns_it, 1);
+}
+
+
+/**
+ * Done iterating over tickets and we apparently did
+ * not find an existing, matching ticket.
+ * Continue by issuing a new ticket.
+ *
+ * @param cls handle to the operation
+ */
+static void
+filter_tickets_finished_cb (void *cls)
+{
+  struct TicketIssueHandle *tih = cls;
+
+  GNUNET_CRYPTO_ecdsa_key_get_public (&tih->identity, &tih->ticket.identity);
+  tih->ticket.rnd =
+    GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
+  issue_ticket (tih);
+}
+
 
+/**
+ * Issue a new reclaim ticket, thereby authorizing
+ * the audience to access the set of provided attributes.
+ *
+ * @param identity the issuer
+ * @param attrs the attributes to share
+ * @param audience the audience to share the attributes with
+ * @param cb the callback to call with the ticket result
+ * @param cb_cls the callback closure
+ * FIXME: Return handle??
+ */
 void
 RECLAIM_TICKETS_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
                        const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
@@ -1021,22 +1410,36 @@ RECLAIM_TICKETS_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
                        void *cb_cls)
 {
   struct TicketIssueHandle *tih;
+
   tih = GNUNET_new (struct TicketIssueHandle);
   tih->cb = cb;
   tih->cb_cls = cb_cls;
   tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
   tih->identity = *identity;
-  GNUNET_CRYPTO_ecdsa_key_get_public (identity, &tih->ticket.identity);
-  tih->ticket.rnd =
-    GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
   tih->ticket.audience = *audience;
-  issue_ticket (tih);
+
+  // First check whether the ticket has already been issued
+  tih->ns_it =
+    GNUNET_NAMESTORE_zone_iteration_start (nsh,
+                                           &tih->identity,
+                                           &filter_tickets_error_cb,
+                                           tih,
+                                           &filter_tickets_cb,
+                                           tih,
+                                           &filter_tickets_finished_cb,
+                                           tih);
 }
 
+
 /************************************
- * Ticket iteration
- ************************************/
+* Ticket iteration
+************************************/
 
+/**
+ * Cleanup ticket iterator
+ *
+ * @param iter handle to the iteration
+ */
 static void
 cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
 {
@@ -1046,6 +1449,17 @@ cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
 }
 
 
+/**
+ * Return each record of type @GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET
+ * to the caller and proceed with the iteration.
+ * FIXME: Should we _not_ proceed automatically here?
+ *
+ * @param cls handle to the iteration
+ * @param zone the ticket issuer
+ * @param label the ticket rnd
+ * @param rd_count number of records in record set
+ * @param rd record set containing a ticket
+ */
 static void
 collect_tickets_cb (void *cls,
                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
@@ -1066,26 +1480,43 @@ collect_tickets_cb (void *cls,
 }
 
 
+/**
+ * Signal ticket iteration has finished
+ *
+ * @param cls handle to the iteration
+ */
 static void
 collect_tickets_finished_cb (void *cls)
 {
   struct RECLAIM_TICKETS_Iterator *iter = cls;
+
   iter->ns_it = NULL;
   iter->cb (iter->cb_cls, NULL);
   cleanup_iter (iter);
 }
 
 
+/**
+ * Cancel ticket iteration on namestore error
+ *
+ * @param cls the iteration handle
+ */
 static void
 collect_tickets_error_cb (void *cls)
 {
   struct RECLAIM_TICKETS_Iterator *iter = cls;
+
   iter->ns_it = NULL;
   iter->cb (iter->cb_cls, NULL);
   cleanup_iter (iter);
 }
 
 
+/**
+ * Continue ticket iteration
+ *
+ * @param iter the iteration to continue
+ */
 void
 RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
 {
@@ -1093,6 +1524,11 @@ RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
 }
 
 
+/**
+ * Stop a running ticket iteration
+ *
+ * @param iter iteration to cancel
+ */
 void
 RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
 {
@@ -1101,6 +1537,14 @@ RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
 }
 
 
+/**
+ * Iterate over all tickets issued by an identity
+ *
+ * @param identity the issuing identity
+ * @param cb ticket callback function
+ * @param cb_cls callback closure
+ * @return a handle to the iteration
+ */
 struct RECLAIM_TICKETS_Iterator *
 RECLAIM_TICKETS_iteration_start (
   const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
@@ -1125,6 +1569,12 @@ RECLAIM_TICKETS_iteration_start (
 }
 
 
+/**
+ * Initialize tickets component
+ *
+ * @param c the configuration
+ * @return GNUNET_SYSERR on error
+ */
 int
 RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
 {
@@ -1162,6 +1612,11 @@ RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
   return GNUNET_OK;
 }
 
+
+/**
+ * Close handles and clean up.
+ * FIXME: cancel all pending operations (gns, ns etc)
+ */
 void
 RECLAIM_TICKETS_deinit (void)
 {