-fix mxrr
[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(uint16_t)+256];
947   int s_len;
948   struct GNUNET_NAMESTORE_RecordData p_rd[rd_count];
949   char* pos;
950   char* trailer;
951
952   if (rd_count > 0)
953     memcpy(p_rd, rd, rd_count*sizeof(struct GNUNET_NAMESTORE_RecordData));
954
955   for (i = 0; i < rd_count; i++)
956   {
957
958     if (rd[i].record_type != GNUNET_GNS_RECORD_TYPE_NS &&
959         rd[i].record_type != GNUNET_GNS_RECORD_TYPE_CNAME &&
960         rd[i].record_type != GNUNET_GNS_RECORD_MX)
961     {
962       p_rd[i].data = rd[i].data;
963       continue;
964     }
965
966     /**
967      * for all those records we 'should'
968      * also try to resolve the A/AAAA records (RFC1035)
969      * FIXME
970      */
971     if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
972     {
973       s_value = (char*)rd[i].data+sizeof(uint16_t);
974     }
975     else
976     {
977       s_value = (char*)rd[i].data;
978     }
979     
980     s_len = strlen(s_value)+1;
981
982     if (s_len < 3)
983     {
984       /* no postprocessing */
985       p_rd[i].data = rd[i].data;
986       continue;
987     }
988
989     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
990                "Postprocessing %s\n", s_value);
991
992     if (0 == strcmp(s_value+s_len-3, ".+"))
993     {
994       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
995                  "Expanding .+ in %s\n", s_value);
996       if (strcmp(rh->name, "+") == 0)
997       {
998         trailer = rlh->name;
999       }
1000       else
1001       {
1002         trailer = rlh->name+strlen(rh->name)+1;
1003       }
1004       memset(new_s_value, 0, s_len+strlen(trailer)+strlen(GNUNET_GNS_TLD));
1005       strcpy(new_s_value, s_value);
1006       pos = new_s_value+s_len-2;
1007       strcpy(pos, trailer);
1008       pos += strlen(trailer);
1009       if (rd[i].record_type == GNUNET_GNS_RECORD_MX)
1010       {
1011
1012         p_rd[i].data_size = sizeof(uint16_t)+strlen(new_s_value)+1;
1013         
1014         p_rd[i].data = new_mx_value;
1015         /* cpy preference */
1016         memcpy(new_mx_value, (char*)rd[i].data, sizeof(uint16_t));
1017         /* cpy string */
1018         memcpy(new_mx_value+sizeof(uint16_t), new_s_value, strlen(new_s_value)+1);
1019       }
1020       else
1021       {
1022         p_rd[i].data = new_s_value;
1023         p_rd[i].data_size = strlen(new_s_value)+1;
1024       }
1025       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1026                  "Expanded to %s\n", new_s_value);
1027     }
1028   }
1029
1030   rlh->proc(rlh->proc_cls, rd_count, p_rd);
1031   GNUNET_free(rlh);
1032   
1033 }
1034
1035 /**
1036  * Process DHT lookup result for record.
1037  *
1038  * @param cls the closure
1039  * @param rh resolver handle
1040  * @param rd_count number of results
1041  * @param rd record data
1042  */
1043 static void
1044 handle_record_dht(void* cls, struct ResolverHandle *rh,
1045                        unsigned int rd_count,
1046                        const struct GNUNET_NAMESTORE_RecordData *rd)
1047 {
1048   struct RecordLookupHandle* rlh;
1049
1050   rlh = (struct RecordLookupHandle*)cls;
1051   if (rd_count == 0)
1052   {
1053     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1054                "No records for %s found in DHT. Aborting\n",
1055                rh->name);
1056     /* give up, cannot resolve */
1057     finish_lookup(rh, rlh, 0, NULL);
1058     free_resolver_handle(rh);
1059     return;
1060   }
1061
1062   /* results found yay */
1063   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1064              "Record resolved from DHT!");
1065
1066   finish_lookup(rh, rlh, rd_count, rd);
1067   free_resolver_handle(rh);
1068
1069 }
1070
1071
1072 /**
1073  * Process namestore lookup result for record.
1074  *
1075  * @param cls the closure
1076  * @param rh resolver handle
1077  * @param rd_count number of results
1078  * @param rd record data
1079  */
1080 static void
1081 handle_record_ns(void* cls, struct ResolverHandle *rh,
1082                        unsigned int rd_count,
1083                        const struct GNUNET_NAMESTORE_RecordData *rd)
1084 {
1085   struct RecordLookupHandle* rlh;
1086   rlh = (struct RecordLookupHandle*) cls;
1087   if (rd_count == 0)
1088   {
1089     /* ns entry expired and not ours. try dht */
1090     if (rh->status & (EXPIRED | !EXISTS) &&
1091         GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1092                                      &rh->authority_chain_tail->zone))
1093     {
1094       rh->proc = &handle_record_dht;
1095       resolve_record_dht(rh);
1096       return;
1097     }
1098     /* give up, cannot resolve */
1099     finish_lookup(rh, rlh, 0, NULL);
1100     free_resolver_handle(rh);
1101     return;
1102   }
1103
1104   /* results found yay */
1105   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1106              "Record resolved from namestore!");
1107
1108   finish_lookup(rh, rlh, rd_count, rd);
1109   free_resolver_handle(rh);
1110
1111 }
1112
1113
1114 /**
1115  * Determine if this name is canonical.
1116  * i.e.
1117  * a.b.gnunet  = not canonical
1118  * a           = canonical
1119  *
1120  * @param name the name to test
1121  * @return 1 if canonical
1122  */
1123 static int
1124 is_canonical(char* name)
1125 {
1126   uint32_t len = strlen(name);
1127   int i;
1128
1129   for (i=0; i<len; i++)
1130   {
1131     if (*(name+i) == '.')
1132       return 0;
1133   }
1134   return 1;
1135 }
1136
1137 /**
1138  * Move one level up in the domain hierarchy and return the
1139  * passed top level domain.
1140  *
1141  * @param name the domain
1142  * @param dest the destination where the tld will be put
1143  */
1144 void
1145 pop_tld(char* name, char* dest)
1146 {
1147   uint32_t len;
1148
1149   if (is_canonical(name))
1150   {
1151     strcpy(dest, name);
1152     strcpy(name, "");
1153     return;
1154   }
1155
1156   for (len = strlen(name); len > 0; len--)
1157   {
1158     if (*(name+len) == '.')
1159       break;
1160   }
1161   
1162   //Was canonical?
1163   if (len == 0)
1164     return;
1165
1166   name[len] = '\0';
1167
1168   strcpy(dest, (name+len+1));
1169 }
1170
1171 /**
1172  * Checks if name is in tld
1173  *
1174  * @param name the name to check
1175  * @return GNUNET_YES or GNUNET_NO
1176  */
1177 int
1178 is_tld(const char* name, const char* tld)
1179 {
1180   int offset = 0;
1181
1182   if (strlen(name) <= strlen(tld))
1183   {
1184     return GNUNET_NO;
1185   }
1186   
1187   offset = strlen(name)-strlen(tld);
1188   if (strcmp(name+offset, tld) != 0)
1189   {
1190     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1191                "%s is not in .%s TLD\n", name, tld);
1192     return GNUNET_NO;
1193   }
1194   return GNUNET_YES;
1195 }
1196
1197 /**
1198  * DHT resolution for delegation finished. Processing result.
1199  *
1200  * @param cls the closure
1201  * @param rh resolver handle
1202  * @param rd_count number of results (always 0)
1203  * @param rd record data (always NULL)
1204  */
1205 static void
1206 handle_delegation_dht(void* cls, struct ResolverHandle *rh,
1207                           unsigned int rd_count,
1208                           const struct GNUNET_NAMESTORE_RecordData *rd)
1209 {
1210   struct RecordLookupHandle* rlh;
1211   rlh = (struct RecordLookupHandle*) cls;
1212   
1213   if (strcmp(rh->name, "") == 0)
1214   {
1215     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1216     {
1217       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1218                  "Resolved queried PKEY via DHT.\n");
1219       finish_lookup(rh, rlh, rd_count, rd);
1220       free_resolver_handle(rh);
1221       return;
1222     }
1223     /* We resolved full name for delegation. resolving record */
1224     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1225       "Resolved full name for delegation via DHT. resolving record '' in ns\n");
1226     strcpy(rh->name, "+\0");
1227     rh->proc = &handle_record_ns;
1228     resolve_record_ns(rh);
1229     return;
1230   }
1231
1232   /**
1233    * we still have some left
1234    **/
1235   if (is_canonical(rh->name))
1236   {
1237     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1238                "Resolving canonical record %s in ns\n", rh->name);
1239     rh->proc = &handle_record_ns;
1240     resolve_record_ns(rh);
1241     return;
1242   }
1243   /* give up, cannot resolve */
1244   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1245              "Cannot fully resolve delegation for %s via DHT!\n",
1246              rh->name);
1247   finish_lookup(rh, rlh, 0, NULL);
1248   free_resolver_handle(rh);
1249 }
1250
1251
1252 /**
1253  * Start DHT lookup for a name -> PKEY (compare NS) record in
1254  * rh->authority's zone
1255  *
1256  * @param rh the pending gns query
1257  */
1258 static void
1259 resolve_delegation_dht(struct ResolverHandle *rh)
1260 {
1261   uint32_t xquery;
1262   struct GNUNET_CRYPTO_ShortHashCode name_hash;
1263   GNUNET_HashCode name_hash_double;
1264   GNUNET_HashCode zone_hash_double;
1265   GNUNET_HashCode lookup_key;
1266   
1267   GNUNET_CRYPTO_short_hash(rh->authority_name,
1268                      strlen(rh->authority_name),
1269                      &name_hash);
1270   GNUNET_CRYPTO_short_hash_double(&name_hash, &name_hash_double);
1271   GNUNET_CRYPTO_short_hash_double(&rh->authority, &zone_hash_double);
1272   GNUNET_CRYPTO_hash_xor(&name_hash_double, &zone_hash_double, &lookup_key);
1273
1274   rh->dht_timeout_task = GNUNET_SCHEDULER_add_delayed (DHT_LOOKUP_TIMEOUT,
1275                                                   &dht_authority_lookup_timeout,
1276                                                        rh);
1277
1278   xquery = htonl(GNUNET_GNS_RECORD_PKEY);
1279   
1280   rh->get_handle = GNUNET_DHT_get_start(dht_handle,
1281                        DHT_OPERATION_TIMEOUT,
1282                        GNUNET_BLOCK_TYPE_GNS_NAMERECORD,
1283                        &lookup_key,
1284                        DHT_GNS_REPLICATION_LEVEL,
1285                        GNUNET_DHT_RO_NONE,
1286                        &xquery,
1287                        sizeof(xquery),
1288                        &process_delegation_result_dht,
1289                        rh);
1290
1291 }
1292
1293
1294 /**
1295  * Namestore resolution for delegation finished. Processing result.
1296  *
1297  * @param cls the closure
1298  * @param rh resolver handle
1299  * @param rd_count number of results (always 0)
1300  * @param rd record data (always NULL)
1301  */
1302 static void
1303 handle_delegation_ns(void* cls, struct ResolverHandle *rh,
1304                           unsigned int rd_count,
1305                           const struct GNUNET_NAMESTORE_RecordData *rd)
1306 {
1307   struct RecordLookupHandle* rlh;
1308   rlh = (struct RecordLookupHandle*) cls;
1309   
1310   if (strcmp(rh->name, "") == 0)
1311   {
1312     if ((rlh->record_type == GNUNET_GNS_RECORD_PKEY))
1313     {
1314       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1315                  "Resolved queried PKEY in NS.\n");
1316       finish_lookup(rh, rlh, rd_count, rd);
1317       free_resolver_handle(rh);
1318       return;
1319     }
1320     /* We resolved full name for delegation. resolving record */
1321     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1322                "Resolved full name for delegation. resolving record '+'\n");
1323     strcpy(rh->name, "+\0");
1324     rh->proc = &handle_record_ns;
1325     resolve_record_ns(rh);
1326     return;
1327   }
1328
1329   /**
1330    * we still have some left
1331    * check if authority in ns is fresh
1332    * and exists
1333    * or we are authority
1334    **/
1335   if ((rh->status & (EXISTS | !EXPIRED)) ||
1336       !GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1337                              &rh->authority_chain_tail->zone))
1338   {
1339     if (is_canonical(rh->name))
1340     {
1341       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1342                  "Resolving canonical record %s\n", rh->name);
1343       rh->proc = &handle_record_ns;
1344       resolve_record_ns(rh);
1345     }
1346     else
1347     {
1348       /* give up, cannot resolve */
1349       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1350                  "Cannot fully resolve delegation for %s!\n",
1351                  rh->name);
1352       rlh->proc(rlh->proc_cls, 0, NULL);
1353     }
1354     return;
1355   }
1356   
1357   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1358              "Trying to resolve delegation for %s via DHT\n",
1359              rh->name);
1360   rh->proc = &handle_delegation_dht;
1361   resolve_delegation_dht(rh);
1362 }
1363
1364 /* Prototype */
1365 static void resolve_delegation_ns(struct ResolverHandle *rh);
1366
1367
1368 /**
1369  * This is a callback function that should give us only PKEY
1370  * records. Used to query the namestore for the authority (PKEY)
1371  * for 'name'. It will recursively try to resolve the
1372  * authority for a given name from the namestore.
1373  *
1374  * @param cls the pending query
1375  * @param key the key of the zone we did the lookup
1376  * @param expiration expiration date of the record data set in the namestore
1377  * @param name the name for which we need an authority
1378  * @param rd_count the number of records with 'name'
1379  * @param rd the record data
1380  * @param signature the signature of the authority for the record data
1381  */
1382 static void
1383 process_delegation_result_ns(void* cls,
1384                    const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *key,
1385                    struct GNUNET_TIME_Absolute expiration,
1386                    const char *name,
1387                    unsigned int rd_count,
1388                    const struct GNUNET_NAMESTORE_RecordData *rd,
1389                    const struct GNUNET_CRYPTO_RsaSignature *signature)
1390 {
1391   struct ResolverHandle *rh;
1392   struct GNUNET_TIME_Relative remaining_time;
1393   struct GNUNET_CRYPTO_ShortHashCode zone;
1394   char new_name[MAX_DNS_NAME_LENGTH];
1395   
1396   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Got %d records from authority lookup\n",
1397              rd_count);
1398
1399   rh = (struct ResolverHandle *)cls;
1400   GNUNET_CRYPTO_short_hash(key,
1401                      sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1402                      &zone);
1403   remaining_time = GNUNET_TIME_absolute_get_remaining (expiration);
1404   
1405   rh->status = 0;
1406   
1407   if (name != NULL)
1408   {
1409     rh->status |= EXISTS;
1410   }
1411   
1412   if (remaining_time.rel_value == 0)
1413   {
1414     rh->status |= EXPIRED;
1415   }
1416   
1417   /**
1418    * No authority found in namestore.
1419    */
1420   if (rd_count == 0)
1421   {
1422     /**
1423      * We did not find an authority in the namestore
1424      */
1425     
1426     /**
1427      * No PKEY in zone.
1428      * Promote this authority back to a name maybe it is
1429      * our record.
1430      */
1431     if (strcmp(rh->name, "") == 0)
1432     {
1433       /* simply promote back */
1434       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1435                  "Promoting %s back to name\n", rh->authority_name);
1436       strcpy(rh->name, rh->authority_name);
1437     }
1438     else
1439     {
1440       /* add back to existing name */
1441       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1442                  "Adding %s back to %s\n",
1443                  rh->authority_name, rh->name);
1444       memset(new_name, 0, strlen(rh->name) + strlen(rh->authority_name) + 2);
1445       strcpy(new_name, rh->name);
1446       strcpy(new_name+strlen(new_name)+1, ".");
1447       strcpy(new_name+strlen(new_name)+2, rh->authority_name);
1448       strcpy(rh->name, new_name);
1449     }
1450     rh->proc(rh->proc_cls, rh, 0, NULL);
1451     return;
1452   }
1453
1454   /**
1455    * We found an authority that may be able to help us
1456    * move on with query
1457    * Note only 1 pkey should have been returned.. anything else would be strange
1458    */
1459   int i;
1460   for (i=0; i<rd_count;i++)
1461   {
1462   
1463     if (rd[i].record_type != GNUNET_GNS_RECORD_PKEY)
1464       continue;
1465     
1466     if ((GNUNET_TIME_absolute_get_remaining (rd[i].expiration)).rel_value
1467          == 0)
1468     {
1469       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "This pkey is expired.\n");
1470       if (remaining_time.rel_value == 0)
1471       {
1472         GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1473                    "This dht entry is expired.\n");
1474         rh->authority_chain_head->fresh = 0;
1475         rh->proc(rh->proc_cls, rh, 0, NULL);
1476         return;
1477       }
1478
1479       continue;
1480     }
1481
1482     /**
1483      * Resolve rest of query with new authority
1484      */
1485     GNUNET_assert(rd[i].record_type == GNUNET_GNS_RECORD_PKEY);
1486     memcpy(&rh->authority, rd[i].data, sizeof(struct GNUNET_CRYPTO_ShortHashCode));
1487     struct AuthorityChain *auth = GNUNET_malloc(sizeof(struct AuthorityChain));
1488     auth->zone = rh->authority;
1489     memset(auth->name, 0, strlen(rh->authority_name)+1);
1490     strcpy(auth->name, rh->authority_name);
1491     GNUNET_CONTAINER_DLL_insert (rh->authority_chain_head,
1492                                  rh->authority_chain_tail,
1493                                  auth);
1494     
1495     /**
1496      * We are done with PKEY resolution if name is empty
1497      * else resolve again with new authority
1498      */
1499     if (strcmp(rh->name, "") == 0)
1500       rh->proc(rh->proc_cls, rh, 0, NULL);
1501     else
1502       resolve_delegation_ns(rh);
1503     return;
1504   }
1505     
1506   /**
1507    * no answers found
1508    */
1509   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1510              "Authority lookup successful but no PKEY... never get here\n");
1511   rh->proc(rh->proc_cls, rh, 0, NULL);
1512 }
1513
1514
1515 /**
1516  * Resolve the delegation chain for the request in our namestore
1517  *
1518  * @param rh the resolver handle
1519  */
1520 static void
1521 resolve_delegation_ns(struct ResolverHandle *rh)
1522 {
1523   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1524              "Resolving delegation for %s\n", rh->name);
1525   pop_tld(rh->name, rh->authority_name);
1526   GNUNET_NAMESTORE_lookup_record(namestore_handle,
1527                                  &rh->authority,
1528                                  rh->authority_name,
1529                                  GNUNET_GNS_RECORD_PKEY,
1530                                  &process_delegation_result_ns,
1531                                  rh);
1532
1533 }
1534
1535
1536 /**
1537  * Lookup of a record in a specific zone
1538  * calls lookup result processor on result
1539  *
1540  * @param zone the root zone
1541  * @param record_type the record type to look up
1542  * @param name the name to look up
1543  * @param proc the processor to call on result
1544  * @param cls the closure to pass to proc
1545  */
1546 void
1547 gns_resolver_lookup_record(struct GNUNET_CRYPTO_ShortHashCode zone,
1548                            uint32_t record_type,
1549                            const char* name,
1550                            struct GNUNET_CRYPTO_RsaPrivateKey *key,
1551                            RecordLookupProcessor proc,
1552                            void* cls)
1553 {
1554   struct ResolverHandle *rh;
1555   struct RecordLookupHandle* rlh;
1556   char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME name len as soon as shorthash
1557
1558   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1559               "Starting resolution for %s (type=%d)!\n",
1560               name, record_type);
1561
1562   
1563   if (is_canonical((char*)name) && (strcmp(GNUNET_GNS_TLD, name) != 0))
1564   {
1565     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1566                 "%s is canonical and not gnunet -> cannot resolve!\n", name);
1567     proc(cls, 0, NULL);
1568     return;
1569   }
1570   
1571   rlh = GNUNET_malloc(sizeof(struct RecordLookupHandle));
1572   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1573
1574   rh->authority = zone;
1575   rh->proc_cls = rlh;
1576   rh->priv_key = key;
1577   
1578   if (strcmp(GNUNET_GNS_TLD, name) == 0)
1579   {
1580     /**
1581      * Only 'gnunet' given
1582      */
1583     strcpy(rh->name, "\0");
1584   }
1585   else
1586   {
1587     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1588                 "Checking for TLD...\n");
1589     if (is_zkey_tld(name) == GNUNET_YES)
1590     {
1591       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1592                   "TLD is zkey\n");
1593       /**
1594        * This is a zkey tld
1595        * build hash and use as initial authority
1596        */
1597       memset(rh->name, 0,
1598              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1599       memcpy(rh->name, name,
1600              strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1601       pop_tld(rh->name, string_hash);
1602
1603       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1604                   "ZKEY is %s!\n", string_hash);
1605
1606       if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1607                                                       &rh->authority))
1608       {
1609         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1610                     "Cannot convert ZKEY %s to hash!\n", string_hash);
1611         GNUNET_free(rh);
1612         GNUNET_free(rlh);
1613         proc(cls, 0, NULL);
1614         return;
1615       }
1616
1617     }
1618     else
1619     {
1620       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1621                   "TLD is gnunet\n");
1622       /**
1623        * Presumably GNUNET tld
1624        */
1625       memset(rh->name, 0,
1626              strlen(name)-strlen(GNUNET_GNS_TLD));
1627       memcpy(rh->name, name,
1628              strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1629     }
1630   }
1631   
1632   /**
1633    * Initialize authority chain
1634    */
1635   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1636   rh->authority_chain_head->prev = NULL;
1637   rh->authority_chain_head->next = NULL;
1638   rh->authority_chain_tail = rh->authority_chain_head;
1639   rh->authority_chain_head->zone = rh->authority;
1640   
1641   /**
1642    * Copy original query into lookup handle
1643    */
1644   rlh->record_type = record_type;
1645   memset(rlh->name, 0, strlen(name) + 1);
1646   strcpy(rlh->name, name);
1647   rlh->proc = proc;
1648   rlh->proc_cls = cls;
1649
1650   rh->proc = &handle_delegation_ns;
1651   resolve_delegation_ns(rh);
1652 }
1653
1654 /******** END Record Resolver ***********/
1655
1656
1657 /**
1658  * Callback calles by namestore for a zone to name
1659  * result
1660  *
1661  * @param cls the closure
1662  * @param zone_key the zone we queried
1663  * @param expire the expiration time of the name
1664  * @param name the name found or NULL
1665  * @param rd_len number of records for the name
1666  * @param rd the record data (PKEY) for the name
1667  * @param signature the signature for the record data
1668  */
1669 static void
1670 process_zone_to_name_shorten(void *cls,
1671                  const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
1672                  struct GNUNET_TIME_Absolute expire,
1673                  const char *name,
1674                  unsigned int rd_len,
1675                  const struct GNUNET_NAMESTORE_RecordData *rd,
1676                  const struct GNUNET_CRYPTO_RsaSignature *signature)
1677 {
1678   struct ResolverHandle *rh = (struct ResolverHandle *)cls;
1679   struct NameShortenHandle* nsh = (struct NameShortenHandle*)rh->proc_cls;
1680   struct AuthorityChain *next_authority;
1681
1682   char result[MAX_DNS_NAME_LENGTH];
1683   char next_authority_name[MAX_DNS_LABEL_LENGTH];
1684   size_t answer_len;
1685   
1686   /* we found a match in our own zone */
1687   if (rd_len != 0)
1688   {
1689     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1690                "result strlen %d\n", strlen(name));
1691     answer_len = strlen(rh->name) + strlen(name) + strlen(GNUNET_GNS_TLD) + 3;
1692     memset(result, 0, answer_len);
1693     if (strlen(rh->name) > 0)
1694     {
1695       strcpy(result, rh->name);
1696       strcpy(result+strlen(rh->name), ".");
1697     }
1698     
1699     strcpy(result+strlen(result), name);
1700     strcpy(result+strlen(result), ".");
1701     strcpy(result+strlen(result), GNUNET_GNS_TLD);
1702     
1703     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1704                "Sending shorten result %s\n", result);
1705
1706     nsh->proc(nsh->proc_cls, result);
1707     GNUNET_free(nsh);
1708     free_resolver_handle(rh);
1709   }
1710   else if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1711                                         &rh->authority_chain_tail->zone))
1712   {
1713     /* our zone, just append .gnunet */
1714     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1715     memset(result, 0, answer_len);
1716     strcpy(result, rh->name);
1717     strcpy(result+strlen(rh->name), ".");
1718     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1719
1720     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1721                "Our zone: Sending name as shorten result %s\n", rh->name);
1722     
1723     nsh->proc(nsh->proc_cls, result);
1724     GNUNET_free(nsh);
1725     free_resolver_handle(rh);
1726   }
1727   else
1728   {
1729     /**
1730      * No PSEU found.
1731      * continue with next authority
1732      */
1733     next_authority = rh->authority_chain_head;
1734     //                         strlen(next_authority->name) + 2);
1735     memset(next_authority_name, 0, strlen(rh->name)+
1736                       strlen(next_authority->name) + 2);
1737     strcpy(next_authority_name, rh->name);
1738     strcpy(next_authority_name+strlen(rh->name)+1, ".");
1739     strcpy(next_authority_name+strlen(rh->name)+2, next_authority->name);
1740   
1741     strcpy(rh->name, next_authority_name);
1742     GNUNET_CONTAINER_DLL_remove(rh->authority_chain_head,
1743                               rh->authority_chain_tail,
1744                               next_authority);
1745
1746     GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1747                                    &rh->authority_chain_tail->zone,
1748                                    &rh->authority_chain_head->zone,
1749                                    &process_zone_to_name_shorten,
1750                                    rh);
1751   }
1752 }
1753
1754
1755 /**
1756  * Process result from namestore delegation lookup
1757  * for shorten operation
1758  *
1759  * @param cls the client shorten handle
1760  * @param rh the resolver handle
1761  * @param rd_count number of results (0)
1762  * @param rd data (NULL)
1763  */
1764 void
1765 handle_delegation_ns_shorten(void* cls,
1766                       struct ResolverHandle *rh,
1767                       uint32_t rd_count,
1768                       const struct GNUNET_NAMESTORE_RecordData *rd)
1769 {
1770   struct NameShortenHandle *nsh;
1771   char result[MAX_DNS_NAME_LENGTH];
1772   size_t answer_len;
1773
1774   nsh = (struct NameShortenHandle *)cls;
1775   
1776   /**
1777    * At this point rh->name contains the part of the name
1778    * that we do not have a PKEY in our namestore to resolve.
1779    * The authority chain in the resolver handle is now
1780    * useful to backtrack if needed
1781    */
1782   
1783   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1784              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1785
1786   if (GNUNET_CRYPTO_short_hash_cmp(&rh->authority_chain_head->zone,
1787                                    &rh->authority_chain_tail->zone) == 0)
1788   {
1789     /**
1790      * This is our zone append .gnunet unless name is empty
1791      * (it shouldn't be, usually FIXME what happens if we
1792      * shorten to our zone to a "" record??)
1793      */
1794     
1795     answer_len = strlen(rh->name) + strlen(GNUNET_GNS_TLD) + 2;
1796     memset(result, 0, answer_len);
1797     strcpy(result, rh->name);
1798     strcpy(result+strlen(rh->name), ".");
1799     strcpy(result+strlen(rh->name)+1, GNUNET_GNS_TLD);
1800
1801     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1802                "Our zone: Sending name as shorten result %s\n", rh->name);
1803     
1804     nsh->proc(nsh->proc_cls, result);
1805     GNUNET_free(nsh);
1806     free_resolver_handle(rh);
1807     return;
1808   }
1809   
1810   /* backtrack authorities for names */
1811   GNUNET_NAMESTORE_zone_to_name (namestore_handle,
1812                                  &rh->authority_chain_tail->zone, //ours
1813                                  &rh->authority_chain_head->zone,
1814                                  &process_zone_to_name_shorten,
1815                                  rh);
1816
1817 }
1818
1819 /**
1820  * Shorten api from resolver
1821  *
1822  * @param zone the zone to use
1823  * @param name the name to shorten
1824  * @param proc the processor to call with result
1825  * @param cls closure to pass to proc
1826  */
1827 void
1828 gns_resolver_shorten_name(struct GNUNET_CRYPTO_ShortHashCode zone,
1829                           const char* name,
1830                           ShortenResultProcessor proc,
1831                           void* cls)
1832 {
1833   struct ResolverHandle *rh;
1834   struct NameShortenHandle *nsh;
1835   char string_hash[MAX_DNS_NAME_LENGTH]; //FIXME LABEL length when shorthash
1836
1837   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1838               "Starting shorten for %s!\n", name);
1839   
1840   if (is_canonical((char*)name))
1841   {
1842     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1843                 "%s is canonical. Returning verbatim\n", name);
1844     proc(cls, name);
1845     return;
1846   }
1847
1848   nsh = GNUNET_malloc(sizeof (struct NameShortenHandle));
1849   
1850
1851   nsh->proc = proc;
1852   nsh->proc_cls = cls;
1853   
1854   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
1855   rh->authority = zone;
1856   
1857   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1858                 "Checking for TLD...\n");
1859   if (is_zkey_tld(name) == GNUNET_YES)
1860   {
1861     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1862                 "TLD is zkey\n");
1863     /**
1864      * This is a zkey tld
1865      * build hash and use as initial authority
1866      */
1867     memset(rh->name, 0,
1868            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY));
1869     memcpy(rh->name, name,
1870            strlen(name)-strlen(GNUNET_GNS_TLD_ZKEY) - 1);
1871     pop_tld(rh->name, string_hash);
1872
1873     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1874                 "ZKEY is %s!\n", string_hash);
1875
1876     if (GNUNET_OK != GNUNET_CRYPTO_short_hash_from_string(string_hash,
1877                                                           &rh->authority))
1878     {
1879       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1880                   "Cannot convert ZKEY %s to hash!\n", string_hash);
1881       GNUNET_free(rh);
1882       GNUNET_free(nsh);
1883       proc(cls, name);
1884       return;
1885     }
1886
1887   }
1888   else
1889   {
1890     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1891                 "TLD is gnunet\n");
1892     /**
1893      * Presumably GNUNET tld
1894      */
1895     memset(rh->name, 0,
1896            strlen(name)-strlen(GNUNET_GNS_TLD));
1897     memcpy(rh->name, name,
1898            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
1899   }
1900
1901   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
1902   rh->authority_chain_tail = rh->authority_chain_head;
1903   rh->authority_chain_head->zone = zone;
1904   rh->proc = &handle_delegation_ns_shorten;
1905   rh->proc_cls = nsh;
1906   
1907   /* Start delegation resolution in our namestore */
1908   resolve_delegation_ns(rh);
1909 }
1910
1911 /*********** END NAME SHORTEN ********************/
1912
1913
1914 /**
1915  * Process result from namestore delegation lookup
1916  * for get authority operation
1917  *
1918  * @param cls the client get auth handle
1919  * @param rh the resolver handle
1920  * @param rd_count number of results (0)
1921  * @param rd data (NULL)
1922  */
1923 void
1924 handle_delegation_result_ns_get_auth(void* cls,
1925                       struct ResolverHandle *rh,
1926                       uint32_t rd_count,
1927                       const struct GNUNET_NAMESTORE_RecordData *rd)
1928 {
1929   struct GetNameAuthorityHandle* nah;
1930   char result[MAX_DNS_NAME_LENGTH];
1931   size_t answer_len;
1932
1933   nah = (struct GetNameAuthorityHandle*) rh->proc_cls;
1934   
1935   /**
1936    * At this point rh->name contains the part of the name
1937    * that we do not have a PKEY in our namestore to resolve.
1938    * The authority chain in the resolver handle is now
1939    * useful to backtrack if needed
1940    */
1941   
1942   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1943              "PKEY resolved as far as possible in ns up to %s!\n", rh->name);
1944
1945   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1946              "Building response!\n");
1947   if (is_canonical(rh->name))
1948   {
1949     /**
1950      * We successfully resolved the authority in the ns
1951      * FIXME for our purposes this is fine
1952      * but maybe we want to have an api that also looks
1953      * into the dht (i.e. option in message)
1954      **/
1955     if (strlen(rh->name) > strlen(nah->name))
1956     {
1957       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1958                  "Record name longer than original lookup name... odd!\n");
1959       //FIXME to sth here
1960     }
1961
1962     answer_len = strlen(nah->name) - strlen(rh->name)
1963       + strlen(GNUNET_GNS_TLD) + 1;
1964     memset(result, 0, answer_len);
1965     strcpy(result, nah->name + strlen(rh->name) + 1);
1966
1967     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1968                "Got authority result %s\n", result);
1969     
1970     nah->proc(nah->proc_cls, result);
1971     GNUNET_free(nah);
1972     free_resolver_handle(rh);
1973   }
1974   else
1975   {
1976     GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1977                "Unable to resolve authority for remaining %s!\n", rh->name);
1978     nah->proc(nah->proc_cls, "");
1979     GNUNET_free(nah);
1980     free_resolver_handle(rh);
1981   }
1982
1983
1984 }
1985
1986
1987 /**
1988  * Tries to resolve the authority for name
1989  * in our namestore
1990  *
1991  * @param zone the root zone to look up for
1992  * @param name the name to lookup up
1993  * @param proc the processor to call when finished
1994  * @param cls the closure to pass to the processor
1995  */
1996 void
1997 gns_resolver_get_authority(struct GNUNET_CRYPTO_ShortHashCode zone,
1998                            const char* name,
1999                            GetAuthorityResultProcessor proc,
2000                            void* cls)
2001 {
2002   struct ResolverHandle *rh;
2003   struct GetNameAuthorityHandle *nah;
2004
2005   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2006               "Starting authority resolution for %s!\n", name);
2007
2008   nah = GNUNET_malloc(sizeof (struct GetNameAuthorityHandle));
2009   rh = GNUNET_malloc(sizeof (struct ResolverHandle));
2010   rh->authority = zone;
2011   
2012   if (strcmp(GNUNET_GNS_TLD, name) == 0)
2013   {
2014     strcpy(rh->name, "\0");
2015   }
2016   else
2017   {
2018     memset(rh->name, 0,
2019            strlen(name)-strlen(GNUNET_GNS_TLD));
2020     memcpy(rh->name, name,
2021            strlen(name)-strlen(GNUNET_GNS_TLD) - 1);
2022   }
2023
2024   memset(nah->name, 0,
2025          strlen(name)+1);
2026   strcpy(nah->name, name);
2027   
2028   rh->authority_chain_head = GNUNET_malloc(sizeof(struct AuthorityChain));
2029   rh->authority_chain_tail = rh->authority_chain_head;
2030   rh->authority_chain_head->zone = zone;
2031   rh->proc = &handle_delegation_result_ns_get_auth;
2032   rh->proc_cls = (void*)nah;
2033
2034   nah->proc = proc;
2035   nah->proc_cls = cls;
2036
2037   /* Start delegation resolution in our namestore */
2038   resolve_delegation_ns(rh);
2039
2040 }
2041
2042 /******** END GET AUTHORITY *************/
2043
2044 /* end of gnunet-service-gns_resolver.c */