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