summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/sys/socket.rs676
-rw-r--r--src/sys/socket/addr.rs131
-rw-r--r--src/sys/socket/consts.rs188
-rw-r--r--src/sys/socket/ffi.rs11
-rw-r--r--src/sys/socket/mod.rs346
5 files changed, 676 insertions, 676 deletions
diff --git a/src/sys/socket.rs b/src/sys/socket.rs
deleted file mode 100644
index 6450ff2c..00000000
--- a/src/sys/socket.rs
+++ /dev/null
@@ -1,676 +0,0 @@
-use {NixError, NixResult, from_ffi};
-use errno::Errno;
-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, ssize_t};
-use std::{fmt, mem, net, ptr, path};
-use std::ffi::{AsOsStr, CStr, OsStr};
-use std::os::unix::prelude::*;
-
-/*
- *
- * ===== Re-exports =====
- *
- */
-
-pub use libc::{
- in_addr,
- sockaddr,
- sockaddr_storage,
- sockaddr_in,
- sockaddr_in6,
- sockaddr_un,
- sa_family_t,
- ip_mreq
-};
-pub use self::consts::*;
-
-mod ffi {
- use libc::{c_int, c_void, socklen_t};
- pub use libc::{socket, listen, bind, accept, connect, setsockopt, sendto, recvfrom, getsockname, getpeername};
-
- extern {
- pub fn getsockopt(
- sockfd: c_int,
- level: c_int,
- optname: c_int,
- optval: *mut c_void,
- optlen: *mut socklen_t) -> c_int;
- }
-}
-
-// Extra flags - Supported by Linux 2.6.27, normalized on other platforms
-bitflags!(
- flags SockFlag: c_int {
- const SOCK_NONBLOCK = 0o0004000,
- const SOCK_CLOEXEC = 0o2000000
- }
-);
-
-/*
- *
- * ===== SockAddr =====
- *
- */
-
-/// Represents a socket address
-#[derive(Copy)]
-pub enum SockAddr {
- // TODO: Rename these variants IpV4, IpV6, Unix
- SockIpV4(sockaddr_in),
- SockIpV6(sockaddr_in6),
- SockUnix(sockaddr_un)
-}
-
-/// A trait for values which can be converted or resolved to a SockAddr.
-pub trait ToSockAddr {
- /// Converts the value to a SockAddr
- fn to_sock_addr(&self) -> NixResult<SockAddr>;
-
- /// Converts and yields the value as a SockAddr
- fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> {
- Ok(action(&try!(self.to_sock_addr())))
- }
-}
-
-impl ToSockAddr for SockAddr {
- fn to_sock_addr(&self) -> NixResult<SockAddr> {
- Ok(*self)
- }
-
- fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> {
- Ok(action(self))
- }
-}
-
-/// Convert a path into a unix domain socket address
-impl ToSockAddr for path::Path {
- fn to_sock_addr(&self) -> NixResult<SockAddr> {
- let bytes = self.as_os_str().as_bytes();
-
- Ok(SockAddr::SockUnix(unsafe {
- let mut ret = sockaddr_un {
- sun_family: AF_UNIX as sa_family_t,
- .. mem::zeroed()
- };
-
- // Make sure the destination has enough capacity
- if bytes.len() >= ret.sun_path.len() {
- return Err(NixError::Sys(Errno::ENAMETOOLONG));
- }
-
- // Copy the path
- ptr::copy_memory(
- ret.sun_path.as_mut_ptr(),
- bytes.as_ptr() as *const i8,
- bytes.len());
-
- ret
- }))
- }
-}
-
-/// Convert an inet address into a socket address
-impl ToSockAddr for net::SocketAddr {
- fn to_sock_addr(&self) -> NixResult<SockAddr> {
- use std::net::IpAddr;
- use std::num::Int;
-
- match self.ip() {
- IpAddr::V4(ip) => {
- let addr = ip.octets();
- Ok(SockAddr::SockIpV4(sockaddr_in {
- sin_family: AF_INET as sa_family_t,
- sin_port: self.port(),
- sin_addr: in_addr {
- s_addr: Int::from_be(
- ((addr[0] as u32) << 24) |
- ((addr[1] as u32) << 16) |
- ((addr[2] as u32) << 8) |
- ((addr[3] as u32) << 0))
- },
- .. unsafe { mem::zeroed() }
- }))
- }
- _ => unimplemented!()
- }
- }
-}
-
-/// Convert from a socket address
-pub trait FromSockAddr {
- fn from_sock_addr(addr: &SockAddr) -> Option<Self>;
-}
-
-impl FromSockAddr for net::SocketAddr {
- fn from_sock_addr(addr: &SockAddr) -> Option<net::SocketAddr> {
- use std::net::{IpAddr, Ipv4Addr};
- use std::num::Int;
-
- match *addr {
- SockAddr::SockIpV4(ref addr) => {
- let ip = Int::from_be(addr.sin_addr.s_addr);
- let ip = Ipv4Addr::new(
- ((ip >> 24) as u8) & 0xff,
- ((ip >> 16) as u8) & 0xff,
- ((ip >> 8) as u8) & 0xff,
- ((ip >> 0) as u8) & 0xff);
-
- Some(net::SocketAddr::new(IpAddr::V4(ip), addr.sin_port))
- }
- SockAddr::SockIpV6(_) => unimplemented!(),
- _ => None,
- }
- }
-}
-
-impl FromSockAddr for path::PathBuf {
- fn from_sock_addr(addr: &SockAddr) -> Option<path::PathBuf> {
- if let SockAddr::SockUnix(ref addr) = *addr {
- unsafe {
- let bytes = CStr::from_ptr(addr.sun_path.as_ptr()).to_bytes();
- let osstr = <OsStr as OsStrExt>::from_bytes(bytes);
- return Some(path::PathBuf::new(osstr));
- }
- }
-
- None
- }
-}
-
-/*
- *
- * ===== Consts =====
- *
- */
-
-#[cfg(target_os = "linux")]
-mod consts {
- use libc::{c_int, uint8_t};
-
- pub type AddressFamily = c_int;
-
- pub const AF_UNIX: AddressFamily = 1;
- pub const AF_LOCAL: AddressFamily = AF_UNIX;
- pub const AF_INET: AddressFamily = 2;
- pub const AF_INET6: AddressFamily = 10;
-
- pub type SockType = c_int;
-
- pub const SOCK_STREAM: SockType = 1;
- pub const SOCK_DGRAM: SockType = 2;
- pub const SOCK_SEQPACKET: SockType = 5;
- 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;
-
- // Socket options for TCP sockets
- pub const TCP_NODELAY: SockOpt = 1;
- pub const TCP_MAXSEG: SockOpt = 2;
- pub const TCP_CORK: SockOpt = 3;
-
- // Socket options for the IP layer of the socket
- pub const IP_MULTICAST_IF: SockOpt = 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 type InAddrT = u32;
-
- // Declarations of special addresses
- pub const INADDR_ANY: InAddrT = 0;
- pub const INADDR_NONE: InAddrT = 0xffffffff;
- pub const INADDR_BROADCAST: InAddrT = 0xffffffff;
-
- pub type SockMessageFlags = i32;
- // Flags for send/recv and their relatives
- pub const MSG_OOB: SockMessageFlags = 0x1;
- pub const MSG_PEEK: SockMessageFlags = 0x2;
- pub const MSG_DONTWAIT: SockMessageFlags = 0x40;
-}
-
-#[cfg(any(target_os = "macos", target_os = "ios"))]
-mod consts {
- use libc::{c_int, uint8_t};
-
- pub type AddressFamily = c_int;
-
- pub const AF_UNIX: AddressFamily = 1;
- pub const AF_LOCAL: AddressFamily = AF_UNIX;
- pub const AF_INET: AddressFamily = 2;
- pub const AF_INET6: AddressFamily = 30;
-
- pub type SockType = c_int;
-
- pub const SOCK_STREAM: SockType = 1;
- pub const SOCK_DGRAM: SockType = 2;
- pub const SOCK_SEQPACKET: SockType = 5;
- 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;
- #[allow(overflowing_literals)]
- pub const SO_RESTRICT_DENYSET: SockOpt = 0x80000000;
-
- // Socket options for TCP sockets
- pub const TCP_NODELAY: SockOpt = 1;
- pub const TCP_MAXSEG: SockOpt = 2;
-
- // Socket options for the IP layer of the socket
- pub const IP_MULTICAST_IF: SockOpt = 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 type InAddrT = u32;
-
- // Declarations of special addresses
- pub const INADDR_ANY: InAddrT = 0;
- pub const INADDR_NONE: InAddrT = 0xffffffff;
- pub const INADDR_BROADCAST: InAddrT = 0xffffffff;
-
- pub type SockMessageFlags = i32;
- // Flags for send/recv and their relatives
- pub const MSG_OOB: SockMessageFlags = 0x1;
- pub const MSG_PEEK: SockMessageFlags = 0x2;
- pub const MSG_DONTWAIT: SockMessageFlags = 0x80;
-}
-
-pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> NixResult<Fd> {
- let feat_atomic = features::socket_atomic_cloexec();
-
- if feat_atomic {
- ty = ty | flags.bits();
- }
-
- // TODO: Check the kernel version
- let res = unsafe { ffi::socket(domain, ty, 0) };
-
- if res < 0 {
- return Err(NixError::Sys(Errno::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)
-}
-
-pub fn listen(sockfd: Fd, backlog: usize) -> NixResult<()> {
- let res = unsafe { ffi::listen(sockfd, backlog as c_int) };
- from_ffi(res)
-}
-
-pub fn bind<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
- use self::SockAddr::*;
-
- let res = unsafe {
- try!(addr.with_sock_addr(|addr| {
- match *addr {
- SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
- SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
- SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
- }
- }))
- };
-
- from_ffi(res)
-}
-
-pub fn accept(sockfd: Fd) -> NixResult<Fd> {
- let res = unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
-
- if res < 0 {
- return Err(NixError::Sys(Errno::last()));
- }
-
- Ok(res)
-}
-
-#[cfg(not(any(target_os = "macos", target_os = "ios")))]
-pub fn accept4(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
- 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 ();
- }
-
- if !accept4.is_null() {
- let res = unsafe {
- mem::transmute::<*const (), F>(accept4)(
- sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits)
- };
-
- if res < 0 {
- return Err(NixError::Sys(Errno::last()));
- }
-
- Ok(res)
- } else {
- accept4_polyfill(sockfd, flags)
- }
-}
-
-#[cfg(any(target_os = "macos", target_os = "ios"))]
-pub fn accept4(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
- accept4_polyfill(sockfd, flags)
-}
-
-#[inline]
-fn accept4_polyfill(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
- let res = unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
-
- if res < 0 {
- return Err(NixError::Sys(Errno::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<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
- use self::SockAddr::*;
-
- let res = unsafe {
- try!(addr.with_sock_addr(|addr| {
- match *addr {
- SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
- SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
- SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
- }
- }))
- };
-
- from_ffi(res)
-}
-
-mod sa_helpers {
- use std::mem;
- use libc::{sockaddr_storage, sockaddr_in, sockaddr_in6, sockaddr_un};
- use super::SockAddr;
- use super::SockAddr::*;
-
- pub fn to_sockaddr_ipv4(addr: &sockaddr_storage) -> SockAddr {
- let sin : &sockaddr_in = unsafe { mem::transmute(addr) };
- SockIpV4( *sin )
- }
-
- pub fn to_sockaddr_ipv6(addr: &sockaddr_storage) -> SockAddr {
- let sin6 : &sockaddr_in6 = unsafe { mem::transmute(addr) };
- SockIpV6( *sin6 )
- }
-
- pub fn to_sockaddr_unix(addr: &sockaddr_storage) -> SockAddr {
- let sun : &sockaddr_un = unsafe { mem::transmute(addr) };
- SockUnix( *sun )
- }
-}
-
-pub fn recvfrom(sockfd: Fd, buf: &mut [u8]) -> NixResult<(usize, SockAddr)> {
- let saddr : sockaddr_storage = unsafe { mem::zeroed() };
- let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
-
- let ret = unsafe {
- ffi::recvfrom(sockfd, buf.as_ptr() as *mut c_void, buf.len() as size_t, 0, mem::transmute(&saddr), &mut len as *mut socklen_t)
- };
-
- if ret < 0 {
- return Err(NixError::Sys(Errno::last()));
- }
-
- Ok((ret as usize,
- match saddr.ss_family as i32 {
- AF_INET => { sa_helpers::to_sockaddr_ipv4(&saddr) },
- AF_INET6 => { sa_helpers::to_sockaddr_ipv6(&saddr) },
- AF_UNIX => { sa_helpers::to_sockaddr_unix(&saddr) },
- _ => unimplemented!()
- }
- ))
-}
-
-fn print_ipv4_addr(sin: &sockaddr_in, f: &mut fmt::Formatter) -> fmt::Result {
- use std::num::Int;
-
- let ip_addr = Int::from_be(sin.sin_addr.s_addr);
- let port = Int::from_be(sin.sin_port);
-
- write!(f, "{}.{}.{}.{}:{}",
- (ip_addr >> 24) & 0xff,
- (ip_addr >> 16) & 0xff,
- (ip_addr >> 8) & 0xff,
- (ip_addr) & 0xff,
- port)
-}
-
-impl fmt::Debug for SockAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- SockAddr::SockIpV4(sin) => print_ipv4_addr(&sin, f),
- _ => unimplemented!()
- }
- }
-}
-
-///
-/// Generic wrapper around sendto
-fn sendto_sockaddr<T>(sockfd: Fd, buf: &[u8], flags: SockMessageFlags, addr: &T) -> ssize_t {
- unsafe {
- ffi::sendto(
- sockfd,
- buf.as_ptr() as *const c_void,
- buf.len() as size_t,
- flags,
- mem::transmute(addr),
- mem::size_of::<T>() as socklen_t)
- }
-}
-
-pub fn sendto(sockfd: Fd, buf: &[u8], addr: &SockAddr, flags: SockMessageFlags) -> NixResult<usize> {
- use self::SockAddr::*;
-
- let ret = match *addr {
- SockIpV4(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
- SockIpV6(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
- SockUnix(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
- };
-
- if ret < 0 {
- Err(NixError::Sys(Errno::last()))
- } else {
- Ok(ret as usize)
- }
-}
-
-#[repr(C)]
-#[derive(Copy)]
-pub struct linger {
- pub l_onoff: c_int,
- 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;
-
- let res = unsafe {
- ffi::getsockopt(
- fd, level, opt,
- mem::transmute(val),
- &mut len as *mut socklen_t)
- };
-
- if res < 0 {
- return Err(NixError::Sys(Errno::last()));
- }
-
- Ok(len as usize)
-}
-
-pub fn setsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &T) -> NixResult<()> {
- let len = mem::size_of::<T>() as socklen_t;
-
- let res = unsafe {
- ffi::setsockopt(
- fd, level, opt,
- mem::transmute(val),
- len)
- };
-
- from_ffi(res)
-}
-
-fn getpeername_sockaddr<T>(sockfd: Fd, addr: &T) -> NixResult<bool> {
- let addrlen_expected = mem::size_of::<T>() as socklen_t;
- let mut addrlen = addrlen_expected;
-
- let ret = unsafe { ffi::getpeername(sockfd, mem::transmute(addr), &mut addrlen) };
- if ret < 0 {
- return Err(NixError::Sys(Errno::last()));
- }
-
- Ok(addrlen == addrlen_expected)
-}
-
-pub fn getpeername(sockfd: Fd, addr: &mut SockAddr) -> NixResult<bool> {
- use self::SockAddr::*;
-
- match *addr {
- SockIpV4(ref addr) => getpeername_sockaddr(sockfd, addr),
- SockIpV6(ref addr) => getpeername_sockaddr(sockfd, addr),
- SockUnix(ref addr) => getpeername_sockaddr(sockfd, addr)
- }
-}
-
-fn getsockname_sockaddr<T>(sockfd: Fd, addr: &T) -> NixResult<bool> {
- let addrlen_expected = mem::size_of::<T>() as socklen_t;
- let mut addrlen = addrlen_expected;
-
- let ret = unsafe { ffi::getsockname(sockfd, mem::transmute(addr), &mut addrlen) };
- if ret < 0 {
- return Err(NixError::Sys(Errno::last()));
- }
-
- Ok(addrlen == addrlen_expected)
-}
-
-pub fn getsockname(sockfd: Fd, addr: &mut SockAddr) -> NixResult<bool> {
- use self::SockAddr::*;
-
- match *addr {
- SockIpV4(ref addr) => getsockname_sockaddr(sockfd, addr),
- SockIpV6(ref addr) => getsockname_sockaddr(sockfd, addr),
- SockUnix(ref addr) => getsockname_sockaddr(sockfd, addr)
- }
-}
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
new file mode 100644
index 00000000..91d2c0d1
--- /dev/null
+++ b/src/sys/socket/addr.rs
@@ -0,0 +1,131 @@
+use {NixResult, NixError};
+use super::{sa_family_t, in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, AF_UNIX, AF_INET};
+use errno::Errno;
+use std::{mem, net, path, ptr};
+use std::ffi::{AsOsStr, CStr, OsStr};
+use std::os::unix::OsStrExt;
+
+/// Represents a socket address
+#[derive(Copy)]
+pub enum SockAddr {
+ // TODO: Rename these variants IpV4, IpV6, Unix
+ SockIpV4(sockaddr_in),
+ SockIpV6(sockaddr_in6),
+ SockUnix(sockaddr_un)
+}
+
+/// A trait for values which can be converted or resolved to a SockAddr.
+pub trait ToSockAddr {
+ /// Converts the value to a SockAddr
+ fn to_sock_addr(&self) -> NixResult<SockAddr>;
+
+ /// Converts and yields the value as a SockAddr
+ fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> {
+ Ok(action(&try!(self.to_sock_addr())))
+ }
+}
+
+impl ToSockAddr for SockAddr {
+ fn to_sock_addr(&self) -> NixResult<SockAddr> {
+ Ok(*self)
+ }
+
+ fn with_sock_addr<T, F: FnOnce(&SockAddr) -> T>(&self, action: F) -> NixResult<T> {
+ Ok(action(self))
+ }
+}
+
+/// Convert a path into a unix domain socket address
+impl ToSockAddr for path::Path {
+ fn to_sock_addr(&self) -> NixResult<SockAddr> {
+ let bytes = self.as_os_str().as_bytes();
+
+ Ok(SockAddr::SockUnix(unsafe {
+ let mut ret = sockaddr_un {
+ sun_family: AF_UNIX as sa_family_t,
+ .. mem::zeroed()
+ };
+
+ // Make sure the destination has enough capacity
+ if bytes.len() >= ret.sun_path.len() {
+ return Err(NixError::Sys(Errno::ENAMETOOLONG));
+ }
+
+ // Copy the path
+ ptr::copy_memory(
+ ret.sun_path.as_mut_ptr(),
+ bytes.as_ptr() as *const i8,
+ bytes.len());
+
+ ret
+ }))
+ }
+}
+
+/// Convert an inet address into a socket address
+impl ToSockAddr for net::SocketAddr {
+ fn to_sock_addr(&self) -> NixResult<SockAddr> {
+ use std::net::IpAddr;
+ use std::num::Int;
+
+ match self.ip() {
+ IpAddr::V4(ip) => {
+ let addr = ip.octets();
+ Ok(SockAddr::SockIpV4(sockaddr_in {
+ sin_family: AF_INET as sa_family_t,
+ sin_port: self.port(),
+ sin_addr: in_addr {
+ s_addr: Int::from_be(
+ ((addr[0] as u32) << 24) |
+ ((addr[1] as u32) << 16) |
+ ((addr[2] as u32) << 8) |
+ ((addr[3] as u32) << 0))
+ },
+ .. unsafe { mem::zeroed() }
+ }))
+ }
+ _ => unimplemented!()
+ }
+ }
+}
+
+/// Convert from a socket address
+pub trait FromSockAddr {
+ fn from_sock_addr(addr: &SockAddr) -> Option<Self>;
+}
+
+impl FromSockAddr for net::SocketAddr {
+ fn from_sock_addr(addr: &SockAddr) -> Option<net::SocketAddr> {
+ use std::net::{IpAddr, Ipv4Addr};
+ use std::num::Int;
+
+ match *addr {
+ SockAddr::SockIpV4(ref addr) => {
+ let ip = Int::from_be(addr.sin_addr.s_addr);
+ let ip = Ipv4Addr::new(
+ ((ip >> 24) as u8) & 0xff,
+ ((ip >> 16) as u8) & 0xff,
+ ((ip >> 8) as u8) & 0xff,
+ ((ip >> 0) as u8) & 0xff);
+
+ Some(net::SocketAddr::new(IpAddr::V4(ip), addr.sin_port))
+ }
+ SockAddr::SockIpV6(_) => unimplemented!(),
+ _ => None,
+ }
+ }
+}
+
+impl FromSockAddr for path::PathBuf {
+ fn from_sock_addr(addr: &SockAddr) -> Option<path::PathBuf> {
+ if let SockAddr::SockUnix(ref addr) = *addr {
+ unsafe {
+ let bytes = CStr::from_ptr(addr.sun_path.as_ptr()).to_bytes();
+ let osstr = <OsStr as OsStrExt>::from_bytes(bytes);
+ return Some(path::PathBuf::new(osstr));
+ }
+ }
+
+ None
+ }
+}
diff --git a/src/sys/socket/consts.rs b/src/sys/socket/consts.rs
new file mode 100644
index 00000000..e23098b6
--- /dev/null
+++ b/src/sys/socket/consts.rs
@@ -0,0 +1,188 @@
+pub use self::os::*;
+
+#[cfg(target_os = "linux")]
+mod os {
+ use libc::{c_int, uint8_t};
+
+ pub type AddressFamily = c_int;
+
+ pub const AF_UNIX: AddressFamily = 1;
+ pub const AF_LOCAL: AddressFamily = AF_UNIX;
+ pub const AF_INET: AddressFamily = 2;
+ pub const AF_INET6: AddressFamily = 10;
+
+ pub type SockType = c_int;
+
+ pub const SOCK_STREAM: SockType = 1;
+ pub const SOCK_DGRAM: SockType = 2;
+ pub const SOCK_SEQPACKET: SockType = 5;
+ 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;
+
+ // Socket options for TCP sockets
+ pub const TCP_NODELAY: SockOpt = 1;
+ pub const TCP_MAXSEG: SockOpt = 2;
+ pub const TCP_CORK: SockOpt = 3;
+
+ // Socket options for the IP layer of the socket
+ pub const IP_MULTICAST_IF: SockOpt = 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 type InAddrT = u32;
+
+ // Declarations of special addresses
+ pub const INADDR_ANY: InAddrT = 0;
+ pub const INADDR_NONE: InAddrT = 0xffffffff;
+ pub const INADDR_BROADCAST: InAddrT = 0xffffffff;
+
+ pub type SockMessageFlags = i32;
+ // Flags for send/recv and their relatives
+ pub const MSG_OOB: SockMessageFlags = 0x1;
+ pub const MSG_PEEK: SockMessageFlags = 0x2;
+ pub const MSG_DONTWAIT: SockMessageFlags = 0x40;
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+mod os {
+ use libc::{c_int, uint8_t};
+
+ pub type AddressFamily = c_int;
+
+ pub const AF_UNIX: AddressFamily = 1;
+ pub const AF_LOCAL: AddressFamily = AF_UNIX;
+ pub const AF_INET: AddressFamily = 2;
+ pub const AF_INET6: AddressFamily = 30;
+
+ pub type SockType = c_int;
+
+ pub const SOCK_STREAM: SockType = 1;
+ pub const SOCK_DGRAM: SockType = 2;
+ pub const SOCK_SEQPACKET: SockType = 5;
+ 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;
+ #[allow(overflowing_literals)]
+ pub const SO_RESTRICT_DENYSET: SockOpt = 0x80000000;
+
+ // Socket options for TCP sockets
+ pub const TCP_NODELAY: SockOpt = 1;
+ pub const TCP_MAXSEG: SockOpt = 2;
+
+ // Socket options for the IP layer of the socket
+ pub const IP_MULTICAST_IF: SockOpt = 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 type InAddrT = u32;
+
+ // Declarations of special addresses
+ pub const INADDR_ANY: InAddrT = 0;
+ pub const INADDR_NONE: InAddrT = 0xffffffff;
+ pub const INADDR_BROADCAST: InAddrT = 0xffffffff;
+
+ pub type SockMessageFlags = i32;
+ // Flags for send/recv and their relatives
+ pub const MSG_OOB: SockMessageFlags = 0x1;
+ pub const MSG_PEEK: SockMessageFlags = 0x2;
+ pub const MSG_DONTWAIT: SockMessageFlags = 0x80;
+}
diff --git a/src/sys/socket/ffi.rs b/src/sys/socket/ffi.rs
new file mode 100644
index 00000000..612854de
--- /dev/null
+++ b/src/sys/socket/ffi.rs
@@ -0,0 +1,11 @@
+use libc::{c_int, c_void, socklen_t};
+pub use libc::{socket, listen, bind, accept, connect, setsockopt, sendto, recvfrom, getsockname, getpeername};
+
+extern {
+ pub fn getsockopt(
+ sockfd: c_int,
+ level: c_int,
+ optname: c_int,
+ optval: *mut c_void,
+ optlen: *mut socklen_t) -> c_int;
+}
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
new file mode 100644
index 00000000..a5c2c97a
--- /dev/null
+++ b/src/sys/socket/mod.rs
@@ -0,0 +1,346 @@
+use {NixError, NixResult, from_ffi};
+use errno::Errno;
+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, ssize_t};
+use std::{fmt, mem, ptr};
+use std::os::unix::prelude::*;
+
+mod addr;
+mod consts;
+mod ffi;
+
+/*
+ *
+ * ===== Re-exports =====
+ *
+ */
+
+pub use self::addr::{
+ SockAddr,
+ ToSockAddr,
+ FromSockAddr
+};
+pub use libc::{
+ in_addr,
+ sockaddr,
+ sockaddr_storage,
+ sockaddr_in,
+ sockaddr_in6,
+ sockaddr_un,
+ sa_family_t,
+ ip_mreq
+};
+pub use self::consts::*;
+
+// Extra flags - Supported by Linux 2.6.27, normalized on other platforms
+bitflags!(
+ flags SockFlag: c_int {
+ const SOCK_NONBLOCK = 0o0004000,
+ const SOCK_CLOEXEC = 0o2000000
+ }
+);
+
+pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> NixResult<Fd> {
+ let feat_atomic = features::socket_atomic_cloexec();
+
+ if feat_atomic {
+ ty = ty | flags.bits();
+ }
+
+ // TODO: Check the kernel version
+ let res = unsafe { ffi::socket(domain, ty, 0) };
+
+ if res < 0 {
+ return Err(NixError::Sys(Errno::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)
+}
+
+pub fn listen(sockfd: Fd, backlog: usize) -> NixResult<()> {
+ let res = unsafe { ffi::listen(sockfd, backlog as c_int) };
+ from_ffi(res)
+}
+
+pub fn bind<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
+ use self::addr::SockAddr::*;
+
+ let res = unsafe {
+ try!(addr.with_sock_addr(|addr| {
+ match *addr {
+ SockIpV4(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
+ SockIpV6(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
+ SockUnix(ref addr) => ffi::bind(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
+ }
+ }))
+ };
+
+ from_ffi(res)
+}
+
+pub fn accept(sockfd: Fd) -> NixResult<Fd> {
+ let res = unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
+
+ if res < 0 {
+ return Err(NixError::Sys(Errno::last()));
+ }
+
+ Ok(res)
+}
+
+#[cfg(not(any(target_os = "macos", target_os = "ios")))]
+pub fn accept4(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
+ 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 ();
+ }
+
+ if !accept4.is_null() {
+ let res = unsafe {
+ mem::transmute::<*const (), F>(accept4)(
+ sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits)
+ };
+
+ if res < 0 {
+ return Err(NixError::Sys(Errno::last()));
+ }
+
+ Ok(res)
+ } else {
+ accept4_polyfill(sockfd, flags)
+ }
+}
+
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+pub fn accept4(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
+ accept4_polyfill(sockfd, flags)
+}
+
+#[inline]
+fn accept4_polyfill(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
+ let res = unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
+
+ if res < 0 {
+ return Err(NixError::Sys(Errno::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<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
+ use self::addr::SockAddr::*;
+
+ let res = unsafe {
+ try!(addr.with_sock_addr(|addr| {
+ match *addr {
+ SockIpV4(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in>() as socklen_t),
+ SockIpV6(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_in6>() as socklen_t),
+ SockUnix(ref addr) => ffi::connect(sockfd, mem::transmute(addr), mem::size_of::<sockaddr_un>() as socklen_t)
+ }
+ }))
+ };
+
+ from_ffi(res)
+}
+
+mod sa_helpers {
+ use std::mem;
+ use libc::{sockaddr_storage, sockaddr_in, sockaddr_in6, sockaddr_un};
+ use super::SockAddr;
+ use super::SockAddr::*;
+
+ pub fn to_sockaddr_ipv4(addr: &sockaddr_storage) -> SockAddr {
+ let sin : &sockaddr_in = unsafe { mem::transmute(addr) };
+ SockIpV4( *sin )
+ }
+
+ pub fn to_sockaddr_ipv6(addr: &sockaddr_storage) -> SockAddr {
+ let sin6 : &sockaddr_in6 = unsafe { mem::transmute(addr) };
+ SockIpV6( *sin6 )
+ }
+
+ pub fn to_sockaddr_unix(addr: &sockaddr_storage) -> SockAddr {
+ let sun : &sockaddr_un = unsafe { mem::transmute(addr) };
+ SockUnix( *sun )
+ }
+}
+
+pub fn recvfrom(sockfd: Fd, buf: &mut [u8]) -> NixResult<(usize, SockAddr)> {
+ let saddr : sockaddr_storage = unsafe { mem::zeroed() };
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+ let ret = unsafe {
+ ffi::recvfrom(sockfd, buf.as_ptr() as *mut c_void, buf.len() as size_t, 0, mem::transmute(&saddr), &mut len as *mut socklen_t)
+ };
+
+ if ret < 0 {
+ return Err(NixError::Sys(Errno::last()));
+ }
+
+ Ok((ret as usize,
+ match saddr.ss_family as i32 {
+ AF_INET => { sa_helpers::to_sockaddr_ipv4(&saddr) },
+ AF_INET6 => { sa_helpers::to_sockaddr_ipv6(&saddr) },
+ AF_UNIX => { sa_helpers::to_sockaddr_unix(&saddr) },
+ _ => unimplemented!()
+ }
+ ))
+}
+
+fn print_ipv4_addr(sin: &sockaddr_in, f: &mut fmt::Formatter) -> fmt::Result {
+ use std::num::Int;
+
+ let ip_addr = Int::from_be(sin.sin_addr.s_addr);
+ let port = Int::from_be(sin.sin_port);
+
+ write!(f, "{}.{}.{}.{}:{}",
+ (ip_addr >> 24) & 0xff,
+ (ip_addr >> 16) & 0xff,
+ (ip_addr >> 8) & 0xff,
+ (ip_addr) & 0xff,
+ port)
+}
+
+impl fmt::Debug for SockAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ SockAddr::SockIpV4(sin) => print_ipv4_addr(&sin, f),
+ _ => unimplemented!()
+ }
+ }
+}
+
+///
+/// Generic wrapper around sendto
+fn sendto_sockaddr<T>(sockfd: Fd, buf: &[u8], flags: SockMessageFlags, addr: &T) -> ssize_t {
+ unsafe {
+ ffi::sendto(
+ sockfd,
+ buf.as_ptr() as *const c_void,
+ buf.len() as size_t,
+ flags,
+ mem::transmute(addr),
+ mem::size_of::<T>() as socklen_t)
+ }
+}
+
+pub fn sendto(sockfd: Fd, buf: &[u8], addr: &SockAddr, flags: SockMessageFlags) -> NixResult<usize> {
+ use self::addr::SockAddr::*;
+
+ let ret = match *addr {
+ SockIpV4(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
+ SockIpV6(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
+ SockUnix(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
+ };
+
+ if ret < 0 {
+ Err(NixError::Sys(Errno::last()))
+ } else {
+ Ok(ret as usize)
+ }
+}
+
+#[repr(C)]
+#[derive(Copy)]
+pub struct linger {
+ pub l_onoff: c_int,
+ 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;
+
+ let res = unsafe {
+ ffi::getsockopt(
+ fd, level, opt,
+ mem::transmute(val),
+ &mut len as *mut socklen_t)
+ };
+
+ if res < 0 {
+ return Err(NixError::Sys(Errno::last()));
+ }
+
+ Ok(len as usize)
+}
+
+pub fn setsockopt<T>(fd: Fd, level: SockLevel, opt: SockOpt, val: &T) -> NixResult<()> {
+ let len = mem::size_of::<T>() as socklen_t;
+
+ let res = unsafe {
+ ffi::setsockopt(
+ fd, level, opt,
+ mem::transmute(val),
+ len)
+ };
+
+ from_ffi(res)
+}
+
+fn getpeername_sockaddr<T>(sockfd: Fd, addr: &T) -> NixResult<bool> {
+ let addrlen_expected = mem::size_of::<T>() as socklen_t;
+ let mut addrlen = addrlen_expected;
+
+ let ret = unsafe { ffi::getpeername(sockfd, mem::transmute(addr), &mut addrlen) };
+ if ret < 0 {
+ return Err(NixError::Sys(Errno::last()));
+ }
+
+ Ok(addrlen == addrlen_expected)
+}
+
+pub fn getpeername(sockfd: Fd, addr: &mut SockAddr) -> NixResult<bool> {
+ use self::addr::SockAddr::*;
+
+ match *addr {
+ SockIpV4(ref addr) => getpeername_sockaddr(sockfd, addr),
+ SockIpV6(ref addr) => getpeername_sockaddr(sockfd, addr),
+ SockUnix(ref addr) => getpeername_sockaddr(sockfd, addr)
+ }
+}
+
+fn getsockname_sockaddr<T>(sockfd: Fd, addr: &T) -> NixResult<bool> {
+ let addrlen_expected = mem::size_of::<T>() as socklen_t;
+ let mut addrlen = addrlen_expected;
+
+ let ret = unsafe { ffi::getsockname(sockfd, mem::transmute(addr), &mut addrlen) };
+ if ret < 0 {
+ return Err(NixError::Sys(Errno::last()));
+ }
+
+ Ok(addrlen == addrlen_expected)
+}
+
+pub fn getsockname(sockfd: Fd, addr: &mut SockAddr) -> NixResult<bool> {
+ use self::addr::SockAddr::*;
+
+ match *addr {
+ SockIpV4(ref addr) => getsockname_sockaddr(sockfd, addr),
+ SockIpV6(ref addr) => getsockname_sockaddr(sockfd, addr),
+ SockUnix(ref addr) => getsockname_sockaddr(sockfd, addr)
+ }
+}