0b11e980f1ee282d8f90935f80fe08fb8726df91
[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  * Initialize the resolver
59  *
60  * @param nh the namestore handle
61  * @param dh the dht handle
62  * @return GNUNET_OK on success
63  */
64 int
65 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
66                   struct GNUNET_DHT_Handle *dh)
67 {
68   namestore_handle = nh;
69   dht_handle = dh;
70   if ((namestore_handle != NULL) && (dht_handle != NULL))
71   {
72     return GNUNET_OK;
73   }
74   return GNUNET_SYSERR;
75 }
76
77 /**
78  * Set the callback to call when we discover a
79  * new authority via the DHT
80  *
81  * @param adb the callback to set
82  *
83 void
84 gns_resolver_set_auth_discovered_cb(AuthorityDiscoveredProcessor adb)
85 {
86   auth_discovered = adb;
87 }
88 */
89
90 /**
91  * Helper function to free resolver handle
92  *
93  * @rh the handle to free
94  */
95 static void
96 free_resolver_handle(struct ResolverHandle* rh)
97 {
98   struct AuthorityChain *ac;
99   struct AuthorityChain *ac_next;
100
101   if (NULL == rh)
102     return;
103
104   GNUNET_free_non_null (rh->name);
105   GNUNET_free_non_null (rh->authority_name);
106
107   ac = rh->authority_chain_head;
108
109   while (NULL != ac)
110   {
111     ac_next = ac->next;
112     GNUNET_free_non_null (ac->name);
113     GNUNET_free(ac);
114     ac = ac_next;
115   }
116   GNUNET_free(rh);
117 }
118
119
120 /**
121  * Callback when record data is put into namestore
122  *
123  * @param cls the closure
124  * @param success GNUNET_OK on success
125  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
126  */
127 void
128 on_namestore_record_put_result(void *cls,
129                                int32_t success,
130                                const char *emsg)
131 {
132   if (GNUNET_NO == success)
133   {
134     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
135     return;
136   }
137   else if (GNUNET_YES == success)
138   {
139     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
140                "records successfully put in namestore\n");
141     return;
142   }
143
144   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
145              "Error putting records into namestore: %s\n", emsg);
146 }
147
148
149 /**
150  * Handle timeout for DHT requests
151  *
152  * @param cls the request handle as closure
153  * @param tc the task context
154  */
155 static void
156 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
157 {
158   struct ResolverHandle *rh = cls;
159
160   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
161              "dht lookup for query %s timed out.\n",
162              rh->name);
163
164   GNUNET_DHT_get_stop (rh->get_handle);
165   rh->proc(rh->proc_cls, rh, 0, NULL);
166 }
167
168
169 /**
170  * Function called when we get a result from the dht
171  * for our record query
172  *
173  * @param cls the request handle
174  * @param exp lifetime
175  * @param key the key the record was stored under
176  * @param get_path get path
177  * @param get_path_length get path length
178  * @param put_path put path
179  * @param put_path_length put path length
180  * @param type the block type
181  * @param size the size of the record
182  * @param data the record data
183  */
184 static void
185 process_record_result_dht(void* cls,
186                  struct GNUNET_TIME_Absolute exp,
187                  const GNUNET_HashCode * key,
188                  const struct GNUNET_PeerIdentity *get_path,
189                  unsigned int get_path_length,
190                  const struct GNUNET_PeerIdentity *put_path,
191                  unsigned int put_path_length,
192                  enum GNUNET_BLOCK_Type type,
193                  size_t size, const void *data)
194 {
195   struct ResolverHandle *rh;
196   struct RecordLookupHandle *rlh;
197   struct GNSNameRecordBlock *nrb;
198   uint32_t num_records;
199   char* name = NULL;
200   char* rd_data = (char*)data;
201   int i;
202   int rd_size;
203   
204   GNUNET_HashCode zone, name_hash;
205   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
206   
207   if (data == NULL)
208     return;
209
210   //FIXME maybe check expiration here, check block type
211   
212   rh = (struct ResolverHandle *)cls;
213   rlh = (struct RecordLookupHandle *) rh->proc_cls;
214   nrb = (struct GNSNameRecordBlock*)data;
215   
216   /* stop lookup and timeout task */
217   GNUNET_DHT_get_stop (rh->get_handle);
218   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
219   
220   rh->get_handle = NULL;
221   name = (char*)&nrb[1];
222   num_records = ntohl(nrb->rd_count);
223   {
224     struct GNUNET_NAMESTORE_RecordData rd[num_records];
225
226     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
227     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
228   
229     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
230                                                                rd_data,
231                                                                num_records,
232                                                                rd))
233     {
234       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
235       return;
236     }
237
238     for (i=0; i<num_records; i++)
239     {
240       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
241                "Got name: %s (wanted %s)\n", name, rh->name);
242       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
243                "Got type: %d\n",
244                rd[i].record_type);
245       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
246                "Got data length: %d\n", rd[i].data_size);
247       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
248                "Got flag %d\n", rd[i].flags);
249     
250      if ((strcmp(name, rh->name) == 0) &&
251          (rd[i].record_type == rlh->record_type))
252       {
253         rh->answered++;
254       }
255
256     }
257
258     GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
259     GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
260   
261     /**
262      * FIXME check pubkey against existing key in namestore?
263      * https://gnunet.org/bugs/view.php?id=2179
264      */
265
266     /* Save to namestore */
267     GNUNET_NAMESTORE_record_put (namestore_handle,
268                                  &nrb->public_key,
269                                  name,
270                                  exp,
271                                  num_records,
272                                  rd,
273                                  &nrb->signature,
274                                  &on_namestore_record_put_result, //cont
275                                  NULL); //cls
276   
277     if (rh->answered)
278       rh->proc(rh->proc_cls, rh, num_records, rd);
279     else
280       rh->proc(rh->proc_cls, rh, 0, NULL);
281   }
282
283 }
284
285
286 /**
287  * Start DHT lookup for a (name -> query->record_type) record in
288  * rh->authority's zone
289  *
290  * @param rh the pending gns query context
291  */
292 static void
293 resolve_record_dht(struct ResolverHandle *rh)
294 {
295   uint32_t xquery;
296   GNUNET_HashCode name_hash;
297   GNUNET_HashCode lookup_key;
298   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
299   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
300   
301   GNUNET_CRYPTO_hash(rh->name, strlen(rh->name), &name_hash);
302   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
303   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
304   
305   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
306              "starting dht lookup for %s with key: %s\n",
307              rh->name, (char*)&lookup_key_string);
308
309   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
310                                                       &dht_lookup_timeout, rh);
311
312   xquery = htonl(rlh->record_type);
313   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
314                        DHT_OPERATION_TIMEOUT,
315                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
316                        &lookup_key,
317                        DHT_GNS_REPLICATION_LEVEL,
318                        GNUNET_DHT_RO_NONE,
319                        &xquery, 
320                        sizeof(xquery),
321                        &process_record_result_dht,
322                        rh);
323
324 }
325
326
327 /**
328  * Namestore calls this function if we have record for this name.
329  * (or with rd_count=0 to indicate no matches)
330  *
331  * @param cls the pending query
332  * @param key the key of the zone we did the lookup
333  * @param expiration expiration date of the namestore entry
334  * @param name the name for which we need an authority
335  * @param rd_count the number of records with 'name'
336  * @param rd the record data
337  * @param signature the signature of the authority for the record data
338  */
339 static void
340 process_record_result_ns(void* cls,
341                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
342                   struct GNUNET_TIME_Absolute expiration,
343                   const char *name, unsigned int rd_count,
344                   const struct GNUNET_NAMESTORE_RecordData *rd,
345                   const struct GNUNET_CRYPTO_RsaSignature *signature)
346 {
347   struct ResolverHandle *rh;
348   struct RecordLookupHandle *rlh;
349   struct GNUNET_TIME_Relative remaining_time;
350   GNUNET_HashCode zone;
351
352   rh = (struct ResolverHandle *) cls;
353   rlh = (struct RecordLookupHandle *)rh->proc_cls;
354   GNUNET_CRYPTO_hash(key,
355                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
356                      &zone);
357   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
358
359   rh->status = 0;
360   
361   if (name != NULL)
362   {
363     rh->status |= EXISTS;
364   }
365   
366   if (remaining_time.rel_value == 0)
367   {
368     rh->status |= EXPIRED;
369   }
370   
371   if (rd_count == 0)
372   {
373     /**
374      * Lookup terminated and no results
375      */
376     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
377                "Namestore lookup for %s terminated without results\n", name);
378
379     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
380                "Record %s unknown in namestore\n",
381                rh->name);
382     /**
383      * Our zone and no result? Cannot resolve TT
384      */
385     rh->proc(rh->proc_cls, rh, 0, NULL);
386     return;
387
388   }
389   else
390   {
391     
392     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
393                "Processing additional result %s from namestore\n", name);
394     int i;
395     for (i=0; i<rd_count;i++)
396     {
397       
398       if (rd[i].record_type != rlh->record_type)
399         continue;
400       
401       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
402           == 0)
403       {
404         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
405                    "This record is expired. Skipping\n");
406         continue;
407       }
408       
409       rh->answered++;
410       
411     }
412     
413     /**
414      * no answers found
415      */
416     if (rh->answered == 0)
417     {
418       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
419                  "No answers found. This is odd!\n");
420       rh->proc(rh->proc_cls, rh, 0, NULL);
421       return;
422     }
423     
424     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
425                rh->answered);
426
427     rh->proc(rh->proc_cls, rh, rd_count, rd);
428   }
429 }
430
431
432 /**
433  * The final phase of resolution.
434  * rh->name is a name that is canonical and we do not have a delegation.
435  * Query namestore for this record
436  *
437  * @param rh the pending lookup
438  */
439 static void
440 resolve_record_ns(struct ResolverHandle *rh)
441 {
442   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
443   
444   /**
445    * Try to resolve this record in our namestore.
446    * The name to resolve is now in rh->authority_name
447    * since we tried to resolve it to an authority
448    * and failed.
449    **/
450   GNUNET_NAMESTORE_lookup_record(namestore_handle,
451                                  &rh->authority,
452                                  rh->name,
453                                  rlh->record_type,
454                                  &process_record_result_ns,
455                                  rh);
456 }
457
458
459 /**
460  * Handle timeout for DHT requests
461  *
462  * @param cls the request handle as closure
463  * @param tc the task context
464  */
465 static void
466 dht_authority_lookup_timeout(void *cls,
467                              const struct GNUNET_SCHEDULER_TaskContext *tc)
468 {
469   struct ResolverHandle *rh = cls;
470
471   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
472              "dht lookup for query %s timed out.\n",
473              rh->name);
474
475   GNUNET_DHT_get_stop (rh->get_handle);
476   if (strcmp(rh->name, "") == 0)
477   {
478     /*
479      * promote authority back to name and try to resolve record
480      */
481     strcpy(rh->name, rh->authority_name);
482   }
483   rh->proc(rh->proc_cls, rh, 0, NULL);
484 }
485
486 /* Prototype */
487 static void resolve_delegation_dht(struct ResolverHandle *rh);
488
489 /**
490  * Function called when we get a result from the dht
491  * for our query. Recursively tries to resolve authorities
492  * for name in DHT.
493  *
494  * @param cls the request handle
495  * @param exp lifetime
496  * @param key the key the record was stored under
497  * @param get_path get path
498  * @param get_path_length get path length
499  * @param put_path put path
500  * @param put_path_length put path length
501  * @param type the block type
502  * @param size the size of the record
503  * @param data the record data
504  */
505 static void
506 process_delegation_result_dht(void* cls,
507                  struct GNUNET_TIME_Absolute exp,
508                  const GNUNET_HashCode * key,
509                  const struct GNUNET_PeerIdentity *get_path,
510                  unsigned int get_path_length,
511                  const struct GNUNET_PeerIdentity *put_path,
512                  unsigned int put_path_length,
513                  enum GNUNET_BLOCK_Type type,
514                  size_t size, const void *data)
515 {
516   struct ResolverHandle *rh;
517   struct GNSNameRecordBlock *nrb;
518   uint32_t num_records;
519   char* name = NULL;
520   char* rd_data = (char*) data;
521   int i;
522   int rd_size;
523   GNUNET_HashCode zone, name_hash;
524   
525   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
526
527   if (data == NULL)
528     return;
529   
530   //FIXME check expiration?
531   
532   rh = (struct ResolverHandle *)cls;
533   nrb = (struct GNSNameRecordBlock*)data;
534   
535   /* stop dht lookup and timeout task */
536   GNUNET_DHT_get_stop (rh->get_handle);
537   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
538
539   rh->get_handle = NULL;
540   num_records = ntohl(nrb->rd_count);
541   name = (char*)&nrb[1];
542   {
543     struct GNUNET_NAMESTORE_RecordData rd[num_records];
544     
545     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
546     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
547   
548     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
549                                                                rd_data,
550                                                                num_records,
551                                                                rd))
552     {
553       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
554       return;
555     }
556
557     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
558                "Got name: %s (wanted %s)\n", name, rh->authority_name);
559     for (i=0; i<num_records; i++)
560     {
561     
562       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
563                 "Got name: %s (wanted %s)\n", name, rh->authority_name);
564       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
565                  "Got type: %d (wanted %d)\n",
566                  rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
567       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
568                  "Got data length: %d\n", rd[i].data_size);
569       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
570                  "Got flag %d\n", rd[i].flags);
571
572       if ((strcmp(name, rh->authority_name) == 0) &&
573           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
574       {
575         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
576         rh->answered = 1;
577         memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
578         struct AuthorityChain *auth =
579           GNUNET_malloc(sizeof(struct AuthorityChain));
580         auth->zone = rh->authority;
581         auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
582         memset(auth->name, 0, strlen(rh->authority_name)+1);
583         strcpy(auth->name, rh->authority_name);
584         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
585                                      rh->authority_chain_tail,
586                                      auth);
587       }
588
589     }
590
591
592     GNUNET_CRYPTO_hash(name, strlen(name), &name_hash);
593     GNUNET_CRYPTO_hash_xor(key, &name_hash, &zone);
594
595     /* Save to namestore */
596     if (0 != GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_tail->zone, &zone))
597     {
598       GNUNET_NAMESTORE_record_put (namestore_handle,
599                                  &nrb->public_key,
600                                  name,
601                                  exp,
602                                  num_records,
603                                  rd,
604                                  &nrb->signature,
605                                  &on_namestore_record_put_result, //cont
606                                  NULL); //cls
607     }
608   }
609   
610   if (rh->answered)
611   {
612     rh->answered = 0;
613     /**
614      * delegate
615      * FIXME in this case. should we ask namestore again?
616      */
617     if (strcmp(rh->name, "") == 0)
618       rh->proc(rh->proc_cls, rh, 0, NULL);
619     else
620       resolve_delegation_dht(rh);
621     return;
622   }
623   
624   /**
625    * No pkey but name exists
626    */
627   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup found no match!\n");
628   rh->proc(rh->proc_cls, rh, 0, NULL);
629 }
630
631
632 /**
633  * Process DHT lookup result for record.
634  *
635  * @param cls the closure
636  * @param rh resolver handle
637  * @param rd_count number of results
638  * @param rd record data
639  */
640 static void
641 handle_record_dht(void* cls, struct ResolverHandle *rh,
642                        unsigned int rd_count,
643                        const struct GNUNET_NAMESTORE_RecordData *rd)
644 {
645   struct RecordLookupHandle* rlh;
646   rlh = (struct RecordLookupHandle*)cls;
647   if (rd_count == 0)
648   {
649     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
650                "No records for %s found in DHT. Aborting\n",
651                rh->name);
652     /* give up, cannot resolve */
653     rlh->proc(rlh->proc_cls, 0, NULL);
654     GNUNET_free(rlh->name);
655     GNUNET_free(rlh);
656     free_resolver_handle(rh);
657     return;
658   }
659
660   /* results found yay */
661   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
662              "Record resolved from DHT!");
663   rlh->proc(rlh->proc_cls, rd_count, rd);
664   GNUNET_free(rlh->name);
665   GNUNET_free(rlh);
666   free_resolver_handle(rh);
667
668 }
669
670
671 /**
672  * Process namestore lookup result for record.
673  *
674  * @param cls the closure
675  * @param rh resolver handle
676  * @param rd_count number of results
677  * @param rd record data
678  */
679 static void
680 handle_record_ns(void* cls, struct ResolverHandle *rh,
681                        unsigned int rd_count,
682                        const struct GNUNET_NAMESTORE_RecordData *rd)
683 {
684   struct RecordLookupHandle* rlh;
685   rlh = (struct RecordLookupHandle*) cls;
686   if (rd_count == 0)
687   {
688     /* ns entry expired and not ours. try dht */
689     if (rh->status & (EXPIRED | !EXISTS) &&
690         GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
691                                &rh->authority_chain_tail->zone))
692     {
693       rh->proc = &handle_record_dht;
694       resolve_record_dht(rh);
695       return;
696     }
697     /* give up, cannot resolve */
698     rlh->proc(rlh->proc_cls, 0, NULL);
699     GNUNET_free(rlh->name);
700     GNUNET_free(rlh);
701     free_resolver_handle(rh);
702     return;
703   }
704
705   /* results found yay */
706   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
707              "Record resolved from namestore!");
708   rlh->proc(rlh->proc_cls, rd_count, rd);
709   GNUNET_free(rlh->name);
710   GNUNET_free(rlh);
711   free_resolver_handle(rh);
712
713 }
714
715
716 /**
717  * Determine if this name is canonical.
718  * i.e.
719  * a.b.gnunet  = not canonical
720  * a           = canonical
721  *
722  * @param name the name to test
723  * @return 1 if canonical
724  */
725 static int
726 is_canonical(char* name)
727 {
728   uint32_t len = strlen(name);
729   int i;
730
731   for (i=0; i<len; i++)
732   {
733     if (*(name+i) == '.')
734       return 0;
735   }
736   return 1;
737 }
738
739 /**
740  * Move one level up in the domain hierarchy and return the
741  * passed top level domain.
742  *
743  * @param name the domain
744  * @param dest the destination where the tld will be put
745  */
746 void
747 pop_tld(char* name, char* dest)
748 {
749   uint32_t len;
750
751   if (is_canonical(name))
752   {
753     strcpy(dest, name);
754     strcpy(name, "");
755     return;
756   }
757
758   for (len = strlen(name); len > 0; len--)
759   {
760     if (*(name+len) == '.')
761       break;
762   }
763   
764   //Was canonical?
765   if (len == 0)
766     return;
767
768   name[len] = '\0';
769
770   strcpy(dest, (name+len+1));
771 }
772
773 /**
774  * DHT resolution for delegation finished. Processing result.
775  *
776  * @param cls the closure
777  * @param rh resolver handle
778  * @param rd_count number of results (always 0)
779  * @param rd record data (always NULL)
780  */
781 static void
782 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
783                           unsigned int rd_count,
784                           const struct GNUNET_NAMESTORE_RecordData *rd)
785 {
786   struct RecordLookupHandle* rlh;
787   rlh = (struct RecordLookupHandle*) cls;
788   
789   if (strcmp(rh->name, "") == 0)
790   {
791     /* We resolved full name for delegation. resolving record */
792     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
793       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
794     rh->proc = &handle_record_ns;
795     resolve_record_ns(rh);
796     return;
797   }
798
799   /**
800    * we still have some left
801    **/
802   if (is_canonical(rh->name))
803   {
804     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
805                "Resolving canonical record %s in ns\n", rh->name);
806     rh->proc = &handle_record_ns;
807     resolve_record_ns(rh);
808     return;
809   }
810   /* give up, cannot resolve */
811   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
812              "Cannot fully resolve delegation for %s via DHT!\n",
813              rh->name);
814   rlh->proc(rlh->proc_cls, 0, NULL);
815   GNUNET_free(rlh->name);
816   GNUNET_free(rlh);
817   free_resolver_handle(rh);
818 }
819
820
821 /**
822  * Start DHT lookup for a name -> PKEY (compare NS) record in
823  * rh->authority's zone
824  *
825  * @param rh the pending gns query
826  */
827 static void
828 resolve_delegation_dht(struct ResolverHandle *rh)
829 {
830   uint32_t xquery;
831   GNUNET_HashCode name_hash;
832   GNUNET_HashCode lookup_key;
833   
834   GNUNET_CRYPTO_hash(rh->authority_name,
835                      strlen(rh->authority_name),
836                      &name_hash);
837   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
838
839   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
840                                                   &dht_authority_lookup_timeout,
841                                                        rh);
842
843   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
844   
845   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
846                        DHT_OPERATION_TIMEOUT,
847                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
848                        &lookup_key,
849                        DHT_GNS_REPLICATION_LEVEL,
850                        GNUNET_DHT_RO_NONE,
851                        &xquery,
852                        sizeof(xquery),
853                        &process_delegation_result_dht,
854                        rh);
855
856 }
857
858
859 /**
860  * Namestore resolution for delegation finished. Processing result.
861  *
862  * @param cls the closure
863  * @param rh resolver handle
864  * @param rd_count number of results (always 0)
865  * @param rd record data (always NULL)
866  */
867 static void
868 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
869                           unsigned int rd_count,
870                           const struct GNUNET_NAMESTORE_RecordData *rd)
871 {
872   struct RecordLookupHandle* rlh;
873   rlh = (struct RecordLookupHandle*) cls;
874   
875   if (strcmp(rh->name, "") == 0)
876   {
877     /* We resolved full name for delegation. resolving record */
878     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
879                "Resolved full name for delegation. resolving record ''\n");
880     rh->proc = &handle_record_ns;
881     resolve_record_ns(rh);
882     return;
883   }
884
885   /**
886    * we still have some left
887    * check if authority in ns is fresh
888    * and exists
889    * or we are authority
890    **/
891   if ((rh->status & (EXISTS | !EXPIRED)) ||
892       !GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
893                              &rh->authority_chain_tail->zone))
894   {
895     if (is_canonical(rh->name))
896     {
897       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
898                  "Resolving canonical record %s\n", rh->name);
899       rh->proc = &handle_record_ns;
900       resolve_record_ns(rh);
901     }
902     else
903     {
904       /* give up, cannot resolve */
905       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
906                  "Cannot fully resolve delegation for %s!\n",
907                  rh->name);
908       rlh->proc(rlh->proc_cls, 0, NULL);
909     }
910     return;
911   }
912   
913   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
914              "Trying to resolve delegation for %s via DHT\n",
915              rh->name);
916   rh->proc = &handle_delegation_dht;
917   resolve_delegation_dht(rh);
918 }
919
920 /* Prototype */
921 static void resolve_delegation_ns(struct ResolverHandle *rh);
922
923
924 /**
925  * This is a callback function that should give us only PKEY
926  * records. Used to query the namestore for the authority (PKEY)
927  * for 'name'. It will recursively try to resolve the
928  * authority for a given name from the namestore.
929  *
930  * @param cls the pending query
931  * @param key the key of the zone we did the lookup
932  * @param expiration expiration date of the record data set in the namestore
933  * @param name the name for which we need an authority
934  * @param rd_count the number of records with 'name'
935  * @param rd the record data
936  * @param signature the signature of the authority for the record data
937  */
938 static void
939 process_delegation_result_ns(void* cls,
940                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
941                    struct GNUNET_TIME_Absolute expiration,
942                    const char *name,
943                    unsigned int rd_count,
944                    const struct GNUNET_NAMESTORE_RecordData *rd,
945                    const struct GNUNET_CRYPTO_RsaSignature *signature)
946 {
947   struct ResolverHandle *rh;
948   struct GNUNET_TIME_Relative remaining_time;
949   GNUNET_HashCode zone;
950   char* new_name;
951   
952   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
953              rd_count);
954
955   rh = (struct ResolverHandle *)cls;
956   GNUNET_CRYPTO_hash(key,
957                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
958                      &zone);
959   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
960   
961   rh->status = 0;
962   
963   if (name != NULL)
964   {
965     rh->status |= EXISTS;
966   }
967   
968   if (remaining_time.rel_value == 0)
969   {
970     rh->status |= EXPIRED;
971   }
972   
973   /**
974    * No authority found in namestore.
975    */
976   if (rd_count == 0)
977   {
978     /**
979      * We did not find an authority in the namestore
980      */
981     
982     /**
983      * No PKEY in zone.
984      * Promote this authority back to a name maybe it is
985      * our record.
986      */
987     if (strcmp(rh->name, "") == 0)
988     {
989       /* simply promote back */
990       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
991                  "Promoting %s back to name\n", rh->authority_name);
992       strcpy(rh->name, rh->authority_name);
993     }
994     else
995     {
996       /* add back to existing name */
997       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
998                  "Adding %s back to %s\n",
999                  rh->authority_name, rh->name);
1000       new_name = GNUNET_malloc(strlen(rh->name)
1001                                + strlen(rh->authority_name) + 2);
1002       memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1003       strcpy(new_name, rh->name);
1004       strcpy(new_name+strlen(new_name)+1, ".");
1005       strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1006       GNUNET_free(rh->name);
1007       rh->name = new_name;
1008     }
1009     rh->proc(rh->proc_cls, rh, 0, NULL);
1010     return;
1011   }
1012
1013   /**
1014    * We found an authority that may be able to help us
1015    * move on with query
1016    * Note only 1 pkey should have been returned.. anything else would be strange
1017    */
1018   int i;
1019   for (i=0; i<rd_count;i++)
1020   {
1021   
1022     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1023       continue;
1024     
1025     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1026          == 0)
1027     {
1028       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1029       if (remaining_time.rel_value == 0)
1030       {
1031         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1032                    "This dht entry is expired.\n");
1033         rh->authority_chain_head->fresh = 0;
1034         rh->proc(rh->proc_cls, rh, 0, NULL);
1035         return;
1036       }
1037
1038       continue;
1039     }
1040
1041     /**
1042      * Resolve rest of query with new authority
1043      */
1044     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1045     memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1046     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1047     auth->zone = rh->authority;
1048     auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1049     memset(auth->name, 0, strlen(rh->authority_name)+1);
1050     strcpy(auth->name, rh->authority_name);
1051     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1052                                  rh->authority_chain_tail,
1053                                  auth);
1054     
1055     /**
1056      * We are done with PKEY resolution if name is empty
1057      * else resolve again with new authority
1058      */
1059     if (strcmp(rh->name, "") == 0)
1060       rh->proc(rh->proc_cls, rh, 0, NULL);
1061     else
1062       resolve_delegation_ns(rh);
1063     return;
1064   }
1065     
1066   /**
1067    * no answers found
1068    */
1069   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1070              "Authority lookup successful but no PKEY... never get here\n");
1071   rh->proc(rh->proc_cls, rh, 0, NULL);
1072 }
1073
1074
1075 /**
1076  * Resolve the delegation chain for the request in our namestore
1077  *
1078  * @param rh the resolver handle
1079  */
1080 static void
1081 resolve_delegation_ns(struct ResolverHandle *rh)
1082 {
1083   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1084              "Resolving delegation for %s\n", rh->name);
1085   pop_tld(rh->name, rh->authority_name);
1086   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1087                                  &rh->authority,
1088                                  rh->authority_name,
1089                                  GNUNET_GNS_RECORD_PKEY,
1090                                  &process_delegation_result_ns,
1091                                  rh);
1092
1093 }
1094
1095
1096 /**
1097  * Lookup of a record in a specific zone
1098  * calls lookup result processor on result
1099  *
1100  * @param zone the root zone
1101  * @param record_type the record type to look up
1102  * @param name the name to look up
1103  * @param proc the processor to call on result
1104  * @param cls the closure to pass to proc
1105  */
1106 void
1107 gns_resolver_lookup_record(GNUNET_HashCode zone,
1108                            uint32_t record_type,
1109                            const char* name,
1110                            RecordLookupProcessor proc,
1111                            void* cls)
1112 {
1113   struct ResolverHandle *rh;
1114   struct RecordLookupHandle* rlh;
1115
1116   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1117               "Starting resolution for %s (type=%d)!\n",
1118               name, record_type);
1119
1120   
1121   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1122   {
1123     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1124                 "%s is canonical and gnunet not our TLD!\n", name);
1125     proc(cls, 0, NULL);
1126     return;
1127   }
1128   
1129   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1130   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1131
1132   rh->authority = zone;
1133   rh->proc_cls = rlh;
1134   
1135   if (strcmp(GNUNET_GNS_TLD, name) == 0)
1136   {
1137     rh->name = GNUNET_malloc(2);
1138     strcpy(rh->name, "");
1139   }
1140   else
1141   {
1142     rh->name = GNUNET_malloc(strlen(name)
1143                              - strlen(GNUNET_GNS_TLD));
1144     memset(rh->name, 0,
1145            strlen(name)-strlen(GNUNET_GNS_TLD));
1146     memcpy(rh->name, name,
1147            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1148   }
1149   
1150   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1151   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1152   rh->authority_chain_head->prev = NULL;
1153   rh->authority_chain_head->next = NULL;
1154   rh->authority_chain_tail = rh->authority_chain_head;
1155   rh->authority_chain_head->zone = zone;
1156
1157   rlh->record_type = record_type;
1158   rlh->name = GNUNET_malloc(strlen(name) + 1);
1159   memset(rlh->name, 0, strlen(name) + 1);
1160   strcpy(rlh->name, name); //FIXME
1161   rlh->proc = proc;
1162   rlh->proc_cls = cls;
1163
1164   rh->proc = &handle_delegation_ns;
1165   resolve_delegation_ns(rh);
1166 }
1167
1168 /******** END Record Resolver ***********/
1169
1170
1171 /**
1172  * Callback calles by namestore for a zone to name
1173  * result
1174  *
1175  * @param cls the closure
1176  * @param zone_key the zone we queried
1177  * @param expire the expiration time of the name
1178  * @param name the name found or NULL
1179  * @param rd_len number of records for the name
1180  * @param rd the record data (PKEY) for the name
1181  * @param signature the signature for the record data
1182  */
1183 static void
1184 process_zone_to_name_shorten(void *cls,
1185                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1186                  struct GNUNET_TIME_Absolute expire,
1187                  const char *name,
1188                  unsigned int rd_len,
1189                  const struct GNUNET_NAMESTORE_RecordData *rd,
1190                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1191 {
1192   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1193   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1194   struct AuthorityChain *next_authority;
1195
1196   char* result;
1197   char* next_authority_name;
1198   size_t answer_len;
1199   
1200   /* we found a match in our own zone */
1201   if (rd_len != 0)
1202   {
1203     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1204                "result strlen %d\n", strlen(name));
1205     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1206     result = GNUNET_malloc(answer_len);
1207     memset(result, 0, answer_len);
1208     if (strlen(rh->name) > 0)
1209     {
1210       strcpy(result, rh->name);
1211       strcpy(result+strlen(rh->name), ".");
1212     }
1213     
1214     strcpy(result+strlen(result), name);
1215     strcpy(result+strlen(result), ".");
1216     strcpy(result+strlen(result), GNUNET_GNS_TLD);
1217     
1218     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1219                "Sending shorten result %s\n", result);
1220
1221     nsh->proc(nsh->proc_cls, result);
1222     GNUNET_free(nsh);
1223     free_resolver_handle(rh);
1224     GNUNET_free(result);
1225   }
1226   else if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1227                                   &rh->authority_chain_tail->zone))
1228   {
1229     /* our zone, just append .gnunet */
1230     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1231     result = GNUNET_malloc(answer_len);
1232     memset(result, 0, answer_len);
1233     strcpy(result, rh->name);
1234     strcpy(result+strlen(rh->name), ".");
1235     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1236
1237     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1238                "Our zone: Sending name as shorten result %s\n", rh->name);
1239     
1240     nsh->proc(nsh->proc_cls, result);
1241     GNUNET_free(nsh);
1242     free_resolver_handle(rh);
1243     GNUNET_free(result);
1244   }
1245   else
1246   {
1247     /**
1248      * No PSEU found.
1249      * continue with next authority
1250      */
1251     next_authority = rh->authority_chain_head;
1252     next_authority_name = GNUNET_malloc(strlen(rh->name)+
1253                              strlen(next_authority->name) + 2);
1254     memset(next_authority_name, 0, strlen(rh->name)+
1255                       strlen(next_authority->name) + 2);
1256     strcpy(next_authority_name, rh->name);
1257     strcpy(next_authority_name+strlen(rh->name)+1, ".");
1258     strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1259   
1260     GNUNET_free(rh->name);
1261     rh->name = next_authority_name;
1262     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1263                               rh->authority_chain_tail,
1264                               next_authority);
1265
1266     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1267                                    &rh->authority_chain_tail->zone,
1268                                    &rh->authority_chain_head->zone,
1269                                    &process_zone_to_name_shorten,
1270                                    rh);
1271   }
1272 }
1273
1274
1275 /**
1276  * Process result from namestore delegation lookup
1277  * for shorten operation
1278  *
1279  * @param cls the client shorten handle
1280  * @param rh the resolver handle
1281  * @param rd_count number of results (0)
1282  * @param rd data (NULL)
1283  */
1284 void
1285 handle_delegation_ns_shorten(void* cls,
1286                       struct ResolverHandle *rh,
1287                       uint32_t rd_count,
1288                       const struct GNUNET_NAMESTORE_RecordData *rd)
1289 {
1290   struct NameShortenHandle *nsh;
1291   char* result;
1292   size_t answer_len;
1293
1294   nsh = (struct NameShortenHandle *)cls;
1295   
1296   /**
1297    * At this point rh->name contains the part of the name
1298    * that we do not have a PKEY in our namestore to resolve.
1299    * The authority chain in the resolver handle is now
1300    * useful to backtrack if needed
1301    */
1302   
1303   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1304              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1305
1306   if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1307                              &rh->authority_chain_tail->zone) == 0)
1308   {
1309     /**
1310      * This is our zone append .gnunet unless name is empty
1311      * (it shouldn't be, usually FIXME what happens if we
1312      * shorten to our zone to a "" record??)
1313      **/
1314     
1315     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1316     result = GNUNET_malloc(answer_len);
1317     memset(result, 0, answer_len);
1318     strcpy(result, rh->name);
1319     strcpy(result+strlen(rh->name), ".");
1320     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1321
1322     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1323                "Our zone: Sending name as shorten result %s\n", rh->name);
1324     
1325     nsh->proc(nsh->proc_cls, result);
1326     GNUNET_free(nsh);
1327     free_resolver_handle(rh);
1328     GNUNET_free(result);
1329     return;
1330   }
1331   
1332   /* backtrack authorities for names */
1333   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1334                                  &rh->authority_chain_tail->zone, //ours
1335                                  &rh->authority_chain_head->zone,
1336                                  &process_zone_to_name_shorten,
1337                                  rh);
1338
1339 }
1340
1341 /**
1342  * Shorten api from resolver
1343  *
1344  * @param zone the zone to use
1345  * @param name the name to shorten
1346  * @param proc the processor to call with result
1347  * @param cls closure to pass to proc
1348  */
1349 void
1350 gns_resolver_shorten_name(GNUNET_HashCode zone,
1351                           const char* name,
1352                           ShortenResultProcessor proc,
1353                           void* cls)
1354 {
1355   struct ResolverHandle *rh;
1356   struct NameShortenHandle *nsh;
1357
1358   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1359               "Starting shorten for %s!\n", name);
1360   
1361   if (is_canonical((char*)name))
1362   {
1363     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1364                 "%s is canonical. Returning verbatim\n", name);
1365     proc(cls, name);
1366     return;
1367   }
1368
1369   nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
1370   
1371
1372   nsh->proc = proc;
1373   nsh->proc_cls = cls;
1374   
1375   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1376   rh->authority = zone;
1377   rh->name = GNUNET_malloc(strlen(name)
1378                            - strlen(GNUNET_GNS_TLD));
1379   memset(rh->name, 0,
1380          strlen(name)-strlen(GNUNET_GNS_TLD));
1381   memcpy(rh->name, name,
1382          strlen(name)-strlen(GNUNET_GNS_TLD)-1);
1383
1384   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1385   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1386   rh->authority_chain_tail = rh->authority_chain_head;
1387   rh->authority_chain_head->zone = zone;
1388   rh->proc = &handle_delegation_ns_shorten;
1389   rh->proc_cls = nsh;
1390   
1391   /* Start delegation resolution in our namestore */
1392   resolve_delegation_ns(rh);
1393 }
1394
1395 /*********** END NAME SHORTEN ********************/
1396
1397
1398 /**
1399  * Process result from namestore delegation lookup
1400  * for get authority operation
1401  *
1402  * @param cls the client get auth handle
1403  * @param rh the resolver handle
1404  * @param rd_count number of results (0)
1405  * @param rd data (NULL)
1406  */
1407 void
1408 handle_delegation_result_ns_get_auth(void* cls,
1409                       struct ResolverHandle *rh,
1410                       uint32_t rd_count,
1411                       const struct GNUNET_NAMESTORE_RecordData *rd)
1412 {
1413   struct GetNameAuthorityHandle* nah;
1414   char* result;
1415   size_t answer_len;
1416
1417   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
1418   
1419   /**
1420    * At this point rh->name contains the part of the name
1421    * that we do not have a PKEY in our namestore to resolve.
1422    * The authority chain in the resolver handle is now
1423    * useful to backtrack if needed
1424    */
1425   
1426   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1427              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1428
1429   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1430              "Building response!\n");
1431   if (is_canonical(rh->name))
1432   {
1433     /**
1434      * We successfully resolved the authority in the ns
1435      * FIXME for our purposes this is fine
1436      * but maybe we want to have an api that also looks
1437      * into the dht (i.e. option in message)
1438      **/
1439     if (strlen(rh->name) > strlen(nah->name))
1440     {
1441       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1442                  "Record name longer than original lookup name... odd!\n");
1443       //FIXME to sth here
1444     }
1445
1446     answer_len = strlen(nah->name) - strlen(rh->name)
1447       + strlen(GNUNET_GNS_TLD) + 1;
1448     result = GNUNET_malloc(answer_len);
1449     memset(result, 0, answer_len);
1450     strcpy(result, nah->name + strlen(rh->name) + 1);
1451
1452     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1453                "Got authority result %s\n", result);
1454     
1455     nah->proc(nah->proc_cls, result);
1456     GNUNET_free(nah->name);
1457     GNUNET_free(nah);
1458     free_resolver_handle(rh);
1459     GNUNET_free(result);
1460   }
1461   else
1462   {
1463     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1464                "Unable to resolve authority for remaining %s!\n", rh->name);
1465     nah->proc(nah->proc_cls, "");
1466     GNUNET_free(nah->name);
1467     GNUNET_free(nah);
1468     free_resolver_handle(rh);
1469   }
1470
1471
1472 }
1473
1474
1475 /**
1476  * Tries to resolve the authority for name
1477  * in our namestore
1478  *
1479  * @param zone the root zone to look up for
1480  * @param name the name to lookup up
1481  * @param proc the processor to call when finished
1482  * @param cls the closure to pass to the processor
1483  */
1484 void
1485 gns_resolver_get_authority(GNUNET_HashCode zone,
1486                            const char* name,
1487                            GetAuthorityResultProcessor proc,
1488                            void* cls)
1489 {
1490   struct ResolverHandle *rh;
1491   struct GetNameAuthorityHandle *nah;
1492
1493   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1494               "Starting authority resolution for %s!\n", name);
1495
1496   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
1497   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1498   rh->authority = zone;
1499   
1500   if (strcmp(GNUNET_GNS_TLD, name) == 0)
1501   {
1502     rh->name = GNUNET_malloc(2);
1503     strcpy(rh->name, "");
1504   }
1505   else
1506   {
1507     rh->name = GNUNET_malloc(strlen(name)
1508                              - strlen(GNUNET_GNS_TLD));
1509     memset(rh->name, 0,
1510            strlen(name)-strlen(GNUNET_GNS_TLD));
1511     memcpy(rh->name, name,
1512            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1513   }
1514
1515   nah->name = GNUNET_malloc(strlen(name)+1);
1516   memset(nah->name, 0,
1517          strlen(name)+1);
1518   strcpy(nah->name, name);
1519   
1520   rh->authority_name = GNUNET_malloc(MAX_DNS_LABEL_LENGTH);
1521
1522   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1523   rh->authority_chain_tail = rh->authority_chain_head;
1524   rh->authority_chain_head->zone = zone;
1525   rh->proc = &handle_delegation_result_ns_get_auth;
1526   rh->proc_cls = (void*)nah;
1527
1528   nah->proc = proc;
1529   nah->proc_cls = cls;
1530
1531   /* Start delegation resolution in our namestore */
1532   resolve_delegation_ns(rh);
1533
1534 }
1535
1536 /******** END GET AUTHORITY *************/
1537
1538 /* end of gnunet-service-gns_resolver.c */