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