-coverity
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.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  *
24  * @file gns/gnunet-service-gns_resolver.c
25  * @brief GNUnet GNS resolver logic
26  * @author Martin Schanzenbach
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_transport_service.h"
31 #include "gnunet_dns_service.h"
32 #include "gnunet_dht_service.h"
33 #include "gnunet_namestore_service.h"
34 #include "gnunet_dns_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gnunet_gns_service.h"
37 #include "block_gns.h"
38 #include "gns.h"
39 #include "gnunet-service-gns_resolver.h"
40
41 #define DHT_OPERATION_TIMEOUT  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
42 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
43 #define DHT_GNS_REPLICATION_LEVEL 5
44 #define MAX_DNS_LABEL_LENGTH 63
45
46
47 /**
48  * Our handle to the namestore service
49  */
50 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
51
52 /**
53  * Resolver handle to the dht
54  */
55 static struct GNUNET_DHT_Handle *dht_handle;
56
57 /**
58  * Heap for parallel DHT lookups
59  */
60 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
61
62 /**
63  * Maximum amount of parallel queries in background
64  */
65 static unsigned long long max_allowed_background_queries;
66
67 /**
68  * Our local zone
69  */
70 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
71
72 /**
73  * Namestore calls this function if we have record for this name.
74  * (or with rd_count=0 to indicate no matches)
75  *
76  * @param cls the pending query
77  * @param key the key of the zone we did the lookup
78  * @param expiration expiration date of the namestore entry
79  * @param name the name for which we need an authority
80  * @param rd_count the number of records with 'name'
81  * @param rd the record data
82  * @param signature the signature of the authority for the record data
83  */
84 static void
85 process_pseu_lookup_ns(void* cls,
86                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
87                       struct GNUNET_TIME_Absolute expiration,
88                       const char *name, unsigned int rd_count,
89                       const struct GNUNET_NAMESTORE_RecordData *rd,
90                       const struct GNUNET_CRYPTO_RsaSignature *signature)
91 {
92   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
93   struct GNUNET_NAMESTORE_RecordData new_pkey;
94
95   if (rd_count > 0)
96   {
97     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
98                "Name %s already taken in NS!\n", name);
99     if (0 == strcmp(gph->name, name))
100     {
101       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
102                  "Intelligent replacement not implemented\n", name);
103       GNUNET_free(gph);
104       return;
105     }
106
107     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
108                "Trying delegated name %s\n", gph->name);
109     memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
110     GNUNET_NAMESTORE_lookup_record(namestore_handle,
111                                    &gph->zone,
112                                    gph->new_name,
113                                    GNUNET_GNS_RECORD_PSEU,
114                                    &process_pseu_lookup_ns,
115                                    gph);
116     return;
117   }
118
119   /** name is free */
120   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
121              "Name %s not taken in NS! Adding\n", gph->new_name);
122
123   new_pkey.expiration = GNUNET_TIME_absolute_get_forever ();
124   new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
125   new_pkey.data = &gph->new_zone;
126   new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
127   GNUNET_NAMESTORE_record_create (namestore_handle,
128                                   gph->key,
129                                   gph->new_name,
130                                   &new_pkey,
131                                   NULL, //cont
132                                   NULL); //cls
133   GNUNET_free(gph);
134
135 }
136
137 /**
138  * process result of a dht pseu lookup
139  *
140  * @param gph the handle
141  * @param name the pseu result or NULL
142  */
143 static void
144 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
145 {
146   if (NULL == name)
147   {
148     memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
149   }
150   else
151   {
152     memcpy(gph->new_name, name, strlen(name)+1);
153   }
154
155   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
156              "Checking %s for collision in NS\n", gph->new_name);
157
158   /**
159    * Check for collision
160    */
161   GNUNET_NAMESTORE_lookup_record(namestore_handle,
162                                  &gph->zone,
163                                  gph->new_name,
164                                  GNUNET_GNS_RECORD_PSEU,
165                                  &process_pseu_lookup_ns,
166                                  gph);
167 }
168
169 /**
170  * Handle timeout for dht request
171  *
172  * @param cls the request handle as closure
173  * @param tc the task context
174  */
175 static void
176 handle_auth_discovery_timeout(void *cls,
177                               const struct GNUNET_SCHEDULER_TaskContext *tc)
178 {
179   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
180
181   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
182              "dht lookup for query PSEU timed out.\n");
183   GNUNET_DHT_get_stop (gph->get_handle);
184   process_pseu_result(gph, NULL);
185 }
186
187 /**
188  * Function called when we find a PSEU entry in the DHT
189  *
190  * @param cls the request handle
191  * @param exp lifetime
192  * @param key the key the record was stored under
193  * @param get_path get path
194  * @param get_path_length get path length
195  * @param put_path put path
196  * @param put_path_length put path length
197  * @param type the block type
198  * @param size the size of the record
199  * @param data the record data
200  */
201 static void
202 process_auth_discovery_dht_result(void* cls,
203                                   struct GNUNET_TIME_Absolute exp,
204                                   const GNUNET_HashCode * key,
205                                   const struct GNUNET_PeerIdentity *get_path,
206                                   unsigned int get_path_length,
207                                   const struct GNUNET_PeerIdentity *put_path,
208                                   unsigned int put_path_length,
209                                   enum GNUNET_BLOCK_Type type,
210                                   size_t size, const void *data)
211 {
212   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
213   struct GNSNameRecordBlock *nrb;
214   char* rd_data = (char*)data;
215   char* name;
216   int num_records;
217   size_t rd_size;
218   int i;
219
220   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
221
222   if (data == NULL)
223   {
224     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "got dht result null!\n", size);
225     GNUNET_break(0);
226     GNUNET_free(gph);
227     return;
228   }
229   
230   nrb = (struct GNSNameRecordBlock*)data;
231
232   /* stop lookup and timeout task */
233   GNUNET_DHT_get_stop (gph->get_handle);
234   GNUNET_SCHEDULER_cancel(gph->timeout);
235
236   gph->get_handle = NULL;
237
238   nrb = (struct GNSNameRecordBlock*)data;
239   
240   name = (char*)&nrb[1];
241   num_records = ntohl(nrb->rd_count);
242   {
243     struct GNUNET_NAMESTORE_RecordData rd[num_records];
244
245     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
246     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
247
248     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
249                                                                rd_data,
250                                                                num_records,
251                                                                rd))
252     {
253       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
254       GNUNET_break(0);
255       GNUNET_free(gph);
256       return;
257     }
258
259     for (i=0; i<num_records; i++)
260     {
261       if ((strcmp(name, "+") == 0) &&
262           (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
263       {
264         /* found pseu */
265         process_pseu_result(gph, (char*)rd[i].data);
266         return;
267       }
268     }
269   }
270
271   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "no pseu in dht!\n");
272   process_pseu_result(gph, NULL);
273 }
274
275 /**
276  * Callback called by namestore for a zone to name
277  * result
278  *
279  * @param cls the closure
280  * @param zone_key the zone we queried
281  * @param expire the expiration time of the name
282  * @param name the name found or NULL
283  * @param rd_len number of records for the name
284  * @param rd the record data (PKEY) for the name
285  * @param signature the signature for the record data
286  */
287 static void
288 process_zone_to_name_discover(void *cls,
289                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
290                  struct GNUNET_TIME_Absolute expire,
291                  const char *name,
292                  unsigned int rd_len,
293                  const struct GNUNET_NAMESTORE_RecordData *rd,
294                  const struct GNUNET_CRYPTO_RsaSignature *signature)
295 {
296   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
297
298   /* we found a match in our own zone */
299   if (rd_len != 0)
300   {
301     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
302                "name for zone in our root %d\n", strlen(name));
303     GNUNET_free(gph);
304   }
305   else
306   {
307     /**
308      * No name found.
309      * check dht
310      */
311     uint32_t xquery;
312     struct GNUNET_CRYPTO_ShortHashCode name_hash;
313     GNUNET_HashCode lookup_key;
314     struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
315     GNUNET_HashCode name_hash_double;
316     GNUNET_HashCode zone_hash_double;
317
318     GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
319     GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
320     GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
321     GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
322     GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
323
324     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
325                "starting dht lookup for %s with key: %s\n",
326                "+", (char*)&lookup_key_string);
327
328     //gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
329     //                                     &handle_auth_discovery_timeout, gph);
330
331     xquery = htonl(GNUNET_GNS_RECORD_PSEU);
332
333     gph->get_handle = GNUNET_DHT_get_start(dht_handle,
334                                            GNUNET_TIME_UNIT_FOREVER_REL,
335                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
336                                            &lookup_key,
337                                            DHT_GNS_REPLICATION_LEVEL,
338                                            GNUNET_DHT_RO_NONE,
339                                            &xquery,
340                                            sizeof(xquery),
341                                            &process_auth_discovery_dht_result,
342                                            gph);
343
344   }
345 }
346
347
348 /**
349  * Callback for new authories
350  *
351  * @param name the name given by delegation
352  * @param zone the authority
353  * @param our_zone our local zone
354  * @param the private key of our authority
355  */
356 static void process_discovered_authority(char* name,
357                                     struct GNUNET_CRYPTO_ShortHashCode zone,
358                                     struct GNUNET_CRYPTO_ShortHashCode our_zone,
359                                     struct GNUNET_CRYPTO_RsaPrivateKey *key)
360 {
361   struct GetPseuAuthorityHandle *gph;
362   size_t namelen;
363
364   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "New authority %s discovered\n",
365              name);
366
367   gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
368   namelen = strlen(name) + 1;
369   memcpy(gph->name, name, namelen);
370   
371   gph->new_zone = zone;
372   gph->zone = our_zone;
373   gph->key = key;
374
375   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
376                                  &our_zone,
377                                  &gph->new_zone,
378                                  &process_zone_to_name_discover,
379                                  gph);
380
381 }
382
383 /**
384  * Initialize the resolver
385  *
386  * @param nh the namestore handle
387  * @param dh the dht handle
388  * @param lz the local zone's hash
389  * @return GNUNET_OK on success
390  */
391 int
392 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
393                   struct GNUNET_DHT_Handle *dh,
394                   struct GNUNET_CRYPTO_ShortHashCode lz,
395                   unsigned long long max_bg_queries)
396 {
397   namestore_handle = nh;
398   dht_handle = dh;
399   local_zone = lz;
400   dht_lookup_heap =
401     GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
402   max_allowed_background_queries = max_bg_queries;
403
404   if ((namestore_handle != NULL) && (dht_handle != NULL))
405   {
406     return GNUNET_OK;
407   }
408   return GNUNET_SYSERR;
409 }
410
411 /**
412  * Cleanup background lookups
413  *
414  * @param cks closure to iterator
415  * @param node heap nodes
416  * @param element the resolver handle
417  * @param cost heap cost
418  * @return always GNUNET_YES
419  */
420 static int
421 cleanup_pending_background_queries(void* cls,
422                                    struct GNUNET_CONTAINER_HeapNode *node,
423                                    void *element,
424                                    GNUNET_CONTAINER_HeapCostType cost)
425 {
426   struct ResolverHandle *rh = (struct ResolverHandle *)element;
427   
428   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
429              "Terminating background lookup for %s\n",
430              rh->name);
431   GNUNET_DHT_get_stop(rh->get_handle);
432   rh->proc(rh->proc_cls, rh, 0, NULL);
433
434   return GNUNET_YES;
435 }
436
437
438 /**
439  * Shutdown resolver
440  */
441 void
442 gns_resolver_cleanup()
443 {
444   if (0 != GNUNET_CONTAINER_heap_get_size(dht_lookup_heap))
445   {
446     GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
447                                    &cleanup_pending_background_queries,
448                                    NULL);
449   }
450 }
451
452
453 /**
454  * Helper function to free resolver handle
455  *
456  * @param rh the handle to free
457  */
458 static void
459 free_resolver_handle(struct ResolverHandle* rh)
460 {
461   struct AuthorityChain *ac;
462   struct AuthorityChain *ac_next;
463
464   if (NULL == rh)
465     return;
466
467   ac = rh->authority_chain_head;
468
469   while (NULL != ac)
470   {
471     ac_next = ac->next;
472     GNUNET_free(ac);
473     ac = ac_next;
474   }
475   GNUNET_free(rh);
476 }
477
478
479 /**
480  * Callback when record data is put into namestore
481  *
482  * @param cls the closure
483  * @param success GNUNET_OK on success
484  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
485  */
486 void
487 on_namestore_record_put_result(void *cls,
488                                int32_t success,
489                                const char *emsg)
490 {
491   if (GNUNET_NO == success)
492   {
493     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
494     return;
495   }
496   else if (GNUNET_YES == success)
497   {
498     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
499                "records successfully put in namestore\n");
500     return;
501   }
502
503   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
504              "Error putting records into namestore: %s\n", emsg);
505 }
506
507 static void
508 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
509 {
510   struct ResolverHandle *rh = cls;
511
512   if (rh->timeout_cont)
513     rh->timeout_cont(rh->timeout_cont_cls, tc);
514 }
515
516 /**
517  * Processor for background lookups in the DHT
518  *
519  * @param cls closure (NULL)
520  * @param rd_count number of records found (not 0)
521  * @param rd record data
522  */
523 static void
524 background_lookup_result_processor(void *cls,
525                                    uint32_t rd_count,
526                                    const struct GNUNET_NAMESTORE_RecordData *rd)
527 {
528   //We could do sth verbose/more useful here but it doesn't make any difference
529   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
530              "background dht lookup finished.\n");
531 }
532
533 /**
534  * Handle timeout for DHT requests
535  *
536  * @param cls the request handle as closure
537  * @param tc the task context
538  */
539 static void
540 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
541 {
542   struct ResolverHandle *rh = cls;
543   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
544   char new_name[MAX_DNS_NAME_LENGTH];
545
546   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
547              "dht lookup for query %s timed out.\n",
548              rh->name);
549   /**
550    * Start resolution in bg
551    */
552   //strcpy(new_name, rh->name);
553   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
554   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
555                   rh->name, GNUNET_GNS_TLD);
556
557   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
558              "Starting background lookup for %s type %d\n",
559              new_name, rlh->record_type);
560
561   gns_resolver_lookup_record(rh->authority,
562                              rlh->record_type,
563                              new_name,
564                              rh->priv_key,
565                              GNUNET_TIME_UNIT_FOREVER_REL,
566                              &background_lookup_result_processor,
567                              NULL);
568   
569   GNUNET_DHT_get_stop (rh->get_handle);
570   rh->proc(rh->proc_cls, rh, 0, NULL);
571 }
572
573
574 /**
575  * Function called when we get a result from the dht
576  * for our record query
577  *
578  * @param cls the request handle
579  * @param exp lifetime
580  * @param key the key the record was stored under
581  * @param get_path get path
582  * @param get_path_length get path length
583  * @param put_path put path
584  * @param put_path_length put path length
585  * @param type the block type
586  * @param size the size of the record
587  * @param data the record data
588  */
589 static void
590 process_record_result_dht(void* cls,
591                  struct GNUNET_TIME_Absolute exp,
592                  const GNUNET_HashCode * key,
593                  const struct GNUNET_PeerIdentity *get_path,
594                  unsigned int get_path_length,
595                  const struct GNUNET_PeerIdentity *put_path,
596                  unsigned int put_path_length,
597                  enum GNUNET_BLOCK_Type type,
598                  size_t size, const void *data)
599 {
600   struct ResolverHandle *rh;
601   struct RecordLookupHandle *rlh;
602   struct GNSNameRecordBlock *nrb;
603   uint32_t num_records;
604   char* name = NULL;
605   char* rd_data = (char*)data;
606   int i;
607   int rd_size;
608   
609   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
610   
611   if (data == NULL)
612     return;
613
614   //FIXME maybe check expiration here, check block type
615   
616   rh = (struct ResolverHandle *)cls;
617   rlh = (struct RecordLookupHandle *) rh->proc_cls;
618   nrb = (struct GNSNameRecordBlock*)data;
619   
620   /* stop lookup and timeout task */
621   GNUNET_DHT_get_stop (rh->get_handle);
622   
623   if (rh->dht_heap_node != NULL)
624   {
625     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
626     rh->dht_heap_node = NULL;
627   }
628   
629   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
630     GNUNET_SCHEDULER_cancel(rh->timeout_task);
631
632   rh->get_handle = NULL;
633   name = (char*)&nrb[1];
634   num_records = ntohl(nrb->rd_count);
635   {
636     struct GNUNET_NAMESTORE_RecordData rd[num_records];
637
638     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
639     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
640   
641     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
642                                                                rd_data,
643                                                                num_records,
644                                                                rd))
645     {
646       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
647       return;
648     }
649
650     for (i=0; i<num_records; i++)
651     {
652       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
653                "Got name: %s (wanted %s)\n", name, rh->name);
654       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
655                "Got type: %d\n",
656                rd[i].record_type);
657       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
658                "Got data length: %d\n", rd[i].data_size);
659       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
660                "Got flag %d\n", rd[i].flags);
661     
662      if ((strcmp(name, rh->name) == 0) &&
663          (rd[i].record_type == rlh->record_type))
664       {
665         rh->answered++;
666       }
667
668     }
669
670     /**
671      * FIXME check pubkey against existing key in namestore?
672      * https://gnunet.org/bugs/view.php?id=2179
673      */
674
675     /* Save to namestore */
676     GNUNET_NAMESTORE_record_put (namestore_handle,
677                                  &nrb->public_key,
678                                  name,
679                                  exp,
680                                  num_records,
681                                  rd,
682                                  &nrb->signature,
683                                  &on_namestore_record_put_result, //cont
684                                  NULL); //cls
685
686   
687     if (rh->answered)
688       rh->proc(rh->proc_cls, rh, num_records, rd);
689     else
690       rh->proc(rh->proc_cls, rh, 0, NULL);
691   }
692
693 }
694
695
696 /**
697  * Start DHT lookup for a (name -> query->record_type) record in
698  * rh->authority's zone
699  *
700  * @param rh the pending gns query context
701  */
702 static void
703 resolve_record_dht(struct ResolverHandle *rh)
704 {
705   uint32_t xquery;
706   struct GNUNET_CRYPTO_ShortHashCode name_hash;
707   GNUNET_HashCode lookup_key;
708   GNUNET_HashCode name_hash_double;
709   GNUNET_HashCode zone_hash_double;
710   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
711   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
712   struct ResolverHandle *rh_heap_root;
713   
714   GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
715   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
716   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
717   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
718   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
719   
720   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
721              "starting dht lookup for %s with key: %s\n",
722              rh->name, (char*)&lookup_key_string);
723
724   //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
725   rh->dht_heap_node = NULL;
726
727   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
728   {
729     /**
730      * Update timeout if necessary
731      */
732     if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
733     {
734
735     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
736                "Adjusting timeout\n");
737     /*
738      * Set timeout for authority lookup phase to 1/2
739      */
740       rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
741                                 GNUNET_TIME_relative_divide(rh->timeout, 2),
742                                                 &handle_lookup_timeout,
743                                                 rh);
744     }
745     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
746     //                                                   &dht_lookup_timeout,
747     //                                                   rh);
748     rh->timeout_cont = &dht_lookup_timeout;
749     rh->timeout_cont_cls = rh;
750   }
751   else 
752   {
753     if (max_allowed_background_queries <=
754         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
755     {
756       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
757       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
758       rh_heap_root->dht_heap_node = NULL;
759       rh_heap_root->proc(rh_heap_root->proc_cls,
760                          rh_heap_root,
761                          0,
762                          NULL);
763     }
764     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
765                                          rh,
766                                          GNUNET_TIME_absolute_get().abs_value);
767   }
768   
769   xquery = htonl(rlh->record_type);
770   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
771                        GNUNET_TIME_UNIT_FOREVER_REL,
772                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
773                        &lookup_key,
774                        DHT_GNS_REPLICATION_LEVEL,
775                        GNUNET_DHT_RO_NONE,
776                        &xquery, 
777                        sizeof(xquery),
778                        &process_record_result_dht,
779                        rh);
780
781 }
782
783
784 /**
785  * Namestore calls this function if we have record for this name.
786  * (or with rd_count=0 to indicate no matches)
787  *
788  * @param cls the pending query
789  * @param key the key of the zone we did the lookup
790  * @param expiration expiration date of the namestore entry
791  * @param name the name for which we need an authority
792  * @param rd_count the number of records with 'name'
793  * @param rd the record data
794  * @param signature the signature of the authority for the record data
795  */
796 static void
797 process_record_result_ns(void* cls,
798                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
799                   struct GNUNET_TIME_Absolute expiration,
800                   const char *name, unsigned int rd_count,
801                   const struct GNUNET_NAMESTORE_RecordData *rd,
802                   const struct GNUNET_CRYPTO_RsaSignature *signature)
803 {
804   struct ResolverHandle *rh;
805   struct RecordLookupHandle *rlh;
806   struct GNUNET_TIME_Relative remaining_time;
807   struct GNUNET_CRYPTO_ShortHashCode zone;
808
809   rh = (struct ResolverHandle *) cls;
810   rlh = (struct RecordLookupHandle *)rh->proc_cls;
811   GNUNET_CRYPTO_short_hash(key,
812                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
813                      &zone);
814   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
815   
816   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
817     GNUNET_SCHEDULER_cancel(rh->timeout_task);
818
819   rh->status = 0;
820   
821   if (name != NULL)
822   {
823     rh->status |= EXISTS;
824   }
825   
826   if (remaining_time.rel_value == 0)
827   {
828     rh->status |= EXPIRED;
829   }
830   
831   if (rd_count == 0)
832   {
833     /**
834      * Lookup terminated and no results
835      */
836     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
837                "Namestore lookup for %s terminated without results\n", name);
838
839     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
840                "Record %s unknown in namestore\n",
841                rh->name);
842     /**
843      * Our zone and no result? Cannot resolve TT
844      */
845     rh->proc(rh->proc_cls, rh, 0, NULL);
846     return;
847
848   }
849   else
850   {
851     
852     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
853                "Processing additional result %s from namestore\n", name);
854     int i;
855     for (i=0; i<rd_count;i++)
856     {
857
858       if (rd[i].record_type != rlh->record_type)
859         continue;
860       
861       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
862           == 0)
863       {
864         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
865                    "This record is expired. Skipping\n");
866         continue;
867       }
868       
869       rh->answered++;
870       
871     }
872     
873     /**
874      * no answers found
875      */
876     if (rh->answered == 0)
877     {
878       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
879                  "No answers found. This is odd!\n");
880       rh->proc(rh->proc_cls, rh, 0, NULL);
881       return;
882     }
883     
884     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
885                "Found %d answer(s) to query in %d records!\n",
886                rh->answered, rd_count);
887
888     rh->proc(rh->proc_cls, rh, rd_count, rd);
889   }
890 }
891
892
893 /**
894  * The final phase of resolution.
895  * rh->name is a name that is canonical and we do not have a delegation.
896  * Query namestore for this record
897  *
898  * @param rh the pending lookup
899  */
900 static void
901 resolve_record_ns(struct ResolverHandle *rh)
902 {
903   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
904   
905   /**
906    * Try to resolve this record in our namestore.
907    * The name to resolve is now in rh->authority_name
908    * since we tried to resolve it to an authority
909    * and failed.
910    **/
911   GNUNET_NAMESTORE_lookup_record(namestore_handle,
912                                  &rh->authority,
913                                  rh->name,
914                                  rlh->record_type,
915                                  &process_record_result_ns,
916                                  rh);
917 }
918
919
920
921 /**
922  * Handle timeout for DHT requests
923  *
924  * @param cls the request handle as closure
925  * @param tc the task context
926  */
927 static void
928 dht_authority_lookup_timeout(void *cls,
929                              const struct GNUNET_SCHEDULER_TaskContext *tc)
930 {
931   struct ResolverHandle *rh = cls;
932   struct RecordLookupHandle *rlh = rh->proc_cls;
933   char new_name[MAX_DNS_NAME_LENGTH];
934
935   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
936              "dht lookup for query %s timed out.\n",
937              rh->name);
938
939   rh->status |= TIMED_OUT;
940
941   
942   if (strcmp(rh->name, "") == 0)
943   {
944     /*
945      * promote authority back to name and try to resolve record
946      */
947     strcpy(rh->name, rh->authority_name);
948     rh->proc(rh->proc_cls, rh, 0, NULL);
949     return;
950   }
951   
952   /**
953    * Start resolution in bg
954    */
955   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
956                   "%s.%s", rh->name, GNUNET_GNS_TLD);
957   //strcpy(new_name, rh->name);
958   //strcpy(new_name+strlen(new_name), ".");
959   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
960   
961   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
962              "Starting background query for %s type %d\n",
963              new_name, rlh->record_type);
964
965   gns_resolver_lookup_record(rh->authority,
966                              rlh->record_type,
967                              new_name,
968                              rh->priv_key,
969                              GNUNET_TIME_UNIT_FOREVER_REL,
970                              &background_lookup_result_processor,
971                              NULL);
972
973   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
974              "Terminating auth lookup\n");
975
976   GNUNET_DHT_get_stop (rh->get_handle);
977   
978   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
979   
980   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
981              "Terminating auth lookup\n");
982
983   rh->proc(rh->proc_cls, rh, 0, NULL);
984 }
985
986 /* Prototype */
987 static void resolve_delegation_dht(struct ResolverHandle *rh);
988
989 /**
990  * Function called when we get a result from the dht
991  * for our query. Recursively tries to resolve authorities
992  * for name in DHT.
993  *
994  * @param cls the request handle
995  * @param exp lifetime
996  * @param key the key the record was stored under
997  * @param get_path get path
998  * @param get_path_length get path length
999  * @param put_path put path
1000  * @param put_path_length put path length
1001  * @param type the block type
1002  * @param size the size of the record
1003  * @param data the record data
1004  */
1005 static void
1006 process_delegation_result_dht(void* cls,
1007                  struct GNUNET_TIME_Absolute exp,
1008                  const GNUNET_HashCode * key,
1009                  const struct GNUNET_PeerIdentity *get_path,
1010                  unsigned int get_path_length,
1011                  const struct GNUNET_PeerIdentity *put_path,
1012                  unsigned int put_path_length,
1013                  enum GNUNET_BLOCK_Type type,
1014                  size_t size, const void *data)
1015 {
1016   struct ResolverHandle *rh;
1017   struct GNSNameRecordBlock *nrb;
1018   uint32_t num_records;
1019   char* name = NULL;
1020   char* rd_data = (char*) data;
1021   int i;
1022   int rd_size;
1023   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1024   GNUNET_HashCode zone_hash_double, name_hash_double;
1025   
1026   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
1027
1028   if (data == NULL)
1029     return;
1030   
1031   //FIXME check expiration?
1032   
1033   rh = (struct ResolverHandle *)cls;
1034   nrb = (struct GNSNameRecordBlock*)data;
1035   
1036   /* stop dht lookup and timeout task */
1037   GNUNET_DHT_get_stop (rh->get_handle);
1038
1039   rh->get_handle = NULL;
1040
1041   if (rh->dht_heap_node != NULL)
1042   {
1043     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1044     rh->dht_heap_node = NULL;
1045   }
1046
1047   num_records = ntohl(nrb->rd_count);
1048   name = (char*)&nrb[1];
1049   {
1050     struct GNUNET_NAMESTORE_RecordData rd[num_records];
1051     
1052     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1053     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1054   
1055     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1056                                                                rd_data,
1057                                                                num_records,
1058                                                                rd))
1059     {
1060       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
1061       return;
1062     }
1063
1064     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1065                "Got name: %s (wanted %s)\n", name, rh->authority_name);
1066     for (i=0; i<num_records; i++)
1067     {
1068     
1069       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1070                 "Got name: %s (wanted %s)\n", name, rh->authority_name);
1071       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1072                  "Got type: %d (wanted %d)\n",
1073                  rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1074       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1075                  "Got data length: %d\n", rd[i].data_size);
1076       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1077                  "Got flag %d\n", rd[i].flags);
1078
1079       if ((strcmp(name, rh->authority_name) == 0) &&
1080           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1081       {
1082         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
1083         rh->answered = 1;
1084         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1085         struct AuthorityChain *auth =
1086           GNUNET_malloc(sizeof(struct AuthorityChain));
1087         auth->zone = rh->authority;
1088         memset(auth->name, 0, strlen(rh->authority_name)+1);
1089         strcpy(auth->name, rh->authority_name);
1090         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1091                                      rh->authority_chain_tail,
1092                                      auth);
1093
1094         /** try to import pkey if private key available */
1095         if (rh->priv_key)
1096           process_discovered_authority(name, auth->zone,
1097                                        rh->authority_chain_tail->zone,
1098                                        rh->priv_key);
1099       }
1100
1101     }
1102
1103
1104     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1105     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1106     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1107     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1108
1109     /* Save to namestore */
1110     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1111                                           &zone))
1112     {
1113       GNUNET_NAMESTORE_record_put (namestore_handle,
1114                                  &nrb->public_key,
1115                                  name,
1116                                  exp,
1117                                  num_records,
1118                                  rd,
1119                                  &nrb->signature,
1120                                  &on_namestore_record_put_result, //cont
1121                                  NULL); //cls
1122     }
1123   }
1124   
1125   if (rh->answered)
1126   {
1127     rh->answered = 0;
1128     /**
1129      * delegate
1130      * FIXME in this case. should we ask namestore again?
1131      */
1132     if (strcmp(rh->name, "") == 0)
1133       rh->proc(rh->proc_cls, rh, 0, NULL);
1134     else
1135       resolve_delegation_dht(rh);
1136     return;
1137   }
1138   
1139   /**
1140    * No pkey but name exists
1141    */
1142   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup found no match!\n");
1143   rh->proc(rh->proc_cls, rh, 0, NULL);
1144 }
1145
1146 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1147                         +(MAX_DNS_NAME_LENGTH*2)
1148 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1149
1150
1151 static void
1152 expand_plus(char** dest, char* src, char* repl)
1153 {
1154   char* pos;
1155   unsigned int s_len = strlen(src)+1;
1156
1157   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1158              "Got %s to expand with %s\n", src, repl);
1159
1160   if (s_len < 3)
1161   {
1162     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1163                "%s to short\n", src);
1164
1165     /* no postprocessing */
1166     memcpy(*dest, src, s_len+1);
1167     return;
1168   }
1169   
1170   if (0 == strcmp(src+s_len-3, ".+"))
1171   {
1172     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1173                "Expanding .+ in %s\n", src);
1174     memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1175     strcpy(*dest, src);
1176     pos = *dest+s_len-2;
1177     strcpy(pos, repl);
1178     pos += strlen(repl);
1179     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1180                "Expanded to %s\n", *dest);
1181   }
1182   else
1183   {
1184     memcpy(*dest, src, s_len+1);
1185   }
1186 }
1187
1188 /**
1189  * finish lookup
1190  */
1191 static void
1192 finish_lookup(struct ResolverHandle *rh,
1193               struct RecordLookupHandle* rlh,
1194               unsigned int rd_count,
1195               const struct GNUNET_NAMESTORE_RecordData *rd)
1196 {
1197   int i;
1198   char new_rr_data[MAX_DNS_NAME_LENGTH];
1199   char new_mx_data[MAX_MX_LENGTH];
1200   char new_soa_data[MAX_SOA_LENGTH];
1201   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1202   char* repl_string;
1203   char* pos;
1204   unsigned int offset;
1205
1206   if (rd_count > 0)
1207     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1208
1209   for (i = 0; i < rd_count; i++)
1210   {
1211
1212     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1213         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1214         rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1215         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1216     {
1217       p_rd[i].data = rd[i].data;
1218       continue;
1219     }
1220
1221     /**
1222      * for all those records we 'should'
1223      * also try to resolve the A/AAAA records (RFC1035)
1224      * This is a feature and not important
1225      */
1226     
1227     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1228                "Postprocessing\n");
1229
1230     if (strcmp(rh->name, "+") == 0)
1231       repl_string = rlh->name;
1232     else
1233       repl_string = rlh->name+strlen(rh->name)+1;
1234
1235     offset = 0;
1236     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1237     {
1238       memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1239       offset = sizeof(uint16_t);
1240       pos = new_mx_data+offset;
1241       expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1242                   repl_string);
1243       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1244       p_rd[i].data = new_mx_data;
1245       p_rd[i].data_size = offset;
1246     }
1247     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1248     {
1249       /* expand mname and rname */
1250       pos = new_soa_data;
1251       expand_plus(&pos, (char*)rd[i].data, repl_string);
1252       offset = strlen(new_soa_data)+1;
1253       pos = new_soa_data+offset;
1254       expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1255       offset += strlen(new_soa_data+offset)+1;
1256       /* cpy the 4 numbers serial refresh retry and expire */
1257       memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*4);
1258       offset += sizeof(uint32_t)*4;
1259       p_rd[i].data_size = offset;
1260       p_rd[i].data = new_soa_data;
1261     }
1262     else
1263     {
1264       pos = new_rr_data;
1265       expand_plus(&pos, (char*)rd[i].data, repl_string);
1266       p_rd[i].data_size = strlen(new_rr_data)+1;
1267       p_rd[i].data = new_rr_data;
1268     }
1269     
1270   }
1271
1272   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1273   GNUNET_free(rlh);
1274   
1275 }
1276
1277 /**
1278  * Process DHT lookup result for record.
1279  *
1280  * @param cls the closure
1281  * @param rh resolver handle
1282  * @param rd_count number of results
1283  * @param rd record data
1284  */
1285 static void
1286 handle_record_dht(void* cls, struct ResolverHandle *rh,
1287                        unsigned int rd_count,
1288                        const struct GNUNET_NAMESTORE_RecordData *rd)
1289 {
1290   struct RecordLookupHandle* rlh;
1291
1292   rlh = (struct RecordLookupHandle*)cls;
1293   if (rd_count == 0)
1294   {
1295     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1296                "No records for %s found in DHT. Aborting\n",
1297                rh->name);
1298     /* give up, cannot resolve */
1299     finish_lookup(rh, rlh, 0, NULL);
1300     free_resolver_handle(rh);
1301     return;
1302   }
1303
1304   /* results found yay */
1305   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1306              "Record resolved from DHT!");
1307
1308   finish_lookup(rh, rlh, rd_count, rd);
1309   free_resolver_handle(rh);
1310
1311 }
1312
1313
1314 /**
1315  * Process namestore lookup result for record.
1316  *
1317  * @param cls the closure
1318  * @param rh resolver handle
1319  * @param rd_count number of results
1320  * @param rd record data
1321  */
1322 static void
1323 handle_record_ns(void* cls, struct ResolverHandle *rh,
1324                        unsigned int rd_count,
1325                        const struct GNUNET_NAMESTORE_RecordData *rd)
1326 {
1327   struct RecordLookupHandle* rlh;
1328   rlh = (struct RecordLookupHandle*) cls;
1329   if (rd_count == 0)
1330   {
1331     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Resolution status: %d!\n", rh->status);
1332     
1333     /* ns entry expired and not ours. try dht */
1334     if (rh->status & (EXPIRED | !EXISTS) &&
1335         GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1336                                      &local_zone))
1337     {
1338       rh->proc = &handle_record_dht;
1339       resolve_record_dht(rh);
1340       return;
1341     }
1342     /* give up, cannot resolve */
1343     finish_lookup(rh, rlh, 0, NULL);
1344     free_resolver_handle(rh);
1345     return;
1346   }
1347
1348   /* results found yay */
1349   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1350              "Record resolved from namestore!");
1351
1352   finish_lookup(rh, rlh, rd_count, rd);
1353
1354   free_resolver_handle(rh);
1355
1356 }
1357
1358
1359 /**
1360  * Determine if this name is canonical.
1361  * i.e.
1362  * a.b.gnunet  = not canonical
1363  * a           = canonical
1364  *
1365  * @param name the name to test
1366  * @return 1 if canonical
1367  */
1368 static int
1369 is_canonical(char* name)
1370 {
1371   uint32_t len = strlen(name);
1372   int i;
1373
1374   for (i=0; i<len; i++)
1375   {
1376     if (*(name+i) == '.')
1377       return 0;
1378   }
1379   return 1;
1380 }
1381
1382 /**
1383  * Move one level up in the domain hierarchy and return the
1384  * passed top level domain.
1385  *
1386  * @param name the domain
1387  * @param dest the destination where the tld will be put
1388  */
1389 void
1390 pop_tld(char* name, char* dest)
1391 {
1392   uint32_t len;
1393
1394   if (is_canonical(name))
1395   {
1396     strcpy(dest, name);
1397     strcpy(name, "");
1398     return;
1399   }
1400
1401   for (len = strlen(name); len > 0; len--)
1402   {
1403     if (*(name+len) == '.')
1404       break;
1405   }
1406   
1407   //Was canonical?
1408   if (len == 0)
1409     return;
1410
1411   name[len] = '\0';
1412
1413   strcpy(dest, (name+len+1));
1414 }
1415
1416 /**
1417  * Checks if name is in tld
1418  *
1419  * @param name the name to check
1420  * @param tld the TLD to check for
1421  * @return GNUNET_YES or GNUNET_NO
1422  */
1423 int
1424 is_tld(const char* name, const char* tld)
1425 {
1426   int offset = 0;
1427
1428   if (strlen(name) <= strlen(tld))
1429   {
1430     return GNUNET_NO;
1431   }
1432   
1433   offset = strlen(name)-strlen(tld);
1434   if (strcmp(name+offset, tld) != 0)
1435   {
1436     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1437                "%s is not in .%s TLD\n", name, tld);
1438     return GNUNET_NO;
1439   }
1440   return GNUNET_YES;
1441 }
1442
1443 /**
1444  * DHT resolution for delegation finished. Processing result.
1445  *
1446  * @param cls the closure
1447  * @param rh resolver handle
1448  * @param rd_count number of results (always 0)
1449  * @param rd record data (always NULL)
1450  */
1451 static void
1452 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1453                           unsigned int rd_count,
1454                           const struct GNUNET_NAMESTORE_RecordData *rd)
1455 {
1456   struct RecordLookupHandle* rlh;
1457   rlh = (struct RecordLookupHandle*) cls;
1458   
1459   
1460
1461   if (strcmp(rh->name, "") == 0)
1462   {
1463     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1464     {
1465       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1466                  "Resolved queried PKEY via DHT.\n");
1467       finish_lookup(rh, rlh, rd_count, rd);
1468       free_resolver_handle(rh);
1469       return;
1470     }
1471     /* We resolved full name for delegation. resolving record */
1472     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1473       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1474     strcpy(rh->name, "+\0");
1475     rh->proc = &handle_record_ns;
1476     resolve_record_ns(rh);
1477     return;
1478   }
1479
1480   /**
1481    * we still have some left
1482    **/
1483   if (is_canonical(rh->name))
1484   {
1485     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1486                "Resolving canonical record %s in ns\n", rh->name);
1487     rh->proc = &handle_record_ns;
1488     resolve_record_ns(rh);
1489     return;
1490   }
1491   /* give up, cannot resolve */
1492   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1493              "Cannot fully resolve delegation for %s via DHT!\n",
1494              rh->name);
1495   finish_lookup(rh, rlh, 0, NULL);
1496   free_resolver_handle(rh);
1497 }
1498
1499
1500 /**
1501  * Start DHT lookup for a name -> PKEY (compare NS) record in
1502  * rh->authority's zone
1503  *
1504  * @param rh the pending gns query
1505  */
1506 static void
1507 resolve_delegation_dht(struct ResolverHandle *rh)
1508 {
1509   uint32_t xquery;
1510   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1511   GNUNET_HashCode name_hash_double;
1512   GNUNET_HashCode zone_hash_double;
1513   GNUNET_HashCode lookup_key;
1514   struct ResolverHandle *rh_heap_root;
1515   
1516   GNUNET_CRYPTO_short_hash(rh->authority_name,
1517                      strlen(rh->authority_name),
1518                      &name_hash);
1519   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1520   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1521   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1522   
1523   rh->dht_heap_node = NULL;
1524
1525   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1526   {
1527     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1528     //                                          &dht_authority_lookup_timeout,
1529     //                                                   rh);
1530     rh->timeout_cont = &dht_authority_lookup_timeout;
1531     rh->timeout_cont_cls = rh;
1532   }
1533   else 
1534   {
1535     if (max_allowed_background_queries <=
1536         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1537     {
1538       /* terminate oldest lookup */
1539       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1540       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1541       rh_heap_root->dht_heap_node = NULL;
1542       rh_heap_root->proc(rh_heap_root->proc_cls,
1543                          rh_heap_root,
1544                          0,
1545                          NULL);
1546     }
1547     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1548                                          rh,
1549                                          GNUNET_TIME_absolute_get().abs_value);
1550   }
1551   
1552   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1553
1554   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1555                        GNUNET_TIME_UNIT_FOREVER_REL,
1556                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1557                        &lookup_key,
1558                        DHT_GNS_REPLICATION_LEVEL,
1559                        GNUNET_DHT_RO_NONE,
1560                        &xquery,
1561                        sizeof(xquery),
1562                        &process_delegation_result_dht,
1563                        rh);
1564
1565 }
1566
1567
1568 /**
1569  * Namestore resolution for delegation finished. Processing result.
1570  *
1571  * @param cls the closure
1572  * @param rh resolver handle
1573  * @param rd_count number of results (always 0)
1574  * @param rd record data (always NULL)
1575  */
1576 static void
1577 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1578                           unsigned int rd_count,
1579                           const struct GNUNET_NAMESTORE_RecordData *rd)
1580 {
1581   struct RecordLookupHandle* rlh;
1582   rlh = (struct RecordLookupHandle*) cls;
1583   
1584   if (strcmp(rh->name, "") == 0)
1585   {
1586     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1587     {
1588       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1589                  "Resolved queried PKEY in NS.\n");
1590       finish_lookup(rh, rlh, rd_count, rd);
1591       free_resolver_handle(rh);
1592       return;
1593     }
1594     /* We resolved full name for delegation. resolving record */
1595     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1596                "Resolved full name for delegation. resolving record '+'\n");
1597     strcpy(rh->name, "+\0");
1598     rh->proc = &handle_record_ns;
1599     resolve_record_ns(rh);
1600     return;
1601   }
1602
1603   /**
1604    * we still have some left
1605    * check if authority in ns is fresh
1606    * and exists
1607    * or we are authority
1608    **/
1609   if ((rh->status & (EXISTS | !EXPIRED)) ||
1610       !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1611                              &rh->authority_chain_tail->zone))
1612   {
1613     if (is_canonical(rh->name))
1614     {
1615       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1616                  "Resolving canonical record %s\n", rh->name);
1617       rh->proc = &handle_record_ns;
1618       resolve_record_ns(rh);
1619     }
1620     else
1621     {
1622       /* give up, cannot resolve */
1623       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1624                  "Cannot fully resolve delegation for %s!\n",
1625                  rh->name);
1626       rlh->proc(rlh->proc_cls, 0, NULL);
1627     }
1628     return;
1629   }
1630   
1631   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1632              "Trying to resolve delegation for %s via DHT\n",
1633              rh->name);
1634   rh->proc = &handle_delegation_dht;
1635   resolve_delegation_dht(rh);
1636 }
1637
1638 /* Prototype */
1639 static void resolve_delegation_ns(struct ResolverHandle *rh);
1640
1641
1642 /**
1643  * This is a callback function that should give us only PKEY
1644  * records. Used to query the namestore for the authority (PKEY)
1645  * for 'name'. It will recursively try to resolve the
1646  * authority for a given name from the namestore.
1647  *
1648  * @param cls the pending query
1649  * @param key the key of the zone we did the lookup
1650  * @param expiration expiration date of the record data set in the namestore
1651  * @param name the name for which we need an authority
1652  * @param rd_count the number of records with 'name'
1653  * @param rd the record data
1654  * @param signature the signature of the authority for the record data
1655  */
1656 static void
1657 process_delegation_result_ns(void* cls,
1658                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1659                    struct GNUNET_TIME_Absolute expiration,
1660                    const char *name,
1661                    unsigned int rd_count,
1662                    const struct GNUNET_NAMESTORE_RecordData *rd,
1663                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1664 {
1665   struct ResolverHandle *rh;
1666   struct GNUNET_TIME_Relative remaining_time;
1667   struct GNUNET_CRYPTO_ShortHashCode zone;
1668   char new_name[MAX_DNS_NAME_LENGTH];
1669   
1670   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1671              rd_count);
1672
1673   rh = (struct ResolverHandle *)cls;
1674   GNUNET_CRYPTO_short_hash(key,
1675                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1676                      &zone);
1677   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1678   
1679   rh->status = 0;
1680   
1681   if (name != NULL)
1682   {
1683     rh->status |= EXISTS;
1684   }
1685   
1686   if (remaining_time.rel_value == 0)
1687   {
1688     rh->status |= EXPIRED;
1689   }
1690   
1691   /**
1692    * No authority found in namestore.
1693    */
1694   if (rd_count == 0)
1695   {
1696     /**
1697      * We did not find an authority in the namestore
1698      */
1699     
1700     /**
1701      * No PKEY in zone.
1702      * Promote this authority back to a name maybe it is
1703      * our record.
1704      */
1705     if (strcmp(rh->name, "") == 0)
1706     {
1707       /* simply promote back */
1708       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1709                  "Promoting %s back to name\n", rh->authority_name);
1710       strcpy(rh->name, rh->authority_name);
1711     }
1712     else
1713     {
1714       /* add back to existing name */
1715       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1716                  "Adding %s back to %s\n",
1717                  rh->authority_name, rh->name);
1718       //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1719       strcpy(new_name, rh->name);
1720       strcpy(new_name+strlen(new_name), ".");
1721       strcpy(new_name+strlen(new_name), rh->authority_name);
1722       strcpy(rh->name, new_name);
1723       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1724                  "%s restored\n", rh->name);
1725     }
1726     rh->proc(rh->proc_cls, rh, 0, NULL);
1727     return;
1728   }
1729
1730   /**
1731    * We found an authority that may be able to help us
1732    * move on with query
1733    * Note only 1 pkey should have been returned.. anything else would be strange
1734    */
1735   int i;
1736   for (i=0; i<rd_count;i++)
1737   {
1738   
1739     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1740       continue;
1741     
1742     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1743          == 0)
1744     {
1745       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1746       if (remaining_time.rel_value == 0)
1747       {
1748         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1749                    "This dht entry is expired.\n");
1750         rh->authority_chain_head->fresh = 0;
1751         rh->proc(rh->proc_cls, rh, 0, NULL);
1752         return;
1753       }
1754
1755       continue;
1756     }
1757
1758     /**
1759      * Resolve rest of query with new authority
1760      */
1761     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1762     memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1763     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1764     auth->zone = rh->authority;
1765     memset(auth->name, 0, strlen(rh->authority_name)+1);
1766     strcpy(auth->name, rh->authority_name);
1767     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1768                                  rh->authority_chain_tail,
1769                                  auth);
1770     
1771     /**
1772      * We are done with PKEY resolution if name is empty
1773      * else resolve again with new authority
1774      */
1775     if (strcmp(rh->name, "") == 0)
1776       rh->proc(rh->proc_cls, rh, 0, NULL);
1777     else
1778       resolve_delegation_ns(rh);
1779     return;
1780   }
1781     
1782   /**
1783    * no answers found
1784    */
1785   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1786              "Authority lookup successful but no PKEY... never get here\n");
1787   rh->proc(rh->proc_cls, rh, 0, NULL);
1788 }
1789
1790
1791 /**
1792  * Resolve the delegation chain for the request in our namestore
1793  *
1794  * @param rh the resolver handle
1795  */
1796 static void
1797 resolve_delegation_ns(struct ResolverHandle *rh)
1798 {
1799   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1800              "Resolving delegation for %s\n", rh->name);
1801   pop_tld(rh->name, rh->authority_name);
1802   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1803                                  &rh->authority,
1804                                  rh->authority_name,
1805                                  GNUNET_GNS_RECORD_PKEY,
1806                                  &process_delegation_result_ns,
1807                                  rh);
1808
1809 }
1810
1811
1812 /**
1813  * Lookup of a record in a specific zone
1814  * calls lookup result processor on result
1815  *
1816  * @param zone the root zone
1817  * @param record_type the record type to look up
1818  * @param name the name to look up
1819  * @param key a private key for use with PSEU import (can be NULL)
1820  * @param timeout timeout for resolution
1821  * @param proc the processor to call on result
1822  * @param cls the closure to pass to proc
1823  */
1824 void
1825 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1826                            uint32_t record_type,
1827                            const char* name,
1828                            struct GNUNET_CRYPTO_RsaPrivateKey *key,
1829                            struct GNUNET_TIME_Relative timeout,
1830                            RecordLookupProcessor proc,
1831                            void* cls)
1832 {
1833   struct ResolverHandle *rh;
1834   struct RecordLookupHandle* rlh;
1835   char string_hash[MAX_DNS_LABEL_LENGTH];
1836
1837   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1838               "Starting resolution for %s (type=%d)!\n",
1839               name, record_type);
1840
1841   
1842   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1843   {
1844     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1845                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1846     proc(cls, 0, NULL);
1847     return;
1848   }
1849   
1850   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1851   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1852
1853   rh->authority = zone;
1854   rh->proc_cls = rlh;
1855   rh->priv_key = key;
1856   rh->timeout = timeout;
1857   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1858   {
1859     /*
1860      * Set timeout for authority lookup phase to 1/2
1861      */
1862     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1863                                 GNUNET_TIME_relative_divide(timeout, 2),
1864                                                 &handle_lookup_timeout,
1865                                                 rh);
1866     rh->timeout_cont = &dht_authority_lookup_timeout;
1867     rh->timeout_cont_cls = rh;
1868   }
1869   else
1870   {
1871     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
1872     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1873   }
1874   
1875   if (strcmp(GNUNET_GNS_TLD, name) == 0)
1876   {
1877     /**
1878      * Only 'gnunet' given
1879      */
1880     strcpy(rh->name, "\0");
1881   }
1882   else
1883   {
1884     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1885                 "Checking for TLD...\n");
1886     if (is_zkey_tld(name) == GNUNET_YES)
1887     {
1888       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1889                   "TLD is zkey\n");
1890       /**
1891        * This is a zkey tld
1892        * build hash and use as initial authority
1893        */
1894       memset(rh->name, 0,
1895              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1896       memcpy(rh->name, name,
1897              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1898       pop_tld(rh->name, string_hash);
1899
1900       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1901                   "ZKEY is %s!\n", string_hash);
1902
1903       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1904                                                       &rh->authority))
1905       {
1906         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1907                     "Cannot convert ZKEY %s to hash!\n", string_hash);
1908         GNUNET_free(rh);
1909         GNUNET_free(rlh);
1910         proc(cls, 0, NULL);
1911         return;
1912       }
1913
1914     }
1915     else
1916     {
1917       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1918                   "TLD is gnunet\n");
1919       /**
1920        * Presumably GNUNET tld
1921        */
1922       memset(rh->name, 0,
1923              strlen(name)-strlen(GNUNET_GNS_TLD));
1924       memcpy(rh->name, name,
1925              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1926     }
1927   }
1928   
1929   /**
1930    * Initialize authority chain
1931    */
1932   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1933   rh->authority_chain_head->prev = NULL;
1934   rh->authority_chain_head->next = NULL;
1935   rh->authority_chain_tail = rh->authority_chain_head;
1936   rh->authority_chain_head->zone = rh->authority;
1937   
1938   /**
1939    * Copy original query into lookup handle
1940    */
1941   rlh->record_type = record_type;
1942   memset(rlh->name, 0, strlen(name) + 1);
1943   strcpy(rlh->name, name);
1944   rlh->proc = proc;
1945   rlh->proc_cls = cls;
1946
1947   rh->proc = &handle_delegation_ns;
1948   resolve_delegation_ns(rh);
1949 }
1950
1951 /******** END Record Resolver ***********/
1952
1953
1954 /**
1955  * Callback calles by namestore for a zone to name
1956  * result
1957  *
1958  * @param cls the closure
1959  * @param zone_key the zone we queried
1960  * @param expire the expiration time of the name
1961  * @param name the name found or NULL
1962  * @param rd_len number of records for the name
1963  * @param rd the record data (PKEY) for the name
1964  * @param signature the signature for the record data
1965  */
1966 static void
1967 process_zone_to_name_shorten(void *cls,
1968                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1969                  struct GNUNET_TIME_Absolute expire,
1970                  const char *name,
1971                  unsigned int rd_len,
1972                  const struct GNUNET_NAMESTORE_RecordData *rd,
1973                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1974 {
1975   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1976   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1977   struct AuthorityChain *next_authority;
1978
1979   char result[MAX_DNS_NAME_LENGTH];
1980   char next_authority_name[MAX_DNS_LABEL_LENGTH];
1981   size_t answer_len;
1982   
1983   /* we found a match in our own zone */
1984   if (rd_len != 0)
1985   {
1986     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1987                "result strlen %d\n", strlen(name));
1988     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1989     memset(result, 0, answer_len);
1990     if (strlen(rh->name) > 0)
1991     {
1992       strcpy(result, rh->name);
1993       strcpy(result+strlen(rh->name), ".");
1994     }
1995     
1996     strcpy(result+strlen(result), name);
1997     strcpy(result+strlen(result), ".");
1998     strcpy(result+strlen(result), GNUNET_GNS_TLD);
1999     
2000     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2001                "Sending shorten result %s\n", result);
2002
2003     nsh->proc(nsh->proc_cls, result);
2004     GNUNET_free(nsh);
2005     free_resolver_handle(rh);
2006   }
2007   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2008                                         &local_zone))
2009   {
2010     /* our zone, just append .gnunet */
2011     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2012     memset(result, 0, answer_len);
2013     strcpy(result, rh->name);
2014     strcpy(result+strlen(rh->name), ".");
2015     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2016
2017     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2018                "Our zone: Sending name as shorten result %s\n", rh->name);
2019     
2020     nsh->proc(nsh->proc_cls, result);
2021     GNUNET_free(nsh);
2022     free_resolver_handle(rh);
2023   }
2024   else
2025   {
2026     /**
2027      * No PSEU found.
2028      * continue with next authority
2029      */
2030     next_authority = rh->authority_chain_head;
2031     //                         strlen(next_authority->name) + 2);
2032     memset(next_authority_name, 0, strlen(rh->name)+
2033                       strlen(next_authority->name) + 2);
2034     strcpy(next_authority_name, rh->name);
2035     strcpy(next_authority_name+strlen(rh->name)+1, ".");
2036     strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
2037   
2038     strcpy(rh->name, next_authority_name);
2039     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2040                               rh->authority_chain_tail,
2041                               next_authority);
2042
2043     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2044                                    &rh->authority_chain_tail->zone,
2045                                    &rh->authority_chain_head->zone,
2046                                    &process_zone_to_name_shorten,
2047                                    rh);
2048   }
2049 }
2050
2051
2052 /**
2053  * Process result from namestore delegation lookup
2054  * for shorten operation
2055  *
2056  * @param cls the client shorten handle
2057  * @param rh the resolver handle
2058  * @param rd_count number of results (0)
2059  * @param rd data (NULL)
2060  */
2061 void
2062 handle_delegation_ns_shorten(void* cls,
2063                       struct ResolverHandle *rh,
2064                       uint32_t rd_count,
2065                       const struct GNUNET_NAMESTORE_RecordData *rd)
2066 {
2067   struct NameShortenHandle *nsh;
2068   char result[MAX_DNS_NAME_LENGTH];
2069   size_t answer_len;
2070
2071   nsh = (struct NameShortenHandle *)cls;
2072   
2073   /**
2074    * At this point rh->name contains the part of the name
2075    * that we do not have a PKEY in our namestore to resolve.
2076    * The authority chain in the resolver handle is now
2077    * useful to backtrack if needed
2078    */
2079   
2080   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2081              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2082
2083   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2084                                    &local_zone) == 0)
2085   {
2086     /**
2087      * This is our zone append .gnunet unless name is empty
2088      * (it shouldn't be, usually FIXME what happens if we
2089      * shorten to our zone to a "" record??)
2090      */
2091     
2092     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2093     memset(result, 0, answer_len);
2094     strcpy(result, rh->name);
2095     strcpy(result+strlen(rh->name), ".");
2096     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2097
2098     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2099                "Our zone: Sending name as shorten result %s\n", rh->name);
2100     
2101     nsh->proc(nsh->proc_cls, result);
2102     GNUNET_free(nsh);
2103     free_resolver_handle(rh);
2104     return;
2105   }
2106   
2107   /* backtrack authorities for names */
2108   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2109                                  &rh->authority_chain_tail->zone, //ours
2110                                  &rh->authority_chain_head->zone,
2111                                  &process_zone_to_name_shorten,
2112                                  rh);
2113
2114 }
2115
2116 /**
2117  * Shorten api from resolver
2118  *
2119  * @param zone the zone to use
2120  * @param name the name to shorten
2121  * @param proc the processor to call with result
2122  * @param cls closure to pass to proc
2123  */
2124 void
2125 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2126                           const char* name,
2127                           ShortenResultProcessor proc,
2128                           void* cls)
2129 {
2130   struct ResolverHandle *rh;
2131   struct NameShortenHandle *nsh;
2132   char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME LABEL length when shorthash
2133
2134   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2135               "Starting shorten for %s!\n", name);
2136   
2137   if (is_canonical((char*)name))
2138   {
2139     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2140                 "%s is canonical. Returning verbatim\n", name);
2141     proc(cls, name);
2142     return;
2143   }
2144
2145   nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2146   
2147
2148   nsh->proc = proc;
2149   nsh->proc_cls = cls;
2150   
2151   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2152   rh->authority = zone;
2153   
2154   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2155                 "Checking for TLD...\n");
2156   if (is_zkey_tld(name) == GNUNET_YES)
2157   {
2158     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2159                 "TLD is zkey\n");
2160     /**
2161      * This is a zkey tld
2162      * build hash and use as initial authority
2163      */
2164     memset(rh->name, 0,
2165            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2166     memcpy(rh->name, name,
2167            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2168     pop_tld(rh->name, string_hash);
2169
2170     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2171                 "ZKEY is %s!\n", string_hash);
2172
2173     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
2174                                                           &rh->authority))
2175     {
2176       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2177                   "Cannot convert ZKEY %s to hash!\n", string_hash);
2178       GNUNET_free(rh);
2179       GNUNET_free(nsh);
2180       proc(cls, name);
2181       return;
2182     }
2183
2184   }
2185   else
2186   {
2187     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2188                 "TLD is gnunet\n");
2189     /**
2190      * Presumably GNUNET tld
2191      */
2192     memset(rh->name, 0,
2193            strlen(name)-strlen(GNUNET_GNS_TLD));
2194     memcpy(rh->name, name,
2195            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2196   }
2197
2198   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2199   rh->authority_chain_tail = rh->authority_chain_head;
2200   rh->authority_chain_head->zone = zone;
2201   rh->proc = &handle_delegation_ns_shorten;
2202   rh->proc_cls = nsh;
2203   
2204   /* Start delegation resolution in our namestore */
2205   resolve_delegation_ns(rh);
2206 }
2207
2208 /*********** END NAME SHORTEN ********************/
2209
2210
2211 /**
2212  * Process result from namestore delegation lookup
2213  * for get authority operation
2214  *
2215  * @param cls the client get auth handle
2216  * @param rh the resolver handle
2217  * @param rd_count number of results (0)
2218  * @param rd data (NULL)
2219  */
2220 void
2221 handle_delegation_result_ns_get_auth(void* cls,
2222                       struct ResolverHandle *rh,
2223                       uint32_t rd_count,
2224                       const struct GNUNET_NAMESTORE_RecordData *rd)
2225 {
2226   struct GetNameAuthorityHandle* nah;
2227   char result[MAX_DNS_NAME_LENGTH];
2228   size_t answer_len;
2229
2230   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2231   
2232   /**
2233    * At this point rh->name contains the part of the name
2234    * that we do not have a PKEY in our namestore to resolve.
2235    * The authority chain in the resolver handle is now
2236    * useful to backtrack if needed
2237    */
2238   
2239   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2240              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2241
2242   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2243              "Building response!\n");
2244   if (is_canonical(rh->name))
2245   {
2246     /**
2247      * We successfully resolved the authority in the ns
2248      * FIXME for our purposes this is fine
2249      * but maybe we want to have an api that also looks
2250      * into the dht (i.e. option in message)
2251      **/
2252     if (strlen(rh->name) > strlen(nah->name))
2253     {
2254       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2255                  "Record name longer than original lookup name... odd!\n");
2256       //FIXME to sth here
2257     }
2258
2259     answer_len = strlen(nah->name) - strlen(rh->name)
2260       + strlen(GNUNET_GNS_TLD) + 1;
2261     memset(result, 0, answer_len);
2262     strcpy(result, nah->name + strlen(rh->name) + 1);
2263
2264     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2265                "Got authority result %s\n", result);
2266     
2267     nah->proc(nah->proc_cls, result);
2268     GNUNET_free(nah);
2269     free_resolver_handle(rh);
2270   }
2271   else
2272   {
2273     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2274                "Unable to resolve authority for remaining %s!\n", rh->name);
2275     nah->proc(nah->proc_cls, "");
2276     GNUNET_free(nah);
2277     free_resolver_handle(rh);
2278   }
2279
2280
2281 }
2282
2283
2284 /**
2285  * Tries to resolve the authority for name
2286  * in our namestore
2287  *
2288  * @param zone the root zone to look up for
2289  * @param name the name to lookup up
2290  * @param proc the processor to call when finished
2291  * @param cls the closure to pass to the processor
2292  */
2293 void
2294 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2295                            const char* name,
2296                            GetAuthorityResultProcessor proc,
2297                            void* cls)
2298 {
2299   struct ResolverHandle *rh;
2300   struct GetNameAuthorityHandle *nah;
2301
2302   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2303               "Starting authority resolution for %s!\n", name);
2304
2305   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2306   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2307   rh->authority = zone;
2308   
2309   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2310   {
2311     strcpy(rh->name, "\0");
2312   }
2313   else
2314   {
2315     memset(rh->name, 0,
2316            strlen(name)-strlen(GNUNET_GNS_TLD));
2317     memcpy(rh->name, name,
2318            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2319   }
2320
2321   memset(nah->name, 0,
2322          strlen(name)+1);
2323   strcpy(nah->name, name);
2324   
2325   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2326   rh->authority_chain_tail = rh->authority_chain_head;
2327   rh->authority_chain_head->zone = zone;
2328   rh->proc = &handle_delegation_result_ns_get_auth;
2329   rh->proc_cls = (void*)nah;
2330
2331   nah->proc = proc;
2332   nah->proc_cls = cls;
2333
2334   /* Start delegation resolution in our namestore */
2335   resolve_delegation_ns(rh);
2336
2337 }
2338
2339 /******** END GET AUTHORITY *************/
2340
2341 /* end of gnunet-service-gns_resolver.c */