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