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