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