Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

no-std support for hickory-proto #2104

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
722 changes: 444 additions & 278 deletions Cargo.lock

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ hickory-proto = { version = "0.24.0", path = "crates/proto", default-features =


# logging
tracing = "0.1.30"
tracing = { version = "0.1.37", default-features = false }
tracing-subscriber = "0.3"
thiserror = "1.0.20"
thiserror = { version = "1.0.50", package = "thiserror-core", default-features = false }


# async/await
Expand Down Expand Up @@ -83,26 +83,26 @@ bytes = "1"
cfg-if = "1"
clap = { version = "4.0", default-features = false }
console = "0.15.0"
data-encoding = "2.2.0"
data-encoding = { version = "2.2.0", default-features = false }
enum-as-inner = "0.6"
idna = "0.4.0"
idna = { version = "0.5", default-features = false, features = ["alloc"] }
ipconfig = "0.3.0"
ipnet = "2.3.0"
ipnet = { version = "2.3.0", default-features = false }
js-sys = "0.3.44"
once_cell = "1.18.0"
once_cell = { version = "1.18.0", default-features = false }
lru-cache = "0.1.2"
pin-utils = "0.1.0"
radix_trie = "0.2.0"
rand = "0.8"
regex = "1.3.4"
rand = { version = "0.8", default-features = false, features = ["std_rng", "alloc"] }
regex = { version = "1.3.4", default-features = false }
resolv-conf = "0.7.0"
rusqlite = "0.29.0"
serde = "1.0"
smallvec = "1.6"
socket2 = "0.5"
time = "0.3"
tinyvec = "1.1.1"
url = "2.4.0"
url = { git = "https://github.com/domenukk/rust-url.git", default-features = false, features = ["alloc", "unstable"], rev = "be73851" }
wasm-bindgen-crate = { version = "0.2.58", package = "wasm-bindgen" }

[patch.crates-io]
Expand Down
42 changes: 32 additions & 10 deletions crates/proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,27 @@ codecov = { repository = "hickory-dns/hickory-dns", branch = "main", service = "
maintenance = { status = "actively-developed" }

[features]
std = [
"data-encoding/std",
"futures-channel/std",
"futures-io/std",
"futures-util/std",
"ipnet/std",
"rand/std",
"ring/std",
"thiserror/std",
"tracing/std",
"tracing-subscriber/std",
"url/std",
]

unstable = [
#"thiserror/unstable",
"const-random",
"critical-section",
"once_cell/critical-section",
]

dns-over-tls = []
dns-over-rustls = [
"dns-over-tls",
Expand Down Expand Up @@ -61,18 +82,18 @@ native-certs = ["dep:rustls-native-certs"]

dnssec-openssl = ["dnssec", "openssl"]
dnssec-ring = ["dnssec", "ring"]
dnssec = []
dnssec = ["std"]

testing = []

text-parsing = []
tokio-runtime = ["tokio/net", "tokio/rt", "tokio/time", "tokio/rt-multi-thread"]
default = ["tokio-runtime"]
tokio-runtime = ["tokio/net", "tokio/rt", "tokio/time", "tokio/rt-multi-thread", "std"]
default = ["tokio-runtime", "std"]

serde-config = ["serde", "url/serde"]

# enables experimental the mDNS (multicast) feature
mdns = ["socket2/all"]
mdns = ["socket2/all", "std"]

# WARNING: there is a bug in the mutual tls auth code at the moment see issue #100
# mtls = ["tls"]
Expand All @@ -90,14 +111,16 @@ async-trait.workspace = true
backtrace = { workspace = true, optional = true }
bytes = { workspace = true, optional = true }
cfg-if.workspace = true
data-encoding.workspace = true
const-random = { version = "0.1.15", optional = true }
critical-section = { version = "1.1.1", optional = true }
data-encoding = { workspace = true, features = ["alloc"] }
enum-as-inner.workspace = true
futures-channel = { workspace = true, default-features = false, features = [
"std",
"alloc",
] }
futures-io = { workspace = true, default-features = false, features = ["std"] }
futures-io = { workspace = true, default-features = false }
futures-util = { workspace = true, default-features = false, features = [
"std",
"alloc",
] }
h2 = { workspace = true, features = ["stream"], optional = true }
h3 = { workspace = true, optional = true }
Expand All @@ -123,7 +146,7 @@ serde = { workspace = true, features = ["derive"], optional = true }
socket2 = { workspace = true, optional = true }
thiserror.workspace = true
tinyvec = { workspace = true, features = ["alloc"] }
tracing.workspace = true
tracing = { workspace = true, default-features = false }
tokio = { workspace = true, features = ["io-util"], optional = true }
tokio-native-tls = { workspace = true, optional = true }
tokio-openssl = { workspace = true, optional = true }
Expand All @@ -139,7 +162,6 @@ futures-executor = { workspace = true, default-features = false, features = [
openssl = { workspace = true, features = ["v102", "v110"] }
tokio = { workspace = true, features = ["rt", "time", "macros"] }
tracing-subscriber = { workspace = true, features = [
"std",
"fmt",
"env-filter",
] }
Expand Down
67 changes: 48 additions & 19 deletions crates/proto/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@

#![deny(missing_docs)]

use std::cmp::Ordering;
use std::{fmt, io, sync};
use core::cmp::Ordering;
use core::fmt;
#[cfg(feature = "std")]
use std::{io, sync};

use alloc::boxed::Box;
use alloc::string::{String, ToString};
#[cfg(feature = "backtrace")]
#[cfg_attr(docsrs, doc(cfg(feature = "backtrace")))]
pub use backtrace::Backtrace as ExtBacktrace;
Expand Down Expand Up @@ -59,7 +63,7 @@ macro_rules! trace {
}

/// An alias for results returned by functions of this crate
pub type ProtoResult<T> = ::std::result::Result<T, ProtoError>;
pub type ProtoResult<T> = ::core::result::Result<T, ProtoError>;

/// The error kind for errors that get returned in the crate
#[derive(Debug, EnumAsInner, Error)]
Expand Down Expand Up @@ -233,6 +237,7 @@ pub enum ProtoErrorKind {

// foreign
/// An error got returned from IO
#[cfg(feature = "std")]
#[error("io error: {0}")]
Io(io::Error),

Expand Down Expand Up @@ -272,15 +277,15 @@ pub enum ProtoErrorKind {

/// A utf8 parsing error
#[error("error parsing utf8 string")]
Utf8(#[from] std::str::Utf8Error),
Utf8(#[from] alloc::str::Utf8Error),

/// A utf8 parsing error
#[error("error parsing utf8 string")]
FromUtf8(#[from] std::string::FromUtf8Error),
FromUtf8(#[from] alloc::string::FromUtf8Error),

/// An int parsing error
#[error("error parsing int")]
ParseInt(#[from] std::num::ParseIntError),
ParseInt(#[from] core::num::ParseIntError),

/// A Quinn (Quic) connection error occurred
#[cfg(feature = "quinn")]
Expand Down Expand Up @@ -376,7 +381,7 @@ impl ProtoError {
pub fn is_no_connections(&self) -> bool {
matches!(*self.kind, ProtoErrorKind::NoConnections)
}

#[cfg(feature = "std")]
pub(crate) fn as_dyn(&self) -> &(dyn std::error::Error + 'static) {
self
}
Expand Down Expand Up @@ -468,8 +473,11 @@ impl ProtoError {
}

match (kind, other) {
#[cfg(feature = "std")]
(ProtoErrorKind::Io { .. }, ProtoErrorKind::Io { .. }) => return Ordering::Equal,
#[cfg(feature = "std")]
(ProtoErrorKind::Io { .. }, _) => return Ordering::Greater,
#[cfg(feature = "std")]
(_, ProtoErrorKind::Io { .. }) => return Ordering::Less,
_ => (),
}
Expand Down Expand Up @@ -547,6 +555,7 @@ impl From<String> for ProtoError {
}
}

#[cfg(feature = "std")]
impl From<io::Error> for ProtoErrorKind {
fn from(e: io::Error) -> Self {
match e.kind() {
Expand All @@ -556,12 +565,14 @@ impl From<io::Error> for ProtoErrorKind {
}
}

#[cfg(feature = "std")]
impl<T> From<sync::PoisonError<T>> for ProtoError {
fn from(_e: sync::PoisonError<T>) -> Self {
ProtoErrorKind::Poisoned.into()
}
}

#[cfg(feature = "std")]
impl From<ProtoError> for io::Error {
fn from(e: ProtoError) -> Self {
match *e.kind() {
Expand Down Expand Up @@ -641,6 +652,7 @@ impl Clone for ProtoErrorKind {
UnrecognizedCsyncFlags(flags) => UnrecognizedCsyncFlags(flags),

// foreign
#[cfg(feature = "std")]
Io(ref e) => Io(if let Some(raw) = e.raw_os_error() {
io::Error::from_raw_os_error(raw)
} else {
Expand Down Expand Up @@ -682,9 +694,17 @@ impl Clone for ProtoErrorKind {

/// A trait marking a type which implements From<ProtoError> and
/// std::error::Error types as well as Clone + Send
#[cfg(feature = "std")]
pub trait FromProtoError: From<ProtoError> + std::error::Error + Clone {}
/// A trait marking a type which implements `From<ProtoError>` and
/// `core::error::Error` types as well as `Clone` + `Send`
#[cfg(not(feature = "std"))]
pub trait FromProtoError: From<ProtoError> + core::error::Error + Clone {}

#[cfg(feature = "std")]
impl<E> FromProtoError for E where E: From<ProtoError> + std::error::Error + Clone {}
#[cfg(not(feature = "std"))]
impl<E> FromProtoError for E where E: From<ProtoError> + core::error::Error + Clone {}

#[cfg(not(feature = "openssl"))]
use self::not_openssl::SslErrorStack;
Expand All @@ -696,7 +716,7 @@ use openssl::error::ErrorStack as SslErrorStack;
use ring::error::{KeyRejected, Unspecified};

/// An alias for dnssec results returned by functions of this crate
pub type DnsSecResult<T> = ::std::result::Result<T, DnsSecError>;
pub type DnsSecResult<T> = ::core::result::Result<T, DnsSecError>;

/// The error kind for dnssec errors that get returned in the crate
#[allow(unreachable_pub)]
Expand Down Expand Up @@ -836,17 +856,23 @@ impl From<SslErrorStack> for DnsSecError {
#[cfg(not(feature = "openssl"))]
#[cfg_attr(docsrs, doc(cfg(not(feature = "openssl"))))]
pub mod not_openssl {
use std;

#[derive(Clone, Copy, Debug)]
pub struct SslErrorStack;

impl std::fmt::Display for SslErrorStack {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl core::fmt::Display for SslErrorStack {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
Ok(())
}
}

#[cfg(not(feature = "std"))]
impl core::error::Error for SslErrorStack {
fn description(&self) -> &str {
"openssl feature not enabled"
}
}

#[cfg(feature = "std")]
impl std::error::Error for SslErrorStack {
fn description(&self) -> &str {
"openssl feature not enabled"
Expand All @@ -859,33 +885,36 @@ pub mod not_openssl {
#[cfg(not(feature = "ring"))]
#[cfg_attr(docsrs, doc(cfg(feature = "ring")))]
pub mod not_ring {
use std;
#[cfg(all(feature = "unstable", not(feature = "std")))]
use core::error::Error;
#[cfg(feature = "std")]
use std::error::Error;

#[derive(Clone, Copy, Debug)]
pub struct KeyRejected;

#[derive(Clone, Copy, Debug)]
pub struct Unspecified;

impl std::fmt::Display for KeyRejected {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl core::fmt::Display for KeyRejected {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
Ok(())
}
}

impl std::error::Error for KeyRejected {
impl Error for KeyRejected {
fn description(&self) -> &str {
"ring feature not enabled"
}
}

impl std::fmt::Display for Unspecified {
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
impl core::fmt::Display for Unspecified {
fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
Ok(())
}
}

impl std::error::Error for Unspecified {
impl Error for Unspecified {
fn description(&self) -> &str {
"ring feature not enabled"
}
Expand Down
13 changes: 8 additions & 5 deletions crates/proto/src/h2/h2_client_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
// https://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use alloc::boxed::Box;
use alloc::str::FromStr;
use alloc::string::String;
use alloc::sync::Arc;
use core::pin::Pin;
use core::task::{Context, Poll};
use std::fmt::{self, Display};
use std::future::Future;
use std::io;
use std::net::SocketAddr;
use std::ops::DerefMut;
use std::pin::Pin;
use std::str::FromStr;
use std::sync::Arc;
use std::task::{Context, Poll};

use bytes::{Buf, Bytes, BytesMut};
use futures_util::future::{FutureExt, TryFutureExt};
Expand Down Expand Up @@ -530,8 +532,9 @@ impl Future for HttpsClientResponse {
#[cfg(any(feature = "webpki-roots", feature = "native-certs"))]
#[cfg(test)]
mod tests {
use alloc::str::FromStr;
use alloc::string::ToString;
use std::net::SocketAddr;
use std::str::FromStr;

use rustls::KeyLogFile;
use tokio::net::TcpStream as TokioTcpStream;
Expand Down
9 changes: 5 additions & 4 deletions crates/proto/src/h2/h2_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

//! HTTPS related server items

use alloc::str::FromStr;
use alloc::sync::Arc;
use std::fmt::Debug;
use std::str::FromStr;
use std::sync::Arc;

use bytes::{Bytes, BytesMut};
use futures_util::stream::{Stream, StreamExt};
Expand Down Expand Up @@ -94,9 +94,10 @@ where

#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use core::pin::Pin;
use core::task::{Context, Poll};
use futures_executor::block_on;
use std::pin::Pin;
use std::task::{Context, Poll};

use crate::http::request;
use crate::op::Message;
Expand Down