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