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