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