rust_p2p_core/socket/
mod.rs1#[cfg(windows)]
2use crate::socket::windows::ignore_conn_reset;
3use socket2::Protocol;
4use std::io;
5use std::net::SocketAddr;
6
7#[cfg(unix)]
8mod unix;
9#[cfg(windows)]
10mod windows;
11
12pub(crate) trait SocketTrait {
13 fn set_ip_unicast_if(&self, _interface: &LocalInterface) -> io::Result<()> {
14 Ok(())
15 }
16}
17
18#[derive(Clone, Debug)]
19pub struct LocalInterface {
20 #[cfg(not(any(target_os = "linux", target_os = "android")))]
21 pub index: u32,
22 #[cfg(any(target_os = "linux", target_os = "android"))]
23 pub name: String,
24}
25
26impl LocalInterface {
27 #[cfg(not(any(target_os = "linux", target_os = "android")))]
28 pub fn new(index: u32) -> Self {
29 Self { index }
30 }
31 #[cfg(any(target_os = "linux", target_os = "android"))]
32 pub fn new(name: String) -> Self {
33 Self { name }
34 }
35}
36
37pub(crate) async fn connect_tcp(
38 addr: SocketAddr,
39 bind_port: u16,
40 default_interface: Option<&LocalInterface>,
41 ttl: Option<u8>,
42) -> io::Result<tokio::net::TcpStream> {
43 let socket = create_tcp0(addr, bind_port, default_interface, ttl)?;
44 socket.writable().await?;
45 Ok(socket)
46}
47
48pub(crate) fn create_tcp0(
49 addr: SocketAddr,
50 bind_port: u16,
51 default_interface: Option<&LocalInterface>,
52 ttl: Option<u8>,
53) -> io::Result<tokio::net::TcpStream> {
54 let v4 = addr.is_ipv4();
55 let socket = if v4 {
56 socket2::Socket::new(
57 socket2::Domain::IPV4,
58 socket2::Type::STREAM,
59 Some(Protocol::TCP),
60 )?
61 } else {
62 socket2::Socket::new(
63 socket2::Domain::IPV6,
64 socket2::Type::STREAM,
65 Some(Protocol::TCP),
66 )?
67 };
68 if v4 && default_interface.is_some() {
69 socket.set_ip_unicast_if(default_interface.unwrap())?;
70 }
71 if bind_port != 0 {
72 _ = socket.set_reuse_address(true);
73 #[cfg(unix)]
74 {
75 _ = socket.set_reuse_port(true);
76 }
77 if v4 {
78 let addr: SocketAddr = format!("0.0.0.0:{bind_port}").parse().unwrap();
79 socket.bind(&addr.into())?;
80 } else {
81 socket.set_only_v6(true)?;
82 let addr: SocketAddr = format!("[::]:{bind_port}").parse().unwrap();
83 socket.bind(&addr.into())?;
84 }
85 }
86 if let Some(ttl) = ttl {
87 _ = socket.set_ttl(ttl as _);
88 }
89 socket.set_nonblocking(true)?;
90 socket.set_nodelay(true)?;
91 let res = socket.connect(&addr.into());
92 match res {
93 Ok(()) => {}
94 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
95 #[cfg(unix)]
96 Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
97 Err(e) => Err(e)?,
98 }
99 tokio::net::TcpStream::from_std(socket.into())
100}
101
102pub(crate) fn create_tcp_listener(addr: SocketAddr) -> io::Result<std::net::TcpListener> {
103 let socket = if addr.is_ipv6() {
104 let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::STREAM, None)?;
105 socket.set_only_v6(false)?;
106 socket
107 } else {
108 socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::STREAM, None)?
109 };
110 socket.set_reuse_address(true)?;
111 #[cfg(unix)]
112 if let Err(e) = socket.set_reuse_port(true) {
113 log::warn!("set_reuse_port {e:?}")
114 }
115 socket.bind(&addr.into())?;
116 socket.listen(128)?;
117 socket.set_nonblocking(true)?;
118 socket.set_nodelay(true)?;
119 Ok(socket.into())
120}
121
122pub(crate) fn bind_udp_ops(
123 addr: SocketAddr,
124 only_v6: bool,
125 default_interface: Option<&LocalInterface>,
126) -> io::Result<socket2::Socket> {
127 let socket = if addr.is_ipv4() {
128 let socket = socket2::Socket::new(
129 socket2::Domain::IPV4,
130 socket2::Type::DGRAM,
131 Some(Protocol::UDP),
132 )?;
133 if let Some(default_interface) = default_interface {
134 socket.set_ip_unicast_if(default_interface)?;
135 }
136 socket
137 } else {
138 let socket = socket2::Socket::new(
139 socket2::Domain::IPV6,
140 socket2::Type::DGRAM,
141 Some(Protocol::UDP),
142 )?;
143 socket.set_only_v6(only_v6)?;
144 socket
145 };
146 #[cfg(windows)]
147 if let Err(e) = ignore_conn_reset(&socket) {
148 log::warn!("ignore_conn_reset {e:?}")
149 }
150 socket.set_nonblocking(true)?;
151 socket.bind(&addr.into())?;
152 Ok(socket)
153}
154
155pub fn bind_udp(
156 addr: SocketAddr,
157 default_interface: Option<&LocalInterface>,
158) -> io::Result<socket2::Socket> {
159 bind_udp_ops(addr, true, default_interface)
160}