icmp_client/
utils.rs

1use std::net::UdpSocket;
2
3use crate::{config::Config, AsyncClientWithConfigError};
4
5// Ref https://github.com/kolapapa/surge-ping/blob/0.7.3/src/client.rs#L36-L54
6pub fn new_socket2_socket(config: &Config) -> Result<socket2::Socket, AsyncClientWithConfigError> {
7    use socket2::{Domain, Protocol, SockAddr, Socket, Type};
8
9    let socket = if config.is_ipv6() {
10        Socket::new(Domain::IPV6, Type::DGRAM, Some(Protocol::ICMPV6)).map_err(|err| {
11            if err.raw_os_error() == Some(93) {
12                AsyncClientWithConfigError::IcmpV6ProtocolNotSupported(err)
13            } else {
14                AsyncClientWithConfigError::OtherIoError(err)
15            }
16        })?
17    } else {
18        Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::ICMPV4))?
19    };
20
21    socket.set_nonblocking(true)?;
22
23    if let Some(bind) = config.bind {
24        socket.bind(&SockAddr::from(bind))?;
25    }
26    #[cfg(any(
27        target_os = "ios",
28        target_os = "macos",
29        target_os = "tvos",
30        target_os = "watchos",
31    ))]
32    if let Some(interface_index) = config.interface_index {
33        socket.bind_device_by_index(Some(interface_index))?;
34    }
35    if let Some(ttl) = config.ttl {
36        socket.set_ttl(ttl)?;
37    }
38    #[cfg(target_os = "freebsd")]
39    if let Some(fib) = config.fib {
40        socket.set_fib(fib)?;
41    }
42
43    Ok(socket)
44}
45
46//
47pub fn new_std_udp_socket(config: &Config) -> Result<UdpSocket, AsyncClientWithConfigError> {
48    #[cfg(unix)]
49    use std::os::fd::{FromRawFd as _, IntoRawFd as _};
50    #[cfg(windows)]
51    use std::os::windows::{FromRawSocket as _, IntoRawSocket as _};
52
53    let socket = new_socket2_socket(config)?;
54
55    #[cfg(unix)]
56    let udp_socket = unsafe { UdpSocket::from_raw_fd(socket.into_raw_fd()) };
57    #[cfg(windows)]
58    let udp_socket = unsafe { UdpSocket::from_raw_socket(socket.into_raw_socket()) };
59
60    Ok(udp_socket)
61}