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