add perf_ logic for namestore iterations, improve namestore insertion performance...
[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) ||
1036        (name_len > MAX_NAME_LEN) )
1037   {
1038     GNUNET_break (0);
1039     return GNUNET_SYSERR;
1040   }
1041   name_tmp = (const char *) &rp_msg[1];
1042   if ('\0' != name_tmp[name_len -1])
1043   {
1044     GNUNET_break (0);
1045     return GNUNET_SYSERR;
1046   }
1047   return GNUNET_OK;
1048 }
1049
1050
1051 /**
1052  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE message
1053  *
1054  * @param cls client sending the message
1055  * @param rp_msg message of type `struct RecordStoreMessage`
1056  */
1057 static void
1058 handle_record_store (void *cls,
1059                      const struct RecordStoreMessage *rp_msg)
1060 {
1061   struct NamestoreClient *nc = cls;
1062   size_t name_len;
1063   size_t rd_ser_len;
1064   uint32_t rid;
1065   const char *name_tmp;
1066   char *conv_name;
1067   const char *rd_ser;
1068   unsigned int rd_count;
1069   int res;
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     conv_name = GNUNET_GNSRECORD_string_to_lowercase (name_tmp);
1097     if (NULL == conv_name)
1098     {
1099       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1100                   "Error converting name `%s'\n",
1101                   name_tmp);
1102       GNUNET_SERVICE_client_drop (nc->client);
1103       return;
1104     }
1105     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1106                 "Creating %u records for name `%s'\n",
1107                 (unsigned int) rd_count,
1108                 conv_name);
1109     if ( (0 == rd_count) &&
1110          (GNUNET_NO ==
1111           GSN_database->iterate_records (GSN_database->cls,
1112                                          &rp_msg->private_key,
1113                                          0,
1114                                          1,
1115                                          NULL,
1116                                          0)) )
1117     {
1118       /* This name does not exist, so cannot be removed */
1119       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1120                   "Name `%s' does not exist, no deletion required\n",
1121                   conv_name);
1122       res = GNUNET_NO;
1123     }
1124     else
1125     {
1126       struct GNUNET_GNSRECORD_Data rd_clean[rd_count];
1127       unsigned int rd_clean_off;
1128
1129       /* remove "NICK" records, unless this is for the
1130          #GNUNET_GNS_EMPTY_LABEL_AT label */
1131       rd_clean_off = 0;
1132       for (unsigned int i=0;i<rd_count;i++)
1133       {
1134         rd_clean[rd_clean_off] = rd[i];
1135         if ( (0 == strcmp (GNUNET_GNS_EMPTY_LABEL_AT,
1136                            conv_name)) ||
1137              (GNUNET_GNSRECORD_TYPE_NICK != rd[i].record_type) )
1138           rd_clean_off++;
1139       }
1140       res = GSN_database->store_records (GSN_database->cls,
1141                                          &rp_msg->private_key,
1142                                          conv_name,
1143                                          rd_clean_off,
1144                                          rd_clean);
1145       if (GNUNET_OK == res)
1146       {
1147         for (zm = monitor_head; NULL != zm; zm = zm->next)
1148         {
1149           if ( (0 == memcmp (&rp_msg->private_key,
1150                              &zm->zone,
1151                              sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) ||
1152                (0 == memcmp (&zm->zone,
1153                              &zero,
1154                              sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))) )
1155           {
1156             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157                         "Notifying monitor about changes under label `%s'\n",
1158                         conv_name);
1159             send_lookup_response (zm->nc,
1160                                   0,
1161                                   &rp_msg->private_key,
1162                                   conv_name,
1163                                   rd_count, rd);
1164           }
1165           else
1166             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1167                         "Monitor is for another zone\n");
1168         }
1169         if (NULL == monitor_head)
1170           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1171                       "No monitors active\n");
1172       }
1173       else
1174       {
1175         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1176                     "Error storing record: %d\n",
1177                     res);
1178       }
1179     }
1180     if (GNUNET_OK == res)
1181     {
1182       refresh_block (nc,
1183                      rid,
1184                      &rp_msg->private_key,
1185                      conv_name,
1186                      rd_count,
1187                      rd);
1188       GNUNET_SERVICE_client_continue (nc->client);
1189       GNUNET_free (conv_name);
1190       return;
1191     }
1192     GNUNET_free (conv_name);
1193   }
1194   send_store_response (nc,
1195                        res,
1196                        rid);
1197   GNUNET_SERVICE_client_continue (nc->client);
1198 }
1199
1200
1201 /**
1202  * Context for record remove operations passed from #handle_zone_to_name to
1203  * #handle_zone_to_name_it as closure
1204  */
1205 struct ZoneToNameCtx
1206 {
1207   /**
1208    * Namestore client
1209    */
1210   struct NamestoreClient *nc;
1211
1212   /**
1213    * Request id (to be used in the response to the client).
1214    */
1215   uint32_t rid;
1216
1217   /**
1218    * Set to #GNUNET_OK on success, #GNUNET_SYSERR on error.  Note that
1219    * not finding a name for the zone still counts as a 'success' here,
1220    * as this field is about the success of executing the IPC protocol.
1221    */
1222   int success;
1223 };
1224
1225
1226 /**
1227  * Zone to name iterator
1228  *
1229  * @param cls struct ZoneToNameCtx *
1230  * @param seq sequence number of the record
1231  * @param zone_key the zone key
1232  * @param name name
1233  * @param rd_count number of records in @a rd
1234  * @param rd record data
1235  */
1236 static void
1237 handle_zone_to_name_it (void *cls,
1238                         uint64_t seq,
1239                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1240                         const char *name,
1241                         unsigned int rd_count,
1242                         const struct GNUNET_GNSRECORD_Data *rd)
1243 {
1244   struct ZoneToNameCtx *ztn_ctx = cls;
1245   struct GNUNET_MQ_Envelope *env;
1246   struct ZoneToNameResponseMessage *ztnr_msg;
1247   int16_t res;
1248   size_t name_len;
1249   size_t rd_ser_len;
1250   size_t msg_size;
1251   char *name_tmp;
1252   char *rd_tmp;
1253
1254   (void) seq;
1255   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1256               "Found result for zone-to-name lookup: `%s'\n",
1257               name);
1258   res = GNUNET_YES;
1259   name_len = (NULL == name) ? 0 : strlen (name) + 1;
1260   rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1261   msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
1262   if (msg_size >= GNUNET_MAX_MESSAGE_SIZE)
1263   {
1264     GNUNET_break (0);
1265     ztn_ctx->success = GNUNET_SYSERR;
1266     return;
1267   }
1268   env = GNUNET_MQ_msg_extra (ztnr_msg,
1269                              name_len + rd_ser_len,
1270                              GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1271   ztnr_msg->gns_header.header.size = htons (msg_size);
1272   ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
1273   ztnr_msg->res = htons (res);
1274   ztnr_msg->rd_len = htons (rd_ser_len);
1275   ztnr_msg->rd_count = htons (rd_count);
1276   ztnr_msg->name_len = htons (name_len);
1277   ztnr_msg->zone = *zone_key;
1278   name_tmp = (char *) &ztnr_msg[1];
1279   GNUNET_memcpy (name_tmp,
1280                  name,
1281                  name_len);
1282   rd_tmp = &name_tmp[name_len];
1283   GNUNET_GNSRECORD_records_serialize (rd_count,
1284                                       rd,
1285                                       rd_ser_len,
1286                                       rd_tmp);
1287   ztn_ctx->success = GNUNET_OK;
1288   GNUNET_MQ_send (ztn_ctx->nc->mq,
1289                   env);
1290 }
1291
1292
1293 /**
1294  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME message
1295  *
1296  * @param cls client client sending the message
1297  * @param ztn_msg message of type 'struct ZoneToNameMessage'
1298  */
1299 static void
1300 handle_zone_to_name (void *cls,
1301                      const struct ZoneToNameMessage *ztn_msg)
1302 {
1303   struct NamestoreClient *nc = cls;
1304   struct ZoneToNameCtx ztn_ctx;
1305   struct GNUNET_MQ_Envelope *env;
1306   struct ZoneToNameResponseMessage *ztnr_msg;
1307
1308   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1309               "Received `%s' message\n",
1310               "ZONE_TO_NAME");
1311   ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
1312   ztn_ctx.nc = nc;
1313   ztn_ctx.success = GNUNET_NO;
1314   if (GNUNET_SYSERR ==
1315       GSN_database->zone_to_name (GSN_database->cls,
1316                                   &ztn_msg->zone,
1317                                   &ztn_msg->value_zone,
1318                                   &handle_zone_to_name_it, &ztn_ctx))
1319   {
1320     /* internal error, hang up instead of signalling something
1321        that might be wrong */
1322     GNUNET_break (0);
1323     GNUNET_SERVICE_client_drop (nc->client);
1324     return;
1325   }
1326   if (GNUNET_NO == ztn_ctx.success)
1327   {
1328     /* no result found, send empty response */
1329     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1330                 "Found no result for zone-to-name lookup.\n");
1331     env = GNUNET_MQ_msg (ztnr_msg,
1332                          GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
1333     ztnr_msg->gns_header.r_id = ztn_msg->gns_header.r_id;
1334     ztnr_msg->res = htons (GNUNET_NO);
1335     GNUNET_MQ_send (nc->mq,
1336                     env);
1337   }
1338   GNUNET_SERVICE_client_continue (nc->client);
1339 }
1340
1341
1342 /**
1343  * Context for record remove operations passed from
1344  * #run_zone_iteration_round to #zone_iterate_proc as closure
1345  */
1346 struct ZoneIterationProcResult
1347 {
1348   /**
1349    * The zone iteration handle
1350    */
1351   struct ZoneIteration *zi;
1352
1353   /**
1354    * Number of results left to be returned in this iteration.
1355    */
1356   uint64_t limit;
1357
1358 };
1359
1360
1361 /**
1362  * Process results for zone iteration from database
1363  *
1364  * @param cls struct ZoneIterationProcResult
1365  * @param seq sequence number of the record
1366  * @param zone_key the zone key
1367  * @param name name
1368  * @param rd_count number of records for this name
1369  * @param rd record data
1370  */
1371 static void
1372 zone_iterate_proc (void *cls,
1373                    uint64_t seq,
1374                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1375                    const char *name,
1376                    unsigned int rd_count,
1377                    const struct GNUNET_GNSRECORD_Data *rd)
1378 {
1379   struct ZoneIterationProcResult *proc = cls;
1380   int do_refresh_block;
1381
1382   if ( (NULL == zone_key) &&
1383        (NULL == name) )
1384   {
1385     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1386                 "Iteration done\n");
1387     return;
1388   }
1389   if ( (NULL == zone_key) ||
1390        (NULL == name) )
1391   {
1392     /* what is this!? should never happen */
1393     GNUNET_break (0);
1394     return;
1395   }
1396   if (0 == proc->limit)
1397   {
1398     /* what is this!? should never happen */
1399     GNUNET_break (0);
1400     return;
1401   }
1402   proc->limit--;
1403   proc->zi->seq = seq;
1404   send_lookup_response (proc->zi->nc,
1405                         proc->zi->request_id,
1406                         zone_key,
1407                         name,
1408                         rd_count,
1409                         rd);
1410   do_refresh_block = GNUNET_NO;
1411   for (unsigned int i=0;i<rd_count;i++)
1412     if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
1413     {
1414       do_refresh_block = GNUNET_YES;
1415       break;
1416     }
1417   if (GNUNET_YES == do_refresh_block)
1418     refresh_block (NULL,
1419                    0,
1420                    zone_key,
1421                    name,
1422                    rd_count,
1423                    rd);
1424 }
1425
1426
1427 /**
1428  * Perform the next round of the zone iteration.
1429  *
1430  * @param zi zone iterator to process
1431  * @param limit number of results to return in one pass
1432  */
1433 static void
1434 run_zone_iteration_round (struct ZoneIteration *zi,
1435                           uint64_t limit)
1436 {
1437   struct ZoneIterationProcResult proc;
1438   struct GNUNET_MQ_Envelope *env;
1439   struct RecordResultMessage *rrm;
1440   struct GNUNET_TIME_Absolute start;
1441   struct GNUNET_TIME_Relative duration;
1442
1443   memset (&proc,
1444           0,
1445           sizeof (proc));
1446   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1447               "Asked to return up to %llu records at position %llu\n",
1448               (unsigned long long) limit,
1449               (unsigned long long) zi->seq);
1450   proc.zi = zi;
1451   proc.limit = limit;
1452   start = GNUNET_TIME_absolute_get ();
1453   GNUNET_break (GNUNET_SYSERR !=
1454                 GSN_database->iterate_records (GSN_database->cls,
1455                                                (0 == memcmp (&zi->zone,
1456                                                              &zero,
1457                                                              sizeof (zero)))
1458                                                ? NULL
1459                                                : &zi->zone,
1460                                                zi->seq,
1461                                                limit,
1462                                                &zone_iterate_proc,
1463                                                &proc));
1464   duration = GNUNET_TIME_absolute_get_duration (start);
1465   duration = GNUNET_TIME_relative_divide (duration,
1466                                           limit - proc.limit);
1467   GNUNET_STATISTICS_set (statistics,
1468                          "NAMESTORE iteration delay (μs/record)",
1469                          duration.rel_value_us,
1470                          GNUNET_NO);
1471   if (0 == proc.limit)
1472   {
1473     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1474                 "Returned %llu results, more results available\n",
1475                 (unsigned long long) limit);
1476     return; /* more results later after we get the
1477                #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message */
1478   }
1479   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1480               "Completed iteration after %llu/%llu results\n",
1481               (unsigned long long) (limit - proc.limit),
1482               (unsigned long long) limit);
1483   /* send empty response to indicate end of list */
1484   env = GNUNET_MQ_msg (rrm,
1485                        GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
1486   rrm->gns_header.r_id = htonl (zi->request_id);
1487   GNUNET_MQ_send (zi->nc->mq,
1488                   env);
1489   GNUNET_CONTAINER_DLL_remove (zi->nc->op_head,
1490                                zi->nc->op_tail,
1491                                zi);
1492   GNUNET_free (zi);
1493 }
1494
1495
1496 /**
1497  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START message
1498  *
1499  * @param cls the client sending the message
1500  * @param zis_msg message from the client
1501  */
1502 static void
1503 handle_iteration_start (void *cls,
1504                         const struct ZoneIterationStartMessage *zis_msg)
1505 {
1506   struct NamestoreClient *nc = cls;
1507   struct ZoneIteration *zi;
1508
1509   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1510               "Received ZONE_ITERATION_START message\n");
1511   zi = GNUNET_new (struct ZoneIteration);
1512   zi->request_id = ntohl (zis_msg->gns_header.r_id);
1513   zi->offset = 0;
1514   zi->nc = nc;
1515   zi->zone = zis_msg->zone;
1516
1517   GNUNET_CONTAINER_DLL_insert (nc->op_head,
1518                                nc->op_tail,
1519                                zi);
1520   run_zone_iteration_round (zi,
1521                             1);
1522   GNUNET_SERVICE_client_continue (nc->client);
1523 }
1524
1525
1526 /**
1527  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP message
1528  *
1529  * @param cls the client sending the message
1530  * @param zis_msg message from the client
1531  */
1532 static void
1533 handle_iteration_stop (void *cls,
1534                        const struct ZoneIterationStopMessage *zis_msg)
1535 {
1536   struct NamestoreClient *nc = cls;
1537   struct ZoneIteration *zi;
1538   uint32_t rid;
1539
1540   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1541               "Received ZONE_ITERATION_STOP message\n");
1542   rid = ntohl (zis_msg->gns_header.r_id);
1543   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1544     if (zi->request_id == rid)
1545       break;
1546   if (NULL == zi)
1547   {
1548     GNUNET_break (0);
1549     GNUNET_SERVICE_client_drop (nc->client);
1550     return;
1551   }
1552   GNUNET_CONTAINER_DLL_remove (nc->op_head,
1553                                nc->op_tail,
1554                                zi);
1555   GNUNET_free (zi);
1556   GNUNET_SERVICE_client_continue (nc->client);
1557 }
1558
1559
1560 /**
1561  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT message
1562  *
1563  * @param cls the client sending the message
1564  * @param message message from the client
1565  */
1566 static void
1567 handle_iteration_next (void *cls,
1568                        const struct ZoneIterationNextMessage *zis_msg)
1569 {
1570   struct NamestoreClient *nc = cls;
1571   struct ZoneIteration *zi;
1572   uint32_t rid;
1573   uint64_t limit;
1574
1575   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1576               "Received ZONE_ITERATION_NEXT message\n");
1577   GNUNET_STATISTICS_update (statistics,
1578                             "Iteration NEXT messages received",
1579                             1,
1580                             GNUNET_NO);
1581   rid = ntohl (zis_msg->gns_header.r_id);
1582   limit = GNUNET_ntohll (zis_msg->limit);
1583   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1584     if (zi->request_id == rid)
1585       break;
1586   if (NULL == zi)
1587   {
1588     GNUNET_break (0);
1589     GNUNET_SERVICE_client_drop (nc->client);
1590     return;
1591   }
1592   run_zone_iteration_round (zi,
1593                             limit);
1594   GNUNET_SERVICE_client_continue (nc->client);
1595 }
1596
1597
1598 /**
1599  * Send 'sync' message to zone monitor, we're now in sync.
1600  *
1601  * @param zm monitor that is now in sync
1602  */
1603 static void
1604 monitor_sync (struct ZoneMonitor *zm)
1605 {
1606   struct GNUNET_MQ_Envelope *env;
1607   struct GNUNET_MessageHeader *sync;
1608
1609   env = GNUNET_MQ_msg (sync,
1610                        GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
1611   GNUNET_MQ_send (zm->nc->mq,
1612                   env);
1613 }
1614
1615
1616 /**
1617  * Obtain the next datum during the zone monitor's zone intiial iteration.
1618  *
1619  * @param cls zone monitor that does its initial iteration
1620  */
1621 static void
1622 monitor_next (void *cls);
1623
1624
1625 /**
1626  * A #GNUNET_NAMESTORE_RecordIterator for monitors.
1627  *
1628  * @param cls a 'struct ZoneMonitor *' with information about the monitor
1629  * @param seq sequence number of the record
1630  * @param zone_key zone key of the zone
1631  * @param name name
1632  * @param rd_count number of records in @a rd
1633  * @param rd array of records
1634  */
1635 static void
1636 monitor_iterate_cb (void *cls,
1637                     uint64_t seq,
1638                     const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
1639                     const char *name,
1640                     unsigned int rd_count,
1641                     const struct GNUNET_GNSRECORD_Data *rd)
1642 {
1643   struct ZoneMonitor *zm = cls;
1644
1645   zm->seq = seq;
1646   if (NULL == name)
1647   {
1648     /* finished with iteration */
1649     monitor_sync (zm);
1650     return;
1651   }
1652   GNUNET_STATISTICS_update (statistics,
1653                             "Monitor notifications sent",
1654                             1,
1655                             GNUNET_NO);
1656   send_lookup_response (zm->nc,
1657                         0,
1658                         zone_key,
1659                         name,
1660                         rd_count,
1661                         rd);
1662   zm->task = GNUNET_SCHEDULER_add_now (&monitor_next,
1663                                        zm);
1664 }
1665
1666
1667 /**
1668  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START message
1669  *
1670  * @param cls the client sending the message
1671  * @param message message from the client
1672  */
1673 static void
1674 handle_monitor_start (void *cls,
1675                       const struct ZoneMonitorStartMessage *zis_msg)
1676 {
1677   struct NamestoreClient *nc = cls;
1678   struct ZoneMonitor *zm;
1679
1680   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1681               "Received ZONE_MONITOR_START message\n");
1682   zm = GNUNET_new (struct ZoneMonitor);
1683   zm->nc = nc;
1684   zm->zone = zis_msg->zone;
1685   GNUNET_CONTAINER_DLL_insert (monitor_head,
1686                                monitor_tail,
1687                                zm);
1688   GNUNET_SERVICE_client_mark_monitor (nc->client);
1689   GNUNET_SERVICE_client_disable_continue_warning (nc->client);
1690   GNUNET_notification_context_add (monitor_nc,
1691                                    nc->mq);
1692   if (GNUNET_YES == ntohl (zis_msg->iterate_first))
1693     zm->task = GNUNET_SCHEDULER_add_now (&monitor_next,
1694                                          zm);
1695   else
1696     monitor_sync (zm);
1697 }
1698
1699
1700 /**
1701  * Obtain the next datum during the zone monitor's zone intiial iteration.
1702  *
1703  * @param cls zone monitor that does its initial iteration
1704  */
1705 static void
1706 monitor_next (void *cls)
1707 {
1708   struct ZoneMonitor *zm = cls;
1709   int ret;
1710
1711   zm->task = NULL;
1712   ret = GSN_database->iterate_records (GSN_database->cls,
1713                                        (0 == memcmp (&zm->zone,
1714                                                      &zero,
1715                                                      sizeof (zero)))
1716                                        ? NULL
1717                                        : &zm->zone,
1718                                        zm->seq,
1719                                        1,
1720                                        &monitor_iterate_cb,
1721                                        zm);
1722   if (GNUNET_SYSERR == ret)
1723   {
1724     GNUNET_SERVICE_client_drop (zm->nc->client);
1725     return;
1726   }
1727   if (GNUNET_NO == ret)
1728   {
1729     /* empty zone */
1730     monitor_sync (zm);
1731     return;
1732   }
1733 }
1734
1735
1736 /**
1737  * Process namestore requests.
1738  *
1739  * @param cls closure
1740  * @param cfg configuration to use
1741  * @param service the initialized service
1742  */
1743 static void
1744 run (void *cls,
1745      const struct GNUNET_CONFIGURATION_Handle *cfg,
1746      struct GNUNET_SERVICE_Handle *service)
1747 {
1748   char *database;
1749
1750   (void) cls;
1751   (void) service;
1752   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1753               "Starting namestore service\n");
1754   cache_keys = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1755                                                      "namestore",
1756                                                      "CACHE_KEYS");
1757   disable_namecache = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1758                                                             "namecache",
1759                                                             "DISABLE");
1760   GSN_cfg = cfg;
1761   monitor_nc = GNUNET_notification_context_create (1);
1762   if (GNUNET_YES != disable_namecache)
1763   {
1764     namecache = GNUNET_NAMECACHE_connect (cfg);
1765     GNUNET_assert (NULL != namecache);
1766   }
1767   /* Loading database plugin */
1768   if (GNUNET_OK !=
1769       GNUNET_CONFIGURATION_get_value_string (cfg,
1770                                              "namestore",
1771                                              "database",
1772                                              &database))
1773     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1774                 "No database backend configured\n");
1775
1776   GNUNET_asprintf (&db_lib_name,
1777                    "libgnunet_plugin_namestore_%s",
1778                    database);
1779   GSN_database = GNUNET_PLUGIN_load (db_lib_name,
1780                                      (void *) GSN_cfg);
1781   GNUNET_free (database);
1782   statistics = GNUNET_STATISTICS_create ("namestore",
1783                                          cfg);
1784   GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
1785                                  NULL);
1786   if (NULL == GSN_database)
1787   {
1788     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1789                 "Could not load database backend `%s'\n",
1790                 db_lib_name);
1791     GNUNET_SCHEDULER_shutdown ();
1792     return;
1793   }
1794 }
1795
1796
1797 /**
1798  * Define "main" method using service macro.
1799  */
1800 GNUNET_SERVICE_MAIN
1801 ("namestore",
1802  GNUNET_SERVICE_OPTION_NONE,
1803  &run,
1804  &client_connect_cb,
1805  &client_disconnect_cb,
1806  NULL,
1807  GNUNET_MQ_hd_var_size (record_store,
1808                         GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE,
1809                         struct RecordStoreMessage,
1810                         NULL),
1811  GNUNET_MQ_hd_var_size (record_lookup,
1812                         GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_LOOKUP,
1813                         struct LabelLookupMessage,
1814                         NULL),
1815  GNUNET_MQ_hd_fixed_size (zone_to_name,
1816                           GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME,
1817                           struct ZoneToNameMessage,
1818                           NULL),
1819  GNUNET_MQ_hd_fixed_size (iteration_start,
1820                           GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START,
1821                           struct ZoneIterationStartMessage,
1822                           NULL),
1823  GNUNET_MQ_hd_fixed_size (iteration_next,
1824                           GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT,
1825                           struct ZoneIterationNextMessage,
1826                           NULL),
1827  GNUNET_MQ_hd_fixed_size (iteration_stop,
1828                           GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP,
1829                           struct ZoneIterationStopMessage,
1830                           NULL),
1831  GNUNET_MQ_hd_fixed_size (monitor_start,
1832                           GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START,
1833                           struct ZoneMonitorStartMessage,
1834                           NULL),
1835  GNUNET_MQ_handler_end ());
1836
1837
1838 /* end of gnunet-service-namestore.c */