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