- -debug
[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                              rlh->record_type,
638                              new_name,
639                              rh->priv_key,
640                              GNUNET_TIME_UNIT_FOREVER_REL,
641                              &background_lookup_result_processor,
642                              NULL);
643   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
644   
645   GNUNET_DHT_get_stop (rh->get_handle);
646   rh->get_handle = NULL;
647   rh->proc(rh->proc_cls, rh, 0, NULL);
648 }
649
650
651 /**
652  * Function called when we get a result from the dht
653  * for our record query
654  *
655  * @param cls the request handle
656  * @param exp lifetime
657  * @param key the key the record was stored under
658  * @param get_path get path
659  * @param get_path_length get path length
660  * @param put_path put path
661  * @param put_path_length put path length
662  * @param type the block type
663  * @param size the size of the record
664  * @param data the record data
665  */
666 static void
667 process_record_result_dht(void* cls,
668                  struct GNUNET_TIME_Absolute exp,
669                  const GNUNET_HashCode * key,
670                  const struct GNUNET_PeerIdentity *get_path,
671                  unsigned int get_path_length,
672                  const struct GNUNET_PeerIdentity *put_path,
673                  unsigned int put_path_length,
674                  enum GNUNET_BLOCK_Type type,
675                  size_t size, const void *data)
676 {
677   struct ResolverHandle *rh;
678   struct RecordLookupHandle *rlh;
679   struct GNSNameRecordBlock *nrb;
680   uint32_t num_records;
681   char* name = NULL;
682   char* rd_data = (char*)data;
683   int i;
684   int rd_size;
685
686   rh = (struct ResolverHandle *)cls;
687   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
688              "GNS_PHASE_REC-%d: got dht result (size=%d)\n", rh->id, size);
689   
690   if (data == NULL)
691     return;
692
693   //FIXME maybe check expiration here, check block type
694   
695   
696   rlh = (struct RecordLookupHandle *) rh->proc_cls;
697   nrb = (struct GNSNameRecordBlock*)data;
698   
699   /* stop lookup and timeout task */
700   GNUNET_DHT_get_stop (rh->get_handle);
701   rh->get_handle = NULL;
702   
703   if (rh->dht_heap_node != NULL)
704   {
705     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
706     rh->dht_heap_node = NULL;
707   }
708   
709   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
710   {
711     GNUNET_SCHEDULER_cancel(rh->timeout_task);
712     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
713   }
714
715   rh->get_handle = NULL;
716   name = (char*)&nrb[1];
717   num_records = ntohl(nrb->rd_count);
718   {
719     struct GNUNET_NAMESTORE_RecordData rd[num_records];
720
721     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
722     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
723   
724     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
725                                                                rd_data,
726                                                                num_records,
727                                                                rd))
728     {
729       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
730                  "GNS_PHASE_REC-%d: Error deserializing data!\n", rh->id);
731       return;
732     }
733
734     for (i=0; i<num_records; i++)
735     {
736       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
737                "GNS_PHASE_REC-%d: Got name: %s (wanted %s)\n",
738                rh->id, name, rh->name);
739       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
740                "GNS_PHASE_REC-%d: Got type: %d\n",
741                rh->id, rd[i].record_type);
742       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
743                "GNS_PHASE_REC-%d: Got data length: %d\n",
744                rh->id, rd[i].data_size);
745       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
746                "GNS_PHASE_REC-%d: Got flag %d\n",
747                rh->id, rd[i].flags);
748     
749      if ((strcmp(name, rh->name) == 0) &&
750          (rd[i].record_type == rlh->record_type))
751       {
752         rh->answered++;
753       }
754
755     }
756
757     /**
758      * FIXME check pubkey against existing key in namestore?
759      * https://gnunet.org/bugs/view.php?id=2179
760      */
761
762     /* Save to namestore */
763     GNUNET_NAMESTORE_record_put (namestore_handle,
764                                  &nrb->public_key,
765                                  name,
766                                  exp,
767                                  num_records,
768                                  rd,
769                                  &nrb->signature,
770                                  &on_namestore_record_put_result, //cont
771                                  NULL); //cls
772
773   
774     if (rh->answered)
775       rh->proc(rh->proc_cls, rh, num_records, rd);
776     else
777       rh->proc(rh->proc_cls, rh, 0, NULL);
778   }
779
780 }
781
782
783 /**
784  * Start DHT lookup for a (name -> query->record_type) record in
785  * rh->authority's zone
786  *
787  * @param rh the pending gns query context
788  */
789 static void
790 resolve_record_dht(struct ResolverHandle *rh)
791 {
792   uint32_t xquery;
793   struct GNUNET_CRYPTO_ShortHashCode name_hash;
794   GNUNET_HashCode lookup_key;
795   GNUNET_HashCode name_hash_double;
796   GNUNET_HashCode zone_hash_double;
797   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
798   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
799   struct ResolverHandle *rh_heap_root;
800   
801   GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
802   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
803   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
804   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
805   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
806   
807   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
808              "GNS_PHASE_REC-%d: starting dht lookup for %s with key: %s\n",
809              rh->id, rh->name, (char*)&lookup_key_string);
810
811   //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
812   rh->dht_heap_node = NULL;
813
814   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
815   {
816     /**
817      * Update timeout if necessary
818      */
819     if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
820     {
821
822     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
823                "GNS_PHASE_REC-%d: Adjusting timeout\n", rh->id);
824     /*
825      * Set timeout for authority lookup phase to 1/2
826      */
827       rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
828                                 GNUNET_TIME_relative_divide(rh->timeout, 2),
829                                                 &handle_lookup_timeout,
830                                                 rh);
831     }
832     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
833     //                                                   &dht_lookup_timeout,
834     //                                                   rh);
835     rh->timeout_cont = &dht_lookup_timeout;
836     rh->timeout_cont_cls = rh;
837   }
838   else 
839   {
840     if (max_allowed_background_queries <=
841         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
842     {
843       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
844       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
845       rh_heap_root->get_handle = NULL;
846       rh_heap_root->dht_heap_node = NULL;
847       
848       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
849            "GNS_PHASE_REC-%d: Replacing oldest background query for %s\n",
850                  rh->id, rh_heap_root->name);
851       rh_heap_root->proc(rh_heap_root->proc_cls,
852                          rh_heap_root,
853                          0,
854                          NULL);
855     }
856     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
857                                          rh,
858                                          GNUNET_TIME_absolute_get().abs_value);
859   }
860   
861   xquery = htonl(rlh->record_type);
862   
863   GNUNET_assert(rh->get_handle == NULL);
864   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
865                        GNUNET_TIME_UNIT_FOREVER_REL,
866                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
867                        &lookup_key,
868                        DHT_GNS_REPLICATION_LEVEL,
869                        GNUNET_DHT_RO_NONE,
870                        &xquery, 
871                        sizeof(xquery),
872                        &process_record_result_dht,
873                        rh);
874
875 }
876
877
878 /**
879  * Namestore calls this function if we have record for this name.
880  * (or with rd_count=0 to indicate no matches)
881  *
882  * @param cls the pending query
883  * @param key the key of the zone we did the lookup
884  * @param expiration expiration date of the namestore entry
885  * @param name the name for which we need an authority
886  * @param rd_count the number of records with 'name'
887  * @param rd the record data
888  * @param signature the signature of the authority for the record data
889  */
890 static void
891 process_record_result_ns(void* cls,
892                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
893                   struct GNUNET_TIME_Absolute expiration,
894                   const char *name, unsigned int rd_count,
895                   const struct GNUNET_NAMESTORE_RecordData *rd,
896                   const struct GNUNET_CRYPTO_RsaSignature *signature)
897 {
898   struct ResolverHandle *rh;
899   struct RecordLookupHandle *rlh;
900   struct GNUNET_TIME_Relative remaining_time;
901   struct GNUNET_CRYPTO_ShortHashCode zone;
902
903   rh = (struct ResolverHandle *) cls;
904   rlh = (struct RecordLookupHandle *)rh->proc_cls;
905   GNUNET_CRYPTO_short_hash(key,
906                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
907                      &zone);
908   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
909   
910   
911
912   rh->status = 0;
913   
914   if (name != NULL)
915   {
916     rh->status |= RSL_RECORD_EXISTS;
917   }
918   
919   if (remaining_time.rel_value == 0)
920   {
921     rh->status |= RSL_RECORD_EXPIRED;
922   }
923   
924   if (rd_count == 0)
925   {
926     /**
927      * Lookup terminated and no results
928      */
929     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
930       "GNS_PHASE_REC-%d: Namestore lookup for %s terminated without results\n",
931          rh->id, name);
932
933     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
934                "GNS_PHASE_REC-%d: Record %s unknown in namestore\n",
935                rh->id, rh->name);
936     /**
937      * Our zone and no result? Cannot resolve TT
938      */
939     rh->proc(rh->proc_cls, rh, 0, NULL);
940     return;
941
942   }
943   else
944   {
945     
946     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
947            "GNS_PHASE_REC-%d: Processing additional result %s from namestore\n",
948               rh->id, name);
949     int i;
950     for (i=0; i<rd_count;i++)
951     {
952
953       if (rd[i].record_type != rlh->record_type)
954         continue;
955
956       if (ignore_pending_records &&
957           (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
958       {
959         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
960         "GNS_PHASE_REC-%d: Record %s is awaiting user confirmation. Skipping\n",
961         rh->id, name);
962         continue;
963       }
964       
965       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
966           == 0)
967       {
968         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
969                    "GNS_PHASE_REC-%d: This record is expired. Skipping\n",
970                    rh->id);
971         continue;
972       }
973       
974       rh->answered++;
975       
976     }
977     
978     /**
979      * no answers found
980      */
981     if (rh->answered == 0)
982     {
983       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
984                  "GNS_PHASE_REC-%d: No answers found. This is odd!\n", rh->id);
985       rh->proc(rh->proc_cls, rh, 0, NULL);
986       return;
987     }
988     
989     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
990                "GNS_PHASE_REC-%d: Found %d answer(s) to query in %d records!\n",
991                rh->id, rh->answered, rd_count);
992
993     rh->proc(rh->proc_cls, rh, rd_count, rd);
994   }
995 }
996
997
998 /**
999  * The final phase of resolution.
1000  * rh->name is a name that is canonical and we do not have a delegation.
1001  * Query namestore for this record
1002  *
1003  * @param rh the pending lookup
1004  */
1005 static void
1006 resolve_record_ns(struct ResolverHandle *rh)
1007 {
1008   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
1009   
1010   /* We cancel here as to not include the ns lookup in the timeout */
1011   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1012   {
1013     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1014     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1015   }
1016   
1017   /**
1018    * Try to resolve this record in our namestore.
1019    * The name to resolve is now in rh->authority_name
1020    * since we tried to resolve it to an authority
1021    * and failed.
1022    **/
1023   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1024                                  &rh->authority,
1025                                  rh->name,
1026                                  rlh->record_type,
1027                                  &process_record_result_ns,
1028                                  rh);
1029 }
1030
1031
1032
1033 /**
1034  * Handle timeout for DHT requests
1035  *
1036  * @param cls the request handle as closure
1037  * @param tc the task context
1038  */
1039 static void
1040 dht_authority_lookup_timeout(void *cls,
1041                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1042 {
1043   struct ResolverHandle *rh = cls;
1044   struct RecordLookupHandle *rlh = rh->proc_cls;
1045   char new_name[MAX_DNS_NAME_LENGTH];
1046
1047   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1048          "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%ds)timed out.\n",
1049          rh->id, rh->authority_name, rh->timeout.rel_value);
1050
1051   rh->status |= RSL_TIMED_OUT;
1052
1053   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1054   
1055   GNUNET_DHT_get_stop (rh->get_handle);
1056   rh->get_handle = NULL;
1057   
1058   if (strcmp(rh->name, "") == 0)
1059   {
1060     /*
1061      * promote authority back to name and try to resolve record
1062      */
1063     strcpy(rh->name, rh->authority_name);
1064     rh->proc(rh->proc_cls, rh, 0, NULL);
1065     return;
1066   }
1067   
1068   /**
1069    * Start resolution in bg
1070    */
1071   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1072                   "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD);
1073   //strcpy(new_name, rh->name);
1074   //strcpy(new_name+strlen(new_name), ".");
1075   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1076   
1077   strcpy(rh->name, new_name);
1078
1079   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1080         "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
1081         rh->id, rh->name, rlh->record_type);
1082
1083   gns_resolver_lookup_record(rh->authority,
1084                              rlh->record_type,
1085                              new_name,
1086                              rh->priv_key,
1087                              GNUNET_TIME_UNIT_FOREVER_REL,
1088                              &background_lookup_result_processor,
1089                              NULL);
1090
1091   rh->proc(rh->proc_cls, rh, 0, NULL);
1092 }
1093
1094 /* Prototype */
1095 static void resolve_delegation_dht(struct ResolverHandle *rh);
1096
1097 /* Prototype */
1098 static void resolve_delegation_ns(struct ResolverHandle *rh);
1099
1100
1101 /**
1102  * Namestore resolution for delegation finished. Processing result.
1103  *
1104  * @param cls the closure
1105  * @param rh resolver handle
1106  * @param rd_count number of results (always 0)
1107  * @param rd record data (always NULL)
1108  */
1109 static void
1110 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1111                           unsigned int rd_count,
1112                           const struct GNUNET_NAMESTORE_RecordData *rd);
1113
1114
1115 /**
1116  * Function called when we get a result from the dht
1117  * for our query. Recursively tries to resolve authorities
1118  * for name in DHT.
1119  *
1120  * @param cls the request handle
1121  * @param exp lifetime
1122  * @param key the key the record was stored under
1123  * @param get_path get path
1124  * @param get_path_length get path length
1125  * @param put_path put path
1126  * @param put_path_length put path length
1127  * @param type the block type
1128  * @param size the size of the record
1129  * @param data the record data
1130  */
1131 static void
1132 process_delegation_result_dht(void* cls,
1133                  struct GNUNET_TIME_Absolute exp,
1134                  const GNUNET_HashCode * key,
1135                  const struct GNUNET_PeerIdentity *get_path,
1136                  unsigned int get_path_length,
1137                  const struct GNUNET_PeerIdentity *put_path,
1138                  unsigned int put_path_length,
1139                  enum GNUNET_BLOCK_Type type,
1140                  size_t size, const void *data)
1141 {
1142   struct ResolverHandle *rh;
1143   struct GNSNameRecordBlock *nrb;
1144   uint32_t num_records;
1145   char* name = NULL;
1146   char* rd_data = (char*) data;
1147   int i;
1148   int rd_size;
1149   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1150   GNUNET_HashCode zone_hash_double, name_hash_double;
1151
1152   rh = (struct ResolverHandle *)cls;
1153   
1154   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1155              "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id);
1156
1157   if (data == NULL)
1158     return;
1159   
1160   nrb = (struct GNSNameRecordBlock*)data;
1161   
1162   /* stop dht lookup and timeout task */
1163   GNUNET_DHT_get_stop (rh->get_handle);
1164
1165   rh->get_handle = NULL;
1166
1167   if (rh->dht_heap_node != NULL)
1168   {
1169     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1170     rh->dht_heap_node = NULL;
1171   }
1172
1173   num_records = ntohl(nrb->rd_count);
1174   name = (char*)&nrb[1];
1175   {
1176     struct GNUNET_NAMESTORE_RecordData rd[num_records];
1177     
1178     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1179     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1180   
1181     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1182                                                                rd_data,
1183                                                                num_records,
1184                                                                rd))
1185     {
1186       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1187                  "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
1188                  rh->id);
1189       return;
1190     }
1191
1192     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1193                "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1194                rh->id, name, rh->authority_name);
1195     for (i=0; i<num_records; i++)
1196     {
1197     
1198       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1199                 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1200                 rh->id, name, rh->authority_name);
1201       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1202                  "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
1203                  rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1204       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1205                  "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
1206                  rh->id, rd[i].data_size);
1207       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1208                  "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
1209                  rh->id, rd[i].flags);
1210
1211       if ((strcmp(name, rh->authority_name) == 0) &&
1212           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1213       {
1214         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1215                    "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
1216                    rh->id);
1217         rh->answered = 1;
1218         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1219         struct AuthorityChain *auth =
1220           GNUNET_malloc(sizeof(struct AuthorityChain));
1221         auth->zone = rh->authority;
1222         memset(auth->name, 0, strlen(rh->authority_name)+1);
1223         strcpy(auth->name, rh->authority_name);
1224         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1225                                      rh->authority_chain_tail,
1226                                      auth);
1227
1228         /** try to import pkey if private key available */
1229         if (rh->priv_key)
1230           process_discovered_authority(name, auth->zone,
1231                                        rh->authority_chain_tail->zone,
1232                                        rh->priv_key);
1233       }
1234
1235     }
1236
1237
1238     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1239     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1240     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1241     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1242
1243     /* Save to namestore */
1244     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1245                                           &zone))
1246     {
1247       GNUNET_NAMESTORE_record_put (namestore_handle,
1248                                  &nrb->public_key,
1249                                  name,
1250                                  exp,
1251                                  num_records,
1252                                  rd,
1253                                  &nrb->signature,
1254                                  &on_namestore_record_put_result, //cont
1255                                  NULL); //cls
1256     }
1257   }
1258   
1259   if (rh->answered)
1260   {
1261     rh->answered = 0;
1262     /**
1263      * delegate
1264      * FIXME in this case. should we ask namestore again?
1265      */
1266     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1267       "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
1268       rh->id, rh->authority_name, rh->name);
1269     if (strcmp(rh->name, "") == 0)
1270     {
1271       rh->proc(rh->proc_cls, rh, 0, NULL);
1272     }
1273     else
1274     {
1275       rh->proc = &handle_delegation_ns;
1276       resolve_delegation_ns(rh);
1277     }
1278     return;
1279   }
1280   
1281   /**
1282    * No pkey but name exists
1283    * promote back
1284    */
1285   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1286              "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
1287              rh->id, rh->authority_name, rh->name);
1288   if (strcmp(rh->name, "") == 0)
1289     strcpy(rh->name, rh->authority_name);
1290   else
1291     GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1292                   rh->name, rh->authority_name); //FIXME ret
1293   
1294   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1295              "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
1296   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1297            "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
1298            rh->id);
1299   rh->proc(rh->proc_cls, rh, 0, NULL);
1300 }
1301
1302 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1303                         +(MAX_DNS_NAME_LENGTH*2)
1304 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1305
1306
1307 static void
1308 expand_plus(char** dest, char* src, char* repl)
1309 {
1310   char* pos;
1311   unsigned int s_len = strlen(src)+1;
1312
1313   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1314              "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1315
1316   if (s_len < 3)
1317   {
1318     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1319                "GNS_POSTPROCESS: %s to short\n", src);
1320
1321     /* no postprocessing */
1322     memcpy(*dest, src, s_len+1);
1323     return;
1324   }
1325   
1326   if (0 == strcmp(src+s_len-3, ".+"))
1327   {
1328     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1329                "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1330     memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1331     strcpy(*dest, src);
1332     pos = *dest+s_len-2;
1333     strcpy(pos, repl);
1334     pos += strlen(repl);
1335     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1336                "GNS_POSTPROCESS: Expanded to %s\n", *dest);
1337   }
1338   else
1339   {
1340     memcpy(*dest, src, s_len+1);
1341   }
1342 }
1343
1344 /**
1345  * finish lookup
1346  */
1347 static void
1348 finish_lookup(struct ResolverHandle *rh,
1349               struct RecordLookupHandle* rlh,
1350               unsigned int rd_count,
1351               const struct GNUNET_NAMESTORE_RecordData *rd)
1352 {
1353   int i;
1354   char new_rr_data[MAX_DNS_NAME_LENGTH];
1355   char new_mx_data[MAX_MX_LENGTH];
1356   char new_soa_data[MAX_SOA_LENGTH];
1357   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
1358   char* repl_string;
1359   char* pos;
1360   unsigned int offset;
1361
1362   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1363     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1364
1365   if (rd_count > 0)
1366     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
1367
1368   for (i = 0; i < rd_count; i++)
1369   {
1370     
1371     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
1372         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
1373         rd[i].record_type != GNUNET_GNS_RECORD_MX &&
1374         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
1375     {
1376       p_rd[i].data = rd[i].data;
1377       continue;
1378     }
1379
1380     /**
1381      * for all those records we 'should'
1382      * also try to resolve the A/AAAA records (RFC1035)
1383      * This is a feature and not important
1384      */
1385     
1386     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1387                "GNS_POSTPROCESS: Postprocessing\n");
1388
1389     if (strcmp(rh->name, "+") == 0)
1390       repl_string = rlh->name;
1391     else
1392       repl_string = rlh->name+strlen(rh->name)+1;
1393
1394     offset = 0;
1395     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1396     {
1397       memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
1398       offset = sizeof(uint16_t);
1399       pos = new_mx_data+offset;
1400       expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
1401                   repl_string);
1402       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
1403       p_rd[i].data = new_mx_data;
1404       p_rd[i].data_size = offset;
1405     }
1406     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
1407     {
1408       /* expand mname and rname */
1409       pos = new_soa_data;
1410       expand_plus(&pos, (char*)rd[i].data, repl_string);
1411       offset = strlen(new_soa_data)+1;
1412       pos = new_soa_data+offset;
1413       expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
1414       offset += strlen(new_soa_data+offset)+1;
1415       /* cpy the 4 numbers serial refresh retry and expire */
1416       memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
1417       offset += sizeof(uint32_t)*5;
1418       p_rd[i].data_size = offset;
1419       p_rd[i].data = new_soa_data;
1420     }
1421     else
1422     {
1423       pos = new_rr_data;
1424       expand_plus(&pos, (char*)rd[i].data, repl_string);
1425       p_rd[i].data_size = strlen(new_rr_data)+1;
1426       p_rd[i].data = new_rr_data;
1427     }
1428     
1429   }
1430
1431   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1432   GNUNET_free(rlh);
1433   
1434 }
1435
1436 /**
1437  * Process DHT lookup result for record.
1438  *
1439  * @param cls the closure
1440  * @param rh resolver handle
1441  * @param rd_count number of results
1442  * @param rd record data
1443  */
1444 static void
1445 handle_record_dht(void* cls, struct ResolverHandle *rh,
1446                        unsigned int rd_count,
1447                        const struct GNUNET_NAMESTORE_RecordData *rd)
1448 {
1449   struct RecordLookupHandle* rlh;
1450
1451   rlh = (struct RecordLookupHandle*)cls;
1452   if (rd_count == 0)
1453   {
1454     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1455                "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n",
1456                rh->id, rh->name);
1457     /* give up, cannot resolve */
1458     finish_lookup(rh, rlh, 0, NULL);
1459     free_resolver_handle(rh);
1460     return;
1461   }
1462
1463   /* results found yay */
1464   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1465              "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id);
1466
1467   finish_lookup(rh, rlh, rd_count, rd);
1468   free_resolver_handle(rh);
1469
1470 }
1471
1472
1473 /**
1474  * Process namestore lookup result for record.
1475  *
1476  * @param cls the closure
1477  * @param rh resolver handle
1478  * @param rd_count number of results
1479  * @param rd record data
1480  */
1481 static void
1482 handle_record_ns(void* cls, struct ResolverHandle *rh,
1483                        unsigned int rd_count,
1484                        const struct GNUNET_NAMESTORE_RecordData *rd)
1485 {
1486   struct RecordLookupHandle* rlh;
1487   rlh = (struct RecordLookupHandle*) cls;
1488   if (rd_count == 0)
1489   {
1490     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1491                "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n",
1492                rh->id,
1493                rh->status);
1494     
1495     /**
1496      * There are 4 conditions that have to met for us to consult the DHT:
1497      * 1. The entry in the DHT is RSL_RECORD_EXPIRED AND
1498      * 2. No entry in the NS existed AND
1499      * 3. The zone queried is not the local resolver's zone AND
1500      * 4. The name that was looked up is '+'
1501      *    because if it was any other canonical name we either already queried
1502      *    the DHT for the authority in the authority lookup phase (and thus
1503      *    would already have an entry in the NS for the record)
1504      */
1505     if (rh->status & (RSL_RECORD_EXPIRED | !RSL_RECORD_EXISTS) &&
1506         GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1507                                      &local_zone) &&
1508         (strcmp(rh->name, "+") == 0))
1509     {
1510       rh->proc = &handle_record_dht;
1511       resolve_record_dht(rh);
1512       return;
1513     }
1514     /* give up, cannot resolve */
1515     finish_lookup(rh, rlh, 0, NULL);
1516     free_resolver_handle(rh);
1517     return;
1518   }
1519
1520   /* results found yay */
1521   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1522              "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id);
1523
1524   finish_lookup(rh, rlh, rd_count, rd);
1525
1526   free_resolver_handle(rh);
1527
1528 }
1529
1530
1531 /**
1532  * Determine if this name is canonical.
1533  * i.e.
1534  * a.b.gnunet  = not canonical
1535  * a           = canonical
1536  *
1537  * @param name the name to test
1538  * @return 1 if canonical
1539  */
1540 static int
1541 is_canonical(char* name)
1542 {
1543   uint32_t len = strlen(name);
1544   int i;
1545
1546   for (i=0; i<len; i++)
1547   {
1548     if (*(name+i) == '.')
1549       return 0;
1550   }
1551   return 1;
1552 }
1553
1554 /**
1555  * Move one level up in the domain hierarchy and return the
1556  * passed top level domain.
1557  *
1558  * @param name the domain
1559  * @param dest the destination where the tld will be put
1560  */
1561 void
1562 pop_tld(char* name, char* dest)
1563 {
1564   uint32_t len;
1565
1566   if (is_canonical(name))
1567   {
1568     strcpy(dest, name);
1569     strcpy(name, "");
1570     return;
1571   }
1572
1573   for (len = strlen(name); len > 0; len--)
1574   {
1575     if (*(name+len) == '.')
1576       break;
1577   }
1578   
1579   //Was canonical?
1580   if (len == 0)
1581     return;
1582
1583   name[len] = '\0';
1584
1585   strcpy(dest, (name+len+1));
1586 }
1587
1588 /**
1589  * Checks if name is in tld
1590  *
1591  * @param name the name to check
1592  * @param tld the TLD to check for
1593  * @return GNUNET_YES or GNUNET_NO
1594  */
1595 int
1596 is_tld(const char* name, const char* tld)
1597 {
1598   int offset = 0;
1599
1600   if (strlen(name) <= strlen(tld))
1601   {
1602     return GNUNET_NO;
1603   }
1604   
1605   offset = strlen(name)-strlen(tld);
1606   if (strcmp(name+offset, tld) != 0)
1607   {
1608     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1609                "%s is not in .%s TLD\n", name, tld);
1610     return GNUNET_NO;
1611   }
1612   return GNUNET_YES;
1613 }
1614
1615 /**
1616  * DHT resolution for delegation finished. Processing result.
1617  *
1618  * @param cls the closure
1619  * @param rh resolver handle
1620  * @param rd_count number of results (always 0)
1621  * @param rd record data (always NULL)
1622  */
1623 static void
1624 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1625                           unsigned int rd_count,
1626                           const struct GNUNET_NAMESTORE_RecordData *rd)
1627 {
1628   struct RecordLookupHandle* rlh;
1629   rlh = (struct RecordLookupHandle*) cls;
1630   
1631
1632   if (strcmp(rh->name, "") == 0)
1633   {
1634     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1635     {
1636       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1637                  "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
1638                  rh->id);
1639       finish_lookup(rh, rlh, rd_count, rd);
1640       free_resolver_handle(rh);
1641       return;
1642     }
1643     /* We resolved full name for delegation. resolving record */
1644     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1645      "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
1646      rh->id);
1647     strcpy(rh->name, "+\0");
1648     rh->proc = &handle_record_ns;
1649     resolve_record_ns(rh);
1650     return;
1651   }
1652
1653   /**
1654    * we still have some left
1655    **/
1656   if (is_canonical(rh->name))
1657   {
1658     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1659              "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
1660              rh->id,
1661              rh->name);
1662     rh->proc = &handle_record_ns;
1663     resolve_record_ns(rh);
1664     return;
1665   }
1666   /* give up, cannot resolve */
1667   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1668  "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
1669  rh->id, rh->name);
1670   finish_lookup(rh, rlh, 0, NULL);
1671   free_resolver_handle(rh);
1672 }
1673
1674
1675 /**
1676  * Start DHT lookup for a name -> PKEY (compare NS) record in
1677  * rh->authority's zone
1678  *
1679  * @param rh the pending gns query
1680  */
1681 static void
1682 resolve_delegation_dht(struct ResolverHandle *rh)
1683 {
1684   uint32_t xquery;
1685   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1686   GNUNET_HashCode name_hash_double;
1687   GNUNET_HashCode zone_hash_double;
1688   GNUNET_HashCode lookup_key;
1689   struct ResolverHandle *rh_heap_root;
1690   
1691   pop_tld(rh->name, rh->authority_name); 
1692   GNUNET_CRYPTO_short_hash(rh->authority_name,
1693                      strlen(rh->authority_name),
1694                      &name_hash);
1695   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1696   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1697   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1698   
1699   rh->dht_heap_node = NULL;
1700
1701   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
1702   {
1703     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1704     //                                          &dht_authority_lookup_timeout,
1705     //                                                   rh);
1706     rh->timeout_cont = &dht_authority_lookup_timeout;
1707     rh->timeout_cont_cls = rh;
1708   }
1709   else 
1710   {
1711     if (max_allowed_background_queries <=
1712         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1713     {
1714       /* terminate oldest lookup */
1715       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1716       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1717       rh_heap_root->dht_heap_node = NULL;
1718       
1719       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1720         "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
1721         rh->id, rh_heap_root->authority_name);
1722       
1723       rh_heap_root->proc(rh_heap_root->proc_cls,
1724                          rh_heap_root,
1725                          0,
1726                          NULL);
1727     }
1728     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1729                                          rh,
1730                                          GNUNET_TIME_absolute_get().abs_value);
1731   }
1732   
1733   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1734   
1735   GNUNET_assert(rh->get_handle == NULL);
1736   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1737                        GNUNET_TIME_UNIT_FOREVER_REL,
1738                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1739                        &lookup_key,
1740                        DHT_GNS_REPLICATION_LEVEL,
1741                        GNUNET_DHT_RO_NONE,
1742                        &xquery,
1743                        sizeof(xquery),
1744                        &process_delegation_result_dht,
1745                        rh);
1746
1747 }
1748
1749
1750 /**
1751  * Namestore resolution for delegation finished. Processing result.
1752  *
1753  * @param cls the closure
1754  * @param rh resolver handle
1755  * @param rd_count number of results (always 0)
1756  * @param rd record data (always NULL)
1757  */
1758 static void
1759 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1760                           unsigned int rd_count,
1761                           const struct GNUNET_NAMESTORE_RecordData *rd)
1762 {
1763   struct RecordLookupHandle* rlh;
1764   rlh = (struct RecordLookupHandle*) cls;
1765   
1766   if (strcmp(rh->name, "") == 0)
1767   {
1768     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1769     {
1770       GNUNET_assert(rd_count == 1);
1771       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1772                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
1773                  rh->id);
1774       finish_lookup(rh, rlh, rd_count, rd);
1775       free_resolver_handle(rh);
1776       return;
1777     }
1778     /* We resolved full name for delegation. resolving record */
1779     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1780               "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
1781               rh->id);
1782     strcpy(rh->name, "+\0");
1783     rh->proc = &handle_record_ns;
1784     resolve_record_ns(rh);
1785     return;
1786   }
1787
1788   /**
1789    * we still have some left
1790    * check if authority in ns is fresh
1791    * and exists
1792    * or we are authority
1793    **/
1794   if (((rh->status & RSL_RECORD_EXISTS) && (rh->status & !RSL_RECORD_EXPIRED))
1795       || !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1796                                        &local_zone))
1797   {
1798     if (is_canonical(rh->name))
1799     {
1800       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1801                  "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
1802                  rh->id,
1803                  rh->name);
1804       rh->proc = &handle_record_ns;
1805       resolve_record_ns(rh);
1806     }
1807     else
1808     {
1809       /* give up, cannot resolve */
1810       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1811           "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
1812           rh->id,
1813           rh->name);
1814       finish_lookup(rh, rlh, rd_count, rd);
1815       //rlh->proc(rlh->proc_cls, 0, NULL);
1816     }
1817     return;
1818   }
1819   
1820   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1821       "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
1822       rh->id, rh->name);
1823   rh->proc = &handle_delegation_dht;
1824   resolve_delegation_dht(rh);
1825 }
1826
1827
1828
1829 /**
1830  * This is a callback function that should give us only PKEY
1831  * records. Used to query the namestore for the authority (PKEY)
1832  * for 'name'. It will recursively try to resolve the
1833  * authority for a given name from the namestore.
1834  *
1835  * @param cls the pending query
1836  * @param key the key of the zone we did the lookup
1837  * @param expiration expiration date of the record data set in the namestore
1838  * @param name the name for which we need an authority
1839  * @param rd_count the number of records with 'name'
1840  * @param rd the record data
1841  * @param signature the signature of the authority for the record data
1842  */
1843 static void
1844 process_delegation_result_ns(void* cls,
1845                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1846                    struct GNUNET_TIME_Absolute expiration,
1847                    const char *name,
1848                    unsigned int rd_count,
1849                    const struct GNUNET_NAMESTORE_RecordData *rd,
1850                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1851 {
1852   struct ResolverHandle *rh;
1853   struct GNUNET_TIME_Relative remaining_time;
1854   struct GNUNET_CRYPTO_ShortHashCode zone;
1855   char new_name[MAX_DNS_NAME_LENGTH];
1856  
1857   rh = (struct ResolverHandle *)cls; 
1858   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1859              "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n",
1860              rh->id, rd_count);
1861
1862   GNUNET_CRYPTO_short_hash(key,
1863                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1864                      &zone);
1865   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1866   
1867   rh->status = 0;
1868   
1869   if (name != NULL)
1870   {
1871     rh->status |= RSL_RECORD_EXISTS;
1872   }
1873   
1874   if (remaining_time.rel_value == 0)
1875   {
1876     rh->status |= RSL_RECORD_EXPIRED;
1877   }
1878   
1879   /**
1880    * No authority found in namestore.
1881    */
1882   if (rd_count == 0)
1883   {
1884     /**
1885      * We did not find an authority in the namestore
1886      */
1887     
1888     /**
1889      * No PKEY in zone.
1890      * Promote this authority back to a name maybe it is
1891      * our record.
1892      */
1893     if (strcmp(rh->name, "") == 0)
1894     {
1895       /* simply promote back */
1896       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1897                  "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
1898                  rh->id, rh->authority_name);
1899       strcpy(rh->name, rh->authority_name);
1900     }
1901     else
1902     {
1903       /* add back to existing name */
1904       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1905                  "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
1906                  rh->id, rh->authority_name, rh->name);
1907       //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1908       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
1909                       rh->name, rh->authority_name);
1910       //strcpy(new_name, rh->name);
1911       //strcpy(new_name+strlen(new_name), ".");
1912       //strcpy(new_name+strlen(new_name), rh->authority_name);
1913       strcpy(rh->name, new_name);
1914       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1915                  "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n", rh->id, rh->name);
1916     }
1917     rh->proc(rh->proc_cls, rh, 0, NULL);
1918     return;
1919   }
1920
1921   /**
1922    * We found an authority that may be able to help us
1923    * move on with query
1924    * Note only 1 pkey should have been returned.. anything else would be strange
1925    */
1926   int i;
1927   for (i=0; i<rd_count;i++)
1928   {
1929   
1930     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1931       continue;
1932
1933     if (ignore_pending_records &&
1934         (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
1935     {
1936       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1937       "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
1938         name,
1939         rh->id);
1940       continue;
1941     }
1942     
1943     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1944          == 0)
1945     {
1946       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1947                  "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
1948                  rh->id);
1949       if (remaining_time.rel_value == 0)
1950       {
1951         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1952                    "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
1953                    rh->id);
1954         rh->authority_chain_head->fresh = 0;
1955         rh->proc(rh->proc_cls, rh, 0, NULL);
1956         return;
1957       }
1958
1959       continue;
1960     }
1961
1962     /**
1963      * Resolve rest of query with new authority
1964      */
1965     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1966     memcpy(&rh->authority, rd[i].data,
1967            sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1968     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1969     auth->zone = rh->authority;
1970     memset(auth->name, 0, strlen(rh->authority_name)+1);
1971     strcpy(auth->name, rh->authority_name);
1972     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1973                                  rh->authority_chain_tail,
1974                                  auth);
1975     
1976     /** try to import pkey if private key available */
1977     if (rh->priv_key)
1978       process_discovered_authority((char*)name, auth->zone,
1979                                    rh->authority_chain_tail->zone,
1980                                    rh->priv_key);
1981     /**
1982      * We are done with PKEY resolution if name is empty
1983      * else resolve again with new authority
1984      */
1985     if (strcmp(rh->name, "") == 0)
1986       rh->proc(rh->proc_cls, rh, rd_count, rd);
1987     else
1988       resolve_delegation_ns(rh);
1989     return;
1990   }
1991     
1992   /**
1993    * no answers found
1994    */
1995   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1996     "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id);
1997   rh->proc(rh->proc_cls, rh, 0, NULL);
1998 }
1999
2000
2001 /**
2002  * Resolve the delegation chain for the request in our namestore
2003  *
2004  * @param rh the resolver handle
2005  */
2006 static void
2007 resolve_delegation_ns(struct ResolverHandle *rh)
2008 {
2009   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2010              "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n",
2011              rh->id, rh->name);
2012   pop_tld(rh->name, rh->authority_name);
2013   GNUNET_NAMESTORE_lookup_record(namestore_handle,
2014                                  &rh->authority,
2015                                  rh->authority_name,
2016                                  GNUNET_GNS_RECORD_PKEY,
2017                                  &process_delegation_result_ns,
2018                                  rh);
2019
2020 }
2021
2022
2023 /**
2024  * Lookup of a record in a specific zone
2025  * calls lookup result processor on result
2026  *
2027  * @param zone the root zone
2028  * @param record_type the record type to look up
2029  * @param name the name to look up
2030  * @param key a private key for use with PSEU import (can be NULL)
2031  * @param timeout timeout for resolution
2032  * @param proc the processor to call on result
2033  * @param cls the closure to pass to proc
2034  */
2035 void
2036 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
2037                            uint32_t record_type,
2038                            const char* name,
2039                            struct GNUNET_CRYPTO_RsaPrivateKey *key,
2040                            struct GNUNET_TIME_Relative timeout,
2041                            RecordLookupProcessor proc,
2042                            void* cls)
2043 {
2044   struct ResolverHandle *rh;
2045   struct RecordLookupHandle* rlh;
2046   char string_hash[MAX_DNS_LABEL_LENGTH];
2047   char nzkey[MAX_DNS_LABEL_LENGTH];
2048   char* nzkey_ptr = nzkey;
2049
2050   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2051               "Starting resolution for %s (type=%d)!\n",
2052               name, record_type);
2053
2054   
2055   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
2056   {
2057     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2058                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
2059     proc(cls, 0, NULL);
2060     return;
2061   }
2062   
2063   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2064   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2065
2066   rh->authority = zone;
2067   rh->id = rid++;
2068   rh->proc_cls = rlh;
2069   rh->priv_key = key;
2070   rh->timeout = timeout;
2071   rh->get_handle = NULL;
2072   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2073   {
2074     /*
2075      * Set timeout for authority lookup phase to 1/2
2076      */
2077     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2078                 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
2079     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
2080                                 GNUNET_TIME_relative_divide(timeout, 2),
2081                                                 &handle_lookup_timeout,
2082                                                 rh);
2083     rh->timeout_cont = &dht_authority_lookup_timeout;
2084     rh->timeout_cont_cls = rh;
2085   }
2086   else
2087   {
2088     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2089     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2090   }
2091   
2092   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2093   {
2094     /**
2095      * Only 'gnunet' given
2096      */
2097     strcpy(rh->name, "\0");
2098   }
2099   else
2100   {
2101     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2102                 "Checking for TLD...\n");
2103     if (is_zkey_tld(name) == GNUNET_YES)
2104     {
2105       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2106                   "TLD is zkey\n");
2107       /**
2108        * This is a zkey tld
2109        * build hash and use as initial authority
2110        */
2111       memset(rh->name, 0,
2112              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2113       memcpy(rh->name, name,
2114              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2115       pop_tld(rh->name, string_hash);
2116
2117       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2118                   "ZKEY is %s!\n", string_hash);
2119       
2120       GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2121
2122       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2123                                                       &rh->authority))
2124       {
2125         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2126                     "Cannot convert ZKEY %s to hash!\n", string_hash);
2127         GNUNET_free(rh);
2128         GNUNET_free(rlh);
2129         proc(cls, 0, NULL);
2130         return;
2131       }
2132
2133     }
2134     else
2135     {
2136       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2137                   "TLD is gnunet\n");
2138       /**
2139        * Presumably GNUNET tld
2140        */
2141       memset(rh->name, 0,
2142              strlen(name)-strlen(GNUNET_GNS_TLD));
2143       memcpy(rh->name, name,
2144              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2145     }
2146   }
2147   
2148   /**
2149    * Initialize authority chain
2150    */
2151   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2152   rh->authority_chain_head->prev = NULL;
2153   rh->authority_chain_head->next = NULL;
2154   rh->authority_chain_tail = rh->authority_chain_head;
2155   rh->authority_chain_head->zone = rh->authority;
2156   
2157   /**
2158    * Copy original query into lookup handle
2159    */
2160   rlh->record_type = record_type;
2161   memset(rlh->name, 0, strlen(name) + 1);
2162   strcpy(rlh->name, name);
2163   rlh->proc = proc;
2164   rlh->proc_cls = cls;
2165
2166   rh->proc = &handle_delegation_ns;
2167   resolve_delegation_ns(rh);
2168 }
2169
2170 /******** END Record Resolver ***********/
2171
2172
2173 /**
2174  * Callback calles by namestore for a zone to name
2175  * result
2176  *
2177  * @param cls the closure
2178  * @param zone_key the zone we queried
2179  * @param expire the expiration time of the name
2180  * @param name the name found or NULL
2181  * @param rd_len number of records for the name
2182  * @param rd the record data (PKEY) for the name
2183  * @param signature the signature for the record data
2184  */
2185 static void
2186 process_zone_to_name_shorten(void *cls,
2187                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2188                  struct GNUNET_TIME_Absolute expire,
2189                  const char *name,
2190                  unsigned int rd_len,
2191                  const struct GNUNET_NAMESTORE_RecordData *rd,
2192                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2193 {
2194   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2195   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2196   struct AuthorityChain *next_authority;
2197
2198   char result[MAX_DNS_NAME_LENGTH];
2199   char next_authority_name[MAX_DNS_LABEL_LENGTH];
2200   size_t answer_len;
2201   
2202   /* we found a match in our own zone */
2203   if (rd_len != 0)
2204   {
2205     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2206                "result strlen %d\n", strlen(name));
2207     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
2208     memset(result, 0, answer_len);
2209     if (strlen(rh->name) > 0)
2210     {
2211       strcpy(result, rh->name);
2212       strcpy(result+strlen(rh->name), ".");
2213     }
2214     
2215     strcpy(result+strlen(result), name);
2216     strcpy(result+strlen(result), ".");
2217     strcpy(result+strlen(result), GNUNET_GNS_TLD);
2218     
2219     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2220                "Sending shorten result %s\n", result);
2221
2222     nsh->proc(nsh->proc_cls, result);
2223     GNUNET_free(nsh);
2224     free_resolver_handle(rh);
2225   }
2226   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2227                                         &local_zone) == 0)
2228   {
2229     /* our zone, just append .gnunet */
2230     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2231     memset(result, 0, answer_len);
2232     strcpy(result, rh->name);
2233     strcpy(result+strlen(rh->name), ".");
2234     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2235
2236     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2237                "Our zone: Sending name as shorten result %s\n", rh->name);
2238     
2239     nsh->proc(nsh->proc_cls, result);
2240     GNUNET_free(nsh);
2241     free_resolver_handle(rh);
2242   }
2243   else
2244   {
2245     /**
2246      * No PSEU found.
2247      * continue with next authority
2248      */
2249     next_authority = rh->authority_chain_head;
2250     
2251     GNUNET_snprintf(next_authority_name, MAX_DNS_NAME_LENGTH,
2252                     "%s.%s", rh->name, next_authority->name);
2253     
2254     strcpy(rh->name, next_authority_name);
2255     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2256                "No PSEU found for authority %s. Promoting back: %s\n",
2257                next_authority->name, rh->name);
2258     
2259     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
2260                               rh->authority_chain_tail,
2261                               next_authority);
2262
2263     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2264                                    &rh->authority_chain_tail->zone,
2265                                    &rh->authority_chain_head->zone,
2266                                    &process_zone_to_name_shorten,
2267                                    rh);
2268   }
2269 }
2270
2271 /**
2272  * DHT resolution for delegation. Processing result.
2273  *
2274  * @param cls the closure
2275  * @param rh resolver handle
2276  * @param rd_count number of results
2277  * @param rd record data
2278  */
2279 static void
2280 handle_delegation_dht_bg_shorten(void* cls, struct ResolverHandle *rh,
2281                           unsigned int rd_count,
2282                           const struct GNUNET_NAMESTORE_RecordData *rd)
2283 {
2284   
2285   /* We resolved full name for delegation. resolving record */
2286   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2287     "GNS_SHORTEN: Resolved up to %s for delegation via DHT in background.\n",
2288     rh->name);
2289   free_resolver_handle(rh);
2290 }
2291
2292 /**
2293  * Process result from namestore delegation lookup
2294  * for shorten operation
2295  *
2296  * @param cls the client shorten handle
2297  * @param rh the resolver handle
2298  * @param rd_count number of results (0)
2299  * @param rd data (NULL)
2300  */
2301 void
2302 handle_delegation_ns_shorten(void* cls,
2303                       struct ResolverHandle *rh,
2304                       uint32_t rd_count,
2305                       const struct GNUNET_NAMESTORE_RecordData *rd)
2306 {
2307   struct NameShortenHandle *nsh;
2308   char result[MAX_DNS_NAME_LENGTH];
2309   size_t answer_len;
2310   struct ResolverHandle *rh_bg;
2311
2312   nsh = (struct NameShortenHandle *)cls;
2313   
2314   /**
2315    * At this point rh->name contains the part of the name
2316    * that we do not have a PKEY in our namestore to resolve.
2317    * The authority chain in the resolver handle is now
2318    * useful to backtrack if needed
2319    */
2320   
2321   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2322              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2323
2324   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2325                                    &local_zone) == 0)
2326   {
2327     /**
2328      * This is our zone append .gnunet unless name is empty
2329      * (it shouldn't be, usually FIXME what happens if we
2330      * shorten to our zone to a "" record??)
2331      */
2332     
2333     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
2334     memset(result, 0, answer_len);
2335     strcpy(result, rh->name);
2336     strcpy(result+strlen(rh->name), ".");
2337     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
2338
2339     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2340                "Our zone: Sending name as shorten result %s\n", rh->name);
2341     
2342     nsh->proc(nsh->proc_cls, result);
2343     GNUNET_free(nsh);
2344     free_resolver_handle(rh);
2345     return;
2346   }
2347   
2348   /**
2349    * we have to this before zone to name for rh might
2350    * be freed by then
2351    */
2352   rh_bg = NULL;
2353   if (!is_canonical(rh->name))
2354   {
2355     rh_bg = GNUNET_malloc(sizeof(struct ResolverHandle));
2356     memcpy(rh_bg, rh, sizeof(struct ResolverHandle));
2357     rh_bg->id = rid++;
2358   }
2359
2360   /* backtrack authorities for names */
2361   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2362                                  &rh->authority_chain_tail->zone, //ours
2363                                  &rh->authority_chain_head->zone,
2364                                  &process_zone_to_name_shorten,
2365                                  rh);
2366   
2367   if (rh_bg == NULL)
2368   {
2369     return;
2370   }
2371
2372   /**
2373    * If authority resolution is incomplete we can do a background lookup
2374    * of the full name so that next time we can (likely) fully or at least
2375    * further shorten the name
2376    */
2377   rh_bg->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2378   rh_bg->authority_chain_tail = rh_bg->authority_chain_head;
2379   rh_bg->authority_chain_head->zone = rh_bg->authority;
2380   
2381   rh_bg->proc = &handle_delegation_dht_bg_shorten;
2382   rh_bg->proc_cls = NULL;
2383   
2384   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2385              "GNS_SHORTEN: Starting background lookup for %s\n",
2386              rh_bg->name);
2387
2388   resolve_delegation_dht(rh_bg);
2389
2390 }
2391
2392
2393 /**
2394  * Callback calles by namestore for a zone to name
2395  * result
2396  *
2397  * @param cls the closure
2398  * @param zone_key the zone we queried
2399  * @param expire the expiration time of the name
2400  * @param name the name found or NULL
2401  * @param rd_len number of records for the name
2402  * @param rd the record data (PKEY) for the name
2403  * @param signature the signature for the record data
2404  */
2405 static void
2406 process_zone_to_name_zkey(void *cls,
2407                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2408                  struct GNUNET_TIME_Absolute expire,
2409                  const char *name,
2410                  unsigned int rd_len,
2411                  const struct GNUNET_NAMESTORE_RecordData *rd,
2412                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2413 {
2414   struct ResolverHandle *rh = cls;
2415   struct NameShortenHandle *nsh = rh->proc_cls;
2416   struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
2417   char new_name[MAX_DNS_NAME_LENGTH];
2418
2419   /* zkey not in our zone */
2420   if (name == NULL)
2421   {
2422     /**
2423      * In this case we have not given this PKEY a name (yet)
2424      * It is either just not in our zone or not even cached
2425      * Since we do not know at this point we will not try to shorten
2426      * because PKEY import will happen if the user follows the zkey
2427      * link.
2428      */
2429     GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
2430                                      &enc);
2431     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2432                "No name found for zkey %s returning verbatim!\n", enc);
2433     if (strcmp(rh->name, "") != 0)
2434       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
2435                       rh->name, enc, GNUNET_GNS_TLD_ZKEY);
2436     else
2437       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2438                       enc, GNUNET_GNS_TLD_ZKEY);
2439     nsh->proc(nsh->proc_cls, new_name);
2440     GNUNET_free(nsh);
2441     free_resolver_handle(rh);
2442     return;
2443   }
2444   
2445   if (strcmp(rh->name, "") != 0)
2446     GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2447                     rh->name, name);
2448   else
2449     strcpy(new_name, name);
2450
2451   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2452              "Continue shorten for %s!\n", new_name);
2453
2454   strcpy(rh->name, new_name);
2455   
2456   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2457   rh->authority_chain_tail = rh->authority_chain_head;
2458   rh->authority_chain_head->zone = rh->authority;
2459   
2460   
2461   /* Start delegation resolution in our namestore */
2462   resolve_delegation_ns(rh);
2463 }
2464
2465
2466 /**
2467  * Shorten api from resolver
2468  *
2469  * @param zone the zone to use
2470  * @param name the name to shorten
2471  * @param key optional private key for background lookups and PSEU import
2472  * @param proc the processor to call with result
2473  * @param proc_cls closure to pass to proc
2474  */
2475 void
2476 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
2477                           const char* name,
2478                           struct GNUNET_CRYPTO_RsaPrivateKey *key,
2479                           ShortenResultProcessor proc,
2480                           void* proc_cls)
2481 {
2482   struct ResolverHandle *rh;
2483   struct NameShortenHandle *nsh;
2484   char string_hash[MAX_DNS_LABEL_LENGTH];
2485   struct GNUNET_CRYPTO_ShortHashCode zkey;
2486   char nzkey[MAX_DNS_LABEL_LENGTH];
2487   char* nzkey_ptr = nzkey;
2488
2489
2490   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2491               "Starting shorten for %s!\n", name);
2492   
2493   if (is_canonical((char*)name))
2494   {
2495     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2496                 "%s is canonical. Returning verbatim\n", name);
2497     proc(proc_cls, name);
2498     return;
2499   }
2500
2501   nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
2502
2503   nsh->proc = proc;
2504   nsh->proc_cls = proc_cls;
2505   
2506   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2507   rh->authority = zone;
2508   rh->id = rid++;
2509   rh->priv_key = key;
2510   rh->proc = &handle_delegation_ns_shorten;
2511   rh->proc_cls = nsh;
2512   rh->id = rid++;
2513   
2514   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2515                 "Checking for TLD...\n");
2516   if (is_zkey_tld(name) == GNUNET_YES)
2517   {
2518     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2519                 "TLD is zkey\n");
2520     /**
2521      * This is a zkey tld
2522      * build hash and use as initial authority
2523      * FIXME sscanf
2524      */
2525     memset(rh->name, 0,
2526            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2527     memcpy(rh->name, name,
2528            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2529     pop_tld(rh->name, string_hash);
2530
2531     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2532                 "ZKEY is %s!\n", string_hash);
2533     
2534     GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2535
2536     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2537                                                           &zkey))
2538     {
2539       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2540                   "Cannot convert ZKEY %s to hash!\n", nzkey);
2541       GNUNET_free(rh);
2542       GNUNET_free(nsh);
2543       proc(proc_cls, name);
2544       return;
2545     }
2546
2547     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
2548                                    &zone, //ours
2549                                    &zkey,
2550                                    &process_zone_to_name_zkey,
2551                                    rh);
2552     return;
2553
2554   }
2555   else
2556   {
2557     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2558                 "TLD is gnunet\n");
2559     /**
2560      * Presumably GNUNET tld
2561      */
2562     memset(rh->name, 0,
2563            strlen(name)-strlen(GNUNET_GNS_TLD));
2564     memcpy(rh->name, name,
2565            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2566   }
2567
2568   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2569   rh->authority_chain_tail = rh->authority_chain_head;
2570   rh->authority_chain_head->zone = zone;
2571   
2572   
2573   /* Start delegation resolution in our namestore */
2574   resolve_delegation_ns(rh);
2575 }
2576
2577 /*********** END NAME SHORTEN ********************/
2578
2579
2580 /**
2581  * Process result from namestore delegation lookup
2582  * for get authority operation
2583  *
2584  * @param cls the client get auth handle
2585  * @param rh the resolver handle
2586  * @param rd_count number of results (0)
2587  * @param rd data (NULL)
2588  */
2589 void
2590 handle_delegation_result_ns_get_auth(void* cls,
2591                       struct ResolverHandle *rh,
2592                       uint32_t rd_count,
2593                       const struct GNUNET_NAMESTORE_RecordData *rd)
2594 {
2595   struct GetNameAuthorityHandle* nah;
2596   char result[MAX_DNS_NAME_LENGTH];
2597   size_t answer_len;
2598
2599   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
2600   
2601   /**
2602    * At this point rh->name contains the part of the name
2603    * that we do not have a PKEY in our namestore to resolve.
2604    * The authority chain in the resolver handle is now
2605    * useful to backtrack if needed
2606    */
2607   
2608   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2609              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
2610
2611   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2612              "Building response!\n");
2613   if (is_canonical(rh->name))
2614   {
2615     /**
2616      * We successfully resolved the authority in the ns
2617      * FIXME for our purposes this is fine
2618      * but maybe we want to have an api that also looks
2619      * into the dht (i.e. option in message)
2620      **/
2621     if (strlen(rh->name) > strlen(nah->name))
2622     {
2623       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2624                  "Record name longer than original lookup name... odd!\n");
2625       //FIXME to sth here
2626     }
2627
2628     answer_len = strlen(nah->name) - strlen(rh->name)
2629       + strlen(GNUNET_GNS_TLD) + 1;
2630     memset(result, 0, answer_len);
2631     strcpy(result, nah->name + strlen(rh->name) + 1);
2632
2633     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2634                "Got authority result %s\n", result);
2635     
2636     nah->proc(nah->proc_cls, result);
2637     GNUNET_free(nah);
2638     free_resolver_handle(rh);
2639   }
2640   else
2641   {
2642     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2643                "Unable to resolve authority for remaining %s!\n", rh->name);
2644     nah->proc(nah->proc_cls, "");
2645     GNUNET_free(nah);
2646     free_resolver_handle(rh);
2647   }
2648
2649
2650 }
2651
2652
2653 /**
2654  * Tries to resolve the authority for name
2655  * in our namestore
2656  *
2657  * @param zone the root zone to look up for
2658  * @param name the name to lookup up
2659  * @param proc the processor to call when finished
2660  * @param proc_cls the closure to pass to the processor
2661  */
2662 void
2663 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2664                            const char* name,
2665                            GetAuthorityResultProcessor proc,
2666                            void* proc_cls)
2667 {
2668   struct ResolverHandle *rh;
2669   struct GetNameAuthorityHandle *nah;
2670
2671   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2672               "Starting authority resolution for %s!\n", name);
2673
2674   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2675   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2676   rh->authority = zone;
2677   rh->id = rid++;
2678   
2679   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2680   {
2681     strcpy(rh->name, "\0");
2682   }
2683   else
2684   {
2685     memset(rh->name, 0,
2686            strlen(name)-strlen(GNUNET_GNS_TLD));
2687     memcpy(rh->name, name,
2688            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2689   }
2690
2691   memset(nah->name, 0,
2692          strlen(name)+1);
2693   strcpy(nah->name, name);
2694   
2695   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2696   rh->authority_chain_tail = rh->authority_chain_head;
2697   rh->authority_chain_head->zone = zone;
2698   rh->proc = &handle_delegation_result_ns_get_auth;
2699   rh->proc_cls = (void*)nah;
2700
2701   nah->proc = proc;
2702   nah->proc_cls = proc_cls;
2703
2704   /* Start delegation resolution in our namestore */
2705   resolve_delegation_ns(rh);
2706
2707 }
2708
2709 /******** END GET AUTHORITY *************/
2710
2711 /* end of gnunet-service-gns_resolver.c */