fix for size
[oweals/gnunet.git] / src / namestore / gnunet-service-namestore.c
index a6be01af0176b8f950cfef2075ce3bd445667a8f..a05055bf9f897cc6545a5548231c67a0c225ce95 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2009 Christian Grothoff (and other contributing authors)
+     (C) 2012, 2013 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
  * @file namestore/gnunet-service-namestore.c
  * @brief namestore for the GNUnet naming system
  * @author Matthias Wachs
+ * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_getopt_lib.h"
-#include "gnunet_service_lib.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_dnsparser_lib.h"
+#include "gnunet_gns_service.h"
+#include "gnunet_namecache_service.h"
 #include "gnunet_namestore_service.h"
 #include "gnunet_namestore_plugin.h"
 #include "gnunet_signatures.h"
 
 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
 
+
+/**
+ * A namestore client
+ */
+struct NamestoreClient;
+
+
 /**
- * A namestore operation.
+ * A namestore iteration operation.
  */
-struct GNUNET_NAMESTORE_ZoneIteration
+struct ZoneIteration
 {
   /**
    * Next element in the DLL
    */
-  struct GNUNET_NAMESTORE_ZoneIteration *next;
+  struct ZoneIteration *next;
 
   /**
    * Previous element in the DLL
    */
-  struct GNUNET_NAMESTORE_ZoneIteration *prev;
+  struct ZoneIteration *prev;
 
   /**
    * Namestore client which intiated this zone iteration
    */
-  struct GNUNET_NAMESTORE_Client * client;
+  struct NamestoreClient *client;
 
   /**
-   * GNUNET_YES if we iterate over a specific zone
-   * GNUNET_NO if we iterate over all zones
+   * The nick to add to the records
    */
-  int has_zone;
+  struct GNUNET_GNSRECORD_Data *nick;
 
   /**
-   * Hash of the specific zone if 'has_zone' is GNUNET_YES,
-   * othwerwise set to '\0'
+   * Key of the zone we are iterating over.
    */
-  struct GNUNET_CRYPTO_ShortHashCode zone;
+  struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
 
   /**
    * The operation id fot the zone iteration in the response for the client
    */
-  uint64_t request_id;
+  uint32_t request_id;
 
   /**
    * Offset of the zone iteration used to address next result of the zone
@@ -76,104 +84,146 @@ struct GNUNET_NAMESTORE_ZoneIteration
    *
    * Initialy set to 0 in handle_iteration_start
    * Incremented with by every call to handle_iteration_next
-   *
    */
   uint32_t offset;
 
-  /**
-   * Which flags must be included
-   */
-  uint16_t must_have_flags;
-
-  /**
-   * Which flags must not be included
-   */
-  uint16_t must_not_have_flags;
 };
 
 
 /**
  * A namestore client
  */
-struct GNUNET_NAMESTORE_Client
+struct NamestoreClient
 {
   /**
    * Next element in the DLL
    */
-  struct GNUNET_NAMESTORE_Client *next;
+  struct NamestoreClient *next;
 
   /**
    * Previous element in the DLL
    */
-  struct GNUNET_NAMESTORE_Client *prev;
+  struct NamestoreClient *prev;
 
   /**
    * The client
    */
-  struct GNUNET_SERVER_Client * client;
+  struct GNUNET_SERVER_Client *client;
 
   /**
    * Head of the DLL of
    * Zone iteration operations in progress initiated by this client
    */
-  struct GNUNET_NAMESTORE_ZoneIteration *op_head;
+  struct ZoneIteration *op_head;
 
   /**
    * Tail of the DLL of
    * Zone iteration operations in progress initiated by this client
    */
-  struct GNUNET_NAMESTORE_ZoneIteration *op_tail;
+  struct ZoneIteration *op_tail;
 };
 
 
 /**
- * A container struct to store information belonging to a zone crypto key pair
+ * A namestore monitor.
  */
-struct GNUNET_NAMESTORE_CryptoContainer
+struct ZoneMonitor
 {
   /**
-   * Filename where to store the container
+   * Next element in the DLL
+   */
+  struct ZoneMonitor *next;
+
+  /**
+   * Previous element in the DLL
+   */
+  struct ZoneMonitor *prev;
+
+  /**
+   * Namestore client which intiated this zone monitor
    */
-  char * filename;
+  struct NamestoreClient *nc;
 
   /**
-   * Short hash of the zone's public key
+   * Private key of the zone.
    */
-  struct GNUNET_CRYPTO_ShortHashCode zone;
+  struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
 
   /**
-   * Zone's private key
+   * Task active during initial iteration.
    */
-  struct GNUNET_CRYPTO_RsaPrivateKey *privkey;
+  GNUNET_SCHEDULER_TaskIdentifier task;
 
   /**
-   * Zone's public key
+   * Offset of the zone iteration used to address next result of the zone
+   * iteration in the store
+   *
+   * Initialy set to 0.
+   * Incremented with by every call to #handle_iteration_next
    */
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey;
+  uint32_t offset;
+
 };
 
 
 /**
-* Configuration handle.
-*/
-const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
+ * Pending operation on the namecache.
+ */
+struct CacheOperation
+{
+
+  /**
+   * Kept in a DLL.
+   */
+  struct CacheOperation *prev;
+
+  /**
+   * Kept in a DLL.
+   */
+  struct CacheOperation *next;
+
+  /**
+   * Handle to namecache queue.
+   */
+  struct GNUNET_NAMECACHE_QueueEntry *qe;
+
+  /**
+   * Client to notify about the result.
+   */
+  struct GNUNET_SERVER_Client *client;
+
+  /**
+   * Client's request ID.
+   */
+  uint32_t rid;
+};
+
 
 /**
-* Database handle
-*/
-struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
+ * Public key of all zeros.
+ */
+static const struct GNUNET_CRYPTO_EcdsaPrivateKey zero;
 
 /**
-* Zonefile directory
-*/
-static char *zonefile_directory;
+ * Configuration handle.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
+
+/**
+ * Namecache handle.
+ */
+static struct GNUNET_NAMECACHE_Handle *namecache;
+
+/**
+ * Database handle
+ */
+static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
 
 /**
  * Name of the database plugin
  */
 static char *db_lib_name;
 
-
 /**
  * Our notification context.
  */
@@ -182,155 +232,39 @@ static struct GNUNET_SERVER_NotificationContext *snc;
 /**
  * Head of the Client DLL
  */
-static struct GNUNET_NAMESTORE_Client *client_head;
+static struct NamestoreClient *client_head;
 
 /**
  * Tail of the Client DLL
  */
-static struct GNUNET_NAMESTORE_Client *client_tail;
+static struct NamestoreClient *client_tail;
 
 /**
- * Hashmap containing the zone keys this namestore has is authoritative for
- *
- * Keys are the GNUNET_CRYPTO_HashCode of the GNUNET_CRYPTO_ShortHashCode
- * The values are 'struct GNUNET_NAMESTORE_CryptoContainer *'
+ * Head of cop DLL.
  */
-struct GNUNET_CONTAINER_MultiHashMap *zonekeys;
-
+static struct CacheOperation *cop_head;
 
 /**
- * Write zonefile to disk
- * @param filename where to write
- * @param c the crypto container
- *
- * @return GNUNET_OK on success, GNUNET_SYSERR on fail
+ * Tail of cop DLL.
  */
+static struct CacheOperation *cop_tail;
 
-int
-write_key_to_file (const char *filename, struct GNUNET_NAMESTORE_CryptoContainer *c)
-{
-  struct GNUNET_CRYPTO_RsaPrivateKey *ret = c->privkey;
-  struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *enc;
-  struct GNUNET_DISK_FileHandle *fd;
-
-  if (GNUNET_YES == GNUNET_DISK_file_test (filename))
-  {
-    struct GNUNET_CRYPTO_ShortHashCode zone;
-    struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey;
-    struct GNUNET_CRYPTO_RsaPrivateKey * privkey;
-
-    privkey = GNUNET_CRYPTO_rsa_key_create_from_file(filename);
-    if (privkey == NULL)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-           _("File zone `%s' but corrupt content already exists, failed to write! \n"), GNUNET_short_h2s (&zone));
-      return GNUNET_SYSERR;
-    }
-
-    GNUNET_CRYPTO_rsa_key_get_public (privkey, &pubkey);
-    GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone);
-    GNUNET_CRYPTO_rsa_key_free (privkey);
-
-    if (0 == memcmp (&zone, &c->zone, sizeof(zone)))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-           _("File zone `%s' containing this key already exists\n"), GNUNET_short_h2s (&zone));
-      return GNUNET_OK;
-    }
-    else
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-           _("File zone `%s' but different zone key already exists, failed to write! \n"), GNUNET_short_h2s (&zone));
-      return GNUNET_OK;
-    }
-  }
-  fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
-  if (NULL == fd)
-  {
-    if (errno == EEXIST)
-    {
-      if (GNUNET_YES != GNUNET_DISK_file_test (filename))
-      {
-        /* must exist but not be accessible, fail for good! */
-        if (0 != ACCESS (filename, R_OK))
-          LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
-        else
-          GNUNET_break (0);   /* what is going on!? */
-        return GNUNET_SYSERR;
-      }
-    }
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
-    return GNUNET_SYSERR;
-  }
-
-  if (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded), GNUNET_YES))
-  {
-    GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
-    return GNUNET_SYSERR;
-  }
-  enc = GNUNET_CRYPTO_rsa_encode_key (ret);
-  GNUNET_assert (enc != NULL);
-  GNUNET_assert (ntohs (enc->len) == GNUNET_DISK_file_write (fd, enc, ntohs (enc->len)));
-  GNUNET_free (enc);
-  GNUNET_DISK_file_sync (fd);
-  if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)))
-    LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
-  GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-       _("Stored zonekey for zone `%s' in file `%s'\n"), GNUNET_short_h2s(&c->zone), c->filename);
-  return GNUNET_OK;
-}
-
-int zone_to_disk_it (void *cls,
-                     const struct GNUNET_HashCode *key,
-                     void *value)
-{
-  struct GNUNET_NAMESTORE_CryptoContainer * c = value;
-  if (c->filename != NULL)
-    write_key_to_file(c->filename, c);
-  else
-  {
-    GNUNET_asprintf(&c->filename, "%s/%s.zkey", zonefile_directory, GNUNET_short_h2s (&c->zone));
-    write_key_to_file(c->filename, c);
-  }
-
+/**
+ * First active zone monitor.
+ */
+static struct ZoneMonitor *monitor_head;
 
-  GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (zonekeys, key, value));
-  GNUNET_CRYPTO_rsa_key_free (c->privkey);
-  GNUNET_free (c->pubkey);
-  GNUNET_free (c->filename);
-  GNUNET_free (c);
+/**
+ * Last active zone monitor.
+ */
+static struct ZoneMonitor *monitor_tail;
 
-  return GNUNET_OK;
-}
+/**
+ * Notification context shared by all monitors.
+ */
+static struct GNUNET_SERVER_NotificationContext *monitor_nc;
 
 
-struct GNUNET_TIME_Absolute
-get_block_expiration_time (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd)
-{
-  unsigned int c;
-  struct GNUNET_TIME_Absolute expire = GNUNET_TIME_UNIT_FOREVER_ABS;
-  struct GNUNET_TIME_Absolute at;
-  struct GNUNET_TIME_Relative rt;
-
-  if (NULL == rd)
-    return GNUNET_TIME_UNIT_ZERO_ABS;
-  for (c = 0; c < rd_count; c++)  
-  {
-    if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
-    {
-      rt.rel_value = rd[c].expiration_time;
-      at = GNUNET_TIME_relative_to_absolute (rt);
-    }
-    else
-    {
-      at.abs_value = rd[c].expiration_time;
-    }
-    expire = GNUNET_TIME_absolute_min (at, expire);  
-  }
-  return expire;
-}
 
 /**
  * Task run during shutdown.
@@ -341,1126 +275,811 @@ get_block_expiration_time (unsigned int rd_count, const struct GNUNET_NAMESTORE_
 static void
 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
-  struct GNUNET_NAMESTORE_ZoneIteration * no;
-  struct GNUNET_NAMESTORE_ZoneIteration * tmp;
-  struct GNUNET_NAMESTORE_Client * nc;
-  struct GNUNET_NAMESTORE_Client * next;
+  struct ZoneIteration *no;
+  struct NamestoreClient *nc;
+  struct CacheOperation *cop;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Stopping namestore service\n");
   if (NULL != snc)
   {
     GNUNET_SERVER_notification_context_destroy (snc);
     snc = NULL;
   }
-  GNUNET_CONTAINER_multihashmap_iterate(zonekeys, &zone_to_disk_it, NULL);
-  GNUNET_CONTAINER_multihashmap_destroy(zonekeys);
-
-  for (nc = client_head; nc != NULL; nc = next)
+  while (NULL != (cop = cop_head))
+  {
+    GNUNET_NAMECACHE_cancel (cop->qe);
+    GNUNET_CONTAINER_DLL_remove (cop_head,
+                                 cop_tail,
+                                 cop);
+    GNUNET_free (cop);
+  }
+  GNUNET_NAMECACHE_disconnect (namecache);
+  namecache = NULL;
+  while (NULL != (nc = client_head))
   {
-    next = nc->next;
-    for (no = nc->op_head; no != NULL; no = tmp)
+    while (NULL != (no = nc->op_head))
     {
       GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
-      tmp = no->next;
       GNUNET_free (no);
     }
-    GNUNET_SERVER_client_drop(nc->client);
     GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
+    GNUNET_SERVER_client_set_user_context (nc->client, (void *)NULL);
     GNUNET_free (nc);
   }
-
   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
   GNUNET_free (db_lib_name);
-  GNUNET_free_non_null(zonefile_directory);
-}
-
-static struct GNUNET_NAMESTORE_Client *
-client_lookup (struct GNUNET_SERVER_Client *client)
-{
-  struct GNUNET_NAMESTORE_Client * nc;
-
-  GNUNET_assert (NULL != client);
-
-  for (nc = client_head; nc != NULL; nc = nc->next)
+  db_lib_name = NULL;
+  if (NULL != monitor_nc)
   {
-    if (client == nc->client)
-      break;
+    GNUNET_SERVER_notification_context_destroy (monitor_nc);
+    monitor_nc = NULL;
   }
-  return nc;
 }
 
+
 /**
- * Called whenever a client is disconnected.  Frees our
- * resources associated with that client.
+ * Called whenever a client is disconnected.
+ * Frees our resources associated with that client.
  *
  * @param cls closure
  * @param client identification of the client
  */
 static void
-client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
+client_disconnect_notification (void *cls,
+                               struct GNUNET_SERVER_Client *client)
 {
-  struct GNUNET_NAMESTORE_ZoneIteration * no;
-  struct GNUNET_NAMESTORE_Client * nc;
+  struct ZoneIteration *no;
+  struct NamestoreClient *nc;
+  struct ZoneMonitor *zm;
+  struct CacheOperation *cop;
+
   if (NULL == client)
     return;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected \n", client);
-
-  nc = client_lookup (client);
-
-  if ((NULL == client) || (NULL == nc))
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Client %p disconnected\n",
+             client);
+  if (NULL == (nc = GNUNET_SERVER_client_get_user_context (client, struct NamestoreClient)))
     return;
-
-  no = nc->op_head;
-  while (NULL != no)
+  while (NULL != (no = nc->op_head))
   {
     GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
     GNUNET_free (no);
-    no = nc->op_head;
   }
-
-  GNUNET_SERVER_client_drop(nc->client);
   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
   GNUNET_free (nc);
-  nc = NULL;
+  for (zm = monitor_head; NULL != zm; zm = zm->next)
+  {
+    if (client == zm->nc->client)
+    {
+      GNUNET_CONTAINER_DLL_remove (monitor_head,
+                                  monitor_tail,
+                                  zm);
+      if (GNUNET_SCHEDULER_NO_TASK != zm->task)
+      {
+       GNUNET_SCHEDULER_cancel (zm->task);
+       zm->task = GNUNET_SCHEDULER_NO_TASK;
+      }
+      GNUNET_free (zm);
+      break;
+    }
+  }
+  for (cop = cop_head; NULL != cop; cop = cop->next)
+    if (client == cop->client)
+      cop->client = NULL;
 }
 
 
-
-static void handle_start (void *cls,
-                          struct GNUNET_SERVER_Client * client,
-                          const struct GNUNET_MessageHeader * message)
+/**
+ * Add a client to our list of active clients, if it is not yet
+ * in there.
+ *
+ * @param client client to add
+ * @return internal namestore client structure for this client
+ */
+static struct NamestoreClient *
+client_lookup (struct GNUNET_SERVER_Client *client)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
+  struct NamestoreClient *nc;
 
-  struct GNUNET_NAMESTORE_Client * nc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Client));
+  nc = GNUNET_SERVER_client_get_user_context (client, struct NamestoreClient);
+  if (NULL != nc)
+    return nc;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Client %p connected\n",
+             client);
+  nc = GNUNET_new (struct NamestoreClient);
   nc->client = client;
   GNUNET_SERVER_notification_context_add (snc, client);
-  GNUNET_CONTAINER_DLL_insert(client_head, client_tail, nc);
-  GNUNET_SERVER_client_keep (client);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
+  GNUNET_SERVER_client_set_user_context (client, nc);
+  return nc;
 }
 
-struct LookupNameContext
-{
-  struct GNUNET_NAMESTORE_Client *nc;
-  uint32_t request_id;
-  uint32_t record_type;
-  struct GNUNET_CRYPTO_ShortHashCode *zone;
-  char * name;
-};
 
-void drop_iterator (void *cls,
-                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
-                   struct GNUNET_TIME_Absolute expire,
-                   const char *name,
-                   unsigned int rd_len,
-                   const struct GNUNET_NAMESTORE_RecordData *rd,
-                   const struct GNUNET_CRYPTO_RsaSignature *signature)
+static void lookup_nick_it (void *cls,
+     const struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key,
+     const char *label,
+     unsigned int rd_count,
+     const struct GNUNET_GNSRECORD_Data *rd)
 {
-  struct GNUNET_CRYPTO_ShortHashCode zone_hash;
-  int * stop = cls;
-  if (NULL != zone_key)
+  struct GNUNET_GNSRECORD_Data **res = (cls);
+
+  int c;
+  if (0 != strcmp (label, GNUNET_GNS_MASTERZONE_STR))
   {
-    GNUNET_CRYPTO_short_hash(zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_hash);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting zone `%s'\n", GNUNET_short_h2s (&zone_hash));
-    GSN_database->delete_zone (GSN_database->cls, &zone_hash);
+    GNUNET_break (0);
+    return;
   }
-  else
+  for (c = 0; c < rd_count; c++)
   {
-    (*stop) = GNUNET_YES;
+    if (GNUNET_GNSRECORD_TYPE_NICK == rd[c].record_type)
+    {
+      (*res) = GNUNET_malloc (rd[c].data_size + sizeof (struct GNUNET_GNSRECORD_Data));
+      (*res)->data = &(*res)[1];
+      memcpy ((char *)(*res)->data, rd[c].data, rd[c].data_size);
+      (*res)->data_size = rd[c].data_size;
+      (*res)->expiration_time = rd[c].expiration_time;
+      (*res)->flags = rd[c].flags;
+      (*res)->record_type = GNUNET_GNSRECORD_TYPE_NICK;
+      return;
+    }
   }
+  (*res) = NULL;
 }
 
 
-static void
-handle_lookup_name_it (void *cls,
-    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
-    struct GNUNET_TIME_Absolute expire,
-    const char *name,
-    unsigned int rd_count,
-    const struct GNUNET_NAMESTORE_RecordData *rd,
-    const struct GNUNET_CRYPTO_RsaSignature *signature)
+static struct GNUNET_GNSRECORD_Data *
+get_nick_record (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone)
 {
-  /* send response */
-  struct LookupNameContext *lnc = cls;
-  struct LookupNameResponseMessage *lnr_msg;
-  struct GNUNET_NAMESTORE_RecordData *rd_selected = NULL;
-  struct GNUNET_NAMESTORE_CryptoContainer *cc;
-  struct GNUNET_CRYPTO_RsaSignature *signature_new = NULL;
-  struct GNUNET_TIME_Absolute e;
-  struct GNUNET_CRYPTO_ShortHashCode zone_key_hash;
-  struct GNUNET_HashCode long_hash;
-  char *rd_tmp;
-  char *name_tmp;
-  size_t rd_ser_len;
-  size_t r_size = 0;
-  size_t name_len = 0;
-
-  int copied_elements = 0;
-  int contains_signature = GNUNET_NO;
-  int authoritative = GNUNET_NO;
-  int c;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
+  struct GNUNET_GNSRECORD_Data *nick;
+  int res;
 
-  if (NULL != name)
-    name_len = strlen(name) + 1;
+  res = GSN_database->lookup_records (GSN_database->cls, zone,
+      GNUNET_GNS_MASTERZONE_STR, &lookup_nick_it, &nick);
 
-  /* count records to copy */
-  if (rd_count != 0)
-  {
-    if (lnc->record_type != 0)
-    {
-      /* special record type needed */
-      for (c = 0; c < rd_count; c ++)
-        if (rd[c].record_type == lnc->record_type)
-          copied_elements++; /* found matching record */
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u records with type %u for name `%s' in zone `%s'\n",
-          copied_elements, lnc->record_type, lnc->name, GNUNET_short_h2s(lnc->zone));
-      rd_selected = GNUNET_malloc (copied_elements * sizeof (struct GNUNET_NAMESTORE_RecordData));
-      copied_elements = 0;
-      for (c = 0; c < rd_count; c ++)
-      {
-        if (rd[c].record_type == lnc->record_type)
-        {
-          /* found matching record */
-          memcpy (&rd_selected[copied_elements], &rd[c], sizeof (struct GNUNET_NAMESTORE_RecordData));
-          copied_elements++;
-        }
-      }
-    }
-    else
-    {
-      copied_elements = rd_count;
-      rd_selected = (struct GNUNET_NAMESTORE_RecordData *) rd;
-    }
-  }
-  else
+  if ((NULL == nick) || (GNUNET_OK != res))
   {
-    /* No results */
-    copied_elements = 0;
-    rd_selected = NULL;
-    expire = GNUNET_TIME_UNIT_ZERO_ABS;
+    GNUNET_CRYPTO_ecdsa_key_get_public (zone, &pub);
+    GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "No nick name set for zone `%s'\n",
+        GNUNET_CRYPTO_ecdsa_public_key_to_string (&pub));
+    return NULL;
   }
 
-  rd_ser_len = GNUNET_NAMESTORE_records_get_size(copied_elements, rd_selected);
-  char rd_ser[rd_ser_len];
-  GNUNET_NAMESTORE_records_serialize(copied_elements, rd_selected, rd_ser_len, rd_ser);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u records for name `%s' in zone `%s'\n",
-      copied_elements, lnc->name, GNUNET_short_h2s(lnc->zone));
+  return nick;
+}
 
-  if ((copied_elements == rd_count) && (NULL != signature))
-    contains_signature = GNUNET_YES; /* returning all records, so include signature */
-  else
-    contains_signature = GNUNET_NO; /* returning not all records, so do not include signature */
 
+static void merge_records (unsigned int rdc1,
+                           const struct GNUNET_GNSRECORD_Data *rd1,
+                           unsigned int rdc2,
+                           const struct GNUNET_GNSRECORD_Data *rd2,
+                           unsigned int *rdc_res,
+                           struct GNUNET_GNSRECORD_Data **rd_res)
+{
+  int c;
+  size_t req;
+  char *data;
+  int record_offset;
+  size_t data_offset;
+  (*rdc_res) = rdc1 + rdc2;
 
-  if ((NULL != zone_key) && (copied_elements == rd_count))
+  if (0 == rdc1 + rdc2)
   {
-    GNUNET_CRYPTO_short_hash(zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone_key_hash);
-    GNUNET_CRYPTO_short_hash_double (&zone_key_hash, &long_hash);
-    if (GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
-    {
-      cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash);
-      e = get_block_expiration_time(rd_count, rd);
-      signature_new = GNUNET_NAMESTORE_create_signature(cc->privkey, e, name, rd, rd_count);
-      GNUNET_assert (signature_new != NULL);
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating signature for name `%s' with %u records in zone `%s'\n",name, copied_elements, GNUNET_short_h2s(&zone_key_hash));
-      authoritative = GNUNET_YES;
-    }
-    else
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "I am not authoritative for name `%s' in zone `%s'\n",name, GNUNET_short_h2s(&zone_key_hash));
+    (*rd_res) = NULL;
+    return;
   }
 
-  r_size = sizeof (struct LookupNameResponseMessage) +
-           sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
-           name_len +
-           rd_ser_len;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "NAMESTORE_LOOKUP_NAME_RESPONSE");
-  lnr_msg = GNUNET_malloc (r_size);
-  lnr_msg->gns_header.header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
-  lnr_msg->gns_header.header.size = ntohs (r_size);
-  lnr_msg->gns_header.r_id = htonl (lnc->request_id);
-  lnr_msg->rd_count = htons (copied_elements);
-  lnr_msg->rd_len = htons (rd_ser_len);
-  lnr_msg->name_len = htons (name_len);
-  lnr_msg->expire = GNUNET_TIME_absolute_hton(get_block_expiration_time(copied_elements, rd_selected));
-
-  if (rd_selected != rd)
-    GNUNET_free (rd_selected);
-
-  if (zone_key != NULL)
-    lnr_msg->public_key = (*zone_key);
-  else
-    memset(&lnr_msg->public_key, '\0', sizeof (lnr_msg->public_key));
-
-  if (GNUNET_YES == authoritative)
-  { /* use new created signature */
-    lnr_msg->contains_sig = htons (GNUNET_YES);
-    GNUNET_assert (signature_new != NULL);
-    lnr_msg->signature = *signature_new;
-    GNUNET_free (signature_new);
-  }
-  else if (GNUNET_YES == contains_signature)
+  req = 0;
+  for (c=0; c< rdc1; c++)
+    req += sizeof (struct GNUNET_GNSRECORD_Data) + rd1[c].data_size;
+  for (c=0; c< rdc2; c++)
+    req += sizeof (struct GNUNET_GNSRECORD_Data) + rd2[c].data_size;
+  (*rd_res) = GNUNET_malloc (req);
+  data = (char *) &(*rd_res)[rdc1 + rdc2];
+  data_offset = 0;
+
+  for (c=0; c< rdc1; c++)
   {
-    /* use existing signature */
-    lnr_msg->contains_sig = htons (GNUNET_YES);
-    GNUNET_assert (signature != NULL);
-    lnr_msg->signature = *signature;
+    (*rd_res)[c] = rd1[c];
+    (*rd_res)[c].data = (void *) &data[data_offset];
+    memcpy ((void *) (*rd_res)[c].data, rd1[c].data, rd1[c].data_size);
+    data_offset += (*rd_res)[c].data_size;
   }
-  else
+  record_offset = rdc1;
+  for (c=0; c< rdc2; c++)
   {
-    /* use no signature */
-    memset (&lnr_msg->signature, '\0', sizeof (lnr_msg->signature));
+    (*rd_res)[c+record_offset] = rd2[c];
+    (*rd_res)[c+record_offset].data = (void *) &data[data_offset];
+    memcpy ((void *) (*rd_res)[c+record_offset].data, rd2[c].data, rd2[c].data_size);
+    data_offset += (*rd_res)[c+record_offset].data_size;
   }
+  GNUNET_assert (req == (sizeof (struct GNUNET_GNSRECORD_Data)) * (*rdc_res) + data_offset);
+}
 
-  name_tmp = (char *) &lnr_msg[1];
-  rd_tmp = &name_tmp[name_len];
-
-  memcpy (name_tmp, name, name_len);
-  memcpy (rd_tmp, rd_ser, rd_ser_len);
 
-  GNUNET_SERVER_notification_context_unicast (snc, lnc->nc->client, (const struct GNUNET_MessageHeader *) lnr_msg, GNUNET_NO);
-  GNUNET_free (lnr_msg);
-}
 
-static void handle_lookup_name (void *cls,
-                          struct GNUNET_SERVER_Client * client,
-                          const struct GNUNET_MessageHeader * message)
+/**
+ * Generate a 'struct LookupNameResponseMessage' and send it to the
+ * given client using the given notification context.
+ *
+ * @param nc notification context to use
+ * @param client 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 GNUNET_SERVER_NotificationContext *nc,
+                     struct GNUNET_SERVER_Client *client,
+                     uint32_t request_id,
+                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+                     const char *name,
+                     unsigned int rd_count,
+                     const struct GNUNET_GNSRECORD_Data *rd)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_LOOKUP_NAME");
-  struct LookupNameContext lnc;
-  struct GNUNET_NAMESTORE_Client *nc;
+  struct RecordResultMessage *zir_msg;
+  struct GNUNET_GNSRECORD_Data *nick;
+  struct GNUNET_GNSRECORD_Data *res;
+  unsigned int res_count;
   size_t name_len;
-  char * name;
-  uint32_t rid = 0;
-  uint32_t type = 0;
+  size_t rd_ser_len;
+  size_t msg_size;
+  char *name_tmp;
+  char *rd_ser;
 
-  if (ntohs (message->size) < sizeof (struct LookupNameMessage))
+  nick = get_nick_record (zone_key);
+  if ((NULL != nick) && (0 != strcmp(name, GNUNET_GNS_MASTERZONE_STR)))
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
+    nick->flags = (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
+    merge_records (rd_count,rd, 1, nick, &res_count, &res);
+    GNUNET_free (nick);
   }
-
-  nc = client_lookup(client);
-  if (nc == NULL)
+  else
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
+    res_count = rd_count;
+    res = (struct GNUNET_GNSRECORD_Data *) rd;
+  }
+
+  name_len = strlen (name) + 1;
+  rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count, res);
+  msg_size = sizeof (struct RecordResultMessage) + name_len + rd_ser_len;
+  (void) client_lookup (client);
+  zir_msg = GNUNET_malloc (msg_size);
+  zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
+  zir_msg->gns_header.header.size = htons (msg_size);
+  zir_msg->gns_header.r_id = htonl (request_id);
+  zir_msg->name_len = htons (name_len);
+  zir_msg->rd_count = htons (res_count);
+  zir_msg->rd_len = htons (rd_ser_len);
+  zir_msg->private_key = *zone_key;
+  name_tmp = (char *) &zir_msg[1];
+  memcpy (name_tmp, name, name_len);
+  rd_ser = &name_tmp[name_len];
+  GNUNET_GNSRECORD_records_serialize (res_count, res, rd_ser_len, rd_ser);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Sending `%s' message with %u records and size %u\n",
+             "RECORD_RESULT",
+             rd_count,
+             msg_size);
+  GNUNET_SERVER_notification_context_unicast (nc,
+                                             client,
+                                             &zir_msg->gns_header.header,
+                                             GNUNET_NO);
+  if (rd != res)
+    GNUNET_free (res);
+  GNUNET_free (zir_msg);
+}
 
-  struct LookupNameMessage * ln_msg = (struct LookupNameMessage *) message;
-  rid = ntohl (ln_msg->gns_header.r_id);
-  name_len = ntohl (ln_msg->name_len);
-  type = ntohl (ln_msg->record_type);
 
-  if ((name_len == 0) || (name_len > 256))
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
+/**
+ * Send response to the store request to the client.
+ *
+ * @param client client to talk to
+ * @param res status of the operation
+ * @param rid client's request ID
+ */
+static void
+send_store_response (struct GNUNET_SERVER_Client *client,
+                     int res,
+                     uint32_t rid)
+{
+  struct RecordStoreResponseMessage rcr_msg;
 
-  name = (char *) &ln_msg[1];
-  if (name[name_len -1] != '\0')
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Sending `%s' message\n",
+             "RECORD_STORE_RESPONSE");
+  rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE);
+  rcr_msg.gns_header.header.size = htons (sizeof (struct RecordStoreResponseMessage));
+  rcr_msg.gns_header.r_id = htonl (rid);
+  rcr_msg.op_result = htonl (res);
+  GNUNET_SERVER_notification_context_unicast (snc, client,
+                                             &rcr_msg.gns_header.header,
+                                             GNUNET_NO);
+}
+
+
+/**
+ * Cache operation complete, clean up.
+ *
+ * @param cls the `struct CacheOperation`
+ * @param success success
+ * @param emsg error messages
+ */
+static void
+finish_cache_operation (void *cls,
+                        int32_t success,
+                        const char *emsg)
+{
+  struct CacheOperation *cop = cls;
 
-  if (0 == type)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking up all records for name `%s' in zone `%s'\n", name, GNUNET_short_h2s(&ln_msg->zone));
+  if (NULL != emsg)
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                _("Failed to replicate block in namecache: %s\n"),
+                emsg);
   else
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking up records with type %u for name `%s' in zone `%s'\n", type, name, GNUNET_short_h2s(&ln_msg->zone));
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "CACHE operation completed\n");
+  GNUNET_CONTAINER_DLL_remove (cop_head,
+                               cop_tail,
+                               cop);
+  if (NULL != cop->client)
+    send_store_response (cop->client,
+                         success,
+                         cop->rid);
+  GNUNET_free (cop);
+}
 
-  /* do the actual lookup */
-  lnc.request_id = rid;
-  lnc.nc = nc;
-  lnc.record_type = type;
-  lnc.name = name;
-  lnc.zone = &ln_msg->zone;
-  GSN_database->iterate_records(GSN_database->cls, &ln_msg->zone, name, 0, &handle_lookup_name_it, &lnc);
 
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+/**
+ * We just touched the plaintext information about a name in our zone;
+ * refresh the corresponding (encrypted) block in the namestore.
+ *
+ * @param client client responsible for the request
+ * @param rid request ID of the client
+ * @param zone_key private key of the zone
+ * @param name label for the records
+ * @param rd_count number of records
+ * @param rd records stored under the given @a name
+ */
+static void
+refresh_block (struct GNUNET_SERVER_Client *client,
+               uint32_t rid,
+               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+               const char *name,
+               unsigned int rd_count,
+               const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct GNUNET_GNSRECORD_Block *block;
+  struct CacheOperation *cop;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
+
+  if (0 == rd_count)
+    block = GNUNET_GNSRECORD_block_create (zone_key,
+                                           GNUNET_TIME_UNIT_ZERO_ABS,
+                                           name,
+                                           rd, rd_count);
+  else
+    block = GNUNET_GNSRECORD_block_create (zone_key,
+                                           GNUNET_GNSRECORD_record_get_expiration_time (rd_count,
+                                                                                        rd),
+                                           name,
+                                           rd, rd_count);
+  GNUNET_assert (NULL != block);
+  GNUNET_CRYPTO_ecdsa_key_get_public (zone_key,
+                                      &pkey);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Caching block for label `%s' in zone `%s' in namecache\n",
+              name,
+              GNUNET_GNSRECORD_z2s (&pkey));
+  cop = GNUNET_new (struct CacheOperation);
+  cop->client = client;
+  cop->rid = rid;
+  GNUNET_CONTAINER_DLL_insert (cop_head,
+                               cop_tail,
+                               cop);
+  cop->qe = GNUNET_NAMECACHE_block_cache (namecache,
+                                          block,
+                                          &finish_cache_operation,
+                                          cop);
+  GNUNET_free (block);
 }
 
-static void handle_record_put (void *cls,
-                          struct GNUNET_SERVER_Client * client,
-                          const struct GNUNET_MessageHeader * message)
+
+struct RecordLookupContext
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_PUT");
-  struct GNUNET_NAMESTORE_Client *nc;
-  struct GNUNET_TIME_Absolute expire;
-  struct GNUNET_CRYPTO_RsaSignature *signature;
-  struct RecordPutResponseMessage rpr_msg;
-  size_t name_len;
-  size_t msg_size;
-  size_t msg_size_exp;
-  char * name;
-  char * rd_ser;
-  uint32_t rid = 0;
-  uint32_t rd_ser_len;
-  uint32_t rd_count;
-  int res = GNUNET_SYSERR;
-
-  if (ntohs (message->size) < sizeof (struct RecordPutMessage))
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
+  const char *label;
 
-  nc = client_lookup (client);
-  if (nc == NULL)
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  struct RecordPutMessage * rp_msg = (struct RecordPutMessage *) message;
-
-  rid = ntohl (rp_msg->gns_header.r_id);
-  msg_size = ntohs (rp_msg->gns_header.header.size);
-  name_len = ntohs (rp_msg->name_len);
-  rd_count = ntohs (rp_msg->rd_count);
-  rd_ser_len = ntohs(rp_msg->rd_len);
-
-  if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  if ((rd_count < 1) || (rd_ser_len < 1) || (name_len >=256) || (name_len == 0))
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  msg_size_exp = sizeof (struct RecordPutMessage) +  name_len  + rd_ser_len;
-  if (msg_size != msg_size_exp)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expected message %u size but message size is %u \n", msg_size_exp, msg_size);
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-  if ((name_len == 0) || (name_len > 256))
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  name = (char *) &rp_msg[1];
-
-  if (name[name_len -1] != '\0')
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  expire = GNUNET_TIME_absolute_ntoh(rp_msg->expire);
-  signature = (struct GNUNET_CRYPTO_RsaSignature *) &rp_msg->signature;
-
-  rd_ser = &name[name_len];
-  struct GNUNET_NAMESTORE_RecordData rd[rd_count];
-  res = GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_ser, rd_count, rd);
-  if (res != GNUNET_OK)
-  {
-    GNUNET_break_op (0);
-    goto send;
-  }
-
-  struct GNUNET_CRYPTO_ShortHashCode zone_hash;
-  GNUNET_CRYPTO_short_hash (&rp_msg->public_key, sizeof (rp_msg->public_key), &zone_hash);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting %u record for name `%s' in zone `%s'\n", rd_count, name, GNUNET_short_h2s(&zone_hash));
-
-  /* Database operation */
-  res = GSN_database->put_records(GSN_database->cls,
-                                &rp_msg->public_key,
-                                expire,
-                                name,
-                                rd_count, rd,
-                                signature);
+  int found;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting record for name `%s': %s\n",
-      name, (res == GNUNET_OK) ? "OK" : "FAIL");
+  unsigned int res_rd_count;
 
-  /* Send response */
-send:
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "RECORD_PUT_RESPONSE");
-  rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE);
-  rpr_msg.gns_header.header.size = htons (sizeof (struct RecordPutResponseMessage));
-  rpr_msg.gns_header.r_id = htonl (rid);
-  rpr_msg.op_result = htonl (res);
-  GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &rpr_msg, GNUNET_NO);
+  size_t rd_ser_len;
 
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
+  char *res_rd;
 
-struct CreateRecordContext
-{
-  struct GNUNET_NAMESTORE_RecordData *rd;
-  struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey;
-  struct GNUNET_TIME_Absolute expire;
-  char *name;
-  int res;
+  struct GNUNET_GNSRECORD_Data *nick;
 };
 
 
+
 static void
-handle_create_record_it (void *cls,
-                        const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey,
-                        struct GNUNET_TIME_Absolute expire,
-                        const char *name,
-                        unsigned int rd_count,
-                        const struct GNUNET_NAMESTORE_RecordData *rd,
-                        const struct GNUNET_CRYPTO_RsaSignature *signature)
+lookup_it (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key,
+    const char *label, unsigned int rd_count,
+    const struct GNUNET_GNSRECORD_Data *rd)
 {
-  struct CreateRecordContext * crc = cls;
-  struct GNUNET_NAMESTORE_RecordData *rd_new = NULL;
-  struct GNUNET_CRYPTO_RsaSignature dummy_signature;
-  struct GNUNET_TIME_Absolute block_expiration;
-  int res;
-  int exist = GNUNET_SYSERR;
-  int update = GNUNET_NO;
-  int c;
-  int rd_count_new = 0;
+  struct RecordLookupContext *rlc = cls;
+  struct GNUNET_GNSRECORD_Data *rd_res;
+  unsigned int rdc_res;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u existing records for `%s'\n", rd_count, crc->name);
-  for (c = 0; c < rd_count; c++)
+  if (0 == strcmp (label, rlc->label))
   {
-    if ( (crc->rd->record_type == GNUNET_NAMESTORE_TYPE_PKEY) && 
-        (rd[c].record_type == GNUNET_NAMESTORE_TYPE_PKEY))
-    {
-      /* Update unique PKEY */
-      exist = c;
-      update = GNUNET_YES;
-      break;
-    }
-    if ( (crc->rd->record_type == GNUNET_NAMESTORE_TYPE_PSEU) && 
-        (rd[c].record_type == GNUNET_NAMESTORE_TYPE_PSEU))
-    {
-      /* Update unique PSEU */
-      exist = c;
-      update = GNUNET_YES;
-      break;
-    }
-    if ((crc->rd->record_type == rd[c].record_type) &&
-       (crc->rd->data_size == rd[c].data_size) &&
-       (0 == memcmp (crc->rd->data, rd[c].data, rd[c].data_size)))
+    rlc->found = GNUNET_YES;
+    if (0 != rd_count)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-                 "Found existing records for `%s' to update expiration date!\n",
-                 crc->name);
-      exist = c;
-      if ( (crc->rd->expiration_time != rd[c].expiration_time) &&
-          ((crc->rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) 
-           == (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) ) )
-        update = GNUNET_YES;
-      break;
-    }
-  }
-
-  if (exist == GNUNET_SYSERR)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-               "No existing record for name `%s'!\n", 
-               crc->name);
-    rd_new = GNUNET_malloc ((rd_count+1) * sizeof (struct GNUNET_NAMESTORE_RecordData));
-    memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
-    rd_count_new = rd_count + 1;
-    rd_new[rd_count] = *(crc->rd);
-  }
-  else if (update == GNUNET_NO)
-  {
-    /* Exact same record already exists */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-               "Matching record for %s' exists, no change required!\n",
-               crc->name);
-    res = GNUNET_NO;
-    goto end;
-  }
-  else 
-  {
-    /* Update record */
-    GNUNET_assert (GNUNET_YES == update);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-               "Updating existing records for `%s'!\n", 
-               crc->name);
-    rd_new = GNUNET_malloc ((rd_count) * sizeof (struct GNUNET_NAMESTORE_RecordData));
-    memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
-    rd_count_new = rd_count;
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-               (0 == (crc->rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) 
-               ? "Updating absolute expiration from %llu to %llu!\n"
-               : "Updating relative expiration from %llu to %llu!\n", 
-               rd_new[exist].expiration_time, crc->rd->expiration_time);
-    rd_new[exist] = *(crc->rd);
-  }
-
-  block_expiration = GNUNET_TIME_absolute_max(crc->expire, expire);
-  if (block_expiration.abs_value != expire.abs_value)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-               "Updated block expiration time\n");
-
-  memset (&dummy_signature, '\0', sizeof (dummy_signature));
-
-  /* Database operation */
-  GNUNET_assert ((rd_new != NULL) && (rd_count_new > 0));
-  res = GSN_database->put_records(GSN_database->cls,
-                                (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *) crc->pubkey,
-                                block_expiration,
-                                crc->name,
-                                rd_count_new, rd_new,
-                                &dummy_signature);
-  GNUNET_break (GNUNET_OK == res);
-  if (res == GNUNET_OK)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully put record for `%s' in database \n", crc->name);
-  else
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to put record for `%s' in database \n", crc->name);
-  res = GNUNET_YES;
-
-end:
-  GNUNET_free_non_null (rd_new);
-
-  switch (res) {
-    case GNUNET_SYSERR:
-       /* failed to create the record */
-       crc->res = GNUNET_SYSERR;
-      break;
-    case GNUNET_YES:
-      /* database operations OK */
-      if (GNUNET_YES == update)
+      if ((NULL != rlc->nick) && (0 != strcmp(label, GNUNET_GNS_MASTERZONE_STR)))
       {
-        /* we updated an existing record */
-        crc->res = GNUNET_NO;
+        /* Merge */
+        rd_res = NULL;
+        rdc_res = 0;
+        rlc->nick->flags = (rlc->nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
+        merge_records (rd_count, rd,
+                       1, rlc->nick,
+                       &rdc_res, &rd_res);
+
+        rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rdc_res, rd_res);
+        rlc->res_rd_count = rdc_res;
+        rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
+        GNUNET_GNSRECORD_records_serialize (rdc_res, rd_res, rlc->rd_ser_len , rlc->res_rd);
+
+        GNUNET_free  (rd_res);
+        GNUNET_free  (rlc->nick);
+        rlc->nick = NULL;
       }
       else
       {
-        /* we created a new record */
-        crc->res = GNUNET_YES;
+        rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
+        rlc->res_rd_count = rd_count;
+        rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
+        GNUNET_GNSRECORD_records_serialize (rd_count, rd, rlc->rd_ser_len , rlc->res_rd);
       }
-      break;
-    case GNUNET_NO:
-        /* identical entry existed, so we did nothing */
-        crc->res = GNUNET_NO;
-      break;
-    default:
-      break;
+    }
+    else
+    {
+      rlc->rd_ser_len = 0;
+      rlc->res_rd_count = 0;
+      rlc->res_rd = NULL;
+    }
   }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Update result for name `%s' %u\n", crc->name, res);
-
 }
 
-static void handle_record_create (void *cls,
-                          struct GNUNET_SERVER_Client * client,
-                          const struct GNUNET_MessageHeader * message)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_CREATE");
-  struct GNUNET_NAMESTORE_Client *nc;
-  struct GNUNET_NAMESTORE_CryptoContainer *cc;
-  struct CreateRecordContext crc;
-  struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
-  struct RecordCreateResponseMessage rcr_msg;
-  struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
-  struct GNUNET_HashCode long_hash;
-  size_t name_len;
-  size_t msg_size;
-  size_t msg_size_exp;
-  size_t rd_ser_len;
-  size_t key_len;
-  uint32_t rid = 0;
-  char *pkey_tmp;
-  char *name_tmp;
-  char *rd_ser;
-  int rd_count;
-
-  int res = GNUNET_SYSERR;
-  crc.res = GNUNET_SYSERR;
-
-  if (ntohs (message->size) < sizeof (struct RecordCreateMessage))
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  nc = client_lookup(client);
-  if (nc == NULL)
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  struct RecordCreateMessage * rp_msg = (struct RecordCreateMessage *) message;
-  rid = ntohl (rp_msg->gns_header.r_id);
-  name_len = ntohs (rp_msg->name_len);
-  msg_size = ntohs (message->size);
-  rd_count = ntohs (rp_msg->rd_count);
-  rd_ser_len = ntohs (rp_msg->rd_len);
-  key_len = ntohs (rp_msg->pkey_len);
-  msg_size_exp = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len;
-
-  if (msg_size != msg_size_exp)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expected message %u size but message size is %u \n", msg_size_exp, msg_size);
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  if ((name_len == 0) || (name_len > 256))
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  pkey_tmp = (char *) &rp_msg[1];
-  name_tmp = &pkey_tmp[key_len];
-  rd_ser = &name_tmp[name_len];
-
-  if (name_tmp[name_len -1] != '\0')
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  struct GNUNET_NAMESTORE_RecordData rd[rd_count];
-
-  res = GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_ser, rd_count, rd);
-  if ((res != GNUNET_OK) || (rd_count != 1))
-  {
-    GNUNET_break_op (0);
-    goto send;
-  }
-  /* Extracting and converting private key */
-  pkey = GNUNET_CRYPTO_rsa_decode_key((char *) pkey_tmp, key_len);
-  GNUNET_assert (pkey != NULL);
-  GNUNET_CRYPTO_rsa_key_get_public(pkey, &pub);
-  GNUNET_CRYPTO_short_hash (&pub, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pubkey_hash);
-  GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
-
-  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received new private key for zone `%s'\n",GNUNET_short_h2s(&pubkey_hash));
-
-    cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
-    cc->privkey = GNUNET_CRYPTO_rsa_decode_key((char *) pkey_tmp, key_len);
-    cc->pubkey = GNUNET_malloc(sizeof (pub));
-    memcpy (cc->pubkey, &pub, sizeof(pub));
-    cc->zone = pubkey_hash;
-    GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-  }
-
-  crc.expire = GNUNET_TIME_absolute_ntoh(rp_msg->expire);
-  crc.res = GNUNET_SYSERR;
-  crc.pkey = pkey;
-  crc.pubkey = &pub;
-  crc.rd = rd;
-  crc.name = name_tmp;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating record for name `%s' in zone `%s'\n", name_tmp, GNUNET_short_h2s(&pubkey_hash));
-
-  /* Get existing records for name */
-  res = GSN_database->iterate_records(GSN_database->cls, &pubkey_hash, name_tmp, 0, &handle_create_record_it, &crc);
-  if (res != GNUNET_SYSERR)
-    res = GNUNET_OK;
-  GNUNET_CRYPTO_rsa_key_free(pkey);
-  pkey = NULL;
-
-  /* Send response */
-send:
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "RECORD_CREATE_RESPONSE");
-  rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE);
-  rcr_msg.gns_header.header.size = htons (sizeof (struct RecordCreateResponseMessage));
-  rcr_msg.gns_header.r_id = htonl (rid);
-  if ((GNUNET_OK == res) && (crc.res == GNUNET_YES))
-    rcr_msg.op_result = htonl (GNUNET_YES);
-  else if ((GNUNET_OK == res) && (crc.res == GNUNET_NO))
-    rcr_msg.op_result = htonl (GNUNET_NO);
-  else
-    rcr_msg.op_result = htonl (GNUNET_SYSERR);
-  GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &rcr_msg, GNUNET_NO);
 
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
 
 
-struct RemoveRecordContext
-{
-  struct GNUNET_NAMESTORE_RecordData *rd;
-  struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
-  int remove_name;
-  uint16_t op_res;
-};
 
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
+ *
+ * @param cls unused
+ * @param client client sending the message
+ * @param message message of type 'struct RecordCreateMessage'
+ */
 static void
-handle_record_remove_it (void *cls,
-    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
-    struct GNUNET_TIME_Absolute expire,
-    const char *name,
-    unsigned int rd_count,
-    const struct GNUNET_NAMESTORE_RecordData *rd,
-    const struct GNUNET_CRYPTO_RsaSignature *signature)
+handle_record_lookup (void *cls,
+                     struct GNUNET_SERVER_Client *client,
+                     const struct GNUNET_MessageHeader *message)
 {
-  struct RemoveRecordContext *rrc = cls;
-  unsigned int c;
+  const struct LabelLookupMessage *ll_msg;
+  struct LabelLookupResponseMessage *llr_msg;
+  struct RecordLookupContext rlc;
+  const char *name_tmp;
+  char *res_name;
+  uint32_t name_len;
+  size_t src_size;
+  size_t res_size;
   int res;
-  int found;
-  unsigned int rd_count_new;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name `%s 'currently has %u records\n", name, rd_count);
 
-  if (rd_count == 0)
+  if (ntohs (message->size) < sizeof (struct LabelLookupMessage))
   {
-    /* Could not find record to remove */
-    rrc->op_res = 1;
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
 
-  /* Find record to remove */
-  found = GNUNET_SYSERR;
-  for (c = 0; c < rd_count; c++)
-  {
-    /*
-    if (rd[c].flags != rrc->rd->flags)
-       continue;*/
-    if (rd[c].record_type != rrc->rd->record_type)
-       continue;
-    /*
-    if (rd[c].data_size != rrc->rd->data_size)
-       continue;
-    GNUNET_break(0);
-    if (0 != memcmp (rd[c].data, rrc->rd->data, rrc->rd->data_size))
-        continue;
-    GNUNET_break(0); */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found record to remove!\n", rd_count);
-    found = c;
-    break;
-  }
-  if (GNUNET_SYSERR == found)
+  ll_msg = (const struct LabelLookupMessage *) message;
+  name_len = ntohl (ll_msg->label_len);
+  src_size = ntohs (message->size);
+
+  if (name_len !=  src_size - sizeof (struct LabelLookupMessage))
   {
-    /* Could not find record to remove */
-    rrc->op_res = 2;
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
 
-  if (rd_count-1 == 0)
+  name_tmp = (const char *) &ll_msg[1];
+  if ('\0' != name_tmp[name_len -1])
   {
-    struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
-    GNUNET_CRYPTO_short_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pubkey_hash);
-    res = GSN_database->remove_records (GSN_database->cls,
-                                        &pubkey_hash,
-                                        name);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "No records left for name `%s', removing name\n",
-                name, res);
-    if (GNUNET_OK != res)
-    {
-      /* Could put records into database */
-      rrc->op_res = 4;
-      return;
-    }
-    rrc->op_res = 0;
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
 
-  rd_count_new = rd_count -1;
-  struct GNUNET_NAMESTORE_RecordData rd_new[rd_count_new];
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received `%s' message for name `%s'\n",
+              "NAMESTORE_RECORD_LOOKUP", name_tmp);
 
-  unsigned int c2 = 0;
-  for (c = 0; c < rd_count; c++)
+  if (NULL == (client_lookup (client)))
   {
-    if (c != found)
-    {
-      GNUNET_assert (c2 < rd_count_new);
-      rd_new[c2] = rd[c];
-      c2++;
-    }
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
   }
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name `%s' now has %u records\n", name, rd_count_new);
-
-  /* Create dummy signature */
-  struct GNUNET_CRYPTO_RsaSignature dummy_signature;
-  memset (&dummy_signature, '\0', sizeof (dummy_signature));
-
+  rlc.label = name_tmp;
+  rlc.found = GNUNET_NO;
+  rlc.res_rd_count = 0;
+  rlc.res_rd = NULL;
+  rlc.rd_ser_len = 0;
+  rlc.nick = get_nick_record (&ll_msg->zone);
+
+  res = GSN_database->lookup_records (GSN_database->cls,
+        &ll_msg->zone, name_tmp, &lookup_it, &rlc);
+
+  res_size = sizeof (struct LabelLookupResponseMessage) + name_len + rlc.rd_ser_len;
+  llr_msg = GNUNET_malloc (res_size);
+  llr_msg->gns_header.header.size = htons (res_size);
+  llr_msg->gns_header.header.type = htons (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 (rlc.res_rd_count);
+  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);
+  else
+    llr_msg->found = ntohs (GNUNET_NO);
+  memcpy (&llr_msg[1], name_tmp, name_len);
+  memcpy (&res_name[name_len], rlc.res_rd, rlc.rd_ser_len);
 
-  /* Put records */
-  res = GSN_database->put_records(GSN_database->cls,
-                                  zone_key,
-                                  expire,
-                                  name,
-                                  rd_count_new, rd_new,
-                                  &dummy_signature);
-  if (GNUNET_OK != res)
-  {
-    /* Could put records into database */
-    rrc->op_res = 4;
-    return;
-  }
+  GNUNET_SERVER_notification_context_unicast (snc, client, &llr_msg->gns_header.header,
+      GNUNET_NO);
 
-  rrc->op_res = 0;
+  GNUNET_free_non_null (rlc.res_rd);
+  GNUNET_free (llr_msg);
 }
 
 
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
+ *
+ * @param cls unused
+ * @param client client sending the message
+ * @param message message of type 'struct RecordCreateMessage'
+ */
 static void
-handle_record_remove (void *cls,
-                     struct GNUNET_SERVER_Client * client,
-                     const struct GNUNET_MessageHeader * message)
+handle_record_store (void *cls,
+                     struct GNUNET_SERVER_Client *client,
+                     const struct GNUNET_MessageHeader *message)
 {
-  struct GNUNET_NAMESTORE_Client *nc;
-  const struct RecordRemoveMessage * rr_msg;
-  struct RecordRemoveResponseMessage rrr_msg;
-  struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
-  struct GNUNET_NAMESTORE_CryptoContainer *cc;
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
-  struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
-  struct GNUNET_HashCode long_hash;
-  const char * pkey_tmp;
-  const char * name_tmp;
-  const char * rd_ser;
-  size_t key_len;
+  const struct RecordStoreMessage *rp_msg;
   size_t name_len;
-  size_t rd_ser_len;
   size_t msg_size;
-  size_t msg_size_exp = 0;
-  uint32_t rd_count;
+  size_t msg_size_exp;
+  size_t rd_ser_len;
   uint32_t rid;
+  const char *name_tmp;
+  char *conv_name;
+  const char *rd_ser;
+  unsigned int rd_count;
+  int res;
+  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
+  struct ZoneMonitor *zm;
 
-  int res = GNUNET_SYSERR;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_REMOVE");
-  if (ntohs (message->size) < sizeof (struct RecordRemoveMessage))
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  nc = client_lookup(client);
-  if (nc == NULL)
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received `%s' message\n",
+             "NAMESTORE_RECORD_STORE");
+  if (ntohs (message->size) < sizeof (struct RecordStoreMessage))
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-
-  rr_msg = (const struct RecordRemoveMessage *) message;
-  rid = ntohl (rr_msg->gns_header.r_id);
-  name_len = ntohs (rr_msg->name_len);
-  rd_ser_len = ntohs (rr_msg->rd_len);
-  rd_count = ntohs (rr_msg->rd_count);
-  key_len = ntohs (rr_msg->pkey_len);
+  rp_msg = (const struct RecordStoreMessage *) message;
+  rid = ntohl (rp_msg->gns_header.r_id);
+  name_len = ntohs (rp_msg->name_len);
   msg_size = ntohs (message->size);
-
-  if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  if ((name_len >=256) || (name_len == 0))
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
-
-  msg_size_exp = sizeof (struct RecordRemoveMessage) + key_len + name_len + rd_ser_len;
+  rd_count = ntohs (rp_msg->rd_count);
+  rd_ser_len = ntohs (rp_msg->rd_len);
+  GNUNET_break (0 == ntohs (rp_msg->reserved));
+  msg_size_exp = sizeof (struct RecordStoreMessage) + name_len + rd_ser_len;
   if (msg_size != msg_size_exp)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Expected message %u size but message size is %u \n", msg_size_exp, msg_size);
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-
-  pkey_tmp = (const char *) &rr_msg[1];
-  name_tmp = &pkey_tmp[key_len];
-  rd_ser = &name_tmp[name_len];
-
-
-  if ((name_len == 0) || (name_len > 256))
+  if ((0 == name_len) || (name_len > MAX_NAME_LEN))
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-
-  if (name_tmp[name_len -1] != '\0')
+  name_tmp = (const char *) &rp_msg[1];
+  rd_ser = &name_tmp[name_len];
+  if ('\0' != name_tmp[name_len -1])
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-
-  /* Extracting and converting private key */
-  pkey = GNUNET_CRYPTO_rsa_decode_key((char *) pkey_tmp, key_len);
-  GNUNET_assert (pkey != NULL);
-  GNUNET_CRYPTO_rsa_key_get_public(pkey, &pub);
-  GNUNET_CRYPTO_short_hash (&pub, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &pubkey_hash);
-  GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
-
-  if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
+  (void) client_lookup (client);
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-               "Received new private key for zone `%s'\n",
-               GNUNET_short_h2s(&pubkey_hash));
-    cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
-    cc->privkey = GNUNET_CRYPTO_rsa_decode_key((char *) pkey_tmp, key_len);
-    cc->pubkey = GNUNET_malloc(sizeof (pub));
-    memcpy (cc->pubkey, &pub, sizeof(pub));
-    cc->zone = pubkey_hash;
-
-    GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-  }
-
+    struct GNUNET_GNSRECORD_Data rd[rd_count];
 
-  struct GNUNET_NAMESTORE_RecordData rd[rd_count];
-  res = GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_ser, rd_count, rd);
-  if ((res != GNUNET_OK) || (rd_count > 1))
-  {
-    GNUNET_break_op (0);
-    goto send;
-  }
+    if (GNUNET_OK !=
+       GNUNET_GNSRECORD_records_deserialize (rd_ser_len, rd_ser, rd_count, rd))
+    {
+      GNUNET_break (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
 
-  if (0 == rd_count)
-  {
-    /* remove the whole name and all records */
-    /* Database operation */
-    res = GSN_database->remove_records (GSN_database->cls,
-                                         &pubkey_hash,
-                                         name_tmp);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing name `%s': %s\n",
-        name_tmp, (GNUNET_OK == res) ? "OK" : "FAIL");
-
-    if (GNUNET_OK != res)
-      /* Could not remove entry from database */
-      res = 4;
+    /* Extracting and converting private key */
+    GNUNET_CRYPTO_ecdsa_key_get_public (&rp_msg->private_key,
+                                     &pubkey);
+    conv_name = GNUNET_GNSRECORD_string_to_lowercase (name_tmp);
+    if (NULL == conv_name)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                  "Error converting name `%s'\n", name_tmp);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Creating %u records for name `%s' in zone `%s'\n",
+               (unsigned int) rd_count,
+               conv_name,
+               GNUNET_GNSRECORD_z2s (&pubkey));
+
+    if ( (0 == rd_count) &&
+         (GNUNET_NO ==
+          GSN_database->iterate_records (GSN_database->cls,
+                                         &rp_msg->private_key, 0, NULL, 0)) )
+    {
+      /* This name does not exist, so cannot be removed */
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Name `%s' does not exist, no deletion required\n",
+                  conv_name);
+      res = GNUNET_NO;
+    }
     else
-      res = 0;
-  }
-  else
-  {
-    /* remove a single record */
-    struct RemoveRecordContext rrc;
-    rrc.rd = rd;
-    rrc.pkey = pkey;
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing record for name `%s' in zone `%s'\n", name_tmp, GNUNET_short_h2s(&pubkey_hash));
-
-    /* Database operation */
-    res = GSN_database->iterate_records (GSN_database->cls,
-                                         &pubkey_hash,
-                                         name_tmp,
-                                         0,
-                                         handle_record_remove_it, &rrc);
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing record for name `%s': %s\n",
-        name_tmp, (rrc.op_res == 0) ? "OK" : "FAIL");
-    res = rrc.op_res;
+    {
+      res = GSN_database->store_records (GSN_database->cls,
+                                        &rp_msg->private_key,
+                                        conv_name,
+                                        rd_count, rd);
+      if (GNUNET_OK == res)
+      {
+        for (zm = monitor_head; NULL != zm; zm = zm->next)
+        {
+          if ( (0 == memcmp (&rp_msg->private_key, &zm->zone,
+                             sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) ||
+               (0 == memcmp (&zm->zone,
+                             &zero,
+                             sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) )
+          {
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Notifying monitor about changes under label `%s'\n",
+                        conv_name);
+            send_lookup_response (monitor_nc,
+                                  zm->nc->client,
+                                  0,
+                                  &rp_msg->private_key,
+                                  conv_name,
+                                  rd_count, rd);
+          }
+          else
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                        "Monitor is for another zone\n");
+        }
+        if (NULL == monitor_head)
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                      "No monitors active\n");
+      }
+      else
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Error storing record: %d\n",
+                    res);
+      }
+    }
+    if (GNUNET_OK == res)
+    {
+      refresh_block (client, rid,
+                     &rp_msg->private_key,
+                     conv_name,
+                     rd_count, rd);
+      GNUNET_SERVER_receive_done (client, GNUNET_OK);
+      GNUNET_free (conv_name);
+      return;
+    }
+    GNUNET_free (conv_name);
   }
-  /* Send response */
-send:
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "RECORD_REMOVE_RESPONSE");
-  rrr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE);
-  rrr_msg.gns_header.header.size = htons (sizeof (struct RecordRemoveResponseMessage));
-  rrr_msg.gns_header.r_id = htonl (rid);
-  rrr_msg.op_result = htonl (res);
-  GNUNET_SERVER_notification_context_unicast (snc, nc->client, (const struct GNUNET_MessageHeader *) &rrr_msg, GNUNET_NO);
-
-  GNUNET_CRYPTO_rsa_key_free (pkey);
-
+  send_store_response (client, res, rid);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
 
+/**
+ * Context for record remove operations passed from #handle_zone_to_name to
+ * #handle_zone_to_name_it as closure
+ */
 struct ZoneToNameCtx
 {
-  struct GNUNET_NAMESTORE_Client *nc;
+  /**
+   * Namestore client
+   */
+  struct NamestoreClient *nc;
+
+  /**
+   * Request id (to be used in the response to the client).
+   */
   uint32_t rid;
+
+  /**
+   * Set to #GNUNET_OK on success, #GNUNET_SYSERR on error.  Note that
+   * not finding a name for the zone still counts as a 'success' here,
+   * as this field is about the success of executing the IPC protocol.
+   */
+  int success;
 };
 
+
+/**
+ * Zone to name iterator
+ *
+ * @param cls struct ZoneToNameCtx *
+ * @param zone_key the zone key
+ * @param name name
+ * @param rd_count number of records in @a rd
+ * @param rd record data
+ */
 static void
 handle_zone_to_name_it (void *cls,
-    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
-    struct GNUNET_TIME_Absolute expire,
-    const char *name,
-    unsigned int rd_count,
-    const struct GNUNET_NAMESTORE_RecordData *rd,
-    const struct GNUNET_CRYPTO_RsaSignature *signature)
+                       const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+                       const char *name,
+                       unsigned int rd_count,
+                       const struct GNUNET_GNSRECORD_Data *rd)
 {
-  struct ZoneToNameCtx * ztn_ctx = cls;
+  struct ZoneToNameCtx *ztn_ctx = cls;
   struct ZoneToNameResponseMessage *ztnr_msg;
-  int16_t res = GNUNET_SYSERR;
-  uint16_t name_len = 0;
-  uint16_t rd_ser_len = 0 ;
-  int32_t contains_sig = 0;
-  size_t msg_size = 0;
-
-  char *rd_ser = NULL;
+  int16_t res;
+  size_t name_len;
+  size_t rd_ser_len;
+  size_t msg_size;
   char *name_tmp;
   char *rd_tmp;
-  char *sig_tmp;
-
-  if ((zone_key != NULL) && (name != NULL))
-  {
-    /* found result */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found results: name is `%s', has %u records\n", name, rd_count);
-    res = GNUNET_YES;
-    name_len = strlen (name) +1;
-  }
-  else
-  {
-    /* no result found */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found no results\n");
-    res = GNUNET_NO;
-    name_len = 0;
-  }
 
-  if (rd_count > 0)
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Found result for zone-to-name lookup: `%s'\n",
+             name);
+  res = GNUNET_YES;
+  name_len = (NULL == name) ? 0 : strlen (name) + 1;
+  rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
+  msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
+  if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
   {
-    rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
-    rd_ser = GNUNET_malloc (rd_ser_len);
-    GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser);
+    GNUNET_break (0);
+    ztn_ctx->success = GNUNET_SYSERR;
+    return;
   }
-  else
-    rd_ser_len = 0;
-
-  if (signature != NULL)
-    contains_sig = GNUNET_YES;
-  else
-    contains_sig = GNUNET_NO;
-
-
-
-  msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len + contains_sig * sizeof (struct GNUNET_CRYPTO_RsaSignature);
   ztnr_msg = GNUNET_malloc (msg_size);
-
-  name_tmp = (char *) &ztnr_msg[1];
-  rd_tmp = &name_tmp[name_len];
-  sig_tmp = &rd_tmp[rd_ser_len];
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n", "ZONE_TO_NAME_RESPONSE");
   ztnr_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
   ztnr_msg->gns_header.header.size = htons (msg_size);
   ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
@@ -1468,522 +1087,494 @@ handle_zone_to_name_it (void *cls,
   ztnr_msg->rd_len = htons (rd_ser_len);
   ztnr_msg->rd_count = htons (rd_count);
   ztnr_msg->name_len = htons (name_len);
-  ztnr_msg->expire = GNUNET_TIME_absolute_hton(expire);
-  if (zone_key != NULL)
-    ztnr_msg->zone_key = *zone_key;
-  else
-    memset (&ztnr_msg->zone_key, '\0', sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
-
-  if ((name_len > 0) && (name != NULL))
+  ztnr_msg->zone = *zone_key;
+  name_tmp = (char *) &ztnr_msg[1];
+  if (NULL != name)
     memcpy (name_tmp, name, name_len);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name is `%s', has %u records, rd ser len %u msg_size %u\n", name, rd_count, rd_ser_len, msg_size);
-  if ((rd_ser_len > 0) && (rd_ser != NULL))
-    memcpy (rd_tmp, rd_ser, rd_ser_len);
-  if ((GNUNET_YES == contains_sig) && (signature != NULL))
-    memcpy (sig_tmp, signature, contains_sig * sizeof (struct GNUNET_CRYPTO_RsaSignature));
-
-  GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client, (const struct GNUNET_MessageHeader *) ztnr_msg, GNUNET_NO);
+  rd_tmp = &name_tmp[name_len];
+  GNUNET_GNSRECORD_records_serialize (rd_count, rd, rd_ser_len, rd_tmp);
+  ztn_ctx->success = GNUNET_OK;
+  GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client,
+                                             &ztnr_msg->gns_header.header,
+                                             GNUNET_NO);
   GNUNET_free (ztnr_msg);
-  GNUNET_free_non_null (rd_ser);
 }
 
 
-static void handle_zone_to_name (void *cls,
-                          struct GNUNET_SERVER_Client * client,
-                          const struct GNUNET_MessageHeader * message)
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME message
+ *
+ * @param cls unused
+ * @param client client sending the message
+ * @param message message of type 'struct ZoneToNameMessage'
+ */
+static void
+handle_zone_to_name (void *cls,
+                     struct GNUNET_SERVER_Client *client,
+                     const struct GNUNET_MessageHeader *message)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_TO_NAME");
-  struct GNUNET_NAMESTORE_Client *nc;
+  struct NamestoreClient *nc;
+  const struct ZoneToNameMessage *ztn_msg;
   struct ZoneToNameCtx ztn_ctx;
-  size_t msg_size = 0;
-  uint32_t rid = 0;
-
-  if (ntohs (message->size) != sizeof (struct ZoneToNameMessage))
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
-  }
+  struct ZoneToNameResponseMessage ztnr_msg;
 
-  nc = client_lookup(client);
-  if (nc == NULL)
-  {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received `%s' message\n",
+             "ZONE_TO_NAME");
+  ztn_msg = (const struct ZoneToNameMessage *) message;
+  nc = client_lookup (client);
+  ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
+  ztn_ctx.nc = nc;
+  ztn_ctx.success = GNUNET_NO;
+  if (GNUNET_SYSERR ==
+      GSN_database->zone_to_name (GSN_database->cls,
+                                 &ztn_msg->zone,
+                                 &ztn_msg->value_zone,
+                                 &handle_zone_to_name_it, &ztn_ctx))
+  {
+    /* internal error, hang up instead of signalling something
+       that might be wrong */
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-
-  struct ZoneToNameMessage *ztn_msg = (struct ZoneToNameMessage *) message;
-
-  if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
+  if (GNUNET_NO == ztn_ctx.success)
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
-    return;
+    /* no result found, send empty response */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Found no result for zone-to-name lookup.\n");
+    memset (&ztnr_msg, 0, sizeof (ztnr_msg));
+    ztnr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
+    ztnr_msg.gns_header.header.size = htons (sizeof (ztnr_msg));
+    ztnr_msg.gns_header.r_id = ztn_msg->gns_header.r_id;
+    ztnr_msg.res = htons (GNUNET_NO);
+    GNUNET_SERVER_notification_context_unicast (snc,
+                                               client,
+                                               &ztnr_msg.gns_header.header,
+                                               GNUNET_NO);
   }
-
-  rid = ntohl (ztn_msg->gns_header.r_id);
-
-  ztn_ctx.rid = rid;
-  ztn_ctx.nc = nc;
-
-  struct GNUNET_CRYPTO_ShortHashAsciiEncoded z_tmp;
-  GNUNET_CRYPTO_short_hash_to_enc(&ztn_msg->zone, &z_tmp);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking up name for zone `%s' in zone `%s'\n",
-      (char *) &z_tmp,
-      GNUNET_short_h2s (&ztn_msg->value_zone));
-
-  GSN_database->zone_to_name (GSN_database->cls, &ztn_msg->zone, &ztn_msg->value_zone, &handle_zone_to_name_it, &ztn_ctx);
-
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
 
 /**
- * Copy record, data has to be free separetely
+ * Zone iteration processor result
  */
-void
-copy_record (const struct GNUNET_NAMESTORE_RecordData *src, struct GNUNET_NAMESTORE_RecordData *dest)
+enum ZoneIterationResult
 {
+  /**
+   * Iteration start.
+   */
+  IT_START = 0,
+
+  /**
+   * Found records,
+   * Continue to iterate with next iteration_next call
+   */
+  IT_SUCCESS_MORE_AVAILABLE = 1,
+
+  /**
+   * Iteration complete
+   */
+  IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2
+};
 
-  memcpy (dest, src, sizeof (struct GNUNET_NAMESTORE_RecordData));
-  dest->data = GNUNET_malloc (src->data_size);
-  memcpy ((void *) dest->data, src->data, src->data_size);
-}
 
+/**
+ * Context for record remove operations passed from
+ * #run_zone_iteration_round to #zone_iterate_proc as closure
+ */
 struct ZoneIterationProcResult
 {
-  struct GNUNET_NAMESTORE_ZoneIteration *zi;
+  /**
+   * The zone iteration handle
+   */
+  struct ZoneIteration *zi;
 
+  /**
+   * Iteration result: iteration done?
+   * #IT_SUCCESS_MORE_AVAILABLE:  if there may be more results overall but
+   * we got one for now and have sent it to the client
+   * #IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
+   * #IT_START: if we are still trying to find a result.
+   */
   int res_iteration_finished;
-  int records_included;
-  int has_signature;
-
-  char *name;
-  struct GNUNET_CRYPTO_ShortHashCode zone_hash;
-  struct GNUNET_NAMESTORE_RecordData *rd;
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key;
-  struct GNUNET_CRYPTO_RsaSignature signature;
-  struct GNUNET_TIME_Absolute expire;
+
 };
 
 
-void zone_iteraterate_proc (void *cls,
-                         const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
-                         struct GNUNET_TIME_Absolute expire,
-                         const char *name,
-                         unsigned int rd_count,
-                         const struct GNUNET_NAMESTORE_RecordData *rd,
-                         const struct GNUNET_CRYPTO_RsaSignature *signature)
+/**
+ * Process results for zone iteration from database
+ *
+ * @param cls struct ZoneIterationProcResult *proc
+ * @param zone_key the zone key
+ * @param name name
+ * @param rd_count number of records for this name
+ * @param rd record data
+ */
+static void
+zone_iterate_proc (void *cls,
+                       const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+                       const char *name,
+                       unsigned int rd_count,
+                       const struct GNUNET_GNSRECORD_Data *rd)
 {
   struct ZoneIterationProcResult *proc = cls;
-  struct GNUNET_NAMESTORE_RecordData *rd_filtered;
-  struct GNUNET_CRYPTO_RsaSignature * new_signature;
-  struct GNUNET_NAMESTORE_CryptoContainer *cc;
-  struct GNUNET_CRYPTO_ShortHashCode hash;
-  struct GNUNET_HashCode long_hash;
-  struct GNUNET_TIME_Absolute e;
-  unsigned int rd_count_filtered  = 0;
-  int include;
-  int c;
+  unsigned int i;
+  int do_refresh_block;
 
-  proc->res_iteration_finished = GNUNET_NO;
-  proc->records_included = 0;
-
-  if ((zone_key == NULL) && (name == NULL))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration done\n");
-    proc->res_iteration_finished = GNUNET_YES;
-    proc->rd = NULL;
-    proc->name = NULL;
-  }
-  else if ((zone_key != NULL) && (name != NULL)) /* just a safety check */
+  if ((NULL == zone_key) && (NULL == name))
   {
-    rd_filtered = GNUNET_malloc (rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received result for zone iteration: `%s'\n", name);
-    for (c = 0; c < rd_count; c++)
-    {
-      include = GNUNET_YES;
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: 0x%x must have 0x%x \n",
-          c, rd[c].flags, proc->zi->must_have_flags);
-      /* Checking must have flags */
-      if ((rd[c].flags & proc->zi->must_have_flags) == proc->zi->must_have_flags)
-      {
-        /* Include */
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c);
-      }
-      else
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Not include \n", c);
-        include = GNUNET_NO;
-      }
-
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: 0x%x must not have 0x%x\n",
-          c, rd[c].flags, proc->zi->must_not_have_flags);
-      if ((rd[c].flags & proc->zi->must_not_have_flags) != 0)
-      {
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Not include \n", c);
-        include = GNUNET_NO;
-      }
-      else
-      {
-        /* Include */
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c);
-      }
-      if (GNUNET_YES == include)
-      {
-        copy_record (&rd[c], &rd_filtered[rd_count_filtered]);
-        rd_count_filtered++;
-      }
-
-    }
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Included %i of %i records \n", rd_count_filtered, rd_count);
-
-    proc->records_included = rd_count_filtered;
-    if (0 == rd_count_filtered)
-    {
-      GNUNET_free (rd_filtered);
-      rd_filtered = NULL;
-    }
-    proc->rd = rd_filtered;
-    proc->name = GNUNET_strdup(name);
-    memcpy (&proc->zone_key, zone_key, sizeof (proc->zone_key));
-
-    /* Signature */
-    proc->has_signature = GNUNET_NO;
-    GNUNET_CRYPTO_short_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &hash);
-    GNUNET_CRYPTO_short_hash_double(&hash, &long_hash);
-    proc->zone_hash = hash;
-
-    if (GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
-    {
-      cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash);
-      e = get_block_expiration_time(rd_count_filtered, rd_filtered);
-      proc->expire = e;
-      new_signature = GNUNET_NAMESTORE_create_signature(cc->privkey, e, name, rd_filtered, rd_count_filtered);
-      GNUNET_assert (signature != NULL);
-      proc->signature = (*new_signature);
-      GNUNET_free (new_signature);
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating signature for `%s' in zone `%s' with %u records and expiration %llu\n",
-          name, GNUNET_short_h2s(&hash), rd_count_filtered, e.abs_value);
-      proc->has_signature = GNUNET_YES;
-    }
-    else if (rd_count_filtered == rd_count)
-    {
-      proc->expire = expire;
-      if (NULL != signature)
-      {
-        proc->signature = (*signature);
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using provided signature for `%s' in zone `%s' with %u records and expiration %llu\n",
-            name, GNUNET_short_h2s(&hash), rd_count_filtered, expire.abs_value);
-        proc->has_signature = GNUNET_YES;
-      }
-      else
-      {
-        memset (&proc->signature, '\0', sizeof (proc->signature));
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No signature provided for `%s'\n", name);
-      }
-    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Iteration done\n");
+    proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
+    return;
   }
-  else
+  if ((NULL == zone_key) || (NULL == name))
   {
+    /* what is this!? should never happen */
+    proc->res_iteration_finished = IT_START;
     GNUNET_break (0);
     return;
   }
+  proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
+  send_lookup_response (snc,
+                       proc->zi->client->client,
+                       proc->zi->request_id,
+                       zone_key,
+                       name,
+                       rd_count,
+                       rd);
+  do_refresh_block = GNUNET_NO;
+  for (i=0;i<rd_count;i++)
+    if(  (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) &&
+         (0 == (rd[i].flags & GNUNET_GNSRECORD_RF_PENDING)) )
+    {
+      do_refresh_block = GNUNET_YES;
+      break;
+    }
+  if (GNUNET_YES == do_refresh_block)
+    refresh_block (NULL, 0,
+                   zone_key,
+                   name,
+                   rd_count,
+                   rd);
 
 }
 
-void find_next_zone_iteration_result (struct ZoneIterationProcResult *proc)
-{
-
-  struct GNUNET_CRYPTO_ShortHashCode *zone;
-
-  if (GNUNET_YES == proc->zi->has_zone)
-    zone = &proc->zi->zone;
-  else
-    zone = NULL;
-
-  do
-  {
-    GSN_database->iterate_records (GSN_database->cls, zone , NULL, proc->zi->offset, &zone_iteraterate_proc, proc);
-    proc->zi->offset++;
-  }
-  while ((proc->records_included == 0) && (GNUNET_NO == proc->res_iteration_finished));
-}
-
 
-void send_zone_iteration_result (struct ZoneIterationProcResult *proc)
+/**
+ * Perform the next round of the zone iteration.
+ *
+ * @param zi zone iterator to process
+ */
+static void
+run_zone_iteration_round (struct ZoneIteration *zi)
 {
-  struct GNUNET_NAMESTORE_ZoneIteration *zi = proc->zi;
+  struct ZoneIterationProcResult proc;
+  struct RecordResultMessage rrm;
+  int ret;
 
-  if (GNUNET_YES == proc->res_iteration_finished)
-  {
-    struct ZoneIterationResponseMessage zir_msg;
-    if (zi->has_zone == GNUNET_YES)
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No more results for zone `%s'\n", GNUNET_short_h2s(&zi->zone));
-    else
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No more results for all zones\n");
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending empty `%s' message\n", "ZONE_ITERATION_RESPONSE");
-    zir_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
-    zir_msg.gns_header.header.size = htons (sizeof (struct ZoneIterationResponseMessage));
-    zir_msg.gns_header.r_id = htonl(zi->request_id);
-    zir_msg.expire = GNUNET_TIME_absolute_hton(GNUNET_TIME_UNIT_ZERO_ABS);
-    zir_msg.name_len = htons (0);
-    zir_msg.reserved = htons (0);
-    zir_msg.rd_count = htons (0);
-    zir_msg.rd_len = htons (0);
-    memset (&zir_msg.public_key, '\0', sizeof (zir_msg.public_key));
-    memset (&zir_msg.signature, '\0', sizeof (zir_msg.signature));
-    GNUNET_SERVER_notification_context_unicast (snc, zi->client->client, (const struct GNUNET_MessageHeader *) &zir_msg, GNUNET_NO);
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing zone iterator\n");
-    GNUNET_CONTAINER_DLL_remove (zi->client->op_head, zi->client->op_tail, zi);
-    GNUNET_free (zi);
-    return;
+  memset (&proc, 0, sizeof (proc));
+  proc.zi = zi;
+  proc.res_iteration_finished = IT_START;
+  while (IT_START == proc.res_iteration_finished)
+  {
+    if (GNUNET_SYSERR ==
+       (ret = GSN_database->iterate_records (GSN_database->cls,
+                                             (0 == memcmp (&zi->zone, &zero, sizeof (zero)))
+                                             ? NULL
+                                             : &zi->zone,
+                                             zi->offset,
+                                             &zone_iterate_proc, &proc)))
+    {
+      GNUNET_break (0);
+      break;
+    }
+    if (GNUNET_NO == ret)
+      proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
+    zi->offset++;
   }
-  else
+  if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
   {
-    GNUNET_assert (proc->records_included > 0);
-
-    struct ZoneIterationResponseMessage *zir_msg;
-    if (zi->has_zone == GNUNET_YES)
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending name `%s' for iteration over zone `%s'\n",
-          proc->name, GNUNET_short_h2s(&zi->zone));
-    if (zi->has_zone == GNUNET_NO)
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending name `%s' for iteration over all zones\n",
-          proc->name);
-
-    size_t name_len;
-    size_t rd_ser_len;
-    size_t msg_size;
-    char *name_tmp;
-    char *rd_tmp;
-    name_len = strlen (proc->name) +1;
-
-    rd_ser_len = GNUNET_NAMESTORE_records_get_size(proc->records_included, proc->rd);
-    char rd_ser[rd_ser_len];
-    GNUNET_NAMESTORE_records_serialize(proc->records_included, proc->rd, rd_ser_len, rd_ser);
-    msg_size = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_ser_len;
-    zir_msg = GNUNET_malloc(msg_size);
-
-    name_tmp = (char *) &zir_msg[1];
-    rd_tmp = &name_tmp[name_len];
-
-    zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
-    zir_msg->gns_header.header.size = htons (msg_size);
-    zir_msg->gns_header.r_id = htonl(zi->request_id);
-    zir_msg->expire = GNUNET_TIME_absolute_hton(proc->expire);
-    zir_msg->reserved = htons (0);
-    zir_msg->name_len = htons (name_len);
-    zir_msg->rd_count = htons (proc->records_included);
-    zir_msg->rd_len = htons (rd_ser_len);
-    zir_msg->signature = proc->signature;
-    zir_msg->public_key = proc->zone_key;
-    memcpy (name_tmp, proc->name, name_len);
-    memcpy (rd_tmp, rd_ser, rd_ser_len);
-
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with size %u\n", "ZONE_ITERATION_RESPONSE", msg_size);
-    GNUNET_SERVER_notification_context_unicast (snc, zi->client->client, (const struct GNUNET_MessageHeader *) zir_msg, GNUNET_NO);
-    GNUNET_free (zir_msg);
-  }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "More results available\n");
+    return; /* more results later */
+  }
+  /* send empty response to indicate end of list */
+  memset (&rrm, 0, sizeof (rrm));
+  rrm.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
+  rrm.gns_header.header.size = htons (sizeof (rrm));
+  rrm.gns_header.r_id = htonl (zi->request_id);
+  GNUNET_SERVER_notification_context_unicast (snc,
+                                             zi->client->client,
+                                             &rrm.gns_header.header,
+                                             GNUNET_NO);
+  GNUNET_CONTAINER_DLL_remove (zi->client->op_head,
+                              zi->client->op_tail,
+                              zi);
+  GNUNET_free (zi);
 }
 
-void clean_up_zone_iteration_result (struct ZoneIterationProcResult *proc)
-{
-  int c;
-  GNUNET_free_non_null (proc->name);
-  for (c = 0; c < proc->records_included; c++)
-  {
-    GNUNET_free ((void *) proc->rd[c].data);
-  }
-  GNUNET_free_non_null (proc->rd);
-  proc->name = NULL;
-  proc->rd = NULL;
-}
 
-static void handle_iteration_start (void *cls,
-                          struct GNUNET_SERVER_Client * client,
-                          const struct GNUNET_MessageHeader * message)
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START message
+ *
+ * @param cls unused
+ * @param client the client sending the message
+ * @param message message of type 'struct ZoneIterationStartMessage'
+ */
+static void
+handle_iteration_start (void *cls,
+                        struct GNUNET_SERVER_Client *client,
+                        const struct GNUNET_MessageHeader *message)
 {
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START");
-
-  struct ZoneIterationStartMessage * zis_msg = (struct ZoneIterationStartMessage *) message;
-  struct GNUNET_NAMESTORE_Client *nc;
-  struct GNUNET_NAMESTORE_ZoneIteration *zi;
+  const struct ZoneIterationStartMessage *zis_msg;
+  struct NamestoreClient *nc;
+  struct ZoneIteration *zi;
 
-  nc = client_lookup(client);
-  if (nc == NULL)
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START");
+  if (NULL == (nc = client_lookup (client)))
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-
-  zi = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIteration));
+  zis_msg = (const struct ZoneIterationStartMessage *) message;
+  zi = GNUNET_new (struct ZoneIteration);
   zi->request_id = ntohl (zis_msg->gns_header.r_id);
   zi->offset = 0;
   zi->client = nc;
-  zi->must_have_flags = ntohs (zis_msg->must_have_flags);
-  zi->must_not_have_flags = ntohs (zis_msg->must_not_have_flags);
+  zi->zone = zis_msg->zone;
 
-  struct GNUNET_CRYPTO_ShortHashCode dummy;
-  memset (&dummy, '\0', sizeof (dummy));
-  if (0 == memcmp (&dummy, &zis_msg->zone, sizeof (dummy)))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over all zones\n");
-    zi->zone = zis_msg->zone;
-    zi->has_zone = GNUNET_NO;
-  }
-  else
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over zone  `%s'\n", GNUNET_short_h2s (&zis_msg->zone));
-    zi->zone = zis_msg->zone;
-    zi->has_zone = GNUNET_YES;
-  }
 
   GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
-
-  struct ZoneIterationProcResult proc;
-  proc.zi = zi;
-
-  find_next_zone_iteration_result (&proc);
-  if (GNUNET_YES == proc.res_iteration_finished)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration done\n");
-  }
-  else if (proc.records_included != 0)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration return %u records\n", proc.records_included);
-  }
-  send_zone_iteration_result (&proc);
-  clean_up_zone_iteration_result (&proc);
-
+  run_zone_iteration_round (zi);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
-static void handle_iteration_stop (void *cls,
-                          struct GNUNET_SERVER_Client * client,
-                          const struct GNUNET_MessageHeader * message)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_STOP");
 
-  struct GNUNET_NAMESTORE_Client *nc;
-  struct GNUNET_NAMESTORE_ZoneIteration *zi;
-  struct ZoneIterationStopMessage * zis_msg = (struct ZoneIterationStopMessage *) message;
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP message
+ *
+ * @param cls unused
+ * @param client GNUNET_SERVER_Client sending the message
+ * @param message message of type 'struct ZoneIterationStopMessage'
+ */
+static void
+handle_iteration_stop (void *cls,
+                       struct GNUNET_SERVER_Client *client,
+                       const struct GNUNET_MessageHeader *message)
+{
+  struct NamestoreClient *nc;
+  struct ZoneIteration *zi;
+  const struct ZoneIterationStopMessage *zis_msg;
   uint32_t rid;
 
-  nc = client_lookup(client);
-  if (nc == NULL)
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received `%s' message\n",
+             "ZONE_ITERATION_STOP");
+  if (NULL == (nc = client_lookup(client)))
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-
+  zis_msg = (const struct ZoneIterationStopMessage *) message;
   rid = ntohl (zis_msg->gns_header.r_id);
-  for (zi = nc->op_head; zi != NULL; zi = zi->next)
-  {
+  for (zi = nc->op_head; NULL != zi; zi = zi->next)
     if (zi->request_id == rid)
       break;
-  }
-  if (zi == NULL)
+  if (NULL == zi)
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-
-  GNUNET_CONTAINER_DLL_remove(nc->op_head, nc->op_tail, zi);
-  if (GNUNET_YES == zi->has_zone)
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopped zone iteration for zone `%s'\n", GNUNET_short_h2s (&zi->zone));
-  else
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopped zone iteration all zones\n");
+  GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
   GNUNET_free (zi);
-
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
-static void handle_iteration_next (void *cls,
-                          struct GNUNET_SERVER_Client * client,
-                          const struct GNUNET_MessageHeader * message)
-{
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT");
 
-  struct GNUNET_NAMESTORE_Client *nc;
-  struct GNUNET_NAMESTORE_ZoneIteration *zi;
-  struct ZoneIterationStopMessage * zis_msg = (struct ZoneIterationStopMessage *) message;
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message
+ *
+ * @param cls unused
+ * @param client GNUNET_SERVER_Client sending the message
+ * @param message message of type 'struct ZoneIterationNextMessage'
+ */
+static void
+handle_iteration_next (void *cls,
+                       struct GNUNET_SERVER_Client *client,
+                       const struct GNUNET_MessageHeader *message)
+{
+  struct NamestoreClient *nc;
+  struct ZoneIteration *zi;
+  const struct ZoneIterationNextMessage *zis_msg;
   uint32_t rid;
 
-  nc = client_lookup(client);
-  if (nc == NULL)
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received `%s' message\n",
+              "ZONE_ITERATION_NEXT");
+  if (NULL == (nc = client_lookup(client)))
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-
+  zis_msg = (const struct ZoneIterationNextMessage *) message;
   rid = ntohl (zis_msg->gns_header.r_id);
-  for (zi = nc->op_head; zi != NULL; zi = zi->next)
-  {
+  for (zi = nc->op_head; NULL != zi; zi = zi->next)
     if (zi->request_id == rid)
       break;
-  }
-  if (zi == NULL)
+  if (NULL == zi)
   {
-    GNUNET_break_op (0);
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
+  run_zone_iteration_round (zi);
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
 
-  struct ZoneIterationProcResult proc;
-  proc.zi = zi;
 
-  find_next_zone_iteration_result (&proc);
-  if (GNUNET_YES == proc.res_iteration_finished)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration done\n");
-  }
-  else if (proc.records_included != 0)
+/**
+ * Send 'sync' message to zone monitor, we're now in sync.
+ *
+ * @param zm monitor that is now in sync
+ */
+static void
+monitor_sync (struct ZoneMonitor *zm)
+{
+  struct GNUNET_MessageHeader sync;
+
+  sync.size = htons (sizeof (struct GNUNET_MessageHeader));
+  sync.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
+  GNUNET_SERVER_notification_context_unicast (monitor_nc,
+                                             zm->nc->client,
+                                             &sync,
+                                             GNUNET_NO);
+}
+
+
+/**
+ * Obtain the next datum during the zone monitor's zone intiial iteration.
+ *
+ * @param cls zone monitor that does its initial iteration
+ * @param tc scheduler context
+ */
+static void
+monitor_next (void *cls,
+             const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * A #GNUNET_NAMESTORE_RecordIterator for monitors.
+ *
+ * @param cls a 'struct ZoneMonitor *' with information about the monitor
+ * @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
+monitor_iterate_cb (void *cls,
+                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
+                   const char *name,
+                   unsigned int rd_count,
+                   const struct GNUNET_GNSRECORD_Data *rd)
+{
+  struct ZoneMonitor *zm = cls;
+
+  if (NULL == name)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Zone iteration return %u records\n", proc.records_included);
+    /* finished with iteration */
+    monitor_sync (zm);
+    return;
   }
-  send_zone_iteration_result (&proc);
-  clean_up_zone_iteration_result (&proc);
+  send_lookup_response (monitor_nc,
+                       zm->nc->client,
+                       0,
+                       zone_key,
+                       name,
+                       rd_count,
+                       rd);
+  zm->task = GNUNET_SCHEDULER_add_now (&monitor_next, zm);
+}
 
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START message
+ *
+ * @param cls unused
+ * @param client the client sending the message
+ * @param message message of type 'struct ZoneMonitorStartMessage'
+ */
+static void
+handle_monitor_start (void *cls,
+                     struct GNUNET_SERVER_Client *client,
+                     const struct GNUNET_MessageHeader *message)
+{
+  const struct ZoneMonitorStartMessage *zis_msg;
+  struct ZoneMonitor *zm;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Received `%s' message\n",
+             "ZONE_MONITOR_START");
+  zis_msg = (const struct ZoneMonitorStartMessage *) message;
+  zm = GNUNET_new (struct ZoneMonitor);
+  zm->offset = 0;
+  zm->nc = client_lookup (client);
+  zm->zone = zis_msg->zone;
+  GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm);
+  GNUNET_SERVER_client_mark_monitor (client);
+  GNUNET_SERVER_disable_receive_done_warning (client);
+  GNUNET_SERVER_notification_context_add (monitor_nc,
+                                         client);
+  if (GNUNET_YES == ntohl (zis_msg->iterate_first))
+    zm->task = GNUNET_SCHEDULER_add_now (&monitor_next, zm);
+  else
+    monitor_sync (zm);
 }
 
-int zonekey_file_it (void *cls, const char *filename)
+
+/**
+ * Obtain the next datum during the zone monitor's zone intiial iteration.
+ *
+ * @param cls zone monitor that does its initial iteration
+ * @param tc scheduler context
+ */
+static void
+monitor_next (void *cls,
+             const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
-  struct GNUNET_HashCode long_hash;
-  int *counter = cls;
-   if ((filename != NULL) && (NULL != strstr(filename, ".zkey")))
-   {
-     struct GNUNET_CRYPTO_RsaPrivateKey * privkey;
-     struct GNUNET_NAMESTORE_CryptoContainer *c;
-     privkey = GNUNET_CRYPTO_rsa_key_create_from_file(filename);
-     if (privkey == NULL)
-       return GNUNET_OK;
-
-     c = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
-     c->pubkey = GNUNET_malloc(sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
-     c->privkey = privkey;
-     GNUNET_CRYPTO_rsa_key_get_public(privkey, c->pubkey);
-     GNUNET_CRYPTO_short_hash(c->pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &c->zone);
-
-     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found zonefile for zone `%s'\n", GNUNET_short_h2s (&c->zone));
-     GNUNET_CRYPTO_short_hash_double (&c->zone, &long_hash);
-     GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, c, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
-     (*counter) ++;
-   }
-   return GNUNET_OK;
+  struct ZoneMonitor *zm = cls;
+  int ret;
+
+  zm->task = GNUNET_SCHEDULER_NO_TASK;
+  ret = GSN_database->iterate_records (GSN_database->cls,
+                                       (0 == memcmp (&zm->zone, &zero, sizeof (zero)))
+                                       ? NULL
+                                       : &zm->zone,
+                                      zm->offset++,
+                                      &monitor_iterate_cb, zm);
+  if (GNUNET_SYSERR == ret)
+  {
+    GNUNET_SERVER_client_disconnect (zm->nc->client);
+    return;
+  }
+  if (GNUNET_NO == ret)
+  {
+    /* empty zone */
+    monitor_sync (zm);
+    return;
+  }
 }
 
 
 /**
- * Process template requests.
+ * Process namestore requests.
  *
  * @param cls closure
  * @param server the initialized server
@@ -1993,60 +1584,29 @@ static void
 run (void *cls, struct GNUNET_SERVER_Handle *server,
      const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
-  char * database;
-  int counter = 0;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
-
   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
-    {&handle_start, NULL,
-     GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)},
-    {&handle_lookup_name, NULL,
-     GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0},
-    {&handle_record_put, NULL,
-    GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT, 0},
-    {&handle_record_create, NULL,
-     GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE, 0},
-    {&handle_record_remove, NULL,
-     GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE, 0},
+    {&handle_record_store, NULL,
+     GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE, 0},
+    {&handle_record_lookup, NULL,
+     GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP, 0},
     {&handle_zone_to_name, NULL,
-      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, 0},
+     GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, sizeof (struct ZoneToNameMessage) },
     {&handle_iteration_start, NULL,
-     GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage)},
+     GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage) },
     {&handle_iteration_next, NULL,
-     GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, 0},
-     {&handle_iteration_stop, NULL,
-      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, 0},
+     GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, sizeof (struct ZoneIterationNextMessage) },
+    {&handle_iteration_stop, NULL,
+     GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, sizeof (struct ZoneIterationStopMessage) },
+    {&handle_monitor_start, NULL,
+     GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START, sizeof (struct ZoneMonitorStartMessage) },
     {NULL, NULL, 0, 0}
   };
+  char *database;
 
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
   GSN_cfg = cfg;
-
-  /* Load private keys from disk */
-  if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore", "zonefile_directory",
-                                             &zonefile_directory))
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("No directory to load zonefiles specified in configuration\n"));
-    GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
-    return;
-  }
-
-  if (GNUNET_NO == GNUNET_DISK_file_test (zonefile_directory))
-  {
-    if (GNUNET_SYSERR == GNUNET_DISK_directory_create (zonefile_directory))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Creating directory `%s' for zone files failed!\n"), zonefile_directory);
-      GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
-      return;
-    }
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created directory `%s' for zone files\n", zonefile_directory);
-  }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Scanning directory `%s' for zone files\n", zonefile_directory);
-  zonekeys = GNUNET_CONTAINER_multihashmap_create (10);
-  GNUNET_DISK_directory_scan (zonefile_directory, zonekey_file_it, &counter);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found %u zone files\n", counter);
-
+  monitor_nc = GNUNET_SERVER_notification_context_create (server, 1);
+  namecache = GNUNET_NAMECACHE_connect (cfg);
   /* Loading database plugin */
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
@@ -2056,10 +1616,11 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
   GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
   GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
   GNUNET_free (database);
-  if (GSN_database == NULL)
+  if (NULL == GSN_database)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load database backend `%s'\n",
-        db_lib_name);
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+               "Could not load database backend `%s'\n",
+               db_lib_name);
     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
     return;
   }
@@ -2070,10 +1631,8 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
   GNUNET_SERVER_disconnect_notify (server,
                                    &client_disconnect_notification,
                                    NULL);
-
   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
                                 NULL);
-
 }