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