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