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