diff options
-rw-r--r-- | src/sys/socket/consts.rs | 203 | ||||
-rw-r--r-- | src/sys/socket/mod.rs | 71 | ||||
-rw-r--r-- | src/sys/socket/sockopt.rs | 220 |
3 files changed, 369 insertions, 125 deletions
diff --git a/src/sys/socket/consts.rs b/src/sys/socket/consts.rs index e23098b6..39bcd733 100644 --- a/src/sys/socket/consts.rs +++ b/src/sys/socket/consts.rs @@ -19,64 +19,62 @@ mod os { pub const SOCK_RAW: SockType = 3; pub const SOCK_RDM: SockType = 4; - pub type SockLevel = c_int; - - pub const SOL_IP: SockLevel = 0; - pub const IPPROTO_IP: SockLevel = SOL_IP; - pub const SOL_SOCKET: SockLevel = 1; - pub const SOL_TCP: SockLevel = 6; - pub const IPPROTO_TCP: SockLevel = SOL_TCP; - pub const SOL_UDP: SockLevel = 17; - pub const SOL_IPV6: SockLevel = 41; - - pub type SockOpt = c_int; - - pub const SO_ACCEPTCONN: SockOpt = 30; - pub const SO_BINDTODEVICE: SockOpt = 25; - pub const SO_BROADCAST: SockOpt = 6; - pub const SO_BSDCOMPAT: SockOpt = 14; - pub const SO_DEBUG: SockOpt = 1; - pub const SO_DOMAIN: SockOpt = 39; - pub const SO_ERROR: SockOpt = 4; - pub const SO_DONTROUTE: SockOpt = 5; - pub const SO_KEEPALIVE: SockOpt = 9; - pub const SO_LINGER: SockOpt = 13; - pub const SO_MARK: SockOpt = 36; - pub const SO_OOBINLINE: SockOpt = 10; - pub const SO_PASSCRED: SockOpt = 16; - pub const SO_PEEK_OFF: SockOpt = 42; - pub const SO_PEERCRED: SockOpt = 17; - pub const SO_PRIORITY: SockOpt = 12; - pub const SO_PROTOCOL: SockOpt = 38; - pub const SO_RCVBUF: SockOpt = 8; - pub const SO_RCVBUFFORCE: SockOpt = 33; - pub const SO_RCVLOWAT: SockOpt = 18; - pub const SO_SNDLOWAT: SockOpt = 19; - pub const SO_RCVTIMEO: SockOpt = 20; - pub const SO_SNDTIMEO: SockOpt = 21; - pub const SO_REUSEADDR: SockOpt = 2; - pub const SO_REUSEPORT: SockOpt = 15; - pub const SO_RXQ_OVFL: SockOpt = 40; - pub const SO_SNDBUF: SockOpt = 7; - pub const SO_SNDBUFFORCE: SockOpt = 32; - pub const SO_TIMESTAMP: SockOpt = 29; - pub const SO_TYPE: SockOpt = 3; - pub const SO_BUSY_POLL: SockOpt = 46; + pub const SOL_IP: c_int = 0; + pub const SOL_SOCKET: c_int = 1; + pub const SOL_TCP: c_int = 6; + pub const SOL_UDP: c_int = 17; + pub const SOL_IPV6: c_int = 41; + pub const IPPROTO_IP: c_int = SOL_IP; + pub const IPPROTO_IPV6: c_int = SOL_IPV6; + pub const IPPROTO_TCP: c_int = SOL_TCP; + pub const IPPROTO_UDP: c_int = SOL_UDP; + + pub const SO_ACCEPTCONN: c_int = 30; + pub const SO_BINDTODEVICE: c_int = 25; + pub const SO_BROADCAST: c_int = 6; + pub const SO_BSDCOMPAT: c_int = 14; + pub const SO_DEBUG: c_int = 1; + pub const SO_DOMAIN: c_int = 39; + pub const SO_ERROR: c_int = 4; + pub const SO_DONTROUTE: c_int = 5; + pub const SO_KEEPALIVE: c_int = 9; + pub const SO_LINGER: c_int = 13; + pub const SO_MARK: c_int = 36; + pub const SO_OOBINLINE: c_int = 10; + pub const SO_PASSCRED: c_int = 16; + pub const SO_PEEK_OFF: c_int = 42; + pub const SO_PEERCRED: c_int = 17; + pub const SO_PRIORITY: c_int = 12; + pub const SO_PROTOCOL: c_int = 38; + pub const SO_RCVBUF: c_int = 8; + pub const SO_RCVBUFFORCE: c_int = 33; + pub const SO_RCVLOWAT: c_int = 18; + pub const SO_SNDLOWAT: c_int = 19; + pub const SO_RCVTIMEO: c_int = 20; + pub const SO_SNDTIMEO: c_int = 21; + pub const SO_REUSEADDR: c_int = 2; + pub const SO_REUSEPORT: c_int = 15; + pub const SO_RXQ_OVFL: c_int = 40; + pub const SO_SNDBUF: c_int = 7; + pub const SO_SNDBUFFORCE: c_int = 32; + pub const SO_TIMESTAMP: c_int = 29; + pub const SO_TYPE: c_int = 3; + pub const SO_BUSY_POLL: c_int = 46; // Socket options for TCP sockets - pub const TCP_NODELAY: SockOpt = 1; - pub const TCP_MAXSEG: SockOpt = 2; - pub const TCP_CORK: SockOpt = 3; + pub const TCP_NODELAY: c_int = 1; + pub const TCP_MAXSEG: c_int = 2; + pub const TCP_CORK: c_int = 3; // Socket options for the IP layer of the socket - pub const IP_MULTICAST_IF: SockOpt = 32; + pub const IP_MULTICAST_IF: c_int = 32; pub type IpMulticastTtl = uint8_t; - pub const IP_MULTICAST_TTL: SockOpt = 33; - pub const IP_MULTICAST_LOOP: SockOpt = 34; - pub const IP_ADD_MEMBERSHIP: SockOpt = 35; - pub const IP_DROP_MEMBERSHIP: SockOpt = 36; + pub const IP_MULTICAST_TTL: c_int = 33; + pub const IP_MULTICAST_LOOP: c_int = 34; + pub const IP_ADD_MEMBERSHIP: c_int = 35; + pub const IP_DROP_MEMBERSHIP: c_int = 36; pub type InAddrT = u32; @@ -111,67 +109,64 @@ mod os { pub const SOCK_RAW: SockType = 3; pub const SOCK_RDM: SockType = 4; - pub type SockLevel = c_int; - - pub const SOL_SOCKET: SockLevel = 0xffff; - pub const IPPROTO_IP: SockLevel = 0; - pub const IPPROTO_TCP: SockLevel = 6; - pub const IPPROTO_UDP: SockLevel = 17; - - pub type SockOpt = c_int; - - pub const SO_ACCEPTCONN: SockOpt = 0x0002; - pub const SO_BROADCAST: SockOpt = 0x0020; - pub const SO_DEBUG: SockOpt = 0x0001; - pub const SO_DONTTRUNC: SockOpt = 0x2000; - pub const SO_ERROR: SockOpt = 0x1007; - pub const SO_DONTROUTE: SockOpt = 0x0010; - pub const SO_KEEPALIVE: SockOpt = 0x0008; - pub const SO_LABEL: SockOpt = 0x1010; - pub const SO_LINGER: SockOpt = 0x0080; - pub const SO_NREAD: SockOpt = 0x1020; - pub const SO_NKE: SockOpt = 0x1021; - pub const SO_NOSIGPIPE: SockOpt = 0x1022; - pub const SO_NOADDRERR: SockOpt = 0x1023; - pub const SO_NOTIFYCONFLICT: SockOpt = 0x1026; - pub const SO_NP_EXTENSIONS: SockOpt = 0x1083; - pub const SO_NWRITE: SockOpt = 0x1024; - pub const SO_OOBINLINE: SockOpt = 0x0100; - pub const SO_PEERLABEL: SockOpt = 0x1011; - pub const SO_RCVBUF: SockOpt = 0x1002; - pub const SO_RCVLOWAT: SockOpt = 0x1004; - pub const SO_SNDLOWAT: SockOpt = 0x1003; - pub const SO_RCVTIMEO: SockOpt = 0x1006; - pub const SO_SNDTIMEO: SockOpt = 0x1005; - pub const SO_RANDOMPORT: SockOpt = 0x1082; - pub const SO_RESTRICTIONS: SockOpt = 0x1081; - pub const SO_RESTRICT_DENYIN: SockOpt = 0x00000001; - pub const SO_RESTRICT_DENYOUT: SockOpt = 0x00000002; - pub const SO_REUSEADDR: SockOpt = 0x0004; - pub const SO_REUSEPORT: SockOpt = 0x0200; - pub const SO_REUSESHAREUID: SockOpt = 0x1025; - pub const SO_SNDBUF: SockOpt = 0x1001; - pub const SO_TIMESTAMP: SockOpt = 0x0400; - pub const SO_TIMESTAMP_MONOTONIC: SockOpt = 0x0800; - pub const SO_TYPE: SockOpt = 0x1008; - pub const SO_WANTMORE: SockOpt = 0x4000; - pub const SO_WANTOOBFLAG: SockOpt = 0x8000; + pub const SOL_SOCKET: c_int = 0xffff; + pub const IPPROTO_IP: c_int = 0; + pub const IPPROTO_IPV6: c_int = 41; + pub const IPPROTO_TCP: c_int = 6; + pub const IPPROTO_UDP: c_int = 17; + + pub const SO_ACCEPTCONN: c_int = 0x0002; + pub const SO_BROADCAST: c_int = 0x0020; + pub const SO_DEBUG: c_int = 0x0001; + pub const SO_DONTTRUNC: c_int = 0x2000; + pub const SO_ERROR: c_int = 0x1007; + pub const SO_DONTROUTE: c_int = 0x0010; + pub const SO_KEEPALIVE: c_int = 0x0008; + pub const SO_LABEL: c_int = 0x1010; + pub const SO_LINGER: c_int = 0x0080; + pub const SO_NREAD: c_int = 0x1020; + pub const SO_NKE: c_int = 0x1021; + pub const SO_NOSIGPIPE: c_int = 0x1022; + pub const SO_NOADDRERR: c_int = 0x1023; + pub const SO_NOTIFYCONFLICT: c_int = 0x1026; + pub const SO_NP_EXTENSIONS: c_int = 0x1083; + pub const SO_NWRITE: c_int = 0x1024; + pub const SO_OOBINLINE: c_int = 0x0100; + pub const SO_PEERLABEL: c_int = 0x1011; + pub const SO_RCVBUF: c_int = 0x1002; + pub const SO_RCVLOWAT: c_int = 0x1004; + pub const SO_SNDLOWAT: c_int = 0x1003; + pub const SO_RCVTIMEO: c_int = 0x1006; + pub const SO_SNDTIMEO: c_int = 0x1005; + pub const SO_RANDOMPORT: c_int = 0x1082; + pub const SO_RESTRICTIONS: c_int = 0x1081; + pub const SO_RESTRICT_DENYIN: c_int = 0x00000001; + pub const SO_RESTRICT_DENYOUT: c_int = 0x00000002; + pub const SO_REUSEADDR: c_int = 0x0004; + pub const SO_REUSEPORT: c_int = 0x0200; + pub const SO_REUSESHAREUID: c_int = 0x1025; + pub const SO_SNDBUF: c_int = 0x1001; + pub const SO_TIMESTAMP: c_int = 0x0400; + pub const SO_TIMESTAMP_MONOTONIC: c_int = 0x0800; + pub const SO_TYPE: c_int = 0x1008; + pub const SO_WANTMORE: c_int = 0x4000; + pub const SO_WANTOOBFLAG: c_int = 0x8000; #[allow(overflowing_literals)] - pub const SO_RESTRICT_DENYSET: SockOpt = 0x80000000; + pub const SO_RESTRICT_DENYSET: c_int = 0x80000000; // Socket options for TCP sockets - pub const TCP_NODELAY: SockOpt = 1; - pub const TCP_MAXSEG: SockOpt = 2; + pub const TCP_NODELAY: c_int = 1; + pub const TCP_MAXSEG: c_int = 2; // Socket options for the IP layer of the socket - pub const IP_MULTICAST_IF: SockOpt = 9; + pub const IP_MULTICAST_IF: c_int = 9; pub type IpMulticastTtl = uint8_t; - pub const IP_MULTICAST_TTL: SockOpt = 10; - pub const IP_MULTICAST_LOOP: SockOpt = 11; - pub const IP_ADD_MEMBERSHIP: SockOpt = 12; - pub const IP_DROP_MEMBERSHIP: SockOpt = 13; + pub const IP_MULTICAST_TTL: c_int = 10; + pub const IP_MULTICAST_LOOP: c_int = 11; + pub const IP_ADD_MEMBERSHIP: c_int = 12; + pub const IP_DROP_MEMBERSHIP: c_int = 13; pub type InAddrT = u32; diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 7e8afbfd..046df007 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -10,6 +10,7 @@ use std::os::unix::prelude::*; mod addr; mod consts; mod ffi; +pub mod sockopt; /* * @@ -264,34 +265,62 @@ pub struct linger { pub l_linger: c_int } -pub fn getsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &mut T) -> NixResult<usize> { - let mut len = mem::size_of::<T>() as socklen_t; +/* + * + * ===== Socket Options ===== + * + */ - let res = unsafe { - ffi::getsockopt( - fd, level, opt, - mem::transmute(val), - &mut len as *mut socklen_t) - }; +/// Represents a socket option that can be accessed or set +pub trait SockOpt : Copy + fmt::Debug { + /// Type of `getsockopt` return value + type Get; - if res < 0 { - return Err(NixError::Sys(Errno::last())); - } + /// Type of value used to set the socket option. Used as the argument to + /// `setsockopt`. + type Set; - Ok(len as usize) + #[doc(hidden)] + fn get(&self, fd: Fd, level: c_int) -> NixResult<Self::Get>; + + #[doc(hidden)] + fn set(&self, fd: Fd, level: c_int, val: Self::Set) -> NixResult<()>; } -pub fn setsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &T) -> NixResult<()> { - let len = mem::size_of::<T>() as socklen_t; +pub enum SockLevel { + Socket, + Tcp, + Ip, + Ipv6, + Udp +} - let res = unsafe { - ffi::setsockopt( - fd, level, opt, - mem::transmute(val), - len) - }; +impl SockLevel { + fn as_cint(&self) -> c_int { + use self::SockLevel::*; - from_ffi(res) + match *self { + Socket => consts::SOL_SOCKET, + Tcp => consts::IPPROTO_TCP, + Ip => consts::IPPROTO_IP, + Ipv6 => consts::IPPROTO_IPV6, + Udp => consts::IPPROTO_UDP, + } + } +} + +/// 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: Fd, level: SockLevel, opt: O) -> NixResult<O::Get> { + opt.get(fd, level.as_cint()) +} + +/// 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: Fd, level: SockLevel, opt: O, val: O::Set) -> NixResult<()> { + opt.set(fd, level.as_cint(), val) } fn getpeername_sockaddr<T>(sockfd: Fd, addr: &T) -> NixResult<bool> { diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs new file mode 100644 index 00000000..79c1800e --- /dev/null +++ b/src/sys/socket/sockopt.rs @@ -0,0 +1,220 @@ +use {NixResult, NixError, from_ffi}; +use super::{ffi, consts, SockOpt}; +use errno::Errno; +use libc::{c_int, uint8_t, c_void, socklen_t}; +use std::mem; +use std::os::unix::Fd; + +// 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, bool, SetBool); + }; + + ($name:ident, $flag:path, u8) => { + sockopt_impl!($name, $flag, u8, GetU8, u8, SetU8); + }; + + ($name:ident, $flag:path, $ty:ty) => { + sockopt_impl!($name, $flag, $ty, GetStruct<$ty>, &'a $ty, SetStruct<$ty>); + }; + + ($name:ident, $flag:path, $get_ty:ty, $getter:ty, $set_ty:ty, $setter:ty) => { + #[derive(Copy, Debug)] + pub struct $name; + + impl<'a> SockOpt for $name { + type Get = $get_ty; + type Set = $set_ty; + + fn get(&self, fd: Fd, level: c_int) -> NixResult<$get_ty> { + unsafe { + let mut getter: $getter = Get::blank(); + + let res = ffi::getsockopt( + fd, level, $flag, + getter.ffi_ptr(), + getter.ffi_len()); + + if res < 0 { + return Err(NixError::Sys(Errno::last())); + } + + Ok(getter.unwrap()) + } + } + + fn set(&self, fd: Fd, level: c_int, val: $set_ty) -> NixResult<()> { + unsafe { + let setter: $setter = Set::new(val); + + let res = ffi::setsockopt( + fd, level, $flag, + setter.ffi_ptr(), + setter.ffi_len()); + + from_ffi(res) + } + } + } + }; +} + +/* + * + * ===== Define sockopts ===== + * + */ + +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!(IpMulticastTtl, consts::IP_MULTICAST_TTL, u8); + +/* + * + * ===== Accessor helpers ===== + * + */ + +trait Get<T> { + unsafe fn blank() -> Self; + unsafe fn ffi_ptr(&mut self) -> *mut c_void; + unsafe fn ffi_len(&mut self) -> *mut socklen_t; + unsafe fn unwrap(self) -> T; +} + +trait Set<T> { + fn new(val: T) -> Self; + unsafe fn ffi_ptr(&self) -> *const c_void; + unsafe fn ffi_len(&self) -> socklen_t; +} + +struct GetStruct<T> { + len: socklen_t, + val: T, +} + +impl<T> Get<T> for GetStruct<T> { + unsafe fn blank() -> Self { + mem::zeroed() + } + + unsafe fn ffi_ptr(&mut self) -> *mut c_void { + mem::transmute(&mut self.val) + } + + unsafe fn ffi_len(&mut self) -> *mut socklen_t { + mem::transmute(&mut self.len) + } + + unsafe fn unwrap(self) -> T { + assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation"); + self.val + } +} + +struct SetStruct<'a, T: 'static> { + ptr: &'a T, +} + +impl<'a, T> Set<&'a T> for SetStruct<'a, T> { + fn new(ptr: &'a T) -> SetStruct<'a, T> { + SetStruct { ptr: ptr } + } + + unsafe fn ffi_ptr(&self) -> *const c_void { + mem::transmute(self.ptr) + } + + unsafe fn ffi_len(&self) -> socklen_t { + mem::size_of::<T>() as socklen_t + } +} + +struct GetBool { + len: socklen_t, + val: c_int, +} + +impl Get<bool> for GetBool { + unsafe fn blank() -> Self { + mem::zeroed() + } + + unsafe fn ffi_ptr(&mut self) -> *mut c_void { + mem::transmute(&mut self.val) + } + + unsafe fn ffi_len(&mut self) -> *mut socklen_t { + mem::transmute(&mut self.len) + } + + unsafe fn unwrap(self) -> bool { + assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation"); + self.val != 0 + } +} + +struct SetBool { + val: c_int, +} + +impl Set<bool> for SetBool { + fn new(val: bool) -> SetBool { + SetBool { val: if val { 1 } else { 0 } } + } + + unsafe fn ffi_ptr(&self) -> *const c_void { + mem::transmute(&self.val) + } + + unsafe fn ffi_len(&self) -> socklen_t { + mem::size_of::<c_int>() as socklen_t + } +} + +struct GetU8 { + len: socklen_t, + val: uint8_t, +} + +impl Get<u8> for GetU8 { + unsafe fn blank() -> Self { + mem::zeroed() + } + + unsafe fn ffi_ptr(&mut self) -> *mut c_void { + mem::transmute(&mut self.val) + } + + unsafe fn ffi_len(&mut self) -> *mut socklen_t { + mem::transmute(&mut self.len) + } + + unsafe fn unwrap(self) -> u8 { + assert!(self.len as usize == mem::size_of::<uint8_t>(), "invalid getsockopt implementation"); + self.val as u8 + } +} + +struct SetU8 { + val: uint8_t, +} + +impl Set<u8> for SetU8 { + fn new(val: u8) -> SetU8 { + SetU8 { val: val as uint8_t } + } + + unsafe fn ffi_ptr(&self) -> *const c_void { + mem::transmute(&self.val) + } + + unsafe fn ffi_len(&self) -> socklen_t { + mem::size_of::<c_int>() as socklen_t + } +} |