summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorY. T. Chung <zonyitoo@gmail.com>2015-06-15 14:41:48 +0800
committerCarl Lerche <me@carllerche.com>2015-06-15 12:53:32 -0700
commit30dd0717d1e0c01e3e4bfd1dbe623a4960d38397 (patch)
treeb34f6abb892ec98f3ca93490992a973d5a0d004f
parent0f0d6010b3b9ff0ea764c4411b965b7c8c5c9612 (diff)
downloadnix-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.rs10
-rw-r--r--src/sys/socket/mod.rs28
-rw-r--r--src/sys/socket/sockopt.rs172
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 {