-more namestore service cleanup -- wip
[oweals/gnunet.git] / src / namestore / gnunet-service-namestore.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file namestore/gnunet-service-namestore.c
23  * @brief namestore for the GNUnet naming system
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_getopt_lib.h"
28 #include "gnunet_service_lib.h"
29 #include "gnunet_namestore_service.h"
30 #include "gnunet_namestore_plugin.h"
31 #include "gnunet_signatures.h"
32 #include "namestore.h"
33
34 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
35
36 /**
37  * A namestore operation.
38  */
39 struct GNUNET_NAMESTORE_ZoneIteration
40 {
41   /**
42    * Next element in the DLL
43    */
44   struct GNUNET_NAMESTORE_ZoneIteration *next;
45
46   /**
47    * Previous element in the DLL
48    */
49   struct GNUNET_NAMESTORE_ZoneIteration *prev;
50
51   /**
52    * Namestore client which intiated this zone iteration
53    */
54   struct GNUNET_NAMESTORE_Client *client;
55
56   /**
57    * GNUNET_YES if we iterate over a specific zone
58    * GNUNET_NO if we iterate over all zones
59    */
60   int has_zone;
61
62   /**
63    * Hash of the specific zone if 'has_zone' is GNUNET_YES,
64    * othwerwise set to '\0'
65    */
66   struct GNUNET_CRYPTO_ShortHashCode zone;
67
68   /**
69    * The operation id fot the zone iteration in the response for the client
70    */
71   uint64_t request_id;
72
73   /**
74    * Offset of the zone iteration used to address next result of the zone
75    * iteration in the store
76    *
77    * Initialy set to 0 in handle_iteration_start
78    * Incremented with by every call to handle_iteration_next
79    */
80   uint32_t offset;
81
82   /**
83    * Which flags must be included
84    */
85   uint16_t must_have_flags;
86
87   /**
88    * Which flags must not be included
89    */
90   uint16_t must_not_have_flags;
91 };
92
93
94 /**
95  * A namestore client
96  */
97 struct GNUNET_NAMESTORE_Client
98 {
99   /**
100    * Next element in the DLL
101    */
102   struct GNUNET_NAMESTORE_Client *next;
103
104   /**
105    * Previous element in the DLL
106    */
107   struct GNUNET_NAMESTORE_Client *prev;
108
109   /**
110    * The client
111    */
112   struct GNUNET_SERVER_Client *client;
113
114   /**
115    * Head of the DLL of
116    * Zone iteration operations in progress initiated by this client
117    */
118   struct GNUNET_NAMESTORE_ZoneIteration *op_head;
119
120   /**
121    * Tail of the DLL of
122    * Zone iteration operations in progress initiated by this client
123    */
124   struct GNUNET_NAMESTORE_ZoneIteration *op_tail;
125 };
126
127
128 /**
129  * A container struct to store information belonging to a zone crypto key pair
130  */
131 struct GNUNET_NAMESTORE_CryptoContainer
132 {
133   /**
134    * Filename where to store the container
135    */
136   char *filename;
137
138   /**
139    * Short hash of the zone's public key
140    */
141   struct GNUNET_CRYPTO_ShortHashCode zone;
142
143   /**
144    * Zone's private key
145    */
146   struct GNUNET_CRYPTO_RsaPrivateKey *privkey;
147
148 };
149
150
151 /**
152  * Configuration handle.
153  */
154 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
155
156 /**
157  * Database handle
158  */
159 static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
160
161 /**
162  * Zonefile directory
163  */
164 static char *zonefile_directory;
165
166 /**
167  * Name of the database plugin
168  */
169 static char *db_lib_name;
170
171 /**
172  * Our notification context.
173  */
174 static struct GNUNET_SERVER_NotificationContext *snc;
175
176 /**
177  * Head of the Client DLL
178  */
179 static struct GNUNET_NAMESTORE_Client *client_head;
180
181 /**
182  * Tail of the Client DLL
183  */
184 static struct GNUNET_NAMESTORE_Client *client_tail;
185
186 /**
187  * Hashmap containing the zone keys this namestore has is authoritative for
188  *
189  * Keys are the GNUNET_CRYPTO_HashCode of the GNUNET_CRYPTO_ShortHashCode
190  * The values are 'struct GNUNET_NAMESTORE_CryptoContainer *'
191  */
192 static struct GNUNET_CONTAINER_MultiHashMap *zonekeys;
193
194
195 /**
196  * Writes the encrypted private key of a zone in a file
197  *
198  * @param filename where to store the zone
199  * @param c the crypto container containing private key of the zone
200  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
201  */
202 static int
203 write_key_to_file (const char *filename, 
204                    struct GNUNET_NAMESTORE_CryptoContainer *c)
205 {
206   struct GNUNET_CRYPTO_RsaPrivateKey *ret = c->privkey;
207   struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *enc;
208   struct GNUNET_DISK_FileHandle *fd;
209   struct GNUNET_CRYPTO_ShortHashCode zone;
210   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey;
211   struct GNUNET_CRYPTO_RsaPrivateKey *privkey;
212
213   fd = GNUNET_DISK_file_open (filename, 
214                               GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS, 
215                               GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
216   if ( (NULL == fd) && (EEXIST == errno) )
217   {
218     privkey = GNUNET_CRYPTO_rsa_key_create_from_file (filename);
219     if (NULL == privkey)
220     {
221       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
222                   _("Failed to write zone key to file `%s': %s\n"),
223                   filename,
224                   _("file exists but reading key failed"));
225       return GNUNET_SYSERR;
226     }
227     GNUNET_CRYPTO_rsa_key_get_public (privkey, &pubkey);
228     GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &zone);
229     GNUNET_CRYPTO_rsa_key_free (privkey);
230     if (0 == memcmp (&zone, &c->zone, sizeof(zone)))
231     {
232       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
233                   "File zone `%s' containing this key already exists\n", 
234                   GNUNET_short_h2s (&zone));
235       return GNUNET_OK;
236     }
237     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
238                 _("Failed to write zone key to file `%s': %s\n"),
239                 filename,
240                 _("file exists with different key"));
241     return GNUNET_OK;    
242   }
243   if (NULL == fd)
244   {
245     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
246     return GNUNET_SYSERR;
247   }
248   if (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded), GNUNET_YES))
249   {
250     GNUNET_break (GNUNET_YES == GNUNET_DISK_file_close (fd));
251     return GNUNET_SYSERR;
252   }
253   enc = GNUNET_CRYPTO_rsa_encode_key (ret);
254   GNUNET_assert (NULL != enc);
255   GNUNET_assert (ntohs (enc->len) == GNUNET_DISK_file_write (fd, enc, ntohs (enc->len)));
256   GNUNET_free (enc);
257   GNUNET_DISK_file_sync (fd);
258   if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded)))
259     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
260   GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
261   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262               "Stored zonekey for zone `%s' in file `%s'\n",
263               GNUNET_short_h2s(&c->zone), c->filename);
264   return GNUNET_OK;
265 }
266
267
268 /**
269  * Write allthe given zone key to disk and then removes the entry from the
270  * 'zonekeys' hash map.
271  *
272  * @param cls unused
273  * @param key zone key
274  * @param value 'struct GNUNET_NAMESTORE_CryptoContainer' containing the private
275  *        key
276  * @return GNUNET_OK to continue iteration
277  */
278 static int
279 zone_to_disk_it (void *cls,
280                  const struct GNUNET_HashCode *key,
281                  void *value)
282 {
283   struct GNUNET_NAMESTORE_CryptoContainer *c = value;
284
285   if (NULL == c->filename)
286     GNUNET_asprintf(&c->filename, 
287                     "%s/%s.zkey", 
288                     zonefile_directory, 
289                     GNUNET_short_h2s (&c->zone));
290   (void) write_key_to_file(c->filename, c);
291   GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (zonekeys, key, value));
292   GNUNET_CRYPTO_rsa_key_free (c->privkey);
293   GNUNET_free (c->filename);
294   GNUNET_free (c);
295   return GNUNET_OK;
296 }
297
298
299 /**
300  * Returns the expiration time of the given block of records. The block
301  * expiration time is the expiration time of the block with smallest
302  * expiration time.
303  *
304  * @param rd_count number of records given in 'rd'
305  * @param rd array of records
306  * @return absolute expiration time
307  */
308 static struct GNUNET_TIME_Absolute
309 get_block_expiration_time (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd)
310 {
311   unsigned int c;
312   struct GNUNET_TIME_Absolute expire;
313   struct GNUNET_TIME_Absolute at;
314   struct GNUNET_TIME_Relative rt;
315
316   if (NULL == rd)
317     return GNUNET_TIME_UNIT_ZERO_ABS;
318   expire = GNUNET_TIME_UNIT_FOREVER_ABS;
319   for (c = 0; c < rd_count; c++)  
320   {
321     if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
322     {
323       rt.rel_value = rd[c].expiration_time;
324       at = GNUNET_TIME_relative_to_absolute (rt);
325     }
326     else
327     {
328       at.abs_value = rd[c].expiration_time;
329     }
330     expire = GNUNET_TIME_absolute_min (at, expire);  
331   }
332   return expire;
333 }
334
335
336 /**
337  * Task run during shutdown.
338  *
339  * @param cls unused
340  * @param tc unused
341  */
342 static void
343 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
344 {
345   struct GNUNET_NAMESTORE_ZoneIteration *no;
346   struct GNUNET_NAMESTORE_Client *nc;
347
348   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
349   if (NULL != snc)
350   {
351     GNUNET_SERVER_notification_context_destroy (snc);
352     snc = NULL;
353   }
354   GNUNET_CONTAINER_multihashmap_iterate (zonekeys, &zone_to_disk_it, NULL);
355   GNUNET_CONTAINER_multihashmap_destroy (zonekeys);
356   zonekeys = NULL;
357   while (NULL != (nc = client_head))
358   {
359     while (NULL != (no = nc->op_head))
360     {
361       GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
362       GNUNET_free (no);
363     }
364     GNUNET_SERVER_client_drop(nc->client);
365     GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
366     GNUNET_free (nc);
367   }
368   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
369   GNUNET_free (db_lib_name);
370   db_lib_name = NULL;
371   GNUNET_free_non_null (zonefile_directory);
372   zonefile_directory = NULL;
373 }
374
375
376 /**
377  * Lookup our internal data structure for a given client.
378  *
379  * @param client server client handle to use for the lookup
380  * @return our internal structure for the client, NULL if
381  *         we do not have any yet
382  */
383 static struct GNUNET_NAMESTORE_Client *
384 client_lookup (struct GNUNET_SERVER_Client *client)
385 {
386   struct GNUNET_NAMESTORE_Client *nc;
387
388   GNUNET_assert (NULL != client);
389   for (nc = client_head; NULL != nc; nc = nc->next)  
390     if (client == nc->client)
391       return nc;  
392   return NULL;
393 }
394
395
396 /**
397  * Called whenever a client is disconnected.
398  * Frees our resources associated with that client.
399  *
400  * @param cls closure
401  * @param client identification of the client
402  */
403 static void
404 client_disconnect_notification (void *cls, 
405                                 struct GNUNET_SERVER_Client *client)
406 {
407   struct GNUNET_NAMESTORE_ZoneIteration *no;
408   struct GNUNET_NAMESTORE_Client *nc;
409
410   if (NULL == client)
411     return;
412   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
413               "Client %p disconnected\n", 
414               client);
415   nc = client_lookup (client);
416   if (NULL == nc)
417     return;
418   while (NULL != (no = nc->op_head))
419   {
420     GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
421     GNUNET_free (no);
422   }
423   GNUNET_SERVER_client_drop (nc->client);
424   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
425   GNUNET_free (nc);
426 }
427
428
429 /**
430  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_START' message
431  *
432  * @param cls unused
433  * @param client GNUNET_SERVER_Client sending the message
434  * @param message unused
435  */
436 static void
437 handle_start (void *cls,
438               struct GNUNET_SERVER_Client *client,
439               const struct GNUNET_MessageHeader *message)
440 {
441   struct GNUNET_NAMESTORE_Client *nc;
442
443   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
444               "Client %p connected\n", client);
445   if (NULL != client_lookup (client))
446   {
447     GNUNET_break (0);
448     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
449     return;
450   }
451   nc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Client));
452   nc->client = client;
453   GNUNET_SERVER_notification_context_add (snc, client);
454   GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
455   GNUNET_SERVER_client_keep (client);
456   GNUNET_SERVER_receive_done (client, GNUNET_OK);
457 }
458
459
460 /**
461  * Context for name lookups passed from 'handle_lookup_name' to
462  * 'handle_lookup_name_it' as closure
463  */
464 struct LookupNameContext
465 {
466   /**
467    * The client to send the response to
468    */
469   struct GNUNET_NAMESTORE_Client *nc;
470
471   /**
472    * Requested zone
473    */
474   const struct GNUNET_CRYPTO_ShortHashCode *zone;
475
476   /**
477    * Requested name
478    */
479   const char *name;
480
481   /**
482    * Operation id for the name lookup
483    */
484   uint32_t request_id;
485
486   /**
487    * Requested specific record type
488    */
489   uint32_t record_type;
490 };
491
492
493 /**
494  * A 'GNUNET_NAMESTORE_RecordIterator' for name lookups in handle_lookup_name
495  *
496  * @param cls a 'struct LookupNameContext *' with information about the request
497  * @param zone_key zone key of the zone
498  * @param expire expiration time
499  * @param name name
500  * @param rd_count number of records
501  * @param rd array of records
502  * @param signature signature
503  */
504 static void
505 handle_lookup_name_it (void *cls,
506                        const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
507                        struct GNUNET_TIME_Absolute expire,
508                        const char *name,
509                        unsigned int rd_count,
510                        const struct GNUNET_NAMESTORE_RecordData *rd,
511                        const struct GNUNET_CRYPTO_RsaSignature *signature)
512 {
513   struct LookupNameContext *lnc = cls;
514   struct LookupNameResponseMessage *lnr_msg;
515   struct GNUNET_NAMESTORE_RecordData *rd_selected;
516   struct GNUNET_NAMESTORE_CryptoContainer *cc;
517   struct GNUNET_CRYPTO_RsaSignature *signature_new;
518   struct GNUNET_TIME_Absolute e;
519   struct GNUNET_CRYPTO_ShortHashCode zone_key_hash;
520   struct GNUNET_HashCode long_hash;
521   char *rd_tmp;
522   char *name_tmp;
523   size_t rd_ser_len;
524   size_t r_size;
525   size_t name_len;
526   int copied_elements;
527   int contains_signature;
528   int authoritative;
529   int c;
530
531   name_len = (NULL == name) ? 0 : strlen(name) + 1;
532   copied_elements = 0;
533   rd_selected = NULL;
534   /* count records to copy */
535   if (0 != lnc->record_type)
536   {
537     /* special record type needed */
538     for (c = 0; c < rd_count; c++)
539       if (rd[c].record_type == lnc->record_type)
540         copied_elements++; /* found matching record */
541     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
542                 "Found %u records with type %u for name `%s' in zone `%s'\n",
543                 copied_elements, 
544                 lnc->record_type, 
545                 lnc->name, 
546                 GNUNET_short_h2s(lnc->zone));
547     if (copied_elements > 0)
548     {
549       rd_selected = GNUNET_malloc (copied_elements * sizeof (struct GNUNET_NAMESTORE_RecordData));
550       copied_elements = 0;
551       for (c = 0; c < rd_count; c++)
552       {
553         if (rd[c].record_type == lnc->record_type)
554         {
555           /* found matching record */
556           rd_selected[copied_elements] = rd[c]; /* shallow copy! */
557           copied_elements++;
558         }
559       }
560     }
561   }
562   else
563   {
564     copied_elements = rd_count;
565     rd_selected = (struct GNUNET_NAMESTORE_RecordData *) rd;
566   }
567   // FIXME: need to adjust 'rd' from relative to absolute times!
568   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
569               "Found %u records for name `%s' in zone `%s'\n",
570               copied_elements,
571               lnc->name, 
572               GNUNET_short_h2s (lnc->zone));
573
574   if ((copied_elements == rd_count) && (NULL != signature))
575     contains_signature = GNUNET_YES; /* returning all records, so include signature */
576   else
577     contains_signature = GNUNET_NO; /* returning not all records, so do not include signature */
578
579   authoritative = GNUNET_NO;
580   signature_new = NULL;
581   if ((NULL != zone_key) && (copied_elements == rd_count))
582   {
583     GNUNET_CRYPTO_short_hash (zone_key, 
584                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
585                               &zone_key_hash);
586     GNUNET_CRYPTO_short_hash_double (&zone_key_hash, &long_hash);
587     if (NULL != (cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash)))
588     {
589       e = get_block_expiration_time (rd_count, rd);
590       signature_new = GNUNET_NAMESTORE_create_signature (cc->privkey, e, name, rd, rd_count);
591       GNUNET_assert (NULL != signature_new);
592       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
593                   "Creating signature for name `%s' with %u records in zone `%s'\n",
594                   name, 
595                   copied_elements,
596                   GNUNET_short_h2s(&zone_key_hash));
597       authoritative = GNUNET_YES;
598     }
599   }
600
601   rd_ser_len = GNUNET_NAMESTORE_records_get_size (copied_elements, rd_selected);
602   r_size = sizeof (struct LookupNameResponseMessage) +
603            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
604            name_len +
605            rd_ser_len;
606   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
607               "Sending `%s' message\n", 
608               "NAMESTORE_LOOKUP_NAME_RESPONSE");
609   lnr_msg = GNUNET_malloc (r_size);
610   lnr_msg->gns_header.header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
611   lnr_msg->gns_header.header.size = ntohs (r_size);
612   lnr_msg->gns_header.r_id = htonl (lnc->request_id);
613   lnr_msg->rd_count = htons (copied_elements);
614   lnr_msg->rd_len = htons (rd_ser_len);
615   lnr_msg->name_len = htons (name_len);
616   lnr_msg->expire = GNUNET_TIME_absolute_hton (get_block_expiration_time (copied_elements, 
617                                                                           rd_selected));
618   name_tmp = (char *) &lnr_msg[1];
619   memcpy (name_tmp, name, name_len);
620   rd_tmp = &name_tmp[name_len];
621   GNUNET_NAMESTORE_records_serialize (copied_elements, rd_selected, rd_ser_len, rd_tmp);
622
623   if (rd_selected != rd)
624     GNUNET_free_non_null (rd_selected);
625
626   if (NULL != zone_key)
627     lnr_msg->public_key = *zone_key;
628   if (GNUNET_YES == authoritative)
629   {
630     /* use new created signature */
631     lnr_msg->contains_sig = htons (GNUNET_YES);
632     GNUNET_assert (NULL != signature_new);
633     lnr_msg->signature = *signature_new;
634     GNUNET_free (signature_new);
635   }
636   else if (GNUNET_YES == contains_signature)
637   {
638     /* use existing signature */
639     lnr_msg->contains_sig = htons (GNUNET_YES);
640     GNUNET_assert (NULL != signature);
641     lnr_msg->signature = *signature;
642   }
643   GNUNET_SERVER_notification_context_unicast (snc, lnc->nc->client, 
644                                               &lnr_msg->gns_header.header, 
645                                               GNUNET_NO);
646   GNUNET_free (lnr_msg);
647 }
648
649
650 /**
651  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME' message
652  *
653  * @param cls unused
654  * @param client GNUNET_SERVER_Client sending the message
655  * @param message message of type 'struct LookupNameMessage'
656  */
657 static void
658 handle_lookup_name (void *cls,
659                     struct GNUNET_SERVER_Client *client,
660                     const struct GNUNET_MessageHeader *message)
661 {
662   const struct LookupNameMessage *ln_msg;
663   struct LookupNameContext lnc;
664   struct GNUNET_NAMESTORE_Client *nc;
665   size_t name_len;
666   const char *name;
667   uint32_t rid;
668   uint32_t type;
669
670   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
671               "Received `%s' message\n", 
672               "NAMESTORE_LOOKUP_NAME");
673   if (ntohs (message->size) < sizeof (struct LookupNameMessage))
674   {
675     GNUNET_break (0);
676     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
677     return;
678   }
679   if (NULL == (nc = client_lookup(client)))
680   {
681     GNUNET_break (0);
682     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
683     return;
684   }
685   ln_msg = (const struct LookupNameMessage *) message;
686   rid = ntohl (ln_msg->gns_header.r_id);
687   name_len = ntohl (ln_msg->name_len);
688   type = ntohl (ln_msg->record_type);
689   if ((0 == name_len) || (name_len > MAX_NAME_LEN))
690   {
691     GNUNET_break (0);
692     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
693     return;
694   }
695   name = (const char *) &ln_msg[1];
696   if (name[name_len -1] != '\0')
697   {
698     GNUNET_break (0);
699     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
700     return;
701   }
702   if (GNUNET_NAMESTORE_TYPE_ANY == type)
703     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
704                 "Looking up all records for name `%s' in zone `%s'\n", 
705                 name, 
706                 GNUNET_short_h2s(&ln_msg->zone));
707   else
708     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
709                 "Looking up records with type %u for name `%s' in zone `%s'\n", 
710                 type, name, 
711                 GNUNET_short_h2s(&ln_msg->zone));
712
713   /* do the actual lookup */
714   lnc.request_id = rid;
715   lnc.nc = nc;
716   lnc.record_type = type;
717   lnc.name = name;
718   lnc.zone = &ln_msg->zone;
719   if (GNUNET_SYSERR ==
720       GSN_database->iterate_records (GSN_database->cls, 
721                                      &ln_msg->zone, name, 0 /* offset */, 
722                                      &handle_lookup_name_it, &lnc))
723   {
724     /* internal error (in database plugin); might be best to just hang up on
725        plugin rather than to signal that there are 'no' results, which 
726        might also be false... */
727     GNUNET_break (0); 
728     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
729     return;
730   }
731   GNUNET_SERVER_receive_done (client, GNUNET_OK);
732 }
733
734
735 /**
736  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT' message
737  *
738  * @param cls unused
739  * @param client GNUNET_SERVER_Client sending the message
740  * @param message message of type 'struct RecordPutMessage'
741  */
742 static void
743 handle_record_put (void *cls,
744                    struct GNUNET_SERVER_Client *client,
745                    const struct GNUNET_MessageHeader *message)
746 {
747   struct GNUNET_NAMESTORE_Client *nc;
748   const struct RecordPutMessage *rp_msg;
749   struct GNUNET_TIME_Absolute expire;
750   const struct GNUNET_CRYPTO_RsaSignature *signature;
751   struct RecordPutResponseMessage rpr_msg;
752   struct GNUNET_CRYPTO_ShortHashCode zone_hash;
753   size_t name_len;
754   size_t msg_size;
755   size_t msg_size_exp;
756   const char *name;
757   const char *rd_ser;
758   uint32_t rid;
759   uint32_t rd_ser_len;
760   uint32_t rd_count;
761   int res;
762
763   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
764               "Received `%s' message\n",
765               "NAMESTORE_RECORD_PUT");
766   if (ntohs (message->size) < sizeof (struct RecordPutMessage))
767   {
768     GNUNET_break (0);
769     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
770     return;
771   }
772   if (NULL == (nc = client_lookup (client)))
773   {
774     GNUNET_break (0);
775     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
776     return;
777   }
778   rp_msg = (const struct RecordPutMessage *) message;
779   rid = ntohl (rp_msg->gns_header.r_id);
780   msg_size = ntohs (rp_msg->gns_header.header.size);
781   name_len = ntohs (rp_msg->name_len);
782   rd_count = ntohs (rp_msg->rd_count);
783   rd_ser_len = ntohs (rp_msg->rd_len);
784   if ((rd_count < 1) || (rd_ser_len < 1) || (name_len >= MAX_NAME_LEN) || (0 == name_len))
785   {
786     GNUNET_break (0);
787     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
788     return;
789   }
790   msg_size_exp = sizeof (struct RecordPutMessage) + name_len + rd_ser_len;
791   if (msg_size != msg_size_exp)
792   {
793     GNUNET_break (0);
794     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
795     return;
796   }
797   name = (const char *) &rp_msg[1];
798   if ('\0' != name[name_len -1])
799   {
800     GNUNET_break (0);
801     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
802     return;
803   }
804   expire = GNUNET_TIME_absolute_ntoh (rp_msg->expire);
805   signature = &rp_msg->signature;
806   rd_ser = &name[name_len];
807   {
808     struct GNUNET_NAMESTORE_RecordData rd[rd_count];
809
810     if (GNUNET_OK !=
811         GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_ser, rd_count, rd))
812     {
813       GNUNET_break (0);
814       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
815       return;
816     }
817     GNUNET_CRYPTO_short_hash (&rp_msg->public_key, 
818                               sizeof (rp_msg->public_key), 
819                               &zone_hash);
820     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
821                 "Putting %u records under name `%s' in zone `%s'\n",
822                 rd_count, name,
823                 GNUNET_short_h2s (&zone_hash));
824     res = GSN_database->put_records(GSN_database->cls,
825                                     &rp_msg->public_key,
826                                     expire,
827                                     name,
828                                     rd_count, rd,
829                                     signature);
830     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
831                 "Putting record for name `%s': %s\n",
832                 name, 
833                 (res == GNUNET_OK) ? "OK" : "FAILED");
834   }
835   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
836               "Sending `%s' message\n", 
837               "RECORD_PUT_RESPONSE");
838   rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE);
839   rpr_msg.gns_header.header.size = htons (sizeof (struct RecordPutResponseMessage));
840   rpr_msg.gns_header.r_id = htonl (rid);
841   rpr_msg.op_result = htonl (res);
842   GNUNET_SERVER_notification_context_unicast (snc, 
843                                               nc->client, 
844                                               &rpr_msg.gns_header.header, 
845                                               GNUNET_NO);
846   GNUNET_SERVER_receive_done (client, GNUNET_OK);
847 }
848
849
850 /**
851  * Context for record create operations passed from 'handle_record_create' to
852  * 'handle_create_record_it' as closure
853  */
854 struct CreateRecordContext
855 {
856   /**
857    * Record data
858    */
859   const struct GNUNET_NAMESTORE_RecordData *rd;
860
861   /**
862    * Zone's public key
863    */
864   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey;
865
866   /**
867    * Name for the record to create
868    */
869   const char *name;
870
871   /**
872    * Record expiration time
873    */
874   struct GNUNET_TIME_Absolute expire;
875
876   /**
877    * result returned from 'handle_create_record_it'
878    * GNUNET_SYSERR: failed to create the record
879    * GNUNET_NO: we updated an existing record or identical entry existed
880    * GNUNET_YES : we created a new record
881    */
882   int res;
883 };
884
885
886 /**
887  * A 'GNUNET_NAMESTORE_RecordIterator' for record create operations
888  * in handle_record_create
889  *
890  * @param cls a 'struct CreateRecordContext *' with information about the request
891  * @param pubkey zone key of the zone
892  * @param expire expiration time
893  * @param name name
894  * @param rd_count number of records
895  * @param rd array of records
896  * @param signature signature
897  */
898 static void
899 handle_create_record_it (void *cls,
900                          const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey,
901                          struct GNUNET_TIME_Absolute expire,
902                          const char *name,
903                          unsigned int rd_count,
904                          const struct GNUNET_NAMESTORE_RecordData *rd,
905                          const struct GNUNET_CRYPTO_RsaSignature *signature)
906 {
907   static struct GNUNET_CRYPTO_RsaSignature dummy_signature;
908   struct CreateRecordContext *crc = cls;
909   struct GNUNET_NAMESTORE_RecordData *rd_new;
910   struct GNUNET_TIME_Absolute block_expiration;
911   int exist;
912   int update;
913   unsigned int c;
914   unsigned int rd_count_new;
915
916   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
917               "Found %u existing records for `%s'\n", 
918               rd_count, crc->name);
919   exist = -1;
920   update = GNUNET_NO;
921   for (c = 0; c < rd_count; c++)
922   {
923     if (crc->rd->record_type != rd[c].record_type)
924       continue; /* no match */
925     if ( (GNUNET_NAMESTORE_TYPE_PKEY == crc->rd->record_type) ||
926          (GNUNET_NAMESTORE_TYPE_PSEU == crc->rd->record_type) )
927     {
928       /* Update unique PKEY or PSEU */
929       /* FIXME: should we do this test here? Is this not something
930          that should be handled closer to the UI? If not, what 
931          about othrer 'unique' record types like CNAME? */
932       exist = c;
933       if ( (crc->rd->data_size != rd[c].data_size) ||
934            (0 != memcmp (crc->rd->data, rd[c].data, rd[c].data_size)) ||
935            (crc->rd->expiration_time != rd[c].expiration_time) ||
936            ((crc->rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) 
937             != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) )
938         update = GNUNET_YES;
939       break;
940     }
941     if ( (crc->rd->data_size == rd[c].data_size) &&
942          (0 == memcmp (crc->rd->data, rd[c].data, rd[c].data_size)))
943     {
944       /* FIXME: again, do we need to handle this special case here? */
945       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
946                   "Found matching existing record for `%s'; only updating expiration date!\n",
947                   crc->name);
948       exist = c;
949       if ( (crc->rd->expiration_time != rd[c].expiration_time) &&
950            ((crc->rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) 
951             == (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) ) )
952         update = GNUNET_YES;
953       break;
954     }
955   }
956
957   if ( (-1 != exist) &&
958        (GNUNET_NO == update) )
959   {
960     /* Exact same record already exists */
961     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
962                 "Matching record for %s' exists, no change required!\n",
963                 crc->name);
964     crc->res = GNUNET_NO; /* identical record existed */
965     return;
966   }
967   if (-1 == exist)
968   {
969     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
970                 "No existing record for name `%s'!\n", 
971                 crc->name);
972     rd_count_new = rd_count + 1;
973     rd_new = GNUNET_malloc (rd_count_new * sizeof (struct GNUNET_NAMESTORE_RecordData));
974     memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
975     rd_new[rd_count] = *(crc->rd);
976   }
977   else 
978   {
979     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
980                 "Updating existing records for `%s'!\n", 
981                 crc->name);
982     rd_count_new = rd_count;
983     rd_new = GNUNET_malloc (rd_count_new * sizeof (struct GNUNET_NAMESTORE_RecordData));
984     memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
985     rd_new[exist] = *(crc->rd);
986   }
987   block_expiration = GNUNET_TIME_absolute_max (crc->expire, expire);
988   if (GNUNET_OK !=
989       GSN_database->put_records (GSN_database->cls,
990                                  crc->pubkey,
991                                  block_expiration,
992                                  crc->name,
993                                  rd_count_new, rd_new,
994                                  &dummy_signature))
995     crc->res = GNUNET_SYSERR; /* error */
996   else if (GNUNET_YES == update)
997     crc->res = GNUNET_NO; /* update */
998   else
999     crc->res = GNUNET_YES; /* created new record */
1000   GNUNET_free (rd_new);
1001 }
1002
1003
1004 /**
1005  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE' message
1006  *
1007  * @param cls unused
1008  * @param client GNUNET_SERVER_Client sending the message
1009  * @param message message of type 'struct RecordCreateMessage'
1010  */
1011 static void
1012 handle_record_create (void *cls,
1013                       struct GNUNET_SERVER_Client *client,
1014                       const struct GNUNET_MessageHeader *message)
1015 {
1016   struct GNUNET_NAMESTORE_Client *nc;
1017   const struct RecordCreateMessage *rp_msg;
1018   struct GNUNET_NAMESTORE_CryptoContainer *cc;
1019   struct CreateRecordContext crc;
1020   struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
1021   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
1022   struct RecordCreateResponseMessage rcr_msg;
1023   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1024   struct GNUNET_HashCode long_hash;
1025   size_t name_len;
1026   size_t msg_size;
1027   size_t msg_size_exp;
1028   size_t rd_ser_len;
1029   size_t key_len;
1030   uint32_t rid;
1031   const char *pkey_tmp;
1032   const char *name_tmp;
1033   const char *rd_ser;
1034   unsigned int rd_count;
1035   int res;
1036   struct GNUNET_NAMESTORE_RecordData rd;
1037
1038   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1039               "Received `%s' message\n", "NAMESTORE_RECORD_CREATE");
1040   if (ntohs (message->size) < sizeof (struct RecordCreateMessage))
1041   {
1042     GNUNET_break (0);
1043     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1044     return;
1045   }
1046   if (NULL == (nc = client_lookup (client)))
1047   {
1048     GNUNET_break (0);
1049     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1050     return;
1051   }
1052   rp_msg = (const struct RecordCreateMessage *) message;
1053   rid = ntohl (rp_msg->gns_header.r_id);
1054   name_len = ntohs (rp_msg->name_len);
1055   msg_size = ntohs (message->size);
1056   rd_count = ntohs (rp_msg->rd_count);
1057   rd_ser_len = ntohs (rp_msg->rd_len);
1058   key_len = ntohs (rp_msg->pkey_len);
1059   msg_size_exp = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len;
1060   if ( (msg_size != msg_size_exp) || (1 != rd_count) )
1061   {
1062     GNUNET_break (0);
1063     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1064     return;
1065   }
1066   if ((0 == name_len) || (name_len > MAX_NAME_LEN))
1067   {
1068     GNUNET_break (0);
1069     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1070     return;
1071   }
1072   pkey_tmp = (const char *) &rp_msg[1];
1073   name_tmp = &pkey_tmp[key_len];
1074   rd_ser = &name_tmp[name_len];
1075   if (name_tmp[name_len -1] != '\0')
1076   {
1077     GNUNET_break (0);
1078     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1079     return;
1080   }
1081   if (NULL == (pkey = GNUNET_CRYPTO_rsa_decode_key (pkey_tmp, key_len)))
1082   {
1083     GNUNET_break (0);
1084     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1085     return;
1086   }
1087   if (GNUNET_OK !=
1088       GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, &rd))
1089   {
1090     GNUNET_break (0);
1091     GNUNET_CRYPTO_rsa_key_free (pkey);
1092     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1093     return;
1094   }
1095
1096   /* Extracting and converting private key */
1097   GNUNET_CRYPTO_rsa_key_get_public (pkey, &pub);
1098   GNUNET_CRYPTO_short_hash (&pub,
1099                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1100                             &pubkey_hash);
1101   GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
1102
1103   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
1104   {
1105     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1106                 "Received new private key for zone `%s'\n",
1107                 GNUNET_short_h2s(&pubkey_hash));
1108     cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
1109     cc->privkey = pkey;
1110     pkey = NULL;
1111     cc->zone = pubkey_hash;
1112     GNUNET_assert (GNUNET_YES ==
1113                    GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc, 
1114                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1115   }
1116
1117   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1118               "Creating record for name `%s' in zone `%s'\n",
1119               name_tmp, GNUNET_short_h2s(&pubkey_hash));
1120   crc.expire = GNUNET_TIME_absolute_ntoh(rp_msg->expire);
1121   crc.res = GNUNET_SYSERR;
1122   crc.pubkey = &pub;
1123   crc.rd = &rd;
1124   crc.name = name_tmp;
1125
1126   /* Get existing records for name */
1127   res = GSN_database->iterate_records (GSN_database->cls, &pubkey_hash, name_tmp, 0, 
1128                                        &handle_create_record_it, &crc);
1129   if (res != GNUNET_SYSERR)
1130     res = GNUNET_OK;
1131   if (NULL != pkey)
1132     GNUNET_CRYPTO_rsa_key_free (pkey);
1133
1134   /* Send response */
1135   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1136               "Sending `%s' message\n", "RECORD_CREATE_RESPONSE");
1137   rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE);
1138   rcr_msg.gns_header.header.size = htons (sizeof (struct RecordCreateResponseMessage));
1139   rcr_msg.gns_header.r_id = htonl (rid);
1140   if ((GNUNET_OK == res) && (crc.res == GNUNET_YES))
1141     rcr_msg.op_result = htonl (GNUNET_YES);
1142   else if ((GNUNET_OK == res) && (crc.res == GNUNET_NO))
1143     rcr_msg.op_result = htonl (GNUNET_NO);
1144   else
1145     rcr_msg.op_result = htonl (GNUNET_SYSERR);
1146   GNUNET_SERVER_notification_context_unicast (snc, nc->client,
1147                                               &rcr_msg.gns_header.header,
1148                                               GNUNET_NO);
1149   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1150 }
1151
1152
1153 /////////////////////////////////////////////////////////////
1154
1155
1156 /**
1157  * Context for record remove operations passed from 'handle_record_remove' to
1158  * 'handle_record_remove_it' as closure
1159  */
1160 struct RemoveRecordContext
1161 {
1162   /**
1163    * Record to remove
1164    */
1165   const struct GNUNET_NAMESTORE_RecordData *rd;
1166
1167   /**
1168    * See RECORD_REMOVE_RESULT_*-codes.  Set by 'handle_record_remove_it'
1169    * to the result of the operation.
1170    */
1171   int32_t op_res;
1172 };
1173
1174
1175 /**
1176  * We are to remove a record (or all records for a given name).  This function
1177  * will be called with the existing records (if there are any) and is to then
1178  * compute what to keep and trigger the necessary changes.
1179  *
1180  * @param cls the 'struct RecordRemoveContext' with information about what to remove
1181  * @param zone_key public key of the zone
1182  * @param expire when does the corresponding block in the DHT expire (until
1183  *               when should we never do a DHT lookup for the same name again)?
1184  * @param name name that is being mapped (at most 255 characters long)
1185  * @param rd_count number of entries in 'rd' array
1186  * @param rd array of records with data to store
1187  * @param signature signature of the record block, NULL if signature is unavailable (i.e. 
1188  *        because the user queried for a particular record type only)
1189  */
1190 static void
1191 handle_record_remove_it (void *cls,
1192                          const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1193                          struct GNUNET_TIME_Absolute expire,
1194                          const char *name,
1195                          unsigned int rd_count,
1196                          const struct GNUNET_NAMESTORE_RecordData *rd,
1197                          const struct GNUNET_CRYPTO_RsaSignature *signature)
1198 {
1199   static struct GNUNET_CRYPTO_RsaSignature dummy_signature;
1200   struct RemoveRecordContext *rrc = cls;
1201   unsigned int c;
1202   int found;
1203   unsigned int rd_count_new;
1204
1205   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1206               "Name `%s 'currently has %u records\n", 
1207               name, rd_count);
1208   if (0 == rd_count)
1209   {
1210     /* Could not find record to remove */
1211     rrc->op_res = RECORD_REMOVE_RESULT_NO_RECORDS;
1212     return;
1213   }
1214
1215   /* Find record to remove */
1216   found = GNUNET_SYSERR;
1217   for (c = 0; c < rd_count; c++)
1218   {
1219     /*
1220     if (rd[c].flags != rrc->rd->flags)
1221        continue;*/
1222     if (rd[c].record_type != rrc->rd->record_type)
1223        continue;
1224     /*
1225     if (rd[c].data_size != rrc->rd->data_size)
1226        continue;
1227     GNUNET_break(0);
1228     if (0 != memcmp (rd[c].data, rrc->rd->data, rrc->rd->data_size))
1229         continue;
1230     GNUNET_break(0); */
1231     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found record to remove!\n", rd_count);
1232     found = c;
1233     break;
1234   }
1235   if (GNUNET_SYSERR == found)
1236   {
1237     /* Could not find record to remove */
1238     rrc->op_res = RECORD_REMOVE_RESULT_RECORD_NOT_FOUND;
1239     return;
1240   }
1241
1242   if (1 == rd_count)
1243   {
1244     struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1245
1246     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1247                 "No records left for name `%s', removing name\n",
1248                 name);
1249     GNUNET_CRYPTO_short_hash (zone_key, 
1250                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
1251                               &pubkey_hash);
1252     if (GNUNET_OK !=
1253         GSN_database->remove_records (GSN_database->cls,
1254                                       &pubkey_hash,
1255                                       name))
1256     {
1257       /* Could not remove records from database */
1258       rrc->op_res = RECORD_REMOVE_RESULT_FAILED_TO_REMOVE;
1259       return;
1260     }
1261     rrc->op_res = RECORD_REMOVE_RESULT_SUCCESS;
1262     return;
1263   }
1264
1265   rd_count_new = rd_count - 1;
1266   struct GNUNET_NAMESTORE_RecordData rd_new[rd_count_new];
1267   unsigned int c2 = 0;
1268   for (c = 0; c < rd_count; c++)
1269   {
1270     if (c != found)
1271     {
1272       GNUNET_assert (c2 < rd_count_new);
1273       rd_new[c2] = rd[c];
1274       c2++;
1275     }
1276   }
1277
1278   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name `%s' now has %u records\n", name, rd_count_new);
1279   if (GNUNET_OK !=
1280       GSN_database->put_records(GSN_database->cls,
1281                                 zone_key,
1282                                 expire,
1283                                 name,
1284                                 rd_count_new, rd_new,
1285                                 &dummy_signature))
1286   {
1287     /* Could not put records into database */
1288     rrc->op_res = RECORD_REMOVE_RESULT_FAILED_TO_PUT_UPDATE;
1289     return;
1290   }
1291   rrc->op_res = RECORD_REMOVE_RESULT_SUCCESS;
1292 }
1293
1294
1295 /**
1296  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE' message
1297  *
1298  * @param cls unused
1299  * @param client GNUNET_SERVER_Client sending the message
1300  * @param message message of type 'struct RecordRemoveMessage'
1301  */
1302 static void
1303 handle_record_remove (void *cls,
1304                       struct GNUNET_SERVER_Client *client,
1305                       const struct GNUNET_MessageHeader *message)
1306 {
1307   struct GNUNET_NAMESTORE_Client *nc;
1308   const struct RecordRemoveMessage *rr_msg;
1309   struct RecordRemoveResponseMessage rrr_msg;
1310   struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
1311   struct GNUNET_NAMESTORE_CryptoContainer *cc;
1312   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
1313   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1314   struct GNUNET_HashCode long_hash;
1315   struct GNUNET_NAMESTORE_RecordData rd;
1316   const char *pkey_tmp;
1317   const char *name_tmp;
1318   const char *rd_ser;
1319   size_t key_len;
1320   size_t name_len;
1321   size_t rd_ser_len;
1322   size_t msg_size;
1323   size_t msg_size_exp;
1324   uint32_t rd_count;
1325   uint32_t rid;
1326   struct RemoveRecordContext rrc;
1327   int res;
1328
1329   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_REMOVE");
1330   if (ntohs (message->size) < sizeof (struct RecordRemoveMessage))
1331   {
1332     GNUNET_break (0);
1333     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1334     return;
1335   }
1336   if (NULL == (nc = client_lookup(client)))
1337   {
1338     GNUNET_break (0);
1339     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1340     return;
1341   }
1342   rr_msg = (const struct RecordRemoveMessage *) message;
1343   rid = ntohl (rr_msg->gns_header.r_id);
1344   name_len = ntohs (rr_msg->name_len);
1345   rd_ser_len = ntohs (rr_msg->rd_len);
1346   rd_count = ntohs (rr_msg->rd_count);
1347   key_len = ntohs (rr_msg->pkey_len);
1348   msg_size = ntohs (message->size);
1349   if ((name_len >= MAX_NAME_LEN) || (0 == name_len) || (1 < rd_count) )
1350   {
1351     GNUNET_break (0);
1352     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1353     return;
1354   }
1355   msg_size_exp = sizeof (struct RecordRemoveMessage) + key_len + name_len + rd_ser_len;
1356   if (msg_size != msg_size_exp)
1357   {
1358     GNUNET_break (0);
1359     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1360     return;
1361   }
1362   pkey_tmp = (const char *) &rr_msg[1];
1363   name_tmp = &pkey_tmp[key_len];
1364   rd_ser = &name_tmp[name_len];
1365   if ('\0' != name_tmp[name_len -1])
1366   {
1367     GNUNET_break (0);
1368     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1369     return;
1370   }
1371   if (NULL == (pkey = GNUNET_CRYPTO_rsa_decode_key (pkey_tmp, key_len)))
1372   {
1373     GNUNET_break (0);
1374     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1375     return;
1376   }
1377   GNUNET_CRYPTO_rsa_key_get_public (pkey, &pub);
1378   GNUNET_CRYPTO_short_hash (&pub, 
1379                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
1380                             &pubkey_hash);
1381   GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
1382   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (zonekeys, &long_hash))
1383   {
1384     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1385                 "Received new private key for zone `%s'\n",
1386                 GNUNET_short_h2s (&pubkey_hash));
1387     cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
1388     cc->privkey = GNUNET_CRYPTO_rsa_decode_key (pkey_tmp, key_len);
1389     cc->zone = pubkey_hash;
1390     GNUNET_assert (GNUNET_YES ==
1391                    GNUNET_CONTAINER_multihashmap_put (zonekeys, 
1392                                                       &long_hash, cc, 
1393                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1394   }
1395   if (GNUNET_OK !=
1396       GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, &rd))
1397   {
1398     GNUNET_break (0);
1399     GNUNET_CRYPTO_rsa_key_free (pkey);
1400     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1401     return;
1402   }
1403
1404   if (0 == rd_count)
1405   {
1406     /* remove the whole name and all records */
1407     res = GSN_database->remove_records (GSN_database->cls,
1408                                         &pubkey_hash,
1409                                         name_tmp);
1410     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1411                 "Removing name `%s': %s\n",
1412                 name_tmp, (GNUNET_OK == res) ? "OK" : "FAIL");
1413     if (GNUNET_OK != res)
1414       /* Could not remove entry from database */
1415       res = RECORD_REMOVE_RESULT_FAILED_TO_PUT_UPDATE;
1416     else
1417       res = RECORD_REMOVE_RESULT_SUCCESS;
1418   }
1419   else
1420   {
1421     /* remove a single record */
1422     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1423                 "Removing record for name `%s' in zone `%s'\n", name_tmp, 
1424                 GNUNET_short_h2s (&pubkey_hash));
1425     rrc.rd = &rd;
1426     res = GSN_database->iterate_records (GSN_database->cls,
1427                                          &pubkey_hash,
1428                                          name_tmp,
1429                                          0,
1430                                          handle_record_remove_it, &rrc);
1431
1432     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1433                 "Removing record for name `%s': %s\n",
1434                 name_tmp, 
1435                 (0 == rrc.op_res) ? "OK" : "FAIL");
1436     res = rrc.op_res;
1437   }
1438   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1439               "Sending `%s' message\n",
1440               "RECORD_REMOVE_RESPONSE");
1441   rrr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE);
1442   rrr_msg.gns_header.header.size = htons (sizeof (struct RecordRemoveResponseMessage));
1443   rrr_msg.gns_header.r_id = htonl (rid);
1444   rrr_msg.op_result = htonl (res);
1445   GNUNET_SERVER_notification_context_unicast (snc, nc->client, 
1446                                               &rrr_msg.gns_header.header,
1447                                               GNUNET_NO);
1448   GNUNET_CRYPTO_rsa_key_free (pkey);
1449   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1450 }
1451
1452
1453 /**
1454  * Context for record remove operations passed from 'handle_zone_to_name' to
1455  * 'handle_zone_to_name_it' as closure
1456  */
1457 struct ZoneToNameCtx
1458 {
1459   /**
1460    * Namestore client
1461    */
1462   struct GNUNET_NAMESTORE_Client *nc;
1463
1464   /**
1465    * Request id
1466    */
1467   uint32_t rid;
1468
1469   /**
1470    * Set to GNUNET_OK on success, GNUNET_SYSERR on error
1471    */
1472   int success;
1473 };
1474
1475
1476 /**
1477  * Zone to name iterator
1478  *
1479  * @param cls struct ZoneToNameCtx *
1480  * @param zone_key the zone key
1481  * @param expire expiration date
1482  * @param name name
1483  * @param rd_count number of records
1484  * @param rd record data
1485  * @param signature signature
1486  */
1487 static void
1488 handle_zone_to_name_it (void *cls,
1489                         const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1490                         struct GNUNET_TIME_Absolute expire,
1491                         const char *name,
1492                         unsigned int rd_count,
1493                         const struct GNUNET_NAMESTORE_RecordData *rd,
1494                         const struct GNUNET_CRYPTO_RsaSignature *signature)
1495 {
1496   struct ZoneToNameCtx *ztn_ctx = cls;
1497   struct ZoneToNameResponseMessage *ztnr_msg;
1498   int16_t res;
1499   size_t name_len;
1500   size_t rd_ser_len;
1501   size_t msg_size;
1502   char *name_tmp;
1503   char *rd_tmp;
1504   char *sig_tmp;
1505
1506   if ((zone_key != NULL) && (name != NULL))
1507   {
1508     /* found result */
1509     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found results: name is `%s', has %u records\n", name, rd_count);
1510     res = GNUNET_YES;
1511     name_len = strlen (name) + 1;
1512   }
1513   else
1514   {
1515     /* no result found */
1516     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found no results\n");
1517     res = GNUNET_NO;
1518     name_len = 0;
1519   }
1520
1521   if (rd_count > 0)
1522     rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1523   else
1524     rd_ser_len = 0;
1525
1526   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1527               "Sending `%s' message\n", 
1528               "ZONE_TO_NAME_RESPONSE");
1529   msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1530   if (NULL != signature)
1531     msg_size += sizeof (struct GNUNET_CRYPTO_RsaSignature);
1532   if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1533   {
1534     GNUNET_break (0);
1535     ztn_ctx->success = GNUNET_SYSERR;
1536     return;
1537   }
1538   ztnr_msg = GNUNET_malloc (msg_size);
1539   ztnr_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1540   ztnr_msg->gns_header.header.size = htons (msg_size);
1541   ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1542   ztnr_msg->res = htons (res);
1543   ztnr_msg->rd_len = htons (rd_ser_len);
1544   ztnr_msg->rd_count = htons (rd_count);
1545   ztnr_msg->name_len = htons (name_len);
1546   ztnr_msg->expire = GNUNET_TIME_absolute_hton (expire);
1547   if (NULL != zone_key)
1548     ztnr_msg->zone_key = *zone_key;
1549   name_tmp = (char *) &ztnr_msg[1];
1550   if (NULL != name)
1551     memcpy (name_tmp, name, name_len);
1552   rd_tmp = &name_tmp[name_len];
1553   GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_tmp);
1554   sig_tmp = &rd_tmp[rd_ser_len];
1555   if (NULL != signature)
1556     memcpy (sig_tmp, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature));
1557   ztn_ctx->success = GNUNET_OK;
1558   GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client,
1559                                               &ztnr_msg->gns_header.header,
1560                                               GNUNET_NO);
1561   GNUNET_free (ztnr_msg);
1562 }
1563
1564
1565 /**
1566  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME' message
1567  *
1568  * @param cls unused
1569  * @param client GNUNET_SERVER_Client sending the message
1570  * @param message message of type 'struct ZoneToNameMessage'
1571  */
1572 static void
1573 handle_zone_to_name (void *cls,
1574                      struct GNUNET_SERVER_Client *client,
1575                      const struct GNUNET_MessageHeader *message)
1576 {
1577   struct GNUNET_NAMESTORE_Client *nc;
1578   const struct ZoneToNameMessage *ztn_msg;
1579   struct ZoneToNameCtx ztn_ctx;
1580
1581   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1582               "Received `%s' message\n",
1583               "ZONE_TO_NAME");
1584   if (ntohs (message->size) != sizeof (struct ZoneToNameMessage))
1585   {
1586     GNUNET_break (0);
1587     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1588     return;
1589   }
1590   if (NULL == (nc = client_lookup(client)))
1591   {
1592     GNUNET_break (0);
1593     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1594     return;
1595   }
1596   ztn_msg = (const struct ZoneToNameMessage *) message;
1597   ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1598   ztn_ctx.nc = nc;
1599   ztn_ctx.success = GNUNET_SYSERR;
1600   GSN_database->zone_to_name (GSN_database->cls, 
1601                               &ztn_msg->zone,
1602                               &ztn_msg->value_zone,
1603                               &handle_zone_to_name_it, &ztn_ctx);
1604   GNUNET_SERVER_receive_done (client, ztn_ctx.success);
1605 }
1606
1607
1608 /**
1609  * Copy record, data has to be free'd separetely
1610  *
1611  * @param src source record
1612  * @param dest destination record
1613  */
1614 static void
1615 copy_record (const struct GNUNET_NAMESTORE_RecordData *src,
1616              struct GNUNET_NAMESTORE_RecordData *dest)
1617 {
1618   memcpy (dest, src, sizeof (struct GNUNET_NAMESTORE_RecordData));
1619   dest->data = GNUNET_malloc (src->data_size);
1620   memcpy ((void *) dest->data, src->data, src->data_size);
1621 }
1622
1623
1624 /**
1625  * Context for record remove operations passed from
1626  * 'find_next_zone_iteration_result' to 'zone_iteraterate_proc' as closure
1627  */
1628 struct ZoneIterationProcResult
1629 {
1630   /**
1631    * The zone iteration handle
1632    */
1633   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1634
1635   /**
1636    * Iteration result: iteration done?
1637    */
1638   int res_iteration_finished;
1639
1640   /**
1641    * Iteration result: number of records included
1642    */
1643   int records_included;
1644
1645   /**
1646    * Iteration result: is a valid signature included?
1647    */
1648   int has_signature;
1649
1650   /**
1651    * Name????
1652    */
1653   char *name;
1654
1655   /**
1656    * Zone hash
1657    */
1658   struct GNUNET_CRYPTO_ShortHashCode zone_hash;
1659
1660   /**
1661    * Record data
1662    */
1663   struct GNUNET_NAMESTORE_RecordData *rd;
1664
1665   /**
1666    * Zone's public key
1667    */
1668   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key;
1669
1670   /**
1671    * Signature
1672    */
1673   struct GNUNET_CRYPTO_RsaSignature signature;
1674
1675   /**
1676    * Expiration date
1677    */
1678   struct GNUNET_TIME_Absolute expire;
1679 };
1680
1681
1682 /**
1683  * Process results for zone iteration from database
1684  *
1685  * @param cls struct ZoneIterationProcResult *proc
1686  * @param zone_key the zone key
1687  * @param expire expiration time
1688  * @param name name
1689  * @param rd_count number of records for this name
1690  * @param rd record data
1691  * @param signature block signature
1692  */
1693 static void
1694 zone_iteraterate_proc (void *cls,
1695                        const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1696                        struct GNUNET_TIME_Absolute expire,
1697                        const char *name,
1698                        unsigned int rd_count,
1699                        const struct GNUNET_NAMESTORE_RecordData *rd,
1700                        const struct GNUNET_CRYPTO_RsaSignature *signature)
1701 {
1702   struct ZoneIterationProcResult *proc = cls;
1703   struct GNUNET_NAMESTORE_RecordData *rd_filtered;
1704   struct GNUNET_CRYPTO_RsaSignature *new_signature;
1705   struct GNUNET_NAMESTORE_CryptoContainer *cc;
1706   struct GNUNET_CRYPTO_ShortHashCode hash;
1707   struct GNUNET_HashCode long_hash;
1708   struct GNUNET_TIME_Absolute e;
1709   unsigned int rd_count_filtered  = 0;
1710   int include;
1711   int c;
1712
1713   proc->res_iteration_finished = GNUNET_NO;
1714   proc->records_included = 0;
1715
1716   if ((zone_key == NULL) && (name == NULL))
1717   {
1718     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration done\n");
1719     proc->res_iteration_finished = GNUNET_YES;
1720     proc->rd = NULL;
1721     proc->name = NULL;
1722   }
1723   else if ((zone_key != NULL) && (name != NULL)) /* just a safety check */
1724   {
1725     rd_filtered = GNUNET_malloc (rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
1726     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received result for zone iteration: `%s'\n", name);
1727     for (c = 0; c < rd_count; c++)
1728     {
1729       include = GNUNET_YES;
1730       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: 0x%x must have 0x%x \n",
1731           c, rd[c].flags, proc->zi->must_have_flags);
1732       /* Checking must have flags */
1733       if ((rd[c].flags & proc->zi->must_have_flags) == proc->zi->must_have_flags)
1734       {
1735         /* Include */
1736         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c);
1737       }
1738       else
1739       {
1740         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Not include \n", c);
1741         include = GNUNET_NO;
1742       }
1743
1744       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: 0x%x must not have 0x%x\n",
1745           c, rd[c].flags, proc->zi->must_not_have_flags);
1746       if ((rd[c].flags & proc->zi->must_not_have_flags) != 0)
1747       {
1748         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Not include \n", c);
1749         include = GNUNET_NO;
1750       }
1751       else
1752       {
1753         /* Include */
1754         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c);
1755       }
1756       if (GNUNET_YES == include)
1757       {
1758         copy_record (&rd[c], &rd_filtered[rd_count_filtered]);
1759         rd_count_filtered++;
1760       }
1761
1762     }
1763     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Included %i of %i records \n", rd_count_filtered, rd_count);
1764
1765     proc->records_included = rd_count_filtered;
1766     if (0 == rd_count_filtered)
1767     {
1768       GNUNET_free (rd_filtered);
1769       rd_filtered = NULL;
1770     }
1771     proc->rd = rd_filtered;
1772     proc->name = GNUNET_strdup(name);
1773     memcpy (&proc->zone_key, zone_key, sizeof (proc->zone_key));
1774
1775     /* Signature */
1776     proc->has_signature = GNUNET_NO;
1777     GNUNET_CRYPTO_short_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &hash);
1778     GNUNET_CRYPTO_short_hash_double(&hash, &long_hash);
1779     proc->zone_hash = hash;
1780
1781     if (GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
1782     {
1783       cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash);
1784       e = get_block_expiration_time(rd_count_filtered, rd_filtered);
1785       proc->expire = e;
1786       new_signature = GNUNET_NAMESTORE_create_signature(cc->privkey, e, name, rd_filtered, rd_count_filtered);
1787       GNUNET_assert (signature != NULL);
1788       proc->signature = (*new_signature);
1789       GNUNET_free (new_signature);
1790       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1791           name, GNUNET_short_h2s(&hash), rd_count_filtered, e.abs_value);
1792       proc->has_signature = GNUNET_YES;
1793     }
1794     else if (rd_count_filtered == rd_count)
1795     {
1796       proc->expire = expire;
1797       if (NULL != signature)
1798       {
1799         proc->signature = (*signature);
1800         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using provided signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1801             name, GNUNET_short_h2s(&hash), rd_count_filtered, expire.abs_value);
1802         proc->has_signature = GNUNET_YES;
1803       }
1804       else
1805       {
1806         memset (&proc->signature, '\0', sizeof (proc->signature));
1807         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No signature provided for `%s'\n", name);
1808       }
1809     }
1810   }
1811   else
1812   {
1813     GNUNET_break (0);
1814     return;
1815   }
1816 }
1817 /////////////////////////////////////////////////////////////
1818
1819
1820 /**
1821  * Find next zone iteration result in database
1822  *
1823  * @param proc the zone iteration processing to use
1824  */
1825 static void
1826 find_next_zone_iteration_result (struct ZoneIterationProcResult *proc)
1827 {
1828   struct GNUNET_CRYPTO_ShortHashCode *zone;
1829
1830   if (GNUNET_YES == proc->zi->has_zone)
1831     zone = &proc->zi->zone;
1832   else
1833     zone = NULL;
1834   do
1835   {
1836     if (GNUNET_SYSERR ==
1837         GSN_database->iterate_records (GSN_database->cls, zone, NULL, 
1838                                        proc->zi->offset, 
1839                                        &zone_iteraterate_proc, proc))
1840     {
1841       GNUNET_break (0);
1842       break;
1843     }
1844     proc->zi->offset++;
1845   }
1846   while ((0 == proc->records_included) && (GNUNET_NO == proc->res_iteration_finished));
1847 }
1848
1849
1850 /**
1851  * Send zone iteration result to client
1852  *
1853  * @param proc the zone iteration processing result to send
1854  */
1855 static void
1856 send_zone_iteration_result (struct ZoneIterationProcResult *proc)
1857 {
1858   struct GNUNET_NAMESTORE_ZoneIteration *zi = proc->zi;
1859   struct ZoneIterationResponseMessage zir_end;
1860   struct ZoneIterationResponseMessage *zir_msg;
1861   size_t name_len;
1862   size_t rd_ser_len;
1863   size_t msg_size;
1864   char *name_tmp;
1865   char *rd_ser;
1866
1867   if (GNUNET_YES == proc->res_iteration_finished)
1868   {
1869     if (zi->has_zone == GNUNET_YES)
1870       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1871                   "No more results for zone `%s'\n", 
1872                   GNUNET_short_h2s(&zi->zone));
1873     else
1874       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1875                   "No more results for all zones\n");
1876     memset (&zir_end, 0, sizeof (zir_end));
1877     zir_end.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1878     zir_end.gns_header.header.size = htons (sizeof (struct ZoneIterationResponseMessage));
1879     zir_end.gns_header.r_id = htonl(zi->request_id);
1880     GNUNET_SERVER_notification_context_unicast (snc, 
1881                                                 zi->client->client, 
1882                                                 &zir_end.gns_header.header, GNUNET_NO);
1883     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing zone iterator\n");
1884     GNUNET_CONTAINER_DLL_remove (zi->client->op_head, zi->client->op_tail, zi);
1885     GNUNET_free (zi);
1886     return;
1887   }
1888   GNUNET_assert (proc->records_included > 0);
1889   if (GNUNET_YES == zi->has_zone)
1890     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1891                 "Sending name `%s' for iteration over zone `%s'\n",
1892                 proc->name, GNUNET_short_h2s(&zi->zone));
1893   else
1894     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1895                 "Sending name `%s' for iteration over all zones\n",
1896                 proc->name);
1897   name_len = strlen (proc->name) + 1;
1898   rd_ser_len = GNUNET_NAMESTORE_records_get_size(proc->records_included, proc->rd);  
1899   msg_size = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_ser_len;
1900
1901   zir_msg = GNUNET_malloc(msg_size);
1902   zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1903   zir_msg->gns_header.header.size = htons (msg_size);
1904   zir_msg->gns_header.r_id = htonl(zi->request_id);
1905   zir_msg->expire = GNUNET_TIME_absolute_hton(proc->expire);
1906   zir_msg->reserved = htons (0);
1907   zir_msg->name_len = htons (name_len);
1908   zir_msg->rd_count = htons (proc->records_included);
1909   zir_msg->rd_len = htons (rd_ser_len);
1910   zir_msg->signature = proc->signature;
1911   zir_msg->public_key = proc->zone_key;
1912   name_tmp = (char *) &zir_msg[1];
1913   memcpy (name_tmp, proc->name, name_len);
1914   rd_ser = &name_tmp[name_len];
1915   GNUNET_NAMESTORE_records_serialize (proc->records_included, proc->rd, rd_ser_len, rd_ser);
1916   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1917               "Sending `%s' message with size %u\n", 
1918               "ZONE_ITERATION_RESPONSE",
1919               msg_size);
1920   GNUNET_SERVER_notification_context_unicast (snc, zi->client->client, 
1921                                               (const struct GNUNET_MessageHeader *) zir_msg,
1922                                               GNUNET_NO);
1923   GNUNET_free (zir_msg);
1924 }
1925
1926
1927 /**
1928  * Clean up after zone iteration
1929  * @param proc the zone iteration processor
1930  */
1931 static void
1932 clean_up_zone_iteration_result (struct ZoneIterationProcResult *proc)
1933 {
1934   unsigned int c;
1935
1936   GNUNET_free_non_null (proc->name);
1937   proc->name = NULL;
1938   for (c = 0; c < proc->records_included; c++)  
1939     GNUNET_free ((void *) proc->rd[c].data);  
1940   GNUNET_free_non_null (proc->rd);
1941   proc->rd = NULL;
1942   proc->records_included = 0;
1943 }
1944
1945
1946 /**
1947  * Perform the next round of the zone iteration.
1948  *
1949  * @param zi zone iterator to process
1950  */
1951 static void
1952 run_zone_iteration_round (struct GNUNET_NAMESTORE_ZoneIteration *zi)
1953 {
1954   struct ZoneIterationProcResult proc;
1955
1956   memset (&proc, 0, sizeof (proc));
1957   proc.zi = zi;
1958   find_next_zone_iteration_result (&proc);
1959   if (GNUNET_YES == proc.res_iteration_finished)
1960   {
1961     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1962                 "Zone iteration done\n");
1963   }
1964   else if (0 != proc.records_included)
1965   {
1966     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1967                 "Zone iteration returns %u records\n", 
1968                 proc.records_included);
1969   }
1970   send_zone_iteration_result (&proc);
1971   clean_up_zone_iteration_result (&proc);
1972 }
1973
1974
1975 /**
1976  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START' message
1977  *
1978  * @param cls unused
1979  * @param client GNUNET_SERVER_Client sending the message
1980  * @param message message of type 'struct ZoneIterationStartMessage'
1981  */
1982 static void
1983 handle_iteration_start (void *cls,
1984                         struct GNUNET_SERVER_Client *client,
1985                         const struct GNUNET_MessageHeader *message)
1986 {
1987   static struct GNUNET_CRYPTO_ShortHashCode zeros;
1988   const struct ZoneIterationStartMessage *zis_msg;
1989   struct GNUNET_NAMESTORE_Client *nc;
1990   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1991
1992   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START");
1993   nc = client_lookup (client);
1994   if (NULL == nc)
1995   {
1996     GNUNET_break_op (0);
1997     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1998     return;
1999   }
2000   zis_msg = (const struct ZoneIterationStartMessage *) message;
2001   zi = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIteration));
2002   zi->request_id = ntohl (zis_msg->gns_header.r_id);
2003   zi->offset = 0;
2004   zi->client = nc;
2005   zi->must_have_flags = ntohs (zis_msg->must_have_flags);
2006   zi->must_not_have_flags = ntohs (zis_msg->must_not_have_flags);
2007   if (0 == memcmp (&zeros, &zis_msg->zone, sizeof (zeros)))
2008   {
2009     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over all zones\n");
2010     zi->zone = zis_msg->zone;
2011     zi->has_zone = GNUNET_NO;
2012   }
2013   else
2014   {
2015     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2016                 "Starting to iterate over zone `%s'\n", GNUNET_short_h2s (&zis_msg->zone));
2017     zi->zone = zis_msg->zone;
2018     zi->has_zone = GNUNET_YES;
2019   }
2020   GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
2021   run_zone_iteration_round (zi);
2022   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2023 }
2024
2025
2026 /**
2027  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP' message
2028  *
2029  * @param cls unused
2030  * @param client GNUNET_SERVER_Client sending the message
2031  * @param message message of type 'struct ZoneIterationStopMessage'
2032  */
2033 static void
2034 handle_iteration_stop (void *cls,
2035                        struct GNUNET_SERVER_Client *client,
2036                        const struct GNUNET_MessageHeader *message)
2037 {
2038   struct GNUNET_NAMESTORE_Client *nc;
2039   struct GNUNET_NAMESTORE_ZoneIteration *zi;
2040   const struct ZoneIterationStopMessage *zis_msg;
2041   uint32_t rid;
2042
2043   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2044               "Received `%s' message\n",
2045               "ZONE_ITERATION_STOP");
2046   nc = client_lookup(client);
2047   if (NULL == nc)
2048   {
2049     GNUNET_break (0);
2050     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2051     return;
2052   }
2053   zis_msg = (const struct ZoneIterationStopMessage *) message;
2054   rid = ntohl (zis_msg->gns_header.r_id);
2055   for (zi = nc->op_head; NULL != zi; zi = zi->next)
2056     if (zi->request_id == rid)
2057       break;
2058   if (NULL == zi)
2059   {
2060     GNUNET_break (0);
2061     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2062     return;
2063   }
2064   GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
2065   if (GNUNET_YES == zi->has_zone)
2066     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2067                 "Stopped zone iteration for zone `%s'\n",
2068                 GNUNET_short_h2s (&zi->zone));
2069   else
2070     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2071                 "Stopped zone iteration over all zones\n");
2072   GNUNET_free (zi);
2073   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2074 }
2075
2076
2077 /**
2078  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT' message
2079  *
2080  * @param cls unused
2081  * @param client GNUNET_SERVER_Client sending the message
2082  * @param message message of type 'struct ZoneIterationNextMessage'
2083  */
2084 static void
2085 handle_iteration_next (void *cls,
2086                        struct GNUNET_SERVER_Client *client,
2087                        const struct GNUNET_MessageHeader *message)
2088 {
2089   struct GNUNET_NAMESTORE_Client *nc;
2090   struct GNUNET_NAMESTORE_ZoneIteration *zi;
2091   const struct ZoneIterationNextMessage *zis_msg;
2092   uint32_t rid;
2093
2094   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT");
2095   nc = client_lookup(client);
2096   if (NULL == nc)
2097   {
2098     GNUNET_break (0);
2099     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2100     return;
2101   }
2102   zis_msg = (const struct ZoneIterationNextMessage *) message;
2103   rid = ntohl (zis_msg->gns_header.r_id);
2104   for (zi = nc->op_head; NULL != zi; zi = zi->next)
2105     if (zi->request_id == rid)
2106       break;
2107   if (NULL == zi)
2108   {
2109     GNUNET_break (0);
2110     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2111     return;
2112   }
2113   run_zone_iteration_round (zi);
2114   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2115 }
2116
2117
2118 /**
2119  * Load zone keys from directory by reading all .zkey files in this directory
2120  *
2121  * @param cls int * 'counter' to store the number of files found
2122  * @param filename directory to scan
2123  * @return GNUNET_OK to continue
2124  */
2125 static int
2126 zonekey_file_it (void *cls, const char *filename)
2127 {
2128   unsigned int *counter = cls;
2129   struct GNUNET_HashCode long_hash;
2130   struct GNUNET_CRYPTO_RsaPrivateKey *privkey;
2131   struct GNUNET_NAMESTORE_CryptoContainer *c;
2132   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey;
2133
2134   if ((NULL == filename) ||
2135       (NULL == strstr(filename, ".zkey")))
2136     return GNUNET_OK;
2137   privkey = GNUNET_CRYPTO_rsa_key_create_from_file (filename);
2138   if (NULL == privkey)
2139   {
2140     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2141                 _("Could not parse zone key file `%s'\n"),
2142                 filename);
2143     return GNUNET_OK;
2144   }
2145   c = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
2146   c->privkey = privkey;
2147   GNUNET_CRYPTO_rsa_key_get_public (privkey, &pubkey);
2148   GNUNET_CRYPTO_short_hash (&pubkey, 
2149                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
2150                             &c->zone);
2151   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2152               "Found zonefile for zone `%s'\n", GNUNET_short_h2s (&c->zone));
2153   GNUNET_CRYPTO_short_hash_double (&c->zone, &long_hash);
2154   GNUNET_assert (GNUNET_OK == 
2155                  GNUNET_CONTAINER_multihashmap_put (zonekeys, &long_hash, c, 
2156                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2157   (*counter)++;
2158   return GNUNET_OK;
2159 }
2160
2161
2162 /**
2163  * Process namestore requests.
2164  *
2165  * @param cls closure
2166  * @param server the initialized server
2167  * @param cfg configuration to use
2168  */
2169 static void
2170 run (void *cls, struct GNUNET_SERVER_Handle *server,
2171      const struct GNUNET_CONFIGURATION_Handle *cfg)
2172 {
2173   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2174     {&handle_start, NULL,
2175      GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)},
2176     {&handle_lookup_name, NULL,
2177      GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0},
2178     {&handle_record_put, NULL,
2179     GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT, 0},
2180     {&handle_record_create, NULL,
2181      GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE, 0},
2182     {&handle_record_remove, NULL,
2183      GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE, 0},
2184     {&handle_zone_to_name, NULL,
2185       GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, 0},
2186     {&handle_iteration_start, NULL,
2187      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage) },
2188     {&handle_iteration_next, NULL,
2189      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, sizeof (struct ZoneIterationNextMessage) },
2190      {&handle_iteration_stop, NULL,
2191       GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, sizeof (struct ZoneIterationStopMessage) },
2192     {NULL, NULL, 0, 0}
2193   };
2194   char *database;
2195   unsigned int counter;
2196
2197   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
2198   GSN_cfg = cfg;
2199
2200   /* Load private keys from disk */
2201   if (GNUNET_OK !=
2202       GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore", 
2203                                                "zonefile_directory",
2204                                                &zonefile_directory))
2205   {
2206     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
2207                 _("No directory to load zonefiles specified in configuration\n"));
2208     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2209     return;
2210   }
2211
2212   if (GNUNET_NO == GNUNET_DISK_file_test (zonefile_directory))
2213   {
2214     if (GNUNET_SYSERR == GNUNET_DISK_directory_create (zonefile_directory))
2215     {
2216       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
2217                   _("Creating directory `%s' for zone files failed!\n"),
2218                   zonefile_directory);
2219       GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2220       return;
2221     }
2222     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2223                 "Created directory `%s' for zone files\n", 
2224                 zonefile_directory);
2225   }
2226
2227   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2228               "Scanning directory `%s' for zone files\n", zonefile_directory);
2229   zonekeys = GNUNET_CONTAINER_multihashmap_create (16);
2230   counter = 0;
2231   GNUNET_DISK_directory_scan (zonefile_directory, zonekey_file_it, &counter);
2232   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2233               "Found %u zone files\n", 
2234               counter);
2235
2236   /* Loading database plugin */
2237   if (GNUNET_OK !=
2238       GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
2239                                              &database))
2240     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
2241
2242   GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
2243   GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
2244   GNUNET_free (database);
2245   if (NULL == GSN_database)
2246   {
2247     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
2248                 "Could not load database backend `%s'\n",
2249                 db_lib_name);
2250     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2251     return;
2252   }
2253
2254   /* Configuring server handles */
2255   GNUNET_SERVER_add_handlers (server, handlers);
2256   snc = GNUNET_SERVER_notification_context_create (server, 16);
2257   GNUNET_SERVER_disconnect_notify (server,
2258                                    &client_disconnect_notification,
2259                                    NULL);
2260   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
2261                                 NULL);
2262 }
2263
2264
2265 /**
2266  * The main function for the template service.
2267  *
2268  * @param argc number of arguments from the command line
2269  * @param argv command line arguments
2270  * @return 0 ok, 1 on error
2271  */
2272 int
2273 main (int argc, char *const *argv)
2274 {
2275   return (GNUNET_OK ==
2276           GNUNET_SERVICE_run (argc, argv, "namestore",
2277                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
2278 }
2279
2280 /* end of gnunet-service-namestore.c */
2281