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