s2n_quic_platform/features/
gso.rs1use super::c_int;
5use core::{
6 convert::{TryFrom, TryInto},
7 fmt,
8 fmt::{Display, Formatter},
9 num::NonZeroUsize,
10};
11
12#[derive(Clone, Copy, Debug)]
13pub struct MaxSegments(NonZeroUsize);
14
15impl MaxSegments {
16 pub const MAX: Self = gso_impl::MAX_SEGMENTS;
17 pub const DEFAULT: Self = gso_impl::DEFAULT_SEGMENTS;
18}
19
20impl Default for MaxSegments {
21 #[inline]
22 fn default() -> Self {
23 MaxSegments::DEFAULT
24 }
25}
26
27impl TryFrom<usize> for MaxSegments {
28 type Error = MaxSegmentsError;
29
30 fn try_from(value: usize) -> Result<Self, Self::Error> {
31 if !(1..=Self::MAX.into()).contains(&value) {
32 return Err(MaxSegmentsError);
33 }
34
35 Ok(MaxSegments(value.try_into().expect(
36 "Value must be greater than zero according to the check above",
37 )))
38 }
39}
40
41#[derive(Debug)]
42pub struct MaxSegmentsError;
43
44impl Display for MaxSegmentsError {
45 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
46 write!(
47 f,
48 "MaxSegments must be a non-zero value less than or equal to {}",
49 MaxSegments::MAX.0.get()
50 )
51 }
52}
53
54impl From<MaxSegments> for usize {
55 #[inline]
56 fn from(value: MaxSegments) -> Self {
57 value.0.get()
58 }
59}
60
61#[cfg(s2n_quic_platform_gso)]
62mod gso_enabled {
63 use super::*;
64 use libc::{SOL_UDP, UDP_SEGMENT};
65 use std::sync::{
66 atomic::{AtomicUsize, Ordering},
67 Arc,
68 };
69
70 pub const LEVEL: Option<c_int> = Some(SOL_UDP as _);
71 pub const TYPE: Option<c_int> = Some(UDP_SEGMENT as _);
72 pub const CMSG_SPACE: usize = crate::message::cmsg::size_of_cmsg::<super::Cmsg>();
73
74 #[inline]
75 pub const fn is_match(level: c_int, ty: c_int) -> bool {
76 level == SOL_UDP as c_int && ty == UDP_SEGMENT as c_int
77 }
78
79 pub const MAX_SEGMENTS: MaxSegments = MaxSegments(NonZeroUsize::new(1 << 6).unwrap());
87
88 pub const DEFAULT_SEGMENTS: MaxSegments = MaxSegments(
96 NonZeroUsize::new(s2n_quic_core::recovery::MAX_BURST_PACKETS as usize).unwrap(),
97 );
98
99 #[derive(Clone, Debug)]
100 pub struct Gso(Arc<AtomicUsize>);
101
102 impl Default for Gso {
103 fn default() -> Self {
104 MaxSegments::DEFAULT.into()
105 }
106 }
107
108 impl Gso {
109 #[inline]
110 pub fn max_segments(&self) -> usize {
111 self.0.load(Ordering::Relaxed)
112 }
113
114 #[inline]
115 pub fn disable(&self) {
116 self.0.store(1, Ordering::Relaxed);
117 }
118
119 #[inline]
120 pub fn handle_socket_error(&self, error: &std::io::Error) -> Option<usize> {
121 let raw_error = error.raw_os_error()?;
122 s2n_quic_core::ensure!(raw_error == libc::EIO, None);
123 let prev = self.0.swap(1, Ordering::Relaxed);
124 Some(prev)
125 }
126 }
127
128 impl From<MaxSegments> for Gso {
129 #[inline]
130 fn from(segments: MaxSegments) -> Self {
131 Self(Arc::new(AtomicUsize::new(segments.0.into())))
132 }
133 }
134}
135
136#[cfg(any(not(s2n_quic_platform_gso), test))]
137mod gso_disabled {
138 #![cfg_attr(test, allow(dead_code))]
139
140 use super::*;
141
142 pub const LEVEL: Option<c_int> = None;
143 pub const TYPE: Option<c_int> = None;
144 pub const CMSG_SPACE: usize = 0;
145
146 #[inline]
147 pub const fn is_match(level: c_int, ty: c_int) -> bool {
148 let _ = level;
149 let _ = ty;
150 false
151 }
152
153 pub const MAX_SEGMENTS: MaxSegments = MaxSegments(NonZeroUsize::new(1).unwrap());
154 pub const DEFAULT_SEGMENTS: MaxSegments = MAX_SEGMENTS;
155
156 #[derive(Clone, Default, Debug)]
157 pub struct Gso(());
158
159 impl Gso {
160 #[inline]
161 pub fn max_segments(&self) -> usize {
162 1
163 }
164
165 #[inline]
166 #[allow(dead_code)] pub fn disable(&self) {
168 }
170
171 #[inline(always)]
172 pub fn handle_socket_error(&self, error: &std::io::Error) -> Option<usize> {
173 let _ = error;
174 None
175 }
176 }
177
178 impl From<MaxSegments> for Gso {
179 #[inline]
180 fn from(_segments: MaxSegments) -> Self {
181 Self(())
182 }
183 }
184}
185
186mod gso_impl {
187 #[cfg(not(s2n_quic_platform_gso))]
188 pub use super::gso_disabled::*;
189 #[cfg(s2n_quic_platform_gso)]
190 pub use super::gso_enabled::*;
191}
192
193pub use gso_impl::*;
194pub type Cmsg = u16;
195
196pub const IS_SUPPORTED: bool = cfg!(s2n_quic_platform_gso);