Skip to content

Commit

Permalink
Usability tweaks (#397)
Browse files Browse the repository at this point in the history
This PR adds a few trait impls and documentation.

Specifically:

* Add blanket `SendRequest` and `SendRequestMulti` impls for boxes.
* Add `Display` impl to `tsig::Key`.
* Add an `as_any` method and `Clone` and `Debug` impls to various zonetree
  types.
* Add `AsRef<dyn ZoneStore>` to `Zone`.
  • Loading branch information
ximon18 authored Oct 3, 2024
1 parent 3b7ccb7 commit 41d72b3
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 11 deletions.
22 changes: 22 additions & 0 deletions src/net/client/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,17 @@ pub trait SendRequest<CR> {
) -> Box<dyn GetResponse + Send + Sync>;
}

impl<T: SendRequest<RequestMessage<Octs>> + ?Sized, Octs: Octets>
SendRequest<RequestMessage<Octs>> for Box<T>
{
fn send_request(
&self,
request_msg: RequestMessage<Octs>,
) -> Box<dyn GetResponse + Send + Sync> {
(**self).send_request(request_msg)
}
}

//------------ SendRequestMulti -----------------------------------------------

/// Trait for starting a DNS request based on a request composer.
Expand All @@ -133,6 +144,17 @@ pub trait SendRequestMulti<CR> {
) -> Box<dyn GetResponseMulti + Send + Sync>;
}

impl<T: SendRequestMulti<RequestMessage<Octs>> + ?Sized, Octs: Octets>
SendRequestMulti<RequestMessage<Octs>> for Box<T>
{
fn send_request(
&self,
request_msg: RequestMessage<Octs>,
) -> Box<dyn GetResponseMulti + Send + Sync> {
(**self).send_request(request_msg)
}
}

//------------ GetResponse ---------------------------------------------------

/// Trait for getting the result of a DNS query.
Expand Down
42 changes: 36 additions & 6 deletions src/tsig/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@
#![cfg(feature = "tsig")]
#![cfg_attr(docsrs, doc(cfg(feature = "tsig")))]

use core::{cmp, fmt, mem, str};

#[cfg(feature = "std")]
use std::collections::HashMap;
use std::sync::Arc;

use bytes::{Bytes, BytesMut};
use octseq::octets::Octets;
use ring::{constant_time, hkdf::KeyType, hmac, rand};

use crate::base::header::HeaderSection;
use crate::base::iana::{Class, Rcode, TsigRcode};
use crate::base::message::Message;
Expand All @@ -64,12 +74,6 @@ use crate::base::name::{Label, Name, ParsedName, ToLabelIter, ToName};
use crate::base::record::Record;
use crate::base::wire::{Composer, ParseError};
use crate::rdata::tsig::{Time48, Tsig};
use bytes::{Bytes, BytesMut};
use core::{cmp, fmt, mem, str};
use octseq::octets::Octets;
use ring::{constant_time, hkdf::KeyType, hmac, rand};
#[cfg(feature = "std")]
use std::collections::HashMap;

//------------ KeyName -------------------------------------------------------

Expand Down Expand Up @@ -387,6 +391,15 @@ impl AsRef<Key> for Key {
}
}

//--- Display

#[cfg(feature = "std")]
impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.name.fmt(f)
}
}

//------------ KeyStore ------------------------------------------------------

/// A type that stores TSIG secret keys.
Expand Down Expand Up @@ -458,6 +471,23 @@ where
}
}

#[cfg(feature = "std")]
impl KeyStore for Arc<HashMap<(KeyName, Algorithm), Key>> {
type Key = Key;

fn get_key<N: ToName>(
&self,
name: &N,
algorithm: Algorithm,
) -> Option<Self::Key> {
if let Ok(name) = name.try_to_name() {
self.get(&(name, algorithm)).cloned()
} else {
None
}
}
}

//------------ ClientTransaction ---------------------------------------------

/// TSIG Client transaction state.
Expand Down
6 changes: 6 additions & 0 deletions src/zonetree/in_memory/nodes.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! The resource record tree nodes of an in-memory zone.
use core::any::Any;

use std::boxed::Box;
use std::collections::{hash_map, HashMap};
use std::future::Future;
Expand Down Expand Up @@ -145,6 +147,10 @@ impl ZoneStore for ZoneApex {
as Box<dyn WritableZone>
})
}

fn as_any(&self) -> &dyn Any {
self as &dyn Any
}
}

//--- impl From<&'a ZoneApex>
Expand Down
7 changes: 7 additions & 0 deletions src/zonetree/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ pub trait ZoneStore: Debug + Sync + Send + Any {
+ 'static),
>,
>;

/// Returns an [`Any`] interface to the store.
///
/// This can be used to obtain access to methods on the specific
/// [`ZoneStore`] implementation. See [`Zone`] for how this can used to
/// layer functionality on top of a zone.
fn as_any(&self) -> &dyn Any;
}

//------------ ReadableZone --------------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions src/zonetree/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::zone::Zone;
/// A multi-rooted [`Zone`] hierarchy.
///
/// [`Zone`]: crate::zonetree::Zone
#[derive(Default)]
#[derive(Clone, Default, Debug)]
pub struct ZoneTree {
roots: Roots,
}
Expand Down Expand Up @@ -82,7 +82,7 @@ impl ZoneTree {

//------------ Roots ---------------------------------------------------------

#[derive(Default)]
#[derive(Clone, Default, Debug)]
struct Roots {
in_: ZoneSetNode,
others: HashMap<Class, ZoneSetNode>,
Expand Down Expand Up @@ -116,7 +116,7 @@ impl Roots {

//------------ ZoneSetNode ---------------------------------------------------

#[derive(Default)]
#[derive(Clone, Default, Debug)]
struct ZoneSetNode {
zone: Option<Zone>,
children: HashMap<OwnedLabel, ZoneSetNode>,
Expand Down
14 changes: 14 additions & 0 deletions src/zonetree/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,20 @@ pub enum Error {
Finished,
}

//--- Display

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::OutOfZone => f.write_str("OutOfZone"),
Error::NotSoaRecord => f.write_str("NotSoaRecord"),
Error::IoError(err) => write!(f, "I/O error: {err}"),

Error::Finished => f.write_str("Finished"),
}
}
}

//--- From

impl From<std::io::Error> for Error {
Expand Down
43 changes: 41 additions & 2 deletions src/zonetree/zone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,36 @@ use super::traits::WritableZone;
use super::types::StoredName;
use super::{parsed, ReadableZone, ZoneStore};

//------------ Zone ----------------------------------------------------------

/// A single DNS zone.
///
/// # Abstract backing store
///
/// The actual backing store implementation used by a [`Zone`] is determined
/// by the [`ZoeStore`] impl it wraps. In this way one can treat in-memory
/// zone implementations and other backing store types (for example a database
/// backed zone) in the same way, and even to store zones with different
/// backing stores together in the same [`ZoneTree`].
///
/// # Layering functionality
///
/// The functionality of [`Zone`]s can be extended by creating a [`ZoneStore`]
/// implementation that wraps another [`ZoneStore`] implementation with the
/// purpose of wrapping the original zone with additional state and
/// functionality.
///
/// This could be used to detect changes to the [`Zone`] via your own
/// [`WritableZone`] impl e.g. to sign it or persist it, or to detect updated
/// SOA timers, and so on.
///
/// To layer [`ZoneStore`] implementations on top of one another, use
/// [`Zone::into_inner()`] to obtain backing store implementation of a
/// [`Zone`] then store that (via [`Arc<dyn ZoneStore`]) in a wrapper type
/// that itself implements [`ZoneStore`], and then use [`Zone::new()`] to
/// create a new [`Zone`] based on the outer backing store impl.
///
/// Then to gain access to the additional functionality and state use
/// [`ZoneStore::as_any()`] and attempt to [`Any::downcast()`] to a
/// [`ZoneStore`] implementing type that was used earlier.
#[derive(Clone, Debug)]
pub struct Zone {
store: Arc<dyn ZoneStore>,
Expand All @@ -29,6 +56,12 @@ impl Zone {
}
}

/// Exchange this [`Zone`] wrapper for the actual underlying backing store
/// implementation.
pub fn into_inner(self) -> Arc<dyn ZoneStore> {
self.store
}

/// Gets the CLASS of this zone.
pub fn class(&self) -> Class {
self.store.class()
Expand All @@ -53,6 +86,12 @@ impl Zone {
}
}

impl AsRef<dyn ZoneStore> for Zone {
fn as_ref(&self) -> &dyn ZoneStore {
self.store.as_ref()
}
}

//--- TryFrom<inplace::Zonefile>

impl TryFrom<inplace::Zonefile> for Zone {
Expand Down

0 comments on commit 41d72b3

Please sign in to comment.