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