dope_core/io/socket/option/
mod.rs1use std::{mem, num::NonZero, time};
2
3use dope_sys::io::socket::option::{Kind, Value, tuning};
4
5use crate::{
6 Engine, driver,
7 driver::{life::native::Apply, retained::flight, route, route::kind},
8 io::{fd::handles, socket::pending},
9};
10
11mod kinds;
12
13pub(super) use kinds::Mask;
14pub(crate) use kinds::NonEmpty;
15
16pub(crate) const MAX_STREAM_OPTIONS: usize = 7;
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
21#[repr(u8)]
22pub enum Switch {
23 Off,
24 On,
25}
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29#[repr(transparent)]
30pub struct Buffer(Value);
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
34#[repr(transparent)]
35pub struct Period(NonZero<u32>);
36
37#[derive(Clone, Copy, Debug, PartialEq, Eq)]
39#[repr(transparent)]
40pub struct Retries(NonZero<u32>);
41
42impl Switch {
43 pub(crate) const fn value(self) -> Value {
44 match self {
45 Self::Off => Value::ZERO,
46 Self::On => Value::from_enabled(true),
47 }
48 }
49}
50
51impl Buffer {
52 const fn value(self) -> Value {
53 self.0
54 }
55}
56
57impl Period {
58 const fn value(self) -> Value {
59 Value::new(self.0.get() as i32)
60 }
61}
62
63impl Retries {
64 const fn value(self) -> Value {
65 Value::new(self.0.get() as i32)
66 }
67}
68
69#[derive(Clone, Copy)]
72pub struct Set {
73 recv_buffer: Value,
74 send_buffer: Value,
75 keep_alive_idle: Value,
76 keep_alive_interval: Value,
77 keep_alive_retries: Value,
78 present: Mask,
79 enabled: Mask,
80}
81
82#[derive(Clone, Copy, PartialEq, Eq, Debug)]
84#[repr(u8)]
85pub enum Error {
86 Buffer {
87 actual: usize,
88 maximum: usize,
89 },
90 Period {
91 actual: time::Duration,
92 maximum: time::Duration,
93 },
94 Retries {
95 actual: u32,
96 maximum: u32,
97 },
98}
99
100impl Default for Set {
101 fn default() -> Self {
102 Self::EMPTY
103 }
104}
105
106pub enum Tuning<'d> {
108 Applied(handles::Descriptor<'d>),
110 Pending(pending::Tuning<'d>),
113}
114
115impl Set {
116 pub fn new(
118 recv: Option<Buffer>,
119 send: Option<Buffer>,
120 no_delay: Option<Switch>,
121 alive: Option<Switch>,
122 idle: Option<Period>,
123 interval: Option<Period>,
124 retries: Option<Retries>,
125 ) -> Self {
126 let mut set = Self::EMPTY;
127 if let Some(value) = recv {
128 set.set(Kind::RecvBuffer, value.value());
129 }
130 if let Some(value) = send {
131 set.set(Kind::SendBuffer, value.value());
132 }
133 if let Some(value) = no_delay {
134 set.set(Kind::NoDelay, value.value());
135 }
136 if let Some(value) = alive {
137 set.set(Kind::KeepAlive, value.value());
138 }
139 if let Some(value) = idle {
140 set.set(Kind::KeepAliveIdle, value.value());
141 }
142 if let Some(value) = interval {
143 set.set(Kind::KeepAliveInterval, value.value());
144 }
145 if let Some(value) = retries {
146 set.set(Kind::KeepAliveRetries, value.value());
147 }
148 set
149 }
150
151 pub const EMPTY: Self = Self {
152 recv_buffer: Value::ZERO,
153 send_buffer: Value::ZERO,
154 keep_alive_idle: Value::ZERO,
155 keep_alive_interval: Value::ZERO,
156 keep_alive_retries: Value::ZERO,
157 present: Mask::EMPTY,
158 enabled: Mask::EMPTY,
159 };
160
161 pub(crate) fn non_empty(&self) -> Option<NonEmpty<'_>> {
162 NonEmpty::new(self, self.present)
163 }
164
165 fn value(&self, kind: Kind) -> Value {
166 match kind {
167 Kind::NoDelay | Kind::KeepAlive => Value::from_enabled(self.enabled.contains(kind)),
168 Kind::RecvBuffer => self.recv_buffer,
169 Kind::SendBuffer => self.send_buffer,
170 Kind::KeepAliveIdle => self.keep_alive_idle,
171 Kind::KeepAliveInterval => self.keep_alive_interval,
172 Kind::KeepAliveRetries => self.keep_alive_retries,
173 }
174 }
175
176 fn set(&mut self, kind: Kind, value: Value) {
177 self.present.insert(kind);
178 match kind {
179 Kind::NoDelay | Kind::KeepAlive if !value.is_zero() => self.enabled.insert(kind),
180 Kind::NoDelay | Kind::KeepAlive => {}
181 Kind::RecvBuffer => self.recv_buffer = value,
182 Kind::SendBuffer => self.send_buffer = value,
183 Kind::KeepAliveIdle => self.keep_alive_idle = value,
184 Kind::KeepAliveInterval => self.keep_alive_interval = value,
185 Kind::KeepAliveRetries => self.keep_alive_retries = value,
186 }
187 }
188}
189
190impl TryFrom<usize> for Buffer {
191 type Error = Error;
192
193 fn try_from(actual: usize) -> Result<Self, Self::Error> {
194 let maximum = i32::MAX as usize;
195 if actual <= maximum {
196 Ok(Self(Value::new(actual as i32)))
197 } else {
198 Err(Error::Buffer { actual, maximum })
199 }
200 }
201}
202
203impl TryFrom<time::Duration> for Period {
204 type Error = Error;
205
206 fn try_from(actual: time::Duration) -> Result<Self, Self::Error> {
207 let maximum = time::Duration::from_secs(i32::MAX as u64);
208 if actual.is_zero() || actual > maximum {
209 return Err(Error::Period { actual, maximum });
210 }
211 let seconds = actual.as_secs() + u64::from(actual.subsec_nanos() != 0);
212 Ok(Self(NonZero::<u32>::MIN.saturating_add(seconds as u32 - 1)))
213 }
214}
215
216impl TryFrom<u32> for Retries {
217 type Error = Error;
218
219 fn try_from(actual: u32) -> Result<Self, Self::Error> {
220 let maximum = i32::MAX as u32;
221 if actual == 0 || actual > maximum {
222 return Err(Error::Retries { actual, maximum });
223 }
224 Ok(Self(NonZero::<u32>::MIN.saturating_add(actual - 1)))
225 }
226}
227
228const _: () = {
229 assert!(mem::size_of::<Switch>() == mem::size_of::<bool>());
230 assert!(mem::align_of::<Switch>() == mem::align_of::<bool>());
231 assert!(mem::size_of::<Buffer>() == mem::size_of::<Value>());
232 assert!(mem::size_of::<Period>() == mem::size_of::<Value>());
233 assert!(mem::size_of::<Retries>() == mem::size_of::<Value>());
234 assert!(mem::size_of::<Option<Period>>() == mem::size_of::<Period>());
235 assert!(mem::size_of::<Option<Retries>>() == mem::size_of::<Retries>());
236 assert!(mem::size_of::<Set>() == 24);
237};
238
239impl<'d> Tuning<'d> {
240 pub fn try_new<Tag: route::Tag + route::Select<kind::Tuning>>(
241 driver: &mut driver::Context<'_, 'd>,
242 slots: &flight::Slots<'d, Tag>,
243 target: route::Target<'d, Tag>,
244 fd: handles::Descriptor<'d>,
245 opts: Set,
246 ) -> Result<Self, pending::Rejection<'d>> {
247 use tuning::device::{Owner as _, Source};
248 let owner = Apply::new(driver.native(), slots, target, fd, opts);
249 let request = <crate::Backend as Source>::Socket::new(owner);
250 unsafe { tuning::raw::Apply::<Engine, _, { MAX_STREAM_OPTIONS }>::try_apply(request) }
253 }
254}