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