diff options
author | Y. T. Chung <zonyitoo@gmail.com> | 2015-06-15 14:41:48 +0800 |
---|---|---|
committer | Carl Lerche <me@carllerche.com> | 2015-06-15 12:53:32 -0700 |
commit | 30dd0717d1e0c01e3e4bfd1dbe623a4960d38397 (patch) | |
tree | b34f6abb892ec98f3ca93490992a973d5a0d004f | |
parent | 0f0d6010b3b9ff0ea764c4411b965b7c8c5c9612 (diff) | |
download | nix-30dd0717d1e0c01e3e4bfd1dbe623a4960d38397.zip |
TCP_KEEPALIVE, TCP_KEEPIDLE, split SockOpt trait
* Split SockOpt trait into GetSockOpt and SetSockOpt.
* Add support for TCP_KEEPALIVE & TCP_KEEPIDLE
-rw-r--r-- | src/sys/socket/consts.rs | 10 | ||||
-rw-r--r-- | src/sys/socket/mod.rs | 28 | ||||
-rw-r--r-- | src/sys/socket/sockopt.rs | 172 |
3 files changed, 145 insertions, 65 deletions
diff --git a/src/sys/socket/consts.rs b/src/sys/socket/consts.rs index a716b1ab..09994bda 100644 --- a/src/sys/socket/consts.rs +++ b/src/sys/socket/consts.rs @@ -6,7 +6,7 @@ pub const IPV6_DROP_MEMBERSHIP: c_int = libc::IPV6_DROP_MEMBERSHIP; #[cfg(any(target_os = "linux", target_os = "android"))] mod os { - use libc::{c_int, uint8_t}; + use libc::{self, c_int, uint8_t}; pub const AF_UNIX: c_int = 1; pub const AF_LOCAL: c_int = AF_UNIX; @@ -65,6 +65,7 @@ mod os { pub const TCP_NODELAY: c_int = 1; pub const TCP_MAXSEG: c_int = 2; pub const TCP_CORK: c_int = 3; + pub const TCP_KEEPIDLE: c_int = libc::TCP_KEEPIDLE; // Socket options for the IP layer of the socket pub const IP_MULTICAST_IF: c_int = 32; @@ -98,7 +99,7 @@ mod os { // Not all of these constants exist on freebsd #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "ios", target_os = "openbsd"))] mod os { - use libc::{c_int, uint8_t}; + use libc::{self, c_int, uint8_t}; pub const AF_UNIX: c_int = 1; pub const AF_LOCAL: c_int = AF_UNIX; @@ -159,6 +160,11 @@ mod os { // Socket options for TCP sockets pub const TCP_NODELAY: c_int = 1; pub const TCP_MAXSEG: c_int = 2; + #[cfg(any(target_os = "macos", + target_os = "ios"))] + pub const TCP_KEEPALIVE: c_int = libc::TCP_KEEPALIVE; + #[cfg(target_os = "freebsd")] + pub const TCP_KEEPIDLE: c_int = libc::TCP_KEEPIDLE; // Socket options for the IP layer of the socket pub const IP_MULTICAST_IF: c_int = 9; diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index dd8893d6..21a93060 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -7,7 +7,7 @@ use features; use fcntl::{fcntl, FD_CLOEXEC, O_NONBLOCK}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; use libc::{c_void, c_int, socklen_t, size_t}; -use std::{fmt, mem, ptr}; +use std::{mem, ptr}; use std::os::unix::io::RawFd; mod addr; @@ -271,7 +271,7 @@ pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: SockMessageFlags) - } } -/// Send data to a connection-oriented socket. Returns the number of bytes read +/// Send data to a connection-oriented socket. Returns the number of bytes read /// /// [Further reading](http://man7.org/linux/man-pages/man2/send.2.html) pub fn send(fd: RawFd, buf: &[u8], flags: SockMessageFlags) -> Result<usize> { @@ -313,29 +313,35 @@ pub enum SockLevel { } /// Represents a socket option that can be accessed or set. Used as an argument -/// to `getsockopt` and `setsockopt`. -pub trait SockOpt : Copy + fmt::Debug { +/// to `getsockopt` +pub trait GetSockOpt : Copy { type Val; #[doc(hidden)] - fn get(&self, fd: RawFd, level: c_int) -> Result<Self::Val>; + fn get(&self, fd: RawFd) -> Result<Self::Val>; +} + +/// Represents a socket option that can be accessed or set. Used as an argument +/// to `setsockopt` +pub trait SetSockOpt : Copy { + type Val; #[doc(hidden)] - fn set(&self, fd: RawFd, level: c_int, val: &Self::Val) -> Result<()>; + fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>; } /// Get the current value for the requested socket option /// -/// [Further reading](http://man7.org/linux/man-pages/man2/setsockopt.2.html) -pub fn getsockopt<O: SockOpt>(fd: RawFd, level: SockLevel, opt: O) -> Result<O::Val> { - opt.get(fd, level as c_int) +/// [Further reading](http://man7.org/linux/man-pages/man2/getsockopt.2.html) +pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> { + opt.get(fd) } /// Sets the value for the requested socket option /// /// [Further reading](http://man7.org/linux/man-pages/man2/setsockopt.2.html) -pub fn setsockopt<O: SockOpt>(fd: RawFd, level: SockLevel, opt: O, val: &O::Val) -> Result<()> { - opt.set(fd, level as c_int, val) +pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> { + opt.set(fd, val) } /// Get the address of the peer connected to the socket `fd`. diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs index 83aec5cb..13e87476 100644 --- a/src/sys/socket/sockopt.rs +++ b/src/sys/socket/sockopt.rs @@ -1,42 +1,42 @@ use {Result, Error, from_ffi}; -use super::{ffi, consts, SockOpt}; +use super::{ffi, consts, GetSockOpt, SetSockOpt}; use errno::Errno; use sys::time::TimeVal; use libc::{c_int, uint8_t, c_void, socklen_t}; use std::mem; use std::os::unix::io::RawFd; -// Helper to generate the sockopt accessors -// TODO: Figure out how to ommit gets when not supported by opt -macro_rules! sockopt_impl { - ($name:ident, $flag:path, bool) => { - sockopt_impl!($name, $flag, bool, GetBool, SetBool); - }; - - ($name:ident, $flag:path, u8) => { - sockopt_impl!($name, $flag, u8, GetU8, SetU8); - }; +macro_rules! setsockopt_impl { + ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => { + impl SetSockOpt for $name { + type Val = $ty; - ($name:ident, $flag:path, $ty:ty) => { - sockopt_impl!($name, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>); - }; + fn set(&self, fd: RawFd, val: &$ty) -> Result<()> { + unsafe { + let setter: $setter = Set::new(val); - ($name:ident, $flag:path, $ty:ty, $getter:ty, $setter:ty) => { - #[derive(Clone, Copy, Debug)] - pub struct $name; + let res = ffi::setsockopt(fd, $level, $flag, + setter.ffi_ptr(), + setter.ffi_len()); + from_ffi(res) + } + } + } + } +} - impl SockOpt for $name { +macro_rules! getsockopt_impl { + ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => { + impl GetSockOpt for $name { type Val = $ty; - fn get(&self, fd: RawFd, level: c_int) -> Result<$ty> { + fn get(&self, fd: RawFd) -> Result<$ty> { unsafe { let mut getter: $getter = Get::blank(); - let res = ffi::getsockopt( - fd, level, $flag, - getter.ffi_ptr(), - getter.ffi_len()); - + let res = ffi::getsockopt(fd, $level, $flag, + getter.ffi_ptr(), + getter.ffi_len()); if res < 0 { return Err(Error::Sys(Errno::last())); } @@ -44,20 +44,68 @@ macro_rules! sockopt_impl { Ok(getter.unwrap()) } } + } + } +} - fn set(&self, fd: RawFd, level: c_int, val: &$ty) -> Result<()> { - unsafe { - let setter: $setter = Set::new(val); +// Helper to generate the sockopt accessors +macro_rules! sockopt_impl { + (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => { + sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>); + }; - let res = ffi::setsockopt( - fd, level, $flag, - setter.ffi_ptr(), - setter.ffi_len()); + (GetOnly, $name:ident, $level:path, $flag:path, bool) => { + sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool); + }; - from_ffi(res) - } - } - } + (GetOnly, $name:ident, $level:path, $flag:path, u8) => { + sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8); + }; + + (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => { + #[derive(Copy, Clone, Debug)] + pub struct $name; + + getsockopt_impl!($name, $level, $flag, $ty, $getter); + }; + + (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => { + sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>); + }; + + (SetOnly, $name:ident, $level:path, $flag:path, bool) => { + sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool); + }; + + (SetOnly, $name:ident, $level:path, $flag:path, u8) => { + sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8); + }; + + (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => { + #[derive(Copy, Clone, Debug)] + pub struct $name; + + setsockopt_impl!($name, $level, $flag, $ty, $setter); + }; + + (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => { + #[derive(Copy, Clone, Debug)] + pub struct $name; + + setsockopt_impl!($name, $level, $flag, $ty, $setter); + getsockopt_impl!($name, $level, $flag, $ty, $getter); + }; + + (Both, $name:ident, $level:path, $flag:path, bool) => { + sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool); + }; + + (Both, $name:ident, $level:path, $flag:path, u8) => { + sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8); + }; + + (Both, $name:ident, $level:path, $flag:path, $ty:ty) => { + sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>); }; } @@ -67,20 +115,31 @@ macro_rules! sockopt_impl { * */ -sockopt_impl!(ReuseAddr, consts::SO_REUSEADDR, bool); -sockopt_impl!(ReusePort, consts::SO_REUSEPORT, bool); -sockopt_impl!(TcpNoDelay, consts::TCP_NODELAY, bool); -sockopt_impl!(Linger, consts::SO_LINGER, super::linger); -sockopt_impl!(IpAddMembership, consts::IP_ADD_MEMBERSHIP, super::ip_mreq); -sockopt_impl!(IpDropMembership, consts::IP_DROP_MEMBERSHIP, super::ip_mreq); -sockopt_impl!(Ipv6AddMembership, consts::IPV6_ADD_MEMBERSHIP, super::ipv6_mreq); -sockopt_impl!(Ipv6DropMembership, consts::IPV6_DROP_MEMBERSHIP, super::ipv6_mreq); -sockopt_impl!(IpMulticastTtl, consts::IP_MULTICAST_TTL, u8); -sockopt_impl!(IpMulticastLoop, consts::IP_MULTICAST_LOOP, bool); -sockopt_impl!(ReceiveTimeout, consts::SO_RCVTIMEO, TimeVal); -sockopt_impl!(SendTimeout, consts::SO_SNDTIMEO, TimeVal); -sockopt_impl!(Broadcast, consts::SO_BROADCAST, bool); -sockopt_impl!(OobInline, consts::SO_OOBINLINE, bool); +sockopt_impl!(Both, ReuseAddr, consts::SOL_SOCKET, consts::SO_REUSEADDR, bool); +sockopt_impl!(Both, ReusePort, consts::SOL_SOCKET, consts::SO_REUSEPORT, bool); +sockopt_impl!(Both, TcpNoDelay, consts::SOL_SOCKET, consts::TCP_NODELAY, bool); +sockopt_impl!(Both, Linger, consts::SOL_SOCKET, consts::SO_LINGER, super::linger); +sockopt_impl!(SetOnly, IpAddMembership, consts::IPPROTO_IP, consts::IP_ADD_MEMBERSHIP, super::ip_mreq); +sockopt_impl!(SetOnly, IpDropMembership, consts::IPPROTO_IP, consts::IP_DROP_MEMBERSHIP, super::ip_mreq); +sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_ADD_MEMBERSHIP, super::ipv6_mreq); +sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_DROP_MEMBERSHIP, super::ipv6_mreq); +sockopt_impl!(Both, IpMulticastTtl, consts::IPPROTO_IP, consts::IP_MULTICAST_TTL, u8); +sockopt_impl!(Both, IpMulticastLoop, consts::IPPROTO_IP, consts::IP_MULTICAST_LOOP, bool); +sockopt_impl!(Both, ReceiveTimeout, consts::SOL_SOCKET, consts::SO_RCVTIMEO, TimeVal); +sockopt_impl!(Both, SendTimeout, consts::SOL_SOCKET, consts::SO_SNDTIMEO, TimeVal); +sockopt_impl!(Both, Broadcast, consts::SOL_SOCKET, consts::SO_BROADCAST, bool); +sockopt_impl!(Both, OobInline, consts::SOL_SOCKET, consts::SO_OOBINLINE, bool); +sockopt_impl!(GetOnly, SocketError, consts::SOL_SOCKET, consts::SO_ERROR, i32); +sockopt_impl!(Both, KeepAlive, consts::SOL_SOCKET, consts::SO_KEEPALIVE, bool); +#[cfg(any(target_os = "macos", + target_os = "ios"))] +sockopt_impl!(Both, TcpKeepAlive, consts::IPPROTO_TCP, consts::TCP_KEEPALIVE, u32); +#[cfg(any(target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux", + target_os = "android", + target_os = "nacl"))] +sockopt_impl!(Both, TcpKeepIdle, consts::IPPROTO_TCP, consts::TCP_KEEPIDLE, u32); /* * @@ -108,7 +167,10 @@ struct GetStruct<T> { impl<T> Get<T> for GetStruct<T> { unsafe fn blank() -> Self { - mem::zeroed() + GetStruct { + len: mem::size_of::<T>() as socklen_t, + val: mem::zeroed(), + } } unsafe fn ffi_ptr(&mut self) -> *mut c_void { @@ -150,7 +212,10 @@ struct GetBool { impl Get<bool> for GetBool { unsafe fn blank() -> Self { - mem::zeroed() + GetBool { + len: mem::size_of::<c_int>() as socklen_t, + val: mem::zeroed(), + } } unsafe fn ffi_ptr(&mut self) -> *mut c_void { @@ -192,7 +257,10 @@ struct GetU8 { impl Get<u8> for GetU8 { unsafe fn blank() -> Self { - mem::zeroed() + GetU8 { + len: mem::size_of::<uint8_t>() as socklen_t, + val: mem::zeroed(), + } } unsafe fn ffi_ptr(&mut self) -> *mut c_void { |