nex_socket/icmp/
async_impl.rs1use crate::SocketFamily;
2use crate::icmp::{IcmpConfig, IcmpKind, IcmpSocketType};
3use socket2::{Domain, Protocol, Socket, Type as SockType};
4use std::io;
5use std::net::{SocketAddr, UdpSocket as StdUdpSocket};
6use tokio::net::UdpSocket;
7
8#[derive(Debug)]
10pub struct AsyncIcmpSocket {
11 inner: UdpSocket,
12 socket_type: IcmpSocketType,
13 socket_family: SocketFamily,
14}
15
16impl AsyncIcmpSocket {
17 pub async fn new(config: &IcmpConfig) -> io::Result<Self> {
19 let (domain, proto) = match config.socket_family {
20 SocketFamily::IPV4 => (Domain::IPV4, Some(Protocol::ICMPV4)),
21 SocketFamily::IPV6 => (Domain::IPV6, Some(Protocol::ICMPV6)),
22 };
23
24 let socket = match Socket::new(domain, config.sock_type_hint.to_sock_type(), proto) {
26 Ok(s) => s,
27 Err(_) => {
28 let alt_type = if config.sock_type_hint.is_dgram() {
29 SockType::RAW
30 } else {
31 SockType::DGRAM
32 };
33 Socket::new(domain, alt_type, proto)?
34 }
35 };
36
37 socket.set_nonblocking(true)?;
38
39 if let Some(ttl) = config.ttl {
41 socket.set_ttl(ttl)?;
42 }
43 if let Some(hoplimit) = config.hoplimit {
44 socket.set_unicast_hops_v6(hoplimit)?;
45 }
46 if let Some(timeout) = config.read_timeout {
47 socket.set_read_timeout(Some(timeout))?;
48 }
49 if let Some(timeout) = config.write_timeout {
50 socket.set_write_timeout(Some(timeout))?;
51 }
52 #[cfg(target_os = "freebsd")]
54 if let Some(fib) = config.fib {
55 socket.set_fib(fib)?;
56 }
57 #[cfg(any(target_os = "linux", target_os = "android", target_os = "fuchsia"))]
59 if let Some(interface) = &config.interface {
60 socket.bind_device(Some(interface.as_bytes()))?;
61 }
62
63 if let Some(addr) = &config.bind {
65 socket.bind(&(*addr).into())?;
66 }
67
68 let sock_type = socket.r#type()?;
69
70 #[cfg(windows)]
72 let std_socket = unsafe {
73 use std::os::windows::io::{FromRawSocket, IntoRawSocket};
74
75 StdUdpSocket::from_raw_socket(socket.into_raw_socket())
76 };
77 #[cfg(unix)]
78 let std_socket = unsafe {
79 use std::os::fd::{FromRawFd, IntoRawFd};
80
81 StdUdpSocket::from_raw_fd(socket.into_raw_fd())
82 };
83
84 let inner = UdpSocket::from_std(std_socket)?;
86
87 Ok(Self {
88 inner,
89 socket_type: IcmpSocketType::from_sock_type(sock_type),
90 socket_family: config.socket_family,
91 })
92 }
93
94 pub async fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
96 self.inner.send_to(buf, target).await
97 }
98
99 pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
101 self.inner.recv_from(buf).await
102 }
103
104 pub fn local_addr(&self) -> io::Result<SocketAddr> {
106 self.inner.local_addr()
107 }
108
109 pub fn socket_type(&self) -> IcmpSocketType {
111 self.socket_type
112 }
113
114 pub fn socket_family(&self) -> SocketFamily {
116 self.socket_family
117 }
118
119 pub fn icmp_kind(&self) -> IcmpKind {
121 match self.socket_family {
122 SocketFamily::IPV4 => IcmpKind::V4,
123 SocketFamily::IPV6 => IcmpKind::V6,
124 }
125 }
126
127 #[cfg(unix)]
129 pub fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
130 use std::os::fd::AsRawFd;
131 self.inner.as_raw_fd()
132 }
133
134 #[cfg(windows)]
136 pub fn as_raw_socket(&self) -> std::os::windows::io::RawSocket {
137 use std::os::windows::io::AsRawSocket;
138 self.inner.as_raw_socket()
139 }
140}