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