e95030db670589c81401c16c625be65d96a5cbf0
[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_dns_service.h"
35 #include "gnunet_dnsparser_lib.h"
36 #include "gnunet_gns_service.h"
37 #include "block_gns.h"
38 #include "gns.h"
39 #include "gnunet-service-gns_resolver.h"
40
41 #define DHT_OPERATION_TIMEOUT  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
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  * Resolver handle to the dht
54  */
55 static struct GNUNET_DHT_Handle *dht_handle;
56
57 /**
58  * Namestore calls this function if we have record for this name.
59  * (or with rd_count=0 to indicate no matches)
60  *
61  * @param cls the pending query
62  * @param key the key of the zone we did the lookup
63  * @param expiration expiration date of the namestore entry
64  * @param name the name for which we need an authority
65  * @param rd_count the number of records with 'name'
66  * @param rd the record data
67  * @param signature the signature of the authority for the record data
68  */
69 static void
70 process_pseu_lookup_ns(void* cls,
71                       const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
72                       struct GNUNET_TIME_Absolute expiration,
73                       const char *name, unsigned int rd_count,
74                       const struct GNUNET_NAMESTORE_RecordData *rd,
75                       const struct GNUNET_CRYPTO_RsaSignature *signature)
76 {
77   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
78   struct GNUNET_NAMESTORE_RecordData new_pkey;
79
80   if (rd_count > 0)
81   {
82     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
83                "Name %s already taken in NS!\n", name);
84     if (0 == strcmp(gph->name, name))
85     {
86       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
87                  "Intelligent replacement not implemented\n", name);
88       GNUNET_free(gph);
89       return;
90     }
91
92     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
93                "Trying delegated name %s\n", gph->name);
94     memcpy(gph->new_name, gph->name, strlen(gph->name)+1);
95     GNUNET_NAMESTORE_lookup_record(namestore_handle,
96                                    &gph->zone,
97                                    gph->new_name,
98                                    GNUNET_GNS_RECORD_PSEU,
99                                    &process_pseu_lookup_ns,
100                                    gph);
101     return;
102   }
103
104   /** name is free */
105   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
106              "Name %s not taken in NS! Adding\n", gph->new_name);
107
108   new_pkey.expiration = GNUNET_TIME_absolute_get_forever ();
109   new_pkey.data_size = sizeof(struct GNUNET_CRYPTO_ShortHashCode);
110   new_pkey.data = &gph->new_zone;
111   new_pkey.record_type = GNUNET_GNS_RECORD_PKEY;
112   GNUNET_NAMESTORE_record_create (namestore_handle,
113                                   gph->key,
114                                   gph->new_name,
115                                   &new_pkey,
116                                   NULL, //cont
117                                   NULL); //cls
118   GNUNET_free(gph);
119
120 }
121
122 /**
123  * process result of a dht pseu lookup
124  *
125  * @param gph the handle
126  * @param name the pseu result or NULL
127  */
128 static void
129 process_pseu_result(struct GetPseuAuthorityHandle* gph, char* name)
130 {
131   if (NULL == name)
132   {
133     memcpy(gph->new_name, name, strlen(gph->name)+1);
134   }
135   else
136   {
137     memcpy(gph->new_name, name, strlen(name)+1);
138   }
139
140   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
141              "Checking %s for collision in NS\n", gph->new_name);
142
143   /**
144    * Check for collision
145    */
146   GNUNET_NAMESTORE_lookup_record(namestore_handle,
147                                  &gph->zone,
148                                  gph->new_name,
149                                  GNUNET_GNS_RECORD_PSEU,
150                                  &process_pseu_lookup_ns,
151                                  gph);
152 }
153
154 /**
155  * Handle timeout for dht request
156  *
157  * @param cls the request handle as closure
158  * @param tc the task context
159  */
160 static void
161 handle_auth_discovery_timeout(void *cls,
162                               const struct GNUNET_SCHEDULER_TaskContext *tc)
163 {
164   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
165
166   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
167              "dht lookup for query PSEU timed out.\n");
168   GNUNET_DHT_get_stop (gph->get_handle);
169   process_pseu_result(gph, NULL);
170 }
171
172 /**
173  * Function called when we find a PSEU entry in the DHT
174  *
175  * @param cls the request handle
176  * @param exp lifetime
177  * @param key the key the record was stored under
178  * @param get_path get path
179  * @param get_path_length get path length
180  * @param put_path put path
181  * @param put_path_length put path length
182  * @param type the block type
183  * @param size the size of the record
184  * @param data the record data
185  */
186 static void
187 process_auth_discovery_dht_result(void* cls,
188                                   struct GNUNET_TIME_Absolute exp,
189                                   const GNUNET_HashCode * key,
190                                   const struct GNUNET_PeerIdentity *get_path,
191                                   unsigned int get_path_length,
192                                   const struct GNUNET_PeerIdentity *put_path,
193                                   unsigned int put_path_length,
194                                   enum GNUNET_BLOCK_Type type,
195                                   size_t size, const void *data)
196 {
197   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
198   struct GNSNameRecordBlock *nrb;
199   char* rd_data = (char*)data;
200   char* name;
201   int num_records;
202   size_t rd_size;
203   int i;
204
205   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
206
207   if (data == NULL)
208   {
209     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "got dht result null!\n", size);
210     GNUNET_break(0);
211     GNUNET_free(gph);
212     return;
213   }
214   
215   nrb = (struct GNSNameRecordBlock*)data;
216
217   /* stop lookup and timeout task */
218   GNUNET_DHT_get_stop (gph->get_handle);
219   GNUNET_SCHEDULER_cancel(gph->dht_timeout);
220
221   gph->get_handle = NULL;
222
223   nrb = (struct GNSNameRecordBlock*)data;
224   
225   name = (char*)&nrb[1];
226   num_records = ntohl(nrb->rd_count);
227   {
228     struct GNUNET_NAMESTORE_RecordData rd[num_records];
229
230     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
231     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
232
233     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
234                                                                rd_data,
235                                                                num_records,
236                                                                rd))
237     {
238       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
239       GNUNET_break(0);
240       GNUNET_free(gph);
241       return;
242     }
243
244     for (i=0; i<num_records; i++)
245     {
246       if ((strcmp(name, "+") == 0) &&
247           (rd[i].record_type == GNUNET_GNS_RECORD_PSEU))
248       {
249         /* found pseu */
250         process_pseu_result(gph, (char*)rd[i].data);
251         return;
252       }
253     }
254   }
255
256   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "no pseu in dht!\n");
257   process_pseu_result(gph, NULL);
258 }
259
260 /**
261  * Callback called by namestore for a zone to name
262  * result
263  *
264  * @param cls the closure
265  * @param zone_key the zone we queried
266  * @param expire the expiration time of the name
267  * @param name the name found or NULL
268  * @param rd_len number of records for the name
269  * @param rd the record data (PKEY) for the name
270  * @param signature the signature for the record data
271  */
272 static void
273 process_zone_to_name_discover(void *cls,
274                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
275                  struct GNUNET_TIME_Absolute expire,
276                  const char *name,
277                  unsigned int rd_len,
278                  const struct GNUNET_NAMESTORE_RecordData *rd,
279                  const struct GNUNET_CRYPTO_RsaSignature *signature)
280 {
281   struct GetPseuAuthorityHandle* gph = (struct GetPseuAuthorityHandle*)cls;
282
283   /* we found a match in our own zone */
284   if (rd_len != 0)
285   {
286     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
287                "name for zone in our root %d\n", strlen(name));
288     GNUNET_free(gph);
289   }
290   else
291   {
292     /**
293      * No name found.
294      * check dht
295      */
296     uint32_t xquery;
297     struct GNUNET_CRYPTO_ShortHashCode name_hash;
298     GNUNET_HashCode lookup_key;
299     struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
300     GNUNET_HashCode name_hash_double;
301     GNUNET_HashCode zone_hash_double;
302
303     GNUNET_CRYPTO_short_hash("+", strlen("+"), &name_hash);
304     GNUNET_CRYPTO_short_hash_double (&name_hash, &name_hash_double);
305     GNUNET_CRYPTO_short_hash_double (&gph->new_zone, &zone_hash_double);
306     GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
307     GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
308
309     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
310                "starting dht lookup for %s with key: %s\n",
311                "+", (char*)&lookup_key_string);
312
313     gph->dht_timeout = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
314                                          &handle_auth_discovery_timeout, gph);
315
316     xquery = htonl(GNUNET_GNS_RECORD_PSEU);
317
318     gph->get_handle = GNUNET_DHT_get_start(dht_handle,
319                                            DHT_OPERATION_TIMEOUT,
320                                            GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
321                                            &lookup_key,
322                                            DHT_GNS_REPLICATION_LEVEL,
323                                            GNUNET_DHT_RO_NONE,
324                                            &xquery,
325                                            sizeof(xquery),
326                                            &process_auth_discovery_dht_result,
327                                            gph);
328
329   }
330 }
331
332
333 /**
334  * Callback for new authories
335  *
336  * @param name the name given by delegation
337  * @param zone the authority
338  * @param the private key of our authority
339  */
340 static void process_discovered_authority(char* name,
341                                     struct GNUNET_CRYPTO_ShortHashCode zone,
342                                     struct GNUNET_CRYPTO_ShortHashCode our_zone,
343                                     struct GNUNET_CRYPTO_RsaPrivateKey *key)
344 {
345   struct GetPseuAuthorityHandle *gph;
346   size_t namelen;
347
348   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "New authority %s discovered\n",
349              name);
350
351   gph = GNUNET_malloc(sizeof(struct GetPseuAuthorityHandle));
352   namelen = strlen(name) + 1;
353   memcpy(gph->name, name, namelen);
354   
355   gph->new_zone = zone;
356   gph->zone = our_zone;
357   gph->key = key;
358
359   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
360                                  &our_zone,
361                                  &gph->new_zone,
362                                  &process_zone_to_name_discover,
363                                  gph);
364
365 }
366
367 /**
368  * Initialize the resolver
369  *
370  * @param nh the namestore handle
371  * @param dh the dht handle
372  * @return GNUNET_OK on success
373  */
374 int
375 gns_resolver_init(struct GNUNET_NAMESTORE_Handle *nh,
376                   struct GNUNET_DHT_Handle *dh)
377 {
378   namestore_handle = nh;
379   dht_handle = dh;
380   if ((namestore_handle != NULL) && (dht_handle != NULL))
381   {
382     return GNUNET_OK;
383   }
384   return GNUNET_SYSERR;
385 }
386
387
388 /**
389  * Helper function to free resolver handle
390  *
391  * @rh the handle to free
392  */
393 static void
394 free_resolver_handle(struct ResolverHandle* rh)
395 {
396   struct AuthorityChain *ac;
397   struct AuthorityChain *ac_next;
398
399   if (NULL == rh)
400     return;
401
402   ac = rh->authority_chain_head;
403
404   while (NULL != ac)
405   {
406     ac_next = ac->next;
407     GNUNET_free(ac);
408     ac = ac_next;
409   }
410   GNUNET_free(rh);
411 }
412
413
414 /**
415  * Callback when record data is put into namestore
416  *
417  * @param cls the closure
418  * @param success GNUNET_OK on success
419  * @param emsg the error message. NULL if SUCCESS==GNUNET_OK
420  */
421 void
422 on_namestore_record_put_result(void *cls,
423                                int32_t success,
424                                const char *emsg)
425 {
426   if (GNUNET_NO == success)
427   {
428     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "records already in namestore\n");
429     return;
430   }
431   else if (GNUNET_YES == success)
432   {
433     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
434                "records successfully put in namestore\n");
435     return;
436   }
437
438   GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
439              "Error putting records into namestore: %s\n", emsg);
440 }
441
442
443 /**
444  * Handle timeout for DHT requests
445  *
446  * @param cls the request handle as closure
447  * @param tc the task context
448  */
449 static void
450 dht_lookup_timeout(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
451 {
452   struct ResolverHandle *rh = cls;
453
454   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
455              "dht lookup for query %s timed out.\n",
456              rh->name);
457
458   GNUNET_DHT_get_stop (rh->get_handle);
459   rh->proc(rh->proc_cls, rh, 0, NULL);
460 }
461
462
463 /**
464  * Function called when we get a result from the dht
465  * for our record query
466  *
467  * @param cls the request handle
468  * @param exp lifetime
469  * @param key the key the record was stored under
470  * @param get_path get path
471  * @param get_path_length get path length
472  * @param put_path put path
473  * @param put_path_length put path length
474  * @param type the block type
475  * @param size the size of the record
476  * @param data the record data
477  */
478 static void
479 process_record_result_dht(void* cls,
480                  struct GNUNET_TIME_Absolute exp,
481                  const GNUNET_HashCode * key,
482                  const struct GNUNET_PeerIdentity *get_path,
483                  unsigned int get_path_length,
484                  const struct GNUNET_PeerIdentity *put_path,
485                  unsigned int put_path_length,
486                  enum GNUNET_BLOCK_Type type,
487                  size_t size, const void *data)
488 {
489   struct ResolverHandle *rh;
490   struct RecordLookupHandle *rlh;
491   struct GNSNameRecordBlock *nrb;
492   uint32_t num_records;
493   char* name = NULL;
494   char* rd_data = (char*)data;
495   int i;
496   int rd_size;
497   
498   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "got dht result (size=%d)\n", size);
499   
500   if (data == NULL)
501     return;
502
503   //FIXME maybe check expiration here, check block type
504   
505   rh = (struct ResolverHandle *)cls;
506   rlh = (struct RecordLookupHandle *) rh->proc_cls;
507   nrb = (struct GNSNameRecordBlock*)data;
508   
509   /* stop lookup and timeout task */
510   GNUNET_DHT_get_stop (rh->get_handle);
511   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
512   
513   rh->get_handle = NULL;
514   name = (char*)&nrb[1];
515   num_records = ntohl(nrb->rd_count);
516   {
517     struct GNUNET_NAMESTORE_RecordData rd[num_records];
518
519     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
520     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
521   
522     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
523                                                                rd_data,
524                                                                num_records,
525                                                                rd))
526     {
527       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
528       return;
529     }
530
531     for (i=0; i<num_records; i++)
532     {
533       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
534                "Got name: %s (wanted %s)\n", name, rh->name);
535       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
536                "Got type: %d\n",
537                rd[i].record_type);
538       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
539                "Got data length: %d\n", rd[i].data_size);
540       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
541                "Got flag %d\n", rd[i].flags);
542     
543      if ((strcmp(name, rh->name) == 0) &&
544          (rd[i].record_type == rlh->record_type))
545       {
546         rh->answered++;
547       }
548
549     }
550
551     /**
552      * FIXME check pubkey against existing key in namestore?
553      * https://gnunet.org/bugs/view.php?id=2179
554      */
555
556     /* Save to namestore */
557     GNUNET_NAMESTORE_record_put (namestore_handle,
558                                  &nrb->public_key,
559                                  name,
560                                  exp,
561                                  num_records,
562                                  rd,
563                                  &nrb->signature,
564                                  &on_namestore_record_put_result, //cont
565                                  NULL); //cls
566   
567     if (rh->answered)
568       rh->proc(rh->proc_cls, rh, num_records, rd);
569     else
570       rh->proc(rh->proc_cls, rh, 0, NULL);
571   }
572
573 }
574
575
576 /**
577  * Start DHT lookup for a (name -> query->record_type) record in
578  * rh->authority's zone
579  *
580  * @param rh the pending gns query context
581  */
582 static void
583 resolve_record_dht(struct ResolverHandle *rh)
584 {
585   uint32_t xquery;
586   struct GNUNET_CRYPTO_ShortHashCode name_hash;
587   GNUNET_HashCode lookup_key;
588   GNUNET_HashCode name_hash_double;
589   GNUNET_HashCode zone_hash_double;
590   struct GNUNET_CRYPTO_HashAsciiEncoded lookup_key_string;
591   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
592   
593   GNUNET_CRYPTO_short_hash(rh->name, strlen(rh->name), &name_hash);
594   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
595   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
596   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
597   GNUNET_CRYPTO_hash_to_enc (&lookup_key, &lookup_key_string);
598   
599   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
600              "starting dht lookup for %s with key: %s\n",
601              rh->name, (char*)&lookup_key_string);
602
603   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed(DHT_LOOKUP_TIMEOUT,
604                                                       &dht_lookup_timeout, rh);
605
606   xquery = htonl(rlh->record_type);
607   rh->get_handle = GNUNET_DHT_get_start(dht_handle, 
608                        DHT_OPERATION_TIMEOUT,
609                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
610                        &lookup_key,
611                        DHT_GNS_REPLICATION_LEVEL,
612                        GNUNET_DHT_RO_NONE,
613                        &xquery, 
614                        sizeof(xquery),
615                        &process_record_result_dht,
616                        rh);
617
618 }
619
620
621 /**
622  * Namestore calls this function if we have record for this name.
623  * (or with rd_count=0 to indicate no matches)
624  *
625  * @param cls the pending query
626  * @param key the key of the zone we did the lookup
627  * @param expiration expiration date of the namestore entry
628  * @param name the name for which we need an authority
629  * @param rd_count the number of records with 'name'
630  * @param rd the record data
631  * @param signature the signature of the authority for the record data
632  */
633 static void
634 process_record_result_ns(void* cls,
635                   const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
636                   struct GNUNET_TIME_Absolute expiration,
637                   const char *name, unsigned int rd_count,
638                   const struct GNUNET_NAMESTORE_RecordData *rd,
639                   const struct GNUNET_CRYPTO_RsaSignature *signature)
640 {
641   struct ResolverHandle *rh;
642   struct RecordLookupHandle *rlh;
643   struct GNUNET_TIME_Relative remaining_time;
644   struct GNUNET_CRYPTO_ShortHashCode zone;
645
646   rh = (struct ResolverHandle *) cls;
647   rlh = (struct RecordLookupHandle *)rh->proc_cls;
648   GNUNET_CRYPTO_short_hash(key,
649                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
650                      &zone);
651   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
652
653   rh->status = 0;
654   
655   if (name != NULL)
656   {
657     rh->status |= EXISTS;
658   }
659   
660   if (remaining_time.rel_value == 0)
661   {
662     rh->status |= EXPIRED;
663   }
664   
665   if (rd_count == 0)
666   {
667     /**
668      * Lookup terminated and no results
669      */
670     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
671                "Namestore lookup for %s terminated without results\n", name);
672
673     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
674                "Record %s unknown in namestore\n",
675                rh->name);
676     /**
677      * Our zone and no result? Cannot resolve TT
678      */
679     rh->proc(rh->proc_cls, rh, 0, NULL);
680     return;
681
682   }
683   else
684   {
685     
686     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
687                "Processing additional result %s from namestore\n", name);
688     int i;
689     for (i=0; i<rd_count;i++)
690     {
691
692       if (rd[i].record_type != rlh->record_type)
693         continue;
694       
695       if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
696           == 0)
697       {
698         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
699                    "This record is expired. Skipping\n");
700         continue;
701       }
702       
703       rh->answered++;
704       
705     }
706     
707     /**
708      * no answers found
709      */
710     if (rh->answered == 0)
711     {
712       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
713                  "No answers found. This is odd!\n");
714       rh->proc(rh->proc_cls, rh, 0, NULL);
715       return;
716     }
717     
718     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Found %d answer(s) to query!\n",
719                rh->answered);
720
721     rh->proc(rh->proc_cls, rh, rd_count, rd);
722   }
723 }
724
725
726 /**
727  * The final phase of resolution.
728  * rh->name is a name that is canonical and we do not have a delegation.
729  * Query namestore for this record
730  *
731  * @param rh the pending lookup
732  */
733 static void
734 resolve_record_ns(struct ResolverHandle *rh)
735 {
736   struct RecordLookupHandle *rlh = (struct RecordLookupHandle *)rh->proc_cls;
737   
738   /**
739    * Try to resolve this record in our namestore.
740    * The name to resolve is now in rh->authority_name
741    * since we tried to resolve it to an authority
742    * and failed.
743    **/
744   GNUNET_NAMESTORE_lookup_record(namestore_handle,
745                                  &rh->authority,
746                                  rh->name,
747                                  rlh->record_type,
748                                  &process_record_result_ns,
749                                  rh);
750 }
751
752
753 /**
754  * Handle timeout for DHT requests
755  *
756  * @param cls the request handle as closure
757  * @param tc the task context
758  */
759 static void
760 dht_authority_lookup_timeout(void *cls,
761                              const struct GNUNET_SCHEDULER_TaskContext *tc)
762 {
763   struct ResolverHandle *rh = cls;
764
765   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
766              "dht lookup for query %s timed out.\n",
767              rh->name);
768
769   GNUNET_DHT_get_stop (rh->get_handle);
770   if (strcmp(rh->name, "") == 0)
771   {
772     /*
773      * promote authority back to name and try to resolve record
774      */
775     strcpy(rh->name, rh->authority_name);
776   }
777   rh->proc(rh->proc_cls, rh, 0, NULL);
778 }
779
780 /* Prototype */
781 static void resolve_delegation_dht(struct ResolverHandle *rh);
782
783 /**
784  * Function called when we get a result from the dht
785  * for our query. Recursively tries to resolve authorities
786  * for name in DHT.
787  *
788  * @param cls the request handle
789  * @param exp lifetime
790  * @param key the key the record was stored under
791  * @param get_path get path
792  * @param get_path_length get path length
793  * @param put_path put path
794  * @param put_path_length put path length
795  * @param type the block type
796  * @param size the size of the record
797  * @param data the record data
798  */
799 static void
800 process_delegation_result_dht(void* cls,
801                  struct GNUNET_TIME_Absolute exp,
802                  const GNUNET_HashCode * key,
803                  const struct GNUNET_PeerIdentity *get_path,
804                  unsigned int get_path_length,
805                  const struct GNUNET_PeerIdentity *put_path,
806                  unsigned int put_path_length,
807                  enum GNUNET_BLOCK_Type type,
808                  size_t size, const void *data)
809 {
810   struct ResolverHandle *rh;
811   struct GNSNameRecordBlock *nrb;
812   uint32_t num_records;
813   char* name = NULL;
814   char* rd_data = (char*) data;
815   int i;
816   int rd_size;
817   struct GNUNET_CRYPTO_ShortHashCode zone, name_hash;
818   GNUNET_HashCode zone_hash_double, name_hash_double;
819   
820   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got DHT result\n");
821
822   if (data == NULL)
823     return;
824   
825   //FIXME check expiration?
826   
827   rh = (struct ResolverHandle *)cls;
828   nrb = (struct GNSNameRecordBlock*)data;
829   
830   /* stop dht lookup and timeout task */
831   GNUNET_DHT_get_stop (rh->get_handle);
832   GNUNET_SCHEDULER_cancel(rh->dht_timeout_task);
833
834   rh->get_handle = NULL;
835   num_records = ntohl(nrb->rd_count);
836   name = (char*)&nrb[1];
837   {
838     struct GNUNET_NAMESTORE_RecordData rd[num_records];
839     
840     rd_data += strlen(name) + 1 + sizeof(struct GNSNameRecordBlock);
841     rd_size = size - strlen(name) - 1 - sizeof(struct GNSNameRecordBlock);
842   
843     if (GNUNET_SYSERR == GNUNET_NAMESTORE_records_deserialize (rd_size,
844                                                                rd_data,
845                                                                num_records,
846                                                                rd))
847     {
848       GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error deserializing data!\n");
849       return;
850     }
851
852     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
853                "Got name: %s (wanted %s)\n", name, rh->authority_name);
854     for (i=0; i<num_records; i++)
855     {
856     
857       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
858                 "Got name: %s (wanted %s)\n", name, rh->authority_name);
859       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
860                  "Got type: %d (wanted %d)\n",
861                  rd[i].record_type, GNUNET_GNS_RECORD_PKEY);
862       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
863                  "Got data length: %d\n", rd[i].data_size);
864       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
865                  "Got flag %d\n", rd[i].flags);
866
867       if ((strcmp(name, rh->authority_name) == 0) &&
868           (rd[i].record_type == GNUNET_GNS_RECORD_PKEY))
869       {
870         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Authority found in DHT\n");
871         rh->answered = 1;
872         memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
873         struct AuthorityChain *auth =
874           GNUNET_malloc(sizeof(struct AuthorityChain));
875         auth->zone = rh->authority;
876         memset(auth->name, 0, strlen(rh->authority_name)+1);
877         strcpy(auth->name, rh->authority_name);
878         GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
879                                      rh->authority_chain_tail,
880                                      auth);
881
882         /** try to import pkey if private key available */
883         if (rh->priv_key)
884           process_discovered_authority(name, auth->zone,
885                                        rh->authority_chain_tail->zone,
886                                        rh->priv_key);
887       }
888
889     }
890
891
892     GNUNET_CRYPTO_short_hash(name, strlen(name), &name_hash);
893     GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
894     GNUNET_CRYPTO_hash_xor(key, &name_hash_double, &zone_hash_double);
895     GNUNET_CRYPTO_short_hash_from_truncation (&zone_hash_double, &zone);
896
897     /* Save to namestore */
898     if (0 != GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_tail->zone,
899                                           &zone))
900     {
901       GNUNET_NAMESTORE_record_put (namestore_handle,
902                                  &nrb->public_key,
903                                  name,
904                                  exp,
905                                  num_records,
906                                  rd,
907                                  &nrb->signature,
908                                  &on_namestore_record_put_result, //cont
909                                  NULL); //cls
910     }
911   }
912   
913   if (rh->answered)
914   {
915     rh->answered = 0;
916     /**
917      * delegate
918      * FIXME in this case. should we ask namestore again?
919      */
920     if (strcmp(rh->name, "") == 0)
921       rh->proc(rh->proc_cls, rh, 0, NULL);
922     else
923       resolve_delegation_dht(rh);
924     return;
925   }
926   
927   /**
928    * No pkey but name exists
929    */
930   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "DHT authority lookup found no match!\n");
931   rh->proc(rh->proc_cls, rh, 0, NULL);
932 }
933
934 /**
935  * finish lookup
936  */
937 static void
938 finish_lookup(struct ResolverHandle *rh,
939               struct RecordLookupHandle* rlh,
940               unsigned int rd_count,
941               const struct GNUNET_NAMESTORE_RecordData *rd)
942 {
943   int i;
944   char* s_value;
945   char new_s_value[256];
946   char new_mx_value[sizeof(struct GNUNET_DNSPARSER_MxRecord)+256];
947   int s_len;
948   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
949   char* pos;
950   char* trailer;
951   struct GNUNET_DNSPARSER_MxRecord *mx;
952
953   if (rd_count > 0)
954     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
955
956   for (i = 0; i < rd_count; i++)
957   {
958
959     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
960         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
961         rd[i].record_type != GNUNET_GNS_RECORD_MX)
962     {
963       p_rd[i].data = rd[i].data;
964       continue;
965     }
966
967     /**
968      * for all those records we 'should'
969      * also try to resolve the A/AAAA records (RFC1035)
970      * FIXME
971      */
972     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
973     {
974       mx = (struct GNUNET_DNSPARSER_MxRecord*)rd[i].data;
975       s_value = (char*)&mx[1];
976     }
977     else
978     {
979       s_value = (char*)rd[i].data;
980     }
981     
982     s_len = strlen(s_value)+1;
983
984     if (s_len < 3)
985     {
986       /* no postprocessing */
987       p_rd[i].data = rd[i].data;
988       continue;
989     }
990
991     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
992                "Postprocessing %s\n", s_value);
993
994     if (0 == strcmp(s_value+s_len-3, ".+"))
995     {
996       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
997                  "Expanding .+ in %s\n", s_value);
998       if (strcmp(rh->name, "+") == 0)
999       {
1000         trailer = rlh->name;
1001       }
1002       else
1003       {
1004         trailer = rlh->name+strlen(rh->name)+1;
1005       }
1006       memset(new_s_value, 0, s_len+strlen(trailer)+strlen(GNUNET_GNS_TLD));
1007       strcpy(new_s_value, s_value);
1008       pos = new_s_value+s_len-2;
1009       strcpy(pos, trailer);
1010       pos += strlen(trailer);
1011       if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1012       {
1013
1014         p_rd[i].data_size = sizeof(struct GNUNET_DNSPARSER_MxRecord)
1015           +strlen(new_s_value)+1;
1016         
1017         p_rd[i].data = new_mx_value;
1018         mx = (struct GNUNET_DNSPARSER_MxRecord*)p_rd[i].data;
1019         mx->preference =
1020           ((struct GNUNET_DNSPARSER_MxRecord*)rd[i].data)->preference;
1021         memcpy((char*)&mx[1], new_s_value, strlen(new_s_value)+1);
1022         mx->mxhost = (char*)&mx[1];
1023       }
1024       else
1025       {
1026         p_rd[i].data = new_s_value;
1027         p_rd[i].data_size = strlen(new_s_value)+1;
1028       }
1029       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1030                  "Expanded to %s\n", new_s_value);
1031     }
1032   }
1033
1034   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1035   GNUNET_free(rlh);
1036   
1037 }
1038
1039 /**
1040  * Process DHT lookup result for record.
1041  *
1042  * @param cls the closure
1043  * @param rh resolver handle
1044  * @param rd_count number of results
1045  * @param rd record data
1046  */
1047 static void
1048 handle_record_dht(void* cls, struct ResolverHandle *rh,
1049                        unsigned int rd_count,
1050                        const struct GNUNET_NAMESTORE_RecordData *rd)
1051 {
1052   struct RecordLookupHandle* rlh;
1053
1054   rlh = (struct RecordLookupHandle*)cls;
1055   if (rd_count == 0)
1056   {
1057     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1058                "No records for %s found in DHT. Aborting\n",
1059                rh->name);
1060     /* give up, cannot resolve */
1061     finish_lookup(rh, rlh, 0, NULL);
1062     free_resolver_handle(rh);
1063     return;
1064   }
1065
1066   /* results found yay */
1067   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1068              "Record resolved from DHT!");
1069
1070   finish_lookup(rh, rlh, rd_count, rd);
1071   free_resolver_handle(rh);
1072
1073 }
1074
1075
1076 /**
1077  * Process namestore lookup result for record.
1078  *
1079  * @param cls the closure
1080  * @param rh resolver handle
1081  * @param rd_count number of results
1082  * @param rd record data
1083  */
1084 static void
1085 handle_record_ns(void* cls, struct ResolverHandle *rh,
1086                        unsigned int rd_count,
1087                        const struct GNUNET_NAMESTORE_RecordData *rd)
1088 {
1089   struct RecordLookupHandle* rlh;
1090   rlh = (struct RecordLookupHandle*) cls;
1091   if (rd_count == 0)
1092   {
1093     /* ns entry expired and not ours. try dht */
1094     if (rh->status & (EXPIRED | !EXISTS) &&
1095         GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1096                                      &rh->authority_chain_tail->zone))
1097     {
1098       rh->proc = &handle_record_dht;
1099       resolve_record_dht(rh);
1100       return;
1101     }
1102     /* give up, cannot resolve */
1103     finish_lookup(rh, rlh, 0, NULL);
1104     free_resolver_handle(rh);
1105     return;
1106   }
1107
1108   /* results found yay */
1109   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1110              "Record resolved from namestore!");
1111
1112   finish_lookup(rh, rlh, rd_count, rd);
1113   free_resolver_handle(rh);
1114
1115 }
1116
1117
1118 /**
1119  * Determine if this name is canonical.
1120  * i.e.
1121  * a.b.gnunet  = not canonical
1122  * a           = canonical
1123  *
1124  * @param name the name to test
1125  * @return 1 if canonical
1126  */
1127 static int
1128 is_canonical(char* name)
1129 {
1130   uint32_t len = strlen(name);
1131   int i;
1132
1133   for (i=0; i<len; i++)
1134   {
1135     if (*(name+i) == '.')
1136       return 0;
1137   }
1138   return 1;
1139 }
1140
1141 /**
1142  * Move one level up in the domain hierarchy and return the
1143  * passed top level domain.
1144  *
1145  * @param name the domain
1146  * @param dest the destination where the tld will be put
1147  */
1148 void
1149 pop_tld(char* name, char* dest)
1150 {
1151   uint32_t len;
1152
1153   if (is_canonical(name))
1154   {
1155     strcpy(dest, name);
1156     strcpy(name, "");
1157     return;
1158   }
1159
1160   for (len = strlen(name); len > 0; len--)
1161   {
1162     if (*(name+len) == '.')
1163       break;
1164   }
1165   
1166   //Was canonical?
1167   if (len == 0)
1168     return;
1169
1170   name[len] = '\0';
1171
1172   strcpy(dest, (name+len+1));
1173 }
1174
1175 /**
1176  * Checks if name is in tld
1177  *
1178  * @param name the name to check
1179  * @return GNUNET_YES or GNUNET_NO
1180  */
1181 int
1182 is_tld(const char* name, const char* tld)
1183 {
1184   int offset = 0;
1185
1186   if (strlen(name) <= strlen(tld))
1187   {
1188     return GNUNET_NO;
1189   }
1190   
1191   offset = strlen(name)-strlen(tld);
1192   if (strcmp(name+offset, tld) != 0)
1193   {
1194     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1195                "%s is not in .%s TLD\n", name, tld);
1196     return GNUNET_NO;
1197   }
1198   return GNUNET_YES;
1199 }
1200
1201 /**
1202  * DHT resolution for delegation finished. Processing result.
1203  *
1204  * @param cls the closure
1205  * @param rh resolver handle
1206  * @param rd_count number of results (always 0)
1207  * @param rd record data (always NULL)
1208  */
1209 static void
1210 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1211                           unsigned int rd_count,
1212                           const struct GNUNET_NAMESTORE_RecordData *rd)
1213 {
1214   struct RecordLookupHandle* rlh;
1215   rlh = (struct RecordLookupHandle*) cls;
1216   
1217   if (strcmp(rh->name, "") == 0)
1218   {
1219     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1220     {
1221       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1222                  "Resolved queried PKEY via DHT.\n");
1223       finish_lookup(rh, rlh, rd_count, rd);
1224       free_resolver_handle(rh);
1225       return;
1226     }
1227     /* We resolved full name for delegation. resolving record */
1228     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1229       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1230     strcpy(rh->name, "+\0");
1231     rh->proc = &handle_record_ns;
1232     resolve_record_ns(rh);
1233     return;
1234   }
1235
1236   /**
1237    * we still have some left
1238    **/
1239   if (is_canonical(rh->name))
1240   {
1241     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1242                "Resolving canonical record %s in ns\n", rh->name);
1243     rh->proc = &handle_record_ns;
1244     resolve_record_ns(rh);
1245     return;
1246   }
1247   /* give up, cannot resolve */
1248   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1249              "Cannot fully resolve delegation for %s via DHT!\n",
1250              rh->name);
1251   finish_lookup(rh, rlh, 0, NULL);
1252   free_resolver_handle(rh);
1253 }
1254
1255
1256 /**
1257  * Start DHT lookup for a name -> PKEY (compare NS) record in
1258  * rh->authority's zone
1259  *
1260  * @param rh the pending gns query
1261  */
1262 static void
1263 resolve_delegation_dht(struct ResolverHandle *rh)
1264 {
1265   uint32_t xquery;
1266   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1267   GNUNET_HashCode name_hash_double;
1268   GNUNET_HashCode zone_hash_double;
1269   GNUNET_HashCode lookup_key;
1270   
1271   GNUNET_CRYPTO_short_hash(rh->authority_name,
1272                      strlen(rh->authority_name),
1273                      &name_hash);
1274   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1275   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1276   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1277
1278   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1279                                                   &dht_authority_lookup_timeout,
1280                                                        rh);
1281
1282   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1283   
1284   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1285                        DHT_OPERATION_TIMEOUT,
1286                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1287                        &lookup_key,
1288                        DHT_GNS_REPLICATION_LEVEL,
1289                        GNUNET_DHT_RO_NONE,
1290                        &xquery,
1291                        sizeof(xquery),
1292                        &process_delegation_result_dht,
1293                        rh);
1294
1295 }
1296
1297
1298 /**
1299  * Namestore resolution for delegation finished. Processing result.
1300  *
1301  * @param cls the closure
1302  * @param rh resolver handle
1303  * @param rd_count number of results (always 0)
1304  * @param rd record data (always NULL)
1305  */
1306 static void
1307 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1308                           unsigned int rd_count,
1309                           const struct GNUNET_NAMESTORE_RecordData *rd)
1310 {
1311   struct RecordLookupHandle* rlh;
1312   rlh = (struct RecordLookupHandle*) cls;
1313   
1314   if (strcmp(rh->name, "") == 0)
1315   {
1316     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1317     {
1318       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1319                  "Resolved queried PKEY in NS.\n");
1320       finish_lookup(rh, rlh, rd_count, rd);
1321       free_resolver_handle(rh);
1322       return;
1323     }
1324     /* We resolved full name for delegation. resolving record */
1325     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1326                "Resolved full name for delegation. resolving record '+'\n");
1327     strcpy(rh->name, "+\0");
1328     rh->proc = &handle_record_ns;
1329     resolve_record_ns(rh);
1330     return;
1331   }
1332
1333   /**
1334    * we still have some left
1335    * check if authority in ns is fresh
1336    * and exists
1337    * or we are authority
1338    **/
1339   if ((rh->status & (EXISTS | !EXPIRED)) ||
1340       !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1341                              &rh->authority_chain_tail->zone))
1342   {
1343     if (is_canonical(rh->name))
1344     {
1345       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1346                  "Resolving canonical record %s\n", rh->name);
1347       rh->proc = &handle_record_ns;
1348       resolve_record_ns(rh);
1349     }
1350     else
1351     {
1352       /* give up, cannot resolve */
1353       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1354                  "Cannot fully resolve delegation for %s!\n",
1355                  rh->name);
1356       rlh->proc(rlh->proc_cls, 0, NULL);
1357     }
1358     return;
1359   }
1360   
1361   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1362              "Trying to resolve delegation for %s via DHT\n",
1363              rh->name);
1364   rh->proc = &handle_delegation_dht;
1365   resolve_delegation_dht(rh);
1366 }
1367
1368 /* Prototype */
1369 static void resolve_delegation_ns(struct ResolverHandle *rh);
1370
1371
1372 /**
1373  * This is a callback function that should give us only PKEY
1374  * records. Used to query the namestore for the authority (PKEY)
1375  * for 'name'. It will recursively try to resolve the
1376  * authority for a given name from the namestore.
1377  *
1378  * @param cls the pending query
1379  * @param key the key of the zone we did the lookup
1380  * @param expiration expiration date of the record data set in the namestore
1381  * @param name the name for which we need an authority
1382  * @param rd_count the number of records with 'name'
1383  * @param rd the record data
1384  * @param signature the signature of the authority for the record data
1385  */
1386 static void
1387 process_delegation_result_ns(void* cls,
1388                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1389                    struct GNUNET_TIME_Absolute expiration,
1390                    const char *name,
1391                    unsigned int rd_count,
1392                    const struct GNUNET_NAMESTORE_RecordData *rd,
1393                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1394 {
1395   struct ResolverHandle *rh;
1396   struct GNUNET_TIME_Relative remaining_time;
1397   struct GNUNET_CRYPTO_ShortHashCode zone;
1398   char new_name[MAX_DNS_NAME_LENGTH];
1399   
1400   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1401              rd_count);
1402
1403   rh = (struct ResolverHandle *)cls;
1404   GNUNET_CRYPTO_short_hash(key,
1405                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1406                      &zone);
1407   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1408   
1409   rh->status = 0;
1410   
1411   if (name != NULL)
1412   {
1413     rh->status |= EXISTS;
1414   }
1415   
1416   if (remaining_time.rel_value == 0)
1417   {
1418     rh->status |= EXPIRED;
1419   }
1420   
1421   /**
1422    * No authority found in namestore.
1423    */
1424   if (rd_count == 0)
1425   {
1426     /**
1427      * We did not find an authority in the namestore
1428      */
1429     
1430     /**
1431      * No PKEY in zone.
1432      * Promote this authority back to a name maybe it is
1433      * our record.
1434      */
1435     if (strcmp(rh->name, "") == 0)
1436     {
1437       /* simply promote back */
1438       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1439                  "Promoting %s back to name\n", rh->authority_name);
1440       strcpy(rh->name, rh->authority_name);
1441     }
1442     else
1443     {
1444       /* add back to existing name */
1445       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1446                  "Adding %s back to %s\n",
1447                  rh->authority_name, rh->name);
1448       memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1449       strcpy(new_name, rh->name);
1450       strcpy(new_name+strlen(new_name)+1, ".");
1451       strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1452       strcpy(rh->name, new_name);
1453     }
1454     rh->proc(rh->proc_cls, rh, 0, NULL);
1455     return;
1456   }
1457
1458   /**
1459    * We found an authority that may be able to help us
1460    * move on with query
1461    * Note only 1 pkey should have been returned.. anything else would be strange
1462    */
1463   int i;
1464   for (i=0; i<rd_count;i++)
1465   {
1466   
1467     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1468       continue;
1469     
1470     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1471          == 0)
1472     {
1473       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1474       if (remaining_time.rel_value == 0)
1475       {
1476         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1477                    "This dht entry is expired.\n");
1478         rh->authority_chain_head->fresh = 0;
1479         rh->proc(rh->proc_cls, rh, 0, NULL);
1480         return;
1481       }
1482
1483       continue;
1484     }
1485
1486     /**
1487      * Resolve rest of query with new authority
1488      */
1489     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1490     memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1491     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1492     auth->zone = rh->authority;
1493     memset(auth->name, 0, strlen(rh->authority_name)+1);
1494     strcpy(auth->name, rh->authority_name);
1495     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1496                                  rh->authority_chain_tail,
1497                                  auth);
1498     
1499     /**
1500      * We are done with PKEY resolution if name is empty
1501      * else resolve again with new authority
1502      */
1503     if (strcmp(rh->name, "") == 0)
1504       rh->proc(rh->proc_cls, rh, 0, NULL);
1505     else
1506       resolve_delegation_ns(rh);
1507     return;
1508   }
1509     
1510   /**
1511    * no answers found
1512    */
1513   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1514              "Authority lookup successful but no PKEY... never get here\n");
1515   rh->proc(rh->proc_cls, rh, 0, NULL);
1516 }
1517
1518
1519 /**
1520  * Resolve the delegation chain for the request in our namestore
1521  *
1522  * @param rh the resolver handle
1523  */
1524 static void
1525 resolve_delegation_ns(struct ResolverHandle *rh)
1526 {
1527   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1528              "Resolving delegation for %s\n", rh->name);
1529   pop_tld(rh->name, rh->authority_name);
1530   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1531                                  &rh->authority,
1532                                  rh->authority_name,
1533                                  GNUNET_GNS_RECORD_PKEY,
1534                                  &process_delegation_result_ns,
1535                                  rh);
1536
1537 }
1538
1539
1540 /**
1541  * Lookup of a record in a specific zone
1542  * calls lookup result processor on result
1543  *
1544  * @param zone the root zone
1545  * @param record_type the record type to look up
1546  * @param name the name to look up
1547  * @param proc the processor to call on result
1548  * @param cls the closure to pass to proc
1549  */
1550 void
1551 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1552                            uint32_t record_type,
1553                            const char* name,
1554                            struct GNUNET_CRYPTO_RsaPrivateKey *key,
1555                            RecordLookupProcessor proc,
1556                            void* cls)
1557 {
1558   struct ResolverHandle *rh;
1559   struct RecordLookupHandle* rlh;
1560   char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME name len as soon as shorthash
1561
1562   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1563               "Starting resolution for %s (type=%d)!\n",
1564               name, record_type);
1565
1566   
1567   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1568   {
1569     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1570                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1571     proc(cls, 0, NULL);
1572     return;
1573   }
1574   
1575   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1576   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1577
1578   rh->authority = zone;
1579   rh->proc_cls = rlh;
1580   rh->priv_key = key;
1581   
1582   if (strcmp(GNUNET_GNS_TLD, name) == 0)
1583   {
1584     /**
1585      * Only 'gnunet' given
1586      */
1587     strcpy(rh->name, "\0");
1588   }
1589   else
1590   {
1591     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1592                 "Checking for TLD...\n");
1593     if (is_zkey_tld(name) == GNUNET_YES)
1594     {
1595       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1596                   "TLD is zkey\n");
1597       /**
1598        * This is a zkey tld
1599        * build hash and use as initial authority
1600        */
1601       memset(rh->name, 0,
1602              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1603       memcpy(rh->name, name,
1604              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1605       pop_tld(rh->name, string_hash);
1606
1607       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1608                   "ZKEY is %s!\n", string_hash);
1609
1610       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1611                                                       &rh->authority))
1612       {
1613         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1614                     "Cannot convert ZKEY %s to hash!\n", string_hash);
1615         GNUNET_free(rh);
1616         GNUNET_free(rlh);
1617         proc(cls, 0, NULL);
1618         return;
1619       }
1620
1621     }
1622     else
1623     {
1624       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1625                   "TLD is gnunet\n");
1626       /**
1627        * Presumably GNUNET tld
1628        */
1629       memset(rh->name, 0,
1630              strlen(name)-strlen(GNUNET_GNS_TLD));
1631       memcpy(rh->name, name,
1632              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1633     }
1634   }
1635   
1636   /**
1637    * Initialize authority chain
1638    */
1639   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1640   rh->authority_chain_head->prev = NULL;
1641   rh->authority_chain_head->next = NULL;
1642   rh->authority_chain_tail = rh->authority_chain_head;
1643   rh->authority_chain_head->zone = rh->authority;
1644   
1645   /**
1646    * Copy original query into lookup handle
1647    */
1648   rlh->record_type = record_type;
1649   memset(rlh->name, 0, strlen(name) + 1);
1650   strcpy(rlh->name, name);
1651   rlh->proc = proc;
1652   rlh->proc_cls = cls;
1653
1654   rh->proc = &handle_delegation_ns;
1655   resolve_delegation_ns(rh);
1656 }
1657
1658 /******** END Record Resolver ***********/
1659
1660
1661 /**
1662  * Callback calles by namestore for a zone to name
1663  * result
1664  *
1665  * @param cls the closure
1666  * @param zone_key the zone we queried
1667  * @param expire the expiration time of the name
1668  * @param name the name found or NULL
1669  * @param rd_len number of records for the name
1670  * @param rd the record data (PKEY) for the name
1671  * @param signature the signature for the record data
1672  */
1673 static void
1674 process_zone_to_name_shorten(void *cls,
1675                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1676                  struct GNUNET_TIME_Absolute expire,
1677                  const char *name,
1678                  unsigned int rd_len,
1679                  const struct GNUNET_NAMESTORE_RecordData *rd,
1680                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1681 {
1682   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1683   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1684   struct AuthorityChain *next_authority;
1685
1686   char result[MAX_DNS_NAME_LENGTH];
1687   char next_authority_name[MAX_DNS_LABEL_LENGTH];
1688   size_t answer_len;
1689   
1690   /* we found a match in our own zone */
1691   if (rd_len != 0)
1692   {
1693     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1694                "result strlen %d\n", strlen(name));
1695     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1696     memset(result, 0, answer_len);
1697     if (strlen(rh->name) > 0)
1698     {
1699       strcpy(result, rh->name);
1700       strcpy(result+strlen(rh->name), ".");
1701     }
1702     
1703     strcpy(result+strlen(result), name);
1704     strcpy(result+strlen(result), ".");
1705     strcpy(result+strlen(result), GNUNET_GNS_TLD);
1706     
1707     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1708                "Sending shorten result %s\n", result);
1709
1710     nsh->proc(nsh->proc_cls, result);
1711     GNUNET_free(nsh);
1712     free_resolver_handle(rh);
1713   }
1714   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1715                                         &rh->authority_chain_tail->zone))
1716   {
1717     /* our zone, just append .gnunet */
1718     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1719     memset(result, 0, answer_len);
1720     strcpy(result, rh->name);
1721     strcpy(result+strlen(rh->name), ".");
1722     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1723
1724     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1725                "Our zone: Sending name as shorten result %s\n", rh->name);
1726     
1727     nsh->proc(nsh->proc_cls, result);
1728     GNUNET_free(nsh);
1729     free_resolver_handle(rh);
1730   }
1731   else
1732   {
1733     /**
1734      * No PSEU found.
1735      * continue with next authority
1736      */
1737     next_authority = rh->authority_chain_head;
1738     //                         strlen(next_authority->name) + 2);
1739     memset(next_authority_name, 0, strlen(rh->name)+
1740                       strlen(next_authority->name) + 2);
1741     strcpy(next_authority_name, rh->name);
1742     strcpy(next_authority_name+strlen(rh->name)+1, ".");
1743     strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1744   
1745     strcpy(rh->name, next_authority_name);
1746     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1747                               rh->authority_chain_tail,
1748                               next_authority);
1749
1750     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1751                                    &rh->authority_chain_tail->zone,
1752                                    &rh->authority_chain_head->zone,
1753                                    &process_zone_to_name_shorten,
1754                                    rh);
1755   }
1756 }
1757
1758
1759 /**
1760  * Process result from namestore delegation lookup
1761  * for shorten operation
1762  *
1763  * @param cls the client shorten handle
1764  * @param rh the resolver handle
1765  * @param rd_count number of results (0)
1766  * @param rd data (NULL)
1767  */
1768 void
1769 handle_delegation_ns_shorten(void* cls,
1770                       struct ResolverHandle *rh,
1771                       uint32_t rd_count,
1772                       const struct GNUNET_NAMESTORE_RecordData *rd)
1773 {
1774   struct NameShortenHandle *nsh;
1775   char result[MAX_DNS_NAME_LENGTH];
1776   size_t answer_len;
1777
1778   nsh = (struct NameShortenHandle *)cls;
1779   
1780   /**
1781    * At this point rh->name contains the part of the name
1782    * that we do not have a PKEY in our namestore to resolve.
1783    * The authority chain in the resolver handle is now
1784    * useful to backtrack if needed
1785    */
1786   
1787   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1788              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1789
1790   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1791                                    &rh->authority_chain_tail->zone) == 0)
1792   {
1793     /**
1794      * This is our zone append .gnunet unless name is empty
1795      * (it shouldn't be, usually FIXME what happens if we
1796      * shorten to our zone to a "" record??)
1797      */
1798     
1799     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1800     memset(result, 0, answer_len);
1801     strcpy(result, rh->name);
1802     strcpy(result+strlen(rh->name), ".");
1803     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1804
1805     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1806                "Our zone: Sending name as shorten result %s\n", rh->name);
1807     
1808     nsh->proc(nsh->proc_cls, result);
1809     GNUNET_free(nsh);
1810     free_resolver_handle(rh);
1811     return;
1812   }
1813   
1814   /* backtrack authorities for names */
1815   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1816                                  &rh->authority_chain_tail->zone, //ours
1817                                  &rh->authority_chain_head->zone,
1818                                  &process_zone_to_name_shorten,
1819                                  rh);
1820
1821 }
1822
1823 /**
1824  * Shorten api from resolver
1825  *
1826  * @param zone the zone to use
1827  * @param name the name to shorten
1828  * @param proc the processor to call with result
1829  * @param cls closure to pass to proc
1830  */
1831 void
1832 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
1833                           const char* name,
1834                           ShortenResultProcessor proc,
1835                           void* cls)
1836 {
1837   struct ResolverHandle *rh;
1838   struct NameShortenHandle *nsh;
1839   char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME LABEL length when shorthash
1840
1841   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1842               "Starting shorten for %s!\n", name);
1843   
1844   if (is_canonical((char*)name))
1845   {
1846     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1847                 "%s is canonical. Returning verbatim\n", name);
1848     proc(cls, name);
1849     return;
1850   }
1851
1852   nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
1853   
1854
1855   nsh->proc = proc;
1856   nsh->proc_cls = cls;
1857   
1858   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1859   rh->authority = zone;
1860   
1861   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1862                 "Checking for TLD...\n");
1863   if (is_zkey_tld(name) == GNUNET_YES)
1864   {
1865     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1866                 "TLD is zkey\n");
1867     /**
1868      * This is a zkey tld
1869      * build hash and use as initial authority
1870      */
1871     memset(rh->name, 0,
1872            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1873     memcpy(rh->name, name,
1874            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1875     pop_tld(rh->name, string_hash);
1876
1877     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1878                 "ZKEY is %s!\n", string_hash);
1879
1880     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1881                                                           &rh->authority))
1882     {
1883       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1884                   "Cannot convert ZKEY %s to hash!\n", string_hash);
1885       GNUNET_free(rh);
1886       GNUNET_free(nsh);
1887       proc(cls, name);
1888       return;
1889     }
1890
1891   }
1892   else
1893   {
1894     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1895                 "TLD is gnunet\n");
1896     /**
1897      * Presumably GNUNET tld
1898      */
1899     memset(rh->name, 0,
1900            strlen(name)-strlen(GNUNET_GNS_TLD));
1901     memcpy(rh->name, name,
1902            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1903   }
1904
1905   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1906   rh->authority_chain_tail = rh->authority_chain_head;
1907   rh->authority_chain_head->zone = zone;
1908   rh->proc = &handle_delegation_ns_shorten;
1909   rh->proc_cls = nsh;
1910   
1911   /* Start delegation resolution in our namestore */
1912   resolve_delegation_ns(rh);
1913 }
1914
1915 /*********** END NAME SHORTEN ********************/
1916
1917
1918 /**
1919  * Process result from namestore delegation lookup
1920  * for get authority operation
1921  *
1922  * @param cls the client get auth handle
1923  * @param rh the resolver handle
1924  * @param rd_count number of results (0)
1925  * @param rd data (NULL)
1926  */
1927 void
1928 handle_delegation_result_ns_get_auth(void* cls,
1929                       struct ResolverHandle *rh,
1930                       uint32_t rd_count,
1931                       const struct GNUNET_NAMESTORE_RecordData *rd)
1932 {
1933   struct GetNameAuthorityHandle* nah;
1934   char result[MAX_DNS_NAME_LENGTH];
1935   size_t answer_len;
1936
1937   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
1938   
1939   /**
1940    * At this point rh->name contains the part of the name
1941    * that we do not have a PKEY in our namestore to resolve.
1942    * The authority chain in the resolver handle is now
1943    * useful to backtrack if needed
1944    */
1945   
1946   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1947              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1948
1949   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1950              "Building response!\n");
1951   if (is_canonical(rh->name))
1952   {
1953     /**
1954      * We successfully resolved the authority in the ns
1955      * FIXME for our purposes this is fine
1956      * but maybe we want to have an api that also looks
1957      * into the dht (i.e. option in message)
1958      **/
1959     if (strlen(rh->name) > strlen(nah->name))
1960     {
1961       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1962                  "Record name longer than original lookup name... odd!\n");
1963       //FIXME to sth here
1964     }
1965
1966     answer_len = strlen(nah->name) - strlen(rh->name)
1967       + strlen(GNUNET_GNS_TLD) + 1;
1968     memset(result, 0, answer_len);
1969     strcpy(result, nah->name + strlen(rh->name) + 1);
1970
1971     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1972                "Got authority result %s\n", result);
1973     
1974     nah->proc(nah->proc_cls, result);
1975     GNUNET_free(nah);
1976     free_resolver_handle(rh);
1977   }
1978   else
1979   {
1980     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1981                "Unable to resolve authority for remaining %s!\n", rh->name);
1982     nah->proc(nah->proc_cls, "");
1983     GNUNET_free(nah);
1984     free_resolver_handle(rh);
1985   }
1986
1987
1988 }
1989
1990
1991 /**
1992  * Tries to resolve the authority for name
1993  * in our namestore
1994  *
1995  * @param zone the root zone to look up for
1996  * @param name the name to lookup up
1997  * @param proc the processor to call when finished
1998  * @param cls the closure to pass to the processor
1999  */
2000 void
2001 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
2002                            const char* name,
2003                            GetAuthorityResultProcessor proc,
2004                            void* cls)
2005 {
2006   struct ResolverHandle *rh;
2007   struct GetNameAuthorityHandle *nah;
2008
2009   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2010               "Starting authority resolution for %s!\n", name);
2011
2012   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2013   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2014   rh->authority = zone;
2015   
2016   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2017   {
2018     strcpy(rh->name, "\0");
2019   }
2020   else
2021   {
2022     memset(rh->name, 0,
2023            strlen(name)-strlen(GNUNET_GNS_TLD));
2024     memcpy(rh->name, name,
2025            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2026   }
2027
2028   memset(nah->name, 0,
2029          strlen(name)+1);
2030   strcpy(nah->name, name);
2031   
2032   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2033   rh->authority_chain_tail = rh->authority_chain_head;
2034   rh->authority_chain_head->zone = zone;
2035   rh->proc = &handle_delegation_result_ns_get_auth;
2036   rh->proc_cls = (void*)nah;
2037
2038   nah->proc = proc;
2039   nah->proc_cls = cls;
2040
2041   /* Start delegation resolution in our namestore */
2042   resolve_delegation_ns(rh);
2043
2044 }
2045
2046 /******** END GET AUTHORITY *************/
2047
2048 /* end of gnunet-service-gns_resolver.c */