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