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