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