more logging
[oweals/gnunet.git] / src / namestore / gnunet-service-namestore.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2013, 2014 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, 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_gns_service.h"
31 #include "gnunet_namecache_service.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_namestore_plugin.h"
34 #include "gnunet_statistics_service.h"
35 #include "gnunet_signatures.h"
36 #include "namestore.h"
37
38 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
39
40
41 /**
42  * A namestore client
43  */
44 struct NamestoreClient;
45
46
47 /**
48  * A namestore iteration operation.
49  */
50 struct ZoneIteration
51 {
52   /**
53    * Next element in the DLL
54    */
55   struct ZoneIteration *next;
56
57   /**
58    * Previous element in the DLL
59    */
60   struct ZoneIteration *prev;
61
62   /**
63    * Namestore client which intiated this zone iteration
64    */
65   struct NamestoreClient *nc;
66
67   /**
68    * The nick to add to the records
69    */
70   struct GNUNET_GNSRECORD_Data *nick;
71
72   /**
73    * Key of the zone we are iterating over.
74    */
75   struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
76
77   /**
78    * Last sequence number in the zone iteration used to address next
79    * result of the zone iteration in the store
80    *
81    * Initialy set to 0.
82    * Updated in #zone_iterate_proc()
83    */
84   uint64_t seq;
85
86   /**
87    * The operation id fot the zone iteration in the response for the client
88    */
89   uint32_t request_id;
90
91   /**
92    * Offset of the zone iteration used to address next result of the zone
93    * iteration in the store
94    *
95    * Initialy set to 0 in #handle_iteration_start
96    * Incremented with by every call to #handle_iteration_next
97    */
98   uint32_t offset;
99
100 };
101
102
103 /**
104  * A namestore client
105  */
106 struct NamestoreClient
107 {
108
109   /**
110    * The client
111    */
112   struct GNUNET_SERVICE_Client *client;
113
114   /**
115    * Message queue for transmission to @e client
116    */
117   struct GNUNET_MQ_Handle *mq;
118
119   /**
120    * Head of the DLL of
121    * Zone iteration operations in progress initiated by this client
122    */
123   struct ZoneIteration *op_head;
124
125   /**
126    * Tail of the DLL of
127    * Zone iteration operations in progress initiated by this client
128    */
129   struct ZoneIteration *op_tail;
130 };
131
132
133 /**
134  * A namestore monitor.
135  */
136 struct ZoneMonitor
137 {
138   /**
139    * Next element in the DLL
140    */
141   struct ZoneMonitor *next;
142
143   /**
144    * Previous element in the DLL
145    */
146   struct ZoneMonitor *prev;
147
148   /**
149    * Namestore client which intiated this zone monitor
150    */
151   struct NamestoreClient *nc;
152
153   /**
154    * Private key of the zone.
155    */
156   struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
157
158   /**
159    * Task active during initial iteration.
160    */
161   struct GNUNET_SCHEDULER_Task *task;
162
163   /**
164    * Last sequence number in the zone iteration used to address next
165    * result of the zone iteration in the store
166    *
167    * Initialy set to 0.
168    * Updated in #monitor_iterate_cb()
169    */
170   uint64_t seq;
171
172 };
173
174
175 /**
176  * Pending operation on the namecache.
177  */
178 struct CacheOperation
179 {
180
181   /**
182    * Kept in a DLL.
183    */
184   struct CacheOperation *prev;
185
186   /**
187    * Kept in a DLL.
188    */
189   struct CacheOperation *next;
190
191   /**
192    * Handle to namecache queue.
193    */
194   struct GNUNET_NAMECACHE_QueueEntry *qe;
195
196   /**
197    * Client to notify about the result.
198    */
199   struct NamestoreClient *nc;
200
201   /**
202    * Client's request ID.
203    */
204   uint32_t rid;
205 };
206
207
208 /**
209  * Public key of all zeros.
210  */
211 static const struct GNUNET_CRYPTO_EcdsaPrivateKey zero;
212
213 /**
214  * Configuration handle.
215  */
216 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
217
218 /**
219  * Handle to the statistics service
220  */
221 static struct GNUNET_STATISTICS_Handle *statistics;
222
223 /**
224  * Namecache handle.
225  */
226 static struct GNUNET_NAMECACHE_Handle *namecache;
227
228 /**
229  * Database handle
230  */
231 static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
232
233 /**
234  * Name of the database plugin
235  */
236 static char *db_lib_name;
237
238 /**
239  * Head of cop DLL.
240  */
241 static struct CacheOperation *cop_head;
242
243 /**
244  * Tail of cop DLL.
245  */
246 static struct CacheOperation *cop_tail;
247
248 /**
249  * First active zone monitor.
250  */
251 static struct ZoneMonitor *monitor_head;
252
253 /**
254  * Last active zone monitor.
255  */
256 static struct ZoneMonitor *monitor_tail;
257
258 /**
259  * Notification context shared by all monitors.
260  */
261 static struct GNUNET_NotificationContext *monitor_nc;
262
263 /**
264  * Optimize block insertion by caching map of private keys to
265  * public keys in memory?
266  */
267 static int cache_keys;
268
269 /**
270  * Use the namecache? Doing so creates additional cryptographic
271  * operations whenever we touch a record.
272  */
273 static int disable_namecache;
274
275
276 /**
277  * Task run during shutdown.
278  *
279  * @param cls unused
280  */
281 static void
282 cleanup_task (void *cls)
283 {
284   struct CacheOperation *cop;
285
286   (void) cls;
287   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
288               "Stopping namestore service\n");
289   while (NULL != (cop = cop_head))
290   {
291     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
292                 "Aborting incomplete namecache operation\n");
293     GNUNET_NAMECACHE_cancel (cop->qe);
294     GNUNET_CONTAINER_DLL_remove (cop_head,
295                                  cop_tail,
296                                  cop);
297     GNUNET_free (cop);
298   }
299   if (NULL != namecache)
300   {
301     GNUNET_NAMECACHE_disconnect (namecache);
302     namecache = NULL;
303   }
304   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name,
305                                               GSN_database));
306   GNUNET_free (db_lib_name);
307   db_lib_name = NULL;
308   if (NULL != monitor_nc)
309   {
310     GNUNET_notification_context_destroy (monitor_nc);
311     monitor_nc = NULL;
312   }
313   if (NULL != statistics)
314   {
315     GNUNET_STATISTICS_destroy (statistics,
316                                GNUNET_NO);
317     statistics = NULL;
318   }
319 }
320
321
322 /**
323  * Called whenever a client is disconnected.
324  * Frees our resources associated with that client.
325  *
326  * @param cls closure
327  * @param client identification of the client
328  * @param app_ctx the `struct NamestoreClient` of @a client
329  */
330 static void
331 client_disconnect_cb (void *cls,
332                       struct GNUNET_SERVICE_Client *client,
333                       void *app_ctx)
334 {
335   struct NamestoreClient *nc = app_ctx;
336   struct ZoneIteration *no;
337   struct ZoneMonitor *zm;
338   struct CacheOperation *cop;
339
340   (void) cls;
341   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342               "Client %p disconnected\n",
343               client);
344   for (zm = monitor_head; NULL != zm; zm = zm->next)
345   {
346     if (nc == zm->nc)
347     {
348       GNUNET_CONTAINER_DLL_remove (monitor_head,
349                                    monitor_tail,
350                                    zm);
351       if (NULL != zm->task)
352       {
353         GNUNET_SCHEDULER_cancel (zm->task);
354         zm->task = NULL;
355       }
356       GNUNET_free (zm);
357       break;
358     }
359   }
360   while (NULL != (no = nc->op_head))
361   {
362     GNUNET_CONTAINER_DLL_remove (nc->op_head,
363                                  nc->op_tail,
364                                  no);
365     GNUNET_free (no);
366   }
367   for (cop = cop_head; NULL != cop; cop = cop->next)
368     if (nc == cop->nc)
369       cop->nc = NULL;
370   GNUNET_free (nc);
371 }
372
373
374 /**
375  * Add a client to our list of active clients.
376  *
377  * @param cls NULL
378  * @param client client to add
379  * @param mq message queue for @a client
380  * @return internal namestore client structure for this client
381  */
382 static void *
383 client_connect_cb (void *cls,
384                    struct GNUNET_SERVICE_Client *client,
385                    struct GNUNET_MQ_Handle *mq)
386 {
387   struct NamestoreClient *nc;
388
389   (void) cls;
390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391               "Client %p connected\n",
392               client);
393   nc = GNUNET_new (struct NamestoreClient);
394   nc->client = client;
395   nc->mq = mq;
396   return nc;
397 }
398
399
400 /**
401  * Function called with the records for the #GNUNET_GNS_EMPTY_LABEL_AT
402  * label in the zone.  Used to locate the #GNUNET_GNSRECORD_TYPE_NICK
403  * record, which (if found) is then copied to @a cls for future use.
404  *
405  * @param cls a `struct GNUNET_GNSRECORD_Data **` for storing the nick (if found)
406  * @param seq sequence number of the record
407  * @param private_key the private key of the zone (unused)
408  * @param label should be #GNUNET_GNS_EMPTY_LABEL_AT
409  * @param rd_count number of records in @a rd
410  * @param rd records stored under @a label in the zone
411  */
412 static void
413 lookup_nick_it (void *cls,
414                 uint64_t seq,
415                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key,
416                 const char *label,
417                 unsigned int rd_count,
418                 const struct GNUNET_GNSRECORD_Data *rd)
419 {
420   struct GNUNET_GNSRECORD_Data **res = cls;
421
422   (void) private_key;
423   (void) seq;
424   if (0 != strcmp (label, GNUNET_GNS_EMPTY_LABEL_AT))
425   {
426     GNUNET_break (0);
427     return;
428   }
429   for (unsigned int c = 0; c < rd_count; c++)
430   {
431     if (GNUNET_GNSRECORD_TYPE_NICK == rd[c].record_type)
432     {
433       (*res) = GNUNET_malloc (rd[c].data_size + sizeof (struct GNUNET_GNSRECORD_Data));
434       (*res)->data = &(*res)[1];
435       GNUNET_memcpy ((void *) (*res)->data,
436                      rd[c].data,
437                      rd[c].data_size);
438       (*res)->data_size = rd[c].data_size;
439       (*res)->expiration_time = rd[c].expiration_time;
440       (*res)->flags = rd[c].flags;
441       (*res)->record_type = GNUNET_GNSRECORD_TYPE_NICK;
442       return;
443     }
444   }
445   (*res) = NULL;
446 }
447
448
449 /**
450  * Return the NICK record for the zone (if it exists).
451  *
452  * @param zone private key for the zone to look for nick
453  * @return NULL if no NICK record was found
454  */
455 static struct GNUNET_GNSRECORD_Data *
456 get_nick_record (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone)
457 {
458   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
459   struct GNUNET_GNSRECORD_Data *nick;
460   int res;
461
462   nick = NULL;
463   res = GSN_database->lookup_records (GSN_database->cls,
464                                       zone,
465                                       GNUNET_GNS_EMPTY_LABEL_AT,
466                                       &lookup_nick_it,
467                                       &nick);
468   if ( (GNUNET_OK != res) ||
469        (NULL == nick) )
470   {
471     GNUNET_CRYPTO_ecdsa_key_get_public (zone, &pub);
472     GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
473                 "No nick name set for zone `%s'\n",
474                 GNUNET_GNSRECORD_z2s (&pub));
475     return NULL;
476   }
477   return nick;
478 }
479
480
481 /**
482  * Merge the nick record @a nick_rd with the rest of the
483  * record set given in @a rd2.  Store the result in @a rdc_res
484  * and @a rd_res.  The @a nick_rd's expiration time is set to
485  * the maximum expiration time of all of the records in @a rd2.
486  *
487  * @param nick_rd the nick record to integrate
488  * @param rd2_length length of the @a rd2 array
489  * @param rd2 array of records
490  * @param rdc_res[out] length of the resulting @a rd_res array
491  * @param rd_res[out] set to an array of records,
492  *                    including @a nick_rd and @a rd2;
493  *           all of the variable-size 'data' fields in @a rd2 are
494  *           allocated in the same chunk of memory!
495  */
496 static void
497 merge_with_nick_records (const struct GNUNET_GNSRECORD_Data *nick_rd,
498                          unsigned int rd2_length,
499                          const struct GNUNET_GNSRECORD_Data *rd2,
500                          unsigned int *rdc_res,
501                          struct GNUNET_GNSRECORD_Data **rd_res)
502 {
503   uint64_t latest_expiration;
504   size_t req;
505   char *data;
506   int record_offset;
507   size_t data_offset;
508
509   (*rdc_res) = 1 + rd2_length;
510   if (0 == 1 + rd2_length)
511   {
512     (*rd_res) = NULL;
513     return;
514   }
515   req = 0;
516   for (unsigned int c=0; c< 1; c++)
517     req += sizeof (struct GNUNET_GNSRECORD_Data) + nick_rd[c].data_size;
518   for (unsigned int c=0; c< rd2_length; c++)
519     req += sizeof (struct GNUNET_GNSRECORD_Data) + rd2[c].data_size;
520   (*rd_res) = GNUNET_malloc (req);
521   data = (char *) &(*rd_res)[1 + rd2_length];
522   data_offset = 0;
523   latest_expiration = 0;
524   for (unsigned int c=0; c< rd2_length; c++)
525   {
526     if (0 != (rd2[c].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
527     {
528       if ((GNUNET_TIME_absolute_get().abs_value_us + rd2[c].expiration_time) >
529         latest_expiration)
530           latest_expiration = rd2[c].expiration_time;
531     }
532     else if (rd2[c].expiration_time > latest_expiration)
533       latest_expiration = rd2[c].expiration_time;
534     (*rd_res)[c] = rd2[c];
535     (*rd_res)[c].data = (void *) &data[data_offset];
536     GNUNET_memcpy ((void *) (*rd_res)[c].data,
537                    rd2[c].data,
538                    rd2[c].data_size);
539     data_offset += (*rd_res)[c].data_size;
540   }
541   /* append nick */
542   record_offset = rd2_length;
543   (*rd_res)[record_offset] = *nick_rd;
544   (*rd_res)[record_offset].expiration_time = latest_expiration;
545   (*rd_res)[record_offset].data = (void *) &data[data_offset];
546   GNUNET_memcpy ((void *) (*rd_res)[record_offset].data,
547                  nick_rd->data,
548                  nick_rd->data_size);
549   data_offset += (*rd_res)[record_offset].data_size;
550   GNUNET_assert (req == (sizeof (struct GNUNET_GNSRECORD_Data)) * (*rdc_res) + data_offset);
551 }
552
553
554 /**
555  * Generate a `struct LookupNameResponseMessage` and send it to the
556  * given client using the given notification context.
557  *
558  * @param nc client to unicast to
559  * @param request_id request ID to use
560  * @param zone_key zone key of the zone
561  * @param name name
562  * @param rd_count number of records in @a rd
563  * @param rd array of records
564  */
565 static void
566 send_lookup_response (struct NamestoreClient *nc,
567                       uint32_t request_id,
568                       const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
569                       const char *name,
570                       unsigned int rd_count,
571                       const struct GNUNET_GNSRECORD_Data *rd)
572 {
573   struct GNUNET_MQ_Envelope *env;
574   struct RecordResultMessage *zir_msg;
575   struct GNUNET_GNSRECORD_Data *nick;
576   struct GNUNET_GNSRECORD_Data *res;
577   unsigned int res_count;
578   size_t name_len;
579   size_t rd_ser_len;
580   char *name_tmp;
581   char *rd_ser;
582
583   nick = get_nick_record (zone_key);
584   if ( (NULL != nick) &&
585        (0 != strcmp (name,
586                      GNUNET_GNS_EMPTY_LABEL_AT)))
587   {
588     nick->flags = (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
589     merge_with_nick_records (nick,
590                              rd_count,
591                              rd,
592                              &res_count,
593                              &res);
594     GNUNET_free (nick);
595   }
596   else
597   {
598     res_count = rd_count;
599     res = (struct GNUNET_GNSRECORD_Data *) rd;
600   }
601
602   name_len = strlen (name) + 1;
603   rd_ser_len = GNUNET_GNSRECORD_records_get_size (res_count, res);
604   env = GNUNET_MQ_msg_extra (zir_msg,
605                              name_len + rd_ser_len,
606                              GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
607   zir_msg->gns_header.r_id = htonl (request_id);
608   zir_msg->name_len = htons (name_len);
609   zir_msg->rd_count = htons (res_count);
610   zir_msg->rd_len = htons (rd_ser_len);
611   zir_msg->private_key = *zone_key;
612   name_tmp = (char *) &zir_msg[1];
613   GNUNET_memcpy (name_tmp,
614                  name,
615                  name_len);
616   rd_ser = &name_tmp[name_len];
617   GNUNET_GNSRECORD_records_serialize (res_count,
618                                       res,
619                                       rd_ser_len,
620                                       rd_ser);
621   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
622               "Sending RECORD_RESULT message with %u records\n",
623               res_count);
624   GNUNET_STATISTICS_update (statistics,
625                             "Record sets sent to clients",
626                             1,
627                             GNUNET_NO);
628   GNUNET_MQ_send (nc->mq,
629                   env);
630   if (rd != res)
631     GNUNET_free (res);
632 }
633
634
635 /**
636  * Send response to the store request to the client.
637  *
638  * @param client client to talk to
639  * @param res status of the operation
640  * @param rid client's request ID
641  */
642 static void
643 send_store_response (struct NamestoreClient *nc,
644                      int res,
645                      uint32_t rid)
646 {
647   struct GNUNET_MQ_Envelope *env;
648   struct RecordStoreResponseMessage *rcr_msg;
649
650   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651               "Sending RECORD_STORE_RESPONSE message\n");
652   env = GNUNET_MQ_msg (rcr_msg,
653                        GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE);
654   rcr_msg->gns_header.r_id = htonl (rid);
655   rcr_msg->op_result = htonl (res);
656   GNUNET_MQ_send (nc->mq,
657                   env);
658 }
659
660
661 /**
662  * Cache operation complete, clean up.
663  *
664  * @param cls the `struct CacheOperation`
665  * @param success success
666  * @param emsg error messages
667  */
668 static void
669 finish_cache_operation (void *cls,
670                         int32_t success,
671                         const char *emsg)
672 {
673   struct CacheOperation *cop = cls;
674
675   if (NULL != emsg)
676     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
677                 _("Failed to replicate block in namecache: %s\n"),
678                 emsg);
679   else
680     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681                 "CACHE operation completed\n");
682   GNUNET_CONTAINER_DLL_remove (cop_head,
683                                cop_tail,
684                                cop);
685   if (NULL != cop->nc)
686     send_store_response (cop->nc,
687                          success,
688                          cop->rid);
689   GNUNET_free (cop);
690 }
691
692
693 /**
694  * We just touched the plaintext information about a name in our zone;
695  * refresh the corresponding (encrypted) block in the namecache.
696  *
697  * @param nc client responsible for the request, can be NULL
698  * @param rid request ID of the client
699  * @param zone_key private key of the zone
700  * @param name label for the records
701  * @param rd_count number of records
702  * @param rd records stored under the given @a name
703  */
704 static void
705 refresh_block (struct NamestoreClient *nc,
706                uint32_t rid,
707                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
708                const char *name,
709                unsigned int rd_count,
710                const struct GNUNET_GNSRECORD_Data *rd)
711 {
712   struct GNUNET_GNSRECORD_Block *block;
713   struct CacheOperation *cop;
714   struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
715   struct GNUNET_GNSRECORD_Data *nick;
716   struct GNUNET_GNSRECORD_Data *res;
717   unsigned int res_count;
718   struct GNUNET_TIME_Absolute exp_time;
719
720   nick = get_nick_record (zone_key);
721   res_count = rd_count;
722   res = (struct GNUNET_GNSRECORD_Data *) rd; /* fixme: a bit unclean... */
723   if (NULL != nick)
724   {
725     nick->flags = (nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
726     merge_with_nick_records (nick,
727                              rd_count,rd,
728                              &res_count,
729                              &res);
730     GNUNET_free (nick);
731   }
732   if (0 == res_count)
733   {
734     send_store_response (nc,
735                          GNUNET_OK,
736                          rid);
737     return; /* no data, no need to update cache */
738   }
739   if (GNUNET_YES == disable_namecache)
740   {
741     GNUNET_STATISTICS_update (statistics,
742                               "Namecache updates skipped (NC disabled)",
743                               1,
744                               GNUNET_NO);
745     send_store_response (nc,
746                          GNUNET_OK,
747                          rid);
748     return;
749   }
750   exp_time = GNUNET_GNSRECORD_record_get_expiration_time (res_count,
751                                                           res);
752   if (cache_keys)
753     block = GNUNET_GNSRECORD_block_create2 (zone_key,
754                                             exp_time,
755                                             name,
756                                             res,
757                                             res_count);
758   else
759     block = GNUNET_GNSRECORD_block_create (zone_key,
760                                            exp_time,
761                                            name,
762                                            res,
763                                            res_count);
764   GNUNET_assert (NULL != block);
765   GNUNET_CRYPTO_ecdsa_key_get_public (zone_key,
766                                       &pkey);
767   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768               "Caching block for label `%s' with %u records and expiration %s in zone `%s' in namecache\n",
769               name,
770               res_count,
771               GNUNET_STRINGS_absolute_time_to_string (exp_time),
772               GNUNET_GNSRECORD_z2s (&pkey));
773   GNUNET_STATISTICS_update (statistics,
774                             "Namecache updates pushed",
775                             1,
776                             GNUNET_NO);
777   cop = GNUNET_new (struct CacheOperation);
778   cop->nc = nc;
779   cop->rid = rid;
780   GNUNET_CONTAINER_DLL_insert (cop_head,
781                                cop_tail,
782                                cop);
783   cop->qe = GNUNET_NAMECACHE_block_cache (namecache,
784                                           block,
785                                           &finish_cache_operation,
786                                           cop);
787   GNUNET_free (block);
788 }
789
790
791 /**
792  * Closure for #lookup_it().
793  */
794 struct RecordLookupContext
795 {
796
797   /**
798    * FIXME.
799    */
800   const char *label;
801
802   /**
803    * FIXME.
804    */
805   char *res_rd;
806
807   /**
808    * FIXME.
809    */
810   struct GNUNET_GNSRECORD_Data *nick;
811
812   /**
813    * FIXME.
814    */
815   int found;
816
817   /**
818    * FIXME.
819    */
820   unsigned int res_rd_count;
821
822   /**
823    * FIXME.
824    */
825   size_t rd_ser_len;
826 };
827
828
829 /**
830  * FIXME.
831  * @param seq sequence number of the record
832  */
833 static void
834 lookup_it (void *cls,
835            uint64_t seq,
836            const struct GNUNET_CRYPTO_EcdsaPrivateKey *private_key,
837            const char *label,
838            unsigned int rd_count,
839            const struct GNUNET_GNSRECORD_Data *rd)
840 {
841   struct RecordLookupContext *rlc = cls;
842   struct GNUNET_GNSRECORD_Data *rd_res;
843   unsigned int rdc_res;
844
845   (void) private_key;
846   (void) seq;
847   if (0 == strcmp (label,
848                    rlc->label))
849   {
850     rlc->found = GNUNET_YES;
851     if (0 != rd_count)
852     {
853       if ( (NULL != rlc->nick) &&
854            (0 != strcmp (label,
855                          GNUNET_GNS_EMPTY_LABEL_AT)) )
856       {
857         /* Merge */
858         rd_res = NULL;
859         rdc_res = 0;
860         rlc->nick->flags = (rlc->nick->flags | GNUNET_GNSRECORD_RF_PRIVATE) ^ GNUNET_GNSRECORD_RF_PRIVATE;
861         merge_with_nick_records (rlc->nick,
862                                  rd_count,
863                                  rd,
864                                  &rdc_res,
865                                  &rd_res);
866         rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rdc_res,
867                                                              rd_res);
868         rlc->res_rd_count = rdc_res;
869         rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
870         GNUNET_GNSRECORD_records_serialize (rdc_res,
871                                             rd_res,
872                                             rlc->rd_ser_len,
873                                             rlc->res_rd);
874
875         GNUNET_free  (rd_res);
876         GNUNET_free  (rlc->nick);
877         rlc->nick = NULL;
878       }
879       else
880       {
881         rlc->rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count,
882                                                              rd);
883         rlc->res_rd_count = rd_count;
884         rlc->res_rd = GNUNET_malloc (rlc->rd_ser_len);
885         GNUNET_GNSRECORD_records_serialize (rd_count,
886                                             rd,
887                                             rlc->rd_ser_len,
888                                             rlc->res_rd);
889       }
890     }
891     else
892     {
893       rlc->rd_ser_len = 0;
894       rlc->res_rd_count = 0;
895       rlc->res_rd = NULL;
896     }
897   }
898 }
899
900
901 /**
902  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
903  *
904  * @param cls client sending the message
905  * @param ll_msg message of type `struct LabelLookupMessage`
906  * @return #GNUNET_OK if @a ll_msg is well-formed
907  */
908 static int
909 check_record_lookup (void *cls,
910                      const struct LabelLookupMessage *ll_msg)
911 {
912   uint32_t name_len;
913   size_t src_size;
914   const char *name_tmp;
915
916   (void) cls;
917   name_len = ntohl (ll_msg->label_len);
918   src_size = ntohs (ll_msg->gns_header.header.size);
919   if (name_len != src_size - sizeof (struct LabelLookupMessage))
920   {
921     GNUNET_break (0);
922     return GNUNET_SYSERR;
923   }
924
925   name_tmp = (const char *) &ll_msg[1];
926   if ('\0' != name_tmp[name_len -1])
927   {
928     GNUNET_break (0);
929     return GNUNET_SYSERR;
930   }
931   return GNUNET_OK;
932 }
933
934
935 /**
936  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP message
937  *
938  * @param cls client sending the message
939  * @param ll_msg message of type `struct LabelLookupMessage`
940  */
941 static void
942 handle_record_lookup (void *cls,
943                       const struct LabelLookupMessage *ll_msg)
944 {
945   struct NamestoreClient *nc = cls;
946   struct GNUNET_MQ_Envelope *env;
947   struct LabelLookupResponseMessage *llr_msg;
948   struct RecordLookupContext rlc;
949   const char *name_tmp;
950   char *res_name;
951   char *conv_name;
952   uint32_t name_len;
953   int res;
954
955   name_len = ntohl (ll_msg->label_len);
956   name_tmp = (const char *) &ll_msg[1];
957   GNUNET_SERVICE_client_continue (nc->client);
958   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
959               "Received NAMESTORE_RECORD_LOOKUP message for name `%s'\n",
960               name_tmp);
961
962   conv_name = GNUNET_GNSRECORD_string_to_lowercase (name_tmp);
963   if (NULL == conv_name)
964   {
965     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
966                 "Error converting name `%s'\n",
967                 name_tmp);
968     GNUNET_SERVICE_client_drop (nc->client);
969     return;
970   }
971   rlc.label = conv_name;
972   rlc.found = GNUNET_NO;
973   rlc.res_rd_count = 0;
974   rlc.res_rd = NULL;
975   rlc.rd_ser_len = 0;
976   rlc.nick = get_nick_record (&ll_msg->zone);
977   res = GSN_database->lookup_records (GSN_database->cls,
978                                       &ll_msg->zone,
979                                       conv_name,
980                                       &lookup_it,
981                                       &rlc);
982   GNUNET_free (conv_name);
983   env = GNUNET_MQ_msg_extra (llr_msg,
984                              name_len + rlc.rd_ser_len,
985                              GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP_RESPONSE);
986   llr_msg->gns_header.r_id = ll_msg->gns_header.r_id;
987   llr_msg->private_key = ll_msg->zone;
988   llr_msg->name_len = htons (name_len);
989   llr_msg->rd_count = htons (rlc.res_rd_count);
990   llr_msg->rd_len = htons (rlc.rd_ser_len);
991   res_name = (char *) &llr_msg[1];
992   if  ((GNUNET_YES == rlc.found) && (GNUNET_OK == res))
993     llr_msg->found = ntohs (GNUNET_YES);
994   else
995     llr_msg->found = ntohs (GNUNET_NO);
996   GNUNET_memcpy (&llr_msg[1],
997                  name_tmp,
998                  name_len);
999   GNUNET_memcpy (&res_name[name_len],
1000                  rlc.res_rd,
1001                  rlc.rd_ser_len);
1002   GNUNET_MQ_send (nc->mq,
1003                   env);
1004   GNUNET_free_non_null (rlc.res_rd);
1005 }
1006
1007
1008 /**
1009  * Checks a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
1010  *
1011  * @param cls client sending the message
1012  * @param rp_msg message of type `struct RecordStoreMessage`
1013  * @return #GNUNET_OK if @a rp_msg is well-formed
1014  */
1015 static int
1016 check_record_store (void *cls,
1017                     const struct RecordStoreMessage *rp_msg)
1018 {
1019   size_t name_len;
1020   size_t msg_size;
1021   size_t msg_size_exp;
1022   size_t rd_ser_len;
1023   const char *name_tmp;
1024
1025   (void) cls;
1026   name_len = ntohs (rp_msg->name_len);
1027   msg_size = ntohs (rp_msg->gns_header.header.size);
1028   rd_ser_len = ntohs (rp_msg->rd_len);
1029   msg_size_exp = sizeof (struct RecordStoreMessage) + name_len + rd_ser_len;
1030   if (msg_size != msg_size_exp)
1031   {
1032     GNUNET_break (0);
1033     return GNUNET_SYSERR;
1034   }
1035   if ((0 == name_len) || (name_len > MAX_NAME_LEN))
1036   {
1037     GNUNET_break (0);
1038     return GNUNET_SYSERR;
1039   }
1040   name_tmp = (const char *) &rp_msg[1];
1041   if ('\0' != name_tmp[name_len -1])
1042   {
1043     GNUNET_break (0);
1044     return GNUNET_SYSERR;
1045   }
1046   return GNUNET_OK;
1047 }
1048
1049
1050 /**
1051  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
1052  *
1053  * @param cls client sending the message
1054  * @param rp_msg message of type `struct RecordStoreMessage`
1055  */
1056 static void
1057 handle_record_store (void *cls,
1058                      const struct RecordStoreMessage *rp_msg)
1059 {
1060   struct NamestoreClient *nc = cls;
1061   size_t name_len;
1062   size_t rd_ser_len;
1063   uint32_t rid;
1064   const char *name_tmp;
1065   char *conv_name;
1066   const char *rd_ser;
1067   unsigned int rd_count;
1068   int res;
1069   struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1070   struct ZoneMonitor *zm;
1071
1072   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073               "Received NAMESTORE_RECORD_STORE message\n");
1074   rid = ntohl (rp_msg->gns_header.r_id);
1075   name_len = ntohs (rp_msg->name_len);
1076   rd_count = ntohs (rp_msg->rd_count);
1077   rd_ser_len = ntohs (rp_msg->rd_len);
1078   GNUNET_break (0 == ntohs (rp_msg->reserved));
1079   name_tmp = (const char *) &rp_msg[1];
1080   rd_ser = &name_tmp[name_len];
1081   {
1082     struct GNUNET_GNSRECORD_Data rd[rd_count];
1083
1084     if (GNUNET_OK !=
1085         GNUNET_GNSRECORD_records_deserialize (rd_ser_len,
1086                                               rd_ser,
1087                                               rd_count,
1088                                               rd))
1089     {
1090       GNUNET_break (0);
1091       GNUNET_SERVICE_client_drop (nc->client);
1092       return;
1093     }
1094
1095     /* Extracting and converting private key */
1096     GNUNET_CRYPTO_ecdsa_key_get_public (&rp_msg->private_key,
1097                                         &pubkey);
1098     conv_name = GNUNET_GNSRECORD_string_to_lowercase (name_tmp);
1099     if (NULL == conv_name)
1100     {
1101       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1102                   "Error converting name `%s'\n",
1103                   name_tmp);
1104       GNUNET_SERVICE_client_drop (nc->client);
1105       return;
1106     }
1107     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108                 "Creating %u records for name `%s' in zone `%s'\n",
1109                 (unsigned int) rd_count,
1110                 conv_name,
1111                 GNUNET_GNSRECORD_z2s (&pubkey));
1112
1113     if ( (0 == rd_count) &&
1114          (GNUNET_NO ==
1115           GSN_database->iterate_records (GSN_database->cls,
1116                                          &rp_msg->private_key,
1117                                          0,
1118                                          1,
1119                                          NULL,
1120                                          0)) )
1121     {
1122       /* This name does not exist, so cannot be removed */
1123       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1124                   "Name `%s' does not exist, no deletion required\n",
1125                   conv_name);
1126       res = GNUNET_NO;
1127     }
1128     else
1129     {
1130       struct GNUNET_GNSRECORD_Data rd_clean[rd_count];
1131       unsigned int rd_clean_off;
1132
1133       /* remove "NICK" records, unless this is for the
1134          #GNUNET_GNS_EMPTY_LABEL_AT label */
1135       rd_clean_off = 0;
1136       for (unsigned int i=0;i<rd_count;i++)
1137       {
1138         rd_clean[rd_clean_off] = rd[i];
1139         if ( (0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT,
1140                            conv_name)) ||
1141              (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type) )
1142           rd_clean_off++;
1143       }
1144       res = GSN_database->store_records (GSN_database->cls,
1145                                          &rp_msg->private_key,
1146                                          conv_name,
1147                                          rd_clean_off,
1148                                          rd_clean);
1149       if (GNUNET_OK == res)
1150       {
1151         for (zm = monitor_head; NULL != zm; zm = zm->next)
1152         {
1153           if ( (0 == memcmp (&rp_msg->private_key, &zm->zone,
1154                              sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) ||
1155                (0 == memcmp (&zm->zone,
1156                              &zero,
1157                              sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) )
1158           {
1159             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1160                         "Notifying monitor about changes under label `%s'\n",
1161                         conv_name);
1162             send_lookup_response (zm->nc,
1163                                   0,
1164                                   &rp_msg->private_key,
1165                                   conv_name,
1166                                   rd_count, rd);
1167           }
1168           else
1169             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1170                         "Monitor is for another zone\n");
1171         }
1172         if (NULL == monitor_head)
1173           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1174                       "No monitors active\n");
1175       }
1176       else
1177       {
1178         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1179                     "Error storing record: %d\n",
1180                     res);
1181       }
1182     }
1183     if (GNUNET_OK == res)
1184     {
1185       refresh_block (nc,
1186                      rid,
1187                      &rp_msg->private_key,
1188                      conv_name,
1189                      rd_count,
1190                      rd);
1191       GNUNET_SERVICE_client_continue (nc->client);
1192       GNUNET_free (conv_name);
1193       return;
1194     }
1195     GNUNET_free (conv_name);
1196   }
1197   send_store_response (nc,
1198                        res,
1199                        rid);
1200   GNUNET_SERVICE_client_continue (nc->client);
1201 }
1202
1203
1204 /**
1205  * Context for record remove operations passed from #handle_zone_to_name to
1206  * #handle_zone_to_name_it as closure
1207  */
1208 struct ZoneToNameCtx
1209 {
1210   /**
1211    * Namestore client
1212    */
1213   struct NamestoreClient *nc;
1214
1215   /**
1216    * Request id (to be used in the response to the client).
1217    */
1218   uint32_t rid;
1219
1220   /**
1221    * Set to #GNUNET_OK on success, #GNUNET_SYSERR on error.  Note that
1222    * not finding a name for the zone still counts as a 'success' here,
1223    * as this field is about the success of executing the IPC protocol.
1224    */
1225   int success;
1226 };
1227
1228
1229 /**
1230  * Zone to name iterator
1231  *
1232  * @param cls struct ZoneToNameCtx *
1233  * @param seq sequence number of the record
1234  * @param zone_key the zone key
1235  * @param name name
1236  * @param rd_count number of records in @a rd
1237  * @param rd record data
1238  */
1239 static void
1240 handle_zone_to_name_it (void *cls,
1241                         uint64_t seq,
1242                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1243                         const char *name,
1244                         unsigned int rd_count,
1245                         const struct GNUNET_GNSRECORD_Data *rd)
1246 {
1247   struct ZoneToNameCtx *ztn_ctx = cls;
1248   struct GNUNET_MQ_Envelope *env;
1249   struct ZoneToNameResponseMessage *ztnr_msg;
1250   int16_t res;
1251   size_t name_len;
1252   size_t rd_ser_len;
1253   size_t msg_size;
1254   char *name_tmp;
1255   char *rd_tmp;
1256
1257   (void) seq;
1258   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1259               "Found result for zone-to-name lookup: `%s'\n",
1260               name);
1261   res = GNUNET_YES;
1262   name_len = (NULL == name) ? 0 : strlen (name) + 1;
1263   rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1264   msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1265   if (msg_size >= GNUNET_MAX_MESSAGE_SIZE)
1266   {
1267     GNUNET_break (0);
1268     ztn_ctx->success = GNUNET_SYSERR;
1269     return;
1270   }
1271   env = GNUNET_MQ_msg_extra (ztnr_msg,
1272                              name_len + rd_ser_len,
1273                              GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1274   ztnr_msg->gns_header.header.size = htons (msg_size);
1275   ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1276   ztnr_msg->res = htons (res);
1277   ztnr_msg->rd_len = htons (rd_ser_len);
1278   ztnr_msg->rd_count = htons (rd_count);
1279   ztnr_msg->name_len = htons (name_len);
1280   ztnr_msg->zone = *zone_key;
1281   name_tmp = (char *) &ztnr_msg[1];
1282   GNUNET_memcpy (name_tmp,
1283                  name,
1284                  name_len);
1285   rd_tmp = &name_tmp[name_len];
1286   GNUNET_GNSRECORD_records_serialize (rd_count,
1287                                       rd,
1288                                       rd_ser_len,
1289                                       rd_tmp);
1290   ztn_ctx->success = GNUNET_OK;
1291   GNUNET_MQ_send (ztn_ctx->nc->mq,
1292                   env);
1293 }
1294
1295
1296 /**
1297  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME message
1298  *
1299  * @param cls client client sending the message
1300  * @param ztn_msg message of type 'struct ZoneToNameMessage'
1301  */
1302 static void
1303 handle_zone_to_name (void *cls,
1304                      const struct ZoneToNameMessage *ztn_msg)
1305 {
1306   struct NamestoreClient *nc = cls;
1307   struct ZoneToNameCtx ztn_ctx;
1308   struct GNUNET_MQ_Envelope *env;
1309   struct ZoneToNameResponseMessage *ztnr_msg;
1310
1311   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1312               "Received `%s' message\n",
1313               "ZONE_TO_NAME");
1314   ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1315   ztn_ctx.nc = nc;
1316   ztn_ctx.success = GNUNET_NO;
1317   if (GNUNET_SYSERR ==
1318       GSN_database->zone_to_name (GSN_database->cls,
1319                                   &ztn_msg->zone,
1320                                   &ztn_msg->value_zone,
1321                                   &handle_zone_to_name_it, &ztn_ctx))
1322   {
1323     /* internal error, hang up instead of signalling something
1324        that might be wrong */
1325     GNUNET_break (0);
1326     GNUNET_SERVICE_client_drop (nc->client);
1327     return;
1328   }
1329   if (GNUNET_NO == ztn_ctx.success)
1330   {
1331     /* no result found, send empty response */
1332     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1333                 "Found no result for zone-to-name lookup.\n");
1334     env = GNUNET_MQ_msg (ztnr_msg,
1335                          GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1336     ztnr_msg->gns_header.r_id = ztn_msg->gns_header.r_id;
1337     ztnr_msg->res = htons (GNUNET_NO);
1338     GNUNET_MQ_send (nc->mq,
1339                     env);
1340   }
1341   GNUNET_SERVICE_client_continue (nc->client);
1342 }
1343
1344
1345 /**
1346  * Context for record remove operations passed from
1347  * #run_zone_iteration_round to #zone_iterate_proc as closure
1348  */
1349 struct ZoneIterationProcResult
1350 {
1351   /**
1352    * The zone iteration handle
1353    */
1354   struct ZoneIteration *zi;
1355
1356   /**
1357    * Number of results left to be returned in this iteration.
1358    */
1359   uint64_t limit;
1360
1361 };
1362
1363
1364 /**
1365  * Process results for zone iteration from database
1366  * 
1367  * @param cls struct ZoneIterationProcResult
1368  * @param seq sequence number of the record
1369  * @param zone_key the zone key
1370  * @param name name
1371  * @param rd_count number of records for this name
1372  * @param rd record data
1373  */
1374 static void
1375 zone_iterate_proc (void *cls,
1376                    uint64_t seq,
1377                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1378                    const char *name,
1379                    unsigned int rd_count,
1380                    const struct GNUNET_GNSRECORD_Data *rd)
1381 {
1382   struct ZoneIterationProcResult *proc = cls;
1383   int do_refresh_block;
1384
1385   if ( (NULL == zone_key) &&
1386        (NULL == name) )
1387   {
1388     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1389                 "Iteration done\n");
1390     return;
1391   }
1392   if ( (NULL == zone_key) ||
1393        (NULL == name) )
1394   {
1395     /* what is this!? should never happen */
1396     GNUNET_break (0);
1397     return;
1398   }
1399   if (0 == proc->limit)
1400   {
1401     /* what is this!? should never happen */
1402     GNUNET_break (0);
1403     return;
1404   }
1405   proc->limit--;
1406   proc->zi->seq = seq;
1407   send_lookup_response (proc->zi->nc,
1408                         proc->zi->request_id,
1409                         zone_key,
1410                         name,
1411                         rd_count,
1412                         rd);
1413   do_refresh_block = GNUNET_NO;
1414   for (unsigned int i=0;i<rd_count;i++)
1415     if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
1416     {
1417       do_refresh_block = GNUNET_YES;
1418       break;
1419     }
1420   if (GNUNET_YES == do_refresh_block)
1421     refresh_block (NULL,
1422                    0,
1423                    zone_key,
1424                    name,
1425                    rd_count,
1426                    rd);
1427 }
1428
1429
1430 /**
1431  * Perform the next round of the zone iteration.
1432  *
1433  * @param zi zone iterator to process
1434  * @param limit number of results to return in one pass
1435  */
1436 static void
1437 run_zone_iteration_round (struct ZoneIteration *zi,
1438                           uint64_t limit)
1439 {
1440   struct ZoneIterationProcResult proc;
1441   struct GNUNET_MQ_Envelope *env;
1442   struct RecordResultMessage *rrm;
1443   struct GNUNET_TIME_Absolute start;
1444   struct GNUNET_TIME_Relative duration;
1445
1446   memset (&proc,
1447           0,
1448           sizeof (proc));
1449   proc.zi = zi;
1450   proc.limit = limit;
1451   start = GNUNET_TIME_absolute_get ();
1452   GNUNET_break (GNUNET_SYSERR !=
1453                 GSN_database->iterate_records (GSN_database->cls,
1454                                                (0 == memcmp (&zi->zone,
1455                                                              &zero,
1456                                                              sizeof (zero)))
1457                                                ? NULL
1458                                                : &zi->zone,
1459                                                zi->seq,
1460                                                limit,
1461                                                &zone_iterate_proc,
1462                                                &proc));
1463   duration = GNUNET_TIME_absolute_get_duration (start);
1464   duration = GNUNET_TIME_relative_divide (duration,
1465                                           limit - proc.limit);
1466   GNUNET_STATISTICS_set (statistics,
1467                          "NAMESTORE iteration delay (μs/record)",
1468                          duration.rel_value_us,
1469                          GNUNET_NO);
1470   if (0 == proc.limit)
1471   {
1472     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1473                 "Returned %llu results, more results available\n",
1474                 (unsigned long long) limit);
1475     return; /* more results later after we get the
1476                #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message */
1477   }
1478   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1479               "Completed iteration after %llu/%llu results\n",
1480               (unsigned long long) (limit - proc.limit),
1481               (unsigned long long) limit);
1482   /* send empty response to indicate end of list */
1483   env = GNUNET_MQ_msg (rrm,
1484                        GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
1485   rrm->gns_header.r_id = htonl (zi->request_id);
1486   GNUNET_MQ_send (zi->nc->mq,
1487                   env);
1488   GNUNET_CONTAINER_DLL_remove (zi->nc->op_head,
1489                                zi->nc->op_tail,
1490                                zi);
1491   GNUNET_free (zi);
1492 }
1493
1494
1495 /**
1496  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START message
1497  *
1498  * @param cls the client sending the message
1499  * @param zis_msg message from the client
1500  */
1501 static void
1502 handle_iteration_start (void *cls,
1503                         const struct ZoneIterationStartMessage *zis_msg)
1504 {
1505   struct NamestoreClient *nc = cls;
1506   struct ZoneIteration *zi;
1507
1508   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1509               "Received ZONE_ITERATION_START message\n");
1510   zi = GNUNET_new (struct ZoneIteration);
1511   zi->request_id = ntohl (zis_msg->gns_header.r_id);
1512   zi->offset = 0;
1513   zi->nc = nc;
1514   zi->zone = zis_msg->zone;
1515
1516   GNUNET_CONTAINER_DLL_insert (nc->op_head,
1517                                nc->op_tail,
1518                                zi);
1519   run_zone_iteration_round (zi,
1520                             1);
1521   GNUNET_SERVICE_client_continue (nc->client);
1522 }
1523
1524
1525 /**
1526  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP message
1527  *
1528  * @param cls the client sending the message
1529  * @param zis_msg message from the client
1530  */
1531 static void
1532 handle_iteration_stop (void *cls,
1533                        const struct ZoneIterationStopMessage *zis_msg)
1534 {
1535   struct NamestoreClient *nc = cls;
1536   struct ZoneIteration *zi;
1537   uint32_t rid;
1538
1539   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1540               "Received ZONE_ITERATION_STOP message\n");
1541   rid = ntohl (zis_msg->gns_header.r_id);
1542   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1543     if (zi->request_id == rid)
1544       break;
1545   if (NULL == zi)
1546   {
1547     GNUNET_break (0);
1548     GNUNET_SERVICE_client_drop (nc->client);
1549     return;
1550   }
1551   GNUNET_CONTAINER_DLL_remove (nc->op_head,
1552                                nc->op_tail,
1553                                zi);
1554   GNUNET_free (zi);
1555   GNUNET_SERVICE_client_continue (nc->client);
1556 }
1557
1558
1559 /**
1560  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message
1561  *
1562  * @param cls the client sending the message
1563  * @param message message from the client
1564  */
1565 static void
1566 handle_iteration_next (void *cls,
1567                        const struct ZoneIterationNextMessage *zis_msg)
1568 {
1569   struct NamestoreClient *nc = cls;
1570   struct ZoneIteration *zi;
1571   uint32_t rid;
1572   uint64_t limit;
1573
1574   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1575               "Received ZONE_ITERATION_NEXT message\n");
1576   GNUNET_STATISTICS_update (statistics,
1577                             "Iteration NEXT messages received",
1578                             1,
1579                             GNUNET_NO);
1580   rid = ntohl (zis_msg->gns_header.r_id);
1581   limit = GNUNET_ntohll (zis_msg->limit);
1582   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1583     if (zi->request_id == rid)
1584       break;
1585   if (NULL == zi)
1586   {
1587     GNUNET_break (0);
1588     GNUNET_SERVICE_client_drop (nc->client);
1589     return;
1590   }
1591   run_zone_iteration_round (zi,
1592                             limit);
1593   GNUNET_SERVICE_client_continue (nc->client);
1594 }
1595
1596
1597 /**
1598  * Send 'sync' message to zone monitor, we're now in sync.
1599  *
1600  * @param zm monitor that is now in sync
1601  */
1602 static void
1603 monitor_sync (struct ZoneMonitor *zm)
1604 {
1605   struct GNUNET_MQ_Envelope *env;
1606   struct GNUNET_MessageHeader *sync;
1607
1608   env = GNUNET_MQ_msg (sync,
1609                        GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
1610   GNUNET_MQ_send (zm->nc->mq,
1611                   env);
1612 }
1613
1614
1615 /**
1616  * Obtain the next datum during the zone monitor's zone intiial iteration.
1617  *
1618  * @param cls zone monitor that does its initial iteration
1619  */
1620 static void
1621 monitor_next (void *cls);
1622
1623
1624 /**
1625  * A #GNUNET_NAMESTORE_RecordIterator for monitors.
1626  *
1627  * @param cls a 'struct ZoneMonitor *' with information about the monitor
1628  * @param seq sequence number of the record
1629  * @param zone_key zone key of the zone
1630  * @param name name
1631  * @param rd_count number of records in @a rd
1632  * @param rd array of records
1633  */
1634 static void
1635 monitor_iterate_cb (void *cls,
1636                     uint64_t seq,
1637                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1638                     const char *name,
1639                     unsigned int rd_count,
1640                     const struct GNUNET_GNSRECORD_Data *rd)
1641 {
1642   struct ZoneMonitor *zm = cls;
1643
1644   zm->seq = seq;
1645   if (NULL == name)
1646   {
1647     /* finished with iteration */
1648     monitor_sync (zm);
1649     return;
1650   }
1651   GNUNET_STATISTICS_update (statistics,
1652                             "Monitor notifications sent",
1653                             1,
1654                             GNUNET_NO);
1655   send_lookup_response (zm->nc,
1656                         0,
1657                         zone_key,
1658                         name,
1659                         rd_count,
1660                         rd);
1661   zm->task = GNUNET_SCHEDULER_add_now (&monitor_next,
1662                                        zm);
1663 }
1664
1665
1666 /**
1667  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START message
1668  *
1669  * @param cls the client sending the message
1670  * @param message message from the client
1671  */
1672 static void
1673 handle_monitor_start (void *cls,
1674                       const struct ZoneMonitorStartMessage *zis_msg)
1675 {
1676   struct NamestoreClient *nc = cls;
1677   struct ZoneMonitor *zm;
1678
1679   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1680               "Received ZONE_MONITOR_START message\n");
1681   zm = GNUNET_new (struct ZoneMonitor);
1682   zm->nc = nc;
1683   zm->zone = zis_msg->zone;
1684   GNUNET_CONTAINER_DLL_insert (monitor_head,
1685                                monitor_tail,
1686                                zm);
1687   GNUNET_SERVICE_client_mark_monitor (nc->client);
1688   GNUNET_SERVICE_client_disable_continue_warning (nc->client);
1689   GNUNET_notification_context_add (monitor_nc,
1690                                    nc->mq);
1691   if (GNUNET_YES == ntohl (zis_msg->iterate_first))
1692     zm->task = GNUNET_SCHEDULER_add_now (&monitor_next,
1693                                          zm);
1694   else
1695     monitor_sync (zm);
1696 }
1697
1698
1699 /**
1700  * Obtain the next datum during the zone monitor's zone intiial iteration.
1701  *
1702  * @param cls zone monitor that does its initial iteration
1703  */
1704 static void
1705 monitor_next (void *cls)
1706 {
1707   struct ZoneMonitor *zm = cls;
1708   int ret;
1709
1710   zm->task = NULL;
1711   ret = GSN_database->iterate_records (GSN_database->cls,
1712                                        (0 == memcmp (&zm->zone,
1713                                                      &zero,
1714                                                      sizeof (zero)))
1715                                        ? NULL
1716                                        : &zm->zone,
1717                                        zm->seq,
1718                                        1,
1719                                        &monitor_iterate_cb,
1720                                        zm);
1721   if (GNUNET_SYSERR == ret)
1722   {
1723     GNUNET_SERVICE_client_drop (zm->nc->client);
1724     return;
1725   }
1726   if (GNUNET_NO == ret)
1727   {
1728     /* empty zone */
1729     monitor_sync (zm);
1730     return;
1731   }
1732 }
1733
1734
1735 /**
1736  * Process namestore requests.
1737  *
1738  * @param cls closure
1739  * @param cfg configuration to use
1740  * @param service the initialized service
1741  */
1742 static void
1743 run (void *cls,
1744      const struct GNUNET_CONFIGURATION_Handle *cfg,
1745      struct GNUNET_SERVICE_Handle *service)
1746 {
1747   char *database;
1748
1749   (void) cls;
1750   (void) service;
1751   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1752               "Starting namestore service\n");
1753   cache_keys = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1754                                                      "namestore",
1755                                                      "CACHE_KEYS");
1756   disable_namecache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1757                                                             "namecache",
1758                                                             "DISABLE");
1759   GSN_cfg = cfg;
1760   monitor_nc = GNUNET_notification_context_create (1);
1761   if (GNUNET_YES != disable_namecache)
1762   {
1763     namecache = GNUNET_NAMECACHE_connect (cfg);
1764     GNUNET_assert (NULL != namecache);
1765   }
1766   /* Loading database plugin */
1767   if (GNUNET_OK !=
1768       GNUNET_CONFIGURATION_get_value_string (cfg,
1769                                              "namestore",
1770                                              "database",
1771                                              &database))
1772     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1773                 "No database backend configured\n");
1774
1775   GNUNET_asprintf (&db_lib_name,
1776                    "libgnunet_plugin_namestore_%s",
1777                    database);
1778   GSN_database = GNUNET_PLUGIN_load (db_lib_name,
1779                                      (void *) GSN_cfg);
1780   GNUNET_free (database);
1781   statistics = GNUNET_STATISTICS_create ("namestore",
1782                                          cfg);
1783   GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
1784                                  NULL);
1785   if (NULL == GSN_database)
1786   {
1787     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1788                 "Could not load database backend `%s'\n",
1789                 db_lib_name);
1790     GNUNET_SCHEDULER_shutdown ();
1791     return;
1792   }
1793 }
1794
1795
1796 /**
1797  * Define "main" method using service macro.
1798  */
1799 GNUNET_SERVICE_MAIN
1800 ("namestore",
1801  GNUNET_SERVICE_OPTION_NONE,
1802  &run,
1803  &client_connect_cb,
1804  &client_disconnect_cb,
1805  NULL,
1806  GNUNET_MQ_hd_var_size (record_store,
1807                         GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE,
1808                         struct RecordStoreMessage,
1809                         NULL),
1810  GNUNET_MQ_hd_var_size (record_lookup,
1811                         GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP,
1812                         struct LabelLookupMessage,
1813                         NULL),
1814  GNUNET_MQ_hd_fixed_size (zone_to_name,
1815                           GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME,
1816                           struct ZoneToNameMessage,
1817                           NULL),
1818  GNUNET_MQ_hd_fixed_size (iteration_start,
1819                           GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START,
1820                           struct ZoneIterationStartMessage,
1821                           NULL),
1822  GNUNET_MQ_hd_fixed_size (iteration_next,
1823                           GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT,
1824                           struct ZoneIterationNextMessage,
1825                           NULL),
1826  GNUNET_MQ_hd_fixed_size (iteration_stop,
1827                           GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP,
1828                           struct ZoneIterationStopMessage,
1829                           NULL),
1830  GNUNET_MQ_hd_fixed_size (monitor_start,
1831                           GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START,
1832                           struct ZoneMonitorStartMessage,
1833                           NULL),
1834  GNUNET_MQ_handler_end ());
1835
1836
1837 /* end of gnunet-service-namestore.c */