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