-towards implementing improved namestore API
[oweals/gnunet.git] / src / namestore / gnunet-service-namestore.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012, 2013 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  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_dnsparser_lib.h"
30 #include "gnunet_namestore_service.h"
31 #include "gnunet_namestore_plugin.h"
32 #include "gnunet_signatures.h"
33 #include "namestore.h"
34
35 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
36
37 /**
38  * A namestore operation.
39  */
40 struct GNUNET_NAMESTORE_ZoneIteration
41 {
42   /**
43    * Next element in the DLL
44    */
45   struct GNUNET_NAMESTORE_ZoneIteration *next;
46
47   /**
48    * Previous element in the DLL
49    */
50   struct GNUNET_NAMESTORE_ZoneIteration *prev;
51
52   /**
53    * Namestore client which intiated this zone iteration
54    */
55   struct GNUNET_NAMESTORE_Client *client;
56
57   /**
58    * GNUNET_YES if we iterate over a specific zone
59    * GNUNET_NO if we iterate over all zones
60    */
61   int has_zone;
62
63   /**
64    * Hash of the specific zone if 'has_zone' is GNUNET_YES,
65    * othwerwise set to '\0'
66    */
67   struct GNUNET_CRYPTO_ShortHashCode zone;
68
69   /**
70    * The operation id fot the zone iteration in the response for the client
71    */
72   uint64_t request_id;
73
74   /**
75    * Offset of the zone iteration used to address next result of the zone
76    * iteration in the store
77    *
78    * Initialy set to 0 in handle_iteration_start
79    * Incremented with by every call to handle_iteration_next
80    */
81   uint32_t offset;
82
83   /**
84    * Which flags must be included
85    */
86   uint16_t must_have_flags;
87
88   /**
89    * Which flags must not be included
90    */
91   uint16_t must_not_have_flags;
92 };
93
94
95 /**
96  * A namestore client
97  */
98 struct GNUNET_NAMESTORE_Client
99 {
100   /**
101    * Next element in the DLL
102    */
103   struct GNUNET_NAMESTORE_Client *next;
104
105   /**
106    * Previous element in the DLL
107    */
108   struct GNUNET_NAMESTORE_Client *prev;
109
110   /**
111    * The client
112    */
113   struct GNUNET_SERVER_Client *client;
114
115   /**
116    * Head of the DLL of
117    * Zone iteration operations in progress initiated by this client
118    */
119   struct GNUNET_NAMESTORE_ZoneIteration *op_head;
120
121   /**
122    * Tail of the DLL of
123    * Zone iteration operations in progress initiated by this client
124    */
125   struct GNUNET_NAMESTORE_ZoneIteration *op_tail;
126 };
127
128
129 /**
130  * A container struct to store information belonging to a zone crypto key pair
131  */
132 struct GNUNET_NAMESTORE_CryptoContainer
133 {
134   /**
135    * Filename where to store the container
136    */
137   char *filename;
138
139   /**
140    * Short hash of the zone's public key
141    */
142   struct GNUNET_CRYPTO_ShortHashCode zone;
143
144   /**
145    * Zone's private key
146    */
147   struct GNUNET_CRYPTO_EccPrivateKey *privkey;
148
149 };
150
151
152 /**
153  * Configuration handle.
154  */
155 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
156
157 /**
158  * Database handle
159  */
160 static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
161
162 /**
163  * Zonefile directory
164  */
165 static char *zonefile_directory;
166
167 /**
168  * Name of the database plugin
169  */
170 static char *db_lib_name;
171
172 /**
173  * Our notification context.
174  */
175 static struct GNUNET_SERVER_NotificationContext *snc;
176
177 /**
178  * Head of the Client DLL
179  */
180 static struct GNUNET_NAMESTORE_Client *client_head;
181
182 /**
183  * Tail of the Client DLL
184  */
185 static struct GNUNET_NAMESTORE_Client *client_tail;
186
187 /**
188  * Hashmap containing the zone keys this namestore has is authoritative for
189  *
190  * Keys are the GNUNET_CRYPTO_HashCode of the GNUNET_CRYPTO_ShortHashCode
191  * The values are 'struct GNUNET_NAMESTORE_CryptoContainer *'
192  */
193 static struct GNUNET_CONTAINER_MultiHashMap *zonekeys;
194
195 /**
196  * DLL head for key loading contexts
197  */
198 static struct KeyLoadContext *kl_head;
199
200 /**
201  * DLL tail for key loading contexts
202  */
203 static struct KeyLoadContext *kl_tail;
204
205 struct KeyLoadContext
206 {
207   struct KeyLoadContext *next;
208   struct KeyLoadContext *prev;
209   struct GNUNET_CRYPTO_EccKeyGenerationContext *keygen;
210   char *filename;
211   unsigned int *counter;
212 };
213
214
215 /**
216  * Writes the encrypted private key of a zone in a file
217  *
218  * @param filename where to store the zone
219  * @param c the crypto container containing private key of the zone
220  * @return GNUNET_OK on success, GNUNET_SYSERR on failure
221  */
222 static int
223 write_key_to_file (const char *filename, 
224                    struct GNUNET_NAMESTORE_CryptoContainer *c)
225 {
226   struct GNUNET_CRYPTO_EccPrivateKey *ret = c->privkey;
227   struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
228   struct GNUNET_DISK_FileHandle *fd;
229   struct GNUNET_CRYPTO_ShortHashCode zone;
230   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pubkey;
231   struct GNUNET_CRYPTO_EccPrivateKey *privkey;
232
233   fd = GNUNET_DISK_file_open (filename, 
234                               GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS, 
235                               GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
236   if ( (NULL == fd) && (EEXIST == errno) )
237   {
238     privkey = GNUNET_CRYPTO_ecc_key_create_from_file (filename);
239     if (NULL == privkey)
240     {
241       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
242                   _("Failed to write zone key to file `%s': %s\n"),
243                   filename,
244                   _("file exists but reading key failed"));
245       return GNUNET_SYSERR;
246     }
247     GNUNET_CRYPTO_ecc_key_get_public (privkey, &pubkey);
248     GNUNET_CRYPTO_short_hash (&pubkey, sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded), &zone);
249     GNUNET_CRYPTO_ecc_key_free (privkey);
250     if (0 == memcmp (&zone, &c->zone, sizeof(zone)))
251     {
252       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
253                   "File zone `%s' containing this key already exists\n", 
254                   GNUNET_NAMESTORE_short_h2s (&zone));
255       return GNUNET_OK;
256     }
257     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
258                 _("Failed to write zone key to file `%s': %s\n"),
259                 filename,
260                 _("file exists with different key"));
261     return GNUNET_OK;    
262   }
263   if (NULL == fd)
264   {
265     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
266     return GNUNET_SYSERR;
267   }
268   if (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded), GNUNET_YES))
269   {
270     GNUNET_break (GNUNET_YES == GNUNET_DISK_file_close (fd));
271     return GNUNET_SYSERR;
272   }
273   enc = GNUNET_CRYPTO_ecc_encode_key (ret);
274   GNUNET_assert (NULL != enc);
275   GNUNET_assert (ntohs (enc->size) == GNUNET_DISK_file_write (fd, enc, ntohs (enc->size)));
276   GNUNET_free (enc);
277   GNUNET_DISK_file_sync (fd);
278   if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded)))
279     LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
280   GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
281   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
282               "Stored zonekey for zone `%s' in file `%s'\n",
283               GNUNET_NAMESTORE_short_h2s(&c->zone), c->filename);
284   return GNUNET_OK;
285 }
286
287
288 /**
289  * Write allthe given zone key to disk and then removes the entry from the
290  * 'zonekeys' hash map.
291  *
292  * @param cls unused
293  * @param key zone key
294  * @param value 'struct GNUNET_NAMESTORE_CryptoContainer' containing the private
295  *        key
296  * @return GNUNET_OK to continue iteration
297  */
298 static int
299 zone_to_disk_it (void *cls,
300                  const struct GNUNET_HashCode *key,
301                  void *value)
302 {
303   struct GNUNET_NAMESTORE_CryptoContainer *c = value;
304
305   if (NULL == c->filename)
306     GNUNET_asprintf(&c->filename, 
307                     "%s/%s.zkey", 
308                     zonefile_directory, 
309                     GNUNET_NAMESTORE_short_h2s (&c->zone));
310   (void) write_key_to_file(c->filename, c);
311   GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (zonekeys, key, value));
312   GNUNET_CRYPTO_ecc_key_free (c->privkey);
313   GNUNET_free (c->filename);
314   GNUNET_free (c);
315   return GNUNET_OK;
316 }
317
318
319 /**
320  * Add the given private key to the set of private keys
321  * this namestore can use to sign records when needed.
322  *
323  * @param pkey private key to add to our list (reference will
324  *        be taken over or freed and should not be used afterwards)
325  */
326 static void
327 learn_private_key (struct GNUNET_CRYPTO_EccPrivateKey *pkey)
328 {
329   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
330   struct GNUNET_HashCode long_hash;
331   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
332   struct GNUNET_NAMESTORE_CryptoContainer *cc;
333
334   GNUNET_CRYPTO_ecc_key_get_public (pkey, &pub);
335   GNUNET_CRYPTO_short_hash (&pub,
336                             sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
337                             &pubkey_hash);
338   GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
339
340   if (GNUNET_NO != GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
341   {
342     GNUNET_CRYPTO_ecc_key_free (pkey);
343     return;
344   }  
345   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
346               "Received new private key for zone `%s'\n",
347               GNUNET_NAMESTORE_short_h2s(&pubkey_hash));
348   cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
349   cc->privkey = pkey;
350   cc->zone = pubkey_hash;
351   GNUNET_assert (GNUNET_YES ==
352                  GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc, 
353                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));  
354 }
355
356
357 /**
358  * Returns the expiration time of the given block of records. The block
359  * expiration time is the expiration time of the block with smallest
360  * expiration time.
361  *
362  * @param rd_count number of records given in 'rd'
363  * @param rd array of records
364  * @return absolute expiration time
365  */
366 static struct GNUNET_TIME_Absolute
367 get_block_expiration_time (unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd)
368 {
369   unsigned int c;
370   struct GNUNET_TIME_Absolute expire;
371   struct GNUNET_TIME_Absolute at;
372   struct GNUNET_TIME_Relative rt;
373
374   if (NULL == rd)
375     return GNUNET_TIME_UNIT_ZERO_ABS;
376   expire = GNUNET_TIME_UNIT_FOREVER_ABS;
377   for (c = 0; c < rd_count; c++)  
378   {
379     if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
380     {
381       rt.rel_value = rd[c].expiration_time;
382       at = GNUNET_TIME_relative_to_absolute (rt);
383     }
384     else
385     {
386       at.abs_value = rd[c].expiration_time;
387     }
388     expire = GNUNET_TIME_absolute_min (at, expire);  
389   }
390   return expire;
391 }
392
393
394 /**
395  * Task run during shutdown.
396  *
397  * @param cls unused
398  * @param tc unused
399  */
400 static void
401 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
402 {
403   struct GNUNET_NAMESTORE_ZoneIteration *no;
404   struct GNUNET_NAMESTORE_Client *nc;
405   struct KeyLoadContext *kl;
406
407   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping namestore service\n");
408   if (NULL != snc)
409   {
410     GNUNET_SERVER_notification_context_destroy (snc);
411     snc = NULL;
412   }
413
414   while (NULL != (kl = kl_head))
415   {
416     GNUNET_CONTAINER_DLL_remove (kl_head, kl_tail, kl);
417     if (NULL != kl->keygen)
418       GNUNET_CRYPTO_ecc_key_create_stop (kl->keygen);
419     GNUNET_free (kl->filename);
420     GNUNET_free (kl);
421   }
422
423   GNUNET_CONTAINER_multihashmap_iterate (zonekeys, &zone_to_disk_it, NULL);
424   GNUNET_CONTAINER_multihashmap_destroy (zonekeys);
425   zonekeys = NULL;
426   while (NULL != (nc = client_head))
427   {
428     while (NULL != (no = nc->op_head))
429     {
430       GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
431       GNUNET_free (no);
432     }
433     GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
434     GNUNET_free (nc);
435   }
436   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
437   GNUNET_free (db_lib_name);
438   db_lib_name = NULL;
439   GNUNET_free_non_null (zonefile_directory);
440   zonefile_directory = NULL;
441 }
442
443
444 /**
445  * Lookup our internal data structure for a given client.
446  *
447  * @param client server client handle to use for the lookup
448  * @return our internal structure for the client, NULL if
449  *         we do not have any yet
450  */
451 static struct GNUNET_NAMESTORE_Client *
452 client_lookup (struct GNUNET_SERVER_Client *client)
453 {
454   struct GNUNET_NAMESTORE_Client *nc;
455
456   GNUNET_assert (NULL != client);
457   for (nc = client_head; NULL != nc; nc = nc->next)  
458     if (client == nc->client)
459       return nc;  
460   return NULL;
461 }
462
463
464 /**
465  * Called whenever a client is disconnected.
466  * Frees our resources associated with that client.
467  *
468  * @param cls closure
469  * @param client identification of the client
470  */
471 static void
472 client_disconnect_notification (void *cls, 
473                                 struct GNUNET_SERVER_Client *client)
474 {
475   struct GNUNET_NAMESTORE_ZoneIteration *no;
476   struct GNUNET_NAMESTORE_Client *nc;
477
478   if (NULL == client)
479     return;
480   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
481               "Client %p disconnected\n", 
482               client);
483   if (NULL == (nc = client_lookup (client)))
484     return;
485   while (NULL != (no = nc->op_head))
486   {
487     GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
488     GNUNET_free (no);
489   }
490   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
491   GNUNET_free (nc);
492 }
493
494
495 /**
496  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_START' message
497  *
498  * @param cls unused
499  * @param client GNUNET_SERVER_Client sending the message
500  * @param message unused
501  */
502 static void
503 handle_start (void *cls,
504               struct GNUNET_SERVER_Client *client,
505               const struct GNUNET_MessageHeader *message)
506 {
507   struct GNUNET_NAMESTORE_Client *nc;
508
509   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
510               "Client %p connected\n", client);
511   if (NULL != client_lookup (client))
512   {
513     GNUNET_break (0);
514     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
515     return;
516   }
517   nc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Client));
518   nc->client = client;
519   GNUNET_SERVER_notification_context_add (snc, client);
520   GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
521   GNUNET_SERVER_receive_done (client, GNUNET_OK);
522 }
523
524
525 /**
526  * Context for name lookups passed from 'handle_lookup_name' to
527  * 'handle_lookup_name_it' as closure
528  */
529 struct LookupNameContext
530 {
531   /**
532    * The client to send the response to
533    */
534   struct GNUNET_NAMESTORE_Client *nc;
535
536   /**
537    * Requested zone
538    */
539   const struct GNUNET_CRYPTO_ShortHashCode *zone;
540
541   /**
542    * Requested name
543    */
544   const char *name;
545
546   /**
547    * Operation id for the name lookup
548    */
549   uint32_t request_id;
550
551   /**
552    * Requested specific record type
553    */
554   uint32_t record_type;
555 };
556
557
558 /**
559  * A 'GNUNET_NAMESTORE_RecordIterator' for name lookups in handle_lookup_name
560  *
561  * @param cls a 'struct LookupNameContext *' with information about the request
562  * @param zone_key zone key of the zone
563  * @param expire expiration time
564  * @param name name
565  * @param rd_count number of records
566  * @param rd array of records
567  * @param signature signature
568  */
569 static void
570 handle_lookup_name_it (void *cls,
571                        const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
572                        struct GNUNET_TIME_Absolute expire,
573                        const char *name,
574                        unsigned int rd_count,
575                        const struct GNUNET_NAMESTORE_RecordData *rd,
576                        const struct GNUNET_CRYPTO_EccSignature *signature)
577 {
578   struct LookupNameContext *lnc = cls;
579   struct LookupNameResponseMessage *lnr_msg;
580   struct GNUNET_NAMESTORE_RecordData *rd_selected;
581   struct GNUNET_NAMESTORE_CryptoContainer *cc;
582   struct GNUNET_CRYPTO_EccSignature *signature_new;
583   struct GNUNET_TIME_Absolute e;
584   struct GNUNET_TIME_Relative re;
585   struct GNUNET_CRYPTO_ShortHashCode zone_key_hash;
586   struct GNUNET_HashCode long_hash;
587   char *rd_tmp;
588   char *name_tmp;
589   size_t rd_ser_len;
590   size_t r_size;
591   size_t name_len;
592   int copied_elements;
593   int contains_signature;
594   int authoritative;
595   int rd_modified;
596   unsigned int c;
597
598   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
599               "Found %u records under name `%s'\n",
600               rd_count,
601               name);
602   authoritative = GNUNET_NO;
603   signature_new = NULL;
604   cc = NULL;
605   if (NULL != zone_key) 
606   {
607     GNUNET_CRYPTO_short_hash (zone_key, 
608                               sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded), 
609                               &zone_key_hash);
610     GNUNET_CRYPTO_short_hash_double (&zone_key_hash, &long_hash);
611     if (NULL != (cc = GNUNET_CONTAINER_multihashmap_get (zonekeys, &long_hash)))   
612     {
613       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
614                   "Am authoritative for zone `%s'\n",
615                   GNUNET_NAMESTORE_short_h2s (&zone_key_hash));
616       authoritative = GNUNET_YES;    
617     }
618   }
619
620   copied_elements = 0;
621   rd_modified = GNUNET_NO;
622   rd_selected = NULL;
623   /* count records to copy */
624   for (c = 0; c < rd_count; c++)
625   {
626     if ( (GNUNET_YES == authoritative) &&
627          (GNUNET_YES ==
628           GNUNET_NAMESTORE_is_expired (&rd[c]) ) )
629     {
630       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
631                   "Skipping expired record\n");
632       continue; 
633     }
634     if ( (GNUNET_NAMESTORE_TYPE_ANY == lnc->record_type) || 
635          (rd[c].record_type == lnc->record_type) )
636       copied_elements++; /* found matching record */
637     else
638     {
639       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
640                   "Skipping non-mtaching record\n");
641       rd_modified = GNUNET_YES;
642     }
643   }
644   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
645               "Found %u records with type %u for name `%s' in zone `%s'\n",
646               copied_elements, 
647               lnc->record_type, 
648               lnc->name, 
649               GNUNET_NAMESTORE_short_h2s(lnc->zone));
650   if (copied_elements > 0)
651   {
652     rd_selected = GNUNET_malloc (copied_elements * sizeof (struct GNUNET_NAMESTORE_RecordData));
653     copied_elements = 0;
654     for (c = 0; c < rd_count; c++)
655     {
656       if ( (GNUNET_YES == authoritative) &&
657            (GNUNET_YES ==
658             GNUNET_NAMESTORE_is_expired (&rd[c])) )
659         continue;
660       if ( (GNUNET_NAMESTORE_TYPE_ANY == lnc->record_type) || 
661            (rd[c].record_type == lnc->record_type) )
662       {
663         if (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
664         {
665           GNUNET_break (GNUNET_YES == authoritative);
666           rd_modified = GNUNET_YES;
667           re.rel_value = rd[c].expiration_time;
668           e = GNUNET_TIME_relative_to_absolute (re);
669         }
670         else
671         {
672           e.abs_value = rd[c].expiration_time;
673         }
674         /* found matching record, copy and convert flags to public format */
675         rd_selected[copied_elements] = rd[c]; /* shallow copy! */
676         rd_selected[copied_elements].expiration_time = e.abs_value;
677         if (0 != (rd_selected[copied_elements].flags &
678                   (GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION | GNUNET_NAMESTORE_RF_AUTHORITY)))
679         {
680           rd_selected[copied_elements].flags &= ~ (GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION | 
681                                   GNUNET_NAMESTORE_RF_AUTHORITY);
682           rd_modified = GNUNET_YES;
683         }
684         copied_elements++;
685       }
686       else
687       {
688         rd_modified = GNUNET_YES;
689       }
690     }
691   }
692   else
693     rd_selected = NULL;
694
695   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
696               "Found %u matching records for name `%s' in zone `%s'\n",
697               copied_elements,
698               lnc->name, 
699               GNUNET_NAMESTORE_short_h2s (lnc->zone));
700   contains_signature = GNUNET_NO;
701   if (copied_elements > 0)
702   {
703     if (GNUNET_YES == authoritative)
704     {
705       GNUNET_assert (NULL != cc);
706       e = get_block_expiration_time (rd_count, rd);
707       signature_new = GNUNET_NAMESTORE_create_signature (cc->privkey, e, name, rd_selected, copied_elements);
708       GNUNET_assert (NULL != signature_new);
709       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
710                   "Creating signature for name `%s' with %u records in zone `%s'\n",
711                   name, 
712                   copied_elements,
713                   GNUNET_NAMESTORE_short_h2s(&zone_key_hash));
714     }
715     else
716     {
717       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
718                   "Not authoritative, records modified is %d, have sig is %d\n",
719                   rd_modified,
720                   NULL != signature);
721       if ((GNUNET_NO == rd_modified) && (NULL != signature))
722         contains_signature = GNUNET_YES; /* returning all records, so include signature */
723     }
724   }
725
726   rd_ser_len = GNUNET_NAMESTORE_records_get_size (copied_elements, rd_selected);
727   name_len = (NULL == name) ? 0 : strlen(name) + 1;
728   r_size = sizeof (struct LookupNameResponseMessage) +
729            sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded) +
730            name_len +
731            rd_ser_len;
732   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
733               "Sending `%s' message\n", 
734               "NAMESTORE_LOOKUP_NAME_RESPONSE");
735   lnr_msg = GNUNET_malloc (r_size);
736   lnr_msg->gns_header.header.type = ntohs (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE);
737   lnr_msg->gns_header.header.size = ntohs (r_size);
738   lnr_msg->gns_header.r_id = htonl (lnc->request_id);
739   lnr_msg->rd_count = htons (copied_elements);
740   lnr_msg->rd_len = htons (rd_ser_len);
741   lnr_msg->name_len = htons (name_len);
742   lnr_msg->expire = GNUNET_TIME_absolute_hton (get_block_expiration_time (copied_elements, 
743                                                                           rd_selected));
744   name_tmp = (char *) &lnr_msg[1];
745   memcpy (name_tmp, name, name_len);
746   rd_tmp = &name_tmp[name_len];
747   GNUNET_NAMESTORE_records_serialize (copied_elements, rd_selected, rd_ser_len, rd_tmp);
748   if (rd_selected != rd)
749     GNUNET_free_non_null (rd_selected);
750   if (NULL != zone_key)
751     lnr_msg->public_key = *zone_key;
752   if ( (GNUNET_YES == authoritative) &&
753        (copied_elements > 0) )
754   {
755     /* use new created signature */
756     lnr_msg->contains_sig = htons (GNUNET_YES);
757     GNUNET_assert (NULL != signature_new);
758     lnr_msg->signature = *signature_new;
759     GNUNET_free (signature_new);
760   }
761   else if (GNUNET_YES == contains_signature)
762   {
763     /* use existing signature */
764     lnr_msg->contains_sig = htons (GNUNET_YES);
765     GNUNET_assert (NULL != signature);
766     lnr_msg->signature = *signature;
767   }
768   GNUNET_SERVER_notification_context_unicast (snc, lnc->nc->client, 
769                                               &lnr_msg->gns_header.header, 
770                                               GNUNET_NO);
771   GNUNET_free (lnr_msg);
772 }
773
774
775 /**
776  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME' message
777  *
778  * @param cls unused
779  * @param client GNUNET_SERVER_Client sending the message
780  * @param message message of type 'struct LookupNameMessage'
781  */
782 static void
783 handle_lookup_name (void *cls,
784                     struct GNUNET_SERVER_Client *client,
785                     const struct GNUNET_MessageHeader *message)
786 {
787   const struct LookupNameMessage *ln_msg;
788   struct LookupNameContext lnc;
789   struct GNUNET_NAMESTORE_Client *nc;
790   size_t name_len;
791   const char *name;
792   uint32_t rid;
793   uint32_t type;
794   char *conv_name;
795
796   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
797               "Received `%s' message\n", 
798               "NAMESTORE_LOOKUP_NAME");
799   if (ntohs (message->size) < sizeof (struct LookupNameMessage))
800   {
801     GNUNET_break (0);
802     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
803     return;
804   }
805   if (NULL == (nc = client_lookup(client)))
806   {
807     GNUNET_break (0);
808     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
809     return;
810   }
811   ln_msg = (const struct LookupNameMessage *) message;
812   rid = ntohl (ln_msg->gns_header.r_id);
813   name_len = ntohl (ln_msg->name_len);
814   type = ntohl (ln_msg->record_type);
815   if ((0 == name_len) || (name_len > MAX_NAME_LEN))
816   {
817     GNUNET_break (0);
818     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
819     return;
820   }
821   name = (const char *) &ln_msg[1];
822   if ('\0' != name[name_len -1])
823   {
824     GNUNET_break (0);
825     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
826     return;
827   }
828   if (GNUNET_NAMESTORE_TYPE_ANY == type)
829     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
830                 "Looking up all records for name `%s' in zone `%s'\n", 
831                 name, 
832                 GNUNET_NAMESTORE_short_h2s(&ln_msg->zone));
833   else
834     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
835                 "Looking up records with type %u for name `%s' in zone `%s'\n", 
836                 type, name, 
837                 GNUNET_NAMESTORE_short_h2s(&ln_msg->zone));
838
839   conv_name = GNUNET_NAMESTORE_normalize_string (name);
840   if (NULL == conv_name)
841   {
842       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
843                   "Error converting name `%s'\n", name);
844       return;
845   }
846
847   /* do the actual lookup */
848   lnc.request_id = rid;
849   lnc.nc = nc;
850   lnc.record_type = type;
851   lnc.name = conv_name;
852   lnc.zone = &ln_msg->zone;
853   if (GNUNET_SYSERR ==
854       GSN_database->iterate_records (GSN_database->cls, 
855                                      &ln_msg->zone, conv_name, 0 /* offset */,
856                                      &handle_lookup_name_it, &lnc))
857   {
858     /* internal error (in database plugin); might be best to just hang up on
859        plugin rather than to signal that there are 'no' results, which 
860        might also be false... */
861     GNUNET_break (0); 
862     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
863     GNUNET_free (conv_name);
864     return;
865   }
866   GNUNET_free (conv_name);
867   GNUNET_SERVER_receive_done (client, GNUNET_OK);
868 }
869
870
871 /**
872  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT' message
873  *
874  * @param cls unused
875  * @param client GNUNET_SERVER_Client sending the message
876  * @param message message of type 'struct RecordPutMessage'
877  */
878 static void
879 handle_record_put (void *cls,
880                    struct GNUNET_SERVER_Client *client,
881                    const struct GNUNET_MessageHeader *message)
882 {
883   struct GNUNET_NAMESTORE_Client *nc;
884   const struct RecordPutMessage *rp_msg;
885   struct GNUNET_TIME_Absolute expire;
886   const struct GNUNET_CRYPTO_EccSignature *signature;
887   struct RecordPutResponseMessage rpr_msg;
888   struct GNUNET_CRYPTO_ShortHashCode zone_hash;
889   size_t name_len;
890   size_t msg_size;
891   size_t msg_size_exp;
892   const char *name;
893   const char *rd_ser;
894   char * conv_name;
895   uint32_t rid;
896   uint32_t rd_ser_len;
897   uint32_t rd_count;
898   int res;
899
900   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
901               "Received `%s' message\n",
902               "NAMESTORE_RECORD_PUT");
903   if (ntohs (message->size) < sizeof (struct RecordPutMessage))
904   {
905     GNUNET_break (0);
906     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
907     return;
908   }
909   if (NULL == (nc = client_lookup (client)))
910   {
911     GNUNET_break (0);
912     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
913     return;
914   }
915   rp_msg = (const struct RecordPutMessage *) message;
916   rid = ntohl (rp_msg->gns_header.r_id);
917   msg_size = ntohs (rp_msg->gns_header.header.size);
918   name_len = ntohs (rp_msg->name_len);
919   rd_count = ntohs (rp_msg->rd_count);
920   rd_ser_len = ntohs (rp_msg->rd_len);
921   if ((rd_count < 1) || (rd_ser_len < 1) || (name_len >= MAX_NAME_LEN) || (0 == name_len))
922   {
923     GNUNET_break (0);
924     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
925     return;
926   }
927   msg_size_exp = sizeof (struct RecordPutMessage) + name_len + rd_ser_len;
928   if (msg_size != msg_size_exp)
929   {
930     GNUNET_break (0);
931     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
932     return;
933   }
934   name = (const char *) &rp_msg[1];
935   if ('\0' != name[name_len -1])
936   {
937     GNUNET_break (0);
938     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
939     return;
940   }
941   expire = GNUNET_TIME_absolute_ntoh (rp_msg->expire);
942   signature = &rp_msg->signature;
943   rd_ser = &name[name_len];
944   struct GNUNET_NAMESTORE_RecordData rd[rd_count];
945
946   if (GNUNET_OK !=
947       GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, rd))
948   {
949     GNUNET_break (0);
950     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
951     return;
952   }
953   GNUNET_CRYPTO_short_hash (&rp_msg->public_key,
954                             sizeof (rp_msg->public_key),
955                             &zone_hash);
956
957   conv_name = GNUNET_NAMESTORE_normalize_string (name);
958   if (NULL == conv_name)
959   {
960       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
961                   "Error converting name `%s'\n", name);
962       return;
963   }
964
965   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966               "Putting %u records under name `%s' in zone `%s'\n",
967               rd_count, conv_name,
968               GNUNET_NAMESTORE_short_h2s (&zone_hash));
969   res = GSN_database->put_records(GSN_database->cls,
970                                   &rp_msg->public_key,
971                                   expire,
972                                   conv_name,
973                                   rd_count, rd,
974                                   signature);
975   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
976               "Putting record for name `%s': %s\n",
977               conv_name,
978               (GNUNET_OK == res) ? "OK" : "FAILED");
979   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
980               "Sending `%s' message\n", 
981               "RECORD_PUT_RESPONSE");
982   GNUNET_free (conv_name);
983   rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT_RESPONSE);
984   rpr_msg.gns_header.header.size = htons (sizeof (struct RecordPutResponseMessage));
985   rpr_msg.gns_header.r_id = htonl (rid);
986   rpr_msg.op_result = htonl (res);
987   GNUNET_SERVER_notification_context_unicast (snc, 
988                                               nc->client, 
989                                               &rpr_msg.gns_header.header, 
990                                               GNUNET_NO);
991   GNUNET_SERVER_receive_done (client, GNUNET_OK);
992 }
993
994
995 /**
996  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE' message
997  *
998  * @param cls unused
999  * @param client GNUNET_SERVER_Client sending the message
1000  * @param message message of type 'struct RecordCreateMessage'
1001  */
1002 static void
1003 handle_record_create (void *cls,
1004                       struct GNUNET_SERVER_Client *client,
1005                       const struct GNUNET_MessageHeader *message)
1006 {
1007   static struct GNUNET_CRYPTO_EccSignature dummy_signature;
1008   struct GNUNET_NAMESTORE_Client *nc;
1009   const struct RecordCreateMessage *rp_msg;
1010   struct GNUNET_CRYPTO_EccPrivateKey *pkey;
1011   struct RecordCreateResponseMessage rcr_msg;
1012   size_t name_len;
1013   size_t msg_size;
1014   size_t msg_size_exp;
1015   size_t rd_ser_len;
1016   size_t key_len;
1017   uint32_t rid;
1018   const char *pkey_tmp;
1019   const char *name_tmp;
1020   char *conv_name;
1021   const char *rd_ser;
1022   unsigned int rd_count;
1023   int res;
1024   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1025   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pubkey;
1026
1027   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1028               "Received `%s' message\n", "NAMESTORE_RECORD_CREATE");
1029   if (ntohs (message->size) < sizeof (struct RecordCreateMessage))
1030   {
1031     GNUNET_break (0);
1032     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1033     return;
1034   }
1035   if (NULL == (nc = client_lookup (client)))
1036   {
1037     GNUNET_break (0);
1038     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1039     return;
1040   }
1041   rp_msg = (const struct RecordCreateMessage *) message;
1042   rid = ntohl (rp_msg->gns_header.r_id);
1043   name_len = ntohs (rp_msg->name_len);
1044   msg_size = ntohs (message->size);
1045   rd_count = ntohs (rp_msg->rd_count);
1046   rd_ser_len = ntohs (rp_msg->rd_len);
1047   key_len = ntohs (rp_msg->pkey_len);
1048   msg_size_exp = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len;
1049   if (msg_size != msg_size_exp)
1050   {
1051     GNUNET_break (0);
1052     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1053     return;
1054   }
1055   if ((0 == name_len) || (name_len > MAX_NAME_LEN))
1056   {
1057     GNUNET_break (0);
1058     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1059     return;
1060   }
1061   pkey_tmp = (const char *) &rp_msg[1];
1062   name_tmp = &pkey_tmp[key_len];
1063   rd_ser = &name_tmp[name_len];
1064   if ('\0' != name_tmp[name_len -1])
1065   {
1066     GNUNET_break (0);
1067     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1068     return;
1069   }
1070   if (NULL == (pkey = GNUNET_CRYPTO_ecc_decode_key (pkey_tmp, key_len,
1071                                                     GNUNET_NO)))
1072   {
1073     GNUNET_break (0);
1074     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1075     return;
1076   }
1077   {
1078     struct GNUNET_NAMESTORE_RecordData rd[rd_count];
1079
1080     if (GNUNET_OK !=
1081         GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, rd))
1082     {
1083       GNUNET_break (0);
1084       GNUNET_CRYPTO_ecc_key_free (pkey);
1085       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1086       return;
1087     }
1088
1089     /* Extracting and converting private key */
1090     GNUNET_CRYPTO_ecc_key_get_public (pkey, &pubkey);
1091     GNUNET_CRYPTO_short_hash (&pubkey,
1092                               sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
1093                               &pubkey_hash);
1094     learn_private_key (pkey);    
1095     conv_name = GNUNET_NAMESTORE_normalize_string (name_tmp);
1096     if (NULL == conv_name)
1097     {
1098       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1099                   "Error converting name `%s'\n", name_tmp);
1100       GNUNET_CRYPTO_ecc_key_free (pkey);
1101       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1102       return;
1103     }
1104     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1105                 "Creating %u records for name `%s' in zone `%s'\n",
1106                 (unsigned int) rd_count,
1107                 conv_name,
1108                 GNUNET_NAMESTORE_short_h2s (&pubkey_hash));
1109     if (0 == rd_count)
1110       res = GSN_database->remove_records (GSN_database->cls,
1111                                           &pubkey_hash,
1112                                           conv_name);
1113     else
1114       res = GSN_database->put_records (GSN_database->cls,
1115                                        &pubkey,
1116                                        GNUNET_TIME_absolute_ntoh(rp_msg->expire),
1117                                        conv_name,
1118                                        rd_count, rd,
1119                                        &dummy_signature);
1120     GNUNET_free (conv_name);
1121   }
1122   
1123   /* Send response */
1124   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1125               "Sending `%s' message\n", "RECORD_CREATE_RESPONSE");
1126   rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE);
1127   rcr_msg.gns_header.header.size = htons (sizeof (struct RecordCreateResponseMessage));
1128   rcr_msg.gns_header.r_id = htonl (rid);
1129   rcr_msg.op_result = htonl (res);
1130   GNUNET_SERVER_notification_context_unicast (snc, nc->client,
1131                                               &rcr_msg.gns_header.header,
1132                                               GNUNET_NO);
1133   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1134 }
1135
1136
1137 /**
1138  * Context for record remove operations passed from 'handle_zone_to_name' to
1139  * 'handle_zone_to_name_it' as closure
1140  */
1141 struct ZoneToNameCtx
1142 {
1143   /**
1144    * Namestore client
1145    */
1146   struct GNUNET_NAMESTORE_Client *nc;
1147
1148   /**
1149    * Request id (to be used in the response to the client).
1150    */
1151   uint32_t rid;
1152
1153   /**
1154    * Set to GNUNET_OK on success, GNUNET_SYSERR on error.  Note that
1155    * not finding a name for the zone still counts as a 'success' here,
1156    * as this field is about the success of executing the IPC protocol.
1157    */
1158   int success;
1159 };
1160
1161
1162 /**
1163  * Zone to name iterator
1164  *
1165  * @param cls struct ZoneToNameCtx *
1166  * @param zone_key the zone key
1167  * @param expire expiration date
1168  * @param name name
1169  * @param rd_count number of records
1170  * @param rd record data
1171  * @param signature signature
1172  */
1173 static void
1174 handle_zone_to_name_it (void *cls,
1175                         const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
1176                         struct GNUNET_TIME_Absolute expire,
1177                         const char *name,
1178                         unsigned int rd_count,
1179                         const struct GNUNET_NAMESTORE_RecordData *rd,
1180                         const struct GNUNET_CRYPTO_EccSignature *signature)
1181 {
1182   struct ZoneToNameCtx *ztn_ctx = cls;
1183   struct ZoneToNameResponseMessage *ztnr_msg;
1184   int16_t res;
1185   size_t name_len;
1186   size_t rd_ser_len;
1187   size_t msg_size;
1188   char *name_tmp;
1189   char *rd_tmp;
1190   char *sig_tmp;
1191
1192   if ((NULL != zone_key) && (NULL != name))
1193   {
1194     /* found result */
1195     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1196                 "Found result: name `%s' has %u records\n", 
1197                 name, rd_count);
1198     res = GNUNET_YES;
1199     name_len = strlen (name) + 1;
1200   }
1201   else
1202   {
1203     /* no result found */
1204     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1205                 "Found no results\n");
1206     res = GNUNET_NO;
1207     name_len = 0;
1208   }
1209   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1210               "Sending `%s' message\n", 
1211               "ZONE_TO_NAME_RESPONSE");
1212   rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1213   msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1214   if (NULL != signature)
1215     msg_size += sizeof (struct GNUNET_CRYPTO_EccSignature);
1216   if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1217   {
1218     GNUNET_break (0);
1219     ztn_ctx->success = GNUNET_SYSERR;
1220     return;
1221   }
1222   ztnr_msg = GNUNET_malloc (msg_size);
1223   ztnr_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1224   ztnr_msg->gns_header.header.size = htons (msg_size);
1225   ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1226   ztnr_msg->res = htons (res);
1227   ztnr_msg->rd_len = htons (rd_ser_len);
1228   ztnr_msg->rd_count = htons (rd_count);
1229   ztnr_msg->name_len = htons (name_len);
1230   ztnr_msg->expire = GNUNET_TIME_absolute_hton (expire);
1231   if (NULL != zone_key)
1232     ztnr_msg->zone_key = *zone_key;
1233   name_tmp = (char *) &ztnr_msg[1];
1234   if (NULL != name)
1235     memcpy (name_tmp, name, name_len);
1236   rd_tmp = &name_tmp[name_len];
1237   GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_tmp);
1238   sig_tmp = &rd_tmp[rd_ser_len];
1239   if (NULL != signature)
1240     memcpy (sig_tmp, signature, sizeof (struct GNUNET_CRYPTO_EccSignature));
1241   ztn_ctx->success = GNUNET_OK;
1242   GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client,
1243                                               &ztnr_msg->gns_header.header,
1244                                               GNUNET_NO);
1245   GNUNET_free (ztnr_msg);
1246 }
1247
1248
1249 /**
1250  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME' message
1251  *
1252  * @param cls unused
1253  * @param client GNUNET_SERVER_Client sending the message
1254  * @param message message of type 'struct ZoneToNameMessage'
1255  */
1256 static void
1257 handle_zone_to_name (void *cls,
1258                      struct GNUNET_SERVER_Client *client,
1259                      const struct GNUNET_MessageHeader *message)
1260 {
1261   struct GNUNET_NAMESTORE_Client *nc;
1262   const struct ZoneToNameMessage *ztn_msg;
1263   struct ZoneToNameCtx ztn_ctx;
1264
1265   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1266               "Received `%s' message\n",
1267               "ZONE_TO_NAME");
1268   ztn_msg = (const struct ZoneToNameMessage *) message;
1269   if (NULL == (nc = client_lookup(client)))
1270   {
1271     GNUNET_break (0);
1272     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1273     return;
1274   }
1275   ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1276   ztn_ctx.nc = nc;
1277   ztn_ctx.success = GNUNET_SYSERR;
1278   if (GNUNET_SYSERR ==
1279       GSN_database->zone_to_name (GSN_database->cls, 
1280                                   &ztn_msg->zone,
1281                                   &ztn_msg->value_zone,
1282                                   &handle_zone_to_name_it, &ztn_ctx))
1283   {
1284     /* internal error, hang up instead of signalling something
1285        that might be wrong */
1286     GNUNET_break (0);
1287     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1288     return;    
1289   }
1290   GNUNET_SERVER_receive_done (client, ztn_ctx.success);
1291 }
1292
1293
1294 /**
1295  * Zone iteration processor result
1296  */
1297 enum ZoneIterationResult
1298 {
1299   /**
1300    * Found records, but all records were filtered
1301    * Continue to iterate
1302    */
1303   IT_ALL_RECORDS_FILTERED = -1,
1304
1305   /**
1306    * Found records,
1307    * Continue to iterate with next iteration_next call
1308    */
1309   IT_SUCCESS_MORE_AVAILABLE = 0,
1310
1311   /**
1312    * Iteration complete
1313    */
1314   IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 1
1315 };
1316
1317
1318 /**
1319  * Context for record remove operations passed from
1320  * 'run_zone_iteration_round' to 'zone_iteraterate_proc' as closure
1321  */
1322 struct ZoneIterationProcResult
1323 {
1324   /**
1325    * The zone iteration handle
1326    */
1327   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1328
1329   /**
1330    * Iteration result: iteration done?
1331    * IT_SUCCESS_MORE_AVAILABLE:  if there may be more results overall but
1332    * we got one for now and have sent it to the client
1333    * IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
1334    * IT_ALL_RECORDS_FILTERED: if all results were filtered so far.
1335    */
1336   int res_iteration_finished;
1337
1338 };
1339
1340
1341 /**
1342  * Process results for zone iteration from database
1343  *
1344  * @param cls struct ZoneIterationProcResult *proc
1345  * @param zone_key the zone key
1346  * @param expire expiration time
1347  * @param name name
1348  * @param rd_count number of records for this name
1349  * @param rd record data
1350  * @param signature block signature
1351  */
1352 static void
1353 zone_iteraterate_proc (void *cls,
1354                        const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
1355                        struct GNUNET_TIME_Absolute expire,
1356                        const char *name,
1357                        unsigned int rd_count,
1358                        const struct GNUNET_NAMESTORE_RecordData *rd,
1359                        const struct GNUNET_CRYPTO_EccSignature *signature)
1360 {
1361   struct ZoneIterationProcResult *proc = cls;
1362   struct GNUNET_NAMESTORE_RecordData rd_filtered[rd_count];
1363   struct GNUNET_CRYPTO_EccSignature *new_signature = NULL;
1364   struct GNUNET_NAMESTORE_CryptoContainer *cc;
1365   struct GNUNET_HashCode long_hash;
1366   struct GNUNET_CRYPTO_ShortHashCode zone_hash;
1367   struct ZoneIterationResponseMessage *zir_msg;
1368   struct GNUNET_TIME_Relative rt;
1369   unsigned int rd_count_filtered;
1370   unsigned int c;
1371   size_t name_len;
1372   size_t rd_ser_len;
1373   size_t msg_size;
1374   char *name_tmp;
1375   char *rd_ser;
1376
1377   proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
1378   if ((NULL == zone_key) && (NULL == name))
1379   {
1380     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1381                 "Iteration done\n");
1382     proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
1383     return;
1384   }
1385   if ((NULL == zone_key) || (NULL == name)) 
1386   {
1387     /* what is this!? should never happen */
1388     GNUNET_break (0);
1389     return;    
1390   }
1391   rd_count_filtered  = 0;
1392   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1393               "Received result for zone iteration: `%s'\n", 
1394               name);
1395   for (c = 0; c < rd_count; c++)
1396   {
1397     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1398                 "Record %u has flags: %x must have flags are %x, must not have flags are %x\n",
1399                 c, rd[c].flags, 
1400                 proc->zi->must_have_flags,
1401                 proc->zi->must_not_have_flags);
1402     /* Checking must have flags, except 'relative-expiration' which is a special flag */
1403     if ((rd[c].flags & proc->zi->must_have_flags & (~GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
1404         != (proc->zi->must_have_flags & (~ GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)))
1405     {
1406       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %u lacks 'must-have' flags: Not included\n", c);
1407       continue;
1408     }
1409     /* Checking must-not-have flags */
1410     if (0 != (rd[c].flags & proc->zi->must_not_have_flags))
1411     {
1412       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1413                   "Record %u has 'must-not-have' flags: Not included\n", c);
1414       continue;
1415     }
1416     rd_filtered[rd_count_filtered] = rd[c];
1417     /* convert relative to absolute expiration time unless explicitly requested otherwise */
1418     if ( (0 == (proc->zi->must_have_flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) &&
1419          (0 != (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) )
1420     {
1421       /* should convert relative-to-absolute expiration time */
1422       rt.rel_value = rd[c].expiration_time;
1423       rd_filtered[c].expiration_time = GNUNET_TIME_relative_to_absolute (rt).abs_value;
1424       rd_filtered[c].flags &= ~ GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
1425     }
1426     /* we NEVER keep the 'authority' flag */
1427     rd_filtered[c].flags &= ~ GNUNET_NAMESTORE_RF_AUTHORITY;
1428     rd_count_filtered++;    
1429   }
1430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1431               "Included %u of %u records\n", 
1432               rd_count_filtered, rd_count);
1433
1434   signature = NULL;    
1435   if ( (rd_count_filtered > 0) &&
1436        (0 == (proc->zi->must_have_flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) )
1437   {
1438     /* compute / obtain signature, but only if we (a) have records and (b) expiration times were 
1439        converted to absolute expiration times */
1440     GNUNET_CRYPTO_short_hash (zone_key, 
1441                               sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
1442                               &zone_hash);
1443     GNUNET_CRYPTO_short_hash_double (&zone_hash, &long_hash);
1444     if (NULL != (cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash)))
1445     {
1446       expire = get_block_expiration_time (rd_count_filtered, rd_filtered);
1447       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1448                   "Creating signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1449                   name, GNUNET_NAMESTORE_short_h2s(&zone_hash), 
1450                   rd_count_filtered,
1451                   (unsigned long long) expire.abs_value);
1452       new_signature = GNUNET_NAMESTORE_create_signature (cc->privkey, expire, name, 
1453                                                          rd_filtered, rd_count_filtered);
1454       GNUNET_assert (NULL != new_signature);
1455       signature = new_signature;
1456     }
1457     else if (rd_count_filtered == rd_count)
1458     {
1459       if (NULL != signature)
1460         {
1461           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1462                       "Using provided signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1463                       name, GNUNET_NAMESTORE_short_h2s (&zone_hash), rd_count_filtered, 
1464                       (unsigned long long) expire.abs_value);
1465           return;
1466         }    
1467     }
1468   }
1469   if (rd_count_filtered == 0)
1470   {
1471     /* After filtering records there are no records left to return */
1472     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No records to transmit\n");
1473     proc->res_iteration_finished = IT_ALL_RECORDS_FILTERED;
1474     return;
1475   }
1476
1477   if (GNUNET_YES == proc->zi->has_zone)
1478     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1479                 "Sending name `%s' for iteration over zone `%s'\n",
1480                 name, GNUNET_NAMESTORE_short_h2s(&proc->zi->zone));
1481   else
1482     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1483                 "Sending name `%s' for iteration over all zones\n",
1484                 name);
1485   name_len = strlen (name) + 1;
1486   rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count_filtered, rd_filtered);  
1487   msg_size = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_ser_len;
1488
1489   zir_msg = GNUNET_malloc (msg_size);
1490   zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1491   zir_msg->gns_header.header.size = htons (msg_size);
1492   zir_msg->gns_header.r_id = htonl (proc->zi->request_id);
1493   zir_msg->expire = GNUNET_TIME_absolute_hton (expire);
1494   zir_msg->reserved = htons (0);
1495   zir_msg->name_len = htons (name_len);
1496   zir_msg->rd_count = htons (rd_count_filtered);
1497   zir_msg->rd_len = htons (rd_ser_len);
1498   if (NULL != signature)
1499     zir_msg->signature = *signature;
1500   zir_msg->public_key = *zone_key;
1501   name_tmp = (char *) &zir_msg[1];
1502   memcpy (name_tmp, name, name_len);
1503   rd_ser = &name_tmp[name_len];
1504   GNUNET_NAMESTORE_records_serialize (rd_count_filtered, rd_filtered, rd_ser_len, rd_ser);
1505   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1506               "Sending `%s' message with size %u\n", 
1507               "ZONE_ITERATION_RESPONSE",
1508               msg_size);
1509   GNUNET_SERVER_notification_context_unicast (snc, proc->zi->client->client, 
1510                                               (const struct GNUNET_MessageHeader *) zir_msg,
1511                                               GNUNET_NO);
1512   proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
1513   GNUNET_free (zir_msg);
1514   GNUNET_free_non_null (new_signature);
1515 }
1516
1517
1518 /**
1519  * Perform the next round of the zone iteration.
1520  *
1521  * @param zi zone iterator to process
1522  */
1523 static void
1524 run_zone_iteration_round (struct GNUNET_NAMESTORE_ZoneIteration *zi)
1525 {
1526   struct ZoneIterationProcResult proc;
1527   struct ZoneIterationResponseMessage zir_end;
1528   struct GNUNET_CRYPTO_ShortHashCode *zone;
1529
1530   memset (&proc, 0, sizeof (proc));
1531   proc.zi = zi;
1532   if (GNUNET_YES == zi->has_zone)
1533     zone = &zi->zone;
1534   else
1535     zone = NULL;
1536   proc.res_iteration_finished = IT_ALL_RECORDS_FILTERED;
1537   while (IT_ALL_RECORDS_FILTERED == proc.res_iteration_finished)
1538   {
1539     if (GNUNET_SYSERR ==
1540         GSN_database->iterate_records (GSN_database->cls, zone, NULL, 
1541                                        zi->offset, 
1542                                        &zone_iteraterate_proc, &proc))
1543     {
1544       GNUNET_break (0);
1545       break;
1546     }
1547     zi->offset++;
1548   }
1549   if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
1550   {
1551     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1552                 "More results available\n");
1553     return; /* more results later */
1554   }
1555   if (GNUNET_YES == zi->has_zone)
1556     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1557                 "No more results for zone `%s'\n", 
1558                 GNUNET_NAMESTORE_short_h2s(&zi->zone));
1559   else
1560     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1561                 "No more results for all zones\n");
1562   memset (&zir_end, 0, sizeof (zir_end));
1563   zir_end.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1564   zir_end.gns_header.header.size = htons (sizeof (struct ZoneIterationResponseMessage));
1565   zir_end.gns_header.r_id = htonl(zi->request_id);
1566   GNUNET_SERVER_notification_context_unicast (snc, 
1567                                               zi->client->client, 
1568                                               &zir_end.gns_header.header, GNUNET_NO);
1569   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1570               "Removing zone iterator\n");
1571   GNUNET_CONTAINER_DLL_remove (zi->client->op_head, zi->client->op_tail, zi);
1572   GNUNET_free (zi);
1573 }
1574
1575
1576 /**
1577  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START' message
1578  *
1579  * @param cls unused
1580  * @param client GNUNET_SERVER_Client sending the message
1581  * @param message message of type 'struct ZoneIterationStartMessage'
1582  */
1583 static void
1584 handle_iteration_start (void *cls,
1585                         struct GNUNET_SERVER_Client *client,
1586                         const struct GNUNET_MessageHeader *message)
1587 {
1588   static struct GNUNET_CRYPTO_ShortHashCode zeros;
1589   const struct ZoneIterationStartMessage *zis_msg;
1590   struct GNUNET_NAMESTORE_Client *nc;
1591   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1592
1593   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START");
1594   if (NULL == (nc = client_lookup (client)))
1595   {
1596     GNUNET_break (0);
1597     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1598     return;
1599   }
1600   zis_msg = (const struct ZoneIterationStartMessage *) message;
1601   zi = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIteration));
1602   zi->request_id = ntohl (zis_msg->gns_header.r_id);
1603   zi->offset = 0;
1604   zi->client = nc;
1605   zi->must_have_flags = ntohs (zis_msg->must_have_flags);
1606   zi->must_not_have_flags = ntohs (zis_msg->must_not_have_flags);
1607   if (0 == memcmp (&zeros, &zis_msg->zone, sizeof (zeros)))
1608   {
1609     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over all zones\n");
1610     zi->zone = zis_msg->zone;
1611     zi->has_zone = GNUNET_NO;
1612   }
1613   else
1614   {
1615     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1616                 "Starting to iterate over zone `%s'\n", GNUNET_NAMESTORE_short_h2s (&zis_msg->zone));
1617     zi->zone = zis_msg->zone;
1618     zi->has_zone = GNUNET_YES;
1619   }
1620   GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
1621   run_zone_iteration_round (zi);
1622   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1623 }
1624
1625
1626 /**
1627  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP' message
1628  *
1629  * @param cls unused
1630  * @param client GNUNET_SERVER_Client sending the message
1631  * @param message message of type 'struct ZoneIterationStopMessage'
1632  */
1633 static void
1634 handle_iteration_stop (void *cls,
1635                        struct GNUNET_SERVER_Client *client,
1636                        const struct GNUNET_MessageHeader *message)
1637 {
1638   struct GNUNET_NAMESTORE_Client *nc;
1639   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1640   const struct ZoneIterationStopMessage *zis_msg;
1641   uint32_t rid;
1642
1643   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1644               "Received `%s' message\n",
1645               "ZONE_ITERATION_STOP");
1646   if (NULL == (nc = client_lookup(client)))
1647   {
1648     GNUNET_break (0);
1649     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1650     return;
1651   }
1652   zis_msg = (const struct ZoneIterationStopMessage *) message;
1653   rid = ntohl (zis_msg->gns_header.r_id);
1654   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1655     if (zi->request_id == rid)
1656       break;
1657   if (NULL == zi)
1658   {
1659     GNUNET_break (0);
1660     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1661     return;
1662   }
1663   GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
1664   if (GNUNET_YES == zi->has_zone)
1665     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1666                 "Stopped zone iteration for zone `%s'\n",
1667                 GNUNET_NAMESTORE_short_h2s (&zi->zone));
1668   else
1669     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1670                 "Stopped zone iteration over all zones\n");
1671   GNUNET_free (zi);
1672   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1673 }
1674
1675
1676 /**
1677  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT' message
1678  *
1679  * @param cls unused
1680  * @param client GNUNET_SERVER_Client sending the message
1681  * @param message message of type 'struct ZoneIterationNextMessage'
1682  */
1683 static void
1684 handle_iteration_next (void *cls,
1685                        struct GNUNET_SERVER_Client *client,
1686                        const struct GNUNET_MessageHeader *message)
1687 {
1688   struct GNUNET_NAMESTORE_Client *nc;
1689   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1690   const struct ZoneIterationNextMessage *zis_msg;
1691   uint32_t rid;
1692
1693   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT");
1694   if (NULL == (nc = client_lookup(client)))
1695   {
1696     GNUNET_break (0);
1697     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1698     return;
1699   }
1700   zis_msg = (const struct ZoneIterationNextMessage *) message;
1701   rid = ntohl (zis_msg->gns_header.r_id);
1702   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1703     if (zi->request_id == rid)
1704       break;
1705   if (NULL == zi)
1706   {
1707     GNUNET_break (0);
1708     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1709     return;
1710   }
1711   run_zone_iteration_round (zi);
1712   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1713 }
1714
1715 static void
1716 zonekey_it_key_cb (void *cls,
1717                    struct GNUNET_CRYPTO_EccPrivateKey *pk,
1718                    const char *emsg)
1719 {
1720   struct KeyLoadContext *kl = cls;
1721
1722   kl->keygen = NULL;
1723   if (NULL == pk)
1724   {
1725     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1726                 _("Could not parse zone key file `%s'\n"),
1727                 kl->filename);
1728     return;
1729   }
1730   learn_private_key (pk);
1731   (*kl->counter) ++;
1732
1733   GNUNET_CONTAINER_DLL_remove (kl_head, kl_tail, kl);
1734   GNUNET_free (kl->filename);
1735   GNUNET_free (kl);
1736 }
1737
1738
1739 /**
1740  * Load zone keys from directory by reading all .zkey files in this directory
1741  *
1742  * @param cls int * 'counter' to store the number of files found
1743  * @param filename directory to scan
1744  * @return GNUNET_OK to continue
1745  */
1746 static int
1747 zonekey_file_it (void *cls, const char *filename)
1748 {
1749   struct KeyLoadContext *kl;
1750
1751   if ((NULL == filename) ||
1752       (NULL == strstr(filename, ".zkey")))
1753     return GNUNET_OK;
1754
1755   kl = GNUNET_malloc (sizeof (struct KeyLoadContext));
1756   kl->filename = strdup (filename);
1757   kl->counter = cls;
1758   kl->keygen = GNUNET_CRYPTO_ecc_key_create_start (filename, zonekey_it_key_cb, kl);
1759   if (NULL == kl->keygen)
1760   {
1761     GNUNET_free (kl->filename);
1762     GNUNET_free (kl);
1763     return GNUNET_OK;
1764   }
1765
1766   GNUNET_CONTAINER_DLL_insert (kl_head, kl_tail, kl);
1767   return GNUNET_OK;
1768 }
1769
1770
1771 /**
1772  * Process namestore requests.
1773  *
1774  * @param cls closure
1775  * @param server the initialized server
1776  * @param cfg configuration to use
1777  */
1778 static void
1779 run (void *cls, struct GNUNET_SERVER_Handle *server,
1780      const struct GNUNET_CONFIGURATION_Handle *cfg)
1781 {
1782   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1783     {&handle_start, NULL,
1784      GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)},
1785     {&handle_lookup_name, NULL,
1786      GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0},
1787     {&handle_record_put, NULL,
1788     GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT, 0},
1789     {&handle_record_create, NULL,
1790      GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE, 0},
1791     {&handle_zone_to_name, NULL,
1792      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, sizeof (struct ZoneToNameMessage) },
1793     {&handle_iteration_start, NULL,
1794      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage) },
1795     {&handle_iteration_next, NULL,
1796      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, sizeof (struct ZoneIterationNextMessage) },
1797      {&handle_iteration_stop, NULL,
1798       GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, sizeof (struct ZoneIterationStopMessage) },
1799     {NULL, NULL, 0, 0}
1800   };
1801   char *database;
1802   unsigned int counter;
1803
1804   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
1805   GSN_cfg = cfg;
1806
1807   /* Load private keys from disk */
1808   if (GNUNET_OK !=
1809       GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore", 
1810                                                "zonefile_directory",
1811                                                &zonefile_directory))
1812   {
1813     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1814                 _("No directory to load zonefiles specified in configuration\n"));
1815     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
1816     return;
1817   }
1818
1819   if (GNUNET_NO == GNUNET_DISK_file_test (zonefile_directory))
1820   {
1821     if (GNUNET_SYSERR == GNUNET_DISK_directory_create (zonefile_directory))
1822     {
1823       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1824                   _("Creating directory `%s' for zone files failed!\n"),
1825                   zonefile_directory);
1826       GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
1827       return;
1828     }
1829     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1830                 "Created directory `%s' for zone files\n", 
1831                 zonefile_directory);
1832   }
1833
1834   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1835               "Scanning directory `%s' for zone files\n", zonefile_directory);
1836   zonekeys = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
1837   counter = 0;
1838   GNUNET_DISK_directory_scan (zonefile_directory, zonekey_file_it, &counter);
1839   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1840               "Found %u zone files\n", 
1841               counter);
1842
1843   /* Loading database plugin */
1844   if (GNUNET_OK !=
1845       GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
1846                                              &database))
1847     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
1848
1849   GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
1850   GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
1851   GNUNET_free (database);
1852   if (NULL == GSN_database)
1853   {
1854     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1855                 "Could not load database backend `%s'\n",
1856                 db_lib_name);
1857     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
1858     return;
1859   }
1860
1861   /* Configuring server handles */
1862   GNUNET_SERVER_add_handlers (server, handlers);
1863   snc = GNUNET_SERVER_notification_context_create (server, 16);
1864   GNUNET_SERVER_disconnect_notify (server,
1865                                    &client_disconnect_notification,
1866                                    NULL);
1867   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1868                                 NULL);
1869 }
1870
1871
1872 /**
1873  * The main function for the template service.
1874  *
1875  * @param argc number of arguments from the command line
1876  * @param argv command line arguments
1877  * @return 0 ok, 1 on error
1878  */
1879 int
1880 main (int argc, char *const *argv)
1881 {
1882   return (GNUNET_OK ==
1883           GNUNET_SERVICE_run (argc, argv, "namestore",
1884                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
1885 }
1886
1887 /* end of gnunet-service-namestore.c */
1888