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