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