-fixes
[oweals/gnunet.git] / src / gns / gnunet-service-gns_resolver.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  *
23  *
24  * @file gns/gnunet-service-gns_resolver.c
25  * @brief GNUnet GNS resolver logic
26  * @author Martin Schanzenbach
27  */
28 #include "platform.h"
29 #include <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 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: 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  * Function called when we get a result from the dht
1070  * for our query. Recursively tries to resolve authorities
1071  * for name in DHT.
1072  *
1073  * @param cls the request handle
1074  * @param exp lifetime
1075  * @param key the key the record was stored under
1076  * @param get_path get path
1077  * @param get_path_length get path length
1078  * @param put_path put path
1079  * @param put_path_length put path length
1080  * @param type the block type
1081  * @param size the size of the record
1082  * @param data the record data
1083  */
1084 static void
1085 process_delegation_result_dht(void* cls,
1086                  struct GNUNET_TIME_Absolute exp,
1087                  const GNUNET_HashCode * key,
1088                  const struct GNUNET_PeerIdentity *get_path,
1089                  unsigned int get_path_length,
1090                  const struct GNUNET_PeerIdentity *put_path,
1091                  unsigned int put_path_length,
1092                  enum GNUNET_BLOCK_Type type,
1093                  size_t size, const void *data)
1094 {
1095   struct ResolverHandle *rh;
1096   struct GNSNameRecordBlock *nrb;
1097   uint32_t num_records;
1098   char* name = NULL;
1099   char* rd_data = (char*) data;
1100   int i;
1101   int rd_size;
1102   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1103   GNUNET_HashCode zone_hash_double, name_hash_double;
1104   
1105   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "GNS_PHASE_DELEGATE: Got DHT result\n");
1106
1107   if (data == NULL)
1108     return;
1109   
1110   //FIXME check expiration?
1111   
1112   rh = (struct ResolverHandle *)cls;
1113   nrb = (struct GNSNameRecordBlock*)data;
1114   
1115   /* stop dht lookup and timeout task */
1116   GNUNET_DHT_get_stop (rh->get_handle);
1117
1118   rh->get_handle = NULL;
1119
1120   if (rh->dht_heap_node != NULL)
1121   {
1122     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1123     rh->dht_heap_node = NULL;
1124   }
1125
1126   num_records = ntohl(nrb->rd_count);
1127   name = (char*)&nrb[1];
1128   {
1129     struct GNUNET_NAMESTORE_RecordData rd[num_records];
1130     
1131     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1132     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1133   
1134     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1135                                                                rd_data,
1136                                                                num_records,
1137                                                                rd))
1138     {
1139       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1140                  "GNS_PHASE_DELEGATE: Error deserializing data!\n");
1141       return;
1142     }
1143
1144     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1145                "GNS_PHASE_DELEGATE: Got name: %s (wanted %s)\n",
1146                name, rh->authority_name);
1147     for (i=0; i<num_records; i++)
1148     {
1149     
1150       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1151                 "GNS_PHASE_DELEGATE: Got name: %s (wanted %s)\n",
1152                 name, rh->authority_name);
1153       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1154                  "GNS_PHASE_DELEGATE: Got type: %d (wanted %d)\n",
1155                  rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1156       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1157                  "GNS_PHASE_DELEGATE: Got data length: %d\n",
1158                  rd[i].data_size);
1159       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1160                  "GNS_PHASE_DELEGATE: Got flag %d\n", rd[i].flags);
1161
1162       if ((strcmp(name, rh->authority_name) == 0) &&
1163           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1164       {
1165         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1166                    "GNS_PHASE_DELEGATE: Authority found in DHT\n");
1167         rh->answered = 1;
1168         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1169         struct AuthorityChain *auth =
1170           GNUNET_malloc(sizeof(struct AuthorityChain));
1171         auth->zone = rh->authority;
1172         memset(auth->name, 0, strlen(rh->authority_name)+1);
1173         strcpy(auth->name, rh->authority_name);
1174         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1175                                      rh->authority_chain_tail,
1176                                      auth);
1177
1178         /** try to import pkey if private key available */
1179         if (rh->priv_key)
1180           process_discovered_authority(name, auth->zone,
1181                                        rh->authority_chain_tail->zone,
1182                                        rh->priv_key);
1183       }
1184
1185     }
1186
1187
1188     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1189     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1190     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1191     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1192
1193     /* Save to namestore */
1194     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1195                                           &zone))
1196     {
1197       GNUNET_NAMESTORE_record_put (namestore_handle,
1198                                  &nrb->public_key,
1199                                  name,
1200                                  exp,
1201                                  num_records,
1202                                  rd,
1203                                  &nrb->signature,
1204                                  &on_namestore_record_put_result, //cont
1205                                  NULL); //cls
1206     }
1207   }
1208   
1209   if (rh->answered)
1210   {
1211     rh->answered = 0;
1212     /**
1213      * delegate
1214      * FIXME in this case. should we ask namestore again?
1215      */
1216     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1217                "GNS_PHASE_DELEGATE: Answer from DHT for %s to resolve: %s\n",
1218                rh->authority_name, rh->name);
1219     if (strcmp(rh->name, "") == 0)
1220       rh->proc(rh->proc_cls, rh, 0, NULL);
1221     else
1222       resolve_delegation_ns(rh);
1223     return;
1224   }
1225   
1226   /**
1227    * No pkey but name exists
1228    * promote back
1229    */
1230   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1231              "GNS_PHASE_DELEGATE: Adding %s back to %s\n",
1232              rh->authority_name, rh->name);
1233   if (strcmp(rh->name, "") == 0)
1234     strcpy(rh->name, rh->authority_name);
1235   else
1236     GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1237                   rh->name, rh->authority_name); //FIXME ret
1238   
1239   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1240              "GNS_PHASE_DELEGATE: %s restored\n", rh->name);
1241   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1242              "GNS_PHASE_DELEGATE: DHT authority lookup found no match!\n");
1243   rh->proc(rh->proc_cls, rh, 0, NULL);
1244 }
1245
1246 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1247                         +(MAX_DNS_NAME_LENGTH*2)
1248 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1249
1250
1251 static void
1252 expand_plus(char** dest, char* src, char* repl)
1253 {
1254   char* pos;
1255   unsigned int s_len = strlen(src)+1;
1256
1257   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1258              "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1259
1260   if (s_len < 3)
1261   {
1262     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1263                "GNS_POSTPROCESS: %s to short\n", src);
1264
1265     /* no postprocessing */
1266     memcpy(*dest, src, s_len+1);
1267     return;
1268   }
1269   
1270   if (0 == strcmp(src+s_len-3, ".+"))
1271   {
1272     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1273                "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1274     memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1275     strcpy(*dest, src);
1276     pos = *dest+s_len-2;
1277     strcpy(pos, repl);
1278     pos += strlen(repl);
1279     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1280                "GNS_POSTPROCESS: Expanded to %s\n", *dest);
1281   }
1282   else
1283   {
1284     memcpy(*dest, src, s_len+1);
1285   }
1286 }
1287
1288 /**
1289  * finish lookup
1290  */
1291 static void
1292 finish_lookup(struct ResolverHandle *rh,
1293               struct RecordLookupHandle* rlh,
1294               unsigned int rd_count,
1295               const struct GNUNET_NAMESTORE_RecordData *rd)
1296 {
1297   int i;
1298   char new_rr_data[MAX_DNS_NAME_LENGTH];
1299   char new_mx_data[MAX_MX_LENGTH];
1300   char new_soa_data[MAX_SOA_LENGTH];
1301   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1302   char* repl_string;
1303   char* pos;
1304   unsigned int offset;
1305
1306   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1307     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1308
1309   if (rd_count > 0)
1310     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1311
1312   for (i = 0; i < rd_count; i++)
1313   {
1314     
1315     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1316         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1317         rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1318         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1319     {
1320       p_rd[i].data = rd[i].data;
1321       continue;
1322     }
1323
1324     /**
1325      * for all those records we 'should'
1326      * also try to resolve the A/AAAA records (RFC1035)
1327      * This is a feature and not important
1328      */
1329     
1330     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1331                "GNS_POSTPROCESS: Postprocessing\n");
1332
1333     if (strcmp(rh->name, "+") == 0)
1334       repl_string = rlh->name;
1335     else
1336       repl_string = rlh->name+strlen(rh->name)+1;
1337
1338     offset = 0;
1339     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1340     {
1341       memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1342       offset = sizeof(uint16_t);
1343       pos = new_mx_data+offset;
1344       expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1345                   repl_string);
1346       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1347       p_rd[i].data = new_mx_data;
1348       p_rd[i].data_size = offset;
1349     }
1350     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1351     {
1352       /* expand mname and rname */
1353       pos = new_soa_data;
1354       expand_plus(&pos, (char*)rd[i].data, repl_string);
1355       offset = strlen(new_soa_data)+1;
1356       pos = new_soa_data+offset;
1357       expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1358       offset += strlen(new_soa_data+offset)+1;
1359       /* cpy the 4 numbers serial refresh retry and expire */
1360       memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
1361       offset += sizeof(uint32_t)*5;
1362       p_rd[i].data_size = offset;
1363       p_rd[i].data = new_soa_data;
1364     }
1365     else
1366     {
1367       pos = new_rr_data;
1368       expand_plus(&pos, (char*)rd[i].data, repl_string);
1369       p_rd[i].data_size = strlen(new_rr_data)+1;
1370       p_rd[i].data = new_rr_data;
1371     }
1372     
1373   }
1374
1375   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1376   GNUNET_free(rlh);
1377   
1378 }
1379
1380 /**
1381  * Process DHT lookup result for record.
1382  *
1383  * @param cls the closure
1384  * @param rh resolver handle
1385  * @param rd_count number of results
1386  * @param rd record data
1387  */
1388 static void
1389 handle_record_dht(void* cls, struct ResolverHandle *rh,
1390                        unsigned int rd_count,
1391                        const struct GNUNET_NAMESTORE_RecordData *rd)
1392 {
1393   struct RecordLookupHandle* rlh;
1394
1395   rlh = (struct RecordLookupHandle*)cls;
1396   if (rd_count == 0)
1397   {
1398     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1399                "GNS_PHASE_REC: No records for %s found in DHT. Aborting\n",
1400                rh->name);
1401     /* give up, cannot resolve */
1402     finish_lookup(rh, rlh, 0, NULL);
1403     free_resolver_handle(rh);
1404     return;
1405   }
1406
1407   /* results found yay */
1408   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1409              "GNS_PHASE_REC: Record resolved from DHT!");
1410
1411   finish_lookup(rh, rlh, rd_count, rd);
1412   free_resolver_handle(rh);
1413
1414 }
1415
1416
1417 /**
1418  * Process namestore lookup result for record.
1419  *
1420  * @param cls the closure
1421  * @param rh resolver handle
1422  * @param rd_count number of results
1423  * @param rd record data
1424  */
1425 static void
1426 handle_record_ns(void* cls, struct ResolverHandle *rh,
1427                        unsigned int rd_count,
1428                        const struct GNUNET_NAMESTORE_RecordData *rd)
1429 {
1430   struct RecordLookupHandle* rlh;
1431   rlh = (struct RecordLookupHandle*) cls;
1432   if (rd_count == 0)
1433   {
1434     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1435                "GNS_PHASE_REC: NS returned no records. (status: %d)!\n",
1436                rh->status);
1437     
1438     /**
1439      * There are 4 conditions that have to met for us to consult the DHT:
1440      * 1. The entry in the DHT is EXPIRED AND
1441      * 2. No entry in the NS existed AND
1442      * 3. The zone queried is not the local resolver's zone AND
1443      * 4. The name that was looked up is '+'
1444      *    because if it was any other canonical name we either already queried
1445      *    the DHT for the authority in the authority lookup phase (and thus
1446      *    would already have an entry in the NS for the record)
1447      */
1448     if (rh->status & (EXPIRED | !EXISTS) &&
1449         GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1450                                      &local_zone) &&
1451         (strcmp(rh->name, "+") == 0))
1452     {
1453       rh->proc = &handle_record_dht;
1454       resolve_record_dht(rh);
1455       return;
1456     }
1457     /* give up, cannot resolve */
1458     finish_lookup(rh, rlh, 0, NULL);
1459     free_resolver_handle(rh);
1460     return;
1461   }
1462
1463   /* results found yay */
1464   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1465              "GNS_PHASE_REC: Record resolved from namestore!");
1466
1467   finish_lookup(rh, rlh, rd_count, rd);
1468
1469   free_resolver_handle(rh);
1470
1471 }
1472
1473
1474 /**
1475  * Determine if this name is canonical.
1476  * i.e.
1477  * a.b.gnunet  = not canonical
1478  * a           = canonical
1479  *
1480  * @param name the name to test
1481  * @return 1 if canonical
1482  */
1483 static int
1484 is_canonical(char* name)
1485 {
1486   uint32_t len = strlen(name);
1487   int i;
1488
1489   for (i=0; i<len; i++)
1490   {
1491     if (*(name+i) == '.')
1492       return 0;
1493   }
1494   return 1;
1495 }
1496
1497 /**
1498  * Move one level up in the domain hierarchy and return the
1499  * passed top level domain.
1500  *
1501  * @param name the domain
1502  * @param dest the destination where the tld will be put
1503  */
1504 void
1505 pop_tld(char* name, char* dest)
1506 {
1507   uint32_t len;
1508
1509   if (is_canonical(name))
1510   {
1511     strcpy(dest, name);
1512     strcpy(name, "");
1513     return;
1514   }
1515
1516   for (len = strlen(name); len > 0; len--)
1517   {
1518     if (*(name+len) == '.')
1519       break;
1520   }
1521   
1522   //Was canonical?
1523   if (len == 0)
1524     return;
1525
1526   name[len] = '\0';
1527
1528   strcpy(dest, (name+len+1));
1529 }
1530
1531 /**
1532  * Checks if name is in tld
1533  *
1534  * @param name the name to check
1535  * @param tld the TLD to check for
1536  * @return GNUNET_YES or GNUNET_NO
1537  */
1538 int
1539 is_tld(const char* name, const char* tld)
1540 {
1541   int offset = 0;
1542
1543   if (strlen(name) <= strlen(tld))
1544   {
1545     return GNUNET_NO;
1546   }
1547   
1548   offset = strlen(name)-strlen(tld);
1549   if (strcmp(name+offset, tld) != 0)
1550   {
1551     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1552                "%s is not in .%s TLD\n", name, tld);
1553     return GNUNET_NO;
1554   }
1555   return GNUNET_YES;
1556 }
1557
1558 /**
1559  * DHT resolution for delegation finished. Processing result.
1560  *
1561  * @param cls the closure
1562  * @param rh resolver handle
1563  * @param rd_count number of results (always 0)
1564  * @param rd record data (always NULL)
1565  */
1566 static void
1567 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1568                           unsigned int rd_count,
1569                           const struct GNUNET_NAMESTORE_RecordData *rd)
1570 {
1571   struct RecordLookupHandle* rlh;
1572   rlh = (struct RecordLookupHandle*) cls;
1573   
1574
1575   if (strcmp(rh->name, "") == 0)
1576   {
1577     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1578     {
1579       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1580                  "GNS_PHASE_DELEGATE_DHT: Resolved queried PKEY via DHT.\n");
1581       finish_lookup(rh, rlh, rd_count, rd);
1582       free_resolver_handle(rh);
1583       return;
1584     }
1585     /* We resolved full name for delegation. resolving record */
1586     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1587       "GNS_PHASE_DELEGATE_DHT: Resolved full name for delegation via DHT.\n");
1588     strcpy(rh->name, "+\0");
1589     rh->proc = &handle_record_ns;
1590     resolve_record_ns(rh);
1591     return;
1592   }
1593
1594   /**
1595    * we still have some left
1596    **/
1597   if (is_canonical(rh->name))
1598   {
1599     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1600                "GNS_PHASE_DELEGATE_DHT: Resolving canonical record %s in ns\n",
1601                rh->name);
1602     rh->proc = &handle_record_ns;
1603     resolve_record_ns(rh);
1604     return;
1605   }
1606   /* give up, cannot resolve */
1607   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1608     "GNS_PHASE_DELEGATE_DHT: Cannot fully resolve delegation for %s via DHT!\n",
1609              rh->name);
1610   finish_lookup(rh, rlh, 0, NULL);
1611   free_resolver_handle(rh);
1612 }
1613
1614
1615 /**
1616  * Start DHT lookup for a name -> PKEY (compare NS) record in
1617  * rh->authority's zone
1618  *
1619  * @param rh the pending gns query
1620  */
1621 static void
1622 resolve_delegation_dht(struct ResolverHandle *rh)
1623 {
1624   uint32_t xquery;
1625   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1626   GNUNET_HashCode name_hash_double;
1627   GNUNET_HashCode zone_hash_double;
1628   GNUNET_HashCode lookup_key;
1629   struct ResolverHandle *rh_heap_root;
1630   
1631   pop_tld(rh->name, rh->authority_name); 
1632   GNUNET_CRYPTO_short_hash(rh->authority_name,
1633                      strlen(rh->authority_name),
1634                      &name_hash);
1635   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1636   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1637   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1638   
1639   rh->dht_heap_node = NULL;
1640
1641   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1642   {
1643     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1644     //                                          &dht_authority_lookup_timeout,
1645     //                                                   rh);
1646     rh->timeout_cont = &dht_authority_lookup_timeout;
1647     rh->timeout_cont_cls = rh;
1648   }
1649   else 
1650   {
1651     if (max_allowed_background_queries <=
1652         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1653     {
1654       /* terminate oldest lookup */
1655       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1656       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1657       rh_heap_root->dht_heap_node = NULL;
1658       
1659       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1660              "GNS_PHASE_DELEGATE: Replacing oldest background query for %s\n",
1661                  rh_heap_root->authority_name);
1662       
1663       rh_heap_root->proc(rh_heap_root->proc_cls,
1664                          rh_heap_root,
1665                          0,
1666                          NULL);
1667     }
1668     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1669                                          rh,
1670                                          GNUNET_TIME_absolute_get().abs_value);
1671   }
1672   
1673   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1674   
1675   GNUNET_assert(rh->get_handle == NULL);
1676   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1677                        GNUNET_TIME_UNIT_FOREVER_REL,
1678                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1679                        &lookup_key,
1680                        DHT_GNS_REPLICATION_LEVEL,
1681                        GNUNET_DHT_RO_NONE,
1682                        &xquery,
1683                        sizeof(xquery),
1684                        &process_delegation_result_dht,
1685                        rh);
1686
1687 }
1688
1689
1690 /**
1691  * Namestore resolution for delegation finished. Processing result.
1692  *
1693  * @param cls the closure
1694  * @param rh resolver handle
1695  * @param rd_count number of results (always 0)
1696  * @param rd record data (always NULL)
1697  */
1698 static void
1699 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1700                           unsigned int rd_count,
1701                           const struct GNUNET_NAMESTORE_RecordData *rd)
1702 {
1703   struct RecordLookupHandle* rlh;
1704   rlh = (struct RecordLookupHandle*) cls;
1705   
1706   if (strcmp(rh->name, "") == 0)
1707   {
1708     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1709     {
1710       GNUNET_assert(rd_count == 1);
1711       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1712                  "GNS_PHASE_DELEGATE_NS: Resolved queried PKEY in NS.\n");
1713       finish_lookup(rh, rlh, rd_count, rd);
1714       free_resolver_handle(rh);
1715       return;
1716     }
1717     /* We resolved full name for delegation. resolving record */
1718     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1719                "GNS_PHASE_DELEGATE_NS: Resolved full name for delegation.\n");
1720     strcpy(rh->name, "+\0");
1721     rh->proc = &handle_record_ns;
1722     resolve_record_ns(rh);
1723     return;
1724   }
1725
1726   /**
1727    * we still have some left
1728    * check if authority in ns is fresh
1729    * and exists
1730    * or we are authority
1731    **/
1732   if ((rh->status & (EXISTS | !EXPIRED)) ||
1733       !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1734                              &rh->authority_chain_tail->zone))
1735   {
1736     if (is_canonical(rh->name))
1737     {
1738       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1739                  "GNS_PHASE_DELEGATE_NS: Resolving canonical record %s\n",
1740                  rh->name);
1741       rh->proc = &handle_record_ns;
1742       resolve_record_ns(rh);
1743     }
1744     else
1745     {
1746       /* give up, cannot resolve */
1747       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1748              "GNS_PHASE_DELEGATE_NS: Cannot fully resolve delegation for %s!\n",
1749                 rh->name);
1750       finish_lookup(rh, rlh, rd_count, rd);
1751       //rlh->proc(rlh->proc_cls, 0, NULL);
1752     }
1753     return;
1754   }
1755   
1756   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1757          "GNS_PHASE_DELEGATE_NS: Trying to resolve delegation for %s via DHT\n",
1758             rh->name);
1759   rh->proc = &handle_delegation_dht;
1760   resolve_delegation_dht(rh);
1761 }
1762
1763
1764
1765 /**
1766  * This is a callback function that should give us only PKEY
1767  * records. Used to query the namestore for the authority (PKEY)
1768  * for 'name'. It will recursively try to resolve the
1769  * authority for a given name from the namestore.
1770  *
1771  * @param cls the pending query
1772  * @param key the key of the zone we did the lookup
1773  * @param expiration expiration date of the record data set in the namestore
1774  * @param name the name for which we need an authority
1775  * @param rd_count the number of records with 'name'
1776  * @param rd the record data
1777  * @param signature the signature of the authority for the record data
1778  */
1779 static void
1780 process_delegation_result_ns(void* cls,
1781                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1782                    struct GNUNET_TIME_Absolute expiration,
1783                    const char *name,
1784                    unsigned int rd_count,
1785                    const struct GNUNET_NAMESTORE_RecordData *rd,
1786                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1787 {
1788   struct ResolverHandle *rh;
1789   struct GNUNET_TIME_Relative remaining_time;
1790   struct GNUNET_CRYPTO_ShortHashCode zone;
1791   char new_name[MAX_DNS_NAME_LENGTH];
1792   
1793   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1794              "GNS_PHASE_DELEGATE: Got %d records from authority lookup\n",
1795              rd_count);
1796
1797   rh = (struct ResolverHandle *)cls;
1798   GNUNET_CRYPTO_short_hash(key,
1799                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1800                      &zone);
1801   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1802   
1803   rh->status = 0;
1804   
1805   if (name != NULL)
1806   {
1807     rh->status |= EXISTS;
1808   }
1809   
1810   if (remaining_time.rel_value == 0)
1811   {
1812     rh->status |= EXPIRED;
1813   }
1814   
1815   /**
1816    * No authority found in namestore.
1817    */
1818   if (rd_count == 0)
1819   {
1820     /**
1821      * We did not find an authority in the namestore
1822      */
1823     
1824     /**
1825      * No PKEY in zone.
1826      * Promote this authority back to a name maybe it is
1827      * our record.
1828      */
1829     if (strcmp(rh->name, "") == 0)
1830     {
1831       /* simply promote back */
1832       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1833                  "GNS_PHASE_DELEGATE: Promoting %s back to name\n",
1834                  rh->authority_name);
1835       strcpy(rh->name, rh->authority_name);
1836     }
1837     else
1838     {
1839       /* add back to existing name */
1840       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1841                  "GNS_PHASE_DELEGATE: Adding %s back to %s\n",
1842                  rh->authority_name, rh->name);
1843       //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1844       strcpy(new_name, rh->name);
1845       strcpy(new_name+strlen(new_name), ".");
1846       strcpy(new_name+strlen(new_name), rh->authority_name);
1847       strcpy(rh->name, new_name);
1848       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1849                  "GNS_PHASE_DELEGATE: %s restored\n", rh->name);
1850     }
1851     rh->proc(rh->proc_cls, rh, 0, NULL);
1852     return;
1853   }
1854
1855   /**
1856    * We found an authority that may be able to help us
1857    * move on with query
1858    * Note only 1 pkey should have been returned.. anything else would be strange
1859    */
1860   int i;
1861   for (i=0; i<rd_count;i++)
1862   {
1863   
1864     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1865       continue;
1866     
1867     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1868          == 0)
1869     {
1870       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1871                  "GNS_PHASE_DELEGATE: This pkey is expired.\n");
1872       if (remaining_time.rel_value == 0)
1873       {
1874         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1875                    "GNS_PHASE_DELEGATE: This dht entry is expired.\n");
1876         rh->authority_chain_head->fresh = 0;
1877         rh->proc(rh->proc_cls, rh, 0, NULL);
1878         return;
1879       }
1880
1881       continue;
1882     }
1883
1884     /**
1885      * Resolve rest of query with new authority
1886      */
1887     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1888     memcpy(&rh->authority, rd[i].data,
1889            sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1890     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1891     auth->zone = rh->authority;
1892     memset(auth->name, 0, strlen(rh->authority_name)+1);
1893     strcpy(auth->name, rh->authority_name);
1894     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1895                                  rh->authority_chain_tail,
1896                                  auth);
1897     
1898     /** try to import pkey if private key available */
1899     if (rh->priv_key)
1900       process_discovered_authority((char*)name, auth->zone,
1901                                    rh->authority_chain_tail->zone,
1902                                    rh->priv_key);
1903     /**
1904      * We are done with PKEY resolution if name is empty
1905      * else resolve again with new authority
1906      */
1907     if (strcmp(rh->name, "") == 0)
1908       rh->proc(rh->proc_cls, rh, rd_count, rd);
1909     else
1910       resolve_delegation_ns(rh);
1911     return;
1912   }
1913     
1914   /**
1915    * no answers found
1916    */
1917   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1918     "GNS_PHASE_DELEGATE: Authority lookup and but no PKEY... never get here\n");
1919   rh->proc(rh->proc_cls, rh, 0, NULL);
1920 }
1921
1922
1923 /**
1924  * Resolve the delegation chain for the request in our namestore
1925  *
1926  * @param rh the resolver handle
1927  */
1928 static void
1929 resolve_delegation_ns(struct ResolverHandle *rh)
1930 {
1931   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1932              "GNS_PHASE_DELEGATE: Resolving delegation for %s\n", rh->name);
1933   pop_tld(rh->name, rh->authority_name);
1934   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1935                                  &rh->authority,
1936                                  rh->authority_name,
1937                                  GNUNET_GNS_RECORD_PKEY,
1938                                  &process_delegation_result_ns,
1939                                  rh);
1940
1941 }
1942
1943
1944 /**
1945  * Lookup of a record in a specific zone
1946  * calls lookup result processor on result
1947  *
1948  * @param zone the root zone
1949  * @param record_type the record type to look up
1950  * @param name the name to look up
1951  * @param key a private key for use with PSEU import (can be NULL)
1952  * @param timeout timeout for resolution
1953  * @param proc the processor to call on result
1954  * @param cls the closure to pass to proc
1955  */
1956 void
1957 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1958                            uint32_t record_type,
1959                            const char* name,
1960                            struct GNUNET_CRYPTO_RsaPrivateKey *key,
1961                            struct GNUNET_TIME_Relative timeout,
1962                            RecordLookupProcessor proc,
1963                            void* cls)
1964 {
1965   struct ResolverHandle *rh;
1966   struct RecordLookupHandle* rlh;
1967   char string_hash[MAX_DNS_LABEL_LENGTH];
1968   uint8_t* normalized_zkey;
1969   char nzkey[MAX_DNS_LABEL_LENGTH];
1970   size_t normal_len;
1971
1972   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1973               "Starting resolution for %s (type=%d)!\n",
1974               name, record_type);
1975
1976   
1977   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1978   {
1979     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1980                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1981     proc(cls, 0, NULL);
1982     return;
1983   }
1984   
1985   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1986   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1987
1988   rh->authority = zone;
1989   rh->proc_cls = rlh;
1990   rh->priv_key = key;
1991   rh->timeout = timeout;
1992   rh->get_handle = NULL;
1993   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1994   {
1995     /*
1996      * Set timeout for authority lookup phase to 1/2
1997      */
1998     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1999                                 GNUNET_TIME_relative_divide(timeout, 2),
2000                                                 &handle_lookup_timeout,
2001                                                 rh);
2002     rh->timeout_cont = &dht_authority_lookup_timeout;
2003     rh->timeout_cont_cls = rh;
2004   }
2005   else
2006   {
2007     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2008     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2009   }
2010   
2011   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2012   {
2013     /**
2014      * Only 'gnunet' given
2015      */
2016     strcpy(rh->name, "\0");
2017   }
2018   else
2019   {
2020     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2021                 "Checking for TLD...\n");
2022     if (is_zkey_tld(name) == GNUNET_YES)
2023     {
2024       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2025                   "TLD is zkey\n");
2026       /**
2027        * This is a zkey tld
2028        * build hash and use as initial authority
2029        */
2030       memset(rh->name, 0,
2031              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2032       memcpy(rh->name, name,
2033              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2034       pop_tld(rh->name, string_hash);
2035
2036       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2037                   "ZKEY is %s!\n", string_hash);
2038       
2039       normalized_zkey = u8_toupper ((uint8_t*)string_hash,
2040                                     strlen ((char *) string_hash),
2041                                     NULL, UNINORM_NFD, NULL, &normal_len);
2042
2043
2044       memcpy(nzkey, normalized_zkey, normal_len);
2045       nzkey[normal_len] = '\0';
2046       free(normalized_zkey);
2047       
2048       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2049                                                       &rh->authority))
2050       {
2051         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2052                     "Cannot convert ZKEY %s to hash!\n", string_hash);
2053         GNUNET_free(rh);
2054         GNUNET_free(rlh);
2055         proc(cls, 0, NULL);
2056         return;
2057       }
2058
2059     }
2060     else
2061     {
2062       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2063                   "TLD is gnunet\n");
2064       /**
2065        * Presumably GNUNET tld
2066        */
2067       memset(rh->name, 0,
2068              strlen(name)-strlen(GNUNET_GNS_TLD));
2069       memcpy(rh->name, name,
2070              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2071     }
2072   }
2073   
2074   /**
2075    * Initialize authority chain
2076    */
2077   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2078   rh->authority_chain_head->prev = NULL;
2079   rh->authority_chain_head->next = NULL;
2080   rh->authority_chain_tail = rh->authority_chain_head;
2081   rh->authority_chain_head->zone = rh->authority;
2082   
2083   /**
2084    * Copy original query into lookup handle
2085    */
2086   rlh->record_type = record_type;
2087   memset(rlh->name, 0, strlen(name) + 1);
2088   strcpy(rlh->name, name);
2089   rlh->proc = proc;
2090   rlh->proc_cls = cls;
2091
2092   rh->proc = &handle_delegation_ns;
2093   resolve_delegation_ns(rh);
2094 }
2095
2096 /******** END Record Resolver ***********/
2097
2098
2099 /**
2100  * Callback calles by namestore for a zone to name
2101  * result
2102  *
2103  * @param cls the closure
2104  * @param zone_key the zone we queried
2105  * @param expire the expiration time of the name
2106  * @param name the name found or NULL
2107  * @param rd_len number of records for the name
2108  * @param rd the record data (PKEY) for the name
2109  * @param signature the signature for the record data
2110  */
2111 static void
2112 process_zone_to_name_shorten(void *cls,
2113                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2114                  struct GNUNET_TIME_Absolute expire,
2115                  const char *name,
2116                  unsigned int rd_len,
2117                  const struct GNUNET_NAMESTORE_RecordData *rd,
2118                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2119 {
2120   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2121   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2122   struct AuthorityChain *next_authority;
2123
2124   char result[MAX_DNS_NAME_LENGTH];
2125   char next_authority_name[MAX_DNS_LABEL_LENGTH];
2126   size_t answer_len;
2127   
2128   /* we found a match in our own zone */
2129   if (rd_len != 0)
2130   {
2131     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2132                "result strlen %d\n", strlen(name));
2133     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2134     memset(result, 0, answer_len);
2135     if (strlen(rh->name) > 0)
2136     {
2137       strcpy(result, rh->name);
2138       strcpy(result+strlen(rh->name), ".");
2139     }
2140     
2141     strcpy(result+strlen(result), name);
2142     strcpy(result+strlen(result), ".");
2143     strcpy(result+strlen(result), GNUNET_GNS_TLD);
2144     
2145     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2146                "Sending shorten result %s\n", result);
2147
2148     nsh->proc(nsh->proc_cls, result);
2149     GNUNET_free(nsh);
2150     free_resolver_handle(rh);
2151   }
2152   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2153                                         &local_zone))
2154   {
2155     /* our zone, just append .gnunet */
2156     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2157     memset(result, 0, answer_len);
2158     strcpy(result, rh->name);
2159     strcpy(result+strlen(rh->name), ".");
2160     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2161
2162     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2163                "Our zone: Sending name as shorten result %s\n", rh->name);
2164     
2165     nsh->proc(nsh->proc_cls, result);
2166     GNUNET_free(nsh);
2167     free_resolver_handle(rh);
2168   }
2169   else
2170   {
2171     /**
2172      * No PSEU found.
2173      * continue with next authority
2174      */
2175     next_authority = rh->authority_chain_head;
2176     //                         strlen(next_authority->name) + 2);
2177     memset(next_authority_name, 0, strlen(rh->name)+
2178                       strlen(next_authority->name) + 2);
2179     strcpy(next_authority_name, rh->name);
2180     strcpy(next_authority_name+strlen(rh->name)+1, ".");
2181     strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
2182   
2183     strcpy(rh->name, next_authority_name);
2184     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2185                               rh->authority_chain_tail,
2186                               next_authority);
2187
2188     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2189                                    &rh->authority_chain_tail->zone,
2190                                    &rh->authority_chain_head->zone,
2191                                    &process_zone_to_name_shorten,
2192                                    rh);
2193   }
2194 }
2195
2196 /**
2197  * DHT resolution for delegation finished. Processing result.
2198  *
2199  * @param cls the closure
2200  * @param rh resolver handle
2201  * @param rd_count number of results (always 0)
2202  * @param rd record data (always NULL)
2203  */
2204 static void
2205 handle_delegation_dht_bg_shorten(void* cls, struct ResolverHandle *rh,
2206                           unsigned int rd_count,
2207                           const struct GNUNET_NAMESTORE_RecordData *rd)
2208 {
2209   
2210   /* We resolved full name for delegation. resolving record */
2211   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2212     "GNS_SHORTEN: Resolved up to %s for delegation via DHT in background.\n",
2213     rh->name);
2214   free_resolver_handle(rh);
2215 }
2216
2217 /**
2218  * Process result from namestore delegation lookup
2219  * for shorten operation
2220  *
2221  * @param cls the client shorten handle
2222  * @param rh the resolver handle
2223  * @param rd_count number of results (0)
2224  * @param rd data (NULL)
2225  */
2226 void
2227 handle_delegation_ns_shorten(void* cls,
2228                       struct ResolverHandle *rh,
2229                       uint32_t rd_count,
2230                       const struct GNUNET_NAMESTORE_RecordData *rd)
2231 {
2232   struct NameShortenHandle *nsh;
2233   char result[MAX_DNS_NAME_LENGTH];
2234   size_t answer_len;
2235   struct ResolverHandle *rh_bg;
2236
2237   nsh = (struct NameShortenHandle *)cls;
2238   
2239   /**
2240    * At this point rh->name contains the part of the name
2241    * that we do not have a PKEY in our namestore to resolve.
2242    * The authority chain in the resolver handle is now
2243    * useful to backtrack if needed
2244    */
2245   
2246   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2247              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2248
2249   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2250                                    &local_zone) == 0)
2251   {
2252     /**
2253      * This is our zone append .gnunet unless name is empty
2254      * (it shouldn't be, usually FIXME what happens if we
2255      * shorten to our zone to a "" record??)
2256      */
2257     
2258     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2259     memset(result, 0, answer_len);
2260     strcpy(result, rh->name);
2261     strcpy(result+strlen(rh->name), ".");
2262     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2263
2264     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2265                "Our zone: Sending name as shorten result %s\n", rh->name);
2266     
2267     nsh->proc(nsh->proc_cls, result);
2268     GNUNET_free(nsh);
2269     free_resolver_handle(rh);
2270     return;
2271   }
2272   
2273   /**
2274    * we have to this before zone to name for rh might
2275    * be freed by then
2276    */
2277   rh_bg = NULL;
2278   if (!is_canonical(rh->name))
2279   {
2280     rh_bg = GNUNET_malloc(sizeof(struct ResolverHandle));
2281     memcpy(rh_bg, rh, sizeof(struct ResolverHandle));
2282   }
2283
2284   /* backtrack authorities for names */
2285   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2286                                  &rh->authority_chain_tail->zone, //ours
2287                                  &rh->authority_chain_head->zone,
2288                                  &process_zone_to_name_shorten,
2289                                  rh);
2290   
2291   if (rh_bg == NULL)
2292   {
2293     return;
2294   }
2295
2296   /**
2297    * If authority resolution is incomplete we can do a background lookup
2298    * of the full name so that next time we can (likely) fully or at least
2299    * further shorten the name
2300    */
2301   rh_bg->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2302   rh_bg->authority_chain_tail = rh_bg->authority_chain_head;
2303   rh_bg->authority_chain_head->zone = rh_bg->authority;
2304   
2305   rh_bg->proc = &handle_delegation_dht_bg_shorten;
2306   rh_bg->proc_cls = NULL;
2307   
2308   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2309              "GNS_SHORTEN: Starting background lookup for %s\n",
2310              rh_bg->name);
2311
2312   resolve_delegation_dht(rh_bg);
2313
2314 }
2315
2316
2317 /**
2318  * Callback calles by namestore for a zone to name
2319  * result
2320  *
2321  * @param cls the closure
2322  * @param zone_key the zone we queried
2323  * @param expire the expiration time of the name
2324  * @param name the name found or NULL
2325  * @param rd_len number of records for the name
2326  * @param rd the record data (PKEY) for the name
2327  * @param signature the signature for the record data
2328  */
2329 static void
2330 process_zone_to_name_zkey(void *cls,
2331                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2332                  struct GNUNET_TIME_Absolute expire,
2333                  const char *name,
2334                  unsigned int rd_len,
2335                  const struct GNUNET_NAMESTORE_RecordData *rd,
2336                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2337 {
2338   struct ResolverHandle *rh = cls;
2339   struct NameShortenHandle *nsh = rh->proc_cls;
2340   struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
2341   char new_name[MAX_DNS_NAME_LENGTH];
2342
2343   /* zkey not in our zone */
2344   if (name == NULL)
2345   {
2346     /**
2347      * In this case we have not given this PKEY a name (yet)
2348      * It is either just not in our zone or not even cached
2349      * Since we do not know at this point we will not try to shorten
2350      * because PKEY import will happen if the user follows the zkey
2351      * link.
2352      */
2353     GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
2354                                      &enc);
2355     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2356                "No name found for zkey %s returning verbatim!\n", enc);
2357     if (strcmp(rh->name, "") != 0)
2358       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
2359                       rh->name, enc, GNUNET_GNS_TLD_ZKEY);
2360     else
2361       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2362                       enc, GNUNET_GNS_TLD_ZKEY);
2363     nsh->proc(nsh->proc_cls, new_name);
2364     GNUNET_free(nsh);
2365     free_resolver_handle(rh);
2366     return;
2367   }
2368   
2369   if (strcmp(rh->name, "") != 0)
2370     GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2371                     rh->name, name);
2372   else
2373     strcpy(new_name, name);
2374
2375   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2376              "Continue shorten for %s!\n", new_name);
2377
2378   strcpy(rh->name, new_name);
2379   
2380   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2381   rh->authority_chain_tail = rh->authority_chain_head;
2382   rh->authority_chain_head->zone = rh->authority;
2383   
2384   
2385   /* Start delegation resolution in our namestore */
2386   resolve_delegation_ns(rh);
2387 }
2388   
2389 /**
2390  * Shorten api from resolver
2391  *
2392  * @param zone the zone to use
2393  * @param name the name to shorten
2394  * @param key optional private key for background lookups and PSEU import
2395  * @param proc the processor to call with result
2396  * @param proc_cls closure to pass to proc
2397  */
2398 void
2399 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2400                           const char* name,
2401                           struct GNUNET_CRYPTO_RsaPrivateKey *key,
2402                           ShortenResultProcessor proc,
2403                           void* proc_cls)
2404 {
2405   struct ResolverHandle *rh;
2406   struct NameShortenHandle *nsh;
2407   char string_hash[MAX_DNS_LABEL_LENGTH];
2408   struct GNUNET_CRYPTO_ShortHashCode zkey;
2409   uint8_t* normalized_zkey;
2410   size_t normal_len;
2411   char nzkey[MAX_DNS_LABEL_LENGTH];
2412
2413
2414   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2415               "Starting shorten for %s!\n", name);
2416   
2417   if (is_canonical((char*)name))
2418   {
2419     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2420                 "%s is canonical. Returning verbatim\n", name);
2421     proc(proc_cls, name);
2422     return;
2423   }
2424
2425   nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2426
2427   nsh->proc = proc;
2428   nsh->proc_cls = proc_cls;
2429   
2430   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2431   rh->authority = zone;
2432   rh->priv_key = key;
2433   rh->proc = &handle_delegation_ns_shorten;
2434   rh->proc_cls = nsh;
2435   
2436   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2437                 "Checking for TLD...\n");
2438   if (is_zkey_tld(name) == GNUNET_YES)
2439   {
2440     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2441                 "TLD is zkey\n");
2442     /**
2443      * This is a zkey tld
2444      * build hash and use as initial authority
2445      * FIXME sscanf
2446      */
2447     memset(rh->name, 0,
2448            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2449     memcpy(rh->name, name,
2450            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2451     pop_tld(rh->name, string_hash);
2452
2453     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2454                 "ZKEY is %s!\n", string_hash);
2455
2456     normalized_zkey = u8_toupper ((uint8_t*)string_hash, strlen ((char *) string_hash),
2457                                   NULL, UNINORM_NFD, NULL, &normal_len);
2458
2459     memcpy(nzkey, normalized_zkey, normal_len);
2460     nzkey[normal_len] = '\0';
2461     free(normalized_zkey);
2462
2463     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2464                                                           &zkey))
2465     {
2466       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2467                   "Cannot convert ZKEY %s to hash!\n", nzkey);
2468       GNUNET_free(rh);
2469       GNUNET_free(nsh);
2470       proc(proc_cls, name);
2471       return;
2472     }
2473
2474     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2475                                    &zone, //ours
2476                                    &zkey,
2477                                    &process_zone_to_name_zkey,
2478                                    rh);
2479     return;
2480
2481   }
2482   else
2483   {
2484     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2485                 "TLD is gnunet\n");
2486     /**
2487      * Presumably GNUNET tld
2488      */
2489     memset(rh->name, 0,
2490            strlen(name)-strlen(GNUNET_GNS_TLD));
2491     memcpy(rh->name, name,
2492            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2493   }
2494
2495   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2496   rh->authority_chain_tail = rh->authority_chain_head;
2497   rh->authority_chain_head->zone = zone;
2498   
2499   
2500   /* Start delegation resolution in our namestore */
2501   resolve_delegation_ns(rh);
2502 }
2503
2504 /*********** END NAME SHORTEN ********************/
2505
2506
2507 /**
2508  * Process result from namestore delegation lookup
2509  * for get authority operation
2510  *
2511  * @param cls the client get auth handle
2512  * @param rh the resolver handle
2513  * @param rd_count number of results (0)
2514  * @param rd data (NULL)
2515  */
2516 void
2517 handle_delegation_result_ns_get_auth(void* cls,
2518                       struct ResolverHandle *rh,
2519                       uint32_t rd_count,
2520                       const struct GNUNET_NAMESTORE_RecordData *rd)
2521 {
2522   struct GetNameAuthorityHandle* nah;
2523   char result[MAX_DNS_NAME_LENGTH];
2524   size_t answer_len;
2525
2526   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2527   
2528   /**
2529    * At this point rh->name contains the part of the name
2530    * that we do not have a PKEY in our namestore to resolve.
2531    * The authority chain in the resolver handle is now
2532    * useful to backtrack if needed
2533    */
2534   
2535   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2536              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2537
2538   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2539              "Building response!\n");
2540   if (is_canonical(rh->name))
2541   {
2542     /**
2543      * We successfully resolved the authority in the ns
2544      * FIXME for our purposes this is fine
2545      * but maybe we want to have an api that also looks
2546      * into the dht (i.e. option in message)
2547      **/
2548     if (strlen(rh->name) > strlen(nah->name))
2549     {
2550       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2551                  "Record name longer than original lookup name... odd!\n");
2552       //FIXME to sth here
2553     }
2554
2555     answer_len = strlen(nah->name) - strlen(rh->name)
2556       + strlen(GNUNET_GNS_TLD) + 1;
2557     memset(result, 0, answer_len);
2558     strcpy(result, nah->name + strlen(rh->name) + 1);
2559
2560     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2561                "Got authority result %s\n", result);
2562     
2563     nah->proc(nah->proc_cls, result);
2564     GNUNET_free(nah);
2565     free_resolver_handle(rh);
2566   }
2567   else
2568   {
2569     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2570                "Unable to resolve authority for remaining %s!\n", rh->name);
2571     nah->proc(nah->proc_cls, "");
2572     GNUNET_free(nah);
2573     free_resolver_handle(rh);
2574   }
2575
2576
2577 }
2578
2579
2580 /**
2581  * Tries to resolve the authority for name
2582  * in our namestore
2583  *
2584  * @param zone the root zone to look up for
2585  * @param name the name to lookup up
2586  * @param proc the processor to call when finished
2587  * @param proc_cls the closure to pass to the processor
2588  */
2589 void
2590 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2591                            const char* name,
2592                            GetAuthorityResultProcessor proc,
2593                            void* proc_cls)
2594 {
2595   struct ResolverHandle *rh;
2596   struct GetNameAuthorityHandle *nah;
2597
2598   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2599               "Starting authority resolution for %s!\n", name);
2600
2601   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2602   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2603   rh->authority = zone;
2604   
2605   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2606   {
2607     strcpy(rh->name, "\0");
2608   }
2609   else
2610   {
2611     memset(rh->name, 0,
2612            strlen(name)-strlen(GNUNET_GNS_TLD));
2613     memcpy(rh->name, name,
2614            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2615   }
2616
2617   memset(nah->name, 0,
2618          strlen(name)+1);
2619   strcpy(nah->name, name);
2620   
2621   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2622   rh->authority_chain_tail = rh->authority_chain_head;
2623   rh->authority_chain_head->zone = zone;
2624   rh->proc = &handle_delegation_result_ns_get_auth;
2625   rh->proc_cls = (void*)nah;
2626
2627   nah->proc = proc;
2628   nah->proc_cls = proc_cls;
2629
2630   /* Start delegation resolution in our namestore */
2631   resolve_delegation_ns(rh);
2632
2633 }
2634
2635 /******** END GET AUTHORITY *************/
2636
2637 /* end of gnunet-service-gns_resolver.c */