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 socket.set_reuse_port(true)?;
75 if v4 {
76 let addr: SocketAddr = format!("0.0.0.0:{}", bind_port).parse().unwrap();
77 socket.bind(&addr.into())?;
78 } else {
79 socket.set_only_v6(true)?;
80 let addr: SocketAddr = format!("[::]:{}", bind_port).parse().unwrap();
81 socket.bind(&addr.into())?;
82 }
83 }
84 if let Some(ttl) = ttl {
85 socket.set_ttl(ttl as _)?;
86 }
87 socket.set_nonblocking(true)?;
88 socket.set_nodelay(true)?;
89 let res = socket.connect(&addr.into());
90 match res {
91 Ok(()) => {}
92 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
93 #[cfg(unix)]
94 Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
95 Err(e) => Err(e)?,
96 }
97 tokio::net::TcpStream::from_std(socket.into())
98}
99
100pub(crate) fn create_tcp_listener(addr: SocketAddr) -> io::Result<std::net::TcpListener> {
101 let socket = if addr.is_ipv6() {
102 let socket = socket2::Socket::new(socket2::Domain::IPV6, socket2::Type::STREAM, None)?;
103 socket.set_only_v6(false)?;
104 socket
105 } else {
106 socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::STREAM, None)?
107 };
108 socket.set_reuse_address(true)?;
109 #[cfg(unix)]
110 if let Err(e) = socket.set_reuse_port(true) {
111 log::warn!("set_reuse_port {:?}", e)
112 }
113 socket.bind(&addr.into())?;
114 socket.listen(128)?;
115 socket.set_nonblocking(true)?;
116 socket.set_nodelay(true)?;
117 Ok(socket.into())
118}
119
120pub(crate) fn bind_udp_ops(
121 addr: SocketAddr,
122 only_v6: bool,
123 default_interface: Option<&LocalInterface>,
124) -> io::Result<socket2::Socket> {
125 let socket = if addr.is_ipv4() {
126 let socket = socket2::Socket::new(
127 socket2::Domain::IPV4,
128 socket2::Type::DGRAM,
129 Some(Protocol::UDP),
130 )?;
131 if let Some(default_interface) = default_interface {
132 socket.set_ip_unicast_if(default_interface)?;
133 }
134 socket
135 } else {
136 let socket = socket2::Socket::new(
137 socket2::Domain::IPV6,
138 socket2::Type::DGRAM,
139 Some(Protocol::UDP),
140 )?;
141 socket.set_only_v6(only_v6)?;
142 socket
143 };
144 #[cfg(windows)]
145 if let Err(e) = ignore_conn_reset(&socket) {
146 log::warn!("ignore_conn_reset {e:?}")
147 }
148 socket.set_nonblocking(true)?;
149 socket.bind(&addr.into())?;
150 Ok(socket)
151}
152
153pub fn bind_udp(
154 addr: SocketAddr,
155 default_interface: Option<&LocalInterface>,
156) -> io::Result<socket2::Socket> {
157 bind_udp_ops(addr, true, default_interface)
158}