-fix xquery
[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  * TODO:
24  *    - Write xquery and block plugin
25  *    - The smaller FIXME issues all around
26  *
27  * @file gns/gnunet-service-gns.c
28  * @brief GNUnet GNS service
29  * @author Martin Schanzenbach
30  */
31 #include "platform.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_transport_service.h"
34 #include "gnunet_dns_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gnunet_dht_service.h"
37 #include "gnunet_namestore_service.h"
38 #include "gnunet_gns_service.h"
39 #include "block_gns.h"
40 #include "gns.h"
41
42 /* Ignore for now not used anyway and probably never will */
43 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23
44 #define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24
45
46 /**
47  * Handle to a currenty pending resolution
48  */
49 struct GNUNET_GNS_ResolverHandle
50 {
51   /* The name to resolve */
52   char *name;
53
54   /* the request handle to reply to */
55   struct GNUNET_DNS_RequestHandle *request_handle;
56   
57   /* the dns parser packet received */
58   struct GNUNET_DNSPARSER_Packet *packet;
59   
60   /* the query parsed from the packet */
61
62   struct GNUNET_DNSPARSER_Query *query;
63   
64   /* has this query been answered? how many matches */
65   int answered;
66
67   /* the authoritative zone to query */
68   GNUNET_HashCode authority;
69
70   /* the name of the authoritative zone to query */
71   char *authority_name;
72
73   /**
74    * we have an authority in namestore that
75    * may be able to resolve
76    */
77   int authority_found;
78
79   /* a handle for dht lookups. should be NULL if no lookups are in progress */
80   struct GNUNET_DHT_GetHandle *get_handle;
81
82 };
83
84
85 /**
86  * Our handle to the DNS handler library
87  */
88 struct GNUNET_DNS_Handle *dns_handle;
89
90 /**
91  * Our handle to the DHT
92  */
93 struct GNUNET_DHT_Handle *dht_handle;
94
95 /**
96  * Our zone's private key
97  */
98 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
99
100 /**
101  * Our handle to the namestore service
102  * FIXME maybe need a second handle for iteration
103  */
104 struct GNUNET_NAMESTORE_Handle *namestore_handle;
105
106 /**
107  * Handle to iterate over our authoritative zone in namestore
108  */
109 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
110
111 /**
112  * The configuration the GNS service is running with
113  */
114 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
115
116 /**
117  * Our notification context.
118  */
119 static struct GNUNET_SERVER_NotificationContext *nc;
120
121 /**
122  * Our zone hash
123  */
124 GNUNET_HashCode zone_hash;
125
126 /**
127  * Our tld. Maybe get from config file
128  */
129 const char* gnunet_tld = ".gnunet";
130
131 /**
132  * Useful for zone update for DHT put
133  */
134 static int num_public_records =  3600;
135 struct GNUNET_TIME_Relative dht_update_interval;
136 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
137
138 /* Prototypes */
139 void reply_to_dns(struct GNUNET_GNS_ResolverHandle *answer, uint32_t rd_count,
140                   const struct GNUNET_NAMESTORE_RecordData *rd);
141 void resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
142
143 /**
144  * Task run during shutdown.
145  *
146  * @param cls unused
147  * @param tc unused
148  */
149 static void
150 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
151 {
152   /* Kill zone task for it may make the scheduler hang */
153   GNUNET_SCHEDULER_cancel(zone_update_taskid);
154
155   GNUNET_DNS_disconnect(dns_handle);
156   GNUNET_NAMESTORE_disconnect(namestore_handle, 0);
157   GNUNET_DHT_disconnect(dht_handle);
158 }
159
160 /**
161  * Callback when record data is put into namestore
162  *
163  * @param cls the closure
164  * @param success GNUNET_OK on success
165  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
166  */
167 void
168 on_namestore_record_put_result(void *cls,
169                                int32_t success,
170                                const char *emsg)
171 {
172   if (GNUNET_NO == success)
173   {
174     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
175     return;
176   }
177   else if (GNUNET_YES == success)
178   {
179     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
180                "records successfully put in namestore\n");
181     return;
182   }
183
184   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
185              "Error putting records into namestore: %s\n", emsg);
186 }
187
188 /**
189  * Function called when we get a result from the dht
190  * for our query
191  *
192  * @param cls the request handle
193  * @param exp lifetime
194  * @param key the key the record was stored under
195  * @param get_path get path
196  * @param get_path_length get path length
197  * @param put_path put path
198  * @param put_path_length put path length
199  * @param type the block type
200  * @param size the size of the record
201  * @param data the record data
202  */
203 void
204 process_authority_dht_result(void* cls,
205                  struct GNUNET_TIME_Absolute exp,
206                  const GNUNET_HashCode * key,
207                  const struct GNUNET_PeerIdentity *get_path,
208                  unsigned int get_path_length,
209                  const struct GNUNET_PeerIdentity *put_path,
210                  unsigned int put_path_length,
211                  enum GNUNET_BLOCK_Type type,
212                  size_t size, const void *data)
213 {
214   struct GNUNET_GNS_ResolverHandle *rh;
215   struct GNSNameRecordBlock *nrb;
216   struct GNSRecordBlock *rb;
217   uint32_t num_records;
218   char* name = NULL;
219   int i;
220   GNUNET_HashCode zone, name_hash;
221   
222   if (data == NULL)
223     return;
224   
225   //FIXME check expiration?
226   
227   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
228   nrb = (struct GNSNameRecordBlock*)data;
229   
230   GNUNET_DHT_get_stop (rh->get_handle);
231   rh->get_handle = NULL;
232   num_records = ntohl(nrb->rd_count);
233   struct GNUNET_NAMESTORE_RecordData rd[num_records];
234   name = (char*)&nrb[1];
235   rb = (struct GNSRecordBlock *)&name[strlen(name) + 1];
236
237   for (i=0; i<num_records; i++)
238   {
239   
240     rd[i].record_type = ntohl(rb->type);
241     rd[i].data_size = ntohl(rb->data_length);
242     rd[i].data = &rb[1];
243     rd[i].expiration = GNUNET_TIME_absolute_ntoh(rb->expiration);
244     rd[i].flags = ntohl(rb->flags);
245     
246     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
247                "Got name: %s (wanted %s)\n", name, rh->authority_name);
248     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
249                "Got type: %d raw %d (wanted %d)\n",
250                rd[i].record_type, rb->type, GNUNET_GNS_RECORD_PKEY);
251     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
252                "Got data length: %d\n", rd[i].data_size);
253     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
254                "Got flag %d\n", rd[i].flags);
255
256     if ((strcmp(name, rh->authority_name) == 0) &&
257         (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
258     {
259       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
260       rh->answered = 1;
261       GNUNET_CRYPTO_hash(
262                  (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *)rd[i].data,
263                  rd[i].data_size,
264                  &rh->authority);
265     }
266     rb = (struct GNSRecordBlock*)((char*)&rb[1] + rd[i].data_size);
267
268   }
269
270   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
271   GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
272
273   /* Save to namestore */
274   if (0 == GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone))
275   {
276     GNUNET_NAMESTORE_record_put (namestore_handle,
277                                &nrb->public_key,
278                                name,
279                                exp,
280                                num_records,
281                                rd,
282                                &nrb->signature,
283                                &on_namestore_record_put_result, //cont
284                                NULL); //cls
285   }
286   
287   if (rh->answered)
288   {
289     rh->answered = 0;
290     resolve_name(rh);
291     return;
292   }
293   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No authority in records\n");
294   reply_to_dns(rh, 0, NULL);
295 }
296
297 /**
298  * Start DHT lookup for a name -> PKEY (compare NS) record in
299  * query->authority's zone
300  *
301  * @param rh the pending gns query
302  * @param name the name of the PKEY record
303  */
304 void
305 resolve_authority_dht(struct GNUNET_GNS_ResolverHandle *rh)
306 {
307   uint32_t xquery;
308   struct GNUNET_TIME_Relative timeout;
309   GNUNET_HashCode name_hash;
310   GNUNET_HashCode lookup_key;
311
312   GNUNET_CRYPTO_hash(rh->authority_name,
313                      strlen(rh->authority_name),
314                      &name_hash);
315   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
316
317   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5);
318   
319   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
320   //FIXME how long to wait for results?
321   rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout,
322                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
323                        &lookup_key,
324                        5, //Replication level FIXME
325                        GNUNET_DHT_RO_NONE,
326                        &xquery,
327                        sizeof(xquery),
328                        &process_authority_dht_result,
329                        rh);
330
331 }
332
333 /**
334  * Function called when we get a result from the dht
335  * for our query
336  *
337  * @param cls the request handle
338  * @param exp lifetime
339  * @param key the key the record was stored under
340  * @param get_path get path
341  * @param get_path_length get path length
342  * @param put_path put path
343  * @param put_path_length put path length
344  * @param type the block type
345  * @param size the size of the record
346  * @param data the record data
347  */
348 void
349 process_name_dht_result(void* cls,
350                  struct GNUNET_TIME_Absolute exp,
351                  const GNUNET_HashCode * key,
352                  const struct GNUNET_PeerIdentity *get_path,
353                  unsigned int get_path_length,
354                  const struct GNUNET_PeerIdentity *put_path,
355                  unsigned int put_path_length,
356                  enum GNUNET_BLOCK_Type type,
357                  size_t size, const void *data)
358 {
359   struct GNUNET_GNS_ResolverHandle *rh;
360   struct GNSNameRecordBlock *nrb;
361   struct GNSRecordBlock *rb;
362   uint32_t num_records;
363   char* name = NULL;
364   int i;
365   GNUNET_HashCode zone, name_hash;
366   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
367   
368   if (data == NULL)
369     return;
370
371   //FIXME maybe check expiration here, check block type
372   
373   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
374   nrb = (struct GNSNameRecordBlock*)data;
375
376   GNUNET_DHT_get_stop (rh->get_handle);
377   rh->get_handle = NULL;
378   num_records = ntohl(nrb->rd_count);
379   struct GNUNET_NAMESTORE_RecordData rd[num_records];
380
381   name = (char*)&nrb[1];
382   rb = (struct GNSRecordBlock*)&name[strlen(name) + 1];
383   
384   for (i=0; i<num_records; i++)
385   {
386     rd[i].record_type = ntohl(rb->type);
387     rd[i].data_size = ntohl(rb->data_length);
388     rd[i].data = (char*)&rb[1];
389     rd[i].expiration = GNUNET_TIME_absolute_ntoh(rb->expiration);
390     rd[i].flags = ntohl(rb->flags);
391     
392     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
393                "Got name: %s (wanted %s)\n", name, rh->name);
394     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
395                "Got type: %d raw %d (wanted %d)\n",
396                rd[i].record_type, rb->type, rh->query->type);
397     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
398                "Got data length: %d\n", rd[i].data_size);
399     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
400                "Got flag %d\n", rd[i].flags);
401     
402     /* FIXME class? */
403     if ((strcmp(name, rh->name) == 0) &&
404        (rd[i].record_type == rh->query->type))
405     {
406       rh->answered++;
407     }
408
409     rb = (struct GNSRecordBlock*)((char*)&rb[1] + rd[i].data_size);
410
411   }
412
413   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
414   GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
415   
416   /**
417    * FIXME check pubkey against existing key in namestore?
418    * https://gnunet.org/bugs/view.php?id=2179
419    */
420
421   /* Save to namestore */
422   GNUNET_NAMESTORE_record_put (namestore_handle,
423                                &nrb->public_key,
424                                name,
425                                exp,
426                                num_records,
427                                rd,
428                                &nrb->signature,
429                                &on_namestore_record_put_result, //cont
430                                NULL); //cls
431   
432   if (rh->answered)
433     reply_to_dns(rh, num_records, rd);
434   else
435     reply_to_dns(rh, 0, NULL);
436
437 }
438
439 /**
440  * Start DHT lookup for a (name -> query->record_type) record in
441  * query->authority's zone
442  *
443  * @param rh the pending gns query context
444  * @param name the name to query record
445  */
446 void
447 resolve_name_dht(struct GNUNET_GNS_ResolverHandle *rh, const char* name)
448 {
449   uint32_t xquery;
450   struct GNUNET_TIME_Relative timeout;
451   GNUNET_HashCode name_hash;
452   GNUNET_HashCode lookup_key;
453   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
454
455   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
456   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
457   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
458   
459   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
460              "starting dht lookup for %s with key: %s\n",
461              name, (char*)&lookup_key_string);
462
463   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5);
464   
465   xquery = htonl(rh->query->type);
466   //FIXME how long to wait for results?
467   rh->get_handle = GNUNET_DHT_get_start(dht_handle, timeout,
468                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
469                        &lookup_key,
470                        5, //Replication level FIXME
471                        GNUNET_DHT_RO_NONE,
472                        &xquery, //xquery FIXME is this bad?
473                        sizeof(xquery),
474                        &process_name_dht_result,
475                        rh);
476
477 }
478
479 //Prototype
480 void
481 resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
482
483 /**
484  * This is a callback function that should give us only PKEY
485  * records. Used to query the namestore for the authority (PKEY)
486  * for 'name'
487  *
488  * @param cls the pending query
489  * @param key the key of the zone we did the lookup
490  * @param expiration expiration date of the record data set in the namestore
491  * @param name the name for which we need an authority
492  * @param rd_count the number of records with 'name'
493  * @param rd the record data
494  * @param signature the signature of the authority for the record data
495  */
496 void
497 process_authority_lookup(void* cls,
498                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
499                    struct GNUNET_TIME_Absolute expiration,
500                    const char *name,
501                    unsigned int rd_count,
502                    const struct GNUNET_NAMESTORE_RecordData *rd,
503                    const struct GNUNET_CRYPTO_RsaSignature *signature)
504 {
505   struct GNUNET_GNS_ResolverHandle *rh;
506   struct GNUNET_TIME_Relative remaining_time;
507   GNUNET_HashCode zone;
508
509   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
510   GNUNET_CRYPTO_hash(key,
511                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
512                      &zone);
513   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
514   
515   /**
516    * No authority found in namestore.
517    */
518   if (rd_count == 0)
519   {
520     /**
521      * We did not find an authority in the namestore
522      * _IF_ the current authoritative zone is us we cannot resolve
523      * _ELSE_ we can still check the _expired_ dht
524      */
525     if (0 != GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash) &&
526         (remaining_time.rel_value == 0))
527     {
528       resolve_authority_dht(rh);
529       return;
530     }
531     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority %s unknown\n",
532                rh->authority_name);
533     reply_to_dns(rh, 0, NULL);
534     return;
535   }
536
537   //Note only 1 pkey should have been returned.. anything else would be strange
538   /**
539    * We found an authority that may be able to help us
540    * move on with query
541    */
542   int i;
543   for (i=0; i<rd_count;i++)
544   {
545   
546     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
547       continue;
548     
549       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
550           == 0)
551       {
552         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
553         if (remaining_time.rel_value == 0)
554         {
555           GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
556                      "This dht entry is expired. Refreshing\n");
557           resolve_authority_dht(rh);
558         }
559
560         continue;
561       }
562
563       /**
564        * Resolve rest of query with new authority
565        */
566       GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
567       GNUNET_CRYPTO_hash(rd[i].data,
568                          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
569                          &rh->authority);
570       resolve_name(rh);
571       return;
572       
573   }
574     
575   /**
576    * no answers found
577    */
578   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
579              "Authority lookup successful but no PKEY... never get here\n");
580   reply_to_dns(rh, 0, NULL);
581 }
582
583
584 /**
585  * Reply to client with the result from our lookup.
586  *
587  * @param rh the request handle of the lookup
588  * @param rd_count the number of records to return
589  * @param rd the record data
590  */
591 void
592 reply_to_dns(struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
593              const struct GNUNET_NAMESTORE_RecordData *rd)
594 {
595   int i;
596   size_t len;
597   int ret;
598   char *buf;
599   struct GNUNET_DNSPARSER_Packet *packet = rh->packet;
600   struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
601   struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
602   packet->answers = answer_records;
603   packet->additional_records = additional_records;
604   
605   /**
606    * Put records in the DNS packet and modify it
607    * to a response
608    */
609   len = sizeof(struct GNUNET_DNSPARSER_Record*);
610   for (i=0; i < rd_count; i++)
611   {
612     
613     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
614                "Adding type %d to DNS response\n", rd[i].record_type);
615     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name);
616     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", rh->query->name);
617     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count);
618     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size);
619     
620     if (rd[i].record_type == rh->query->type)
621     {
622       answer_records[i].name = rh->query->name;
623       answer_records[i].type = rd[i].record_type;
624       answer_records[i].data.raw.data_len = rd[i].data_size;
625       answer_records[i].data.raw.data = (char*)rd[i].data;
626       answer_records[i].expiration_time = rd[i].expiration;
627       answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
628     }
629     else
630     {
631       additional_records[i].name = rh->query->name;
632       additional_records[i].type = rd[i].record_type;
633       additional_records[i].data.raw.data_len = rd[i].data_size;
634       additional_records[i].data.raw.data = (char*)rd[i].data;
635       additional_records[i].expiration_time = rd[i].expiration;
636       additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
637     }
638   }
639   
640   packet->num_answers = rh->answered;
641   packet->num_additional_records = rd_count-(rh->answered);
642   
643   if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
644     packet->flags.authoritative_answer = 1;
645   else
646     packet->flags.authoritative_answer = 0;
647
648   if (rd == NULL)
649     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
650   else
651     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
652   
653   packet->flags.query_or_response = 1;
654
655   
656   /**
657    * Reply to DNS
658    */
659   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
660              "Building DNS response\n");
661   ret = GNUNET_DNSPARSER_pack (packet,
662                                1024, /* FIXME magic from dns redirector */
663                                &buf,
664                                &len);
665   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
666              "Built DNS response! (ret=%d,len=%d)\n", ret, len);
667   if (ret == GNUNET_OK)
668   {
669     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
670                "Answering DNS request\n");
671     GNUNET_DNS_request_answer(rh->request_handle,
672                               len,
673                               buf);
674     //GNUNET_free(answer);
675     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n");
676   }
677   else
678   {
679     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
680                "Error building DNS response! (ret=%d)", ret);
681   }
682
683   GNUNET_free(rh->name);
684   GNUNET_free(rh);
685 }
686
687
688 /**
689  * Namestore calls this function if we have record for this name.
690  * (or with rd_count=0 to indicate no matches)
691  *
692  * @param cls the pending query
693  * @param key the key of the zone we did the lookup
694  * @param expiration expiration date of the namestore entry
695  * @param name the name for which we need an authority
696  * @param rd_count the number of records with 'name'
697  * @param rd the record data
698  * @param signature the signature of the authority for the record data
699  */
700 static void
701 process_authoritative_result(void* cls,
702                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
703                   struct GNUNET_TIME_Absolute expiration,
704                   const char *name, unsigned int rd_count,
705                   const struct GNUNET_NAMESTORE_RecordData *rd,
706                   const struct GNUNET_CRYPTO_RsaSignature *signature)
707 {
708   struct GNUNET_GNS_ResolverHandle *rh;
709   struct GNUNET_TIME_Relative remaining_time;
710   GNUNET_HashCode zone;
711
712   rh = (struct GNUNET_GNS_ResolverHandle *) cls;
713   GNUNET_CRYPTO_hash(key,
714                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
715                      &zone);
716   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
717
718   if (rd_count == 0)
719   {
720     /**
721      * Lookup terminated and no results
722      * -> DHT Phase unless data is recent
723      */
724     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
725                "Namestore lookup for %s terminated without results\n", name);
726     
727     /**
728      * if this is not our zone we cannot rely on the namestore to be
729      * complete. -> Query DHT
730      */
731     if (GNUNET_CRYPTO_hash_cmp(&zone, &zone_hash))
732     {
733       if (remaining_time.rel_value == 0)
734       {
735         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
736                    "trying dht...\n");
737         resolve_name_dht(rh, name);
738         return;
739       }
740       else
741       {
742         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
743                    "Record is still recent. No DHT lookup\n");
744       }
745     }
746
747     /**
748      * Our zone and no result? Cannot resolve TT
749      */
750     GNUNET_assert(rh->answered == 0);
751     reply_to_dns(rh, 0, NULL);
752     return;
753
754   }
755   else
756   {
757     
758     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
759                "Processing additional result %s from namestore\n", name);
760     int i;
761     for (i=0; i<rd_count;i++)
762     {
763       
764       if ((strcmp(name, rh->query->name) == 0)
765           && (rd[i].record_type != rh->query->type))
766         continue;
767       
768       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
769           == 0)
770       {
771         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
772         continue;
773       }
774       
775       rh->answered++;
776       
777     }
778     
779     /**
780      * no answers found
781      * consult dht if expired
782      */
783     if ((remaining_time.rel_value == 0) && (rh->answered == 0))
784     {
785       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
786                  "This dht entry is old. Refreshing.\n");
787       resolve_name_dht(rh, name);
788       return;
789     }
790     
791     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
792                rh->answered);
793
794     reply_to_dns(rh, rd_count, rd);
795   }
796 }
797
798 /**
799  * Determine if this name is canonical.
800  * i.e.
801  * a.b.gnunet  = not canonical
802  * a           = canonical
803  *
804  * @param name the name to test
805  * @return 1 if canonical
806  */
807 int
808 is_canonical(char* name)
809 {
810   uint32_t len = strlen(name);
811   int i;
812
813   for (i=0; i<len; i++)
814   {
815     if (*(name+i) == '.')
816       return 0;
817   }
818   return 1;
819 }
820
821 /**
822  * Move one level up in the domain hierarchy and return the
823  * passed top level domain.
824  *
825  * @param name the domain
826  * @return the tld
827  */
828 char* pop_tld(char* name)
829 {
830   uint32_t len;
831
832   if (is_canonical(name))
833     return NULL;
834
835   for (len = strlen(name); len > 0; len--)
836   {
837     if (*(name+len) == '.')
838       break;
839   }
840
841   if (len == 0)
842     return NULL;
843
844   name[len] = '\0';
845
846   return (name+len+1);
847 }
848
849
850 /**
851  * The first phase of resolution.
852  * First check if the name is canonical.
853  * If it is then try to resolve directly.
854  * If not then we first have to resolve the authoritative entities.
855  *
856  * @param rh the pending lookup
857  */
858 void
859 resolve_name(struct GNUNET_GNS_ResolverHandle *rh)
860 {
861   if (is_canonical(rh->name))
862   {
863     /* We only need to check the current zone's ns */
864     GNUNET_NAMESTORE_lookup_record(namestore_handle,
865                                &rh->authority,
866                                rh->name,
867                                rh->query->type,
868                                &process_authoritative_result,
869                                rh);
870   }
871   else
872   {
873     /* We have to resolve the authoritative entity first */
874     rh->authority_name = pop_tld(rh->name);
875     GNUNET_NAMESTORE_lookup_record(namestore_handle,
876                                  &rh->authority,
877                                  rh->authority_name,
878                                  GNUNET_GNS_RECORD_PKEY,
879                                  &process_authority_lookup,
880                                  rh);
881   }
882 }
883
884 /**
885  * Entry point for name resolution
886  * Setup a new query and try to resolve
887  *
888  * @param request the request handle of the DNS request from a client
889  * @param p the DNS query packet we received
890  * @param q the DNS query we received parsed from p
891  */
892 void
893 start_resolution(struct GNUNET_DNS_RequestHandle *request,
894                  struct GNUNET_DNSPARSER_Packet *p,
895                  struct GNUNET_DNSPARSER_Query *q)
896 {
897   struct GNUNET_GNS_ResolverHandle *rh;
898   
899   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting resolution for (%s)!\n",
900               q->name);
901   
902   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
903   rh->packet = p;
904   rh->query = q;
905   rh->authority = zone_hash;
906   
907   rh->name = GNUNET_malloc(strlen(q->name)
908                               - strlen(gnunet_tld) + 1);
909   memset(rh->name, 0,
910          strlen(q->name)-strlen(gnunet_tld) + 1);
911   memcpy(rh->name, q->name,
912          strlen(q->name)-strlen(gnunet_tld));
913
914   rh->request_handle = request;
915
916   /* Start resolution in our zone */
917   resolve_name(rh);
918 }
919
920 /**
921  * The DNS request handler
922  * Called for every incoming DNS request.
923  *
924  * @param cls closure
925  * @param rh request handle to user for reply
926  * @param request_length number of bytes in request
927  * @param request udp payload of the DNS request
928  */
929 void
930 handle_dns_request(void *cls,
931                    struct GNUNET_DNS_RequestHandle *rh,
932                    size_t request_length,
933                    const char *request)
934 {
935   struct GNUNET_DNSPARSER_Packet *p;
936   char *tldoffset;
937
938   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n");
939   p = GNUNET_DNSPARSER_parse (request, request_length);
940   
941   if (NULL == p)
942   {
943     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
944                 "Received malformed DNS packet, leaving it untouched\n");
945     GNUNET_DNS_request_forward (rh);
946     return;
947   }
948   
949   /**
950    * Check tld and decide if we or
951    * legacy dns is responsible
952    *
953    * FIXME now in theory there could be more than 1 query in the request
954    * but if this is case we get into trouble:
955    * either we query the GNS or the DNS. We cannot do both!
956    * So I suggest to either only allow a single query per request or
957    * only allow GNS or DNS requests.
958    * The way it is implemented here now is buggy and will lead to erratic
959    * behaviour (if multiple queries are present).
960    */
961   if (p->num_queries == 0)
962   {
963     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
964                 "No Queries in DNS packet... forwarding\n");
965     GNUNET_DNS_request_forward (rh);
966   }
967
968   if (p->num_queries > 1)
969   {
970     /* Note: We could also look for .gnunet */
971     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
972                 ">1 queriy in DNS packet... odd. We only process #1\n");
973   }
974
975   
976   /**
977    * Check for .gnunet
978    */
979   tldoffset = p->queries[0].name + strlen(p->queries[0].name);
980
981   while ((*tldoffset) != '.')
982     tldoffset--;
983   
984   if (0 == strcmp(tldoffset, gnunet_tld))
985   {
986     start_resolution(rh, p, p->queries);
987   }
988   else
989   {
990     /**
991      * This request does not concern us. Forward to real DNS.
992      */
993     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
994                "Request for %s is forwarded to DNS\n", p->queries[0].name);
995     GNUNET_DNS_request_forward (rh);
996   }
997
998 }
999
1000 /**
1001  * test function that stores some data in the namestore
1002  * This will also be replaced by a test progrm that
1003  * directl interfaces with the namestore
1004  */
1005 void
1006 put_some_records(void)
1007 {
1008   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Populating namestore\n");
1009   /* put an A record into namestore FIXME use gnunet.org */
1010   char* ipB = "5.6.7.8";
1011
1012   struct in_addr *web = GNUNET_malloc(sizeof(struct in_addr));
1013   struct GNUNET_NAMESTORE_RecordData rdb_web;
1014
1015   GNUNET_assert(1 == inet_pton (AF_INET, ipB, web));
1016
1017   rdb_web.data_size = sizeof(struct in_addr);
1018   rdb_web.data = web;
1019   rdb_web.record_type = GNUNET_DNSPARSER_TYPE_A;
1020   rdb_web.expiration = GNUNET_TIME_absolute_get_forever ();
1021   
1022   GNUNET_NAMESTORE_record_create (namestore_handle,
1023                                   zone_key,
1024                                   "www",
1025                                   &rdb_web,
1026                                   NULL,
1027                                   NULL);
1028 }
1029
1030 /**
1031  * Method called periodicattluy that triggers
1032  * iteration over root zone
1033  *
1034  * @param cls closure
1035  * @param tc task context
1036  */
1037 void
1038 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1039 {
1040   GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1041 }
1042
1043 /**
1044  * Continuation for DHT put
1045  *
1046  * @param cls closure
1047  * @param tc task context
1048  */
1049 void
1050 record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1051 {
1052   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
1053 }
1054
1055 /* prototype */
1056 static void
1057 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1058
1059 /**
1060  * Function used to put all records successively into the DHT.
1061  * FIXME bug here
1062  *
1063  * @param cls the closure (NULL)
1064  * @param key the public key of the authority (ours)
1065  * @param expiration lifetime of the namestore entry
1066  * @param name the name of the records
1067  * @param rd_count the number of records in data
1068  * @param rd the record data
1069  * @param signature the signature for the record data
1070  */
1071 void
1072 put_gns_record(void *cls,
1073                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1074                 struct GNUNET_TIME_Absolute expiration,
1075                 const char *name,
1076                 unsigned int rd_count,
1077                 const struct GNUNET_NAMESTORE_RecordData *rd,
1078                 const struct GNUNET_CRYPTO_RsaSignature *signature)
1079 {
1080   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1081              "Putting records for %s into the DHT\n", name);
1082   struct GNUNET_TIME_Relative timeout;
1083   struct GNSNameRecordBlock *nrb;
1084   struct GNSRecordBlock *rb;
1085   GNUNET_HashCode name_hash;
1086   GNUNET_HashCode xor_hash;
1087   struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string;
1088   int i;
1089   uint32_t rd_payload_length;
1090
1091   /* we're done */
1092   if (NULL == name)
1093   {
1094     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished\n");
1095     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1096     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start,
1097                                                    NULL);
1098     return;
1099   }
1100   
1101   rd_payload_length = rd_count * sizeof(struct GNSRecordBlock);
1102   rd_payload_length += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1103   
1104   /* calculate payload size */
1105   for (i=0; i<rd_count; i++)
1106   {
1107     rd_payload_length += rd[i].data_size;
1108   }
1109   
1110   nrb = GNUNET_malloc(rd_payload_length);
1111   
1112   if (signature != NULL)
1113     memcpy(&nrb->signature, signature,
1114          sizeof(struct GNUNET_CRYPTO_RsaSignature));
1115   //FIXME signature purpose
1116   memcpy(&nrb->public_key, key,
1117          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1118
1119   nrb->rd_count = htonl(rd_count);
1120
1121   memcpy(&nrb[1], name, strlen(name) + 1); //FIXME is this 0 terminated??
1122
1123   rb = (struct GNSRecordBlock *)((char*)&nrb[1] + strlen(name) + 1);
1124
1125   for (i=0; i<rd_count; i++)
1126   {
1127     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Read record with type %d\n",
1128                rd[i].record_type);
1129     rb->type = htonl(rd[i].record_type);
1130     rb->expiration = GNUNET_TIME_absolute_hton(rd[i].expiration);
1131     rb->data_length = htonl(rd[i].data_size);
1132     rb->flags = htonl(rd[i].flags);
1133     memcpy(&rb[1], rd[i].data, rd[i].data_size);
1134     rb = &rb[1] + rd[i].data_size;
1135   }
1136
1137   /**
1138    * FIXME magic number 20 move to config file
1139    * DHT_WAIT_TIMEOUT
1140    */
1141   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
1142   
1143   /*
1144    * calculate DHT key: H(name) xor H(pubkey)
1145    */
1146   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1147   GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1148   GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string);
1149   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1150              "putting records for %s under key: %s with size %d\n",
1151              name, (char*)&xor_hash_string, rd_payload_length);
1152
1153   GNUNET_DHT_put (dht_handle, &xor_hash,
1154                   5, //replication level
1155                   GNUNET_DHT_RO_NONE,
1156                   GNUNET_BLOCK_TYPE_GNS_NAMERECORD, //FIXME todo block plugin
1157                   rd_payload_length,
1158                   (char*)nrb,
1159                   expiration,
1160                   timeout,
1161                   &record_dht_put, //FIXME continuation needed? success check? yes ofc
1162                   NULL); //cls for cont
1163   
1164   num_public_records++;
1165
1166   /**
1167    * Reschedule periodic put
1168    */
1169   zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1170                                 &update_zone_dht_next,
1171                                 NULL);
1172
1173 }
1174
1175 /**
1176  * Puts a single trusted entity into the
1177  * namestore. Will be replaced in a testcase
1178  * that directly interacts with a persistent
1179  * namestore.
1180  *
1181  * @param name name of entity
1182  * @param keyfile keyfile
1183  */
1184 void
1185 put_trusted(char* name, char* keyfile)
1186 {
1187   struct GNUNET_NAMESTORE_RecordData rd;
1188   struct GNUNET_CRYPTO_RsaPrivateKey *key;
1189   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *pkey;
1190   pkey = GNUNET_malloc(sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1191
1192   key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1193   GNUNET_CRYPTO_rsa_key_get_public (key, pkey);
1194   rd.data = pkey;
1195   rd.expiration = GNUNET_TIME_absolute_get_forever ();
1196   rd.data_size = sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded);
1197   rd.record_type = GNUNET_GNS_RECORD_PKEY;
1198
1199   GNUNET_NAMESTORE_record_create (namestore_handle,
1200                                   zone_key,
1201                                   name,
1202                                   &rd,
1203                                   NULL,
1204                                   NULL);
1205 }
1206
1207
1208
1209 /**
1210  * Periodically iterate over our zone and store everything in dht
1211  *
1212  * @param cls NULL
1213  * @param tc task context
1214  */
1215 static void
1216 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1217 {
1218   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting DHT zone update!\n");
1219   if (0 == num_public_records)
1220   {
1221     dht_update_interval = GNUNET_TIME_relative_multiply(
1222                                                       GNUNET_TIME_UNIT_SECONDS,
1223                                                       1);
1224   }
1225   else
1226   {
1227     dht_update_interval = GNUNET_TIME_relative_multiply(
1228                                                       GNUNET_TIME_UNIT_SECONDS,
1229                                                      (3600/num_public_records));
1230   }
1231   num_public_records = 0; //start counting again
1232   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1233                                                           &zone_hash,
1234                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
1235                                                           GNUNET_NAMESTORE_RF_PRIVATE,
1236                                                           &put_gns_record,
1237                                                           NULL);
1238 }
1239
1240 /**
1241  * Process GNS requests.
1242  *
1243  * @param cls closure
1244  * @param server the initialized server
1245  * @param c configuration to use
1246  */
1247 static void
1248 run (void *cls, struct GNUNET_SERVER_Handle *server,
1249      const struct GNUNET_CONFIGURATION_Handle *c)
1250 {
1251   
1252   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
1253
1254   char* keyfile;
1255   char* trusted_entities;
1256   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
1257
1258   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns",
1259                                              "ZONEKEY", &keyfile))
1260   {
1261     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1262                 "No private key for root zone specified%s!\n", keyfile);
1263     GNUNET_SCHEDULER_shutdown(0);
1264     return;
1265   }
1266
1267   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1268   GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
1269
1270   GNUNET_CRYPTO_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1271                      &zone_hash);
1272   
1273   nc = GNUNET_SERVER_notification_context_create (server, 1);
1274
1275   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
1276                                 NULL);
1277
1278   if (GNUNET_YES ==
1279       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
1280                                             "HIJACK_DNS"))
1281   {
1282     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1283                "DNS hijacking enabled... connecting to service.\n");
1284     /**
1285      * Do gnunet dns init here
1286      */
1287     dns_handle = GNUNET_DNS_connect(c,
1288                                     GNUNET_DNS_FLAG_PRE_RESOLUTION,
1289                                     &handle_dns_request, /* rh */
1290                                     NULL); /* Closure */
1291     if (NULL == dns_handle)
1292     {
1293       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1294                "Failed to connect to the dnsservice!\n");
1295     }
1296   }
1297
1298   
1299
1300   /**
1301    * handle to our local namestore
1302    */
1303   namestore_handle = GNUNET_NAMESTORE_connect(c);
1304
1305   if (NULL == namestore_handle)
1306   {
1307     //FIXME do error handling;
1308     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1309                "Failed to connect to the namestore!\n");
1310     GNUNET_SCHEDULER_shutdown(0);
1311     return;
1312   }
1313   
1314   char* trusted_start;
1315   char* trusted_name;
1316   char *trusted_key;
1317   int trusted_len;
1318   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (c, "gns",
1319                                                       "TRUSTED",
1320                                                       &trusted_entities))
1321   {
1322     trusted_start = trusted_entities;
1323     trusted_len = strlen(trusted_entities);
1324     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1325                "Found trusted entities in config file, importing\n");
1326     while ((trusted_entities-trusted_start) < trusted_len)
1327     {
1328       trusted_name = trusted_entities;
1329       while (*trusted_entities != ':')
1330         trusted_entities++;
1331       *trusted_entities = '\0';
1332       trusted_entities++;
1333       trusted_key = trusted_entities;
1334       while (*trusted_entities != ',' && (*trusted_entities != '\0'))
1335         trusted_entities++;
1336       *trusted_entities = '\0';
1337       trusted_entities++;
1338       
1339       if (GNUNET_YES == GNUNET_DISK_file_test (trusted_key))
1340       {
1341         GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Adding %s:%s to root zone\n",
1342                  trusted_name,
1343                  trusted_key);
1344         put_trusted(trusted_name, trusted_key);
1345       }
1346       else
1347       {
1348         GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Keyfile %s does not exist!\n",
1349                    trusted_key);
1350         //put_trusted(trusted_name, trusted_key); //FIXME for testing
1351       }
1352     }
1353
1354   }
1355
1356   /**
1357    * handle to the dht
1358    */
1359   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
1360
1361   if (NULL == dht_handle)
1362   {
1363     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
1364   }
1365
1366   put_some_records(); //FIXME for testing
1367   
1368   /**
1369    * Schedule periodic put
1370    * for our records
1371    * We have roughly an hour for all records;
1372    */
1373   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
1374                                                       1);
1375   zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
1376
1377 }
1378
1379
1380 /**
1381  * The main function for the GNS service.
1382  *
1383  * @param argc number of arguments from the command line
1384  * @param argv command line arguments
1385  * @return 0 ok, 1 on error
1386  */
1387 int
1388 main (int argc, char *const *argv)
1389 {
1390   int ret;
1391
1392   ret =
1393       (GNUNET_OK ==
1394        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
1395                            NULL)) ? 0 : 1;
1396   return ret;
1397 }
1398
1399 /* end of gnunet-service-gns.c */