diff options
| author | Tobias Bucher <tobiasbucher5991@gmail.com> | 2015-08-24 13:57:11 +0200 |
|---|---|---|
| committer | Tobias Bucher <tobiasbucher5991@gmail.com> | 2015-08-30 10:24:05 +0200 |
| commit | 1f81ef4d0f2547cacc316b01ad03603ad772e38e (patch) | |
| tree | e7495a22e3340d8930b5e4be7f95620b9a9b6a51 /src/libstd/sys/unix | |
| parent | 4bb90232daab451cf58359e0c5874bc905d2f101 (diff) | |
| download | rust-1f81ef4d0f2547cacc316b01ad03603ad772e38e.tar.gz rust-1f81ef4d0f2547cacc316b01ad03603ad772e38e.zip | |
Atomically set CLOEXEC on duplicated sockets
For Bitrig, NetBSD and OpenBSD the constant was incorrectly in posix01, when it's actually posix08, so we move it. This is a [breaking-change], but we already had one in #27930. 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 This assumes that an int literal has type `c_int` for varidic functions.
Diffstat (limited to 'src/libstd/sys/unix')
| -rw-r--r-- | src/libstd/sys/unix/net.rs | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index e65f64f2029..f1a9518d08d 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -13,9 +13,10 @@ use prelude::v1::*; use ffi::CStr; use io; use libc::{self, c_int, size_t}; +use net::SocketAddr; use str; +use sync::atomic::{self, AtomicBool}; use sys::c; -use net::SocketAddr; use sys::fd::FileDesc; use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{getsockopt, setsockopt}; @@ -66,10 +67,29 @@ impl Socket { } pub fn duplicate(&self) -> io::Result<Socket> { - let fd = try!(cvt(unsafe { libc::dup(self.0.raw()) })); - let fd = FileDesc::new(fd); - fd.set_cloexec(); - Ok(Socket(fd)) + use libc::funcs::posix88::fcntl::fcntl; + let make_socket = |fd| { + let fd = FileDesc::new(fd); + fd.set_cloexec(); + Socket(fd) + }; + static EMULATE_F_DUPFD_CLOEXEC: AtomicBool = AtomicBool::new(false); + if !EMULATE_F_DUPFD_CLOEXEC.load(atomic::Ordering::Relaxed) { + match cvt(unsafe { fcntl(self.0.raw(), libc::F_DUPFD_CLOEXEC, 0) }) { + // `EINVAL` can only be returned on two occasions: Invalid + // command (second parameter) or invalid third parameter. 0 is + // always a valid third parameter, so it must be the second + // parameter. + // + // Store the result in a global variable so we don't try each + // syscall twice. + Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { + EMULATE_F_DUPFD_CLOEXEC.store(true, atomic::Ordering::Relaxed); + } + res => return res.map(make_socket), + } + } + cvt(unsafe { fcntl(self.0.raw(), libc::F_DUPFD, 0) }).map(make_socket) } pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
