rust_p2p_core/socket/
mod.rs1#[cfg(windows)]
20use crate::socket::windows::ignore_conn_reset;
21use socket2::Protocol;
22use std::io;
23use std::net::SocketAddr;
24
25#[cfg(unix)]
26mod unix;
27#[cfg(windows)]
28mod windows;
29
30pub(crate) trait SocketTrait {
31 fn set_ip_unicast_if(&self, _interface: &LocalInterface) -> io::Result<()> {
32 Ok(())
33 }
34}
35
36#[derive(Clone, Debug)]
55pub struct LocalInterface {
56 #[cfg(not(any(target_os = "linux", target_os = "android")))]
57 pub index: u32,
58 #[cfg(any(target_os = "linux", target_os = "android"))]
59 pub name: String,
60}
61
62impl LocalInterface {
63 #[cfg(not(any(target_os = "linux", target_os = "android")))]
64 pub fn new(index: u32) -> Self {
65 Self { index }
66 }
67 #[cfg(any(target_os = "linux", target_os = "android"))]
68 pub fn new(name: String) -> Self {
69 Self { name }
70 }
71}
72
73pub(crate) async fn connect_tcp(
74 addr: SocketAddr,
75 bind_port: u16,
76 default_interface: Option<&LocalInterface>,
77 ttl: Option<u8>,
78) -> io::Result<tokio::net::TcpStream> {
79 let socket = create_tcp0(addr, bind_port, default_interface, ttl)?;
80 socket.writable().await?;
81 Ok(socket)
82}
83
84pub(crate) fn create_tcp0(
85 addr: SocketAddr,
86 bind_port: u16,
87 default_interface: Option<&LocalInterface>,
88 ttl: Option<u8>,
89) -> io::Result<tokio::net::TcpStream> {
90 let v4 = addr.is_ipv4();
91 let socket = if v4 {
92 socket2::Socket::new(
93 socket2::Domain::IPV4,
94 socket2::Type::STREAM,
95 Some(Protocol::TCP),
96 )?
97 } else {
98 socket2::Socket::new(
99 socket2::Domain::IPV6,
100 socket2::Type::STREAM,
101 Some(Protocol::TCP),
102 )?
103 };
104 if let (true, Some(interface)) = (v4, default_interface) {
105 socket.set_ip_unicast_if(interface)?;
106 }
107 if bind_port != 0 {
108 _ = socket.set_reuse_address(true);
109 #[cfg(unix)]
110 {
111 _ = socket.set_reuse_port(true);
112 }
113 if v4 {
114 let addr: SocketAddr = format!("0.0.0.0:{bind_port}").parse().unwrap();
115 socket.bind(&addr.into())?;
116 } else {
117 socket.set_only_v6(true)?;
118 let addr: SocketAddr = format!("[::]:{bind_port}").parse().unwrap();
119 socket.bind(&addr.into())?;
120 }
121 }
122 if let Some(ttl) = ttl {
123 _ = socket.set_ttl(ttl as _);
124 }
125 socket.set_nonblocking(true)?;
126 socket.set_nodelay(true)?;
127 let res = socket.connect(&addr.into());
128 match res {
129 Ok(()) => {}
130 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
131 #[cfg(unix)]
132 Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
133 Err(e) => Err(e)?,
134 }
135 tokio::net::TcpStream::from_std(socket.into())
136}
137
138pub(crate) fn create_tcp_listener(addr: SocketAddr) -> io::Result<std::net::TcpListener> {
139 let socket = if addr.is_ipv6() {
140 let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::STREAM, None)?;
141 socket.set_only_v6(false)?;
142 socket
143 } else {
144 socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::STREAM, None)?
145 };
146 socket.set_reuse_address(true)?;
147 #[cfg(unix)]
148 if let Err(e) = socket.set_reuse_port(true) {
149 log::warn!("set_reuse_port {e:?}")
150 }
151 socket.bind(&addr.into())?;
152 socket.listen(128)?;
153 socket.set_nonblocking(true)?;
154 socket.set_nodelay(true)?;
155 Ok(socket.into())
156}
157
158pub(crate) fn bind_udp_ops(
159 addr: SocketAddr,
160 only_v6: bool,
161 default_interface: Option<&LocalInterface>,
162) -> io::Result<socket2::Socket> {
163 let socket = if addr.is_ipv4() {
164 let socket = socket2::Socket::new(
165 socket2::Domain::IPV4,
166 socket2::Type::DGRAM,
167 Some(Protocol::UDP),
168 )?;
169 if let Some(default_interface) = default_interface {
170 socket.set_ip_unicast_if(default_interface)?;
171 }
172 socket
173 } else {
174 let socket = socket2::Socket::new(
175 socket2::Domain::IPV6,
176 socket2::Type::DGRAM,
177 Some(Protocol::UDP),
178 )?;
179 socket.set_only_v6(only_v6)?;
180 socket
181 };
182 #[cfg(windows)]
183 if let Err(e) = ignore_conn_reset(&socket) {
184 log::warn!("ignore_conn_reset {e:?}")
185 }
186 socket.set_nonblocking(true)?;
187 socket.bind(&addr.into())?;
188 Ok(socket)
189}
190
191pub fn bind_udp(
192 addr: SocketAddr,
193 default_interface: Option<&LocalInterface>,
194) -> io::Result<socket2::Socket> {
195 bind_udp_ops(addr, true, default_interface)
196}