1use std::{
2 mem, net, num,
3 os::fd::{AsFd, AsRawFd as _, BorrowedFd, OwnedFd},
4 ptr,
5};
6
7use libc::socklen_t;
8use option::fast;
9
10use crate::{
11 Cloexec, Errno, Nonblock,
12 io::{self, fd},
13 kernel::{self, errno},
14};
15
16pub mod accept;
17pub mod addr;
18pub mod gso;
19pub mod msg;
20pub mod option;
21pub mod raw;
22pub mod record;
23pub mod route;
24
25pub const BACKLOG: i32 = libc::SOMAXCONN;
27
28#[derive(Clone, Copy, Debug, Eq, PartialEq)]
30#[repr(transparent)]
31pub struct Connect(Errno);
32
33impl Connect {
34 pub const fn errno(self) -> Errno {
35 self.0
36 }
37}
38
39impl From<Errno> for Connect {
40 fn from(errno: Errno) -> Self {
41 Self(errno)
42 }
43}
44
45const _: () = assert!(size_of::<Connect>() == size_of::<Errno>());
46
47#[derive(Clone, Copy, PartialEq, Eq, Debug)]
49#[repr(C)]
50pub struct Create {
51 fault: Errno,
52 kind: Option<SetupKind>,
53}
54
55pub enum Origin {
57 Socket(Errno),
58 Setup(Setup),
59}
60
61impl Create {
62 pub const fn socket(fault: Errno) -> Self {
64 Self { fault, kind: None }
65 }
66
67 pub const fn setup(error: Setup) -> Self {
69 Self {
70 fault: error.fault,
71 kind: Some(error.kind),
72 }
73 }
74
75 pub const fn origin(self) -> Origin {
76 match self.kind {
77 Some(kind) => Origin::Setup(Setup {
78 fault: self.fault,
79 kind,
80 }),
81 None => Origin::Socket(self.fault),
82 }
83 }
84}
85
86const _: () = assert!(mem::size_of::<Create>() == 2 * mem::size_of::<u32>());
87
88#[derive(Clone, Copy, PartialEq, Eq)]
89pub enum Domain {
90 Inet4,
91 Inet6,
92 Unix,
93}
94
95impl Domain {
96 pub fn for_addr(addr: &net::SocketAddr) -> Self {
97 if addr.is_ipv4() {
98 Self::Inet4
99 } else {
100 Self::Inet6
101 }
102 }
103
104 pub const fn raw(self) -> libc::c_int {
105 use libc::{AF_INET, AF_INET6};
106 match self {
107 Self::Inet4 => AF_INET,
108 Self::Inet6 => AF_INET6,
109 Self::Unix => libc::AF_UNIX,
110 }
111 }
112}
113
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
116#[repr(transparent)]
117pub struct Type(libc::c_int);
118
119impl Type {
120 pub const fn is_stream(self) -> bool {
122 self.0 == libc::SOCK_STREAM
123 }
124
125 pub const fn is_datagram(self) -> bool {
127 self.0 == libc::SOCK_DGRAM
128 }
129
130 pub const fn raw(self) -> i32 {
132 self.0
133 }
134}
135
136#[derive(Clone, Copy, Debug, Eq, PartialEq)]
138#[repr(transparent)]
139pub struct How(libc::c_int);
140
141impl How {
142 pub const READ: Self = Self(libc::SHUT_RD);
143 pub const WRITE: Self = Self(libc::SHUT_WR);
144 pub const BOTH: Self = Self(libc::SHUT_RDWR);
145
146 pub const fn raw(self) -> libc::c_int {
147 self.0
148 }
149}
150
151#[derive(Clone, Copy, Debug, Eq, PartialEq)]
153pub enum Reuse {
154 Address,
155 Port,
156}
157
158#[derive(Clone, Copy, Debug, PartialEq, Eq)]
160pub enum Failure {
161 Socket(Errno),
162 Cloexec(Cloexec),
163}
164
165impl From<Errno> for Failure {
166 fn from(error: Errno) -> Self {
167 Self::Socket(error)
168 }
169}
170
171impl From<Cloexec> for Failure {
172 fn from(error: Cloexec) -> Self {
173 Self::Cloexec(error)
174 }
175}
176
177#[derive(Clone, Copy, PartialEq, Eq)]
178pub enum Kind {
179 Stream,
180 Dgram,
181}
182
183impl Kind {
184 pub const fn raw(self) -> libc::c_int {
185 use libc::{SOCK_DGRAM, SOCK_STREAM};
186 match self {
187 Self::Stream => SOCK_STREAM,
188 Self::Dgram => SOCK_DGRAM,
189 }
190 }
191}
192
193pub trait Prepare: Socket {
195 type Handle: AsFd;
196 type Fast;
197
198 fn fast_open(depth: Option<num::NonZero<i32>>) -> Result<Option<Self::Fast>, fast::Error>;
199 fn open(domain: Domain, kind: Kind) -> Result<Self::Handle, Create>;
200 fn listener(domain: Domain) -> Result<Self::Handle, Create>;
201 fn adopt(file: OwnedFd) -> Result<Self::Handle, Setup>;
202 fn into_fd(handle: Self::Handle) -> OwnedFd;
204 fn set_fast(file: BorrowedFd<'_>, fast: Self::Fast) -> Result<(), Errno>;
205}
206
207#[derive(Clone, Copy, PartialEq, Eq, Debug)]
209#[repr(C)]
210pub struct Setup {
211 fault: Errno,
212 kind: SetupKind,
213}
214
215pub enum SetupOrigin {
217 Cloexec(Cloexec),
218 Nonblock(Nonblock),
219 Sigpipe(Errno),
220}
221
222#[derive(Clone, Copy, Debug, PartialEq, Eq)]
223#[repr(u8)]
224enum SetupKind {
225 GetFd,
226 SetFd,
227 GetFlags,
228 SetFlags,
229 Sigpipe,
230}
231
232impl Setup {
233 pub const fn cloexec(error: Cloexec) -> Self {
234 match error {
235 Cloexec::Get(fault) => Self {
236 fault,
237 kind: SetupKind::GetFd,
238 },
239 Cloexec::Set(fault) => Self {
240 fault,
241 kind: SetupKind::SetFd,
242 },
243 }
244 }
245
246 pub const fn nonblock(error: Nonblock) -> Self {
247 match error {
248 Nonblock::Get(fault) => Self {
249 fault,
250 kind: SetupKind::GetFlags,
251 },
252 Nonblock::Set(fault) => Self {
253 fault,
254 kind: SetupKind::SetFlags,
255 },
256 }
257 }
258
259 pub const fn sigpipe(fault: Errno) -> Self {
260 Self {
261 fault,
262 kind: SetupKind::Sigpipe,
263 }
264 }
265
266 pub const fn origin(self) -> SetupOrigin {
267 match self.kind {
268 SetupKind::GetFd => SetupOrigin::Cloexec(Cloexec::Get(self.fault)),
269 SetupKind::SetFd => SetupOrigin::Cloexec(Cloexec::Set(self.fault)),
270 SetupKind::GetFlags => SetupOrigin::Nonblock(Nonblock::Get(self.fault)),
271 SetupKind::SetFlags => SetupOrigin::Nonblock(Nonblock::Set(self.fault)),
272 SetupKind::Sigpipe => SetupOrigin::Sigpipe(self.fault),
273 }
274 }
275}
276
277const _: () = assert!(mem::size_of::<Setup>() == 2 * mem::size_of::<u32>());
278
279pub trait Socket: errno::Source {
281 const MAX_IOVECS: usize;
282 type Error;
283
284 fn socket(domain: libc::c_int, kind: libc::c_int) -> Result<OwnedFd, Self::Error>;
285 fn pair() -> Result<(OwnedFd, OwnedFd), record::Error>;
287
288 fn datagram<E: From<Errno>>(domain: Domain) -> Result<OwnedFd, E> {
290 let protocol = match domain {
291 Domain::Inet4 | Domain::Inet6 => libc::IPPROTO_UDP,
292 Domain::Unix => 0,
293 };
294 Self::try_open(domain.raw(), libc::SOCK_DGRAM, protocol)
295 }
296
297 fn try_open<E: From<Errno>>(
298 domain: libc::c_int,
299 kind: libc::c_int,
300 protocol: libc::c_int,
301 ) -> Result<OwnedFd, E> {
302 let raw = unsafe { libc::socket(domain, kind, protocol) };
303 unsafe {
304 <OwnedFd as fd::raw::Adopt>::try_adopt(raw, || kernel::raw::Code::last::<Self>().into())
305 }
306 }
307
308 fn listen<E: From<Errno>>(file: BorrowedFd<'_>, backlog: libc::c_int) -> Result<(), E> {
309 unsafe {
311 kernel::raw::Status::new(libc::listen(file.as_raw_fd(), backlog))
312 .try_zero(|| kernel::raw::Code::last::<Self>().into())
313 }
314 }
315
316 fn shutdown<E: From<Errno>>(file: BorrowedFd<'_>, how: How) -> Result<(), E> {
318 unsafe {
320 kernel::raw::Status::new(libc::shutdown(file.as_raw_fd(), how.raw()))
321 .try_zero(|| kernel::raw::Code::last::<Self>().into())
322 }
323 }
324
325 fn peer_addr<E: From<Errno>>(
327 file: BorrowedFd<'_>,
328 address: &mut addr::Storage,
329 ) -> Result<(), E> {
330 let (storage, len) = address.output_mut();
331 *len = mem::size_of_val(storage) as socklen_t;
332 let raw =
334 unsafe { libc::getpeername(file.as_raw_fd(), ptr::from_mut(storage).cast(), len) };
335 unsafe {
337 kernel::raw::Status::new(raw).try_zero(|| kernel::raw::Code::last::<Self>().into())
338 }
339 }
340
341 fn reset_on_close<E: From<Errno>>(file: BorrowedFd<'_>) -> Result<(), E> {
343 let linger = libc::linger {
344 l_onoff: 1,
345 l_linger: 0,
346 };
347 let raw = unsafe {
349 libc::setsockopt(
350 file.as_raw_fd(),
351 libc::SOL_SOCKET,
352 libc::SO_LINGER,
353 ptr::from_ref(&linger).cast(),
354 mem::size_of_val(&linger) as socklen_t,
355 )
356 };
357 unsafe {
359 kernel::raw::Status::new(raw).try_zero(|| kernel::raw::Code::last::<Self>().into())
360 }
361 }
362
363 fn kind<E: From<Errno>>(file: BorrowedFd<'_>) -> Result<Type, E> {
365 Self::get_option::<{ libc::SO_TYPE }, E>(file).map(Type)
366 }
367
368 fn is_listening<E: From<Errno>>(file: BorrowedFd<'_>) -> Result<bool, E> {
370 Ok(Self::get_option::<{ libc::SO_ACCEPTCONN }, E>(file)? != 0)
371 }
372
373 fn set_reuse<E: From<Errno>>(file: BorrowedFd<'_>, reuse: Reuse) -> Result<(), E> {
375 let option = match reuse {
376 Reuse::Address => libc::SO_REUSEADDR,
377 Reuse::Port => libc::SO_REUSEPORT,
378 };
379 Self::set_option(file, libc::SOL_SOCKET, option, &1)
380 }
381
382 fn send_quiet<'a, E: From<Errno>>(
384 file: BorrowedFd<'_>,
385 input: &'a [u8],
386 ) -> Result<&'a [u8], E> {
387 Self::send::<{ libc::MSG_NOSIGNAL }, E>(file, input)
388 }
389
390 fn send_now<'a, E: From<Errno>>(file: BorrowedFd<'_>, input: &'a [u8]) -> Result<&'a [u8], E> {
392 Self::send::<{ libc::MSG_DONTWAIT | libc::MSG_NOSIGNAL }, E>(file, input)
393 }
394
395 fn get_option<const OPTION: libc::c_int, E: From<Errno>>(
396 file: BorrowedFd<'_>,
397 ) -> Result<libc::c_int, E> {
398 const {
399 assert!(
400 OPTION == libc::SO_TYPE
401 || OPTION == libc::SO_ACCEPTCONN
402 || OPTION == libc::SO_ERROR
403 );
404 }
405 let mut value = 0;
406 let mut len = mem::size_of::<libc::c_int>() as socklen_t;
407 let raw = unsafe {
408 libc::getsockopt(
409 file.as_raw_fd(),
410 libc::SOL_SOCKET,
411 OPTION,
412 ptr::from_mut(&mut value).cast(),
413 &mut len,
414 )
415 };
416 unsafe {
418 kernel::raw::Status::new(raw).try_zero::<E>(|| kernel::raw::Code::last::<Self>().into())
419 }?;
420 Ok(value)
421 }
422
423 fn set_option<E: From<Errno>>(
424 file: BorrowedFd<'_>,
425 level: libc::c_int,
426 option: libc::c_int,
427 value: &libc::c_int,
428 ) -> Result<(), E> {
429 let raw = unsafe {
430 libc::setsockopt(
431 file.as_raw_fd(),
432 level,
433 option,
434 ptr::from_ref(value).cast(),
435 mem::size_of::<libc::c_int>() as socklen_t,
436 )
437 };
438 unsafe {
440 kernel::raw::Status::new(raw).try_zero(|| kernel::raw::Code::last::<Self>().into())
441 }
442 }
443
444 fn send<'a, const FLAGS: libc::c_int, E: From<Errno>>(
445 file: BorrowedFd<'_>,
446 input: &'a [u8],
447 ) -> Result<&'a [u8], E> {
448 const { assert!(FLAGS & !(libc::MSG_NOSIGNAL | libc::MSG_DONTWAIT) == 0) };
449 let raw =
450 unsafe { libc::send(file.as_raw_fd(), input.as_ptr().cast(), input.len(), FLAGS) };
451 unsafe {
453 io::raw::Buffer::try_native(input, raw, || kernel::raw::Code::last::<Self>().into())
454 }
455 }
456
457 fn recv<'a, const FLAGS: libc::c_int, E: From<Errno>>(
458 file: BorrowedFd<'_>,
459 output: &'a mut [u8],
460 ) -> Result<&'a mut [u8], E> {
461 const { assert!(FLAGS & !(libc::MSG_DONTWAIT | libc::MSG_PEEK | libc::MSG_WAITALL) == 0) };
462 let raw = unsafe {
463 libc::recv(
464 file.as_raw_fd(),
465 output.as_mut_ptr().cast(),
466 output.len(),
467 FLAGS,
468 )
469 };
470 unsafe {
473 io::raw::Buffer::try_native(output, raw, || kernel::raw::Code::last::<Self>().into())
474 }
475 }
476
477 fn recv_now<'a, E: From<Errno>>(
478 file: BorrowedFd<'_>,
479 output: &'a mut [u8],
480 ) -> Result<&'a mut [u8], E> {
481 Self::recv::<{ libc::MSG_DONTWAIT }, E>(file, output)
482 }
483
484 fn send_to<'a, E: From<Errno>>(
486 file: BorrowedFd<'_>,
487 input: &'a [u8],
488 address: addr::Addr<'_>,
489 ) -> Result<&'a [u8], E> {
490 let (address, len) = address.parts();
491 let raw = unsafe {
493 libc::sendto(
494 file.as_raw_fd(),
495 input.as_ptr().cast(),
496 input.len(),
497 libc::MSG_NOSIGNAL,
498 address,
499 len.raw(),
500 )
501 };
502 unsafe {
504 io::raw::Buffer::try_native(input, raw, || kernel::raw::Code::last::<Self>().into())
505 }
506 }
507
508 fn recv_from<'a, E: From<Errno>>(
510 file: BorrowedFd<'_>,
511 output: &'a mut [u8],
512 address: &mut addr::Storage,
513 ) -> Result<&'a mut [u8], E> {
514 let (storage, len) = address.output_mut();
515 *len = mem::size_of_val(storage) as socklen_t;
516 let raw = unsafe {
518 libc::recvfrom(
519 file.as_raw_fd(),
520 output.as_mut_ptr().cast(),
521 output.len(),
522 0,
523 ptr::from_mut(storage).cast(),
524 len,
525 )
526 };
527 unsafe {
529 io::raw::Buffer::try_native(output, raw, || kernel::raw::Code::last::<Self>().into())
530 }
531 }
532
533 fn try_pair<E: From<Errno>>(kind: libc::c_int) -> Result<(OwnedFd, OwnedFd), E> {
534 let mut fds = [-1; 2];
535 let raw = unsafe { libc::socketpair(libc::AF_UNIX, kind, 0, fds.as_mut_ptr()) };
536 unsafe {
538 fd::raw::Pair::new(fds).try_adopt::<E>(raw, || kernel::raw::Code::last::<Self>().into())
539 }
540 }
541}