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