-more namestore code cleanup
[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  * Add the given private key to the set of private keys
301  * this namestore can use to sign records when needed.
302  *
303  * @param pkey private key to add to our list (reference will
304  *        be taken over or freed and should not be used afterwards)
305  */
306 static void
307 learn_private_key (struct GNUNET_CRYPTO_RsaPrivateKey *pkey)
308 {
309   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
310   struct GNUNET_HashCode long_hash;
311   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
312   struct GNUNET_NAMESTORE_CryptoContainer *cc;
313
314   GNUNET_CRYPTO_rsa_key_get_public (pkey, &pub);
315   GNUNET_CRYPTO_short_hash (&pub,
316                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
317                             &pubkey_hash);
318   GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
319
320   if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
321   {
322     GNUNET_CRYPTO_rsa_key_free (pkey);
323     return;
324   }  
325   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
326               "Received new private key for zone `%s'\n",
327               GNUNET_short_h2s(&pubkey_hash));
328   cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
329   cc->privkey = pkey;
330   cc->zone = pubkey_hash;
331   GNUNET_assert (GNUNET_YES ==
332                  GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc, 
333                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));  
334 }
335
336
337 /**
338  * Returns the expiration time of the given block of records. The block
339  * expiration time is the expiration time of the block with smallest
340  * expiration time.
341  *
342  * @param rd_count number of records given in 'rd'
343  * @param rd array of records
344  * @return absolute expiration time
345  */
346 static struct GNUNET_TIME_Absolute
347 get_block_expiration_time (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd)
348 {
349   unsigned int c;
350   struct GNUNET_TIME_Absolute expire;
351   struct GNUNET_TIME_Absolute at;
352   struct GNUNET_TIME_Relative rt;
353
354   if (NULL == rd)
355     return GNUNET_TIME_UNIT_ZERO_ABS;
356   expire = GNUNET_TIME_UNIT_FOREVER_ABS;
357   for (c = 0; c < rd_count; c++)  
358   {
359     if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
360     {
361       rt.rel_value = rd[c].expiration_time;
362       at = GNUNET_TIME_relative_to_absolute (rt);
363     }
364     else
365     {
366       at.abs_value = rd[c].expiration_time;
367     }
368     expire = GNUNET_TIME_absolute_min (at, expire);  
369   }
370   return expire;
371 }
372
373
374 /**
375  * Task run during shutdown.
376  *
377  * @param cls unused
378  * @param tc unused
379  */
380 static void
381 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
382 {
383   struct GNUNET_NAMESTORE_ZoneIteration *no;
384   struct GNUNET_NAMESTORE_Client *nc;
385
386   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
387   if (NULL != snc)
388   {
389     GNUNET_SERVER_notification_context_destroy (snc);
390     snc = NULL;
391   }
392   GNUNET_CONTAINER_multihashmap_iterate (zonekeys, &zone_to_disk_it, NULL);
393   GNUNET_CONTAINER_multihashmap_destroy (zonekeys);
394   zonekeys = NULL;
395   while (NULL != (nc = client_head))
396   {
397     while (NULL != (no = nc->op_head))
398     {
399       GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
400       GNUNET_free (no);
401     }
402     GNUNET_SERVER_client_drop(nc->client);
403     GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
404     GNUNET_free (nc);
405   }
406   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
407   GNUNET_free (db_lib_name);
408   db_lib_name = NULL;
409   GNUNET_free_non_null (zonefile_directory);
410   zonefile_directory = NULL;
411 }
412
413
414 /**
415  * Lookup our internal data structure for a given client.
416  *
417  * @param client server client handle to use for the lookup
418  * @return our internal structure for the client, NULL if
419  *         we do not have any yet
420  */
421 static struct GNUNET_NAMESTORE_Client *
422 client_lookup (struct GNUNET_SERVER_Client *client)
423 {
424   struct GNUNET_NAMESTORE_Client *nc;
425
426   GNUNET_assert (NULL != client);
427   for (nc = client_head; NULL != nc; nc = nc->next)  
428     if (client == nc->client)
429       return nc;  
430   return NULL;
431 }
432
433
434 /**
435  * Called whenever a client is disconnected.
436  * Frees our resources associated with that client.
437  *
438  * @param cls closure
439  * @param client identification of the client
440  */
441 static void
442 client_disconnect_notification (void *cls, 
443                                 struct GNUNET_SERVER_Client *client)
444 {
445   struct GNUNET_NAMESTORE_ZoneIteration *no;
446   struct GNUNET_NAMESTORE_Client *nc;
447
448   if (NULL == client)
449     return;
450   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
451               "Client %p disconnected\n", 
452               client);
453   if (NULL == (nc = client_lookup (client)))
454     return;
455   while (NULL != (no = nc->op_head))
456   {
457     GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
458     GNUNET_free (no);
459   }
460   GNUNET_SERVER_client_drop (nc->client);
461   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
462   GNUNET_free (nc);
463 }
464
465
466 /**
467  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_START' message
468  *
469  * @param cls unused
470  * @param client GNUNET_SERVER_Client sending the message
471  * @param message unused
472  */
473 static void
474 handle_start (void *cls,
475               struct GNUNET_SERVER_Client *client,
476               const struct GNUNET_MessageHeader *message)
477 {
478   struct GNUNET_NAMESTORE_Client *nc;
479
480   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
481               "Client %p connected\n", client);
482   if (NULL != client_lookup (client))
483   {
484     GNUNET_break (0);
485     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
486     return;
487   }
488   nc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Client));
489   nc->client = client;
490   GNUNET_SERVER_notification_context_add (snc, client);
491   GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
492   GNUNET_SERVER_client_keep (client);
493   GNUNET_SERVER_receive_done (client, GNUNET_OK);
494 }
495
496
497 /**
498  * Context for name lookups passed from 'handle_lookup_name' to
499  * 'handle_lookup_name_it' as closure
500  */
501 struct LookupNameContext
502 {
503   /**
504    * The client to send the response to
505    */
506   struct GNUNET_NAMESTORE_Client *nc;
507
508   /**
509    * Requested zone
510    */
511   const struct GNUNET_CRYPTO_ShortHashCode *zone;
512
513   /**
514    * Requested name
515    */
516   const char *name;
517
518   /**
519    * Operation id for the name lookup
520    */
521   uint32_t request_id;
522
523   /**
524    * Requested specific record type
525    */
526   uint32_t record_type;
527 };
528
529
530 /**
531  * A 'GNUNET_NAMESTORE_RecordIterator' for name lookups in handle_lookup_name
532  *
533  * @param cls a 'struct LookupNameContext *' with information about the request
534  * @param zone_key zone key of the zone
535  * @param expire expiration time
536  * @param name name
537  * @param rd_count number of records
538  * @param rd array of records
539  * @param signature signature
540  */
541 static void
542 handle_lookup_name_it (void *cls,
543                        const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
544                        struct GNUNET_TIME_Absolute expire,
545                        const char *name,
546                        unsigned int rd_count,
547                        const struct GNUNET_NAMESTORE_RecordData *rd,
548                        const struct GNUNET_CRYPTO_RsaSignature *signature)
549 {
550   struct LookupNameContext *lnc = cls;
551   struct LookupNameResponseMessage *lnr_msg;
552   struct GNUNET_NAMESTORE_RecordData *rd_selected;
553   struct GNUNET_NAMESTORE_CryptoContainer *cc;
554   struct GNUNET_CRYPTO_RsaSignature *signature_new;
555   struct GNUNET_TIME_Absolute e;
556   struct GNUNET_CRYPTO_ShortHashCode zone_key_hash;
557   struct GNUNET_HashCode long_hash;
558   char *rd_tmp;
559   char *name_tmp;
560   size_t rd_ser_len;
561   size_t r_size;
562   size_t name_len;
563   int copied_elements;
564   int contains_signature;
565   int authoritative;
566   int c;
567
568   name_len = (NULL == name) ? 0 : strlen(name) + 1;
569   copied_elements = 0;
570   rd_selected = NULL;
571   /* count records to copy */
572   if (0 != lnc->record_type)
573   {
574     /* special record type needed */
575     for (c = 0; c < rd_count; c++)
576       if (rd[c].record_type == lnc->record_type)
577         copied_elements++; /* found matching record */
578     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
579                 "Found %u records with type %u for name `%s' in zone `%s'\n",
580                 copied_elements, 
581                 lnc->record_type, 
582                 lnc->name, 
583                 GNUNET_short_h2s(lnc->zone));
584     if (copied_elements > 0)
585     {
586       rd_selected = GNUNET_malloc (copied_elements * sizeof (struct GNUNET_NAMESTORE_RecordData));
587       copied_elements = 0;
588       for (c = 0; c < rd_count; c++)
589       {
590         if (rd[c].record_type == lnc->record_type)
591         {
592           /* found matching record */
593           rd_selected[copied_elements] = rd[c]; /* shallow copy! */
594           copied_elements++;
595         }
596       }
597     }
598   }
599   else
600   {
601     copied_elements = rd_count;
602     rd_selected = (struct GNUNET_NAMESTORE_RecordData *) rd;
603   }
604   // FIXME: need to adjust 'rd' from relative to absolute times!
605   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
606               "Found %u records for name `%s' in zone `%s'\n",
607               copied_elements,
608               lnc->name, 
609               GNUNET_short_h2s (lnc->zone));
610
611   if ((copied_elements == rd_count) && (NULL != signature))
612     contains_signature = GNUNET_YES; /* returning all records, so include signature */
613   else
614     contains_signature = GNUNET_NO; /* returning not all records, so do not include signature */
615
616   authoritative = GNUNET_NO;
617   signature_new = NULL;
618   if ((NULL != zone_key) && (copied_elements == rd_count))
619   {
620     GNUNET_CRYPTO_short_hash (zone_key, 
621                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
622                               &zone_key_hash);
623     GNUNET_CRYPTO_short_hash_double (&zone_key_hash, &long_hash);
624     if (NULL != (cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash)))
625     {
626       e = get_block_expiration_time (rd_count, rd);
627       signature_new = GNUNET_NAMESTORE_create_signature (cc->privkey, e, name, rd, rd_count);
628       GNUNET_assert (NULL != signature_new);
629       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
630                   "Creating signature for name `%s' with %u records in zone `%s'\n",
631                   name, 
632                   copied_elements,
633                   GNUNET_short_h2s(&zone_key_hash));
634       authoritative = GNUNET_YES;
635     }
636   }
637
638   rd_ser_len = GNUNET_NAMESTORE_records_get_size (copied_elements, rd_selected);
639   r_size = sizeof (struct LookupNameResponseMessage) +
640            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
641            name_len +
642            rd_ser_len;
643   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
644               "Sending `%s' message\n", 
645               "NAMESTORE_LOOKUP_NAME_RESPONSE");
646   lnr_msg = GNUNET_malloc (r_size);
647   lnr_msg->gns_header.header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
648   lnr_msg->gns_header.header.size = ntohs (r_size);
649   lnr_msg->gns_header.r_id = htonl (lnc->request_id);
650   lnr_msg->rd_count = htons (copied_elements);
651   lnr_msg->rd_len = htons (rd_ser_len);
652   lnr_msg->name_len = htons (name_len);
653   lnr_msg->expire = GNUNET_TIME_absolute_hton (get_block_expiration_time (copied_elements, 
654                                                                           rd_selected));
655   name_tmp = (char *) &lnr_msg[1];
656   memcpy (name_tmp, name, name_len);
657   rd_tmp = &name_tmp[name_len];
658   GNUNET_NAMESTORE_records_serialize (copied_elements, rd_selected, rd_ser_len, rd_tmp);
659
660   if (rd_selected != rd)
661     GNUNET_free_non_null (rd_selected);
662
663   if (NULL != zone_key)
664     lnr_msg->public_key = *zone_key;
665   if (GNUNET_YES == authoritative)
666   {
667     /* use new created signature */
668     lnr_msg->contains_sig = htons (GNUNET_YES);
669     GNUNET_assert (NULL != signature_new);
670     lnr_msg->signature = *signature_new;
671     GNUNET_free (signature_new);
672   }
673   else if (GNUNET_YES == contains_signature)
674   {
675     /* use existing signature */
676     lnr_msg->contains_sig = htons (GNUNET_YES);
677     GNUNET_assert (NULL != signature);
678     lnr_msg->signature = *signature;
679   }
680   GNUNET_SERVER_notification_context_unicast (snc, lnc->nc->client, 
681                                               &lnr_msg->gns_header.header, 
682                                               GNUNET_NO);
683   GNUNET_free (lnr_msg);
684 }
685
686
687 /**
688  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME' message
689  *
690  * @param cls unused
691  * @param client GNUNET_SERVER_Client sending the message
692  * @param message message of type 'struct LookupNameMessage'
693  */
694 static void
695 handle_lookup_name (void *cls,
696                     struct GNUNET_SERVER_Client *client,
697                     const struct GNUNET_MessageHeader *message)
698 {
699   const struct LookupNameMessage *ln_msg;
700   struct LookupNameContext lnc;
701   struct GNUNET_NAMESTORE_Client *nc;
702   size_t name_len;
703   const char *name;
704   uint32_t rid;
705   uint32_t type;
706
707   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
708               "Received `%s' message\n", 
709               "NAMESTORE_LOOKUP_NAME");
710   if (ntohs (message->size) < sizeof (struct LookupNameMessage))
711   {
712     GNUNET_break (0);
713     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
714     return;
715   }
716   if (NULL == (nc = client_lookup(client)))
717   {
718     GNUNET_break (0);
719     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
720     return;
721   }
722   ln_msg = (const struct LookupNameMessage *) message;
723   rid = ntohl (ln_msg->gns_header.r_id);
724   name_len = ntohl (ln_msg->name_len);
725   type = ntohl (ln_msg->record_type);
726   if ((0 == name_len) || (name_len > MAX_NAME_LEN))
727   {
728     GNUNET_break (0);
729     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
730     return;
731   }
732   name = (const char *) &ln_msg[1];
733   if ('\0' != name[name_len -1])
734   {
735     GNUNET_break (0);
736     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
737     return;
738   }
739   if (GNUNET_NAMESTORE_TYPE_ANY == type)
740     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
741                 "Looking up all records for name `%s' in zone `%s'\n", 
742                 name, 
743                 GNUNET_short_h2s(&ln_msg->zone));
744   else
745     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
746                 "Looking up records with type %u for name `%s' in zone `%s'\n", 
747                 type, name, 
748                 GNUNET_short_h2s(&ln_msg->zone));
749
750   /* do the actual lookup */
751   lnc.request_id = rid;
752   lnc.nc = nc;
753   lnc.record_type = type;
754   lnc.name = name;
755   lnc.zone = &ln_msg->zone;
756   if (GNUNET_SYSERR ==
757       GSN_database->iterate_records (GSN_database->cls, 
758                                      &ln_msg->zone, name, 0 /* offset */, 
759                                      &handle_lookup_name_it, &lnc))
760   {
761     /* internal error (in database plugin); might be best to just hang up on
762        plugin rather than to signal that there are 'no' results, which 
763        might also be false... */
764     GNUNET_break (0); 
765     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
766     return;
767   }
768   GNUNET_SERVER_receive_done (client, GNUNET_OK);
769 }
770
771
772 /**
773  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT' message
774  *
775  * @param cls unused
776  * @param client GNUNET_SERVER_Client sending the message
777  * @param message message of type 'struct RecordPutMessage'
778  */
779 static void
780 handle_record_put (void *cls,
781                    struct GNUNET_SERVER_Client *client,
782                    const struct GNUNET_MessageHeader *message)
783 {
784   struct GNUNET_NAMESTORE_Client *nc;
785   const struct RecordPutMessage *rp_msg;
786   struct GNUNET_TIME_Absolute expire;
787   const struct GNUNET_CRYPTO_RsaSignature *signature;
788   struct RecordPutResponseMessage rpr_msg;
789   struct GNUNET_CRYPTO_ShortHashCode zone_hash;
790   size_t name_len;
791   size_t msg_size;
792   size_t msg_size_exp;
793   const char *name;
794   const char *rd_ser;
795   uint32_t rid;
796   uint32_t rd_ser_len;
797   uint32_t rd_count;
798   int res;
799
800   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
801               "Received `%s' message\n",
802               "NAMESTORE_RECORD_PUT");
803   if (ntohs (message->size) < sizeof (struct RecordPutMessage))
804   {
805     GNUNET_break (0);
806     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
807     return;
808   }
809   if (NULL == (nc = client_lookup (client)))
810   {
811     GNUNET_break (0);
812     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
813     return;
814   }
815   rp_msg = (const struct RecordPutMessage *) message;
816   rid = ntohl (rp_msg->gns_header.r_id);
817   msg_size = ntohs (rp_msg->gns_header.header.size);
818   name_len = ntohs (rp_msg->name_len);
819   rd_count = ntohs (rp_msg->rd_count);
820   rd_ser_len = ntohs (rp_msg->rd_len);
821   if ((rd_count < 1) || (rd_ser_len < 1) || (name_len >= MAX_NAME_LEN) || (0 == name_len))
822   {
823     GNUNET_break (0);
824     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
825     return;
826   }
827   msg_size_exp = sizeof (struct RecordPutMessage) + name_len + rd_ser_len;
828   if (msg_size != msg_size_exp)
829   {
830     GNUNET_break (0);
831     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
832     return;
833   }
834   name = (const char *) &rp_msg[1];
835   if ('\0' != name[name_len -1])
836   {
837     GNUNET_break (0);
838     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
839     return;
840   }
841   expire = GNUNET_TIME_absolute_ntoh (rp_msg->expire);
842   signature = &rp_msg->signature;
843   rd_ser = &name[name_len];
844   {
845     struct GNUNET_NAMESTORE_RecordData rd[rd_count];
846
847     if (GNUNET_OK !=
848         GNUNET_NAMESTORE_records_deserialize(rd_ser_len, rd_ser, rd_count, rd))
849     {
850       GNUNET_break (0);
851       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
852       return;
853     }
854     GNUNET_CRYPTO_short_hash (&rp_msg->public_key, 
855                               sizeof (rp_msg->public_key), 
856                               &zone_hash);
857     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
858                 "Putting %u records under name `%s' in zone `%s'\n",
859                 rd_count, name,
860                 GNUNET_short_h2s (&zone_hash));
861     res = GSN_database->put_records(GSN_database->cls,
862                                     &rp_msg->public_key,
863                                     expire,
864                                     name,
865                                     rd_count, rd,
866                                     signature);
867     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
868                 "Putting record for name `%s': %s\n",
869                 name, 
870                 (GNUNET_OK == res) ? "OK" : "FAILED");
871   }
872   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
873               "Sending `%s' message\n", 
874               "RECORD_PUT_RESPONSE");
875   rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE);
876   rpr_msg.gns_header.header.size = htons (sizeof (struct RecordPutResponseMessage));
877   rpr_msg.gns_header.r_id = htonl (rid);
878   rpr_msg.op_result = htonl (res);
879   GNUNET_SERVER_notification_context_unicast (snc, 
880                                               nc->client, 
881                                               &rpr_msg.gns_header.header, 
882                                               GNUNET_NO);
883   GNUNET_SERVER_receive_done (client, GNUNET_OK);
884 }
885
886
887 /**
888  * Context for record create operations passed from 'handle_record_create' to
889  * 'handle_create_record_it' as closure
890  */
891 struct CreateRecordContext
892 {
893   /**
894    * Record data
895    */
896   const struct GNUNET_NAMESTORE_RecordData *rd;
897
898   /**
899    * Zone's public key
900    */
901   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey;
902
903   /**
904    * Name for the record to create
905    */
906   const char *name;
907
908   /**
909    * Record expiration time
910    */
911   struct GNUNET_TIME_Absolute expire;
912
913   /**
914    * result returned from 'handle_create_record_it'
915    * GNUNET_SYSERR: failed to create the record
916    * GNUNET_NO: we updated an existing record or identical entry existed
917    * GNUNET_YES : we created a new record
918    */
919   int res;
920 };
921
922
923 /**
924  * A 'GNUNET_NAMESTORE_RecordIterator' for record create operations
925  * in handle_record_create
926  *
927  * @param cls a 'struct CreateRecordContext *' with information about the request
928  * @param pubkey zone key of the zone
929  * @param expire expiration time
930  * @param name name
931  * @param rd_count number of records
932  * @param rd array of records
933  * @param signature signature
934  */
935 static void
936 handle_create_record_it (void *cls,
937                          const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey,
938                          struct GNUNET_TIME_Absolute expire,
939                          const char *name,
940                          unsigned int rd_count,
941                          const struct GNUNET_NAMESTORE_RecordData *rd,
942                          const struct GNUNET_CRYPTO_RsaSignature *signature)
943 {
944   static struct GNUNET_CRYPTO_RsaSignature dummy_signature;
945   struct CreateRecordContext *crc = cls;
946   struct GNUNET_NAMESTORE_RecordData *rd_new;
947   struct GNUNET_TIME_Absolute block_expiration;
948   int exist;
949   int update;
950   unsigned int c;
951   unsigned int rd_count_new;
952
953   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
954               "Found %u existing records for `%s'\n", 
955               rd_count, crc->name);
956   exist = -1;
957   update = GNUNET_NO;
958   for (c = 0; c < rd_count; c++)
959   {
960     if (crc->rd->record_type != rd[c].record_type)
961       continue; /* no match */
962     if ( (GNUNET_NAMESTORE_TYPE_PKEY == crc->rd->record_type) ||
963          (GNUNET_NAMESTORE_TYPE_PSEU == crc->rd->record_type) )
964     {
965       /* Update unique PKEY or PSEU */
966       /* FIXME: should we do this test here? Is this not something
967          that should be handled closer to the UI? If not, what 
968          about othrer 'unique' record types like CNAME? */
969       exist = c;
970       if ( (crc->rd->data_size != rd[c].data_size) ||
971            (0 != memcmp (crc->rd->data, rd[c].data, rd[c].data_size)) ||
972            (crc->rd->expiration_time != rd[c].expiration_time) ||
973            ((crc->rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) 
974             != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) )
975         update = GNUNET_YES;
976       break;
977     }
978     if ( (crc->rd->data_size == rd[c].data_size) &&
979          (0 == memcmp (crc->rd->data, rd[c].data, rd[c].data_size)))
980     {
981       /* FIXME: again, do we need to handle this special case here? */
982       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
983                   "Found matching existing record for `%s'; only updating expiration date!\n",
984                   crc->name);
985       exist = c;
986       if ( (crc->rd->expiration_time != rd[c].expiration_time) &&
987            ((crc->rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) 
988             == (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) ) )
989         update = GNUNET_YES;
990       break;
991     }
992   }
993
994   if ( (-1 != exist) &&
995        (GNUNET_NO == update) )
996   {
997     /* Exact same record already exists */
998     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
999                 "Matching record for %s' exists, no change required!\n",
1000                 crc->name);
1001     crc->res = GNUNET_NO; /* identical record existed */
1002     return;
1003   }
1004   if (-1 == exist)
1005   {
1006     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1007                 "No existing record for name `%s'!\n", 
1008                 crc->name);
1009     rd_count_new = rd_count + 1;
1010     rd_new = GNUNET_malloc (rd_count_new * sizeof (struct GNUNET_NAMESTORE_RecordData));
1011     memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
1012     rd_new[rd_count] = *(crc->rd);
1013   }
1014   else 
1015   {
1016     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1017                 "Updating existing records for `%s'!\n", 
1018                 crc->name);
1019     rd_count_new = rd_count;
1020     rd_new = GNUNET_malloc (rd_count_new * sizeof (struct GNUNET_NAMESTORE_RecordData));
1021     memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
1022     rd_new[exist] = *(crc->rd);
1023   }
1024   block_expiration = GNUNET_TIME_absolute_max (crc->expire, expire);
1025   if (GNUNET_OK !=
1026       GSN_database->put_records (GSN_database->cls,
1027                                  &crc->pubkey,
1028                                  block_expiration,
1029                                  crc->name,
1030                                  rd_count_new, rd_new,
1031                                  &dummy_signature))
1032     crc->res = GNUNET_SYSERR; /* error */
1033   else if (GNUNET_YES == update)
1034     crc->res = GNUNET_NO; /* update */
1035   else
1036     crc->res = GNUNET_YES; /* created new record */
1037   GNUNET_free (rd_new);
1038 }
1039
1040
1041 /**
1042  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE' message
1043  *
1044  * @param cls unused
1045  * @param client GNUNET_SERVER_Client sending the message
1046  * @param message message of type 'struct RecordCreateMessage'
1047  */
1048 static void
1049 handle_record_create (void *cls,
1050                       struct GNUNET_SERVER_Client *client,
1051                       const struct GNUNET_MessageHeader *message)
1052 {
1053   struct GNUNET_NAMESTORE_Client *nc;
1054   const struct RecordCreateMessage *rp_msg;
1055   struct CreateRecordContext crc;
1056   struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
1057   struct RecordCreateResponseMessage rcr_msg;
1058   size_t name_len;
1059   size_t msg_size;
1060   size_t msg_size_exp;
1061   size_t rd_ser_len;
1062   size_t key_len;
1063   uint32_t rid;
1064   const char *pkey_tmp;
1065   const char *name_tmp;
1066   const char *rd_ser;
1067   unsigned int rd_count;
1068   int res;
1069   struct GNUNET_NAMESTORE_RecordData rd;
1070   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1071
1072   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1073               "Received `%s' message\n", "NAMESTORE_RECORD_CREATE");
1074   if (ntohs (message->size) < sizeof (struct RecordCreateMessage))
1075   {
1076     GNUNET_break (0);
1077     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1078     return;
1079   }
1080   if (NULL == (nc = client_lookup (client)))
1081   {
1082     GNUNET_break (0);
1083     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1084     return;
1085   }
1086   rp_msg = (const struct RecordCreateMessage *) message;
1087   rid = ntohl (rp_msg->gns_header.r_id);
1088   name_len = ntohs (rp_msg->name_len);
1089   msg_size = ntohs (message->size);
1090   rd_count = ntohs (rp_msg->rd_count);
1091   rd_ser_len = ntohs (rp_msg->rd_len);
1092   key_len = ntohs (rp_msg->pkey_len);
1093   msg_size_exp = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len;
1094   if ( (msg_size != msg_size_exp) || (1 != rd_count) )
1095   {
1096     GNUNET_break (0);
1097     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1098     return;
1099   }
1100   if ((0 == name_len) || (name_len > MAX_NAME_LEN))
1101   {
1102     GNUNET_break (0);
1103     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1104     return;
1105   }
1106   pkey_tmp = (const char *) &rp_msg[1];
1107   name_tmp = &pkey_tmp[key_len];
1108   rd_ser = &name_tmp[name_len];
1109   if ('\0' != name_tmp[name_len -1])
1110   {
1111     GNUNET_break (0);
1112     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1113     return;
1114   }
1115   if (NULL == (pkey = GNUNET_CRYPTO_rsa_decode_key (pkey_tmp, key_len)))
1116   {
1117     GNUNET_break (0);
1118     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1119     return;
1120   }
1121   if (GNUNET_OK !=
1122       GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, &rd))
1123   {
1124     GNUNET_break (0);
1125     GNUNET_CRYPTO_rsa_key_free (pkey);
1126     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1127     return;
1128   }
1129
1130   /* Extracting and converting private key */
1131   GNUNET_CRYPTO_rsa_key_get_public (pkey, &crc.pubkey);
1132   GNUNET_CRYPTO_short_hash (&crc.pubkey,
1133                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1134                             &pubkey_hash);
1135   learn_private_key (pkey);
1136   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1137               "Creating record for name `%s' in zone `%s'\n",
1138               name_tmp, GNUNET_short_h2s(&pubkey_hash));
1139   crc.expire = GNUNET_TIME_absolute_ntoh(rp_msg->expire);
1140   crc.res = GNUNET_SYSERR;
1141   crc.rd = &rd;
1142   crc.name = name_tmp;
1143
1144   /* Get existing records for name */
1145   res = GSN_database->iterate_records (GSN_database->cls, &pubkey_hash, name_tmp, 0, 
1146                                        &handle_create_record_it, &crc);
1147   if (res != GNUNET_SYSERR)
1148     res = GNUNET_OK;
1149
1150   /* Send response */
1151   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1152               "Sending `%s' message\n", "RECORD_CREATE_RESPONSE");
1153   rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE);
1154   rcr_msg.gns_header.header.size = htons (sizeof (struct RecordCreateResponseMessage));
1155   rcr_msg.gns_header.r_id = htonl (rid);
1156   if ((GNUNET_OK == res) && (crc.res == GNUNET_YES))
1157     rcr_msg.op_result = htonl (GNUNET_YES);
1158   else if ((GNUNET_OK == res) && (crc.res == GNUNET_NO))
1159     rcr_msg.op_result = htonl (GNUNET_NO);
1160   else
1161     rcr_msg.op_result = htonl (GNUNET_SYSERR);
1162   GNUNET_SERVER_notification_context_unicast (snc, nc->client,
1163                                               &rcr_msg.gns_header.header,
1164                                               GNUNET_NO);
1165   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1166 }
1167
1168
1169 /**
1170  * Context for record remove operations passed from 'handle_record_remove' to
1171  * 'handle_record_remove_it' as closure
1172  */
1173 struct RemoveRecordContext
1174 {
1175   /**
1176    * Record to remove
1177    */
1178   const struct GNUNET_NAMESTORE_RecordData *rd;
1179
1180   /**
1181    * See RECORD_REMOVE_RESULT_*-codes.  Set by 'handle_record_remove_it'
1182    * to the result of the operation.
1183    */
1184   int32_t op_res;
1185 };
1186
1187
1188 /**
1189  * We are to remove a record (or all records for a given name).  This function
1190  * will be called with the existing records (if there are any) and is to then
1191  * compute what to keep and trigger the necessary changes.
1192  *
1193  * @param cls the 'struct RecordRemoveContext' with information about what to remove
1194  * @param zone_key public key of the zone
1195  * @param expire when does the corresponding block in the DHT expire (until
1196  *               when should we never do a DHT lookup for the same name again)?
1197  * @param name name that is being mapped (at most 255 characters long)
1198  * @param rd_count number of entries in 'rd' array
1199  * @param rd array of records with data to store
1200  * @param signature signature of the record block, NULL if signature is unavailable (i.e. 
1201  *        because the user queried for a particular record type only)
1202  */
1203 static void
1204 handle_record_remove_it (void *cls,
1205                          const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1206                          struct GNUNET_TIME_Absolute expire,
1207                          const char *name,
1208                          unsigned int rd_count,
1209                          const struct GNUNET_NAMESTORE_RecordData *rd,
1210                          const struct GNUNET_CRYPTO_RsaSignature *signature)
1211 {
1212   static struct GNUNET_CRYPTO_RsaSignature dummy_signature;
1213   struct RemoveRecordContext *rrc = cls;
1214   unsigned int c;
1215   int found;
1216   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1217
1218   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1219               "Name `%s 'currently has %u records\n", 
1220               name, rd_count);
1221   if (0 == rd_count)
1222   {
1223     /* Could not find record to remove */
1224     rrc->op_res = RECORD_REMOVE_RESULT_NO_RECORDS;
1225     return;
1226   }
1227
1228   /* Find record to remove */
1229   found = -1;
1230   for (c = 0; c < rd_count; c++)
1231   {
1232     /* FIXME: shouldn't we test for all fields to match? Otherwise
1233        we might remove the wrong record, just because the type matches! */
1234     /*
1235     if (rd[c].flags != rrc->rd->flags)
1236        continue;*/
1237     if (rd[c].record_type != rrc->rd->record_type)
1238        continue;
1239     /*
1240     if (rd[c].data_size != rrc->rd->data_size)
1241        continue;
1242     GNUNET_break(0);
1243     if (0 != memcmp (rd[c].data, rrc->rd->data, rrc->rd->data_size))
1244         continue;
1245     GNUNET_break(0); */
1246     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found record to remove!\n", rd_count);
1247     found = c;
1248     break;
1249   }
1250   if (-1 == found)
1251   {
1252     /* Could not find record to remove */
1253     rrc->op_res = RECORD_REMOVE_RESULT_RECORD_NOT_FOUND;
1254     return;
1255   }
1256   if (1 == rd_count)
1257   {
1258     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1259                 "No records left for name `%s', removing name\n",
1260                 name);
1261     GNUNET_CRYPTO_short_hash (zone_key, 
1262                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
1263                               &pubkey_hash);
1264     if (GNUNET_OK !=
1265         GSN_database->remove_records (GSN_database->cls,
1266                                       &pubkey_hash,
1267                                       name))
1268     {
1269       /* Could not remove records from database */
1270       rrc->op_res = RECORD_REMOVE_RESULT_FAILED_TO_REMOVE;
1271       return;
1272     }
1273     rrc->op_res = RECORD_REMOVE_RESULT_SUCCESS;
1274     return;
1275   }
1276
1277   {
1278     struct GNUNET_NAMESTORE_RecordData rd_new[rd_count - 1];
1279     unsigned int c2 = 0;
1280     
1281     for (c = 0; c < rd_count; c++)
1282     {
1283       if (c == found)
1284         continue;       
1285       rd_new[c2++] = rd[c];
1286     }
1287     if (GNUNET_OK !=
1288         GSN_database->put_records(GSN_database->cls,
1289                                   zone_key,
1290                                   expire,
1291                                   name,
1292                                   rd_count - 1, rd_new,
1293                                   &dummy_signature))
1294     {
1295       /* Could not put records into database */
1296       rrc->op_res = RECORD_REMOVE_RESULT_FAILED_TO_PUT_UPDATE;
1297       return;
1298     }
1299   }
1300   rrc->op_res = RECORD_REMOVE_RESULT_SUCCESS;
1301 }
1302
1303
1304 /**
1305  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE' message
1306  *
1307  * @param cls unused
1308  * @param client GNUNET_SERVER_Client sending the message
1309  * @param message message of type 'struct RecordRemoveMessage'
1310  */
1311 static void
1312 handle_record_remove (void *cls,
1313                       struct GNUNET_SERVER_Client *client,
1314                       const struct GNUNET_MessageHeader *message)
1315 {
1316   struct GNUNET_NAMESTORE_Client *nc;
1317   const struct RecordRemoveMessage *rr_msg;
1318   struct RecordRemoveResponseMessage rrr_msg;
1319   struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
1320   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
1321   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1322   struct GNUNET_NAMESTORE_RecordData rd;
1323   const char *pkey_tmp;
1324   const char *name_tmp;
1325   const char *rd_ser;
1326   size_t key_len;
1327   size_t name_len;
1328   size_t rd_ser_len;
1329   size_t msg_size;
1330   size_t msg_size_exp;
1331   uint32_t rd_count;
1332   uint32_t rid;
1333   struct RemoveRecordContext rrc;
1334   int res;
1335
1336   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1337               "Received `%s' message\n", 
1338               "NAMESTORE_RECORD_REMOVE");
1339   if (ntohs (message->size) < sizeof (struct RecordRemoveMessage))
1340   {
1341     GNUNET_break (0);
1342     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1343     return;
1344   }
1345   if (NULL == (nc = client_lookup(client)))
1346   {
1347     GNUNET_break (0);
1348     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1349     return;
1350   }
1351   rr_msg = (const struct RecordRemoveMessage *) message;
1352   rid = ntohl (rr_msg->gns_header.r_id);
1353   name_len = ntohs (rr_msg->name_len);
1354   rd_ser_len = ntohs (rr_msg->rd_len);
1355   rd_count = ntohs (rr_msg->rd_count);
1356   key_len = ntohs (rr_msg->pkey_len);
1357   msg_size = ntohs (message->size);
1358   if ((name_len >= MAX_NAME_LEN) || (0 == name_len) || (1 < rd_count) )
1359   {
1360     GNUNET_break (0);
1361     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1362     return;
1363   }
1364   msg_size_exp = sizeof (struct RecordRemoveMessage) + key_len + name_len + rd_ser_len;
1365   if (msg_size != msg_size_exp)
1366   {
1367     GNUNET_break (0);
1368     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1369     return;
1370   }
1371   pkey_tmp = (const char *) &rr_msg[1];
1372   name_tmp = &pkey_tmp[key_len];
1373   rd_ser = &name_tmp[name_len];
1374   if ('\0' != name_tmp[name_len -1])
1375   {
1376     GNUNET_break (0);
1377     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1378     return;
1379   }
1380   if (NULL == (pkey = GNUNET_CRYPTO_rsa_decode_key (pkey_tmp, key_len)))
1381   {
1382     GNUNET_break (0);
1383     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1384     return;
1385   }
1386   GNUNET_CRYPTO_rsa_key_get_public (pkey, &pub);
1387   GNUNET_CRYPTO_short_hash (&pub, 
1388                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
1389                             &pubkey_hash);
1390   learn_private_key (pkey);
1391   if (GNUNET_OK !=
1392       GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, &rd))
1393   {
1394     GNUNET_break (0);
1395     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1396     return;
1397   }
1398
1399   if (0 == rd_count)
1400   {
1401     /* remove the whole name and all records */
1402     res = GSN_database->remove_records (GSN_database->cls,
1403                                         &pubkey_hash,
1404                                         name_tmp);
1405     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1406                 "Removing name `%s': %s\n",
1407                 name_tmp, (GNUNET_OK == res) ? "OK" : "FAILED");
1408     if (GNUNET_OK != res)
1409       /* Could not remove entry from database */
1410       res = RECORD_REMOVE_RESULT_FAILED_TO_PUT_UPDATE;
1411     else
1412       res = RECORD_REMOVE_RESULT_SUCCESS;
1413   }
1414   else
1415   {
1416     /* remove a single record */
1417     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1418                 "Removing record for name `%s' in zone `%s'\n", name_tmp, 
1419                 GNUNET_short_h2s (&pubkey_hash));
1420     rrc.rd = &rd;
1421     res = GSN_database->iterate_records (GSN_database->cls,
1422                                          &pubkey_hash,
1423                                          name_tmp,
1424                                          0,
1425                                          handle_record_remove_it, &rrc);
1426     switch (res)
1427     {
1428     case GNUNET_OK:
1429       res = rrc.op_res;
1430       break;
1431     case GNUNET_NO:
1432       res = RECORD_REMOVE_RESULT_NO_RECORDS;
1433       break;
1434     case GNUNET_SYSERR:
1435       res = RECORD_REMOVE_RESULT_FAILED_ACCESS_DATABASE;
1436       break;
1437     default:
1438       GNUNET_break (0);
1439       res = RECORD_REMOVE_RESULT_FAILED_INTERNAL_ERROR;
1440       break;
1441     }
1442   }
1443   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1444               "Sending `%s' message\n",
1445               "RECORD_REMOVE_RESPONSE");
1446   rrr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE);
1447   rrr_msg.gns_header.header.size = htons (sizeof (struct RecordRemoveResponseMessage));
1448   rrr_msg.gns_header.r_id = htonl (rid);
1449   rrr_msg.op_result = htonl (res);
1450   GNUNET_SERVER_notification_context_unicast (snc, nc->client, 
1451                                               &rrr_msg.gns_header.header,
1452                                               GNUNET_NO);
1453   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1454 }
1455
1456
1457 /**
1458  * Context for record remove operations passed from 'handle_zone_to_name' to
1459  * 'handle_zone_to_name_it' as closure
1460  */
1461 struct ZoneToNameCtx
1462 {
1463   /**
1464    * Namestore client
1465    */
1466   struct GNUNET_NAMESTORE_Client *nc;
1467
1468   /**
1469    * Request id (to be used in the response to the client).
1470    */
1471   uint32_t rid;
1472
1473   /**
1474    * Set to GNUNET_OK on success, GNUNET_SYSERR on error.  Note that
1475    * not finding a name for the zone still counts as a 'success' here,
1476    * as this field is about the success of executing the IPC protocol.
1477    */
1478   int success;
1479 };
1480
1481
1482 /**
1483  * Zone to name iterator
1484  *
1485  * @param cls struct ZoneToNameCtx *
1486  * @param zone_key the zone key
1487  * @param expire expiration date
1488  * @param name name
1489  * @param rd_count number of records
1490  * @param rd record data
1491  * @param signature signature
1492  */
1493 static void
1494 handle_zone_to_name_it (void *cls,
1495                         const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1496                         struct GNUNET_TIME_Absolute expire,
1497                         const char *name,
1498                         unsigned int rd_count,
1499                         const struct GNUNET_NAMESTORE_RecordData *rd,
1500                         const struct GNUNET_CRYPTO_RsaSignature *signature)
1501 {
1502   struct ZoneToNameCtx *ztn_ctx = cls;
1503   struct ZoneToNameResponseMessage *ztnr_msg;
1504   int16_t res;
1505   size_t name_len;
1506   size_t rd_ser_len;
1507   size_t msg_size;
1508   char *name_tmp;
1509   char *rd_tmp;
1510   char *sig_tmp;
1511
1512   if ((NULL != zone_key) && (NULL != name))
1513   {
1514     /* found result */
1515     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1516                 "Found result: name `%s' has %u records\n", 
1517                 name, rd_count);
1518     res = GNUNET_YES;
1519     name_len = strlen (name) + 1;
1520   }
1521   else
1522   {
1523     /* no result found */
1524     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1525                 "Found no results\n");
1526     res = GNUNET_NO;
1527     name_len = 0;
1528   }
1529   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1530               "Sending `%s' message\n", 
1531               "ZONE_TO_NAME_RESPONSE");
1532   rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1533   msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1534   if (NULL != signature)
1535     msg_size += sizeof (struct GNUNET_CRYPTO_RsaSignature);
1536   if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1537   {
1538     GNUNET_break (0);
1539     ztn_ctx->success = GNUNET_SYSERR;
1540     return;
1541   }
1542   ztnr_msg = GNUNET_malloc (msg_size);
1543   ztnr_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1544   ztnr_msg->gns_header.header.size = htons (msg_size);
1545   ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1546   ztnr_msg->res = htons (res);
1547   ztnr_msg->rd_len = htons (rd_ser_len);
1548   ztnr_msg->rd_count = htons (rd_count);
1549   ztnr_msg->name_len = htons (name_len);
1550   ztnr_msg->expire = GNUNET_TIME_absolute_hton (expire);
1551   if (NULL != zone_key)
1552     ztnr_msg->zone_key = *zone_key;
1553   name_tmp = (char *) &ztnr_msg[1];
1554   if (NULL != name)
1555     memcpy (name_tmp, name, name_len);
1556   rd_tmp = &name_tmp[name_len];
1557   GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_tmp);
1558   sig_tmp = &rd_tmp[rd_ser_len];
1559   if (NULL != signature)
1560     memcpy (sig_tmp, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature));
1561   ztn_ctx->success = GNUNET_OK;
1562   GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client,
1563                                               &ztnr_msg->gns_header.header,
1564                                               GNUNET_NO);
1565   GNUNET_free (ztnr_msg);
1566 }
1567
1568
1569 /**
1570  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME' message
1571  *
1572  * @param cls unused
1573  * @param client GNUNET_SERVER_Client sending the message
1574  * @param message message of type 'struct ZoneToNameMessage'
1575  */
1576 static void
1577 handle_zone_to_name (void *cls,
1578                      struct GNUNET_SERVER_Client *client,
1579                      const struct GNUNET_MessageHeader *message)
1580 {
1581   struct GNUNET_NAMESTORE_Client *nc;
1582   const struct ZoneToNameMessage *ztn_msg;
1583   struct ZoneToNameCtx ztn_ctx;
1584
1585   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1586               "Received `%s' message\n",
1587               "ZONE_TO_NAME");
1588   ztn_msg = (const struct ZoneToNameMessage *) message;
1589   if (NULL == (nc = client_lookup(client)))
1590   {
1591     GNUNET_break (0);
1592     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1593     return;
1594   }
1595   ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1596   ztn_ctx.nc = nc;
1597   ztn_ctx.success = GNUNET_SYSERR;
1598   if (GNUNET_SYSERR ==
1599       GSN_database->zone_to_name (GSN_database->cls, 
1600                                   &ztn_msg->zone,
1601                                   &ztn_msg->value_zone,
1602                                   &handle_zone_to_name_it, &ztn_ctx))
1603   {
1604     /* internal error, hang up instead of signalling something
1605        that might be wrong */
1606     GNUNET_break (0);
1607     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1608     return;    
1609   }
1610   GNUNET_SERVER_receive_done (client, ztn_ctx.success);
1611 }
1612
1613
1614 /**
1615  * Context for record remove operations passed from
1616  * 'run_zone_iteration_round' to 'zone_iteraterate_proc' as closure
1617  */
1618 struct ZoneIterationProcResult
1619 {
1620   /**
1621    * The zone iteration handle
1622    */
1623   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1624
1625   /**
1626    * Iteration result: iteration done?  Set to GNUNET_YES
1627    * if there are no further results, GNUNET_NO if there
1628    * may be more results overall but we got one for now,
1629    * GNUNET_SYSERR if all results were filtered so far.
1630    */
1631   int res_iteration_finished;
1632
1633 };
1634
1635
1636 /**
1637  * Process results for zone iteration from database
1638  *
1639  * @param cls struct ZoneIterationProcResult *proc
1640  * @param zone_key the zone key
1641  * @param expire expiration time
1642  * @param name name
1643  * @param rd_count number of records for this name
1644  * @param rd record data
1645  * @param signature block signature
1646  */
1647 static void
1648 zone_iteraterate_proc (void *cls,
1649                        const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1650                        struct GNUNET_TIME_Absolute expire,
1651                        const char *name,
1652                        unsigned int rd_count,
1653                        const struct GNUNET_NAMESTORE_RecordData *rd,
1654                        const struct GNUNET_CRYPTO_RsaSignature *signature)
1655 {
1656   struct ZoneIterationProcResult *proc = cls;
1657   struct GNUNET_NAMESTORE_RecordData rd_filtered[rd_count];
1658   struct GNUNET_CRYPTO_RsaSignature *new_signature;
1659   struct GNUNET_NAMESTORE_CryptoContainer *cc;
1660   struct GNUNET_HashCode long_hash;
1661   struct GNUNET_CRYPTO_ShortHashCode zone_hash;
1662   struct ZoneIterationResponseMessage *zir_msg;
1663   unsigned int rd_count_filtered;
1664   unsigned int c;
1665   size_t name_len;
1666   size_t rd_ser_len;
1667   size_t msg_size;
1668   char *name_tmp;
1669   char *rd_ser;
1670   int include;
1671
1672   proc->res_iteration_finished = GNUNET_NO;
1673   if ((NULL == zone_key) && (NULL == name))
1674   {
1675     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1676                 "Iteration done\n");
1677     proc->res_iteration_finished = GNUNET_YES;
1678     return;
1679   }
1680   if ((NULL == zone_key) || (NULL == name)) 
1681   {
1682     /* what is this!? should never happen */
1683     GNUNET_break (0);
1684     return;    
1685   }
1686   rd_count_filtered  = 0;
1687   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1688               "Received result for zone iteration: `%s'\n", 
1689               name);
1690   for (c = 0; c < rd_count; c++)
1691   {
1692     // FIXME: new expiration flags need additional special treatment here!
1693     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1694                 "Record %i has flags: 0x%x must have 0x%x \n",
1695                 c, rd[c].flags, 
1696                 proc->zi->must_have_flags);
1697     include = GNUNET_YES;
1698     /* Checking must have flags */
1699     if ((rd[c].flags & proc->zi->must_have_flags) == proc->zi->must_have_flags)
1700     {
1701       /* Include */
1702       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c);
1703     }
1704     else
1705     {
1706       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Not include \n", c);
1707       include = GNUNET_NO;
1708     }
1709     
1710     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1711                 "Record %i has flags: 0x%x must not have 0x%x\n",
1712                 c, rd[c].flags, proc->zi->must_not_have_flags);
1713     if (0 != (rd[c].flags & proc->zi->must_not_have_flags))
1714     {
1715       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1716                   "Record %i has flags: Not include \n", c);
1717       include = GNUNET_NO;
1718     }
1719     else
1720     {
1721       /* Include */
1722       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c);
1723     }
1724     if (GNUNET_YES == include)
1725       rd_filtered[rd_count_filtered++] = rd[c];
1726   }
1727   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1728               "Included %u of %u records\n", 
1729               rd_count_filtered, rd_count);
1730
1731   /* compute / obtain signature */
1732   GNUNET_CRYPTO_short_hash (zone_key, 
1733                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1734                             &zone_hash);
1735   GNUNET_CRYPTO_short_hash_double (&zone_hash, &long_hash);
1736   if (NULL != (cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash)))
1737   {
1738     expire = get_block_expiration_time (rd_count_filtered, rd_filtered);
1739     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1740                 "Creating signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1741                 name, GNUNET_short_h2s(&zone_hash), 
1742                 rd_count_filtered,
1743                 (unsigned long long) expire.abs_value);
1744     new_signature = GNUNET_NAMESTORE_create_signature (cc->privkey, expire, name, 
1745                                                        rd_filtered, rd_count_filtered);
1746     GNUNET_assert (NULL != signature);
1747     signature = new_signature;
1748   }
1749   else if (rd_count_filtered == rd_count)
1750   {
1751     if (NULL != signature)
1752     {
1753       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1754                   "Using provided signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1755                   name, GNUNET_short_h2s (&zone_hash), rd_count_filtered, 
1756                   (unsigned long long) expire.abs_value);
1757       return;
1758     }
1759   }
1760   else
1761   {
1762     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1763                 "No signature provided for `%s'\n",
1764                 name);
1765     signature = NULL;
1766   }
1767
1768   if (GNUNET_YES == proc->zi->has_zone)
1769     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1770                 "Sending name `%s' for iteration over zone `%s'\n",
1771                 name, GNUNET_short_h2s(&proc->zi->zone));
1772   else
1773     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1774                 "Sending name `%s' for iteration over all zones\n",
1775                 name);
1776   name_len = strlen (name) + 1;
1777   rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count_filtered, rd_filtered);  
1778   msg_size = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_ser_len;
1779
1780   zir_msg = GNUNET_malloc (msg_size);
1781   zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1782   zir_msg->gns_header.header.size = htons (msg_size);
1783   zir_msg->gns_header.r_id = htonl (proc->zi->request_id);
1784   zir_msg->expire = GNUNET_TIME_absolute_hton (expire);
1785   zir_msg->reserved = htons (0);
1786   zir_msg->name_len = htons (name_len);
1787   zir_msg->rd_count = htons (rd_count_filtered);
1788   zir_msg->rd_len = htons (rd_ser_len);
1789   if (NULL != signature)
1790     zir_msg->signature = *signature;
1791   zir_msg->public_key = *zone_key;
1792   name_tmp = (char *) &zir_msg[1];
1793   memcpy (name_tmp, name, name_len);
1794   rd_ser = &name_tmp[name_len];
1795   GNUNET_NAMESTORE_records_serialize (rd_count_filtered, rd_filtered, rd_ser_len, rd_ser);
1796   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1797               "Sending `%s' message with size %u\n", 
1798               "ZONE_ITERATION_RESPONSE",
1799               msg_size);
1800   GNUNET_SERVER_notification_context_unicast (snc, proc->zi->client->client, 
1801                                               (const struct GNUNET_MessageHeader *) zir_msg,
1802                                               GNUNET_NO);
1803   proc->res_iteration_finished = GNUNET_NO;
1804   GNUNET_free (zir_msg);
1805   GNUNET_free_non_null (new_signature);
1806 }
1807
1808
1809 /**
1810  * Perform the next round of the zone iteration.
1811  *
1812  * @param zi zone iterator to process
1813  */
1814 static void
1815 run_zone_iteration_round (struct GNUNET_NAMESTORE_ZoneIteration *zi)
1816 {
1817   struct ZoneIterationProcResult proc;
1818   struct ZoneIterationResponseMessage zir_end;
1819   struct GNUNET_CRYPTO_ShortHashCode *zone;
1820
1821   memset (&proc, 0, sizeof (proc));
1822   proc.zi = zi;
1823   if (GNUNET_YES == zi->has_zone)
1824     zone = &zi->zone;
1825   else
1826     zone = NULL;
1827   proc.res_iteration_finished = GNUNET_SYSERR;
1828   while (GNUNET_SYSERR == proc.res_iteration_finished)
1829   {
1830     if (GNUNET_SYSERR ==
1831         GSN_database->iterate_records (GSN_database->cls, zone, NULL, 
1832                                        zi->offset, 
1833                                        &zone_iteraterate_proc, &proc))
1834     {
1835       GNUNET_break (0);
1836       break;
1837     }
1838     zi->offset++;
1839   }
1840   if (GNUNET_YES != proc.res_iteration_finished)
1841     return; /* more results later */
1842   if (GNUNET_YES == zi->has_zone)
1843     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1844                 "No more results for zone `%s'\n", 
1845                 GNUNET_short_h2s(&zi->zone));
1846   else
1847     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1848                 "No more results for all zones\n");
1849   memset (&zir_end, 0, sizeof (zir_end));
1850   zir_end.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1851   zir_end.gns_header.header.size = htons (sizeof (struct ZoneIterationResponseMessage));
1852   zir_end.gns_header.r_id = htonl(zi->request_id);
1853   GNUNET_SERVER_notification_context_unicast (snc, 
1854                                               zi->client->client, 
1855                                               &zir_end.gns_header.header, GNUNET_NO);
1856   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1857               "Removing zone iterator\n");
1858   GNUNET_CONTAINER_DLL_remove (zi->client->op_head, zi->client->op_tail, zi);
1859   GNUNET_free (zi);
1860 }
1861
1862
1863 /**
1864  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START' message
1865  *
1866  * @param cls unused
1867  * @param client GNUNET_SERVER_Client sending the message
1868  * @param message message of type 'struct ZoneIterationStartMessage'
1869  */
1870 static void
1871 handle_iteration_start (void *cls,
1872                         struct GNUNET_SERVER_Client *client,
1873                         const struct GNUNET_MessageHeader *message)
1874 {
1875   static struct GNUNET_CRYPTO_ShortHashCode zeros;
1876   const struct ZoneIterationStartMessage *zis_msg;
1877   struct GNUNET_NAMESTORE_Client *nc;
1878   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1879
1880   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START");
1881   if (NULL == (nc = client_lookup (client)))
1882   {
1883     GNUNET_break (0);
1884     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1885     return;
1886   }
1887   zis_msg = (const struct ZoneIterationStartMessage *) message;
1888   zi = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIteration));
1889   zi->request_id = ntohl (zis_msg->gns_header.r_id);
1890   zi->offset = 0;
1891   zi->client = nc;
1892   zi->must_have_flags = ntohs (zis_msg->must_have_flags);
1893   zi->must_not_have_flags = ntohs (zis_msg->must_not_have_flags);
1894   if (0 == memcmp (&zeros, &zis_msg->zone, sizeof (zeros)))
1895   {
1896     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over all zones\n");
1897     zi->zone = zis_msg->zone;
1898     zi->has_zone = GNUNET_NO;
1899   }
1900   else
1901   {
1902     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1903                 "Starting to iterate over zone `%s'\n", GNUNET_short_h2s (&zis_msg->zone));
1904     zi->zone = zis_msg->zone;
1905     zi->has_zone = GNUNET_YES;
1906   }
1907   GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
1908   run_zone_iteration_round (zi);
1909   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1910 }
1911
1912
1913 /**
1914  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP' message
1915  *
1916  * @param cls unused
1917  * @param client GNUNET_SERVER_Client sending the message
1918  * @param message message of type 'struct ZoneIterationStopMessage'
1919  */
1920 static void
1921 handle_iteration_stop (void *cls,
1922                        struct GNUNET_SERVER_Client *client,
1923                        const struct GNUNET_MessageHeader *message)
1924 {
1925   struct GNUNET_NAMESTORE_Client *nc;
1926   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1927   const struct ZoneIterationStopMessage *zis_msg;
1928   uint32_t rid;
1929
1930   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1931               "Received `%s' message\n",
1932               "ZONE_ITERATION_STOP");
1933   if (NULL == (nc = client_lookup(client)))
1934   {
1935     GNUNET_break (0);
1936     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1937     return;
1938   }
1939   zis_msg = (const struct ZoneIterationStopMessage *) message;
1940   rid = ntohl (zis_msg->gns_header.r_id);
1941   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1942     if (zi->request_id == rid)
1943       break;
1944   if (NULL == zi)
1945   {
1946     GNUNET_break (0);
1947     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1948     return;
1949   }
1950   GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
1951   if (GNUNET_YES == zi->has_zone)
1952     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1953                 "Stopped zone iteration for zone `%s'\n",
1954                 GNUNET_short_h2s (&zi->zone));
1955   else
1956     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1957                 "Stopped zone iteration over all zones\n");
1958   GNUNET_free (zi);
1959   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1960 }
1961
1962
1963 /**
1964  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT' message
1965  *
1966  * @param cls unused
1967  * @param client GNUNET_SERVER_Client sending the message
1968  * @param message message of type 'struct ZoneIterationNextMessage'
1969  */
1970 static void
1971 handle_iteration_next (void *cls,
1972                        struct GNUNET_SERVER_Client *client,
1973                        const struct GNUNET_MessageHeader *message)
1974 {
1975   struct GNUNET_NAMESTORE_Client *nc;
1976   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1977   const struct ZoneIterationNextMessage *zis_msg;
1978   uint32_t rid;
1979
1980   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT");
1981   if (NULL == (nc = client_lookup(client)))
1982   {
1983     GNUNET_break (0);
1984     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1985     return;
1986   }
1987   zis_msg = (const struct ZoneIterationNextMessage *) message;
1988   rid = ntohl (zis_msg->gns_header.r_id);
1989   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1990     if (zi->request_id == rid)
1991       break;
1992   if (NULL == zi)
1993   {
1994     GNUNET_break (0);
1995     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1996     return;
1997   }
1998   run_zone_iteration_round (zi);
1999   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2000 }
2001
2002
2003 /**
2004  * Load zone keys from directory by reading all .zkey files in this directory
2005  *
2006  * @param cls int * 'counter' to store the number of files found
2007  * @param filename directory to scan
2008  * @return GNUNET_OK to continue
2009  */
2010 static int
2011 zonekey_file_it (void *cls, const char *filename)
2012 {
2013   unsigned int *counter = cls;
2014   struct GNUNET_CRYPTO_RsaPrivateKey *privkey;
2015
2016   if ((NULL == filename) ||
2017       (NULL == strstr(filename, ".zkey")))
2018     return GNUNET_OK;
2019   privkey = GNUNET_CRYPTO_rsa_key_create_from_file (filename);
2020   if (NULL == privkey)
2021   {
2022     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2023                 _("Could not parse zone key file `%s'\n"),
2024                 filename);
2025     return GNUNET_OK;
2026   }
2027   learn_private_key (privkey);
2028   (*counter)++;
2029   return GNUNET_OK;
2030 }
2031
2032
2033 /**
2034  * Process namestore requests.
2035  *
2036  * @param cls closure
2037  * @param server the initialized server
2038  * @param cfg configuration to use
2039  */
2040 static void
2041 run (void *cls, struct GNUNET_SERVER_Handle *server,
2042      const struct GNUNET_CONFIGURATION_Handle *cfg)
2043 {
2044   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2045     {&handle_start, NULL,
2046      GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)},
2047     {&handle_lookup_name, NULL,
2048      GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0},
2049     {&handle_record_put, NULL,
2050     GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT, 0},
2051     {&handle_record_create, NULL,
2052      GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE, 0},
2053     {&handle_record_remove, NULL,
2054      GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE, 0},
2055     {&handle_zone_to_name, NULL,
2056      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, sizeof (struct ZoneToNameMessage) },
2057     {&handle_iteration_start, NULL,
2058      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage) },
2059     {&handle_iteration_next, NULL,
2060      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, sizeof (struct ZoneIterationNextMessage) },
2061      {&handle_iteration_stop, NULL,
2062       GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, sizeof (struct ZoneIterationStopMessage) },
2063     {NULL, NULL, 0, 0}
2064   };
2065   char *database;
2066   unsigned int counter;
2067
2068   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
2069   GSN_cfg = cfg;
2070
2071   /* Load private keys from disk */
2072   if (GNUNET_OK !=
2073       GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore", 
2074                                                "zonefile_directory",
2075                                                &zonefile_directory))
2076   {
2077     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
2078                 _("No directory to load zonefiles specified in configuration\n"));
2079     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2080     return;
2081   }
2082
2083   if (GNUNET_NO == GNUNET_DISK_file_test (zonefile_directory))
2084   {
2085     if (GNUNET_SYSERR == GNUNET_DISK_directory_create (zonefile_directory))
2086     {
2087       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
2088                   _("Creating directory `%s' for zone files failed!\n"),
2089                   zonefile_directory);
2090       GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2091       return;
2092     }
2093     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2094                 "Created directory `%s' for zone files\n", 
2095                 zonefile_directory);
2096   }
2097
2098   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2099               "Scanning directory `%s' for zone files\n", zonefile_directory);
2100   zonekeys = GNUNET_CONTAINER_multihashmap_create (16);
2101   counter = 0;
2102   GNUNET_DISK_directory_scan (zonefile_directory, zonekey_file_it, &counter);
2103   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2104               "Found %u zone files\n", 
2105               counter);
2106
2107   /* Loading database plugin */
2108   if (GNUNET_OK !=
2109       GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
2110                                              &database))
2111     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
2112
2113   GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
2114   GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
2115   GNUNET_free (database);
2116   if (NULL == GSN_database)
2117   {
2118     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
2119                 "Could not load database backend `%s'\n",
2120                 db_lib_name);
2121     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2122     return;
2123   }
2124
2125   /* Configuring server handles */
2126   GNUNET_SERVER_add_handlers (server, handlers);
2127   snc = GNUNET_SERVER_notification_context_create (server, 16);
2128   GNUNET_SERVER_disconnect_notify (server,
2129                                    &client_disconnect_notification,
2130                                    NULL);
2131   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
2132                                 NULL);
2133 }
2134
2135
2136 /**
2137  * The main function for the template service.
2138  *
2139  * @param argc number of arguments from the command line
2140  * @param argv command line arguments
2141  * @return 0 ok, 1 on error
2142  */
2143 int
2144 main (int argc, char *const *argv)
2145 {
2146   return (GNUNET_OK ==
2147           GNUNET_SERVICE_run (argc, argv, "namestore",
2148                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
2149 }
2150
2151 /* end of gnunet-service-namestore.c */
2152