diff --git a/CHANGELOG.md b/CHANGELOG.md index 31b3760..7c80f56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Bump MSRV to 1.77.0 for `ip_in_core`. - Removed the `no-std-net` and `ip_in_core` features, `ip_in_core` is now the default. +## Changed +- [breaking] The DNS traits have been removed and placed into the default `NetworkStack` +implementation. All stacks must implement these traits (but may implement them as `Unsupported` + features. + ## [0.8.0] - 2023-11-10 - Bump MSRV to 1.60.0 (required for Edition 2021) diff --git a/src/dns.rs b/src/dns.rs deleted file mode 100644 index 7470421..0000000 --- a/src/dns.rs +++ /dev/null @@ -1,75 +0,0 @@ -use core::net::IpAddr; - -/// This is the host address type to be returned by `gethostbyname`. -/// -/// An IPv4 address type always looks for `A` records, while IPv6 address type -/// will look for `AAAA` records -#[derive(Clone, Debug, PartialEq)] -pub enum AddrType { - /// Result is `A` record - IPv4, - /// Result is `AAAA` record - IPv6, - /// Result is either a `A` record, or a `AAAA` record - Either, -} - -/// This trait is an extension trait for [`TcpStack`] and [`UdpStack`] for dns -/// resolutions. It does not handle every DNS record type, but is meant as an -/// embedded alternative to [`ToSocketAddrs`], and is as such meant to resolve -/// an ip address from a hostname, or a hostname from an ip address. This means -/// that it only deals in host address records `A` (IPv4) and `AAAA` (IPv6). -/// -/// [`TcpStack`]: crate::trait@TcpStack -/// [`UdpStack`]: crate::trait@UdpStack -/// [`ToSocketAddrs`]: -/// https://doc.rust-lang.org/std/net/trait.ToSocketAddrs.html -pub trait Dns { - /// The type returned when we have an error - type Error: core::fmt::Debug; - - /// Resolve the first ip address of a host, given its hostname and a desired - /// address record type to look for - fn get_host_by_name( - &mut self, - hostname: &str, - addr_type: AddrType, - ) -> nb::Result; - - /// Resolve the hostname of a host, given its ip address. - /// - /// The hostname is stored at the beginning of `result`, the length is returned. - /// - /// If the buffer is too small to hold the domain name, an error should be returned. - /// - /// **Note**: A fully qualified domain name (FQDN), has a maximum length of - /// 255 bytes according to [`rfc1035`]. Therefore, you can pass a 255-byte long - /// buffer to guarantee it'll always be large enough. - /// - /// [`rfc1035`]: https://tools.ietf.org/html/rfc1035 - fn get_host_by_address( - &mut self, - addr: IpAddr, - result: &mut [u8], - ) -> nb::Result; -} - -impl Dns for &mut T { - type Error = T::Error; - - fn get_host_by_name( - &mut self, - hostname: &str, - addr_type: AddrType, - ) -> nb::Result { - T::get_host_by_name(self, hostname, addr_type) - } - - fn get_host_by_address( - &mut self, - addr: IpAddr, - result: &mut [u8], - ) -> nb::Result { - T::get_host_by_address(self, addr, result) - } -} diff --git a/src/lib.rs b/src/lib.rs index 5cf4aa8..c4a3fc7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,13 +3,105 @@ #![deny(missing_docs)] #![deny(unsafe_code)] -mod dns; mod stack; +use core::net::IpAddr; pub use nb; -pub use dns::{AddrType, Dns}; pub use stack::{ - SharableStack, SharedStack, TcpClientStack, TcpError, TcpErrorKind, TcpFullStack, - UdpClientStack, UdpFullStack, + SharableStack, SharedStack, TcpClientStack, TcpFullStack, UdpClientStack, UdpFullStack, }; + +/// This is the host address type to be returned by `gethostbyname`. +/// +/// An IPv4 address type always looks for `A` records, while IPv6 address type +/// will look for `AAAA` records +#[derive(Clone, Debug, PartialEq)] +pub enum AddrType { + /// Result is `A` record + IPv4, + /// Result is `AAAA` record + IPv6, + /// Result is either a `A` record, or a `AAAA` record + Either, +} + +/// Represents specific errors encountered during TCP operations. +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum ErrorKind { + /// The socket has been closed in the direction in which the failing operation was attempted. + PipeClosed, + + /// The operation requested is not supported. + Unsupported, + + /// Some other error has occurred. + Other, +} + +/// Marker trait for errors that can be resolved to predefined categorical types. +pub trait Error: core::fmt::Debug { + /// Determine the type of error that occurred. + fn kind(&self) -> ErrorKind; +} + +/// This trait is an extension trait for [`TcpStack`] and [`UdpStack`] for dns +/// resolutions. It does not handle every DNS record type, but is meant as an +/// embedded alternative to [`ToSocketAddrs`], and is as such meant to resolve +/// an ip address from a hostname, or a hostname from an ip address. This means +/// that it only deals in host address records `A` (IPv4) and `AAAA` (IPv6). +/// +/// [`TcpStack`]: crate::trait@TcpStack +/// [`UdpStack`]: crate::trait@UdpStack +/// [`ToSocketAddrs`]: +/// https://doc.rust-lang.org/std/net/trait.ToSocketAddrs.html +pub trait NetworkStack { + /// The type returned when we have an error + type Error: Error; + + /// Resolve the first ip address of a host, given its hostname and a desired + /// address record type to look for + fn get_host_by_name( + &mut self, + hostname: &str, + addr_type: AddrType, + ) -> nb::Result; + + /// Resolve the hostname of a host, given its ip address. + /// + /// The hostname is stored at the beginning of `result`, the length is returned. + /// + /// If the buffer is too small to hold the domain name, an error should be returned. + /// + /// **Note**: A fully qualified domain name (FQDN), has a maximum length of + /// 255 bytes according to [`rfc1035`]. Therefore, you can pass a 255-byte long + /// buffer to guarantee it'll always be large enough. + /// + /// [`rfc1035`]: https://tools.ietf.org/html/rfc1035 + fn get_host_by_address( + &mut self, + addr: IpAddr, + result: &mut [u8], + ) -> nb::Result; +} + +impl NetworkStack for &mut T { + type Error = T::Error; + + fn get_host_by_name( + &mut self, + hostname: &str, + addr_type: AddrType, + ) -> nb::Result { + T::get_host_by_name(self, hostname, addr_type) + } + + fn get_host_by_address( + &mut self, + addr: IpAddr, + result: &mut [u8], + ) -> nb::Result { + T::get_host_by_address(self, addr, result) + } +} diff --git a/src/stack/mod.rs b/src/stack/mod.rs index f86c594..7f2c57d 100644 --- a/src/stack/mod.rs +++ b/src/stack/mod.rs @@ -3,5 +3,5 @@ mod tcp; mod udp; pub use share::{SharableStack, SharedStack}; -pub use tcp::{TcpClientStack, TcpError, TcpErrorKind, TcpFullStack}; +pub use tcp::{TcpClientStack, TcpFullStack}; pub use udp::{UdpClientStack, UdpFullStack}; diff --git a/src/stack/share.rs b/src/stack/share.rs index c8caec8..95b17c2 100644 --- a/src/stack/share.rs +++ b/src/stack/share.rs @@ -1,4 +1,6 @@ -use crate::{nb, TcpClientStack, TcpFullStack, UdpClientStack, UdpFullStack}; +use crate::{ + nb, AddrType, IpAddr, NetworkStack, TcpClientStack, TcpFullStack, UdpClientStack, UdpFullStack, +}; use core::cell::RefCell; use core::net::SocketAddr; @@ -97,17 +99,26 @@ macro_rules! forward { } } +impl<'a, T> NetworkStack for SharedStack<'a, T> +where + T: NetworkStack, +{ + type Error = T::Error; + + forward! {get_host_by_name(hostname: &str, addr_type: AddrType) -> nb::Result} + forward! {get_host_by_address(addr: IpAddr, result: &mut [u8]) -> nb::Result} +} + impl<'a, T> UdpClientStack for SharedStack<'a, T> where T: UdpClientStack, { - type Error = T::Error; type UdpSocket = T::UdpSocket; forward! {socket() -> Result} forward! {connect(socket: &mut Self::UdpSocket, address: SocketAddr) -> Result<(), Self::Error>} - forward! {send(socket: &mut Self::UdpSocket, data: &[u8]) -> Result<(), nb::Error<::Error>>} - forward! {receive(socket: &mut Self::UdpSocket, data: &mut [u8]) -> Result<(usize, SocketAddr), nb::Error<::Error>>} + forward! {send(socket: &mut Self::UdpSocket, data: &[u8]) -> Result<(), nb::Error>} + forward! {receive(socket: &mut Self::UdpSocket, data: &mut [u8]) -> Result<(usize, SocketAddr), nb::Error>} forward! {close(socket: Self::UdpSocket) -> Result<(), Self::Error>} } @@ -116,7 +127,7 @@ where T: UdpFullStack, { forward! {bind(socket: &mut Self::UdpSocket, local_port: u16) -> Result<(), Self::Error>} - forward! {send_to(socket: &mut Self::UdpSocket, remote: SocketAddr, buffer: &[u8]) -> Result<(), nb::Error<::Error>>} + forward! {send_to(socket: &mut Self::UdpSocket, remote: SocketAddr, buffer: &[u8]) -> Result<(), nb::Error>} } impl<'a, T> TcpClientStack for SharedStack<'a, T> @@ -124,12 +135,11 @@ where T: TcpClientStack, { type TcpSocket = T::TcpSocket; - type Error = T::Error; forward! {socket() -> Result} - forward! {connect(socket: &mut Self::TcpSocket, address: SocketAddr) -> Result<(), nb::Error<::Error>>} - forward! {send(socket: &mut Self::TcpSocket, data: &[u8]) -> Result::Error>>} - forward! {receive(socket: &mut Self::TcpSocket, data: &mut [u8]) -> Result::Error>>} + forward! {connect(socket: &mut Self::TcpSocket, address: SocketAddr) -> Result<(), nb::Error>} + forward! {send(socket: &mut Self::TcpSocket, data: &[u8]) -> Result>} + forward! {receive(socket: &mut Self::TcpSocket, data: &mut [u8]) -> Result>} forward! {close(socket: Self::TcpSocket) -> Result<(), Self::Error>} } @@ -137,7 +147,7 @@ impl<'a, T> TcpFullStack for SharedStack<'a, T> where T: TcpFullStack, { - forward! {bind(socket: &mut Self::TcpSocket, port: u16) -> Result<(), ::Error>} - forward! {listen(socket: &mut Self::TcpSocket) -> Result<(), ::Error>} - forward! {accept(socket: &mut Self::TcpSocket) -> Result<(::TcpSocket, SocketAddr), nb::Error<::Error>>} + forward! {bind(socket: &mut Self::TcpSocket, port: u16) -> Result<(), T::Error>} + forward! {listen(socket: &mut Self::TcpSocket) -> Result<(), T::Error>} + forward! {accept(socket: &mut Self::TcpSocket) -> Result<(T::TcpSocket, SocketAddr), nb::Error>} } diff --git a/src/stack/tcp.rs b/src/stack/tcp.rs index d28f76f..61f8b36 100644 --- a/src/stack/tcp.rs +++ b/src/stack/tcp.rs @@ -1,31 +1,13 @@ +use crate::NetworkStack; use core::net::SocketAddr; -/// Represents specific errors encountered during TCP operations. -#[non_exhaustive] -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum TcpErrorKind { - /// The socket has been closed in the direction in which the failing operation was attempted. - PipeClosed, - - /// Some other error has occurred. - Other, -} - -/// Methods to resolve errors into identifiable, actionable codes on the client side. -pub trait TcpError: core::fmt::Debug { - /// Determines the kind of error that occurred. - fn kind(&self) -> TcpErrorKind; -} - /// This trait is implemented by TCP/IP stacks. You could, for example, have an implementation /// which knows how to send AT commands to an ESP8266 WiFi module. You could have another implementation /// which knows how to driver the Rust Standard Library's `std::net` module. Given this trait, you can /// write a portable HTTP client which can work with either implementation. -pub trait TcpClientStack { +pub trait TcpClientStack: NetworkStack { /// The type returned when we create a new TCP socket type TcpSocket; - /// The type returned when we have an error - type Error: TcpError; /// Open a socket for usage as a TCP client. /// @@ -96,8 +78,6 @@ pub trait TcpFullStack: TcpClientStack { } impl TcpClientStack for &mut T { - type Error = T::Error; - type TcpSocket = T::TcpSocket; fn socket(&mut self) -> Result { diff --git a/src/stack/udp.rs b/src/stack/udp.rs index c45e6fb..ffcc548 100644 --- a/src/stack/udp.rs +++ b/src/stack/udp.rs @@ -1,3 +1,4 @@ +use crate::NetworkStack; use core::net::SocketAddr; /// This trait is implemented by UDP/IP stacks. You could, for example, have @@ -5,11 +6,9 @@ use core::net::SocketAddr; /// module. You could have another implementation which knows how to driver the /// Rust Standard Library's `std::net` module. Given this trait, you can how /// write a portable CoAP client which can work with either implementation. -pub trait UdpClientStack { +pub trait UdpClientStack: NetworkStack { /// The type returned when we create a new UDP socket type UdpSocket; - /// The type returned when we have an error - type Error: core::fmt::Debug; /// Allocate a socket for further use. fn socket(&mut self) -> Result; @@ -61,8 +60,6 @@ pub trait UdpFullStack: UdpClientStack { } impl UdpClientStack for &mut T { - type Error = T::Error; - type UdpSocket = T::UdpSocket; fn socket(&mut self) -> Result {