- new program_run and run_2
[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 error!\n");
606   GNUNET_break(0);
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     return;
633   }
634
635   /* results found yay */
636   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
637              "Record resolved from DHT!");
638   rlh->proc(rlh->proc_cls, rd_count, rd);
639
640 }
641
642
643 /**
644  * Process namestore lookup result for record.
645  *
646  * @param cls the closure
647  * @param rh resolver handle
648  * @param rd_count number of results
649  * @param rd record data
650  */
651 static void
652 handle_record_ns(void* cls, struct ResolverHandle *rh,
653                        unsigned int rd_count,
654                        const struct GNUNET_NAMESTORE_RecordData *rd)
655 {
656   struct RecordLookupHandle* rlh;
657   rlh = (struct RecordLookupHandle*) cls;
658   if (rd_count == 0)
659   {
660     /* ns entry expired and not ours. try dht */
661     if (rh->status & (EXPIRED | !EXISTS) &&
662         GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
663                                &rh->authority_chain_tail->zone))
664     {
665       rh->proc = &handle_record_dht;
666       resolve_record_dht(rh);
667       return;
668     }
669     /* give up, cannot resolve */
670     rlh->proc(rlh->proc_cls, 0, NULL);
671     return;
672   }
673
674   /* results found yay */
675   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
676              "Record resolved from namestore!");
677   rlh->proc(rlh->proc_cls, rd_count, rd);
678
679 }
680
681
682 /**
683  * Determine if this name is canonical.
684  * i.e.
685  * a.b.gnunet  = not canonical
686  * a           = canonical
687  *
688  * @param name the name to test
689  * @return 1 if canonical
690  */
691 static int
692 is_canonical(char* name)
693 {
694   uint32_t len = strlen(name);
695   int i;
696
697   for (i=0; i<len; i++)
698   {
699     if (*(name+i) == '.')
700       return 0;
701   }
702   return 1;
703 }
704
705 /**
706  * Move one level up in the domain hierarchy and return the
707  * passed top level domain.
708  *
709  * @param name the domain
710  * @param dest the destination where the tld will be put
711  */
712 void
713 pop_tld(char* name, char* dest)
714 {
715   uint32_t len;
716
717   if (is_canonical(name))
718   {
719     strcpy(dest, name);
720     strcpy(name, "");
721     return;
722   }
723
724   for (len = strlen(name); len > 0; len--)
725   {
726     if (*(name+len) == '.')
727       break;
728   }
729   
730   //Was canonical?
731   if (len == 0)
732     return;
733
734   name[len] = '\0';
735
736   strcpy(dest, (name+len+1));
737 }
738
739 /**
740  * DHT resolution for delegation finished. Processing result.
741  *
742  * @param cls the closure
743  * @param rh resolver handle
744  * @param rd_count number of results (always 0)
745  * @param rd record data (always NULL)
746  */
747 static void
748 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
749                           unsigned int rd_count,
750                           const struct GNUNET_NAMESTORE_RecordData *rd)
751 {
752   struct RecordLookupHandle* rlh;
753   rlh = (struct RecordLookupHandle*) cls;
754   
755   if (strcmp(rh->name, "") == 0)
756   {
757     /* We resolved full name for delegation. resolving record */
758     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
759       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
760     rh->proc = &handle_record_ns;
761     resolve_record_ns(rh);
762     return;
763   }
764
765   /**
766    * we still have some left
767    **/
768   if (is_canonical(rh->name))
769   {
770     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
771                "Resolving canonical record %s in ns\n", rh->name);
772     rh->proc = &handle_record_ns;
773     resolve_record_ns(rh);
774     return;
775   }
776   /* give up, cannot resolve */
777   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
778              "Cannot fully resolve delegation for %s via DHT!\n",
779              rh->name);
780   rlh->proc(rlh->proc_cls, 0, NULL);
781 }
782
783
784 /**
785  * Start DHT lookup for a name -> PKEY (compare NS) record in
786  * rh->authority's zone
787  *
788  * @param rh the pending gns query
789  */
790 static void
791 resolve_delegation_dht(struct ResolverHandle *rh)
792 {
793   uint32_t xquery;
794   GNUNET_HashCode name_hash;
795   GNUNET_HashCode lookup_key;
796
797   GNUNET_CRYPTO_hash(rh->authority_name,
798                      strlen(rh->authority_name),
799                      &name_hash);
800   GNUNET_CRYPTO_hash_xor(&name_hash, &rh->authority, &lookup_key);
801
802   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
803                                                   &dht_authority_lookup_timeout,
804                                                        rh);
805
806   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
807   
808   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
809                        DHT_OPERATION_TIMEOUT,
810                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
811                        &lookup_key,
812                        DHT_GNS_REPLICATION_LEVEL,
813                        GNUNET_DHT_RO_NONE,
814                        &xquery,
815                        sizeof(xquery),
816                        &process_delegation_result_dht,
817                        rh);
818
819 }
820
821
822 /**
823  * Namestore resolution for delegation finished. Processing result.
824  *
825  * @param cls the closure
826  * @param rh resolver handle
827  * @param rd_count number of results (always 0)
828  * @param rd record data (always NULL)
829  */
830 static void
831 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
832                           unsigned int rd_count,
833                           const struct GNUNET_NAMESTORE_RecordData *rd)
834 {
835   struct RecordLookupHandle* rlh;
836   rlh = (struct RecordLookupHandle*) cls;
837   
838   if (strcmp(rh->name, "") == 0)
839   {
840     /* We resolved full name for delegation. resolving record */
841     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
842                "Resolved full name for delegation. resolving record ''\n");
843     rh->proc = &handle_record_ns;
844     resolve_record_ns(rh);
845     return;
846   }
847
848   /**
849    * we still have some left
850    * check if authority in ns is fresh
851    * and exists
852    * or we are authority
853    **/
854   if ((rh->status & (EXISTS | !EXPIRED)) ||
855       !GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
856                              &rh->authority_chain_tail->zone))
857   {
858     if (is_canonical(rh->name))
859     {
860       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
861                  "Resolving canonical record %s\n", rh->name);
862       rh->proc = &handle_record_ns;
863       resolve_record_ns(rh);
864     }
865     else
866     {
867       /* give up, cannot resolve */
868       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
869                  "Cannot fully resolve delegation for %s!\n",
870                  rh->name);
871       rlh->proc(rlh->proc_cls, 0, NULL);
872     }
873     return;
874   }
875   
876   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
877              "Trying to resolve delegation for %s via DHT\n",
878              rh->name);
879   rh->proc = &handle_delegation_dht;
880   resolve_delegation_dht(rh);
881 }
882
883 /* Prototype */
884 static void resolve_delegation_ns(struct ResolverHandle *rh);
885
886
887 /**
888  * This is a callback function that should give us only PKEY
889  * records. Used to query the namestore for the authority (PKEY)
890  * for 'name'. It will recursively try to resolve the
891  * authority for a given name from the namestore.
892  *
893  * @param cls the pending query
894  * @param key the key of the zone we did the lookup
895  * @param expiration expiration date of the record data set in the namestore
896  * @param name the name for which we need an authority
897  * @param rd_count the number of records with 'name'
898  * @param rd the record data
899  * @param signature the signature of the authority for the record data
900  */
901 static void
902 process_delegation_result_ns(void* cls,
903                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
904                    struct GNUNET_TIME_Absolute expiration,
905                    const char *name,
906                    unsigned int rd_count,
907                    const struct GNUNET_NAMESTORE_RecordData *rd,
908                    const struct GNUNET_CRYPTO_RsaSignature *signature)
909 {
910   struct ResolverHandle *rh;
911   struct GNUNET_TIME_Relative remaining_time;
912   GNUNET_HashCode zone;
913   char* new_name;
914   
915   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
916              rd_count);
917
918   rh = (struct ResolverHandle *)cls;
919   GNUNET_CRYPTO_hash(key,
920                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
921                      &zone);
922   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
923   
924   rh->status = 0;
925   
926   if (name != NULL)
927   {
928     rh->status |= EXISTS;
929   }
930   
931   if (remaining_time.rel_value == 0)
932   {
933     rh->status |= EXPIRED;
934   }
935   
936   /**
937    * No authority found in namestore.
938    */
939   if (rd_count == 0)
940   {
941     /**
942      * We did not find an authority in the namestore
943      */
944     
945     /**
946      * No PKEY in zone.
947      * Promote this authority back to a name maybe it is
948      * our record.
949      */
950     if (strcmp(rh->name, "") == 0)
951     {
952       /* simply promote back */
953       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
954                  "Promoting %s back to name\n", rh->authority_name);
955       strcpy(rh->name, rh->authority_name);
956     }
957     else
958     {
959       /* add back to existing name */
960       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
961                  "Adding %s back to %s\n",
962                  rh->authority_name, rh->name);
963       new_name = GNUNET_malloc(strlen(rh->name)
964                                + strlen(rh->authority_name) + 2);
965       memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
966       strcpy(new_name, rh->name);
967       strcpy(new_name+strlen(new_name)+1, ".");
968       strcpy(new_name+strlen(new_name)+2, rh->authority_name);
969       GNUNET_free(rh->name);
970       rh->name = new_name;
971     }
972     rh->proc(rh->proc_cls, rh, 0, NULL);
973     return;
974   }
975
976   /**
977    * We found an authority that may be able to help us
978    * move on with query
979    * Note only 1 pkey should have been returned.. anything else would be strange
980    */
981   int i;
982   for (i=0; i<rd_count;i++)
983   {
984   
985     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
986       continue;
987     
988     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
989          == 0)
990     {
991       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
992       if (remaining_time.rel_value == 0)
993       {
994         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
995                    "This dht entry is expired.\n");
996         rh->authority_chain_head->fresh = 0;
997         rh->proc(rh->proc_cls, rh, 0, NULL);
998         return;
999       }
1000
1001       continue;
1002     }
1003
1004     /**
1005      * Resolve rest of query with new authority
1006      */
1007     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1008     memcpy(&rh->authority, rd[i].data, sizeof(GNUNET_HashCode));
1009     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1010     auth->zone = rh->authority;
1011     auth->name = GNUNET_malloc(strlen(rh->authority_name)+1);
1012     memset(auth->name, 0, strlen(rh->authority_name)+1);
1013     strcpy(auth->name, rh->authority_name);
1014     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1015                                  rh->authority_chain_tail,
1016                                  auth);
1017     
1018     /**
1019      * We are done with PKEY resolution if name is empty
1020      * else resolve again with new authority
1021      */
1022     if (strcmp(rh->name, "") == 0)
1023       rh->proc(rh->proc_cls, rh, 0, NULL);
1024     else
1025       resolve_delegation_ns(rh);
1026     return;
1027   }
1028     
1029   /**
1030    * no answers found
1031    */
1032   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1033              "Authority lookup successful but no PKEY... never get here\n");
1034   rh->proc(rh->proc_cls, rh, 0, NULL);
1035 }
1036
1037
1038 /**
1039  * Resolve the delegation chain for the request in our namestore
1040  *
1041  * @param rh the resolver handle
1042  */
1043 static void
1044 resolve_delegation_ns(struct ResolverHandle *rh)
1045 {
1046   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1047              "Resolving delegation for %s\n", rh->name);
1048   pop_tld(rh->name, rh->authority_name);
1049   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1050                                  &rh->authority,
1051                                  rh->authority_name,
1052                                  GNUNET_GNS_RECORD_PKEY,
1053                                  &process_delegation_result_ns,
1054                                  rh);
1055
1056 }
1057
1058
1059 /**
1060  * Lookup of a record in a specific zone
1061  * calls lookup result processor on result
1062  *
1063  * @param zone the root zone
1064  * @param record_type the record type to look up
1065  * @param name the name to look up
1066  * @param proc the processor to call on result
1067  * @param cls the closure to pass to proc
1068  */
1069 void
1070 gns_resolver_lookup_record(GNUNET_HashCode zone,
1071                            uint32_t record_type,
1072                            const char* name,
1073                            RecordLookupProcessor proc,
1074                            void* cls)
1075 {
1076   struct ResolverHandle *rh;
1077   struct RecordLookupHandle* rlh;
1078
1079   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080               "Starting resolution for %s (type=%d)!\n",
1081               name, record_type);
1082
1083   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1084   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1085
1086   rh->authority = zone;
1087   rh->proc_cls = rlh;
1088   rh->name = GNUNET_malloc(strlen(name)
1089                            - strlen(GNUNET_GNS_TLD));
1090   memset(rh->name, 0,
1091          strlen(name)-strlen(GNUNET_GNS_TLD));
1092   memcpy(rh->name, name,
1093          strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1094   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1095   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1096   rh->authority_chain_head->prev = NULL;
1097   rh->authority_chain_head->next = NULL;
1098   rh->authority_chain_tail = rh->authority_chain_head;
1099   rh->authority_chain_head->zone = zone;
1100
1101   rlh->record_type = record_type;
1102   rlh->name = (char*)name; //FIXME
1103   rlh->proc = proc;
1104   rlh->proc_cls = cls;
1105
1106   rh->proc = &handle_delegation_ns;
1107   resolve_delegation_ns(rh);
1108 }
1109
1110 /******** END Record Resolver ***********/
1111
1112
1113 /**
1114  * Callback calles by namestore for a zone to name
1115  * result
1116  *
1117  * @param cls the closure
1118  * @param zone_key the zone we queried
1119  * @param expire the expiration time of the name
1120  * @param name the name found or NULL
1121  * @param rd_len number of records for the name
1122  * @param rd the record data (PKEY) for the name
1123  * @param signature the signature for the record data
1124  */
1125 static void
1126 process_zone_to_name_shorten(void *cls,
1127                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1128                  struct GNUNET_TIME_Absolute expire,
1129                  const char *name,
1130                  unsigned int rd_len,
1131                  const struct GNUNET_NAMESTORE_RecordData *rd,
1132                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1133 {
1134   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1135   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1136   struct AuthorityChain *next_authority;
1137
1138   char* result;
1139   char* next_authority_name;
1140   size_t answer_len;
1141   
1142   /* we found a match in our own zone */
1143   if (rd_len != 0)
1144   {
1145     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1146                "result strlen %d\n", strlen(name));
1147     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1148     result = GNUNET_malloc(answer_len);
1149     memset(result, 0, answer_len);
1150     strcpy(result, rh->name);
1151     strcpy(result+strlen(rh->name), ".");
1152     strcpy(result+strlen(rh->name)+1, name);
1153     strcpy(result+strlen(rh->name)+strlen(name)+1, ".");
1154     strcpy(result+strlen(rh->name)+strlen(name)+2, GNUNET_GNS_TLD);
1155     
1156     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1157                "Sending shorten result %s\n", result);
1158
1159     nsh->proc(nsh->proc_cls, result);
1160     free_resolver_handle(rh);
1161     GNUNET_free(result);
1162   }
1163   else if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1164                                   &rh->authority_chain_tail->zone))
1165   {
1166     /* our zone, just append .gnunet */
1167     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1168     result = GNUNET_malloc(answer_len);
1169     memset(result, 0, answer_len);
1170     strcpy(result, rh->name);
1171     strcpy(result+strlen(rh->name), ".");
1172     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1173
1174     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1175                "Our zone: Sending name as shorten result %s\n", rh->name);
1176     
1177     nsh->proc(nsh->proc_cls, result);
1178     free_resolver_handle(rh);
1179     GNUNET_free(result);
1180   }
1181   else
1182   {
1183     /**
1184      * No PSEU found.
1185      * continue with next authority
1186      */
1187     next_authority = rh->authority_chain_head;
1188     next_authority_name = GNUNET_malloc(strlen(rh->name)+
1189                              strlen(next_authority->name) + 2);
1190     memset(next_authority_name, 0, strlen(rh->name)+
1191                       strlen(next_authority->name) + 2);
1192     strcpy(next_authority_name, rh->name);
1193     strcpy(next_authority_name+strlen(rh->name)+1, ".");
1194     strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1195   
1196     GNUNET_free(rh->name);
1197     rh->name = next_authority_name;
1198     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1199                               rh->authority_chain_tail,
1200                               next_authority);
1201
1202     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1203                                    &rh->authority_chain_tail->zone,
1204                                    &rh->authority_chain_head->zone,
1205                                    &process_zone_to_name_shorten,
1206                                    rh);
1207   }
1208 }
1209
1210
1211 /**
1212  * Process result from namestore delegation lookup
1213  * for shorten operation
1214  *
1215  * @param cls the client shorten handle
1216  * @param rh the resolver handle
1217  * @param rd_count number of results (0)
1218  * @param rd data (NULL)
1219  */
1220 void
1221 handle_delegation_ns_shorten(void* cls,
1222                       struct ResolverHandle *rh,
1223                       uint32_t rd_count,
1224                       const struct GNUNET_NAMESTORE_RecordData *rd)
1225 {
1226   struct NameShortenHandle *nsh;
1227   char* result;
1228   size_t answer_len;
1229
1230   nsh = (struct NameShortenHandle *)cls;
1231   
1232   /**
1233    * At this point rh->name contains the part of the name
1234    * that we do not have a PKEY in our namestore to resolve.
1235    * The authority chain in the resolver handle is now
1236    * useful to backtrack if needed
1237    */
1238   
1239   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1240              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1241
1242   if (GNUNET_CRYPTO_hash_cmp(&rh->authority_chain_head->zone,
1243                              &rh->authority_chain_tail->zone) == 0)
1244   {
1245     /**
1246      * This is our zone append .gnunet unless name is empty
1247      * (it shouldn't be, usually FIXME what happens if we
1248      * shorten to our zone to a "" record??)
1249      **/
1250     
1251     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1252     result = GNUNET_malloc(answer_len);
1253     memset(result, 0, answer_len);
1254     strcpy(result, rh->name);
1255     strcpy(result+strlen(rh->name), ".");
1256     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1257
1258     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1259                "Our zone: Sending name as shorten result %s\n", rh->name);
1260     
1261     nsh->proc(nsh->proc_cls, result);
1262     free_resolver_handle(rh);
1263     GNUNET_free(result);
1264     return;
1265   }
1266   
1267   /* backtrack authorities for names */
1268   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1269                                  &rh->authority_chain_tail->zone, //ours
1270                                  &rh->authority_chain_head->zone,
1271                                  &process_zone_to_name_shorten,
1272                                  rh);
1273
1274 }
1275
1276 /**
1277  * Shorten api from resolver
1278  *
1279  * @param zone the zone to use
1280  * @param name the name to shorten
1281  * @param proc the processor to call with result
1282  * @param cls closure to pass to proc
1283  */
1284 void
1285 gns_resolver_shorten_name(GNUNET_HashCode zone,
1286                           const char* name,
1287                           ShortenResultProcessor proc,
1288                           void* cls)
1289 {
1290   struct ResolverHandle *rh;
1291   struct NameShortenHandle *nsh;
1292
1293   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1294               "Starting shorten for %s!\n", name);
1295   
1296   nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
1297   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1298   rh->authority = zone;
1299   rh->name = GNUNET_malloc(strlen(name)
1300                            - strlen(GNUNET_GNS_TLD));
1301   memset(rh->name, 0,
1302          strlen(name)-strlen(GNUNET_GNS_TLD));
1303   memcpy(rh->name, name,
1304          strlen(name)-strlen(GNUNET_GNS_TLD)-1);
1305
1306   rh->authority_name = GNUNET_malloc(sizeof(char)*MAX_DNS_LABEL_LENGTH);
1307   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1308   rh->authority_chain_tail = rh->authority_chain_head;
1309   rh->authority_chain_head->zone = zone;
1310   rh->proc = &handle_delegation_ns_shorten;
1311   rh->proc_cls = nsh;
1312
1313   nsh->proc = proc;
1314   nsh->proc_cls = cls;
1315   
1316   /* Start delegation resolution in our namestore */
1317   resolve_delegation_ns(rh);
1318 }
1319
1320 /*********** END NAME SHORTEN ********************/
1321
1322
1323 /**
1324  * Process result from namestore delegation lookup
1325  * for get authority operation
1326  *
1327  * @param cls the client get auth handle
1328  * @param rh the resolver handle
1329  * @param rd_count number of results (0)
1330  * @param rd data (NULL)
1331  */
1332 void
1333 handle_delegation_result_ns_get_auth(void* cls,
1334                       struct ResolverHandle *rh,
1335                       uint32_t rd_count,
1336                       const struct GNUNET_NAMESTORE_RecordData *rd)
1337 {
1338   struct GetNameAuthorityHandle* nah;
1339   char* result;
1340   size_t answer_len;
1341
1342   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
1343   
1344   /**
1345    * At this point rh->name contains the part of the name
1346    * that we do not have a PKEY in our namestore to resolve.
1347    * The authority chain in the resolver handle is now
1348    * useful to backtrack if needed
1349    */
1350   
1351   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1352              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1353
1354   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1355              "Building response!\n");
1356   if (is_canonical(rh->name))
1357   {
1358     /**
1359      * We successfully resolved the authority in the ns
1360      * FIXME for our purposes this is fine
1361      * but maybe we want to have an api that also looks
1362      * into the dht (i.e. option in message)
1363      **/
1364     if (strlen(rh->name) > strlen(nah->name))
1365     {
1366       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1367                  "Record name longer than original lookup name... odd!\n");
1368       //FIXME to sth here
1369     }
1370
1371     answer_len = strlen(nah->name) - strlen(rh->name)
1372       + strlen(GNUNET_GNS_TLD) + 1;
1373     result = GNUNET_malloc(answer_len);
1374     memset(result, 0, answer_len);
1375     strcpy(result, nah->name + strlen(rh->name) + 1);
1376
1377     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1378                "Got authority result %s\n", result);
1379     
1380     nah->proc(nah->proc_cls, result);
1381     free_resolver_handle(rh);
1382     GNUNET_free(result);
1383     GNUNET_free(nah);
1384   }
1385   else
1386   {
1387     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1388                "Unable to resolve authority for remaining %s!\n", rh->name);
1389     nah->proc(nah->proc_cls, "");
1390     free_resolver_handle(rh);
1391     GNUNET_free(nah);
1392   }
1393
1394
1395 }
1396
1397
1398 /**
1399  * Tries to resolve the authority for name
1400  * in our namestore
1401  *
1402  * @param zone the root zone to look up for
1403  * @param name the name to lookup up
1404  * @param proc the processor to call when finished
1405  * @param cls the closure to pass to the processor
1406  */
1407 void
1408 gns_resolver_get_authority(GNUNET_HashCode zone,
1409                            const char* name,
1410                            GetAuthorityResultProcessor proc,
1411                            void* cls)
1412 {
1413   struct ResolverHandle *rh;
1414   struct GetNameAuthorityHandle *nah;
1415
1416   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1417               "Starting authority resolution for %s!\n", name);
1418
1419   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
1420   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1421   rh->authority = zone;
1422
1423   rh->name = GNUNET_malloc(strlen(name)
1424                            - strlen(GNUNET_GNS_TLD));
1425   memset(rh->name, 0,
1426          strlen(name)-strlen(GNUNET_GNS_TLD));
1427   memcpy(rh->name, name,
1428          strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1429
1430   nah->name = GNUNET_malloc(strlen(name)+1);
1431   memset(nah->name, 0,
1432          strlen(name)+1);
1433   strcpy(nah->name, name);
1434   
1435   rh->authority_name = GNUNET_malloc(MAX_DNS_LABEL_LENGTH);
1436
1437   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1438   rh->authority_chain_tail = rh->authority_chain_head;
1439   rh->authority_chain_head->zone = zone;
1440   rh->proc = &handle_delegation_result_ns_get_auth;
1441   rh->proc_cls = (void*)nah;
1442
1443   nah->proc = proc;
1444   nah->proc_cls = cls;
1445
1446   /* Start delegation resolution in our namestore */
1447   resolve_delegation_ns(rh);
1448
1449 }
1450
1451 /******** END GET AUTHORITY *************/
1452
1453 /* end of gnunet-service-gns_resolver.c */