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