-documenting open issues
[oweals/gnunet.git] / src / namestore / gnunet-service-namestore.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012, 2013 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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, 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  * TODO:
28  * - private records can currently not be used for resolving
29  *   our own queries as our lookup only goes for the encrypted
30  *   records; we need a way to ensure that the records available
31  *   in our own zone can actually always be used for our own
32  *   resolutions!
33  */
34 #include "platform.h"
35 #include "gnunet_util_lib.h"
36 #include "gnunet_dnsparser_lib.h"
37 #include "gnunet_namestore_service.h"
38 #include "gnunet_namestore_plugin.h"
39 #include "gnunet_signatures.h"
40 #include "namestore.h"
41
42 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
43
44
45 /**
46  * A namestore client
47  */
48 struct NamestoreClient;
49
50
51 /**
52  * A namestore iteration operation.
53  */
54 struct ZoneIteration
55 {
56   /**
57    * Next element in the DLL
58    */
59   struct ZoneIteration *next;
60
61   /**
62    * Previous element in the DLL
63    */
64   struct ZoneIteration *prev;
65
66   /**
67    * Namestore client which intiated this zone iteration
68    */
69   struct NamestoreClient *client;
70
71   /**
72    * Key of the zone we are iterating over.
73    */
74   struct GNUNET_CRYPTO_EccPrivateKey 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_EccPrivateKey zone;
151
152   /**
153    * The operation id fot the zone iteration in the response for the client
154    */
155   uint32_t request_id;
156
157   /**
158    * Task active during initial iteration.
159    */
160   GNUNET_SCHEDULER_TaskIdentifier task;
161
162   /**
163    * Offset of the zone iteration used to address next result of the zone
164    * iteration in the store
165    *
166    * Initialy set to 0 in handle_iteration_start
167    * Incremented with by every call to handle_iteration_next
168    */
169   uint32_t offset;
170
171 };
172
173
174 /**
175  * Configuration handle.
176  */
177 static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
178
179 /**
180  * Database handle
181  */
182 static struct GNUNET_NAMESTORE_PluginFunctions *GSN_database;
183
184 /**
185  * Name of the database plugin
186  */
187 static char *db_lib_name;
188
189 /**
190  * Our notification context.
191  */
192 static struct GNUNET_SERVER_NotificationContext *snc;
193
194 /**
195  * Head of the Client DLL
196  */
197 static struct NamestoreClient *client_head;
198
199 /**
200  * Tail of the Client DLL
201  */
202 static struct NamestoreClient *client_tail;
203
204 /**
205  * First active zone monitor.
206  */
207 static struct ZoneMonitor *monitor_head;
208
209 /**
210  * Last active zone monitor.
211  */
212 static struct ZoneMonitor *monitor_tail;
213
214 /**
215  * Notification context shared by all monitors.
216  */
217 static struct GNUNET_SERVER_NotificationContext *monitor_nc;
218
219
220
221 /**
222  * Task run during shutdown.
223  *
224  * @param cls unused
225  * @param tc unused
226  */
227 static void
228 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
229 {
230   struct ZoneIteration *no;
231   struct NamestoreClient *nc;
232
233   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234               "Stopping namestore service\n");
235   if (NULL != snc)
236   {
237     GNUNET_SERVER_notification_context_destroy (snc);
238     snc = NULL;
239   }
240   while (NULL != (nc = client_head))
241   {
242     while (NULL != (no = nc->op_head))
243     {
244       GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
245       GNUNET_free (no);
246     }
247     GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
248     GNUNET_free (nc);
249   }
250   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, GSN_database));
251   GNUNET_free (db_lib_name);
252   db_lib_name = NULL;
253   if (NULL != monitor_nc)
254   {
255     GNUNET_SERVER_notification_context_destroy (monitor_nc);
256     monitor_nc = NULL;
257   }
258 }
259
260
261 /**
262  * Called whenever a client is disconnected.
263  * Frees our resources associated with that client.
264  *
265  * @param cls closure
266  * @param client identification of the client
267  */
268 static void
269 client_disconnect_notification (void *cls, 
270                                 struct GNUNET_SERVER_Client *client)
271 {
272   struct ZoneIteration *no;
273   struct NamestoreClient *nc;
274   struct ZoneMonitor *zm;
275
276   if (NULL == client)
277     return;
278   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
279               "Client %p disconnected\n", 
280               client);
281   if (NULL == (nc = GNUNET_SERVER_client_get_user_context (client, struct NamestoreClient)))
282     return;
283   while (NULL != (no = nc->op_head))
284   {
285     GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, no);
286     GNUNET_free (no);
287   }
288   GNUNET_CONTAINER_DLL_remove (client_head, client_tail, nc);
289   GNUNET_free (nc);
290   for (zm = monitor_head; NULL != zm; zm = zm->next)
291   {
292     if (client == zm->nc->client)
293     {
294       GNUNET_CONTAINER_DLL_remove (monitor_head,
295                                    monitor_tail,
296                                    zm);
297       if (GNUNET_SCHEDULER_NO_TASK != zm->task)
298       {
299         GNUNET_SCHEDULER_cancel (zm->task);
300         zm->task = GNUNET_SCHEDULER_NO_TASK;
301       }
302       GNUNET_free (zm);
303       break;
304     }
305   }
306 }
307
308
309 /**
310  * Add a client to our list of active clients, if it is not yet
311  * in there.
312  *
313  * @param client client to add
314  * @return internal namestore client structure for this client
315  */
316 static struct NamestoreClient *
317 client_lookup (struct GNUNET_SERVER_Client *client)
318 {
319   struct NamestoreClient *nc;
320
321   nc = GNUNET_SERVER_client_get_user_context (client, struct NamestoreClient);
322   if (NULL != nc)
323     return nc;
324   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
325               "Client %p connected\n",
326               client);
327   nc = GNUNET_new (struct NamestoreClient);
328   nc->client = client;
329   GNUNET_SERVER_notification_context_add (snc, client);
330   GNUNET_CONTAINER_DLL_insert (client_head, client_tail, nc);
331   GNUNET_SERVER_client_set_user_context (client, nc);
332   return nc;
333 }
334
335
336 /**
337  * Context for name lookups passed from 'handle_lookup_name' to
338  * 'handle_lookup_name_it' as closure
339  */
340 struct LookupNameContext
341 {
342   /**
343    * The client to send the response to
344    */
345   struct NamestoreClient *nc;
346
347   /**
348    * Operation id for the name lookup
349    */
350   uint32_t request_id;
351
352 };
353
354
355 /**
356  * A #GNUNET_NAMESTORE_BlockCallback for name lookups in #handle_lookup_name
357  *
358  * @param cls a 'struct LookupNameContext *' with information about the request
359  * @param block the block
360  */
361 static void
362 handle_lookup_block_it (void *cls,
363                         const struct GNUNET_NAMESTORE_Block *block)
364 {
365   struct LookupNameContext *lnc = cls;
366   struct LookupBlockResponseMessage *r;
367   size_t esize;
368
369   esize = ntohl (block->purpose.size)
370     - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) 
371     - sizeof (struct GNUNET_TIME_AbsoluteNBO);
372   r = GNUNET_malloc (sizeof (struct LookupBlockResponseMessage) + esize);
373   r->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK_RESPONSE);
374   r->gns_header.header.size = htons (sizeof (struct LookupBlockResponseMessage) + esize);
375   r->gns_header.r_id = htonl (lnc->request_id);
376   r->expire = block->expiration_time;
377   r->signature = block->signature;
378   r->derived_key = block->derived_key;  
379   memcpy (&r[1], &block[1], esize);
380   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
381               "Sending `%s' message\n", 
382               "NAMESTORE_LOOKUP_NAME_RESPONSE");
383   GNUNET_SERVER_notification_context_unicast (snc, 
384                                               lnc->nc->client, 
385                                               &r->gns_header.header, 
386                                               GNUNET_NO);
387   GNUNET_free (r);
388 }
389
390
391 /**
392  * Handles a #GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK message
393  *
394  * @param cls unused
395  * @param client client sending the message
396  * @param message message of type 'struct LookupNameMessage'
397  */
398 static void
399 handle_lookup_block (void *cls,
400                     struct GNUNET_SERVER_Client *client,
401                     const struct GNUNET_MessageHeader *message)
402 {
403   const struct LookupBlockMessage *ln_msg;
404   struct LookupNameContext lnc;
405   struct NamestoreClient *nc;
406   struct LookupBlockResponseMessage zir_end;
407   int ret;
408
409   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
410               "Received `%s' message\n", 
411               "NAMESTORE_LOOKUP_NAME");
412   nc = client_lookup(client);
413   ln_msg = (const struct LookupBlockMessage *) message;
414   lnc.request_id = ntohl (ln_msg->gns_header.r_id);
415   lnc.nc = nc;
416   if (GNUNET_SYSERR ==
417       (ret = GSN_database->lookup_block (GSN_database->cls, 
418                                          &ln_msg->query,
419                                          &handle_lookup_block_it, &lnc)))
420   {
421     /* internal error (in database plugin); might be best to just hang up on
422        plugin rather than to signal that there are 'no' results, which 
423        might also be false... */
424     GNUNET_break (0); 
425     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
426     return;
427   }  
428   if (0 == ret)
429   {
430     /* no records match at all, generate empty response */
431     memset (&zir_end, 0, sizeof (zir_end));
432     zir_end.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK_RESPONSE);
433     zir_end.gns_header.header.size = htons (sizeof (struct LookupBlockResponseMessage));
434     zir_end.gns_header.r_id = ln_msg->gns_header.r_id;
435     GNUNET_SERVER_notification_context_unicast (snc, 
436                                                 client, 
437                                                 &zir_end.gns_header.header, 
438                                                 GNUNET_NO);
439
440   }
441   GNUNET_SERVER_receive_done (client, GNUNET_OK);
442 }
443
444
445 /**
446  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE' message
447  *
448  * @param cls unused
449  * @param client GNUNET_SERVER_Client sending the message
450  * @param message message of type 'struct BlockCacheMessage'
451  */
452 static void
453 handle_block_cache (void *cls,
454                      struct GNUNET_SERVER_Client *client,
455                      const struct GNUNET_MessageHeader *message)
456 {
457   struct NamestoreClient *nc;
458   const struct BlockCacheMessage *rp_msg;  
459   struct BlockCacheResponseMessage rpr_msg;
460   struct GNUNET_NAMESTORE_Block *block;
461   size_t esize;
462   int res;
463
464   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
465               "Received `%s' message\n",
466               "NAMESTORE_BLOCK_CACHE");
467   nc = client_lookup (client);
468   if (ntohs (message->size) < sizeof (struct BlockCacheMessage))
469   {
470     GNUNET_break (0);
471     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
472     return;
473   }
474   rp_msg = (const struct BlockCacheMessage *) message;
475   esize = ntohs (rp_msg->gns_header.header.size) - sizeof (struct BlockCacheMessage);
476
477   block = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Block) + esize);
478   block->signature = rp_msg->signature;
479   block->derived_key = rp_msg->derived_key;
480   block->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
481                                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
482                                esize);
483   block->expiration_time = rp_msg->expire;
484   memcpy (&block[1], &rp_msg[1], esize);
485   res = GSN_database->cache_block (GSN_database->cls,
486                                    block);
487   GNUNET_free (block);
488
489   rpr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE_RESPONSE);
490   rpr_msg.gns_header.header.size = htons (sizeof (struct BlockCacheResponseMessage));
491   rpr_msg.gns_header.r_id = rp_msg->gns_header.r_id;
492   rpr_msg.op_result = htonl (res);
493   GNUNET_SERVER_notification_context_unicast (snc, 
494                                               nc->client, 
495                                               &rpr_msg.gns_header.header, 
496                                               GNUNET_NO);
497   GNUNET_SERVER_receive_done (client, GNUNET_OK);
498 }
499
500
501 /**
502  * Generate a 'struct LookupNameResponseMessage' and send it to the
503  * given client using the given notification context.
504  *
505  * @param nc notification context to use
506  * @param client client to unicast to
507  * @param request_id request ID to use
508  * @param zone_key zone key of the zone
509  * @param name name
510  * @param rd_count number of records
511  * @param rd array of records
512  */
513 static void
514 send_lookup_response (struct GNUNET_SERVER_NotificationContext *nc,                     
515                       struct GNUNET_SERVER_Client *client,
516                       uint32_t request_id,
517                       const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
518                       const char *name,
519                       unsigned int rd_count,
520                       const struct GNUNET_NAMESTORE_RecordData *rd)
521 {
522   struct RecordResultMessage *zir_msg;
523   size_t name_len;
524   size_t rd_ser_len;
525   size_t msg_size;
526   char *name_tmp;
527   char *rd_ser;
528
529   name_len = strlen (name) + 1;
530   rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);  
531   msg_size = sizeof (struct RecordResultMessage) + name_len + rd_ser_len;
532
533   zir_msg = GNUNET_malloc (msg_size);
534   zir_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
535   zir_msg->gns_header.header.size = htons (msg_size);
536   zir_msg->gns_header.r_id = htonl (request_id);
537   zir_msg->name_len = htons (name_len);
538   zir_msg->rd_count = htons (rd_count);
539   zir_msg->rd_len = htons (rd_ser_len);
540   zir_msg->private_key = *zone_key;
541   name_tmp = (char *) &zir_msg[1];
542   memcpy (name_tmp, name, name_len);
543   rd_ser = &name_tmp[name_len];
544   GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser);
545   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
546               "Sending `%s' message with size %u\n", 
547               "RECORD_RESULT",
548               msg_size);
549   GNUNET_SERVER_notification_context_unicast (nc,
550                                               client, 
551                                               &zir_msg->gns_header.header,
552                                               GNUNET_NO);
553   GNUNET_free (zir_msg);
554 }
555
556
557 /**
558  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE' message
559  *
560  * @param cls unused
561  * @param client client sending the message
562  * @param message message of type 'struct RecordCreateMessage'
563  */
564 static void
565 handle_record_store (void *cls,
566                       struct GNUNET_SERVER_Client *client,
567                       const struct GNUNET_MessageHeader *message)
568 {
569   struct NamestoreClient *nc;
570   const struct RecordStoreMessage *rp_msg;
571   struct RecordStoreResponseMessage rcr_msg;
572   size_t name_len;
573   size_t msg_size;
574   size_t msg_size_exp;
575   size_t rd_ser_len;
576   uint32_t rid;
577   const char *name_tmp;
578   char *conv_name;
579   const char *rd_ser;
580   unsigned int rd_count;
581   int res;
582   struct GNUNET_CRYPTO_EccPublicKey pubkey;
583
584   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
585               "Received `%s' message\n", 
586               "NAMESTORE_RECORD_STORE");
587   if (ntohs (message->size) < sizeof (struct RecordStoreMessage))
588   {
589     GNUNET_break (0);
590     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
591     return;
592   }
593   nc = client_lookup (client);
594   rp_msg = (const struct RecordStoreMessage *) message;
595   rid = ntohl (rp_msg->gns_header.r_id);
596   name_len = ntohs (rp_msg->name_len);
597   msg_size = ntohs (message->size);
598   rd_count = ntohs (rp_msg->rd_count);
599   rd_ser_len = ntohs (rp_msg->rd_len);
600   GNUNET_break (0 == ntohs (rp_msg->reserved));
601   msg_size_exp = sizeof (struct RecordStoreMessage) + name_len + rd_ser_len;
602   if (msg_size != msg_size_exp)
603   {
604     GNUNET_break (0);
605     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
606     return;
607   }
608   if ((0 == name_len) || (name_len > MAX_NAME_LEN))
609   {
610     GNUNET_break (0);
611     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
612     return;
613   }
614   name_tmp = (const char *) &rp_msg[1];
615   rd_ser = &name_tmp[name_len];
616   if ('\0' != name_tmp[name_len -1])
617   {
618     GNUNET_break (0);
619     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
620     return;
621   }
622   {
623     struct GNUNET_NAMESTORE_RecordData rd[rd_count];
624
625     if (GNUNET_OK !=
626         GNUNET_NAMESTORE_records_deserialize (rd_ser_len, rd_ser, rd_count, rd))
627     {
628       GNUNET_break (0);
629       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
630       return;
631     }
632
633     /* Extracting and converting private key */
634     GNUNET_CRYPTO_ecc_key_get_public (&rp_msg->private_key,
635                                       &pubkey);
636     conv_name = GNUNET_NAMESTORE_normalize_string (name_tmp);
637     if (NULL == conv_name)
638     {
639       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
640                   "Error converting name `%s'\n", name_tmp);
641       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
642       return;
643     }
644     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
645                 "Creating %u records for name `%s' in zone `%s'\n",
646                 (unsigned int) rd_count,
647                 conv_name,
648                 GNUNET_NAMESTORE_z2s (&pubkey));
649     res = GSN_database->store_records (GSN_database->cls,
650                                        &rp_msg->private_key,
651                                        conv_name,                                      
652                                        rd_count, rd);
653     if (GNUNET_OK == res)
654     {
655       struct ZoneMonitor *zm;
656       
657       for (zm = monitor_head; NULL != zm; zm = zm->next)    
658         if (0 == memcmp (&rp_msg->private_key,
659                          &zm->zone, 
660                          sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
661           send_lookup_response (monitor_nc,
662                                 zm->nc->client,
663                                 zm->request_id,
664                                 &rp_msg->private_key,
665                                 conv_name,
666                                 rd_count, rd);      
667     }    
668     GNUNET_free (conv_name);
669   }
670   
671   /* Send response */
672   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
673               "Sending `%s' message\n", 
674               "RECORD_STORE_RESPONSE");
675   rcr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE);
676   rcr_msg.gns_header.header.size = htons (sizeof (struct RecordStoreResponseMessage));
677   rcr_msg.gns_header.r_id = htonl (rid);
678   rcr_msg.op_result = htonl (res);
679   GNUNET_SERVER_notification_context_unicast (snc, nc->client,
680                                               &rcr_msg.gns_header.header,
681                                               GNUNET_NO);
682   GNUNET_SERVER_receive_done (client, GNUNET_OK);
683 }
684
685
686 /**
687  * Context for record remove operations passed from 'handle_zone_to_name' to
688  * 'handle_zone_to_name_it' as closure
689  */
690 struct ZoneToNameCtx
691 {
692   /**
693    * Namestore client
694    */
695   struct NamestoreClient *nc;
696
697   /**
698    * Request id (to be used in the response to the client).
699    */
700   uint32_t rid;
701
702   /**
703    * Set to GNUNET_OK on success, GNUNET_SYSERR on error.  Note that
704    * not finding a name for the zone still counts as a 'success' here,
705    * as this field is about the success of executing the IPC protocol.
706    */
707   int success;
708 };
709
710
711 /**
712  * Zone to name iterator
713  *
714  * @param cls struct ZoneToNameCtx *
715  * @param zone_key the zone key
716  * @param name name
717  * @param rd_count number of records
718  * @param rd record data
719  */
720 static void
721 handle_zone_to_name_it (void *cls,
722                         const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
723                         const char *name,
724                         unsigned int rd_count,
725                         const struct GNUNET_NAMESTORE_RecordData *rd)
726 {
727   struct ZoneToNameCtx *ztn_ctx = cls;
728   struct ZoneToNameResponseMessage *ztnr_msg;
729   int16_t res;
730   size_t name_len;
731   size_t rd_ser_len;
732   size_t msg_size;
733   char *name_tmp;
734   char *rd_tmp;
735
736   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
737               "Found result for zone-to-name lookup: `%s'\n", 
738               name);
739   res = GNUNET_YES;
740   name_len = strlen (name) + 1;
741   rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
742   msg_size = sizeof (struct ZoneToNameResponseMessage) + name_len + rd_ser_len;
743   if (msg_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
744   {
745     GNUNET_break (0);
746     ztn_ctx->success = GNUNET_SYSERR;
747     return;
748   }
749   ztnr_msg = GNUNET_malloc (msg_size);
750   ztnr_msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
751   ztnr_msg->gns_header.header.size = htons (msg_size);
752   ztnr_msg->gns_header.r_id = htonl (ztn_ctx->rid);
753   ztnr_msg->res = htons (res);
754   ztnr_msg->rd_len = htons (rd_ser_len);
755   ztnr_msg->rd_count = htons (rd_count);
756   ztnr_msg->name_len = htons (name_len);
757   ztnr_msg->zone = *zone_key;
758   name_tmp = (char *) &ztnr_msg[1];
759   if (NULL != name)
760     memcpy (name_tmp, name, name_len);
761   rd_tmp = &name_tmp[name_len];
762   GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_tmp);
763   ztn_ctx->success = GNUNET_OK;
764   GNUNET_SERVER_notification_context_unicast (snc, ztn_ctx->nc->client,
765                                               &ztnr_msg->gns_header.header,
766                                               GNUNET_NO);
767   GNUNET_free (ztnr_msg);
768 }
769
770
771 /**
772  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME' message
773  *
774  * @param cls unused
775  * @param client GNUNET_SERVER_Client sending the message
776  * @param message message of type 'struct ZoneToNameMessage'
777  */
778 static void
779 handle_zone_to_name (void *cls,
780                      struct GNUNET_SERVER_Client *client,
781                      const struct GNUNET_MessageHeader *message)
782 {
783   struct NamestoreClient *nc;
784   const struct ZoneToNameMessage *ztn_msg;
785   struct ZoneToNameCtx ztn_ctx;
786   struct ZoneToNameResponseMessage ztnr_msg;
787
788   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
789               "Received `%s' message\n",
790               "ZONE_TO_NAME");
791   ztn_msg = (const struct ZoneToNameMessage *) message;
792   nc = client_lookup (client);
793   ztn_ctx.rid = ntohl (ztn_msg->gns_header.r_id);
794   ztn_ctx.nc = nc;
795   ztn_ctx.success = GNUNET_NO;
796   if (GNUNET_SYSERR ==
797       GSN_database->zone_to_name (GSN_database->cls, 
798                                   &ztn_msg->zone,
799                                   &ztn_msg->value_zone,
800                                   &handle_zone_to_name_it, &ztn_ctx))
801   {
802     /* internal error, hang up instead of signalling something
803        that might be wrong */
804     GNUNET_break (0);
805     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
806     return;    
807   }
808   if (GNUNET_NO == ztn_ctx.success)
809   {
810     /* no result found, send empty response */
811     memset (&ztnr_msg, 0, sizeof (ztnr_msg));
812     ztnr_msg.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME_RESPONSE);
813     ztnr_msg.gns_header.header.size = htons (sizeof (ztnr_msg));
814     ztnr_msg.gns_header.r_id = ztn_msg->gns_header.r_id;
815     ztnr_msg.res = htons (GNUNET_NO);
816     GNUNET_SERVER_notification_context_unicast (snc,
817                                                 client,
818                                                 &ztnr_msg.gns_header.header,
819                                                 GNUNET_NO);
820   }
821   GNUNET_SERVER_receive_done (client, ztn_ctx.success);
822 }
823
824
825 /**
826  * Zone iteration processor result
827  */
828 enum ZoneIterationResult
829 {
830   /**
831    * Iteration start.
832    */
833   IT_START = 0,
834
835   /**
836    * Found records,
837    * Continue to iterate with next iteration_next call
838    */
839   IT_SUCCESS_MORE_AVAILABLE = 1,
840
841   /**
842    * Iteration complete
843    */
844   IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2
845 };
846
847
848 /**
849  * Context for record remove operations passed from
850  * 'run_zone_iteration_round' to 'zone_iteraterate_proc' as closure
851  */
852 struct ZoneIterationProcResult
853 {
854   /**
855    * The zone iteration handle
856    */
857   struct ZoneIteration *zi;
858
859   /**
860    * Iteration result: iteration done?
861    * IT_SUCCESS_MORE_AVAILABLE:  if there may be more results overall but
862    * we got one for now and have sent it to the client
863    * IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
864    * IT_ALL_RECORDS_FILTERED: if all results were filtered so far.
865    */
866   int res_iteration_finished;
867
868 };
869
870
871 /**
872  * Process results for zone iteration from database
873  *
874  * @param cls struct ZoneIterationProcResult *proc
875  * @param zone_key the zone key
876  * @param expire expiration time
877  * @param name name
878  * @param rd_count number of records for this name
879  * @param rd record data
880  * @param signature block signature
881  */
882 static void
883 zone_iteraterate_proc (void *cls,
884                        const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
885                        const char *name,
886                        unsigned int rd_count,
887                        const struct GNUNET_NAMESTORE_RecordData *rd)
888 {
889   struct ZoneIterationProcResult *proc = cls;
890
891   if ((NULL == zone_key) && (NULL == name))
892   {
893     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
894                 "Iteration done\n");
895     proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
896     return;
897   }
898   if ((NULL == zone_key) || (NULL == name)) 
899   {
900     /* what is this!? should never happen */
901     proc->res_iteration_finished = IT_START;
902     GNUNET_break (0);
903     return;    
904   }
905   proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
906   send_lookup_response (snc,
907                         proc->zi->client->client,
908                         proc->zi->request_id,
909                         zone_key,
910                         name,
911                         rd_count,
912                         rd);
913 }
914
915
916 /**
917  * Perform the next round of the zone iteration.
918  *
919  * @param zi zone iterator to process
920  */
921 static void
922 run_zone_iteration_round (struct ZoneIteration *zi)
923 {
924   struct ZoneIterationProcResult proc;
925   struct RecordResultMessage rrm;
926   int ret;
927
928   memset (&proc, 0, sizeof (proc));
929   proc.zi = zi;
930   proc.res_iteration_finished = IT_START;
931   while (IT_START == proc.res_iteration_finished)
932   {
933     if (GNUNET_SYSERR ==
934         (ret = GSN_database->iterate_records (GSN_database->cls, 
935                                               &zi->zone, 
936                                               zi->offset, 
937                                               &zone_iteraterate_proc, &proc)))
938     {
939       GNUNET_break (0);
940       break;
941     }
942     if (GNUNET_NO == ret)
943       proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
944     zi->offset++;
945   }
946   if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
947   {
948     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
949                 "More results available\n");
950     return; /* more results later */
951   }
952   /* send empty response to indicate end of list */
953   memset (&rrm, 0, sizeof (rrm));
954   rrm.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT);
955   rrm.gns_header.header.size = htons (sizeof (rrm));
956   rrm.gns_header.r_id = htonl (zi->request_id);
957   GNUNET_SERVER_notification_context_unicast (snc,
958                                               zi->client->client, 
959                                               &rrm.gns_header.header,
960                                               GNUNET_NO);
961   GNUNET_CONTAINER_DLL_remove (zi->client->op_head, 
962                                zi->client->op_tail,
963                                zi);
964   GNUNET_free (zi);
965 }
966
967
968 /**
969  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START' message
970  *
971  * @param cls unused
972  * @param client GNUNET_SERVER_Client sending the message
973  * @param message message of type 'struct ZoneIterationStartMessage'
974  */
975 static void
976 handle_iteration_start (void *cls,
977                         struct GNUNET_SERVER_Client *client,
978                         const struct GNUNET_MessageHeader *message)
979 {
980   const struct ZoneIterationStartMessage *zis_msg;
981   struct NamestoreClient *nc;
982   struct ZoneIteration *zi;
983
984   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_START");
985   if (NULL == (nc = client_lookup (client)))
986   {
987     GNUNET_break (0);
988     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
989     return;
990   }
991   zis_msg = (const struct ZoneIterationStartMessage *) message;
992   zi = GNUNET_new (struct ZoneIteration);
993   zi->request_id = ntohl (zis_msg->gns_header.r_id);
994   zi->offset = 0;
995   zi->client = nc;
996   zi->zone = zis_msg->zone;
997   GNUNET_CONTAINER_DLL_insert (nc->op_head, nc->op_tail, zi);
998   run_zone_iteration_round (zi);
999   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1000 }
1001
1002
1003 /**
1004  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP' message
1005  *
1006  * @param cls unused
1007  * @param client GNUNET_SERVER_Client sending the message
1008  * @param message message of type 'struct ZoneIterationStopMessage'
1009  */
1010 static void
1011 handle_iteration_stop (void *cls,
1012                        struct GNUNET_SERVER_Client *client,
1013                        const struct GNUNET_MessageHeader *message)
1014 {
1015   struct NamestoreClient *nc;
1016   struct ZoneIteration *zi;
1017   const struct ZoneIterationStopMessage *zis_msg;
1018   uint32_t rid;
1019
1020   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1021               "Received `%s' message\n",
1022               "ZONE_ITERATION_STOP");
1023   if (NULL == (nc = client_lookup(client)))
1024   {
1025     GNUNET_break (0);
1026     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1027     return;
1028   }
1029   zis_msg = (const struct ZoneIterationStopMessage *) message;
1030   rid = ntohl (zis_msg->gns_header.r_id);
1031   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1032     if (zi->request_id == rid)
1033       break;
1034   if (NULL == zi)
1035   {
1036     GNUNET_break (0);
1037     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1038     return;
1039   }
1040   GNUNET_CONTAINER_DLL_remove (nc->op_head, nc->op_tail, zi);
1041   GNUNET_free (zi);
1042   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1043 }
1044
1045
1046 /**
1047  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT' message
1048  *
1049  * @param cls unused
1050  * @param client GNUNET_SERVER_Client sending the message
1051  * @param message message of type 'struct ZoneIterationNextMessage'
1052  */
1053 static void
1054 handle_iteration_next (void *cls,
1055                        struct GNUNET_SERVER_Client *client,
1056                        const struct GNUNET_MessageHeader *message)
1057 {
1058   struct NamestoreClient *nc;
1059   struct ZoneIteration *zi;
1060   const struct ZoneIterationNextMessage *zis_msg;
1061   uint32_t rid;
1062
1063   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "ZONE_ITERATION_NEXT");
1064   if (NULL == (nc = client_lookup(client)))
1065   {
1066     GNUNET_break (0);
1067     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1068     return;
1069   }
1070   zis_msg = (const struct ZoneIterationNextMessage *) message;
1071   rid = ntohl (zis_msg->gns_header.r_id);
1072   for (zi = nc->op_head; NULL != zi; zi = zi->next)
1073     if (zi->request_id == rid)
1074       break;
1075   if (NULL == zi)
1076   {
1077     GNUNET_break (0);
1078     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1079     return;
1080   }
1081   run_zone_iteration_round (zi);
1082   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1083 }
1084
1085
1086 /**
1087  * Send 'sync' message to zone monitor, we're now in sync.
1088  *
1089  * @param zm monitor that is now in sync
1090  */ 
1091 static void
1092 monitor_sync (struct ZoneMonitor *zm)
1093 {
1094   struct GNUNET_MessageHeader sync;
1095
1096   sync.size = htons (sizeof (struct GNUNET_MessageHeader));
1097   sync.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC);
1098   GNUNET_SERVER_notification_context_unicast (monitor_nc,
1099                                               zm->nc->client,
1100                                               &sync,
1101                                               GNUNET_NO);
1102 }
1103
1104
1105 /**
1106  * Obtain the next datum during the zone monitor's zone intiial iteration.
1107  *
1108  * @param cls zone monitor that does its initial iteration
1109  * @param tc scheduler context
1110  */
1111 static void
1112 monitor_next (void *cls,
1113               const struct GNUNET_SCHEDULER_TaskContext *tc);
1114
1115
1116 /**
1117  * A 'GNUNET_NAMESTORE_RecordIterator' for monitors.
1118  *
1119  * @param cls a 'struct ZoneMonitor *' with information about the monitor
1120  * @param zone_key zone key of the zone
1121  * @param expire expiration time
1122  * @param name name
1123  * @param rd_count number of records
1124  * @param rd array of records
1125  * @param signature signature
1126  */
1127 static void
1128 monitor_iterate_cb (void *cls,
1129                     const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
1130                     const char *name,
1131                     unsigned int rd_count,
1132                     const struct GNUNET_NAMESTORE_RecordData *rd)
1133 {
1134   struct ZoneMonitor *zm = cls;
1135
1136   if (NULL == name)
1137   {
1138     /* finished with iteration */
1139     monitor_sync (zm);
1140     return;
1141   }
1142   send_lookup_response (monitor_nc,
1143                         zm->nc->client,
1144                         zm->request_id,
1145                         zone_key,
1146                         name,
1147                         rd_count,
1148                         rd);
1149   zm->task = GNUNET_SCHEDULER_add_now (&monitor_next, zm);
1150 }
1151
1152
1153 /**
1154  * Handles a 'GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START' message
1155  *
1156  * @param cls unused
1157  * @param client GNUNET_SERVER_Client sending the message
1158  * @param message message of type 'struct ZoneMonitorStartMessage'
1159  */
1160 static void
1161 handle_monitor_start (void *cls,
1162                       struct GNUNET_SERVER_Client *client,
1163                       const struct GNUNET_MessageHeader *message)
1164 {
1165   const struct ZoneMonitorStartMessage *zis_msg;
1166   struct ZoneMonitor *zm;
1167   
1168   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1169               "Received `%s' message\n",
1170               "ZONE_MONITOR_START");
1171   zis_msg = (const struct ZoneMonitorStartMessage *) message;
1172   zm = GNUNET_new (struct ZoneMonitor);
1173   zm->request_id = ntohl (zis_msg->gns_header.r_id);
1174   zm->offset = 0;
1175   zm->nc = client_lookup (client);
1176   zm->zone = zis_msg->zone;
1177   GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, zm);
1178   GNUNET_SERVER_client_mark_monitor (client);
1179   GNUNET_SERVER_disable_receive_done_warning (client);
1180   GNUNET_SERVER_notification_context_add (monitor_nc,
1181                                           client);
1182   zm->task = GNUNET_SCHEDULER_add_now (&monitor_next, zm);  
1183 }
1184
1185
1186 /**
1187  * Obtain the next datum during the zone monitor's zone intiial iteration.
1188  *
1189  * @param cls zone monitor that does its initial iteration
1190  * @param tc scheduler context
1191  */
1192 static void
1193 monitor_next (void *cls,
1194               const struct GNUNET_SCHEDULER_TaskContext *tc)
1195 {
1196   struct ZoneMonitor *zm = cls;
1197   int ret;
1198   
1199   zm->task = GNUNET_SCHEDULER_NO_TASK;
1200   ret = GSN_database->iterate_records (GSN_database->cls,
1201                                        &zm->zone,
1202                                        zm->offset++,
1203                                        &monitor_iterate_cb, zm);
1204   if (GNUNET_SYSERR == ret)
1205   {
1206     GNUNET_SERVER_client_disconnect (zm->nc->client);
1207     return;
1208   }
1209   if (GNUNET_NO == ret)
1210   {
1211     /* empty zone */
1212     monitor_sync (zm);
1213     return;
1214   }
1215 }
1216
1217
1218 /**
1219  * Process namestore requests.
1220  *
1221  * @param cls closure
1222  * @param server the initialized server
1223  * @param cfg configuration to use
1224  */
1225 static void
1226 run (void *cls, struct GNUNET_SERVER_Handle *server,
1227      const struct GNUNET_CONFIGURATION_Handle *cfg)
1228 {
1229   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1230     {&handle_lookup_block, NULL,
1231      GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_BLOCK, sizeof (struct LookupBlockMessage)},
1232     {&handle_block_cache, NULL,
1233     GNUNET_MESSAGE_TYPE_NAMESTORE_BLOCK_CACHE, 0},
1234     {&handle_record_store, NULL,
1235      GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE, 0},
1236     {&handle_zone_to_name, NULL,
1237      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_TO_NAME, sizeof (struct ZoneToNameMessage) },
1238     {&handle_iteration_start, NULL,
1239      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_START, sizeof (struct ZoneIterationStartMessage) },
1240     {&handle_iteration_next, NULL,
1241      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT, sizeof (struct ZoneIterationNextMessage) },
1242     {&handle_iteration_stop, NULL,
1243      GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP, sizeof (struct ZoneIterationStopMessage) },
1244     {&handle_monitor_start, NULL,
1245      GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START, sizeof (struct ZoneMonitorStartMessage) },
1246     {NULL, NULL, 0, 0}
1247   };
1248   char *database;
1249
1250   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting namestore service\n");
1251   GSN_cfg = cfg;
1252   monitor_nc = GNUNET_SERVER_notification_context_create (server, 1);
1253
1254   /* Loading database plugin */
1255   if (GNUNET_OK !=
1256       GNUNET_CONFIGURATION_get_value_string (cfg, "namestore", "database",
1257                                              &database))
1258     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
1259
1260   GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_namestore_%s", database);
1261   GSN_database = GNUNET_PLUGIN_load (db_lib_name, (void *) GSN_cfg);
1262   GNUNET_free (database);
1263   if (NULL == GSN_database)
1264   {
1265     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1266                 "Could not load database backend `%s'\n",
1267                 db_lib_name);
1268     GNUNET_SCHEDULER_add_now (&cleanup_task, NULL);
1269     return;
1270   }
1271
1272   /* Configuring server handles */
1273   GNUNET_SERVER_add_handlers (server, handlers);
1274   snc = GNUNET_SERVER_notification_context_create (server, 16);
1275   GNUNET_SERVER_disconnect_notify (server,
1276                                    &client_disconnect_notification,
1277                                    NULL);
1278   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1279                                 NULL);
1280 }
1281
1282
1283 /**
1284  * The main function for the template service.
1285  *
1286  * @param argc number of arguments from the command line
1287  * @param argv command line arguments
1288  * @return 0 ok, 1 on error
1289  */
1290 int
1291 main (int argc, char *const *argv)
1292 {
1293   return (GNUNET_OK ==
1294           GNUNET_SERVICE_run (argc, argv, "namestore",
1295                               GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
1296 }
1297
1298 /* end of gnunet-service-namestore.c */
1299