-more NS delegation
[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_vpn_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_LOOKUP_TIMEOUT DHT_OPERATION_TIMEOUT
43 #define DHT_GNS_REPLICATION_LEVEL 5
44 #define MAX_DNS_LABEL_LENGTH 63
45
46
47 /**
48  * Our handle to the namestore service
49  */
50 static struct GNUNET_NAMESTORE_Handle *namestore_handle;
51
52 /**
53  * Our handle to the vpn service
54  */
55 static struct GNUNET_VPN_Handle *vpn_handle;
56
57 /**
58  * Resolver handle to the dht
59  */
60 static struct GNUNET_DHT_Handle *dht_handle;
61
62 /**
63  * Heap for parallel DHT lookups
64  */
65 static struct GNUNET_CONTAINER_Heap *dht_lookup_heap;
66
67 /**
68  * Maximum amount of parallel queries in background
69  */
70 static unsigned long long max_allowed_background_queries;
71
72 /**
73  * Wheather or not to ignore pending records
74  */
75 static int ignore_pending_records;
76
77 /**
78  * Our local zone
79  */
80 static struct GNUNET_CRYPTO_ShortHashCode local_zone;
81
82 /**
83  * a resolution identifier pool variable
84  * FIXME overflow?
85  * This is a non critical identifier useful for debugging
86  */
87 static unsigned long long rid = 0;
88
89
90 /**
91  * Determine if this name is canonical.
92  * i.e.
93  * a.b.gnunet  = not canonical
94  * a           = canonical
95  *
96  * @param name the name to test
97  * @return 1 if canonical
98  */
99 static int
100 is_canonical(char* name)
101 {
102   uint32_t len = strlen(name);
103   int i;
104
105   for (i=0; i<len; i++)
106   {
107     if (*(name+i) == '.')
108       return 0;
109   }
110   return 1;
111 }
112
113
114 /**
115  * Callback that shortens authorities
116  *
117  * @param gph the handle containing the name to shorten
118  */
119 static void
120 shorten_authority_chain (struct GetPseuAuthorityHandle *gph);
121
122
123 /**
124  * Namestore calls this function if we have record for this name.
125  * (or with rd_count=0 to indicate no matches)
126  *
127  * @param cls the pending query
128  * @param key the key of the zone we did the lookup
129  * @param expiration expiration date of the namestore entry
130  * @param name the name for which we need an authority
131  * @param rd_count the number of records with 'name'
132  * @param rd the record data
133  * @param signature the signature of the authority for the record data
134  */
135 static void
136 process_pseu_lookup_ns (void* cls,
137                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
138                       struct GNUNET_TIME_Absolute expiration,
139                       const char *name, unsigned int rd_count,
140                       const struct GNUNET_NAMESTORE_RecordData *rd,
141                       const struct GNUNET_CRYPTO_RsaSignature *signature)
142 {
143   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
144   struct GNUNET_NAMESTORE_RecordData new_pkey;
145   struct AuthorityChain *iter;
146
147   if (rd_count > 0)
148   {
149     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
150                "GNS_AUTO_PSEU: Name %s already taken in NS!\n", name);
151     if (0 == strcmp (gph->name, name))
152     {
153       if (gph->ahead->next != NULL)
154       {
155         if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
156                                           &gph->our_zone))
157         {
158           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
159           iter = gph->ahead->next;
160           GNUNET_free (gph->ahead);
161           gph->ahead = iter;
162           shorten_authority_chain (gph);
163           return;
164         }
165       }
166
167       /* Clean up */
168       do
169       {
170         iter = gph->ahead->next;
171         GNUNET_free (gph->ahead);
172         gph->ahead = iter;
173       } while (iter != NULL);
174       GNUNET_CRYPTO_rsa_key_free (gph->key);
175
176       GNUNET_free (gph);
177       return;
178     }
179
180     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
181                 "GNS_AUTO_PSEU: Trying delegated name %s\n", gph->name);
182     memcpy (gph->test_name, gph->name, strlen (gph->name)+1);
183     GNUNET_NAMESTORE_lookup_record (namestore_handle,
184                                     &gph->our_zone,
185                                     gph->test_name,
186                                     GNUNET_NAMESTORE_TYPE_ANY,
187                                     &process_pseu_lookup_ns,
188                                     gph);
189     return;
190   }
191
192   /** name is free */
193   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
194             "GNS_AUTO_PSEU: Name %s not taken in NS! Adding\n", gph->test_name);
195
196   new_pkey.expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
197   new_pkey.data_size = sizeof (struct GNUNET_CRYPTO_ShortHashCode);
198   new_pkey.data = &gph->ahead->zone;
199   new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
200   new_pkey.flags = GNUNET_NAMESTORE_RF_AUTHORITY
201                  | GNUNET_NAMESTORE_RF_PRIVATE
202                  | GNUNET_NAMESTORE_RF_PENDING;
203   GNUNET_NAMESTORE_record_create (namestore_handle,
204                                   gph->key,
205                                   gph->test_name,
206                                   &new_pkey,
207                                   NULL, //cont
208                                   NULL); //cls
209   do
210   {
211     iter = gph->ahead->next;
212     GNUNET_free (gph->ahead);
213     gph->ahead = iter;
214   } while (iter != NULL);
215   GNUNET_CRYPTO_rsa_key_free (gph->key);
216   GNUNET_free (gph);
217
218 }
219
220 /**
221  * process result of a dht pseu lookup
222  *
223  * @param gph the handle
224  * @param name the pseu result or NULL
225  */
226 static void
227 process_pseu_result (struct GetPseuAuthorityHandle* gph, char* name)
228 {
229   if (NULL == name)
230   {
231     memcpy (gph->test_name, gph->ahead->name, strlen (gph->ahead->name)+1);
232   }
233   else
234   {
235     memcpy (gph->test_name, name, strlen(name)+1);
236   }
237
238   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
239               "GNS_AUTO_PSEU: Checking %s for collision in NS\n",
240               gph->test_name);
241
242   /**
243    * Check for collision
244    */
245   GNUNET_NAMESTORE_lookup_record (namestore_handle,
246                                   &gph->our_zone,
247                                   gph->test_name,
248                                   GNUNET_NAMESTORE_TYPE_ANY,
249                                   &process_pseu_lookup_ns,
250                                   gph);
251 }
252
253 /**
254  * Handle timeout for dht request
255  *
256  * @param cls the request handle as closure
257  * @param tc the task context
258  */
259 static void
260 handle_auth_discovery_timeout(void *cls,
261                               const struct GNUNET_SCHEDULER_TaskContext *tc)
262 {
263   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
264   struct AuthorityChain *iter;
265
266   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
267               "GNS_GET_AUTH: dht lookup for query PSEU timed out.\n");
268   GNUNET_DHT_get_stop (gph->get_handle);
269   gph->get_handle = NULL;
270   
271   if (gph->ahead->next != NULL)
272   {
273     if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
274                                       &gph->our_zone))
275     {
276       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
277       iter = gph->ahead->next;
278       GNUNET_free (gph->ahead);
279       gph->ahead = iter;
280       shorten_authority_chain (gph);
281       return;
282     }
283   }
284   
285   process_pseu_result (gph, NULL);
286 }
287
288 /**
289  * Function called when we find a PSEU entry in the DHT
290  *
291  * @param cls the request handle
292  * @param exp lifetime
293  * @param key the key the record was stored under
294  * @param get_path get path
295  * @param get_path_length get path length
296  * @param put_path put path
297  * @param put_path_length put path length
298  * @param type the block type
299  * @param size the size of the record
300  * @param data the record data
301  */
302 static void
303 process_auth_discovery_dht_result(void* cls,
304                                   struct GNUNET_TIME_Absolute exp,
305                                   const struct GNUNET_HashCode * key,
306                                   const struct GNUNET_PeerIdentity *get_path,
307                                   unsigned int get_path_length,
308                                   const struct GNUNET_PeerIdentity *put_path,
309                                   unsigned int put_path_length,
310                                   enum GNUNET_BLOCK_Type type,
311                                   size_t size, const void *data)
312 {
313   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
314   struct AuthorityChain *iter;
315   struct GNSNameRecordBlock *nrb;
316   char* rd_data = (char*)data;
317   char* name;
318   int num_records;
319   size_t rd_size;
320   int i;
321
322   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
323               "GNS_GET_AUTH: got dht result (size=%d)\n", size);
324
325   if (data == NULL)
326   {
327     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
328                 "GNS_GET_AUTH: got dht result null!\n", size);
329     
330     do
331     {
332       iter = gph->ahead->next;
333       GNUNET_free (gph->ahead);
334       gph->ahead = iter;
335     } while (iter != NULL);
336     GNUNET_CRYPTO_rsa_key_free (gph->key);
337     GNUNET_free (gph);
338     return;
339   }
340   
341   nrb = (struct GNSNameRecordBlock*)data;
342
343   /* stop lookup and timeout task */
344   GNUNET_DHT_get_stop (gph->get_handle);
345   gph->get_handle = NULL;
346   GNUNET_SCHEDULER_cancel (gph->timeout);
347
348   gph->get_handle = NULL;
349
350   nrb = (struct GNSNameRecordBlock*)data;
351   
352   name = (char*)&nrb[1];
353   num_records = ntohl (nrb->rd_count);
354   {
355     struct GNUNET_NAMESTORE_RecordData rd[num_records];
356
357     rd_data += strlen (name) + 1 + sizeof (struct GNSNameRecordBlock);
358     rd_size = size - strlen (name) - 1 - sizeof (struct GNSNameRecordBlock);
359
360     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
361                                                                rd_data,
362                                                                num_records,
363                                                                rd))
364     {
365       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
366                   "GNS_GET_AUTH: Error deserializing data!\n");
367     }
368     else
369     {
370       for (i=0; i < num_records; i++)
371       {
372         if ((strcmp (name, "+") == 0) &&
373             (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
374         {
375           /* found pseu */
376           process_pseu_result (gph, (char*)rd[i].data);
377           return;
378         }
379       }
380     }
381   }
382
383   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in dht!\n");
384
385   if (gph->ahead->next != NULL)
386   {
387     if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
388                                       &gph->our_zone))
389     {
390       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
391       iter = gph->ahead->next;
392       GNUNET_free (gph->ahead);
393       gph->ahead = iter;
394       shorten_authority_chain (gph);
395       return;
396     }
397   }
398   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
399               "GNS_GET_AUTH: finished shorten, no results!\n");
400   process_pseu_result (gph, NULL);
401 }
402
403 /**
404  * Process PSEU discovery for shorten via namestore
405  *
406  * @param cls the GetPseuAuthorityHandle
407  * @param key the public key
408  * @param expiration recorddata expiration
409  * @param name the looked up name
410  * @param rd_count number of records in set
411  * @param rd record data
412  * @param signature the signature
413  */
414 static void
415 process_auth_discovery_ns_result(void* cls,
416                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
417                       struct GNUNET_TIME_Absolute expiration,
418                       const char *name,
419                       unsigned int rd_count,
420                       const struct GNUNET_NAMESTORE_RecordData *rd,
421                       const struct GNUNET_CRYPTO_RsaSignature *signature)
422 {
423   uint32_t xquery;
424   struct GNUNET_CRYPTO_ShortHashCode name_hash;
425   struct GNUNET_HashCode lookup_key;
426   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
427   struct GNUNET_HashCode name_hash_double;
428   struct GNUNET_HashCode zone_hash_double;
429   int i;
430   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
431   struct AuthorityChain *iter;
432   
433   /* no pseu found */
434   if (rd_count == 0)
435   {
436     /**
437      * check dht
438      */
439     GNUNET_CRYPTO_short_hash ("+", strlen ("+"), &name_hash);
440     GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
441     GNUNET_CRYPTO_short_hash_double (&gph->ahead->zone, &zone_hash_double);
442     GNUNET_CRYPTO_hash_xor (&name_hash_double, &zone_hash_double, &lookup_key);
443     GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
444
445     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
446                "GNS_AUTO_PSEU: starting dht lookup for %s with key: %s\n",
447                "+", (char*)&lookup_key_string);
448
449     gph->timeout = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
450                                          &handle_auth_discovery_timeout, gph);
451
452     xquery = htonl (GNUNET_GNS_RECORD_PSEU);
453     
454     GNUNET_assert (gph->get_handle == NULL);
455
456     gph->get_handle = GNUNET_DHT_get_start(dht_handle,
457                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
458                                            &lookup_key,
459                                            DHT_GNS_REPLICATION_LEVEL,
460                                            GNUNET_DHT_RO_NONE,
461                                            &xquery,
462                                            sizeof(xquery),
463                                            &process_auth_discovery_dht_result,
464                                            gph);
465     return;
466   }
467
468   for (i=0; i < rd_count; i++)
469   {
470     if ((strcmp (name, "+") == 0) &&
471         (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
472     {
473       /* found pseu */
474       process_pseu_result (gph, (char*)rd[i].data);
475       return;
476     }
477   }
478
479   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: no pseu in namestore!\n");
480   
481   if (gph->ahead->next != NULL)
482   {
483     if (GNUNET_CRYPTO_short_hash_cmp (&gph->ahead->next->zone,
484                                       &gph->our_zone))
485     {
486       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS_GET_AUTH: trying next!\n");
487       iter = gph->ahead->next;
488       GNUNET_free (gph->ahead);
489       gph->ahead = iter;
490       shorten_authority_chain (gph);
491       return;
492     }
493   }
494   
495   process_pseu_result (gph, NULL);
496 }
497
498 /**
499  * Callback called by namestore for a zone to name
500  * result
501  *
502  * @param cls the closure
503  * @param zone_key the zone we queried
504  * @param expire the expiration time of the name
505  * @param name the name found or NULL
506  * @param rd_len number of records for the name
507  * @param rd the record data (PKEY) for the name
508  * @param signature the signature for the record data
509  */
510 static void
511 process_zone_to_name_discover (void *cls,
512                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
513                  struct GNUNET_TIME_Absolute expire,
514                  const char *name,
515                  unsigned int rd_len,
516                  const struct GNUNET_NAMESTORE_RecordData *rd,
517                  const struct GNUNET_CRYPTO_RsaSignature *signature)
518 {
519   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
520   struct AuthorityChain *iter;
521
522   /* we found a match in our own zone */
523   if (rd_len != 0)
524   {
525     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
526                "GNS_AUTO_PSEU: name for zone in our root %s\n", name);
527
528     iter = gph->ahead;
529     do
530     {
531       iter = gph->ahead->next;
532       GNUNET_free (gph->ahead);
533       gph->ahead = iter;
534     } while (iter != NULL);
535     GNUNET_CRYPTO_rsa_key_free (gph->key);
536     GNUNET_free (gph);
537   }
538   else
539   {
540
541     GNUNET_NAMESTORE_lookup_record (namestore_handle,
542                                     &gph->ahead->zone,
543                                     "+",
544                                     GNUNET_GNS_RECORD_PSEU,
545                                     &process_auth_discovery_ns_result,
546                                     gph);
547   }
548
549 }
550
551
552 /**
553  * Callback that shortens authorities
554  *
555  * @param name the name given by delegation
556  * @param zone the authority
557  * @param our_zone our local zone
558  * @param key the private key of our authority
559  */
560 static void
561 shorten_authority_chain (struct GetPseuAuthorityHandle *gph)
562 {
563
564   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
565               "GNS_AUTO_PSEU: New authority %s discovered\n",
566               gph->ahead->name);
567
568   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
569                                  &gph->our_zone,
570                                  &gph->ahead->zone,
571                                  &process_zone_to_name_discover,
572                                  gph);
573
574 }
575
576 static void
577 start_shorten (struct AuthorityChain *atail,
578                struct GNUNET_CRYPTO_RsaPrivateKey *key)
579 {
580   struct AuthorityChain *new_head = NULL;
581   struct AuthorityChain *new_tail = NULL;
582   struct AuthorityChain *iter;
583   struct AuthorityChain *acopy;
584   struct GetPseuAuthorityHandle *gph;
585   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
586   struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded *pb_key;
587
588   /* First copy the authority chain in reverse order */
589   for (iter = atail; iter != NULL; iter = iter->prev)
590   {
591     acopy = GNUNET_malloc (sizeof (struct AuthorityChain));
592     memcpy (acopy, iter, sizeof (struct AuthorityChain));
593     acopy->next = NULL;
594     acopy->prev = NULL;
595     GNUNET_CONTAINER_DLL_insert (new_head, new_tail, acopy);
596   }
597
598   gph = GNUNET_malloc (sizeof (struct GetPseuAuthorityHandle));
599
600   GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
601   pb_key = GNUNET_CRYPTO_rsa_encode_key (key);
602   gph->key = GNUNET_CRYPTO_rsa_decode_key ((char*)pb_key, ntohs (pb_key->len));
603   //gph->key = key;//GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
604   //memcpy (gph->key, key, sizeof (struct GNUNET_CRYPTO_RsaPrivateKey));
605   
606   GNUNET_CRYPTO_short_hash (&pkey,
607                         sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
608                         &gph->our_zone);
609   gph->ahead = new_head;
610
611   shorten_authority_chain (gph);
612 }
613
614 /**
615  * Initialize the resolver
616  *
617  * @param nh the namestore handle
618  * @param dh the dht handle
619  * @param lz the local zone's hash
620  * @param max_bg_queries maximum number of parallel background queries in dht
621  * @param ignore_pending ignore records that still require user confirmation
622  *        on lookup
623  * @return GNUNET_OK on success
624  */
625 int
626 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
627                   struct GNUNET_DHT_Handle *dh,
628                   struct GNUNET_CRYPTO_ShortHashCode lz,
629                   unsigned long long max_bg_queries,
630                   int ignore_pending)
631 {
632   namestore_handle = nh;
633   dht_handle = dh;
634   local_zone = lz;
635   dht_lookup_heap =
636     GNUNET_CONTAINER_heap_create(GNUNET_CONTAINER_HEAP_ORDER_MIN);
637   max_allowed_background_queries = max_bg_queries;
638   ignore_pending_records = ignore_pending;
639
640   if ((namestore_handle != NULL) && (dht_handle != NULL))
641   {
642     return GNUNET_OK;
643   }
644   return GNUNET_SYSERR;
645 }
646
647 /**
648  * Cleanup background lookups
649  *
650  * @param cls closure to iterator
651  * @param node heap nodes
652  * @param element the resolver handle
653  * @param cost heap cost
654  * @return always GNUNET_YES
655  */
656 static int
657 cleanup_pending_background_queries(void* cls,
658                                    struct GNUNET_CONTAINER_HeapNode *node,
659                                    void *element,
660                                    GNUNET_CONTAINER_HeapCostType cost)
661 {
662   struct ResolverHandle *rh = (struct ResolverHandle *)element;
663   ResolverCleanupContinuation cont = cls;
664   
665   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
666              "GNS_CLEANUP-%llu: Terminating background lookup for %s\n",
667              rh->id, rh->name);
668   GNUNET_DHT_get_stop(rh->get_handle);
669   rh->get_handle = NULL;
670   rh->proc(rh->proc_cls, rh, 0, NULL);
671
672   GNUNET_CONTAINER_heap_remove_node(node);
673
674   if (GNUNET_CONTAINER_heap_get_size(dht_lookup_heap) == 0)
675     cont();
676
677
678   return GNUNET_YES;
679 }
680
681
682 /**
683  * Shutdown resolver
684  */
685 void
686 gns_resolver_cleanup(ResolverCleanupContinuation cont)
687 {
688   unsigned int s = GNUNET_CONTAINER_heap_get_size(dht_lookup_heap);
689   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
690              "GNS_CLEANUP: %d pending background queries to terminate\n", s);
691
692   if (0 != s)
693     GNUNET_CONTAINER_heap_iterate (dht_lookup_heap,
694                                    &cleanup_pending_background_queries,
695                                    cont);
696   else
697     cont();
698 }
699
700
701 /**
702  * Helper function to free resolver handle
703  *
704  * @param rh the handle to free
705  */
706 static void
707 free_resolver_handle(struct ResolverHandle* rh)
708 {
709   struct AuthorityChain *ac;
710   struct AuthorityChain *ac_next;
711
712   if (NULL == rh)
713     return;
714
715   ac = rh->authority_chain_head;
716
717   while (NULL != ac)
718   {
719     ac_next = ac->next;
720     GNUNET_free(ac);
721     ac = ac_next;
722   }
723   GNUNET_free(rh);
724 }
725
726
727 /**
728  * Callback when record data is put into namestore
729  *
730  * @param cls the closure
731  * @param success GNUNET_OK on success
732  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
733  */
734 void
735 on_namestore_record_put_result(void *cls,
736                                int32_t success,
737                                const char *emsg)
738 {
739   if (GNUNET_NO == success)
740   {
741     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
742                "GNS_NS: records already in namestore\n");
743     return;
744   }
745   else if (GNUNET_YES == success)
746   {
747     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
748                "GNS_NS: records successfully put in namestore\n");
749     return;
750   }
751
752   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
753              "GNS_NS: Error putting records into namestore: %s\n", emsg);
754 }
755
756 static void
757 handle_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
758 {
759   struct ResolverHandle *rh = cls;
760
761   if (rh->timeout_cont)
762     rh->timeout_cont(rh->timeout_cont_cls, tc);
763 }
764
765 /**
766  * Processor for background lookups in the DHT
767  *
768  * @param cls closure (NULL)
769  * @param rd_count number of records found (not 0)
770  * @param rd record data
771  */
772 static void
773 background_lookup_result_processor(void *cls,
774                                    uint32_t rd_count,
775                                    const struct GNUNET_NAMESTORE_RecordData *rd)
776 {
777   //We could do sth verbose/more useful here but it doesn't make any difference
778   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
779              "GNS_BG: background dht lookup for finished. (%d results)\n",
780              rd_count);
781 }
782
783 /**
784  * Handle timeout for DHT requests
785  *
786  * @param cls the request handle as closure
787  * @param tc the task context
788  */
789 static void
790 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
791 {
792   struct ResolverHandle *rh = cls;
793   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
794   char new_name[MAX_DNS_NAME_LENGTH];
795
796   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
797              "GNS_PHASE_REC-%d: dht lookup for query %s (%ds)timed out.\n",
798              rh->id, rh->name, rh->timeout.rel_value);
799   /**
800    * Start resolution in bg
801    */
802   //strcpy(new_name, rh->name);
803   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
804   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
805                   rh->name, GNUNET_GNS_TLD);
806
807   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
808              "GNS_PHASE_REC-%d: Starting background lookup for %s type %d\n",
809              rh->id, new_name, rlh->record_type);
810
811   gns_resolver_lookup_record(rh->authority,
812                              rh->private_local_zone,
813                              rlh->record_type,
814                              new_name,
815                              rh->priv_key,
816                              GNUNET_TIME_UNIT_FOREVER_REL,
817                              GNUNET_NO,
818                              &background_lookup_result_processor,
819                              NULL);
820   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
821   
822   GNUNET_DHT_get_stop (rh->get_handle);
823   rh->get_handle = NULL;
824   rh->proc(rh->proc_cls, rh, 0, NULL);
825 }
826
827
828 /**
829  * Function called when we get a result from the dht
830  * for our record query
831  *
832  * @param cls the request handle
833  * @param exp lifetime
834  * @param key the key the record was stored under
835  * @param get_path get path
836  * @param get_path_length get path length
837  * @param put_path put path
838  * @param put_path_length put path length
839  * @param type the block type
840  * @param size the size of the record
841  * @param data the record data
842  */
843 static void
844 process_record_result_dht(void* cls,
845                  struct GNUNET_TIME_Absolute exp,
846                  const struct GNUNET_HashCode * key,
847                  const struct GNUNET_PeerIdentity *get_path,
848                  unsigned int get_path_length,
849                  const struct GNUNET_PeerIdentity *put_path,
850                  unsigned int put_path_length,
851                  enum GNUNET_BLOCK_Type type,
852                  size_t size, const void *data)
853 {
854   struct ResolverHandle *rh;
855   struct RecordLookupHandle *rlh;
856   struct GNSNameRecordBlock *nrb;
857   uint32_t num_records;
858   char* name = NULL;
859   char* rd_data = (char*)data;
860   int i;
861   int rd_size;
862
863   rh = (struct ResolverHandle *)cls;
864   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
865              "GNS_PHASE_REC-%d: got dht result (size=%d)\n", rh->id, size);
866   
867   if (data == NULL)
868     return;
869
870   //FIXME maybe check expiration here, check block type
871   
872   
873   rlh = (struct RecordLookupHandle *) rh->proc_cls;
874   nrb = (struct GNSNameRecordBlock*)data;
875   
876   /* stop lookup and timeout task */
877   GNUNET_DHT_get_stop (rh->get_handle);
878   rh->get_handle = NULL;
879   
880   if (rh->dht_heap_node != NULL)
881   {
882     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
883     rh->dht_heap_node = NULL;
884   }
885   
886   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
887   {
888     GNUNET_SCHEDULER_cancel(rh->timeout_task);
889     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
890   }
891
892   rh->get_handle = NULL;
893   name = (char*)&nrb[1];
894   num_records = ntohl(nrb->rd_count);
895   {
896     struct GNUNET_NAMESTORE_RecordData rd[num_records];
897
898     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
899     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
900   
901     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
902                                                                rd_data,
903                                                                num_records,
904                                                                rd))
905     {
906       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
907                  "GNS_PHASE_REC-%d: Error deserializing data!\n", rh->id);
908       return;
909     }
910
911     for (i=0; i<num_records; i++)
912     {
913       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
914                "GNS_PHASE_REC-%d: Got name: %s (wanted %s)\n",
915                rh->id, name, rh->name);
916       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
917                "GNS_PHASE_REC-%d: Got type: %d\n",
918                rh->id, rd[i].record_type);
919       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
920                "GNS_PHASE_REC-%d: Got data length: %d\n",
921                rh->id, rd[i].data_size);
922       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
923                "GNS_PHASE_REC-%d: Got flag %d\n",
924                rh->id, rd[i].flags);
925     
926      if ((strcmp(name, rh->name) == 0) &&
927          (rd[i].record_type == rlh->record_type))
928       {
929         rh->answered++;
930       }
931
932     }
933
934     /**
935      * FIXME check pubkey against existing key in namestore?
936      * https://gnunet.org/bugs/view.php?id=2179
937      */
938
939     /* Save to namestore */
940     GNUNET_NAMESTORE_record_put (namestore_handle,
941                                  &nrb->public_key,
942                                  name,
943                                  exp,
944                                  num_records,
945                                  rd,
946                                  &nrb->signature,
947                                  &on_namestore_record_put_result, //cont
948                                  NULL); //cls
949
950   
951     if (rh->answered)
952       rh->proc(rh->proc_cls, rh, num_records, rd);
953     else
954       rh->proc(rh->proc_cls, rh, 0, NULL);
955   }
956
957 }
958
959
960 /**
961  * Start DHT lookup for a (name -> query->record_type) record in
962  * rh->authority's zone
963  *
964  * @param rh the pending gns query context
965  */
966 static void
967 resolve_record_dht(struct ResolverHandle *rh)
968 {
969   uint32_t xquery;
970   struct GNUNET_CRYPTO_ShortHashCode name_hash;
971   struct GNUNET_HashCode lookup_key;
972   struct GNUNET_HashCode name_hash_double;
973   struct GNUNET_HashCode zone_hash_double;
974   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
975   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
976   struct ResolverHandle *rh_heap_root;
977   
978   GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
979   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
980   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
981   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
982   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
983   
984   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
985              "GNS_PHASE_REC-%d: starting dht lookup for %s with key: %s\n",
986              rh->id, rh->name, (char*)&lookup_key_string);
987
988   //rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
989   rh->dht_heap_node = NULL;
990
991   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
992   {
993     /**
994      * Update timeout if necessary
995      */
996     if (rh->timeout_task == GNUNET_SCHEDULER_NO_TASK)
997     {
998
999     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1000                "GNS_PHASE_REC-%d: Adjusting timeout\n", rh->id);
1001     /*
1002      * Set timeout for authority lookup phase to 1/2
1003      */
1004       rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
1005                                 GNUNET_TIME_relative_divide(rh->timeout, 2),
1006                                                 &handle_lookup_timeout,
1007                                                 rh);
1008     }
1009     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1010     //                                                   &dht_lookup_timeout,
1011     //                                                   rh);
1012     rh->timeout_cont = &dht_lookup_timeout;
1013     rh->timeout_cont_cls = rh;
1014   }
1015   else 
1016   {
1017     if (max_allowed_background_queries <=
1018         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
1019     {
1020       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
1021       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
1022       rh_heap_root->get_handle = NULL;
1023       rh_heap_root->dht_heap_node = NULL;
1024       
1025       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1026            "GNS_PHASE_REC-%d: Replacing oldest background query for %s\n",
1027                  rh->id, rh_heap_root->name);
1028       rh_heap_root->proc(rh_heap_root->proc_cls,
1029                          rh_heap_root,
1030                          0,
1031                          NULL);
1032     }
1033     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
1034                                          rh,
1035                                          GNUNET_TIME_absolute_get().abs_value);
1036   }
1037   
1038   xquery = htonl(rlh->record_type);
1039   
1040   GNUNET_assert(rh->get_handle == NULL);
1041   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
1042                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1043                        &lookup_key,
1044                        DHT_GNS_REPLICATION_LEVEL,
1045                        GNUNET_DHT_RO_NONE,
1046                        &xquery, 
1047                        sizeof(xquery),
1048                        &process_record_result_dht,
1049                        rh);
1050
1051 }
1052
1053
1054 /**
1055  * Namestore calls this function if we have record for this name.
1056  * (or with rd_count=0 to indicate no matches)
1057  *
1058  * @param cls the pending query
1059  * @param key the key of the zone we did the lookup
1060  * @param expiration expiration date of the namestore entry
1061  * @param name the name for which we need an authority
1062  * @param rd_count the number of records with 'name'
1063  * @param rd the record data
1064  * @param signature the signature of the authority for the record data
1065  */
1066 static void
1067 process_record_result_ns(void* cls,
1068                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1069                   struct GNUNET_TIME_Absolute expiration,
1070                   const char *name, unsigned int rd_count,
1071                   const struct GNUNET_NAMESTORE_RecordData *rd,
1072                   const struct GNUNET_CRYPTO_RsaSignature *signature)
1073 {
1074   struct ResolverHandle *rh;
1075   struct RecordLookupHandle *rlh;
1076   struct GNUNET_TIME_Relative remaining_time;
1077   struct GNUNET_CRYPTO_ShortHashCode zone;
1078
1079   rh = (struct ResolverHandle *) cls;
1080   rlh = (struct RecordLookupHandle *)rh->proc_cls;
1081   GNUNET_CRYPTO_short_hash(key,
1082                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1083                      &zone);
1084   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1085   
1086   
1087
1088   rh->status = 0;
1089   
1090   if (name != NULL)
1091   {
1092     rh->status |= RSL_RECORD_EXISTS;
1093   }
1094   
1095   if (remaining_time.rel_value == 0)
1096   {
1097     rh->status |= RSL_RECORD_EXPIRED;
1098   }
1099   
1100   if (rd_count == 0)
1101   {
1102     /**
1103      * Lookup terminated and no results
1104      */
1105     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1106       "GNS_PHASE_REC-%d: Namestore lookup for %s terminated without results\n",
1107          rh->id, name);
1108
1109     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1110                "GNS_PHASE_REC-%d: Record %s unknown in namestore\n",
1111                rh->id, rh->name);
1112     /**
1113      * Our zone and no result? Cannot resolve TT
1114      */
1115     rh->proc(rh->proc_cls, rh, 0, NULL);
1116     return;
1117
1118   }
1119   else
1120   {
1121     
1122     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1123            "GNS_PHASE_REC-%d: Processing additional result %s from namestore\n",
1124               rh->id, name);
1125     int i;
1126     for (i=0; i<rd_count;i++)
1127     {
1128
1129       if (rd[i].record_type != rlh->record_type)
1130         continue;
1131
1132       if (ignore_pending_records &&
1133           (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
1134       {
1135         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1136         "GNS_PHASE_REC-%d: Record %s is awaiting user confirmation. Skipping\n",
1137         rh->id, name);
1138         continue;
1139       }
1140       
1141       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1142           == 0)
1143       {
1144         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1145                    "GNS_PHASE_REC-%d: This record is expired. Skipping\n",
1146                    rh->id);
1147         continue;
1148       }
1149       
1150       rh->answered++;
1151       
1152     }
1153     
1154     /**
1155      * no answers found
1156      */
1157     if (rh->answered == 0)
1158     {
1159       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
1160                  "GNS_PHASE_REC-%d: No answers found. This is odd!\n", rh->id);
1161       rh->proc(rh->proc_cls, rh, 0, NULL);
1162       return;
1163     }
1164     
1165     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1166                "GNS_PHASE_REC-%d: Found %d answer(s) to query in %d records!\n",
1167                rh->id, rh->answered, rd_count);
1168
1169     rh->proc(rh->proc_cls, rh, rd_count, rd);
1170   }
1171 }
1172
1173
1174 /**
1175  * VPN redirect result callback
1176  *
1177  * @param cls the resolver handle
1178  * @param af the requested address family
1179  * @param address in_addr(6) respectively
1180  */
1181 static void
1182 process_record_result_vpn (void* cls, int af, const void *address)
1183 {
1184   struct ResolverHandle *rh = cls;
1185   struct RecordLookupHandle *rlh;
1186   struct GNUNET_NAMESTORE_RecordData rd;
1187
1188   rlh = (struct RecordLookupHandle *)rh->proc_cls;
1189
1190   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1191              "GNS_PHASE_REC_VPN-%d: Got answer from VPN to query!\n",
1192              rh->id);
1193   if (af == AF_INET)
1194   {
1195     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1196                "GNS_PHASE_REC-%d: Answer is IPv4!\n",
1197                rh->id);
1198     if (rlh->record_type != GNUNET_GNS_RECORD_TYPE_A)
1199     {
1200       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1201                  "GNS_PHASE_REC-%d: Requested record is not IPv4!\n",
1202                  rh->id);
1203       rh->proc (rh->proc_cls, rh, 0, NULL);
1204       return;
1205     }
1206     rd.record_type = GNUNET_GNS_RECORD_TYPE_A;
1207     rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
1208     rd.data = address;
1209     rd.data_size = sizeof (struct in_addr);
1210     rd.flags = 0;
1211     rh->proc (rh->proc_cls, rh, 1, &rd);
1212     return;
1213   }
1214   else if (af == AF_INET6)
1215   {
1216     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1217                "GNS_PHASE_REC-%d: Answer is IPv6!\n",
1218                rh->id);
1219     if (rlh->record_type != GNUNET_GNS_RECORD_AAAA)
1220     {
1221       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1222                  "GNS_PHASE_REC-%d: Requested record is not IPv6!\n",
1223                  rh->id);
1224       rh->proc (rh->proc_cls, rh, 0, NULL);
1225       return;
1226     }
1227     rd.record_type = GNUNET_GNS_RECORD_AAAA;
1228     rd.expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
1229     rd.data = address;
1230     rd.data_size = sizeof (struct in6_addr);
1231     rd.flags = 0;
1232     rh->proc (rh->proc_cls, rh, 1, &rd);
1233     return;
1234   }
1235   
1236   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1237              "GNS_PHASE_REC-%d: Got garbage from VPN!\n",
1238              rh->id);
1239   rh->proc (rh->proc_cls, rh, 0, NULL);
1240 }
1241
1242
1243 /**
1244  * finish lookup
1245  *
1246  * @param rh resolver handle
1247  * @param rlh record lookup handle
1248  * @param rd_cound number of results
1249  * @param rd results
1250  */
1251 static void
1252 finish_lookup(struct ResolverHandle *rh,
1253               struct RecordLookupHandle* rlh,
1254               unsigned int rd_count,
1255               const struct GNUNET_NAMESTORE_RecordData *rd);
1256
1257 /**
1258  * Process VPN lookup result for record
1259  *
1260  * @param cls the record lookup handle
1261  * @param rh resolver handle
1262  * @param rd_count number of results (1)
1263  * @param rd record data containing the result
1264  */
1265 static void
1266 handle_record_vpn (void* cls, struct ResolverHandle *rh,
1267                    unsigned int rd_count,
1268                    const struct GNUNET_NAMESTORE_RecordData *rd)
1269 {
1270   struct RecordLookupHandle* rlh = (struct RecordLookupHandle*) cls;
1271   
1272   if (rd_count == 0)
1273   {
1274     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1275                "GNS_PHASE_REC_VPN-%d: VPN returned no records. (status: %d)!\n",
1276                rh->id,
1277                rh->status);
1278     /* give up, cannot resolve */
1279     finish_lookup(rh, rlh, 0, NULL);
1280     free_resolver_handle(rh);
1281     return;
1282   }
1283
1284   /* results found yay */
1285   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1286              "GNS_PHASE_REC_VPN-%d: Record resolved from VPN!", rh->id);
1287
1288   finish_lookup(rh, rlh, rd_count, rd);
1289
1290   free_resolver_handle(rh);
1291 }
1292
1293
1294 /**
1295  * Sends a UDP dns query to a nameserver specified in the rh
1296  * 
1297  * @param rh the request handle
1298  */
1299 static void
1300 send_dns_packet (struct ResolverHandle *rh);
1301
1302
1303 static void
1304 read_dns_response (void *cls,
1305                    const struct GNUNET_SCHEDULER_TaskContext *tc)
1306 {
1307   struct ResolverHandle *rh = cls;
1308   struct RecordLookupHandle *rlh = rh->proc_cls;
1309   char buf[UINT16_MAX];
1310   ssize_t r;
1311   struct sockaddr_in addr;
1312   socklen_t addrlen;
1313   struct GNUNET_DNSPARSER_Packet *packet;
1314   struct GNUNET_NAMESTORE_RecordData rd;
1315   int found_delegation = GNUNET_NO;
1316   char* delegation_name = NULL;
1317   int i;
1318
1319   rh->dns_read_task = GNUNET_SCHEDULER_NO_TASK;
1320   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1321   {
1322     /* timeout or shutdown */
1323     rh->proc (rh->proc_cls, rh, 0, NULL);
1324     GNUNET_NETWORK_socket_close (rh->dns_sock);
1325     free_resolver_handle (rh);
1326     return;
1327   }
1328
1329   addrlen = sizeof (addr);
1330   r = GNUNET_NETWORK_socket_recvfrom (rh->dns_sock,
1331                                       buf, sizeof (buf),
1332                                       (struct sockaddr*) &addr,
1333                                       &addrlen);
1334
1335   if (-1 == r)
1336   {
1337     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
1338     rh->proc (rh->proc_cls, rh, 0, NULL);
1339     GNUNET_NETWORK_socket_close (rh->dns_sock);
1340     free_resolver_handle (rh);
1341     return;
1342   }
1343
1344   packet = GNUNET_DNSPARSER_parse (buf, r);
1345   
1346   if (NULL == packet)
1347   {
1348     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1349                 "Failed to parse DNS reply!\n");
1350     rh->proc (rh->proc_cls, rh, 0, NULL);
1351     GNUNET_NETWORK_socket_close (rh->dns_sock);
1352     free_resolver_handle (rh);
1353     return;
1354   }
1355
1356   for (i = 0; i < packet->num_answers; i++)
1357   {
1358     if ((packet->answers[i].type == rlh->record_type) &&
1359         (0 == strcmp (packet->answers[i].name, rh->dns_name)))
1360     {
1361       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1362                   "Found record!\n");
1363       rd.data = packet->answers[i].data.raw.data;
1364       rd.data_size = packet->answers[i].data.raw.data_len;
1365       rd.record_type = packet->answers[i].type;
1366       rd.flags = 0;
1367       rd.expiration = packet->answers[i].expiration_time;
1368       rh->proc (rh->proc_cls, rh, 1, &rd);
1369       GNUNET_NETWORK_socket_close (rh->dns_sock);
1370       GNUNET_DNSPARSER_free_packet (packet);
1371       free_resolver_handle (rh);
1372       return;
1373     }
1374   }
1375
1376   for (i = 0; i < packet->num_authority_records; i++)
1377   {
1378     if (packet->authority_records[i].type == GNUNET_GNS_RECORD_TYPE_NS)
1379     {
1380       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1381                   "Found NS delegation!\n");
1382       found_delegation = GNUNET_YES;
1383       delegation_name = packet->authority_records[i].data.hostname;
1384       break;
1385     }
1386   }
1387
1388   for (i = 0; i < packet->num_additional_records; i++)
1389   {
1390     if (found_delegation == GNUNET_NO)
1391       break;
1392
1393     if ((packet->additional_records[i].type == GNUNET_GNS_RECORD_TYPE_A) &&
1394         (0 == strcmp (packet->additional_records[i].name, delegation_name)))
1395     {
1396       GNUNET_assert (sizeof (struct in_addr) ==
1397                      packet->authority_records[i].data.raw.data_len);
1398       
1399       rh->dns_addr.sin_addr =
1400         *((struct in_addr*)packet->authority_records[i].data.raw.data);
1401       send_dns_packet (rh);
1402       GNUNET_DNSPARSER_free_packet (packet);
1403       return;
1404     }
1405   }
1406
1407   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1408               "Failed to parse DNS reply!\n");
1409   rh->proc (rh->proc_cls, rh, 0, NULL);
1410   GNUNET_NETWORK_socket_close (rh->dns_sock);
1411   free_resolver_handle (rh);
1412   GNUNET_DNSPARSER_free_packet (packet);
1413   return;
1414 }
1415
1416 /**
1417  * Sends a UDP dns query to a nameserver specified in the rh
1418  * 
1419  * @param rh the request handle
1420  */
1421 static void
1422 send_dns_packet (struct ResolverHandle *rh)
1423 {
1424   struct GNUNET_NETWORK_FDSet *rset = GNUNET_NETWORK_fdset_create ();
1425   GNUNET_NETWORK_fdset_set (rset, rh->dns_sock);
1426   
1427   GNUNET_NETWORK_socket_sendto (rh->dns_sock,
1428                                 rh->dns_raw_packet,
1429                                 rh->dns_raw_packet_size,
1430                                 (struct sockaddr*)&rh->dns_addr,
1431                                 sizeof (struct sockaddr_in));
1432
1433   rh->dns_read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1434                                                     rh->timeout, //FIXME less?
1435                                                     rset,
1436                                                     NULL,
1437                                                     &read_dns_response,
1438                                                     rh);
1439
1440   GNUNET_NETWORK_fdset_destroy (rset);
1441
1442 }
1443
1444 /**
1445  * The final phase of resoution.
1446  * We found a NS RR and want to resolve via DNS
1447  *
1448  * @param rh the pending lookup handle
1449  * @param rd_count length of record data
1450  * @param rd record data containing VPN RR
1451  */
1452 static void
1453 resolve_record_dns (struct ResolverHandle *rh,
1454                     int rd_count,
1455                     const struct GNUNET_NAMESTORE_RecordData *rd)
1456 {
1457   struct GNUNET_DNSPARSER_Query query;
1458   struct GNUNET_DNSPARSER_Packet packet;
1459   struct GNUNET_DNSPARSER_Flags flags;
1460   char dns_name[MAX_DNS_NAME_LENGTH];
1461   struct in_addr dnsip;
1462   struct sockaddr_in addr;
1463   struct sockaddr *sa;
1464   int i;
1465   struct RecordLookupHandle *rlh = rh->proc_cls;
1466   
1467   /* We cancel here as to not include the ns lookup in the timeout */
1468   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1469   {
1470     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1471     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1472   }
1473   /* Start shortening */
1474   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1475   {
1476     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1477              "GNS_PHASE_REC_DNS-%llu: Trying to shorten authority chain\n",
1478              rh->id);
1479              start_shorten (rh->authority_chain_tail,
1480              rh->priv_key);
1481   }
1482
1483   for (i = 0; i < rd_count; i++)
1484   {
1485     /* Synthesize dns name */
1486     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_NS)
1487       sprintf (rh->dns_name, "%s.%s", rh->name, (char*)rd[i].data);
1488     /* The glue */
1489     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A)
1490       dnsip = *((struct in_addr*)rd[i].data);
1491   }
1492   
1493   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1494               "GNS_PHASE_REC_DNS-%llu: Looking up %s from %s\n",
1495               dns_name,
1496               inet_ntoa (dnsip));
1497   rh->dns_sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
1498   if (rh->dns_sock == NULL)
1499   {
1500     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1501                 "GNS_PHASE_REC_DNS-%llu: Error creating udp socket for dns!\n",
1502                 rh->id);
1503     rh->proc(rh->proc_cls, rh, 0, NULL);
1504     return;
1505   }
1506
1507   memset (&addr, 0, sizeof (struct sockaddr_in));
1508   sa = (struct sockaddr *) &addr;
1509   sa->sa_family = AF_INET;
1510   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (rh->dns_sock,
1511                                                sa,
1512                                                sizeof (struct sockaddr_in)))
1513   {
1514     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1515                 "GNS_PHASE_REC_DNS-%llu: Error binding udp socket for dns!\n",
1516                 rh->id);
1517     GNUNET_NETWORK_socket_close (rh->dns_sock);
1518     rh->proc(rh->proc_cls, rh, 0, NULL);
1519     return;
1520   }
1521   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1522               "GNS_PHASE_REC_DNS-%llu: NOT IMPLEMENTED!\n",
1523               rh->id);
1524   GNUNET_NETWORK_socket_close (rh->dns_sock);
1525   rh->proc(rh->proc_cls, rh, 0, NULL);
1526   /*TODO create dnsparser query, serialize, sendto, handle reply*/
1527   query.name = dns_name;
1528   query.type = rlh->record_type;
1529   query.class = GNUNET_DNSPARSER_CLASS_INTERNET;
1530   memset (&flags, 0, sizeof (flags));
1531   flags.recursion_desired = 1;
1532   flags.checking_disabled = 1;
1533   packet.queries = &query;
1534   packet.answers = NULL;
1535   packet.authority_records = NULL;
1536   packet.num_queries = 1;
1537   packet.num_answers = 0;
1538   packet.num_authority_records = 0;
1539   packet.num_additional_records = 0;
1540   packet.flags = flags;
1541   packet.id = rh->id;
1542   if (GNUNET_OK != GNUNET_DNSPARSER_pack (&packet,
1543                                           UINT16_MAX,
1544                                           &rh->dns_raw_packet,
1545                                           &rh->dns_raw_packet_size))
1546   {
1547     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1548                 "GNS_PHASE_REC_DNS-%llu: Creating raw dns packet!\n",
1549                 rh->id);
1550     GNUNET_NETWORK_socket_close (rh->dns_sock);
1551     rh->proc(rh->proc_cls, rh, 0, NULL);
1552     return;
1553   }
1554
1555   rh->dns_addr.sin_family = AF_INET;
1556   rh->dns_addr.sin_port = htons (53); //domain
1557   rh->dns_addr.sin_addr = dnsip;
1558 #if HAVE_SOCKADDR_IN_SIN_LEN
1559   rh->dns_addr.sin_len = (u_char) sizeof (struct sockaddr_in);
1560 #endif
1561
1562   send_dns_packet (rh);
1563   
1564   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1565               "GNS_PHASE_REC_DNS-%llu: NOT IMPLEMENTED!\n",
1566               rh->id);
1567   GNUNET_free (rh->dns_raw_packet);
1568   GNUNET_NETWORK_socket_close (rh->dns_sock);
1569   rh->proc(rh->proc_cls, rh, 0, NULL);
1570 }
1571
1572
1573 /**
1574  * The final phase of resoution.
1575  * We found a VPN RR and want to request an IPv4/6 address
1576  *
1577  * @param rh the pending lookup handle
1578  * @param rd_count length of record data
1579  * @param rd record data containing VPN RR
1580  */
1581 static void
1582 resolve_record_vpn (struct ResolverHandle *rh,
1583                     int rd_count,
1584                     const struct GNUNET_NAMESTORE_RecordData *rd)
1585 {
1586   int af;
1587   int proto;
1588   struct GNUNET_HashCode peer_id;
1589   struct GNUNET_CRYPTO_HashAsciiEncoded s_pid;
1590   struct GNUNET_HashCode serv_desc;
1591   struct GNUNET_CRYPTO_HashAsciiEncoded s_sd;
1592   
1593   /* We cancel here as to not include the ns lookup in the timeout */
1594   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1595   {
1596     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1597     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1598   }
1599   /* Start shortening */
1600   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1601   {
1602     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1603              "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1604              rh->id);
1605              start_shorten (rh->authority_chain_tail,
1606              rh->priv_key);
1607   }
1608
1609   /* Extracting VPN information FIXME rd parsing with NS API?*/
1610   if (4 != SSCANF ((char*)rd, "%d:%d:%s:%s", &af, &proto,
1611                    (char*)&s_pid, (char*)&s_sd))
1612   {
1613     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1614                 "GNS_PHASE_REC_VPN-%llu: Error parsing VPN RR!\n",
1615                 rh->id);
1616     rh->proc(rh->proc_cls, rh, 0, NULL);
1617     return;
1618   }
1619
1620   if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char*)&s_pid, &peer_id)) ||
1621       (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char*)&s_sd, &serv_desc)))
1622   {
1623     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1624                 "GNS_PHASE_REC_VPN-%llu: Error parsing VPN RR hashes!\n",
1625                 rh->id);
1626     rh->proc(rh->proc_cls, rh, 0, NULL);
1627     return;
1628   }
1629
1630   rh->proc = &handle_record_vpn;
1631   
1632   //FIXME timeout??
1633   rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1634                                           af, proto,
1635                                           (struct GNUNET_PeerIdentity*)&peer_id,
1636                                           &serv_desc,
1637                                           GNUNET_NO, //nac
1638                                           GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1639                                           &process_record_result_vpn,
1640                                           rh);
1641
1642 }
1643
1644 /**
1645  * The final phase of resolution.
1646  * rh->name is a name that is canonical and we do not have a delegation.
1647  * Query namestore for this record
1648  *
1649  * @param rh the pending lookup handle
1650  */
1651 static void
1652 resolve_record_ns(struct ResolverHandle *rh)
1653 {
1654   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
1655   
1656   /* We cancel here as to not include the ns lookup in the timeout */
1657   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1658   {
1659     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1660     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1661   }
1662   /* Start shortening */
1663   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1664   {
1665     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1666              "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1667              rh->id);
1668              start_shorten (rh->authority_chain_tail,
1669              rh->priv_key);
1670   }
1671   
1672   /**
1673    * Try to resolve this record in our namestore.
1674    * The name to resolve is now in rh->authority_name
1675    * since we tried to resolve it to an authority
1676    * and failed.
1677    **/
1678   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1679                                  &rh->authority,
1680                                  rh->name,
1681                                  rlh->record_type,
1682                                  &process_record_result_ns,
1683                                  rh);
1684 }
1685
1686
1687
1688 /**
1689  * Handle timeout for DHT requests
1690  *
1691  * @param cls the request handle as closure
1692  * @param tc the task context
1693  */
1694 static void
1695 dht_authority_lookup_timeout(void *cls,
1696                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1697 {
1698   struct ResolverHandle *rh = cls;
1699   struct RecordLookupHandle *rlh = rh->proc_cls;
1700   char new_name[MAX_DNS_NAME_LENGTH];
1701
1702   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1703          "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%ds)timed out.\n",
1704          rh->id, rh->authority_name, rh->timeout.rel_value);
1705
1706   rh->status |= RSL_TIMED_OUT;
1707
1708   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1709   
1710   GNUNET_DHT_get_stop (rh->get_handle);
1711   rh->get_handle = NULL;
1712   
1713   if (strcmp(rh->name, "") == 0)
1714   {
1715     /*
1716      * promote authority back to name and try to resolve record
1717      */
1718     strcpy(rh->name, rh->authority_name);
1719     rh->proc(rh->proc_cls, rh, 0, NULL);
1720     return;
1721   }
1722   
1723   /**
1724    * Start resolution in bg
1725    */
1726   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1727                   "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD);
1728   //strcpy(new_name, rh->name);
1729   //strcpy(new_name+strlen(new_name), ".");
1730   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1731   
1732   strcpy(rh->name, new_name);
1733
1734   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1735         "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
1736         rh->id, rh->name, rlh->record_type);
1737
1738   gns_resolver_lookup_record(rh->authority,
1739                              rh->private_local_zone,
1740                              rlh->record_type,
1741                              new_name,
1742                              rh->priv_key,
1743                              GNUNET_TIME_UNIT_FOREVER_REL,
1744                              GNUNET_NO,
1745                              &background_lookup_result_processor,
1746                              NULL);
1747
1748   rh->proc(rh->proc_cls, rh, 0, NULL);
1749 }
1750
1751 /* Prototype */
1752 static void resolve_delegation_dht(struct ResolverHandle *rh);
1753
1754 /* Prototype */
1755 static void resolve_delegation_ns(struct ResolverHandle *rh);
1756
1757
1758 /**
1759  * Namestore resolution for delegation finished. Processing result.
1760  *
1761  * @param cls the closure
1762  * @param rh resolver handle
1763  * @param rd_count number of results (always 0)
1764  * @param rd record data (always NULL)
1765  */
1766 static void
1767 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1768                           unsigned int rd_count,
1769                           const struct GNUNET_NAMESTORE_RecordData *rd);
1770
1771
1772 /**
1773  * Function called when we get a result from the dht
1774  * for our query. Recursively tries to resolve authorities
1775  * for name in DHT.
1776  *
1777  * @param cls the request handle
1778  * @param exp lifetime
1779  * @param key the key the record was stored under
1780  * @param get_path get path
1781  * @param get_path_length get path length
1782  * @param put_path put path
1783  * @param put_path_length put path length
1784  * @param type the block type
1785  * @param size the size of the record
1786  * @param data the record data
1787  */
1788 static void
1789 process_delegation_result_dht(void* cls,
1790                  struct GNUNET_TIME_Absolute exp,
1791                  const struct GNUNET_HashCode * key,
1792                  const struct GNUNET_PeerIdentity *get_path,
1793                  unsigned int get_path_length,
1794                  const struct GNUNET_PeerIdentity *put_path,
1795                  unsigned int put_path_length,
1796                  enum GNUNET_BLOCK_Type type,
1797                  size_t size, const void *data)
1798 {
1799   struct ResolverHandle *rh;
1800   struct GNSNameRecordBlock *nrb;
1801   uint32_t num_records;
1802   char* name = NULL;
1803   char* rd_data = (char*) data;
1804   int i;
1805   int rd_size;
1806   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
1807   struct GNUNET_HashCode zone_hash_double, name_hash_double;
1808
1809   rh = (struct ResolverHandle *)cls;
1810   
1811   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1812              "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id);
1813
1814   if (data == NULL)
1815     return;
1816   
1817   nrb = (struct GNSNameRecordBlock*)data;
1818   
1819   /* stop dht lookup and timeout task */
1820   GNUNET_DHT_get_stop (rh->get_handle);
1821
1822   rh->get_handle = NULL;
1823
1824   if (rh->dht_heap_node != NULL)
1825   {
1826     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
1827     rh->dht_heap_node = NULL;
1828   }
1829
1830   num_records = ntohl(nrb->rd_count);
1831   name = (char*)&nrb[1];
1832   {
1833     struct GNUNET_NAMESTORE_RecordData rd[num_records];
1834     
1835     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
1836     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
1837   
1838     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
1839                                                                rd_data,
1840                                                                num_records,
1841                                                                rd))
1842     {
1843       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
1844                  "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
1845                  rh->id);
1846       return;
1847     }
1848
1849     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1850                "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1851                rh->id, name, rh->authority_name);
1852     for (i=0; i<num_records; i++)
1853     {
1854     
1855       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1856                 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
1857                 rh->id, name, rh->authority_name);
1858       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1859                  "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
1860                  rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
1861       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1862                  "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
1863                  rh->id, rd[i].data_size);
1864       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1865                  "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
1866                  rh->id, rd[i].flags);
1867
1868       if ((strcmp(name, rh->authority_name) == 0) &&
1869           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
1870       {
1871         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1872                    "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
1873                    rh->id);
1874         rh->answered = 1;
1875         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1876         struct AuthorityChain *auth =
1877           GNUNET_malloc(sizeof(struct AuthorityChain));
1878         auth->zone = rh->authority;
1879         memset(auth->name, 0, strlen(rh->authority_name)+1);
1880         strcpy(auth->name, rh->authority_name);
1881         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1882                                      rh->authority_chain_tail,
1883                                      auth);
1884
1885         /** try to import pkey if private key available */
1886         //if (rh->priv_key && is_canonical (rh->name))
1887         //  process_discovered_authority(name, auth->zone,
1888         //                               rh->authority_chain_tail->zone,
1889         //                               rh->priv_key);
1890       }
1891
1892     }
1893
1894
1895     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
1896     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1897     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
1898     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
1899
1900     /* Save to namestore */
1901     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
1902                                           &zone))
1903     {
1904       GNUNET_NAMESTORE_record_put (namestore_handle,
1905                                  &nrb->public_key,
1906                                  name,
1907                                  exp,
1908                                  num_records,
1909                                  rd,
1910                                  &nrb->signature,
1911                                  &on_namestore_record_put_result, //cont
1912                                  NULL); //cls
1913     }
1914   }
1915   
1916   if (rh->answered)
1917   {
1918     rh->answered = 0;
1919     /**
1920      * delegate
1921      * FIXME in this case. should we ask namestore again?
1922      */
1923     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1924       "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
1925       rh->id, rh->authority_name, rh->name);
1926     
1927     if (strcmp(rh->name, "") == 0)
1928     {
1929       /* Start shortening */
1930       if ((rh->priv_key != NULL) && is_canonical (rh->name))
1931       {
1932         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1933              "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
1934              rh->id);
1935         start_shorten (rh->authority_chain_tail,
1936                        rh->priv_key);
1937       }
1938       
1939       rh->proc(rh->proc_cls, rh, 0, NULL);
1940     }
1941     else
1942     {
1943       rh->proc = &handle_delegation_ns;
1944       resolve_delegation_ns(rh);
1945     }
1946     return;
1947   }
1948   
1949   /**
1950    * No pkey but name exists
1951    * promote back
1952    */
1953   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1954              "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
1955              rh->id, rh->authority_name, rh->name);
1956   if (strcmp(rh->name, "") == 0)
1957     strcpy(rh->name, rh->authority_name);
1958   else
1959     GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
1960                   rh->name, rh->authority_name); //FIXME ret
1961   
1962   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1963              "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
1964   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1965            "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
1966            rh->id);
1967   rh->proc(rh->proc_cls, rh, 0, NULL);
1968 }
1969
1970 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
1971                         +(MAX_DNS_NAME_LENGTH*2)
1972 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
1973
1974
1975 static void
1976 expand_plus(char** dest, char* src, char* repl)
1977 {
1978   char* pos;
1979   unsigned int s_len = strlen(src)+1;
1980
1981   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1982              "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
1983
1984   if (s_len < 3)
1985   {
1986     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1987                "GNS_POSTPROCESS: %s to short\n", src);
1988
1989     /* no postprocessing */
1990     memcpy(*dest, src, s_len+1);
1991     return;
1992   }
1993   
1994   if (0 == strcmp(src+s_len-3, ".+"))
1995   {
1996     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1997                "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
1998     memset(*dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
1999     strcpy(*dest, src);
2000     pos = *dest+s_len-2;
2001     strcpy(pos, repl);
2002     pos += strlen(repl);
2003     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2004                "GNS_POSTPROCESS: Expanded to %s\n", *dest);
2005   }
2006   else
2007   {
2008     memcpy(*dest, src, s_len+1);
2009   }
2010 }
2011
2012 /**
2013  * finish lookup
2014  */
2015 static void
2016 finish_lookup(struct ResolverHandle *rh,
2017               struct RecordLookupHandle* rlh,
2018               unsigned int rd_count,
2019               const struct GNUNET_NAMESTORE_RecordData *rd)
2020 {
2021   int i;
2022   char new_rr_data[MAX_DNS_NAME_LENGTH];
2023   char new_mx_data[MAX_MX_LENGTH];
2024   char new_soa_data[MAX_SOA_LENGTH];
2025   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
2026   char* repl_string;
2027   char* pos;
2028   unsigned int offset;
2029
2030   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2031   {
2032     GNUNET_SCHEDULER_cancel(rh->timeout_task);
2033     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2034   }
2035
2036   if (rd_count > 0)
2037     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
2038
2039   for (i = 0; i < rd_count; i++)
2040   {
2041     
2042     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
2043         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
2044         rd[i].record_type != GNUNET_GNS_RECORD_MX &&
2045         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA)
2046     {
2047       p_rd[i].data = rd[i].data;
2048       continue;
2049     }
2050
2051     /**
2052      * for all those records we 'should'
2053      * also try to resolve the A/AAAA records (RFC1035)
2054      * This is a feature and not important
2055      */
2056     
2057     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2058                "GNS_POSTPROCESS: Postprocessing\n");
2059
2060     if (strcmp(rh->name, "+") == 0)
2061       repl_string = rlh->name;
2062     else
2063       repl_string = rlh->name+strlen(rh->name)+1;
2064
2065     offset = 0;
2066     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
2067     {
2068       memcpy(new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
2069       offset = sizeof(uint16_t);
2070       pos = new_mx_data+offset;
2071       expand_plus(&pos, (char*)rd[i].data+sizeof(uint16_t),
2072                   repl_string);
2073       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
2074       p_rd[i].data = new_mx_data;
2075       p_rd[i].data_size = offset;
2076     }
2077     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
2078     {
2079       /* expand mname and rname */
2080       pos = new_soa_data;
2081       expand_plus(&pos, (char*)rd[i].data, repl_string);
2082       offset = strlen(new_soa_data)+1;
2083       pos = new_soa_data+offset;
2084       expand_plus(&pos, (char*)rd[i].data+offset, repl_string);
2085       offset += strlen(new_soa_data+offset)+1;
2086       /* cpy the 4 numbers serial refresh retry and expire */
2087       memcpy(new_soa_data+offset, (char*)rd[i].data+offset, sizeof(uint32_t)*5);
2088       offset += sizeof(uint32_t)*5;
2089       p_rd[i].data_size = offset;
2090       p_rd[i].data = new_soa_data;
2091     }
2092     else
2093     {
2094       pos = new_rr_data;
2095       expand_plus(&pos, (char*)rd[i].data, repl_string);
2096       p_rd[i].data_size = strlen(new_rr_data)+1;
2097       p_rd[i].data = new_rr_data;
2098     }
2099     
2100   }
2101
2102   rlh->proc(rlh->proc_cls, rd_count, p_rd);
2103   GNUNET_free(rlh);
2104   
2105 }
2106
2107 /**
2108  * Process DHT lookup result for record.
2109  *
2110  * @param cls the closure
2111  * @param rh resolver handle
2112  * @param rd_count number of results
2113  * @param rd record data
2114  */
2115 static void
2116 handle_record_dht(void* cls, struct ResolverHandle *rh,
2117                        unsigned int rd_count,
2118                        const struct GNUNET_NAMESTORE_RecordData *rd)
2119 {
2120   struct RecordLookupHandle* rlh;
2121
2122   rlh = (struct RecordLookupHandle*)cls;
2123   if (rd_count == 0)
2124   {
2125     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2126                "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n",
2127                rh->id, rh->name);
2128     /* give up, cannot resolve */
2129     finish_lookup(rh, rlh, 0, NULL);
2130     free_resolver_handle(rh);
2131     return;
2132   }
2133
2134   /* results found yay */
2135   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2136              "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id);
2137
2138   finish_lookup(rh, rlh, rd_count, rd);
2139   free_resolver_handle(rh);
2140
2141 }
2142
2143
2144
2145
2146 /**
2147  * Process namestore lookup result for record.
2148  *
2149  * @param cls the closure
2150  * @param rh resolver handle
2151  * @param rd_count number of results
2152  * @param rd record data
2153  */
2154 static void
2155 handle_record_ns (void* cls, struct ResolverHandle *rh,
2156                   unsigned int rd_count,
2157                   const struct GNUNET_NAMESTORE_RecordData *rd)
2158 {
2159   struct RecordLookupHandle* rlh;
2160   rlh = (struct RecordLookupHandle*) cls;
2161   if (rd_count == 0)
2162   {
2163     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2164                "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n",
2165                rh->id,
2166                rh->status);
2167     
2168     /**
2169      * There are 5 conditions that have to met for us to consult the DHT:
2170      * 1. The entry in the DHT is RSL_RECORD_EXPIRED AND
2171      * 2. No entry in the NS existed AND
2172      * 3. The zone queried is not the local resolver's zone AND
2173      * 4. The name that was looked up is '+'
2174      *    because if it was any other canonical name we either already queried
2175      *    the DHT for the authority in the authority lookup phase (and thus
2176      *    would already have an entry in the NS for the record)
2177      * 5. We are not in cache only mode
2178      */
2179     if (rh->status & (RSL_RECORD_EXPIRED | !RSL_RECORD_EXISTS) &&
2180         GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2181                                      &rh->private_local_zone) &&
2182         (strcmp(rh->name, "+") == 0) &&
2183         (rh->only_cached == GNUNET_NO))
2184     {
2185       rh->proc = &handle_record_dht;
2186       resolve_record_dht(rh);
2187       return;
2188     }
2189     /* give up, cannot resolve */
2190     finish_lookup(rh, rlh, 0, NULL);
2191     free_resolver_handle(rh);
2192     return;
2193   }
2194
2195   /* results found yay */
2196   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2197              "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id);
2198
2199   finish_lookup(rh, rlh, rd_count, rd);
2200
2201   free_resolver_handle(rh);
2202
2203 }
2204
2205
2206 /**
2207  * Move one level up in the domain hierarchy and return the
2208  * passed top level domain.
2209  *
2210  * @param name the domain
2211  * @param dest the destination where the tld will be put
2212  */
2213 void
2214 pop_tld(char* name, char* dest)
2215 {
2216   uint32_t len;
2217
2218   if (is_canonical(name))
2219   {
2220     strcpy(dest, name);
2221     strcpy(name, "");
2222     return;
2223   }
2224
2225   for (len = strlen(name); len > 0; len--)
2226   {
2227     if (*(name+len) == '.')
2228       break;
2229   }
2230   
2231   //Was canonical?
2232   if (len == 0)
2233     return;
2234
2235   name[len] = '\0';
2236
2237   strcpy(dest, (name+len+1));
2238 }
2239
2240 /**
2241  * Checks if name is in tld
2242  *
2243  * @param name the name to check
2244  * @param tld the TLD to check for
2245  * @return GNUNET_YES or GNUNET_NO
2246  */
2247 int
2248 is_tld(const char* name, const char* tld)
2249 {
2250   int offset = 0;
2251
2252   if (strlen(name) <= strlen(tld))
2253   {
2254     return GNUNET_NO;
2255   }
2256   
2257   offset = strlen(name)-strlen(tld);
2258   if (strcmp(name+offset, tld) != 0)
2259   {
2260     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2261                "%s is not in .%s TLD\n", name, tld);
2262     return GNUNET_NO;
2263   }
2264   return GNUNET_YES;
2265 }
2266
2267 /**
2268  * DHT resolution for delegation finished. Processing result.
2269  *
2270  * @param cls the closure
2271  * @param rh resolver handle
2272  * @param rd_count number of results (always 0)
2273  * @param rd record data (always NULL)
2274  */
2275 static void
2276 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
2277                           unsigned int rd_count,
2278                           const struct GNUNET_NAMESTORE_RecordData *rd)
2279 {
2280   struct RecordLookupHandle* rlh;
2281   rlh = (struct RecordLookupHandle*) cls;
2282   
2283
2284   if (strcmp(rh->name, "") == 0)
2285   {
2286     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
2287     {
2288       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2289                  "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
2290                  rh->id);
2291       finish_lookup(rh, rlh, rd_count, rd);
2292       free_resolver_handle(rh);
2293       return;
2294     }
2295     /* We resolved full name for delegation. resolving record */
2296     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2297      "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
2298      rh->id);
2299     strcpy(rh->name, "+\0");
2300     rh->proc = &handle_record_ns;
2301     resolve_record_ns(rh);
2302     return;
2303   }
2304
2305   /**
2306    * we still have some left
2307    **/
2308   if (is_canonical(rh->name))
2309   {
2310     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2311              "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
2312              rh->id,
2313              rh->name);
2314     rh->proc = &handle_record_ns;
2315     resolve_record_ns(rh);
2316     return;
2317   }
2318   /* give up, cannot resolve */
2319   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2320  "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
2321  rh->id, rh->name);
2322   finish_lookup(rh, rlh, 0, NULL);
2323   free_resolver_handle(rh);
2324 }
2325
2326
2327 /**
2328  * Start DHT lookup for a name -> PKEY (compare NS) record in
2329  * rh->authority's zone
2330  *
2331  * @param rh the pending gns query
2332  */
2333 static void
2334 resolve_delegation_dht(struct ResolverHandle *rh)
2335 {
2336   uint32_t xquery;
2337   struct GNUNET_CRYPTO_ShortHashCode name_hash;
2338   struct GNUNET_HashCode name_hash_double;
2339   struct GNUNET_HashCode zone_hash_double;
2340   struct GNUNET_HashCode lookup_key;
2341   struct ResolverHandle *rh_heap_root;
2342   
2343   pop_tld(rh->name, rh->authority_name); 
2344   GNUNET_CRYPTO_short_hash(rh->authority_name,
2345                      strlen(rh->authority_name),
2346                      &name_hash);
2347   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
2348   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
2349   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
2350   
2351   rh->dht_heap_node = NULL;
2352
2353   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2354   {
2355     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
2356     //                                          &dht_authority_lookup_timeout,
2357     //                                                   rh);
2358     rh->timeout_cont = &dht_authority_lookup_timeout;
2359     rh->timeout_cont_cls = rh;
2360   }
2361   else 
2362   {
2363     if (max_allowed_background_queries <=
2364         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
2365     {
2366       /* terminate oldest lookup */
2367       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2368       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
2369       rh_heap_root->dht_heap_node = NULL;
2370       
2371       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2372         "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
2373         rh->id, rh_heap_root->authority_name);
2374       
2375       rh_heap_root->proc(rh_heap_root->proc_cls,
2376                          rh_heap_root,
2377                          0,
2378                          NULL);
2379     }
2380     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2381                                          rh,
2382                                          GNUNET_TIME_absolute_get().abs_value);
2383   }
2384   
2385   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
2386   
2387   GNUNET_assert(rh->get_handle == NULL);
2388   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
2389                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2390                        &lookup_key,
2391                        DHT_GNS_REPLICATION_LEVEL,
2392                        GNUNET_DHT_RO_NONE,
2393                        &xquery,
2394                        sizeof(xquery),
2395                        &process_delegation_result_dht,
2396                        rh);
2397
2398 }
2399
2400
2401 /**
2402  * Namestore resolution for delegation finished. Processing result.
2403  *
2404  * @param cls the closure
2405  * @param rh resolver handle
2406  * @param rd_count number of results (always 0)
2407  * @param rd record data (always NULL)
2408  */
2409 static void
2410 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
2411                           unsigned int rd_count,
2412                           const struct GNUNET_NAMESTORE_RecordData *rd)
2413 {
2414   struct RecordLookupHandle* rlh;
2415   rlh = (struct RecordLookupHandle*) cls;
2416
2417   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2418              "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
2419              rh->id, rh->status);
2420   
2421   if (strcmp(rh->name, "") == 0)
2422   {
2423     if (rlh->record_type == GNUNET_GNS_RECORD_PKEY)
2424     {
2425       GNUNET_assert(rd_count == 1);
2426       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2427                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
2428                  rh->id);
2429       finish_lookup(rh, rlh, rd_count, rd);
2430       free_resolver_handle(rh);
2431       return;
2432     }
2433     /* We resolved full name for delegation. resolving record */
2434     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2435               "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
2436               rh->id);
2437
2438     if (rh->status & RSL_DELEGATE_VPN)
2439     {
2440       if (rlh->record_type == GNUNET_GNS_RECORD_VPN)
2441       {
2442         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2443                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried VPNRR in NS.\n",
2444                  rh->id);
2445         finish_lookup(rh, rlh, rd_count, rd);
2446         free_resolver_handle(rh);
2447         return;
2448       }
2449       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2450              "GNS_PHASE_DELEGATE_NS-%llu: VPN delegation starting.\n",
2451              rh->id);
2452       GNUNET_assert (NULL != rd);
2453       rh->proc = &handle_record_vpn;
2454       resolve_record_vpn (rh, rd_count, rd);
2455     }
2456     else if (rh->status & RSL_DELEGATE_NS)
2457     {
2458       if (rlh->record_type == GNUNET_GNS_RECORD_TYPE_NS)
2459       {
2460         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2461                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2462                    rh->id);
2463         finish_lookup(rh, rlh, rd_count, rd);
2464         free_resolver_handle(rh);
2465         return;
2466       }
2467       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2468                  "GNS_PHASE_DELEGATE_NS-%llu: VPN delegation starting.\n",
2469                  rh->id);
2470       GNUNET_assert (NULL != rd);
2471       rh->proc = &handle_record_ns;
2472       resolve_record_dns (rh, rd_count, rd);
2473     }
2474     else
2475     {
2476       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2477                  "GNS_PHASE_DELEGATE_NS-%llu: Resolving record +\n",
2478                  rh->id);
2479       strcpy(rh->name, "+\0");
2480       rh->proc = &handle_record_ns;
2481       resolve_record_ns(rh);
2482     }
2483     return;
2484   }
2485
2486   /**
2487    * we still have some left
2488    * check if authority in ns is fresh
2489    * and exists
2490    * or we are authority
2491    **/
2492   if (((rh->status & RSL_RECORD_EXISTS) && (!(rh->status & RSL_RECORD_EXPIRED)))
2493       || !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2494                                        &rh->private_local_zone))
2495   {
2496     if (is_canonical(rh->name))
2497     {
2498       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2499                  "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
2500                  rh->id,
2501                  rh->name);
2502       rh->proc = &handle_record_ns;
2503       resolve_record_ns(rh);
2504     }
2505     else
2506     {
2507       /* give up, cannot resolve */
2508       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2509           "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
2510           rh->id,
2511           rh->name);
2512       finish_lookup(rh, rlh, rd_count, rd);
2513       //rlh->proc(rlh->proc_cls, 0, NULL);
2514     }
2515     return;
2516   }
2517
2518   if (rh->only_cached == GNUNET_YES)
2519   {
2520     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2521                "GNS_PHASE_DELEGATE_NS-%llu: Only cache resolution, no result\n",
2522                rh->id, rh->name);
2523     finish_lookup(rh, rlh, rd_count, rd);
2524     return;
2525   }
2526   
2527   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2528       "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
2529       rh->id, rh->name);
2530   rh->proc = &handle_delegation_dht;
2531   resolve_delegation_dht(rh);
2532 }
2533
2534
2535
2536 /**
2537  * This is a callback function that should give us only PKEY
2538  * records. Used to query the namestore for the authority (PKEY)
2539  * for 'name'. It will recursively try to resolve the
2540  * authority for a given name from the namestore.
2541  *
2542  * @param cls the pending query
2543  * @param key the key of the zone we did the lookup
2544  * @param expiration expiration date of the record data set in the namestore
2545  * @param name the name for which we need an authority
2546  * @param rd_count the number of records with 'name'
2547  * @param rd the record data
2548  * @param signature the signature of the authority for the record data
2549  */
2550 static void
2551 process_delegation_result_ns(void* cls,
2552                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
2553                    struct GNUNET_TIME_Absolute expiration,
2554                    const char *name,
2555                    unsigned int rd_count,
2556                    const struct GNUNET_NAMESTORE_RecordData *rd,
2557                    const struct GNUNET_CRYPTO_RsaSignature *signature)
2558 {
2559   struct ResolverHandle *rh;
2560   struct GNUNET_TIME_Relative remaining_time;
2561   struct GNUNET_CRYPTO_ShortHashCode zone;
2562   char new_name[MAX_DNS_NAME_LENGTH];
2563  
2564   rh = (struct ResolverHandle *)cls; 
2565   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2566              "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n",
2567              rh->id, rd_count);
2568
2569   GNUNET_CRYPTO_short_hash(key,
2570                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2571                      &zone);
2572   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2573   
2574   rh->status = 0;
2575   
2576   if (name != NULL)
2577   {
2578     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2579                "GNS_PHASE_DELEGATE_NS-%llu: Records with name %s exist.\n",
2580                rh->id, name);
2581     rh->status |= RSL_RECORD_EXISTS;
2582   }
2583   
2584   if (remaining_time.rel_value == 0)
2585   {
2586     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2587                "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
2588                rh->id, name);
2589     rh->status |= RSL_RECORD_EXPIRED;
2590   }
2591   
2592   /**
2593    * No authority found in namestore.
2594    */
2595   if (rd_count == 0)
2596   {
2597     /**
2598      * We did not find an authority in the namestore
2599      */
2600     
2601     /**
2602      * No PKEY in zone.
2603      * Promote this authority back to a name maybe it is
2604      * our record.
2605      */
2606     if (strcmp(rh->name, "") == 0)
2607     {
2608       /* simply promote back */
2609       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2610                  "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2611                  rh->id, rh->authority_name);
2612       strcpy(rh->name, rh->authority_name);
2613     }
2614     else
2615     {
2616       /* add back to existing name */
2617       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2618                  "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
2619                  rh->id, rh->authority_name, rh->name);
2620       //memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
2621       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
2622                       rh->name, rh->authority_name);
2623       //strcpy(new_name, rh->name);
2624       //strcpy(new_name+strlen(new_name), ".");
2625       //strcpy(new_name+strlen(new_name), rh->authority_name);
2626       strcpy(rh->name, new_name);
2627       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2628                  "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n", rh->id, rh->name);
2629     }
2630     rh->proc(rh->proc_cls, rh, 0, NULL);
2631     return;
2632   }
2633
2634   /**
2635    * We found an authority that may be able to help us
2636    * move on with query
2637    * Note only 1 pkey should have been returned.. anything else would be strange
2638    */
2639   int i;
2640   for (i=0; i<rd_count;i++)
2641   {
2642     /**
2643      * Redirect via VPN
2644      */
2645     if (rd[i].record_type == GNUNET_GNS_RECORD_VPN)
2646     {
2647       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2648                  "GNS_PHASE_DELEGATE_NS-%llu: VPNRR found.\n",
2649                  rh->id);
2650       rh->status |= RSL_DELEGATE_VPN;
2651       rh->proc (rh->proc_cls, rh, rd_count, rd);
2652       return;
2653     }
2654
2655     /**
2656      * Redirect via NS
2657      * FIXME make optional
2658      */
2659     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_NS)
2660     {
2661       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2662                  "GNS_PHASE_DELEGATE_NS-%llu: NS found.\n",
2663                  rh->id);
2664       rh->status |= RSL_DELEGATE_NS;
2665       rh->proc (rh->proc_cls, rh, rd_count, rd);
2666     }
2667   
2668     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
2669       continue;
2670
2671     if (ignore_pending_records &&
2672         (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
2673     {
2674       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2675       "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
2676         rh->id,
2677         name);
2678       continue;
2679     }
2680     
2681     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
2682          == 0)
2683     {
2684       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2685                  "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
2686                  rh->id);
2687       if (remaining_time.rel_value == 0)
2688       {
2689         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2690                    "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
2691                    rh->id);
2692         rh->authority_chain_head->fresh = 0;
2693         rh->proc(rh->proc_cls, rh, 0, NULL);
2694         return;
2695       }
2696
2697       continue;
2698     }
2699
2700     /**
2701      * Resolve rest of query with new authority
2702      */
2703     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
2704     memcpy(&rh->authority, rd[i].data,
2705            sizeof(struct GNUNET_CRYPTO_ShortHashCode));
2706     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
2707     auth->zone = rh->authority;
2708     memset(auth->name, 0, strlen(rh->authority_name)+1);
2709     strcpy(auth->name, rh->authority_name);
2710     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2711                                  rh->authority_chain_tail,
2712                                  auth);
2713     
2714     /** try to import pkey if private key available
2715      * TODO: Only import last one?
2716      */
2717     //if (rh->priv_key && (name != NULL) && is_canonical (rh->name))
2718     //  process_discovered_authority((char*)name, auth->zone,
2719     //                               rh->authority_chain_tail->zone,
2720     //                               rh->priv_key);
2721     /**
2722      * We are done with PKEY resolution if name is empty
2723      * else resolve again with new authority
2724      */
2725     if (strcmp(rh->name, "") == 0)
2726       rh->proc(rh->proc_cls, rh, rd_count, rd);
2727     else
2728       resolve_delegation_ns(rh);
2729     return;
2730   }
2731     
2732   /**
2733    * no answers found
2734    */
2735   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2736     "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id);
2737   /**
2738    * If we have found some records for the LAST label
2739    * we return the results. Else null.
2740    */
2741   if (strcmp(rh->name, "") == 0)
2742   {
2743     /* Start shortening */
2744     if ((rh->priv_key != NULL) && is_canonical (rh->name))
2745     {
2746       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2747               "GNS_PHASE_DELEGATE_NS-%llu: Trying to shorten authority chain\n",
2748               rh->id);
2749       start_shorten (rh->authority_chain_tail,
2750                     rh->priv_key);
2751     }
2752     /* simply promote back */
2753     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2754                "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
2755                rh->id, rh->authority_name);
2756     strcpy(rh->name, rh->authority_name);
2757     rh->proc(rh->proc_cls, rh, rd_count, rd);
2758   }
2759   else
2760   {
2761     rh->proc(rh->proc_cls, rh, 0, NULL);
2762   }
2763 }
2764
2765
2766 /**
2767  * Resolve the delegation chain for the request in our namestore
2768  *
2769  * @param rh the resolver handle
2770  */
2771 static void
2772 resolve_delegation_ns(struct ResolverHandle *rh)
2773 {
2774   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2775              "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n",
2776              rh->id, rh->name);
2777   pop_tld(rh->name, rh->authority_name);
2778   GNUNET_NAMESTORE_lookup_record(namestore_handle,
2779                                  &rh->authority,
2780                                  rh->authority_name,
2781                                  GNUNET_GNS_RECORD_ANY,
2782                                  &process_delegation_result_ns,
2783                                  rh);
2784
2785 }
2786
2787
2788 /**
2789  * Lookup of a record in a specific zone
2790  * calls lookup result processor on result
2791  *
2792  * @param zone the root zone
2793  * @param pzone the private local zone
2794  * @param record_type the record type to look up
2795  * @param name the name to look up
2796  * @param key a private key for use with PSEU import (can be NULL)
2797  * @param timeout timeout for resolution
2798  * @param only_cached GNUNET_NO to only check locally not DHT for performance
2799  * @param proc the processor to call on result
2800  * @param cls the closure to pass to proc
2801  */
2802 void
2803 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
2804                            struct GNUNET_CRYPTO_ShortHashCode pzone,
2805                            uint32_t record_type,
2806                            const char* name,
2807                            struct GNUNET_CRYPTO_RsaPrivateKey *key,
2808                            struct GNUNET_TIME_Relative timeout,
2809                            int only_cached,
2810                            RecordLookupProcessor proc,
2811                            void* cls)
2812 {
2813   struct ResolverHandle *rh;
2814   struct RecordLookupHandle* rlh;
2815   char string_hash[MAX_DNS_LABEL_LENGTH];
2816   char nzkey[MAX_DNS_LABEL_LENGTH];
2817   char* nzkey_ptr = nzkey;
2818
2819   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2820               "Starting resolution for %s (type=%d)!\n",
2821               name, record_type);
2822
2823   
2824   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
2825   {
2826     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2827                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
2828     proc(cls, 0, NULL);
2829     return;
2830   }
2831   
2832   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
2833   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2834
2835   rh->authority = zone;
2836   rh->id = rid++;
2837   rh->proc_cls = rlh;
2838   rh->priv_key = key;
2839   rh->timeout = timeout;
2840   rh->get_handle = NULL;
2841   rh->private_local_zone = pzone;
2842   rh->only_cached = only_cached;
2843   
2844   if (NULL == key)
2845   {
2846     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2847                 "No shorten key for resolution\n");
2848   }
2849
2850   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2851   {
2852     /*
2853      * Set timeout for authority lookup phase to 1/2
2854      */
2855     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2856                 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
2857     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
2858                                 GNUNET_TIME_relative_divide(timeout, 2),
2859                                                 &handle_lookup_timeout,
2860                                                 rh);
2861     rh->timeout_cont = &dht_authority_lookup_timeout;
2862     rh->timeout_cont_cls = rh;
2863   }
2864   else
2865   {
2866     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
2867     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2868   }
2869   
2870   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2871   {
2872     /**
2873      * Only 'gnunet' given
2874      */
2875     strcpy(rh->name, "\0");
2876   }
2877   else
2878   {
2879     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2880                 "Checking for TLD...\n");
2881     if (is_zkey_tld(name) == GNUNET_YES)
2882     {
2883       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2884                   "TLD is zkey\n");
2885       /**
2886        * This is a zkey tld
2887        * build hash and use as initial authority
2888        */
2889       memset(rh->name, 0,
2890              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
2891       memcpy(rh->name, name,
2892              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
2893       pop_tld(rh->name, string_hash);
2894
2895       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2896                   "ZKEY is %s!\n", string_hash);
2897       
2898       GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
2899
2900       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
2901                                                       &rh->authority))
2902       {
2903         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2904                     "Cannot convert ZKEY %s to hash!\n", string_hash);
2905         GNUNET_free(rh);
2906         GNUNET_free(rlh);
2907         proc(cls, 0, NULL);
2908         return;
2909       }
2910
2911     }
2912     else
2913     {
2914       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2915                   "TLD is gnunet\n");
2916       /**
2917        * Presumably GNUNET tld
2918        */
2919       memset(rh->name, 0,
2920              strlen(name)-strlen(GNUNET_GNS_TLD));
2921       memcpy(rh->name, name,
2922              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2923     }
2924   }
2925   
2926   /**
2927    * Initialize authority chain
2928    */
2929   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2930   rh->authority_chain_head->prev = NULL;
2931   rh->authority_chain_head->next = NULL;
2932   rh->authority_chain_tail = rh->authority_chain_head;
2933   rh->authority_chain_head->zone = rh->authority;
2934   
2935   /**
2936    * Copy original query into lookup handle
2937    */
2938   rlh->record_type = record_type;
2939   memset(rlh->name, 0, strlen(name) + 1);
2940   strcpy(rlh->name, name);
2941   rlh->proc = proc;
2942   rlh->proc_cls = cls;
2943
2944   rh->proc = &handle_delegation_ns;
2945   resolve_delegation_ns(rh);
2946 }
2947
2948 /******** END Record Resolver ***********/
2949
2950 /**
2951  * Callback calles by namestore for a zone to name
2952  * result
2953  *
2954  * @param cls the closure
2955  * @param zone_key the zone we queried
2956  * @param expire the expiration time of the name
2957  * @param name the name found or NULL
2958  * @param rd_len number of records for the name
2959  * @param rd the record data (PKEY) for the name
2960  * @param signature the signature for the record data
2961  */
2962 static void
2963 process_zone_to_name_shorten_root (void *cls,
2964                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2965                  struct GNUNET_TIME_Absolute expire,
2966                  const char *name,
2967                  unsigned int rd_len,
2968                  const struct GNUNET_NAMESTORE_RecordData *rd,
2969                  const struct GNUNET_CRYPTO_RsaSignature *signature);
2970
2971
2972 /**
2973  * Callback called by namestore for a zone to name
2974  * result
2975  *
2976  * @param cls the closure
2977  * @param zone_key the zone we queried
2978  * @param expire the expiration time of the name
2979  * @param name the name found or NULL
2980  * @param rd_len number of records for the name
2981  * @param rd the record data (PKEY) for the name
2982  * @param signature the signature for the record data
2983  */
2984 static void
2985 process_zone_to_name_shorten_shorten (void *cls,
2986                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
2987                  struct GNUNET_TIME_Absolute expire,
2988                  const char *name,
2989                  unsigned int rd_len,
2990                  const struct GNUNET_NAMESTORE_RecordData *rd,
2991                  const struct GNUNET_CRYPTO_RsaSignature *signature)
2992 {
2993   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
2994   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
2995   struct AuthorityChain *next_authority;
2996
2997   char result[MAX_DNS_NAME_LENGTH];
2998   char tmp_name[MAX_DNS_NAME_LENGTH];
2999   size_t answer_len;
3000   
3001   /* we found a match in our own root zone */
3002   if (rd_len != 0)
3003   {
3004     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3005                "result strlen %d\n", strlen(name));
3006     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3007     memset(result, 0, answer_len);
3008
3009     if (strlen(rh->name) > 0)
3010     {
3011       sprintf (result, "%s.%s.%s.%s.%s",
3012                rh->name, name,
3013                nsh->shorten_zone_name, nsh->private_zone_name,
3014                GNUNET_GNS_TLD);
3015     }
3016     else
3017     {
3018       sprintf (result, "%s.%s.%s.%s", name,
3019                nsh->shorten_zone_name, nsh->private_zone_name,
3020                GNUNET_GNS_TLD);
3021     }
3022     
3023     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3024                "Found shorten result %s\n", result);
3025     if (strlen (nsh->result) > strlen (result))
3026       strcpy (nsh->result, result);
3027   }
3028   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3029                                         nsh->shorten_zone) == 0)
3030   {
3031     /**
3032      * This is our zone append .gnunet unless name is empty
3033      * (it shouldn't be, usually FIXME what happens if we
3034      * shorten to our zone to a "" record??)
3035      */
3036     
3037     sprintf (result, "%s.%s.%s.%s",
3038              rh->name,
3039              nsh->shorten_zone_name, nsh->private_zone_name,
3040              GNUNET_GNS_TLD);
3041     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3042                "Our zone: Found %s as shorten result\n", result);
3043     
3044     if (strlen (nsh->result) > strlen (result))
3045       strcpy (nsh->result, result);
3046     //nsh->proc(nsh->proc_cls, result);
3047     //GNUNET_free(nsh);
3048     //free_resolver_handle(rh);
3049     //return;
3050   }
3051   
3052   
3053   /**
3054    * No PSEU found.
3055    * continue with next authority if exists
3056    */
3057   if ((rh->authority_chain_head->next == NULL))
3058   {
3059     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3060                 "Sending %s as shorten result\n", nsh->result);
3061     nsh->proc(nsh->proc_cls, nsh->result);
3062     GNUNET_free (nsh);
3063     free_resolver_handle (rh);
3064     return;
3065   }
3066   next_authority = rh->authority_chain_head;
3067   
3068   GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3069                   "%s.%s", rh->name, next_authority->name);
3070   
3071   strcpy(rh->name, tmp_name);
3072   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3073              "No PSEU found for authority %s. Promoting back: %s\n",
3074              next_authority->name, rh->name);
3075   
3076   GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3077                             rh->authority_chain_tail,
3078                             next_authority);
3079
3080   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3081                                  &rh->authority_chain_tail->zone,
3082                                  &rh->authority_chain_head->zone,
3083                                  &process_zone_to_name_shorten_root,
3084                                  rh);
3085 }
3086
3087 /**
3088  * Callback calles by namestore for a zone to name
3089  * result
3090  *
3091  * @param cls the closure
3092  * @param zone_key the zone we queried
3093  * @param expire the expiration time of the name
3094  * @param name the name found or NULL
3095  * @param rd_len number of records for the name
3096  * @param rd the record data (PKEY) for the name
3097  * @param signature the signature for the record data
3098  */
3099 static void
3100 process_zone_to_name_shorten_private (void *cls,
3101                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3102                  struct GNUNET_TIME_Absolute expire,
3103                  const char *name,
3104                  unsigned int rd_len,
3105                  const struct GNUNET_NAMESTORE_RecordData *rd,
3106                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3107 {
3108   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3109   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3110   struct AuthorityChain *next_authority;
3111
3112   char result[MAX_DNS_NAME_LENGTH];
3113   char tmp_name[MAX_DNS_NAME_LENGTH];
3114   size_t answer_len;
3115   
3116   /* we found a match in our own root zone */
3117   if (rd_len != 0)
3118   {
3119     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3120                "result strlen %d\n", strlen(name));
3121     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3122     memset(result, 0, answer_len);
3123
3124     if (strlen(rh->name) > 0)
3125     {
3126       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3127     }
3128     else
3129     {
3130       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3131     }
3132     
3133     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3134                "Found shorten result %s\n", result);
3135     if (strlen (nsh->result) > strlen (result))
3136       strcpy (nsh->result, result);
3137   }
3138   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3139                                         nsh->private_zone) == 0)
3140   {
3141     /**
3142      * This is our zone append .gnunet unless name is empty
3143      * (it shouldn't be, usually FIXME what happens if we
3144      * shorten to our zone to a "" record??)
3145      */
3146     
3147     sprintf (result, "%s.%s.%s",
3148              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3149     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3150                "Our private zone: Found %s as shorten result %s\n", result);
3151     if (strlen (nsh->result) > strlen (result))
3152       strcpy (nsh->result, result);
3153   }
3154   
3155   if (nsh->shorten_zone != NULL)
3156   {
3157     /* backtrack authorities for names in priv zone */
3158     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3159                                    nsh->shorten_zone,
3160                                    &rh->authority_chain_head->zone,
3161                                    &process_zone_to_name_shorten_shorten,
3162                                    rh);
3163   }
3164   else
3165   {
3166     /**
3167      * No PSEU found.
3168      * continue with next authority if exists
3169      */
3170     if ((rh->authority_chain_head->next == NULL))
3171     {
3172       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3173                  "Sending %s as shorten result\n", nsh->result);
3174       nsh->proc(nsh->proc_cls, nsh->result);
3175       GNUNET_free(nsh);
3176       free_resolver_handle(rh);
3177       return;
3178     }
3179     next_authority = rh->authority_chain_head;
3180     
3181     GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3182                     "%s.%s", rh->name, next_authority->name);
3183     
3184     strcpy(rh->name, tmp_name);
3185     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3186                "No PSEU found for authority %s. Promoting back: %s\n",
3187                next_authority->name, rh->name);
3188     
3189     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3190                               rh->authority_chain_tail,
3191                               next_authority);
3192
3193     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3194                                    &rh->authority_chain_tail->zone,
3195                                    &rh->authority_chain_head->zone,
3196                                    &process_zone_to_name_shorten_root,
3197                                    rh);
3198   }
3199 }
3200
3201 /**
3202  * Callback calles by namestore for a zone to name
3203  * result
3204  *
3205  * @param cls the closure
3206  * @param zone_key the zone we queried
3207  * @param expire the expiration time of the name
3208  * @param name the name found or NULL
3209  * @param rd_len number of records for the name
3210  * @param rd the record data (PKEY) for the name
3211  * @param signature the signature for the record data
3212  */
3213 static void
3214 process_zone_to_name_shorten_root (void *cls,
3215                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3216                  struct GNUNET_TIME_Absolute expire,
3217                  const char *name,
3218                  unsigned int rd_len,
3219                  const struct GNUNET_NAMESTORE_RecordData *rd,
3220                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3221 {
3222   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3223   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3224   struct AuthorityChain *next_authority;
3225
3226   char result[MAX_DNS_NAME_LENGTH];
3227   char tmp_name[MAX_DNS_NAME_LENGTH];
3228   size_t answer_len;
3229   
3230   /* we found a match in our own root zone */
3231   if (rd_len != 0)
3232   {
3233     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3234                "result strlen %d\n", strlen(name));
3235     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3236     memset(result, 0, answer_len);
3237
3238     if (strlen(rh->name) > 0)
3239     {
3240       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3241     }
3242     else
3243     {
3244       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3245     }
3246     
3247     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3248                "Found shorten result %s\n", result);
3249     if (strlen (nsh->result) > strlen (result))
3250       strcpy (nsh->result, result);
3251   }
3252   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3253                                         nsh->root_zone) == 0)
3254   {
3255     /**
3256      * This is our zone append .gnunet unless name is empty
3257      * (it shouldn't be, usually FIXME what happens if we
3258      * shorten to our zone to a "" record??)
3259      */
3260     
3261     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3262     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3263                "Our zone: Found %s as shorten result\n", result);
3264     if (strlen (nsh->result) > strlen (result))
3265       strcpy (nsh->result, result);
3266   }
3267   
3268   if (nsh->private_zone != NULL)
3269   {
3270     /* backtrack authorities for names in priv zone */
3271     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3272                                    nsh->private_zone,
3273                                    &rh->authority_chain_head->zone,
3274                                    &process_zone_to_name_shorten_private,
3275                                    rh);
3276   }
3277   else
3278   {
3279     /**
3280      * No PSEU found.
3281      * continue with next authority if exists
3282      */
3283     if ((rh->authority_chain_head->next == NULL))
3284     {
3285       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3286                  "Sending %s as shorten result\n", nsh->result);
3287       nsh->proc(nsh->proc_cls, nsh->result);
3288       GNUNET_free(nsh);
3289       free_resolver_handle(rh);
3290       return;
3291     }
3292     next_authority = rh->authority_chain_head;
3293     
3294     GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3295                     "%s.%s", rh->name, next_authority->name);
3296     
3297     strcpy(rh->name, tmp_name);
3298     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3299                "No PSEU found for authority %s. Promoting back: %s\n",
3300                next_authority->name, rh->name);
3301     
3302     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3303                               rh->authority_chain_tail,
3304                               next_authority);
3305
3306     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3307                                    &rh->authority_chain_tail->zone,
3308                                    &rh->authority_chain_head->zone,
3309                                    &process_zone_to_name_shorten_root,
3310                                    rh);
3311   }
3312 }
3313
3314
3315 /**
3316  * Process result from namestore delegation lookup
3317  * for shorten operation
3318  *
3319  * @param cls the client shorten handle
3320  * @param rh the resolver handle
3321  * @param rd_count number of results (0)
3322  * @param rd data (NULL)
3323  */
3324 void
3325 handle_delegation_ns_shorten(void* cls,
3326                       struct ResolverHandle *rh,
3327                       uint32_t rd_count,
3328                       const struct GNUNET_NAMESTORE_RecordData *rd)
3329 {
3330   struct NameShortenHandle *nsh;
3331   char result[MAX_DNS_NAME_LENGTH];
3332
3333   nsh = (struct NameShortenHandle *)cls;
3334   
3335   /**
3336    * At this point rh->name contains the part of the name
3337    * that we do not have a PKEY in our namestore to resolve.
3338    * The authority chain in the resolver handle is now
3339    * useful to backtrack if needed
3340    */
3341   
3342   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3343              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
3344   memset(result, 0, sizeof (result));
3345
3346   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3347                                    nsh->root_zone) == 0)
3348   {
3349     /**
3350      * This is our zone append .gnunet unless name is empty
3351      * (it shouldn't be, usually FIXME what happens if we
3352      * shorten to our zone to a "" record??)
3353      */
3354     
3355     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3356     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3357                "Our zone: Found %s as shorten result\n", result);
3358     
3359     if (strlen (nsh->result) > strlen (result))
3360       strcpy (nsh->result, result);
3361
3362   }
3363   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3364                                         nsh->private_zone) == 0)
3365   {
3366     /**
3367      * This is our zone append .gnunet unless name is empty
3368      * (it shouldn't be, usually FIXME what happens if we
3369      * shorten to our zone to a "" record??)
3370      */
3371     
3372     sprintf (result, "%s.%s.%s",
3373              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3374     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3375                "Our zone: Found %s as shorten result %s\n", result);
3376     
3377     if (strlen (nsh->result) > strlen (result))
3378       strcpy (nsh->result, result);
3379   }
3380   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3381                                         nsh->shorten_zone) == 0)
3382   {
3383     /**
3384      * This is our zone append .gnunet unless name is empty
3385      * (it shouldn't be, usually FIXME what happens if we
3386      * shorten to our zone to a "" record??)
3387      */
3388     
3389     sprintf (result, "%s.%s.%s",
3390              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3391     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3392                "Our zone: Found %s as shorten result\n", result);
3393     
3394     if (strlen (nsh->result) > strlen (result))
3395       strcpy (nsh->result, result);
3396   }
3397   
3398   
3399   /* backtrack authorities for names */
3400   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3401                                  nsh->root_zone,
3402                                  &rh->authority_chain_head->zone,
3403                                  &process_zone_to_name_shorten_root,
3404                                  rh);
3405   
3406 }
3407
3408
3409 /**
3410  * Callback calles by namestore for a zone to name
3411  * result
3412  *
3413  * @param cls the closure
3414  * @param zone_key the zone we queried
3415  * @param expire the expiration time of the name
3416  * @param name the name found or NULL
3417  * @param rd_len number of records for the name
3418  * @param rd the record data (PKEY) for the name
3419  * @param signature the signature for the record data
3420  */
3421 static void
3422 process_zone_to_name_zkey(void *cls,
3423                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3424                  struct GNUNET_TIME_Absolute expire,
3425                  const char *name,
3426                  unsigned int rd_len,
3427                  const struct GNUNET_NAMESTORE_RecordData *rd,
3428                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3429 {
3430   struct ResolverHandle *rh = cls;
3431   struct NameShortenHandle *nsh = rh->proc_cls;
3432   struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
3433   char new_name[MAX_DNS_NAME_LENGTH];
3434
3435   /* zkey not in our zone */
3436   if (name == NULL)
3437   {
3438     /**
3439      * In this case we have not given this PKEY a name (yet)
3440      * It is either just not in our zone or not even cached
3441      * Since we do not know at this point we will not try to shorten
3442      * because PKEY import will happen if the user follows the zkey
3443      * link.
3444      */
3445     GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
3446                                      &enc);
3447     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3448                "No name found for zkey %s returning verbatim!\n", enc);
3449     if (strcmp(rh->name, "") != 0)
3450       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
3451                       rh->name, enc, GNUNET_GNS_TLD_ZKEY);
3452     else
3453       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
3454                       enc, GNUNET_GNS_TLD_ZKEY);
3455
3456     strcpy (nsh->result, new_name);
3457
3458     nsh->proc(nsh->proc_cls, new_name);
3459     GNUNET_free(nsh);
3460     free_resolver_handle(rh);
3461     return;
3462   }
3463   
3464   if (strcmp(rh->name, "") != 0)
3465     GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
3466                     rh->name, name);
3467   else
3468     strcpy(new_name, name);
3469
3470   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3471              "Continue shorten for %s!\n", new_name);
3472
3473   strcpy(rh->name, new_name);
3474   
3475   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
3476   rh->authority_chain_tail = rh->authority_chain_head;
3477   rh->authority_chain_head->zone = rh->authority;
3478   
3479   
3480   /* Start delegation resolution in our namestore */
3481   resolve_delegation_ns(rh);
3482 }
3483
3484
3485 /**
3486  * Shorten api from resolver
3487  *
3488  * @param zone the root zone to use
3489  * @param pzone the private zone to use
3490  * @param szone the shorten zone to use
3491  * @param name the name to shorten
3492  * @param private_zone_name name of the private zone
3493  * @param shorten_zone_name name of the shorten zone
3494  * @param proc the processor to call with result
3495  * @param proc_cls closure to pass to proc
3496  */
3497 void
3498 gns_resolver_shorten_name (struct GNUNET_CRYPTO_ShortHashCode *zone,
3499                            struct GNUNET_CRYPTO_ShortHashCode *pzone,
3500                            struct GNUNET_CRYPTO_ShortHashCode *szone,
3501                            const char* name,
3502                            const char* private_zone_name,
3503                            const char* shorten_zone_name,
3504                            ShortenResultProcessor proc,
3505                            void* proc_cls)
3506 {
3507   struct ResolverHandle *rh;
3508   struct NameShortenHandle *nsh;
3509   char string_hash[MAX_DNS_LABEL_LENGTH];
3510   struct GNUNET_CRYPTO_ShortHashCode zkey;
3511   char nzkey[MAX_DNS_LABEL_LENGTH];
3512   char* nzkey_ptr = nzkey;
3513
3514
3515   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3516               "Starting shorten for %s!\n", name);
3517   
3518   if (is_canonical ((char*)name))
3519   {
3520     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3521                 "%s is canonical. Returning verbatim\n", name);
3522     proc (proc_cls, name);
3523     return;
3524   }
3525
3526   nsh = GNUNET_malloc (sizeof (struct NameShortenHandle));
3527
3528   nsh->proc = proc;
3529   nsh->proc_cls = proc_cls;
3530   nsh->root_zone = zone;
3531   nsh->private_zone = pzone;
3532   nsh->shorten_zone = szone;
3533   strcpy (nsh->private_zone_name, private_zone_name);
3534   strcpy (nsh->shorten_zone_name, shorten_zone_name);
3535   strcpy (nsh->result, name);
3536   
3537   rh = GNUNET_malloc (sizeof (struct ResolverHandle));
3538   rh->authority = *zone;
3539   rh->id = rid++;
3540   rh->priv_key = NULL;
3541   rh->proc = &handle_delegation_ns_shorten;
3542   rh->proc_cls = nsh;
3543   rh->id = rid++;
3544   rh->private_local_zone = *zone;
3545   
3546   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3547                 "Checking for TLD...\n");
3548   if (is_zkey_tld (name) == GNUNET_YES)
3549   {
3550     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3551                 "TLD is zkey\n");
3552     /**
3553      * This is a zkey tld
3554      * build hash and use as initial authority
3555      * FIXME sscanf
3556      */
3557     memset (rh->name, 0,
3558             strlen (name)-strlen (GNUNET_GNS_TLD_ZKEY));
3559     memcpy (rh->name, name,
3560             strlen(name)-strlen (GNUNET_GNS_TLD_ZKEY) - 1);
3561     pop_tld (rh->name, string_hash);
3562
3563     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3564                 "ZKEY is %s!\n", string_hash);
3565     
3566     GNUNET_STRINGS_utf8_toupper (string_hash, &nzkey_ptr);
3567
3568     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string (nzkey,
3569                                                            &zkey))
3570     {
3571       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3572                   "Cannot convert ZKEY %s to hash!\n", nzkey);
3573       GNUNET_free (rh);
3574       GNUNET_free (nsh);
3575       proc (proc_cls, name);
3576       return;
3577     }
3578
3579     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3580                                    zone, //ours
3581                                    &zkey,
3582                                    &process_zone_to_name_zkey,
3583                                    rh);
3584     return;
3585
3586   }
3587   else
3588   {
3589     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3590                 "TLD is gnunet\n");
3591     /**
3592      * Presumably GNUNET tld
3593      */
3594     memset (rh->name, 0,
3595             strlen (name)-strlen (GNUNET_GNS_TLD));
3596     memcpy (rh->name, name,
3597             strlen (name)-strlen (GNUNET_GNS_TLD) - 1);
3598   }
3599
3600   rh->authority_chain_head = GNUNET_malloc (sizeof (struct AuthorityChain));
3601   rh->authority_chain_tail = rh->authority_chain_head;
3602   rh->authority_chain_head->zone = *zone;
3603   
3604   
3605   /* Start delegation resolution in our namestore */
3606   resolve_delegation_ns (rh);
3607 }
3608
3609 /*********** END NAME SHORTEN ********************/
3610
3611
3612 /**
3613  * Process result from namestore delegation lookup
3614  * for get authority operation
3615  *
3616  * @param cls the client get auth handle
3617  * @param rh the resolver handle
3618  * @param rd_count number of results (0)
3619  * @param rd data (NULL)
3620  */
3621 void
3622 handle_delegation_result_ns_get_auth(void* cls,
3623                       struct ResolverHandle *rh,
3624                       uint32_t rd_count,
3625                       const struct GNUNET_NAMESTORE_RecordData *rd)
3626 {
3627   struct GetNameAuthorityHandle* nah;
3628   char result[MAX_DNS_NAME_LENGTH];
3629   size_t answer_len;
3630
3631   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
3632   
3633   /**
3634    * At this point rh->name contains the part of the name
3635    * that we do not have a PKEY in our namestore to resolve.
3636    * The authority chain in the resolver handle is now
3637    * useful to backtrack if needed
3638    */
3639   
3640   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3641              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
3642
3643   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3644              "Building response!\n");
3645   if (is_canonical(rh->name))
3646   {
3647     /**
3648      * We successfully resolved the authority in the ns
3649      * FIXME for our purposes this is fine
3650      * but maybe we want to have an api that also looks
3651      * into the dht (i.e. option in message)
3652      **/
3653     if (strlen(rh->name) > strlen(nah->name))
3654     {
3655       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3656                  "Record name longer than original lookup name... odd!\n");
3657       //FIXME to sth here
3658     }
3659
3660     answer_len = strlen(nah->name) - strlen(rh->name)
3661       + strlen(GNUNET_GNS_TLD) + 1;
3662     memset(result, 0, answer_len);
3663     strcpy(result, nah->name + strlen(rh->name) + 1);
3664
3665     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3666                "Got authority result %s\n", result);
3667     
3668     nah->proc(nah->proc_cls, result);
3669     GNUNET_free(nah);
3670     free_resolver_handle(rh);
3671   }
3672   else
3673   {
3674     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3675                "Unable to resolve authority for remaining %s!\n", rh->name);
3676     nah->proc(nah->proc_cls, "");
3677     GNUNET_free(nah);
3678     free_resolver_handle(rh);
3679   }
3680
3681
3682 }
3683
3684
3685 /**
3686  * Tries to resolve the authority for name
3687  * in our namestore
3688  *
3689  * @param zone the root zone to look up for
3690  * @param pzone the private local zone
3691  * @param name the name to lookup up
3692  * @param proc the processor to call when finished
3693  * @param proc_cls the closure to pass to the processor
3694  */
3695 void
3696 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
3697                            struct GNUNET_CRYPTO_ShortHashCode pzone,
3698                            const char* name,
3699                            GetAuthorityResultProcessor proc,
3700                            void* proc_cls)
3701 {
3702   struct ResolverHandle *rh;
3703   struct GetNameAuthorityHandle *nah;
3704
3705   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3706               "Starting authority resolution for %s!\n", name);
3707
3708   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
3709   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
3710   rh->authority = zone;
3711   rh->id = rid++;
3712   rh->private_local_zone = pzone;
3713   
3714   if (strcmp(GNUNET_GNS_TLD, name) == 0)
3715   {
3716     strcpy(rh->name, "\0");
3717   }
3718   else
3719   {
3720     memset(rh->name, 0,
3721            strlen(name)-strlen(GNUNET_GNS_TLD));
3722     memcpy(rh->name, name,
3723            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
3724   }
3725
3726   memset(nah->name, 0,
3727          strlen(name)+1);
3728   strcpy(nah->name, name);
3729   
3730   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
3731   rh->authority_chain_tail = rh->authority_chain_head;
3732   rh->authority_chain_head->zone = zone;
3733   rh->proc = &handle_delegation_result_ns_get_auth;
3734   rh->proc_cls = (void*)nah;
3735
3736   nah->proc = proc;
3737   nah->proc_cls = proc_cls;
3738
3739   /* Start delegation resolution in our namestore */
3740   resolve_delegation_ns(rh);
3741
3742 }
3743
3744 /******** END GET AUTHORITY *************/
3745
3746 /* end of gnunet-service-gns_resolver.c */