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