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