f3040749a5f8b76806586f1b8dd6cacea8cab4bc
[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                                                0))
1753   {
1754     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1755                 "GNS_PHASE_REC_DNS-%llu: Error binding UDP socket for DNS lookup!\n",
1756                 rh->id);
1757     finish_lookup (rh, rlh, 0, NULL);
1758     return;
1759   }
1760   query.name = rh->dns_name;
1761   query.type = rlh->record_type;
1762   query.class = GNUNET_DNSPARSER_CLASS_INTERNET;
1763   memset (&flags, 0, sizeof (flags));
1764   flags.recursion_desired = 1;
1765   flags.checking_disabled = 1;
1766   packet.queries = &query;
1767   packet.answers = NULL;
1768   packet.authority_records = NULL;
1769   packet.num_queries = 1;
1770   packet.num_answers = 0;
1771   packet.num_authority_records = 0;
1772   packet.num_additional_records = 0;
1773   packet.flags = flags;
1774   packet.id = rh->id;
1775   if (GNUNET_OK != GNUNET_DNSPARSER_pack (&packet,
1776                                           UINT16_MAX,
1777                                           &rh->dns_raw_packet,
1778                                           &rh->dns_raw_packet_size))
1779   {
1780     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1781                 "GNS_PHASE_REC_DNS-%llu: Creating raw dns packet!\n",
1782                 rh->id);
1783     GNUNET_NETWORK_socket_close (rh->dns_sock);
1784     finish_lookup (rh, rlh, 0, NULL);
1785     return;
1786   }
1787
1788   rh->dns_addr.sin_family = AF_INET;
1789   rh->dns_addr.sin_port = htons (53); //domain
1790   rh->dns_addr.sin_addr = dnsip;
1791 #if HAVE_SOCKADDR_IN_SIN_LEN
1792   rh->dns_addr.sin_len = (u_char) sizeof (struct sockaddr_in);
1793 #endif
1794   send_dns_packet (rh);
1795 }
1796
1797
1798 /**
1799  * The final phase of resoution.
1800  * We found a VPN RR and want to request an IPv4/6 address
1801  *
1802  * @param rh the pending lookup handle
1803  * @param rd_count length of record data
1804  * @param rd record data containing VPN RR
1805  */
1806 static void
1807 resolve_record_vpn (struct ResolverHandle *rh,
1808                     unsigned int rd_count,
1809                     const struct GNUNET_NAMESTORE_RecordData *rd)
1810 {
1811   struct RecordLookupHandle *rlh = rh->proc_cls;
1812   struct GNUNET_HashCode serv_desc;
1813   struct vpn_data* vpn;
1814   int af;
1815   
1816   /* We cancel here as to not include the ns lookup in the timeout */
1817   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1818   {
1819     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1820     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1821   }
1822   /* Start shortening */
1823   if ((NULL != rh->priv_key) &&
1824       (GNUNET_YES == is_canonical (rh->name)))
1825   {
1826     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1827              "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1828              rh->id);
1829     start_shorten (rh->authority_chain_head,
1830                    rh->priv_key);
1831   }
1832
1833   vpn = (struct vpn_data*)rd->data;
1834   GNUNET_CRYPTO_hash ((char*)&vpn[1],
1835                       strlen ((char*)&vpn[1]) + 1,
1836                       &serv_desc);
1837   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1838               "GNS_PHASE_REC_VPN-%llu: proto %hu peer %s!\n",
1839               rh->id,
1840               ntohs (vpn->proto),
1841               GNUNET_h2s (&vpn->peer));
1842
1843   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1844               "GNS_PHASE_REC_VPN-%llu: service %s -> %s!\n",
1845               rh->id,
1846               (char*)&vpn[1],
1847               GNUNET_h2s (&serv_desc));
1848   rh->proc = &handle_record_vpn;
1849   if (GNUNET_GNS_RECORD_A == rlh->record_type)
1850     af = AF_INET;
1851   else
1852     af = AF_INET6;
1853 #ifndef WINDOWS
1854   if (NULL == vpn_handle)
1855   {
1856     vpn_handle = GNUNET_VPN_connect (cfg);
1857     if (NULL == vpn_handle)
1858     {
1859       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1860                   "GNS_PHASE_INIT: Error connecting to VPN!\n");
1861       finish_lookup (rh, rh->proc_cls, 0, NULL);
1862       return;
1863     }
1864   }
1865
1866   rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1867                                                 af, ntohs (vpn->proto),
1868                                                 (struct GNUNET_PeerIdentity *)&vpn->peer,
1869                                                 &serv_desc,
1870                                                 GNUNET_NO, //nac
1871                                                 GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1872                                                 &process_record_result_vpn,
1873                                                 rh);
1874 #else
1875   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1876               "Error connecting to VPN (not available on W32 yet)\n");
1877   finish_lookup (rh, rh->proc_cls, 0, NULL);  
1878 #endif
1879 }
1880
1881
1882 /**
1883  * The final phase of resolution.
1884  * rh->name is a name that is canonical and we do not have a delegation.
1885  * Query namestore for this record
1886  *
1887  * @param rh the pending lookup handle
1888  */
1889 static void
1890 resolve_record_ns(struct ResolverHandle *rh)
1891 {
1892   struct RecordLookupHandle *rlh = rh->proc_cls;
1893   
1894   /* We cancel here as to not include the ns lookup in the timeout */
1895   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1896   {
1897     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1898     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1899   }
1900   /* Start shortening */
1901   if ((NULL != rh->priv_key) &&
1902      (GNUNET_YES == is_canonical (rh->name)))
1903   {
1904     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1905              "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1906              rh->id);
1907     start_shorten (rh->authority_chain_head,
1908                    rh->priv_key);
1909   }
1910   
1911   /**
1912    * Try to resolve this record in our namestore.
1913    * The name to resolve is now in rh->authority_name
1914    * since we tried to resolve it to an authority
1915    * and failed.
1916    **/
1917   rh->namestore_task = GNUNET_NAMESTORE_lookup_record(namestore_handle,
1918                                  &rh->authority,
1919                                  rh->name,
1920                                  rlh->record_type,
1921                                  &process_record_result_ns,
1922                                  rh);
1923 }
1924
1925
1926 /**
1927  * Handle timeout for DHT requests
1928  *
1929  * @param cls the request handle as closure
1930  * @param tc the task context
1931  */
1932 static void
1933 dht_authority_lookup_timeout (void *cls,
1934                               const struct GNUNET_SCHEDULER_TaskContext *tc)
1935 {
1936   struct ResolverHandle *rh = cls;
1937   struct RecordLookupHandle *rlh = rh->proc_cls;
1938   char new_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
1939
1940   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1941               "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%llus) timed out.\n",
1942               rh->id, rh->authority_name, 
1943               rh->timeout.rel_value);
1944
1945   rh->status |= RSL_TIMED_OUT;
1946   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1947   if (NULL != rh->get_handle)
1948   {
1949     GNUNET_DHT_get_stop (rh->get_handle);
1950     rh->get_handle = NULL;
1951   }
1952   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1953   {
1954     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1955                 "GNS_PHASE_DELEGATE_DHT-%llu: Got shutdown\n",
1956                 rh->id);
1957     rh->proc (rh->proc_cls, rh, 0, NULL);
1958     return;
1959   }
1960   if (0 == strcmp (rh->name, ""))
1961   {
1962     /*
1963      * promote authority back to name and try to resolve record
1964      */
1965     strcpy (rh->name, rh->authority_name);
1966     rh->proc (rh->proc_cls, rh, 0, NULL);
1967     return;
1968   }
1969   
1970   /**
1971    * Start resolution in bg
1972    */
1973   GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH,
1974                    "%s.%s.%s", 
1975                    rh->name, rh->authority_name, GNUNET_GNS_TLD);
1976   strcpy (rh->name, new_name);
1977   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1978               "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
1979               rh->id, rh->name,
1980               rlh->record_type);
1981   gns_resolver_lookup_record (rh->authority,
1982                               rh->private_local_zone,
1983                               rlh->record_type,
1984                               new_name,
1985                               NULL,
1986                               GNUNET_TIME_UNIT_FOREVER_REL,
1987                               GNUNET_NO,
1988                               &background_lookup_result_processor,
1989                               NULL);
1990   rh->proc (rh->proc_cls, rh, 0, NULL);
1991 }
1992
1993
1994 /**
1995  * Start DHT lookup for a name -> PKEY (compare NS) record in
1996  * rh->authority's zone
1997  *
1998  * @param rh the pending gns query
1999  */
2000 static void 
2001 resolve_delegation_dht (struct ResolverHandle *rh);
2002
2003
2004 /**
2005  * Resolve the delegation chain for the request in our namestore
2006  *
2007  * @param rh the resolver handle
2008  */
2009 static void 
2010 resolve_delegation_ns (struct ResolverHandle *rh);
2011
2012
2013 /**
2014  * Namestore resolution for delegation finished. Processing result.
2015  *
2016  * @param cls the closure
2017  * @param rh resolver handle
2018  * @param rd_count number of results (always 0)
2019  * @param rd record data (always NULL)
2020  */
2021 static void
2022 handle_delegation_ns (void* cls, struct ResolverHandle *rh,
2023                       unsigned int rd_count,
2024                       const struct GNUNET_NAMESTORE_RecordData *rd);
2025
2026
2027 /**
2028  * This is a callback function that checks for key revocation
2029  *
2030  * @param cls the pending query
2031  * @param key the key of the zone we did the lookup
2032  * @param expiration expiration date of the record data set in the namestore
2033  * @param name the name for which we need an authority
2034  * @param rd_count the number of records with 'name'
2035  * @param rd the record data
2036  * @param signature the signature of the authority for the record data
2037  */
2038 static void
2039 process_pkey_revocation_result_ns (void *cls,
2040                                    const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *key,
2041                                    struct GNUNET_TIME_Absolute expiration,
2042                                    const char *name,
2043                                    unsigned int rd_count,
2044                                    const struct GNUNET_NAMESTORE_RecordData *rd,
2045                                    const struct GNUNET_CRYPTO_EccSignature *signature)
2046 {
2047   struct ResolverHandle *rh = cls;
2048   struct GNUNET_TIME_Relative remaining_time;
2049   int i;
2050   
2051   rh->namestore_task = NULL;
2052   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2053   
2054   for (i = 0; i < rd_count; i++)
2055   {
2056     if (GNUNET_GNS_RECORD_REV == rd[i].record_type)
2057     {
2058       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2059                  "GNS_PHASE_DELEGATE_REV-%llu: Zone has been revoked.\n",
2060                  rh->id);
2061       rh->status |= RSL_PKEY_REVOKED;
2062       rh->proc (rh->proc_cls, rh, 0, NULL);
2063       return;
2064     }
2065   }
2066   
2067   if ((NULL == name) ||
2068       (0 == remaining_time.rel_value))
2069   {
2070     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2071           "GNS_PHASE_DELEGATE_REV-%llu: + Records don't exist or are expired.\n",
2072           rh->id, name);
2073
2074     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value != rh->timeout.rel_value)
2075     {
2076       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2077         "GNS_PHASE_DELEGATE_REV-%llu: Starting background lookup for %s type %d\n",
2078         rh->id, "+.gads", GNUNET_GNS_RECORD_REV);
2079
2080       gns_resolver_lookup_record(rh->authority,
2081                                  rh->private_local_zone,
2082                                  GNUNET_GNS_RECORD_REV,
2083                                  GNUNET_GNS_TLD,
2084                                  NULL,
2085                                  GNUNET_TIME_UNIT_FOREVER_REL,
2086                                  GNUNET_NO,
2087                                  &background_lookup_result_processor,
2088                                  NULL);
2089     }
2090   }
2091  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2092              "GNS_PHASE_DELEGATE_REV-%llu: Revocation check passed\n",
2093              rh->id);
2094   /**
2095    * We are done with PKEY resolution if name is empty
2096    * else resolve again with new authority
2097    */
2098   if (strcmp (rh->name, "") == 0)
2099     rh->proc (rh->proc_cls, rh, rh->rd_count, &rh->rd);
2100   else
2101     resolve_delegation_ns (rh);
2102 }
2103
2104
2105 /**
2106  * Callback when record data is put into namestore
2107  *
2108  * @param cls the closure
2109  * @param success GNUNET_OK on success
2110  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
2111  */
2112 void
2113 on_namestore_delegation_put_result(void *cls,
2114                                    int32_t success,
2115                                    const char *emsg)
2116 {
2117   struct NamestoreBGTask *nbg = cls;
2118
2119   GNUNET_CONTAINER_heap_remove_node (nbg->node);
2120   GNUNET_free (nbg);
2121
2122   if (GNUNET_NO == success)
2123   {
2124     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2125                "GNS_NS: records already in namestore\n");
2126     return;
2127   }
2128   else if (GNUNET_YES == success)
2129   {
2130     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2131                "GNS_NS: records successfully put in namestore\n");
2132     return;
2133   }
2134
2135   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2136              "GNS_NS: Error putting records into namestore: %s\n", emsg);
2137 }
2138
2139
2140 /**
2141  * Function called when we get a result from the dht
2142  * for our query. Recursively tries to resolve authorities
2143  * for name in DHT.
2144  *
2145  * @param cls the request handle
2146  * @param exp lifetime
2147  * @param key the key the record was stored under
2148  * @param get_path get path
2149  * @param get_path_length get path length
2150  * @param put_path put path
2151  * @param put_path_length put path length
2152  * @param type the block type
2153  * @param size the size of the record
2154  * @param data the record data
2155  */
2156 static void
2157 process_delegation_result_dht (void* cls,
2158                                struct GNUNET_TIME_Absolute exp,
2159                                const struct GNUNET_HashCode * key,
2160                                const struct GNUNET_PeerIdentity *get_path,
2161                                unsigned int get_path_length,
2162                                const struct GNUNET_PeerIdentity *put_path,
2163                                unsigned int put_path_length,
2164                                enum GNUNET_BLOCK_Type type,
2165                                size_t size, const void *data)
2166 {
2167   struct ResolverHandle *rh = cls;
2168   const struct GNSNameRecordBlock *nrb = data;
2169   const char* rd_data;
2170   uint32_t num_records;
2171   const char* name;
2172   uint32_t i;
2173   int rd_size;
2174   struct GNUNET_CRYPTO_ShortHashCode zone;
2175
2176   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2177               "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n",
2178               rh->id);
2179   if (data == NULL)
2180     return;
2181    /* stop dht lookup and timeout task */
2182   GNUNET_DHT_get_stop (rh->get_handle);
2183   rh->get_handle = NULL;
2184   if (rh->dht_heap_node != NULL)
2185   {
2186     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
2187     rh->dht_heap_node = NULL;
2188   }
2189
2190   num_records = ntohl(nrb->rd_count);
2191   name = (const char*) &nrb[1];
2192   {
2193     struct GNUNET_NAMESTORE_RecordData rd[num_records];
2194     struct NamestoreBGTask *ns_heap_root;
2195     struct NamestoreBGTask *namestore_bg_task;
2196     
2197     rd_data = name + strlen(name) + 1;
2198     rd_size = size - strlen(name) - 1 - sizeof (struct GNSNameRecordBlock);
2199     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
2200                                                                rd_data,
2201                                                                num_records,
2202                                                                rd))
2203     {
2204       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2205                  "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
2206                  rh->id);
2207       return;
2208     }
2209
2210     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2211                "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2212                rh->id, name, rh->authority_name);
2213     for (i=0; i<num_records; i++)
2214     {
2215       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2216                   "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2217                   rh->id, name, rh->authority_name);
2218       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2219                  "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
2220                  rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
2221       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2222                  "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
2223                  rh->id, rd[i].data_size);
2224       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2225                  "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
2226                  rh->id, rd[i].flags);
2227       
2228       if ((GNUNET_GNS_RECORD_VPN == rd[i].record_type) ||
2229           (GNUNET_GNS_RECORD_NS == rd[i].record_type) ||
2230           (GNUNET_GNS_RECORD_CNAME == rd[i].record_type))
2231       {
2232         /**
2233          * This is a VPN,NS,CNAME entry. Let namestore handle this after caching
2234          */
2235         if (0 == strcmp(rh->name, ""))
2236           strcpy(rh->name, rh->authority_name);
2237         else
2238           GNUNET_snprintf(rh->name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
2239                  rh->name, rh->authority_name); //FIXME ret
2240         rh->answered = 1;
2241         break;
2242       }
2243
2244       if ((0 == strcmp(name, rh->authority_name)) &&
2245           (GNUNET_GNS_RECORD_PKEY == rd[i].record_type))
2246       {
2247         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2248                    "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
2249                    rh->id);
2250         rh->answered = 1;
2251         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
2252         struct AuthorityChain *auth =
2253           GNUNET_malloc(sizeof(struct AuthorityChain));
2254         auth->zone = rh->authority;
2255         memset(auth->name, 0, strlen(rh->authority_name)+1);
2256         strcpy(auth->name, rh->authority_name);
2257         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2258                                      rh->authority_chain_tail,
2259                                      auth);
2260
2261         if (NULL != rh->rd.data)
2262           GNUNET_free ((void*)rh->rd.data);
2263         
2264         memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
2265         rh->rd.data = GNUNET_malloc (rd[i].data_size);
2266         memcpy ((void*)(rh->rd.data), rd[i].data, rd[i].data_size);
2267         rh->rd_count = 1;
2268
2269         /** try to import pkey if private key available */
2270         //if (rh->priv_key && is_canonical (rh->name))
2271         //  process_discovered_authority(name, auth->zone,
2272         //                               rh->authority_chain_tail->zone,
2273         //                               rh->priv_key);
2274       }
2275
2276     }
2277     GNUNET_GNS_get_zone_from_key (name, key, &zone);
2278
2279
2280     /* Save to namestore
2281     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2282                                           &zone))
2283     {*/
2284       if (max_allowed_ns_tasks <=
2285           GNUNET_CONTAINER_heap_get_size (ns_task_heap))
2286       {
2287         ns_heap_root = GNUNET_CONTAINER_heap_remove_root (ns_task_heap);
2288         GNUNET_NAMESTORE_cancel (ns_heap_root->qe);
2289
2290         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2291                    "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background ns task\n",
2292                    rh->id);
2293       }
2294       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2295                   "GNS_PHASE_DELEGATE_DHT-%llu: Caching record for %s\n",
2296                   rh->id, name);
2297       namestore_bg_task = GNUNET_malloc (sizeof (struct NamestoreBGTask));
2298
2299       namestore_bg_task->node = GNUNET_CONTAINER_heap_insert (ns_task_heap,
2300                                     namestore_bg_task,
2301                                     GNUNET_TIME_absolute_get().abs_value);
2302       namestore_bg_task->qe = GNUNET_NAMESTORE_record_put (namestore_handle,
2303                                  &nrb->public_key,
2304                                  name,
2305                                  exp,
2306                                  num_records,
2307                                  rd,
2308                                  &nrb->signature,
2309                                  &on_namestore_delegation_put_result, //cont
2310                                  namestore_bg_task); //cls
2311     }
2312   //}
2313
2314   if (0 != rh->answered)
2315   {
2316     rh->answered = 0;
2317     /**
2318      * delegate
2319      * FIXME in this case. should we ask namestore again?
2320      */
2321     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2322     "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
2323     rh->id, rh->authority_name, rh->name);
2324
2325     if (0 == strcmp(rh->name, ""))
2326     {
2327       /* Start shortening */
2328       if ((NULL != rh->priv_key) &&
2329           (GNUNET_YES == is_canonical (rh->name)))
2330       {
2331         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2332              "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
2333              rh->id);
2334         start_shorten (rh->authority_chain_head,
2335                        rh->priv_key);
2336       }
2337     }
2338     else
2339       rh->proc = &handle_delegation_ns;
2340
2341
2342     /* Check for key revocation and delegate */
2343     rh->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
2344                                     &rh->authority,
2345                                     GNUNET_GNS_MASTERZONE_STR,
2346                                     GNUNET_GNS_RECORD_REV,
2347                                     &process_pkey_revocation_result_ns,
2348                                     rh);
2349
2350     return;
2351   }
2352   
2353   /**
2354    * No pkey but name exists
2355    * promote back
2356    */
2357   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2358              "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
2359              rh->id, rh->authority_name, rh->name);
2360   if (0 == strcmp(rh->name, ""))
2361     strcpy(rh->name, rh->authority_name);
2362   else
2363     GNUNET_snprintf(rh->name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
2364                   rh->name, rh->authority_name); //FIXME ret
2365   
2366   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2367              "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
2368   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2369           "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
2370            rh->id);
2371   rh->proc(rh->proc_cls, rh, 0, NULL);
2372 }
2373
2374 //FIXME maybe define somewhere else?
2375 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
2376                         +(GNUNET_DNSPARSER_MAX_NAME_LENGTH*2)
2377 #define MAX_MX_LENGTH sizeof(uint16_t)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
2378 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+GNUNET_DNSPARSER_MAX_NAME_LENGTH
2379
2380
2381 /**
2382  * Exands a name ending in .+ with the zone of origin.
2383  * FIXME: funky api: 'dest' must be large enough to hold
2384  * the result; this is a bit yucky...
2385  *
2386  * @param dest destination buffer
2387  * @param src the .+ name
2388  * @param repl the string to replace the + with
2389  */
2390 static void
2391 expand_plus (char* dest, 
2392              const char* src, 
2393              const char* repl)
2394 {
2395   char* pos;
2396   size_t s_len = strlen (src) + 1;
2397
2398   //Eh? I guess this is at least strlen ('x.+') == 3 FIXME
2399   if (3 > s_len)
2400   {
2401     /* no postprocessing */
2402     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2403                "GNS_POSTPROCESS: %s too short\n", src);
2404     memcpy (dest, src, s_len);
2405     return;
2406   }
2407   if (0 == strcmp (src + s_len - 3, ".+"))
2408   {
2409     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2410                 "GNS_POSTPROCESS: Expanding .+ in %s\n", 
2411                 src);
2412     memset (dest, 0, s_len + strlen (repl) + strlen(GNUNET_GNS_TLD));
2413     strcpy (dest, src);
2414     pos = dest + s_len - 2;
2415     strcpy (pos, repl);
2416     pos += strlen (repl);
2417     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2418                 "GNS_POSTPROCESS: Expanded to %s\n", 
2419                 dest);
2420   }
2421   else
2422   {
2423     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2424                "GNS_POSTPROCESS: No postprocessing for %s\n", src);
2425     memcpy (dest, src, s_len);
2426   }
2427 }
2428
2429
2430 /**
2431  * finish lookup
2432  */
2433 static void
2434 finish_lookup (struct ResolverHandle *rh,
2435                struct RecordLookupHandle* rlh,
2436                unsigned int rd_count,
2437                const struct GNUNET_NAMESTORE_RecordData *rd)
2438 {
2439   unsigned int i;
2440   char new_rr_data[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
2441   char new_mx_data[MAX_MX_LENGTH];
2442   char new_soa_data[MAX_SOA_LENGTH];
2443   char new_srv_data[MAX_SRV_LENGTH];
2444   struct srv_data *old_srv;
2445   struct srv_data *new_srv;
2446   struct soa_data *old_soa;
2447   struct soa_data *new_soa;
2448   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
2449   char* repl_string;
2450   char* pos;
2451   unsigned int offset;
2452
2453   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
2454   {
2455     GNUNET_SCHEDULER_cancel(rh->timeout_task);
2456     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2457   }
2458
2459   GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
2460
2461   if (0 < rd_count)
2462     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
2463
2464   for (i = 0; i < rd_count; i++)
2465   {
2466     
2467     if ((GNUNET_GNS_RECORD_NS != rd[i].record_type) &&
2468         (GNUNET_GNS_RECORD_PTR != rd[i].record_type) &&
2469         (GNUNET_GNS_RECORD_CNAME != rd[i].record_type) &&
2470         (GNUNET_GNS_RECORD_MX != rd[i].record_type) &&
2471         (GNUNET_GNS_RECORD_SOA != rd[i].record_type) &&
2472         (GNUNET_GNS_RECORD_SRV != rd[i].record_type))
2473     {
2474       p_rd[i].data = rd[i].data;
2475       continue;
2476     }
2477
2478     /**
2479      * for all those records we 'should'
2480      * also try to resolve the A/AAAA records (RFC1035)
2481      * This is a feature and not important
2482      */
2483     
2484     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2485                "GNS_POSTPROCESS: Postprocessing\n");
2486     if (0 == strcmp(rh->name, GNUNET_GNS_MASTERZONE_STR))
2487       repl_string = rlh->name;
2488     else
2489       repl_string = rlh->name+strlen(rh->name)+1;
2490
2491     offset = 0;
2492     if (GNUNET_GNS_RECORD_MX == rd[i].record_type)
2493     {
2494       memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
2495       offset = sizeof (uint16_t);
2496       pos = new_mx_data + offset;
2497       // FIXME: how do we know that 'pos' has enough space for the new name?
2498       expand_plus (pos, (char*)rd[i].data+sizeof(uint16_t),
2499                    repl_string);
2500       offset += strlen(new_mx_data+sizeof(uint16_t)) + 1;
2501       p_rd[i].data = new_mx_data;
2502       p_rd[i].data_size = offset;
2503     }
2504     else if (GNUNET_GNS_RECORD_SRV == rd[i].record_type)
2505     {
2506       /*
2507        * Prio, weight and port
2508        */
2509       new_srv = (struct srv_data*)new_srv_data;
2510       old_srv = (struct srv_data*)rd[i].data;
2511       new_srv->prio = old_srv->prio;
2512       new_srv->weight = old_srv->weight;
2513       new_srv->port = old_srv->port;
2514       // FIXME: how do we know that '&new_srv[1]' has enough space for the new name?
2515       expand_plus((char*)&new_srv[1], (char*)&old_srv[1],
2516                   repl_string);
2517       p_rd[i].data = new_srv_data;
2518       p_rd[i].data_size = sizeof (struct srv_data) + strlen ((char*)&new_srv[1]) + 1;
2519     }
2520     else if (GNUNET_GNS_RECORD_SOA == rd[i].record_type)
2521     {
2522       /* expand mname and rname */
2523       old_soa = (struct soa_data*)rd[i].data;
2524       new_soa = (struct soa_data*)new_soa_data;
2525       memcpy (new_soa, old_soa, sizeof (struct soa_data));
2526       // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
2527       expand_plus((char*)&new_soa[1], (char*)&old_soa[1], repl_string);
2528       offset = strlen ((char*)&new_soa[1]) + 1;
2529       // FIXME: how do we know that 'new_soa[1]' has enough space for the new name?
2530       expand_plus((char*)&new_soa[1] + offset,
2531                   (char*)&old_soa[1] + strlen ((char*)&old_soa[1]) + 1,
2532                   repl_string);
2533       p_rd[i].data_size = sizeof (struct soa_data)
2534                           + offset
2535                           + strlen ((char*)&new_soa[1] + offset);
2536       p_rd[i].data = new_soa_data;
2537     }
2538     else
2539     {
2540       pos = new_rr_data;
2541       // FIXME: how do we know that 'rd[i].data' has enough space for the new name?
2542       expand_plus(pos, (char*)rd[i].data, repl_string);
2543       p_rd[i].data_size = strlen(new_rr_data)+1;
2544       p_rd[i].data = new_rr_data;
2545     }
2546     
2547   }
2548
2549   rlh->proc(rlh->proc_cls, rd_count, p_rd);
2550   GNUNET_free(rlh);
2551   free_resolver_handle (rh);
2552 }
2553
2554
2555 /**
2556  * Process DHT lookup result for record.
2557  *
2558  * @param cls the closure
2559  * @param rh resolver handle
2560  * @param rd_count number of results
2561  * @param rd record data
2562  */
2563 static void
2564 handle_record_dht (void* cls, struct ResolverHandle *rh,
2565                    unsigned int rd_count,
2566                    const struct GNUNET_NAMESTORE_RecordData *rd)
2567 {
2568   struct RecordLookupHandle* rlh = cls;
2569
2570   if (0 == rd_count)
2571   {
2572     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2573                "GNS_PHASE_REC-%llu: No records for %s found in DHT. Aborting\n",
2574                rh->id, rh->name);
2575     /* give up, cannot resolve */
2576     finish_lookup (rh, rlh, 0, NULL);
2577     return;
2578   }
2579   /* results found yay */
2580   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2581              "GNS_PHASE_REC-%llu: Record resolved from DHT!", rh->id);
2582   finish_lookup (rh, rlh, rd_count, rd);
2583 }
2584
2585
2586 /**
2587  * Process namestore lookup result for record.
2588  *
2589  * @param cls the closure
2590  * @param rh resolver handle
2591  * @param rd_count number of results
2592  * @param rd record data
2593  */
2594 static void
2595 handle_record_ns (void* cls, struct ResolverHandle *rh,
2596                   unsigned int rd_count,
2597                   const struct GNUNET_NAMESTORE_RecordData *rd)
2598 {
2599   struct RecordLookupHandle* rlh = cls;
2600   int check_dht = GNUNET_YES;
2601   
2602   if (0 != rd_count)
2603   {
2604     /* results found yay */
2605     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2606                "GNS_PHASE_REC-%llu: Record resolved from namestore!\n", rh->id);
2607     finish_lookup (rh, rlh, rd_count, rd);
2608     return;
2609   }
2610   
2611   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2612               "GNS_PHASE_REC-%llu: NS returned no records. (status: %d)!\n",
2613               rh->id,
2614               rh->status);
2615   /**
2616    * There are 5 conditions that have to met for us to consult the DHT:
2617    * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
2618    * 2. No entry in the NS existed AND
2619    * 3. The zone queried is not the local resolver's zone AND
2620    * 4. The name that was looked up is '+'
2621    *    because if it was any other canonical name we either already queried
2622    *    the DHT for the authority in the authority lookup phase (and thus
2623    *    would already have an entry in the NS for the record)
2624    * 5. We are not in cache only mode
2625    */
2626   if ((0 != (rh->status & RSL_RECORD_EXPIRED)) &&
2627       (0 == (rh->status & RSL_RECORD_EXISTS)) )
2628   {
2629     
2630     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2631               "GNS_PHASE_REC-%llu: Not expired and exists!\n",
2632               rh->id);
2633     check_dht = GNUNET_NO;
2634   }
2635   
2636   if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2637                                         &rh->private_local_zone))
2638   {
2639
2640     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2641               "GNS_PHASE_REC-%llu: Our zone!\n",
2642               rh->id);
2643     check_dht = GNUNET_NO;
2644   }
2645   
2646   if ((0 != strcmp (rh->name, GNUNET_GNS_MASTERZONE_STR)) && (GNUNET_YES == is_srv (rh->name)))
2647       check_dht = GNUNET_NO;
2648
2649   if (GNUNET_YES == rh->only_cached)
2650     check_dht = GNUNET_NO;
2651   
2652   if (GNUNET_YES == check_dht)
2653   {
2654     rh->proc = &handle_record_dht;
2655     resolve_record_dht(rh);
2656     return;
2657   }
2658   /* give up, cannot resolve */
2659   finish_lookup (rh, rlh, 0, NULL);
2660 }
2661
2662
2663 /**
2664  * Move one level up in the domain hierarchy and return the
2665  * passed top level domain.
2666  *
2667  * FIXME: funky API: not only 'dest' is updated, so is 'name'!
2668  *
2669  * @param name the domain
2670  * @param dest the destination where the tld will be put
2671  */
2672 static void
2673 pop_tld (char* name, char* dest)
2674 {
2675   uint32_t len;
2676
2677   if (GNUNET_YES == is_canonical (name))
2678   {
2679     strcpy (dest, name);
2680     strcpy (name, "");
2681     return;
2682   }
2683
2684   for (len = strlen(name); 0 < len; len--)
2685   {
2686     if (*(name+len) == '.')
2687       break;
2688   }
2689   
2690   //Was canonical?
2691   if (0 == len)
2692     return;
2693   name[len] = '\0';
2694   strcpy (dest, (name+len+1));
2695 }
2696
2697
2698 /**
2699  * DHT resolution for delegation finished. Processing result.
2700  *
2701  * @param cls the closure
2702  * @param rh resolver handle
2703  * @param rd_count number of results (always 0)
2704  * @param rd record data (always NULL)
2705  */
2706 static void
2707 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
2708                           unsigned int rd_count,
2709                           const struct GNUNET_NAMESTORE_RecordData *rd)
2710 {
2711   struct RecordLookupHandle* rlh = cls;
2712   
2713   if (0 == strcmp(rh->name, ""))
2714   {
2715     if (GNUNET_GNS_RECORD_PKEY == rlh->record_type)
2716     {
2717       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2718                  "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
2719                  rh->id);
2720       finish_lookup(rh, rlh, rd_count, rd);
2721       return;
2722     }
2723     /* We resolved full name for delegation. resolving record */
2724     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2725      "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
2726      rh->id);
2727     strcpy(rh->name, "+\0");
2728     rh->proc = &handle_record_ns;
2729     resolve_record_ns(rh);
2730     return;
2731   }
2732
2733   /**
2734    * we still have some left
2735    **/
2736   if (GNUNET_YES == is_canonical (rh->name))
2737   {
2738     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2739              "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
2740              rh->id,
2741              rh->name);
2742     rh->proc = &handle_record_ns;
2743     resolve_record_ns(rh);
2744     return;
2745   }
2746   /* give up, cannot resolve */
2747   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2748  "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
2749  rh->id, rh->name);
2750   finish_lookup(rh, rlh, 0, NULL);
2751 }
2752
2753
2754 /**
2755  * Start DHT lookup for a name -> PKEY (compare NS) record in
2756  * rh->authority's zone
2757  *
2758  * @param rh the pending gns query
2759  */
2760 static void
2761 resolve_delegation_dht (struct ResolverHandle *rh)
2762 {
2763   uint32_t xquery;
2764   struct GNUNET_HashCode lookup_key;
2765   struct ResolverHandle *rh_heap_root;
2766   
2767   pop_tld (rh->name, rh->authority_name);
2768   GNUNET_GNS_get_key_for_record (rh->authority_name,
2769                                  &rh->authority, 
2770                                  &lookup_key);
2771   rh->dht_heap_node = NULL;
2772   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2773   {
2774     rh->timeout_cont = &dht_authority_lookup_timeout;
2775     rh->timeout_cont_cls = rh;
2776   }
2777   else 
2778   {
2779     if (max_allowed_background_queries <=
2780         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
2781     {
2782       /* terminate oldest lookup */
2783       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2784       GNUNET_DHT_get_stop (rh_heap_root->get_handle);
2785       rh_heap_root->get_handle = NULL;
2786       rh_heap_root->dht_heap_node = NULL;
2787       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2788                   "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
2789                   rh->id, 
2790                   rh_heap_root->authority_name);
2791       rh_heap_root->proc (rh_heap_root->proc_cls,
2792                           rh_heap_root,
2793                           0,
2794                           NULL);
2795     }
2796     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2797                                                       rh,
2798                                                       GNUNET_TIME_absolute_get().abs_value);
2799   }
2800   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2801               "Beginning DHT lookup for %s in zone %s for request %llu\n",
2802               rh->authority_name,
2803               GNUNET_short_h2s (&rh->authority),
2804               rh->id);
2805   xquery = htonl (GNUNET_GNS_RECORD_PKEY);
2806   GNUNET_assert (rh->get_handle == NULL);
2807   rh->get_handle = GNUNET_DHT_get_start (dht_handle,
2808                                          GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2809                                          &lookup_key,
2810                                          DHT_GNS_REPLICATION_LEVEL,
2811                                          GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
2812                                          &xquery,
2813                                          sizeof(xquery),
2814                                          &process_delegation_result_dht,
2815                                          rh);
2816 }
2817
2818
2819 /**
2820  * Checks if "name" ends in ".tld"
2821  *
2822  * @param name the name to check
2823  * @param tld the TLD to check for
2824  * @return GNUNET_YES or GNUNET_NO
2825  */
2826 int
2827 is_tld (const char* name, const char* tld)
2828 {
2829   size_t offset = 0;
2830
2831   if (strlen (name) <= strlen (tld))
2832     return GNUNET_NO;
2833   offset = strlen (name) - strlen (tld);
2834   if (0 != strcmp (name + offset, tld))
2835     return GNUNET_NO;
2836   return GNUNET_YES;
2837 }
2838
2839
2840 /**
2841  * Namestore resolution for delegation finished. Processing result.
2842  *
2843  * @param cls the closure
2844  * @param rh resolver handle
2845  * @param rd_count number of results (always 0)
2846  * @param rd record data (always NULL)
2847  */
2848 static void
2849 handle_delegation_ns (void* cls, struct ResolverHandle *rh,
2850                       unsigned int rd_count,
2851                       const struct GNUNET_NAMESTORE_RecordData *rd)
2852 {
2853   struct RecordLookupHandle* rlh = cls;
2854   int check_dht;
2855   size_t s_len;
2856
2857   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2858               "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
2859               rh->id, rh->status);
2860
2861   if (rh->status & RSL_PKEY_REVOKED)
2862   {
2863     finish_lookup (rh, rlh, 0, NULL);
2864     return;
2865   }
2866   
2867   if (0 == strcmp(rh->name, ""))
2868   {
2869     
2870     /* We resolved full name for delegation. resolving record */
2871     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2872               "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
2873               rh->id);
2874     if (rh->status & RSL_CNAME_FOUND)
2875     {
2876       if (GNUNET_GNS_RECORD_CNAME == rlh->record_type)
2877       {
2878         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2879                   "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried CNAME in NS.\n",
2880                   rh->id);
2881         strcpy (rh->name, rh->authority_name);
2882         finish_lookup (rh, rlh, rd_count, rd);
2883         return;
2884       }
2885       
2886       /* A .+ CNAME  */
2887       if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_PLUS))
2888       {
2889         s_len = strlen (rd->data) - 2;
2890         memcpy (rh->name, rd->data, s_len);
2891         rh->name[s_len] = '\0';
2892         resolve_delegation_ns (rh);
2893         return;
2894       }
2895       else if (GNUNET_YES == is_tld ((char*)rd->data, GNUNET_GNS_TLD_ZKEY))
2896       {
2897         gns_resolver_lookup_record (rh->authority,
2898                                     rh->private_local_zone,
2899                                     rlh->record_type,
2900                                     (char*)rd->data,
2901                                     rh->priv_key,
2902                                     rh->timeout,
2903                                     rh->only_cached,
2904                                     rlh->proc,
2905                                     rlh->proc_cls);
2906         GNUNET_free (rlh);
2907         GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
2908         free_resolver_handle (rh);
2909         return;
2910       }
2911       else
2912       {
2913         //Try DNS resolver
2914         strcpy (rh->dns_name, (char*)rd->data);
2915         resolve_dns_name (rh);
2916         return;
2917       }
2918
2919     }
2920     else if (rh->status & RSL_DELEGATE_VPN)
2921     {
2922       if (GNUNET_GNS_RECORD_VPN == rlh->record_type)
2923       {
2924         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2925                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried VPNRR in NS.\n",
2926                  rh->id);
2927         finish_lookup(rh, rlh, rd_count, rd);
2928         return;
2929       }
2930       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2931              "GNS_PHASE_DELEGATE_NS-%llu: VPN delegation starting.\n",
2932              rh->id);
2933       GNUNET_assert (NULL != rd);
2934       rh->proc = &handle_record_vpn;
2935       resolve_record_vpn (rh, rd_count, rd);
2936       return;
2937     }
2938     else if (rh->status & RSL_DELEGATE_NS)
2939     {
2940       if (GNUNET_GNS_RECORD_NS == rlh->record_type)
2941       {
2942         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2943                     "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2944                     rh->id);
2945         finish_lookup (rh, rlh, rd_count, rd);
2946         return;
2947       }      
2948       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2949                   "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2950                   rh->id);
2951       GNUNET_assert (NULL != rd);
2952       rh->proc = &handle_record_ns;
2953       resolve_record_dns (rh, rd_count, rd);
2954       return;
2955     }
2956     else if (rh->status & RSL_DELEGATE_PKEY)
2957     {
2958       if (rh->status & RSL_PKEY_REVOKED)
2959       {
2960         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2961                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved PKEY is revoked.\n",
2962                    rh->id);
2963         finish_lookup (rh, rlh, 0, NULL);
2964         return;
2965       }
2966       else if (GNUNET_GNS_RECORD_PKEY == rlh->record_type)
2967       {
2968         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2969                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
2970                    rh->id);
2971         finish_lookup(rh, rlh, rd_count, rd);
2972         return;
2973       }
2974     }
2975     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2976                "GNS_PHASE_DELEGATE_NS-%llu: Resolving record +\n",
2977                rh->id);
2978     strcpy(rh->name, "+\0");
2979     rh->proc = &handle_record_ns;
2980     resolve_record_ns(rh);
2981     return;
2982   }
2983   
2984   if (rh->status & RSL_DELEGATE_NS)
2985   {
2986     if (GNUNET_GNS_RECORD_NS == rlh->record_type)
2987     {
2988       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2989                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2990                  rh->id);
2991       finish_lookup(rh, rlh, rd_count, rd);
2992       return;
2993     }
2994     
2995     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2996                "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2997                rh->id);
2998     GNUNET_assert (NULL != rd);
2999     rh->proc = &handle_record_ns;
3000     resolve_record_dns (rh, rd_count, rd);
3001     return;
3002   }
3003   
3004   /**
3005    * we still have some left
3006    * check if authority in ns is fresh
3007    * and exists
3008    * or we are authority
3009    **/
3010
3011   check_dht = GNUNET_YES;
3012   if ((rh->status & RSL_RECORD_EXISTS) &&
3013        !(rh->status & RSL_RECORD_EXPIRED))
3014     check_dht = GNUNET_NO;
3015
3016   if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3017                                         &rh->private_local_zone))
3018     check_dht = GNUNET_NO;
3019
3020   if (GNUNET_YES == rh->only_cached)
3021     check_dht = GNUNET_NO;
3022
3023   if (GNUNET_YES == check_dht)
3024   {
3025
3026     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3027         "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
3028         rh->id, rh->name);
3029     rh->proc = &handle_delegation_dht;
3030     resolve_delegation_dht(rh);
3031     return;
3032   }
3033   
3034   if (GNUNET_NO == is_canonical (rh->name))
3035   {
3036     /* give up, cannot resolve */
3037     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3038         "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
3039         rh->id,
3040         rh->name);
3041     finish_lookup(rh, rlh, rd_count, rd);
3042     return;
3043   }
3044   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3045              "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
3046              rh->id,
3047              rh->name);
3048   rh->proc = &handle_record_ns;
3049   resolve_record_ns(rh);
3050 }
3051
3052
3053 /**
3054  * This is a callback function that should give us only PKEY
3055  * records. Used to query the namestore for the authority (PKEY)
3056  * for 'name'. It will recursively try to resolve the
3057  * authority for a given name from the namestore.
3058  *
3059  * @param cls the pending query
3060  * @param key the key of the zone we did the lookup
3061  * @param expiration expiration date of the record data set in the namestore
3062  * @param name the name for which we need an authority
3063  * @param rd_count the number of records with 'name'
3064  * @param rd the record data
3065  * @param signature the signature of the authority for the record data
3066  */
3067 static void
3068 process_delegation_result_ns (void* cls,
3069                               const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *key,
3070                               struct GNUNET_TIME_Absolute expiration,
3071                               const char *name,
3072                               unsigned int rd_count,
3073                               const struct GNUNET_NAMESTORE_RecordData *rd,
3074                               const struct GNUNET_CRYPTO_EccSignature *signature)
3075 {
3076   struct ResolverHandle *rh = cls;
3077   struct GNUNET_TIME_Relative remaining_time;
3078   struct GNUNET_CRYPTO_ShortHashCode zone;
3079   char new_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
3080   unsigned int i;
3081   struct GNUNET_TIME_Absolute et;
3082   struct AuthorityChain *auth;
3083  
3084   rh->namestore_task = NULL;
3085   GNUNET_CRYPTO_short_hash (key,
3086                             sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded),
3087                             &zone);
3088   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3089               "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup for `%s' in zone %s\n",
3090               rh->id, rd_count,
3091               name,
3092               GNUNET_short_h2s (&zone));
3093
3094   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
3095   
3096   rh->status = 0;
3097   
3098   if (NULL != name)
3099   {
3100     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3101                 "GNS_PHASE_DELEGATE_NS-%llu: Records with name `%s' exist in zone %s.\n",
3102                 rh->id, name,
3103                 GNUNET_short_h2s (&zone));
3104     rh->status |= RSL_RECORD_EXISTS;
3105   
3106     if (0 == remaining_time.rel_value)
3107     {
3108       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3109                   "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
3110                   rh->id, name);
3111       rh->status |= RSL_RECORD_EXPIRED;
3112     }
3113   }
3114   
3115   /**
3116    * No authority found in namestore.
3117    */
3118   if (0 == rd_count)
3119   {
3120     /**
3121      * We did not find an authority in the namestore
3122      */
3123     
3124     /**
3125      * No PKEY in zone.
3126      * Promote this authority back to a name maybe it is
3127      * our record.
3128      */
3129     if (strcmp (rh->name, "") == 0)
3130     {
3131       /* simply promote back */
3132       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3133                   "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
3134                   rh->id, rh->authority_name);
3135       strcpy (rh->name, rh->authority_name);
3136     }
3137     else
3138     {
3139       /* add back to existing name */
3140       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3141                   "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
3142                   rh->id, rh->authority_name, rh->name);
3143       GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
3144                        rh->name, rh->authority_name);
3145       strcpy (rh->name, new_name);
3146       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3147                   "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n",
3148                   rh->id, rh->name);
3149     }
3150
3151     rh->proc (rh->proc_cls, rh, 0, NULL);
3152     return;
3153   }
3154
3155   /**
3156    * We found an authority that may be able to help us
3157    * move on with query
3158    * Note only 1 pkey should have been returned.. anything else would be strange
3159    */
3160   for (i=0; i < rd_count;i++)
3161   {
3162     switch (rd[i].record_type)
3163     {
3164     case GNUNET_GNS_RECORD_CNAME:
3165       /* Like in regular DNS this should mean that there is no other
3166        * record for this name.  */
3167
3168       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3169                   "GNS_PHASE_DELEGATE_NS-%llu: CNAME `%.*s' found.\n",
3170                   rh->id,
3171                   (int) rd[i].data_size,
3172                   rd[i].data);
3173       rh->status |= RSL_CNAME_FOUND;
3174       rh->proc (rh->proc_cls, rh, rd_count, rd);
3175       return;
3176     case GNUNET_GNS_RECORD_VPN:
3177       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3178                   "GNS_PHASE_DELEGATE_NS-%llu: VPN found.\n",
3179                   rh->id);
3180       rh->status |= RSL_DELEGATE_VPN;
3181       rh->proc (rh->proc_cls, rh, rd_count, rd);
3182       return;
3183     case GNUNET_GNS_RECORD_NS:
3184       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3185                   "GNS_PHASE_DELEGATE_NS-%llu: NS `%.*s' found.\n",
3186                   rh->id,
3187                   (int) rd[i].data_size,
3188                   rd[i].data);
3189       rh->status |= RSL_DELEGATE_NS;
3190       rh->proc (rh->proc_cls, rh, rd_count, rd);
3191       return;
3192     case GNUNET_GNS_RECORD_PKEY:
3193       rh->status |= RSL_DELEGATE_PKEY;
3194       if ((ignore_pending_records != 0) &&
3195           (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
3196       {
3197         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3198                     "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
3199                     rh->id,
3200                     name);
3201         continue;
3202       }    
3203       GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
3204       et.abs_value = rd[i].expiration_time;
3205       if (0 == (GNUNET_TIME_absolute_get_remaining (et)).rel_value)
3206       {
3207         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3208                     "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
3209                     rh->id);
3210         if (remaining_time.rel_value == 0)
3211         {
3212           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3213                       "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
3214                       rh->id);
3215           rh->authority_chain_head->fresh = 0;
3216           rh->proc (rh->proc_cls, rh, 0, NULL);
3217           return;
3218         }       
3219         continue;
3220       }
3221       /* Resolve rest of query with new authority */
3222       memcpy (&rh->authority, rd[i].data,
3223               sizeof (struct GNUNET_CRYPTO_ShortHashCode));
3224       auth = GNUNET_malloc(sizeof (struct AuthorityChain));
3225       auth->zone = rh->authority;
3226       memset (auth->name, 0, strlen (rh->authority_name)+1);
3227       strcpy (auth->name, rh->authority_name);
3228       GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
3229                                    rh->authority_chain_tail,
3230                                    auth);
3231       if (NULL != rh->rd.data)
3232         GNUNET_free ((void*)(rh->rd.data));      
3233       memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
3234       rh->rd.data = GNUNET_malloc (rd[i].data_size);
3235       memcpy ((void*)rh->rd.data, rd[i].data, rd[i].data_size);
3236       rh->rd_count = 1;
3237       /* Check for key revocation and delegate */
3238       rh->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
3239                                                            &rh->authority,
3240                                                            GNUNET_GNS_MASTERZONE_STR,
3241                                                            GNUNET_GNS_RECORD_REV,
3242                                                            &process_pkey_revocation_result_ns,
3243                                                            rh);
3244       return;
3245     default:
3246       /* ignore, move to next result */
3247       break;
3248     }
3249   }
3250   
3251   /* no answers that would cause delegation were found */
3252   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3253              "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup failed (no PKEY record)\n", 
3254              rh->id);
3255   /**
3256    * If we have found some records for the LAST label
3257    * we return the results. Else NULL.
3258    */
3259   if (0 == strcmp (rh->name, ""))
3260   {
3261     /* Start shortening */
3262     if ((rh->priv_key != NULL) &&
3263         (is_canonical (rh->name) == GNUNET_YES))
3264     {
3265       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3266               "GNS_PHASE_DELEGATE_NS-%llu: Trying to shorten authority chain\n",
3267               rh->id);
3268       start_shorten (rh->authority_chain_head,
3269                     rh->priv_key);
3270     }
3271     /* simply promote back */
3272     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3273                 "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
3274                 rh->id, rh->authority_name);
3275     strcpy (rh->name, rh->authority_name);
3276     rh->proc (rh->proc_cls, rh, rd_count, rd);
3277   }
3278   else
3279   {
3280     GNUNET_snprintf (new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH,
3281                      "%s.%s", rh->name, rh->authority_name);
3282     strcpy (rh->name, new_name);
3283     rh->proc (rh->proc_cls, rh, 0, NULL);
3284   }
3285 }
3286
3287
3288 /**
3289  * Resolve the delegation chain for the request in our namestore
3290  * (as in, find the respective authority for the leftmost label).
3291  *
3292  * @param rh the resolver handle
3293  */
3294 static void
3295 resolve_delegation_ns (struct ResolverHandle *rh)
3296 {
3297   pop_tld (rh->name, rh->authority_name);
3298   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3299               "GNS_PHASE_DELEGATE_NS-%llu: Finding authority for `%s' by looking up `%s' in GADS zone `%s'\n",
3300               rh->id,         
3301               rh->name,
3302               rh->authority_name,
3303               GNUNET_short_h2s (&rh->authority));
3304   rh->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
3305                                                        &rh->authority,
3306                                                        rh->authority_name,
3307                                                        GNUNET_GNS_RECORD_ANY,
3308                                                        &process_delegation_result_ns,
3309                                                        rh);
3310 }
3311
3312
3313 /**
3314  * Lookup of a record in a specific zone
3315  * calls lookup result processor on result
3316  *
3317  * @param zone the root zone
3318  * @param pzone the private local zone
3319  * @param record_type the record type to look up
3320  * @param name the name to look up
3321  * @param key a private key for use with PSEU import (can be NULL)
3322  * @param timeout timeout for resolution
3323  * @param only_cached GNUNET_NO to only check locally not DHT for performance
3324  * @param proc the processor to call on result
3325  * @param cls the closure to pass to proc
3326  */
3327 void
3328 gns_resolver_lookup_record (struct GNUNET_CRYPTO_ShortHashCode zone,
3329                             struct GNUNET_CRYPTO_ShortHashCode pzone,
3330                             uint32_t record_type,
3331                             const char* name,
3332                             struct GNUNET_CRYPTO_EccPrivateKey *key,
3333                             struct GNUNET_TIME_Relative timeout,
3334                             int only_cached,
3335                             RecordLookupProcessor proc,
3336                             void* cls)
3337 {
3338   struct ResolverHandle *rh;
3339   struct RecordLookupHandle* rlh;
3340   char string_hash[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
3341   char nzkey[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
3342   char* nzkey_ptr = nzkey;
3343
3344   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3345               "Starting resolution for `%s' (type=%d) with timeout %s!\n",
3346               name, record_type,
3347               GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_YES));
3348
3349   if ((is_canonical ((char*)name) == GNUNET_YES) &&
3350       (strcmp(GNUNET_GNS_TLD, name) != 0))
3351   {
3352     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3353                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
3354     proc(cls, 0, NULL);
3355     return;
3356   }
3357   
3358   rlh = GNUNET_malloc (sizeof(struct RecordLookupHandle));
3359   rh = GNUNET_malloc (sizeof (struct ResolverHandle));
3360   rh->authority = zone;
3361   rh->id = rid_gen++;
3362   rh->proc_cls = rlh;
3363   rh->priv_key = key;
3364   rh->timeout = timeout;
3365   rh->private_local_zone = pzone;
3366   rh->only_cached = only_cached;
3367
3368   GNUNET_CONTAINER_DLL_insert (rlh_head, rlh_tail, rh);
3369   
3370   if (NULL == key)
3371     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3372                 "No shorten key for resolution\n");
3373
3374   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3375   {
3376     /*
3377      * Set timeout for authority lookup phase to 1/2
3378      */
3379     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3380                 "Timeout for lookup set to %s/2\n", 
3381                 GNUNET_STRINGS_relative_time_to_string (rh->timeout, GNUNET_YES));
3382     rh->timeout_task = GNUNET_SCHEDULER_add_delayed (
3383                                 GNUNET_TIME_relative_divide(timeout, 2),
3384                                                 &handle_lookup_timeout,
3385                                                 rh);
3386     rh->timeout_cont = &dht_authority_lookup_timeout;
3387     rh->timeout_cont_cls = rh;
3388   }
3389   else
3390   {
3391     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
3392     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3393   }
3394   
3395   if (strcmp(GNUNET_GNS_TLD, name) == 0)
3396   {
3397     /**
3398      * Only '.gads' given
3399      */
3400     strcpy (rh->name, "\0");
3401   }
3402   else
3403   {
3404     if (is_zkey_tld(name) == GNUNET_YES)
3405     {
3406       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3407                   "TLD is zkey\n");
3408       /**
3409        * This is a zkey tld
3410        * build hash and use as initial authority
3411        */
3412       memset(rh->name, 0,
3413              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
3414       memcpy(rh->name, name,
3415              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
3416       pop_tld (rh->name, string_hash);
3417
3418       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3419                   "ZKEY is %s!\n", string_hash);
3420       
3421       GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
3422
3423       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
3424                                                       &rh->authority))
3425       {
3426         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3427                     "Cannot convert ZKEY `%s' to hash!\n", string_hash);
3428         
3429         if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
3430           GNUNET_SCHEDULER_cancel (rh->timeout_task);
3431         GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3432         GNUNET_free (rh);
3433         GNUNET_free (rlh);
3434         proc (cls, 0, NULL);
3435         return;
3436       }
3437
3438     }
3439     else if (is_gads_tld (name) == GNUNET_YES)
3440     {
3441       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3442                   "TLD is gads\n");
3443       /**
3444        * Presumably GADS tld
3445        */
3446       memcpy (rh->name, name,
3447               strlen (name) - strlen(GNUNET_GNS_TLD) - 1);
3448       rh->name[strlen (name) - strlen(GNUNET_GNS_TLD) - 1] = '\0';
3449     }
3450     else
3451     {
3452       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3453                   _("Not a GADS TLD: `%s'\n"), 
3454                   name);      
3455       if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
3456         GNUNET_SCHEDULER_cancel (rh->timeout_task);
3457       GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3458       GNUNET_free (rh);
3459       GNUNET_free (rlh);
3460       proc (cls, 0, NULL);
3461       return;
3462     }
3463   }
3464   
3465   /**
3466    * Initialize authority chain
3467    */
3468   rh->authority_chain_head = GNUNET_malloc (sizeof(struct AuthorityChain));
3469   rh->authority_chain_tail = rh->authority_chain_head;
3470   rh->authority_chain_head->zone = rh->authority;
3471   strcpy (rh->authority_chain_head->name, "");
3472   
3473   /**
3474    * Copy original query into lookup handle
3475    */
3476   rlh->record_type = record_type;
3477   memset(rlh->name, 0, strlen(name) + 1);
3478   strcpy(rlh->name, name);
3479   rlh->proc = proc;
3480   rlh->proc_cls = cls;
3481
3482   rh->proc = &handle_delegation_ns;
3483   resolve_delegation_ns (rh);
3484 }
3485
3486 /******** END Record Resolver ***********/
3487
3488 static void
3489 finish_shorten (struct ResolverHandle *rh,
3490                 struct NameShortenHandle *nsh)
3491 {
3492   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3493               "Sending %s as shorten result\n", nsh->result);
3494   nsh->proc (nsh->proc_cls, nsh->result);
3495   GNUNET_CONTAINER_DLL_remove (nsh_head, nsh_tail, rh);
3496   GNUNET_free (nsh);
3497   free_resolver_handle (rh);
3498 }
3499
3500
3501 /**
3502  * Callback calles by namestore for a zone to name
3503  * result
3504  *
3505  * @param cls the closure
3506  * @param zone_key the zone we queried
3507  * @param expire the expiration time of the name
3508  * @param name the name found or NULL
3509  * @param rd_len number of records for the name
3510  * @param rd the record data (PKEY) for the name
3511  * @param signature the signature for the record data
3512  */
3513 static void
3514 process_zone_to_name_shorten_root (void *cls,
3515                  const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
3516                  struct GNUNET_TIME_Absolute expire,
3517                  const char *name,
3518                  unsigned int rd_len,
3519                  const struct GNUNET_NAMESTORE_RecordData *rd,
3520                  const struct GNUNET_CRYPTO_EccSignature *signature);
3521
3522
3523 /**
3524  * Callback called by namestore for a zone to name
3525  * result
3526  *
3527  * @param cls the closure
3528  * @param zone_key the zone we queried
3529  * @param expire the expiration time of the name
3530  * @param name the name found or NULL
3531  * @param rd_len number of records for the name
3532  * @param rd the record data (PKEY) for the name
3533  * @param signature the signature for the record data
3534  */
3535 static void
3536 process_zone_to_name_shorten_shorten (void *cls,
3537                  const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
3538                  struct GNUNET_TIME_Absolute expire,
3539                  const char *name,
3540                  unsigned int rd_len,
3541                  const struct GNUNET_NAMESTORE_RecordData *rd,
3542                  const struct GNUNET_CRYPTO_EccSignature *signature)
3543 {
3544   struct ResolverHandle *rh = cls;
3545   struct NameShortenHandle* nsh = rh->proc_cls;
3546   struct AuthorityChain *next_authority;
3547
3548   char result[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
3549   char tmp_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
3550   size_t answer_len;
3551   
3552   rh->namestore_task = NULL;
3553   /* we found a match in our own root zone */
3554   if (rd_len != 0)
3555   {
3556     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3557     memset(result, 0, answer_len);
3558
3559     if (strlen(rh->name) > 0)
3560     {
3561       sprintf (result, "%s.%s.%s.%s",
3562                rh->name, name,
3563                nsh->shorten_zone_name,
3564                GNUNET_GNS_TLD);
3565     }
3566     else
3567     {
3568       sprintf (result, "%s.%s.%s", name,
3569                nsh->shorten_zone_name,
3570                GNUNET_GNS_TLD);
3571     }
3572     
3573     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3574                "Found shorten result %s\n", result);
3575     if (strlen (nsh->result) > strlen (result))
3576       strcpy (nsh->result, result);
3577   }
3578   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3579                                         nsh->shorten_zone) == 0)
3580   {
3581     /**
3582      * This is our zone append .gads unless name is empty
3583      * (it shouldn't be, usually FIXME what happens if we
3584      * shorten to our zone to a "" record??)
3585      */
3586     
3587     sprintf (result, "%s.%s.%s",
3588              rh->name,
3589              nsh->shorten_zone_name,
3590              GNUNET_GNS_TLD);
3591     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3592                "Our zone: Found %s as shorten result\n", result);
3593     
3594     if (strlen (nsh->result) > strlen (result))
3595       strcpy (nsh->result, result);
3596     //nsh->proc(nsh->proc_cls, result);
3597     //GNUNET_free(nsh);
3598     //free_resolver_handle(rh);
3599     //return;
3600   }
3601   
3602   
3603   /**
3604    * No PSEU found.
3605    * continue with next authority if exists
3606    */
3607   if (NULL == rh->authority_chain_head->next)
3608   {
3609     finish_shorten (rh, nsh);
3610     return;
3611   }
3612   next_authority = rh->authority_chain_head;
3613   
3614   if (0 == strcmp (rh->name, ""))
3615     strcpy (tmp_name, next_authority->name);
3616   else
3617     GNUNET_snprintf(tmp_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH,
3618                     "%s.%s", rh->name, next_authority->name);
3619   
3620   strcpy(rh->name, tmp_name);
3621   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3622              "No PSEU found for authority %s. Promoting back: %s\n",
3623              next_authority->name, rh->name);
3624   
3625   GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3626                             rh->authority_chain_tail,
3627                             next_authority);
3628
3629   GNUNET_free (next_authority);
3630
3631   rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3632                                  &rh->authority_chain_tail->zone,
3633                                  &rh->authority_chain_head->zone,
3634                                  &process_zone_to_name_shorten_root,
3635                                  rh);
3636 }
3637
3638
3639 /**
3640  * Callback calles by namestore for a zone to name
3641  * result
3642  *
3643  * @param cls the closure
3644  * @param zone_key the zone we queried
3645  * @param expire the expiration time of the name
3646  * @param name the name found or NULL
3647  * @param rd_len number of records for the name
3648  * @param rd the record data (PKEY) for the name
3649  * @param signature the signature for the record data
3650  */
3651 static void
3652 process_zone_to_name_shorten_private (void *cls,
3653                  const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
3654                  struct GNUNET_TIME_Absolute expire,
3655                  const char *name,
3656                  unsigned int rd_len,
3657                  const struct GNUNET_NAMESTORE_RecordData *rd,
3658                  const struct GNUNET_CRYPTO_EccSignature *signature)
3659 {
3660   struct ResolverHandle *rh = cls;
3661   struct NameShortenHandle* nsh = rh->proc_cls;
3662   struct AuthorityChain *next_authority;
3663
3664   char result[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
3665   char tmp_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
3666   size_t answer_len;
3667   
3668   rh->namestore_task = NULL;
3669   /* we found a match in our own root zone */
3670   if (rd_len != 0)
3671   {
3672     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3673     memset(result, 0, answer_len);
3674
3675     if (strlen(rh->name) > 0)
3676     {
3677       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3678     }
3679     else
3680     {
3681       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3682     }
3683     
3684     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3685                "Found shorten result %s\n", result);
3686     if (strlen (nsh->result) > strlen (result))
3687       strcpy (nsh->result, result);
3688   }
3689   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3690                                         nsh->private_zone) == 0)
3691   {
3692     /**
3693      * This is our zone append .gads unless name is empty
3694      * (it shouldn't be, usually FIXME what happens if we
3695      * shorten to our zone to a "" record??)
3696      */
3697     
3698     sprintf (result, "%s.%s.%s",
3699              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3700     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3701                "Our private zone: Found %s as shorten result %s\n", result);
3702     if (strlen (nsh->result) > strlen (result))
3703       strcpy (nsh->result, result);
3704   }
3705   
3706   if (0 != strcmp (nsh->shorten_zone_name, ""))
3707   {
3708     /* backtrack authorities for names in priv zone */
3709     rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3710                                    nsh->shorten_zone,
3711                                    &rh->authority_chain_head->zone,
3712                                    &process_zone_to_name_shorten_shorten,
3713                                    rh);
3714   }
3715   else
3716   {
3717     /**
3718      * No PSEU found.
3719      * continue with next authority if exists
3720      */
3721     if (NULL == rh->authority_chain_head->next)
3722     {
3723       finish_shorten (rh, nsh);
3724       return;
3725     }
3726     next_authority = rh->authority_chain_head;
3727     
3728     if (0 == strcmp (rh->name, ""))
3729       strcpy (tmp_name, next_authority->name);
3730     else
3731       GNUNET_snprintf(tmp_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH,
3732                       "%s.%s", rh->name, next_authority->name);
3733     
3734     strcpy(rh->name, tmp_name);
3735     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3736                "No PSEU found for authority %s. Promoting back: %s\n",
3737                next_authority->name, rh->name);
3738     
3739     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3740                               rh->authority_chain_tail,
3741                               next_authority);
3742
3743     GNUNET_free (next_authority);
3744
3745     rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3746                                    &rh->authority_chain_tail->zone,
3747                                    &rh->authority_chain_head->zone,
3748                                    &process_zone_to_name_shorten_root,
3749                                    rh);
3750   }
3751 }
3752
3753
3754 /**
3755  * Callback calles by namestore for a zone to name
3756  * result
3757  *
3758  * @param cls the closure
3759  * @param zone_key the zone we queried
3760  * @param expire the expiration time of the name
3761  * @param name the name found or NULL
3762  * @param rd_len number of records for the name
3763  * @param rd the record data (PKEY) for the name
3764  * @param signature the signature for the record data
3765  */
3766 static void
3767 process_zone_to_name_shorten_root (void *cls,
3768                  const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
3769                  struct GNUNET_TIME_Absolute expire,
3770                  const char *name,
3771                  unsigned int rd_len,
3772                  const struct GNUNET_NAMESTORE_RecordData *rd,
3773                  const struct GNUNET_CRYPTO_EccSignature *signature)
3774 {
3775   struct ResolverHandle *rh = cls;
3776   struct NameShortenHandle* nsh = rh->proc_cls;
3777   struct AuthorityChain *next_authority;
3778   char result[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
3779   char tmp_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
3780   size_t answer_len;
3781   
3782   rh->namestore_task = NULL;
3783   /* we found a match in our own root zone */
3784   if (rd_len != 0)
3785   {
3786     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3787     memset(result, 0, answer_len);
3788
3789     if (strlen(rh->name) > 0)
3790     {
3791       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3792     }
3793     else
3794     {
3795       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3796     }
3797     
3798     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3799                "Found shorten result %s\n", result);
3800     if (strlen (nsh->result) > strlen (result))
3801       strcpy (nsh->result, result);
3802   }
3803   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3804                                         nsh->root_zone) == 0)
3805   {
3806     /**
3807      * This is our zone append .gads unless name is empty
3808      * (it shouldn't be, usually FIXME what happens if we
3809      * shorten to our zone to a "" record??)
3810      */
3811     
3812     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3813     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3814                "Our zone: Found %s as shorten result\n", result);
3815     if (strlen (nsh->result) > strlen (result))
3816       strcpy (nsh->result, result);
3817   }
3818   
3819   if (NULL != nsh->private_zone)
3820   {
3821     /* backtrack authorities for names in priv zone */
3822     rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3823                                    nsh->private_zone,
3824                                    &rh->authority_chain_head->zone,
3825                                    &process_zone_to_name_shorten_private,
3826                                    rh);
3827   }
3828   else if (NULL != nsh->shorten_zone)
3829   {
3830     /* backtrack authorities for names in shorten zone */
3831     rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3832                                           nsh->shorten_zone,
3833                                           &rh->authority_chain_head->zone,
3834                                           &process_zone_to_name_shorten_shorten,
3835                                           rh);
3836   }
3837   else
3838   {
3839     /**
3840      * No PSEU found.
3841      * continue with next authority if exists
3842      */
3843     if (NULL == rh->authority_chain_head->next)
3844     {
3845       finish_shorten (rh, nsh);
3846       return;
3847     }
3848     next_authority = rh->authority_chain_head;
3849     
3850     if (0 == strcmp (rh->name, ""))
3851       strcpy (tmp_name, next_authority->name);
3852     else
3853       GNUNET_snprintf(tmp_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH,
3854                       "%s.%s", rh->name, next_authority->name);
3855     
3856     strcpy(rh->name, tmp_name);
3857     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3858                "No PSEU found for authority %s. Promoting back: %s\n",
3859                next_authority->name, rh->name);
3860     
3861     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3862                               rh->authority_chain_tail,
3863                               next_authority);
3864
3865     GNUNET_free (next_authority);
3866
3867     rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3868                                    &rh->authority_chain_tail->zone,
3869                                    &rh->authority_chain_head->zone,
3870                                    &process_zone_to_name_shorten_root,
3871                                    rh);
3872   }
3873 }
3874
3875
3876 /**
3877  * Process result from namestore delegation lookup
3878  * for shorten operation
3879  *
3880  * @param cls the client shorten handle
3881  * @param rh the resolver handle
3882  * @param rd_count number of results (0)
3883  * @param rd data (NULL)
3884  */
3885 static void
3886 handle_delegation_ns_shorten (void* cls,
3887                       struct ResolverHandle *rh,
3888                       uint32_t rd_count,
3889                       const struct GNUNET_NAMESTORE_RecordData *rd)
3890 {
3891   struct NameShortenHandle *nsh;
3892   char result[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
3893
3894   nsh = (struct NameShortenHandle *)cls;
3895   rh->namestore_task = NULL;
3896   /**
3897    * At this point rh->name contains the part of the name
3898    * that we do not have a PKEY in our namestore to resolve.
3899    * The authority chain in the resolver handle is now
3900    * useful to backtrack if needed
3901    */
3902   
3903   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3904              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
3905   memset(result, 0, sizeof (result));
3906
3907   if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3908                                    nsh->root_zone))
3909   {
3910     /**
3911      * This is our zone append .gads unless name is empty
3912      * (it shouldn't be, usually FIXME what happens if we
3913      * shorten to our zone to a "" record??)
3914      */
3915     
3916     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3917     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3918                "Our zone: Found %s as shorten result\n", result);
3919     
3920     if (strlen (nsh->result) > strlen (result))
3921       strcpy (nsh->result, result);
3922
3923   }
3924   else if (NULL != nsh->private_zone)
3925   {
3926     /**
3927      * This is our zone append .gads unless name is empty
3928      * (it shouldn't be, usually FIXME what happens if we
3929      * shorten to our zone to a "" record??)
3930      */
3931     if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3932                                      nsh->private_zone) == 0)
3933     {
3934     
3935       sprintf (result, "%s.%s.%s",
3936                rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3937       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3938                  "Our zone: Found %s as shorten result in private zone %s\n",
3939                  result);
3940     
3941       if (strlen (nsh->result) > strlen (result))
3942         strcpy (nsh->result, result);
3943     }
3944   }
3945   else if (NULL != nsh->shorten_zone)
3946   {
3947     /**
3948      * This is our zone append .gads unless name is empty
3949      * (it shouldn't be, usually FIXME what happens if we
3950      * shorten to our zone to a "" record??)
3951      */
3952     if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3953                                      nsh->shorten_zone) == 0)
3954     {
3955       sprintf (result, "%s.%s.%s",
3956                rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3957       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3958                  "Our zone: Found %s as shorten result in shorten zone\n",
3959                  result);
3960     
3961       if (strlen (nsh->result) > strlen (result))
3962         strcpy (nsh->result, result);
3963     }
3964   }
3965   
3966   
3967   /* backtrack authorities for names */
3968   rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3969                                  nsh->root_zone,
3970                                  &rh->authority_chain_head->zone,
3971                                  &process_zone_to_name_shorten_root,
3972                                  rh);
3973   
3974 }
3975
3976
3977 /**
3978  * Callback calles by namestore for a zone to name
3979  * result
3980  *
3981  * @param cls the closure
3982  * @param zone_key the zone we queried
3983  * @param expire the expiration time of the name
3984  * @param name the name found or NULL
3985  * @param rd_len number of records for the name
3986  * @param rd the record data (PKEY) for the name
3987  * @param signature the signature for the record data
3988  */
3989 static void
3990 process_zone_to_name_zkey(void *cls,
3991                  const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
3992                  struct GNUNET_TIME_Absolute expire,
3993                  const char *name,
3994                  unsigned int rd_len,
3995                  const struct GNUNET_NAMESTORE_RecordData *rd,
3996                  const struct GNUNET_CRYPTO_EccSignature *signature)
3997 {
3998   struct ResolverHandle *rh = cls;
3999   struct NameShortenHandle *nsh = rh->proc_cls;
4000   char new_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
4001
4002   rh->namestore_task = NULL;
4003
4004   /* zkey not in our zone */
4005   if (name == NULL)
4006   {
4007     /**
4008      * In this case we have not given this PKEY a name (yet)
4009      * It is either just not in our zone or not even cached
4010      * Since we do not know at this point we will not try to shorten
4011      * because PKEY import will happen if the user follows the zkey
4012      * link.
4013      */
4014     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4015                "No name found for zkey %s returning verbatim!\n", nsh->result);
4016     /*if (strcmp(rh->name, "") != 0)
4017       GNUNET_snprintf(new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s.%s",
4018                       rh->name, enc, GNUNET_GNS_TLD_ZKEY);
4019     else
4020       GNUNET_snprintf(new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
4021                       enc, GNUNET_GNS_TLD_ZKEY);
4022
4023     strcpy (nsh->result, new_name);*/
4024
4025     finish_shorten (rh, nsh);
4026     return;
4027   }
4028   
4029   if (strcmp(rh->name, "") != 0)
4030     GNUNET_snprintf(new_name, GNUNET_DNSPARSER_MAX_NAME_LENGTH, "%s.%s",
4031                     rh->name, name);
4032   else
4033     strcpy(new_name, name);
4034
4035   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4036              "Continue shorten for %s!\n", new_name);
4037
4038   strcpy(rh->name, new_name);
4039   
4040   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
4041   rh->authority_chain_tail = rh->authority_chain_head;
4042   rh->authority_chain_head->zone = rh->authority;
4043   
4044   
4045   /* Start delegation resolution in our namestore */
4046   resolve_delegation_ns (rh);
4047 }
4048
4049
4050 /**
4051  * Shorten api from resolver
4052  *
4053  * @param zone the root zone to use
4054  * @param pzone the private zone to use
4055  * @param szone the shorten zone to use
4056  * @param name the name to shorten
4057  * @param private_zone_name name of the private zone
4058  * @param shorten_zone_name name of the shorten zone
4059  * @param proc the processor to call with result
4060  * @param proc_cls closure to pass to proc
4061  */
4062 void
4063 gns_resolver_shorten_name (struct GNUNET_CRYPTO_ShortHashCode *zone,
4064                            struct GNUNET_CRYPTO_ShortHashCode *pzone,
4065                            struct GNUNET_CRYPTO_ShortHashCode *szone,
4066                            const char* name,
4067                            const char* private_zone_name,
4068                            const char* shorten_zone_name,
4069                            ShortenResultProcessor proc,
4070                            void* proc_cls)
4071 {
4072   struct ResolverHandle *rh;
4073   struct NameShortenHandle *nsh;
4074   char string_hash[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
4075   struct GNUNET_CRYPTO_ShortHashCode zkey;
4076   char nzkey[GNUNET_DNSPARSER_MAX_LABEL_LENGTH];
4077   char* nzkey_ptr = nzkey;
4078
4079   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4080               "Starting shorten for %s!\n", name);
4081   
4082   if (is_canonical ((char*)name) == GNUNET_YES)
4083   {
4084     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4085                 "%s is canonical. Returning verbatim\n", name);
4086     proc (proc_cls, name);
4087     return;
4088   }
4089
4090   nsh = GNUNET_malloc (sizeof (struct NameShortenHandle));
4091   nsh->proc = proc;
4092   nsh->proc_cls = proc_cls;
4093   nsh->root_zone = zone;
4094   nsh->private_zone = pzone;
4095   nsh->shorten_zone = szone;
4096   strcpy (nsh->private_zone_name, private_zone_name);
4097   strcpy (nsh->shorten_zone_name, shorten_zone_name);
4098   strcpy (nsh->result, name);
4099   
4100   rh = GNUNET_malloc (sizeof (struct ResolverHandle));
4101   rh->authority = *zone;
4102   rh->id = rid_gen++;
4103   rh->proc = &handle_delegation_ns_shorten;
4104   rh->proc_cls = nsh;
4105   rh->private_local_zone = *zone;
4106
4107   GNUNET_CONTAINER_DLL_insert (nsh_head, nsh_tail, rh);
4108   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4109               "Checking for TLD...\n");
4110   if (is_zkey_tld (name) == GNUNET_YES)
4111   {
4112     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4113                 "TLD is zkey\n");
4114     /**
4115      * This is a zkey tld
4116      * build hash and use as initial authority
4117      * FIXME sscanf
4118      */
4119     memset (rh->name, 0,
4120             strlen (name)-strlen (GNUNET_GNS_TLD_ZKEY));
4121     memcpy (rh->name, name,
4122             strlen(name)-strlen (GNUNET_GNS_TLD_ZKEY) - 1);
4123     pop_tld (rh->name, string_hash);
4124
4125     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4126                 "ZKEY is %s!\n", string_hash);
4127     
4128     GNUNET_STRINGS_utf8_toupper (string_hash, &nzkey_ptr);
4129
4130     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string (nzkey,
4131                                                            &zkey))
4132     {
4133       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4134                   "Cannot convert ZKEY %s to hash!\n", nzkey);
4135       GNUNET_CONTAINER_DLL_remove (nsh_head, nsh_tail, rh);
4136       GNUNET_free (rh);
4137       GNUNET_free (nsh);
4138       proc (proc_cls, name);
4139       return;
4140     }
4141     rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
4142                                    zone, //ours
4143                                    &zkey,
4144                                    &process_zone_to_name_zkey,
4145                                    rh);
4146     return;
4147
4148   }
4149   else if (is_gads_tld (name) == GNUNET_YES)
4150   {
4151     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4152                 "TLD is gnunet\n");
4153     /**
4154      * Presumably GNUNET tld
4155      */
4156     memset (rh->name, 0,
4157             strlen (name)-strlen (GNUNET_GNS_TLD));
4158     memcpy (rh->name, name,
4159             strlen (name)-strlen (GNUNET_GNS_TLD) - 1);
4160   }
4161   else
4162   {
4163     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown TLD in %s\n", name);
4164     GNUNET_CONTAINER_DLL_remove (nsh_head, nsh_tail, rh);
4165     GNUNET_free (rh);
4166     GNUNET_free (nsh);
4167     proc (proc_cls, name);
4168     return;
4169   }
4170
4171   rh->authority_chain_head = GNUNET_malloc (sizeof (struct AuthorityChain));
4172   rh->authority_chain_tail = rh->authority_chain_head;
4173   rh->authority_chain_head->zone = *zone;
4174   
4175   /* Start delegation resolution in our namestore */
4176   resolve_delegation_ns (rh);
4177 }
4178
4179 /*********** END NAME SHORTEN ********************/
4180
4181 /**
4182  * Conclude get authority lookup
4183  *
4184  * @param rh resolver handle
4185  * @param nah get authority lookup handle
4186  */
4187 static void
4188 finish_get_auth (struct ResolverHandle *rh,
4189                  struct GetNameAuthorityHandle *nah)
4190 {
4191   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4192              "Got authority result %s\n", nah->result);
4193   
4194   nah->proc (nah->proc_cls, nah->result);
4195   GNUNET_CONTAINER_DLL_remove (nah_head, nah_tail, rh);
4196   GNUNET_free (nah);
4197   free_resolver_handle (rh);
4198 }
4199
4200
4201 /**
4202  * Process result from namestore delegation lookup
4203  * for get authority operation
4204  *
4205  * @param cls the client get auth handle
4206  * @param rh the resolver handle
4207  * @param rd_count number of results (0)
4208  * @param rd data (NULL)
4209  */
4210 static void
4211 handle_delegation_result_ns_get_auth(void* cls,
4212                       struct ResolverHandle *rh,
4213                       uint32_t rd_count,
4214                       const struct GNUNET_NAMESTORE_RecordData *rd)
4215 {
4216   struct GetNameAuthorityHandle* nah = rh->proc_cls;
4217   size_t answer_len;
4218
4219   /**
4220    * At this point rh->name contains the part of the name
4221    * that we do not have a PKEY in our namestore to resolve.
4222    * The authority chain in the resolver handle is now
4223    * useful to backtrack if needed
4224    */
4225   
4226   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4227              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
4228
4229   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4230              "Building response!\n");
4231   if (is_canonical (rh->name) == GNUNET_YES)
4232   {
4233     /**
4234      * We successfully resolved the authority in the ns
4235      * FIXME for our purposes this is fine
4236      * but maybe we want to have an api that also looks
4237      * into the dht (i.e. option in message)
4238      **/
4239     if (strlen(rh->name) > strlen(nah->name))
4240     {
4241       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4242                  "Record name longer than original lookup name... odd!\n");
4243       //FIXME to sth here
4244     }
4245
4246     answer_len = strlen(nah->name) - strlen(rh->name)
4247       + strlen(GNUNET_GNS_TLD) + 1;
4248     memset(nah->result, 0, answer_len);
4249     if (0 != strcmp (rh->name, ""))
4250       strcpy(nah->result, nah->name + strlen(rh->name) + 1);
4251     else
4252       strcpy(nah->result, nah->name);
4253
4254     finish_get_auth (rh, nah);
4255   }
4256   else
4257   {
4258     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4259                "Unable to resolve authority for remaining %s!\n", rh->name);
4260     strcpy(nah->result, "");
4261     finish_get_auth (rh, nah);
4262   }
4263 }
4264
4265
4266 /**
4267  * Tries to resolve the authority for name
4268  * in our namestore
4269  *
4270  * @param zone the root zone to look up for
4271  * @param pzone the private local zone
4272  * @param name the name to lookup up
4273  * @param proc the processor to call when finished
4274  * @param proc_cls the closure to pass to the processor
4275  */
4276 void
4277 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
4278                            struct GNUNET_CRYPTO_ShortHashCode pzone,
4279                            const char* name,
4280                            GetAuthorityResultProcessor proc,
4281                            void* proc_cls)
4282 {
4283   struct ResolverHandle *rh;
4284   struct GetNameAuthorityHandle *nah;
4285
4286   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4287               "Starting authority resolution for %s!\n", name);
4288
4289   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
4290   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
4291   rh->authority = zone;
4292   rh->id = rid_gen++;
4293   rh->private_local_zone = pzone;
4294
4295   GNUNET_CONTAINER_DLL_insert (nah_head, nah_tail, rh);
4296   
4297   if (strcmp(GNUNET_GNS_TLD, name) == 0)
4298   {
4299     strcpy(rh->name, "\0");
4300   }
4301   else
4302   {
4303     memset(rh->name, 0,
4304            strlen(name)-strlen(GNUNET_GNS_TLD));
4305     memcpy(rh->name, name,
4306            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
4307   }
4308
4309   memset(nah->name, 0,
4310          strlen(name)+1);
4311   strcpy(nah->name, name);
4312   
4313   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
4314   rh->authority_chain_tail = rh->authority_chain_head;
4315   rh->authority_chain_head->zone = zone;
4316   rh->proc = &handle_delegation_result_ns_get_auth;
4317   rh->proc_cls = (void*)nah;
4318
4319   nah->proc = proc;
4320   nah->proc_cls = proc_cls;
4321   strcpy (nah->result, "");
4322
4323   /* Start delegation resolution in our namestore */
4324   resolve_delegation_ns(rh);
4325
4326 }
4327
4328 /******** END GET AUTHORITY *************/
4329
4330 /* end of gnunet-service-gns_resolver.c */