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