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