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