Skip to content

Commit 169d880

Browse files
committed
feat(shadowsocks): macOS if_nametoindex cache result
1 parent be18b4e commit 169d880

File tree

1 file changed

+43
-10
lines changed
  • crates/shadowsocks/src/net/sys/unix/bsd

1 file changed

+43
-10
lines changed

crates/shadowsocks/src/net/sys/unix/bsd/macos.rs

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use std::{
2+
cell::RefCell,
3+
collections::HashMap,
24
io::{self, ErrorKind},
35
mem,
46
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, TcpStream as StdTcpStream},
@@ -7,6 +9,7 @@ use std::{
79
ptr,
810
sync::atomic::{AtomicBool, Ordering},
911
task::{self, Poll},
12+
time::{Duration, Instant},
1013
};
1114

1215
use log::{debug, error, warn};
@@ -228,11 +231,24 @@ pub async fn create_inbound_tcp_socket(bind_addr: &SocketAddr, _accept_opts: &Ac
228231
}
229232
}
230233

231-
fn set_ip_bound_if<S: AsRawFd>(socket: &S, addr: &SocketAddr, iface: &str) -> io::Result<()> {
232-
const IP_BOUND_IF: libc::c_int = 25; // bsd/netinet/in.h
233-
const IPV6_BOUND_IF: libc::c_int = 125; // bsd/netinet6/in6.h
234+
fn find_interface_index_cached(iface: &str) -> io::Result<u32> {
235+
const INDEX_EXPIRE_DURATION: Duration = Duration::from_secs(5);
234236

235-
unsafe {
237+
thread_local! {
238+
static INTERFACE_INDEX_CACHE: RefCell<HashMap<String, (u32, Instant)>> =
239+
RefCell::new(HashMap::new());
240+
}
241+
242+
let cache_index = INTERFACE_INDEX_CACHE.with(|cache| cache.borrow().get(iface).cloned());
243+
if let Some((idx, insert_time)) = cache_index {
244+
// short-path, cache hit for most cases
245+
let now = Instant::now();
246+
if now - insert_time < INDEX_EXPIRE_DURATION {
247+
return Ok(idx);
248+
}
249+
}
250+
251+
let index = unsafe {
236252
let mut ciface = [0u8; libc::IFNAMSIZ];
237253
if iface.len() >= ciface.len() {
238254
return Err(ErrorKind::InvalidInput.into());
@@ -241,12 +257,28 @@ fn set_ip_bound_if<S: AsRawFd>(socket: &S, addr: &SocketAddr, iface: &str) -> io
241257
let iface_bytes = iface.as_bytes();
242258
ptr::copy_nonoverlapping(iface_bytes.as_ptr(), ciface.as_mut_ptr(), iface_bytes.len());
243259

244-
let index = libc::if_nametoindex(ciface.as_ptr() as *const libc::c_char);
245-
if index == 0 {
246-
let err = io::Error::last_os_error();
247-
error!("if_nametoindex ifname: {} error: {}", iface, err);
248-
return Err(err);
249-
}
260+
libc::if_nametoindex(ciface.as_ptr() as *const libc::c_char)
261+
};
262+
263+
if index == 0 {
264+
let err = io::Error::last_os_error();
265+
error!("if_nametoindex ifname: {} error: {}", iface, err);
266+
return Err(err);
267+
}
268+
269+
INTERFACE_INDEX_CACHE.with(|cache| {
270+
cache.borrow_mut().insert(iface.to_owned(), (index, Instant::now()));
271+
});
272+
273+
Ok(index)
274+
}
275+
276+
fn set_ip_bound_if<S: AsRawFd>(socket: &S, addr: &SocketAddr, iface: &str) -> io::Result<()> {
277+
const IP_BOUND_IF: libc::c_int = 25; // bsd/netinet/in.h
278+
const IPV6_BOUND_IF: libc::c_int = 125; // bsd/netinet6/in6.h
279+
280+
unsafe {
281+
let index = find_interface_index_cached(iface)?;
250282

251283
let ret = match addr {
252284
SocketAddr::V4(..) => libc::setsockopt(
@@ -359,6 +391,7 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, config: &ConnectOp
359391

360392
/// https://github.com/apple/darwin-xnu/blob/main/bsd/sys/socket.h
361393
#[repr(C)]
394+
#[allow(non_camel_case_types)]
362395
struct msghdr_x {
363396
msg_name: *mut libc::c_void, //< optional address
364397
msg_namelen: libc::socklen_t, //< size of address

0 commit comments

Comments
 (0)