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