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