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