cff311cd042e8eb579fb3df8ec048516c5c6b7b9
[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\n");
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_NETWORK_socket_sendto (rh->dns_sock,
1657                                 rh->dns_raw_packet,
1658                                 rh->dns_raw_packet_size,
1659                                 (struct sockaddr*)&rh->dns_addr,
1660                                 sizeof (struct sockaddr_in));
1661
1662   rh->dns_read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1663                                                     rh->timeout, //FIXME less?
1664                                                     rset,
1665                                                     NULL,
1666                                                     &read_dns_response,
1667                                                     rh);
1668
1669   GNUNET_NETWORK_fdset_destroy (rset);
1670
1671 }
1672
1673 /**
1674  * The final phase of resoution.
1675  * We found a NS RR and want to resolve via DNS
1676  *
1677  * @param rh the pending lookup handle
1678  * @param rd_count length of record data
1679  * @param rd record data containing VPN RR
1680  */
1681 static void
1682 resolve_record_dns (struct ResolverHandle *rh,
1683                     int rd_count,
1684                     const struct GNUNET_NAMESTORE_RecordData *rd)
1685 {
1686   struct GNUNET_DNSPARSER_Query query;
1687   struct GNUNET_DNSPARSER_Packet packet;
1688   struct GNUNET_DNSPARSER_Flags flags;
1689   struct in_addr dnsip;
1690   struct sockaddr_in addr;
1691   struct sockaddr *sa;
1692   int i;
1693   struct RecordLookupHandle *rlh = rh->proc_cls;
1694
1695   memset (&packet, 0, sizeof (struct GNUNET_DNSPARSER_Packet));
1696   
1697   /* We cancel here as to not include the ns lookup in the timeout */
1698   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1699   {
1700     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1701     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1702   }
1703   /* Start shortening */
1704   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1705   {
1706     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1707              "GNS_PHASE_REC_DNS-%llu: Trying to shorten authority chain\n",
1708              rh->id);
1709     start_shorten (rh->authority_chain_tail,
1710                    rh->priv_key);
1711   }
1712
1713   for (i = 0; i < rd_count; i++)
1714   {
1715     /* Synthesize dns name */
1716     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_NS)
1717     {
1718       strcpy (rh->dns_zone, (char*)rd[i].data);
1719       if (0 == strcmp (rh->name, ""))
1720         strcpy (rh->dns_name, (char*)rd[i].data);
1721       else
1722         sprintf (rh->dns_name, "%s.%s", rh->name, (char*)rd[i].data);
1723     }
1724     /* The glue */
1725     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_A)
1726       dnsip = *((struct in_addr*)rd[i].data);
1727   }
1728   
1729   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1730               "GNS_PHASE_REC_DNS-%llu: Looking up %s from %s\n",
1731               rh->id,
1732               rh->dns_name,
1733               inet_ntoa (dnsip));
1734   rh->dns_sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
1735   if (rh->dns_sock == NULL)
1736   {
1737     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1738                 "GNS_PHASE_REC_DNS-%llu: Error creating udp socket for dns!\n",
1739                 rh->id);
1740     finish_lookup (rh, rlh, 0, NULL);
1741     free_resolver_handle (rh);
1742     return;
1743   }
1744
1745   memset (&addr, 0, sizeof (struct sockaddr_in));
1746   sa = (struct sockaddr *) &addr;
1747   sa->sa_family = AF_INET;
1748   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (rh->dns_sock,
1749                                                sa,
1750                                                sizeof (struct sockaddr_in)))
1751   {
1752     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1753                 "GNS_PHASE_REC_DNS-%llu: Error binding udp socket for dns!\n",
1754                 rh->id);
1755     GNUNET_NETWORK_socket_close (rh->dns_sock);
1756     finish_lookup (rh, rlh, 0, NULL);
1757     free_resolver_handle (rh);
1758     return;
1759   }
1760   
1761   /*TODO create dnsparser query, serialize, sendto, handle reply*/
1762   query.name = rh->dns_name;
1763   query.type = rlh->record_type;
1764   query.class = GNUNET_DNSPARSER_CLASS_INTERNET;
1765   memset (&flags, 0, sizeof (flags));
1766   flags.recursion_desired = 1;
1767   flags.checking_disabled = 1;
1768   packet.queries = &query;
1769   packet.answers = NULL;
1770   packet.authority_records = NULL;
1771   packet.num_queries = 1;
1772   packet.num_answers = 0;
1773   packet.num_authority_records = 0;
1774   packet.num_additional_records = 0;
1775   packet.flags = flags;
1776   packet.id = rh->id;
1777   if (GNUNET_OK != GNUNET_DNSPARSER_pack (&packet,
1778                                           UINT16_MAX,
1779                                           &rh->dns_raw_packet,
1780                                           &rh->dns_raw_packet_size))
1781   {
1782     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1783                 "GNS_PHASE_REC_DNS-%llu: Creating raw dns packet!\n",
1784                 rh->id);
1785     GNUNET_NETWORK_socket_close (rh->dns_sock);
1786     finish_lookup (rh, rlh, 0, NULL);
1787     free_resolver_handle (rh);
1788     return;
1789   }
1790
1791   rh->dns_addr.sin_family = AF_INET;
1792   rh->dns_addr.sin_port = htons (53); //domain
1793   rh->dns_addr.sin_addr = dnsip;
1794 #if HAVE_SOCKADDR_IN_SIN_LEN
1795   rh->dns_addr.sin_len = (u_char) sizeof (struct sockaddr_in);
1796 #endif
1797
1798   send_dns_packet (rh);
1799 }
1800
1801
1802 /**
1803  * The final phase of resoution.
1804  * We found a VPN RR and want to request an IPv4/6 address
1805  *
1806  * @param rh the pending lookup handle
1807  * @param rd_count length of record data
1808  * @param rd record data containing VPN RR
1809  */
1810 static void
1811 resolve_record_vpn (struct ResolverHandle *rh,
1812                     int rd_count,
1813                     const struct GNUNET_NAMESTORE_RecordData *rd)
1814 {
1815   struct RecordLookupHandle *rlh = rh->proc_cls;
1816   struct GNUNET_HashCode serv_desc;
1817   struct vpn_data* vpn;
1818   int af;
1819   
1820   /* We cancel here as to not include the ns lookup in the timeout */
1821   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1822   {
1823     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1824     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1825   }
1826   /* Start shortening */
1827   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1828   {
1829     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1830              "GNS_PHASE_REC_VPN-%llu: Trying to shorten authority chain\n",
1831              rh->id);
1832     start_shorten (rh->authority_chain_tail,
1833                    rh->priv_key);
1834   }
1835
1836   vpn = (struct vpn_data*)rd->data;
1837
1838
1839   GNUNET_CRYPTO_hash ((char*)&vpn[1],
1840                       strlen ((char*)&vpn[1]) + 1,
1841                       &serv_desc);
1842   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1843               "GNS_PHASE_REC_VPN-%llu: proto %hu peer %s!\n",
1844               rh->id,
1845               ntohs (vpn->proto),
1846               GNUNET_h2s (&vpn->peer));
1847
1848   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1849               "GNS_PHASE_REC_VPN-%llu: service %s -> %s!\n",
1850               rh->id,
1851               (char*)&vpn[1],
1852               GNUNET_h2s (&serv_desc));
1853   rh->proc = &handle_record_vpn;
1854
1855   if (NULL == vpn_handle)
1856   {
1857     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1858                 "GNS_PHASE_REC_VPN-%llu: VPN not connected!\n",
1859                 rh->id);
1860     finish_lookup (rh, rh->proc_cls, 0, NULL);
1861     free_resolver_handle (rh);
1862     return;
1863   }
1864
1865   if (rlh->record_type == GNUNET_GNS_RECORD_TYPE_A)
1866     af = AF_INET;
1867   else
1868     af = AF_INET6;
1869   
1870   //FIXME timeout??
1871   rh->vpn_handle = GNUNET_VPN_redirect_to_peer (vpn_handle,
1872                                           af, ntohs (vpn->proto),
1873                                           (struct GNUNET_PeerIdentity *)&vpn->peer,
1874                                           &serv_desc,
1875                                           GNUNET_NO, //nac
1876                                           GNUNET_TIME_UNIT_FOREVER_ABS, //FIXME
1877                                           &process_record_result_vpn,
1878                                           rh);
1879
1880 }
1881
1882 /**
1883  * The final phase of resolution.
1884  * rh->name is a name that is canonical and we do not have a delegation.
1885  * Query namestore for this record
1886  *
1887  * @param rh the pending lookup handle
1888  */
1889 static void
1890 resolve_record_ns(struct ResolverHandle *rh)
1891 {
1892   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
1893   
1894   /* We cancel here as to not include the ns lookup in the timeout */
1895   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
1896   {
1897     GNUNET_SCHEDULER_cancel(rh->timeout_task);
1898     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1899   }
1900   /* Start shortening */
1901   if ((rh->priv_key != NULL) && is_canonical (rh->name))
1902   {
1903     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1904              "GNS_PHASE_REC-%llu: Trying to shorten authority chain\n",
1905              rh->id);
1906     start_shorten (rh->authority_chain_tail,
1907                    rh->priv_key);
1908   }
1909   
1910   /**
1911    * Try to resolve this record in our namestore.
1912    * The name to resolve is now in rh->authority_name
1913    * since we tried to resolve it to an authority
1914    * and failed.
1915    **/
1916   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1917                                  &rh->authority,
1918                                  rh->name,
1919                                  rlh->record_type,
1920                                  &process_record_result_ns,
1921                                  rh);
1922 }
1923
1924
1925
1926 /**
1927  * Handle timeout for DHT requests
1928  *
1929  * @param cls the request handle as closure
1930  * @param tc the task context
1931  */
1932 static void
1933 dht_authority_lookup_timeout(void *cls,
1934                              const struct GNUNET_SCHEDULER_TaskContext *tc)
1935 {
1936   struct ResolverHandle *rh = cls;
1937   struct RecordLookupHandle *rlh = rh->proc_cls;
1938   char new_name[MAX_DNS_NAME_LENGTH];
1939
1940   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1941          "GNS_PHASE_DELEGATE_DHT-%llu: dht lookup for query %s (%ds)timed out.\n",
1942          rh->id, rh->authority_name, rh->timeout.rel_value);
1943
1944   rh->status |= RSL_TIMED_OUT;
1945
1946   rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1947   
1948   GNUNET_DHT_get_stop (rh->get_handle);
1949   rh->get_handle = NULL;
1950   
1951   if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
1952   {
1953     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1954                "GNS_PHASE_DELEGATE_DHT-%llu: Got shutdown\n",
1955                rh->id);
1956     rh->proc(rh->proc_cls, rh, 0, NULL);
1957     return;
1958   }
1959
1960   if (strcmp(rh->name, "") == 0)
1961   {
1962     /*
1963      * promote authority back to name and try to resolve record
1964      */
1965     strcpy(rh->name, rh->authority_name);
1966     rh->proc(rh->proc_cls, rh, 0, NULL);
1967     return;
1968   }
1969   
1970   /**
1971    * Start resolution in bg
1972    */
1973   GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH,
1974                   "%s.%s.%s", rh->name, rh->authority_name, GNUNET_GNS_TLD);
1975   //strcpy(new_name, rh->name);
1976   //strcpy(new_name+strlen(new_name), ".");
1977   //memcpy(new_name+strlen(new_name), GNUNET_GNS_TLD, strlen(GNUNET_GNS_TLD));
1978   
1979   strcpy(rh->name, new_name);
1980
1981   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1982         "GNS_PHASE_DELEGATE_DHT-%llu: Starting background query for %s type %d\n",
1983         rh->id, rh->name, rlh->record_type);
1984
1985   gns_resolver_lookup_record(rh->authority,
1986                              rh->private_local_zone,
1987                              rlh->record_type,
1988                              new_name,
1989                              rh->priv_key,
1990                              GNUNET_TIME_UNIT_FOREVER_REL,
1991                              GNUNET_NO,
1992                              &background_lookup_result_processor,
1993                              NULL);
1994
1995   rh->proc(rh->proc_cls, rh, 0, NULL);
1996 }
1997
1998 /* Prototype */
1999 static void resolve_delegation_dht(struct ResolverHandle *rh);
2000
2001 /* Prototype */
2002 static void resolve_delegation_ns(struct ResolverHandle *rh);
2003
2004
2005 /**
2006  * Namestore resolution for delegation finished. Processing result.
2007  *
2008  * @param cls the closure
2009  * @param rh resolver handle
2010  * @param rd_count number of results (always 0)
2011  * @param rd record data (always NULL)
2012  */
2013 static void
2014 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
2015                           unsigned int rd_count,
2016                           const struct GNUNET_NAMESTORE_RecordData *rd);
2017
2018
2019 /**
2020  * This is a callback function that checks for key revocation
2021  *
2022  * @param cls the pending query
2023  * @param key the key of the zone we did the lookup
2024  * @param expiration expiration date of the record data set in the namestore
2025  * @param name the name for which we need an authority
2026  * @param rd_count the number of records with 'name'
2027  * @param rd the record data
2028  * @param signature the signature of the authority for the record data
2029  */
2030 static void
2031 process_pkey_revocation_result_ns (void *cls,
2032                     const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
2033                     struct GNUNET_TIME_Absolute expiration,
2034                     const char *name,
2035                     unsigned int rd_count,
2036                     const struct GNUNET_NAMESTORE_RecordData *rd,
2037                     const struct GNUNET_CRYPTO_RsaSignature *signature)
2038 {
2039   struct ResolverHandle *rh = cls;
2040   struct GNUNET_TIME_Relative remaining_time;
2041   int i;
2042   
2043   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
2044   
2045   for (i = 0; i < rd_count; i++)
2046   {
2047     if (rd[i].record_type == GNUNET_GNS_RECORD_REV)
2048     {
2049       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2050                  "GNS_PHASE_DELEGATE_REV-%llu: Zone has been revoked.\n",
2051                  rh->id);
2052       rh->status |= RSL_PKEY_REVOKED;
2053       rh->proc (rh->proc_cls, rh, 0, NULL);
2054       return;
2055     }
2056   }
2057   
2058   if ((name == NULL) ||
2059       (remaining_time.rel_value == 0))
2060   {
2061     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2062           "GNS_PHASE_DELEGATE_REV-%llu: + Records don't exist or are expired.\n",
2063           rh->id, name);
2064
2065     if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2066     {
2067       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2068         "GNS_PHASE_DELEGATE_REV-%d: Starting background lookup for %s type %d\n",
2069         rh->id, "+.gnunet", GNUNET_GNS_RECORD_REV);
2070
2071       gns_resolver_lookup_record(rh->authority,
2072                                  rh->private_local_zone,
2073                                  GNUNET_GNS_RECORD_REV,
2074                                  GNUNET_GNS_TLD,
2075                                  rh->priv_key,
2076                                  GNUNET_TIME_UNIT_FOREVER_REL,
2077                                  GNUNET_NO,
2078                                  &background_lookup_result_processor,
2079                                  NULL);
2080     }
2081   }
2082  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2083              "GNS_PHASE_DELEGATE_REV-%llu: Revocation checkpassed\n",
2084              rh->id);
2085   /**
2086    * We are done with PKEY resolution if name is empty
2087    * else resolve again with new authority
2088    */
2089   if (strcmp (rh->name, "") == 0)
2090     rh->proc (rh->proc_cls, rh, 0, NULL);
2091   else
2092     resolve_delegation_ns (rh);
2093   return;
2094 }
2095
2096
2097 /**
2098  * Function called when we get a result from the dht
2099  * for our query. Recursively tries to resolve authorities
2100  * for name in DHT.
2101  *
2102  * @param cls the request handle
2103  * @param exp lifetime
2104  * @param key the key the record was stored under
2105  * @param get_path get path
2106  * @param get_path_length get path length
2107  * @param put_path put path
2108  * @param put_path_length put path length
2109  * @param type the block type
2110  * @param size the size of the record
2111  * @param data the record data
2112  */
2113 static void
2114 process_delegation_result_dht(void* cls,
2115                  struct GNUNET_TIME_Absolute exp,
2116                  const struct GNUNET_HashCode * key,
2117                  const struct GNUNET_PeerIdentity *get_path,
2118                  unsigned int get_path_length,
2119                  const struct GNUNET_PeerIdentity *put_path,
2120                  unsigned int put_path_length,
2121                  enum GNUNET_BLOCK_Type type,
2122                  size_t size, const void *data)
2123 {
2124   struct ResolverHandle *rh;
2125   struct GNSNameRecordBlock *nrb;
2126   uint32_t num_records;
2127   char* name = NULL;
2128   char* rd_data = (char*) data;
2129   int i;
2130   int rd_size;
2131   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
2132   struct GNUNET_HashCode zone_hash_double, name_hash_double;
2133
2134   rh = (struct ResolverHandle *)cls;
2135   
2136   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2137              "GNS_PHASE_DELEGATE_DHT-%llu: Got DHT result\n", rh->id);
2138
2139   if (data == NULL)
2140     return;
2141   
2142   nrb = (struct GNSNameRecordBlock*)data;
2143   
2144   /* stop dht lookup and timeout task */
2145   GNUNET_DHT_get_stop (rh->get_handle);
2146
2147   rh->get_handle = NULL;
2148
2149   if (rh->dht_heap_node != NULL)
2150   {
2151     GNUNET_CONTAINER_heap_remove_node(rh->dht_heap_node);
2152     rh->dht_heap_node = NULL;
2153   }
2154
2155   num_records = ntohl(nrb->rd_count);
2156   name = (char*)&nrb[1];
2157   {
2158     struct GNUNET_NAMESTORE_RecordData rd[num_records];
2159     
2160     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
2161     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
2162   
2163     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
2164                                                                rd_data,
2165                                                                num_records,
2166                                                                rd))
2167     {
2168       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
2169                  "GNS_PHASE_DELEGATE_DHT-%llu: Error deserializing data!\n",
2170                  rh->id);
2171       return;
2172     }
2173
2174     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2175                "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2176                rh->id, name, rh->authority_name);
2177     for (i=0; i<num_records; i++)
2178     {
2179     
2180       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2181                 "GNS_PHASE_DELEGATE_DHT-%llu: Got name: %s (wanted %s)\n",
2182                 rh->id, name, rh->authority_name);
2183       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2184                  "GNS_PHASE_DELEGATE_DHT-%llu: Got type: %d (wanted %d)\n",
2185                  rh->id, rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
2186       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2187                  "GNS_PHASE_DELEGATE_DHT-%llu: Got data length: %d\n",
2188                  rh->id, rd[i].data_size);
2189       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2190                  "GNS_PHASE_DELEGATE_DHT-%llu: Got flag %d\n",
2191                  rh->id, rd[i].flags);
2192       
2193       if ((rd[i].record_type == GNUNET_GNS_RECORD_VPN) ||
2194           (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_NS) ||
2195           (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_CNAME))
2196       {
2197         /**
2198          * This is a VPN,NS,CNAME entry. Let namestore handle this after caching
2199          */
2200         if (strcmp(rh->name, "") == 0)
2201           strcpy(rh->name, rh->authority_name);
2202         else
2203           GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
2204                  rh->name, rh->authority_name); //FIXME ret
2205         rh->answered = 1;
2206         break;
2207       }
2208
2209       if ((strcmp(name, rh->authority_name) == 0) &&
2210           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
2211       {
2212         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2213                    "GNS_PHASE_DELEGATE_DHT-%llu: Authority found in DHT\n",
2214                    rh->id);
2215         rh->answered = 1;
2216         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
2217         struct AuthorityChain *auth =
2218           GNUNET_malloc(sizeof(struct AuthorityChain));
2219         auth->zone = rh->authority;
2220         memset(auth->name, 0, strlen(rh->authority_name)+1);
2221         strcpy(auth->name, rh->authority_name);
2222         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
2223                                      rh->authority_chain_tail,
2224                                      auth);
2225
2226         /** try to import pkey if private key available */
2227         //if (rh->priv_key && is_canonical (rh->name))
2228         //  process_discovered_authority(name, auth->zone,
2229         //                               rh->authority_chain_tail->zone,
2230         //                               rh->priv_key);
2231       }
2232
2233     }
2234
2235
2236     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
2237     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
2238     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
2239     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
2240
2241     /* Save to namestore */
2242     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
2243                                           &zone))
2244     {
2245       GNUNET_NAMESTORE_record_put (namestore_handle,
2246                                  &nrb->public_key,
2247                                  name,
2248                                  exp,
2249                                  num_records,
2250                                  rd,
2251                                  &nrb->signature,
2252                                  &on_namestore_record_put_result, //cont
2253                                  NULL); //cls
2254     }
2255   }
2256   
2257   if (rh->answered)
2258   {
2259     rh->answered = 0;
2260     /**
2261      * delegate
2262      * FIXME in this case. should we ask namestore again?
2263      */
2264     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2265       "GNS_PHASE_DELEGATE_DHT-%llu: Answer from DHT for %s. Yet to resolve: %s\n",
2266       rh->id, rh->authority_name, rh->name);
2267
2268     if (strcmp(rh->name, "") == 0)
2269     {
2270       /* Start shortening */
2271       if ((rh->priv_key != NULL) && is_canonical (rh->name))
2272       {
2273         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2274              "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
2275              rh->id);
2276         start_shorten (rh->authority_chain_tail,
2277                        rh->priv_key);
2278       }
2279     }
2280     else
2281       rh->proc = &handle_delegation_ns;
2282
2283     /* Check for key revocation and delegate */
2284     GNUNET_NAMESTORE_lookup_record (namestore_handle,
2285                                     &rh->authority,
2286                                     "+",
2287                                     GNUNET_GNS_RECORD_REV,
2288                                     &process_pkey_revocation_result_ns,
2289                                     rh);   
2290     
2291     /*if (strcmp(rh->name, "") == 0)
2292     {
2293       if ((rh->priv_key != NULL) && is_canonical (rh->name))
2294       {
2295         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2296              "GNS_PHASE_DELEGATE_DHT-%llu: Trying to shorten authority chain\n",
2297              rh->id);
2298         start_shorten (rh->authority_chain_tail,
2299                        rh->priv_key);
2300       }
2301       
2302       rh->proc(rh->proc_cls, rh, 0, NULL);
2303     }
2304     else
2305     {
2306       rh->proc = &handle_delegation_ns;
2307       resolve_delegation_ns (rh);
2308     }
2309     */
2310     return;
2311   }
2312   
2313   /**
2314    * No pkey but name exists
2315    * promote back
2316    */
2317   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2318              "GNS_PHASE_DELEGATE_DHT-%llu: Adding %s back to %s\n",
2319              rh->id, rh->authority_name, rh->name);
2320   if (strcmp(rh->name, "") == 0)
2321     strcpy(rh->name, rh->authority_name);
2322   else
2323     GNUNET_snprintf(rh->name, MAX_DNS_NAME_LENGTH, "%s.%s",
2324                   rh->name, rh->authority_name); //FIXME ret
2325   
2326   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2327              "GNS_PHASE_DELEGATE_DHT-%llu: %s restored\n", rh->id, rh->name);
2328   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2329            "GNS_PHASE_DELEGATE_DHT-%llu: DHT authority lookup found no match!\n",
2330            rh->id);
2331   rh->proc(rh->proc_cls, rh, 0, NULL);
2332 }
2333
2334 #define MAX_SOA_LENGTH sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)\
2335                         +(MAX_DNS_NAME_LENGTH*2)
2336 #define MAX_MX_LENGTH sizeof(uint16_t)+MAX_DNS_NAME_LENGTH
2337 #define MAX_SRV_LENGTH (sizeof(uint16_t)*3)+MAX_DNS_NAME_LENGTH
2338
2339
2340 static void
2341 expand_plus(char* dest, char* src, char* repl)
2342 {
2343   char* pos;
2344   unsigned int s_len = strlen(src)+1;
2345
2346   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2347              "GNS_POSTPROCESS: Got %s to expand with %s\n", src, repl);
2348
2349   if (s_len < 3)
2350   {
2351     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2352                "GNS_POSTPROCESS: %s to short\n", src);
2353
2354     /* no postprocessing */
2355     memcpy(dest, src, s_len+1);
2356     return;
2357   }
2358   
2359   if (0 == strcmp(src+s_len-3, ".+"))
2360   {
2361     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2362                "GNS_POSTPROCESS: Expanding .+ in %s\n", src);
2363     memset(dest, 0, s_len+strlen(repl)+strlen(GNUNET_GNS_TLD));
2364     strcpy(dest, src);
2365     pos = dest+s_len-2;
2366     strcpy(pos, repl);
2367     pos += strlen(repl);
2368     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2369                "GNS_POSTPROCESS: Expanded to %s\n", dest);
2370   }
2371   else
2372   {
2373     memcpy(dest, src, s_len+1);
2374   }
2375 }
2376
2377 /**
2378  * finish lookup
2379  */
2380 static void
2381 finish_lookup(struct ResolverHandle *rh,
2382               struct RecordLookupHandle* rlh,
2383               unsigned int rd_count,
2384               const struct GNUNET_NAMESTORE_RecordData *rd)
2385 {
2386   int i;
2387   char new_rr_data[MAX_DNS_NAME_LENGTH];
2388   char new_mx_data[MAX_MX_LENGTH];
2389   char new_soa_data[MAX_SOA_LENGTH];
2390   char new_srv_data[MAX_SRV_LENGTH];
2391   struct srv_data *old_srv;
2392   struct srv_data *new_srv;
2393   struct soa_data *old_soa;
2394   struct soa_data *new_soa;
2395   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
2396   char* repl_string;
2397   char* pos;
2398   unsigned int offset;
2399
2400   if (rh->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2401   {
2402     GNUNET_SCHEDULER_cancel(rh->timeout_task);
2403     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2404   }
2405
2406   if (rd_count > 0)
2407     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
2408
2409   for (i = 0; i < rd_count; i++)
2410   {
2411     
2412     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
2413         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
2414         rd[i].record_type != GNUNET_GNS_RECORD_MX &&
2415         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SOA &&
2416         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_SRV)
2417     {
2418       p_rd[i].data = rd[i].data;
2419       continue;
2420     }
2421
2422     /**
2423      * for all those records we 'should'
2424      * also try to resolve the A/AAAA records (RFC1035)
2425      * This is a feature and not important
2426      */
2427     
2428     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2429                "GNS_POSTPROCESS: Postprocessing\n");
2430
2431     if (strcmp(rh->name, "+") == 0)
2432       repl_string = rlh->name;
2433     else
2434       repl_string = rlh->name+strlen(rh->name)+1;
2435
2436     offset = 0;
2437     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
2438     {
2439       memcpy (new_mx_data, (char*)rd[i].data, sizeof(uint16_t));
2440       offset = sizeof(uint16_t);
2441       pos = new_mx_data+offset;
2442       expand_plus(pos, (char*)rd[i].data+sizeof(uint16_t),
2443                   repl_string);
2444       offset += strlen(new_mx_data+sizeof(uint16_t))+1;
2445       p_rd[i].data = new_mx_data;
2446       p_rd[i].data_size = offset;
2447     }
2448     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SRV)
2449     {
2450       /*
2451        * Prio, weight and port
2452        */
2453       new_srv = (struct srv_data*)new_srv_data;
2454       old_srv = (struct srv_data*)rd[i].data;
2455       new_srv->prio = old_srv->prio;
2456       new_srv->weight = old_srv->weight;
2457       new_srv->port = old_srv->port;
2458       expand_plus((char*)&new_srv[1], (char*)&old_srv[1],
2459                   repl_string);
2460       p_rd[i].data = new_srv_data;
2461       p_rd[i].data_size = sizeof (struct srv_data) + strlen ((char*)&new_srv[1]) + 1;
2462     }
2463     else if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_SOA)
2464     {
2465       /* expand mname and rname */
2466       old_soa = (struct soa_data*)rd[i].data;
2467       new_soa = (struct soa_data*)new_soa_data;
2468       memcpy (new_soa, old_soa, sizeof (struct soa_data));
2469       expand_plus((char*)&new_soa[1], (char*)&old_soa[1], repl_string);
2470       offset = strlen ((char*)&new_soa[1]) + 1;
2471       expand_plus((char*)&new_soa[1] + offset,
2472                   (char*)&old_soa[1] + strlen ((char*)&old_soa[1]) + 1,
2473                   repl_string);
2474       p_rd[i].data_size = sizeof (struct soa_data)
2475                           + offset
2476                           + strlen ((char*)&new_soa[1] + offset);
2477       p_rd[i].data = new_soa_data;
2478     }
2479     else
2480     {
2481       pos = new_rr_data;
2482       expand_plus(pos, (char*)rd[i].data, repl_string);
2483       p_rd[i].data_size = strlen(new_rr_data)+1;
2484       p_rd[i].data = new_rr_data;
2485     }
2486     
2487   }
2488
2489   rlh->proc(rlh->proc_cls, rd_count, p_rd);
2490   GNUNET_free(rlh);
2491   
2492 }
2493
2494 /**
2495  * Process DHT lookup result for record.
2496  *
2497  * @param cls the closure
2498  * @param rh resolver handle
2499  * @param rd_count number of results
2500  * @param rd record data
2501  */
2502 static void
2503 handle_record_dht(void* cls, struct ResolverHandle *rh,
2504                        unsigned int rd_count,
2505                        const struct GNUNET_NAMESTORE_RecordData *rd)
2506 {
2507   struct RecordLookupHandle* rlh;
2508
2509   rlh = (struct RecordLookupHandle*)cls;
2510   if (rd_count == 0)
2511   {
2512     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2513                "GNS_PHASE_REC-%d: No records for %s found in DHT. Aborting\n",
2514                rh->id, rh->name);
2515     /* give up, cannot resolve */
2516     finish_lookup(rh, rlh, 0, NULL);
2517     free_resolver_handle(rh);
2518     return;
2519   }
2520
2521   /* results found yay */
2522   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2523              "GNS_PHASE_REC-%d: Record resolved from DHT!", rh->id);
2524
2525   finish_lookup(rh, rlh, rd_count, rd);
2526   free_resolver_handle(rh);
2527
2528 }
2529
2530
2531
2532
2533 /**
2534  * Process namestore lookup result for record.
2535  *
2536  * @param cls the closure
2537  * @param rh resolver handle
2538  * @param rd_count number of results
2539  * @param rd record data
2540  */
2541 static void
2542 handle_record_ns (void* cls, struct ResolverHandle *rh,
2543                   unsigned int rd_count,
2544                   const struct GNUNET_NAMESTORE_RecordData *rd)
2545 {
2546   struct RecordLookupHandle* rlh;
2547   rlh = (struct RecordLookupHandle*) cls;
2548   int check_dht = GNUNET_YES;
2549
2550   if (rd_count == 0)
2551   {
2552     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2553                "GNS_PHASE_REC-%d: NS returned no records. (status: %d)!\n",
2554                rh->id,
2555                rh->status);
2556     
2557     /**
2558      * There are 5 conditions that have to met for us to consult the DHT:
2559      * 1. The entry in the DHT is RSL_RECORD_EXPIRED OR
2560      * 2. No entry in the NS existed AND
2561      * 3. The zone queried is not the local resolver's zone AND
2562      * 4. The name that was looked up is '+'
2563      *    because if it was any other canonical name we either already queried
2564      *    the DHT for the authority in the authority lookup phase (and thus
2565      *    would already have an entry in the NS for the record)
2566      * 5. We are not in cache only mode
2567      */
2568     if (((rh->status & RSL_RECORD_EXPIRED) != 0) &&
2569         ((rh->status & RSL_RECORD_EXISTS) == 0) )
2570       check_dht = GNUNET_NO;
2571     
2572     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2573                                           &rh->private_local_zone))
2574       check_dht = GNUNET_NO;
2575     
2576     if ((strcmp (rh->name, "+") != 0) && (is_srv (rh->name) != 0))
2577         check_dht = GNUNET_NO;
2578
2579
2580     if (rh->only_cached == GNUNET_YES)
2581       check_dht = GNUNET_NO;
2582     
2583     if (GNUNET_YES == check_dht)
2584     {
2585       rh->proc = &handle_record_dht;
2586       resolve_record_dht(rh);
2587       return;
2588     }
2589     /* give up, cannot resolve */
2590     finish_lookup(rh, rlh, 0, NULL);
2591     free_resolver_handle(rh);
2592     return;
2593   }
2594
2595   /* results found yay */
2596   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2597              "GNS_PHASE_REC-%d: Record resolved from namestore!", rh->id);
2598
2599   finish_lookup(rh, rlh, rd_count, rd);
2600
2601   free_resolver_handle(rh);
2602
2603 }
2604
2605
2606 /**
2607  * Move one level up in the domain hierarchy and return the
2608  * passed top level domain.
2609  *
2610  * @param name the domain
2611  * @param dest the destination where the tld will be put
2612  */
2613 void
2614 pop_tld(char* name, char* dest)
2615 {
2616   uint32_t len;
2617
2618   if (is_canonical (name))
2619   {
2620     strcpy(dest, name);
2621     strcpy(name, "");
2622     return;
2623   }
2624
2625   for (len = strlen(name); len > 0; len--)
2626   {
2627     if (*(name+len) == '.')
2628       break;
2629   }
2630   
2631   //Was canonical?
2632   if (len == 0)
2633     return;
2634
2635   name[len] = '\0';
2636
2637   strcpy(dest, (name+len+1));
2638 }
2639
2640 /**
2641  * Checks if name is in tld
2642  *
2643  * @param name the name to check
2644  * @param tld the TLD to check for
2645  * @return GNUNET_YES or GNUNET_NO
2646  */
2647 int
2648 is_tld(const char* name, const char* tld)
2649 {
2650   int offset = 0;
2651
2652   if (strlen(name) <= strlen(tld))
2653   {
2654     return GNUNET_NO;
2655   }
2656   
2657   offset = strlen(name)-strlen(tld);
2658   if (strcmp(name+offset, tld) != 0)
2659   {
2660     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2661                "%s is not in .%s TLD\n", name, tld);
2662     return GNUNET_NO;
2663   }
2664   return GNUNET_YES;
2665 }
2666
2667 /**
2668  * DHT resolution for delegation finished. Processing result.
2669  *
2670  * @param cls the closure
2671  * @param rh resolver handle
2672  * @param rd_count number of results (always 0)
2673  * @param rd record data (always NULL)
2674  */
2675 static void
2676 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
2677                           unsigned int rd_count,
2678                           const struct GNUNET_NAMESTORE_RecordData *rd)
2679 {
2680   struct RecordLookupHandle* rlh;
2681   rlh = (struct RecordLookupHandle*) cls;
2682   
2683
2684   if (strcmp(rh->name, "") == 0)
2685   {
2686     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
2687     {
2688       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2689                  "GNS_PHASE_DELEGATE_DHT-%llu: Resolved queried PKEY via DHT.\n",
2690                  rh->id);
2691       finish_lookup(rh, rlh, rd_count, rd);
2692       free_resolver_handle(rh);
2693       return;
2694     }
2695     /* We resolved full name for delegation. resolving record */
2696     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2697      "GNS_PHASE_DELEGATE_DHT-%llu: Resolved full name for delegation via DHT.\n",
2698      rh->id);
2699     strcpy(rh->name, "+\0");
2700     rh->proc = &handle_record_ns;
2701     resolve_record_ns(rh);
2702     return;
2703   }
2704
2705   /**
2706    * we still have some left
2707    **/
2708   if (is_canonical(rh->name))
2709   {
2710     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2711              "GNS_PHASE_DELEGATE_DHT-%llu: Resolving canonical record %s in ns\n",
2712              rh->id,
2713              rh->name);
2714     rh->proc = &handle_record_ns;
2715     resolve_record_ns(rh);
2716     return;
2717   }
2718   /* give up, cannot resolve */
2719   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2720  "GNS_PHASE_DELEGATE_DHT-%llu: Cannot fully resolve delegation for %s via DHT!\n",
2721  rh->id, rh->name);
2722   finish_lookup(rh, rlh, 0, NULL);
2723   free_resolver_handle(rh);
2724 }
2725
2726
2727 /**
2728  * Start DHT lookup for a name -> PKEY (compare NS) record in
2729  * rh->authority's zone
2730  *
2731  * @param rh the pending gns query
2732  */
2733 static void
2734 resolve_delegation_dht(struct ResolverHandle *rh)
2735 {
2736   uint32_t xquery;
2737   struct GNUNET_CRYPTO_ShortHashCode name_hash;
2738   struct GNUNET_HashCode name_hash_double;
2739   struct GNUNET_HashCode zone_hash_double;
2740   struct GNUNET_HashCode lookup_key;
2741   struct ResolverHandle *rh_heap_root;
2742   
2743   pop_tld(rh->name, rh->authority_name); 
2744   GNUNET_CRYPTO_short_hash(rh->authority_name,
2745                      strlen(rh->authority_name),
2746                      &name_hash);
2747   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
2748   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
2749   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
2750   
2751   rh->dht_heap_node = NULL;
2752
2753   if (rh->timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
2754   {
2755     //rh->timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
2756     //                                          &dht_authority_lookup_timeout,
2757     //                                                   rh);
2758     rh->timeout_cont = &dht_authority_lookup_timeout;
2759     rh->timeout_cont_cls = rh;
2760   }
2761   else 
2762   {
2763     if (max_allowed_background_queries <=
2764         GNUNET_CONTAINER_heap_get_size (dht_lookup_heap))
2765     {
2766       /* terminate oldest lookup */
2767       rh_heap_root = GNUNET_CONTAINER_heap_remove_root (dht_lookup_heap);
2768       GNUNET_DHT_get_stop(rh_heap_root->get_handle);
2769       rh_heap_root->dht_heap_node = NULL;
2770       
2771       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2772         "GNS_PHASE_DELEGATE_DHT-%llu: Replacing oldest background query for %s\n",
2773         rh->id, rh_heap_root->authority_name);
2774       
2775       rh_heap_root->proc(rh_heap_root->proc_cls,
2776                          rh_heap_root,
2777                          0,
2778                          NULL);
2779     }
2780     rh->dht_heap_node = GNUNET_CONTAINER_heap_insert (dht_lookup_heap,
2781                                          rh,
2782                                          GNUNET_TIME_absolute_get().abs_value);
2783   }
2784   
2785   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
2786   
2787   GNUNET_assert(rh->get_handle == NULL);
2788   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
2789                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
2790                        &lookup_key,
2791                        DHT_GNS_REPLICATION_LEVEL,
2792                        GNUNET_DHT_RO_NONE,
2793                        &xquery,
2794                        sizeof(xquery),
2795                        &process_delegation_result_dht,
2796                        rh);
2797
2798 }
2799
2800
2801 /**
2802  * Namestore resolution for delegation finished. Processing result.
2803  *
2804  * @param cls the closure
2805  * @param rh resolver handle
2806  * @param rd_count number of results (always 0)
2807  * @param rd record data (always NULL)
2808  */
2809 static void
2810 handle_delegation_ns (void* cls, struct ResolverHandle *rh,
2811                       unsigned int rd_count,
2812                       const struct GNUNET_NAMESTORE_RecordData *rd)
2813 {
2814   struct RecordLookupHandle* rlh;
2815   rlh = (struct RecordLookupHandle*) cls;
2816   int check_dht = GNUNET_YES;
2817   int s_len = 0;
2818
2819   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2820              "GNS_PHASE_DELEGATE_NS-%llu: Resolution status: %d.\n",
2821              rh->id, rh->status);
2822
2823   if (rh->status & RSL_PKEY_REVOKED)
2824   {
2825     finish_lookup (rh, rlh, 0, NULL);
2826     free_resolver_handle (rh);
2827     return;
2828   }
2829   
2830   if (strcmp(rh->name, "") == 0)
2831   {
2832     
2833     /* We resolved full name for delegation. resolving record */
2834     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2835               "GNS_PHASE_DELEGATE_NS-%llu: Resolved full name for delegation.\n",
2836               rh->id);
2837     if (rh->status & RSL_CNAME_FOUND)
2838     {
2839       if (rlh->record_type == GNUNET_GNS_RECORD_TYPE_CNAME)
2840       {
2841         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2842                   "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried CNAME in NS.\n",
2843                   rh->id);
2844         strcpy (rh->name, rh->authority_name);
2845         finish_lookup (rh, rlh, rd_count, rd);
2846         free_resolver_handle (rh);
2847         return;
2848       }
2849       
2850       /* A .+ CNAME  */
2851       if (is_tld ((char*)rd->data, GNUNET_GNS_TLD_PLUS))
2852       {
2853         s_len = strlen (rd->data) - 2;
2854         memcpy (rh->name, rd->data, s_len);
2855         rh->name[s_len] = '\0';
2856         resolve_delegation_ns (rh);
2857         return;
2858       }
2859       else if (is_tld ((char*)rd->data, GNUNET_GNS_TLD_ZKEY))
2860       {
2861         gns_resolver_lookup_record (rh->authority,
2862                                     rh->private_local_zone,
2863                                     rlh->record_type,
2864                                     (char*)rd->data,
2865                                     rh->priv_key,
2866                                     rh->timeout,
2867                                     rh->only_cached,
2868                                     rlh->proc,
2869                                     rlh->proc_cls);
2870         GNUNET_free (rlh);
2871         free_resolver_handle (rh);
2872         return;
2873       }
2874       else
2875       {
2876         //Try DNS resolver
2877         strcpy (rh->dns_name, (char*)rd->data);
2878         resolve_dns_name (rh);
2879         return;
2880       }
2881
2882     }
2883     else if (rh->status & RSL_DELEGATE_VPN)
2884     {
2885       if (rlh->record_type == GNUNET_GNS_RECORD_VPN)
2886       {
2887         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2888                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried VPNRR in NS.\n",
2889                  rh->id);
2890         finish_lookup(rh, rlh, rd_count, rd);
2891         free_resolver_handle(rh);
2892         return;
2893       }
2894       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2895              "GNS_PHASE_DELEGATE_NS-%llu: VPN delegation starting.\n",
2896              rh->id);
2897       GNUNET_assert (NULL != rd);
2898       rh->proc = &handle_record_vpn;
2899       resolve_record_vpn (rh, rd_count, rd);
2900       return;
2901     }
2902     else if (rh->status & RSL_DELEGATE_NS)
2903     {
2904       if (rlh->record_type == GNUNET_GNS_RECORD_TYPE_NS)
2905       {
2906         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2907                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2908                    rh->id);
2909         finish_lookup(rh, rlh, rd_count, rd);
2910         free_resolver_handle(rh);
2911         return;
2912       }
2913       
2914       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2915                  "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2916                  rh->id);
2917       GNUNET_assert (NULL != rd);
2918       rh->proc = &handle_record_ns;
2919       resolve_record_dns (rh, rd_count, rd);
2920       return;
2921     }
2922     else if (rh->status & RSL_DELEGATE_PKEY)
2923     {
2924       if (rh->status & RSL_PKEY_REVOKED)
2925       {
2926         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2927                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved PKEY is revoked.\n",
2928                    rh->id);
2929         finish_lookup (rh, rlh, 0, NULL);
2930         free_resolver_handle (rh);
2931         return;
2932       }
2933       else if (rlh->record_type == GNUNET_GNS_RECORD_PKEY)
2934       {
2935         GNUNET_assert(rd_count == 1);
2936         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2937                    "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried PKEY in NS.\n",
2938                    rh->id);
2939         finish_lookup(rh, rlh, rd_count, rd);
2940         free_resolver_handle(rh);
2941         return;
2942       }
2943     }
2944     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2945                "GNS_PHASE_DELEGATE_NS-%llu: Resolving record +\n",
2946                rh->id);
2947     strcpy(rh->name, "+\0");
2948     rh->proc = &handle_record_ns;
2949     resolve_record_ns(rh);
2950     return;
2951   }
2952   
2953   if (rh->status & RSL_DELEGATE_NS)
2954   {
2955     if (rlh->record_type == GNUNET_GNS_RECORD_TYPE_NS)
2956     {
2957       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2958                  "GNS_PHASE_DELEGATE_NS-%llu: Resolved queried NSRR in NS.\n",
2959                  rh->id);
2960       finish_lookup(rh, rlh, rd_count, rd);
2961       free_resolver_handle(rh);
2962       return;
2963     }
2964     
2965     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2966                "GNS_PHASE_DELEGATE_NS-%llu: NS delegation starting.\n",
2967                rh->id);
2968     GNUNET_assert (NULL != rd);
2969     rh->proc = &handle_record_ns;
2970     resolve_record_dns (rh, rd_count, rd);
2971     return;
2972   }
2973   
2974   /**
2975    * we still have some left
2976    * check if authority in ns is fresh
2977    * and exists
2978    * or we are authority
2979    **/
2980
2981   if ((rh->status & RSL_RECORD_EXISTS) &&
2982        !(rh->status & RSL_RECORD_EXPIRED))
2983     check_dht = GNUNET_NO;
2984
2985   if (0 == GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
2986                                         &rh->private_local_zone))
2987     check_dht = GNUNET_NO;
2988
2989   if (rh->only_cached == GNUNET_YES)
2990     check_dht = GNUNET_NO;
2991
2992   if (check_dht == GNUNET_NO)
2993   {
2994     if (is_canonical(rh->name))
2995     {
2996       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
2997                  "GNS_PHASE_DELEGATE_NS-%llu: Resolving canonical record %s\n",
2998                  rh->id,
2999                  rh->name);
3000       rh->proc = &handle_record_ns;
3001       resolve_record_ns(rh);
3002     }
3003     else
3004     {
3005       /* give up, cannot resolve */
3006       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3007           "GNS_PHASE_DELEGATE_NS-%llu: Cannot fully resolve delegation for %s!\n",
3008           rh->id,
3009           rh->name);
3010       finish_lookup(rh, rlh, rd_count, rd);
3011       //rlh->proc(rlh->proc_cls, 0, NULL);
3012     }
3013     return;
3014   }
3015
3016   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3017       "GNS_PHASE_DELEGATE_NS-%llu: Trying to resolve delegation for %s via DHT\n",
3018       rh->id, rh->name);
3019   rh->proc = &handle_delegation_dht;
3020   resolve_delegation_dht(rh);
3021 }
3022
3023
3024 /**
3025  * This is a callback function that should give us only PKEY
3026  * records. Used to query the namestore for the authority (PKEY)
3027  * for 'name'. It will recursively try to resolve the
3028  * authority for a given name from the namestore.
3029  *
3030  * @param cls the pending query
3031  * @param key the key of the zone we did the lookup
3032  * @param expiration expiration date of the record data set in the namestore
3033  * @param name the name for which we need an authority
3034  * @param rd_count the number of records with 'name'
3035  * @param rd the record data
3036  * @param signature the signature of the authority for the record data
3037  */
3038 static void
3039 process_delegation_result_ns (void* cls,
3040                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
3041                    struct GNUNET_TIME_Absolute expiration,
3042                    const char *name,
3043                    unsigned int rd_count,
3044                    const struct GNUNET_NAMESTORE_RecordData *rd,
3045                    const struct GNUNET_CRYPTO_RsaSignature *signature)
3046 {
3047   struct ResolverHandle *rh;
3048   struct GNUNET_TIME_Relative remaining_time;
3049   struct GNUNET_CRYPTO_ShortHashCode zone;
3050   char new_name[MAX_DNS_NAME_LENGTH];
3051   unsigned int i;
3052   struct GNUNET_TIME_Absolute et;
3053  
3054   rh = (struct ResolverHandle *)cls; 
3055   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3056           "GNS_PHASE_DELEGATE_NS-%llu: Got %d records from authority lookup\n",
3057           rh->id, rd_count);
3058
3059   GNUNET_CRYPTO_short_hash (key,
3060                       sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3061                       &zone);
3062   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
3063   
3064   rh->status = 0;
3065   
3066   if (name != NULL)
3067   {
3068     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3069                 "GNS_PHASE_DELEGATE_NS-%llu: Records with name %s exist.\n",
3070                 rh->id, name);
3071     rh->status |= RSL_RECORD_EXISTS;
3072   
3073     if (remaining_time.rel_value == 0)
3074     {
3075       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3076                   "GNS_PHASE_DELEGATE_NS-%llu: Record set %s expired.\n",
3077                   rh->id, name);
3078       rh->status |= RSL_RECORD_EXPIRED;
3079     }
3080   }
3081   
3082   /**
3083    * No authority found in namestore.
3084    */
3085   if (rd_count == 0)
3086   {
3087     /**
3088      * We did not find an authority in the namestore
3089      */
3090     
3091     /**
3092      * No PKEY in zone.
3093      * Promote this authority back to a name maybe it is
3094      * our record.
3095      */
3096     if (strcmp (rh->name, "") == 0)
3097     {
3098       /* simply promote back */
3099       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3100                   "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
3101                   rh->id, rh->authority_name);
3102       strcpy (rh->name, rh->authority_name);
3103     }
3104     else
3105     {
3106       /* add back to existing name */
3107       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3108                   "GNS_PHASE_DELEGATE_NS-%llu: Adding %s back to %s\n",
3109                   rh->id, rh->authority_name, rh->name);
3110       GNUNET_snprintf (new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
3111                        rh->name, rh->authority_name);
3112       strcpy (rh->name, new_name);
3113       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3114                   "GNS_PHASE_DELEGATE_NS-%llu: %s restored\n",
3115                   rh->id, rh->name);
3116     }
3117
3118     rh->proc (rh->proc_cls, rh, 0, NULL);
3119     return;
3120   }
3121
3122   /**
3123    * We found an authority that may be able to help us
3124    * move on with query
3125    * Note only 1 pkey should have been returned.. anything else would be strange
3126    */
3127   for (i=0; i < rd_count;i++)
3128   {
3129     
3130     /**
3131      * A CNAME. Like regular DNS this means the is no other record for this
3132      * name.
3133      */
3134     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_CNAME)
3135     {
3136       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3137                  "GNS_PHASE_DELEGATE_NS-%llu: CNAME found.\n",
3138                  rh->id);
3139
3140       rh->status |= RSL_CNAME_FOUND;
3141       rh->proc (rh->proc_cls, rh, rd_count, rd);
3142       return;
3143     }
3144
3145     /**
3146      * Redirect via VPN
3147      */
3148     if (rd[i].record_type == GNUNET_GNS_RECORD_VPN)
3149     {
3150       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3151                  "GNS_PHASE_DELEGATE_NS-%llu: VPN found.\n",
3152                  rh->id);
3153       rh->status |= RSL_DELEGATE_VPN;
3154       rh->proc (rh->proc_cls, rh, rd_count, rd);
3155       return;
3156     }
3157
3158     /**
3159      * Redirect via NS
3160      * FIXME make optional
3161      */
3162     if (rd[i].record_type == GNUNET_GNS_RECORD_TYPE_NS)
3163     {
3164       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3165                  "GNS_PHASE_DELEGATE_NS-%llu: NS found.\n",
3166                  rh->id);
3167       rh->status |= RSL_DELEGATE_NS;
3168       rh->proc (rh->proc_cls, rh, rd_count, rd);
3169       return;
3170     }
3171   
3172     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
3173       continue;
3174
3175     rh->status |= RSL_DELEGATE_PKEY;
3176
3177     if ((ignore_pending_records != 0) &&
3178         (rd[i].flags & GNUNET_NAMESTORE_RF_PENDING))
3179     {
3180       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3181      "GNS_PHASE_DELEGATE_NS-%llu: PKEY for %s is pending user confirmation.\n",
3182         rh->id,
3183         name);
3184       continue;
3185     }
3186     
3187     GNUNET_break (0 == (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION));
3188     et.abs_value = rd[i].expiration_time;
3189     if ((GNUNET_TIME_absolute_get_remaining (et)).rel_value
3190          == 0)
3191     {
3192       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3193                   "GNS_PHASE_DELEGATE_NS-%llu: This pkey is expired.\n",
3194                   rh->id);
3195       if (remaining_time.rel_value == 0)
3196       {
3197         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3198                     "GNS_PHASE_DELEGATE_NS-%llu: This dht entry is expired.\n",
3199                     rh->id);
3200         rh->authority_chain_head->fresh = 0;
3201         rh->proc (rh->proc_cls, rh, 0, NULL);
3202         return;
3203       }
3204
3205       continue;
3206     }
3207
3208     /**
3209      * Resolve rest of query with new authority
3210      */
3211     GNUNET_assert (rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
3212     memcpy (&rh->authority, rd[i].data,
3213             sizeof (struct GNUNET_CRYPTO_ShortHashCode));
3214     struct AuthorityChain *auth = GNUNET_malloc(sizeof (struct AuthorityChain));
3215     auth->zone = rh->authority;
3216     memset (auth->name, 0, strlen (rh->authority_name)+1);
3217     strcpy (auth->name, rh->authority_name);
3218     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
3219                                  rh->authority_chain_tail,
3220                                  auth);
3221     
3222     /* Check for key revocation and delegate */
3223     GNUNET_NAMESTORE_lookup_record (namestore_handle,
3224                                     &rh->authority,
3225                                     "+",
3226                                     GNUNET_GNS_RECORD_REV,
3227                                     &process_pkey_revocation_result_ns,
3228                                     rh);
3229     return;
3230   
3231   }
3232   
3233   /**
3234    * no answers found
3235    */
3236   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3237     "GNS_PHASE_DELEGATE_NS-%llu: Authority lookup and no PKEY...\n", rh->id);
3238   /**
3239    * If we have found some records for the LAST label
3240    * we return the results. Else null.
3241    */
3242   if (strcmp(rh->name, "") == 0)
3243   {
3244     /* Start shortening */
3245     if ((rh->priv_key != NULL) && is_canonical (rh->name))
3246     {
3247       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3248               "GNS_PHASE_DELEGATE_NS-%llu: Trying to shorten authority chain\n",
3249               rh->id);
3250       start_shorten (rh->authority_chain_tail,
3251                     rh->priv_key);
3252     }
3253     /* simply promote back */
3254     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3255                "GNS_PHASE_DELEGATE_NS-%llu: Promoting %s back to name\n",
3256                rh->id, rh->authority_name);
3257     strcpy(rh->name, rh->authority_name);
3258     rh->proc(rh->proc_cls, rh, rd_count, rd);
3259   }
3260   else
3261   {
3262     rh->proc(rh->proc_cls, rh, 0, NULL);
3263   }
3264 }
3265
3266
3267 /**
3268  * Resolve the delegation chain for the request in our namestore
3269  *
3270  * @param rh the resolver handle
3271  */
3272 static void
3273 resolve_delegation_ns (struct ResolverHandle *rh)
3274 {
3275   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3276              "GNS_PHASE_DELEGATE_NS-%llu: Resolving delegation for %s\n",
3277              rh->id, rh->name);
3278   pop_tld(rh->name, rh->authority_name);
3279   GNUNET_NAMESTORE_lookup_record(namestore_handle,
3280                                  &rh->authority,
3281                                  rh->authority_name,
3282                                  GNUNET_GNS_RECORD_ANY,
3283                                  &process_delegation_result_ns,
3284                                  rh);
3285
3286 }
3287
3288
3289 /**
3290  * Lookup of a record in a specific zone
3291  * calls lookup result processor on result
3292  *
3293  * @param zone the root zone
3294  * @param pzone the private local zone
3295  * @param record_type the record type to look up
3296  * @param name the name to look up
3297  * @param key a private key for use with PSEU import (can be NULL)
3298  * @param timeout timeout for resolution
3299  * @param only_cached GNUNET_NO to only check locally not DHT for performance
3300  * @param proc the processor to call on result
3301  * @param cls the closure to pass to proc
3302  */
3303 void
3304 gns_resolver_lookup_record (struct GNUNET_CRYPTO_ShortHashCode zone,
3305                             struct GNUNET_CRYPTO_ShortHashCode pzone,
3306                             uint32_t record_type,
3307                             const char* name,
3308                             struct GNUNET_CRYPTO_RsaPrivateKey *key,
3309                             struct GNUNET_TIME_Relative timeout,
3310                             int only_cached,
3311                             RecordLookupProcessor proc,
3312                             void* cls)
3313 {
3314   struct ResolverHandle *rh;
3315   struct RecordLookupHandle* rlh;
3316   char string_hash[MAX_DNS_LABEL_LENGTH];
3317   char nzkey[MAX_DNS_LABEL_LENGTH];
3318   char* nzkey_ptr = nzkey;
3319
3320   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3321               "Starting resolution for %s (type=%d)!\n",
3322               name, record_type);
3323
3324   
3325   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
3326   {
3327     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3328                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
3329     proc(cls, 0, NULL);
3330     return;
3331   }
3332   
3333   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
3334   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
3335
3336   rh->authority = zone;
3337   rh->id = rid++;
3338   rh->proc_cls = rlh;
3339   rh->priv_key = key;
3340   rh->timeout = timeout;
3341   rh->get_handle = NULL;
3342   rh->private_local_zone = pzone;
3343   rh->only_cached = only_cached;
3344   
3345   if (NULL == key)
3346   {
3347     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3348                 "No shorten key for resolution\n");
3349   }
3350
3351   if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3352   {
3353     /*
3354      * Set timeout for authority lookup phase to 1/2
3355      */
3356     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3357                 "Timeout for lookup set to %ds\n", rh->timeout.rel_value);
3358     rh->timeout_task = GNUNET_SCHEDULER_add_delayed(
3359                                 GNUNET_TIME_relative_divide(timeout, 2),
3360                                                 &handle_lookup_timeout,
3361                                                 rh);
3362     rh->timeout_cont = &dht_authority_lookup_timeout;
3363     rh->timeout_cont_cls = rh;
3364   }
3365   else
3366   {
3367     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "No timeout for query!\n");
3368     rh->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3369   }
3370   
3371   if (strcmp(GNUNET_GNS_TLD, name) == 0)
3372   {
3373     /**
3374      * Only 'gnunet' given
3375      */
3376     strcpy(rh->name, "\0");
3377   }
3378   else
3379   {
3380     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3381                 "Checking for TLD...\n");
3382     if (is_zkey_tld(name) == GNUNET_YES)
3383     {
3384       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3385                   "TLD is zkey\n");
3386       /**
3387        * This is a zkey tld
3388        * build hash and use as initial authority
3389        */
3390       memset(rh->name, 0,
3391              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
3392       memcpy(rh->name, name,
3393              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
3394       pop_tld(rh->name, string_hash);
3395
3396       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3397                   "ZKEY is %s!\n", string_hash);
3398       
3399       GNUNET_STRINGS_utf8_toupper(string_hash, &nzkey_ptr);
3400
3401       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(nzkey,
3402                                                       &rh->authority))
3403       {
3404         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3405                     "Cannot convert ZKEY %s to hash!\n", string_hash);
3406         GNUNET_free(rh);
3407         GNUNET_free(rlh);
3408         proc(cls, 0, NULL);
3409         return;
3410       }
3411
3412     }
3413     else
3414     {
3415       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3416                   "TLD is gnunet\n");
3417       /**
3418        * Presumably GNUNET tld
3419        */
3420       memset(rh->name, 0,
3421              strlen(name)-strlen(GNUNET_GNS_TLD));
3422       memcpy(rh->name, name,
3423              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
3424     }
3425   }
3426   
3427   /**
3428    * Initialize authority chain
3429    */
3430   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
3431   rh->authority_chain_head->prev = NULL;
3432   rh->authority_chain_head->next = NULL;
3433   rh->authority_chain_tail = rh->authority_chain_head;
3434   rh->authority_chain_head->zone = rh->authority;
3435   
3436   /**
3437    * Copy original query into lookup handle
3438    */
3439   rlh->record_type = record_type;
3440   memset(rlh->name, 0, strlen(name) + 1);
3441   strcpy(rlh->name, name);
3442   rlh->proc = proc;
3443   rlh->proc_cls = cls;
3444
3445   rh->proc = &handle_delegation_ns;
3446   resolve_delegation_ns(rh);
3447 }
3448
3449 /******** END Record Resolver ***********/
3450
3451 /**
3452  * Callback calles by namestore for a zone to name
3453  * result
3454  *
3455  * @param cls the closure
3456  * @param zone_key the zone we queried
3457  * @param expire the expiration time of the name
3458  * @param name the name found or NULL
3459  * @param rd_len number of records for the name
3460  * @param rd the record data (PKEY) for the name
3461  * @param signature the signature for the record data
3462  */
3463 static void
3464 process_zone_to_name_shorten_root (void *cls,
3465                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3466                  struct GNUNET_TIME_Absolute expire,
3467                  const char *name,
3468                  unsigned int rd_len,
3469                  const struct GNUNET_NAMESTORE_RecordData *rd,
3470                  const struct GNUNET_CRYPTO_RsaSignature *signature);
3471
3472
3473 /**
3474  * Callback called by namestore for a zone to name
3475  * result
3476  *
3477  * @param cls the closure
3478  * @param zone_key the zone we queried
3479  * @param expire the expiration time of the name
3480  * @param name the name found or NULL
3481  * @param rd_len number of records for the name
3482  * @param rd the record data (PKEY) for the name
3483  * @param signature the signature for the record data
3484  */
3485 static void
3486 process_zone_to_name_shorten_shorten (void *cls,
3487                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3488                  struct GNUNET_TIME_Absolute expire,
3489                  const char *name,
3490                  unsigned int rd_len,
3491                  const struct GNUNET_NAMESTORE_RecordData *rd,
3492                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3493 {
3494   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3495   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3496   struct AuthorityChain *next_authority;
3497
3498   char result[MAX_DNS_NAME_LENGTH];
3499   char tmp_name[MAX_DNS_NAME_LENGTH];
3500   size_t answer_len;
3501   
3502   /* we found a match in our own root zone */
3503   if (rd_len != 0)
3504   {
3505     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3506                "result strlen %d\n", strlen(name));
3507     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3508     memset(result, 0, answer_len);
3509
3510     if (strlen(rh->name) > 0)
3511     {
3512       sprintf (result, "%s.%s.%s.%s.%s",
3513                rh->name, name,
3514                nsh->shorten_zone_name, nsh->private_zone_name,
3515                GNUNET_GNS_TLD);
3516     }
3517     else
3518     {
3519       sprintf (result, "%s.%s.%s.%s", name,
3520                nsh->shorten_zone_name, nsh->private_zone_name,
3521                GNUNET_GNS_TLD);
3522     }
3523     
3524     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3525                "Found shorten result %s\n", result);
3526     if (strlen (nsh->result) > strlen (result))
3527       strcpy (nsh->result, result);
3528   }
3529   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3530                                         nsh->shorten_zone) == 0)
3531   {
3532     /**
3533      * This is our zone append .gnunet unless name is empty
3534      * (it shouldn't be, usually FIXME what happens if we
3535      * shorten to our zone to a "" record??)
3536      */
3537     
3538     sprintf (result, "%s.%s.%s.%s",
3539              rh->name,
3540              nsh->shorten_zone_name, nsh->private_zone_name,
3541              GNUNET_GNS_TLD);
3542     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3543                "Our zone: Found %s as shorten result\n", result);
3544     
3545     if (strlen (nsh->result) > strlen (result))
3546       strcpy (nsh->result, result);
3547     //nsh->proc(nsh->proc_cls, result);
3548     //GNUNET_free(nsh);
3549     //free_resolver_handle(rh);
3550     //return;
3551   }
3552   
3553   
3554   /**
3555    * No PSEU found.
3556    * continue with next authority if exists
3557    */
3558   if ((rh->authority_chain_head->next == NULL))
3559   {
3560     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3561                 "Sending %s as shorten result\n", nsh->result);
3562     nsh->proc(nsh->proc_cls, nsh->result);
3563     GNUNET_free (nsh);
3564     free_resolver_handle (rh);
3565     return;
3566   }
3567   next_authority = rh->authority_chain_head;
3568   
3569   GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3570                   "%s.%s", rh->name, next_authority->name);
3571   
3572   strcpy(rh->name, tmp_name);
3573   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3574              "No PSEU found for authority %s. Promoting back: %s\n",
3575              next_authority->name, rh->name);
3576   
3577   GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3578                             rh->authority_chain_tail,
3579                             next_authority);
3580
3581   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3582                                  &rh->authority_chain_tail->zone,
3583                                  &rh->authority_chain_head->zone,
3584                                  &process_zone_to_name_shorten_root,
3585                                  rh);
3586 }
3587
3588 /**
3589  * Callback calles by namestore for a zone to name
3590  * result
3591  *
3592  * @param cls the closure
3593  * @param zone_key the zone we queried
3594  * @param expire the expiration time of the name
3595  * @param name the name found or NULL
3596  * @param rd_len number of records for the name
3597  * @param rd the record data (PKEY) for the name
3598  * @param signature the signature for the record data
3599  */
3600 static void
3601 process_zone_to_name_shorten_private (void *cls,
3602                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3603                  struct GNUNET_TIME_Absolute expire,
3604                  const char *name,
3605                  unsigned int rd_len,
3606                  const struct GNUNET_NAMESTORE_RecordData *rd,
3607                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3608 {
3609   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3610   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3611   struct AuthorityChain *next_authority;
3612
3613   char result[MAX_DNS_NAME_LENGTH];
3614   char tmp_name[MAX_DNS_NAME_LENGTH];
3615   size_t answer_len;
3616   
3617   /* we found a match in our own root zone */
3618   if (rd_len != 0)
3619   {
3620     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3621                "result strlen %d\n", strlen(name));
3622     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3623     memset(result, 0, answer_len);
3624
3625     if (strlen(rh->name) > 0)
3626     {
3627       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3628     }
3629     else
3630     {
3631       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3632     }
3633     
3634     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3635                "Found shorten result %s\n", result);
3636     if (strlen (nsh->result) > strlen (result))
3637       strcpy (nsh->result, result);
3638   }
3639   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3640                                         nsh->private_zone) == 0)
3641   {
3642     /**
3643      * This is our zone append .gnunet unless name is empty
3644      * (it shouldn't be, usually FIXME what happens if we
3645      * shorten to our zone to a "" record??)
3646      */
3647     
3648     sprintf (result, "%s.%s.%s",
3649              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3650     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3651                "Our private zone: Found %s as shorten result %s\n", result);
3652     if (strlen (nsh->result) > strlen (result))
3653       strcpy (nsh->result, result);
3654   }
3655   
3656   if (nsh->shorten_zone != NULL)
3657   {
3658     /* backtrack authorities for names in priv zone */
3659     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3660                                    nsh->shorten_zone,
3661                                    &rh->authority_chain_head->zone,
3662                                    &process_zone_to_name_shorten_shorten,
3663                                    rh);
3664   }
3665   else
3666   {
3667     /**
3668      * No PSEU found.
3669      * continue with next authority if exists
3670      */
3671     if ((rh->authority_chain_head->next == NULL))
3672     {
3673       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3674                  "Sending %s as shorten result\n", nsh->result);
3675       nsh->proc(nsh->proc_cls, nsh->result);
3676       GNUNET_free(nsh);
3677       free_resolver_handle(rh);
3678       return;
3679     }
3680     next_authority = rh->authority_chain_head;
3681     
3682     GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3683                     "%s.%s", rh->name, next_authority->name);
3684     
3685     strcpy(rh->name, tmp_name);
3686     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3687                "No PSEU found for authority %s. Promoting back: %s\n",
3688                next_authority->name, rh->name);
3689     
3690     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3691                               rh->authority_chain_tail,
3692                               next_authority);
3693
3694     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3695                                    &rh->authority_chain_tail->zone,
3696                                    &rh->authority_chain_head->zone,
3697                                    &process_zone_to_name_shorten_root,
3698                                    rh);
3699   }
3700 }
3701
3702 /**
3703  * Callback calles by namestore for a zone to name
3704  * result
3705  *
3706  * @param cls the closure
3707  * @param zone_key the zone we queried
3708  * @param expire the expiration time of the name
3709  * @param name the name found or NULL
3710  * @param rd_len number of records for the name
3711  * @param rd the record data (PKEY) for the name
3712  * @param signature the signature for the record data
3713  */
3714 static void
3715 process_zone_to_name_shorten_root (void *cls,
3716                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3717                  struct GNUNET_TIME_Absolute expire,
3718                  const char *name,
3719                  unsigned int rd_len,
3720                  const struct GNUNET_NAMESTORE_RecordData *rd,
3721                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3722 {
3723   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
3724   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
3725   struct AuthorityChain *next_authority;
3726
3727   char result[MAX_DNS_NAME_LENGTH];
3728   char tmp_name[MAX_DNS_NAME_LENGTH];
3729   size_t answer_len;
3730   
3731   /* we found a match in our own root zone */
3732   if (rd_len != 0)
3733   {
3734     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3735                "result strlen %d\n", strlen(name));
3736     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
3737     memset(result, 0, answer_len);
3738
3739     if (strlen(rh->name) > 0)
3740     {
3741       sprintf (result, "%s.%s.%s", rh->name, name, GNUNET_GNS_TLD);
3742     }
3743     else
3744     {
3745       sprintf (result, "%s.%s", name, GNUNET_GNS_TLD);
3746     }
3747     
3748     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3749                "Found shorten result %s\n", result);
3750     if (strlen (nsh->result) > strlen (result))
3751       strcpy (nsh->result, result);
3752   }
3753   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3754                                         nsh->root_zone) == 0)
3755   {
3756     /**
3757      * This is our zone append .gnunet unless name is empty
3758      * (it shouldn't be, usually FIXME what happens if we
3759      * shorten to our zone to a "" record??)
3760      */
3761     
3762     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3763     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3764                "Our zone: Found %s as shorten result\n", result);
3765     if (strlen (nsh->result) > strlen (result))
3766       strcpy (nsh->result, result);
3767   }
3768   
3769   if (nsh->private_zone != NULL)
3770   {
3771     /* backtrack authorities for names in priv zone */
3772     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3773                                    nsh->private_zone,
3774                                    &rh->authority_chain_head->zone,
3775                                    &process_zone_to_name_shorten_private,
3776                                    rh);
3777   }
3778   else
3779   {
3780     /**
3781      * No PSEU found.
3782      * continue with next authority if exists
3783      */
3784     if ((rh->authority_chain_head->next == NULL))
3785     {
3786       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3787                  "Sending %s as shorten result\n", nsh->result);
3788       nsh->proc(nsh->proc_cls, nsh->result);
3789       GNUNET_free(nsh);
3790       free_resolver_handle(rh);
3791       return;
3792     }
3793     next_authority = rh->authority_chain_head;
3794     
3795     GNUNET_snprintf(tmp_name, MAX_DNS_NAME_LENGTH,
3796                     "%s.%s", rh->name, next_authority->name);
3797     
3798     strcpy(rh->name, tmp_name);
3799     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3800                "No PSEU found for authority %s. Promoting back: %s\n",
3801                next_authority->name, rh->name);
3802     
3803     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
3804                               rh->authority_chain_tail,
3805                               next_authority);
3806
3807     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3808                                    &rh->authority_chain_tail->zone,
3809                                    &rh->authority_chain_head->zone,
3810                                    &process_zone_to_name_shorten_root,
3811                                    rh);
3812   }
3813 }
3814
3815
3816 /**
3817  * Process result from namestore delegation lookup
3818  * for shorten operation
3819  *
3820  * @param cls the client shorten handle
3821  * @param rh the resolver handle
3822  * @param rd_count number of results (0)
3823  * @param rd data (NULL)
3824  */
3825 void
3826 handle_delegation_ns_shorten (void* cls,
3827                       struct ResolverHandle *rh,
3828                       uint32_t rd_count,
3829                       const struct GNUNET_NAMESTORE_RecordData *rd)
3830 {
3831   struct NameShortenHandle *nsh;
3832   char result[MAX_DNS_NAME_LENGTH];
3833
3834   nsh = (struct NameShortenHandle *)cls;
3835   
3836   /**
3837    * At this point rh->name contains the part of the name
3838    * that we do not have a PKEY in our namestore to resolve.
3839    * The authority chain in the resolver handle is now
3840    * useful to backtrack if needed
3841    */
3842   
3843   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3844              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
3845   memset(result, 0, sizeof (result));
3846
3847   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3848                                    nsh->root_zone) == 0)
3849   {
3850     /**
3851      * This is our zone append .gnunet unless name is empty
3852      * (it shouldn't be, usually FIXME what happens if we
3853      * shorten to our zone to a "" record??)
3854      */
3855     
3856     sprintf (result, "%s.%s", rh->name, GNUNET_GNS_TLD);
3857     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3858                "Our zone: Found %s as shorten result\n", result);
3859     
3860     if (strlen (nsh->result) > strlen (result))
3861       strcpy (nsh->result, result);
3862
3863   }
3864   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3865                                         nsh->private_zone) == 0)
3866   {
3867     /**
3868      * This is our zone append .gnunet unless name is empty
3869      * (it shouldn't be, usually FIXME what happens if we
3870      * shorten to our zone to a "" record??)
3871      */
3872     
3873     sprintf (result, "%s.%s.%s",
3874              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3875     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3876                "Our zone: Found %s as shorten result %s\n", result);
3877     
3878     if (strlen (nsh->result) > strlen (result))
3879       strcpy (nsh->result, result);
3880   }
3881   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
3882                                         nsh->shorten_zone) == 0)
3883   {
3884     /**
3885      * This is our zone append .gnunet unless name is empty
3886      * (it shouldn't be, usually FIXME what happens if we
3887      * shorten to our zone to a "" record??)
3888      */
3889     
3890     sprintf (result, "%s.%s.%s",
3891              rh->name, nsh->private_zone_name, GNUNET_GNS_TLD);
3892     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3893                "Our zone: Found %s as shorten result\n", result);
3894     
3895     if (strlen (nsh->result) > strlen (result))
3896       strcpy (nsh->result, result);
3897   }
3898   
3899   
3900   /* backtrack authorities for names */
3901   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
3902                                  nsh->root_zone,
3903                                  &rh->authority_chain_head->zone,
3904                                  &process_zone_to_name_shorten_root,
3905                                  rh);
3906   
3907 }
3908
3909
3910 /**
3911  * Callback calles by namestore for a zone to name
3912  * result
3913  *
3914  * @param cls the closure
3915  * @param zone_key the zone we queried
3916  * @param expire the expiration time of the name
3917  * @param name the name found or NULL
3918  * @param rd_len number of records for the name
3919  * @param rd the record data (PKEY) for the name
3920  * @param signature the signature for the record data
3921  */
3922 static void
3923 process_zone_to_name_zkey(void *cls,
3924                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
3925                  struct GNUNET_TIME_Absolute expire,
3926                  const char *name,
3927                  unsigned int rd_len,
3928                  const struct GNUNET_NAMESTORE_RecordData *rd,
3929                  const struct GNUNET_CRYPTO_RsaSignature *signature)
3930 {
3931   struct ResolverHandle *rh = cls;
3932   struct NameShortenHandle *nsh = rh->proc_cls;
3933   struct GNUNET_CRYPTO_ShortHashAsciiEncoded enc;
3934   char new_name[MAX_DNS_NAME_LENGTH];
3935
3936   /* zkey not in our zone */
3937   if (name == NULL)
3938   {
3939     /**
3940      * In this case we have not given this PKEY a name (yet)
3941      * It is either just not in our zone or not even cached
3942      * Since we do not know at this point we will not try to shorten
3943      * because PKEY import will happen if the user follows the zkey
3944      * link.
3945      */
3946     GNUNET_CRYPTO_short_hash_to_enc ((struct GNUNET_CRYPTO_ShortHashCode*)rd,
3947                                      &enc);
3948     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3949                "No name found for zkey %s returning verbatim!\n", enc);
3950     if (strcmp(rh->name, "") != 0)
3951       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s.%s",
3952                       rh->name, enc, GNUNET_GNS_TLD_ZKEY);
3953     else
3954       GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
3955                       enc, GNUNET_GNS_TLD_ZKEY);
3956
3957     strcpy (nsh->result, new_name);
3958
3959     nsh->proc(nsh->proc_cls, new_name);
3960     GNUNET_free(nsh);
3961     free_resolver_handle(rh);
3962     return;
3963   }
3964   
3965   if (strcmp(rh->name, "") != 0)
3966     GNUNET_snprintf(new_name, MAX_DNS_NAME_LENGTH, "%s.%s",
3967                     rh->name, name);
3968   else
3969     strcpy(new_name, name);
3970
3971   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
3972              "Continue shorten for %s!\n", new_name);
3973
3974   strcpy(rh->name, new_name);
3975   
3976   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
3977   rh->authority_chain_tail = rh->authority_chain_head;
3978   rh->authority_chain_head->zone = rh->authority;
3979   
3980   
3981   /* Start delegation resolution in our namestore */
3982   resolve_delegation_ns(rh);
3983 }
3984
3985
3986 /**
3987  * Shorten api from resolver
3988  *
3989  * @param zone the root zone to use
3990  * @param pzone the private zone to use
3991  * @param szone the shorten zone to use
3992  * @param name the name to shorten
3993  * @param private_zone_name name of the private zone
3994  * @param shorten_zone_name name of the shorten zone
3995  * @param proc the processor to call with result
3996  * @param proc_cls closure to pass to proc
3997  */
3998 void
3999 gns_resolver_shorten_name (struct GNUNET_CRYPTO_ShortHashCode *zone,
4000                            struct GNUNET_CRYPTO_ShortHashCode *pzone,
4001                            struct GNUNET_CRYPTO_ShortHashCode *szone,
4002                            const char* name,
4003                            const char* private_zone_name,
4004                            const char* shorten_zone_name,
4005                            ShortenResultProcessor proc,
4006                            void* proc_cls)
4007 {
4008   struct ResolverHandle *rh;
4009   struct NameShortenHandle *nsh;
4010   char string_hash[MAX_DNS_LABEL_LENGTH];
4011   struct GNUNET_CRYPTO_ShortHashCode zkey;
4012   char nzkey[MAX_DNS_LABEL_LENGTH];
4013   char* nzkey_ptr = nzkey;
4014
4015
4016   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4017               "Starting shorten for %s!\n", name);
4018   
4019   if (is_canonical ((char*)name))
4020   {
4021     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4022                 "%s is canonical. Returning verbatim\n", name);
4023     proc (proc_cls, name);
4024     return;
4025   }
4026
4027   nsh = GNUNET_malloc (sizeof (struct NameShortenHandle));
4028
4029   nsh->proc = proc;
4030   nsh->proc_cls = proc_cls;
4031   nsh->root_zone = zone;
4032   nsh->private_zone = pzone;
4033   nsh->shorten_zone = szone;
4034   strcpy (nsh->private_zone_name, private_zone_name);
4035   strcpy (nsh->shorten_zone_name, shorten_zone_name);
4036   strcpy (nsh->result, name);
4037   
4038   rh = GNUNET_malloc (sizeof (struct ResolverHandle));
4039   rh->authority = *zone;
4040   rh->id = rid++;
4041   rh->priv_key = NULL;
4042   rh->proc = &handle_delegation_ns_shorten;
4043   rh->proc_cls = nsh;
4044   rh->id = rid++;
4045   rh->private_local_zone = *zone;
4046   
4047   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4048                 "Checking for TLD...\n");
4049   if (is_zkey_tld (name) == GNUNET_YES)
4050   {
4051     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4052                 "TLD is zkey\n");
4053     /**
4054      * This is a zkey tld
4055      * build hash and use as initial authority
4056      * FIXME sscanf
4057      */
4058     memset (rh->name, 0,
4059             strlen (name)-strlen (GNUNET_GNS_TLD_ZKEY));
4060     memcpy (rh->name, name,
4061             strlen(name)-strlen (GNUNET_GNS_TLD_ZKEY) - 1);
4062     pop_tld (rh->name, string_hash);
4063
4064     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4065                 "ZKEY is %s!\n", string_hash);
4066     
4067     GNUNET_STRINGS_utf8_toupper (string_hash, &nzkey_ptr);
4068
4069     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string (nzkey,
4070                                                            &zkey))
4071     {
4072       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4073                   "Cannot convert ZKEY %s to hash!\n", nzkey);
4074       GNUNET_free (rh);
4075       GNUNET_free (nsh);
4076       proc (proc_cls, name);
4077       return;
4078     }
4079
4080     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
4081                                    zone, //ours
4082                                    &zkey,
4083                                    &process_zone_to_name_zkey,
4084                                    rh);
4085     return;
4086
4087   }
4088   else
4089   {
4090     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4091                 "TLD is gnunet\n");
4092     /**
4093      * Presumably GNUNET tld
4094      */
4095     memset (rh->name, 0,
4096             strlen (name)-strlen (GNUNET_GNS_TLD));
4097     memcpy (rh->name, name,
4098             strlen (name)-strlen (GNUNET_GNS_TLD) - 1);
4099   }
4100
4101   rh->authority_chain_head = GNUNET_malloc (sizeof (struct AuthorityChain));
4102   rh->authority_chain_tail = rh->authority_chain_head;
4103   rh->authority_chain_head->zone = *zone;
4104   
4105   
4106   /* Start delegation resolution in our namestore */
4107   resolve_delegation_ns (rh);
4108 }
4109
4110 /*********** END NAME SHORTEN ********************/
4111
4112
4113 /**
4114  * Process result from namestore delegation lookup
4115  * for get authority operation
4116  *
4117  * @param cls the client get auth handle
4118  * @param rh the resolver handle
4119  * @param rd_count number of results (0)
4120  * @param rd data (NULL)
4121  */
4122 void
4123 handle_delegation_result_ns_get_auth(void* cls,
4124                       struct ResolverHandle *rh,
4125                       uint32_t rd_count,
4126                       const struct GNUNET_NAMESTORE_RecordData *rd)
4127 {
4128   struct GetNameAuthorityHandle* nah;
4129   char result[MAX_DNS_NAME_LENGTH];
4130   size_t answer_len;
4131
4132   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
4133   
4134   /**
4135    * At this point rh->name contains the part of the name
4136    * that we do not have a PKEY in our namestore to resolve.
4137    * The authority chain in the resolver handle is now
4138    * useful to backtrack if needed
4139    */
4140   
4141   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4142              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
4143
4144   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4145              "Building response!\n");
4146   if (is_canonical(rh->name))
4147   {
4148     /**
4149      * We successfully resolved the authority in the ns
4150      * FIXME for our purposes this is fine
4151      * but maybe we want to have an api that also looks
4152      * into the dht (i.e. option in message)
4153      **/
4154     if (strlen(rh->name) > strlen(nah->name))
4155     {
4156       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4157                  "Record name longer than original lookup name... odd!\n");
4158       //FIXME to sth here
4159     }
4160
4161     answer_len = strlen(nah->name) - strlen(rh->name)
4162       + strlen(GNUNET_GNS_TLD) + 1;
4163     memset(result, 0, answer_len);
4164     strcpy(result, nah->name + strlen(rh->name) + 1);
4165
4166     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4167                "Got authority result %s\n", result);
4168     
4169     nah->proc(nah->proc_cls, result);
4170     GNUNET_free(nah);
4171     free_resolver_handle(rh);
4172   }
4173   else
4174   {
4175     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
4176                "Unable to resolve authority for remaining %s!\n", rh->name);
4177     nah->proc(nah->proc_cls, "");
4178     GNUNET_free(nah);
4179     free_resolver_handle(rh);
4180   }
4181
4182
4183 }
4184
4185
4186 /**
4187  * Tries to resolve the authority for name
4188  * in our namestore
4189  *
4190  * @param zone the root zone to look up for
4191  * @param pzone the private local zone
4192  * @param name the name to lookup up
4193  * @param proc the processor to call when finished
4194  * @param proc_cls the closure to pass to the processor
4195  */
4196 void
4197 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
4198                            struct GNUNET_CRYPTO_ShortHashCode pzone,
4199                            const char* name,
4200                            GetAuthorityResultProcessor proc,
4201                            void* proc_cls)
4202 {
4203   struct ResolverHandle *rh;
4204   struct GetNameAuthorityHandle *nah;
4205
4206   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4207               "Starting authority resolution for %s!\n", name);
4208
4209   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
4210   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
4211   rh->authority = zone;
4212   rh->id = rid++;
4213   rh->private_local_zone = pzone;
4214   
4215   if (strcmp(GNUNET_GNS_TLD, name) == 0)
4216   {
4217     strcpy(rh->name, "\0");
4218   }
4219   else
4220   {
4221     memset(rh->name, 0,
4222            strlen(name)-strlen(GNUNET_GNS_TLD));
4223     memcpy(rh->name, name,
4224            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
4225   }
4226
4227   memset(nah->name, 0,
4228          strlen(name)+1);
4229   strcpy(nah->name, name);
4230   
4231   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
4232   rh->authority_chain_tail = rh->authority_chain_head;
4233   rh->authority_chain_head->zone = zone;
4234   rh->proc = &handle_delegation_result_ns_get_auth;
4235   rh->proc_cls = (void*)nah;
4236
4237   nah->proc = proc;
4238   nah->proc_cls = proc_cls;
4239
4240   /* Start delegation resolution in our namestore */
4241   resolve_delegation_ns(rh);
4242
4243 }
4244
4245 /******** END GET AUTHORITY *************/
4246
4247 /* end of gnunet-service-gns_resolver.c */