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