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