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