-shortening in cli app (in progress)
[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 #define DHT_OPERATION_TIMEOUT  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
43 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
44 #define DHT_GNS_REPLICATION_LEVEL 5
45 #define MAX_DNS_LABEL_LENGTH 63
46
47 /* Ignore for now not used anyway and probably never will */
48 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP 23
49 #define GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT 24
50 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN 25
51 #define GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT 26
52
53
54 struct AuthorityChain
55 {
56   struct AuthorityChain *prev;
57
58   struct AuthorityChain *next;
59
60   GNUNET_HashCode zone;
61
62   /* (local) name of the authority */
63   char* name;
64
65   /* was the ns entry fresh */
66   int fresh;
67 };
68
69 struct GNUNET_GNS_ResolverHandle;
70
71 typedef void (*ResolutionResultProcessor) (void *cls,
72                                   struct GNUNET_GNS_ResolverHandle *rh,
73                                   uint32_t rd_count,
74                                   const struct GNUNET_NAMESTORE_RecordData *rd);
75
76 enum ResolutionStatus
77 {
78   EXISTS = 1,
79   EXPIRED = 2
80 };
81
82 /**
83  * Handle to a currenty pending resolution
84  */
85 struct GNUNET_GNS_ResolverHandle
86 {
87   /* The name to resolve */
88   char *name;
89
90   /* the request handle to reply to */
91   struct GNUNET_DNS_RequestHandle *request_handle;
92   
93   /* the dns parser packet received */
94   struct GNUNET_DNSPARSER_Packet *packet;
95   
96   /* the query parsed from the packet */
97
98   struct GNUNET_DNSPARSER_Query *query;
99   
100   /* has this query been answered? how many matches */
101   int answered;
102
103   /* the authoritative zone to query */
104   GNUNET_HashCode authority;
105
106   /* the name of the authoritative zone to query */
107   char *authority_name;
108
109   /**
110    * we have an authority in namestore that
111    * may be able to resolve
112    */
113   int authority_found;
114
115   /* a handle for dht lookups. should be NULL if no lookups are in progress */
116   struct GNUNET_DHT_GetHandle *get_handle;
117
118   /* timeout task for dht lookups */
119   GNUNET_SCHEDULER_TaskIdentifier dht_timeout_task;
120
121   ResolutionResultProcessor proc;
122
123   void* proc_cls;
124
125   struct AuthorityChain *authority_chain_head;
126   struct AuthorityChain *authority_chain_tail;
127
128   enum ResolutionStatus status;
129
130 };
131
132 struct ClientShortenHandle
133 {
134   struct GNUNET_SERVER_Client *client;
135   uint64_t unique_id;
136   GNUNET_HashCode key;
137   char* name;
138   uint32_t offset;
139 };
140
141 /**
142  * Our handle to the DNS handler library
143  */
144 struct GNUNET_DNS_Handle *dns_handle;
145
146 /**
147  * Our handle to the DHT
148  */
149 struct GNUNET_DHT_Handle *dht_handle;
150
151 /**
152  * Our zone's private key
153  */
154 struct GNUNET_CRYPTO_RsaPrivateKey *zone_key;
155
156 /**
157  * Our handle to the namestore service
158  * FIXME maybe need a second handle for iteration
159  */
160 struct GNUNET_NAMESTORE_Handle *namestore_handle;
161
162 /**
163  * Handle to iterate over our authoritative zone in namestore
164  */
165 struct GNUNET_NAMESTORE_ZoneIterator *namestore_iter;
166
167 /**
168  * The configuration the GNS service is running with
169  */
170 const struct GNUNET_CONFIGURATION_Handle *GNS_cfg;
171
172 /**
173  * Our notification context.
174  */
175 static struct GNUNET_SERVER_NotificationContext *nc;
176
177 /**
178  * Our zone hash
179  */
180 GNUNET_HashCode zone_hash;
181
182 /**
183  * Our tld. Maybe get from config file
184  */
185 const char* gnunet_tld = ".gnunet";
186
187 /**
188  * Useful for zone update for DHT put
189  */
190 static int num_public_records =  3600;
191 struct GNUNET_TIME_Relative dht_update_interval;
192 GNUNET_SCHEDULER_TaskIdentifier zone_update_taskid = GNUNET_SCHEDULER_NO_TASK;
193
194 //static void resolve_name(struct GNUNET_GNS_ResolverHandle *rh);
195
196 /**
197  * Reply to client with the result from our lookup.
198  *
199  * @param rh the request handle of the lookup
200  * @param rd_count the number of records to return
201  * @param rd the record data
202  */
203 static void
204 reply_to_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh, uint32_t rd_count,
205              const struct GNUNET_NAMESTORE_RecordData *rd)
206 {
207   int i;
208   size_t len;
209   int ret;
210   char *buf;
211   struct GNUNET_DNSPARSER_Packet *packet = rh->packet;
212   struct GNUNET_DNSPARSER_Record answer_records[rh->answered];
213   struct GNUNET_DNSPARSER_Record additional_records[rd_count-(rh->answered)];
214   packet->answers = answer_records;
215   packet->additional_records = additional_records;
216   
217   /**
218    * Put records in the DNS packet and modify it
219    * to a response
220    */
221   len = sizeof(struct GNUNET_DNSPARSER_Record*);
222   for (i=0; i < rd_count; i++)
223   {
224     
225     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
226                "Adding type %d to DNS response\n", rd[i].record_type);
227     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Name: %s\n", rh->name);
228     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "QName: %s\n", rh->query->name);
229     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record %d/%d\n", i+1, rd_count);
230     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Record len %d\n", rd[i].data_size);
231     
232     if (rd[i].record_type == rh->query->type)
233     {
234       answer_records[i].name = rh->query->name;
235       answer_records[i].type = rd[i].record_type;
236       answer_records[i].data.raw.data_len = rd[i].data_size;
237       answer_records[i].data.raw.data = (char*)rd[i].data;
238       answer_records[i].expiration_time = rd[i].expiration;
239       answer_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
240     }
241     else
242     {
243       additional_records[i].name = rh->query->name;
244       additional_records[i].type = rd[i].record_type;
245       additional_records[i].data.raw.data_len = rd[i].data_size;
246       additional_records[i].data.raw.data = (char*)rd[i].data;
247       additional_records[i].expiration_time = rd[i].expiration;
248       additional_records[i].class = GNUNET_DNSPARSER_CLASS_INTERNET;//hmmn
249     }
250   }
251   
252   packet->num_answers = rh->answered;
253   packet->num_additional_records = rd_count-(rh->answered);
254   
255   if (0 == GNUNET_CRYPTO_hash_cmp(&rh->authority, &zone_hash))
256     packet->flags.authoritative_answer = 1;
257   else
258     packet->flags.authoritative_answer = 0;
259
260   if (rd == NULL)
261     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NAME_ERROR;
262   else
263     packet->flags.return_code = GNUNET_DNSPARSER_RETURN_CODE_NO_ERROR;
264   
265   packet->flags.query_or_response = 1;
266
267   
268   /**
269    * Reply to DNS
270    */
271   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
272              "Building DNS response\n");
273   ret = GNUNET_DNSPARSER_pack (packet,
274                                1024, /* FIXME magic from dns redirector */
275                                &buf,
276                                &len);
277   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
278              "Built DNS response! (ret=%d,len=%d)\n", ret, len);
279   if (ret == GNUNET_OK)
280   {
281     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
282                "Answering DNS request\n");
283     GNUNET_DNS_request_answer(rh->request_handle,
284                               len,
285                               buf);
286     //GNUNET_free(answer);
287     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Answered DNS request\n");
288   }
289   else
290   {
291     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
292                "Error building DNS response! (ret=%d)", ret);
293   }
294
295   GNUNET_free(rh->name);
296   GNUNET_free(rh);
297 }
298
299
300 /**
301  * Task run during shutdown.
302  *
303  * @param cls unused
304  * @param tc unused
305  */
306 static void
307 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
308 {
309   /* Kill zone task for it may make the scheduler hang */
310   if (zone_update_taskid)
311     GNUNET_SCHEDULER_cancel(zone_update_taskid);
312
313   GNUNET_DNS_disconnect(dns_handle);
314   GNUNET_NAMESTORE_disconnect(namestore_handle, 1);
315   GNUNET_DHT_disconnect(dht_handle);
316 }
317
318 /**
319  * Callback when record data is put into namestore
320  *
321  * @param cls the closure
322  * @param success GNUNET_OK on success
323  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
324  */
325 void
326 on_namestore_record_put_result(void *cls,
327                                int32_t success,
328                                const char *emsg)
329 {
330   if (GNUNET_NO == success)
331   {
332     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
333     return;
334   }
335   else if (GNUNET_YES == success)
336   {
337     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
338                "records successfully put in namestore\n");
339     return;
340   }
341
342   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
343              "Error putting records into namestore: %s\n", emsg);
344 }
345
346 /**
347  * Handle timeout for DHT requests
348  *
349  * @param cls the request handle as closure
350  * @param tc the task context
351  */
352 static void
353 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
354 {
355   struct GNUNET_GNS_ResolverHandle *rh = cls;
356
357   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
358              "dht lookup for query %s (type=%d) timed out.\n",
359              rh->name, rh->query->type);
360
361   GNUNET_DHT_get_stop (rh->get_handle);
362   rh->proc(rh->proc_cls, rh, 0, NULL);
363 }
364
365
366
367 /**
368  * Function called when we get a result from the dht
369  * for our query
370  *
371  * @param cls the request handle
372  * @param exp lifetime
373  * @param key the key the record was stored under
374  * @param get_path get path
375  * @param get_path_length get path length
376  * @param put_path put path
377  * @param put_path_length put path length
378  * @param type the block type
379  * @param size the size of the record
380  * @param data the record data
381  */
382 static void
383 process_record_dht_result(void* cls,
384                  struct GNUNET_TIME_Absolute exp,
385                  const GNUNET_HashCode * key,
386                  const struct GNUNET_PeerIdentity *get_path,
387                  unsigned int get_path_length,
388                  const struct GNUNET_PeerIdentity *put_path,
389                  unsigned int put_path_length,
390                  enum GNUNET_BLOCK_Type type,
391                  size_t size, const void *data)
392 {
393   struct GNUNET_GNS_ResolverHandle *rh;
394   struct GNSNameRecordBlock *nrb;
395   uint32_t num_records;
396   char* name = NULL;
397   char* rd_data = (char*)data;
398   int i;
399   int rd_size;
400   
401   GNUNET_HashCode zone, name_hash;
402   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
403   
404   if (data == NULL)
405     return;
406
407   //FIXME maybe check expiration here, check block type
408   
409   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
410   nrb = (struct GNSNameRecordBlock*)data;
411   
412   /* stop lookup and timeout task */
413   GNUNET_DHT_get_stop (rh->get_handle);
414   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
415   
416   rh->get_handle = NULL;
417   name = (char*)&nrb[1];
418   num_records = ntohl(nrb->rd_count);
419   {
420     struct GNUNET_NAMESTORE_RecordData rd[num_records];
421
422     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
423     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
424   
425     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
426                                                                rd_data,
427                                                                num_records,
428                                                                rd))
429     {
430       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
431       return;
432     }
433
434     for (i=0; i<num_records; i++)
435     {
436       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
437                "Got name: %s (wanted %s)\n", name, rh->name);
438       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
439                "Got type: %d (wanted %d)\n",
440                rd[i].record_type, rh->query->type);
441       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
442                "Got data length: %d\n", rd[i].data_size);
443       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
444                "Got flag %d\n", rd[i].flags);
445     
446      if ((strcmp(name, rh->name) == 0) &&
447          (rd[i].record_type == rh->query->type))
448       {
449         rh->answered++;
450       }
451
452     }
453
454     GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
455     GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
456   
457     /**
458      * FIXME check pubkey against existing key in namestore?
459      * https://gnunet.org/bugs/view.php?id=2179
460      */
461
462     /* Save to namestore */
463     GNUNET_NAMESTORE_record_put (namestore_handle,
464                                  &nrb->public_key,
465                                  name,
466                                  exp,
467                                  num_records,
468                                  rd,
469                                  &nrb->signature,
470                                  &on_namestore_record_put_result, //cont
471                                  NULL); //cls
472   
473     if (rh->answered)
474       rh->proc(rh->proc_cls, rh, num_records, rd);
475     else
476       rh->proc(rh->proc_cls, rh, 0, NULL);
477   }
478
479 }
480
481
482 /**
483  * Start DHT lookup for a (name -> query->record_type) record in
484  * rh->authority's zone
485  *
486  * @param rh the pending gns query context
487  * @param name the name to query record
488  */
489 static void
490 resolve_record_from_dht(struct GNUNET_GNS_ResolverHandle *rh)
491 {
492   uint32_t xquery;
493   GNUNET_HashCode name_hash;
494   GNUNET_HashCode lookup_key;
495   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
496
497   GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
498   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
499   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
500   
501   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
502              "starting dht lookup for %s with key: %s\n",
503              rh->name, (char*)&lookup_key_string);
504
505   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
506                                                       &dht_lookup_timeout, rh);
507
508   xquery = htonl(rh->query->type);
509   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
510                        DHT_OPERATION_TIMEOUT,
511                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
512                        &lookup_key,
513                        DHT_GNS_REPLICATION_LEVEL,
514                        GNUNET_DHT_RO_NONE,
515                        &xquery, 
516                        sizeof(xquery),
517                        &process_record_dht_result,
518                        rh);
519
520 }
521
522
523 /**
524  * Namestore calls this function if we have record for this name.
525  * (or with rd_count=0 to indicate no matches)
526  *
527  * @param cls the pending query
528  * @param key the key of the zone we did the lookup
529  * @param expiration expiration date of the namestore entry
530  * @param name the name for which we need an authority
531  * @param rd_count the number of records with 'name'
532  * @param rd the record data
533  * @param signature the signature of the authority for the record data
534  */
535 static void
536 process_record_lookup_ns(void* cls,
537                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
538                   struct GNUNET_TIME_Absolute expiration,
539                   const char *name, unsigned int rd_count,
540                   const struct GNUNET_NAMESTORE_RecordData *rd,
541                   const struct GNUNET_CRYPTO_RsaSignature *signature)
542 {
543   struct GNUNET_GNS_ResolverHandle *rh;
544   struct GNUNET_TIME_Relative remaining_time;
545   GNUNET_HashCode zone;
546
547   rh = (struct GNUNET_GNS_ResolverHandle *) cls;
548   GNUNET_CRYPTO_hash(key,
549                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
550                      &zone);
551   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
552
553   rh->status = 0;
554   
555   if (name != NULL)
556   {
557     rh->status |= EXISTS;
558   }
559   
560   if (remaining_time.rel_value == 0)
561   {
562     rh->status |= EXPIRED;
563   }
564   
565   if (rd_count == 0)
566   {
567     /**
568      * Lookup terminated and no results
569      */
570     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
571                "Namestore lookup for %s terminated without results\n", name);
572     
573     
574
575     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
576                "Record %s unknown in namestore\n",
577                rh->name);
578     /**
579      * Our zone and no result? Cannot resolve TT
580      */
581     rh->proc(rh->proc_cls, rh, 0, NULL);
582     return;
583
584   }
585   else
586   {
587     
588     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
589                "Processing additional result %s from namestore\n", name);
590     int i;
591     for (i=0; i<rd_count;i++)
592     {
593       
594       if (rd[i].record_type != rh->query->type)
595         continue;
596       
597       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
598           == 0)
599       {
600         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This record is expired. Skipping\n");
601         continue;
602       }
603       
604       rh->answered++;
605       
606     }
607     
608     /**
609      * no answers found
610      */
611     if (rh->answered == 0)
612     {
613       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
614                  "No answers found. This is odd!\n");
615       rh->proc(rh->proc_cls, rh, 0, NULL);
616       return;
617     }
618     
619     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
620                rh->answered);
621
622     rh->proc(rh->proc_cls, rh, rd_count, rd);
623   }
624 }
625
626 /**
627  * The final phase of resolution.
628  * This is a name that is canonical and we do not have a delegation.
629  *
630  * @param rh the pending lookup
631  */
632 static void
633 resolve_record_from_ns(struct GNUNET_GNS_ResolverHandle *rh)
634 {
635   
636   /**
637    * Try to resolve this record in our namestore.
638    * The name to resolve is now in rh->authority_name
639    * since we tried to resolve it to an authority
640    * and failed.
641    **/
642   GNUNET_NAMESTORE_lookup_record(namestore_handle,
643                                  &rh->authority,
644                                  rh->name,
645                                  rh->query->type,
646                                  &process_record_lookup_ns,
647                                  rh);
648
649 }
650
651
652 /**
653  * Handle timeout for DHT requests
654  *
655  * @param cls the request handle as closure
656  * @param tc the task context
657  */
658 static void
659 dht_authority_lookup_timeout(void *cls,
660                              const struct GNUNET_SCHEDULER_TaskContext *tc)
661 {
662   struct GNUNET_GNS_ResolverHandle *rh = cls;
663
664   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
665              "dht lookup for query %s (type=%d) timed out.\n",
666              rh->name, rh->query->type);
667
668   GNUNET_DHT_get_stop (rh->get_handle);
669   if (strcmp(rh->name, "") == 0)
670   {
671     /*
672      * promote authority back to name and try to resolve record
673      */
674     strcpy(rh->name, rh->authority_name);
675   }
676   rh->proc(rh->proc_cls, rh, 0, NULL);
677 }
678
679 // Prototype
680 static void resolve_delegation_from_dht(struct GNUNET_GNS_ResolverHandle *rh);
681
682 /**
683  * Function called when we get a result from the dht
684  * for our query. Recursively tries to resolve PKEYs
685  * for name in DHT.
686  *
687  * @param cls the request handle
688  * @param exp lifetime
689  * @param key the key the record was stored under
690  * @param get_path get path
691  * @param get_path_length get path length
692  * @param put_path put path
693  * @param put_path_length put path length
694  * @param type the block type
695  * @param size the size of the record
696  * @param data the record data
697  */
698 static void
699 process_authority_dht_result(void* cls,
700                  struct GNUNET_TIME_Absolute exp,
701                  const GNUNET_HashCode * key,
702                  const struct GNUNET_PeerIdentity *get_path,
703                  unsigned int get_path_length,
704                  const struct GNUNET_PeerIdentity *put_path,
705                  unsigned int put_path_length,
706                  enum GNUNET_BLOCK_Type type,
707                  size_t size, const void *data)
708 {
709   struct GNUNET_GNS_ResolverHandle *rh;
710   struct GNSNameRecordBlock *nrb;
711   uint32_t num_records;
712   char* name = NULL;
713   char* rd_data = (char*) data;
714   int i;
715   int rd_size;
716   GNUNET_HashCode zone, name_hash;
717   
718   if (data == NULL)
719     return;
720   
721   //FIXME check expiration?
722   
723   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
724   nrb = (struct GNSNameRecordBlock*)data;
725   
726   /* stop dht lookup and timeout task */
727   GNUNET_DHT_get_stop (rh->get_handle);
728   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
729
730   rh->get_handle = NULL;
731   num_records = ntohl(nrb->rd_count);
732   name = (char*)&nrb[1];
733   {
734     struct GNUNET_NAMESTORE_RecordData rd[num_records];
735     
736     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
737     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
738   
739     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
740                                                                rd_data,
741                                                                num_records,
742                                                                rd))
743     {
744       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
745       return;
746     }
747
748     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
749                "Got name: %s (wanted %s)\n", name, rh->authority_name);
750     for (i=0; i<num_records; i++)
751     {
752     
753       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
754                 "Got name: %s (wanted %s)\n", name, rh->authority_name);
755       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
756                  "Got type: %d (wanted %d)\n",
757                  rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
758       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
759                  "Got data length: %d\n", rd[i].data_size);
760       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
761                  "Got flag %d\n", rd[i].flags);
762
763       if ((strcmp(name, rh->authority_name) == 0) &&
764           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
765       {
766         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
767         rh->answered = 1;
768         memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
769         struct AuthorityChain *auth =
770           GNUNET_malloc(sizeof(struct AuthorityChain));
771         auth->zone = rh->authority;
772         auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
773         memset(auth->name, 0, strlen(rh->authority_name)+1);
774         strcpy(auth->name, rh->authority_name);
775         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
776                                      rh->authority_chain_tail,
777                                      auth);
778       }
779
780     }
781
782
783     GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
784     GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
785
786     /* Save to namestore */
787     if (0 != GNUNET_CRYPTO_hash_cmp(&zone_hash, &zone))
788     {
789       GNUNET_NAMESTORE_record_put (namestore_handle,
790                                  &nrb->public_key,
791                                  name,
792                                  exp,
793                                  num_records,
794                                  rd,
795                                  &nrb->signature,
796                                  &on_namestore_record_put_result, //cont
797                                  NULL); //cls
798     }
799   }
800   
801   if (rh->answered)
802   {
803     rh->answered = 0;
804     /* delegate */
805     if (strcmp(rh->name, "") == 0)
806       rh->proc(rh->proc_cls, rh, 0, NULL);
807     else
808       resolve_delegation_from_dht(rh);
809     return;
810   }
811
812   /**
813    * should never get here unless false dht key/put
814    * block plugin should handle this
815    **/
816   
817   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup error!\n");
818   GNUNET_break(0);
819 }
820
821
822 /**
823  * Process DHT lookup result for record.
824  *
825  * @param cls the closure
826  * @param rh resolver handle
827  * @param rd_count number of results (always 0)
828  * @param rd record data (always NULL)
829  */
830 static void
831 process_record_result_dht(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
832                        unsigned int rd_count,
833                        const struct GNUNET_NAMESTORE_RecordData *rd)
834 {
835   if (rd_count == 0)
836   {
837     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
838                "No records for %s found in DHT. Aborting\n",
839                rh->name);
840     /* give up, cannot resolve */
841     reply_to_dns(NULL, rh, 0, NULL);
842     return;
843   }
844
845   /* results found yay */
846   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
847              "Record resolved from namestore!");
848   reply_to_dns(NULL, rh, rd_count, rd);
849
850 }
851
852
853 /**
854  * Process namestore lookup result for record.
855  *
856  * @param cls the closure
857  * @param rh resolver handle
858  * @param rd_count number of results (always 0)
859  * @param rd record data (always NULL)
860  */
861 static void
862 process_record_result_ns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
863                        unsigned int rd_count,
864                        const struct GNUNET_NAMESTORE_RecordData *rd)
865 {
866   if (rd_count == 0)
867   {
868     /* ns entry expired. try dht */
869     if (rh->status & (EXPIRED | !EXISTS))
870     {
871       rh->proc = &process_record_result_dht;
872       resolve_record_from_dht(rh);
873       return;
874     }
875     /* give up, cannot resolve */
876     reply_to_dns(NULL, rh, 0, NULL);
877     return;
878   }
879
880   /* results found yay */
881   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
882              "Record resolved from namestore!");
883   reply_to_dns(NULL, rh, rd_count, rd);
884
885 }
886
887
888 /**
889  * Determine if this name is canonical.
890  * i.e.
891  * a.b.gnunet  = not canonical
892  * a           = canonical
893  *
894  * @param name the name to test
895  * @return 1 if canonical
896  */
897 static int
898 is_canonical(char* name)
899 {
900   uint32_t len = strlen(name);
901   int i;
902
903   for (i=0; i<len; i++)
904   {
905     if (*(name+i) == '.')
906       return 0;
907   }
908   return 1;
909 }
910
911 /**
912  * Move one level up in the domain hierarchy and return the
913  * passed top level domain.
914  *
915  * @param name the domain
916  * @param dest the destination where the tld will be put
917  */
918 void
919 pop_tld(char* name, char* dest)
920 {
921   uint32_t len;
922
923   if (is_canonical(name))
924   {
925     strcpy(dest, name);
926     strcpy(name, "");
927     return;
928   }
929
930   for (len = strlen(name); len > 0; len--)
931   {
932     if (*(name+len) == '.')
933       break;
934   }
935   
936   //Was canonical?
937   if (len == 0)
938     return;
939
940   name[len] = '\0';
941
942   strcpy(dest, (name+len+1));
943 }
944
945 /**
946  * DHT resolution for delegation finished. Processing result.
947  *
948  * @param cls the closure
949  * @param rh resolver handle
950  * @param rd_count number of results (always 0)
951  * @param rd record data (always NULL)
952  */
953 static void
954 process_dht_delegation_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
955                           unsigned int rd_count,
956                           const struct GNUNET_NAMESTORE_RecordData *rd)
957 {
958   if (strcmp(rh->name, "") == 0)
959   {
960     /* We resolved full name for delegation. resolving record */
961     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
962       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
963     rh->proc = &process_record_result_ns;
964     resolve_record_from_ns(rh);
965     return;
966   }
967
968   /**
969    * we still have some left
970    **/
971   if (is_canonical(rh->name))
972   {
973     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
974                "Resolving canonical record %s in ns\n", rh->name);
975     rh->proc = &process_record_result_ns;
976     resolve_record_from_ns(rh);
977     return;
978   }
979   /* give up, cannot resolve */
980   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
981              "Cannot fully resolve delegation for %s via DHT!\n",
982              rh->name);
983   reply_to_dns(NULL, rh, 0, NULL);
984 }
985
986
987 /**
988  * Start DHT lookup for a name -> PKEY (compare NS) record in
989  * rh->authority's zone
990  *
991  * @param rh the pending gns query
992  * @param name the name of the PKEY record
993  */
994 static void
995 resolve_delegation_from_dht(struct GNUNET_GNS_ResolverHandle *rh)
996 {
997   uint32_t xquery;
998   GNUNET_HashCode name_hash;
999   GNUNET_HashCode lookup_key;
1000
1001   GNUNET_CRYPTO_hash(rh->authority_name,
1002                      strlen(rh->authority_name),
1003                      &name_hash);
1004   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1005
1006   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1007                                                   &dht_authority_lookup_timeout,
1008                                                        rh);
1009
1010   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1011   
1012   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1013                        DHT_OPERATION_TIMEOUT,
1014                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1015                        &lookup_key,
1016                        DHT_GNS_REPLICATION_LEVEL,
1017                        GNUNET_DHT_RO_NONE,
1018                        &xquery,
1019                        sizeof(xquery),
1020                        &process_authority_dht_result,
1021                        rh);
1022
1023 }
1024
1025
1026 /**
1027  * Namestore resolution for delegation finished. Processing result.
1028  *
1029  * @param cls the closure
1030  * @param rh resolver handle
1031  * @param rd_count number of results (always 0)
1032  * @param rd record data (always NULL)
1033  */
1034 static void
1035 process_ns_delegation_dns(void* cls, struct GNUNET_GNS_ResolverHandle *rh,
1036                           unsigned int rd_count,
1037                           const struct GNUNET_NAMESTORE_RecordData *rd)
1038 {
1039   if (strcmp(rh->name, "") == 0)
1040   {
1041     /* We resolved full name for delegation. resolving record */
1042     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1043                "Resolved full name for delegation. resolving record ''\n");
1044     rh->proc = &process_record_result_ns;
1045     resolve_record_from_ns(rh);
1046     return;
1047   }
1048
1049   /**
1050    * we still have some left
1051    * check if ns entry is fresh
1052    **/
1053   if (rh->status & (EXISTS | !EXPIRED))
1054   {
1055     if (is_canonical(rh->name))
1056     {
1057       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1058                  "Resolving canonical record %s\n", rh->name);
1059       rh->proc = &process_record_result_ns;
1060       resolve_record_from_ns(rh);
1061     }
1062     else
1063     {
1064       /* give up, cannot resolve */
1065       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1066                  "Cannot fully resolve delegation for %s!\n",
1067                  rh->name);
1068       reply_to_dns(NULL, rh, 0, NULL);
1069     }
1070     return;
1071   }
1072   
1073   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1074              "Trying to resolve delegation for %s via DHT\n",
1075              rh->name);
1076   rh->proc = &process_dht_delegation_dns;
1077   resolve_delegation_from_dht(rh);
1078 }
1079
1080 //Prototype
1081 static void resolve_delegation_from_ns(struct GNUNET_GNS_ResolverHandle *rh);
1082
1083 /**
1084  * This is a callback function that should give us only PKEY
1085  * records. Used to query the namestore for the authority (PKEY)
1086  * for 'name'. It will recursively try to resolve the
1087  * authority for a given name from the namestore.
1088  *
1089  * @param cls the pending query
1090  * @param key the key of the zone we did the lookup
1091  * @param expiration expiration date of the record data set in the namestore
1092  * @param name the name for which we need an authority
1093  * @param rd_count the number of records with 'name'
1094  * @param rd the record data
1095  * @param signature the signature of the authority for the record data
1096  */
1097 static void
1098 process_authority_lookup_ns(void* cls,
1099                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1100                    struct GNUNET_TIME_Absolute expiration,
1101                    const char *name,
1102                    unsigned int rd_count,
1103                    const struct GNUNET_NAMESTORE_RecordData *rd,
1104                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1105 {
1106   struct GNUNET_GNS_ResolverHandle *rh;
1107   struct GNUNET_TIME_Relative remaining_time;
1108   GNUNET_HashCode zone;
1109   char* new_name;
1110   
1111   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1112              rd_count);
1113
1114   rh = (struct GNUNET_GNS_ResolverHandle *)cls;
1115   GNUNET_CRYPTO_hash(key,
1116                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1117                      &zone);
1118   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1119   
1120   rh->status = 0;
1121   
1122   if (name != NULL)
1123   {
1124     rh->status |= EXISTS;
1125   }
1126   
1127   if (remaining_time.rel_value == 0)
1128   {
1129     rh->status |= EXPIRED;
1130   }
1131   
1132   /**
1133    * No authority found in namestore.
1134    */
1135   if (rd_count == 0)
1136   {
1137     /**
1138      * We did not find an authority in the namestore
1139      */
1140     
1141     /**
1142      * No PKEY in zone.
1143      * Promote this authority back to a name maybe it is
1144      * our record.
1145      */
1146     if (strcmp(rh->name, "") == 0)
1147     {
1148       /* simply promote back */
1149       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1150                  "Promoting %s back to name\n", rh->authority_name);
1151       strcpy(rh->name, rh->authority_name);
1152     }
1153     else
1154     {
1155       /* add back to existing name */
1156       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1157                  "Adding %s back to %s\n",
1158                  rh->authority_name, rh->name);
1159       new_name = GNUNET_malloc(strlen(rh->name)
1160                                + strlen(rh->authority_name) + 2);
1161       memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1162       strcpy(new_name, rh->name);
1163       strcpy(new_name+strlen(new_name)+1, ".");
1164       strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1165       GNUNET_free(rh->name);
1166       rh->name = new_name;
1167     }
1168     rh->proc(rh->proc_cls, rh, 0, NULL);
1169     return;
1170   }
1171
1172   //Note only 1 pkey should have been returned.. anything else would be strange
1173   /**
1174    * We found an authority that may be able to help us
1175    * move on with query
1176    */
1177   int i;
1178   for (i=0; i<rd_count;i++)
1179   {
1180   
1181     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1182       continue;
1183     
1184     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1185          == 0)
1186     {
1187       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1188       if (remaining_time.rel_value == 0)
1189       {
1190         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1191                    "This dht entry is expired.\n");
1192         rh->authority_chain_head->fresh = 0;
1193         rh->proc(rh->proc_cls, rh, 0, NULL);
1194         return;
1195       }
1196
1197       continue;
1198     }
1199
1200     /**
1201      * Resolve rest of query with new authority
1202      */
1203     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1204     memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1205     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1206     auth->zone = rh->authority;
1207     auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1208     memset(auth->name, 0, strlen(rh->authority_name)+1);
1209     strcpy(auth->name, rh->authority_name);
1210     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1211                                  rh->authority_chain_tail,
1212                                  auth);
1213     
1214     /**
1215      * We are done with PKEY resolution if name is empty
1216      * else resolve again with new authority
1217      */
1218     if (strcmp(rh->name, "") == 0)
1219       rh->proc(rh->proc_cls, rh, 0, NULL);
1220     else
1221       resolve_delegation_from_ns(rh);
1222     return;
1223   }
1224     
1225   /**
1226    * no answers found
1227    */
1228   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1229              "Authority lookup successful but no PKEY... never get here\n");
1230   rh->proc(rh->proc_cls, rh, 0, NULL);
1231 }
1232
1233
1234 /**
1235  * Resolve the delegation chain for the request
1236  *
1237  * @param rh the resolver handle
1238  */
1239 static void
1240 resolve_delegation_from_ns(struct GNUNET_GNS_ResolverHandle *rh)
1241 {
1242   
1243   pop_tld(rh->name, rh->authority_name);
1244   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1245                                  &rh->authority,
1246                                  rh->authority_name,
1247                                  GNUNET_GNS_RECORD_PKEY,
1248                                  &process_authority_lookup_ns,
1249                                  rh);
1250
1251 }
1252
1253 /**
1254  * Entry point for name resolution
1255  * Setup a new query and try to resolve
1256  *
1257  * @param request the request handle of the DNS request from a client
1258  * @param p the DNS query packet we received
1259  * @param q the DNS query we received parsed from p
1260  */
1261 static void
1262 start_resolution_from_dns(struct GNUNET_DNS_RequestHandle *request,
1263                           struct GNUNET_DNSPARSER_Packet *p,
1264                           struct GNUNET_DNSPARSER_Query *q)
1265 {
1266   struct GNUNET_GNS_ResolverHandle *rh;
1267   
1268   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1269               "Starting resolution for %s (type=%d)!\n",
1270               q->name, q->type);
1271   
1272   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1273   rh->packet = p;
1274   rh->query = q;
1275   rh->authority = zone_hash;
1276   
1277   
1278   rh->name = GNUNET_malloc(strlen(q->name)
1279                               - strlen(gnunet_tld) + 1);
1280   memset(rh->name, 0,
1281          strlen(q->name)-strlen(gnunet_tld) + 1);
1282   memcpy(rh->name, q->name,
1283          strlen(q->name)-strlen(gnunet_tld));
1284
1285   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1286
1287   rh->request_handle = request;
1288
1289   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1290   rh->authority_chain_tail = rh->authority_chain_head;
1291   rh->authority_chain_head->zone = zone_hash;
1292
1293   /* Start resolution in our zone */
1294   rh->proc = &process_ns_delegation_dns;
1295   resolve_delegation_from_ns(rh);
1296 }
1297
1298 /**
1299  * The DNS request handler
1300  * Called for every incoming DNS request.
1301  *
1302  * @param cls closure
1303  * @param rh request handle to user for reply
1304  * @param request_length number of bytes in request
1305  * @param request udp payload of the DNS request
1306  */
1307 static void
1308 handle_dns_request(void *cls,
1309                    struct GNUNET_DNS_RequestHandle *rh,
1310                    size_t request_length,
1311                    const char *request)
1312 {
1313   struct GNUNET_DNSPARSER_Packet *p;
1314   char *tldoffset;
1315
1316   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacked a DNS request...processing\n");
1317   p = GNUNET_DNSPARSER_parse (request, request_length);
1318   
1319   if (NULL == p)
1320   {
1321     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1322                 "Received malformed DNS packet, leaving it untouched\n");
1323     GNUNET_DNS_request_forward (rh);
1324     return;
1325   }
1326   
1327   /**
1328    * Check tld and decide if we or
1329    * legacy dns is responsible
1330    *
1331    * FIXME now in theory there could be more than 1 query in the request
1332    * but if this is case we get into trouble:
1333    * either we query the GNS or the DNS. We cannot do both!
1334    * So I suggest to either only allow a single query per request or
1335    * only allow GNS or DNS requests.
1336    * The way it is implemented here now is buggy and will lead to erratic
1337    * behaviour (if multiple queries are present).
1338    */
1339   if (p->num_queries == 0)
1340   {
1341     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1342                 "No Queries in DNS packet... forwarding\n");
1343     GNUNET_DNS_request_forward (rh);
1344   }
1345
1346   if (p->num_queries > 1)
1347   {
1348     /* Note: We could also look for .gnunet */
1349     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1350                 ">1 queriy in DNS packet... odd. We only process #1\n");
1351   }
1352
1353   
1354   /**
1355    * Check for .gnunet
1356    */
1357   tldoffset = p->queries[0].name + strlen(p->queries[0].name);
1358
1359   while ((*tldoffset) != '.')
1360     tldoffset--;
1361   
1362   if (0 == strcmp(tldoffset, gnunet_tld))
1363   {
1364     start_resolution_from_dns(rh, p, p->queries);
1365   }
1366   else
1367   {
1368     /**
1369      * This request does not concern us. Forward to real DNS.
1370      */
1371     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1372                "Request for %s is forwarded to DNS\n", p->queries[0].name);
1373     GNUNET_DNS_request_forward (rh);
1374   }
1375
1376 }
1377
1378 /**
1379  * Method called periodicattluy that triggers
1380  * iteration over root zone
1381  *
1382  * @param cls closure
1383  * @param tc task context
1384  */
1385 static void
1386 update_zone_dht_next(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1387 {
1388   GNUNET_NAMESTORE_zone_iterator_next(namestore_iter);
1389 }
1390
1391 /**
1392  * Continuation for DHT put
1393  *
1394  * @param cls closure
1395  * @param tc task context
1396  */
1397 static void
1398 record_dht_put(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1399 {
1400   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "put request transmitted\n");
1401 }
1402
1403 /* prototype */
1404 static void
1405 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1406
1407 /**
1408  * Function used to put all records successively into the DHT.
1409  *
1410  * @param cls the closure (NULL)
1411  * @param key the public key of the authority (ours)
1412  * @param expiration lifetime of the namestore entry
1413  * @param name the name of the records
1414  * @param rd_count the number of records in data
1415  * @param rd the record data
1416  * @param signature the signature for the record data
1417  */
1418 static void
1419 put_gns_record(void *cls,
1420                 const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1421                 struct GNUNET_TIME_Absolute expiration,
1422                 const char *name,
1423                 unsigned int rd_count,
1424                 const struct GNUNET_NAMESTORE_RecordData *rd,
1425                 const struct GNUNET_CRYPTO_RsaSignature *signature)
1426 {
1427   
1428   struct GNSNameRecordBlock *nrb;
1429   GNUNET_HashCode name_hash;
1430   GNUNET_HashCode xor_hash;
1431   struct GNUNET_CRYPTO_HashAsciiEncoded xor_hash_string;
1432   uint32_t rd_payload_length;
1433   char* nrb_data = NULL;
1434
1435   /* we're done */
1436   if (NULL == name)
1437   {
1438     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Zone iteration finished\n");
1439     GNUNET_NAMESTORE_zone_iteration_stop (namestore_iter);
1440     zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start,
1441                                                    NULL);
1442     return;
1443   }
1444   
1445   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1446              "Putting records for %s into the DHT\n", name);
1447   
1448   rd_payload_length = GNUNET_NAMESTORE_records_get_size (rd_count, rd);
1449   
1450   nrb = GNUNET_malloc(rd_payload_length + strlen(name) + 1 
1451                       + sizeof(struct GNSNameRecordBlock));
1452   
1453   if (signature != NULL)
1454     nrb->signature = *signature;
1455   
1456   nrb->public_key = *key;
1457
1458   nrb->rd_count = htonl(rd_count);
1459   
1460   memset(&nrb[1], 0, strlen(name) + 1);
1461   memcpy(&nrb[1], name, strlen(name));
1462
1463   nrb_data = (char*)&nrb[1];
1464   nrb_data += strlen(name) + 1;
1465
1466   rd_payload_length += sizeof(struct GNSNameRecordBlock) +
1467     strlen(name) + 1;
1468
1469   if (-1 == GNUNET_NAMESTORE_records_serialize (rd_count,
1470                                                 rd,
1471                                                 rd_payload_length,
1472                                                 nrb_data))
1473   {
1474     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Record serialization failed!\n");
1475     return;
1476     //FIXME what to do
1477   }
1478
1479
1480   /*
1481    * calculate DHT key: H(name) xor H(pubkey)
1482    */
1483   GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
1484   GNUNET_CRYPTO_hash_xor(&zone_hash, &name_hash, &xor_hash);
1485   GNUNET_CRYPTO_hash_to_enc (&xor_hash, &xor_hash_string);
1486   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1487              "putting records for %s under key: %s with size %d\n",
1488              name, (char*)&xor_hash_string, rd_payload_length);
1489
1490   GNUNET_DHT_put (dht_handle, &xor_hash,
1491                   DHT_GNS_REPLICATION_LEVEL,
1492                   GNUNET_DHT_RO_NONE,
1493                   GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1494                   rd_payload_length,
1495                   (char*)nrb,
1496                   expiration,
1497                   DHT_OPERATION_TIMEOUT,
1498                   &record_dht_put,
1499                   NULL); //cls for cont
1500   
1501   num_public_records++;
1502
1503   /**
1504    * Reschedule periodic put
1505    */
1506   zone_update_taskid = GNUNET_SCHEDULER_add_delayed (dht_update_interval,
1507                                 &update_zone_dht_next,
1508                                 NULL);
1509
1510 }
1511
1512 /**
1513  * Periodically iterate over our zone and store everything in dht
1514  *
1515  * @param cls NULL
1516  * @param tc task context
1517  */
1518 static void
1519 update_zone_dht_start(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1520 {
1521   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Starting DHT zone update!\n");
1522   if (0 == num_public_records)
1523   {
1524     dht_update_interval = GNUNET_TIME_relative_multiply(
1525                                                       GNUNET_TIME_UNIT_SECONDS,
1526                                                       1);
1527   }
1528   else
1529   {
1530     dht_update_interval = GNUNET_TIME_relative_multiply(
1531                                                       GNUNET_TIME_UNIT_SECONDS,
1532                                                      (3600/num_public_records));
1533   }
1534   num_public_records = 0; //start counting again
1535   namestore_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore_handle,
1536                                                           &zone_hash,
1537                                                           GNUNET_NAMESTORE_RF_AUTHORITY,
1538                                                           GNUNET_NAMESTORE_RF_PRIVATE,
1539                                                           &put_gns_record,
1540                                                           NULL);
1541 }
1542
1543 //Prototype
1544 static void send_shorten_response(const char* name,
1545                                   struct ClientShortenHandle *csh);
1546 static void
1547 process_shorten_pseu_lookup_ns(void *cls,
1548                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1549                  struct GNUNET_TIME_Absolute expire,
1550                  const char *name,
1551                  unsigned int rd_len,
1552                  const struct GNUNET_NAMESTORE_RecordData *rd,
1553                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1554 {
1555   struct GNUNET_GNS_ResolverHandle *rh = 
1556     (struct GNUNET_GNS_ResolverHandle *)cls;
1557   struct GNUNET_TIME_Relative remaining_time;
1558
1559   
1560   rh->status = 0;
1561   
1562   if (name != NULL)
1563   {
1564     rh->status |= EXISTS;
1565   }
1566   
1567   if (remaining_time.rel_value == 0)
1568   {
1569     rh->status |= EXPIRED;
1570   }
1571
1572   rh->proc(cls, rh, rd_len, rd);
1573 }
1574
1575
1576 /**
1577  * Start DHT lookup for a PSEUdonym record in
1578  * rh->authority's zone
1579  *
1580  * @param rh the pending gns query
1581  * @param name the name of the PKEY record
1582  */
1583 static void
1584 resolve_pseu_from_dht(struct GNUNET_GNS_ResolverHandle *rh)
1585 {
1586   uint32_t xquery;
1587   GNUNET_HashCode name_hash;
1588   GNUNET_HashCode lookup_key;
1589
1590   //Empty string
1591   GNUNET_CRYPTO_hash("",
1592                      1,
1593                      &name_hash);
1594
1595   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
1596
1597   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1598                                                   &dht_lookup_timeout,
1599                                                   rh);
1600
1601   xquery = htonl(GNUNET_GNS_RECORD_PSEU);
1602   
1603   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1604                        DHT_OPERATION_TIMEOUT,
1605                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1606                        &lookup_key,
1607                        DHT_GNS_REPLICATION_LEVEL,
1608                        GNUNET_DHT_RO_NONE,
1609                        &xquery,
1610                        sizeof(xquery),
1611                        &process_authority_dht_result,
1612                        rh);
1613
1614 }
1615
1616 //Prototype
1617 static void
1618 handle_shorten_pseu_ns_result(void* cls,
1619                               struct GNUNET_GNS_ResolverHandle *rh,
1620                               uint32_t rd_count,
1621                               const struct GNUNET_NAMESTORE_RecordData *rd);
1622
1623 static void
1624 handle_shorten_zone_to_name(void *cls,
1625                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1626                  struct GNUNET_TIME_Absolute expire,
1627                  const char *name,
1628                  unsigned int rd_len,
1629                  const struct GNUNET_NAMESTORE_RecordData *rd,
1630                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1631 {
1632   struct GNUNET_GNS_ResolverHandle *rh = 
1633     (struct GNUNET_GNS_ResolverHandle *)cls;
1634   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) rh->proc_cls;
1635
1636   char* result;
1637   
1638   /* we found a match in our own zone */
1639   if (rd_len != 0)
1640   {
1641     result = GNUNET_malloc(strlen(rh->name) + strlen(name) + 1);
1642     memset(result, 0, strlen(rh->name) + strlen(name) + 1);
1643     memcpy(result, rh->name, strlen(rh->name));
1644     memcpy(result+strlen(rh->name)+1, name, strlen(name));
1645
1646     send_shorten_response(result, csh);
1647
1648     GNUNET_free(result);
1649   }
1650   else
1651   {
1652     /**
1653      * Nothing in our zone
1654      * check PSEU for this authority in namestore
1655      */
1656     rh->proc = &handle_shorten_pseu_ns_result;
1657     GNUNET_NAMESTORE_lookup_record(namestore_handle,
1658                                    &rh->authority_chain_head->zone,
1659                                    "",
1660                                    GNUNET_GNS_RECORD_PSEU,
1661                                    &process_shorten_pseu_lookup_ns,
1662                                    rh);
1663   }
1664 }
1665
1666 /**
1667  * Process result from namestore delegation lookup
1668  * for shorten operation
1669  *
1670  * @param cls the client shorten handle
1671  * @param rh the resolver handle
1672  * @param rd_count number of results (0)
1673  * @param rd data (NULL)
1674  */
1675 void
1676 handle_shorten_pseu_dht_result(void* cls,
1677                       struct GNUNET_GNS_ResolverHandle *rh,
1678                       uint32_t rd_len,
1679                       const struct GNUNET_NAMESTORE_RecordData *rd)
1680 {
1681   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1682   struct AuthorityChain *auth_chain;
1683   char* pseu;
1684   char* result;
1685   char* new_name;
1686   int i;
1687   
1688   /**
1689    * PSEU found
1690    */
1691   if (rd_len != 0)
1692   {
1693     for (i=0; i < rd_len; i++)
1694     {
1695       if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
1696         break;
1697     }
1698     
1699     pseu = (char*) rd[i].data;
1700     result = GNUNET_malloc(strlen(rh->name) + strlen(pseu) + 1);
1701     memset(result, 0, strlen(rh->name) + strlen(pseu) + 1);
1702     memcpy(result, rh->name, strlen(rh->name));
1703     memcpy(result+strlen(rh->name)+1, pseu, strlen(pseu));
1704
1705     send_shorten_response(result, csh);
1706
1707     GNUNET_free(result);
1708     return;
1709   }
1710   
1711   /**
1712    * No PSEU found.
1713    * continue with next authority
1714    * backtrack
1715    */
1716   auth_chain = rh->authority_chain_head;
1717
1718   if ((auth_chain->next->next == NULL) &&
1719       GNUNET_CRYPTO_hash_cmp(&auth_chain->next->zone, &zone_hash) == 0)
1720   {
1721     /**
1722      * Our zone is next
1723      */
1724     result = GNUNET_malloc(strlen(rh->name) + strlen(auth_chain->name) + 2);
1725     memset(result, 0, strlen(rh->name) + strlen(auth_chain->name) + 2);
1726     strcpy(result, rh->name);
1727     strcpy(result+strlen(rh->name)+1, ".");
1728     strcpy(result+strlen(rh->name)+2, auth_chain->name);
1729     send_shorten_response(result, csh);
1730
1731     return;
1732   }
1733
1734   /**
1735    * Continue with next authority
1736    */
1737   new_name = GNUNET_malloc(strlen(rh->name)+
1738                            strlen(auth_chain->name) + 2);
1739   memset(new_name, 0, strlen(rh->name)+
1740                       strlen(auth_chain->name) + 2);
1741   strcpy(new_name, rh->name);
1742   strcpy(new_name+strlen(rh->name)+1, ".");
1743   strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
1744   GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1745                               rh->authority_chain_tail,
1746                               auth_chain);
1747   GNUNET_free(auth_chain->name);
1748   GNUNET_free(auth_chain);
1749   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1750                                  &zone_hash,
1751                                  &rh->authority_chain_head->zone,
1752                                  &handle_shorten_zone_to_name,
1753                                  rh);
1754
1755 }
1756
1757
1758
1759 /**
1760  * Process result from namestore PSEU lookup
1761  * for shorten operation
1762  * FIXME do we need to check for own zone here?
1763  *
1764  * @param cls the client shorten handle
1765  * @param rh the resolver handle
1766  * @param rd_count number of results (0 if none found)
1767  * @param rd data (NULL if none found)
1768  */
1769 static void
1770 handle_shorten_pseu_ns_result(void* cls,
1771                       struct GNUNET_GNS_ResolverHandle *rh,
1772                       uint32_t rd_len,
1773                       const struct GNUNET_NAMESTORE_RecordData *rd)
1774 {
1775   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1776   struct AuthorityChain *auth_chain;
1777   char* pseu;
1778   char* result;
1779   char* new_name;
1780   int i;
1781   
1782   /**
1783    * PSEU found
1784    */
1785   if (rd_len != 0)
1786   {
1787     for (i=0; i < rd_len; i++)
1788     {
1789       if (rd[i].record_type == GNUNET_GNS_RECORD_PSEU)
1790         break;
1791     }
1792     
1793     pseu = (char*) rd[i].data;
1794     result = GNUNET_malloc(strlen(rh->name) + strlen(pseu) + 1);
1795     memset(result, 0, strlen(rh->name) + strlen(pseu) + 1);
1796     memcpy(result, rh->name, strlen(rh->name));
1797     memcpy(result+strlen(rh->name)+1, pseu, strlen(pseu));
1798
1799     send_shorten_response(result, csh);
1800
1801     GNUNET_free(result);
1802     return;
1803   }
1804   
1805   /**
1806    * No PSEU found. Ask DHT if expired.
1807    * Else contunue with next authority
1808    */
1809   if (rh->status & (EXISTS | !EXPIRED))
1810   {
1811     /**
1812      * backtrack
1813      */
1814     auth_chain = rh->authority_chain_head;
1815     new_name = GNUNET_malloc(strlen(rh->name)+
1816                              strlen(auth_chain->name) + 2);
1817     memset(new_name, 0, strlen(rh->name)+
1818                         strlen(auth_chain->name) + 2);
1819     strcpy(new_name, rh->name);
1820     strcpy(new_name+strlen(rh->name)+1, ".");
1821     strcpy(new_name+strlen(rh->name)+2, auth_chain->name);
1822
1823     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1824                                 rh->authority_chain_tail,
1825                                 auth_chain);
1826
1827     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1828                                    &zone_hash,
1829                                    &rh->authority_chain_head->zone,
1830                                    &handle_shorten_zone_to_name,
1831                                    rh);
1832     return;
1833   }
1834
1835   /**
1836    * Ask DHT
1837    */
1838   rh->authority = rh->authority_chain_head->zone;
1839   rh->proc = &handle_shorten_pseu_dht_result;
1840   resolve_pseu_from_dht(rh);
1841
1842 }
1843
1844
1845
1846 /**
1847  * Process result from namestore delegation lookup
1848  * for shorten operation
1849  *
1850  * @param cls the client shorten handle
1851  * @param rh the resolver handle
1852  * @param rd_count number of results (0)
1853  * @param rd data (NULL)
1854  */
1855 void
1856 handle_shorten_delegation_result(void* cls,
1857                       struct GNUNET_GNS_ResolverHandle *rh,
1858                       uint32_t rd_count,
1859                       const struct GNUNET_NAMESTORE_RecordData *rd)
1860 {
1861   struct ClientShortenHandle* csh = (struct ClientShortenHandle*) cls;
1862   struct AuthorityChain *auth_chain;
1863   
1864   /**
1865    * At this point rh->name contains the part of the name
1866    * that we do not have a PKEY in our namestore to resolve.
1867    * The authority chain in the resolver handle is now
1868    * useful to backtrack if needed
1869    */
1870   
1871   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1872              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1873
1874   if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1875                              &zone_hash) == 0)
1876   {
1877     /**
1878      * This is our zone append .gnunet unless name is empty
1879      * (it shouldn't be, usually FIXME what happens if we
1880      * shorten to our zone to a "" record??)
1881      **/
1882     send_shorten_response(rh->name, csh); //FIXME +.gnunet!
1883     //FIXME free
1884     return;
1885   }
1886   csh->offset++; //FIXME needed?
1887   auth_chain = rh->authority_chain_head;
1888   /* backtrack authorities for pseu */
1889   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1890                                  &zone_hash, //ours
1891                                  &auth_chain->zone,
1892                                  &handle_shorten_zone_to_name,
1893                                  rh);
1894
1895 }
1896
1897 typedef void (*ShortenResponseProc) (void* cls, const char* name);
1898
1899 /**
1900  * Shorten a given name
1901  *
1902  * @param name the name to shorten
1903  * @param proc the processor to call when finished
1904  * @praram cls the closure to the processor
1905  */
1906 static void
1907 shorten_name(char* name, struct ClientShortenHandle* csh)
1908 {
1909
1910   struct GNUNET_GNS_ResolverHandle *rh;
1911   
1912   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1913               "Starting resolution for %s (type=%d)!\n",
1914               name, GNUNET_GNS_RECORD_PKEY);
1915   
1916   rh = GNUNET_malloc(sizeof (struct GNUNET_GNS_ResolverHandle));
1917   rh->authority = zone_hash;
1918   
1919   rh->name = GNUNET_malloc(strlen(name)
1920                               - strlen(gnunet_tld) + 1);
1921   memset(rh->name, 0,
1922          strlen(name)-strlen(gnunet_tld) + 1);
1923   memcpy(rh->name, name,
1924          strlen(name)-strlen(gnunet_tld));
1925
1926   csh->name = GNUNET_malloc(strlen(name)
1927                             - strlen(gnunet_tld) + 1);
1928   memset(rh->name, 0,
1929          strlen(name)-strlen(gnunet_tld) + 1);
1930   memcpy(rh->name, name,
1931          strlen(name)-strlen(gnunet_tld));
1932
1933   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1934
1935   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1936   rh->authority_chain_tail = rh->authority_chain_head;
1937   rh->authority_chain_head->zone = zone_hash;
1938   rh->proc = &handle_shorten_delegation_result;
1939   rh->proc_cls = (void*)csh;
1940
1941   /* Start delegation resolution in our namestore */
1942   resolve_delegation_from_ns(rh);
1943
1944 }
1945
1946 /**
1947  * Send shorten response back to client
1948  * FIXME this is without .gnunet!
1949  * 
1950  * @param cls the client handle in closure
1951  * @param name the shortened name result or NULL if cannot be shortened
1952  */
1953 static void
1954 send_shorten_response(const char* name, struct ClientShortenHandle *csh)
1955 {
1956   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message\n",
1957               "SHORTEN_RESULT");
1958   struct GNUNET_GNS_ClientShortenResultMessage *rmsg;
1959   
1960   if (name == NULL)
1961   {
1962     name = '\0';
1963   }
1964
1965   rmsg = GNUNET_malloc(sizeof(struct GNUNET_GNS_ClientShortenResultMessage *)
1966                        + strlen(name));
1967   
1968   rmsg->unique_id = csh->unique_id;
1969   rmsg->key = csh->key;
1970   rmsg->header.type = htons(GNUNET_MESSAGE_TYPE_GNS_SHORTEN_RESULT);
1971   rmsg->header.size = 
1972     htons(sizeof(struct GNUNET_GNS_ClientShortenResultMessage) +
1973           strlen(name));
1974
1975   strcpy((char*)&rmsg[1], name);
1976
1977   GNUNET_SERVER_notification_context_unicast (nc, csh->client,
1978                               (const struct GNUNET_MessageHeader *) rmsg,
1979                               GNUNET_NO);
1980
1981   GNUNET_SERVER_receive_done (csh->client, GNUNET_OK);
1982   
1983   //GNUNET_free(csh);
1984   //GNUNET_free(rmsg);
1985
1986 }
1987
1988 /**
1989  * Handle a shorten message from the api
1990  *
1991  * @param cls the closure
1992  * @param client the client
1993  * @param message the message
1994  */
1995 static void handle_shorten(void *cls,
1996                            struct GNUNET_SERVER_Client * client,
1997                            const struct GNUNET_MessageHeader * message)
1998 {
1999   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n", "SHORTEN");
2000
2001   size_t msg_size = 0;
2002   struct ClientShortenHandle *csh;
2003
2004   if (ntohs (message->size) < sizeof (struct GNUNET_GNS_ClientShortenMessage))
2005   {
2006     GNUNET_break_op (0);
2007     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2008     return;
2009   }
2010
2011   GNUNET_SERVER_notification_context_add (nc, client);
2012   GNUNET_SERVER_client_keep (client);
2013
2014   struct GNUNET_GNS_ClientShortenMessage *sh_msg =
2015     (struct GNUNET_GNS_ClientShortenMessage *) message;
2016   
2017   msg_size = ntohs(message->size);
2018
2019   if (msg_size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2020   {
2021     GNUNET_break_op (0);
2022     GNUNET_SERVER_receive_done (client, GNUNET_OK);
2023     return;
2024   }
2025
2026   csh = GNUNET_malloc(sizeof(struct ClientShortenHandle));
2027   csh->client = client;
2028   csh->unique_id = sh_msg->unique_id;
2029   csh->key = sh_msg->key;
2030   
2031   //Offset in original name
2032   csh->offset = 0;
2033   
2034
2035   shorten_name((char*)&sh_msg[1], csh);
2036
2037 }
2038
2039 /**
2040  * TODO
2041  */
2042 static void
2043 handle_lookup(void *cls,
2044               struct GNUNET_SERVER_Client * client,
2045               const struct GNUNET_MessageHeader * message)
2046 {
2047 }
2048
2049 /**
2050  * Process GNS requests.
2051  *
2052  * @param cls closure)
2053  * @param server the initialized server
2054  * @param c configuration to use
2055  */
2056 static void
2057 run (void *cls, struct GNUNET_SERVER_Handle *server,
2058      const struct GNUNET_CONFIGURATION_Handle *c)
2059 {
2060   
2061   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Initializing GNS\n");
2062
2063   char* keyfile;
2064   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
2065
2066   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
2067     {&handle_shorten, NULL, GNUNET_MESSAGE_TYPE_GNS_SHORTEN, 0},
2068     {&handle_lookup, NULL, GNUNET_MESSAGE_TYPE_GNS_LOOKUP, 0}
2069   };
2070
2071   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "gns",
2072                                              "ZONEKEY", &keyfile))
2073   {
2074     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2075                 "No private key for root zone specified%s!\n", keyfile);
2076     GNUNET_SCHEDULER_shutdown(0);
2077     return;
2078   }
2079
2080   zone_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2081   GNUNET_CRYPTO_rsa_key_get_public (zone_key, &pkey);
2082
2083   GNUNET_CRYPTO_hash(&pkey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2084                      &zone_hash);
2085   
2086
2087   if (GNUNET_YES ==
2088       GNUNET_CONFIGURATION_get_value_yesno (c, "gns",
2089                                             "HIJACK_DNS"))
2090   {
2091     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2092                "DNS hijacking enabled... connecting to service.\n");
2093     /**
2094      * Do gnunet dns init here
2095      */
2096     dns_handle = GNUNET_DNS_connect(c,
2097                                     GNUNET_DNS_FLAG_PRE_RESOLUTION,
2098                                     &handle_dns_request, /* rh */
2099                                     NULL); /* Closure */
2100     if (NULL == dns_handle)
2101     {
2102       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2103                "Failed to connect to the dnsservice!\n");
2104     }
2105   }
2106
2107   
2108
2109   /**
2110    * handle to our local namestore
2111    */
2112   namestore_handle = GNUNET_NAMESTORE_connect(c);
2113
2114   if (NULL == namestore_handle)
2115   {
2116     //FIXME do error handling;
2117     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2118                "Failed to connect to the namestore!\n");
2119     GNUNET_SCHEDULER_shutdown(0);
2120     return;
2121   }
2122   
2123   /**
2124    * handle to the dht
2125    */
2126   dht_handle = GNUNET_DHT_connect(c, 1); //FIXME get ht_len from cfg
2127
2128   if (NULL == dht_handle)
2129   {
2130     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Could not connect to DHT!\n");
2131   }
2132
2133   //put_some_records(); //FIXME for testing
2134   
2135   /**
2136    * Schedule periodic put
2137    * for our records
2138    * We have roughly an hour for all records;
2139    */
2140   dht_update_interval = GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS,
2141                                                       1);
2142   //zone_update_taskid = GNUNET_SCHEDULER_add_now (&update_zone_dht_start, NULL);
2143
2144   GNUNET_SERVER_add_handlers (server, handlers);
2145   
2146   //FIXME
2147   //GNUNET_SERVER_disconnect_notify (server,
2148   //                                 &client_disconnect_notification,
2149   //                                 NULL);
2150
2151   nc = GNUNET_SERVER_notification_context_create (server, 1);
2152
2153   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
2154                                 NULL);
2155 }
2156
2157
2158 /**
2159  * The main function for the GNS service.
2160  *
2161  * @param argc number of arguments from the command line
2162  * @param argv command line arguments
2163  * @return 0 ok, 1 on error
2164  */
2165 int
2166 main (int argc, char *const *argv)
2167 {
2168   int ret;
2169
2170   ret =
2171       (GNUNET_OK ==
2172        GNUNET_SERVICE_run (argc, argv, "gns", GNUNET_SERVICE_OPTION_NONE, &run,
2173                            NULL)) ? 0 : 1;
2174   return ret;
2175 }
2176
2177 /* end of gnunet-service-gns.c */