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