dope 0.3.1

The manifold runtime
Documentation
use std::time::Duration;

use crate::{Driver, Sockopt};

const TCP_KEEPIDLE: libc::c_int = 4;
const TCP_KEEPINTVL: libc::c_int = 5;
const TCP_KEEPCNT: libc::c_int = 6;
const TCP_QUICKACK: libc::c_int = 12;
const TCP_USER_TIMEOUT: libc::c_int = 18;

#[derive(Clone, Copy)]
enum SockOpt {
    Keepalive(bool),
    RecvBuf(usize),
    SendBuf(usize),
    Nodelay(bool),
    Quickack(bool),
    KeepaliveIdle(Duration),
    KeepaliveIntvl(Duration),
    KeepaliveCnt(u32),
    UserTimeout(Duration),
}

impl SockOpt {
    fn resolve(self) -> Option<(libc::c_int, libc::c_int, libc::c_int)> {
        let (level, opt, raw): (libc::c_int, libc::c_int, u128) = match self {
            Self::Keepalive(on) => (libc::SOL_SOCKET, libc::SO_KEEPALIVE, on as u128),
            Self::RecvBuf(size) => (libc::SOL_SOCKET, libc::SO_RCVBUF, size as u128),
            Self::SendBuf(size) => (libc::SOL_SOCKET, libc::SO_SNDBUF, size as u128),
            Self::Nodelay(on) => (libc::IPPROTO_TCP, libc::TCP_NODELAY, on as u128),
            Self::Quickack(on) => (libc::IPPROTO_TCP, TCP_QUICKACK, on as u128),
            Self::KeepaliveIdle(d) => (libc::IPPROTO_TCP, TCP_KEEPIDLE, d.as_secs() as u128),
            Self::KeepaliveIntvl(d) => (libc::IPPROTO_TCP, TCP_KEEPINTVL, d.as_secs() as u128),
            Self::KeepaliveCnt(cnt) => (libc::IPPROTO_TCP, TCP_KEEPCNT, cnt as u128),
            Self::UserTimeout(d) => (libc::IPPROTO_TCP, TCP_USER_TIMEOUT, d.as_millis()),
        };
        let value = libc::c_int::try_from(raw).ok()?;
        Some((level, opt, value))
    }

    fn submit(self, idx: u32, driver: &mut Driver) {
        if let Some((level, opt, value)) = self.resolve() {
            let _ = driver.set(idx, level as u32, opt as u32, value);
        }
    }
}

pub trait Submittable {
    fn submit(self, idx: u32, driver: &mut Driver);
}

#[derive(Clone, Copy, Default)]
pub enum SocketToggle {
    #[default]
    Inherit,
    Enabled,
}

impl SocketToggle {
    pub(super) const fn flag(self) -> Option<bool> {
        match self {
            Self::Inherit => None,
            Self::Enabled => Some(true),
        }
    }
}

pub mod tcp {
    use std::time::Duration;

    use super::{SockOpt, SocketToggle, Submittable};
    use crate::Driver;

    #[derive(Clone, Copy, Default)]
    pub struct StreamOpts {
        pub recv_buffer_size: Option<usize>,
        pub send_buffer_size: Option<usize>,
        pub quickack: SocketToggle,
        pub nodelay: SocketToggle,
        pub keepalive: SocketToggle,
        pub keepalive_idle: Option<Duration>,
        pub keepalive_interval: Option<Duration>,
        pub keepalive_retries: Option<u32>,
        pub user_timeout: Option<Duration>,
    }

    impl StreamOpts {
        const fn keepalive_tuned(self) -> bool {
            self.keepalive_idle.is_some()
                || self.keepalive_interval.is_some()
                || self.keepalive_retries.is_some()
        }
    }

    impl Submittable for StreamOpts {
        fn submit(self, idx: u32, driver: &mut Driver) {
            let tuned = self.keepalive_tuned();
            let opts: [Option<SockOpt>; 9] = [
                self.quickack.flag().map(SockOpt::Quickack),
                self.nodelay.flag().map(SockOpt::Nodelay),
                self.keepalive.flag().map(SockOpt::Keepalive),
                self.recv_buffer_size.map(SockOpt::RecvBuf),
                self.send_buffer_size.map(SockOpt::SendBuf),
                self.keepalive_idle
                    .filter(|_| tuned)
                    .map(SockOpt::KeepaliveIdle),
                self.keepalive_interval
                    .filter(|_| tuned)
                    .map(SockOpt::KeepaliveIntvl),
                self.keepalive_retries
                    .filter(|_| tuned)
                    .map(SockOpt::KeepaliveCnt),
                self.user_timeout.map(SockOpt::UserTimeout),
            ];
            for opt in opts.into_iter().flatten() {
                opt.submit(idx, driver);
            }
        }
    }

    #[derive(Clone, Copy, Default)]
    pub struct ListenerOpts {
        pub reuseport: SocketToggle,
        pub fastopen_backlog: Option<u32>,
        pub defer_accept_secs: Option<u32>,
        pub per_ip_cap: Option<u32>,
    }
}

pub mod unix {
    use super::{SockOpt, Submittable};
    use crate::Driver;

    #[derive(Clone, Copy, Default)]
    pub struct StreamOpts {
        pub recv_buffer_size: Option<usize>,
        pub send_buffer_size: Option<usize>,
    }

    impl Submittable for StreamOpts {
        fn submit(self, idx: u32, driver: &mut Driver) {
            let opts: [Option<SockOpt>; 2] = [
                self.recv_buffer_size.map(SockOpt::RecvBuf),
                self.send_buffer_size.map(SockOpt::SendBuf),
            ];
            for opt in opts.into_iter().flatten() {
                opt.submit(idx, driver);
            }
        }
    }

    #[derive(Clone, Copy, Default)]
    pub struct ListenerOpts;
}