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