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