Skip to main content

nex_socket/
lib.rs

1//! Cross-platform low-level socket APIs for TCP, UDP and ICMP.
2//!
3//! `nex-socket` focuses on predictable, low-level behavior and platform-aware
4//! socket option control.
5//!
6//! TCP, UDP, and ICMP use an infallible configuration value followed by a
7//! fallible socket constructor. Synchronous constructors create blocking
8//! sockets unless their TCP configuration explicitly requests nonblocking
9//! operation. Asynchronous constructors always register a nonblocking socket
10//! with Tokio. Address-family mismatches are rejected by configuration
11//! validation or returned by the operating system for per-operation targets.
12//!
13//! Raw TCP and ICMP sockets normally require root/`CAP_NET_RAW` on Unix and an
14//! elevated process on Windows. Unprivileged UDP and TCP stream sockets do not.
15
16pub mod icmp;
17pub mod tcp;
18pub mod udp;
19
20use std::io;
21use std::net::{IpAddr, SocketAddr};
22
23#[cfg(any(
24    target_os = "android",
25    target_os = "dragonfly",
26    target_os = "freebsd",
27    target_os = "fuchsia",
28    target_os = "linux",
29    target_os = "macos",
30    target_os = "netbsd",
31    target_os = "openbsd"
32))]
33pub(crate) fn apply_tclass_v6(socket: &socket2::Socket, tclass: Option<u32>) -> io::Result<()> {
34    if let Some(tclass) = tclass {
35        socket.set_tclass_v6(tclass)?;
36    }
37    Ok(())
38}
39
40#[cfg(not(any(
41    target_os = "android",
42    target_os = "dragonfly",
43    target_os = "freebsd",
44    target_os = "fuchsia",
45    target_os = "linux",
46    target_os = "macos",
47    target_os = "netbsd",
48    target_os = "openbsd"
49)))]
50pub(crate) fn apply_tclass_v6(_socket: &socket2::Socket, tclass: Option<u32>) -> io::Result<()> {
51    if tclass.is_some() {
52        return Err(io::Error::new(
53            io::ErrorKind::Unsupported,
54            "IPv6 traffic class is not supported on this platform",
55        ));
56    }
57    Ok(())
58}
59
60/// Represents the socket address family (IPv4 or IPv6)
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62#[non_exhaustive]
63pub enum SocketFamily {
64    IPV4,
65    IPV6,
66}
67
68impl SocketFamily {
69    /// Returns the socket family of the IP address.
70    pub fn from_ip(ip: &IpAddr) -> Self {
71        match ip {
72            IpAddr::V4(_) => SocketFamily::IPV4,
73            IpAddr::V6(_) => SocketFamily::IPV6,
74        }
75    }
76
77    /// Returns the socket family of the socket address.
78    pub fn from_socket_addr(addr: &SocketAddr) -> Self {
79        match addr {
80            SocketAddr::V4(_) => SocketFamily::IPV4,
81            SocketAddr::V6(_) => SocketFamily::IPV6,
82        }
83    }
84
85    /// Returns true if the socket family is IPv4.
86    pub fn is_v4(&self) -> bool {
87        matches!(self, SocketFamily::IPV4)
88    }
89
90    /// Returns true if the socket family is IPv6.
91    pub fn is_v6(&self) -> bool {
92        matches!(self, SocketFamily::IPV6)
93    }
94
95    /// Converts the socket family to a `socket2::Domain`.
96    pub(crate) fn to_domain(self) -> socket2::Domain {
97        match self {
98            SocketFamily::IPV4 => socket2::Domain::IPV4,
99            SocketFamily::IPV6 => socket2::Domain::IPV6,
100        }
101    }
102}