1use std::net::UdpSocket;
2
3use crate::{config::Config, AsyncClientWithConfigError};
4
5pub 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
46pub 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}