e1fc507fb148183682717c7b3515194e1c1e1877
[oweals/gnunet.git] / src / gns / gnunet-service-gns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011, 2012 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  * @file gns/gnunet-service-gns.c
22  * @brief GNUnet GNS service
23  * @author Martin Schanzenbach
24  */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_transport_service.h"
28 #include "gnunet_dns_service.h"
29 #include "gnunet_dnsparser_lib.h"
30 #include "gnunet_dht_service.h"
31 #include "gnunet_namestore_service.h"
32 #include "gnunet_gns_service.h"
33 #include "gnunet_statistics_service.h"
34 #include "gns.h"
35 #include "gns_common.h"
36 #include "gnunet-service-gns_resolver.h"
37 #include "gnunet-service-gns_interceptor.h"
38 #include "gnunet_protocols.h"
39
40 /**
41  * The initial interval in milliseconds btween puts in
42  * a zone iteration
43  */
44 #define INITIAL_PUT_INTERVAL GNUNET_TIME_UNIT_MILLISECONDS
45
46 /**
47  * The upper bound for the zone iteration interval in milliseconds
48  */
49 #define MINIMUM_ZONE_ITERATION_INTERVAL GNUNET_TIME_UNIT_SECONDS
50
51 /**
52  * The default put interval for the zone iteration. In case
53  * No option is found
54  */
55 #define DEFAULT_ZONE_PUBLISH_TIME_WINDOW GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
56
57 /**
58  * The factor the current zone iteration interval is divided by for each
59  * additional new record
60  */
61 #define LATE_ITERATION_SPEEDUP_FACTOR 2
62
63
64 /**
65  * Handle to a shorten operation from api
66  */
67 struct ClientShortenHandle
68 {
69
70   /**
71    * List for all shorten requests
72    */
73   struct ClientShortenHandle *next;
74
75   /**
76    * List for all shorten requests
77    */
78   struct ClientShortenHandle *prev;
79
80   /**
81    * Handle to the requesting client
82    */
83   struct GNUNET_SERVER_Client *client;
84
85   /**
86    * Namestore lookup task
87    */
88   struct GNUNET_NAMESTORE_QueueEntry *namestore_task;
89
90   /**
91    * master zone
92    */
93   struct GNUNET_CRYPTO_ShortHashCode root_zone;
94
95   /**
96    * private zone
97    */
98   struct GNUNET_CRYPTO_ShortHashCode private_zone;
99   
100   /**
101    * shorten zone
102    */
103   struct GNUNET_CRYPTO_ShortHashCode shorten_zone;
104   
105   /**
106    * The request id
107    */
108   uint32_t request_id;
109
110   /**
111    * request type
112    */
113   int type;
114
115   /** 
116    * name to shorten
117    */
118   char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
119
120   /**
121    * name of private zone (relative to root)
122    */
123   char private_zone_id[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
124   
125   /**
126    * name of shorten zone (relative to root)
127    */
128   char shorten_zone_id[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
129
130 };
131
132
133 /**
134  * Handle to a get authority operation from api
135  */
136 struct ClientGetAuthHandle
137 {
138   /**
139    * Handle to the requesting client 
140    */
141   struct GNUNET_SERVER_Client *client;
142
143   /**
144    * name to lookup authority
145    */
146   char *name;
147
148   /**
149    * request id
150    */
151   uint32_t request_id;
152
153 };
154
155
156 /**
157  * Handle to a lookup operation from api
158  */
159 struct ClientLookupHandle
160 {
161
162   /**
163    * Handle to the requesting client
164    */
165   struct GNUNET_SERVER_Client *client;
166
167   /**
168    * optional zone private key used for shorten
169    */
170   struct GNUNET_CRYPTO_EccPrivateKey *shorten_key;
171
172   /**
173    * the name to look up
174    */
175   char *name; 
176
177   /**
178    * The zone we look up in
179    */
180   struct GNUNET_CRYPTO_ShortHashCode zone;
181
182   /**
183    * request id 
184    */
185   uint32_t request_id;
186
187   /**
188    * GNUNET_YES if we only want to lookup from local cache
189    */
190   int only_cached;
191
192   /**
193    * request type
194    */
195   int type;
196 };
197
198
199 /**
200  * Our handle to the DHT
201  */
202 static struct GNUNET_DHT_Handle *dht_handle;
203
204 /**
205  * Our zone's private key
206  */
207 static struct GNUNET_CRYPTO_EccPrivateKey *zone_key;
208
209 /**
210  * Our handle to the namestore service
211  */
212 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
213
214 /**
215  * Handle to iterate over our authoritative zone in namestore
216  */
217 static struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
218
219 /**
220  * Our notification context.
221  */
222 static struct GNUNET_SERVER_NotificationContext *nc;
223
224 /**
225  * Our zone hash
226  */
227 static struct GNUNET_CRYPTO_ShortHashCode zone_hash;
228
229 /**
230  * Useful for zone update for DHT put
231  */
232 static unsigned long long num_public_records;
233
234 /**
235  * Last seen record count
236  */
237 static unsigned long long last_num_public_records;
238
239 /**
240  * Zone iteration PUT interval.
241  */
242 static struct GNUNET_TIME_Relative put_interval;
243
244 /**
245  * Time window for zone iteration
246  */
247 static struct GNUNET_TIME_Relative zone_publish_time_window;
248
249 /**
250  * zone publish task
251  */
252 static GNUNET_SCHEDULER_TaskIdentifier zone_publish_task;
253
254 /**
255  * GNUNET_YES if automatic pkey import for name shortening
256  * is enabled
257  */
258 static int auto_import_pkey;
259
260 /**
261  * GNUNET_YES if zone has never been published before
262  */
263 static int first_zone_iteration;
264
265 /**
266  * The lookup timeout
267  */
268 static struct GNUNET_TIME_Relative default_lookup_timeout;
269
270 /**
271  * GNUNET_YES if ipv6 is supported
272  */
273 static int v6_enabled;
274
275 /**
276  * GNUNET_YES if ipv4 is supported
277  */
278 static int v4_enabled;
279
280 /**
281  * List for shorten requests
282  */
283 static struct ClientShortenHandle *csh_head;
284
285 /**
286  * List for shorten requests
287  */
288 static struct ClientShortenHandle *csh_tail;
289
290 /**
291  * Handle to the statistics service
292  */
293 static struct GNUNET_STATISTICS_Handle *statistics;
294
295
296 /**
297  * Task run during shutdown.
298  *
299  * @param cls unused
300  * @param tc unused
301  */
302 static void
303 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
304 {
305   struct ClientShortenHandle *csh_tmp;
306
307   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
308              "Shutting down!\n");
309   while (NULL != (csh_tmp = csh_head))
310   {
311     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh_tmp);
312     GNUNET_free (csh_tmp);
313   }
314   GNUNET_SERVER_notification_context_destroy (nc);  
315   gns_interceptor_stop ();
316   gns_resolver_cleanup ();
317   if (NULL != statistics)
318   {
319     GNUNET_STATISTICS_destroy (statistics, GNUNET_NO);
320     statistics = NULL;
321   }
322   if (GNUNET_SCHEDULER_NO_TASK != zone_publish_task)
323   {
324     GNUNET_SCHEDULER_cancel (zone_publish_task);
325     zone_publish_task = GNUNET_SCHEDULER_NO_TASK;
326   }
327   if (NULL != namestore_iter)
328   {
329     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
330     namestore_iter = NULL;
331   }
332   if (NULL != namestore_handle)
333   {
334     GNUNET_NAMESTORE_disconnect (namestore_handle);
335     namestore_handle = NULL;
336   }
337   if (NULL != dht_handle)
338   {
339     GNUNET_DHT_disconnect (dht_handle);
340     dht_handle = NULL;
341   }
342 }
343
344
345 /**
346  * Method called periodically that triggers iteration over authoritative records
347  *
348  * @param cls closure
349  * @param tc task context
350  */
351 static void
352 publish_zone_dht_next (void *cls,
353                        const struct GNUNET_SCHEDULER_TaskContext *tc)
354 {
355   zone_publish_task = GNUNET_SCHEDULER_NO_TASK;
356   GNUNET_NAMESTORE_zone_iterator_next (namestore_iter);
357 }
358
359
360 /**
361  * Periodically iterate over our zone and store everything in dht
362  *
363  * @param cls NULL
364  * @param tc task context
365  */
366 static void
367 publish_zone_dht_start (void *cls, 
368                         const struct GNUNET_SCHEDULER_TaskContext *tc);
369
370
371 /**
372  * Function used to put all records successively into the DHT.
373  *
374  * @param cls the closure (NULL)
375  * @param key the public key of the authority (ours)
376  * @param expiration lifetime of the namestore entry
377  * @param name the name of the records
378  * @param rd_count the number of records in data
379  * @param rd the record data
380  * @param signature the signature for the record data
381  */
382 static void
383 put_gns_record (void *cls,
384                 const struct GNUNET_CRYPTO_EccPublicKey *key,
385                 struct GNUNET_TIME_Absolute expiration,
386                 const char *name,
387                 unsigned int rd_count,
388                 const struct GNUNET_NAMESTORE_RecordData *rd,
389                 const struct GNUNET_CRYPTO_EccSignature *signature)
390 {  
391   struct GNSNameRecordBlock *nrb;
392   struct GNUNET_CRYPTO_ShortHashCode zhash;
393   struct GNUNET_HashCode dht_key;
394   uint32_t rd_payload_length;
395   char* nrb_data = NULL;
396   size_t namelen;
397   struct GNUNET_TIME_Relative next_put_interval; 
398
399   if (NULL == name)
400   {
401     /* we're done */
402     namestore_iter = NULL;
403     last_num_public_records = num_public_records;
404     first_zone_iteration = GNUNET_NO;
405     if (0 == num_public_records)
406     {
407       /**
408        * If no records are known (startup) or none present
409        * we can safely set the interval to the value for a single
410        * record
411        */
412       put_interval = zone_publish_time_window;
413       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
414                   "No records in db.\n");
415     }
416     else
417     {
418       put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
419                                                   num_public_records);
420     }
421     put_interval = GNUNET_TIME_relative_max (MINIMUM_ZONE_ITERATION_INTERVAL,
422                                              put_interval);
423
424     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
425                 "Zone iteration finished. Adjusted zone iteration interval to %s\n",
426                 GNUNET_STRINGS_relative_time_to_string (put_interval, GNUNET_YES));
427     GNUNET_STATISTICS_set (statistics,
428                            "Current zone iteration interval (in ms)",
429                            put_interval.rel_value_us / 1000LL,
430                            GNUNET_NO);
431     GNUNET_STATISTICS_update (statistics,
432                               "Number of zone iterations", 1, GNUNET_NO);
433     GNUNET_STATISTICS_set (statistics,
434                            "Number of public records in DHT",
435                            last_num_public_records,
436                            GNUNET_NO);
437     if (0 == num_public_records)
438       zone_publish_task = GNUNET_SCHEDULER_add_delayed (put_interval,
439                                                          &publish_zone_dht_start,
440                                                          NULL);
441     else
442       zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start, NULL);
443     return;
444   }
445   
446   namelen = strlen (name) + 1;
447   if (0 == rd_count)
448   {
449     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450                 "No records for name `%s'! Skipping.\n",
451                 name);
452     zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_next,
453                                                    NULL);
454     return;
455   }
456   if (NULL == signature)
457   {
458     GNUNET_break (0);
459     zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_next,
460                                                    NULL);
461     return;
462   }
463   
464   /* TODO 2) AB: New publishing
465    *
466    * - Use new signature S_d
467    * - Obtain new derived public key V = H(H(i,Q) * Q)
468    * - Obtain HKDF(i,Q)
469    * - Compute encrypte record block E with HKDF(i,Q) (rd, rd_count)
470    * - Create block B = |V,E,S_d|
471    * - Compute new DHT key H(V) in TODO 3)
472    *
473    * -> Put (H(V), B)
474    */
475   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
476               "Putting records for `%s' into the DHT\n", name); 
477   rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd); 
478   nrb = GNUNET_malloc (rd_payload_length + namelen
479                        + sizeof (struct GNSNameRecordBlock));
480   nrb->signature = *signature;
481   nrb->public_key = *key;
482   nrb->rd_count = htonl (rd_count);
483   memcpy (&nrb[1], name, namelen);
484   nrb_data = (char *) &nrb[1];
485   nrb_data += namelen;
486   rd_payload_length += sizeof(struct GNSNameRecordBlock) + namelen;
487   GNUNET_CRYPTO_short_hash (key,
488                             sizeof (struct GNUNET_CRYPTO_EccPublicKey),
489                             &zhash);
490   if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
491                                                 rd,
492                                                 rd_payload_length,
493                                                 nrb_data))
494   {
495     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
496                 _("Records for name `%s' in zone %s too large to fit into DHT"),
497                 name,
498                 GNUNET_short_h2s (&zhash));
499     GNUNET_free (nrb);
500     zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_next,
501                                                    NULL);
502     return;
503   }
504   /* TODO AB: Here records are put in the DHT: modify dht_key to H(key) = H(H(name,zone) * zone) */
505   GNUNET_GNS_get_key_for_record (name, &zhash, &dht_key);
506   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
507               "putting %u records from zone %s for `%s' under key: %s with size %u and timeout %s\n",
508               rd_count,
509               GNUNET_short_h2s (&zhash),
510               name, 
511               GNUNET_h2s (&dht_key), 
512               (unsigned int) rd_payload_length,
513               GNUNET_STRINGS_relative_time_to_string (DHT_OPERATION_TIMEOUT, GNUNET_YES));
514   
515   GNUNET_STATISTICS_update (statistics,
516                             "Record bytes put into DHT", 
517                             rd_payload_length, GNUNET_NO);
518
519   (void) GNUNET_DHT_put (dht_handle, &dht_key,
520                          DHT_GNS_REPLICATION_LEVEL,
521                          GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
522                          GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
523                          rd_payload_length,
524                          (char*)nrb,
525                          expiration,
526                          DHT_OPERATION_TIMEOUT,
527                          NULL,
528                          NULL); 
529   GNUNET_free (nrb);
530
531   num_public_records++;  
532   if ( (num_public_records > last_num_public_records)
533        && (GNUNET_NO == first_zone_iteration) )
534   {
535     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536                 "Last record count was lower than current record count.  Reducing interval.\n");
537     put_interval = GNUNET_TIME_relative_divide (zone_publish_time_window,
538                                                 num_public_records);
539     next_put_interval = GNUNET_TIME_relative_divide (put_interval,
540                                                      LATE_ITERATION_SPEEDUP_FACTOR);
541   }
542   else
543     next_put_interval = put_interval;
544
545   GNUNET_STATISTICS_set (statistics,
546                          "Current zone iteration interval (ms)",
547                          next_put_interval.rel_value_us / 1000LL,
548                          GNUNET_NO); 
549   zone_publish_task = GNUNET_SCHEDULER_add_delayed (next_put_interval,
550                                                     &publish_zone_dht_next,
551                                                     NULL);
552 }
553
554
555 /**
556  * Periodically iterate over our zone and store everything in dht
557  *
558  * @param cls NULL
559  * @param tc task context
560  */
561 static void
562 publish_zone_dht_start (void *cls, 
563                         const struct GNUNET_SCHEDULER_TaskContext *tc)
564 {
565   zone_publish_task = GNUNET_SCHEDULER_NO_TASK;
566
567   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
568               "Scheduling DHT zone update!\n");  
569   /* start counting again */
570   num_public_records = 0;
571   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
572                                                           NULL, /* All zones */
573                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
574                                                           GNUNET_NAMESTORE_RF_PRIVATE,
575                                                           &put_gns_record,
576                                                           NULL);
577 }
578
579
580 /* END DHT ZONE PROPAGATION */
581
582
583 /**
584  * Send shorten response back to client
585  * 
586  * @param cls the closure containing a client shorten handle
587  * @param name the shortened name result or NULL if cannot be shortened
588  */
589 static void
590 send_shorten_response (void* cls, const char* name)
591 {
592   struct ClientShortenHandle *csh = cls;
593   struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
594   size_t name_len;
595   
596   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
597               "Sending `%s' message with %s\n",
598               "SHORTEN_RESULT", name);
599   if (NULL == name)
600     name_len = 0;
601   else
602     name_len = strlen (name) + 1;
603   GNUNET_STATISTICS_update (statistics,
604                             "Name shorten results", 1, GNUNET_NO);
605
606   rmsg = GNUNET_malloc (sizeof (struct GNUNET_GNS_ClientShortenResultMessage) +
607                         name_len);
608   
609   rmsg->id = csh->request_id;
610   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT);
611   rmsg->header.size = 
612     htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) +
613           name_len);
614   memcpy (&rmsg[1], name, name_len);
615   GNUNET_SERVER_notification_context_unicast (nc, csh->client,
616                                               &rmsg->header,
617                                               GNUNET_NO);
618   if (NULL != csh->namestore_task)
619     GNUNET_NAMESTORE_cancel (csh->namestore_task); 
620   GNUNET_free (rmsg);
621   GNUNET_free (csh);
622 }
623
624
625 /**
626  * Lookup the zone infos and shorten name
627  *
628  * @param cls the client shorten handle
629  * @param key key of the zone
630  * @param expiration expiration of record
631  * @param name name found or null if no result
632  * @param rd_count number of records found
633  * @param rd record data
634  * @param signature
635  *
636  */
637 static void
638 process_shorten_in_private_zone_lookup (void *cls,
639                                         const struct GNUNET_CRYPTO_EccPublicKey *key,
640                                         struct GNUNET_TIME_Absolute expiration,
641                                         const char *name,
642                                         unsigned int rd_count,
643                                         const struct GNUNET_NAMESTORE_RecordData *rd,
644                                         const struct GNUNET_CRYPTO_EccSignature *signature)
645 {
646   struct ClientShortenHandle *csh = cls;
647   struct GNUNET_CRYPTO_ShortHashCode *szone = &csh->shorten_zone;
648   struct GNUNET_CRYPTO_ShortHashCode *pzone = &csh->private_zone;
649
650   csh->namestore_task = NULL;
651   if (0 == strcmp (csh->private_zone_id, ""))
652     pzone = NULL;  
653   if (0 == rd_count)
654   {
655     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
656                 "No shorten zone in private zone!\n");
657     strcpy (csh->shorten_zone_id, "");
658     szone = NULL;
659   }
660   else
661   {
662     GNUNET_break (1 == rd_count);
663     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
664                 "Shorten zone %s found in private zone %s\n",
665                 name, csh->private_zone_id);
666
667     sprintf (csh->shorten_zone_id, "%s.%s", name, csh->private_zone_id);
668   }
669   GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
670   gns_resolver_shorten_name (&csh->root_zone,
671                              pzone,
672                              szone,
673                              csh->name,
674                              csh->private_zone_id,
675                              csh->shorten_zone_id,
676                              &send_shorten_response, csh);
677
678 }
679
680
681 /**
682  * Lookup the zone infos and shorten name
683  *
684  * @param cls the shorten handle
685  * @param key key of the zone
686  * @param expiration expiration of record
687  * @param name name found or null if no result
688  * @param rd_count number of records found
689  * @param rd record data
690  * @param signature
691  *
692  */
693 static void
694 process_shorten_in_root_zone_lookup (void *cls,
695                                      const struct GNUNET_CRYPTO_EccPublicKey *key,
696                                      struct GNUNET_TIME_Absolute expiration,
697                                      const char *name,
698                                      unsigned int rd_count,
699                                      const struct GNUNET_NAMESTORE_RecordData *rd,
700                                      const struct GNUNET_CRYPTO_EccSignature *signature)
701 {
702   struct ClientShortenHandle *csh = cls;
703   struct GNUNET_CRYPTO_ShortHashCode *szone = &csh->shorten_zone;
704   struct GNUNET_CRYPTO_ShortHashCode *pzone = &csh->private_zone;
705   
706   csh->namestore_task = NULL;
707   if (0 == strcmp (csh->private_zone_id, ""))
708     pzone = NULL;
709   if (0 == rd_count)
710   {
711     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
712                 "No shorten zone in zone and no private zone!\n");
713
714     strcpy (csh->shorten_zone_id, "");
715     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
716     szone = NULL;
717     gns_resolver_shorten_name (&csh->root_zone,
718                                pzone,
719                                szone,
720                                csh->name,
721                                csh->private_zone_id,
722                                csh->shorten_zone_id,
723                                &send_shorten_response, csh);
724     return;
725   }
726   GNUNET_break (rd_count == 1);
727   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
728               "Private zone %s found in root zone\n", name);
729   strcpy (csh->private_zone_id, name);
730   csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
731                                                        pzone,
732                                                        szone,
733                                                        &process_shorten_in_private_zone_lookup,
734                                                        csh);
735 }
736
737
738 /**
739  * Lookup the zone infos and shorten name
740  *
741  * @param cls the shorten handle
742  * @param key key of the zone
743  * @param expiration expiration of record
744  * @param name name found or null if no result
745  * @param rd_count number of records found
746  * @param rd record data
747  * @param signature
748  */
749 static void
750 process_private_in_root_zone_lookup (void *cls,
751                                      const struct GNUNET_CRYPTO_EccPublicKey *key,
752                                      struct GNUNET_TIME_Absolute expiration,
753                                      const char *name,
754                                      unsigned int rd_count,
755                                      const struct GNUNET_NAMESTORE_RecordData *rd,
756                                      const struct GNUNET_CRYPTO_EccSignature *signature)
757 {
758   struct ClientShortenHandle *csh = cls;
759
760   csh->namestore_task = NULL;
761   if (0 == rd_count)
762   {
763     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
764                 "No private zone in root zone\n");
765     strcpy (csh->private_zone_id, "");
766     csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
767                                                          &csh->root_zone,
768                                                          &csh->shorten_zone,
769                                                          &process_shorten_in_root_zone_lookup,
770                                                          csh);
771     return;
772   }
773   GNUNET_break (1 == rd_count);
774   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775               "Private zone `%s' found in root zone\n", 
776               name);
777   strcpy (csh->private_zone_id, name);
778   csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
779                                                        &csh->private_zone,
780                                                        &csh->shorten_zone,
781                                                        &process_shorten_in_private_zone_lookup,
782                                                        csh);
783 }
784
785
786 /**
787  * Handle a shorten message from the api
788  *
789  * @param cls the closure (unused)
790  * @param client the client
791  * @param message the message
792  */
793 static void 
794 handle_shorten (void *cls,
795                 struct GNUNET_SERVER_Client * client,
796                 const struct GNUNET_MessageHeader * message)
797 {
798   struct ClientShortenHandle *csh;
799   const char *utf_in;
800   char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
801   char* nameptr = name;
802   uint16_t msg_size;
803   const struct GNUNET_GNS_ClientShortenMessage *sh_msg;
804
805   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
806               "Received `%s' message\n", "SHORTEN");
807   msg_size = ntohs (message->size);
808   if (msg_size < sizeof (struct GNUNET_GNS_ClientShortenMessage))
809   {
810     GNUNET_break (0);
811     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
812     return;
813   }
814   sh_msg = (const struct GNUNET_GNS_ClientShortenMessage *) message;
815   utf_in = (const char *) &sh_msg[1];
816   if ('\0' != utf_in[msg_size - sizeof (struct GNUNET_GNS_ClientShortenMessage) - 1])
817   {
818     GNUNET_break (0);
819     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
820     return;
821   }
822   csh = GNUNET_malloc(sizeof (struct ClientShortenHandle));
823   csh->client = client;
824   csh->request_id = sh_msg->id;
825   GNUNET_CONTAINER_DLL_insert (csh_head, csh_tail, csh); 
826   GNUNET_STRINGS_utf8_tolower (utf_in, &nameptr);
827   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
828              "SHORTEN: Converted `%s' to `%s'\n", 
829              utf_in, 
830              nameptr);
831   GNUNET_SERVER_notification_context_add (nc, client);  
832   if (strlen (name) < strlen (GNUNET_GNS_TLD)) 
833   {
834     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
835                "SHORTEN: %s is too short\n", name);
836     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
837     send_shorten_response(csh, name);
838     GNUNET_SERVER_receive_done (client, GNUNET_OK);
839     return;
840   }
841   if (strlen (name) > GNUNET_DNSPARSER_MAX_NAME_LENGTH) 
842   {
843     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
844                "SHORTEN: %s is too long\n", name);
845     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
846     send_shorten_response(csh, name);
847     GNUNET_SERVER_receive_done (client, GNUNET_OK);
848     return;
849   }  
850   if ( (! is_gads_tld (name)) && 
851        (! is_zkey_tld (name)) )
852   {
853     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
854                 "%s is not our domain. Returning\n", name);
855     GNUNET_CONTAINER_DLL_remove (csh_head, csh_tail, csh);
856     send_shorten_response (csh, name);
857     GNUNET_SERVER_receive_done (client, GNUNET_OK);
858     return;
859   }
860   csh->shorten_zone = sh_msg->shorten_zone;
861   csh->private_zone = sh_msg->private_zone;
862   strcpy (csh->name, name);  
863   if (1 == ntohl(sh_msg->use_default_zone))
864     csh->root_zone = zone_hash; //Default zone
865   else
866     csh->root_zone = sh_msg->zone;
867   csh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
868                                                        &csh->root_zone,
869                                                        &csh->private_zone,
870                                                        &process_private_in_root_zone_lookup,
871                                                        csh);
872   GNUNET_STATISTICS_update (statistics,
873                             "Name shorten attempts", 1, GNUNET_NO);
874   GNUNET_SERVER_receive_done (client, GNUNET_OK);
875 }
876
877
878 /**
879  * Send get authority response back to client
880  * 
881  * @param cls the closure containing a client get auth handle
882  * @param name the name of the authority, or NULL on error
883  */
884 static void 
885 send_get_auth_response (void *cls, 
886                         const char* name)
887 {
888   struct ClientGetAuthHandle *cah = cls;
889   struct GNUNET_GNS_ClientGetAuthResultMessage *rmsg;
890   
891   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
892               "Sending `%s' message with `%s'\n",
893               "GET_AUTH_RESULT", name);
894   if (NULL != name)
895   {
896     GNUNET_STATISTICS_update (statistics,
897                               "Authorities resolved", 1, GNUNET_NO);
898   }  
899   if (NULL == name)  
900     name = "";  
901   rmsg = GNUNET_malloc (sizeof (struct GNUNET_GNS_ClientGetAuthResultMessage)
902                         + strlen (name) + 1);
903   
904   rmsg->id = cah->request_id;
905   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_GET_AUTH_RESULT);
906   rmsg->header.size = 
907     htons(sizeof(struct GNUNET_GNS_ClientGetAuthResultMessage) +
908           strlen (name) + 1);
909   strcpy ((char*)&rmsg[1], name);
910
911   GNUNET_SERVER_notification_context_unicast (nc, cah->client,
912                                               &rmsg->header,
913                                               GNUNET_NO);
914   GNUNET_SERVER_receive_done (cah->client, GNUNET_OK);
915   GNUNET_free(rmsg);
916   GNUNET_free_non_null(cah->name);
917   GNUNET_free(cah);  
918 }
919
920
921 /**
922  * Handle a get authority message from the api
923  *
924  * @param cls the closure
925  * @param client the client
926  * @param message the message
927  */
928 static void 
929 handle_get_authority (void *cls,
930                       struct GNUNET_SERVER_Client * client,
931                       const struct GNUNET_MessageHeader * message)
932 {
933   struct ClientGetAuthHandle *cah;
934   const char *utf_in;
935   char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
936   char* nameptr = name;
937   uint16_t msg_size;
938   const struct GNUNET_GNS_ClientGetAuthMessage *sh_msg;
939
940   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
941               "Received `%s' message\n", "GET_AUTH");
942   msg_size = ntohs(message->size);
943   if (msg_size < sizeof (struct GNUNET_GNS_ClientGetAuthMessage))
944   {
945     GNUNET_break (0);
946     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
947     return;
948   }
949   GNUNET_SERVER_notification_context_add (nc, client);
950   sh_msg = (const struct GNUNET_GNS_ClientGetAuthMessage *) message;
951   utf_in = (const char *) &sh_msg[1];
952   if ('\0' != utf_in[msg_size - sizeof (struct GNUNET_GNS_ClientGetAuthMessage) - 1])
953   {
954     GNUNET_break (0);
955     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
956     return;
957   }  
958   GNUNET_STRINGS_utf8_tolower(utf_in, &nameptr);
959   cah = GNUNET_malloc(sizeof(struct ClientGetAuthHandle));
960   cah->client = client;
961   cah->request_id = sh_msg->id;
962   if (strlen (name) < strlen(GNUNET_GNS_TLD))
963   {
964     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
965                 "GET_AUTH: `%s' is too short. Returning\n", name);
966     cah->name = NULL;
967     send_get_auth_response(cah, name);
968     return;
969   }  
970   if (strlen (name) > GNUNET_DNSPARSER_MAX_NAME_LENGTH) 
971   {
972     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
973                "GET_AUTH: `%s' is too long", name);
974     cah->name = NULL;
975     send_get_auth_response(cah, name);
976     return;
977   }  
978   if (0 != strcmp (name + strlen (name) - strlen (GNUNET_GNS_TLD),
979                    GNUNET_GNS_TLD))
980   {
981     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
982                 "GET_AUTH: %s is not our domain. Returning\n", name);
983     cah->name = NULL;
984     send_get_auth_response (cah, name);
985     return;
986   }
987
988   if (0 == strcmp (name, GNUNET_GNS_TLD))
989   {
990     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991                 "GET_AUTH: %s is us. Returning\n", name);
992     cah->name = NULL;
993     send_get_auth_response(cah, name);
994     return;
995   }
996   
997   cah->name = GNUNET_malloc (strlen (name)
998                             - strlen (GNUNET_GNS_TLD) + 1);
999   memcpy (cah->name, name,
1000           strlen (name) - strlen (GNUNET_GNS_TLD));
1001
1002   /* Start delegation resolution in our namestore */
1003   gns_resolver_get_authority (zone_hash, zone_hash, name,
1004                               &send_get_auth_response, cah);
1005   GNUNET_STATISTICS_update (statistics,
1006                             "Authority lookup attempts", 1, GNUNET_NO);
1007 }
1008
1009
1010 /**
1011  * Reply to client with the result from our lookup.
1012  *
1013  * @param cls the closure (our client lookup handle)
1014  * @param rd_count the number of records
1015  * @param rd the record data
1016  */
1017 static void
1018 send_lookup_response (void* cls,
1019                       uint32_t rd_count,
1020                       const struct GNUNET_NAMESTORE_RecordData *rd)
1021 {
1022   struct ClientLookupHandle* clh = cls;
1023   struct GNUNET_GNS_ClientLookupResultMessage *rmsg;
1024   size_t len;
1025   
1026   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message with %d results\n",
1027               "LOOKUP_RESULT", rd_count);
1028   
1029   len = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1030   rmsg = GNUNET_malloc (len + sizeof (struct GNUNET_GNS_ClientLookupResultMessage));
1031   
1032   rmsg->id = clh->request_id;
1033   rmsg->rd_count = htonl(rd_count);
1034   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT);
1035   rmsg->header.size = 
1036     htons(len+sizeof(struct GNUNET_GNS_ClientLookupResultMessage));
1037   
1038   GNUNET_NAMESTORE_records_serialize (rd_count, rd, len, (char*)&rmsg[1]);
1039   
1040   GNUNET_SERVER_notification_context_unicast (nc, clh->client,
1041                                 (const struct GNUNET_MessageHeader *) rmsg,
1042                                 GNUNET_NO);
1043   GNUNET_SERVER_receive_done (clh->client, GNUNET_OK);
1044   
1045   GNUNET_free(rmsg);
1046   GNUNET_free(clh->name);
1047   
1048   if (NULL != clh->shorten_key)
1049     GNUNET_CRYPTO_ecc_key_free (clh->shorten_key);
1050   GNUNET_free (clh);
1051   GNUNET_STATISTICS_update (statistics,
1052                             "Completed lookups", 1, GNUNET_NO);
1053   if (NULL != rd)
1054     GNUNET_STATISTICS_update (statistics,
1055                               "Records resolved", rd_count, GNUNET_NO);
1056 }
1057
1058
1059 /**
1060  * Handle lookup requests from client
1061  *
1062  * @param cls the closure
1063  * @param client the client
1064  * @param message the message
1065  */
1066 static void
1067 handle_lookup (void *cls,
1068                struct GNUNET_SERVER_Client * client,
1069                const struct GNUNET_MessageHeader * message)
1070 {
1071   size_t namelen;
1072   char name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
1073   struct ClientLookupHandle *clh;
1074   char* nameptr = name;
1075   const char *utf_in;
1076   int only_cached;
1077   const struct GNUNET_CRYPTO_EccPrivateKey *key;
1078   uint16_t msg_size;
1079   const struct GNUNET_GNS_ClientLookupMessage *sh_msg;
1080   
1081   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
1082               "Received `%s' message\n", "LOOKUP");
1083   msg_size = ntohs(message->size);
1084   if (msg_size < sizeof (struct GNUNET_GNS_ClientLookupMessage))
1085   {
1086     GNUNET_break (0);
1087     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1088     return;
1089   }
1090   sh_msg = (const struct GNUNET_GNS_ClientLookupMessage *) message;
1091   GNUNET_SERVER_notification_context_add (nc, client);
1092   if (GNUNET_YES == ntohl (sh_msg->have_key))
1093   {
1094     key = &sh_msg->shorten_key;
1095   }
1096   else
1097   {
1098     key = NULL;
1099   }
1100   utf_in = (const char *) &sh_msg[1];
1101   if ('\0' != utf_in[msg_size - sizeof (struct GNUNET_GNS_ClientLookupMessage) - 1])
1102   {
1103     GNUNET_break (0);
1104     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1105     return;
1106   }  
1107   GNUNET_STRINGS_utf8_tolower (utf_in, &nameptr);
1108   
1109   namelen = strlen (name) + 1;
1110   clh = GNUNET_malloc (sizeof (struct ClientLookupHandle));
1111   memset (clh, 0, sizeof (struct ClientLookupHandle));
1112   clh->client = client;
1113   clh->name = GNUNET_malloc (namelen);
1114   strcpy (clh->name, name);
1115   clh->request_id = sh_msg->id;
1116   clh->type = ntohl (sh_msg->type);
1117   if (NULL != key)
1118   {
1119     clh->shorten_key = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
1120     *clh->shorten_key = *key;
1121   }
1122   only_cached = ntohl (sh_msg->only_cached);
1123   
1124   if (strlen (name) > GNUNET_DNSPARSER_MAX_NAME_LENGTH) {
1125     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1126                 "LOOKUP: %s is too long", name);
1127     clh->name = NULL;
1128     send_lookup_response (clh, 0, NULL);
1129     return;
1130   }
1131
1132   if ((GNUNET_DNSPARSER_TYPE_A == clh->type) &&
1133       (GNUNET_OK != v4_enabled))
1134   {
1135     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1136                "LOOKUP: Query for A record but AF_INET not supported!");
1137     clh->name = NULL;
1138     send_lookup_response (clh, 0, NULL);
1139     return;
1140   }
1141   
1142   if ((GNUNET_DNSPARSER_TYPE_AAAA == clh->type) &&
1143       (GNUNET_OK != v6_enabled))
1144   {
1145     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1146                 "LOOKUP: Query for AAAA record but AF_INET6 not supported!");
1147     clh->name = NULL;
1148     send_lookup_response (clh, 0, NULL);
1149     return;
1150   }
1151   
1152   if (GNUNET_NO == ntohl (sh_msg->have_zone))
1153     clh->zone = zone_hash;  /* Default zone */
1154   else
1155     clh->zone = sh_msg->zone;
1156   
1157   if (GNUNET_YES == auto_import_pkey)
1158   {
1159     gns_resolver_lookup_record (clh->zone, clh->zone, clh->type, clh->name,
1160                                 clh->shorten_key,
1161                                 default_lookup_timeout,
1162                                 clh->only_cached,
1163                                 &send_lookup_response, clh);  
1164   }
1165   else
1166   {
1167     gns_resolver_lookup_record (clh->zone, clh->zone, clh->type, name,
1168                                 NULL,
1169                                 default_lookup_timeout,
1170                                 only_cached,
1171                                 &send_lookup_response, clh);
1172   }
1173   GNUNET_STATISTICS_update (statistics,
1174                             "Record lookup attempts", 1, GNUNET_NO);
1175 }
1176
1177
1178 /**
1179  * Process GNS requests.
1180  *
1181  * @param cls closure
1182  * @param server the initialized server
1183  * @param c configuration to use
1184  */
1185 static void
1186 run (void *cls, struct GNUNET_SERVER_Handle *server,
1187      const struct GNUNET_CONFIGURATION_Handle *c)
1188 {
1189   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1190     {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
1191     {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0},
1192     {&handle_get_authority, NULL, GNUNET_MESSAGE_TYPE_GNS_GET_AUTH, 0}
1193   };
1194   char* keyfile;
1195   struct GNUNET_CRYPTO_EccPublicKey pkey;
1196   unsigned long long max_parallel_bg_queries = 0;
1197   int ignore_pending = GNUNET_NO;
1198
1199   v6_enabled = GNUNET_NETWORK_test_pf (PF_INET6);
1200   v4_enabled = GNUNET_NETWORK_test_pf (PF_INET);
1201
1202   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c, "gns",
1203                                                             "ZONEKEY", &keyfile))
1204   {
1205     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1206                 "No private key for root zone specified!\n");
1207     GNUNET_SCHEDULER_shutdown ();
1208     return;
1209   }
1210
1211   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1212              "Using keyfile %s for root zone.\n", keyfile);
1213
1214   zone_key = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
1215   GNUNET_CRYPTO_ecc_key_get_public (zone_key, &pkey);
1216   GNUNET_CRYPTO_short_hash (&pkey,
1217                             sizeof(struct GNUNET_CRYPTO_EccPublicKey),
1218                             &zone_hash);
1219   GNUNET_free(keyfile);
1220   namestore_handle = GNUNET_NAMESTORE_connect (c);
1221   if (NULL == namestore_handle)
1222   {
1223     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1224                 _("Failed to connect to the namestore!\n"));
1225     GNUNET_SCHEDULER_shutdown ();
1226     return;
1227   }
1228   
1229   auto_import_pkey = GNUNET_NO;
1230   if (GNUNET_YES ==
1231       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1232                                             "AUTO_IMPORT_PKEY"))
1233   {
1234     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1235                 "Automatic PKEY import is enabled.\n");
1236     auto_import_pkey = GNUNET_YES;
1237   }
1238   put_interval = INITIAL_PUT_INTERVAL;
1239   zone_publish_time_window = DEFAULT_ZONE_PUBLISH_TIME_WINDOW;
1240
1241   if (GNUNET_OK ==
1242       GNUNET_CONFIGURATION_get_value_time (c, "gns",
1243                                            "ZONE_PUBLISH_TIME_WINDOW",
1244                                            &zone_publish_time_window))
1245   {
1246     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1247                 "Time window for zone iteration: %s\n",
1248                 GNUNET_STRINGS_relative_time_to_string (zone_publish_time_window, GNUNET_YES));
1249   }
1250   if (GNUNET_OK ==
1251       GNUNET_CONFIGURATION_get_value_number (c, "gns",
1252                                             "MAX_PARALLEL_BACKGROUND_QUERIES",
1253                                             &max_parallel_bg_queries))
1254   {
1255     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1256                 "Number of allowed parallel background queries: %llu\n",
1257                 max_parallel_bg_queries);
1258   }
1259
1260   if (GNUNET_YES ==
1261       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1262                                             "AUTO_IMPORT_CONFIRMATION_REQ"))
1263   {
1264     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1265                 "Auto import requires user confirmation\n");
1266     ignore_pending = GNUNET_YES;
1267   }
1268
1269   if (GNUNET_OK ==
1270       GNUNET_CONFIGURATION_get_value_time (c, "gns",
1271                                            "DEFAULT_LOOKUP_TIMEOUT",
1272                                            &default_lookup_timeout))
1273   {
1274     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1275                 "Default lookup timeout: %s\n",
1276                 GNUNET_STRINGS_relative_time_to_string (default_lookup_timeout,
1277                                                         GNUNET_YES));
1278   }
1279   
1280   dht_handle = GNUNET_DHT_connect (c,
1281                                    (unsigned int) max_parallel_bg_queries);
1282   if (NULL == dht_handle)
1283   {
1284     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1285                 _("Could not connect to DHT!\n"));
1286     GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1287     return;
1288   }
1289   
1290   if (GNUNET_SYSERR ==
1291       gns_resolver_init (namestore_handle, dht_handle, zone_hash, c,
1292                          max_parallel_bg_queries,
1293                          ignore_pending))
1294   {
1295     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1296                 _("Unable to initialize resolver!\n"));
1297     GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
1298     return;
1299   }
1300
1301   if (GNUNET_YES ==
1302       GNUNET_CONFIGURATION_get_value_yesno (c, "gns", "HIJACK_DNS"))
1303   {
1304     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1305                 "DNS hijacking enabled. Connecting to DNS service.\n");
1306
1307     if (GNUNET_SYSERR ==
1308         gns_interceptor_init (zone_hash, zone_key, c))
1309     {
1310       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1311                "Failed to enable the DNS interceptor!\n");
1312     }
1313   }
1314   
1315   /**
1316    * Schedule periodic put
1317    * for our records
1318    * We have roughly an hour for all records;
1319    */
1320   first_zone_iteration = GNUNET_YES;
1321   zone_publish_task = GNUNET_SCHEDULER_add_now (&publish_zone_dht_start, NULL);
1322   GNUNET_SERVER_add_handlers (server, handlers);
1323   statistics = GNUNET_STATISTICS_create ("gns", c);
1324   nc = GNUNET_SERVER_notification_context_create (server, 1);
1325   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1326                                 NULL);
1327 }
1328
1329
1330 /**
1331  * The main function for the GNS service.
1332  *
1333  * @param argc number of arguments from the command line
1334  * @param argv command line arguments
1335  * @return 0 ok, 1 on error
1336  */
1337 int
1338 main (int argc, char *const *argv)
1339 {
1340   int ret;
1341
1342   ret =
1343       (GNUNET_OK ==
1344        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1345                            NULL)) ? 0 : 1;
1346   return ret;
1347 }
1348
1349 /* end of gnunet-service-gns.c */