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