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