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