ff7842758e3f331af755809ccde1245699c1c3f8
[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_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
42 #define DHT_GNS_REPLICATION_LEVEL 5
43 #define MAX_DNS_LABEL_LENGTH 63
44
45
46 /**
47  * Our handle to the namestore service
48  */
49 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
50
51 /**
52  * Resolver handle to the dht
53  */
54 static struct GNUNET_DHT_Handle *dht_handle;
55
56 /**
57  * Heap for parallel DHT lookups
58  */
59 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
60
61 /**
62  * Maximum amount of parallel queries in background
63  */
64 static unsigned long long max_allowed_background_queries;
65
66 /**
67  * Wheather or not to ignore pending records
68  */
69 static int ignore_pending_records;
70
71 /**
72  * Our local zone
73  */
74 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
75
76 /**
77  * a resolution identifier pool variable
78  * FIXME overflow?
79  * This is a non critical identifier useful for debugging
80  */
81 static unsigned long long rid = 0;
82
83
84 /**
85  * Determine if this name is canonical.
86  * i.e.
87  * a.b.gnunet  = not canonical
88  * a           = canonical
89  *
90  * @param name the name to test
91  * @return 1 if canonical
92  */
93 static int
94 is_canonical(char* name)
95 {
96   uint32_t len = strlen(name);
97   int i;
98
99   for (i=0; i<len; i++)
100   {
101     if (*(name+i) == '.')
102       return 0;
103   }
104   return 1;
105 }
106
107
108 /**
109  * Callback that shortens authorities
110  *
111  * @param name the name given by delegation
112  * @param zone the authority
113  * @param our_zone our local zone
114  * @param key the private key of our authority
115  */
116 static void
117 shorten_authority_chain (struct GetPseuAuthorityHandle *gph);
118
119
120 /**
121  * Namestore calls this function if we have record for this name.
122  * (or with rd_count=0 to indicate no matches)
123  *
124  * @param cls the pending query
125  * @param key the key of the zone we did the lookup
126  * @param expiration expiration date of the namestore entry
127  * @param name the name for which we need an authority
128  * @param rd_count the number of records with 'name'
129  * @param rd the record data
130  * @param signature the signature of the authority for the record data
131  */
132 static void
133 process_pseu_lookup_ns (void* cls,
134                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
135                       struct GNUNET_TIME_Absolute expiration,
136                       const char *name, unsigned int rd_count,
137                       const struct GNUNET_NAMESTORE_RecordData *rd,
138                       const struct GNUNET_CRYPTO_RsaSignature *signature)
139 {
140   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
141   struct GNUNET_NAMESTORE_RecordData new_pkey;
142   struct AuthorityChain *iter;
143
144   if (rd_count > 0)
145   {
146     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
147                "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
148     if (0 == strcmp (gph->name, name))
149     {
150       if (gph->ahead->next != NULL)
151       {
152         if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
153                                           &gph->our_zone))
154         {
155           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
156           iter = gph->ahead->next;
157           GNUNET_free (gph->ahead);
158           gph->ahead = iter;
159           shorten_authority_chain (gph);
160           return;
161         }
162       }
163
164       /* Clean up */
165       do
166       {
167         iter = gph->ahead->next;
168         GNUNET_free (gph->ahead);
169         gph->ahead = iter;
170       } while (iter != NULL);
171       GNUNET_CRYPTO_rsa_key_free (gph->key);
172
173       GNUNET_free (gph);
174       return;
175     }
176
177     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178                 "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name);
179     memcpy (gph->test_name, gph->name, strlen (gph->name)+1);
180     GNUNET_NAMESTORE_lookup_record (namestore_handle,
181                                     &gph->our_zone,
182                                     gph->test_name,
183                                     GNUNET_NAMESTORE_TYPE_ANY,
184                                     &process_pseu_lookup_ns,
185                                     gph);
186     return;
187   }
188
189   /** name is free */
190   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191             "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->test_name);
192
193   new_pkey.expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
194   new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode);
195   new_pkey.data = &gph->ahead->zone;
196   new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
197   new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
198                  | GNUNET_NAMESTORE_RF_PRIVATE
199                  | GNUNET_NAMESTORE_RF_PENDING;
200   GNUNET_NAMESTORE_record_create (namestore_handle,
201                                   gph->key,
202                                   gph->test_name,
203                                   &new_pkey,
204                                   NULL, //cont
205                                   NULL); //cls
206   do
207   {
208     iter = gph->ahead->next;
209     GNUNET_free (gph->ahead);
210     gph->ahead = iter;
211   } while (iter != NULL);
212   GNUNET_CRYPTO_rsa_key_free (gph->key);
213   GNUNET_free (gph);
214
215 }
216
217 /**
218  * process result of a dht pseu lookup
219  *
220  * @param gph the handle
221  * @param name the pseu result or NULL
222  */
223 static void
224 process_pseu_result (struct GetPseuAuthorityHandle* gph, char* name)
225 {
226   if (NULL == name)
227   {
228     memcpy (gph->test_name, gph->ahead->name, strlen (gph->ahead->name)+1);
229   }
230   else
231   {
232     memcpy (gph->test_name, name, strlen(name)+1);
233   }
234
235   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236               "GNS_AUTO_PSEU: Checking %s for collision in NS\n",
237               gph->test_name);
238
239   /**
240    * Check for collision
241    */
242   GNUNET_NAMESTORE_lookup_record (namestore_handle,
243                                   &gph->our_zone,
244                                   gph->test_name,
245                                   GNUNET_NAMESTORE_TYPE_ANY,
246                                   &process_pseu_lookup_ns,
247                                   gph);
248 }
249
250 /**
251  * Handle timeout for dht request
252  *
253  * @param cls the request handle as closure
254  * @param tc the task context
255  */
256 static void
257 handle_auth_discovery_timeout(void *cls,
258                               const struct GNUNET_SCHEDULER_TaskContext *tc)
259 {
260   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
261   struct AuthorityChain *iter;
262
263   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
264               "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
265   GNUNET_DHT_get_stop (gph->get_handle);
266   gph->get_handle = NULL;
267   
268   if (gph->ahead->next != NULL)
269   {
270     if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
271                                       &gph->our_zone))
272     {
273       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
274       iter = gph->ahead->next;
275       GNUNET_free (gph->ahead);
276       gph->ahead = iter;
277       shorten_authority_chain (gph);
278       return;
279     }
280   }
281   
282   process_pseu_result (gph, NULL);
283 }
284
285 /**
286  * Function called when we find a PSEU entry in the DHT
287  *
288  * @param cls the request handle
289  * @param exp lifetime
290  * @param key the key the record was stored under
291  * @param get_path get path
292  * @param get_path_length get path length
293  * @param put_path put path
294  * @param put_path_length put path length
295  * @param type the block type
296  * @param size the size of the record
297  * @param data the record data
298  */
299 static void
300 process_auth_discovery_dht_result(void* cls,
301                                   struct GNUNET_TIME_Absolute exp,
302                                   const struct GNUNET_HashCode * key,
303                                   const struct GNUNET_PeerIdentity *get_path,
304                                   unsigned int get_path_length,
305                                   const struct GNUNET_PeerIdentity *put_path,
306                                   unsigned int put_path_length,
307                                   enum GNUNET_BLOCK_Type type,
308                                   size_t size, const void *data)
309 {
310   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
311   struct AuthorityChain *iter;
312   struct GNSNameRecordBlock *nrb;
313   char* rd_data = (char*)data;
314   char* name;
315   int num_records;
316   size_t rd_size;
317   int i;
318
319   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
320               "GNS_GET_AUTH: got dht result (size=%d)\n", size);
321
322   if (data == NULL)
323   {
324     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
325                 "GNS_GET_AUTH: got dht result null!\n", size);
326     
327     do
328     {
329       iter = gph->ahead->next;
330       GNUNET_free (gph->ahead);
331       gph->ahead = iter;
332     } while (iter != NULL);
333     GNUNET_CRYPTO_rsa_key_free (gph->key);
334     GNUNET_free (gph);
335     return;
336   }
337   
338   nrb = (struct GNSNameRecordBlock*)data;
339
340   /* stop lookup and timeout task */
341   GNUNET_DHT_get_stop (gph->get_handle);
342   gph->get_handle = NULL;
343   GNUNET_SCHEDULER_cancel (gph->timeout);
344
345   gph->get_handle = NULL;
346
347   nrb = (struct GNSNameRecordBlock*)data;
348   
349   name = (char*)&nrb[1];
350   num_records = ntohl (nrb->rd_count);
351   {
352     struct GNUNET_NAMESTORE_RecordData rd[num_records];
353
354     rd_data += strlen (name) + 1 + sizeof (struct GNSNameRecordBlock);
355     rd_size = size - strlen (name) - 1 - sizeof (struct GNSNameRecordBlock);
356
357     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
358                                                                rd_data,
359                                                                num_records,
360                                                                rd))
361     {
362       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
363                   "GNS_GET_AUTH: Error deserializing data!\n");
364     }
365     else
366     {
367       for (i=0; i < num_records; i++)
368       {
369         if ((strcmp (name, "+") == 0) &&
370             (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
371         {
372           /* found pseu */
373           process_pseu_result (gph, (char*)rd[i].data);
374           return;
375         }
376       }
377     }
378   }
379
380   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n");
381
382   if (gph->ahead->next != NULL)
383   {
384     if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
385                                       &gph->our_zone))
386     {
387       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
388       iter = gph->ahead->next;
389       GNUNET_free (gph->ahead);
390       gph->ahead = iter;
391       shorten_authority_chain (gph);
392       return;
393     }
394   }
395   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
396               "GNS_GET_AUTH: finished shorten, no results!\n");
397   process_pseu_result (gph, NULL);
398 }
399
400 /**
401  * Process PSEU discovery for shorten via namestore
402  *
403  * @param cls the GetPseuAuthorityHandle
404  * @param key the public key
405  * @param expiration recorddata expiration
406  * @param name the looked up name
407  * @param rd_count number of records in set
408  * @param rd record data
409  * @param signature the signature
410  */
411 static void
412 process_auth_discovery_ns_result(void* cls,
413                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
414                       struct GNUNET_TIME_Absolute expiration,
415                       const char *name,
416                       unsigned int rd_count,
417                       const struct GNUNET_NAMESTORE_RecordData *rd,
418                       const struct GNUNET_CRYPTO_RsaSignature *signature)
419 {
420   uint32_t xquery;
421   struct GNUNET_CRYPTO_ShortHashCode name_hash;
422   struct GNUNET_HashCode lookup_key;
423   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
424   struct GNUNET_HashCode name_hash_double;
425   struct GNUNET_HashCode zone_hash_double;
426   int i;
427   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
428   struct AuthorityChain *iter;
429   
430   /* no pseu found */
431   if (rd_count == 0)
432   {
433     /**
434      * check dht
435      */
436     GNUNET_CRYPTO_short_hash ("+", strlen ("+"), &name_hash);
437     GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
438     GNUNET_CRYPTO_short_hash_double (&gph->ahead->zone, &zone_hash_double);
439     GNUNET_CRYPTO_hash_xor (&name_hash_double, &zone_hash_double, &lookup_key);
440     GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
441
442     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
443                "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
444                "+", (char*)&lookup_key_string);
445
446     gph->timeout = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
447                                          &handle_auth_discovery_timeout, gph);
448
449     xquery = htonl (GNUNET_GNS_RECORD_PSEU);
450     
451     GNUNET_assert (gph->get_handle == NULL);
452
453     gph->get_handle = GNUNET_DHT_get_start(dht_handle,
454                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
455                                            &lookup_key,
456                                            DHT_GNS_REPLICATION_LEVEL,
457                                            GNUNET_DHT_RO_NONE,
458                                            &xquery,
459                                            sizeof(xquery),
460                                            &process_auth_discovery_dht_result,
461                                            gph);
462     return;
463   }
464
465   for (i=0; i < rd_count; i++)
466   {
467     if ((strcmp (name, "+") == 0) &&
468         (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
469     {
470       /* found pseu */
471       process_pseu_result (gph, (char*)rd[i].data);
472       return;
473     }
474   }
475
476   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in namestore!\n");
477   
478   if (gph->ahead->next != NULL)
479   {
480     if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
481                                       &gph->our_zone))
482     {
483       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
484       iter = gph->ahead->next;
485       GNUNET_free (gph->ahead);
486       gph->ahead = iter;
487       shorten_authority_chain (gph);
488       return;
489     }
490   }
491   
492   process_pseu_result (gph, NULL);
493 }
494
495 /**
496  * Callback called by namestore for a zone to name
497  * result
498  *
499  * @param cls the closure
500  * @param zone_key the zone we queried
501  * @param expire the expiration time of the name
502  * @param name the name found or NULL
503  * @param rd_len number of records for the name
504  * @param rd the record data (PKEY) for the name
505  * @param signature the signature for the record data
506  */
507 static void
508 process_zone_to_name_discover (void *cls,
509                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
510                  struct GNUNET_TIME_Absolute expire,
511                  const char *name,
512                  unsigned int rd_len,
513                  const struct GNUNET_NAMESTORE_RecordData *rd,
514                  const struct GNUNET_CRYPTO_RsaSignature *signature)
515 {
516   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
517   struct AuthorityChain *iter;
518
519   /* we found a match in our own zone */
520   if (rd_len != 0)
521   {
522     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
523                "GNS_AUTO_PSEU: name for zone in our root %s\n", name);
524
525     iter = gph->ahead;
526     do
527     {
528       iter = gph->ahead->next;
529       GNUNET_free (gph->ahead);
530       gph->ahead = iter;
531     } while (iter != NULL);
532     GNUNET_CRYPTO_rsa_key_free (gph->key);
533     GNUNET_free (gph);
534   }
535   else
536   {
537
538     GNUNET_NAMESTORE_lookup_record (namestore_handle,
539                                     &gph->ahead->zone,
540                                     "+",
541                                     GNUNET_GNS_RECORD_PSEU,
542                                     &process_auth_discovery_ns_result,
543                                     gph);
544   }
545
546 }
547
548
549 /**
550  * Callback that shortens authorities
551  *
552  * @param name the name given by delegation
553  * @param zone the authority
554  * @param our_zone our local zone
555  * @param key the private key of our authority
556  */
557 static void
558 shorten_authority_chain (struct GetPseuAuthorityHandle *gph)
559 {
560
561   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
562               "GNS_AUTO_PSEU: New authority %s discovered\n",
563               gph->ahead->name);
564
565   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
566                                  &gph->our_zone,
567                                  &gph->ahead->zone,
568                                  &process_zone_to_name_discover,
569                                  gph);
570
571 }
572
573 static void
574 start_shorten (struct AuthorityChain *atail,
575                struct GNUNET_CRYPTO_RsaPrivateKey *key)
576 {
577   struct AuthorityChain *new_head = NULL;
578   struct AuthorityChain *new_tail = NULL;
579   struct AuthorityChain *iter;
580   struct AuthorityChain *acopy;
581   struct GetPseuAuthorityHandle *gph;
582   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
583   struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pb_key;
584
585   /* First copy the authority chain in reverse order */
586   for (iter = atail; iter != NULL; iter = iter->prev)
587   {
588     acopy = GNUNET_malloc (sizeof (struct AuthorityChain));
589     memcpy (acopy, iter, sizeof (struct AuthorityChain));
590     acopy->next = NULL;
591     acopy->prev = NULL;
592     GNUNET_CONTAINER_DLL_insert (new_head, new_tail, acopy);
593   }
594
595   gph = GNUNET_malloc (sizeof (struct GetPseuAuthorityHandle));
596
597   GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
598   pb_key = GNUNET_CRYPTO_rsa_encode_key (key);
599   gph->key = GNUNET_CRYPTO_rsa_decode_key ((char*)pb_key, ntohs (pb_key->len));
600   //gph->key = key;//GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
601   //memcpy (gph->key, key, sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
602   
603   GNUNET_CRYPTO_short_hash (&pkey,
604                         sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
605                         &gph->our_zone);
606   gph->ahead = new_head;
607
608   shorten_authority_chain (gph);
609 }
610
611 /**
612  * Initialize the resolver
613  *
614  * @param nh the namestore handle
615  * @param dh the dht handle
616  * @param lz the local zone's hash
617  * @param max_bg_queries maximum number of parallel background queries in dht
618  * @param ignore_pending ignore records that still require user confirmation
619  *        on lookup
620  * @return GNUNET_OK on success
621  */
622 int
623 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
624                   struct GNUNET_DHT_Handle *dh,
625                   struct GNUNET_CRYPTO_ShortHashCode lz,
626                   unsigned long long max_bg_queries,
627                   int ignore_pending)
628 {
629   namestore_handle = nh;
630   dht_handle = dh;
631   local_zone = lz;
632   dht_lookup_heap =
633     GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
634   max_allowed_background_queries = max_bg_queries;
635   ignore_pending_records = ignore_pending;
636
637   if ((namestore_handle != NULL) && (dht_handle != NULL))
638   {
639     return GNUNET_OK;
640   }
641   return GNUNET_SYSERR;
642 }
643
644 /**
645  * Cleanup background lookups
646  *
647  * @param cls closure to iterator
648  * @param node heap nodes
649  * @param element the resolver handle
650  * @param cost heap cost
651  * @return always GNUNET_YES
652  */
653 static int
654 cleanup_pending_background_queries(void* cls,
655                                    struct GNUNET_CONTAINER_HeapNode *node,
656                                    void *element,
657                                    GNUNET_CONTAINER_HeapCostType cost)
658 {
659   struct ResolverHandle *rh = (struct ResolverHandle *)element;
660   ResolverCleanupContinuation cont = cls;
661   
662   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
663              "GNS_CLEANUP-%llu: Terminating background lookup for %s\n",
664              rh->id, rh->name);
665   GNUNET_DHT_get_stop(rh->get_handle);
666   rh->get_handle = NULL;
667   rh->proc(rh->proc_cls, rh, 0, NULL);
668
669   GNUNET_CONTAINER_heap_remove_node(node);
670
671   if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0)
672     cont();
673
674
675   return GNUNET_YES;
676 }
677
678
679 /**
680  * Shutdown resolver
681  */
682 void
683 gns_resolver_cleanup(ResolverCleanupContinuation cont)
684 {
685   unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap);
686   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
687              "GNS_CLEANUP: %d pending background queries to terminate\n", s);
688
689   if (0 != s)
690     GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
691                                    &cleanup_pending_background_queries,
692                                    cont);
693   else
694     cont();
695 }
696
697
698 /**
699  * Helper function to free resolver handle
700  *
701  * @param rh the handle to free
702  */
703 static void
704 free_resolver_handle(struct ResolverHandle* rh)
705 {
706   struct AuthorityChain *ac;
707   struct AuthorityChain *ac_next;
708
709   if (NULL == rh)
710     return;
711
712   ac = rh->authority_chain_head;
713
714   while (NULL != ac)
715   {
716     ac_next = ac->next;
717     GNUNET_free(ac);
718     ac = ac_next;
719   }
720   GNUNET_free(rh);
721 }
722
723
724 /**
725  * Callback when record data is put into namestore
726  *
727  * @param cls the closure
728  * @param success GNUNET_OK on success
729  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
730  */
731 void
732 on_namestore_record_put_result(void *cls,
733                                int32_t success,
734                                const char *emsg)
735 {
736   if (GNUNET_NO == success)
737   {
738     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
739                "GNS_NS: records already in namestore\n");
740     return;
741   }
742   else if (GNUNET_YES == success)
743   {
744     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
745                "GNS_NS: records successfully put in namestore\n");
746     return;
747   }
748
749   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
750              "GNS_NS: Error putting records into namestore: %s\n", emsg);
751 }
752
753 static void
754 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
755 {
756   struct ResolverHandle *rh = cls;
757
758   if (rh->timeout_cont)
759     rh->timeout_cont(rh->timeout_cont_cls, tc);
760 }
761
762 /**
763  * Processor for background lookups in the DHT
764  *
765  * @param cls closure (NULL)
766  * @param rd_count number of records found (not 0)
767  * @param rd record data
768  */
769 static void
770 background_lookup_result_processor(void *cls,
771                                    uint32_t rd_count,
772                                    const struct GNUNET_NAMESTORE_RecordData *rd)
773 {
774   //We could do sth verbose/more useful here but it doesn't make any difference
775   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
776              "GNS_BG: background dht lookup for finished. (%d results)\n",
777              rd_count);
778 }
779
780 /**
781  * Handle timeout for DHT requests
782  *
783  * @param cls the request handle as closure
784  * @param tc the task context
785  */
786 static void
787 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
788 {
789   struct ResolverHandle *rh = cls;
790   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
791   char new_name[MAX_DNS_NAME_LENGTH];
792
793   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
794              "GNS_PHASE_REC-%d: dht lookup for query %s (%ds)timed out.\n",
795              rh->id, rh->name, rh->timeout.rel_value);
796   /**
797    * Start resolution in bg
798    */
799   //strcpy(new_name, rh->name);
800   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
801   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
802                   rh->name, GNUNET_GNS_TLD);
803
804   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
805              "GNS_PHASE_REC-%d: Starting background lookup for %s type %d\n",
806              rh->id, new_name, rlh->record_type);
807
808   gns_resolver_lookup_record(rh->authority,
809                              rh->private_local_zone,
810                              rlh->record_type,
811                              new_name,
812                              rh->priv_key,
813                              GNUNET_TIME_UNIT_FOREVER_REL,
814                              GNUNET_NO,
815                              &background_lookup_result_processor,
816                              NULL);
817   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
818   
819   GNUNET_DHT_get_stop (rh->get_handle);
820   rh->get_handle = NULL;
821   rh->proc(rh->proc_cls, rh, 0, NULL);
822 }
823
824
825 /**
826  * Function called when we get a result from the dht
827  * for our record query
828  *
829  * @param cls the request handle
830  * @param exp lifetime
831  * @param key the key the record was stored under
832  * @param get_path get path
833  * @param get_path_length get path length
834  * @param put_path put path
835  * @param put_path_length put path length
836  * @param type the block type
837  * @param size the size of the record
838  * @param data the record data
839  */
840 static void
841 process_record_result_dht(void* cls,
842                  struct GNUNET_TIME_Absolute exp,
843                  const struct GNUNET_HashCode * key,
844                  const struct GNUNET_PeerIdentity *get_path,
845                  unsigned int get_path_length,
846                  const struct GNUNET_PeerIdentity *put_path,
847                  unsigned int put_path_length,
848                  enum GNUNET_BLOCK_Type type,
849                  size_t size, const void *data)
850 {
851   struct ResolverHandle *rh;
852   struct RecordLookupHandle *rlh;
853   struct GNSNameRecordBlock *nrb;
854   uint32_t num_records;
855   char* name = NULL;
856   char* rd_data = (char*)data;
857   int i;
858   int rd_size;
859
860   rh = (struct ResolverHandle *)cls;
861   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
862              "GNS_PHASE_REC-%d: got dht result (size=%d)\n", rh->id, size);
863   
864   if (data == NULL)
865     return;
866
867   //FIXME maybe check expiration here, check block type
868   
869   
870   rlh = (struct RecordLookupHandle *) rh->proc_cls;
871   nrb = (struct GNSNameRecordBlock*)data;
872   
873   /* stop lookup and timeout task */
874   GNUNET_DHT_get_stop (rh->get_handle);
875   rh->get_handle = NULL;
876   
877   if (rh->dht_heap_node != NULL)
878   {
879     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
880     rh->dht_heap_node = NULL;
881   }
882   
883   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
884   {
885     GNUNET_SCHEDULER_cancel(rh->timeout_task);
886     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
887   }
888
889   rh->get_handle = NULL;
890   name = (char*)&nrb[1];
891   num_records = ntohl(nrb->rd_count);
892   {
893     struct GNUNET_NAMESTORE_RecordData rd[num_records];
894
895     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
896     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
897   
898     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
899                                                                rd_data,
900                                                                num_records,
901                                                                rd))
902     {
903       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
904                  "GNS_PHASE_REC-%d: Error deserializing data!\n", rh->id);
905       return;
906     }
907
908     for (i=0; i<num_records; i++)
909     {
910       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
911                "GNS_PHASE_REC-%d: Got name: %s (wanted %s)\n",
912                rh->id, name, rh->name);
913       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
914                "GNS_PHASE_REC-%d: Got type: %d\n",
915                rh->id, rd[i].record_type);
916       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
917                "GNS_PHASE_REC-%d: Got data length: %d\n",
918                rh->id, rd[i].data_size);
919       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
920                "GNS_PHASE_REC-%d: Got flag %d\n",
921                rh->id, rd[i].flags);
922     
923      if ((strcmp(name, rh->name) == 0) &&
924          (rd[i].record_type == rlh->record_type))
925       {
926         rh->answered++;
927       }
928
929     }
930
931     /**
932      * FIXME check pubkey against existing key in namestore?
933      * https://gnunet.org/bugs/view.php?id=2179
934      */
935
936     /* Save to namestore */
937     GNUNET_NAMESTORE_record_put (namestore_handle,
938                                  &nrb->public_key,
939                                  name,
940                                  exp,
941                                  num_records,
942                                  rd,
943                                  &nrb->signature,
944                                  &on_namestore_record_put_result, //cont
945                                  NULL); //cls
946
947   
948     if (rh->answered)
949       rh->proc(rh->proc_cls, rh, num_records, rd);
950     else
951       rh->proc(rh->proc_cls, rh, 0, NULL);
952   }
953
954 }
955
956
957 /**
958  * Start DHT lookup for a (name -> query->record_type) record in
959  * rh->authority's zone
960  *
961  * @param rh the pending gns query context
962  */
963 static void
964 resolve_record_dht(struct ResolverHandle *rh)
965 {
966   uint32_t xquery;
967   struct GNUNET_CRYPTO_ShortHashCode name_hash;
968   struct GNUNET_HashCode lookup_key;
969   struct GNUNET_HashCode name_hash_double;
970   struct GNUNET_HashCode zone_hash_double;
971   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
972   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
973   struct ResolverHandle *rh_heap_root;
974   
975   GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
976   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
977   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
978   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
979   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
980   
981   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
982              "GNS_PHASE_REC-%d: starting dht lookup for %s with key: %s\n",
983              rh->id, rh->name, (char*)&lookup_key_string);
984
985   //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
986   rh->dht_heap_node = NULL;
987
988   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
989   {
990     /**
991      * Update timeout if necessary
992      */
993     if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
994     {
995
996     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
997                "GNS_PHASE_REC-%d: Adjusting timeout\n", rh->id);
998     /*
999      * Set timeout for authority lookup phase to 1/2
1000      */
1001       rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1002                                 GNUNET_TIME_relative_divide(rh->timeout, 2),
1003                                                 &handle_lookup_timeout,
1004                                                 rh);
1005     }
1006     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1007     //                                                   &dht_lookup_timeout,
1008     //                                                   rh);
1009     rh->timeout_cont = &dht_lookup_timeout;
1010     rh->timeout_cont_cls = rh;
1011   }
1012   else 
1013   {
1014     if (max_allowed_background_queries <=
1015         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1016     {
1017       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1018       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1019       rh_heap_root->get_handle = NULL;
1020       rh_heap_root->dht_heap_node = NULL;
1021       
1022       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1023            "GNS_PHASE_REC-%d: Replacing oldest background query for %s\n",
1024                  rh->id, rh_heap_root->name);
1025       rh_heap_root->proc(rh_heap_root->proc_cls,
1026                          rh_heap_root,
1027                          0,
1028                          NULL);
1029     }
1030     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1031                                          rh,
1032                                          GNUNET_TIME_absolute_get().abs_value);
1033   }
1034   
1035   xquery = htonl(rlh->record_type);
1036   
1037   GNUNET_assert(rh->get_handle == NULL);
1038   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
1039                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1040                        &lookup_key,
1041                        DHT_GNS_REPLICATION_LEVEL,
1042                        GNUNET_DHT_RO_NONE,
1043                        &xquery, 
1044                        sizeof(xquery),
1045                        &process_record_result_dht,
1046                        rh);
1047
1048 }
1049
1050
1051 /**
1052  * Namestore calls this function if we have record for this name.
1053  * (or with rd_count=0 to indicate no matches)
1054  *
1055  * @param cls the pending query
1056  * @param key the key of the zone we did the lookup
1057  * @param expiration expiration date of the namestore entry
1058  * @param name the name for which we need an authority
1059  * @param rd_count the number of records with 'name'
1060  * @param rd the record data
1061  * @param signature the signature of the authority for the record data
1062  */
1063 static void
1064 process_record_result_ns(void* cls,
1065                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1066                   struct GNUNET_TIME_Absolute expiration,
1067                   const char *name, unsigned int rd_count,
1068                   const struct GNUNET_NAMESTORE_RecordData *rd,
1069                   const struct GNUNET_CRYPTO_RsaSignature *signature)
1070 {
1071   struct ResolverHandle *rh;
1072   struct RecordLookupHandle *rlh;
1073   struct GNUNET_TIME_Relative remaining_time;
1074   struct GNUNET_CRYPTO_ShortHashCode zone;
1075
1076   rh = (struct ResolverHandle *) cls;
1077   rlh = (struct RecordLookupHandle *)rh->proc_cls;
1078   GNUNET_CRYPTO_short_hash(key,
1079                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1080                      &zone);
1081   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1082   
1083   
1084
1085   rh->status = 0;
1086   
1087   if (name != NULL)
1088   {
1089     rh->status |= RSL_RECORD_EXISTS;
1090   }
1091   
1092   if (remaining_time.rel_value == 0)
1093   {
1094     rh->status |= RSL_RECORD_EXPIRED;
1095   }
1096   
1097   if (rd_count == 0)
1098   {
1099     /**
1100      * Lookup terminated and no results
1101      */
1102     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1103       "GNS_PHASE_REC-%d: Namestore lookup for %s terminated without results\n",
1104          rh->id, name);
1105
1106     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1107                "GNS_PHASE_REC-%d: Record %s unknown in namestore\n",
1108                rh->id, rh->name);
1109     /**
1110      * Our zone and no result? Cannot resolve TT
1111      */
1112     rh->proc(rh->proc_cls, rh, 0, NULL);
1113     return;
1114
1115   }
1116   else
1117   {
1118     
1119     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1120            "GNS_PHASE_REC-%d: Processing additional result %s from namestore\n",
1121               rh->id, name);
1122     int i;
1123     for (i=0; i<rd_count;i++)
1124     {
1125
1126       if (rd[i].record_type != rlh->record_type)
1127         continue;
1128
1129       if (ignore_pending_records &&
1130           (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
1131       {
1132         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1133         "GNS_PHASE_REC-%d: Record %s is awaiting user confirmation. Skipping\n",
1134         rh->id, name);
1135         continue;
1136       }
1137       
1138       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1139           == 0)
1140       {
1141         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1142                    "GNS_PHASE_REC-%d: This record is expired. Skipping\n",
1143                    rh->id);
1144         continue;
1145       }
1146       
1147       rh->answered++;
1148       
1149     }
1150     
1151     /**
1152      * no answers found
1153      */
1154     if (rh->answered == 0)
1155     {
1156       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
1157                  "GNS_PHASE_REC-%d: No answers found. This is odd!\n", rh->id);
1158       rh->proc(rh->proc_cls, rh, 0, NULL);
1159       return;
1160     }
1161     
1162     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1163                "GNS_PHASE_REC-%d: Found %d answer(s) to query in %d records!\n",
1164                rh->id, rh->answered, rd_count);
1165
1166     rh->proc(rh->proc_cls, rh, rd_count, rd);
1167   }
1168 }
1169
1170
1171 /**
1172  * The final phase of resolution.
1173  * rh->name is a name that is canonical and we do not have a delegation.
1174  * Query namestore for this record
1175  *
1176  * @param rh the pending lookup
1177  */
1178 static void
1179 resolve_record_ns(struct ResolverHandle *rh)
1180 {
1181   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
1182   
1183   /* We cancel here as to not include the ns lookup in the timeout */
1184   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1185   {
1186     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1187     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1188   }
1189   /* Start shortening */
1190   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1191   {
1192     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1193              "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1194              rh->id);
1195              start_shorten (rh->authority_chain_tail,
1196              rh->priv_key);
1197   }
1198   
1199   /**
1200    * Try to resolve this record in our namestore.
1201    * The name to resolve is now in rh->authority_name
1202    * since we tried to resolve it to an authority
1203    * and failed.
1204    **/
1205   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1206                                  &rh->authority,
1207                                  rh->name,
1208                                  rlh->record_type,
1209                                  &process_record_result_ns,
1210                                  rh);
1211 }
1212
1213
1214
1215 /**
1216  * Handle timeout for DHT requests
1217  *
1218  * @param cls the request handle as closure
1219  * @param tc the task context
1220  */
1221 static void
1222 dht_authority_lookup_timeout(void *cls,
1223                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1224 {
1225   struct ResolverHandle *rh = cls;
1226   struct RecordLookupHandle *rlh = rh->proc_cls;
1227   char new_name[MAX_DNS_NAME_LENGTH];
1228
1229   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1230          "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%ds)timed out.\n",
1231          rh->id, rh->authority_name, rh->timeout.rel_value);
1232
1233   rh->status |= RSL_TIMED_OUT;
1234
1235   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1236   
1237   GNUNET_DHT_get_stop (rh->get_handle);
1238   rh->get_handle = NULL;
1239   
1240   if (strcmp(rh->name, "") == 0)
1241   {
1242     /*
1243      * promote authority back to name and try to resolve record
1244      */
1245     strcpy(rh->name, rh->authority_name);
1246     rh->proc(rh->proc_cls, rh, 0, NULL);
1247     return;
1248   }
1249   
1250   /**
1251    * Start resolution in bg
1252    */
1253   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1254                   "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD);
1255   //strcpy(new_name, rh->name);
1256   //strcpy(new_name+strlen(new_name), ".");
1257   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1258   
1259   strcpy(rh->name, new_name);
1260
1261   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1262         "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
1263         rh->id, rh->name, rlh->record_type);
1264
1265   gns_resolver_lookup_record(rh->authority,
1266                              rh->private_local_zone,
1267                              rlh->record_type,
1268                              new_name,
1269                              rh->priv_key,
1270                              GNUNET_TIME_UNIT_FOREVER_REL,
1271                              GNUNET_NO,
1272                              &background_lookup_result_processor,
1273                              NULL);
1274
1275   rh->proc(rh->proc_cls, rh, 0, NULL);
1276 }
1277
1278 /* Prototype */
1279 static void resolve_delegation_dht(struct ResolverHandle *rh);
1280
1281 /* Prototype */
1282 static void resolve_delegation_ns(struct ResolverHandle *rh);
1283
1284
1285 /**
1286  * Namestore resolution for delegation finished. Processing result.
1287  *
1288  * @param cls the closure
1289  * @param rh resolver handle
1290  * @param rd_count number of results (always 0)
1291  * @param rd record data (always NULL)
1292  */
1293 static void
1294 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1295                           unsigned int rd_count,
1296                           const struct GNUNET_NAMESTORE_RecordData *rd);
1297
1298
1299 /**
1300  * Function called when we get a result from the dht
1301  * for our query. Recursively tries to resolve authorities
1302  * for name in DHT.
1303  *
1304  * @param cls the request handle
1305  * @param exp lifetime
1306  * @param key the key the record was stored under
1307  * @param get_path get path
1308  * @param get_path_length get path length
1309  * @param put_path put path
1310  * @param put_path_length put path length
1311  * @param type the block type
1312  * @param size the size of the record
1313  * @param data the record data
1314  */
1315 static void
1316 process_delegation_result_dht(void* cls,
1317                  struct GNUNET_TIME_Absolute exp,
1318                  const struct GNUNET_HashCode * key,
1319                  const struct GNUNET_PeerIdentity *get_path,
1320                  unsigned int get_path_length,
1321                  const struct GNUNET_PeerIdentity *put_path,
1322                  unsigned int put_path_length,
1323                  enum GNUNET_BLOCK_Type type,
1324                  size_t size, const void *data)
1325 {
1326   struct ResolverHandle *rh;
1327   struct GNSNameRecordBlock *nrb;
1328   uint32_t num_records;
1329   char* name = NULL;
1330   char* rd_data = (char*) data;
1331   int i;
1332   int rd_size;
1333   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1334   struct GNUNET_HashCode zone_hash_double, name_hash_double;
1335
1336   rh = (struct ResolverHandle *)cls;
1337   
1338   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1339              "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id);
1340
1341   if (data == NULL)
1342     return;
1343   
1344   nrb = (struct GNSNameRecordBlock*)data;
1345   
1346   /* stop dht lookup and timeout task */
1347   GNUNET_DHT_get_stop (rh->get_handle);
1348
1349   rh->get_handle = NULL;
1350
1351   if (rh->dht_heap_node != NULL)
1352   {
1353     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1354     rh->dht_heap_node = NULL;
1355   }
1356
1357   num_records = ntohl(nrb->rd_count);
1358   name = (char*)&nrb[1];
1359   {
1360     struct GNUNET_NAMESTORE_RecordData rd[num_records];
1361     
1362     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1363     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1364   
1365     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1366                                                                rd_data,
1367                                                                num_records,
1368                                                                rd))
1369     {
1370       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1371                  "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
1372                  rh->id);
1373       return;
1374     }
1375
1376     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1377                "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1378                rh->id, name, rh->authority_name);
1379     for (i=0; i<num_records; i++)
1380     {
1381     
1382       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1383                 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1384                 rh->id, name, rh->authority_name);
1385       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1386                  "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
1387                  rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1388       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1389                  "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
1390                  rh->id, rd[i].data_size);
1391       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1392                  "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
1393                  rh->id, rd[i].flags);
1394
1395       if ((strcmp(name, rh->authority_name) == 0) &&
1396           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1397       {
1398         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1399                    "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
1400                    rh->id);
1401         rh->answered = 1;
1402         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1403         struct AuthorityChain *auth =
1404           GNUNET_malloc(sizeof(struct AuthorityChain));
1405         auth->zone = rh->authority;
1406         memset(auth->name, 0, strlen(rh->authority_name)+1);
1407         strcpy(auth->name, rh->authority_name);
1408         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1409                                      rh->authority_chain_tail,
1410                                      auth);
1411
1412         /** try to import pkey if private key available */
1413         //if (rh->priv_key && is_canonical (rh->name))
1414         //  process_discovered_authority(name, auth->zone,
1415         //                               rh->authority_chain_tail->zone,
1416         //                               rh->priv_key);
1417       }
1418
1419     }
1420
1421
1422     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1423     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1424     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1425     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1426
1427     /* Save to namestore */
1428     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1429                                           &zone))
1430     {
1431       GNUNET_NAMESTORE_record_put (namestore_handle,
1432                                  &nrb->public_key,
1433                                  name,
1434                                  exp,
1435                                  num_records,
1436                                  rd,
1437                                  &nrb->signature,
1438                                  &on_namestore_record_put_result, //cont
1439                                  NULL); //cls
1440     }
1441   }
1442   
1443   if (rh->answered)
1444   {
1445     rh->answered = 0;
1446     /**
1447      * delegate
1448      * FIXME in this case. should we ask namestore again?
1449      */
1450     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1451       "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
1452       rh->id, rh->authority_name, rh->name);
1453     
1454     if (strcmp(rh->name, "") == 0)
1455     {
1456       /* Start shortening */
1457       if ((rh->priv_key != NULL) && is_canonical (rh->name))
1458       {
1459         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1460              "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
1461              rh->id);
1462         start_shorten (rh->authority_chain_tail,
1463                        rh->priv_key);
1464       }
1465       
1466       rh->proc(rh->proc_cls, rh, 0, NULL);
1467     }
1468     else
1469     {
1470       rh->proc = &handle_delegation_ns;
1471       resolve_delegation_ns(rh);
1472     }
1473     return;
1474   }
1475   
1476   /**
1477    * No pkey but name exists
1478    * promote back
1479    */
1480   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1481              "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
1482              rh->id, rh->authority_name, rh->name);
1483   if (strcmp(rh->name, "") == 0)
1484     strcpy(rh->name, rh->authority_name);
1485   else
1486     GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1487                   rh->name, rh->authority_name); //FIXME ret
1488   
1489   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1490              "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
1491   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1492            "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
1493            rh->id);
1494   rh->proc(rh->proc_cls, rh, 0, NULL);
1495 }
1496
1497 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1498                         +(MAX_DNS_NAME_LENGTH*2)
1499 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1500
1501
1502 static void
1503 expand_plus(char** dest, char* src, char* repl)
1504 {
1505   char* pos;
1506   unsigned int s_len = strlen(src)+1;
1507
1508   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1509              "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1510
1511   if (s_len < 3)
1512   {
1513     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1514                "GNS_POSTPROCESS: %s to short\n", src);
1515
1516     /* no postprocessing */
1517     memcpy(*dest, src, s_len+1);
1518     return;
1519   }
1520   
1521   if (0 == strcmp(src+s_len-3, ".+"))
1522   {
1523     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1524                "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1525     memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1526     strcpy(*dest, src);
1527     pos = *dest+s_len-2;
1528     strcpy(pos, repl);
1529     pos += strlen(repl);
1530     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1531                "GNS_POSTPROCESS: Expanded to %s\n", *dest);
1532   }
1533   else
1534   {
1535     memcpy(*dest, src, s_len+1);
1536   }
1537 }
1538
1539 /**
1540  * finish lookup
1541  */
1542 static void
1543 finish_lookup(struct ResolverHandle *rh,
1544               struct RecordLookupHandle* rlh,
1545               unsigned int rd_count,
1546               const struct GNUNET_NAMESTORE_RecordData *rd)
1547 {
1548   int i;
1549   char new_rr_data[MAX_DNS_NAME_LENGTH];
1550   char new_mx_data[MAX_MX_LENGTH];
1551   char new_soa_data[MAX_SOA_LENGTH];
1552   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1553   char* repl_string;
1554   char* pos;
1555   unsigned int offset;
1556
1557   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1558   {
1559     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1560     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1561   }
1562
1563   if (rd_count > 0)
1564     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1565
1566   for (i = 0; i < rd_count; i++)
1567   {
1568     
1569     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1570         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1571         rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1572         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1573     {
1574       p_rd[i].data = rd[i].data;
1575       continue;
1576     }
1577
1578     /**
1579      * for all those records we 'should'
1580      * also try to resolve the A/AAAA records (RFC1035)
1581      * This is a feature and not important
1582      */
1583     
1584     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1585                "GNS_POSTPROCESS: Postprocessing\n");
1586
1587     if (strcmp(rh->name, "+") == 0)
1588       repl_string = rlh->name;
1589     else
1590       repl_string = rlh->name+strlen(rh->name)+1;
1591
1592     offset = 0;
1593     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1594     {
1595       memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1596       offset = sizeof(uint16_t);
1597       pos = new_mx_data+offset;
1598       expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1599                   repl_string);
1600       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1601       p_rd[i].data = new_mx_data;
1602       p_rd[i].data_size = offset;
1603     }
1604     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1605     {
1606       /* expand mname and rname */
1607       pos = new_soa_data;
1608       expand_plus(&pos, (char*)rd[i].data, repl_string);
1609       offset = strlen(new_soa_data)+1;
1610       pos = new_soa_data+offset;
1611       expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1612       offset += strlen(new_soa_data+offset)+1;
1613       /* cpy the 4 numbers serial refresh retry and expire */
1614       memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
1615       offset += sizeof(uint32_t)*5;
1616       p_rd[i].data_size = offset;
1617       p_rd[i].data = new_soa_data;
1618     }
1619     else
1620     {
1621       pos = new_rr_data;
1622       expand_plus(&pos, (char*)rd[i].data, repl_string);
1623       p_rd[i].data_size = strlen(new_rr_data)+1;
1624       p_rd[i].data = new_rr_data;
1625     }
1626     
1627   }
1628
1629   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1630   GNUNET_free(rlh);
1631   
1632 }
1633
1634 /**
1635  * Process DHT lookup result for record.
1636  *
1637  * @param cls the closure
1638  * @param rh resolver handle
1639  * @param rd_count number of results
1640  * @param rd record data
1641  */
1642 static void
1643 handle_record_dht(void* cls, struct ResolverHandle *rh,
1644                        unsigned int rd_count,
1645                        const struct GNUNET_NAMESTORE_RecordData *rd)
1646 {
1647   struct RecordLookupHandle* rlh;
1648
1649   rlh = (struct RecordLookupHandle*)cls;
1650   if (rd_count == 0)
1651   {
1652     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1653                "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n",
1654                rh->id, rh->name);
1655     /* give up, cannot resolve */
1656     finish_lookup(rh, rlh, 0, NULL);
1657     free_resolver_handle(rh);
1658     return;
1659   }
1660
1661   /* results found yay */
1662   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1663              "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id);
1664
1665   finish_lookup(rh, rlh, rd_count, rd);
1666   free_resolver_handle(rh);
1667
1668 }
1669
1670
1671 /**
1672  * Process namestore lookup result for record.
1673  *
1674  * @param cls the closure
1675  * @param rh resolver handle
1676  * @param rd_count number of results
1677  * @param rd record data
1678  */
1679 static void
1680 handle_record_ns(void* cls, struct ResolverHandle *rh,
1681                        unsigned int rd_count,
1682                        const struct GNUNET_NAMESTORE_RecordData *rd)
1683 {
1684   struct RecordLookupHandle* rlh;
1685   rlh = (struct RecordLookupHandle*) cls;
1686   if (rd_count == 0)
1687   {
1688     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1689                "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n",
1690                rh->id,
1691                rh->status);
1692     
1693     /**
1694      * There are 5 conditions that have to met for us to consult the DHT:
1695      * 1. The entry in the DHT is RSL_RECORD_EXPIRED AND
1696      * 2. No entry in the NS existed AND
1697      * 3. The zone queried is not the local resolver's zone AND
1698      * 4. The name that was looked up is '+'
1699      *    because if it was any other canonical name we either already queried
1700      *    the DHT for the authority in the authority lookup phase (and thus
1701      *    would already have an entry in the NS for the record)
1702      * 5. We are not in cache only mode
1703      */
1704     if (rh->status & (RSL_RECORD_EXPIRED | !RSL_RECORD_EXISTS) &&
1705         GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1706                                      &rh->private_local_zone) &&
1707         (strcmp(rh->name, "+") == 0) &&
1708         (rh->only_cached == GNUNET_NO))
1709     {
1710       rh->proc = &handle_record_dht;
1711       resolve_record_dht(rh);
1712       return;
1713     }
1714     /* give up, cannot resolve */
1715     finish_lookup(rh, rlh, 0, NULL);
1716     free_resolver_handle(rh);
1717     return;
1718   }
1719
1720   /* results found yay */
1721   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1722              "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id);
1723
1724   finish_lookup(rh, rlh, rd_count, rd);
1725
1726   free_resolver_handle(rh);
1727
1728 }
1729
1730
1731 /**
1732  * Move one level up in the domain hierarchy and return the
1733  * passed top level domain.
1734  *
1735  * @param name the domain
1736  * @param dest the destination where the tld will be put
1737  */
1738 void
1739 pop_tld(char* name, char* dest)
1740 {
1741   uint32_t len;
1742
1743   if (is_canonical(name))
1744   {
1745     strcpy(dest, name);
1746     strcpy(name, "");
1747     return;
1748   }
1749
1750   for (len = strlen(name); len > 0; len--)
1751   {
1752     if (*(name+len) == '.')
1753       break;
1754   }
1755   
1756   //Was canonical?
1757   if (len == 0)
1758     return;
1759
1760   name[len] = '\0';
1761
1762   strcpy(dest, (name+len+1));
1763 }
1764
1765 /**
1766  * Checks if name is in tld
1767  *
1768  * @param name the name to check
1769  * @param tld the TLD to check for
1770  * @return GNUNET_YES or GNUNET_NO
1771  */
1772 int
1773 is_tld(const char* name, const char* tld)
1774 {
1775   int offset = 0;
1776
1777   if (strlen(name) <= strlen(tld))
1778   {
1779     return GNUNET_NO;
1780   }
1781   
1782   offset = strlen(name)-strlen(tld);
1783   if (strcmp(name+offset, tld) != 0)
1784   {
1785     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1786                "%s is not in .%s TLD\n", name, tld);
1787     return GNUNET_NO;
1788   }
1789   return GNUNET_YES;
1790 }
1791
1792 /**
1793  * DHT resolution for delegation finished. Processing result.
1794  *
1795  * @param cls the closure
1796  * @param rh resolver handle
1797  * @param rd_count number of results (always 0)
1798  * @param rd record data (always NULL)
1799  */
1800 static void
1801 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1802                           unsigned int rd_count,
1803                           const struct GNUNET_NAMESTORE_RecordData *rd)
1804 {
1805   struct RecordLookupHandle* rlh;
1806   rlh = (struct RecordLookupHandle*) cls;
1807   
1808
1809   if (strcmp(rh->name, "") == 0)
1810   {
1811     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1812     {
1813       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1814                  "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
1815                  rh->id);
1816       finish_lookup(rh, rlh, rd_count, rd);
1817       free_resolver_handle(rh);
1818       return;
1819     }
1820     /* We resolved full name for delegation. resolving record */
1821     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1822      "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
1823      rh->id);
1824     strcpy(rh->name, "+\0");
1825     rh->proc = &handle_record_ns;
1826     resolve_record_ns(rh);
1827     return;
1828   }
1829
1830   /**
1831    * we still have some left
1832    **/
1833   if (is_canonical(rh->name))
1834   {
1835     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1836              "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
1837              rh->id,
1838              rh->name);
1839     rh->proc = &handle_record_ns;
1840     resolve_record_ns(rh);
1841     return;
1842   }
1843   /* give up, cannot resolve */
1844   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1845  "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
1846  rh->id, rh->name);
1847   finish_lookup(rh, rlh, 0, NULL);
1848   free_resolver_handle(rh);
1849 }
1850
1851
1852 /**
1853  * Start DHT lookup for a name -> PKEY (compare NS) record in
1854  * rh->authority's zone
1855  *
1856  * @param rh the pending gns query
1857  */
1858 static void
1859 resolve_delegation_dht(struct ResolverHandle *rh)
1860 {
1861   uint32_t xquery;
1862   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1863   struct GNUNET_HashCode name_hash_double;
1864   struct GNUNET_HashCode zone_hash_double;
1865   struct GNUNET_HashCode lookup_key;
1866   struct ResolverHandle *rh_heap_root;
1867   
1868   pop_tld(rh->name, rh->authority_name); 
1869   GNUNET_CRYPTO_short_hash(rh->authority_name,
1870                      strlen(rh->authority_name),
1871                      &name_hash);
1872   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1873   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1874   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1875   
1876   rh->dht_heap_node = NULL;
1877
1878   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1879   {
1880     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1881     //                                          &dht_authority_lookup_timeout,
1882     //                                                   rh);
1883     rh->timeout_cont = &dht_authority_lookup_timeout;
1884     rh->timeout_cont_cls = rh;
1885   }
1886   else 
1887   {
1888     if (max_allowed_background_queries <=
1889         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1890     {
1891       /* terminate oldest lookup */
1892       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1893       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1894       rh_heap_root->dht_heap_node = NULL;
1895       
1896       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1897         "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
1898         rh->id, rh_heap_root->authority_name);
1899       
1900       rh_heap_root->proc(rh_heap_root->proc_cls,
1901                          rh_heap_root,
1902                          0,
1903                          NULL);
1904     }
1905     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1906                                          rh,
1907                                          GNUNET_TIME_absolute_get().abs_value);
1908   }
1909   
1910   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1911   
1912   GNUNET_assert(rh->get_handle == NULL);
1913   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1914                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1915                        &lookup_key,
1916                        DHT_GNS_REPLICATION_LEVEL,
1917                        GNUNET_DHT_RO_NONE,
1918                        &xquery,
1919                        sizeof(xquery),
1920                        &process_delegation_result_dht,
1921                        rh);
1922
1923 }
1924
1925
1926 /**
1927  * Namestore resolution for delegation finished. Processing result.
1928  *
1929  * @param cls the closure
1930  * @param rh resolver handle
1931  * @param rd_count number of results (always 0)
1932  * @param rd record data (always NULL)
1933  */
1934 static void
1935 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1936                           unsigned int rd_count,
1937                           const struct GNUNET_NAMESTORE_RecordData *rd)
1938 {
1939   struct RecordLookupHandle* rlh;
1940   rlh = (struct RecordLookupHandle*) cls;
1941
1942   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1943              "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
1944              rh->id, rh->status);
1945   
1946   if (strcmp(rh->name, "") == 0)
1947   {
1948     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1949     {
1950       GNUNET_assert(rd_count == 1);
1951       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1952                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
1953                  rh->id);
1954       finish_lookup(rh, rlh, rd_count, rd);
1955       free_resolver_handle(rh);
1956       return;
1957     }
1958     /* We resolved full name for delegation. resolving record */
1959     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1960               "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
1961               rh->id);
1962     strcpy(rh->name, "+\0");
1963     rh->proc = &handle_record_ns;
1964     resolve_record_ns(rh);
1965     return;
1966   }
1967
1968   /**
1969    * we still have some left
1970    * check if authority in ns is fresh
1971    * and exists
1972    * or we are authority
1973    **/
1974   if (((rh->status & RSL_RECORD_EXISTS) && (!(rh->status & RSL_RECORD_EXPIRED)))
1975       || !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1976                                        &rh->private_local_zone))
1977   {
1978     if (is_canonical(rh->name))
1979     {
1980       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1981                  "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
1982                  rh->id,
1983                  rh->name);
1984       rh->proc = &handle_record_ns;
1985       resolve_record_ns(rh);
1986     }
1987     else
1988     {
1989       /* give up, cannot resolve */
1990       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1991           "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
1992           rh->id,
1993           rh->name);
1994       finish_lookup(rh, rlh, rd_count, rd);
1995       //rlh->proc(rlh->proc_cls, 0, NULL);
1996     }
1997     return;
1998   }
1999
2000   if (rh->only_cached == GNUNET_YES)
2001   {
2002     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2003                "GNS_PHASE_DELEGATE_NS-%llu: Only cache resolution, no result\n",
2004                rh->id, rh->name);
2005     finish_lookup(rh, rlh, rd_count, rd);
2006     return;
2007   }
2008   
2009   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2010       "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
2011       rh->id, rh->name);
2012   rh->proc = &handle_delegation_dht;
2013   resolve_delegation_dht(rh);
2014 }
2015
2016
2017
2018 /**
2019  * This is a callback function that should give us only PKEY
2020  * records. Used to query the namestore for the authority (PKEY)
2021  * for 'name'. It will recursively try to resolve the
2022  * authority for a given name from the namestore.
2023  *
2024  * @param cls the pending query
2025  * @param key the key of the zone we did the lookup
2026  * @param expiration expiration date of the record data set in the namestore
2027  * @param name the name for which we need an authority
2028  * @param rd_count the number of records with 'name'
2029  * @param rd the record data
2030  * @param signature the signature of the authority for the record data
2031  */
2032 static void
2033 process_delegation_result_ns(void* cls,
2034                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
2035                    struct GNUNET_TIME_Absolute expiration,
2036                    const char *name,
2037                    unsigned int rd_count,
2038                    const struct GNUNET_NAMESTORE_RecordData *rd,
2039                    const struct GNUNET_CRYPTO_RsaSignature *signature)
2040 {
2041   struct ResolverHandle *rh;
2042   struct GNUNET_TIME_Relative remaining_time;
2043   struct GNUNET_CRYPTO_ShortHashCode zone;
2044   char new_name[MAX_DNS_NAME_LENGTH];
2045  
2046   rh = (struct ResolverHandle *)cls; 
2047   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2048              "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n",
2049              rh->id, rd_count);
2050
2051   GNUNET_CRYPTO_short_hash(key,
2052                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2053                      &zone);
2054   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2055   
2056   rh->status = 0;
2057   
2058   if (name != NULL)
2059   {
2060     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2061                "GNS_PHASE_DELEGATE_NS-%llu: Records with name %s exist.\n",
2062                rh->id, name);
2063     rh->status |= RSL_RECORD_EXISTS;
2064   }
2065   
2066   if (remaining_time.rel_value == 0)
2067   {
2068     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2069                "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
2070                rh->id, name);
2071     rh->status |= RSL_RECORD_EXPIRED;
2072   }
2073   
2074   /**
2075    * No authority found in namestore.
2076    */
2077   if (rd_count == 0)
2078   {
2079     /**
2080      * We did not find an authority in the namestore
2081      */
2082     
2083     /**
2084      * No PKEY in zone.
2085      * Promote this authority back to a name maybe it is
2086      * our record.
2087      */
2088     if (strcmp(rh->name, "") == 0)
2089     {
2090       /* simply promote back */
2091       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2092                  "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2093                  rh->id, rh->authority_name);
2094       strcpy(rh->name, rh->authority_name);
2095     }
2096     else
2097     {
2098       /* add back to existing name */
2099       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2100                  "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
2101                  rh->id, rh->authority_name, rh->name);
2102       //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
2103       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2104                       rh->name, rh->authority_name);
2105       //strcpy(new_name, rh->name);
2106       //strcpy(new_name+strlen(new_name), ".");
2107       //strcpy(new_name+strlen(new_name), rh->authority_name);
2108       strcpy(rh->name, new_name);
2109       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2110                  "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n", rh->id, rh->name);
2111     }
2112     rh->proc(rh->proc_cls, rh, 0, NULL);
2113     return;
2114   }
2115
2116   /**
2117    * We found an authority that may be able to help us
2118    * move on with query
2119    * Note only 1 pkey should have been returned.. anything else would be strange
2120    */
2121   int i;
2122   for (i=0; i<rd_count;i++)
2123   {
2124   
2125     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
2126       continue;
2127
2128     if (ignore_pending_records &&
2129         (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
2130     {
2131       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2132       "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
2133         name,
2134         rh->id);
2135       continue;
2136     }
2137     
2138     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
2139          == 0)
2140     {
2141       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2142                  "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
2143                  rh->id);
2144       if (remaining_time.rel_value == 0)
2145       {
2146         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2147                    "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
2148                    rh->id);
2149         rh->authority_chain_head->fresh = 0;
2150         rh->proc(rh->proc_cls, rh, 0, NULL);
2151         return;
2152       }
2153
2154       continue;
2155     }
2156
2157     /**
2158      * Resolve rest of query with new authority
2159      */
2160     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
2161     memcpy(&rh->authority, rd[i].data,
2162            sizeof(struct GNUNET_CRYPTO_ShortHashCode));
2163     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
2164     auth->zone = rh->authority;
2165     memset(auth->name, 0, strlen(rh->authority_name)+1);
2166     strcpy(auth->name, rh->authority_name);
2167     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2168                                  rh->authority_chain_tail,
2169                                  auth);
2170     
2171     /** try to import pkey if private key available
2172      * TODO: Only import last one?
2173      */
2174     //if (rh->priv_key && (name != NULL) && is_canonical (rh->name))
2175     //  process_discovered_authority((char*)name, auth->zone,
2176     //                               rh->authority_chain_tail->zone,
2177     //                               rh->priv_key);
2178     /**
2179      * We are done with PKEY resolution if name is empty
2180      * else resolve again with new authority
2181      */
2182     if (strcmp(rh->name, "") == 0)
2183       rh->proc(rh->proc_cls, rh, rd_count, rd);
2184     else
2185       resolve_delegation_ns(rh);
2186     return;
2187   }
2188     
2189   /**
2190    * no answers found
2191    */
2192   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2193     "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id);
2194   /**
2195    * If we have found some records for the LAST label
2196    * we return the results. Else null.
2197    */
2198   if (strcmp(rh->name, "") == 0)
2199   {
2200     /* Start shortening */
2201     if ((rh->priv_key != NULL) && is_canonical (rh->name))
2202     {
2203       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2204               "GNS_PHASE_DELEGATE_NS-%llu: Trying to shorten authority chain\n",
2205               rh->id);
2206       start_shorten (rh->authority_chain_tail,
2207                     rh->priv_key);
2208     }
2209     /* simply promote back */
2210     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2211                "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2212                rh->id, rh->authority_name);
2213     strcpy(rh->name, rh->authority_name);
2214     rh->proc(rh->proc_cls, rh, rd_count, rd);
2215   }
2216   else
2217   {
2218     rh->proc(rh->proc_cls, rh, 0, NULL);
2219   }
2220 }
2221
2222
2223 /**
2224  * Resolve the delegation chain for the request in our namestore
2225  *
2226  * @param rh the resolver handle
2227  */
2228 static void
2229 resolve_delegation_ns(struct ResolverHandle *rh)
2230 {
2231   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2232              "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n",
2233              rh->id, rh->name);
2234   pop_tld(rh->name, rh->authority_name);
2235   GNUNET_NAMESTORE_lookup_record(namestore_handle,
2236                                  &rh->authority,
2237                                  rh->authority_name,
2238                                  GNUNET_GNS_RECORD_ANY,
2239                                  &process_delegation_result_ns,
2240                                  rh);
2241
2242 }
2243
2244
2245 /**
2246  * Lookup of a record in a specific zone
2247  * calls lookup result processor on result
2248  *
2249  * @param zone the root zone
2250  * @param pzone the private local zone
2251  * @param record_type the record type to look up
2252  * @param name the name to look up
2253  * @param key a private key for use with PSEU import (can be NULL)
2254  * @param timeout timeout for resolution
2255  * @param only_cached GNUNET_NO to only check locally not DHT for performance
2256  * @param proc the processor to call on result
2257  * @param cls the closure to pass to proc
2258  */
2259 void
2260 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
2261                            struct GNUNET_CRYPTO_ShortHashCode pzone,
2262                            uint32_t record_type,
2263                            const char* name,
2264                            struct GNUNET_CRYPTO_RsaPrivateKey *key,
2265                            struct GNUNET_TIME_Relative timeout,
2266                            int only_cached,
2267                            RecordLookupProcessor proc,
2268                            void* cls)
2269 {
2270   struct ResolverHandle *rh;
2271   struct RecordLookupHandle* rlh;
2272   char string_hash[MAX_DNS_LABEL_LENGTH];
2273   char nzkey[MAX_DNS_LABEL_LENGTH];
2274   char* nzkey_ptr = nzkey;
2275
2276   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2277               "Starting resolution for %s (type=%d)!\n",
2278               name, record_type);
2279
2280   
2281   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
2282   {
2283     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2284                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
2285     proc(cls, 0, NULL);
2286     return;
2287   }
2288   
2289   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2290   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2291
2292   rh->authority = zone;
2293   rh->id = rid++;
2294   rh->proc_cls = rlh;
2295   rh->priv_key = key;
2296   rh->timeout = timeout;
2297   rh->get_handle = NULL;
2298   rh->private_local_zone = pzone;
2299   rh->only_cached = only_cached;
2300   
2301   if (NULL == key)
2302   {
2303     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2304                 "No shorten key for resolution\n");
2305   }
2306
2307   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2308   {
2309     /*
2310      * Set timeout for authority lookup phase to 1/2
2311      */
2312     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2313                 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
2314     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
2315                                 GNUNET_TIME_relative_divide(timeout, 2),
2316                                                 &handle_lookup_timeout,
2317                                                 rh);
2318     rh->timeout_cont = &dht_authority_lookup_timeout;
2319     rh->timeout_cont_cls = rh;
2320   }
2321   else
2322   {
2323     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2324     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2325   }
2326   
2327   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2328   {
2329     /**
2330      * Only 'gnunet' given
2331      */
2332     strcpy(rh->name, "\0");
2333   }
2334   else
2335   {
2336     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2337                 "Checking for TLD...\n");
2338     if (is_zkey_tld(name) == GNUNET_YES)
2339     {
2340       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2341                   "TLD is zkey\n");
2342       /**
2343        * This is a zkey tld
2344        * build hash and use as initial authority
2345        */
2346       memset(rh->name, 0,
2347              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2348       memcpy(rh->name, name,
2349              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2350       pop_tld(rh->name, string_hash);
2351
2352       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2353                   "ZKEY is %s!\n", string_hash);
2354       
2355       GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2356
2357       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2358                                                       &rh->authority))
2359       {
2360         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2361                     "Cannot convert ZKEY %s to hash!\n", string_hash);
2362         GNUNET_free(rh);
2363         GNUNET_free(rlh);
2364         proc(cls, 0, NULL);
2365         return;
2366       }
2367
2368     }
2369     else
2370     {
2371       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2372                   "TLD is gnunet\n");
2373       /**
2374        * Presumably GNUNET tld
2375        */
2376       memset(rh->name, 0,
2377              strlen(name)-strlen(GNUNET_GNS_TLD));
2378       memcpy(rh->name, name,
2379              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2380     }
2381   }
2382   
2383   /**
2384    * Initialize authority chain
2385    */
2386   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2387   rh->authority_chain_head->prev = NULL;
2388   rh->authority_chain_head->next = NULL;
2389   rh->authority_chain_tail = rh->authority_chain_head;
2390   rh->authority_chain_head->zone = rh->authority;
2391   
2392   /**
2393    * Copy original query into lookup handle
2394    */
2395   rlh->record_type = record_type;
2396   memset(rlh->name, 0, strlen(name) + 1);
2397   strcpy(rlh->name, name);
2398   rlh->proc = proc;
2399   rlh->proc_cls = cls;
2400
2401   rh->proc = &handle_delegation_ns;
2402   resolve_delegation_ns(rh);
2403 }
2404
2405 /******** END Record Resolver ***********/
2406
2407 /**
2408  * Callback calles by namestore for a zone to name
2409  * result
2410  *
2411  * @param cls the closure
2412  * @param zone_key the zone we queried
2413  * @param expire the expiration time of the name
2414  * @param name the name found or NULL
2415  * @param rd_len number of records for the name
2416  * @param rd the record data (PKEY) for the name
2417  * @param signature the signature for the record data
2418  */
2419 static void
2420 process_zone_to_name_shorten_root (void *cls,
2421                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2422                  struct GNUNET_TIME_Absolute expire,
2423                  const char *name,
2424                  unsigned int rd_len,
2425                  const struct GNUNET_NAMESTORE_RecordData *rd,
2426                  const struct GNUNET_CRYPTO_RsaSignature *signature);
2427
2428
2429 /**
2430  * Callback called by namestore for a zone to name
2431  * result
2432  *
2433  * @param cls the closure
2434  * @param zone_key the zone we queried
2435  * @param expire the expiration time of the name
2436  * @param name the name found or NULL
2437  * @param rd_len number of records for the name
2438  * @param rd the record data (PKEY) for the name
2439  * @param signature the signature for the record data
2440  */
2441 static void
2442 process_zone_to_name_shorten_shorten (void *cls,
2443                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2444                  struct GNUNET_TIME_Absolute expire,
2445                  const char *name,
2446                  unsigned int rd_len,
2447                  const struct GNUNET_NAMESTORE_RecordData *rd,
2448                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2449 {
2450   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2451   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2452   struct AuthorityChain *next_authority;
2453
2454   char result[MAX_DNS_NAME_LENGTH];
2455   char tmp_name[MAX_DNS_NAME_LENGTH];
2456   size_t answer_len;
2457   
2458   /* we found a match in our own root zone */
2459   if (rd_len != 0)
2460   {
2461     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2462                "result strlen %d\n", strlen(name));
2463     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2464     memset(result, 0, answer_len);
2465
2466     if (strlen(rh->name) > 0)
2467     {
2468       sprintf (result, "%s.%s.%s.%s.%s",
2469                rh->name, name,
2470                nsh->shorten_zone_name, nsh->private_zone_name,
2471                GNUNET_GNS_TLD);
2472     }
2473     else
2474     {
2475       sprintf (result, "%s.%s.%s.%s", name,
2476                nsh->shorten_zone_name, nsh->private_zone_name,
2477                GNUNET_GNS_TLD);
2478     }
2479     
2480     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2481                "Found shorten result %s\n", result);
2482     if (strlen (nsh->result) > strlen (result))
2483       strcpy (nsh->result, result);
2484   }
2485   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2486                                         nsh->shorten_zone) == 0)
2487   {
2488     /**
2489      * This is our zone append .gnunet unless name is empty
2490      * (it shouldn't be, usually FIXME what happens if we
2491      * shorten to our zone to a "" record??)
2492      */
2493     
2494     sprintf (result, "%s.%s.%s.%s",
2495              rh->name,
2496              nsh->shorten_zone_name, nsh->private_zone_name,
2497              GNUNET_GNS_TLD);
2498     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2499                "Our zone: Found %s as shorten result\n", result);
2500     
2501     if (strlen (nsh->result) > strlen (result))
2502       strcpy (nsh->result, result);
2503     //nsh->proc(nsh->proc_cls, result);
2504     //GNUNET_free(nsh);
2505     //free_resolver_handle(rh);
2506     //return;
2507   }
2508   
2509   
2510   /**
2511    * No PSEU found.
2512    * continue with next authority if exists
2513    */
2514   if ((rh->authority_chain_head->next == NULL))
2515   {
2516     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2517                 "Sending %s as shorten result\n", nsh->result);
2518     nsh->proc(nsh->proc_cls, nsh->result);
2519     GNUNET_free (nsh);
2520     free_resolver_handle (rh);
2521     return;
2522   }
2523   next_authority = rh->authority_chain_head;
2524   
2525   GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
2526                   "%s.%s", rh->name, next_authority->name);
2527   
2528   strcpy(rh->name, tmp_name);
2529   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2530              "No PSEU found for authority %s. Promoting back: %s\n",
2531              next_authority->name, rh->name);
2532   
2533   GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2534                             rh->authority_chain_tail,
2535                             next_authority);
2536
2537   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2538                                  &rh->authority_chain_tail->zone,
2539                                  &rh->authority_chain_head->zone,
2540                                  &process_zone_to_name_shorten_root,
2541                                  rh);
2542 }
2543
2544 /**
2545  * Callback calles by namestore for a zone to name
2546  * result
2547  *
2548  * @param cls the closure
2549  * @param zone_key the zone we queried
2550  * @param expire the expiration time of the name
2551  * @param name the name found or NULL
2552  * @param rd_len number of records for the name
2553  * @param rd the record data (PKEY) for the name
2554  * @param signature the signature for the record data
2555  */
2556 static void
2557 process_zone_to_name_shorten_private (void *cls,
2558                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2559                  struct GNUNET_TIME_Absolute expire,
2560                  const char *name,
2561                  unsigned int rd_len,
2562                  const struct GNUNET_NAMESTORE_RecordData *rd,
2563                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2564 {
2565   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2566   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2567   struct AuthorityChain *next_authority;
2568
2569   char result[MAX_DNS_NAME_LENGTH];
2570   char tmp_name[MAX_DNS_NAME_LENGTH];
2571   size_t answer_len;
2572   
2573   /* we found a match in our own root zone */
2574   if (rd_len != 0)
2575   {
2576     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2577                "result strlen %d\n", strlen(name));
2578     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2579     memset(result, 0, answer_len);
2580
2581     if (strlen(rh->name) > 0)
2582     {
2583       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
2584     }
2585     else
2586     {
2587       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
2588     }
2589     
2590     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2591                "Found shorten result %s\n", result);
2592     if (strlen (nsh->result) > strlen (result))
2593       strcpy (nsh->result, result);
2594   }
2595   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2596                                         nsh->private_zone) == 0)
2597   {
2598     /**
2599      * This is our zone append .gnunet unless name is empty
2600      * (it shouldn't be, usually FIXME what happens if we
2601      * shorten to our zone to a "" record??)
2602      */
2603     
2604     sprintf (result, "%s.%s.%s",
2605              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
2606     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2607                "Our private zone: Found %s as shorten result %s\n", result);
2608     if (strlen (nsh->result) > strlen (result))
2609       strcpy (nsh->result, result);
2610   }
2611   
2612   if (nsh->shorten_zone != NULL)
2613   {
2614     /* backtrack authorities for names in priv zone */
2615     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2616                                    nsh->shorten_zone,
2617                                    &rh->authority_chain_head->zone,
2618                                    &process_zone_to_name_shorten_shorten,
2619                                    rh);
2620   }
2621   else
2622   {
2623     /**
2624      * No PSEU found.
2625      * continue with next authority if exists
2626      */
2627     if ((rh->authority_chain_head->next == NULL))
2628     {
2629       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2630                  "Sending %s as shorten result\n", nsh->result);
2631       nsh->proc(nsh->proc_cls, nsh->result);
2632       GNUNET_free(nsh);
2633       free_resolver_handle(rh);
2634       return;
2635     }
2636     next_authority = rh->authority_chain_head;
2637     
2638     GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
2639                     "%s.%s", rh->name, next_authority->name);
2640     
2641     strcpy(rh->name, tmp_name);
2642     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2643                "No PSEU found for authority %s. Promoting back: %s\n",
2644                next_authority->name, rh->name);
2645     
2646     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2647                               rh->authority_chain_tail,
2648                               next_authority);
2649
2650     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2651                                    &rh->authority_chain_tail->zone,
2652                                    &rh->authority_chain_head->zone,
2653                                    &process_zone_to_name_shorten_root,
2654                                    rh);
2655   }
2656 }
2657
2658 /**
2659  * Callback calles by namestore for a zone to name
2660  * result
2661  *
2662  * @param cls the closure
2663  * @param zone_key the zone we queried
2664  * @param expire the expiration time of the name
2665  * @param name the name found or NULL
2666  * @param rd_len number of records for the name
2667  * @param rd the record data (PKEY) for the name
2668  * @param signature the signature for the record data
2669  */
2670 static void
2671 process_zone_to_name_shorten_root (void *cls,
2672                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2673                  struct GNUNET_TIME_Absolute expire,
2674                  const char *name,
2675                  unsigned int rd_len,
2676                  const struct GNUNET_NAMESTORE_RecordData *rd,
2677                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2678 {
2679   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2680   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2681   struct AuthorityChain *next_authority;
2682
2683   char result[MAX_DNS_NAME_LENGTH];
2684   char tmp_name[MAX_DNS_NAME_LENGTH];
2685   size_t answer_len;
2686   
2687   /* we found a match in our own root zone */
2688   if (rd_len != 0)
2689   {
2690     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2691                "result strlen %d\n", strlen(name));
2692     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2693     memset(result, 0, answer_len);
2694
2695     if (strlen(rh->name) > 0)
2696     {
2697       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
2698     }
2699     else
2700     {
2701       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
2702     }
2703     
2704     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2705                "Found shorten result %s\n", result);
2706     if (strlen (nsh->result) > strlen (result))
2707       strcpy (nsh->result, result);
2708   }
2709   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2710                                         nsh->root_zone) == 0)
2711   {
2712     /**
2713      * This is our zone append .gnunet unless name is empty
2714      * (it shouldn't be, usually FIXME what happens if we
2715      * shorten to our zone to a "" record??)
2716      */
2717     
2718     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
2719     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2720                "Our zone: Found %s as shorten result\n", result);
2721     if (strlen (nsh->result) > strlen (result))
2722       strcpy (nsh->result, result);
2723   }
2724   
2725   if (nsh->private_zone != NULL)
2726   {
2727     /* backtrack authorities for names in priv zone */
2728     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2729                                    nsh->private_zone,
2730                                    &rh->authority_chain_head->zone,
2731                                    &process_zone_to_name_shorten_private,
2732                                    rh);
2733   }
2734   else
2735   {
2736     /**
2737      * No PSEU found.
2738      * continue with next authority if exists
2739      */
2740     if ((rh->authority_chain_head->next == NULL))
2741     {
2742       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2743                  "Sending %s as shorten result\n", nsh->result);
2744       nsh->proc(nsh->proc_cls, nsh->result);
2745       GNUNET_free(nsh);
2746       free_resolver_handle(rh);
2747       return;
2748     }
2749     next_authority = rh->authority_chain_head;
2750     
2751     GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
2752                     "%s.%s", rh->name, next_authority->name);
2753     
2754     strcpy(rh->name, tmp_name);
2755     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2756                "No PSEU found for authority %s. Promoting back: %s\n",
2757                next_authority->name, rh->name);
2758     
2759     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2760                               rh->authority_chain_tail,
2761                               next_authority);
2762
2763     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2764                                    &rh->authority_chain_tail->zone,
2765                                    &rh->authority_chain_head->zone,
2766                                    &process_zone_to_name_shorten_root,
2767                                    rh);
2768   }
2769 }
2770
2771
2772 /**
2773  * Process result from namestore delegation lookup
2774  * for shorten operation
2775  *
2776  * @param cls the client shorten handle
2777  * @param rh the resolver handle
2778  * @param rd_count number of results (0)
2779  * @param rd data (NULL)
2780  */
2781 void
2782 handle_delegation_ns_shorten(void* cls,
2783                       struct ResolverHandle *rh,
2784                       uint32_t rd_count,
2785                       const struct GNUNET_NAMESTORE_RecordData *rd)
2786 {
2787   struct NameShortenHandle *nsh;
2788   char result[MAX_DNS_NAME_LENGTH];
2789
2790   nsh = (struct NameShortenHandle *)cls;
2791   
2792   /**
2793    * At this point rh->name contains the part of the name
2794    * that we do not have a PKEY in our namestore to resolve.
2795    * The authority chain in the resolver handle is now
2796    * useful to backtrack if needed
2797    */
2798   
2799   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2800              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2801   memset(result, 0, sizeof (result));
2802
2803   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2804                                    nsh->root_zone) == 0)
2805   {
2806     /**
2807      * This is our zone append .gnunet unless name is empty
2808      * (it shouldn't be, usually FIXME what happens if we
2809      * shorten to our zone to a "" record??)
2810      */
2811     
2812     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
2813     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2814                "Our zone: Found %s as shorten result\n", result);
2815     
2816     if (strlen (nsh->result) > strlen (result))
2817       strcpy (nsh->result, result);
2818
2819   }
2820   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2821                                         nsh->private_zone) == 0)
2822   {
2823     /**
2824      * This is our zone append .gnunet unless name is empty
2825      * (it shouldn't be, usually FIXME what happens if we
2826      * shorten to our zone to a "" record??)
2827      */
2828     
2829     sprintf (result, "%s.%s.%s",
2830              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
2831     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2832                "Our zone: Found %s as shorten result %s\n", result);
2833     
2834     if (strlen (nsh->result) > strlen (result))
2835       strcpy (nsh->result, result);
2836   }
2837   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2838                                         nsh->shorten_zone) == 0)
2839   {
2840     /**
2841      * This is our zone append .gnunet unless name is empty
2842      * (it shouldn't be, usually FIXME what happens if we
2843      * shorten to our zone to a "" record??)
2844      */
2845     
2846     sprintf (result, "%s.%s.%s",
2847              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
2848     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2849                "Our zone: Found %s as shorten result\n", result);
2850     
2851     if (strlen (nsh->result) > strlen (result))
2852       strcpy (nsh->result, result);
2853   }
2854   
2855   
2856   /* backtrack authorities for names */
2857   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2858                                  nsh->root_zone,
2859                                  &rh->authority_chain_head->zone,
2860                                  &process_zone_to_name_shorten_root,
2861                                  rh);
2862   
2863 }
2864
2865
2866 /**
2867  * Callback calles by namestore for a zone to name
2868  * result
2869  *
2870  * @param cls the closure
2871  * @param zone_key the zone we queried
2872  * @param expire the expiration time of the name
2873  * @param name the name found or NULL
2874  * @param rd_len number of records for the name
2875  * @param rd the record data (PKEY) for the name
2876  * @param signature the signature for the record data
2877  */
2878 static void
2879 process_zone_to_name_zkey(void *cls,
2880                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2881                  struct GNUNET_TIME_Absolute expire,
2882                  const char *name,
2883                  unsigned int rd_len,
2884                  const struct GNUNET_NAMESTORE_RecordData *rd,
2885                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2886 {
2887   struct ResolverHandle *rh = cls;
2888   struct NameShortenHandle *nsh = rh->proc_cls;
2889   struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
2890   char new_name[MAX_DNS_NAME_LENGTH];
2891
2892   /* zkey not in our zone */
2893   if (name == NULL)
2894   {
2895     /**
2896      * In this case we have not given this PKEY a name (yet)
2897      * It is either just not in our zone or not even cached
2898      * Since we do not know at this point we will not try to shorten
2899      * because PKEY import will happen if the user follows the zkey
2900      * link.
2901      */
2902     GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
2903                                      &enc);
2904     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2905                "No name found for zkey %s returning verbatim!\n", enc);
2906     if (strcmp(rh->name, "") != 0)
2907       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
2908                       rh->name, enc, GNUNET_GNS_TLD_ZKEY);
2909     else
2910       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2911                       enc, GNUNET_GNS_TLD_ZKEY);
2912
2913     strcpy (nsh->result, new_name);
2914
2915     nsh->proc(nsh->proc_cls, new_name);
2916     GNUNET_free(nsh);
2917     free_resolver_handle(rh);
2918     return;
2919   }
2920   
2921   if (strcmp(rh->name, "") != 0)
2922     GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2923                     rh->name, name);
2924   else
2925     strcpy(new_name, name);
2926
2927   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2928              "Continue shorten for %s!\n", new_name);
2929
2930   strcpy(rh->name, new_name);
2931   
2932   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2933   rh->authority_chain_tail = rh->authority_chain_head;
2934   rh->authority_chain_head->zone = rh->authority;
2935   
2936   
2937   /* Start delegation resolution in our namestore */
2938   resolve_delegation_ns(rh);
2939 }
2940
2941
2942 /**
2943  * Shorten api from resolver
2944  *
2945  * @param zone the root zone to use
2946  * @param pzone the private zone to use
2947  * @param szone the shorten zone to use
2948  * @param name the name to shorten
2949  * @param private_zone_name name of the private zone
2950  * @param shorten_zone_name name of the shorten zone
2951  * @param proc the processor to call with result
2952  * @param proc_cls closure to pass to proc
2953  */
2954 void
2955 gns_resolver_shorten_name (struct GNUNET_CRYPTO_ShortHashCode *zone,
2956                            struct GNUNET_CRYPTO_ShortHashCode *pzone,
2957                            struct GNUNET_CRYPTO_ShortHashCode *szone,
2958                            const char* name,
2959                            const char* private_zone_name,
2960                            const char* shorten_zone_name,
2961                            ShortenResultProcessor proc,
2962                            void* proc_cls)
2963 {
2964   struct ResolverHandle *rh;
2965   struct NameShortenHandle *nsh;
2966   char string_hash[MAX_DNS_LABEL_LENGTH];
2967   struct GNUNET_CRYPTO_ShortHashCode zkey;
2968   char nzkey[MAX_DNS_LABEL_LENGTH];
2969   char* nzkey_ptr = nzkey;
2970
2971
2972   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2973               "Starting shorten for %s!\n", name);
2974   
2975   if (is_canonical ((char*)name))
2976   {
2977     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2978                 "%s is canonical. Returning verbatim\n", name);
2979     proc (proc_cls, name);
2980     return;
2981   }
2982
2983   nsh = GNUNET_malloc (sizeof (struct NameShortenHandle));
2984
2985   nsh->proc = proc;
2986   nsh->proc_cls = proc_cls;
2987   nsh->root_zone = zone;
2988   nsh->private_zone = pzone;
2989   nsh->shorten_zone = szone;
2990   strcpy (nsh->private_zone_name, private_zone_name);
2991   strcpy (nsh->shorten_zone_name, shorten_zone_name);
2992   strcpy (nsh->result, name);
2993   
2994   rh = GNUNET_malloc (sizeof (struct ResolverHandle));
2995   rh->authority = *zone;
2996   rh->id = rid++;
2997   rh->priv_key = NULL;
2998   rh->proc = &handle_delegation_ns_shorten;
2999   rh->proc_cls = nsh;
3000   rh->id = rid++;
3001   rh->private_local_zone = *zone;
3002   
3003   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3004                 "Checking for TLD...\n");
3005   if (is_zkey_tld (name) == GNUNET_YES)
3006   {
3007     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3008                 "TLD is zkey\n");
3009     /**
3010      * This is a zkey tld
3011      * build hash and use as initial authority
3012      * FIXME sscanf
3013      */
3014     memset (rh->name, 0,
3015             strlen (name)-strlen (GNUNET_GNS_TLD_ZKEY));
3016     memcpy (rh->name, name,
3017             strlen(name)-strlen (GNUNET_GNS_TLD_ZKEY) - 1);
3018     pop_tld (rh->name, string_hash);
3019
3020     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3021                 "ZKEY is %s!\n", string_hash);
3022     
3023     GNUNET_STRINGS_utf8_toupper (string_hash, &nzkey_ptr);
3024
3025     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string (nzkey,
3026                                                            &zkey))
3027     {
3028       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3029                   "Cannot convert ZKEY %s to hash!\n", nzkey);
3030       GNUNET_free (rh);
3031       GNUNET_free (nsh);
3032       proc (proc_cls, name);
3033       return;
3034     }
3035
3036     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3037                                    zone, //ours
3038                                    &zkey,
3039                                    &process_zone_to_name_zkey,
3040                                    rh);
3041     return;
3042
3043   }
3044   else
3045   {
3046     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3047                 "TLD is gnunet\n");
3048     /**
3049      * Presumably GNUNET tld
3050      */
3051     memset (rh->name, 0,
3052             strlen (name)-strlen (GNUNET_GNS_TLD));
3053     memcpy (rh->name, name,
3054             strlen (name)-strlen (GNUNET_GNS_TLD) - 1);
3055   }
3056
3057   rh->authority_chain_head = GNUNET_malloc (sizeof (struct AuthorityChain));
3058   rh->authority_chain_tail = rh->authority_chain_head;
3059   rh->authority_chain_head->zone = *zone;
3060   
3061   
3062   /* Start delegation resolution in our namestore */
3063   resolve_delegation_ns (rh);
3064 }
3065
3066 /*********** END NAME SHORTEN ********************/
3067
3068
3069 /**
3070  * Process result from namestore delegation lookup
3071  * for get authority operation
3072  *
3073  * @param cls the client get auth handle
3074  * @param rh the resolver handle
3075  * @param rd_count number of results (0)
3076  * @param rd data (NULL)
3077  */
3078 void
3079 handle_delegation_result_ns_get_auth(void* cls,
3080                       struct ResolverHandle *rh,
3081                       uint32_t rd_count,
3082                       const struct GNUNET_NAMESTORE_RecordData *rd)
3083 {
3084   struct GetNameAuthorityHandle* nah;
3085   char result[MAX_DNS_NAME_LENGTH];
3086   size_t answer_len;
3087
3088   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
3089   
3090   /**
3091    * At this point rh->name contains the part of the name
3092    * that we do not have a PKEY in our namestore to resolve.
3093    * The authority chain in the resolver handle is now
3094    * useful to backtrack if needed
3095    */
3096   
3097   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3098              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
3099
3100   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3101              "Building response!\n");
3102   if (is_canonical(rh->name))
3103   {
3104     /**
3105      * We successfully resolved the authority in the ns
3106      * FIXME for our purposes this is fine
3107      * but maybe we want to have an api that also looks
3108      * into the dht (i.e. option in message)
3109      **/
3110     if (strlen(rh->name) > strlen(nah->name))
3111     {
3112       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3113                  "Record name longer than original lookup name... odd!\n");
3114       //FIXME to sth here
3115     }
3116
3117     answer_len = strlen(nah->name) - strlen(rh->name)
3118       + strlen(GNUNET_GNS_TLD) + 1;
3119     memset(result, 0, answer_len);
3120     strcpy(result, nah->name + strlen(rh->name) + 1);
3121
3122     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3123                "Got authority result %s\n", result);
3124     
3125     nah->proc(nah->proc_cls, result);
3126     GNUNET_free(nah);
3127     free_resolver_handle(rh);
3128   }
3129   else
3130   {
3131     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3132                "Unable to resolve authority for remaining %s!\n", rh->name);
3133     nah->proc(nah->proc_cls, "");
3134     GNUNET_free(nah);
3135     free_resolver_handle(rh);
3136   }
3137
3138
3139 }
3140
3141
3142 /**
3143  * Tries to resolve the authority for name
3144  * in our namestore
3145  *
3146  * @param zone the root zone to look up for
3147  * @param pzone the private local zone
3148  * @param name the name to lookup up
3149  * @param proc the processor to call when finished
3150  * @param proc_cls the closure to pass to the processor
3151  */
3152 void
3153 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
3154                            struct GNUNET_CRYPTO_ShortHashCode pzone,
3155                            const char* name,
3156                            GetAuthorityResultProcessor proc,
3157                            void* proc_cls)
3158 {
3159   struct ResolverHandle *rh;
3160   struct GetNameAuthorityHandle *nah;
3161
3162   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3163               "Starting authority resolution for %s!\n", name);
3164
3165   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
3166   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
3167   rh->authority = zone;
3168   rh->id = rid++;
3169   rh->private_local_zone = pzone;
3170   
3171   if (strcmp(GNUNET_GNS_TLD, name) == 0)
3172   {
3173     strcpy(rh->name, "\0");
3174   }
3175   else
3176   {
3177     memset(rh->name, 0,
3178            strlen(name)-strlen(GNUNET_GNS_TLD));
3179     memcpy(rh->name, name,
3180            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
3181   }
3182
3183   memset(nah->name, 0,
3184          strlen(name)+1);
3185   strcpy(nah->name, name);
3186   
3187   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
3188   rh->authority_chain_tail = rh->authority_chain_head;
3189   rh->authority_chain_head->zone = zone;
3190   rh->proc = &handle_delegation_result_ns_get_auth;
3191   rh->proc_cls = (void*)nah;
3192
3193   nah->proc = proc;
3194   nah->proc_cls = proc_cls;
3195
3196   /* Start delegation resolution in our namestore */
3197   resolve_delegation_ns(rh);
3198
3199 }
3200
3201 /******** END GET AUTHORITY *************/
3202
3203 /* end of gnunet-service-gns_resolver.c */