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