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