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