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