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