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