summaryrefslogtreecommitdiff
path: root/src/sys/socket.rs
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2014-08-25 14:01:28 -0700
committerCarl Lerche <me@carllerche.com>2014-08-25 14:01:28 -0700
commitcfeed110492cc53da67f99e51f9268567556c428 (patch)
treedb4f90dc30a6f3f374078ab86dfead3c99838da9 /src/sys/socket.rs
parent74d49ab9a1d03787544b4a9d8d7e1b2828577bff (diff)
downloadnix-cfeed110492cc53da67f99e51f9268567556c428.zip
Tweaks + fix accept4
Diffstat (limited to 'src/sys/socket.rs')
-rw-r--r--src/sys/socket.rs72
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 {