Skip to content

Commit edee43d

Browse files
committed
Atomically set CLOEXEC on duplicated sockets
For Bitrig, NetBSD and OpenBSD the constant was incorrectly in posix01, when it's actually posix08. In order to maintain backwards-compatiblity, the constant is still imported in posix01. Fix NetBSD's F_DUPFD_CLOEXEC constant. For a similar feature detection, see this musl thread: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
1 parent 6de7f60 commit edee43d

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

src/liblibc/lib.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -3611,6 +3611,7 @@ pub mod consts {
36113611
pub mod posix08 {
36123612
use types::os::arch::c95::c_int;
36133613
pub const O_CLOEXEC: c_int = 0x80000;
3614+
pub const F_DUPFD_CLOEXEC: c_int = 1030;
36143615
}
36153616
#[cfg(any(target_arch = "arm",
36163617
target_arch = "aarch64",
@@ -4274,11 +4275,13 @@ pub mod consts {
42744275
pub mod posix08 {
42754276
use types::os::arch::c95::c_int;
42764277
pub const O_CLOEXEC: c_int = 0x100000;
4278+
pub const F_DUPFD_CLOEXEC: c_int = 17;
42774279
}
42784280
#[cfg(target_os = "dragonfly")]
42794281
pub mod posix08 {
42804282
use types::os::arch::c95::c_int;
42814283
pub const O_CLOEXEC: c_int = 0x20000;
4284+
pub const F_DUPFD_CLOEXEC: c_int = 17;
42824285
}
42834286
pub mod bsd44 {
42844287
use types::os::arch::c95::c_int;
@@ -4643,7 +4646,7 @@ pub mod consts {
46434646
pub const F_GETLK : c_int = 7;
46444647
pub const F_SETLK : c_int = 8;
46454648
pub const F_SETLKW : c_int = 9;
4646-
pub const F_DUPFD_CLOEXEC : c_int = 10;
4649+
pub use consts::os::posix08::F_DUPFD_CLOEXEC;
46474650

46484651
pub const SIGTRAP : c_int = 5;
46494652
pub const SIG_IGN: size_t = 1;
@@ -4725,11 +4728,13 @@ pub mod consts {
47254728
pub mod posix08 {
47264729
use types::os::arch::c95::c_int;
47274730
pub const O_CLOEXEC: c_int = 0x10000;
4731+
pub const F_DUPFD_CLOEXEC: c_int = 10;
47284732
}
47294733
#[cfg(target_os = "netbsd")]
47304734
pub mod posix08 {
47314735
use types::os::arch::c95::c_int;
47324736
pub const O_CLOEXEC: c_int = 0x400000;
4737+
pub const F_DUPFD_CLOEXEC: c_int = 12;
47334738
}
47344739
pub mod bsd44 {
47354740
use types::os::arch::c95::c_int;
@@ -5169,6 +5174,7 @@ pub mod consts {
51695174
pub mod posix08 {
51705175
use types::os::arch::c95::c_int;
51715176
pub const O_CLOEXEC: c_int = 0x1000000;
5177+
pub const F_DUPFD_CLOEXEC: c_int = 67;
51725178
}
51735179
pub mod bsd44 {
51745180
use types::os::arch::c95::c_int;

src/libstd/sys/unix/net.rs

+37-3
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ use prelude::v1::*;
1313
use ffi::CStr;
1414
use io;
1515
use libc::{self, c_int, size_t};
16+
use net::SocketAddr;
1617
use str;
18+
use sync::Once;
1719
use sys::c;
18-
use net::SocketAddr;
1920
use sys::fd::FileDesc;
21+
use sys::os;
2022
use sys_common::{AsInner, FromInner, IntoInner};
2123
use sys_common::net::{getsockopt, setsockopt};
2224
use time::Duration;
@@ -66,9 +68,41 @@ impl Socket {
6668
}
6769

6870
pub fn duplicate(&self) -> io::Result<Socket> {
69-
let fd = try!(cvt(unsafe { libc::dup(self.0.raw()) }));
71+
use libc::funcs::posix88::fcntl::fcntl;
72+
const ZERO: c_int = 0;
73+
#[cfg(target_os = "linux")]
74+
fn fcntl_dupfd() -> c_int {
75+
static START: Once = Once::new();
76+
static mut FCNTL_DUPFD: c_int = 0xdead;
77+
START.call_once(|| unsafe {
78+
// Detect whether the kernel supports F_DUPFD_CLOEXEC. If it
79+
// doesn't, it'll immediately return `EINVAL`. Otherwise, it'll
80+
// return `EBADF` because we passed in a bad file descriptor.
81+
//
82+
// Store the result in a global variable so we only have to
83+
// calculate it once.
84+
let result = fcntl(-1, libc::F_DUPFD_CLOEXEC, ZERO);
85+
let errno = os::errno();
86+
assert!(result == -1 && (errno == libc::EBADF || errno == libc::EINVAL), "errno={}", errno);
87+
if result == libc::EINVAL {
88+
FCNTL_DUPFD = libc::F_DUPFD_CLOEXEC;
89+
} else {
90+
FCNTL_DUPFD = libc::F_DUPFD;
91+
}
92+
});
93+
unsafe { FCNTL_DUPFD }
94+
}
95+
#[cfg(not(target_os = "linux"))]
96+
fn fcntl_dupfd() -> c_int {
97+
libc::F_DUPFD_CLOEXEC
98+
}
99+
100+
let fcntl_dupfd = fcntl_dupfd();
101+
let fd = try!(cvt(unsafe { fcntl(self.0.raw(), fcntl_dupfd, ZERO) }));
70102
let fd = FileDesc::new(fd);
71-
fd.set_cloexec();
103+
if fcntl_dupfd != libc::F_DUPFD_CLOEXEC {
104+
fd.set_cloexec();
105+
}
72106
Ok(Socket(fd))
73107
}
74108

0 commit comments

Comments
 (0)