@@ -80,7 +80,7 @@ pub type BoxIter<T> = Box<dyn Iterator<Item = T> + Send + 'static>;
8080
8181/// Potential errors related to DNS operations.
8282#[ allow( missing_docs) ]
83- #[ stack_error( derive, add_meta, from_sources , std_sources) ]
83+ #[ stack_error( derive, add_meta, std_sources) ]
8484#[ non_exhaustive]
8585pub enum DnsError {
8686 #[ error( "Request timed out" ) ]
@@ -94,27 +94,62 @@ pub enum DnsError {
9494 } ,
9595 #[ error( "Missing host" ) ]
9696 MissingHost { } ,
97+
98+ /// DEPRECATED since v1.1.0. Replaced by [`Self::Resolve2`].
99+ // TODO: This triggers warnings in n0_error expansions. Fix in n0_error.
100+ // #[deprecated(
101+ // since = "1.1.0",
102+ // note = "No longer constructed, replaced by DnsError::Resolve2"
103+ // )]
97104 #[ error( "Failed to resolve" ) ]
98- Resolve { source : AnyError } ,
105+ Resolve {
106+ // We keep the `from` here, because pre-1.1.0 the `stack_error` macro call on `DnsError` included
107+ // `from_sources`, which expanded to `impl From<AnyError> for `DnsError`. The manual `from` impl
108+ // here on the deprecated variant exists only to maintain backwards compatibility.
109+ #[ error( source, from) ]
110+ source : AnyError ,
111+ } ,
112+ #[ error( "Failed to retrieve {kind} record for {host}" ) ]
113+ Resolve2 {
114+ #[ error( source) ]
115+ source : AnyError ,
116+ host : String ,
117+ kind : QueryKind ,
118+ } ,
99119 #[ error( "Invalid DNS response: not a query for _iroh.z32encodedpubkey" ) ]
100120 InvalidResponse { } ,
101121}
102122
123+ /// DNS query kind, for error reporting.
124+ #[ derive( Debug , derive_more:: Display ) ]
125+ pub enum QueryKind {
126+ /// A record (IPv4)
127+ #[ display( "A" ) ]
128+ A ,
129+ /// AAAA record (IPv6)
130+ #[ display( "AAAA" ) ]
131+ AAAA ,
132+ /// TXT record
133+ #[ display( "TXT" ) ]
134+ TXT ,
135+ }
136+
103137/// Potential errors related to DNS endpoint address lookups.
104138#[ cfg( not( wasm_browser) ) ]
105139#[ allow( missing_docs) ]
106140#[ stack_error( derive, add_meta, from_sources) ]
107141#[ non_exhaustive]
108142pub enum LookupError {
109- #[ error( "Malformed txt from lookup " ) ]
143+ #[ error( "Received malformed TXT record " ) ]
110144 ParseError { source : ParseError } ,
111- #[ error( "Failed to resolve TXT record" ) ]
145+ #[ error( transparent ) ]
112146 LookupFailed { source : DnsError } ,
113147}
114148
115149/// Error returned when a staggered call fails.
116150#[ stack_error( derive, add_meta) ]
117- #[ error( "no calls succeeded: [{}]" , errors. iter( ) . map( |e| e. to_string( ) ) . collect:: <Vec <_>>( ) . join( "" ) ) ]
151+ #[ error( "{}" , errors. first( ) . map( |err| format!( "{err:#}" ) ) . unwrap_or( "all resolves failed" . to_string( ) ) ) ]
152+ // #[error("no calls succeeded:\n{}", errors.iter().map(|(delay, e)| format!("[{delay:?}] {e:#}")).collect::<Vec<_>>().join("\n"))]
118153pub struct StaggeredError < E : n0_error:: StackError + ' static > {
119154 errors : Vec < E > ,
120155}
@@ -795,7 +830,17 @@ impl Resolver for HickoryResolver {
795830 fn lookup_ipv4 ( & self , host : String ) -> BoxFuture < Result < BoxIter < Ipv4Addr > , DnsError > > {
796831 let resolver = self . resolver . clone ( ) ;
797832 Box :: pin ( async move {
798- let lookup = resolver. ipv4_lookup ( host) . await . anyerr ( ) ?;
833+ let lookup = resolver
834+ . ipv4_lookup ( host. clone ( ) )
835+ . await
836+ . anyerr ( )
837+ . map_err ( |source| {
838+ e ! ( DnsError :: Resolve2 {
839+ source,
840+ host,
841+ kind: QueryKind :: A
842+ } )
843+ } ) ?;
799844 let iter: BoxIter < Ipv4Addr > =
800845 Box :: new ( lookup. answers ( ) . to_vec ( ) . into_iter ( ) . filter_map ( |record| {
801846 match & record. data {
@@ -810,7 +855,17 @@ impl Resolver for HickoryResolver {
810855 fn lookup_ipv6 ( & self , host : String ) -> BoxFuture < Result < BoxIter < Ipv6Addr > , DnsError > > {
811856 let resolver = self . resolver . clone ( ) ;
812857 Box :: pin ( async move {
813- let lookup = resolver. ipv6_lookup ( host) . await . anyerr ( ) ?;
858+ let lookup = resolver
859+ . ipv6_lookup ( host. clone ( ) )
860+ . await
861+ . anyerr ( )
862+ . map_err ( |source| {
863+ e ! ( DnsError :: Resolve2 {
864+ source,
865+ host,
866+ kind: QueryKind :: AAAA
867+ } )
868+ } ) ?;
814869 let iter: BoxIter < Ipv6Addr > =
815870 Box :: new ( lookup. answers ( ) . to_vec ( ) . into_iter ( ) . filter_map ( |record| {
816871 match & record. data {
@@ -825,7 +880,17 @@ impl Resolver for HickoryResolver {
825880 fn lookup_txt ( & self , host : String ) -> BoxFuture < Result < BoxIter < TxtRecordData > , DnsError > > {
826881 let resolver = self . resolver . clone ( ) ;
827882 Box :: pin ( async move {
828- let lookup = resolver. txt_lookup ( host) . await . anyerr ( ) ?;
883+ let lookup = resolver
884+ . txt_lookup ( host. clone ( ) )
885+ . await
886+ . anyerr ( )
887+ . map_err ( |source| {
888+ e ! ( DnsError :: Resolve2 {
889+ source,
890+ host,
891+ kind: QueryKind :: TXT
892+ } )
893+ } ) ?;
829894 let iter: BoxIter < TxtRecordData > =
830895 Box :: new ( lookup. answers ( ) . to_vec ( ) . into_iter ( ) . filter_map ( |record| {
831896 match & record. data {
0 commit comments