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