-more code cleanup in namestore
[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
852
853 /**
854  * Context for record create operations passed from 'handle_record_create' to
855  * 'handle_create_record_it' as closure
856  */
857 struct CreateRecordContext
858 {
859   /**
860    * Record data
861    */
862   const struct GNUNET_NAMESTORE_RecordData *rd;
863
864   /**
865    * Zone's private key
866    */
867   const struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
868
869   /**
870    * Zone's public key
871    */
872   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey;
873
874   /**
875    * Name for the record to create
876    */
877   const char *name;
878
879   /**
880    * Record expiration time
881    */
882   struct GNUNET_TIME_Absolute expire;
883
884   /**
885    * result returned from 'handle_create_record_it'
886    * GNUNET_SYSERR: failed to create the record
887    * GNUNET_NO: we updated an existing record or identical entry existed
888    * GNUNET_YES : we created a new record
889    */
890   int res;
891 };
892
893
894 /**
895  * A 'GNUNET_NAMESTORE_RecordIterator' for record create operations
896  * in handle_record_create
897  *
898  * @param cls a 'struct CreateRecordContext *' with information about the request
899  * @param pubkey zone key of the zone
900  * @param expire expiration time
901  * @param name name
902  * @param rd_count number of records
903  * @param rd array of records
904  * @param signature signature
905  */
906 static void
907 handle_create_record_it (void *cls,
908                          const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pubkey,
909                          struct GNUNET_TIME_Absolute expire,
910                          const char *name,
911                          unsigned int rd_count,
912                          const struct GNUNET_NAMESTORE_RecordData *rd,
913                          const struct GNUNET_CRYPTO_RsaSignature *signature)
914 {
915   struct CreateRecordContext *crc = cls;
916   struct GNUNET_NAMESTORE_RecordData *rd_new = NULL;
917   struct GNUNET_CRYPTO_RsaSignature dummy_signature;
918   struct GNUNET_TIME_Absolute block_expiration;
919   int res;
920   int exist = GNUNET_SYSERR;
921   int update = GNUNET_NO;
922   int c;
923   int rd_count_new = 0;
924
925   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
926               "Found %u existing records for `%s'\n", 
927               rd_count, crc->name);
928   for (c = 0; c < rd_count; c++)
929   {
930     if ( (crc->rd->record_type == GNUNET_NAMESTORE_TYPE_PKEY) && 
931          (rd[c].record_type == GNUNET_NAMESTORE_TYPE_PKEY))
932     {
933       /* Update unique PKEY */
934       exist = c;
935       update = GNUNET_YES;
936       break;
937     }
938     if ( (crc->rd->record_type == GNUNET_NAMESTORE_TYPE_PSEU) && 
939          (rd[c].record_type == GNUNET_NAMESTORE_TYPE_PSEU))
940     {
941       /* Update unique PSEU */
942       exist = c;
943       update = GNUNET_YES;
944       break;
945     }
946     if ((crc->rd->record_type == rd[c].record_type) &&
947         (crc->rd->data_size == rd[c].data_size) &&
948         (0 == memcmp (crc->rd->data, rd[c].data, rd[c].data_size)))
949     {
950       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
951                   "Found existing records for `%s' to update expiration date!\n",
952                   crc->name);
953       exist = c;
954       if ( (crc->rd->expiration_time != rd[c].expiration_time) &&
955            ((crc->rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) 
956             == (rd[c].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION) ) )
957         update = GNUNET_YES;
958       break;
959     }
960   }
961
962   if (exist == GNUNET_SYSERR)
963   {
964     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
965                 "No existing record for name `%s'!\n", 
966                 crc->name);
967     rd_new = GNUNET_malloc ((rd_count+1) * sizeof (struct GNUNET_NAMESTORE_RecordData));
968     memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
969     rd_count_new = rd_count + 1;
970     rd_new[rd_count] = *(crc->rd);
971   }
972   else if (update == GNUNET_NO)
973   {
974     /* Exact same record already exists */
975     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
976                 "Matching record for %s' exists, no change required!\n",
977                 crc->name);
978     crc->res = GNUNET_NO;
979     return;
980   }
981   else 
982   {
983     /* Update record */
984     GNUNET_assert (GNUNET_YES == update);
985     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
986                 "Updating existing records for `%s'!\n", 
987                 crc->name);
988     rd_new = GNUNET_malloc ((rd_count) * sizeof (struct GNUNET_NAMESTORE_RecordData));
989     memcpy (rd_new, rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
990     rd_count_new = rd_count;
991     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
992                 (0 == (crc->rd->flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION)) 
993                 ? "Updating absolute expiration from %llu to %llu!\n"
994                 : "Updating relative expiration from %llu to %llu!\n", 
995                 rd_new[exist].expiration_time, crc->rd->expiration_time);
996     rd_new[exist] = *(crc->rd);
997   }
998
999   block_expiration = GNUNET_TIME_absolute_max(crc->expire, expire);
1000   if (block_expiration.abs_value != expire.abs_value)
1001     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1002                 "Updated block expiration time\n");
1003
1004   memset (&dummy_signature, '\0', sizeof (dummy_signature));
1005
1006   /* Database operation */
1007   GNUNET_assert ((rd_new != NULL) && (rd_count_new > 0));
1008   res = GSN_database->put_records(GSN_database->cls,
1009                                 (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *) crc->pubkey,
1010                                 block_expiration,
1011                                 crc->name,
1012                                 rd_count_new, rd_new,
1013                                 &dummy_signature);
1014   GNUNET_break (GNUNET_OK == res);
1015   if (res == GNUNET_OK)
1016     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Successfully put record for `%s' in database \n", crc->name);
1017   else
1018     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to put record for `%s' in database \n", crc->name);
1019   res = GNUNET_YES;
1020
1021   GNUNET_free_non_null (rd_new);
1022
1023   switch (res) {
1024     case GNUNET_SYSERR:
1025        /* failed to create the record */
1026        crc->res = GNUNET_SYSERR;
1027       break;
1028     case GNUNET_YES:
1029       /* database operations OK */
1030       if (GNUNET_YES == update)
1031       {
1032         /* we updated an existing record */
1033         crc->res = GNUNET_NO;
1034       }
1035       else
1036       {
1037         /* we created a new record */
1038         crc->res = GNUNET_YES;
1039       }
1040       break;
1041     case GNUNET_NO:
1042         /* identical entry existed, so we did nothing */
1043         crc->res = GNUNET_NO;
1044       break;
1045     default:
1046       break;
1047   }
1048   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Update result for name `%s' %u\n", crc->name, res);
1049 }
1050
1051
1052 /**
1053  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE' message
1054  *
1055  * @param cls unused
1056  * @param client GNUNET_SERVER_Client sending the message
1057  * @param message message of type 'struct RecordCreateMessage'
1058  */
1059 static void
1060 handle_record_create (void *cls,
1061                       struct GNUNET_SERVER_Client *client,
1062                       const struct GNUNET_MessageHeader *message)
1063 {
1064   struct GNUNET_NAMESTORE_Client *nc;
1065   const struct RecordCreateMessage *rp_msg;
1066   struct GNUNET_NAMESTORE_CryptoContainer *cc;
1067   struct CreateRecordContext crc;
1068   struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
1069   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
1070   struct RecordCreateResponseMessage rcr_msg;
1071   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1072   struct GNUNET_HashCode long_hash;
1073   size_t name_len;
1074   size_t msg_size;
1075   size_t msg_size_exp;
1076   size_t rd_ser_len;
1077   size_t key_len;
1078   uint32_t rid;
1079   const char *pkey_tmp;
1080   const char *name_tmp;
1081   const char *rd_ser;
1082   unsigned int rd_count;
1083   int res;
1084   struct GNUNET_NAMESTORE_RecordData rd;
1085
1086   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1087               "Received `%s' message\n", "NAMESTORE_RECORD_CREATE");
1088   if (ntohs (message->size) < sizeof (struct RecordCreateMessage))
1089   {
1090     GNUNET_break (0);
1091     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1092     return;
1093   }
1094   if (NULL == (nc = client_lookup (client)))
1095   {
1096     GNUNET_break (0);
1097     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1098     return;
1099   }
1100   rp_msg = (const struct RecordCreateMessage *) message;
1101   rid = ntohl (rp_msg->gns_header.r_id);
1102   name_len = ntohs (rp_msg->name_len);
1103   msg_size = ntohs (message->size);
1104   rd_count = ntohs (rp_msg->rd_count);
1105   rd_ser_len = ntohs (rp_msg->rd_len);
1106   key_len = ntohs (rp_msg->pkey_len);
1107   msg_size_exp = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len;
1108   if ( (msg_size != msg_size_exp) || (1 != rd_count) )
1109   {
1110     GNUNET_break (0);
1111     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1112     return;
1113   }
1114   if ((0 == name_len) || (name_len > MAX_NAME_LEN))
1115   {
1116     GNUNET_break (0);
1117     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1118     return;
1119   }
1120   pkey_tmp = (const char *) &rp_msg[1];
1121   name_tmp = &pkey_tmp[key_len];
1122   rd_ser = &name_tmp[name_len];
1123   if (name_tmp[name_len -1] != '\0')
1124   {
1125     GNUNET_break (0);
1126     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1127     return;
1128   }
1129   if (NULL == (pkey = GNUNET_CRYPTO_rsa_decode_key (pkey_tmp, key_len)))
1130   {
1131     GNUNET_break (0);
1132     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1133     return;
1134   }
1135   if (GNUNET_OK !=
1136       GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, &rd))
1137   {
1138     GNUNET_break (0);
1139     GNUNET_CRYPTO_rsa_key_free (pkey);
1140     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1141     return;
1142   }
1143   /* Extracting and converting private key */
1144   GNUNET_CRYPTO_rsa_key_get_public (pkey, &pub);
1145   GNUNET_CRYPTO_short_hash (&pub,
1146                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1147                             &pubkey_hash);
1148   GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
1149
1150   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
1151   {
1152     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1153                 "Received new private key for zone `%s'\n",
1154                 GNUNET_short_h2s(&pubkey_hash));
1155     cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
1156     cc->privkey = GNUNET_CRYPTO_rsa_decode_key (pkey_tmp, key_len);
1157     cc->zone = pubkey_hash;
1158     GNUNET_assert (GNUNET_YES ==
1159                    GNUNET_CONTAINER_multihashmap_put(zonekeys, &long_hash, cc, 
1160                                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1161   }
1162
1163   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1164               "Creating record for name `%s' in zone `%s'\n",
1165               name_tmp, GNUNET_short_h2s(&pubkey_hash));
1166   crc.expire = GNUNET_TIME_absolute_ntoh(rp_msg->expire);
1167   crc.res = GNUNET_SYSERR;
1168   crc.pkey = pkey;
1169   crc.pubkey = &pub;
1170   crc.rd = &rd;
1171   crc.name = name_tmp;
1172
1173   /* Get existing records for name */
1174   res = GSN_database->iterate_records (GSN_database->cls, &pubkey_hash, name_tmp, 0, 
1175                                        &handle_create_record_it, &crc);
1176   if (res != GNUNET_SYSERR)
1177     res = GNUNET_OK;
1178   GNUNET_CRYPTO_rsa_key_free (pkey);
1179
1180   /* Send response */
1181   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1182               "Sending `%s' message\n", "RECORD_CREATE_RESPONSE");
1183   rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE_RESPONSE);
1184   rcr_msg.gns_header.header.size = htons (sizeof (struct RecordCreateResponseMessage));
1185   rcr_msg.gns_header.r_id = htonl (rid);
1186   if ((GNUNET_OK == res) && (crc.res == GNUNET_YES))
1187     rcr_msg.op_result = htonl (GNUNET_YES);
1188   else if ((GNUNET_OK == res) && (crc.res == GNUNET_NO))
1189     rcr_msg.op_result = htonl (GNUNET_NO);
1190   else
1191     rcr_msg.op_result = htonl (GNUNET_SYSERR);
1192   GNUNET_SERVER_notification_context_unicast (snc, nc->client,
1193                                               &rcr_msg.gns_header.header,
1194                                               GNUNET_NO);
1195   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1196 }
1197
1198
1199 /**
1200  * RemoveRecordContext
1201  *
1202  * Context for record remove operations passed from 'handle_record_remove' to
1203  * 'handle_record_remove_it' as closure
1204  */
1205 struct RemoveRecordContext
1206 {
1207   /**
1208    * Record to remove
1209    */
1210   struct GNUNET_NAMESTORE_RecordData *rd;
1211
1212   /**
1213    * Zone's private keys
1214    */
1215   struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
1216
1217   /**
1218    * Name to remove
1219    */
1220   int remove_name;
1221
1222   /**
1223    * 0 : Success
1224    * 1 : Could not find record to remove, empty result set
1225    * 2 : Could not find record to remove, record did not exist in result set
1226    * 3 : Could not remove records from database
1227    * 4 : Could not put records into database
1228    */
1229   uint16_t op_res;
1230 };
1231
1232
1233 /**
1234  * FIXME...
1235  */
1236 static void
1237 handle_record_remove_it (void *cls,
1238     const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1239     struct GNUNET_TIME_Absolute expire,
1240     const char *name,
1241     unsigned int rd_count,
1242     const struct GNUNET_NAMESTORE_RecordData *rd,
1243     const struct GNUNET_CRYPTO_RsaSignature *signature)
1244 {
1245   static struct GNUNET_CRYPTO_RsaSignature dummy_signature;
1246   struct RemoveRecordContext *rrc = cls;
1247   unsigned int c;
1248   int found;
1249   unsigned int rd_count_new;
1250
1251   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1252               "Name `%s 'currently has %u records\n", 
1253               name, rd_count);
1254   if (0 == rd_count)
1255   {
1256     /* Could not find record to remove */
1257     rrc->op_res = RECORD_REMOVE_RESULT_NO_RECORDS;
1258     return;
1259   }
1260
1261   /* Find record to remove */
1262   found = GNUNET_SYSERR;
1263   for (c = 0; c < rd_count; c++)
1264   {
1265     /*
1266     if (rd[c].flags != rrc->rd->flags)
1267        continue;*/
1268     if (rd[c].record_type != rrc->rd->record_type)
1269        continue;
1270     /*
1271     if (rd[c].data_size != rrc->rd->data_size)
1272        continue;
1273     GNUNET_break(0);
1274     if (0 != memcmp (rd[c].data, rrc->rd->data, rrc->rd->data_size))
1275         continue;
1276     GNUNET_break(0); */
1277     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found record to remove!\n", rd_count);
1278     found = c;
1279     break;
1280   }
1281   if (GNUNET_SYSERR == found)
1282   {
1283     /* Could not find record to remove */
1284     rrc->op_res = RECORD_REMOVE_RESULT_RECORD_NOT_FOUND;
1285     return;
1286   }
1287
1288   if (1 == rd_count)
1289   {
1290     struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1291
1292     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1293                 "No records left for name `%s', removing name\n",
1294                 name);
1295     GNUNET_CRYPTO_short_hash (zone_key, 
1296                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
1297                               &pubkey_hash);
1298     if (GNUNET_OK !=
1299         GSN_database->remove_records (GSN_database->cls,
1300                                       &pubkey_hash,
1301                                       name))
1302     {
1303       /* Could not remove records from database */
1304       rrc->op_res = RECORD_REMOVE_RESULT_FAILED_TO_SIGN; /* ??? */
1305       return;
1306     }
1307     rrc->op_res = RECORD_REMOVE_RESULT_SUCCESS;
1308     return;
1309   }
1310
1311   rd_count_new = rd_count - 1;
1312   struct GNUNET_NAMESTORE_RecordData rd_new[rd_count_new];
1313   unsigned int c2 = 0;
1314   for (c = 0; c < rd_count; c++)
1315   {
1316     if (c != found)
1317     {
1318       GNUNET_assert (c2 < rd_count_new);
1319       rd_new[c2] = rd[c];
1320       c2++;
1321     }
1322   }
1323
1324   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Name `%s' now has %u records\n", name, rd_count_new);
1325   if (GNUNET_OK !=
1326       GSN_database->put_records(GSN_database->cls,
1327                                 zone_key,
1328                                 expire,
1329                                 name,
1330                                 rd_count_new, rd_new,
1331                                 &dummy_signature))
1332   {
1333     /* Could not put records into database */
1334     rrc->op_res = RECORD_REMOVE_RESULT_FAILED_TO_PUT_UPDATE;
1335     return;
1336   }
1337   rrc->op_res = RECORD_REMOVE_RESULT_SUCCESS;
1338 }
1339
1340
1341 /**
1342  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE' message
1343  *
1344  * @param cls unused
1345  * @param client GNUNET_SERVER_Client sending the message
1346  * @param message message of type 'struct RecordRemoveMessage'
1347  */
1348 static void
1349 handle_record_remove (void *cls,
1350                       struct GNUNET_SERVER_Client *client,
1351                       const struct GNUNET_MessageHeader *message)
1352 {
1353   struct GNUNET_NAMESTORE_Client *nc;
1354   const struct RecordRemoveMessage *rr_msg;
1355   struct RecordRemoveResponseMessage rrr_msg;
1356   struct GNUNET_CRYPTO_RsaPrivateKey *pkey;
1357   struct GNUNET_NAMESTORE_CryptoContainer *cc;
1358   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
1359   struct GNUNET_CRYPTO_ShortHashCode pubkey_hash;
1360   struct GNUNET_HashCode long_hash;
1361   struct GNUNET_NAMESTORE_RecordData rd;
1362   const char *pkey_tmp;
1363   const char *name_tmp;
1364   const char *rd_ser;
1365   size_t key_len;
1366   size_t name_len;
1367   size_t rd_ser_len;
1368   size_t msg_size;
1369   size_t msg_size_exp;
1370   uint32_t rd_count;
1371   uint32_t rid;
1372   struct RemoveRecordContext rrc;
1373   int res;
1374
1375   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "NAMESTORE_RECORD_REMOVE");
1376   if (ntohs (message->size) < sizeof (struct RecordRemoveMessage))
1377   {
1378     GNUNET_break (0);
1379     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1380     return;
1381   }
1382   if (NULL == (nc = client_lookup(client)))
1383   {
1384     GNUNET_break (0);
1385     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1386     return;
1387   }
1388   rr_msg = (const struct RecordRemoveMessage *) message;
1389   rid = ntohl (rr_msg->gns_header.r_id);
1390   name_len = ntohs (rr_msg->name_len);
1391   rd_ser_len = ntohs (rr_msg->rd_len);
1392   rd_count = ntohs (rr_msg->rd_count);
1393   key_len = ntohs (rr_msg->pkey_len);
1394   msg_size = ntohs (message->size);
1395   if ((name_len >= MAX_NAME_LEN) || (0 == name_len) || (1 < rd_count) )
1396   {
1397     GNUNET_break (0);
1398     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1399     return;
1400   }
1401   msg_size_exp = sizeof (struct RecordRemoveMessage) + key_len + name_len + rd_ser_len;
1402   if (msg_size != msg_size_exp)
1403   {
1404     GNUNET_break (0);
1405     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1406     return;
1407   }
1408   pkey_tmp = (const char *) &rr_msg[1];
1409   name_tmp = &pkey_tmp[key_len];
1410   rd_ser = &name_tmp[name_len];
1411   if ('\0' != name_tmp[name_len -1])
1412   {
1413     GNUNET_break (0);
1414     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1415     return;
1416   }
1417   if (NULL == (pkey = GNUNET_CRYPTO_rsa_decode_key (pkey_tmp, key_len)))
1418   {
1419     GNUNET_break (0);
1420     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1421     return;
1422   }
1423   GNUNET_CRYPTO_rsa_key_get_public (pkey, &pub);
1424   GNUNET_CRYPTO_short_hash (&pub, 
1425                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
1426                             &pubkey_hash);
1427   GNUNET_CRYPTO_short_hash_double (&pubkey_hash, &long_hash);
1428   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains (zonekeys, &long_hash))
1429   {
1430     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1431                 "Received new private key for zone `%s'\n",
1432                 GNUNET_short_h2s (&pubkey_hash));
1433     cc = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
1434     cc->privkey = GNUNET_CRYPTO_rsa_decode_key (pkey_tmp, key_len);
1435     cc->zone = pubkey_hash;
1436     GNUNET_assert (GNUNET_YES ==
1437                    GNUNET_CONTAINER_multihashmap_put (zonekeys, 
1438                                                       &long_hash, cc, 
1439                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1440   }
1441   if (GNUNET_OK !=
1442       GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, &rd))
1443   {
1444     GNUNET_break (0);
1445     GNUNET_CRYPTO_rsa_key_free (pkey);
1446     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1447     return;
1448   }
1449
1450   if (0 == rd_count)
1451   {
1452     /* remove the whole name and all records */
1453     res = GSN_database->remove_records (GSN_database->cls,
1454                                         &pubkey_hash,
1455                                         name_tmp);
1456     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1457                 "Removing name `%s': %s\n",
1458                 name_tmp, (GNUNET_OK == res) ? "OK" : "FAIL");
1459     if (GNUNET_OK != res)
1460       /* Could not remove entry from database */
1461       res = RECORD_REMOVE_RESULT_FAILED_TO_PUT_UPDATE;
1462     else
1463       res = RECORD_REMOVE_RESULT_SUCCESS;
1464   }
1465   else
1466   {
1467     /* remove a single record */
1468     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1469                 "Removing record for name `%s' in zone `%s'\n", name_tmp, 
1470                 GNUNET_short_h2s (&pubkey_hash));
1471     rrc.rd = &rd;
1472     rrc.pkey = pkey;
1473     res = GSN_database->iterate_records (GSN_database->cls,
1474                                          &pubkey_hash,
1475                                          name_tmp,
1476                                          0,
1477                                          handle_record_remove_it, &rrc);
1478
1479     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1480                 "Removing record for name `%s': %s\n",
1481                 name_tmp, 
1482                 (0 == rrc.op_res) ? "OK" : "FAIL");
1483     res = rrc.op_res;
1484   }
1485   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1486               "Sending `%s' message\n",
1487               "RECORD_REMOVE_RESPONSE");
1488   rrr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE_RESPONSE);
1489   rrr_msg.gns_header.header.size = htons (sizeof (struct RecordRemoveResponseMessage));
1490   rrr_msg.gns_header.r_id = htonl (rid);
1491   rrr_msg.op_result = htonl (res);
1492   GNUNET_SERVER_notification_context_unicast (snc, nc->client, 
1493                                               &rrr_msg.gns_header.header,
1494                                               GNUNET_NO);
1495   GNUNET_CRYPTO_rsa_key_free (pkey);
1496   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1497 }
1498
1499
1500 /**
1501  * Context for record remove operations passed from 'handle_zone_to_name' to
1502  * 'handle_zone_to_name_it' as closure
1503  */
1504 struct ZoneToNameCtx
1505 {
1506   /**
1507    * Namestore client
1508    */
1509   struct GNUNET_NAMESTORE_Client *nc;
1510
1511   /**
1512    * Request id
1513    */
1514   uint32_t rid;
1515
1516   /**
1517    * Set to GNUNET_OK on success, GNUNET_SYSERR on error
1518    */
1519   int success;
1520 };
1521
1522
1523 /**
1524  * Zone to name iterator
1525  *
1526  * @param cls struct ZoneToNameCtx *
1527  * @param zone_key the zone key
1528  * @param expire expiration date
1529  * @param name name
1530  * @param rd_count number of records
1531  * @param rd record data
1532  * @param signature signature
1533  */
1534 static void
1535 handle_zone_to_name_it (void *cls,
1536                         const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1537                         struct GNUNET_TIME_Absolute expire,
1538                         const char *name,
1539                         unsigned int rd_count,
1540                         const struct GNUNET_NAMESTORE_RecordData *rd,
1541                         const struct GNUNET_CRYPTO_RsaSignature *signature)
1542 {
1543   struct ZoneToNameCtx *ztn_ctx = cls;
1544   struct ZoneToNameResponseMessage *ztnr_msg;
1545   int16_t res;
1546   size_t name_len;
1547   size_t rd_ser_len;
1548   size_t msg_size;
1549   char *name_tmp;
1550   char *rd_tmp;
1551   char *sig_tmp;
1552
1553   if ((zone_key != NULL) && (name != NULL))
1554   {
1555     /* found result */
1556     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found results: name is `%s', has %u records\n", name, rd_count);
1557     res = GNUNET_YES;
1558     name_len = strlen (name) + 1;
1559   }
1560   else
1561   {
1562     /* no result found */
1563     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found no results\n");
1564     res = GNUNET_NO;
1565     name_len = 0;
1566   }
1567
1568   if (rd_count > 0)
1569     rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1570   else
1571     rd_ser_len = 0;
1572
1573   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1574               "Sending `%s' message\n", 
1575               "ZONE_TO_NAME_RESPONSE");
1576   msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1577   if (NULL != signature)
1578     msg_size += sizeof (struct GNUNET_CRYPTO_RsaSignature);
1579   if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
1580   {
1581     GNUNET_break (0);
1582     ztn_ctx->success = GNUNET_SYSERR;
1583     return;
1584   }
1585   ztnr_msg = GNUNET_malloc (msg_size);
1586   ztnr_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1587   ztnr_msg->gns_header.header.size = htons (msg_size);
1588   ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1589   ztnr_msg->res = htons (res);
1590   ztnr_msg->rd_len = htons (rd_ser_len);
1591   ztnr_msg->rd_count = htons (rd_count);
1592   ztnr_msg->name_len = htons (name_len);
1593   ztnr_msg->expire = GNUNET_TIME_absolute_hton (expire);
1594   if (NULL != zone_key)
1595     ztnr_msg->zone_key = *zone_key;
1596   name_tmp = (char *) &ztnr_msg[1];
1597   if (NULL != name)
1598     memcpy (name_tmp, name, name_len);
1599   rd_tmp = &name_tmp[name_len];
1600   GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_tmp);
1601   sig_tmp = &rd_tmp[rd_ser_len];
1602   if (NULL != signature)
1603     memcpy (sig_tmp, signature, sizeof (struct GNUNET_CRYPTO_RsaSignature));
1604   ztn_ctx->success = GNUNET_OK;
1605   GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client,
1606                                               &ztnr_msg->gns_header.header,
1607                                               GNUNET_NO);
1608   GNUNET_free (ztnr_msg);
1609 }
1610
1611
1612 /**
1613  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME' message
1614  *
1615  * @param cls unused
1616  * @param client GNUNET_SERVER_Client sending the message
1617  * @param message message of type 'struct ZoneToNameMessage'
1618  */
1619 static void
1620 handle_zone_to_name (void *cls,
1621                      struct GNUNET_SERVER_Client *client,
1622                      const struct GNUNET_MessageHeader *message)
1623 {
1624   struct GNUNET_NAMESTORE_Client *nc;
1625   const struct ZoneToNameMessage *ztn_msg;
1626   struct ZoneToNameCtx ztn_ctx;
1627
1628   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1629               "Received `%s' message\n",
1630               "ZONE_TO_NAME");
1631   if (ntohs (message->size) != sizeof (struct ZoneToNameMessage))
1632   {
1633     GNUNET_break (0);
1634     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1635     return;
1636   }
1637   if (NULL == (nc = client_lookup(client)))
1638   {
1639     GNUNET_break (0);
1640     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1641     return;
1642   }
1643   ztn_msg = (const struct ZoneToNameMessage *) message;
1644   ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1645   ztn_ctx.nc = nc;
1646   ztn_ctx.success = GNUNET_SYSERR;
1647   GSN_database->zone_to_name (GSN_database->cls, 
1648                               &ztn_msg->zone,
1649                               &ztn_msg->value_zone,
1650                               &handle_zone_to_name_it, &ztn_ctx);
1651   GNUNET_SERVER_receive_done (client, ztn_ctx.success);
1652 }
1653
1654
1655 /**
1656  * Copy record, data has to be free'd separetely
1657  *
1658  * @param src source record
1659  * @param dest destination record
1660  */
1661 static void
1662 copy_record (const struct GNUNET_NAMESTORE_RecordData *src,
1663              struct GNUNET_NAMESTORE_RecordData *dest)
1664 {
1665   memcpy (dest, src, sizeof (struct GNUNET_NAMESTORE_RecordData));
1666   dest->data = GNUNET_malloc (src->data_size);
1667   memcpy ((void *) dest->data, src->data, src->data_size);
1668 }
1669
1670
1671 /**
1672  * Context for record remove operations passed from
1673  * 'find_next_zone_iteration_result' to 'zone_iteraterate_proc' as closure
1674  */
1675 struct ZoneIterationProcResult
1676 {
1677   /**
1678    * The zone iteration handle
1679    */
1680   struct GNUNET_NAMESTORE_ZoneIteration *zi;
1681
1682   /**
1683    * Iteration result: iteration done?
1684    */
1685   int res_iteration_finished;
1686
1687   /**
1688    * Iteration result: number of records included
1689    */
1690   int records_included;
1691
1692   /**
1693    * Iteration result: is a valid signature included?
1694    */
1695   int has_signature;
1696
1697   /**
1698    * Name????
1699    */
1700   char *name;
1701
1702   /**
1703    * Zone hash
1704    */
1705   struct GNUNET_CRYPTO_ShortHashCode zone_hash;
1706
1707   /**
1708    * Record data
1709    */
1710   struct GNUNET_NAMESTORE_RecordData *rd;
1711
1712   /**
1713    * Zone's public key
1714    */
1715   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded zone_key;
1716
1717   /**
1718    * Signature
1719    */
1720   struct GNUNET_CRYPTO_RsaSignature signature;
1721
1722   /**
1723    * Expiration date
1724    */
1725   struct GNUNET_TIME_Absolute expire;
1726 };
1727
1728
1729 /**
1730  * Process results for zone iteration from database
1731  *
1732  * @param cls struct ZoneIterationProcResult *proc
1733  * @param zone_key the zone key
1734  * @param expire expiration time
1735  * @param name name
1736  * @param rd_count number of records for this name
1737  * @param rd record data
1738  * @param signature block signature
1739  */
1740 static void
1741 zone_iteraterate_proc (void *cls,
1742                        const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1743                        struct GNUNET_TIME_Absolute expire,
1744                        const char *name,
1745                        unsigned int rd_count,
1746                        const struct GNUNET_NAMESTORE_RecordData *rd,
1747                        const struct GNUNET_CRYPTO_RsaSignature *signature)
1748 {
1749   struct ZoneIterationProcResult *proc = cls;
1750   struct GNUNET_NAMESTORE_RecordData *rd_filtered;
1751   struct GNUNET_CRYPTO_RsaSignature *new_signature;
1752   struct GNUNET_NAMESTORE_CryptoContainer *cc;
1753   struct GNUNET_CRYPTO_ShortHashCode hash;
1754   struct GNUNET_HashCode long_hash;
1755   struct GNUNET_TIME_Absolute e;
1756   unsigned int rd_count_filtered  = 0;
1757   int include;
1758   int c;
1759
1760   proc->res_iteration_finished = GNUNET_NO;
1761   proc->records_included = 0;
1762
1763   if ((zone_key == NULL) && (name == NULL))
1764   {
1765     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration done\n");
1766     proc->res_iteration_finished = GNUNET_YES;
1767     proc->rd = NULL;
1768     proc->name = NULL;
1769   }
1770   else if ((zone_key != NULL) && (name != NULL)) /* just a safety check */
1771   {
1772     rd_filtered = GNUNET_malloc (rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
1773     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received result for zone iteration: `%s'\n", name);
1774     for (c = 0; c < rd_count; c++)
1775     {
1776       include = GNUNET_YES;
1777       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: 0x%x must have 0x%x \n",
1778           c, rd[c].flags, proc->zi->must_have_flags);
1779       /* Checking must have flags */
1780       if ((rd[c].flags & proc->zi->must_have_flags) == proc->zi->must_have_flags)
1781       {
1782         /* Include */
1783         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c);
1784       }
1785       else
1786       {
1787         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Not include \n", c);
1788         include = GNUNET_NO;
1789       }
1790
1791       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: 0x%x must not have 0x%x\n",
1792           c, rd[c].flags, proc->zi->must_not_have_flags);
1793       if ((rd[c].flags & proc->zi->must_not_have_flags) != 0)
1794       {
1795         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Not include \n", c);
1796         include = GNUNET_NO;
1797       }
1798       else
1799       {
1800         /* Include */
1801         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Record %i has flags: Include \n", c);
1802       }
1803       if (GNUNET_YES == include)
1804       {
1805         copy_record (&rd[c], &rd_filtered[rd_count_filtered]);
1806         rd_count_filtered++;
1807       }
1808
1809     }
1810     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Included %i of %i records \n", rd_count_filtered, rd_count);
1811
1812     proc->records_included = rd_count_filtered;
1813     if (0 == rd_count_filtered)
1814     {
1815       GNUNET_free (rd_filtered);
1816       rd_filtered = NULL;
1817     }
1818     proc->rd = rd_filtered;
1819     proc->name = GNUNET_strdup(name);
1820     memcpy (&proc->zone_key, zone_key, sizeof (proc->zone_key));
1821
1822     /* Signature */
1823     proc->has_signature = GNUNET_NO;
1824     GNUNET_CRYPTO_short_hash (zone_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &hash);
1825     GNUNET_CRYPTO_short_hash_double(&hash, &long_hash);
1826     proc->zone_hash = hash;
1827
1828     if (GNUNET_CONTAINER_multihashmap_contains(zonekeys, &long_hash))
1829     {
1830       cc = GNUNET_CONTAINER_multihashmap_get(zonekeys, &long_hash);
1831       e = get_block_expiration_time(rd_count_filtered, rd_filtered);
1832       proc->expire = e;
1833       new_signature = GNUNET_NAMESTORE_create_signature(cc->privkey, e, name, rd_filtered, rd_count_filtered);
1834       GNUNET_assert (signature != NULL);
1835       proc->signature = (*new_signature);
1836       GNUNET_free (new_signature);
1837       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1838           name, GNUNET_short_h2s(&hash), rd_count_filtered, e.abs_value);
1839       proc->has_signature = GNUNET_YES;
1840     }
1841     else if (rd_count_filtered == rd_count)
1842     {
1843       proc->expire = expire;
1844       if (NULL != signature)
1845       {
1846         proc->signature = (*signature);
1847         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using provided signature for `%s' in zone `%s' with %u records and expiration %llu\n",
1848             name, GNUNET_short_h2s(&hash), rd_count_filtered, expire.abs_value);
1849         proc->has_signature = GNUNET_YES;
1850       }
1851       else
1852       {
1853         memset (&proc->signature, '\0', sizeof (proc->signature));
1854         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No signature provided for `%s'\n", name);
1855       }
1856     }
1857   }
1858   else
1859   {
1860     GNUNET_break (0);
1861     return;
1862   }
1863 }
1864 /////////////////////////////////////////////////////////////
1865
1866
1867 /**
1868  * Find next zone iteration result in database
1869  *
1870  * @param proc the zone iteration processing to use
1871  */
1872 static void
1873 find_next_zone_iteration_result (struct ZoneIterationProcResult *proc)
1874 {
1875   struct GNUNET_CRYPTO_ShortHashCode *zone;
1876
1877   if (GNUNET_YES == proc->zi->has_zone)
1878     zone = &proc->zi->zone;
1879   else
1880     zone = NULL;
1881   do
1882   {
1883     if (GNUNET_SYSERR ==
1884         GSN_database->iterate_records (GSN_database->cls, zone, NULL, 
1885                                        proc->zi->offset, 
1886                                        &zone_iteraterate_proc, proc))
1887     {
1888       GNUNET_break (0);
1889       break;
1890     }
1891     proc->zi->offset++;
1892   }
1893   while ((0 == proc->records_included) && (GNUNET_NO == proc->res_iteration_finished));
1894 }
1895
1896
1897 /**
1898  * Send zone iteration result to client
1899  *
1900  * @param proc the zone iteration processing result to send
1901  */
1902 static void
1903 send_zone_iteration_result (struct ZoneIterationProcResult *proc)
1904 {
1905   struct GNUNET_NAMESTORE_ZoneIteration *zi = proc->zi;
1906   struct ZoneIterationResponseMessage zir_end;
1907   struct ZoneIterationResponseMessage *zir_msg;
1908   size_t name_len;
1909   size_t rd_ser_len;
1910   size_t msg_size;
1911   char *name_tmp;
1912   char *rd_ser;
1913
1914   if (GNUNET_YES == proc->res_iteration_finished)
1915   {
1916     if (zi->has_zone == GNUNET_YES)
1917       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1918                   "No more results for zone `%s'\n", 
1919                   GNUNET_short_h2s(&zi->zone));
1920     else
1921       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1922                   "No more results for all zones\n");
1923     memset (&zir_end, 0, sizeof (zir_end));
1924     zir_end.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1925     zir_end.gns_header.header.size = htons (sizeof (struct ZoneIterationResponseMessage));
1926     zir_end.gns_header.r_id = htonl(zi->request_id);
1927     GNUNET_SERVER_notification_context_unicast (snc, 
1928                                                 zi->client->client, 
1929                                                 &zir_end.gns_header.header, GNUNET_NO);
1930     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing zone iterator\n");
1931     GNUNET_CONTAINER_DLL_remove (zi->client->op_head, zi->client->op_tail, zi);
1932     GNUNET_free (zi);
1933     return;
1934   }
1935   GNUNET_assert (proc->records_included > 0);
1936   if (GNUNET_YES == zi->has_zone)
1937     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1938                 "Sending name `%s' for iteration over zone `%s'\n",
1939                 proc->name, GNUNET_short_h2s(&zi->zone));
1940   else
1941     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1942                 "Sending name `%s' for iteration over all zones\n",
1943                 proc->name);
1944   name_len = strlen (proc->name) + 1;
1945   rd_ser_len = GNUNET_NAMESTORE_records_get_size(proc->records_included, proc->rd);  
1946   msg_size = sizeof (struct ZoneIterationResponseMessage) + name_len + rd_ser_len;
1947
1948   zir_msg = GNUNET_malloc(msg_size);
1949   zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_RESPONSE);
1950   zir_msg->gns_header.header.size = htons (msg_size);
1951   zir_msg->gns_header.r_id = htonl(zi->request_id);
1952   zir_msg->expire = GNUNET_TIME_absolute_hton(proc->expire);
1953   zir_msg->reserved = htons (0);
1954   zir_msg->name_len = htons (name_len);
1955   zir_msg->rd_count = htons (proc->records_included);
1956   zir_msg->rd_len = htons (rd_ser_len);
1957   zir_msg->signature = proc->signature;
1958   zir_msg->public_key = proc->zone_key;
1959   name_tmp = (char *) &zir_msg[1];
1960   memcpy (name_tmp, proc->name, name_len);
1961   rd_ser = &name_tmp[name_len];
1962   GNUNET_NAMESTORE_records_serialize (proc->records_included, proc->rd, rd_ser_len, rd_ser);
1963   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1964               "Sending `%s' message with size %u\n", 
1965               "ZONE_ITERATION_RESPONSE",
1966               msg_size);
1967   GNUNET_SERVER_notification_context_unicast (snc, zi->client->client, 
1968                                               (const struct GNUNET_MessageHeader *) zir_msg,
1969                                               GNUNET_NO);
1970   GNUNET_free (zir_msg);
1971 }
1972
1973
1974 /**
1975  * Clean up after zone iteration
1976  * @param proc the zone iteration processor
1977  */
1978 static void
1979 clean_up_zone_iteration_result (struct ZoneIterationProcResult *proc)
1980 {
1981   unsigned int c;
1982
1983   GNUNET_free_non_null (proc->name);
1984   proc->name = NULL;
1985   for (c = 0; c < proc->records_included; c++)  
1986     GNUNET_free ((void *) proc->rd[c].data);  
1987   GNUNET_free_non_null (proc->rd);
1988   proc->rd = NULL;
1989   proc->records_included = 0;
1990 }
1991
1992
1993 /**
1994  * Perform the next round of the zone iteration.
1995  *
1996  * @param zi zone iterator to process
1997  */
1998 static void
1999 run_zone_iteration_round (struct GNUNET_NAMESTORE_ZoneIteration *zi)
2000 {
2001   struct ZoneIterationProcResult proc;
2002
2003   memset (&proc, 0, sizeof (proc));
2004   proc.zi = zi;
2005   find_next_zone_iteration_result (&proc);
2006   if (GNUNET_YES == proc.res_iteration_finished)
2007   {
2008     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2009                 "Zone iteration done\n");
2010   }
2011   else if (0 != proc.records_included)
2012   {
2013     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2014                 "Zone iteration returns %u records\n", 
2015                 proc.records_included);
2016   }
2017   send_zone_iteration_result (&proc);
2018   clean_up_zone_iteration_result (&proc);
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   nc = client_lookup (client);
2041   if (NULL == nc)
2042   {
2043     GNUNET_break_op (0);
2044     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2045     return;
2046   }
2047   zis_msg = (const struct ZoneIterationStartMessage *) message;
2048   zi = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_ZoneIteration));
2049   zi->request_id = ntohl (zis_msg->gns_header.r_id);
2050   zi->offset = 0;
2051   zi->client = nc;
2052   zi->must_have_flags = ntohs (zis_msg->must_have_flags);
2053   zi->must_not_have_flags = ntohs (zis_msg->must_not_have_flags);
2054   if (0 == memcmp (&zeros, &zis_msg->zone, sizeof (zeros)))
2055   {
2056     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to iterate over all zones\n");
2057     zi->zone = zis_msg->zone;
2058     zi->has_zone = GNUNET_NO;
2059   }
2060   else
2061   {
2062     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2063                 "Starting to iterate over zone `%s'\n", GNUNET_short_h2s (&zis_msg->zone));
2064     zi->zone = zis_msg->zone;
2065     zi->has_zone = GNUNET_YES;
2066   }
2067   GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
2068   run_zone_iteration_round (zi);
2069   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2070 }
2071
2072
2073 /**
2074  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP' message
2075  *
2076  * @param cls unused
2077  * @param client GNUNET_SERVER_Client sending the message
2078  * @param message message of type 'struct ZoneIterationStopMessage'
2079  */
2080 static void
2081 handle_iteration_stop (void *cls,
2082                        struct GNUNET_SERVER_Client *client,
2083                        const struct GNUNET_MessageHeader *message)
2084 {
2085   struct GNUNET_NAMESTORE_Client *nc;
2086   struct GNUNET_NAMESTORE_ZoneIteration *zi;
2087   const struct ZoneIterationStopMessage *zis_msg;
2088   uint32_t rid;
2089
2090   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2091               "Received `%s' message\n",
2092               "ZONE_ITERATION_STOP");
2093   nc = client_lookup(client);
2094   if (NULL == nc)
2095   {
2096     GNUNET_break (0);
2097     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2098     return;
2099   }
2100   zis_msg = (const struct ZoneIterationStopMessage *) message;
2101   rid = ntohl (zis_msg->gns_header.r_id);
2102   for (zi = nc->op_head; NULL != zi; zi = zi->next)
2103     if (zi->request_id == rid)
2104       break;
2105   if (NULL == zi)
2106   {
2107     GNUNET_break (0);
2108     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2109     return;
2110   }
2111   GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
2112   if (GNUNET_YES == zi->has_zone)
2113     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2114                 "Stopped zone iteration for zone `%s'\n",
2115                 GNUNET_short_h2s (&zi->zone));
2116   else
2117     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2118                 "Stopped zone iteration over all zones\n");
2119   GNUNET_free (zi);
2120   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2121 }
2122
2123
2124 /**
2125  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT' message
2126  *
2127  * @param cls unused
2128  * @param client GNUNET_SERVER_Client sending the message
2129  * @param message message of type 'struct ZoneIterationNextMessage'
2130  */
2131 static void
2132 handle_iteration_next (void *cls,
2133                        struct GNUNET_SERVER_Client *client,
2134                        const struct GNUNET_MessageHeader *message)
2135 {
2136   struct GNUNET_NAMESTORE_Client *nc;
2137   struct GNUNET_NAMESTORE_ZoneIteration *zi;
2138   const struct ZoneIterationNextMessage *zis_msg;
2139   uint32_t rid;
2140
2141   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT");
2142   nc = client_lookup(client);
2143   if (NULL == nc)
2144   {
2145     GNUNET_break (0);
2146     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2147     return;
2148   }
2149   zis_msg = (const struct ZoneIterationNextMessage *) message;
2150   rid = ntohl (zis_msg->gns_header.r_id);
2151   for (zi = nc->op_head; NULL != zi; zi = zi->next)
2152     if (zi->request_id == rid)
2153       break;
2154   if (NULL == zi)
2155   {
2156     GNUNET_break (0);
2157     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2158     return;
2159   }
2160   run_zone_iteration_round (zi);
2161   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2162 }
2163
2164
2165 /**
2166  * Load zone keys from directory by reading all .zkey files in this directory
2167  *
2168  * @param cls int * 'counter' to store the number of files found
2169  * @param filename directory to scan
2170  * @return GNUNET_OK to continue
2171  */
2172 static int
2173 zonekey_file_it (void *cls, const char *filename)
2174 {
2175   unsigned int *counter = cls;
2176   struct GNUNET_HashCode long_hash;
2177   struct GNUNET_CRYPTO_RsaPrivateKey *privkey;
2178   struct GNUNET_NAMESTORE_CryptoContainer *c;
2179   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pubkey;
2180
2181   if ((NULL == filename) ||
2182       (NULL == strstr(filename, ".zkey")))
2183     return GNUNET_OK;
2184   privkey = GNUNET_CRYPTO_rsa_key_create_from_file (filename);
2185   if (NULL == privkey)
2186   {
2187     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2188                 _("Could not parse zone key file `%s'\n"),
2189                 filename);
2190     return GNUNET_OK;
2191   }
2192   c = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_CryptoContainer));
2193   c->privkey = privkey;
2194   GNUNET_CRYPTO_rsa_key_get_public (privkey, &pubkey);
2195   GNUNET_CRYPTO_short_hash (&pubkey, 
2196                             sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), 
2197                             &c->zone);
2198   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2199               "Found zonefile for zone `%s'\n", GNUNET_short_h2s (&c->zone));
2200   GNUNET_CRYPTO_short_hash_double (&c->zone, &long_hash);
2201   GNUNET_assert (GNUNET_OK == 
2202                  GNUNET_CONTAINER_multihashmap_put (zonekeys, &long_hash, c, 
2203                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2204   (*counter)++;
2205   return GNUNET_OK;
2206 }
2207
2208
2209 /**
2210  * Process namestore requests.
2211  *
2212  * @param cls closure
2213  * @param server the initialized server
2214  * @param cfg configuration to use
2215  */
2216 static void
2217 run (void *cls, struct GNUNET_SERVER_Handle *server,
2218      const struct GNUNET_CONFIGURATION_Handle *cfg)
2219 {
2220   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2221     {&handle_start, NULL,
2222      GNUNET_MESSAGE_TYPE_NAMESTORE_START, sizeof (struct StartMessage)},
2223     {&handle_lookup_name, NULL,
2224      GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME, 0},
2225     {&handle_record_put, NULL,
2226     GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT, 0},
2227     {&handle_record_create, NULL,
2228      GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE, 0},
2229     {&handle_record_remove, NULL,
2230      GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_REMOVE, 0},
2231     {&handle_zone_to_name, NULL,
2232       GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, 0},
2233     {&handle_iteration_start, NULL,
2234      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage) },
2235     {&handle_iteration_next, NULL,
2236      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, sizeof (struct ZoneIterationNextMessage) },
2237      {&handle_iteration_stop, NULL,
2238       GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, sizeof (struct ZoneIterationStopMessage) },
2239     {NULL, NULL, 0, 0}
2240   };
2241   char *database;
2242   unsigned int counter;
2243
2244   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
2245   GSN_cfg = cfg;
2246
2247   /* Load private keys from disk */
2248   if (GNUNET_OK !=
2249       GNUNET_CONFIGURATION_get_value_filename (cfg, "namestore", 
2250                                                "zonefile_directory",
2251                                                &zonefile_directory))
2252   {
2253     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
2254                 _("No directory to load zonefiles specified in configuration\n"));
2255     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2256     return;
2257   }
2258
2259   if (GNUNET_NO == GNUNET_DISK_file_test (zonefile_directory))
2260   {
2261     if (GNUNET_SYSERR == GNUNET_DISK_directory_create (zonefile_directory))
2262     {
2263       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
2264                   _("Creating directory `%s' for zone files failed!\n"),
2265                   zonefile_directory);
2266       GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2267       return;
2268     }
2269     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2270                 "Created directory `%s' for zone files\n", 
2271                 zonefile_directory);
2272   }
2273
2274   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2275               "Scanning directory `%s' for zone files\n", zonefile_directory);
2276   zonekeys = GNUNET_CONTAINER_multihashmap_create (16);
2277   counter = 0;
2278   GNUNET_DISK_directory_scan (zonefile_directory, zonekey_file_it, &counter);
2279   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2280               "Found %u zone files\n", 
2281               counter);
2282
2283   /* Loading database plugin */
2284   if (GNUNET_OK !=
2285       GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
2286                                              &database))
2287     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
2288
2289   GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
2290   GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
2291   GNUNET_free (database);
2292   if (NULL == GSN_database)
2293   {
2294     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
2295                 "Could not load database backend `%s'\n",
2296                 db_lib_name);
2297     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
2298     return;
2299   }
2300
2301   /* Configuring server handles */
2302   GNUNET_SERVER_add_handlers (server, handlers);
2303   snc = GNUNET_SERVER_notification_context_create (server, 16);
2304   GNUNET_SERVER_disconnect_notify (server,
2305                                    &client_disconnect_notification,
2306                                    NULL);
2307   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
2308                                 NULL);
2309 }
2310
2311
2312 /**
2313  * The main function for the template service.
2314  *
2315  * @param argc number of arguments from the command line
2316  * @param argv command line arguments
2317  * @return 0 ok, 1 on error
2318  */
2319 int
2320 main (int argc, char *const *argv)
2321 {
2322   return (GNUNET_OK ==
2323           GNUNET_SERVICE_run (argc, argv, "namestore",
2324                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
2325 }
2326
2327 /* end of gnunet-service-namestore.c */
2328