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