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