de6e9ccc3fc8f095aa658521952db84d55d06378
[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  *
23  *
24  * @file gns/gnunet-service-gns_resolver.c
25  * @brief GNUnet GNS resolver logic
26  * @author Martin Schanzenbach
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_transport_service.h"
31 #include "gnunet_dns_service.h"
32 #include "gnunet_dht_service.h"
33 #include "gnunet_namestore_service.h"
34 #include "gnunet_dns_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gnunet_gns_service.h"
37 #include "block_gns.h"
38 #include "gns.h"
39 #include "gnunet-service-gns_resolver.h"
40
41 #define DHT_OPERATION_TIMEOUT  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
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  * Resolver handle to the dht
54  */
55 static struct GNUNET_DHT_Handle *dht_handle;
56
57 /**
58  * Heap for parallel DHT lookups
59  */
60 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
61
62 /**
63  * Maximum amount of parallel queries in background
64  */
65 static unsigned long long max_allowed_background_queries;
66
67 /**
68  * Our local zone
69  */
70 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
71
72 static unsigned long long rid = 0;
73
74 /**
75  * Namestore calls this function if we have record for this name.
76  * (or with rd_count=0 to indicate no matches)
77  *
78  * @param cls the pending query
79  * @param key the key of the zone we did the lookup
80  * @param expiration expiration date of the namestore entry
81  * @param name the name for which we need an authority
82  * @param rd_count the number of records with 'name'
83  * @param rd the record data
84  * @param signature the signature of the authority for the record data
85  */
86 static void
87 process_pseu_lookup_ns(void* cls,
88                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
89                       struct GNUNET_TIME_Absolute expiration,
90                       const char *name, unsigned int rd_count,
91                       const struct GNUNET_NAMESTORE_RecordData *rd,
92                       const struct GNUNET_CRYPTO_RsaSignature *signature)
93 {
94   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
95   struct GNUNET_NAMESTORE_RecordData new_pkey;
96
97   if (rd_count > 0)
98   {
99     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
100                "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
101     if (0 == strcmp(gph->name, name))
102     {
103       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
104                  "GNS_AUTO_PSEU: Intelligent replacement not implemented\n",
105                  name);
106       GNUNET_free(gph);
107       return;
108     }
109
110     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
111                "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name);
112     memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
113     GNUNET_NAMESTORE_lookup_record(namestore_handle,
114                                    &gph->zone,
115                                    gph->new_name,
116                                    GNUNET_GNS_RECORD_PSEU,
117                                    &process_pseu_lookup_ns,
118                                    gph);
119     return;
120   }
121
122   /** name is free */
123   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
124              "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->new_name);
125
126   new_pkey.expiration = GNUNET_TIME_absolute_get_forever ();
127   new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
128   new_pkey.data = &gph->new_zone;
129   new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
130   GNUNET_NAMESTORE_record_create (namestore_handle,
131                                   gph->key,
132                                   gph->new_name,
133                                   &new_pkey,
134                                   NULL, //cont
135                                   NULL); //cls
136   GNUNET_free(gph);
137
138 }
139
140 /**
141  * process result of a dht pseu lookup
142  *
143  * @param gph the handle
144  * @param name the pseu result or NULL
145  */
146 static void
147 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
148 {
149   if (NULL == name)
150   {
151     memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
152   }
153   else
154   {
155     memcpy(gph->new_name, name, strlen(name)+1);
156   }
157
158   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
159              "GNS_AUTO_PSEU: Checking %s for collision in NS\n", gph->new_name);
160
161   /**
162    * Check for collision
163    */
164   GNUNET_NAMESTORE_lookup_record(namestore_handle,
165                                  &gph->zone,
166                                  gph->new_name,
167                                  GNUNET_GNS_RECORD_PSEU,
168                                  &process_pseu_lookup_ns,
169                                  gph);
170 }
171
172 /**
173  * Handle timeout for dht request
174  *
175  * @param cls the request handle as closure
176  * @param tc the task context
177  */
178 static void
179 handle_auth_discovery_timeout(void *cls,
180                               const struct GNUNET_SCHEDULER_TaskContext *tc)
181 {
182   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
183
184   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
185              "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
186   GNUNET_DHT_get_stop (gph->get_handle);
187   gph->get_handle = NULL;
188   process_pseu_result(gph, NULL);
189 }
190
191 /**
192  * Function called when we find a PSEU entry in the DHT
193  *
194  * @param cls the request handle
195  * @param exp lifetime
196  * @param key the key the record was stored under
197  * @param get_path get path
198  * @param get_path_length get path length
199  * @param put_path put path
200  * @param put_path_length put path length
201  * @param type the block type
202  * @param size the size of the record
203  * @param data the record data
204  */
205 static void
206 process_auth_discovery_dht_result(void* cls,
207                                   struct GNUNET_TIME_Absolute exp,
208                                   const GNUNET_HashCode * key,
209                                   const struct GNUNET_PeerIdentity *get_path,
210                                   unsigned int get_path_length,
211                                   const struct GNUNET_PeerIdentity *put_path,
212                                   unsigned int put_path_length,
213                                   enum GNUNET_BLOCK_Type type,
214                                   size_t size, const void *data)
215 {
216   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
217   struct GNSNameRecordBlock *nrb;
218   char* rd_data = (char*)data;
219   char* name;
220   int num_records;
221   size_t rd_size;
222   int i;
223
224   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
225              "GNS_GET_AUTH: got dht result (size=%d)\n", size);
226
227   if (data == NULL)
228   {
229     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
230                "GNS_GET_AUTH: got dht result null!\n", size);
231     GNUNET_break(0);
232     GNUNET_free(gph);
233     return;
234   }
235   
236   nrb = (struct GNSNameRecordBlock*)data;
237
238   /* stop lookup and timeout task */
239   GNUNET_DHT_get_stop (gph->get_handle);
240   gph->get_handle = NULL;
241   GNUNET_SCHEDULER_cancel(gph->timeout);
242
243   gph->get_handle = NULL;
244
245   nrb = (struct GNSNameRecordBlock*)data;
246   
247   name = (char*)&nrb[1];
248   num_records = ntohl(nrb->rd_count);
249   {
250     struct GNUNET_NAMESTORE_RecordData rd[num_records];
251
252     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
253     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
254
255     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
256                                                                rd_data,
257                                                                num_records,
258                                                                rd))
259     {
260       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
261                  "GNS_GET_AUTH: Error deserializing data!\n");
262       GNUNET_break(0);
263       GNUNET_free(gph);
264       return;
265     }
266
267     for (i=0; i<num_records; i++)
268     {
269       if ((strcmp(name, "+") == 0) &&
270           (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
271       {
272         /* found pseu */
273         process_pseu_result(gph, (char*)rd[i].data);
274         return;
275       }
276     }
277   }
278
279   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n");
280   process_pseu_result(gph, NULL);
281 }
282
283 static void
284 process_auth_discovery_ns_result(void* cls,
285                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
286                       struct GNUNET_TIME_Absolute expiration,
287                       const char *name, unsigned int rd_count,
288                       const struct GNUNET_NAMESTORE_RecordData *rd,
289                       const struct GNUNET_CRYPTO_RsaSignature *signature)
290 {
291   uint32_t xquery;
292   struct GNUNET_CRYPTO_ShortHashCode name_hash;
293   GNUNET_HashCode lookup_key;
294   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
295   GNUNET_HashCode name_hash_double;
296   GNUNET_HashCode zone_hash_double;
297   int i;
298   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
299   
300   /* no pseu found */
301   if (rd_count == 0)
302   {
303     /**
304      * check dht
305      */
306     GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
307     GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
308     GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
309     GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
310     GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
311
312     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
313                "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
314                "+", (char*)&lookup_key_string);
315
316     gph->timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
317                                          &handle_auth_discovery_timeout, gph);
318
319     xquery = htonl(GNUNET_GNS_RECORD_PSEU);
320     
321     GNUNET_assert(gph->get_handle == NULL);
322     gph->get_handle = GNUNET_DHT_get_start(dht_handle,
323                                            GNUNET_TIME_UNIT_FOREVER_REL,
324                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
325                                            &lookup_key,
326                                            DHT_GNS_REPLICATION_LEVEL,
327                                            GNUNET_DHT_RO_NONE,
328                                            &xquery,
329                                            sizeof(xquery),
330                                            &process_auth_discovery_dht_result,
331                                            gph);
332     return;
333   }
334   for (i=0; i<rd_count; i++)
335   {
336     if ((strcmp(name, "+") == 0) &&
337         (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
338     {
339       /* found pseu */
340       process_pseu_result(gph, (char*)rd[i].data);
341       return;
342     }
343   }
344 }
345
346 /**
347  * Callback called by namestore for a zone to name
348  * result
349  *
350  * @param cls the closure
351  * @param zone_key the zone we queried
352  * @param expire the expiration time of the name
353  * @param name the name found or NULL
354  * @param rd_len number of records for the name
355  * @param rd the record data (PKEY) for the name
356  * @param signature the signature for the record data
357  */
358 static void
359 process_zone_to_name_discover(void *cls,
360                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
361                  struct GNUNET_TIME_Absolute expire,
362                  const char *name,
363                  unsigned int rd_len,
364                  const struct GNUNET_NAMESTORE_RecordData *rd,
365                  const struct GNUNET_CRYPTO_RsaSignature *signature)
366 {
367   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
368
369   /* we found a match in our own zone */
370   if (rd_len != 0)
371   {
372     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
373                "GNS_AUTO_PSEU: name for zone in our root %s\n", name);
374     GNUNET_free(gph);
375   }
376   else
377   {
378
379     GNUNET_NAMESTORE_lookup_record(namestore_handle,
380                                    &gph->new_zone,
381                                    "+",
382                                    GNUNET_GNS_RECORD_PSEU,
383                                    &process_auth_discovery_ns_result,
384                                    gph);
385   }
386    
387
388 }
389
390
391 /**
392  * Callback for new authories
393  *
394  * @param name the name given by delegation
395  * @param zone the authority
396  * @param our_zone our local zone
397  * @param key the private key of our authority
398  */
399 static void process_discovered_authority(char* name,
400                                     struct GNUNET_CRYPTO_ShortHashCode zone,
401                                     struct GNUNET_CRYPTO_ShortHashCode our_zone,
402                                     struct GNUNET_CRYPTO_RsaPrivateKey *key)
403 {
404   struct GetPseuAuthorityHandle *gph;
405   size_t namelen;
406
407   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
408              "GNS_AUTO_PSEU: New authority %s discovered\n",
409              name);
410
411   gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
412   namelen = strlen(name) + 1;
413   memcpy(gph->name, name, namelen);
414   
415   gph->new_zone = zone;
416   gph->zone = our_zone;
417   gph->key = key;
418
419   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
420                                  &our_zone,
421                                  &gph->new_zone,
422                                  &process_zone_to_name_discover,
423                                  gph);
424
425 }
426
427 /**
428  * Initialize the resolver
429  *
430  * @param nh the namestore handle
431  * @param dh the dht handle
432  * @param lz the local zone's hash
433  * @param max_bg_queries maximum number of parallel background queries in dht
434  * @return GNUNET_OK on success
435  */
436 int
437 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
438                   struct GNUNET_DHT_Handle *dh,
439                   struct GNUNET_CRYPTO_ShortHashCode lz,
440                   unsigned long long max_bg_queries)
441 {
442   namestore_handle = nh;
443   dht_handle = dh;
444   local_zone = lz;
445   dht_lookup_heap =
446     GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
447   max_allowed_background_queries = max_bg_queries;
448
449   if ((namestore_handle != NULL) && (dht_handle != NULL))
450   {
451     return GNUNET_OK;
452   }
453   return GNUNET_SYSERR;
454 }
455
456 /**
457  * Cleanup background lookups
458  *
459  * @param cls closure to iterator
460  * @param node heap nodes
461  * @param element the resolver handle
462  * @param cost heap cost
463  * @return always GNUNET_YES
464  */
465 static int
466 cleanup_pending_background_queries(void* cls,
467                                    struct GNUNET_CONTAINER_HeapNode *node,
468                                    void *element,
469                                    GNUNET_CONTAINER_HeapCostType cost)
470 {
471   struct ResolverHandle *rh = (struct ResolverHandle *)element;
472   ResolverCleanupContinuation cont = cls;
473   
474   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
475              "GNS_CLEANUP-%d: Terminating background lookup for %s\n",
476              rh->id, rh->name);
477   GNUNET_DHT_get_stop(rh->get_handle);
478   rh->get_handle = NULL;
479   rh->proc(rh->proc_cls, rh, 0, NULL);
480
481   GNUNET_CONTAINER_heap_remove_node(node);
482
483   if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0)
484     cont();
485
486
487   return GNUNET_YES;
488 }
489
490
491 /**
492  * Shutdown resolver
493  */
494 void
495 gns_resolver_cleanup(ResolverCleanupContinuation cont)
496 {
497   unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap);
498   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
499              "GNS_CLEANUP: %d pending background queries to terminate\n", s);
500
501   if (0 != s)
502     GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
503                                    &cleanup_pending_background_queries,
504                                    cont);
505   else
506     cont();
507 }
508
509
510 /**
511  * Helper function to free resolver handle
512  *
513  * @param rh the handle to free
514  */
515 static void
516 free_resolver_handle(struct ResolverHandle* rh)
517 {
518   struct AuthorityChain *ac;
519   struct AuthorityChain *ac_next;
520
521   if (NULL == rh)
522     return;
523
524   ac = rh->authority_chain_head;
525
526   while (NULL != ac)
527   {
528     ac_next = ac->next;
529     GNUNET_free(ac);
530     ac = ac_next;
531   }
532   GNUNET_free(rh);
533 }
534
535
536 /**
537  * Callback when record data is put into namestore
538  *
539  * @param cls the closure
540  * @param success GNUNET_OK on success
541  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
542  */
543 void
544 on_namestore_record_put_result(void *cls,
545                                int32_t success,
546                                const char *emsg)
547 {
548   if (GNUNET_NO == success)
549   {
550     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
551                "GNS_NS: records already in namestore\n");
552     return;
553   }
554   else if (GNUNET_YES == success)
555   {
556     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
557                "GNS_NS: records successfully put in namestore\n");
558     return;
559   }
560
561   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
562              "GNS_NS: Error putting records into namestore: %s\n", emsg);
563 }
564
565 static void
566 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
567 {
568   struct ResolverHandle *rh = cls;
569
570   if (rh->timeout_cont)
571     rh->timeout_cont(rh->timeout_cont_cls, tc);
572 }
573
574 /**
575  * Processor for background lookups in the DHT
576  *
577  * @param cls closure (NULL)
578  * @param rd_count number of records found (not 0)
579  * @param rd record data
580  */
581 static void
582 background_lookup_result_processor(void *cls,
583                                    uint32_t rd_count,
584                                    const struct GNUNET_NAMESTORE_RecordData *rd)
585 {
586   //We could do sth verbose/more useful here but it doesn't make any difference
587   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
588              "GNS_BG: background dht lookup for finished. (%d results)\n",
589              rd_count);
590 }
591
592 /**
593  * Handle timeout for DHT requests
594  *
595  * @param cls the request handle as closure
596  * @param tc the task context
597  */
598 static void
599 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
600 {
601   struct ResolverHandle *rh = cls;
602   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
603   char new_name[MAX_DNS_NAME_LENGTH];
604
605   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
606              "GNS_PHASE_REC-%d: dht lookup for query %s (%ds)timed out.\n",
607              rh->id, rh->name, rh->timeout.rel_value);
608   /**
609    * Start resolution in bg
610    */
611   //strcpy(new_name, rh->name);
612   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
613   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
614                   rh->name, GNUNET_GNS_TLD);
615
616   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
617              "GNS_PHASE_REC-%d: Starting background lookup for %s type %d\n",
618              rh->id, new_name, rlh->record_type);
619
620   gns_resolver_lookup_record(rh->authority,
621                              rlh->record_type,
622                              new_name,
623                              rh->priv_key,
624                              GNUNET_TIME_UNIT_FOREVER_REL,
625                              &background_lookup_result_processor,
626                              NULL);
627   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
628   
629   GNUNET_DHT_get_stop (rh->get_handle);
630   rh->get_handle = NULL;
631   rh->proc(rh->proc_cls, rh, 0, NULL);
632 }
633
634
635 /**
636  * Function called when we get a result from the dht
637  * for our record query
638  *
639  * @param cls the request handle
640  * @param exp lifetime
641  * @param key the key the record was stored under
642  * @param get_path get path
643  * @param get_path_length get path length
644  * @param put_path put path
645  * @param put_path_length put path length
646  * @param type the block type
647  * @param size the size of the record
648  * @param data the record data
649  */
650 static void
651 process_record_result_dht(void* cls,
652                  struct GNUNET_TIME_Absolute exp,
653                  const GNUNET_HashCode * key,
654                  const struct GNUNET_PeerIdentity *get_path,
655                  unsigned int get_path_length,
656                  const struct GNUNET_PeerIdentity *put_path,
657                  unsigned int put_path_length,
658                  enum GNUNET_BLOCK_Type type,
659                  size_t size, const void *data)
660 {
661   struct ResolverHandle *rh;
662   struct RecordLookupHandle *rlh;
663   struct GNSNameRecordBlock *nrb;
664   uint32_t num_records;
665   char* name = NULL;
666   char* rd_data = (char*)data;
667   int i;
668   int rd_size;
669
670   rh = (struct ResolverHandle *)cls;
671   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
672              "GNS_PHASE_REC-%d: got dht result (size=%d)\n", rh->id, size);
673   
674   if (data == NULL)
675     return;
676
677   //FIXME maybe check expiration here, check block type
678   
679   
680   rlh = (struct RecordLookupHandle *) rh->proc_cls;
681   nrb = (struct GNSNameRecordBlock*)data;
682   
683   /* stop lookup and timeout task */
684   GNUNET_DHT_get_stop (rh->get_handle);
685   rh->get_handle = NULL;
686   
687   if (rh->dht_heap_node != NULL)
688   {
689     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
690     rh->dht_heap_node = NULL;
691   }
692   
693   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
694   {
695     GNUNET_SCHEDULER_cancel(rh->timeout_task);
696     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
697   }
698
699   rh->get_handle = NULL;
700   name = (char*)&nrb[1];
701   num_records = ntohl(nrb->rd_count);
702   {
703     struct GNUNET_NAMESTORE_RecordData rd[num_records];
704
705     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
706     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
707   
708     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
709                                                                rd_data,
710                                                                num_records,
711                                                                rd))
712     {
713       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
714                  "GNS_PHASE_REC-%d: Error deserializing data!\n", rh->id);
715       return;
716     }
717
718     for (i=0; i<num_records; i++)
719     {
720       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
721                "GNS_PHASE_REC-%d: Got name: %s (wanted %s)\n",
722                rh->id, name, rh->name);
723       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
724                "GNS_PHASE_REC-%d: Got type: %d\n",
725                rh->id, rd[i].record_type);
726       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
727                "GNS_PHASE_REC-%d: Got data length: %d\n",
728                rh->id, rd[i].data_size);
729       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
730                "GNS_PHASE_REC-%d: Got flag %d\n",
731                rh->id, rd[i].flags);
732     
733      if ((strcmp(name, rh->name) == 0) &&
734          (rd[i].record_type == rlh->record_type))
735       {
736         rh->answered++;
737       }
738
739     }
740
741     /**
742      * FIXME check pubkey against existing key in namestore?
743      * https://gnunet.org/bugs/view.php?id=2179
744      */
745
746     /* Save to namestore */
747     GNUNET_NAMESTORE_record_put (namestore_handle,
748                                  &nrb->public_key,
749                                  name,
750                                  exp,
751                                  num_records,
752                                  rd,
753                                  &nrb->signature,
754                                  &on_namestore_record_put_result, //cont
755                                  NULL); //cls
756
757   
758     if (rh->answered)
759       rh->proc(rh->proc_cls, rh, num_records, rd);
760     else
761       rh->proc(rh->proc_cls, rh, 0, NULL);
762   }
763
764 }
765
766
767 /**
768  * Start DHT lookup for a (name -> query->record_type) record in
769  * rh->authority's zone
770  *
771  * @param rh the pending gns query context
772  */
773 static void
774 resolve_record_dht(struct ResolverHandle *rh)
775 {
776   uint32_t xquery;
777   struct GNUNET_CRYPTO_ShortHashCode name_hash;
778   GNUNET_HashCode lookup_key;
779   GNUNET_HashCode name_hash_double;
780   GNUNET_HashCode zone_hash_double;
781   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
782   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
783   struct ResolverHandle *rh_heap_root;
784   
785   GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
786   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
787   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
788   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
789   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
790   
791   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
792              "GNS_PHASE_REC-%d: starting dht lookup for %s with key: %s\n",
793              rh->id, rh->name, (char*)&lookup_key_string);
794
795   //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
796   rh->dht_heap_node = NULL;
797
798   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
799   {
800     /**
801      * Update timeout if necessary
802      */
803     if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
804     {
805
806     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
807                "GNS_PHASE_REC-%d: Adjusting timeout\n", rh->id);
808     /*
809      * Set timeout for authority lookup phase to 1/2
810      */
811       rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
812                                 GNUNET_TIME_relative_divide(rh->timeout, 2),
813                                                 &handle_lookup_timeout,
814                                                 rh);
815     }
816     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
817     //                                                   &dht_lookup_timeout,
818     //                                                   rh);
819     rh->timeout_cont = &dht_lookup_timeout;
820     rh->timeout_cont_cls = rh;
821   }
822   else 
823   {
824     if (max_allowed_background_queries <=
825         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
826     {
827       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
828       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
829       rh_heap_root->get_handle = NULL;
830       rh_heap_root->dht_heap_node = NULL;
831       
832       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
833            "GNS_PHASE_REC-%d: Replacing oldest background query for %s\n",
834                  rh->id, rh_heap_root->name);
835       rh_heap_root->proc(rh_heap_root->proc_cls,
836                          rh_heap_root,
837                          0,
838                          NULL);
839     }
840     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
841                                          rh,
842                                          GNUNET_TIME_absolute_get().abs_value);
843   }
844   
845   xquery = htonl(rlh->record_type);
846   
847   GNUNET_assert(rh->get_handle == NULL);
848   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
849                        GNUNET_TIME_UNIT_FOREVER_REL,
850                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
851                        &lookup_key,
852                        DHT_GNS_REPLICATION_LEVEL,
853                        GNUNET_DHT_RO_NONE,
854                        &xquery, 
855                        sizeof(xquery),
856                        &process_record_result_dht,
857                        rh);
858
859 }
860
861
862 /**
863  * Namestore calls this function if we have record for this name.
864  * (or with rd_count=0 to indicate no matches)
865  *
866  * @param cls the pending query
867  * @param key the key of the zone we did the lookup
868  * @param expiration expiration date of the namestore entry
869  * @param name the name for which we need an authority
870  * @param rd_count the number of records with 'name'
871  * @param rd the record data
872  * @param signature the signature of the authority for the record data
873  */
874 static void
875 process_record_result_ns(void* cls,
876                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
877                   struct GNUNET_TIME_Absolute expiration,
878                   const char *name, unsigned int rd_count,
879                   const struct GNUNET_NAMESTORE_RecordData *rd,
880                   const struct GNUNET_CRYPTO_RsaSignature *signature)
881 {
882   struct ResolverHandle *rh;
883   struct RecordLookupHandle *rlh;
884   struct GNUNET_TIME_Relative remaining_time;
885   struct GNUNET_CRYPTO_ShortHashCode zone;
886
887   rh = (struct ResolverHandle *) cls;
888   rlh = (struct RecordLookupHandle *)rh->proc_cls;
889   GNUNET_CRYPTO_short_hash(key,
890                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
891                      &zone);
892   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
893   
894   
895
896   rh->status = 0;
897   
898   if (name != NULL)
899   {
900     rh->status |= EXISTS;
901   }
902   
903   if (remaining_time.rel_value == 0)
904   {
905     rh->status |= EXPIRED;
906   }
907   
908   if (rd_count == 0)
909   {
910     /**
911      * Lookup terminated and no results
912      */
913     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
914       "GNS_PHASE_REC-%d: Namestore lookup for %s terminated without results\n",
915          rh->id, name);
916
917     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
918                "GNS_PHASE_REC-%d: Record %s unknown in namestore\n",
919                rh->id, rh->name);
920     /**
921      * Our zone and no result? Cannot resolve TT
922      */
923     rh->proc(rh->proc_cls, rh, 0, NULL);
924     return;
925
926   }
927   else
928   {
929     
930     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
931            "GNS_PHASE_REC-%d: Processing additional result %s from namestore\n",
932               rh->id, name);
933     int i;
934     for (i=0; i<rd_count;i++)
935     {
936
937       if (rd[i].record_type != rlh->record_type)
938         continue;
939       
940       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
941           == 0)
942       {
943         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
944                    "GNS_PHASE_REC-%d: This record is expired. Skipping\n",
945                    rh->id);
946         continue;
947       }
948       
949       rh->answered++;
950       
951     }
952     
953     /**
954      * no answers found
955      */
956     if (rh->answered == 0)
957     {
958       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
959                  "GNS_PHASE_REC-%d: No answers found. This is odd!\n", rh->id);
960       rh->proc(rh->proc_cls, rh, 0, NULL);
961       return;
962     }
963     
964     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
965                "GNS_PHASE_REC-%d: Found %d answer(s) to query in %d records!\n",
966                rh->id, rh->answered, rd_count);
967
968     rh->proc(rh->proc_cls, rh, rd_count, rd);
969   }
970 }
971
972
973 /**
974  * The final phase of resolution.
975  * rh->name is a name that is canonical and we do not have a delegation.
976  * Query namestore for this record
977  *
978  * @param rh the pending lookup
979  */
980 static void
981 resolve_record_ns(struct ResolverHandle *rh)
982 {
983   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
984   
985   /* We cancel here as to not include the ns lookup in the timeout */
986   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
987   {
988     GNUNET_SCHEDULER_cancel(rh->timeout_task);
989     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
990   }
991   
992   /**
993    * Try to resolve this record in our namestore.
994    * The name to resolve is now in rh->authority_name
995    * since we tried to resolve it to an authority
996    * and failed.
997    **/
998   GNUNET_NAMESTORE_lookup_record(namestore_handle,
999                                  &rh->authority,
1000                                  rh->name,
1001                                  rlh->record_type,
1002                                  &process_record_result_ns,
1003                                  rh);
1004 }
1005
1006
1007
1008 /**
1009  * Handle timeout for DHT requests
1010  *
1011  * @param cls the request handle as closure
1012  * @param tc the task context
1013  */
1014 static void
1015 dht_authority_lookup_timeout(void *cls,
1016                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1017 {
1018   struct ResolverHandle *rh = cls;
1019   struct RecordLookupHandle *rlh = rh->proc_cls;
1020   char new_name[MAX_DNS_NAME_LENGTH];
1021
1022   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1023          "GNS_PHASE_DELEGATE_DHT-%d: dht lookup for query %s (%ds)timed out.\n",
1024          rh->id, rh->authority_name, rh->timeout.rel_value);
1025
1026   rh->status |= TIMED_OUT;
1027
1028   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1029   
1030   GNUNET_DHT_get_stop (rh->get_handle);
1031   rh->get_handle = NULL;
1032   
1033   if (strcmp(rh->name, "") == 0)
1034   {
1035     /*
1036      * promote authority back to name and try to resolve record
1037      */
1038     strcpy(rh->name, rh->authority_name);
1039     rh->proc(rh->proc_cls, rh, 0, NULL);
1040     return;
1041   }
1042   
1043   /**
1044    * Start resolution in bg
1045    */
1046   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1047                   "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD);
1048   //strcpy(new_name, rh->name);
1049   //strcpy(new_name+strlen(new_name), ".");
1050   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1051   
1052   strcpy(rh->name, new_name);
1053
1054   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1055         "GNS_PHASE_DELEGATE_DHT-%d: Starting background query for %s type %d\n",
1056         rh->id, rh->name, rlh->record_type);
1057
1058   gns_resolver_lookup_record(rh->authority,
1059                              rlh->record_type,
1060                              new_name,
1061                              rh->priv_key,
1062                              GNUNET_TIME_UNIT_FOREVER_REL,
1063                              &background_lookup_result_processor,
1064                              NULL);
1065
1066   rh->proc(rh->proc_cls, rh, 0, NULL);
1067 }
1068
1069 /* Prototype */
1070 static void resolve_delegation_dht(struct ResolverHandle *rh);
1071
1072 /* Prototype */
1073 static void resolve_delegation_ns(struct ResolverHandle *rh);
1074
1075
1076 /**
1077  * Namestore resolution for delegation finished. Processing result.
1078  *
1079  * @param cls the closure
1080  * @param rh resolver handle
1081  * @param rd_count number of results (always 0)
1082  * @param rd record data (always NULL)
1083  */
1084 static void
1085 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1086                           unsigned int rd_count,
1087                           const struct GNUNET_NAMESTORE_RecordData *rd);
1088
1089
1090 /**
1091  * Function called when we get a result from the dht
1092  * for our query. Recursively tries to resolve authorities
1093  * for name in DHT.
1094  *
1095  * @param cls the request handle
1096  * @param exp lifetime
1097  * @param key the key the record was stored under
1098  * @param get_path get path
1099  * @param get_path_length get path length
1100  * @param put_path put path
1101  * @param put_path_length put path length
1102  * @param type the block type
1103  * @param size the size of the record
1104  * @param data the record data
1105  */
1106 static void
1107 process_delegation_result_dht(void* cls,
1108                  struct GNUNET_TIME_Absolute exp,
1109                  const GNUNET_HashCode * key,
1110                  const struct GNUNET_PeerIdentity *get_path,
1111                  unsigned int get_path_length,
1112                  const struct GNUNET_PeerIdentity *put_path,
1113                  unsigned int put_path_length,
1114                  enum GNUNET_BLOCK_Type type,
1115                  size_t size, const void *data)
1116 {
1117   struct ResolverHandle *rh;
1118   struct GNSNameRecordBlock *nrb;
1119   uint32_t num_records;
1120   char* name = NULL;
1121   char* rd_data = (char*) data;
1122   int i;
1123   int rd_size;
1124   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1125   GNUNET_HashCode zone_hash_double, name_hash_double;
1126
1127   rh = (struct ResolverHandle *)cls;
1128   
1129   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1130              "GNS_PHASE_DELEGATE_DHT-%d: Got DHT result\n", rh->id);
1131
1132   if (data == NULL)
1133     return;
1134   
1135   nrb = (struct GNSNameRecordBlock*)data;
1136   
1137   /* stop dht lookup and timeout task */
1138   GNUNET_DHT_get_stop (rh->get_handle);
1139
1140   rh->get_handle = NULL;
1141
1142   if (rh->dht_heap_node != NULL)
1143   {
1144     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1145     rh->dht_heap_node = NULL;
1146   }
1147
1148   num_records = ntohl(nrb->rd_count);
1149   name = (char*)&nrb[1];
1150   {
1151     struct GNUNET_NAMESTORE_RecordData rd[num_records];
1152     
1153     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1154     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1155   
1156     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1157                                                                rd_data,
1158                                                                num_records,
1159                                                                rd))
1160     {
1161       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1162                  "GNS_PHASE_DELEGATE_DHT-%d: Error deserializing data!\n",
1163                  rh->id);
1164       return;
1165     }
1166
1167     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1168                "GNS_PHASE_DELEGATE_DHT-%d: Got name: %s (wanted %s)\n",
1169                rh->id, name, rh->authority_name);
1170     for (i=0; i<num_records; i++)
1171     {
1172     
1173       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1174                 "GNS_PHASE_DELEGATE_DHT-%d: Got name: %s (wanted %s)\n",
1175                 rh->id, name, rh->authority_name);
1176       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1177                  "GNS_PHASE_DELEGATE_DHT-%d: Got type: %d (wanted %d)\n",
1178                  rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1179       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1180                  "GNS_PHASE_DELEGATE_DHT-%d: Got data length: %d\n",
1181                  rh->id, rd[i].data_size);
1182       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1183                  "GNS_PHASE_DELEGATE_DHT-%d: Got flag %d\n",
1184                  rh->id, rd[i].flags);
1185
1186       if ((strcmp(name, rh->authority_name) == 0) &&
1187           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1188       {
1189         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1190                    "GNS_PHASE_DELEGATE_DHT-%d: Authority found in DHT\n",
1191                    rh->id);
1192         rh->answered = 1;
1193         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1194         struct AuthorityChain *auth =
1195           GNUNET_malloc(sizeof(struct AuthorityChain));
1196         auth->zone = rh->authority;
1197         memset(auth->name, 0, strlen(rh->authority_name)+1);
1198         strcpy(auth->name, rh->authority_name);
1199         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1200                                      rh->authority_chain_tail,
1201                                      auth);
1202
1203         /** try to import pkey if private key available */
1204         if (rh->priv_key)
1205           process_discovered_authority(name, auth->zone,
1206                                        rh->authority_chain_tail->zone,
1207                                        rh->priv_key);
1208       }
1209
1210     }
1211
1212
1213     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1214     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1215     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1216     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1217
1218     /* Save to namestore */
1219     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1220                                           &zone))
1221     {
1222       GNUNET_NAMESTORE_record_put (namestore_handle,
1223                                  &nrb->public_key,
1224                                  name,
1225                                  exp,
1226                                  num_records,
1227                                  rd,
1228                                  &nrb->signature,
1229                                  &on_namestore_record_put_result, //cont
1230                                  NULL); //cls
1231     }
1232   }
1233   
1234   if (rh->answered)
1235   {
1236     rh->answered = 0;
1237     /**
1238      * delegate
1239      * FIXME in this case. should we ask namestore again?
1240      */
1241     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1242       "GNS_PHASE_DELEGATE_DHT-%d: Answer from DHT for %s. Yet to resolve: %s\n",
1243       rh->id, rh->authority_name, rh->name);
1244     if (strcmp(rh->name, "") == 0)
1245     {
1246       rh->proc(rh->proc_cls, rh, 0, NULL);
1247     }
1248     else
1249     {
1250       rh->proc = &handle_delegation_ns;
1251       resolve_delegation_ns(rh);
1252     }
1253     return;
1254   }
1255   
1256   /**
1257    * No pkey but name exists
1258    * promote back
1259    */
1260   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1261              "GNS_PHASE_DELEGATE_DHT-%d: Adding %s back to %s\n",
1262              rh->id, rh->authority_name, rh->name);
1263   if (strcmp(rh->name, "") == 0)
1264     strcpy(rh->name, rh->authority_name);
1265   else
1266     GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1267                   rh->name, rh->authority_name); //FIXME ret
1268   
1269   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1270              "GNS_PHASE_DELEGATE_DHT-%d: %s restored\n", rh->id, rh->name);
1271   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1272            "GNS_PHASE_DELEGATE_DHT-%d: DHT authority lookup found no match!\n",
1273            rh->id);
1274   rh->proc(rh->proc_cls, rh, 0, NULL);
1275 }
1276
1277 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1278                         +(MAX_DNS_NAME_LENGTH*2)
1279 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1280
1281
1282 static void
1283 expand_plus(char** dest, char* src, char* repl)
1284 {
1285   char* pos;
1286   unsigned int s_len = strlen(src)+1;
1287
1288   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1289              "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1290
1291   if (s_len < 3)
1292   {
1293     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1294                "GNS_POSTPROCESS: %s to short\n", src);
1295
1296     /* no postprocessing */
1297     memcpy(*dest, src, s_len+1);
1298     return;
1299   }
1300   
1301   if (0 == strcmp(src+s_len-3, ".+"))
1302   {
1303     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1304                "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1305     memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1306     strcpy(*dest, src);
1307     pos = *dest+s_len-2;
1308     strcpy(pos, repl);
1309     pos += strlen(repl);
1310     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1311                "GNS_POSTPROCESS: Expanded to %s\n", *dest);
1312   }
1313   else
1314   {
1315     memcpy(*dest, src, s_len+1);
1316   }
1317 }
1318
1319 /**
1320  * finish lookup
1321  */
1322 static void
1323 finish_lookup(struct ResolverHandle *rh,
1324               struct RecordLookupHandle* rlh,
1325               unsigned int rd_count,
1326               const struct GNUNET_NAMESTORE_RecordData *rd)
1327 {
1328   int i;
1329   char new_rr_data[MAX_DNS_NAME_LENGTH];
1330   char new_mx_data[MAX_MX_LENGTH];
1331   char new_soa_data[MAX_SOA_LENGTH];
1332   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1333   char* repl_string;
1334   char* pos;
1335   unsigned int offset;
1336
1337   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1338     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1339
1340   if (rd_count > 0)
1341     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1342
1343   for (i = 0; i < rd_count; i++)
1344   {
1345     
1346     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1347         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1348         rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1349         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1350     {
1351       p_rd[i].data = rd[i].data;
1352       continue;
1353     }
1354
1355     /**
1356      * for all those records we 'should'
1357      * also try to resolve the A/AAAA records (RFC1035)
1358      * This is a feature and not important
1359      */
1360     
1361     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1362                "GNS_POSTPROCESS: Postprocessing\n");
1363
1364     if (strcmp(rh->name, "+") == 0)
1365       repl_string = rlh->name;
1366     else
1367       repl_string = rlh->name+strlen(rh->name)+1;
1368
1369     offset = 0;
1370     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1371     {
1372       memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1373       offset = sizeof(uint16_t);
1374       pos = new_mx_data+offset;
1375       expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1376                   repl_string);
1377       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1378       p_rd[i].data = new_mx_data;
1379       p_rd[i].data_size = offset;
1380     }
1381     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1382     {
1383       /* expand mname and rname */
1384       pos = new_soa_data;
1385       expand_plus(&pos, (char*)rd[i].data, repl_string);
1386       offset = strlen(new_soa_data)+1;
1387       pos = new_soa_data+offset;
1388       expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1389       offset += strlen(new_soa_data+offset)+1;
1390       /* cpy the 4 numbers serial refresh retry and expire */
1391       memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
1392       offset += sizeof(uint32_t)*5;
1393       p_rd[i].data_size = offset;
1394       p_rd[i].data = new_soa_data;
1395     }
1396     else
1397     {
1398       pos = new_rr_data;
1399       expand_plus(&pos, (char*)rd[i].data, repl_string);
1400       p_rd[i].data_size = strlen(new_rr_data)+1;
1401       p_rd[i].data = new_rr_data;
1402     }
1403     
1404   }
1405
1406   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1407   GNUNET_free(rlh);
1408   
1409 }
1410
1411 /**
1412  * Process DHT lookup result for record.
1413  *
1414  * @param cls the closure
1415  * @param rh resolver handle
1416  * @param rd_count number of results
1417  * @param rd record data
1418  */
1419 static void
1420 handle_record_dht(void* cls, struct ResolverHandle *rh,
1421                        unsigned int rd_count,
1422                        const struct GNUNET_NAMESTORE_RecordData *rd)
1423 {
1424   struct RecordLookupHandle* rlh;
1425
1426   rlh = (struct RecordLookupHandle*)cls;
1427   if (rd_count == 0)
1428   {
1429     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1430                "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n",
1431                rh->id, rh->name);
1432     /* give up, cannot resolve */
1433     finish_lookup(rh, rlh, 0, NULL);
1434     free_resolver_handle(rh);
1435     return;
1436   }
1437
1438   /* results found yay */
1439   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1440              "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id);
1441
1442   finish_lookup(rh, rlh, rd_count, rd);
1443   free_resolver_handle(rh);
1444
1445 }
1446
1447
1448 /**
1449  * Process namestore lookup result for record.
1450  *
1451  * @param cls the closure
1452  * @param rh resolver handle
1453  * @param rd_count number of results
1454  * @param rd record data
1455  */
1456 static void
1457 handle_record_ns(void* cls, struct ResolverHandle *rh,
1458                        unsigned int rd_count,
1459                        const struct GNUNET_NAMESTORE_RecordData *rd)
1460 {
1461   struct RecordLookupHandle* rlh;
1462   rlh = (struct RecordLookupHandle*) cls;
1463   if (rd_count == 0)
1464   {
1465     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1466                "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n",
1467                rh->id,
1468                rh->status);
1469     
1470     /**
1471      * There are 4 conditions that have to met for us to consult the DHT:
1472      * 1. The entry in the DHT is EXPIRED AND
1473      * 2. No entry in the NS existed AND
1474      * 3. The zone queried is not the local resolver's zone AND
1475      * 4. The name that was looked up is '+'
1476      *    because if it was any other canonical name we either already queried
1477      *    the DHT for the authority in the authority lookup phase (and thus
1478      *    would already have an entry in the NS for the record)
1479      */
1480     if (rh->status & (EXPIRED | !EXISTS) &&
1481         GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1482                                      &local_zone) &&
1483         (strcmp(rh->name, "+") == 0))
1484     {
1485       rh->proc = &handle_record_dht;
1486       resolve_record_dht(rh);
1487       return;
1488     }
1489     /* give up, cannot resolve */
1490     finish_lookup(rh, rlh, 0, NULL);
1491     free_resolver_handle(rh);
1492     return;
1493   }
1494
1495   /* results found yay */
1496   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1497              "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id);
1498
1499   finish_lookup(rh, rlh, rd_count, rd);
1500
1501   free_resolver_handle(rh);
1502
1503 }
1504
1505
1506 /**
1507  * Determine if this name is canonical.
1508  * i.e.
1509  * a.b.gnunet  = not canonical
1510  * a           = canonical
1511  *
1512  * @param name the name to test
1513  * @return 1 if canonical
1514  */
1515 static int
1516 is_canonical(char* name)
1517 {
1518   uint32_t len = strlen(name);
1519   int i;
1520
1521   for (i=0; i<len; i++)
1522   {
1523     if (*(name+i) == '.')
1524       return 0;
1525   }
1526   return 1;
1527 }
1528
1529 /**
1530  * Move one level up in the domain hierarchy and return the
1531  * passed top level domain.
1532  *
1533  * @param name the domain
1534  * @param dest the destination where the tld will be put
1535  */
1536 void
1537 pop_tld(char* name, char* dest)
1538 {
1539   uint32_t len;
1540
1541   if (is_canonical(name))
1542   {
1543     strcpy(dest, name);
1544     strcpy(name, "");
1545     return;
1546   }
1547
1548   for (len = strlen(name); len > 0; len--)
1549   {
1550     if (*(name+len) == '.')
1551       break;
1552   }
1553   
1554   //Was canonical?
1555   if (len == 0)
1556     return;
1557
1558   name[len] = '\0';
1559
1560   strcpy(dest, (name+len+1));
1561 }
1562
1563 /**
1564  * Checks if name is in tld
1565  *
1566  * @param name the name to check
1567  * @param tld the TLD to check for
1568  * @return GNUNET_YES or GNUNET_NO
1569  */
1570 int
1571 is_tld(const char* name, const char* tld)
1572 {
1573   int offset = 0;
1574
1575   if (strlen(name) <= strlen(tld))
1576   {
1577     return GNUNET_NO;
1578   }
1579   
1580   offset = strlen(name)-strlen(tld);
1581   if (strcmp(name+offset, tld) != 0)
1582   {
1583     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1584                "%s is not in .%s TLD\n", name, tld);
1585     return GNUNET_NO;
1586   }
1587   return GNUNET_YES;
1588 }
1589
1590 /**
1591  * DHT resolution for delegation finished. Processing result.
1592  *
1593  * @param cls the closure
1594  * @param rh resolver handle
1595  * @param rd_count number of results (always 0)
1596  * @param rd record data (always NULL)
1597  */
1598 static void
1599 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1600                           unsigned int rd_count,
1601                           const struct GNUNET_NAMESTORE_RecordData *rd)
1602 {
1603   struct RecordLookupHandle* rlh;
1604   rlh = (struct RecordLookupHandle*) cls;
1605   
1606
1607   if (strcmp(rh->name, "") == 0)
1608   {
1609     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1610     {
1611       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1612                  "GNS_PHASE_DELEGATE_DHT-%d: Resolved queried PKEY via DHT.\n",
1613                  rh->id);
1614       finish_lookup(rh, rlh, rd_count, rd);
1615       free_resolver_handle(rh);
1616       return;
1617     }
1618     /* We resolved full name for delegation. resolving record */
1619     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1620      "GNS_PHASE_DELEGATE_DHT-%d: Resolved full name for delegation via DHT.\n",
1621      rh->id);
1622     strcpy(rh->name, "+\0");
1623     rh->proc = &handle_record_ns;
1624     resolve_record_ns(rh);
1625     return;
1626   }
1627
1628   /**
1629    * we still have some left
1630    **/
1631   if (is_canonical(rh->name))
1632   {
1633     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1634              "GNS_PHASE_DELEGATE_DHT-%d: Resolving canonical record %s in ns\n",
1635              rh->id,
1636              rh->name);
1637     rh->proc = &handle_record_ns;
1638     resolve_record_ns(rh);
1639     return;
1640   }
1641   /* give up, cannot resolve */
1642   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1643  "GNS_PHASE_DELEGATE_DHT-%d: Cannot fully resolve delegation for %s via DHT!\n",
1644  rh->id, rh->name);
1645   finish_lookup(rh, rlh, 0, NULL);
1646   free_resolver_handle(rh);
1647 }
1648
1649
1650 /**
1651  * Start DHT lookup for a name -> PKEY (compare NS) record in
1652  * rh->authority's zone
1653  *
1654  * @param rh the pending gns query
1655  */
1656 static void
1657 resolve_delegation_dht(struct ResolverHandle *rh)
1658 {
1659   uint32_t xquery;
1660   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1661   GNUNET_HashCode name_hash_double;
1662   GNUNET_HashCode zone_hash_double;
1663   GNUNET_HashCode lookup_key;
1664   struct ResolverHandle *rh_heap_root;
1665   
1666   pop_tld(rh->name, rh->authority_name); 
1667   GNUNET_CRYPTO_short_hash(rh->authority_name,
1668                      strlen(rh->authority_name),
1669                      &name_hash);
1670   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1671   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1672   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1673   
1674   rh->dht_heap_node = NULL;
1675
1676   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1677   {
1678     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1679     //                                          &dht_authority_lookup_timeout,
1680     //                                                   rh);
1681     rh->timeout_cont = &dht_authority_lookup_timeout;
1682     rh->timeout_cont_cls = rh;
1683   }
1684   else 
1685   {
1686     if (max_allowed_background_queries <=
1687         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1688     {
1689       /* terminate oldest lookup */
1690       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1691       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1692       rh_heap_root->dht_heap_node = NULL;
1693       
1694       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1695         "GNS_PHASE_DELEGATE_DHT-%d: Replacing oldest background query for %s\n",
1696         rh->id, rh_heap_root->authority_name);
1697       
1698       rh_heap_root->proc(rh_heap_root->proc_cls,
1699                          rh_heap_root,
1700                          0,
1701                          NULL);
1702     }
1703     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1704                                          rh,
1705                                          GNUNET_TIME_absolute_get().abs_value);
1706   }
1707   
1708   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1709   
1710   GNUNET_assert(rh->get_handle == NULL);
1711   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1712                        GNUNET_TIME_UNIT_FOREVER_REL,
1713                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1714                        &lookup_key,
1715                        DHT_GNS_REPLICATION_LEVEL,
1716                        GNUNET_DHT_RO_NONE,
1717                        &xquery,
1718                        sizeof(xquery),
1719                        &process_delegation_result_dht,
1720                        rh);
1721
1722 }
1723
1724
1725 /**
1726  * Namestore resolution for delegation finished. Processing result.
1727  *
1728  * @param cls the closure
1729  * @param rh resolver handle
1730  * @param rd_count number of results (always 0)
1731  * @param rd record data (always NULL)
1732  */
1733 static void
1734 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1735                           unsigned int rd_count,
1736                           const struct GNUNET_NAMESTORE_RecordData *rd)
1737 {
1738   struct RecordLookupHandle* rlh;
1739   rlh = (struct RecordLookupHandle*) cls;
1740   
1741   if (strcmp(rh->name, "") == 0)
1742   {
1743     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1744     {
1745       GNUNET_assert(rd_count == 1);
1746       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1747                  "GNS_PHASE_DELEGATE_NS-%d: Resolved queried PKEY in NS.\n",
1748                  rh->id);
1749       finish_lookup(rh, rlh, rd_count, rd);
1750       free_resolver_handle(rh);
1751       return;
1752     }
1753     /* We resolved full name for delegation. resolving record */
1754     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1755               "GNS_PHASE_DELEGATE_NS-%d: Resolved full name for delegation.\n",
1756               rh->id);
1757     strcpy(rh->name, "+\0");
1758     rh->proc = &handle_record_ns;
1759     resolve_record_ns(rh);
1760     return;
1761   }
1762
1763   /**
1764    * we still have some left
1765    * check if authority in ns is fresh
1766    * and exists
1767    * or we are authority
1768    **/
1769   if ((rh->status & (EXISTS | !EXPIRED)) ||
1770       !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1771                              &rh->authority_chain_tail->zone))
1772   {
1773     if (is_canonical(rh->name))
1774     {
1775       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1776                  "GNS_PHASE_DELEGATE_NS-%d: Resolving canonical record %s\n",
1777                  rh->id,
1778                  rh->name);
1779       rh->proc = &handle_record_ns;
1780       resolve_record_ns(rh);
1781     }
1782     else
1783     {
1784       /* give up, cannot resolve */
1785       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1786           "GNS_PHASE_DELEGATE_NS-%d: Cannot fully resolve delegation for %s!\n",
1787           rh->id,
1788           rh->name);
1789       finish_lookup(rh, rlh, rd_count, rd);
1790       //rlh->proc(rlh->proc_cls, 0, NULL);
1791     }
1792     return;
1793   }
1794   
1795   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1796       "GNS_PHASE_DELEGATE_NS-%d: Trying to resolve delegation for %s via DHT\n",
1797       rh->id, rh->name);
1798   rh->proc = &handle_delegation_dht;
1799   resolve_delegation_dht(rh);
1800 }
1801
1802
1803
1804 /**
1805  * This is a callback function that should give us only PKEY
1806  * records. Used to query the namestore for the authority (PKEY)
1807  * for 'name'. It will recursively try to resolve the
1808  * authority for a given name from the namestore.
1809  *
1810  * @param cls the pending query
1811  * @param key the key of the zone we did the lookup
1812  * @param expiration expiration date of the record data set in the namestore
1813  * @param name the name for which we need an authority
1814  * @param rd_count the number of records with 'name'
1815  * @param rd the record data
1816  * @param signature the signature of the authority for the record data
1817  */
1818 static void
1819 process_delegation_result_ns(void* cls,
1820                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1821                    struct GNUNET_TIME_Absolute expiration,
1822                    const char *name,
1823                    unsigned int rd_count,
1824                    const struct GNUNET_NAMESTORE_RecordData *rd,
1825                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1826 {
1827   struct ResolverHandle *rh;
1828   struct GNUNET_TIME_Relative remaining_time;
1829   struct GNUNET_CRYPTO_ShortHashCode zone;
1830   char new_name[MAX_DNS_NAME_LENGTH];
1831  
1832   rh = (struct ResolverHandle *)cls; 
1833   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1834              "GNS_PHASE_DELEGATE_NS-%d: Got %d records from authority lookup\n",
1835              rh->id, rd_count);
1836
1837   GNUNET_CRYPTO_short_hash(key,
1838                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1839                      &zone);
1840   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1841   
1842   rh->status = 0;
1843   
1844   if (name != NULL)
1845   {
1846     rh->status |= EXISTS;
1847   }
1848   
1849   if (remaining_time.rel_value == 0)
1850   {
1851     rh->status |= EXPIRED;
1852   }
1853   
1854   /**
1855    * No authority found in namestore.
1856    */
1857   if (rd_count == 0)
1858   {
1859     /**
1860      * We did not find an authority in the namestore
1861      */
1862     
1863     /**
1864      * No PKEY in zone.
1865      * Promote this authority back to a name maybe it is
1866      * our record.
1867      */
1868     if (strcmp(rh->name, "") == 0)
1869     {
1870       /* simply promote back */
1871       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1872                  "GNS_PHASE_DELEGATE_NS-%d: Promoting %s back to name\n",
1873                  rh->id, rh->authority_name);
1874       strcpy(rh->name, rh->authority_name);
1875     }
1876     else
1877     {
1878       /* add back to existing name */
1879       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1880                  "GNS_PHASE_DELEGATE_NS-%d: Adding %s back to %s\n",
1881                  rh->id, rh->authority_name, rh->name);
1882       //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1883       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
1884                       rh->name, rh->authority_name);
1885       //strcpy(new_name, rh->name);
1886       //strcpy(new_name+strlen(new_name), ".");
1887       //strcpy(new_name+strlen(new_name), rh->authority_name);
1888       strcpy(rh->name, new_name);
1889       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1890                  "GNS_PHASE_DELEGATE_NS-%d: %s restored\n", rh->id, rh->name);
1891     }
1892     rh->proc(rh->proc_cls, rh, 0, NULL);
1893     return;
1894   }
1895
1896   /**
1897    * We found an authority that may be able to help us
1898    * move on with query
1899    * Note only 1 pkey should have been returned.. anything else would be strange
1900    */
1901   int i;
1902   for (i=0; i<rd_count;i++)
1903   {
1904   
1905     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1906       continue;
1907     
1908     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1909          == 0)
1910     {
1911       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1912                  "GNS_PHASE_DELEGATE_NS-%d: This pkey is expired.\n",
1913                  rh->id);
1914       if (remaining_time.rel_value == 0)
1915       {
1916         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1917                    "GNS_PHASE_DELEGATE_NS-%d: This dht entry is expired.\n",
1918                    rh->id);
1919         rh->authority_chain_head->fresh = 0;
1920         rh->proc(rh->proc_cls, rh, 0, NULL);
1921         return;
1922       }
1923
1924       continue;
1925     }
1926
1927     /**
1928      * Resolve rest of query with new authority
1929      */
1930     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1931     memcpy(&rh->authority, rd[i].data,
1932            sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1933     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1934     auth->zone = rh->authority;
1935     memset(auth->name, 0, strlen(rh->authority_name)+1);
1936     strcpy(auth->name, rh->authority_name);
1937     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1938                                  rh->authority_chain_tail,
1939                                  auth);
1940     
1941     /** try to import pkey if private key available */
1942     if (rh->priv_key)
1943       process_discovered_authority((char*)name, auth->zone,
1944                                    rh->authority_chain_tail->zone,
1945                                    rh->priv_key);
1946     /**
1947      * We are done with PKEY resolution if name is empty
1948      * else resolve again with new authority
1949      */
1950     if (strcmp(rh->name, "") == 0)
1951       rh->proc(rh->proc_cls, rh, rd_count, rd);
1952     else
1953       resolve_delegation_ns(rh);
1954     return;
1955   }
1956     
1957   /**
1958    * no answers found
1959    */
1960   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1961     "GNS_PHASE_DELEGATE_NS-%d: Authority lookup and no PKEY...\n", rh->id);
1962   rh->proc(rh->proc_cls, rh, 0, NULL);
1963 }
1964
1965
1966 /**
1967  * Resolve the delegation chain for the request in our namestore
1968  *
1969  * @param rh the resolver handle
1970  */
1971 static void
1972 resolve_delegation_ns(struct ResolverHandle *rh)
1973 {
1974   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1975              "GNS_PHASE_DELEGATE_NS-%d: Resolving delegation for %s\n",
1976              rh->id, rh->name);
1977   pop_tld(rh->name, rh->authority_name);
1978   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1979                                  &rh->authority,
1980                                  rh->authority_name,
1981                                  GNUNET_GNS_RECORD_PKEY,
1982                                  &process_delegation_result_ns,
1983                                  rh);
1984
1985 }
1986
1987
1988 /**
1989  * Lookup of a record in a specific zone
1990  * calls lookup result processor on result
1991  *
1992  * @param zone the root zone
1993  * @param record_type the record type to look up
1994  * @param name the name to look up
1995  * @param key a private key for use with PSEU import (can be NULL)
1996  * @param timeout timeout for resolution
1997  * @param proc the processor to call on result
1998  * @param cls the closure to pass to proc
1999  */
2000 void
2001 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
2002                            uint32_t record_type,
2003                            const char* name,
2004                            struct GNUNET_CRYPTO_RsaPrivateKey *key,
2005                            struct GNUNET_TIME_Relative timeout,
2006                            RecordLookupProcessor proc,
2007                            void* cls)
2008 {
2009   struct ResolverHandle *rh;
2010   struct RecordLookupHandle* rlh;
2011   char string_hash[MAX_DNS_LABEL_LENGTH];
2012   char nzkey[MAX_DNS_LABEL_LENGTH];
2013   char* nzkey_ptr = nzkey;
2014
2015   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2016               "Starting resolution for %s (type=%d)!\n",
2017               name, record_type);
2018
2019   
2020   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
2021   {
2022     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2023                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
2024     proc(cls, 0, NULL);
2025     return;
2026   }
2027   
2028   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2029   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2030
2031   rh->authority = zone;
2032   rh->id = rid++;
2033   rh->proc_cls = rlh;
2034   rh->priv_key = key;
2035   rh->timeout = timeout;
2036   rh->get_handle = NULL;
2037   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2038   {
2039     /*
2040      * Set timeout for authority lookup phase to 1/2
2041      */
2042     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2043                 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
2044     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
2045                                 GNUNET_TIME_relative_divide(timeout, 2),
2046                                                 &handle_lookup_timeout,
2047                                                 rh);
2048     rh->timeout_cont = &dht_authority_lookup_timeout;
2049     rh->timeout_cont_cls = rh;
2050   }
2051   else
2052   {
2053     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2054     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2055   }
2056   
2057   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2058   {
2059     /**
2060      * Only 'gnunet' given
2061      */
2062     strcpy(rh->name, "\0");
2063   }
2064   else
2065   {
2066     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2067                 "Checking for TLD...\n");
2068     if (is_zkey_tld(name) == GNUNET_YES)
2069     {
2070       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2071                   "TLD is zkey\n");
2072       /**
2073        * This is a zkey tld
2074        * build hash and use as initial authority
2075        */
2076       memset(rh->name, 0,
2077              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2078       memcpy(rh->name, name,
2079              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2080       pop_tld(rh->name, string_hash);
2081
2082       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2083                   "ZKEY is %s!\n", string_hash);
2084       
2085       GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2086
2087       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2088                                                       &rh->authority))
2089       {
2090         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2091                     "Cannot convert ZKEY %s to hash!\n", string_hash);
2092         GNUNET_free(rh);
2093         GNUNET_free(rlh);
2094         proc(cls, 0, NULL);
2095         return;
2096       }
2097
2098     }
2099     else
2100     {
2101       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2102                   "TLD is gnunet\n");
2103       /**
2104        * Presumably GNUNET tld
2105        */
2106       memset(rh->name, 0,
2107              strlen(name)-strlen(GNUNET_GNS_TLD));
2108       memcpy(rh->name, name,
2109              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2110     }
2111   }
2112   
2113   /**
2114    * Initialize authority chain
2115    */
2116   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2117   rh->authority_chain_head->prev = NULL;
2118   rh->authority_chain_head->next = NULL;
2119   rh->authority_chain_tail = rh->authority_chain_head;
2120   rh->authority_chain_head->zone = rh->authority;
2121   
2122   /**
2123    * Copy original query into lookup handle
2124    */
2125   rlh->record_type = record_type;
2126   memset(rlh->name, 0, strlen(name) + 1);
2127   strcpy(rlh->name, name);
2128   rlh->proc = proc;
2129   rlh->proc_cls = cls;
2130
2131   rh->proc = &handle_delegation_ns;
2132   resolve_delegation_ns(rh);
2133 }
2134
2135 /******** END Record Resolver ***********/
2136
2137
2138 /**
2139  * Callback calles by namestore for a zone to name
2140  * result
2141  *
2142  * @param cls the closure
2143  * @param zone_key the zone we queried
2144  * @param expire the expiration time of the name
2145  * @param name the name found or NULL
2146  * @param rd_len number of records for the name
2147  * @param rd the record data (PKEY) for the name
2148  * @param signature the signature for the record data
2149  */
2150 static void
2151 process_zone_to_name_shorten(void *cls,
2152                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2153                  struct GNUNET_TIME_Absolute expire,
2154                  const char *name,
2155                  unsigned int rd_len,
2156                  const struct GNUNET_NAMESTORE_RecordData *rd,
2157                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2158 {
2159   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2160   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2161   struct AuthorityChain *next_authority;
2162
2163   char result[MAX_DNS_NAME_LENGTH];
2164   char next_authority_name[MAX_DNS_LABEL_LENGTH];
2165   size_t answer_len;
2166   
2167   /* we found a match in our own zone */
2168   if (rd_len != 0)
2169   {
2170     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2171                "result strlen %d\n", strlen(name));
2172     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2173     memset(result, 0, answer_len);
2174     if (strlen(rh->name) > 0)
2175     {
2176       strcpy(result, rh->name);
2177       strcpy(result+strlen(rh->name), ".");
2178     }
2179     
2180     strcpy(result+strlen(result), name);
2181     strcpy(result+strlen(result), ".");
2182     strcpy(result+strlen(result), GNUNET_GNS_TLD);
2183     
2184     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2185                "Sending shorten result %s\n", result);
2186
2187     nsh->proc(nsh->proc_cls, result);
2188     GNUNET_free(nsh);
2189     free_resolver_handle(rh);
2190   }
2191   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2192                                         &local_zone) == 0)
2193   {
2194     /* our zone, just append .gnunet */
2195     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2196     memset(result, 0, answer_len);
2197     strcpy(result, rh->name);
2198     strcpy(result+strlen(rh->name), ".");
2199     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2200
2201     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2202                "Our zone: Sending name as shorten result %s\n", rh->name);
2203     
2204     nsh->proc(nsh->proc_cls, result);
2205     GNUNET_free(nsh);
2206     free_resolver_handle(rh);
2207   }
2208   else
2209   {
2210     /**
2211      * No PSEU found.
2212      * continue with next authority
2213      */
2214     next_authority = rh->authority_chain_head;
2215     //                         strlen(next_authority->name) + 2);
2216     memset(next_authority_name, 0, strlen(rh->name)+
2217                       strlen(next_authority->name) + 2);
2218     GNUNET_snprintf(next_authority_name, MAX_DNS_NAME_LENGTH,
2219                     "%s.%s", rh->name, next_authority->name);
2220     //strcpy(next_authority_name, rh->name);
2221     //strcpy(next_authority_name+strlen(rh->name)+1, ".");
2222     //strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
2223     
2224     strcpy(rh->name, next_authority_name);
2225     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2226                "No PSEU found for authority %s. Promoting back: %s\n",
2227                next_authority->name, rh->name);
2228     
2229     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2230                               rh->authority_chain_tail,
2231                               next_authority);
2232
2233     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2234                                    &rh->authority_chain_tail->zone,
2235                                    &rh->authority_chain_head->zone,
2236                                    &process_zone_to_name_shorten,
2237                                    rh);
2238   }
2239 }
2240
2241 /**
2242  * DHT resolution for delegation finished. Processing result.
2243  *
2244  * @param cls the closure
2245  * @param rh resolver handle
2246  * @param rd_count number of results (always 0)
2247  * @param rd record data (always NULL)
2248  */
2249 static void
2250 handle_delegation_dht_bg_shorten(void* cls, struct ResolverHandle *rh,
2251                           unsigned int rd_count,
2252                           const struct GNUNET_NAMESTORE_RecordData *rd)
2253 {
2254   
2255   /* We resolved full name for delegation. resolving record */
2256   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2257     "GNS_SHORTEN: Resolved up to %s for delegation via DHT in background.\n",
2258     rh->name);
2259   free_resolver_handle(rh);
2260 }
2261
2262 /**
2263  * Process result from namestore delegation lookup
2264  * for shorten operation
2265  *
2266  * @param cls the client shorten handle
2267  * @param rh the resolver handle
2268  * @param rd_count number of results (0)
2269  * @param rd data (NULL)
2270  */
2271 void
2272 handle_delegation_ns_shorten(void* cls,
2273                       struct ResolverHandle *rh,
2274                       uint32_t rd_count,
2275                       const struct GNUNET_NAMESTORE_RecordData *rd)
2276 {
2277   struct NameShortenHandle *nsh;
2278   char result[MAX_DNS_NAME_LENGTH];
2279   size_t answer_len;
2280   struct ResolverHandle *rh_bg;
2281
2282   nsh = (struct NameShortenHandle *)cls;
2283   
2284   /**
2285    * At this point rh->name contains the part of the name
2286    * that we do not have a PKEY in our namestore to resolve.
2287    * The authority chain in the resolver handle is now
2288    * useful to backtrack if needed
2289    */
2290   
2291   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2292              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2293
2294   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2295                                    &local_zone) == 0)
2296   {
2297     /**
2298      * This is our zone append .gnunet unless name is empty
2299      * (it shouldn't be, usually FIXME what happens if we
2300      * shorten to our zone to a "" record??)
2301      */
2302     
2303     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2304     memset(result, 0, answer_len);
2305     strcpy(result, rh->name);
2306     strcpy(result+strlen(rh->name), ".");
2307     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2308
2309     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2310                "Our zone: Sending name as shorten result %s\n", rh->name);
2311     
2312     nsh->proc(nsh->proc_cls, result);
2313     GNUNET_free(nsh);
2314     free_resolver_handle(rh);
2315     return;
2316   }
2317   
2318   /**
2319    * we have to this before zone to name for rh might
2320    * be freed by then
2321    */
2322   rh_bg = NULL;
2323   if (!is_canonical(rh->name))
2324   {
2325     rh_bg = GNUNET_malloc(sizeof(struct ResolverHandle));
2326     memcpy(rh_bg, rh, sizeof(struct ResolverHandle));
2327     rh_bg->id = rid++;
2328   }
2329
2330   /* backtrack authorities for names */
2331   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2332                                  &rh->authority_chain_tail->zone, //ours
2333                                  &rh->authority_chain_head->zone,
2334                                  &process_zone_to_name_shorten,
2335                                  rh);
2336   
2337   if (rh_bg == NULL)
2338   {
2339     return;
2340   }
2341
2342   /**
2343    * If authority resolution is incomplete we can do a background lookup
2344    * of the full name so that next time we can (likely) fully or at least
2345    * further shorten the name
2346    */
2347   rh_bg->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2348   rh_bg->authority_chain_tail = rh_bg->authority_chain_head;
2349   rh_bg->authority_chain_head->zone = rh_bg->authority;
2350   
2351   rh_bg->proc = &handle_delegation_dht_bg_shorten;
2352   rh_bg->proc_cls = NULL;
2353   
2354   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2355              "GNS_SHORTEN: Starting background lookup for %s\n",
2356              rh_bg->name);
2357
2358   resolve_delegation_dht(rh_bg);
2359
2360 }
2361
2362
2363 /**
2364  * Callback calles by namestore for a zone to name
2365  * result
2366  *
2367  * @param cls the closure
2368  * @param zone_key the zone we queried
2369  * @param expire the expiration time of the name
2370  * @param name the name found or NULL
2371  * @param rd_len number of records for the name
2372  * @param rd the record data (PKEY) for the name
2373  * @param signature the signature for the record data
2374  */
2375 static void
2376 process_zone_to_name_zkey(void *cls,
2377                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2378                  struct GNUNET_TIME_Absolute expire,
2379                  const char *name,
2380                  unsigned int rd_len,
2381                  const struct GNUNET_NAMESTORE_RecordData *rd,
2382                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2383 {
2384   struct ResolverHandle *rh = cls;
2385   struct NameShortenHandle *nsh = rh->proc_cls;
2386   struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
2387   char new_name[MAX_DNS_NAME_LENGTH];
2388
2389   /* zkey not in our zone */
2390   if (name == NULL)
2391   {
2392     /**
2393      * In this case we have not given this PKEY a name (yet)
2394      * It is either just not in our zone or not even cached
2395      * Since we do not know at this point we will not try to shorten
2396      * because PKEY import will happen if the user follows the zkey
2397      * link.
2398      */
2399     GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
2400                                      &enc);
2401     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2402                "No name found for zkey %s returning verbatim!\n", enc);
2403     if (strcmp(rh->name, "") != 0)
2404       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
2405                       rh->name, enc, GNUNET_GNS_TLD_ZKEY);
2406     else
2407       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2408                       enc, GNUNET_GNS_TLD_ZKEY);
2409     nsh->proc(nsh->proc_cls, new_name);
2410     GNUNET_free(nsh);
2411     free_resolver_handle(rh);
2412     return;
2413   }
2414   
2415   if (strcmp(rh->name, "") != 0)
2416     GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2417                     rh->name, name);
2418   else
2419     strcpy(new_name, name);
2420
2421   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2422              "Continue shorten for %s!\n", new_name);
2423
2424   strcpy(rh->name, new_name);
2425   
2426   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2427   rh->authority_chain_tail = rh->authority_chain_head;
2428   rh->authority_chain_head->zone = rh->authority;
2429   
2430   
2431   /* Start delegation resolution in our namestore */
2432   resolve_delegation_ns(rh);
2433 }
2434   
2435 /**
2436  * Shorten api from resolver
2437  *
2438  * @param zone the zone to use
2439  * @param name the name to shorten
2440  * @param key optional private key for background lookups and PSEU import
2441  * @param proc the processor to call with result
2442  * @param proc_cls closure to pass to proc
2443  */
2444 void
2445 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2446                           const char* name,
2447                           struct GNUNET_CRYPTO_RsaPrivateKey *key,
2448                           ShortenResultProcessor proc,
2449                           void* proc_cls)
2450 {
2451   struct ResolverHandle *rh;
2452   struct NameShortenHandle *nsh;
2453   char string_hash[MAX_DNS_LABEL_LENGTH];
2454   struct GNUNET_CRYPTO_ShortHashCode zkey;
2455   char nzkey[MAX_DNS_LABEL_LENGTH];
2456   char* nzkey_ptr = nzkey;
2457
2458
2459   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2460               "Starting shorten for %s!\n", name);
2461   
2462   if (is_canonical((char*)name))
2463   {
2464     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2465                 "%s is canonical. Returning verbatim\n", name);
2466     proc(proc_cls, name);
2467     return;
2468   }
2469
2470   nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2471
2472   nsh->proc = proc;
2473   nsh->proc_cls = proc_cls;
2474   
2475   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2476   rh->authority = zone;
2477   rh->id = rid++;
2478   rh->priv_key = key;
2479   rh->proc = &handle_delegation_ns_shorten;
2480   rh->proc_cls = nsh;
2481   rh->id = rid++;
2482   
2483   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2484                 "Checking for TLD...\n");
2485   if (is_zkey_tld(name) == GNUNET_YES)
2486   {
2487     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2488                 "TLD is zkey\n");
2489     /**
2490      * This is a zkey tld
2491      * build hash and use as initial authority
2492      * FIXME sscanf
2493      */
2494     memset(rh->name, 0,
2495            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2496     memcpy(rh->name, name,
2497            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2498     pop_tld(rh->name, string_hash);
2499
2500     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2501                 "ZKEY is %s!\n", string_hash);
2502     
2503     GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2504
2505     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2506                                                           &zkey))
2507     {
2508       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2509                   "Cannot convert ZKEY %s to hash!\n", nzkey);
2510       GNUNET_free(rh);
2511       GNUNET_free(nsh);
2512       proc(proc_cls, name);
2513       return;
2514     }
2515
2516     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2517                                    &zone, //ours
2518                                    &zkey,
2519                                    &process_zone_to_name_zkey,
2520                                    rh);
2521     return;
2522
2523   }
2524   else
2525   {
2526     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2527                 "TLD is gnunet\n");
2528     /**
2529      * Presumably GNUNET tld
2530      */
2531     memset(rh->name, 0,
2532            strlen(name)-strlen(GNUNET_GNS_TLD));
2533     memcpy(rh->name, name,
2534            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2535   }
2536
2537   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2538   rh->authority_chain_tail = rh->authority_chain_head;
2539   rh->authority_chain_head->zone = zone;
2540   
2541   
2542   /* Start delegation resolution in our namestore */
2543   resolve_delegation_ns(rh);
2544 }
2545
2546 /*********** END NAME SHORTEN ********************/
2547
2548
2549 /**
2550  * Process result from namestore delegation lookup
2551  * for get authority operation
2552  *
2553  * @param cls the client get auth handle
2554  * @param rh the resolver handle
2555  * @param rd_count number of results (0)
2556  * @param rd data (NULL)
2557  */
2558 void
2559 handle_delegation_result_ns_get_auth(void* cls,
2560                       struct ResolverHandle *rh,
2561                       uint32_t rd_count,
2562                       const struct GNUNET_NAMESTORE_RecordData *rd)
2563 {
2564   struct GetNameAuthorityHandle* nah;
2565   char result[MAX_DNS_NAME_LENGTH];
2566   size_t answer_len;
2567
2568   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2569   
2570   /**
2571    * At this point rh->name contains the part of the name
2572    * that we do not have a PKEY in our namestore to resolve.
2573    * The authority chain in the resolver handle is now
2574    * useful to backtrack if needed
2575    */
2576   
2577   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2578              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2579
2580   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2581              "Building response!\n");
2582   if (is_canonical(rh->name))
2583   {
2584     /**
2585      * We successfully resolved the authority in the ns
2586      * FIXME for our purposes this is fine
2587      * but maybe we want to have an api that also looks
2588      * into the dht (i.e. option in message)
2589      **/
2590     if (strlen(rh->name) > strlen(nah->name))
2591     {
2592       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2593                  "Record name longer than original lookup name... odd!\n");
2594       //FIXME to sth here
2595     }
2596
2597     answer_len = strlen(nah->name) - strlen(rh->name)
2598       + strlen(GNUNET_GNS_TLD) + 1;
2599     memset(result, 0, answer_len);
2600     strcpy(result, nah->name + strlen(rh->name) + 1);
2601
2602     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2603                "Got authority result %s\n", result);
2604     
2605     nah->proc(nah->proc_cls, result);
2606     GNUNET_free(nah);
2607     free_resolver_handle(rh);
2608   }
2609   else
2610   {
2611     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2612                "Unable to resolve authority for remaining %s!\n", rh->name);
2613     nah->proc(nah->proc_cls, "");
2614     GNUNET_free(nah);
2615     free_resolver_handle(rh);
2616   }
2617
2618
2619 }
2620
2621
2622 /**
2623  * Tries to resolve the authority for name
2624  * in our namestore
2625  *
2626  * @param zone the root zone to look up for
2627  * @param name the name to lookup up
2628  * @param proc the processor to call when finished
2629  * @param proc_cls the closure to pass to the processor
2630  */
2631 void
2632 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2633                            const char* name,
2634                            GetAuthorityResultProcessor proc,
2635                            void* proc_cls)
2636 {
2637   struct ResolverHandle *rh;
2638   struct GetNameAuthorityHandle *nah;
2639
2640   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2641               "Starting authority resolution for %s!\n", name);
2642
2643   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2644   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2645   rh->authority = zone;
2646   rh->id = rid++;
2647   
2648   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2649   {
2650     strcpy(rh->name, "\0");
2651   }
2652   else
2653   {
2654     memset(rh->name, 0,
2655            strlen(name)-strlen(GNUNET_GNS_TLD));
2656     memcpy(rh->name, name,
2657            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2658   }
2659
2660   memset(nah->name, 0,
2661          strlen(name)+1);
2662   strcpy(nah->name, name);
2663   
2664   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2665   rh->authority_chain_tail = rh->authority_chain_head;
2666   rh->authority_chain_head->zone = zone;
2667   rh->proc = &handle_delegation_result_ns_get_auth;
2668   rh->proc_cls = (void*)nah;
2669
2670   nah->proc = proc;
2671   nah->proc_cls = proc_cls;
2672
2673   /* Start delegation resolution in our namestore */
2674   resolve_delegation_ns(rh);
2675
2676 }
2677
2678 /******** END GET AUTHORITY *************/
2679
2680 /* end of gnunet-service-gns_resolver.c */