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