Skip to content

Commit ceec0bc

Browse files
committed
Add accept_from returning remote address
1 parent e4895d3 commit ceec0bc

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed

changelog/2609.added.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add `accept_from` function returning the remote-address.

src/sys/socket/mod.rs

+35
Original file line numberDiff line numberDiff line change
@@ -2364,6 +2364,41 @@ pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
23642364
Errno::result(res)
23652365
}
23662366

2367+
/// Accept a connection on a socket, returning the remote address.
2368+
///
2369+
/// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html)
2370+
#[cfg(any(
2371+
all(
2372+
target_os = "android",
2373+
any(
2374+
target_arch = "aarch64",
2375+
target_arch = "x86",
2376+
target_arch = "x86_64"
2377+
)
2378+
),
2379+
freebsdlike,
2380+
netbsdlike,
2381+
target_os = "emscripten",
2382+
target_os = "fuchsia",
2383+
solarish,
2384+
target_os = "linux",
2385+
))]
2386+
pub fn accept_from<S: SockaddrLike>(sockfd: RawFd, flags: SockFlag) -> Result<(RawFd, Option<S>)> {
2387+
let mut storage = std::mem::MaybeUninit::<libc::sockaddr_storage>::uninit();
2388+
let mut socklen = std::mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
2389+
let res = unsafe {
2390+
libc::accept4(sockfd, storage.as_mut_ptr().cast(), &mut socklen as *mut _, flags.bits())
2391+
};
2392+
2393+
let sock = Errno::result(res)?;
2394+
let addr = unsafe {
2395+
let storage = storage.assume_init();
2396+
S::from_raw((&storage as *const libc::sockaddr_storage).cast(), Some(socklen))
2397+
};
2398+
2399+
Ok((sock, addr))
2400+
}
2401+
23672402
/// Initiate a connection on a socket
23682403
///
23692404
/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html)

test/sys/test_socket.rs

+53
Original file line numberDiff line numberDiff line change
@@ -3161,3 +3161,56 @@ fn can_open_routing_socket() {
31613161
socket(AddressFamily::Route, SockType::Raw, SockFlag::empty(), None)
31623162
.expect("Failed to open routing socket");
31633163
}
3164+
3165+
#[cfg(any(
3166+
all(
3167+
target_os = "android",
3168+
any(
3169+
target_arch = "aarch64",
3170+
target_arch = "x86",
3171+
target_arch = "x86_64"
3172+
)
3173+
),
3174+
freebsdlike,
3175+
netbsdlike,
3176+
target_os = "emscripten",
3177+
target_os = "fuchsia",
3178+
solarish,
3179+
target_os = "linux",
3180+
))]
3181+
#[test]
3182+
fn test_accept_from() {
3183+
use nix::sys::socket::{accept_from, bind, connect, listen, socket};
3184+
use nix::sys::socket::{Backlog, SockFlag, SockType, SockaddrIn};
3185+
use std::net::Ipv4Addr;
3186+
3187+
let sock_addr = SockaddrIn::from_str("127.0.0.1:6780").unwrap();
3188+
let listener = socket(
3189+
AddressFamily::Inet,
3190+
SockType::Stream,
3191+
SockFlag::empty(),
3192+
None,
3193+
)
3194+
.expect("listener socket failed");
3195+
bind(listener.as_raw_fd(), &sock_addr).expect("bind failed");
3196+
listen(&listener, Backlog::MAXCONN).expect("listen failed");
3197+
3198+
let connector = socket(
3199+
AddressFamily::Inet,
3200+
SockType::Stream,
3201+
SockFlag::empty(),
3202+
None,
3203+
)
3204+
.expect("connector socket failed");
3205+
3206+
let send_thread =
3207+
std::thread::spawn(move || connect(connector.as_raw_fd(), &sock_addr));
3208+
let (_peer, address) =
3209+
accept_from::<SockaddrIn>(listener.as_raw_fd(), SockFlag::empty())
3210+
.unwrap();
3211+
let address = address.expect("no address");
3212+
3213+
assert_eq!(address.ip(), Ipv4Addr::LOCALHOST);
3214+
3215+
send_thread.join().unwrap().unwrap();
3216+
}

0 commit comments

Comments
 (0)