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