Skip to content

Commit 30dd071

Browse files
zonyitoocarllerche
authored andcommitted
TCP_KEEPALIVE, TCP_KEEPIDLE, split SockOpt trait
* Split SockOpt trait into GetSockOpt and SetSockOpt. * Add support for TCP_KEEPALIVE & TCP_KEEPIDLE
1 parent 0f0d601 commit 30dd071

File tree

3 files changed

+145
-65
lines changed

3 files changed

+145
-65
lines changed

src/sys/socket/consts.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub const IPV6_DROP_MEMBERSHIP: c_int = libc::IPV6_DROP_MEMBERSHIP;
66

77
#[cfg(any(target_os = "linux", target_os = "android"))]
88
mod os {
9-
use libc::{c_int, uint8_t};
9+
use libc::{self, c_int, uint8_t};
1010

1111
pub const AF_UNIX: c_int = 1;
1212
pub const AF_LOCAL: c_int = AF_UNIX;
@@ -65,6 +65,7 @@ mod os {
6565
pub const TCP_NODELAY: c_int = 1;
6666
pub const TCP_MAXSEG: c_int = 2;
6767
pub const TCP_CORK: c_int = 3;
68+
pub const TCP_KEEPIDLE: c_int = libc::TCP_KEEPIDLE;
6869

6970
// Socket options for the IP layer of the socket
7071
pub const IP_MULTICAST_IF: c_int = 32;
@@ -98,7 +99,7 @@ mod os {
9899
// Not all of these constants exist on freebsd
99100
#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "ios", target_os = "openbsd"))]
100101
mod os {
101-
use libc::{c_int, uint8_t};
102+
use libc::{self, c_int, uint8_t};
102103

103104
pub const AF_UNIX: c_int = 1;
104105
pub const AF_LOCAL: c_int = AF_UNIX;
@@ -159,6 +160,11 @@ mod os {
159160
// Socket options for TCP sockets
160161
pub const TCP_NODELAY: c_int = 1;
161162
pub const TCP_MAXSEG: c_int = 2;
163+
#[cfg(any(target_os = "macos",
164+
target_os = "ios"))]
165+
pub const TCP_KEEPALIVE: c_int = libc::TCP_KEEPALIVE;
166+
#[cfg(target_os = "freebsd")]
167+
pub const TCP_KEEPIDLE: c_int = libc::TCP_KEEPIDLE;
162168

163169
// Socket options for the IP layer of the socket
164170
pub const IP_MULTICAST_IF: c_int = 9;

src/sys/socket/mod.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use features;
77
use fcntl::{fcntl, FD_CLOEXEC, O_NONBLOCK};
88
use fcntl::FcntlArg::{F_SETFD, F_SETFL};
99
use libc::{c_void, c_int, socklen_t, size_t};
10-
use std::{fmt, mem, ptr};
10+
use std::{mem, ptr};
1111
use std::os::unix::io::RawFd;
1212

1313
mod addr;
@@ -271,7 +271,7 @@ pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: SockMessageFlags) -
271271
}
272272
}
273273

274-
/// Send data to a connection-oriented socket. Returns the number of bytes read
274+
/// Send data to a connection-oriented socket. Returns the number of bytes read
275275
///
276276
/// [Further reading](http://man7.org/linux/man-pages/man2/send.2.html)
277277
pub fn send(fd: RawFd, buf: &[u8], flags: SockMessageFlags) -> Result<usize> {
@@ -313,29 +313,35 @@ pub enum SockLevel {
313313
}
314314

315315
/// Represents a socket option that can be accessed or set. Used as an argument
316-
/// to `getsockopt` and `setsockopt`.
317-
pub trait SockOpt : Copy + fmt::Debug {
316+
/// to `getsockopt`
317+
pub trait GetSockOpt : Copy {
318318
type Val;
319319

320320
#[doc(hidden)]
321-
fn get(&self, fd: RawFd, level: c_int) -> Result<Self::Val>;
321+
fn get(&self, fd: RawFd) -> Result<Self::Val>;
322+
}
323+
324+
/// Represents a socket option that can be accessed or set. Used as an argument
325+
/// to `setsockopt`
326+
pub trait SetSockOpt : Copy {
327+
type Val;
322328

323329
#[doc(hidden)]
324-
fn set(&self, fd: RawFd, level: c_int, val: &Self::Val) -> Result<()>;
330+
fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
325331
}
326332

327333
/// Get the current value for the requested socket option
328334
///
329-
/// [Further reading](http://man7.org/linux/man-pages/man2/setsockopt.2.html)
330-
pub fn getsockopt<O: SockOpt>(fd: RawFd, level: SockLevel, opt: O) -> Result<O::Val> {
331-
opt.get(fd, level as c_int)
335+
/// [Further reading](http://man7.org/linux/man-pages/man2/getsockopt.2.html)
336+
pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
337+
opt.get(fd)
332338
}
333339

334340
/// Sets the value for the requested socket option
335341
///
336342
/// [Further reading](http://man7.org/linux/man-pages/man2/setsockopt.2.html)
337-
pub fn setsockopt<O: SockOpt>(fd: RawFd, level: SockLevel, opt: O, val: &O::Val) -> Result<()> {
338-
opt.set(fd, level as c_int, val)
343+
pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
344+
opt.set(fd, val)
339345
}
340346

341347
/// Get the address of the peer connected to the socket `fd`.

src/sys/socket/sockopt.rs

Lines changed: 120 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,111 @@
11
use {Result, Error, from_ffi};
2-
use super::{ffi, consts, SockOpt};
2+
use super::{ffi, consts, GetSockOpt, SetSockOpt};
33
use errno::Errno;
44
use sys::time::TimeVal;
55
use libc::{c_int, uint8_t, c_void, socklen_t};
66
use std::mem;
77
use std::os::unix::io::RawFd;
88

9-
// Helper to generate the sockopt accessors
10-
// TODO: Figure out how to ommit gets when not supported by opt
11-
macro_rules! sockopt_impl {
12-
($name:ident, $flag:path, bool) => {
13-
sockopt_impl!($name, $flag, bool, GetBool, SetBool);
14-
};
15-
16-
($name:ident, $flag:path, u8) => {
17-
sockopt_impl!($name, $flag, u8, GetU8, SetU8);
18-
};
9+
macro_rules! setsockopt_impl {
10+
($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
11+
impl SetSockOpt for $name {
12+
type Val = $ty;
1913

20-
($name:ident, $flag:path, $ty:ty) => {
21-
sockopt_impl!($name, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
22-
};
14+
fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
15+
unsafe {
16+
let setter: $setter = Set::new(val);
2317

24-
($name:ident, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
25-
#[derive(Clone, Copy, Debug)]
26-
pub struct $name;
18+
let res = ffi::setsockopt(fd, $level, $flag,
19+
setter.ffi_ptr(),
20+
setter.ffi_len());
21+
from_ffi(res)
22+
}
23+
}
24+
}
25+
}
26+
}
2727

28-
impl SockOpt for $name {
28+
macro_rules! getsockopt_impl {
29+
($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
30+
impl GetSockOpt for $name {
2931
type Val = $ty;
3032

31-
fn get(&self, fd: RawFd, level: c_int) -> Result<$ty> {
33+
fn get(&self, fd: RawFd) -> Result<$ty> {
3234
unsafe {
3335
let mut getter: $getter = Get::blank();
3436

35-
let res = ffi::getsockopt(
36-
fd, level, $flag,
37-
getter.ffi_ptr(),
38-
getter.ffi_len());
39-
37+
let res = ffi::getsockopt(fd, $level, $flag,
38+
getter.ffi_ptr(),
39+
getter.ffi_len());
4040
if res < 0 {
4141
return Err(Error::Sys(Errno::last()));
4242
}
4343

4444
Ok(getter.unwrap())
4545
}
4646
}
47+
}
48+
}
49+
}
4750

48-
fn set(&self, fd: RawFd, level: c_int, val: &$ty) -> Result<()> {
49-
unsafe {
50-
let setter: $setter = Set::new(val);
51+
// Helper to generate the sockopt accessors
52+
macro_rules! sockopt_impl {
53+
(GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
54+
sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
55+
};
5156

52-
let res = ffi::setsockopt(
53-
fd, level, $flag,
54-
setter.ffi_ptr(),
55-
setter.ffi_len());
57+
(GetOnly, $name:ident, $level:path, $flag:path, bool) => {
58+
sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
59+
};
5660

57-
from_ffi(res)
58-
}
59-
}
60-
}
61+
(GetOnly, $name:ident, $level:path, $flag:path, u8) => {
62+
sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
63+
};
64+
65+
(GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
66+
#[derive(Copy, Clone, Debug)]
67+
pub struct $name;
68+
69+
getsockopt_impl!($name, $level, $flag, $ty, $getter);
70+
};
71+
72+
(SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
73+
sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
74+
};
75+
76+
(SetOnly, $name:ident, $level:path, $flag:path, bool) => {
77+
sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
78+
};
79+
80+
(SetOnly, $name:ident, $level:path, $flag:path, u8) => {
81+
sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
82+
};
83+
84+
(SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
85+
#[derive(Copy, Clone, Debug)]
86+
pub struct $name;
87+
88+
setsockopt_impl!($name, $level, $flag, $ty, $setter);
89+
};
90+
91+
(Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
92+
#[derive(Copy, Clone, Debug)]
93+
pub struct $name;
94+
95+
setsockopt_impl!($name, $level, $flag, $ty, $setter);
96+
getsockopt_impl!($name, $level, $flag, $ty, $getter);
97+
};
98+
99+
(Both, $name:ident, $level:path, $flag:path, bool) => {
100+
sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
101+
};
102+
103+
(Both, $name:ident, $level:path, $flag:path, u8) => {
104+
sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
105+
};
106+
107+
(Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
108+
sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
61109
};
62110
}
63111

@@ -67,20 +115,31 @@ macro_rules! sockopt_impl {
67115
*
68116
*/
69117

70-
sockopt_impl!(ReuseAddr, consts::SO_REUSEADDR, bool);
71-
sockopt_impl!(ReusePort, consts::SO_REUSEPORT, bool);
72-
sockopt_impl!(TcpNoDelay, consts::TCP_NODELAY, bool);
73-
sockopt_impl!(Linger, consts::SO_LINGER, super::linger);
74-
sockopt_impl!(IpAddMembership, consts::IP_ADD_MEMBERSHIP, super::ip_mreq);
75-
sockopt_impl!(IpDropMembership, consts::IP_DROP_MEMBERSHIP, super::ip_mreq);
76-
sockopt_impl!(Ipv6AddMembership, consts::IPV6_ADD_MEMBERSHIP, super::ipv6_mreq);
77-
sockopt_impl!(Ipv6DropMembership, consts::IPV6_DROP_MEMBERSHIP, super::ipv6_mreq);
78-
sockopt_impl!(IpMulticastTtl, consts::IP_MULTICAST_TTL, u8);
79-
sockopt_impl!(IpMulticastLoop, consts::IP_MULTICAST_LOOP, bool);
80-
sockopt_impl!(ReceiveTimeout, consts::SO_RCVTIMEO, TimeVal);
81-
sockopt_impl!(SendTimeout, consts::SO_SNDTIMEO, TimeVal);
82-
sockopt_impl!(Broadcast, consts::SO_BROADCAST, bool);
83-
sockopt_impl!(OobInline, consts::SO_OOBINLINE, bool);
118+
sockopt_impl!(Both, ReuseAddr, consts::SOL_SOCKET, consts::SO_REUSEADDR, bool);
119+
sockopt_impl!(Both, ReusePort, consts::SOL_SOCKET, consts::SO_REUSEPORT, bool);
120+
sockopt_impl!(Both, TcpNoDelay, consts::SOL_SOCKET, consts::TCP_NODELAY, bool);
121+
sockopt_impl!(Both, Linger, consts::SOL_SOCKET, consts::SO_LINGER, super::linger);
122+
sockopt_impl!(SetOnly, IpAddMembership, consts::IPPROTO_IP, consts::IP_ADD_MEMBERSHIP, super::ip_mreq);
123+
sockopt_impl!(SetOnly, IpDropMembership, consts::IPPROTO_IP, consts::IP_DROP_MEMBERSHIP, super::ip_mreq);
124+
sockopt_impl!(SetOnly, Ipv6AddMembership, consts::IPPROTO_IPV6, consts::IPV6_ADD_MEMBERSHIP, super::ipv6_mreq);
125+
sockopt_impl!(SetOnly, Ipv6DropMembership, consts::IPPROTO_IPV6, consts::IPV6_DROP_MEMBERSHIP, super::ipv6_mreq);
126+
sockopt_impl!(Both, IpMulticastTtl, consts::IPPROTO_IP, consts::IP_MULTICAST_TTL, u8);
127+
sockopt_impl!(Both, IpMulticastLoop, consts::IPPROTO_IP, consts::IP_MULTICAST_LOOP, bool);
128+
sockopt_impl!(Both, ReceiveTimeout, consts::SOL_SOCKET, consts::SO_RCVTIMEO, TimeVal);
129+
sockopt_impl!(Both, SendTimeout, consts::SOL_SOCKET, consts::SO_SNDTIMEO, TimeVal);
130+
sockopt_impl!(Both, Broadcast, consts::SOL_SOCKET, consts::SO_BROADCAST, bool);
131+
sockopt_impl!(Both, OobInline, consts::SOL_SOCKET, consts::SO_OOBINLINE, bool);
132+
sockopt_impl!(GetOnly, SocketError, consts::SOL_SOCKET, consts::SO_ERROR, i32);
133+
sockopt_impl!(Both, KeepAlive, consts::SOL_SOCKET, consts::SO_KEEPALIVE, bool);
134+
#[cfg(any(target_os = "macos",
135+
target_os = "ios"))]
136+
sockopt_impl!(Both, TcpKeepAlive, consts::IPPROTO_TCP, consts::TCP_KEEPALIVE, u32);
137+
#[cfg(any(target_os = "freebsd",
138+
target_os = "dragonfly",
139+
target_os = "linux",
140+
target_os = "android",
141+
target_os = "nacl"))]
142+
sockopt_impl!(Both, TcpKeepIdle, consts::IPPROTO_TCP, consts::TCP_KEEPIDLE, u32);
84143

85144
/*
86145
*
@@ -108,7 +167,10 @@ struct GetStruct<T> {
108167

109168
impl<T> Get<T> for GetStruct<T> {
110169
unsafe fn blank() -> Self {
111-
mem::zeroed()
170+
GetStruct {
171+
len: mem::size_of::<T>() as socklen_t,
172+
val: mem::zeroed(),
173+
}
112174
}
113175

114176
unsafe fn ffi_ptr(&mut self) -> *mut c_void {
@@ -150,7 +212,10 @@ struct GetBool {
150212

151213
impl Get<bool> for GetBool {
152214
unsafe fn blank() -> Self {
153-
mem::zeroed()
215+
GetBool {
216+
len: mem::size_of::<c_int>() as socklen_t,
217+
val: mem::zeroed(),
218+
}
154219
}
155220

156221
unsafe fn ffi_ptr(&mut self) -> *mut c_void {
@@ -192,7 +257,10 @@ struct GetU8 {
192257

193258
impl Get<u8> for GetU8 {
194259
unsafe fn blank() -> Self {
195-
mem::zeroed()
260+
GetU8 {
261+
len: mem::size_of::<uint8_t>() as socklen_t,
262+
val: mem::zeroed(),
263+
}
196264
}
197265

198266
unsafe fn ffi_ptr(&mut self) -> *mut c_void {

0 commit comments

Comments
 (0)