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