]> git.lizzy.rs Git - rust.git/commitdiff
std: Add support for accept4 on Linux
authorAlex Crichton <alex@alexcrichton.com>
Thu, 4 Feb 2016 23:22:41 +0000 (15:22 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Sat, 6 Feb 2016 01:11:02 +0000 (17:11 -0800)
This is necessary to atomically accept a socket and set the CLOEXEC flag at the
same time. Support only appeared in Linux 2.6.28 so we have to dynamically
determine which syscall we're supposed to call in this case.

src/libstd/sys/unix/net.rs
src/libstd/sys/unix/weak.rs

index 728bc258c00a84cbbadd7b9838a15355d55e9609..507cc0f4ea46191e930fc0ced1ba266dc7843910 100644 (file)
@@ -12,7 +12,7 @@
 
 use ffi::CStr;
 use io;
-use libc::{self, c_int, size_t};
+use libc::{self, c_int, size_t, sockaddr, socklen_t};
 use net::{SocketAddr, Shutdown};
 use str;
 use sys::fd::FileDesc;
@@ -78,8 +78,28 @@ pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
         }
     }
 
-    pub fn accept(&self, storage: *mut libc::sockaddr,
-                  len: *mut libc::socklen_t) -> io::Result<Socket> {
+    pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
+                  -> io::Result<Socket> {
+        // Unfortunately the only known way right now to accept a socket and
+        // atomically set the CLOEXEC flag is to use the `accept4` syscall on
+        // Linux. This was added in 2.6.28, however, and because we support
+        // 2.6.18 we must detect this support dynamically.
+        if cfg!(target_os = "linux") {
+            weak! {
+                fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int
+            }
+            if let Some(accept) = accept4.get() {
+                let res = cvt_r(|| unsafe {
+                    accept(self.0.raw(), storage, len, SOCK_CLOEXEC)
+                });
+                match res {
+                    Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
+                    Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
+                    Err(e) => return Err(e),
+                }
+            }
+        }
+
         let fd = try!(cvt_r(|| unsafe {
             libc::accept(self.0.raw(), storage, len)
         }));
index 2cbcd62f5339621724f760f81e006a62dc83f640..e6f85c08d1246cf06ee0f88ad9935b49cbf83262 100644 (file)
@@ -61,7 +61,11 @@ pub fn get(&self) -> Option<&F> {
             if self.addr.load(Ordering::SeqCst) == 1 {
                 self.addr.store(fetch(self.name), Ordering::SeqCst);
             }
-            mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
+            if self.addr.load(Ordering::SeqCst) == 0 {
+                None
+            } else {
+                mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
+            }
         }
     }
 }