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