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