-hope springs eternal
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file gns/gnunet-service-gns_resolver.c
23  * @brief GNUnet GNS resolver logic
24  * @author Martin Schanzenbach
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_transport_service.h"
29 #include "gnunet_dns_service.h"
30 #include "gnunet_dht_service.h"
31 #include "gnunet_namestore_service.h"
32 #include "gnunet_vpn_service.h"
33 #include "gnunet_dns_service.h"
34 #include "gnunet_resolver_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gns_protocol.h"
37 #include "gnunet_gns_service.h"
38 #include "block_gns.h"
39 #include "gns.h"
40 #include "gnunet-service-gns_resolver.h"
41
42 #define DHT_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
43 #define DHT_GNS_REPLICATION_LEVEL 5
44 #define MAX_DNS_LABEL_LENGTH 63
45
46
47 /**
48  * Our handle to the namestore service
49  */
50 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
51
52 /**
53  * Our handle to the vpn service
54  */
55 static struct GNUNET_VPN_Handle *vpn_handle;
56
57 /**
58  * Resolver handle to the dht
59  */
60 static struct GNUNET_DHT_Handle *dht_handle;
61
62 /**
63  * Heap for parallel DHT lookups
64  */
65 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
66
67 /**
68  * Heap for namestore queues
69  */
70 static struct GNUNET_CONTAINER_Heap *ns_task_heap;
71
72 /**
73  * Maximum amount of parallel queries in background
74  */
75 static unsigned long long max_allowed_background_queries;
76
77 /**
78  * Maximum amount of parallel namestore tasks in background
79  */
80 static unsigned long long max_allowed_ns_tasks;
81
82 /**
83  * Wheather or not to ignore pending records
84  */
85 static int ignore_pending_records;
86
87 /**
88  * Our local zone
89  */
90 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
91
92 /**
93  * Background shortening handles
94  */
95 static struct GetPseuAuthorityHandle *gph_head;
96
97 /**
98  * Background shortening handles
99  */
100 static struct GetPseuAuthorityHandle *gph_tail;
101
102 /**
103  * Resolver lookup list
104  */
105 static struct ResolverHandle *rlh_head;
106
107 /**
108  * Resolver lookup list
109  */
110 static struct ResolverHandle *rlh_tail;
111
112 /**
113  * Resolver shorten list
114  */
115 static struct ResolverHandle *nsh_head;
116
117 /**
118  * Resolver shorten list
119  */
120 static struct ResolverHandle *nsh_tail;
121
122 /**
123  * Resolver get auth list
124  */
125 static struct ResolverHandle *nah_head;
126
127 /**
128  * Resolver get auth list
129  */
130 static struct ResolverHandle *nah_tail;
131
132 /**
133  * Global configuration.
134  */
135 static const struct GNUNET_CONFIGURATION_Handle *cfg;
136
137 /**
138  * a resolution identifier pool variable
139  * FIXME overflow?
140  * This is a non critical identifier useful for debugging
141  */
142 static unsigned long long rid = 0;
143
144 /*
145  * Check if name is in srv format (_x._y.xxx)
146  *
147  * @param name
148  * @return GNUNET_YES if true
149  */
150 static int
151 is_srv (char* name)
152 {
153   char* ndup;
154   int ret = GNUNET_YES;
155
156   if (*name != '_')
157     return GNUNET_NO;
158   if (NULL == strstr (name, "._"))
159     return GNUNET_NO;
160
161   ndup = GNUNET_strdup (name);
162   strtok (ndup, ".");
163
164   if (NULL == strtok (NULL, "."))
165     ret = GNUNET_NO;
166
167   if (NULL == strtok (NULL, "."))
168     ret = GNUNET_NO;
169
170   if (NULL != strtok (NULL, "."))
171     ret = GNUNET_NO;
172
173   GNUNET_free (ndup);
174
175   return ret;
176 }
177
178 /**
179  * Determine if this name is canonical (is a legal name in a zone, without delegation);
180  * note that we do not test that the name does not contain illegal characters, we only
181  * test for delegation.  Note that service records (i.e. _foo._srv) are canonical names
182  * even though they consist of multiple labels.
183  *
184  * Examples:
185  * a.b.gads  = not canonical
186  * a         = canonical
187  * _foo._srv = canonical
188  * _f.bar    = not canonical
189  *
190  * @param name the name to test
191  * @return GNUNET_YES if canonical
192  */
193 static int
194 is_canonical (const char* name)
195 {
196   const char *pos;
197   const char *dot;
198
199   if (NULL == strchr (name, '.'))
200     return GNUNET_YES;
201   if ('_' != name[0])
202     return GNUNET_NO;
203   pos = &name[1];
204   while (NULL != (dot = strchr (pos, '.')))    
205     if ('_' != dot[1])
206       return GNUNET_NO;
207     else
208       pos = dot + 1;
209   return GNUNET_YES;
210 }
211
212
213 /**
214  * Callback that shortens authorities
215  *
216  * @param gph the handle containing the name to shorten
217  */
218 static void
219 shorten_authority_chain (struct GetPseuAuthorityHandle *gph);
220
221
222 /**
223  * Continueation for pkey record creation (shorten)
224  *
225  * @param cls a GetPseuAuthorityHandle
226  * @param success unused
227  * @param emsg unused
228  */
229 static void
230 create_pkey_cont (void* cls, int32_t success, const char* emsg)
231 {
232   //FIXME do sth with error
233   struct GetPseuAuthorityHandle* gph = cls;
234
235   gph->namestore_task = NULL;
236   GNUNET_free (gph->auth);
237   GNUNET_CRYPTO_rsa_key_free (gph->key);
238   GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
239   GNUNET_free (gph);
240 }
241
242
243 /**
244  * Namestore calls this function if we have record for this name.
245  * (or with rd_count=0 to indicate no matches)
246  *
247  * @param cls the pending query
248  * @param key the key of the zone we did the lookup
249  * @param expiration expiration date of the namestore entry
250  * @param name the name for which we need an authority
251  * @param rd_count the number of records with 'name'
252  * @param rd the record data
253  * @param signature the signature of the authority for the record data
254  */
255 static void
256 process_pseu_lookup_ns (void* cls,
257                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
258                       struct GNUNET_TIME_Absolute expiration,
259                       const char *name, unsigned int rd_count,
260                       const struct GNUNET_NAMESTORE_RecordData *rd,
261                       const struct GNUNET_CRYPTO_RsaSignature *signature)
262 {
263   struct GetPseuAuthorityHandle* gph = cls;
264   struct GNUNET_NAMESTORE_RecordData new_pkey;
265
266   gph->namestore_task = NULL;
267   if (rd_count > 0)
268   {
269     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
270                "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
271     GNUNET_free (gph->auth);
272     GNUNET_CRYPTO_rsa_key_free (gph->key);
273     GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
274     GNUNET_free (gph);
275     return;
276   }
277
278   /* name is free */
279   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
280             "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->test_name);
281
282   new_pkey.expiration_time = UINT64_MAX;
283   new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode);
284   new_pkey.data = &gph->auth->zone;
285   new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
286   new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
287                  | GNUNET_NAMESTORE_RF_PRIVATE
288                  | GNUNET_NAMESTORE_RF_PENDING;
289   gph->namestore_task = GNUNET_NAMESTORE_record_create (namestore_handle,
290                                   gph->key,
291                                   gph->test_name,
292                                   &new_pkey,
293                                   &create_pkey_cont, //cont
294                                   gph); //cls
295 }
296
297 /**
298  * process result of a dht pseu lookup
299  *
300  * @param gph the handle
301  * @param name the pseu result or NULL
302  */
303 static void
304 process_pseu_result (struct GetPseuAuthorityHandle* gph, char* name)
305 {
306   if (NULL == name)
307   {
308     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
309                 "GNS_AUTO_PSEU: No PSEU, no shorten. Finished.\n");
310     GNUNET_free (gph->auth);
311     GNUNET_CRYPTO_rsa_key_free (gph->key);
312     GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
313     GNUNET_free (gph);
314     return;
315   }
316   
317   memcpy (gph->test_name, name, strlen(name)+1);
318
319   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
320               "GNS_AUTO_PSEU: Checking %s for collision in NS\n",
321               gph->test_name);
322   /**
323    * Check for collision
324    */
325   gph->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
326                                   &gph->our_zone,
327                                   gph->test_name,
328                                   GNUNET_NAMESTORE_TYPE_ANY,
329                                   &process_pseu_lookup_ns,
330                                   gph);
331 }
332
333 /**
334  * Handle timeout for dht request
335  *
336  * @param cls the request handle as closure
337  * @param tc the task context
338  */
339 static void
340 handle_auth_discovery_timeout (void *cls,
341                                const struct GNUNET_SCHEDULER_TaskContext *tc)
342 {
343   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
344
345   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
346               "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
347   GNUNET_DHT_get_stop (gph->get_handle);
348   gph->get_handle = NULL;
349   process_pseu_result (gph, NULL);
350 }
351
352 /**
353  * Function called when we find a PSEU entry in the DHT
354  *
355  * @param cls the request handle
356  * @param exp lifetime
357  * @param key the key the record was stored under
358  * @param get_path get path
359  * @param get_path_length get path length
360  * @param put_path put path
361  * @param put_path_length put path length
362  * @param type the block type
363  * @param size the size of the record
364  * @param data the record data
365  */
366 static void
367 process_auth_discovery_dht_result (void* cls,
368                                    struct GNUNET_TIME_Absolute exp,
369                                    const struct GNUNET_HashCode * key,
370                                    const struct GNUNET_PeerIdentity *get_path,
371                                    unsigned int get_path_length,
372                                    const struct GNUNET_PeerIdentity *put_path,
373                                    unsigned int put_path_length,
374                                    enum GNUNET_BLOCK_Type type,
375                                    size_t size,
376                                    const void *data)
377 {
378   struct GetPseuAuthorityHandle* gph = cls;
379   struct GNSNameRecordBlock *nrb;
380   const char* rd_data = data;
381   char* name;
382   int num_records;
383   size_t rd_size;
384   int i;
385
386   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387               "GNS_GET_AUTH: got dht result (size=%d)\n", size);
388
389   /* stop lookup and timeout task */
390   GNUNET_DHT_get_stop (gph->get_handle);
391   gph->get_handle = NULL;
392   GNUNET_SCHEDULER_cancel (gph->timeout);
393   
394   if (NULL == data)
395   {
396     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
397                 "GNS_GET_AUTH: got dht result null!\n", size);
398     GNUNET_free (gph->auth);
399     GNUNET_CRYPTO_rsa_key_free (gph->key);
400     GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
401     GNUNET_free (gph);
402     return;
403   }
404   
405   nrb = (struct GNSNameRecordBlock*)data;
406   name = (char*)&nrb[1];
407   num_records = ntohl (nrb->rd_count);
408   {
409     struct GNUNET_NAMESTORE_RecordData rd[num_records];
410
411     rd_data += strlen (name) + 1 + sizeof (struct GNSNameRecordBlock);
412     rd_size = size - strlen (name) - 1 - sizeof (struct GNSNameRecordBlock);
413
414     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
415                                                                rd_data,
416                                                                num_records,
417                                                                rd))
418     {
419       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
420                   "GNS_GET_AUTH: Error deserializing data!\n");
421     }
422     else
423     {
424       for (i=0; i < num_records; i++)
425       {
426         if ((strcmp (name, "+") == 0) &&
427             (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
428         {
429           /* found pseu */
430           process_pseu_result (gph, (char*)rd[i].data);
431           return;
432         }
433       }
434     }
435   }
436   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
437               "GNS_GET_AUTH: finished shorten, no results!\n");
438   process_pseu_result (gph, NULL);
439 }
440
441 /**
442  * Process PSEU discovery for shorten via namestore
443  *
444  * @param cls the GetPseuAuthorityHandle
445  * @param key the public key
446  * @param expiration recorddata expiration
447  * @param name the looked up name
448  * @param rd_count number of records in set
449  * @param rd record data
450  * @param signature the signature
451  */
452 static void
453 process_auth_discovery_ns_result (void* cls,
454                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
455                       struct GNUNET_TIME_Absolute expiration,
456                       const char *name,
457                       unsigned int rd_count,
458                       const struct GNUNET_NAMESTORE_RecordData *rd,
459                       const struct GNUNET_CRYPTO_RsaSignature *signature)
460 {
461   struct GetPseuAuthorityHandle* gph = cls;
462   struct GNUNET_CRYPTO_ShortHashCode name_hash;
463   struct GNUNET_HashCode lookup_key;
464   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
465   struct GNUNET_HashCode name_hash_double;
466   struct GNUNET_HashCode zone_hash_double;
467   int i;
468   uint32_t xquery;
469   
470   gph->namestore_task = NULL;
471   /* no pseu found */
472   if (0 == rd_count)
473   {
474     /**
475      * check dht
476      */
477     GNUNET_CRYPTO_short_hash ("+", strlen ("+"), &name_hash);
478     GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
479     GNUNET_CRYPTO_short_hash_double (&gph->auth->zone, &zone_hash_double);
480     GNUNET_CRYPTO_hash_xor (&name_hash_double, &zone_hash_double, &lookup_key);
481     GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
482
483     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484                "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
485                "+", (char*)&lookup_key_string);
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, "+")))
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  * Callback called by namestore for a zone to name
525  * result
526  *
527  * @param cls the closure
528  * @param zone_key the zone we queried
529  * @param expire the expiration time of the name
530  * @param name the name found or NULL
531  * @param rd_len number of records for the name
532  * @param rd the record data (PKEY) for the name
533  * @param signature the signature for the record data
534  */
535 static void
536 process_zone_to_name_discover (void *cls,
537                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
538                  struct GNUNET_TIME_Absolute expire,
539                  const char *name,
540                  unsigned int rd_len,
541                  const struct GNUNET_NAMESTORE_RecordData *rd,
542                  const struct GNUNET_CRYPTO_RsaSignature *signature)
543 {
544   struct GetPseuAuthorityHandle* gph = cls;
545   
546   gph->namestore_task = NULL;
547   if (0 == rd_len)
548   {
549     gph->namestore_task = GNUNET_NAMESTORE_lookup_record (namestore_handle,
550                                     &gph->auth->zone,
551                                     "+",
552                                     GNUNET_GNS_RECORD_PSEU,
553                                     &process_auth_discovery_ns_result,
554                                     gph);
555     return;
556   }
557   /* we found a match in our own zone */
558   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
559              "GNS_AUTO_PSEU: name for zone in our root %s\n", name);
560   GNUNET_free (gph->auth);
561   GNUNET_CRYPTO_rsa_key_free (gph->key);
562   GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, gph);
563   GNUNET_free (gph);
564 }
565
566
567 /**
568  * Callback that shortens authorities
569  *
570  * @param gph the handle to the shorten request
571  */
572 static void
573 shorten_authority_chain (struct GetPseuAuthorityHandle *gph)
574 {
575
576   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
577               "GNS_AUTO_PSEU: New authority %s discovered\n",
578               gph->auth->name);
579
580   gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
581                                  &gph->our_zone,
582                                  &gph->auth->zone,
583                                  &process_zone_to_name_discover,
584                                  gph);
585
586 }
587
588
589 static void
590 start_shorten (struct AuthorityChain *auth,
591                const struct GNUNET_CRYPTO_RsaPrivateKey *key)
592 {
593   struct GetPseuAuthorityHandle *gph;
594   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
595   struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pb_key;
596   
597   GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
598   if (NULL == (pb_key = GNUNET_CRYPTO_rsa_encode_key (key)))
599   {
600     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
601                 "Failed to encode RSA key on shorten\n");
602     return;
603   }
604
605   gph = GNUNET_malloc (sizeof (struct GetPseuAuthorityHandle));
606   gph->key = GNUNET_CRYPTO_rsa_decode_key ((const char*) pb_key, ntohs (pb_key->len));
607
608   if (NULL == gph->key)
609   {
610     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
611                 "Failed to decode RSA key on shorten\n");
612     GNUNET_free (gph);
613     return;
614   }
615   GNUNET_CRYPTO_short_hash (&pkey,
616                         sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
617                         &gph->our_zone);
618   gph->auth = GNUNET_malloc (sizeof (struct AuthorityChain));
619   memcpy (gph->auth, auth, sizeof (struct AuthorityChain));
620   GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
621   shorten_authority_chain (gph);
622 }
623
624 /**
625  * Initialize the resolver
626  *
627  * @param nh the namestore handle
628  * @param dh the dht handle
629  * @param lz the local zone's hash
630  * @param c configuration handle
631  * @param max_bg_queries maximum number of parallel background queries in dht
632  * @param ignore_pending ignore records that still require user confirmation
633  *        on lookup
634  * @return GNUNET_OK on success
635  */
636 int
637 gns_resolver_init (struct GNUNET_NAMESTORE_Handle *nh,
638                    struct GNUNET_DHT_Handle *dh,
639                    struct GNUNET_CRYPTO_ShortHashCode lz,
640                    const struct GNUNET_CONFIGURATION_Handle *c,
641                    unsigned long long max_bg_queries,
642                    int ignore_pending)
643 {
644   if ( (NULL == nh) ||
645        (NULL == dh) )
646     return GNUNET_SYSERR;
647   
648   cfg = c;
649   namestore_handle = nh;
650   dht_handle = dh;
651   local_zone = lz;
652   dht_lookup_heap =
653     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
654   ns_task_heap =
655     GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
656   max_allowed_background_queries = max_bg_queries;
657   max_allowed_ns_tasks = GNUNET_GNS_MAX_NS_TASKS;
658   ignore_pending_records = ignore_pending; 
659   GNUNET_RESOLVER_connect (cfg);
660   return GNUNET_OK;
661 }
662
663
664 /**
665  * Cleanup ns tasks
666  *
667  * @param cls closure to iterator
668  * @param node heap nodes
669  * @param element the namestorebgtask
670  * @param cost heap cost
671  * @return always GNUNET_YES
672  */
673 static int
674 cleanup_pending_ns_tasks (void* cls,
675                           struct GNUNET_CONTAINER_HeapNode *node,
676                           void *element,
677                           GNUNET_CONTAINER_HeapCostType cost)
678 {
679   struct NamestoreBGTask *nbg = element;
680   ResolverCleanupContinuation cont = cls;
681
682   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
683              "GNS_CLEANUP: Terminating ns task\n");
684   GNUNET_NAMESTORE_cancel (nbg->qe);
685
686   GNUNET_CONTAINER_heap_remove_node (node);
687
688   if (0 == GNUNET_CONTAINER_heap_get_size (ns_task_heap))
689     cont ();
690
691   return GNUNET_YES;
692 }
693
694
695 /**
696  * finish lookup
697  *
698  * @param rh resolver handle
699  * @param rlh record lookup handle
700  * @param rd_count number of results
701  * @param rd results
702  */
703 static void
704 finish_lookup (struct ResolverHandle *rh,
705                struct RecordLookupHandle* rlh,
706                unsigned int rd_count,
707                const struct GNUNET_NAMESTORE_RecordData *rd);
708
709
710 /**
711  * Cleanup background lookups FIXME get rid of this?? YES this doesn't do
712  * anything! => find in code and remove all references to the heap
713  *
714  * @param cls closure to iterator
715  * @param node heap nodes
716  * @param element the resolver handle
717  * @param cost heap cost
718  * @return always GNUNET_YES
719  */
720 static int
721 cleanup_pending_background_queries (void* cls,
722                                     struct GNUNET_CONTAINER_HeapNode *node,
723                                     void *element,
724                                     GNUNET_CONTAINER_HeapCostType cost)
725 {
726   struct ResolverHandle *rh = element;
727   ResolverCleanupContinuation cont = cls;
728
729   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
730              "GNS_CLEANUP-%llu: Terminating background lookup for %s\n",
731              rh->id, rh->name);
732   GNUNET_CONTAINER_heap_remove_node (node);
733   if (0 == GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
734   {
735     if (GNUNET_CONTAINER_heap_get_size (ns_task_heap) == 0)
736       cont ();
737     else
738     {
739       GNUNET_CONTAINER_heap_iterate (ns_task_heap,
740                                      &cleanup_pending_ns_tasks,
741                                      cont);
742     }
743   }
744
745
746   return GNUNET_YES;
747 }
748
749
750 /**
751  * Helper function to free resolver handle
752  *
753  * @param rh the handle to free
754  */
755 static void
756 free_resolver_handle (struct ResolverHandle* rh)
757 {
758   struct AuthorityChain *ac;
759   struct AuthorityChain *ac_next;
760
761   if (NULL == rh)
762     return;
763
764   ac = rh->authority_chain_head;
765
766   while (NULL != ac)
767   {
768     ac_next = ac->next;
769     GNUNET_free (ac);
770     ac = ac_next;
771   }
772   
773   if (NULL != rh->get_handle)
774     GNUNET_DHT_get_stop (rh->get_handle);
775
776   if (NULL != rh->dns_raw_packet)
777     GNUNET_free (rh->dns_raw_packet);
778
779   if (NULL != rh->namestore_task)
780     GNUNET_NAMESTORE_cancel (rh->namestore_task);
781   rh->namestore_task = NULL;
782
783   if (GNUNET_SCHEDULER_NO_TASK != rh->dns_read_task)
784     GNUNET_SCHEDULER_cancel (rh->dns_read_task);
785
786   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
787     GNUNET_SCHEDULER_cancel (rh->timeout_task);
788
789   if (NULL != rh->dns_sock)
790     GNUNET_NETWORK_socket_close (rh->dns_sock);
791   if (NULL != rh->dns_resolver_handle)
792     GNUNET_RESOLVER_request_cancel (rh->dns_resolver_handle);
793
794   if (NULL != rh->rd.data)
795     GNUNET_free ((void*)(rh->rd.data));
796   GNUNET_free (rh);
797 }
798
799
800 /**
801  * finish shorten
802  *
803  * @param rh resolver handle
804  * @param nsh name shorten handle
805  */
806 static void
807 finish_shorten (struct ResolverHandle *rh,
808                 struct NameShortenHandle *nsh);
809 /**
810  * finish get auth
811  *
812  * @param rh resolver handle
813  * @param nah get name authority handle
814  */
815 static void
816 finish_get_auth (struct ResolverHandle *rh,
817                  struct GetNameAuthorityHandle* rlh);
818 /**
819  * Shutdown resolver
820  */
821 void
822 gns_resolver_cleanup (ResolverCleanupContinuation cont)
823 {
824   unsigned int s;
825   struct GetPseuAuthorityHandle *tmp;
826
827   
828   tmp = gph_head;
829   for (tmp = gph_head; tmp != NULL; tmp = gph_head)
830   {
831     if (tmp->get_handle != NULL)
832       GNUNET_DHT_get_stop (tmp->get_handle);
833     tmp->get_handle = NULL;
834     if (tmp->timeout != GNUNET_SCHEDULER_NO_TASK)
835       GNUNET_SCHEDULER_cancel (tmp->timeout);
836     tmp->timeout = GNUNET_SCHEDULER_NO_TASK;
837
838     if (NULL != tmp->namestore_task)
839       GNUNET_NAMESTORE_cancel (tmp->namestore_task);
840     tmp->namestore_task = NULL;
841     GNUNET_free (tmp->auth);
842     GNUNET_CRYPTO_rsa_key_free (tmp->key);
843     GNUNET_CONTAINER_DLL_remove (gph_head, gph_tail, tmp);
844     GNUNET_free (tmp);
845   }
846
847   while (NULL != rlh_head)
848   {
849     finish_lookup (rlh_head, rlh_head->proc_cls, 0, NULL);
850   }
851   while (NULL != nsh_head)
852   {
853     finish_shorten (nsh_head, nsh_head->proc_cls);
854   }
855   while (NULL != nah_head)
856   {
857     finish_get_auth (nah_head, nah_head->proc_cls);
858   }
859
860   s = GNUNET_CONTAINER_heap_get_size (dht_lookup_heap);
861   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
862              "GNS_CLEANUP: %d pending background queries to terminate\n", s);
863   if (0 != s)
864     GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
865                                    &cleanup_pending_background_queries,
866                                    cont);
867   else if (0 != GNUNET_CONTAINER_heap_get_size (ns_task_heap))
868   {
869     GNUNET_CONTAINER_heap_iterate (ns_task_heap,
870                                    &cleanup_pending_ns_tasks,
871                                    cont);
872   }
873   else
874     cont ();
875 }
876
877
878
879
880 /**
881  * Callback when record data is put into namestore
882  *
883  * @param cls the closure
884  * @param success GNUNET_OK on success
885  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
886  */
887 void
888 on_namestore_record_put_result (void *cls,
889                                 int32_t success,
890                                 const char *emsg)
891 {
892   struct NamestoreBGTask *nbg = cls;
893
894   GNUNET_CONTAINER_heap_remove_node (nbg->node);
895   GNUNET_free (nbg);
896
897   if (GNUNET_NO == success)
898   {
899     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
900                "GNS_NS: records already in namestore\n");
901     return;
902   }
903   else if (GNUNET_YES == success)
904   {
905     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
906                "GNS_NS: records successfully put in namestore\n");
907     return;
908   }
909
910   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
911              "GNS_NS: Error putting records into namestore: %s\n", emsg);
912 }
913
914
915 static void
916 handle_lookup_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
917 {
918   struct ResolverHandle *rh = cls;
919
920   if (NULL != rh->timeout_cont)
921     rh->timeout_cont (rh->timeout_cont_cls, tc);
922   /* FIXME: does this leak memory? */
923 }
924
925
926 /**
927  * Processor for background lookups in the DHT
928  *
929  * @param cls closure (NULL)
930  * @param rd_count number of records found (not 0)
931  * @param rd record data
932  */
933 static void
934 background_lookup_result_processor (void *cls,
935                                    uint32_t rd_count,
936                                    const struct GNUNET_NAMESTORE_RecordData *rd)
937 {
938   //We could do sth verbose/more useful here but it doesn't make any difference
939   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
940               "GNS_BG: background dht lookup finished. (%d results)\n",
941               rd_count);
942 }
943
944 /**
945  * Handle timeout for DHT requests
946  *
947  * @param cls the request handle as closure
948  * @param tc the task context
949  */
950 static void
951 dht_lookup_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
952 {
953   struct ResolverHandle *rh = cls;
954   struct RecordLookupHandle *rlh = rh->proc_cls;
955   char new_name[MAX_DNS_NAME_LENGTH];
956
957   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
958               "GNS_PHASE_REC-%llu: dht lookup for query %s (%llus)timed out.\n",
959               rh->id, rh->name, rh->timeout.rel_value);
960   /**
961    * Start resolution in bg
962    */
963   GNUNET_snprintf (new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
964                    rh->name, GNUNET_GNS_TLD);
965
966   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
967               "GNS_PHASE_REC-%llu: Starting background lookup for %s type %d\n",
968               rh->id, new_name, rlh->record_type);
969   
970   gns_resolver_lookup_record (rh->authority,
971                               rh->private_local_zone,
972                               rlh->record_type,
973                               new_name,
974                               NULL,
975                               GNUNET_TIME_UNIT_FOREVER_REL,
976                               GNUNET_NO,
977                               &background_lookup_result_processor,
978                               NULL);
979                               
980   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
981
982   GNUNET_DHT_get_stop (rh->get_handle);
983   rh->get_handle = NULL;
984   rh->proc (rh->proc_cls, rh, 0, NULL);
985 }
986
987
988 /**
989  * Function called when we get a result from the dht
990  * for our record query
991  *
992  * @param cls the request handle
993  * @param exp lifetime
994  * @param key the key the record was stored under
995  * @param get_path get path
996  * @param get_path_length get path length
997  * @param put_path put path
998  * @param put_path_length put path length
999  * @param type the block type
1000  * @param size the size of the record
1001  * @param data the record data
1002  */
1003 static void
1004 process_record_result_dht (void* cls,
1005                            struct GNUNET_TIME_Absolute exp,
1006                            const struct GNUNET_HashCode * key,
1007                            const struct GNUNET_PeerIdentity *get_path,
1008                            unsigned int get_path_length,
1009                            const struct GNUNET_PeerIdentity *put_path,
1010                            unsigned int put_path_length,
1011                            enum GNUNET_BLOCK_Type type,
1012                            size_t size, const void *data)
1013 {
1014   struct ResolverHandle *rh;
1015   struct RecordLookupHandle *rlh;
1016   struct GNSNameRecordBlock *nrb;
1017   uint32_t num_records;
1018   char* name = NULL;
1019   char* rd_data = (char*)data;
1020   int i;
1021   int rd_size;
1022
1023   rh = (struct ResolverHandle *)cls;
1024   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1025               "GNS_PHASE_REC-%llu: got dht result (size=%d)\n", rh->id, size);
1026
1027   rlh = (struct RecordLookupHandle *) rh->proc_cls;
1028   nrb = (struct GNSNameRecordBlock*)data;
1029
1030   /* stop lookup and timeout task */
1031   GNUNET_DHT_get_stop (rh->get_handle);
1032   rh->get_handle = NULL;
1033
1034   if (rh->dht_heap_node != NULL)
1035   {
1036     GNUNET_CONTAINER_heap_remove_node (rh->dht_heap_node);
1037     rh->dht_heap_node = NULL;
1038   }
1039
1040   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1041   {
1042     GNUNET_SCHEDULER_cancel (rh->timeout_task);
1043     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1044   }
1045
1046   rh->get_handle = NULL;
1047   name = (char*)&nrb[1];
1048   num_records = ntohl (nrb->rd_count);
1049   {
1050     struct GNUNET_NAMESTORE_RecordData rd[num_records];
1051     struct NamestoreBGTask *ns_heap_root;
1052     struct NamestoreBGTask *namestore_bg_task;
1053
1054     rd_data += strlen (name) + 1 + sizeof (struct GNSNameRecordBlock);
1055     rd_size = size - strlen (name) - 1 - sizeof (struct GNSNameRecordBlock);
1056
1057     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1058                                                                rd_data,
1059                                                                num_records,
1060                                                                rd))
1061     {
1062       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1063                   "GNS_PHASE_REC-%llu: Error deserializing data!\n", rh->id);
1064       rh->proc (rh->proc_cls, rh, 0, NULL);
1065       return;
1066     }
1067
1068     for (i=0; i<num_records; i++)
1069     {
1070       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1071                   "GNS_PHASE_REC-%llu: Got name: %s (wanted %s)\n",
1072                   rh->id, name, rh->name);
1073       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1074                   "GNS_PHASE_REC-%llu: Got type: %d (wanted %d)\n",
1075                   rh->id, rd[i].record_type, rlh->record_type);
1076       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077                   "GNS_PHASE_REC-%llu: Got data length: %d\n",
1078                   rh->id, rd[i].data_size);
1079       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080                   "GNS_PHASE_REC-%llu: Got flag %d\n",
1081                   rh->id, rd[i].flags);
1082
1083       if ((strcmp (name, rh->name) == 0) &&
1084           (rd[i].record_type == rlh->record_type))
1085       {
1086         rh->answered++;
1087       }
1088
1089     }
1090
1091     /**
1092      * FIXME check pubkey against existing key in namestore?
1093      * https://gnunet.org/bugs/view.php?id=2179
1094      */
1095     if (max_allowed_ns_tasks <=
1096         GNUNET_CONTAINER_heap_get_size (ns_task_heap))
1097     {
1098       ns_heap_root = GNUNET_CONTAINER_heap_remove_root (ns_task_heap);
1099       GNUNET_NAMESTORE_cancel (ns_heap_root->qe);
1100
1101       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1102                   "GNS_PHASE_REC-%llu: Replacing oldest background ns task\n",
1103                   rh->id);
1104     }
1105     
1106     /* Save to namestore */
1107     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1108                 "GNS_PHASE_REC-%llu: Caching record for %s\n",
1109                 rh->id, name);
1110     namestore_bg_task = GNUNET_malloc (sizeof (struct NamestoreBGTask));
1111     namestore_bg_task->qe = GNUNET_NAMESTORE_record_put (namestore_handle,
1112                                  &nrb->public_key,
1113                                  name,
1114                                  exp,
1115                                  num_records,
1116                                  rd,
1117                                  &nrb->signature,
1118                                  &on_namestore_record_put_result, //cont
1119                                  namestore_bg_task);
1120
1121     namestore_bg_task->node = GNUNET_CONTAINER_heap_insert (ns_task_heap,
1122                                   namestore_bg_task,
1123                                   GNUNET_TIME_absolute_get().abs_value);
1124
1125   
1126     if (0 < rh->answered)
1127      rh->proc (rh->proc_cls, rh, num_records, rd);
1128    else
1129      rh->proc (rh->proc_cls, rh, 0, NULL);
1130   }
1131
1132 }
1133
1134
1135 /**
1136  * Start DHT lookup for a (name -> query->record_type) record in
1137  * rh->authority's zone
1138  *
1139  * @param rh the pending gns query context
1140  */
1141 static void
1142 resolve_record_dht (struct ResolverHandle *rh)
1143 {
1144   uint32_t xquery;
1145   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1146   struct GNUNET_HashCode lookup_key;
1147   struct GNUNET_HashCode name_hash_double;
1148   struct GNUNET_HashCode zone_hash_double;
1149   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
1150   struct RecordLookupHandle *rlh = rh->proc_cls;
1151   struct ResolverHandle *rh_heap_root;
1152
1153   GNUNET_CRYPTO_short_hash (rh->name, strlen (rh->name), &name_hash);
1154   GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
1155   GNUNET_CRYPTO_short_hash_double (&rh->authority, &zone_hash_double);
1156   GNUNET_CRYPTO_hash_xor (&name_hash_double, &zone_hash_double, &lookup_key);
1157   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
1158
1159   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1160               "GNS_PHASE_REC-%llu: starting dht lookup for %s with key: %s\n",
1161               rh->id, rh->name, (char*)&lookup_key_string);
1162
1163   //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1164   rh->dht_heap_node = NULL;
1165
1166   if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value != rh->timeout.rel_value)
1167   {
1168     /**
1169      * Update timeout if necessary
1170      */
1171     if (GNUNET_SCHEDULER_NO_TASK == rh->timeout_task)
1172     {
1173       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1174                   "GNS_PHASE_REC-%llu: Adjusting timeout\n", rh->id);
1175       /*
1176        * Set timeout for authority lookup phase to 1/2
1177        */
1178       rh->timeout_task = GNUNET_SCHEDULER_add_delayed (
1179                                    GNUNET_TIME_relative_divide (rh->timeout, 2),
1180                                    &handle_lookup_timeout,
1181                                    rh);
1182     }
1183     rh->timeout_cont = &dht_lookup_timeout;
1184     rh->timeout_cont_cls = rh;
1185   }
1186   else 
1187   {
1188     if (max_allowed_background_queries <=
1189         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1190     {
1191       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1192       GNUNET_DHT_get_stop (rh_heap_root->get_handle);
1193       rh_heap_root->get_handle = NULL;
1194       rh_heap_root->dht_heap_node = NULL;
1195
1196       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1197                  "GNS_PHASE_REC-%llu: Replacing oldest background query for %s\n",
1198                  rh->id, rh_heap_root->name);
1199       rh_heap_root->proc (rh_heap_root->proc_cls,
1200                           rh_heap_root,
1201                           0,
1202                           NULL);
1203     }
1204     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1205                                          rh,
1206                                          GNUNET_TIME_absolute_get ().abs_value);
1207   }
1208
1209   xquery = htonl (rlh->record_type);
1210
1211   GNUNET_assert (rh->get_handle == NULL);
1212   rh->get_handle = GNUNET_DHT_get_start (dht_handle, 
1213                                          GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1214                                          &lookup_key,
1215                                          DHT_GNS_REPLICATION_LEVEL,
1216                                          GNUNET_DHT_RO_DEMULTIPLEX_EVERYWHERE,
1217                                          &xquery,
1218                                          sizeof (xquery),
1219                                          &process_record_result_dht,
1220                                          rh);
1221
1222 }
1223
1224
1225 /**
1226  * Namestore calls this function if we have record for this name.
1227  * (or with rd_count=0 to indicate no matches)
1228  *
1229  * @param cls the pending query
1230  * @param key the key of the zone we did the lookup
1231  * @param expiration expiration date of the namestore entry
1232  * @param name the name for which we need an authority
1233  * @param rd_count the number of records with 'name'
1234  * @param rd the record data
1235  * @param signature the signature of the authority for the record data
1236  */
1237 static void
1238 process_record_result_ns (void* cls,
1239                           const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1240                           struct GNUNET_TIME_Absolute expiration,
1241                           const char *name, unsigned int rd_count,
1242                           const struct GNUNET_NAMESTORE_RecordData *rd,
1243                           const struct GNUNET_CRYPTO_RsaSignature *signature)
1244 {
1245   struct ResolverHandle *rh;
1246   struct RecordLookupHandle *rlh;
1247   struct GNUNET_TIME_Relative remaining_time;
1248   struct GNUNET_CRYPTO_ShortHashCode zone;
1249   struct GNUNET_TIME_Absolute et;
1250   unsigned int i;
1251
1252   rh = cls;
1253   rlh = rh->proc_cls;
1254
1255   rh->namestore_task = NULL;
1256   GNUNET_CRYPTO_short_hash (key,
1257                         sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1258                         &zone);
1259   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1260
1261
1262
1263   rh->status = 0;
1264
1265   if (NULL != name)
1266   {
1267     rh->status |= RSL_RECORD_EXISTS;
1268
1269     if (remaining_time.rel_value == 0)
1270     {
1271       rh->status |= RSL_RECORD_EXPIRED;
1272     }
1273   }
1274
1275   if (rd_count == 0)
1276   {
1277     /**
1278      * Lookup terminated and no results
1279      */
1280     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1281                "GNS_PHASE_REC-%llu: Namestore lookup for %s terminated without results\n",
1282                rh->id, name);
1283
1284     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1285                "GNS_PHASE_REC-%llu: Record %s unknown in namestore\n",
1286                rh->id, rh->name);
1287     /**
1288      * Our zone and no result? Cannot resolve TT
1289      */
1290     rh->proc(rh->proc_cls, rh, 0, NULL);
1291     return;
1292
1293   }
1294   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1295              "GNS_PHASE_REC-%llu: Processing additional result %s from namestore\n",
1296              rh->id, name);
1297   for (i=0; i<rd_count;i++)
1298   {
1299     if (rd[i].record_type != rlh->record_type)
1300       continue;
1301
1302     if (ignore_pending_records &&
1303         (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
1304     {
1305       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1306                  "GNS_PHASE_REC-%llu: Record %s is awaiting user confirmation. Skipping\n",
1307                  rh->id, name);
1308       continue;
1309     }
1310     
1311     //FIXME: eh? do I have to handle this here?
1312     GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
1313     et.abs_value = rd[i].expiration_time;
1314     if (0 == (GNUNET_TIME_absolute_get_remaining (et)).rel_value)
1315     {
1316       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1317                  "GNS_PHASE_REC-%llu: This record is expired. Skipping\n",
1318                  rh->id);
1319       continue;
1320     }
1321     rh->answered++;
1322   }
1323
1324   /**
1325    * no answers found
1326    */
1327   if (0 == rh->answered)
1328   {
1329     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
1330                "GNS_PHASE_REC-%llu: No answers found. This is odd!\n", rh->id);
1331     rh->proc(rh->proc_cls, rh, 0, NULL);
1332     return;
1333   }
1334
1335   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1336              "GNS_PHASE_REC-%llu: Found %d answer(s) to query in %d records!\n",
1337              rh->id, rh->answered, rd_count);
1338   rh->proc(rh->proc_cls, rh, rd_count, rd);
1339 }
1340
1341
1342 /**
1343  * VPN redirect result callback
1344  *
1345  * @param cls the resolver handle
1346  * @param af the requested address family
1347  * @param address in_addr(6) respectively
1348  */
1349 static void
1350 process_record_result_vpn (void* cls, int af, const void *address)
1351 {
1352   struct ResolverHandle *rh = cls;
1353   struct RecordLookupHandle *rlh;
1354   struct GNUNET_NAMESTORE_RecordData rd;
1355
1356   rlh = rh->proc_cls;
1357
1358   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1359              "GNS_PHASE_REC_VPN-%llu: Got answer from VPN to query!\n",
1360              rh->id);
1361   if (AF_INET == af)
1362   {
1363     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1364                "GNS_PHASE_REC-%llu: Answer is IPv4!\n",
1365                rh->id);
1366     if (GNUNET_GNS_RECORD_A != rlh->record_type)
1367     {
1368       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1369                  "GNS_PHASE_REC-%llu: Requested record is not IPv4!\n",
1370                  rh->id);
1371       rh->proc (rh->proc_cls, rh, 0, NULL);
1372       return;
1373     }
1374     rd.record_type = GNUNET_GNS_RECORD_A;
1375     rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1376     rd.data = address;
1377     rd.data_size = sizeof (struct in_addr);
1378     rd.flags = 0;
1379     rh->proc (rh->proc_cls, rh, 1, &rd);
1380     return;
1381   }
1382   else if (AF_INET6 == af)
1383   {
1384     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1385                "GNS_PHASE_REC-%llu: Answer is IPv6!\n",
1386                rh->id);
1387     if (GNUNET_GNS_RECORD_AAAA != rlh->record_type)
1388     {
1389       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1390                  "GNS_PHASE_REC-%llu: Requested record is not IPv6!\n",
1391                  rh->id);
1392       rh->proc (rh->proc_cls, rh, 0, NULL);
1393       return;
1394     }
1395     rd.record_type = GNUNET_GNS_RECORD_AAAA;
1396     rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter... */
1397     rd.data = address;
1398     rd.data_size = sizeof (struct in6_addr);
1399     rd.flags = 0;
1400     rh->proc (rh->proc_cls, rh, 1, &rd);
1401     return;
1402   }
1403
1404   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1405              "GNS_PHASE_REC-%llu: Got garbage from VPN!\n",
1406              rh->id);
1407   rh->proc (rh->proc_cls, rh, 0, NULL);
1408 }
1409
1410
1411
1412
1413 /**
1414  * Process VPN lookup result for record
1415  *
1416  * @param cls the record lookup handle
1417  * @param rh resolver handle
1418  * @param rd_count number of results (1)
1419  * @param rd record data containing the result
1420  */
1421 static void
1422 handle_record_vpn (void* cls, struct ResolverHandle *rh,
1423                    unsigned int rd_count,
1424                    const struct GNUNET_NAMESTORE_RecordData *rd)
1425 {
1426   struct RecordLookupHandle* rlh = cls;
1427   
1428   if (0 == rd_count)
1429   {
1430     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1431                "GNS_PHASE_REC_VPN-%llu: VPN returned no records. (status: %d)!\n",
1432                rh->id,
1433                rh->status);
1434     /* give up, cannot resolve */
1435     finish_lookup(rh, rlh, 0, NULL);
1436     return;
1437   }
1438
1439   /* results found yay */
1440   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1441              "GNS_PHASE_REC_VPN-%llu: Record resolved from VPN!", rh->id);
1442
1443   finish_lookup(rh, rlh, rd_count, rd);
1444 }
1445
1446
1447 /**
1448  * Sends a UDP dns query to a nameserver specified in the rh
1449  * 
1450  * @param rh the resolver handle
1451  */
1452 static void
1453 send_dns_packet (struct ResolverHandle *rh);
1454
1455
1456 static void
1457 handle_dns_resolver (void *cls,
1458                      const struct sockaddr *addr,
1459                      socklen_t addrlen)
1460 {
1461   struct ResolverHandle *rh = cls;
1462   struct RecordLookupHandle *rlh = rh->proc_cls;
1463   struct GNUNET_NAMESTORE_RecordData rd;
1464   struct sockaddr_in *sai;
1465   struct sockaddr_in6 *sai6;
1466
1467   if (NULL == addr)
1468   {
1469     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1470                 "No address found in DNS!\n");
1471     finish_lookup (rh, rlh, 0, NULL);
1472     return;
1473   }
1474   
1475   if (sizeof (struct sockaddr_in) == addrlen)
1476   {
1477     sai = (struct sockaddr_in*) addr;
1478     rd.record_type = GNUNET_GNS_RECORD_A;
1479     rd.data_size = sizeof (struct in_addr);
1480     rd.data = &sai->sin_addr;
1481   }
1482   else if (sizeof (struct sockaddr_in6) == addrlen)
1483   {
1484     sai6 = (struct sockaddr_in6*) addr;
1485     rd.record_type = GNUNET_GNS_RECORD_AAAA;
1486     rd.data_size = sizeof (struct in6_addr);
1487     rd.data = &sai6->sin6_addr;
1488   }
1489   else
1490   {
1491     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1492                 "Address length is garbage!\n");
1493     finish_lookup (rh, rlh, 0, NULL);
1494     return;
1495   }
1496   rd.expiration_time = UINT64_MAX; /* FIXME: should probably pick something shorter */
1497   rd.flags = 0;
1498   finish_lookup (rh, rlh, 1, &rd);
1499 }
1500
1501 /**
1502  * Resolve DNS name via local stub resolver
1503  *
1504  * @param rh the resolver handle
1505  */
1506 static void
1507 resolve_dns_name (struct ResolverHandle *rh)
1508 {
1509   struct RecordLookupHandle *rlh = rh->proc_cls;
1510   int af;
1511
1512   if ((GNUNET_GNS_RECORD_A != rlh->record_type) &&
1513       (GNUNET_GNS_RECORD_AAAA != rlh->record_type))
1514   {
1515     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1516                 "Can only resolve A/AAAA via stub... abort\n");
1517     finish_lookup (rh, rlh, 0, NULL);
1518     return;
1519   }
1520
1521   if (GNUNET_GNS_RECORD_A == rlh->record_type)
1522     af = AF_INET;
1523   else
1524     af = AF_INET6;
1525
1526   rh->dns_resolver_handle = GNUNET_RESOLVER_ip_get (rh->dns_name,
1527                                                     af,
1528                                                     rh->timeout,
1529                                                     &handle_dns_resolver,
1530                                                     rh);
1531 }
1532
1533
1534 /**
1535  * Read DNS udp packet from socket
1536  *
1537  * @param cls the resolver handle
1538  * @param tc task context
1539  */
1540 static void
1541 read_dns_response (void *cls,
1542                    const struct GNUNET_SCHEDULER_TaskContext *tc)
1543 {
1544   struct ResolverHandle *rh = cls;
1545   struct RecordLookupHandle *rlh = rh->proc_cls;
1546   char buf[UINT16_MAX];
1547   ssize_t r;
1548   struct sockaddr_in addr;
1549   socklen_t addrlen;
1550   struct GNUNET_DNSPARSER_Packet *packet;
1551   struct GNUNET_NAMESTORE_RecordData rd;
1552   int found_delegation = GNUNET_NO;
1553   int found_cname = GNUNET_NO;
1554   char* delegation_name = NULL;
1555   int zone_offset = 0;
1556   int i;
1557
1558   rh->dns_read_task = GNUNET_SCHEDULER_NO_TASK;
1559   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1560   {
1561     /* timeout or shutdown */
1562     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1563                 "Terminating DNS query %d\n", tc->reason);
1564     finish_lookup (rh, rlh, 0, NULL);
1565     return;
1566   }
1567
1568   addrlen = sizeof (addr);
1569   r = GNUNET_NETWORK_socket_recvfrom (rh->dns_sock,
1570                                       buf, sizeof (buf),
1571                                       (struct sockaddr*) &addr,
1572                                       &addrlen);
1573
1574   if (-1 == r)
1575   {
1576     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
1577     finish_lookup (rh, rlh, 0, NULL);
1578     return;
1579   }
1580
1581   packet = GNUNET_DNSPARSER_parse (buf, r);
1582   
1583   if (NULL == packet)
1584   {
1585     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1586                 "Failed to parse DNS reply!\n");
1587     finish_lookup (rh, rlh, 0, NULL);
1588     return;
1589   }
1590
1591   for (i = 0; i < packet->num_answers; i++)
1592   {
1593     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1594                "Got record type %d (want %d)\n",
1595                packet->answers[i].type,
1596                rlh->record_type);
1597     /* http://tools.ietf.org/html/rfc1034#section-3.6.2 */
1598     if (packet->answers[i].type == GNUNET_GNS_RECORD_CNAME)
1599     {
1600       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1601                   "CNAME... restarting query with %s\n",
1602                   packet->answers[i].data.hostname
1603                  );
1604       strcpy (rh->dns_name, packet->answers[i].data.hostname);
1605       found_cname = GNUNET_YES;
1606       continue;
1607     }
1608     
1609     if ((packet->answers[i].type == rlh->record_type) &&
1610         (0 == strcmp (packet->answers[i].name, rh->dns_name)))
1611     {
1612       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1613                   "Found record!\n");
1614       rd.data = packet->answers[i].data.raw.data;
1615       rd.data_size = packet->answers[i].data.raw.data_len;
1616       rd.record_type = packet->answers[i].type;
1617       rd.flags = 0;
1618       rd.expiration_time = packet->answers[i].expiration_time.abs_value;
1619       finish_lookup (rh, rlh, 1, &rd);
1620       GNUNET_DNSPARSER_free_packet (packet);
1621       return;
1622     }
1623   }
1624
1625   if (GNUNET_YES == found_cname)
1626   {
1627     zone_offset = strlen (rh->dns_name) - strlen (rh->dns_zone) - 1;
1628     
1629     if (0 > zone_offset)
1630       zone_offset = 0;
1631
1632     /* restart query with CNAME */
1633     if (0 == strcmp (rh->dns_name+zone_offset, rh->dns_zone))
1634     {
1635       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1636                   "Asking same server for %s\n", rh->dns_name);
1637       send_dns_packet (rh);
1638     }
1639     else
1640     {
1641       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1642                   "Trying system resolver for %s\n", rh->dns_name);
1643       resolve_dns_name (rh);
1644     }
1645
1646     GNUNET_DNSPARSER_free_packet (packet);
1647     return;
1648   }
1649
1650   for (i = 0; i < packet->num_authority_records; i++)
1651   {
1652     
1653     if (packet->authority_records[i].type == GNUNET_GNS_RECORD_NS)
1654     {
1655       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1656                   "Found NS delegation!\n");
1657       found_delegation = GNUNET_YES;
1658       delegation_name = packet->authority_records[i].data.hostname;
1659       break;
1660     }
1661   }
1662
1663   for (i = 0; i < packet->num_additional_records; i++)
1664   {
1665     if (GNUNET_NO == found_delegation)
1666       break;
1667
1668     if ((packet->additional_records[i].type == GNUNET_GNS_RECORD_A) &&
1669         (0 == strcmp (packet->additional_records[i].name, delegation_name)))
1670     {
1671       GNUNET_assert (sizeof (struct in_addr) ==
1672                      packet->authority_records[i].data.raw.data_len);
1673       
1674       rh->dns_addr.sin_addr =
1675         *((struct in_addr*)packet->authority_records[i].data.raw.data);
1676       send_dns_packet (rh);
1677       GNUNET_DNSPARSER_free_packet (packet);
1678       return;
1679     }
1680   }
1681
1682   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1683               "Nothing useful in DNS reply!\n");
1684   finish_lookup (rh, rlh, 0, NULL);
1685   GNUNET_DNSPARSER_free_packet (packet);
1686   return;
1687 }
1688
1689 /**
1690  * Sends a UDP dns query to a nameserver specified in the rh
1691  * 
1692  * @param rh the request handle
1693  */
1694 static void
1695 send_dns_packet (struct ResolverHandle *rh)
1696 {
1697   struct GNUNET_NETWORK_FDSet *rset = GNUNET_NETWORK_fdset_create ();
1698   GNUNET_NETWORK_fdset_set (rset, rh->dns_sock);
1699
1700   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1701               "Sending %dbyte DNS query\n",
1702               rh->dns_raw_packet_size);
1703   
1704   if (GNUNET_SYSERR ==
1705       GNUNET_NETWORK_socket_sendto (rh->dns_sock,
1706                                     rh->dns_raw_packet,
1707                                     rh->dns_raw_packet_size,
1708                                     (struct sockaddr*)&rh->dns_addr,
1709                                     sizeof (struct sockaddr_in)))
1710     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1711                 _("Failed to send DNS request to %s\n"),
1712                 GNUNET_a2s ((const struct sockaddr *)&rh->dns_addr, 
1713                             sizeof (struct sockaddr_in)));
1714
1715   rh->dns_read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1716                                                     rh->timeout, //FIXME less?
1717                                                     rset,
1718                                                     NULL,
1719                                                     &read_dns_response,
1720                                                     rh);
1721
1722   GNUNET_NETWORK_fdset_destroy (rset);
1723
1724 }
1725
1726 /**
1727  * The final phase of resoution.
1728  * We found a NS RR and want to resolve via DNS
1729  *
1730  * @param rh the pending lookup handle
1731  * @param rd_count length of record data
1732  * @param rd record data containing VPN RR
1733  */
1734 static void
1735 resolve_record_dns (struct ResolverHandle *rh,
1736                     int rd_count,
1737                     const struct GNUNET_NAMESTORE_RecordData *rd)
1738 {
1739   struct GNUNET_DNSPARSER_Query query;
1740   struct GNUNET_DNSPARSER_Packet packet;
1741   struct GNUNET_DNSPARSER_Flags flags;
1742   struct in_addr dnsip;
1743   struct sockaddr_in addr;
1744   struct sockaddr *sa;
1745   int i;
1746   struct RecordLookupHandle *rlh = rh->proc_cls;
1747
1748   memset (&packet, 0, sizeof (struct GNUNET_DNSPARSER_Packet));
1749   memset (rh->dns_name, 0, sizeof (rh->dns_name));
1750   
1751   /* We cancel here as to not include the ns lookup in the timeout */
1752   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1753   {
1754     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1755     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1756   }
1757   /* Start shortening */
1758   if ((NULL != rh->priv_key) &&
1759       (GNUNET_YES == is_canonical (rh->name)))
1760   {
1761     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1762              "GNS_PHASE_REC_DNS-%llu: Trying to shorten authority chain\n",
1763              rh->id);
1764     start_shorten (rh->authority_chain_head,
1765                    rh->priv_key);
1766   }
1767
1768   for (i = 0; i < rd_count; i++)
1769   {
1770     /* Synthesize dns name */
1771     if (GNUNET_GNS_RECORD_NS == rd[i].record_type)
1772     {
1773       strcpy (rh->dns_zone, (char*)rd[i].data);
1774       if (0 == strcmp (rh->name, ""))
1775         strcpy (rh->dns_name, (char*)rd[i].data);
1776       else
1777         sprintf (rh->dns_name, "%s.%s", rh->name, (char*)rd[i].data);
1778     }
1779     /* The glue */
1780     if (GNUNET_GNS_RECORD_A == rd[i].record_type)
1781          /* need to use memcpy as .data may be unaligned */
1782         memcpy (&dnsip, rd[i].data, sizeof (dnsip));
1783   }
1784   
1785   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1786               "GNS_PHASE_REC_DNS-%llu: Looking up %s from %s\n",
1787               rh->id,
1788               rh->dns_name,
1789               inet_ntoa (dnsip));
1790   rh->dns_sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
1791   if (NULL == rh->dns_sock)
1792   {
1793     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1794                 "GNS_PHASE_REC_DNS-%llu: Error creating udp socket for dns!\n",
1795                 rh->id);
1796     finish_lookup (rh, rlh, 0, NULL);
1797     return;
1798   }
1799
1800   memset (&addr, 0, sizeof (struct sockaddr_in));
1801   sa = (struct sockaddr *) &addr;
1802   sa->sa_family = AF_INET;
1803   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (rh->dns_sock,
1804                                                sa,
1805                                                sizeof (struct sockaddr_in)))
1806   {
1807     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1808                 "GNS_PHASE_REC_DNS-%llu: Error binding udp socket for dns!\n",
1809                 rh->id);
1810     finish_lookup (rh, rlh, 0, NULL);
1811     return;
1812   }
1813   query.name = rh->dns_name;
1814   query.type = rlh->record_type;
1815   query.class = GNUNET_DNSPARSER_CLASS_INTERNET;
1816   memset (&flags, 0, sizeof (flags));
1817   flags.recursion_desired = 1;
1818   flags.checking_disabled = 1;
1819   packet.queries = &query;
1820   packet.answers = NULL;
1821   packet.authority_records = NULL;
1822   packet.num_queries = 1;
1823   packet.num_answers = 0;
1824   packet.num_authority_records = 0;
1825   packet.num_additional_records = 0;
1826   packet.flags = flags;
1827   packet.id = rh->id;
1828   if (GNUNET_OK != GNUNET_DNSPARSER_pack (&packet,
1829                                           UINT16_MAX,
1830                                           &rh->dns_raw_packet,
1831                                           &rh->dns_raw_packet_size))
1832   {
1833     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1834                 "GNS_PHASE_REC_DNS-%llu: Creating raw dns packet!\n",
1835                 rh->id);
1836     GNUNET_NETWORK_socket_close (rh->dns_sock);
1837     finish_lookup (rh, rlh, 0, NULL);
1838     return;
1839   }
1840
1841   rh->dns_addr.sin_family = AF_INET;
1842   rh->dns_addr.sin_port = htons (53); //domain
1843   rh->dns_addr.sin_addr = dnsip;
1844 #if HAVE_SOCKADDR_IN_SIN_LEN
1845   rh->dns_addr.sin_len = (u_char) sizeof (struct sockaddr_in);
1846 #endif
1847
1848   send_dns_packet (rh);
1849 }
1850
1851
1852 /**
1853  * The final phase of resoution.
1854  * We found a VPN RR and want to request an IPv4/6 address
1855  *
1856  * @param rh the pending lookup handle
1857  * @param rd_count length of record data
1858  * @param rd record data containing VPN RR
1859  */
1860 static void
1861 resolve_record_vpn (struct ResolverHandle *rh,
1862                     int rd_count,
1863                     const struct GNUNET_NAMESTORE_RecordData *rd)
1864 {
1865   struct RecordLookupHandle *rlh = rh->proc_cls;
1866   struct GNUNET_HashCode serv_desc;
1867   struct vpn_data* vpn;
1868   int af;
1869   
1870   /* We cancel here as to not include the ns lookup in the timeout */
1871   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1872   {
1873     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1874     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1875   }
1876   /* Start shortening */
1877   if ((NULL != rh->priv_key) &&
1878       (GNUNET_YES == is_canonical (rh->name)))
1879   {
1880     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1881              "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1882              rh->id);
1883     start_shorten (rh->authority_chain_head,
1884                    rh->priv_key);
1885   }
1886
1887   vpn = (struct vpn_data*)rd->data;
1888
1889
1890   GNUNET_CRYPTO_hash ((char*)&vpn[1],
1891                       strlen ((char*)&vpn[1]) + 1,
1892                       &serv_desc);
1893   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1894               "GNS_PHASE_REC_VPN-%llu: proto %hu peer %s!\n",
1895               rh->id,
1896               ntohs (vpn->proto),
1897               GNUNET_h2s (&vpn->peer));
1898
1899   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1900               "GNS_PHASE_REC_VPN-%llu: service %s -> %s!\n",
1901               rh->id,
1902               (char*)&vpn[1],
1903               GNUNET_h2s (&serv_desc));
1904   rh->proc = &handle_record_vpn;
1905   if (GNUNET_GNS_RECORD_A == rlh->record_type)
1906     af = AF_INET;
1907   else
1908     af = AF_INET6;
1909   if (NULL == vpn_handle)
1910   {
1911     vpn_handle = GNUNET_VPN_connect (cfg);
1912     if (NULL == vpn_handle)
1913     {
1914       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1915                   "GNS_PHASE_INIT: Error connecting to VPN!\n");
1916       finish_lookup (rh, rh->proc_cls, 0, NULL);
1917       return;
1918     }
1919   }
1920
1921   rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1922                                                 af, ntohs (vpn->proto),
1923                                                 (struct GNUNET_PeerIdentity *)&vpn->peer,
1924                                                 &serv_desc,
1925                                                 GNUNET_NO, //nac
1926                                                 GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1927                                                 &process_record_result_vpn,
1928                                                 rh);
1929
1930 }
1931
1932 /**
1933  * The final phase of resolution.
1934  * rh->name is a name that is canonical and we do not have a delegation.
1935  * Query namestore for this record
1936  *
1937  * @param rh the pending lookup handle
1938  */
1939 static void
1940 resolve_record_ns(struct ResolverHandle *rh)
1941 {
1942   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
1943   
1944   /* We cancel here as to not include the ns lookup in the timeout */
1945   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
1946   {
1947     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1948     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1949   }
1950   /* Start shortening */
1951   if ((NULL != rh->priv_key) &&
1952      (GNUNET_YES == is_canonical (rh->name)))
1953   {
1954     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1955              "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1956              rh->id);
1957     start_shorten (rh->authority_chain_head,
1958                    rh->priv_key);
1959   }
1960   
1961   /**
1962    * Try to resolve this record in our namestore.
1963    * The name to resolve is now in rh->authority_name
1964    * since we tried to resolve it to an authority
1965    * and failed.
1966    **/
1967   rh->namestore_task = GNUNET_NAMESTORE_lookup_record(namestore_handle,
1968                                  &rh->authority,
1969                                  rh->name,
1970                                  rlh->record_type,
1971                                  &process_record_result_ns,
1972                                  rh);
1973 }
1974
1975
1976
1977 /**
1978  * Handle timeout for DHT requests
1979  *
1980  * @param cls the request handle as closure
1981  * @param tc the task context
1982  */
1983 static void
1984 dht_authority_lookup_timeout(void *cls,
1985                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1986 {
1987   struct ResolverHandle *rh = cls;
1988   struct RecordLookupHandle *rlh = rh->proc_cls;
1989   char new_name[MAX_DNS_NAME_LENGTH];
1990
1991   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1992          "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%llus)timed out.\n",
1993          rh->id, rh->authority_name, rh->timeout.rel_value);
1994
1995   rh->status |= RSL_TIMED_OUT;
1996   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1997   if (NULL != rh->get_handle)
1998     GNUNET_DHT_get_stop (rh->get_handle);
1999
2000   rh->get_handle = NULL;
2001   if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
2002   {
2003     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2004                "GNS_PHASE_DELEGATE_DHT-%llu: Got shutdown\n",
2005                rh->id);
2006     rh->proc(rh->proc_cls, rh, 0, NULL);
2007     return;
2008   }
2009
2010   if (0 == strcmp(rh->name, ""))
2011   {
2012     /*
2013      * promote authority back to name and try to resolve record
2014      */
2015     strcpy(rh->name, rh->authority_name);
2016     rh->proc(rh->proc_cls, rh, 0, NULL);
2017     return;
2018   }
2019   
2020   /**
2021    * Start resolution in bg
2022    */
2023   GNUNET_assert (0 < GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
2024                   "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD));
2025   
2026   strcpy(rh->name, new_name);
2027
2028   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2029         "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
2030         rh->id, rh->name, rlh->record_type);
2031
2032   gns_resolver_lookup_record (rh->authority,
2033                               rh->private_local_zone,
2034                               rlh->record_type,
2035                               new_name,
2036                               NULL,
2037                               GNUNET_TIME_UNIT_FOREVER_REL,
2038                               GNUNET_NO,
2039                               &background_lookup_result_processor,
2040                               NULL);
2041   rh->proc(rh->proc_cls, rh, 0, NULL);
2042 }
2043
2044 /* Prototype */
2045 static void resolve_delegation_dht(struct ResolverHandle *rh);
2046
2047 /* Prototype */
2048 static void resolve_delegation_ns(struct ResolverHandle *rh);
2049
2050
2051 /**
2052  * Namestore resolution for delegation finished. Processing result.
2053  *
2054  * @param cls the closure
2055  * @param rh resolver handle
2056  * @param rd_count number of results (always 0)
2057  * @param rd record data (always NULL)
2058  */
2059 static void
2060 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
2061                           unsigned int rd_count,
2062                           const struct GNUNET_NAMESTORE_RecordData *rd);
2063
2064
2065 /**
2066  * This is a callback function that checks for key revocation
2067  *
2068  * @param cls the pending query
2069  * @param key the key of the zone we did the lookup
2070  * @param expiration expiration date of the record data set in the namestore
2071  * @param name the name for which we need an authority
2072  * @param rd_count the number of records with 'name'
2073  * @param rd the record data
2074  * @param signature the signature of the authority for the record data
2075  */
2076 static void
2077 process_pkey_revocation_result_ns (void *cls,
2078                     const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
2079                     struct GNUNET_TIME_Absolute expiration,
2080                     const char *name,
2081                     unsigned int rd_count,
2082                     const struct GNUNET_NAMESTORE_RecordData *rd,
2083                     const struct GNUNET_CRYPTO_RsaSignature *signature)
2084 {
2085   struct ResolverHandle *rh = cls;
2086   struct GNUNET_TIME_Relative remaining_time;
2087   int i;
2088   
2089   rh->namestore_task = NULL;
2090   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2091   
2092   for (i = 0; i < rd_count; i++)
2093   {
2094     if (GNUNET_GNS_RECORD_REV == rd[i].record_type)
2095     {
2096       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2097                  "GNS_PHASE_DELEGATE_REV-%llu: Zone has been revoked.\n",
2098                  rh->id);
2099       rh->status |= RSL_PKEY_REVOKED;
2100       rh->proc (rh->proc_cls, rh, 0, NULL);
2101       return;
2102     }
2103   }
2104   
2105   if ((NULL == name) ||
2106       (0 == remaining_time.rel_value))
2107   {
2108     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2109           "GNS_PHASE_DELEGATE_REV-%llu: + Records don't exist or are expired.\n",
2110           rh->id, name);
2111
2112     if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value != rh->timeout.rel_value)
2113     {
2114       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2115         "GNS_PHASE_DELEGATE_REV-%llu: Starting background lookup for %s type %d\n",
2116         rh->id, "+.gads", GNUNET_GNS_RECORD_REV);
2117
2118       gns_resolver_lookup_record(rh->authority,
2119                                  rh->private_local_zone,
2120                                  GNUNET_GNS_RECORD_REV,
2121                                  GNUNET_GNS_TLD,
2122                                  NULL,
2123                                  GNUNET_TIME_UNIT_FOREVER_REL,
2124                                  GNUNET_NO,
2125                                  &background_lookup_result_processor,
2126                                  NULL);
2127     }
2128   }
2129  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2130              "GNS_PHASE_DELEGATE_REV-%llu: Revocation check passed\n",
2131              rh->id);
2132   /**
2133    * We are done with PKEY resolution if name is empty
2134    * else resolve again with new authority
2135    */
2136   if (strcmp (rh->name, "") == 0)
2137     rh->proc (rh->proc_cls, rh, rh->rd_count, &rh->rd);
2138   else
2139     resolve_delegation_ns (rh);
2140 }
2141
2142
2143 /**
2144  * Callback when record data is put into namestore
2145  *
2146  * @param cls the closure
2147  * @param success GNUNET_OK on success
2148  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
2149  */
2150 void
2151 on_namestore_delegation_put_result(void *cls,
2152                                    int32_t success,
2153                                    const char *emsg)
2154 {
2155   struct NamestoreBGTask *nbg = cls;
2156
2157   GNUNET_CONTAINER_heap_remove_node (nbg->node);
2158   GNUNET_free (nbg);
2159
2160   if (GNUNET_NO == success)
2161   {
2162     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2163                "GNS_NS: records already in namestore\n");
2164     return;
2165   }
2166   else if (GNUNET_YES == success)
2167   {
2168     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2169                "GNS_NS: records successfully put in namestore\n");
2170     return;
2171   }
2172
2173   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2174              "GNS_NS: Error putting records into namestore: %s\n", emsg);
2175 }
2176
2177 /**
2178  * Function called when we get a result from the dht
2179  * for our query. Recursively tries to resolve authorities
2180  * for name in DHT.
2181  *
2182  * @param cls the request handle
2183  * @param exp lifetime
2184  * @param key the key the record was stored under
2185  * @param get_path get path
2186  * @param get_path_length get path length
2187  * @param put_path put path
2188  * @param put_path_length put path length
2189  * @param type the block type
2190  * @param size the size of the record
2191  * @param data the record data
2192  */
2193 static void
2194 process_delegation_result_dht(void* cls,
2195                  struct GNUNET_TIME_Absolute exp,
2196                  const struct GNUNET_HashCode * key,
2197                  const struct GNUNET_PeerIdentity *get_path,
2198                  unsigned int get_path_length,
2199                  const struct GNUNET_PeerIdentity *put_path,
2200                  unsigned int put_path_length,
2201                  enum GNUNET_BLOCK_Type type,
2202                  size_t size, const void *data)
2203 {
2204   struct ResolverHandle *rh = cls;
2205   struct GNSNameRecordBlock *nrb;
2206   uint32_t num_records;
2207   char* name = NULL;
2208   char* rd_data = (char*) data;
2209   int i;
2210   int rd_size;
2211   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
2212   struct GNUNET_HashCode zone_hash_double, name_hash_double;
2213
2214   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2215              "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id);
2216
2217   if (data == NULL)
2218     return;
2219   
2220   nrb = (struct GNSNameRecordBlock*)data;
2221   
2222   /* stop dht lookup and timeout task */
2223   GNUNET_DHT_get_stop (rh->get_handle);
2224   rh->get_handle = NULL;
2225   if (rh->dht_heap_node != NULL)
2226   {
2227     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
2228     rh->dht_heap_node = NULL;
2229   }
2230
2231   num_records = ntohl(nrb->rd_count);
2232   name = (char*)&nrb[1];
2233   {
2234     struct GNUNET_NAMESTORE_RecordData rd[num_records];
2235     struct NamestoreBGTask *ns_heap_root;
2236     struct NamestoreBGTask *namestore_bg_task;
2237     
2238     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
2239     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
2240     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
2241                                                                rd_data,
2242                                                                num_records,
2243                                                                rd))
2244     {
2245       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2246                  "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
2247                  rh->id);
2248       return;
2249     }
2250
2251     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2252                "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2253                rh->id, name, rh->authority_name);
2254     for (i=0; i<num_records; i++)
2255     {
2256     
2257       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2258                 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2259                 rh->id, name, rh->authority_name);
2260       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2261                  "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
2262                  rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
2263       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2264                  "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
2265                  rh->id, rd[i].data_size);
2266       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2267                  "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
2268                  rh->id, rd[i].flags);
2269       
2270       if ((GNUNET_GNS_RECORD_VPN == rd[i].record_type) ||
2271           (GNUNET_GNS_RECORD_NS == rd[i].record_type) ||
2272           (GNUNET_GNS_RECORD_CNAME == rd[i].record_type))
2273       {
2274         /**
2275          * This is a VPN,NS,CNAME entry. Let namestore handle this after caching
2276          */
2277         if (0 == strcmp(rh->name, ""))
2278           strcpy(rh->name, rh->authority_name);
2279         else
2280           GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
2281                  rh->name, rh->authority_name); //FIXME ret
2282         rh->answered = 1;
2283         break;
2284       }
2285
2286       if ((0 == strcmp(name, rh->authority_name)) &&
2287           (GNUNET_GNS_RECORD_PKEY == rd[i].record_type))
2288       {
2289         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2290                    "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
2291                    rh->id);
2292         rh->answered = 1;
2293         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
2294         struct AuthorityChain *auth =
2295           GNUNET_malloc(sizeof(struct AuthorityChain));
2296         auth->zone = rh->authority;
2297         memset(auth->name, 0, strlen(rh->authority_name)+1);
2298         strcpy(auth->name, rh->authority_name);
2299         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2300                                      rh->authority_chain_tail,
2301                                      auth);
2302
2303         if (NULL != rh->rd.data)
2304           GNUNET_free ((void*)rh->rd.data);
2305         
2306         memcpy (&rh->rd, &rd[i], sizeof (struct GNUNET_NAMESTORE_RecordData));
2307         rh->rd.data = GNUNET_malloc (rd[i].data_size);
2308         memcpy ((void*)(rh->rd.data), rd[i].data, rd[i].data_size);
2309         rh->rd_count = 1;
2310
2311         /** try to import pkey if private key available */
2312         //if (rh->priv_key && is_canonical (rh->name))
2313         //  process_discovered_authority(name, auth->zone,
2314         //                               rh->authority_chain_tail->zone,
2315         //                               rh->priv_key);
2316       }
2317
2318     }
2319
2320
2321     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
2322     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
2323     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
2324     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
2325
2326     /* Save to namestore
2327     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_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 static void
2428 expand_plus(char* dest, char* src, char* repl)
2429 {
2430   char* pos;
2431   unsigned int s_len = strlen(src)+1;
2432
2433   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2434              "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
2435   //Eh? I guess this is at least strlen ('x.+') == 3 FIXME
2436   if (3 > s_len)
2437   {
2438     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2439                "GNS_POSTPROCESS: %s too short\n", src);
2440
2441     /* no postprocessing */
2442     memcpy(dest, src, s_len+1);
2443     return;
2444   }
2445   
2446   if (0 == strcmp(src+s_len-3, ".+"))
2447   {
2448     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2449                "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
2450     memset(dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
2451     strcpy(dest, src);
2452     pos = dest+s_len-2;
2453     strcpy(pos, repl);
2454     pos += strlen(repl);
2455     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2456                "GNS_POSTPROCESS: Expanded to %s\n", dest);
2457   }
2458   else
2459   {
2460     memcpy(dest, src, s_len+1);
2461   }
2462 }
2463
2464 /**
2465  * finish lookup
2466  */
2467 static void
2468 finish_lookup (struct ResolverHandle *rh,
2469                struct RecordLookupHandle* rlh,
2470                unsigned int rd_count,
2471                const struct GNUNET_NAMESTORE_RecordData *rd)
2472 {
2473   int i;
2474   char new_rr_data[MAX_DNS_NAME_LENGTH];
2475   char new_mx_data[MAX_MX_LENGTH];
2476   char new_soa_data[MAX_SOA_LENGTH];
2477   char new_srv_data[MAX_SRV_LENGTH];
2478   struct srv_data *old_srv;
2479   struct srv_data *new_srv;
2480   struct soa_data *old_soa;
2481   struct soa_data *new_soa;
2482   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
2483   char* repl_string;
2484   char* pos;
2485   unsigned int offset;
2486
2487   if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
2488   {
2489     GNUNET_SCHEDULER_cancel(rh->timeout_task);
2490     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2491   }
2492
2493   GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
2494
2495   if (0 < rd_count)
2496     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
2497
2498   for (i = 0; i < rd_count; i++)
2499   {
2500     
2501     if ((GNUNET_GNS_RECORD_NS != rd[i].record_type) &&
2502         (GNUNET_GNS_RECORD_PTR != rd[i].record_type) &&
2503         (GNUNET_GNS_RECORD_CNAME != rd[i].record_type) &&
2504         (GNUNET_GNS_RECORD_MX != rd[i].record_type) &&
2505         (GNUNET_GNS_RECORD_SOA != rd[i].record_type) &&
2506         (GNUNET_GNS_RECORD_SRV != rd[i].record_type))
2507     {
2508       p_rd[i].data = rd[i].data;
2509       continue;
2510     }
2511
2512     /**
2513      * for all those records we 'should'
2514      * also try to resolve the A/AAAA records (RFC1035)
2515      * This is a feature and not important
2516      */
2517     
2518     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2519                "GNS_POSTPROCESS: Postprocessing\n");
2520     if (0 == strcmp(rh->name, "+"))
2521       repl_string = rlh->name;
2522     else
2523       repl_string = rlh->name+strlen(rh->name)+1;
2524
2525     offset = 0;
2526     if (GNUNET_GNS_RECORD_MX == rd[i].record_type)
2527     {
2528       memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
2529       offset = sizeof(uint16_t);
2530       pos = new_mx_data+offset;
2531       expand_plus(pos, (char*)rd[i].data+sizeof(uint16_t),
2532                   repl_string);
2533       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
2534       p_rd[i].data = new_mx_data;
2535       p_rd[i].data_size = offset;
2536     }
2537     else if (GNUNET_GNS_RECORD_SRV == rd[i].record_type)
2538     {
2539       /*
2540        * Prio, weight and port
2541        */
2542       new_srv = (struct srv_data*)new_srv_data;
2543       old_srv = (struct srv_data*)rd[i].data;
2544       new_srv->prio = old_srv->prio;
2545       new_srv->weight = old_srv->weight;
2546       new_srv->port = old_srv->port;
2547       expand_plus((char*)&new_srv[1], (char*)&old_srv[1],
2548                   repl_string);
2549       p_rd[i].data = new_srv_data;
2550       p_rd[i].data_size = sizeof (struct srv_data) + strlen ((char*)&new_srv[1]) + 1;
2551     }
2552     else if (GNUNET_GNS_RECORD_SOA == rd[i].record_type)
2553     {
2554       /* expand mname and rname */
2555       old_soa = (struct soa_data*)rd[i].data;
2556       new_soa = (struct soa_data*)new_soa_data;
2557       memcpy (new_soa, old_soa, sizeof (struct soa_data));
2558       expand_plus((char*)&new_soa[1], (char*)&old_soa[1], repl_string);
2559       offset = strlen ((char*)&new_soa[1]) + 1;
2560       expand_plus((char*)&new_soa[1] + offset,
2561                   (char*)&old_soa[1] + strlen ((char*)&old_soa[1]) + 1,
2562                   repl_string);
2563       p_rd[i].data_size = sizeof (struct soa_data)
2564                           + offset
2565                           + strlen ((char*)&new_soa[1] + offset);
2566       p_rd[i].data = new_soa_data;
2567     }
2568     else
2569     {
2570       pos = new_rr_data;
2571       expand_plus(pos, (char*)rd[i].data, repl_string);
2572       p_rd[i].data_size = strlen(new_rr_data)+1;
2573       p_rd[i].data = new_rr_data;
2574     }
2575     
2576   }
2577
2578   rlh->proc(rlh->proc_cls, rd_count, p_rd);
2579   GNUNET_free(rlh);
2580   free_resolver_handle (rh);
2581 }
2582
2583 /**
2584  * Process DHT lookup result for record.
2585  *
2586  * @param cls the closure
2587  * @param rh resolver handle
2588  * @param rd_count number of results
2589  * @param rd record data
2590  */
2591 static void
2592 handle_record_dht(void* cls, struct ResolverHandle *rh,
2593                        unsigned int rd_count,
2594                        const struct GNUNET_NAMESTORE_RecordData *rd)
2595 {
2596   struct RecordLookupHandle* rlh = cls;
2597
2598   if (0 == rd_count)
2599   {
2600     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2601                "GNS_PHASE_REC-%llu: No records for %s found in DHT. Aborting\n",
2602                rh->id, rh->name);
2603     /* give up, cannot resolve */
2604     finish_lookup (rh, rlh, 0, NULL);
2605     return;
2606   }
2607   /* results found yay */
2608   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2609              "GNS_PHASE_REC-%llu: Record resolved from DHT!", rh->id);
2610   finish_lookup (rh, rlh, rd_count, rd);
2611 }
2612
2613
2614
2615
2616 /**
2617  * Process namestore lookup result for record.
2618  *
2619  * @param cls the closure
2620  * @param rh resolver handle
2621  * @param rd_count number of results
2622  * @param rd record data
2623  */
2624 static void
2625 handle_record_ns (void* cls, struct ResolverHandle *rh,
2626                   unsigned int rd_count,
2627                   const struct GNUNET_NAMESTORE_RecordData *rd)
2628 {
2629   struct RecordLookupHandle* rlh = cls;
2630   int check_dht = GNUNET_YES;
2631   
2632   if (0 != rd_count)
2633   {
2634     /* results found yay */
2635     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2636                "GNS_PHASE_REC-%llu: Record resolved from namestore!\n", rh->id);
2637     finish_lookup (rh, rlh, rd_count, rd);
2638     return;
2639   }
2640   
2641   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2642               "GNS_PHASE_REC-%llu: NS returned no records. (status: %d)!\n",
2643               rh->id,
2644               rh->status);
2645   /**
2646    * There are 5 conditions that have to met for us to consult the DHT:
2647    * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
2648    * 2. No entry in the NS existed AND
2649    * 3. The zone queried is not the local resolver's zone AND
2650    * 4. The name that was looked up is '+'
2651    *    because if it was any other canonical name we either already queried
2652    *    the DHT for the authority in the authority lookup phase (and thus
2653    *    would already have an entry in the NS for the record)
2654    * 5. We are not in cache only mode
2655    */
2656   if ((0 != (rh->status & RSL_RECORD_EXPIRED)) &&
2657       (0 == (rh->status & RSL_RECORD_EXISTS)) )
2658   {
2659     
2660     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2661               "GNS_PHASE_REC-%llu: Not expired and exists!\n",
2662               rh->id);
2663     check_dht = GNUNET_NO;
2664   }
2665   
2666   if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2667                                         &rh->private_local_zone))
2668   {
2669
2670     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2671               "GNS_PHASE_REC-%llu: Our zone!\n",
2672               rh->id);
2673     check_dht = GNUNET_NO;
2674   }
2675   
2676   if ((0 != strcmp (rh->name, "+")) && (GNUNET_YES == is_srv (rh->name)))
2677       check_dht = GNUNET_NO;
2678
2679   if (GNUNET_YES == rh->only_cached)
2680     check_dht = GNUNET_NO;
2681   
2682   if (GNUNET_YES == check_dht)
2683   {
2684     rh->proc = &handle_record_dht;
2685     resolve_record_dht(rh);
2686     return;
2687   }
2688   /* give up, cannot resolve */
2689   finish_lookup (rh, rlh, 0, NULL);
2690 }
2691
2692
2693 /**
2694  * Move one level up in the domain hierarchy and return the
2695  * passed top level domain.
2696  *
2697  * @param name the domain
2698  * @param dest the destination where the tld will be put
2699  */
2700 void
2701 pop_tld(char* name, char* dest)
2702 {
2703   uint32_t len;
2704
2705   if (GNUNET_YES == is_canonical (name))
2706   {
2707     strcpy(dest, name);
2708     strcpy(name, "");
2709     return;
2710   }
2711
2712   for (len = strlen(name); 0 < len; len--)
2713   {
2714     if (*(name+len) == '.')
2715       break;
2716   }
2717   
2718   //Was canonical?
2719   if (0 == len)
2720     return;
2721
2722   name[len] = '\0';
2723
2724   strcpy(dest, (name+len+1));
2725 }
2726
2727 /**
2728  * Checks if name is in tld
2729  *
2730  * @param name the name to check
2731  * @param tld the TLD to check for
2732  * @return GNUNET_YES or GNUNET_NO
2733  */
2734 int
2735 is_tld(const char* name, const char* tld)
2736 {
2737   int offset = 0;
2738
2739   if (strlen(name) <= strlen(tld))
2740     return GNUNET_NO;
2741   
2742   offset = strlen(name)-strlen(tld);
2743   if (0 != strcmp(name+offset, tld))
2744   {
2745     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2746                "%s is not in .%s TLD\n", name, tld);
2747     return GNUNET_NO;
2748   }
2749   return GNUNET_YES;
2750 }
2751
2752 /**
2753  * DHT resolution for delegation finished. Processing result.
2754  *
2755  * @param cls the closure
2756  * @param rh resolver handle
2757  * @param rd_count number of results (always 0)
2758  * @param rd record data (always NULL)
2759  */
2760 static void
2761 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
2762                           unsigned int rd_count,
2763                           const struct GNUNET_NAMESTORE_RecordData *rd)
2764 {
2765   struct RecordLookupHandle* rlh;
2766   rlh = cls;
2767   
2768
2769   if (0 == strcmp(rh->name, ""))
2770   {
2771     if (GNUNET_GNS_RECORD_PKEY == rlh->record_type)
2772     {
2773       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2774                  "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
2775                  rh->id);
2776       finish_lookup(rh, rlh, rd_count, rd);
2777       return;
2778     }
2779     /* We resolved full name for delegation. resolving record */
2780     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2781      "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
2782      rh->id);
2783     strcpy(rh->name, "+\0");
2784     rh->proc = &handle_record_ns;
2785     resolve_record_ns(rh);
2786     return;
2787   }
2788
2789   /**
2790    * we still have some left
2791    **/
2792   if (GNUNET_YES == is_canonical (rh->name))
2793   {
2794     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2795              "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
2796              rh->id,
2797              rh->name);
2798     rh->proc = &handle_record_ns;
2799     resolve_record_ns(rh);
2800     return;
2801   }
2802   /* give up, cannot resolve */
2803   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2804  "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
2805  rh->id, rh->name);
2806   finish_lookup(rh, rlh, 0, NULL);
2807 }
2808
2809
2810 /**
2811  * Start DHT lookup for a name -> PKEY (compare NS) record in
2812  * rh->authority's zone
2813  *
2814  * @param rh the pending gns query
2815  */
2816 static void
2817 resolve_delegation_dht(struct ResolverHandle *rh)
2818 {
2819   uint32_t xquery;
2820   struct GNUNET_CRYPTO_ShortHashCode name_hash;
2821   struct GNUNET_HashCode name_hash_double;
2822   struct GNUNET_HashCode zone_hash_double;
2823   struct GNUNET_HashCode lookup_key;
2824   struct ResolverHandle *rh_heap_root;
2825   
2826   pop_tld(rh->name, rh->authority_name);
2827
2828   //FIXME handle return values here
2829   GNUNET_CRYPTO_short_hash(rh->authority_name,
2830                      strlen(rh->authority_name),
2831                      &name_hash);
2832   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
2833   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
2834   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &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   {
3436     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3437                 "No shorten key for resolution\n");
3438   }
3439
3440   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3441   {
3442     /*
3443      * Set timeout for authority lookup phase to 1/2
3444      */
3445     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3446                 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
3447     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
3448                                 GNUNET_TIME_relative_divide(timeout, 2),
3449                                                 &handle_lookup_timeout,
3450                                                 rh);
3451     rh->timeout_cont = &dht_authority_lookup_timeout;
3452     rh->timeout_cont_cls = rh;
3453   }
3454   else
3455   {
3456     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
3457     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3458   }
3459   
3460   if (strcmp(GNUNET_GNS_TLD, name) == 0)
3461   {
3462     /**
3463      * Only 'gnunet' given
3464      */
3465     strcpy(rh->name, "\0");
3466   }
3467   else
3468   {
3469     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3470                 "Checking for TLD...\n");
3471     if (is_zkey_tld(name) == GNUNET_YES)
3472     {
3473       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3474                   "TLD is zkey\n");
3475       /**
3476        * This is a zkey tld
3477        * build hash and use as initial authority
3478        */
3479       memset(rh->name, 0,
3480              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
3481       memcpy(rh->name, name,
3482              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
3483       pop_tld(rh->name, string_hash);
3484
3485       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3486                   "ZKEY is %s!\n", string_hash);
3487       
3488       GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
3489
3490       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
3491                                                       &rh->authority))
3492       {
3493         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3494                     "Cannot convert ZKEY `%s' to hash!\n", string_hash);
3495         
3496         if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
3497           GNUNET_SCHEDULER_cancel (rh->timeout_task);
3498         GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3499         GNUNET_free (rh);
3500         GNUNET_free (rlh);
3501         proc (cls, 0, NULL);
3502         return;
3503       }
3504
3505     }
3506     else if (is_gnunet_tld (name) == GNUNET_YES)
3507     {
3508       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3509                   "TLD is gnunet\n");
3510       /**
3511        * Presumably GNUNET tld
3512        */
3513       memset (rh->name, 0,
3514               strlen(name)-strlen(GNUNET_GNS_TLD));
3515       memcpy (rh->name, name,
3516               strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
3517     }
3518     else
3519     {
3520       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3521                   "Cannot handle this TLD %s\n", string_hash);
3522       
3523       if (GNUNET_SCHEDULER_NO_TASK != rh->timeout_task)
3524         GNUNET_SCHEDULER_cancel (rh->timeout_task);
3525       GNUNET_CONTAINER_DLL_remove (rlh_head, rlh_tail, rh);
3526       GNUNET_free (rh);
3527       GNUNET_free (rlh);
3528       proc (cls, 0, NULL);
3529       return;
3530     }
3531   }
3532   
3533   /**
3534    * Initialize authority chain
3535    */
3536   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
3537   rh->authority_chain_head->prev = NULL;
3538   rh->authority_chain_head->next = NULL;
3539   rh->authority_chain_tail = rh->authority_chain_head;
3540   rh->authority_chain_head->zone = rh->authority;
3541   strcpy (rh->authority_chain_head->name, "");
3542   
3543   /**
3544    * Copy original query into lookup handle
3545    */
3546   rlh->record_type = record_type;
3547   memset(rlh->name, 0, strlen(name) + 1);
3548   strcpy(rlh->name, name);
3549   rlh->proc = proc;
3550   rlh->proc_cls = cls;
3551
3552   rh->proc = &handle_delegation_ns;
3553   resolve_delegation_ns(rh);
3554 }
3555
3556 /******** END Record Resolver ***********/
3557
3558 static void
3559 finish_shorten (struct ResolverHandle *rh,
3560                 struct NameShortenHandle *nsh)
3561 {
3562   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3563               "Sending %s as shorten result\n", nsh->result);
3564   nsh->proc (nsh->proc_cls, nsh->result);
3565   GNUNET_CONTAINER_DLL_remove (nsh_head, nsh_tail, rh);
3566   GNUNET_free (nsh);
3567   free_resolver_handle (rh);
3568 }
3569
3570
3571 /**
3572  * Callback calles by namestore for a zone to name
3573  * result
3574  *
3575  * @param cls the closure
3576  * @param zone_key the zone we queried
3577  * @param expire the expiration time of the name
3578  * @param name the name found or NULL
3579  * @param rd_len number of records for the name
3580  * @param rd the record data (PKEY) for the name
3581  * @param signature the signature for the record data
3582  */
3583 static void
3584 process_zone_to_name_shorten_root (void *cls,
3585                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3586                  struct GNUNET_TIME_Absolute expire,
3587                  const char *name,
3588                  unsigned int rd_len,
3589                  const struct GNUNET_NAMESTORE_RecordData *rd,
3590                  const struct GNUNET_CRYPTO_RsaSignature *signature);
3591
3592
3593 /**
3594  * Callback called by namestore for a zone to name
3595  * result
3596  *
3597  * @param cls the closure
3598  * @param zone_key the zone we queried
3599  * @param expire the expiration time of the name
3600  * @param name the name found or NULL
3601  * @param rd_len number of records for the name
3602  * @param rd the record data (PKEY) for the name
3603  * @param signature the signature for the record data
3604  */
3605 static void
3606 process_zone_to_name_shorten_shorten (void *cls,
3607                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3608                  struct GNUNET_TIME_Absolute expire,
3609                  const char *name,
3610                  unsigned int rd_len,
3611                  const struct GNUNET_NAMESTORE_RecordData *rd,
3612                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3613 {
3614   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3615   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3616   struct AuthorityChain *next_authority;
3617
3618   char result[MAX_DNS_NAME_LENGTH];
3619   char tmp_name[MAX_DNS_NAME_LENGTH];
3620   size_t answer_len;
3621   
3622   rh->namestore_task = NULL;
3623   /* we found a match in our own root zone */
3624   if (rd_len != 0)
3625   {
3626     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3627     memset(result, 0, answer_len);
3628
3629     if (strlen(rh->name) > 0)
3630     {
3631       sprintf (result, "%s.%s.%s.%s",
3632                rh->name, name,
3633                nsh->shorten_zone_name,
3634                GNUNET_GNS_TLD);
3635     }
3636     else
3637     {
3638       sprintf (result, "%s.%s.%s", name,
3639                nsh->shorten_zone_name,
3640                GNUNET_GNS_TLD);
3641     }
3642     
3643     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3644                "Found shorten result %s\n", result);
3645     if (strlen (nsh->result) > strlen (result))
3646       strcpy (nsh->result, result);
3647   }
3648   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3649                                         nsh->shorten_zone) == 0)
3650   {
3651     /**
3652      * This is our zone append .gads unless name is empty
3653      * (it shouldn't be, usually FIXME what happens if we
3654      * shorten to our zone to a "" record??)
3655      */
3656     
3657     sprintf (result, "%s.%s.%s",
3658              rh->name,
3659              nsh->shorten_zone_name,
3660              GNUNET_GNS_TLD);
3661     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3662                "Our zone: Found %s as shorten result\n", result);
3663     
3664     if (strlen (nsh->result) > strlen (result))
3665       strcpy (nsh->result, result);
3666     //nsh->proc(nsh->proc_cls, result);
3667     //GNUNET_free(nsh);
3668     //free_resolver_handle(rh);
3669     //return;
3670   }
3671   
3672   
3673   /**
3674    * No PSEU found.
3675    * continue with next authority if exists
3676    */
3677   if ((rh->authority_chain_head->next == NULL))
3678   {
3679     finish_shorten (rh, nsh);
3680     return;
3681   }
3682   next_authority = rh->authority_chain_head;
3683   
3684   if (0 == strcmp (rh->name, ""))
3685     strcpy (tmp_name, next_authority->name);
3686   else
3687     GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3688                     "%s.%s", rh->name, next_authority->name);
3689   
3690   strcpy(rh->name, tmp_name);
3691   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3692              "No PSEU found for authority %s. Promoting back: %s\n",
3693              next_authority->name, rh->name);
3694   
3695   GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3696                             rh->authority_chain_tail,
3697                             next_authority);
3698
3699   GNUNET_free (next_authority);
3700
3701   rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3702                                  &rh->authority_chain_tail->zone,
3703                                  &rh->authority_chain_head->zone,
3704                                  &process_zone_to_name_shorten_root,
3705                                  rh);
3706 }
3707
3708 /**
3709  * Callback calles by namestore for a zone to name
3710  * result
3711  *
3712  * @param cls the closure
3713  * @param zone_key the zone we queried
3714  * @param expire the expiration time of the name
3715  * @param name the name found or NULL
3716  * @param rd_len number of records for the name
3717  * @param rd the record data (PKEY) for the name
3718  * @param signature the signature for the record data
3719  */
3720 static void
3721 process_zone_to_name_shorten_private (void *cls,
3722                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3723                  struct GNUNET_TIME_Absolute expire,
3724                  const char *name,
3725                  unsigned int rd_len,
3726                  const struct GNUNET_NAMESTORE_RecordData *rd,
3727                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3728 {
3729   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3730   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3731   struct AuthorityChain *next_authority;
3732
3733   char result[MAX_DNS_NAME_LENGTH];
3734   char tmp_name[MAX_DNS_NAME_LENGTH];
3735   size_t answer_len;
3736   
3737   rh->namestore_task = NULL;
3738   /* we found a match in our own root zone */
3739   if (rd_len != 0)
3740   {
3741     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3742     memset(result, 0, answer_len);
3743
3744     if (strlen(rh->name) > 0)
3745     {
3746       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3747     }
3748     else
3749     {
3750       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3751     }
3752     
3753     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3754                "Found shorten result %s\n", result);
3755     if (strlen (nsh->result) > strlen (result))
3756       strcpy (nsh->result, result);
3757   }
3758   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3759                                         nsh->private_zone) == 0)
3760   {
3761     /**
3762      * This is our zone append .gads unless name is empty
3763      * (it shouldn't be, usually FIXME what happens if we
3764      * shorten to our zone to a "" record??)
3765      */
3766     
3767     sprintf (result, "%s.%s.%s",
3768              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3769     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3770                "Our private zone: Found %s as shorten result %s\n", result);
3771     if (strlen (nsh->result) > strlen (result))
3772       strcpy (nsh->result, result);
3773   }
3774   
3775   if (0 != strcmp (nsh->shorten_zone_name, ""))
3776   {
3777     /* backtrack authorities for names in priv zone */
3778     rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3779                                    nsh->shorten_zone,
3780                                    &rh->authority_chain_head->zone,
3781                                    &process_zone_to_name_shorten_shorten,
3782                                    rh);
3783   }
3784   else
3785   {
3786     /**
3787      * No PSEU found.
3788      * continue with next authority if exists
3789      */
3790     if ((rh->authority_chain_head->next == NULL))
3791     {
3792       finish_shorten (rh, nsh);
3793       return;
3794     }
3795     next_authority = rh->authority_chain_head;
3796     
3797     if (0 == strcmp (rh->name, ""))
3798       strcpy (tmp_name, next_authority->name);
3799     else
3800       GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3801                       "%s.%s", rh->name, next_authority->name);
3802     
3803     strcpy(rh->name, tmp_name);
3804     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3805                "No PSEU found for authority %s. Promoting back: %s\n",
3806                next_authority->name, rh->name);
3807     
3808     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3809                               rh->authority_chain_tail,
3810                               next_authority);
3811
3812     GNUNET_free (next_authority);
3813
3814     rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3815                                    &rh->authority_chain_tail->zone,
3816                                    &rh->authority_chain_head->zone,
3817                                    &process_zone_to_name_shorten_root,
3818                                    rh);
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 ((rh->authority_chain_head->next == NULL))
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
4162   nsh->proc = proc;
4163   nsh->proc_cls = proc_cls;
4164   nsh->root_zone = zone;
4165   nsh->private_zone = pzone;
4166   nsh->shorten_zone = szone;
4167   strcpy (nsh->private_zone_name, private_zone_name);
4168   strcpy (nsh->shorten_zone_name, shorten_zone_name);
4169   strcpy (nsh->result, name);
4170   
4171
4172   rh = GNUNET_malloc (sizeof (struct ResolverHandle));
4173   rh->authority = *zone;
4174   rh->id = rid++;
4175   rh->priv_key = NULL;
4176   rh->namestore_task = NULL;
4177   rh->proc = &handle_delegation_ns_shorten;
4178   rh->proc_cls = nsh;
4179   rh->id = rid++;
4180   rh->private_local_zone = *zone;
4181
4182   GNUNET_CONTAINER_DLL_insert (nsh_head, nsh_tail, rh);
4183   
4184   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4185                 "Checking for TLD...\n");
4186   if (is_zkey_tld (name) == GNUNET_YES)
4187   {
4188     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4189                 "TLD is zkey\n");
4190     /**
4191      * This is a zkey tld
4192      * build hash and use as initial authority
4193      * FIXME sscanf
4194      */
4195     memset (rh->name, 0,
4196             strlen (name)-strlen (GNUNET_GNS_TLD_ZKEY));
4197     memcpy (rh->name, name,
4198             strlen(name)-strlen (GNUNET_GNS_TLD_ZKEY) - 1);
4199     pop_tld (rh->name, string_hash);
4200
4201     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4202                 "ZKEY is %s!\n", string_hash);
4203     
4204     GNUNET_STRINGS_utf8_toupper (string_hash, &nzkey_ptr);
4205
4206     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string (nzkey,
4207                                                            &zkey))
4208     {
4209       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4210                   "Cannot convert ZKEY %s to hash!\n", nzkey);
4211       GNUNET_free (rh);
4212       GNUNET_free (nsh);
4213       GNUNET_CONTAINER_DLL_remove (nsh_head, nsh_tail, rh);
4214       proc (proc_cls, name);
4215       return;
4216     }
4217
4218     rh->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
4219                                    zone, //ours
4220                                    &zkey,
4221                                    &process_zone_to_name_zkey,
4222                                    rh);
4223     return;
4224
4225   }
4226   else if (is_gnunet_tld (name) == GNUNET_YES)
4227   {
4228     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4229                 "TLD is gnunet\n");
4230     /**
4231      * Presumably GNUNET tld
4232      */
4233     memset (rh->name, 0,
4234             strlen (name)-strlen (GNUNET_GNS_TLD));
4235     memcpy (rh->name, name,
4236             strlen (name)-strlen (GNUNET_GNS_TLD) - 1);
4237   }
4238   else
4239   {
4240     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unknown TLD in %s\n", name);
4241     GNUNET_free (rh);
4242     GNUNET_free (nsh);
4243     GNUNET_CONTAINER_DLL_remove (nsh_head, nsh_tail, rh);
4244     proc (proc_cls, name);
4245     return;
4246   }
4247
4248   rh->authority_chain_head = GNUNET_malloc (sizeof (struct AuthorityChain));
4249   rh->authority_chain_tail = rh->authority_chain_head;
4250   rh->authority_chain_head->zone = *zone;
4251   
4252   
4253   /* Start delegation resolution in our namestore */
4254   resolve_delegation_ns (rh);
4255 }
4256
4257 /*********** END NAME SHORTEN ********************/
4258
4259 /**
4260  * Conclude get authority lookup
4261  *
4262  * @param rh resolver handle
4263  * @param nah get authority lookup handle
4264  */
4265 static void
4266 finish_get_auth (struct ResolverHandle *rh,
4267                  struct GetNameAuthorityHandle *nah)
4268 {
4269   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4270              "Got authority result %s\n", nah->result);
4271   
4272   nah->proc (nah->proc_cls, nah->result);
4273   GNUNET_CONTAINER_DLL_remove (nah_head, nah_tail, rh);
4274   GNUNET_free (nah);
4275   free_resolver_handle (rh);
4276 }
4277
4278 /**
4279  * Process result from namestore delegation lookup
4280  * for get authority operation
4281  *
4282  * @param cls the client get auth handle
4283  * @param rh the resolver handle
4284  * @param rd_count number of results (0)
4285  * @param rd data (NULL)
4286  */
4287 void
4288 handle_delegation_result_ns_get_auth(void* cls,
4289                       struct ResolverHandle *rh,
4290                       uint32_t rd_count,
4291                       const struct GNUNET_NAMESTORE_RecordData *rd)
4292 {
4293   struct GetNameAuthorityHandle* nah;
4294   size_t answer_len;
4295
4296   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
4297   
4298   /**
4299    * At this point rh->name contains the part of the name
4300    * that we do not have a PKEY in our namestore to resolve.
4301    * The authority chain in the resolver handle is now
4302    * useful to backtrack if needed
4303    */
4304   
4305   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4306              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
4307
4308   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4309              "Building response!\n");
4310   if (is_canonical (rh->name) == GNUNET_YES)
4311   {
4312     /**
4313      * We successfully resolved the authority in the ns
4314      * FIXME for our purposes this is fine
4315      * but maybe we want to have an api that also looks
4316      * into the dht (i.e. option in message)
4317      **/
4318     if (strlen(rh->name) > strlen(nah->name))
4319     {
4320       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4321                  "Record name longer than original lookup name... odd!\n");
4322       //FIXME to sth here
4323     }
4324
4325     answer_len = strlen(nah->name) - strlen(rh->name)
4326       + strlen(GNUNET_GNS_TLD) + 1;
4327     memset(nah->result, 0, answer_len);
4328     if (0 != strcmp (rh->name, ""))
4329       strcpy(nah->result, nah->name + strlen(rh->name) + 1);
4330     else
4331       strcpy(nah->result, nah->name);
4332
4333     finish_get_auth (rh, nah);
4334   }
4335   else
4336   {
4337     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4338                "Unable to resolve authority for remaining %s!\n", rh->name);
4339     strcpy(nah->result, "");
4340     finish_get_auth (rh, nah);
4341   }
4342
4343
4344 }
4345
4346
4347 /**
4348  * Tries to resolve the authority for name
4349  * in our namestore
4350  *
4351  * @param zone the root zone to look up for
4352  * @param pzone the private local zone
4353  * @param name the name to lookup up
4354  * @param proc the processor to call when finished
4355  * @param proc_cls the closure to pass to the processor
4356  */
4357 void
4358 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
4359                            struct GNUNET_CRYPTO_ShortHashCode pzone,
4360                            const char* name,
4361                            GetAuthorityResultProcessor proc,
4362                            void* proc_cls)
4363 {
4364   struct ResolverHandle *rh;
4365   struct GetNameAuthorityHandle *nah;
4366
4367   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4368               "Starting authority resolution for %s!\n", name);
4369
4370   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
4371   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
4372   rh->authority = zone;
4373   rh->id = rid++;
4374   rh->private_local_zone = pzone;
4375   rh->namestore_task = NULL;
4376
4377   GNUNET_CONTAINER_DLL_insert (nah_head, nah_tail, rh);
4378   
4379   if (strcmp(GNUNET_GNS_TLD, name) == 0)
4380   {
4381     strcpy(rh->name, "\0");
4382   }
4383   else
4384   {
4385     memset(rh->name, 0,
4386            strlen(name)-strlen(GNUNET_GNS_TLD));
4387     memcpy(rh->name, name,
4388            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
4389   }
4390
4391   memset(nah->name, 0,
4392          strlen(name)+1);
4393   strcpy(nah->name, name);
4394   
4395   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
4396   rh->authority_chain_tail = rh->authority_chain_head;
4397   rh->authority_chain_head->zone = zone;
4398   rh->proc = &handle_delegation_result_ns_get_auth;
4399   rh->proc_cls = (void*)nah;
4400
4401   nah->proc = proc;
4402   nah->proc_cls = proc_cls;
4403   strcpy (nah->result, "");
4404
4405   /* Start delegation resolution in our namestore */
4406   resolve_delegation_ns(rh);
4407
4408 }
4409
4410 /******** END GET AUTHORITY *************/
4411
4412 /* end of gnunet-service-gns_resolver.c */