-cli tool fix, bugfix
[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   else
1172   {
1173     memcpy(*dest, src, s_len+1);
1174   }
1175 }
1176
1177 /**
1178  * finish lookup
1179  */
1180 static void
1181 finish_lookup(struct ResolverHandle *rh,
1182               struct RecordLookupHandle* rlh,
1183               unsigned int rd_count,
1184               const struct GNUNET_NAMESTORE_RecordData *rd)
1185 {
1186   int i;
1187   char new_rr_data[MAX_DNS_NAME_LENGTH];
1188   char new_mx_data[MAX_MX_LENGTH];
1189   char new_soa_data[MAX_SOA_LENGTH];
1190   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1191   char* repl_string;
1192   char* pos;
1193   unsigned int offset;
1194
1195   if (rd_count > 0)
1196     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1197
1198   for (i = 0; i < rd_count; i++)
1199   {
1200
1201     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1202         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1203         rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1204         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1205     {
1206       p_rd[i].data = rd[i].data;
1207       continue;
1208     }
1209
1210     /**
1211      * for all those records we 'should'
1212      * also try to resolve the A/AAAA records (RFC1035)
1213      * This is a feature and not important
1214      */
1215     
1216     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1217                "Postprocessing\n");
1218
1219     if (strcmp(rh->name, "+") == 0)
1220       repl_string = rlh->name;
1221     else
1222       repl_string = rlh->name+strlen(rh->name)+1;
1223
1224     offset = 0;
1225     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1226     {
1227       memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1228       offset = sizeof(uint16_t);
1229       pos = new_mx_data+offset;
1230       expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1231                   repl_string);
1232       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1233       p_rd[i].data = new_mx_data;
1234       p_rd[i].data_size = offset;
1235     }
1236     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1237     {
1238       /* expand mname and rname */
1239       pos = new_soa_data;
1240       expand_plus(&pos, (char*)rd[i].data, repl_string);
1241       offset = strlen(new_soa_data)+1;
1242       pos = new_soa_data+offset;
1243       expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1244       offset += strlen(new_soa_data+offset)+1;
1245       /* cpy the 4 numbers serial refresh retry and expire */
1246       memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*4);
1247       offset += sizeof(uint32_t)*4;
1248       p_rd[i].data_size = offset;
1249       p_rd[i].data = new_soa_data;
1250     }
1251     else
1252     {
1253       pos = new_rr_data;
1254       expand_plus(&pos, (char*)rd[i].data, repl_string);
1255       p_rd[i].data_size = strlen(new_rr_data)+1;
1256       p_rd[i].data = new_rr_data;
1257     }
1258     
1259   }
1260
1261   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1262   GNUNET_free(rlh);
1263   
1264 }
1265
1266 /**
1267  * Process DHT lookup result for record.
1268  *
1269  * @param cls the closure
1270  * @param rh resolver handle
1271  * @param rd_count number of results
1272  * @param rd record data
1273  */
1274 static void
1275 handle_record_dht(void* cls, struct ResolverHandle *rh,
1276                        unsigned int rd_count,
1277                        const struct GNUNET_NAMESTORE_RecordData *rd)
1278 {
1279   struct RecordLookupHandle* rlh;
1280
1281   rlh = (struct RecordLookupHandle*)cls;
1282   if (rd_count == 0)
1283   {
1284     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1285                "No records for %s found in DHT. Aborting\n",
1286                rh->name);
1287     /* give up, cannot resolve */
1288     finish_lookup(rh, rlh, 0, NULL);
1289     free_resolver_handle(rh);
1290     return;
1291   }
1292
1293   /* results found yay */
1294   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1295              "Record resolved from DHT!");
1296
1297   finish_lookup(rh, rlh, rd_count, rd);
1298   free_resolver_handle(rh);
1299
1300 }
1301
1302
1303 /**
1304  * Process namestore lookup result for record.
1305  *
1306  * @param cls the closure
1307  * @param rh resolver handle
1308  * @param rd_count number of results
1309  * @param rd record data
1310  */
1311 static void
1312 handle_record_ns(void* cls, struct ResolverHandle *rh,
1313                        unsigned int rd_count,
1314                        const struct GNUNET_NAMESTORE_RecordData *rd)
1315 {
1316   struct RecordLookupHandle* rlh;
1317   rlh = (struct RecordLookupHandle*) cls;
1318   if (rd_count == 0)
1319   {
1320     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Resolution status: %d!\n", rh->status);
1321     
1322     /* ns entry expired and not ours. try dht */
1323     if (rh->status & (EXPIRED | !EXISTS) &&
1324         GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1325                                      &local_zone))
1326     {
1327       rh->proc = &handle_record_dht;
1328       resolve_record_dht(rh);
1329       return;
1330     }
1331     /* give up, cannot resolve */
1332     finish_lookup(rh, rlh, 0, NULL);
1333     free_resolver_handle(rh);
1334     return;
1335   }
1336
1337   /* results found yay */
1338   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1339              "Record resolved from namestore!");
1340
1341   finish_lookup(rh, rlh, rd_count, rd);
1342
1343   free_resolver_handle(rh);
1344
1345 }
1346
1347
1348 /**
1349  * Determine if this name is canonical.
1350  * i.e.
1351  * a.b.gnunet  = not canonical
1352  * a           = canonical
1353  *
1354  * @param name the name to test
1355  * @return 1 if canonical
1356  */
1357 static int
1358 is_canonical(char* name)
1359 {
1360   uint32_t len = strlen(name);
1361   int i;
1362
1363   for (i=0; i<len; i++)
1364   {
1365     if (*(name+i) == '.')
1366       return 0;
1367   }
1368   return 1;
1369 }
1370
1371 /**
1372  * Move one level up in the domain hierarchy and return the
1373  * passed top level domain.
1374  *
1375  * @param name the domain
1376  * @param dest the destination where the tld will be put
1377  */
1378 void
1379 pop_tld(char* name, char* dest)
1380 {
1381   uint32_t len;
1382
1383   if (is_canonical(name))
1384   {
1385     strcpy(dest, name);
1386     strcpy(name, "");
1387     return;
1388   }
1389
1390   for (len = strlen(name); len > 0; len--)
1391   {
1392     if (*(name+len) == '.')
1393       break;
1394   }
1395   
1396   //Was canonical?
1397   if (len == 0)
1398     return;
1399
1400   name[len] = '\0';
1401
1402   strcpy(dest, (name+len+1));
1403 }
1404
1405 /**
1406  * Checks if name is in tld
1407  *
1408  * @param name the name to check
1409  * @return GNUNET_YES or GNUNET_NO
1410  */
1411 int
1412 is_tld(const char* name, const char* tld)
1413 {
1414   int offset = 0;
1415
1416   if (strlen(name) <= strlen(tld))
1417   {
1418     return GNUNET_NO;
1419   }
1420   
1421   offset = strlen(name)-strlen(tld);
1422   if (strcmp(name+offset, tld) != 0)
1423   {
1424     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1425                "%s is not in .%s TLD\n", name, tld);
1426     return GNUNET_NO;
1427   }
1428   return GNUNET_YES;
1429 }
1430
1431 /**
1432  * DHT resolution for delegation finished. Processing result.
1433  *
1434  * @param cls the closure
1435  * @param rh resolver handle
1436  * @param rd_count number of results (always 0)
1437  * @param rd record data (always NULL)
1438  */
1439 static void
1440 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1441                           unsigned int rd_count,
1442                           const struct GNUNET_NAMESTORE_RecordData *rd)
1443 {
1444   struct RecordLookupHandle* rlh;
1445   rlh = (struct RecordLookupHandle*) cls;
1446   
1447   
1448
1449   if (strcmp(rh->name, "") == 0)
1450   {
1451     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1452     {
1453       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1454                  "Resolved queried PKEY via DHT.\n");
1455       finish_lookup(rh, rlh, rd_count, rd);
1456       free_resolver_handle(rh);
1457       return;
1458     }
1459     /* We resolved full name for delegation. resolving record */
1460     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1461       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1462     strcpy(rh->name, "+\0");
1463     rh->proc = &handle_record_ns;
1464     resolve_record_ns(rh);
1465     return;
1466   }
1467
1468   /**
1469    * we still have some left
1470    **/
1471   if (is_canonical(rh->name))
1472   {
1473     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1474                "Resolving canonical record %s in ns\n", rh->name);
1475     rh->proc = &handle_record_ns;
1476     resolve_record_ns(rh);
1477     return;
1478   }
1479   /* give up, cannot resolve */
1480   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1481              "Cannot fully resolve delegation for %s via DHT!\n",
1482              rh->name);
1483   finish_lookup(rh, rlh, 0, NULL);
1484   free_resolver_handle(rh);
1485 }
1486
1487
1488 /**
1489  * Start DHT lookup for a name -> PKEY (compare NS) record in
1490  * rh->authority's zone
1491  *
1492  * @param rh the pending gns query
1493  */
1494 static void
1495 resolve_delegation_dht(struct ResolverHandle *rh)
1496 {
1497   uint32_t xquery;
1498   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1499   GNUNET_HashCode name_hash_double;
1500   GNUNET_HashCode zone_hash_double;
1501   GNUNET_HashCode lookup_key;
1502   struct ResolverHandle *rh_heap_root;
1503   
1504   GNUNET_CRYPTO_short_hash(rh->authority_name,
1505                      strlen(rh->authority_name),
1506                      &name_hash);
1507   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1508   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1509   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1510   
1511   rh->dht_heap_node = NULL;
1512
1513   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1514   {
1515     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1516     //                                          &dht_authority_lookup_timeout,
1517     //                                                   rh);
1518     rh->timeout_cont = &dht_authority_lookup_timeout;
1519     rh->timeout_cont_cls = rh;
1520   }
1521   else 
1522   {
1523     if (max_allowed_background_queries <=
1524         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1525     {
1526       /* terminate oldest lookup */
1527       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1528       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1529       rh_heap_root->dht_heap_node = NULL;
1530       rh_heap_root->proc(rh_heap_root->proc_cls,
1531                          rh_heap_root,
1532                          0,
1533                          NULL);
1534     }
1535     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1536                                          rh,
1537                                          GNUNET_TIME_absolute_get().abs_value);
1538   }
1539   
1540   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1541
1542   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1543                        GNUNET_TIME_UNIT_FOREVER_REL,
1544                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1545                        &lookup_key,
1546                        DHT_GNS_REPLICATION_LEVEL,
1547                        GNUNET_DHT_RO_NONE,
1548                        &xquery,
1549                        sizeof(xquery),
1550                        &process_delegation_result_dht,
1551                        rh);
1552
1553 }
1554
1555
1556 /**
1557  * Namestore resolution for delegation finished. Processing result.
1558  *
1559  * @param cls the closure
1560  * @param rh resolver handle
1561  * @param rd_count number of results (always 0)
1562  * @param rd record data (always NULL)
1563  */
1564 static void
1565 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1566                           unsigned int rd_count,
1567                           const struct GNUNET_NAMESTORE_RecordData *rd)
1568 {
1569   struct RecordLookupHandle* rlh;
1570   rlh = (struct RecordLookupHandle*) cls;
1571   
1572   if (strcmp(rh->name, "") == 0)
1573   {
1574     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1575     {
1576       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1577                  "Resolved queried PKEY in NS.\n");
1578       finish_lookup(rh, rlh, rd_count, rd);
1579       free_resolver_handle(rh);
1580       return;
1581     }
1582     /* We resolved full name for delegation. resolving record */
1583     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1584                "Resolved full name for delegation. resolving record '+'\n");
1585     strcpy(rh->name, "+\0");
1586     rh->proc = &handle_record_ns;
1587     resolve_record_ns(rh);
1588     return;
1589   }
1590
1591   /**
1592    * we still have some left
1593    * check if authority in ns is fresh
1594    * and exists
1595    * or we are authority
1596    **/
1597   if ((rh->status & (EXISTS | !EXPIRED)) ||
1598       !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1599                              &rh->authority_chain_tail->zone))
1600   {
1601     if (is_canonical(rh->name))
1602     {
1603       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1604                  "Resolving canonical record %s\n", rh->name);
1605       rh->proc = &handle_record_ns;
1606       resolve_record_ns(rh);
1607     }
1608     else
1609     {
1610       /* give up, cannot resolve */
1611       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1612                  "Cannot fully resolve delegation for %s!\n",
1613                  rh->name);
1614       rlh->proc(rlh->proc_cls, 0, NULL);
1615     }
1616     return;
1617   }
1618   
1619   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1620              "Trying to resolve delegation for %s via DHT\n",
1621              rh->name);
1622   rh->proc = &handle_delegation_dht;
1623   resolve_delegation_dht(rh);
1624 }
1625
1626 /* Prototype */
1627 static void resolve_delegation_ns(struct ResolverHandle *rh);
1628
1629
1630 /**
1631  * This is a callback function that should give us only PKEY
1632  * records. Used to query the namestore for the authority (PKEY)
1633  * for 'name'. It will recursively try to resolve the
1634  * authority for a given name from the namestore.
1635  *
1636  * @param cls the pending query
1637  * @param key the key of the zone we did the lookup
1638  * @param expiration expiration date of the record data set in the namestore
1639  * @param name the name for which we need an authority
1640  * @param rd_count the number of records with 'name'
1641  * @param rd the record data
1642  * @param signature the signature of the authority for the record data
1643  */
1644 static void
1645 process_delegation_result_ns(void* cls,
1646                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1647                    struct GNUNET_TIME_Absolute expiration,
1648                    const char *name,
1649                    unsigned int rd_count,
1650                    const struct GNUNET_NAMESTORE_RecordData *rd,
1651                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1652 {
1653   struct ResolverHandle *rh;
1654   struct GNUNET_TIME_Relative remaining_time;
1655   struct GNUNET_CRYPTO_ShortHashCode zone;
1656   char new_name[MAX_DNS_NAME_LENGTH];
1657   
1658   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1659              rd_count);
1660
1661   rh = (struct ResolverHandle *)cls;
1662   GNUNET_CRYPTO_short_hash(key,
1663                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1664                      &zone);
1665   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1666   
1667   rh->status = 0;
1668   
1669   if (name != NULL)
1670   {
1671     rh->status |= EXISTS;
1672   }
1673   
1674   if (remaining_time.rel_value == 0)
1675   {
1676     rh->status |= EXPIRED;
1677   }
1678   
1679   /**
1680    * No authority found in namestore.
1681    */
1682   if (rd_count == 0)
1683   {
1684     /**
1685      * We did not find an authority in the namestore
1686      */
1687     
1688     /**
1689      * No PKEY in zone.
1690      * Promote this authority back to a name maybe it is
1691      * our record.
1692      */
1693     if (strcmp(rh->name, "") == 0)
1694     {
1695       /* simply promote back */
1696       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1697                  "Promoting %s back to name\n", rh->authority_name);
1698       strcpy(rh->name, rh->authority_name);
1699     }
1700     else
1701     {
1702       /* add back to existing name */
1703       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1704                  "Adding %s back to %s\n",
1705                  rh->authority_name, rh->name);
1706       //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1707       strcpy(new_name, rh->name);
1708       strcpy(new_name+strlen(new_name), ".");
1709       strcpy(new_name+strlen(new_name), rh->authority_name);
1710       strcpy(rh->name, new_name);
1711       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1712                  "%s restored\n", rh->name);
1713     }
1714     rh->proc(rh->proc_cls, rh, 0, NULL);
1715     return;
1716   }
1717
1718   /**
1719    * We found an authority that may be able to help us
1720    * move on with query
1721    * Note only 1 pkey should have been returned.. anything else would be strange
1722    */
1723   int i;
1724   for (i=0; i<rd_count;i++)
1725   {
1726   
1727     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1728       continue;
1729     
1730     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1731          == 0)
1732     {
1733       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1734       if (remaining_time.rel_value == 0)
1735       {
1736         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1737                    "This dht entry is expired.\n");
1738         rh->authority_chain_head->fresh = 0;
1739         rh->proc(rh->proc_cls, rh, 0, NULL);
1740         return;
1741       }
1742
1743       continue;
1744     }
1745
1746     /**
1747      * Resolve rest of query with new authority
1748      */
1749     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1750     memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1751     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1752     auth->zone = rh->authority;
1753     memset(auth->name, 0, strlen(rh->authority_name)+1);
1754     strcpy(auth->name, rh->authority_name);
1755     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1756                                  rh->authority_chain_tail,
1757                                  auth);
1758     
1759     /**
1760      * We are done with PKEY resolution if name is empty
1761      * else resolve again with new authority
1762      */
1763     if (strcmp(rh->name, "") == 0)
1764       rh->proc(rh->proc_cls, rh, 0, NULL);
1765     else
1766       resolve_delegation_ns(rh);
1767     return;
1768   }
1769     
1770   /**
1771    * no answers found
1772    */
1773   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1774              "Authority lookup successful but no PKEY... never get here\n");
1775   rh->proc(rh->proc_cls, rh, 0, NULL);
1776 }
1777
1778
1779 /**
1780  * Resolve the delegation chain for the request in our namestore
1781  *
1782  * @param rh the resolver handle
1783  */
1784 static void
1785 resolve_delegation_ns(struct ResolverHandle *rh)
1786 {
1787   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1788              "Resolving delegation for %s\n", rh->name);
1789   pop_tld(rh->name, rh->authority_name);
1790   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1791                                  &rh->authority,
1792                                  rh->authority_name,
1793                                  GNUNET_GNS_RECORD_PKEY,
1794                                  &process_delegation_result_ns,
1795                                  rh);
1796
1797 }
1798
1799
1800 /**
1801  * Lookup of a record in a specific zone
1802  * calls lookup result processor on result
1803  *
1804  * @param zone the root zone
1805  * @param record_type the record type to look up
1806  * @param name the name to look up
1807  * @param proc the processor to call on result
1808  * @param cls the closure to pass to proc
1809  */
1810 void
1811 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1812                            uint32_t record_type,
1813                            const char* name,
1814                            struct GNUNET_CRYPTO_RsaPrivateKey *key,
1815                            struct GNUNET_TIME_Relative timeout,
1816                            RecordLookupProcessor proc,
1817                            void* cls)
1818 {
1819   struct ResolverHandle *rh;
1820   struct RecordLookupHandle* rlh;
1821   char string_hash[MAX_DNS_LABEL_LENGTH];
1822
1823   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1824               "Starting resolution for %s (type=%d)!\n",
1825               name, record_type);
1826
1827   
1828   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1829   {
1830     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1831                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1832     proc(cls, 0, NULL);
1833     return;
1834   }
1835   
1836   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1837   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1838
1839   rh->authority = zone;
1840   rh->proc_cls = rlh;
1841   rh->priv_key = key;
1842   rh->timeout = timeout;
1843   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1844   {
1845     /*
1846      * Set timeout for authority lookup phase to 1/2
1847      */
1848     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1849                                 GNUNET_TIME_relative_divide(timeout, 2),
1850                                                 &handle_lookup_timeout,
1851                                                 rh);
1852     rh->timeout_cont = &dht_authority_lookup_timeout;
1853     rh->timeout_cont_cls = rh;
1854   }
1855   else
1856   {
1857     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
1858     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1859   }
1860   
1861   if (strcmp(GNUNET_GNS_TLD, name) == 0)
1862   {
1863     /**
1864      * Only 'gnunet' given
1865      */
1866     strcpy(rh->name, "\0");
1867   }
1868   else
1869   {
1870     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1871                 "Checking for TLD...\n");
1872     if (is_zkey_tld(name) == GNUNET_YES)
1873     {
1874       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1875                   "TLD is zkey\n");
1876       /**
1877        * This is a zkey tld
1878        * build hash and use as initial authority
1879        */
1880       memset(rh->name, 0,
1881              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1882       memcpy(rh->name, name,
1883              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1884       pop_tld(rh->name, string_hash);
1885
1886       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1887                   "ZKEY is %s!\n", string_hash);
1888
1889       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1890                                                       &rh->authority))
1891       {
1892         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1893                     "Cannot convert ZKEY %s to hash!\n", string_hash);
1894         GNUNET_free(rh);
1895         GNUNET_free(rlh);
1896         proc(cls, 0, NULL);
1897         return;
1898       }
1899
1900     }
1901     else
1902     {
1903       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1904                   "TLD is gnunet\n");
1905       /**
1906        * Presumably GNUNET tld
1907        */
1908       memset(rh->name, 0,
1909              strlen(name)-strlen(GNUNET_GNS_TLD));
1910       memcpy(rh->name, name,
1911              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1912     }
1913   }
1914   
1915   /**
1916    * Initialize authority chain
1917    */
1918   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1919   rh->authority_chain_head->prev = NULL;
1920   rh->authority_chain_head->next = NULL;
1921   rh->authority_chain_tail = rh->authority_chain_head;
1922   rh->authority_chain_head->zone = rh->authority;
1923   
1924   /**
1925    * Copy original query into lookup handle
1926    */
1927   rlh->record_type = record_type;
1928   memset(rlh->name, 0, strlen(name) + 1);
1929   strcpy(rlh->name, name);
1930   rlh->proc = proc;
1931   rlh->proc_cls = cls;
1932
1933   rh->proc = &handle_delegation_ns;
1934   resolve_delegation_ns(rh);
1935 }
1936
1937 /******** END Record Resolver ***********/
1938
1939
1940 /**
1941  * Callback calles by namestore for a zone to name
1942  * result
1943  *
1944  * @param cls the closure
1945  * @param zone_key the zone we queried
1946  * @param expire the expiration time of the name
1947  * @param name the name found or NULL
1948  * @param rd_len number of records for the name
1949  * @param rd the record data (PKEY) for the name
1950  * @param signature the signature for the record data
1951  */
1952 static void
1953 process_zone_to_name_shorten(void *cls,
1954                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1955                  struct GNUNET_TIME_Absolute expire,
1956                  const char *name,
1957                  unsigned int rd_len,
1958                  const struct GNUNET_NAMESTORE_RecordData *rd,
1959                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1960 {
1961   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1962   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1963   struct AuthorityChain *next_authority;
1964
1965   char result[MAX_DNS_NAME_LENGTH];
1966   char next_authority_name[MAX_DNS_LABEL_LENGTH];
1967   size_t answer_len;
1968   
1969   /* we found a match in our own zone */
1970   if (rd_len != 0)
1971   {
1972     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1973                "result strlen %d\n", strlen(name));
1974     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1975     memset(result, 0, answer_len);
1976     if (strlen(rh->name) > 0)
1977     {
1978       strcpy(result, rh->name);
1979       strcpy(result+strlen(rh->name), ".");
1980     }
1981     
1982     strcpy(result+strlen(result), name);
1983     strcpy(result+strlen(result), ".");
1984     strcpy(result+strlen(result), GNUNET_GNS_TLD);
1985     
1986     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1987                "Sending shorten result %s\n", result);
1988
1989     nsh->proc(nsh->proc_cls, result);
1990     GNUNET_free(nsh);
1991     free_resolver_handle(rh);
1992   }
1993   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1994                                         &local_zone))
1995   {
1996     /* our zone, just append .gnunet */
1997     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1998     memset(result, 0, answer_len);
1999     strcpy(result, rh->name);
2000     strcpy(result+strlen(rh->name), ".");
2001     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2002
2003     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2004                "Our zone: Sending name as shorten result %s\n", rh->name);
2005     
2006     nsh->proc(nsh->proc_cls, result);
2007     GNUNET_free(nsh);
2008     free_resolver_handle(rh);
2009   }
2010   else
2011   {
2012     /**
2013      * No PSEU found.
2014      * continue with next authority
2015      */
2016     next_authority = rh->authority_chain_head;
2017     //                         strlen(next_authority->name) + 2);
2018     memset(next_authority_name, 0, strlen(rh->name)+
2019                       strlen(next_authority->name) + 2);
2020     strcpy(next_authority_name, rh->name);
2021     strcpy(next_authority_name+strlen(rh->name)+1, ".");
2022     strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
2023   
2024     strcpy(rh->name, next_authority_name);
2025     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2026                               rh->authority_chain_tail,
2027                               next_authority);
2028
2029     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2030                                    &rh->authority_chain_tail->zone,
2031                                    &rh->authority_chain_head->zone,
2032                                    &process_zone_to_name_shorten,
2033                                    rh);
2034   }
2035 }
2036
2037
2038 /**
2039  * Process result from namestore delegation lookup
2040  * for shorten operation
2041  *
2042  * @param cls the client shorten handle
2043  * @param rh the resolver handle
2044  * @param rd_count number of results (0)
2045  * @param rd data (NULL)
2046  */
2047 void
2048 handle_delegation_ns_shorten(void* cls,
2049                       struct ResolverHandle *rh,
2050                       uint32_t rd_count,
2051                       const struct GNUNET_NAMESTORE_RecordData *rd)
2052 {
2053   struct NameShortenHandle *nsh;
2054   char result[MAX_DNS_NAME_LENGTH];
2055   size_t answer_len;
2056
2057   nsh = (struct NameShortenHandle *)cls;
2058   
2059   /**
2060    * At this point rh->name contains the part of the name
2061    * that we do not have a PKEY in our namestore to resolve.
2062    * The authority chain in the resolver handle is now
2063    * useful to backtrack if needed
2064    */
2065   
2066   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2067              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2068
2069   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2070                                    &local_zone) == 0)
2071   {
2072     /**
2073      * This is our zone append .gnunet unless name is empty
2074      * (it shouldn't be, usually FIXME what happens if we
2075      * shorten to our zone to a "" record??)
2076      */
2077     
2078     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2079     memset(result, 0, answer_len);
2080     strcpy(result, rh->name);
2081     strcpy(result+strlen(rh->name), ".");
2082     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2083
2084     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2085                "Our zone: Sending name as shorten result %s\n", rh->name);
2086     
2087     nsh->proc(nsh->proc_cls, result);
2088     GNUNET_free(nsh);
2089     free_resolver_handle(rh);
2090     return;
2091   }
2092   
2093   /* backtrack authorities for names */
2094   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2095                                  &rh->authority_chain_tail->zone, //ours
2096                                  &rh->authority_chain_head->zone,
2097                                  &process_zone_to_name_shorten,
2098                                  rh);
2099
2100 }
2101
2102 /**
2103  * Shorten api from resolver
2104  *
2105  * @param zone the zone to use
2106  * @param name the name to shorten
2107  * @param proc the processor to call with result
2108  * @param cls closure to pass to proc
2109  */
2110 void
2111 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2112                           const char* name,
2113                           ShortenResultProcessor proc,
2114                           void* cls)
2115 {
2116   struct ResolverHandle *rh;
2117   struct NameShortenHandle *nsh;
2118   char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME LABEL length when shorthash
2119
2120   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2121               "Starting shorten for %s!\n", name);
2122   
2123   if (is_canonical((char*)name))
2124   {
2125     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2126                 "%s is canonical. Returning verbatim\n", name);
2127     proc(cls, name);
2128     return;
2129   }
2130
2131   nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2132   
2133
2134   nsh->proc = proc;
2135   nsh->proc_cls = cls;
2136   
2137   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2138   rh->authority = zone;
2139   
2140   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2141                 "Checking for TLD...\n");
2142   if (is_zkey_tld(name) == GNUNET_YES)
2143   {
2144     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2145                 "TLD is zkey\n");
2146     /**
2147      * This is a zkey tld
2148      * build hash and use as initial authority
2149      */
2150     memset(rh->name, 0,
2151            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2152     memcpy(rh->name, name,
2153            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2154     pop_tld(rh->name, string_hash);
2155
2156     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2157                 "ZKEY is %s!\n", string_hash);
2158
2159     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
2160                                                           &rh->authority))
2161     {
2162       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2163                   "Cannot convert ZKEY %s to hash!\n", string_hash);
2164       GNUNET_free(rh);
2165       GNUNET_free(nsh);
2166       proc(cls, name);
2167       return;
2168     }
2169
2170   }
2171   else
2172   {
2173     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2174                 "TLD is gnunet\n");
2175     /**
2176      * Presumably GNUNET tld
2177      */
2178     memset(rh->name, 0,
2179            strlen(name)-strlen(GNUNET_GNS_TLD));
2180     memcpy(rh->name, name,
2181            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2182   }
2183
2184   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2185   rh->authority_chain_tail = rh->authority_chain_head;
2186   rh->authority_chain_head->zone = zone;
2187   rh->proc = &handle_delegation_ns_shorten;
2188   rh->proc_cls = nsh;
2189   
2190   /* Start delegation resolution in our namestore */
2191   resolve_delegation_ns(rh);
2192 }
2193
2194 /*********** END NAME SHORTEN ********************/
2195
2196
2197 /**
2198  * Process result from namestore delegation lookup
2199  * for get authority operation
2200  *
2201  * @param cls the client get auth handle
2202  * @param rh the resolver handle
2203  * @param rd_count number of results (0)
2204  * @param rd data (NULL)
2205  */
2206 void
2207 handle_delegation_result_ns_get_auth(void* cls,
2208                       struct ResolverHandle *rh,
2209                       uint32_t rd_count,
2210                       const struct GNUNET_NAMESTORE_RecordData *rd)
2211 {
2212   struct GetNameAuthorityHandle* nah;
2213   char result[MAX_DNS_NAME_LENGTH];
2214   size_t answer_len;
2215
2216   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2217   
2218   /**
2219    * At this point rh->name contains the part of the name
2220    * that we do not have a PKEY in our namestore to resolve.
2221    * The authority chain in the resolver handle is now
2222    * useful to backtrack if needed
2223    */
2224   
2225   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2226              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2227
2228   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2229              "Building response!\n");
2230   if (is_canonical(rh->name))
2231   {
2232     /**
2233      * We successfully resolved the authority in the ns
2234      * FIXME for our purposes this is fine
2235      * but maybe we want to have an api that also looks
2236      * into the dht (i.e. option in message)
2237      **/
2238     if (strlen(rh->name) > strlen(nah->name))
2239     {
2240       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2241                  "Record name longer than original lookup name... odd!\n");
2242       //FIXME to sth here
2243     }
2244
2245     answer_len = strlen(nah->name) - strlen(rh->name)
2246       + strlen(GNUNET_GNS_TLD) + 1;
2247     memset(result, 0, answer_len);
2248     strcpy(result, nah->name + strlen(rh->name) + 1);
2249
2250     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2251                "Got authority result %s\n", result);
2252     
2253     nah->proc(nah->proc_cls, result);
2254     GNUNET_free(nah);
2255     free_resolver_handle(rh);
2256   }
2257   else
2258   {
2259     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2260                "Unable to resolve authority for remaining %s!\n", rh->name);
2261     nah->proc(nah->proc_cls, "");
2262     GNUNET_free(nah);
2263     free_resolver_handle(rh);
2264   }
2265
2266
2267 }
2268
2269
2270 /**
2271  * Tries to resolve the authority for name
2272  * in our namestore
2273  *
2274  * @param zone the root zone to look up for
2275  * @param name the name to lookup up
2276  * @param proc the processor to call when finished
2277  * @param cls the closure to pass to the processor
2278  */
2279 void
2280 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2281                            const char* name,
2282                            GetAuthorityResultProcessor proc,
2283                            void* cls)
2284 {
2285   struct ResolverHandle *rh;
2286   struct GetNameAuthorityHandle *nah;
2287
2288   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2289               "Starting authority resolution for %s!\n", name);
2290
2291   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2292   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2293   rh->authority = zone;
2294   
2295   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2296   {
2297     strcpy(rh->name, "\0");
2298   }
2299   else
2300   {
2301     memset(rh->name, 0,
2302            strlen(name)-strlen(GNUNET_GNS_TLD));
2303     memcpy(rh->name, name,
2304            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2305   }
2306
2307   memset(nah->name, 0,
2308          strlen(name)+1);
2309   strcpy(nah->name, name);
2310   
2311   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2312   rh->authority_chain_tail = rh->authority_chain_head;
2313   rh->authority_chain_head->zone = zone;
2314   rh->proc = &handle_delegation_result_ns_get_auth;
2315   rh->proc_cls = (void*)nah;
2316
2317   nah->proc = proc;
2318   nah->proc_cls = cls;
2319
2320   /* Start delegation resolution in our namestore */
2321   resolve_delegation_ns(rh);
2322
2323 }
2324
2325 /******** END GET AUTHORITY *************/
2326
2327 /* end of gnunet-service-gns_resolver.c */