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