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