1use super::get_if_addrs::get_if_addrs;
2use cyfs_base::{BuckyError, BuckyResult, BuckyErrorCode};
3
4use std::error::Error;
5use std::mem;
6use std::net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6};
7
8#[cfg(unix)]
9use async_std::net::UdpSocket;
10#[cfg(unix)]
11use async_std::os::unix::io::RawFd;
12#[cfg(unix)]
13extern crate libc;
14
15#[cfg(windows)]
16use std::os::windows::io::{AsRawSocket, RawSocket};
17#[cfg(windows)]
18extern crate libc;
19
20#[cfg(windows)]
21use std::ptr;
22
23#[cfg(windows)]
24use winapi::{
25 shared::minwindef::{BOOL, DWORD, FALSE, LPDWORD, LPVOID},
26 um::{
27 mswsock::SIO_UDP_CONNRESET,
28 winsock2::{WSAGetLastError, WSAIoctl, SOCKET, SOCKET_ERROR},
29 },
30};
31
32pub fn get_all_ips() -> BuckyResult<Vec<IpAddr>> {
33 let mut ret = Vec::new();
34 for iface in get_if_addrs()? {
35 ret.push(iface.ip())
36 }
37 Ok(ret)
38}
39
40#[cfg(unix)]
41pub fn set_socket_reuseaddr(fd: RawFd) -> Result<(), Box<dyn Error>> {
42 let ret;
43 unsafe {
44 let optval: libc::c_int = 1;
45 ret = libc::setsockopt(
46 fd,
47 libc::SOL_SOCKET,
48 libc::SO_REUSEADDR,
49 &optval as *const _ as *const libc::c_void,
50 mem::size_of_val(&optval) as libc::socklen_t,
51 );
52 }
53
54 if ret != 0 {
55 let msg = format!(
56 "set_socket_reuseaddr error! ret={}, err={}",
57 ret,
58 async_std::io::Error::last_os_error()
59 );
60 error!("{}", msg);
61
62 return Err(Box::<dyn Error>::from(msg));
63 }
64
65 Ok(())
66}
67
68#[cfg(unix)]
69pub fn set_socket_reuseport(fd: RawFd) -> Result<(), Box<dyn Error>> {
70 let ret;
71 unsafe {
72 let optval: libc::c_int = 1;
73 ret = libc::setsockopt(
74 fd,
75 libc::SOL_SOCKET,
76 libc::SO_REUSEPORT,
77 &optval as *const _ as *const libc::c_void,
78 mem::size_of_val(&optval) as libc::socklen_t,
79 );
80 }
81
82 if ret != 0 {
83 let msg = format!(
84 "set_socket_reuseport error! ret={}, err={}",
85 ret,
86 async_std::io::Error::last_os_error()
87 );
88 error!("{}", msg);
89
90 return Err(Box::<dyn Error>::from(msg));
91 }
92
93 Ok(())
94}
95
96#[cfg(unix)]
97pub fn set_socket_keepalive(fd: RawFd) -> Result<(), Box<dyn Error>> {
98 let ret;
99 unsafe {
100 let optval: libc::c_int = 1;
101 ret = libc::setsockopt(
102 fd,
103 libc::SOL_SOCKET,
104 libc::SO_KEEPALIVE,
105 &optval as *const _ as *const libc::c_void,
106 mem::size_of_val(&optval) as libc::socklen_t,
107 );
108 }
109
110 if ret != 0 {
111 let msg = format!(
112 "setsockopt error! ret={}, err={}",
113 ret,
114 async_std::io::Error::last_os_error()
115 );
116 error!("{}", msg);
117
118 return Err(Box::<dyn Error>::from(msg));
119 }
120
121 Ok(())
122}
123
124#[cfg(windows)]
125pub fn set_socket_keepalive(sock: RawSocket) -> Result<(), Box<dyn Error>> {
126 const SOL_SOCKET: i32 = 0xFFFF;
127 const SO_KEEPALIVE: i32 = 0x0008;
128
129 let ret;
130 unsafe {
131 let optval: libc::c_int = 1;
132 ret = libc::setsockopt(
133 sock as libc::SOCKET,
134 SOL_SOCKET,
135 SO_KEEPALIVE,
136 &optval as *const _ as *const libc::c_char,
137 mem::size_of_val(&optval) as libc::c_int,
138 );
139 }
140
141 if ret != 0 {
142 let msg = format!(
143 "setsockopt error! ret={}, err={}",
144 ret,
145 async_std::io::Error::last_os_error()
146 );
147 error!("{}", msg);
148
149 return Err(Box::<dyn Error>::from(msg));
150 }
151
152 Ok(())
153}
154
155#[cfg(not(windows))]
156pub fn init_udp_socket(_socket: &UdpSocket) -> Result<(), BuckyError> {
157 Ok(())
158}
159
160#[cfg(windows)]
161pub fn init_udp_socket<S: AsRawSocket>(socket: &S) -> Result<(), BuckyError> {
162 unsafe {
163 let mut bytes_returned: DWORD = 0;
174 let mut enable: BOOL = FALSE;
175 let handle = socket.as_raw_socket() as SOCKET;
176
177 let ret = WSAIoctl(
178 handle,
179 SIO_UDP_CONNRESET,
180 &mut enable as *mut _ as LPVOID,
181 mem::size_of_val(&enable) as DWORD,
182 ptr::null_mut(),
183 0,
184 &mut bytes_returned as *mut _ as LPDWORD,
185 ptr::null_mut(),
186 None,
187 );
188
189 if ret == SOCKET_ERROR {
190 use std::io::Error;
191
192 let err_code = WSAGetLastError();
193 let err = Error::from_raw_os_error(err_code);
194
195 Err(BuckyError::from(err))
196 } else {
197 Ok(())
198 }
199 }
200}
201
202pub fn parse_address(address: &str) -> Result<(String, u16), BuckyError> {
204 let parts: Vec<&str> = address.split(':').collect();
205 if parts.len() == 1 {
206 match parts[0].parse::<u16>() {
207 Ok(port) => Ok(("0.0.0.0".to_string(), port)),
208 Err(e) => {
209 error!("invalid address port, address={}, e={}", address, e);
210 Err(BuckyError::from(e))
211 }
212 }
213 } else {
214 match parts[1].parse::<u16>() {
215 Ok(port) => Ok((parts[0].to_string(), port)),
216 Err(e) => {
217 error!("invalid address port, address={}, e={}", address, e);
218 Err(BuckyError::from(e))
219 }
220 }
221 }
222}
223
224
225pub fn parse_port_from_toml_value(v: &toml::Value) -> BuckyResult<u16> {
226 let port: u16;
227
228 if v.is_integer() {
229 let v = v.as_integer().unwrap();
230 if v >= 65536 {
231 let msg = format!("invalid port number range: {}", v);
232 error!("{}", msg);
233
234 return Err(BuckyError::from(msg));
235 }
236 port = v as u16;
237 } else if v.is_str() {
238 let v = v.as_str().unwrap();
239 let ret = v.parse::<u16>();
240 if let Err(e) = ret {
241 error!("invalid port number! e={}", e);
242
243 return Err(BuckyError::from(e));
244 }
245
246 port = ret.unwrap();
247 } else {
248 let msg = format!("invalid port type: {:?}", v);
249 error!("{}", msg);
250
251 return Err(BuckyError::new(BuckyErrorCode::InvalidFormat, msg));
252 }
253
254 Ok(port)
255}
256
257pub fn is_invalid_ip(ip: &str) -> bool {
258 let parts: Vec<&str> = ip.split(".").collect();
259
260 return (parts[0] == "169" && parts[1] == "254")
262 || (parts[0] == "0" && parts[1] == "0" && parts[2] == "0" && parts[3] == "0");
263}
264
265pub fn is_private_ip(ip: &str) -> bool {
267 let parts: Vec<&str> = ip.split(".").collect();
268 return parts[0] == "10"
269 || (parts[0] == "172"
270 && (parts[1].parse::<u16>().unwrap_or(0) >= 16
271 && parts[1].parse::<u16>().unwrap_or(0) <= 31))
272 || (parts[0] == "192" && parts[1] == "168");
273}
274
275static SYSTEM_HOST_INFO: once_cell::sync::OnceCell<SystemHostInfo> = once_cell::sync::OnceCell::new();
276
277#[derive(Clone)]
278pub struct SystemHostInfo {
279 pub none_local_ip_v4: Vec<SocketAddr>,
280 pub private_ip_v4: Vec<SocketAddr>,
281 pub public_ip_v4: Vec<SocketAddr>,
282 pub ip_v6: Vec<SocketAddr>,
283}
284
285pub fn bind_system_hosts(info: SystemHostInfo) {
287 if let Err(_e) = SYSTEM_HOST_INFO.set(info) {
288 error!("bind_system_hosts must be call only once or on startup before stack init!")
289 }
290}
291
292pub fn get_system_hosts() -> BuckyResult<SystemHostInfo> {
293 if SYSTEM_HOST_INFO.get().is_none() {
294 let info = init_system_hosts()?;
295 bind_system_hosts(info);
296 }
297
298 Ok(SYSTEM_HOST_INFO.get().unwrap().clone())
299}
300
301pub fn init_system_hosts() -> BuckyResult<SystemHostInfo> {
302 let ret = get_if_addrs();
303 if let Err(e) = ret {
304 let msg = format!("get_if_addrs error! err={}", e);
305 error!("{}", msg);
306
307 return Err(BuckyError::from(msg));
308 }
309
310 let mut result = SystemHostInfo {
311 none_local_ip_v4: Vec::new(),
312 private_ip_v4: Vec::new(),
313 public_ip_v4: Vec::new(),
314 ip_v6: Vec::new(),
315 };
316
317 for iface in ret.unwrap() {
318 info!("got iface={:?}", iface);
319
320 let addr = match iface.ip() {
321 IpAddr::V4(addr) => addr,
322 IpAddr::V6(addr) => {
323 let sock_addr = SocketAddrV6::new(addr, 0, 0, iface.scope_id);
324 result.ip_v6.push(SocketAddr::V6(sock_addr));
325 continue;
326 }
327 };
328
329 let ip_str = addr.to_string();
330 info!("got ip: {} {}", ip_str, iface.description);
331
332 if cfg!(windows) {
333 if iface.description.find("VMware").is_some() {
334 info!("will ignore as VMware addr: {}", ip_str);
335 continue;
336 }
337
338 if iface
339 .description
340 .find("Hyper-V Virtual Ethernet Adapter")
341 .is_some()
342 {
343 info!(
344 "will ignore as Hyper-V Virtual Ethernet Adapter addr: {}",
345 ip_str
346 );
347 continue;
348 }
349 }
350
351 if is_invalid_ip(&ip_str) {
352 info!("will ignore as invalid addr: {}", ip_str);
353 continue;
354 }
355
356 let addr = SocketAddr::V4(SocketAddrV4::new(addr, 0));
357 result.none_local_ip_v4.push(addr);
358 if is_private_ip(&ip_str) {
359 result.private_ip_v4.push(addr);
360 } else {
361 result.public_ip_v4.push(addr);
362 }
363 }
364
365 Ok(result)
366}