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