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