Skip to main content

nex_socket/udp/
mod.rs

1//! UDP socket.
2//!
3//! Provides synchronous and asynchronous UDP APIs along with
4//! configuration utilities for common socket options.
5#[cfg(feature = "async")]
6mod async_impl;
7mod config;
8mod sync_impl;
9
10use std::io;
11
12use socket2::Socket;
13
14use crate::SocketFamily;
15
16#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
17fn set_bool_sockopt(
18    socket: &Socket,
19    level: libc::c_int,
20    optname: libc::c_int,
21    on: bool,
22) -> io::Result<()> {
23    use std::os::fd::AsRawFd;
24    let value: libc::c_int = if on { 1 } else { 0 };
25    // SAFETY: The socket descriptor is open and `value` is readable with the
26    // exact size supplied for the duration of setsockopt.
27    let ret = unsafe {
28        libc::setsockopt(
29            socket.as_raw_fd(),
30            level,
31            optname,
32            (&value as *const libc::c_int).cast(),
33            std::mem::size_of::<libc::c_int>() as libc::socklen_t,
34        )
35    };
36    if ret == 0 {
37        Ok(())
38    } else {
39        Err(io::Error::last_os_error())
40    }
41}
42
43#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
44fn get_bool_sockopt(socket: &Socket, level: libc::c_int, optname: libc::c_int) -> io::Result<bool> {
45    use std::os::fd::AsRawFd;
46    let mut value: libc::c_int = 0;
47    let mut len = std::mem::size_of::<libc::c_int>() as libc::socklen_t;
48    // SAFETY: The socket descriptor is open; `value` and `len` are writable for
49    // the duration of getsockopt.
50    let ret = unsafe {
51        libc::getsockopt(
52            socket.as_raw_fd(),
53            level,
54            optname,
55            (&mut value as *mut libc::c_int).cast(),
56            &mut len,
57        )
58    };
59    if ret == 0 {
60        Ok(value != 0)
61    } else {
62        Err(io::Error::last_os_error())
63    }
64}
65
66pub(crate) fn set_recv_pktinfo(socket: &Socket, family: SocketFamily, on: bool) -> io::Result<()> {
67    match family {
68        SocketFamily::IPV4 => set_recv_pktinfo_v4(socket, on),
69        SocketFamily::IPV6 => set_recv_pktinfo_v6(socket, on),
70    }
71}
72
73#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
74pub(crate) fn set_recv_pktinfo_v4(socket: &Socket, on: bool) -> io::Result<()> {
75    set_bool_sockopt(socket, libc::IPPROTO_IP, libc::IP_PKTINFO, on)
76}
77
78#[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
79pub(crate) fn set_recv_pktinfo_v4(_socket: &Socket, _on: bool) -> io::Result<()> {
80    Err(io::Error::new(
81        io::ErrorKind::Unsupported,
82        "IP_PKTINFO is not supported on this platform",
83    ))
84}
85
86#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
87pub(crate) fn set_recv_pktinfo_v6(socket: &Socket, on: bool) -> io::Result<()> {
88    set_bool_sockopt(socket, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, on)
89}
90
91#[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
92pub(crate) fn set_recv_pktinfo_v6(_socket: &Socket, _on: bool) -> io::Result<()> {
93    Err(io::Error::new(
94        io::ErrorKind::Unsupported,
95        "IPV6_RECVPKTINFO is not supported on this platform",
96    ))
97}
98
99#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
100pub(crate) fn recv_pktinfo_v4(socket: &Socket) -> io::Result<bool> {
101    get_bool_sockopt(socket, libc::IPPROTO_IP, libc::IP_PKTINFO)
102}
103
104#[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
105pub(crate) fn recv_pktinfo_v4(_socket: &Socket) -> io::Result<bool> {
106    Err(io::Error::new(
107        io::ErrorKind::Unsupported,
108        "IP_PKTINFO is not supported on this platform",
109    ))
110}
111
112#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
113pub(crate) fn recv_pktinfo_v6(socket: &Socket) -> io::Result<bool> {
114    get_bool_sockopt(socket, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO)
115}
116
117#[cfg(not(any(target_os = "android", target_os = "fuchsia", target_os = "linux")))]
118pub(crate) fn recv_pktinfo_v6(_socket: &Socket) -> io::Result<bool> {
119    Err(io::Error::new(
120        io::ErrorKind::Unsupported,
121        "IPV6_RECVPKTINFO is not supported on this platform",
122    ))
123}
124
125#[cfg(feature = "async")]
126pub use async_impl::*;
127pub use config::*;
128pub use sync_impl::*;