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