diff options
author | Carl Lerche <me@carllerche.com> | 2014-08-25 14:01:28 -0700 |
---|---|---|
committer | Carl Lerche <me@carllerche.com> | 2014-08-25 14:01:28 -0700 |
commit | cfeed110492cc53da67f99e51f9268567556c428 (patch) | |
tree | db4f90dc30a6f3f374078ab86dfead3c99838da9 /src/sys/socket.rs | |
parent | 74d49ab9a1d03787544b4a9d8d7e1b2828577bff (diff) | |
download | nix-cfeed110492cc53da67f99e51f9268567556c428.zip |
Tweaks + fix accept4
Diffstat (limited to 'src/sys/socket.rs')
-rw-r--r-- | src/sys/socket.rs | 72 |
1 files changed, 60 insertions, 12 deletions
diff --git a/src/sys/socket.rs b/src/sys/socket.rs index e714834b..86089f1f 100644 --- a/src/sys/socket.rs +++ b/src/sys/socket.rs @@ -9,16 +9,10 @@ pub use libc::{in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, sa_family_t}; pub use self::consts::*; mod ffi { - use libc::{c_int, c_void, sockaddr, socklen_t}; + use libc::{c_int, c_void, socklen_t}; pub use libc::{socket, listen, bind, accept, connect, setsockopt}; extern { - pub fn accept4( - sockfd: c_int, - addr: *mut sockaddr, - addrlen: *mut socklen_t, - flags: c_int) -> c_int; - pub fn getsockopt( sockfd: c_int, level: c_int, @@ -169,7 +163,7 @@ mod consts { } pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> SysResult<Fd> { - let feat_atomic = features::atomic_cloexec(); // TODO: detect + let feat_atomic = features::atomic_cloexec(); if feat_atomic { ty = ty | flags.bits(); @@ -183,8 +177,13 @@ pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> SysRe } if !feat_atomic { - try!(fcntl(res, F_SETFD(FD_CLOEXEC))); - try!(fcntl(res, F_SETFL(O_NONBLOCK))); + if flags.contains(SOCK_CLOEXEC) { + try!(fcntl(res, F_SETFD(FD_CLOEXEC))); + } + + if flags.contains(SOCK_NONBLOCK) { + try!(fcntl(res, F_SETFL(O_NONBLOCK))); + } } Ok(res) @@ -217,17 +216,66 @@ pub fn accept(sockfd: Fd) -> SysResult<Fd> { Ok(res) } +#[cfg(target_os = "linux")] pub fn accept4(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> { - // TODO: Check the kernel version - let res = unsafe { ffi::accept4(sockfd, ptr::mut_null(), ptr::mut_null(), flags.bits) }; + use libc::sockaddr; + + type F = unsafe extern "C" fn(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int; + + extern { + #[linkage = "extern_weak"] + static accept4: *const (); + } + + let feat_atomic = !accept4.is_null(); + + let res = if feat_atomic { + unsafe { + mem::transmute::<*const (), F>(accept4)( + sockfd, ptr::mut_null(), ptr::mut_null(), flags.bits) + } + } else { + unsafe { ffi::accept(sockfd, ptr::mut_null(), ptr::mut_null()) } + }; + + if res < 0 { + return Err(SysError::last()); + } + + if !feat_atomic { + if flags.contains(SOCK_CLOEXEC) { + try!(fcntl(res, F_SETFD(FD_CLOEXEC))); + } + + if flags.contains(SOCK_NONBLOCK) { + try!(fcntl(res, F_SETFL(O_NONBLOCK))); + } + } + + Ok(res) +} + +#[cfg(target_os = "macos")] +#[cfg(target_os = "ios")] +pub fn accept4(sockfd: Fd, flags: SockFlag) -> SysResult<Fd> { + let res = unsafe { ffi::accept(sockfd, ptr::mut_null(), ptr::mut_null()) }; if res < 0 { return Err(SysError::last()); } + if flags.contains(SOCK_CLOEXEC) { + try!(fcntl(res, F_SETFD(FD_CLOEXEC))); + } + + if flags.contains(SOCK_NONBLOCK) { + try!(fcntl(res, F_SETFL(O_NONBLOCK))); + } + Ok(res) } + pub fn connect(sockfd: Fd, addr: &SockAddr) -> SysResult<()> { let res = unsafe { match *addr { |