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