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