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