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