-remove pointless client handler, added more comments
[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  *    - Finish dht lookup
25  *    - Think about mixed dns queries (.gnunet and .org)
26  *    - The smaller FIXME issues all around
27  *
28  * @file gns/gnunet-service-gns.c
29  * @brief GNUnet GNS service
30  * @author Martin Schanzenbach
31  */
32 #include "platform.h"
33 #include "gnunet_util_lib.h"
34 #include "gnunet_transport_service.h"
35 #include "gnunet_dns_service.h"
36 #include "gnunet_dnsparser_lib.h"
37 #include "gnunet_dht_service.h"
38 #include "gnunet_namestore_service.h"
39 #include "gnunet_gns_service.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 struct GNUNET_GNS_QueryRecordList
47 {
48   /**
49    * DLL
50    */
51   struct GNUNET_GNS_QueryRecordList * next;
52   struct GNUNET_GNS_QueryRecordList * prev;
53
54   struct GNUNET_DNSPARSER_Record * record;
55 };
56
57 /**
58  * A result list for namestore queries
59  */
60 struct GNUNET_GNS_PendingQuery
61 {
62   /* the answer packet */
63   struct GNUNET_DNSPARSER_Packet *answer;
64
65   /* records to put into answer packet */
66   struct GNUNET_GNS_QueryRecordList * records_head;
67   struct GNUNET_GNS_QueryRecordList * records_tail;
68
69   int num_records;
70   int num_authority_records; //FIXME are all of our replies auth?
71   
72   char *name;
73   uint16_t type;
74   /* the dns request id */
75   int id; // FIXME can handle->request_id also be used here?
76
77   /* the request handle to reply to */
78   struct GNUNET_DNS_RequestHandle *request_handle;
79
80   /* hast this query been answered? */
81   int answered;
82
83   /* we have an authority in namestore that
84    * may be able to resolve
85    */
86   int authority_found;
87 };
88
89
90 /**
91  * Our handle to the DNS handler library
92  */
93 struct GNUNET_DNS_Handle *dns_handle;
94
95 /**
96  * Our handle to the DHT
97  */
98 struct GNUNET_DHT_Handle *dht_handle;
99
100 struct GNUNET_TIME_Relative dht_update_interval;
101
102 /**
103  * Our zone's private key
104  */
105 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
106
107 /**
108  * Our handle to the namestore service
109  */
110 struct GNUNET_NAMESTORE_Handle *namestore_handle;
111
112 /**
113  * The configuration the GNS service is running with
114  */
115 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
116
117 /**
118  * Our notification context.
119  */
120 static struct GNUNET_SERVER_NotificationContext *nc;
121
122 /**
123  * Our zone hash
124  */
125 GNUNET_HashCode *zone_hash;
126
127 /**
128  * Task run during shutdown.
129  *
130  * @param cls unused
131  * @param tc unused
132  */
133 static void
134 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
135 {
136   GNUNET_DNS_disconnect(dns_handle);
137   GNUNET_NAMESTORE_disconnect(namestore_handle, 0);
138   GNUNET_DHT_disconnect(dht_handle);
139 }
140
141 /**
142  * FIXME
143  * This is where it gets tricky
144  * First we store (cache) all replies. Simple.
145  * If we see an authority "closer" to the name
146  * we have to start a new query. Unless we get
147  * a resolution.
148  * It is important that the authority is closer
149  * because else we might end up in an endless loop
150  * (maybe keep track of queried keys?)
151  * Of course we could just limit the resolution
152  * with a timeout (makes sense for clients) but we need
153  * to know when to stop querying.
154  */
155 void
156 handle_dht_reply(void* cls,
157                  struct GNUNET_TIME_Absolute exp,
158                  const GNUNET_HashCode * key,
159                  const struct GNUNET_PeerIdentity *get_path,
160                  unsigned int get_path_length,
161                  const struct GNUNET_PeerIdentity *put_path,
162                  unsigned int put_path_length,
163                  enum GNUNET_BLOCK_Type type,
164                  size_t size, const void *data)
165 {
166 }
167
168 /**
169  * This is a callback function that should give us only PKEY
170  * records. Used to iteratively query the namestore for 'closest'
171  * authority.
172  *
173  * @param cls the pending query
174  * @param zone our zone hash
175  * @param name the name for which we need an authority
176  * @param record_type the type of record (PKEY)
177  * @param expiration expiration date of the record
178  * @param flags namestore record flags
179  * @param sig_loc the location of the record in the signature tree
180  * @param size the size of the record
181  * @param data the record data
182  */
183 void
184 process_auth_query(void* cls, const GNUNET_HashCode *zone,
185                    const char *name, uint32_t record_type,
186                    struct GNUNET_TIME_Absolute expiration,
187                    enum GNUNET_NAMESTORE_RecordFlags flags,
188                    const struct GNUNET_NAMESTORE_SignatureLocation *sig_loc,
189                    size_t size, const void *data)
190 {
191   struct GNUNET_GNS_PendingQuery *query;
192
193   query = (struct GNUNET_GNS_PendingQuery *)cls;
194   
195   /**
196    * No authority found
197    * FIXME We assume this will never return our authority
198    */
199   if ((NULL == data) && !query->authority_found)
200   {
201     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Find authority\n");
202     if (0 == strcmp(name, "gnunet"))
203     {
204       // Reached tld return nx
205       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "NX record\n");
206       return;
207     }
208     
209     //Move name to next level
210     while ((*name) != '.')
211       name++;
212
213     name++;
214     GNUNET_NAMESTORE_lookup_name(namestore_handle,
215                                  zone_hash,
216                                  name,
217                                  GNUNET_GNS_RECORD_PKEY,
218                                  &process_auth_query,
219                                  query);
220     return;
221   }
222   
223   /**
224    * We found a PKEY that may be able to help us
225    */
226   query->authority_found = 1;
227   GNUNET_HashCode *key = (GNUNET_HashCode*) data;
228   
229   //FIXME magic number
230   struct GNUNET_TIME_Relative timeout =
231     GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
232   GNUNET_DHT_get_start (dht_handle,
233                         timeout,
234                         GNUNET_BLOCK_TYPE_TEST, //TODO our plugin
235                         key,
236                         5, //replication
237                         GNUNET_DHT_RO_NONE,
238                         query->name, //xquery FIXME nobody will know this name
239                         strlen(query->name),
240                         &handle_dht_reply,
241                         query); //iter cls
242
243
244 }
245
246
247 /**
248  * Phase 2 of resolution.
249  * We did not find an entry for name in the namestore
250  * so we consult the dht after finding an appropriate NS
251  * in the namestore.
252  *
253  * @param query the pending query handle from the namestore lookup
254  */
255 void
256 lookup_dht(struct GNUNET_GNS_PendingQuery *query)
257 {
258   /**
259    * In this phase we first want to find the
260    * responsible authority in the namestore (a PKEY)
261    */
262   GNUNET_NAMESTORE_lookup_name(namestore_handle,
263                                zone_hash,
264                                query->name,
265                                GNUNET_GNS_RECORD_PKEY,
266                                &process_auth_query,
267                                query);
268 }
269
270 /**
271  * Reply to client with the result from our lookup.
272  *
273  * @param answer the pending query used in the lookup
274  */
275 void
276 reply_to_dns(struct GNUNET_GNS_PendingQuery *answer)
277 {
278   struct GNUNET_GNS_QueryRecordList *i;
279   struct GNUNET_DNSPARSER_Packet *packet;
280   struct GNUNET_DNSPARSER_Flags dnsflags;
281   int j;
282   size_t len;
283   int ret;
284   char *buf;
285   
286   packet = GNUNET_malloc(sizeof(struct GNUNET_DNSPARSER_Packet));
287   packet->answers =
288     GNUNET_malloc(sizeof(struct GNUNET_DNSPARSER_Record) * answer->num_records);
289   
290   len = sizeof(struct GNUNET_DNSPARSER_Record*);
291   j = 0;
292   for (i=answer->records_head; i != NULL; i=i->next)
293   {
294     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
295                "Adding %s to DNS response\n", i->record->name);
296     memcpy(&packet->answers[j], 
297            i->record,
298            sizeof (struct GNUNET_DNSPARSER_Record));
299     GNUNET_free(i->record);
300     j++;
301   }
302   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "after memcpy\n");
303   /* FIXME how to handle auth, additional etc */
304   packet->num_answers = answer->num_records;
305   packet->num_authority_records = answer->num_authority_records;
306
307   dnsflags.authoritative_answer = 1;
308   dnsflags.opcode = GNUNET_DNSPARSER_OPCODE_QUERY;
309   dnsflags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR; //not sure
310   dnsflags.query_or_response = 1;
311   packet->flags = dnsflags;
312
313   packet->id = answer->id;
314   
315   //FIXME this is silently discarded
316   ret = GNUNET_DNSPARSER_pack (packet,
317                                1024, /* FIXME magic from dns redirector */
318                                &buf,
319                                &len);
320   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
321              "Built DNS response! (ret=%d)\n", ret);
322   if (ret == GNUNET_OK)
323   {
324     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
325                "Answering DNS request\n");
326     GNUNET_DNS_request_answer(answer->request_handle,
327                               len,
328                               buf);
329     GNUNET_free(answer);
330     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Answered DNS request\n");
331     //FIXME return code, free datastructures
332   }
333   else
334   {
335     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
336                "Error building DNS response! (ret=%d)", ret);
337   }
338 }
339
340 /**
341  * Namestore calls this function if we have an entry for this name.
342  * (or data=null to indicate the lookup has finished)
343  *
344  * @param cls the pending query
345  * @param zone the zone of the lookup
346  * @param name the name looked up
347  * @param record_type the record type
348  * @param expiration lifetime of the record
349  * @param flags record flags
350  * @param sig_loc location of the record in the signature tree
351  * @param size the size of the record
352  * @param data the record data
353  */
354 static void
355 process_ns_result(void* cls, const GNUNET_HashCode *zone,
356                   const char *name, uint32_t record_type,
357                   struct GNUNET_TIME_Absolute expiration,
358                   enum GNUNET_NAMESTORE_RecordFlags flags,
359                   const struct GNUNET_NAMESTORE_SignatureLocation *sig_loc,
360                   size_t size, const void *data)
361 {
362   struct GNUNET_GNS_PendingQuery *query;
363   struct GNUNET_GNS_QueryRecordList *qrecord;
364   struct GNUNET_DNSPARSER_Record *record;
365   query = (struct GNUNET_GNS_PendingQuery *) cls;
366
367
368   if (NULL == data)
369   {
370     /**
371      * Lookup terminated
372      * Do we have what we need to answer?
373      * If not -> DHT Phase
374      */
375     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
376                "Namestore lookup terminated. (answered=%d)", query->answered);
377
378     if (query->answered)
379       reply_to_dns(query);
380     else
381       lookup_dht(query);
382
383   }
384   else
385   {
386     /**
387      * Record found
388      */
389     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
390                "Processing additional result for %s from namestore\n", name);
391
392     qrecord = GNUNET_malloc(sizeof(struct GNUNET_GNS_QueryRecordList));
393     record = GNUNET_malloc(sizeof(struct GNUNET_DNSPARSER_Record));
394     qrecord->record = record;
395
396     record->name = (char*)name;
397
398     /**
399      * FIXME for gns records this requires the dnsparser to be modified!
400      * or use RAW. But RAW data need serialization!
401      * maybe store record data appropriately in namestore to avoid a
402      * huge switch statement?
403      */
404     if (record_type == GNUNET_DNSPARSER_TYPE_A)
405     {
406       record->data.raw.data = (char*)data;
407       record->data.raw.data_len = size;
408     }
409     record->expiration_time = expiration;
410     record->type = record_type;
411     record->class = GNUNET_DNSPARSER_CLASS_INTERNET; /* srsly? */
412     
413     //FIXME authoritative answer if we find a result in namestore
414     if (flags == GNUNET_NAMESTORE_RF_AUTHORITY)
415     {
416       //query->num_authority_records++;
417     }
418     
419     /**
420      * This seems to take into account that the result could
421      * be different in name and or record type...
422      * but to me this does not make sense
423      */
424     if ((0 == strcmp(query->name , name)) &&
425         (query->type == record_type))
426     {
427       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Found answer to query!\n");
428       query->answered = 1;
429     }
430
431     query->num_records++;
432
433     /**
434      * FIXME watch for leaks
435      * properly free pendingquery when the time comes
436      */
437     GNUNET_CONTAINER_DLL_insert(query->records_head,
438                                 query->records_tail,
439                                 qrecord);
440   }
441 }
442
443
444 /**
445  * Phase 1 of name resolution
446  * Lookup local namestore. If we find a match there we can
447  * provide an authoritative answer without the dht.
448  * If we don't we have to start querying the dht.
449  *
450  * @param rh the request handle of the DNS request from a client
451  * @param name the name to look up
452  * @param id the id of the dns request (for the reply)
453  * @param type the record type to look for
454  */
455 void
456 lookup_namestore(struct GNUNET_DNS_RequestHandle *rh,
457                  char* name, uint16_t id, uint16_t type)
458 {
459   struct GNUNET_GNS_PendingQuery *answer;
460   
461   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "This is .gnunet (%s)!\n", name);
462   answer = GNUNET_malloc(sizeof (struct GNUNET_GNS_PendingQuery));
463   answer->id = id;
464   answer->name = name;
465   answer->type =type;
466   answer->request_handle = rh;
467   
468   GNUNET_NAMESTORE_lookup_name(namestore_handle,
469                                zone_hash,
470                                name,
471                                type,
472                                &process_ns_result,
473                                answer);
474 }
475
476 /**
477  * The DNS request handler
478  * Called for every incoming DNS request.
479  *
480  * @param cls closure
481  * @param rh request handle to user for reply
482  * @param request_length number of bytes in request
483  * @param request udp payload of the DNS request
484  */
485 void
486 handle_dns_request(void *cls,
487                    struct GNUNET_DNS_RequestHandle *rh,
488                    size_t request_length,
489                    const char *request)
490 {
491   struct GNUNET_DNSPARSER_Packet *p;
492   int namelen;
493   int i;
494   char *tail;
495
496   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Hijacked a DNS request...processing\n");
497   p = GNUNET_DNSPARSER_parse (request, request_length);
498   
499   if (NULL == p)
500   {
501     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
502                 "Received malformed DNS packet, leaving it untouched\n");
503     GNUNET_DNS_request_forward (rh);
504     return;
505   }
506   
507   /**
508    * Check tld and decide if we or
509    * legacy dns is responsible
510    *
511    * FIXME now in theory there could be more than 1 query in the request
512    * but if this is case we get into trouble:
513    * either we query the GNS or the DNS. We cannot do both!
514    * So I suggest to either only allow a single query per request or
515    * only allow GNS or DNS requests.
516    * The way it is implemented here now is buggy and will lead to erratic
517    * behaviour (if multiple queries are present).
518    */
519   for (i=0;i<p->num_queries;i++)
520   {
521     namelen = strlen(p->queries[i].name);
522     
523     if (namelen < 7) /* this can't be .gnunet */
524       continue;
525
526     /**
527      * FIXME Move our tld/root to config file
528      */
529     tail = p->queries[i].name+(namelen-7);
530     if (0 == strcmp(tail, ".gnunet"))
531     {
532       lookup_namestore(rh, p->queries[i].name, p->id, p->queries[i].type);
533     }
534     else
535     {
536       /**
537        * This request does not concern us. Forward to real DNS.
538        */
539       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
540                  "Request for %s is forwarded to DNS\n", p->queries[i].name);
541       GNUNET_DNS_request_forward (rh);
542     }
543   }
544 }
545
546 /**
547  * test function that stores some data in the namestore
548  */
549 void
550 put_some_records(void)
551 {
552   /* put a few records into namestore */
553   char* ipA = "1.2.3.4";
554   char* ipB = "5.6.7.8";
555   struct in_addr *alice = GNUNET_malloc(sizeof(struct in_addr));
556   struct in_addr *bob = GNUNET_malloc(sizeof(struct in_addr));
557   GNUNET_assert(1 == inet_pton (AF_INET, ipA, alice));
558   GNUNET_assert(1 == inet_pton (AF_INET, ipB, bob));
559   GNUNET_NAMESTORE_record_put (namestore_handle,
560                                zone_hash,
561                                "alice.gnunet",
562                                GNUNET_GNS_RECORD_TYPE_A,
563                                GNUNET_TIME_absolute_get_forever(),
564                                GNUNET_NAMESTORE_RF_AUTHORITY,
565                                NULL, //sig loc
566                                sizeof(struct in_addr),
567                                alice,
568                                NULL,
569                                NULL);
570   GNUNET_NAMESTORE_record_put (namestore_handle,
571                                zone_hash,
572                                "bob.gnunet",
573                                GNUNET_GNS_RECORD_TYPE_A,
574                                GNUNET_TIME_absolute_get_forever(),
575                                GNUNET_NAMESTORE_RF_AUTHORITY,
576                                NULL, //sig loc
577                                sizeof(struct in_addr),
578                                bob,
579                                NULL,
580                                NULL);
581 }
582
583 //Prototype... needed in put function
584 static void
585 update_zone_dht(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
586
587 /**
588  * Function used to put all records successively into the DHT.
589  * FIXME also serializes records. maybe do this somewhere else...
590  * FIXME don't store private records (maybe zone transfer does this)
591  *
592  * @param cls the closure (NULL)
593  * @param zone our root zone hash
594  * @param name the name of the record
595  * @param record_type the type of the record
596  * @param expiration lifetime of the record
597  * @param flags flags of the record
598  * @param sig_loc location of record in signature tree
599  * @param size size of the record
600  * @param record_data the record data
601  */
602 void
603 put_gns_record(void *cls, const GNUNET_HashCode *zone, const char *name,
604                uint32_t record_type, struct GNUNET_TIME_Absolute expiration,
605                enum GNUNET_NAMESTORE_RecordFlags flags,
606                const struct GNUNET_NAMESTORE_SignatureLocation *sig_loc,
607                size_t size, const void *record_data)
608 {
609   struct GNUNET_TIME_Relative timeout;
610
611   char* data;
612   char* data_ptr;
613   struct GNUNET_TIME_AbsoluteNBO exp_nbo;
614   exp_nbo = GNUNET_TIME_absolute_hton (expiration);
615   uint32_t namelen = htonl(strlen(name));
616   uint16_t flags_nbo = htons(flags);
617   uint64_t offset = GNUNET_htonll(sig_loc->offset);
618   uint32_t depth = htonl(sig_loc->depth);
619   uint32_t revision = htonl(sig_loc->revision);
620
621   /**
622    * I guess this can be done prettier
623    * FIXME extract into function, maybe even into different file
624    */
625   size_t record_len = sizeof(size_t) + sizeof(uint32_t) +
626     sizeof(uint16_t) +
627     sizeof(struct GNUNET_NAMESTORE_SignatureLocation) +
628     sizeof(uint32_t) + strlen(name) + size;
629   
630   record_type = htonl(record_type);
631
632   data = GNUNET_malloc(record_len);
633   
634   /* -_- */
635   data_ptr = data;
636   memcpy(data_ptr, &namelen, sizeof(size_t));
637   data_ptr += sizeof(size_t);
638
639   memcpy(data_ptr, name, namelen);
640   data_ptr += namelen;
641   
642   memcpy(data_ptr, &record_type, sizeof(uint32_t));
643   data_ptr += sizeof(uint32_t);
644
645   memcpy(data_ptr, &exp_nbo, sizeof(struct GNUNET_TIME_AbsoluteNBO));
646   data_ptr += sizeof(struct GNUNET_TIME_AbsoluteNBO);
647
648   memcpy(data_ptr, &flags_nbo, sizeof(uint16_t));
649   data_ptr += sizeof(uint16_t);
650
651   memcpy(data_ptr, &offset, sizeof(uint64_t));
652   data_ptr += sizeof(uint64_t);
653
654   memcpy(data_ptr, &depth, sizeof(uint32_t));
655   data_ptr += sizeof(uint32_t);
656   
657   memcpy(data_ptr, &revision, sizeof(uint32_t));
658   data_ptr += sizeof(uint32_t);
659
660   memcpy(data_ptr, &size, sizeof(uint32_t));
661   data_ptr += sizeof(uint32_t);
662
663   /**
664    * FIXME note that this only works with raw data in nbo
665    * write helper function that converts properly and returns buffer
666    */
667   memcpy(data_ptr, record_data, size);
668   data_ptr += size;
669   /*Doing this made me sad...*/
670
671   /**
672    * FIXME magic number 20 move to config file
673    */
674   timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20);
675
676   GNUNET_DHT_put (dht_handle, zone_hash,
677                   5, //replication level
678                   GNUNET_DHT_RO_NONE,
679                   GNUNET_BLOCK_TYPE_TEST, //FIXME todo block plugin
680                   (data_ptr-data),
681                   data,
682                   expiration, //FIXME from record makes sense? is absolute?
683                   timeout,
684                   NULL, //FIXME continuation needed? success check? yes ofc
685                   NULL); //cls for cont
686
687   /**
688    * Reschedule periodic put
689    */
690   GNUNET_SCHEDULER_add_delayed (dht_update_interval,
691                                 &update_zone_dht,
692                                 NULL);
693
694 }
695
696 /**
697  * Periodically iterate over our zone and store everything in dht
698  *
699  * @param cls NULL
700  * @param tc task context
701  */
702 static void
703 update_zone_dht(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
704 {
705   GNUNET_NAMESTORE_zone_transfer (namestore_handle, zone_hash,
706                                   &put_gns_record,
707                                   NULL);
708 }
709
710 /**
711  * Process GNS requests.
712  *
713  * @param cls closure
714  * @param server the initialized server
715  * @param c configuration to use
716  */
717 static void
718 run (void *cls, struct GNUNET_SERVER_Handle *server,
719      const struct GNUNET_CONFIGURATION_Handle *c)
720 {
721   
722   zone_key = GNUNET_CRYPTO_rsa_key_create ();
723   GNUNET_CRYPTO_hash(zone_key, GNUNET_CRYPTO_RSA_KEY_LENGTH,//FIXME is this ok?
724                      zone_hash);
725
726   nc = GNUNET_SERVER_notification_context_create (server, 1);
727
728   /* FIXME - do some config parsing 
729    *       - Maybe only hijack dns if option is set (HIJACK_DNS=1)
730    */
731
732   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
733                                 NULL);
734   /**
735    * Do gnunet dns init here
736    */
737   dns_handle = GNUNET_DNS_connect(c,
738                                   GNUNET_DNS_FLAG_PRE_RESOLUTION,
739                                   &handle_dns_request, /* rh */
740                                   NULL); /* Closure */
741
742   if (NULL == dns_handle)
743   {
744     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
745                "Failed to connect to the dnsservice!\n");
746   }
747
748   /**
749    * handle to our local namestore
750    */
751   namestore_handle = GNUNET_NAMESTORE_connect(c);
752
753   if (NULL == namestore_handle)
754   {
755     //FIXME do error handling;
756     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
757                "Failed to connect to the namestore!\n");
758   }
759
760   /**
761    * handle to the dht
762    */
763   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
764
765   if (NULL == dht_handle)
766   {
767     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
768   }
769
770   put_some_records(); //FIXME for testing
771   
772   /**
773    * Schedule periodic put
774    * for our records
775    */
776   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
777                                                       60); //FIXME from cfg
778   GNUNET_SCHEDULER_add_delayed (dht_update_interval,
779                                 &update_zone_dht,
780                                 NULL);
781
782 }
783
784
785 /**
786  * The main function for the GNS service.
787  *
788  * @param argc number of arguments from the command line
789  * @param argv command line arguments
790  * @return 0 ok, 1 on error
791  */
792 int
793 main (int argc, char *const *argv)
794 {
795   int ret;
796
797   ret =
798       (GNUNET_OK ==
799        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
800                            NULL)) ? 0 : 1;
801   return ret;
802 }
803
804 /* end of gnunet-service-gns.c */