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