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