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