summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2015-02-25 12:24:43 -0800
committerCarl Lerche <me@carllerche.com>2015-02-25 12:24:43 -0800
commit8a7cd5675d38365d96e322693f455b2cd7fea6e5 (patch)
tree860341241eddeda0168c06bfbdb2d6d1df1ec702
parentfcc952a18c054821480964bc1b0f7b32e7728e62 (diff)
downloadnix-8a7cd5675d38365d96e322693f455b2cd7fea6e5.zip
Large cleanup, mostly of socket functions
-rw-r--r--nix-test/src/sizes.c4
-rw-r--r--src/lib.rs8
-rw-r--r--src/nix.rs4
-rw-r--r--src/sys/mod.rs3
-rw-r--r--src/sys/socket/addr.rs127
-rw-r--r--src/sys/socket/consts.rs44
-rw-r--r--src/sys/socket/mod.rs255
-rw-r--r--src/sys/socket/multicast.rs44
-rw-r--r--src/sys/syscall.rs (renamed from src/syscall.rs)2
-rw-r--r--src/sys/uio.rs3
-rw-r--r--src/unistd.rs4
-rw-r--r--test/sys/test_socket.rs21
-rw-r--r--test/test.rs33
-rw-r--r--test/test_nix_path.rs0
14 files changed, 372 insertions, 180 deletions
diff --git a/nix-test/src/sizes.c b/nix-test/src/sizes.c
index 24c46fd2..8cf30d20 100644
--- a/nix-test/src/sizes.c
+++ b/nix-test/src/sizes.c
@@ -1,3 +1,4 @@
+#include "sys/socket.h"
#include "sys/uio.h"
#define SIZE_OF_T(TYPE) \
@@ -16,6 +17,9 @@
size_t
size_of(const char* type) {
+ // sys/socket
+ SIZE_OF_S(sockaddr_storage);
+
// sys/uio
SIZE_OF_S(iovec);
diff --git a/src/lib.rs b/src/lib.rs
index 5dbcfa2f..d2de27e2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,7 @@
+//! Rust friendly bindings to the various *nix system functions.
+//!
+//! Modules are structured according to the C header file that they would be
+//! defined in.
#![crate_name = "nix"]
#![feature(collections, core, net, linkage, libc, os, path, std_misc)]
@@ -18,6 +22,7 @@ pub use libc::{c_int, c_void};
mod nix;
pub use nix::{NixResult, NixError, NixPath, from_ffi};
+
#[cfg(unix)]
pub mod errno;
@@ -36,8 +41,5 @@ pub mod sched;
#[cfg(unix)]
pub mod sys;
-#[cfg(target_os = "linux")]
-pub mod syscall;
-
#[cfg(unix)]
pub mod unistd;
diff --git a/src/nix.rs b/src/nix.rs
index 3cc5beff..abd41599 100644
--- a/src/nix.rs
+++ b/src/nix.rs
@@ -12,6 +12,10 @@ pub enum NixError {
}
impl NixError {
+ pub fn last() -> NixError {
+ NixError::Sys(Errno::last())
+ }
+
pub fn invalid_argument() -> NixError {
NixError::Sys(EINVAL)
}
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index 5dacde21..8e608d1e 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -17,6 +17,9 @@ pub mod socket;
pub mod stat;
+#[cfg(target_os = "linux")]
+pub mod syscall;
+
#[cfg(not(target_os = "ios"))]
pub mod termios;
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index 835979cf..5dda1194 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -1,13 +1,27 @@
use {NixResult, NixError};
-use super::{sa_family_t, in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, AF_UNIX, AF_INET};
+use super::{consts, sa_family_t, in_addr, sockaddr_in, sockaddr_in6, sockaddr_un, AF_UNIX, AF_INET};
use errno::Errno;
use libc;
-use std::{mem, net, path, ptr};
+use std::{fmt, mem, net, path, ptr};
use std::ffi::{AsOsStr, CStr, OsStr};
use std::os::unix::OsStrExt;
/*
*
+ * ===== AddressFamily =====
+ *
+ */
+
+#[repr(i32)]
+#[derive(Copy, PartialEq, Eq, Debug)]
+pub enum AddressFamily {
+ Unix = consts::AF_UNIX,
+ Inet = consts::AF_INET,
+ Inet6 = consts::AF_INET6,
+}
+
+/*
+ *
* ===== Sock addr =====
*
*/
@@ -15,12 +29,46 @@ use std::os::unix::OsStrExt;
/// Represents a socket address
#[derive(Copy)]
pub enum SockAddr {
- // TODO: Rename these variants IpV4, IpV6, Unix
IpV4(sockaddr_in),
IpV6(sockaddr_in6),
Unix(sockaddr_un)
}
+impl SockAddr {
+ pub fn family(&self) -> AddressFamily {
+ match *self {
+ SockAddr::IpV4(..) => AddressFamily::Inet,
+ SockAddr::IpV6(..) => AddressFamily::Inet6,
+ SockAddr::Unix(..) => AddressFamily::Unix,
+ }
+ }
+
+ pub fn to_str(&self) -> String {
+ format!("{}", self)
+ }
+}
+
+impl fmt::Display for SockAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use std::num::Int;
+
+ match *self {
+ SockAddr::IpV4(sin) => {
+ let ip = Int::from_be(sin.sin_addr.s_addr);
+ let port = Int::from_be(sin.sin_port);
+
+ write!(f, "{}.{}.{}.{}:{}",
+ (ip >> 24) & 0xff,
+ (ip >> 16) & 0xff,
+ (ip >> 8) & 0xff,
+ (ip) & 0xff,
+ port)
+ }
+ _ => write!(f, "[some sock addr type... Debug is not implemented :(]"),
+ }
+ }
+}
+
/// A trait for values which can be converted or resolved to a SockAddr.
pub trait ToSockAddr {
/// Converts the value to a SockAddr
@@ -69,10 +117,18 @@ impl ToSockAddr for path::Path {
}
}
+/// Convert a path buf into a unix domain socket address
+impl ToSockAddr for path::PathBuf {
+ fn to_sock_addr(&self) -> NixResult<SockAddr> {
+ (**self).to_sock_addr()
+ }
+}
+
/// 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) => {
@@ -81,7 +137,7 @@ impl ToSockAddr for net::SocketAddr {
Ok(SockAddr::IpV4(sockaddr_in {
sin_family: AF_INET as sa_family_t,
- sin_port: self.port(),
+ sin_port: self.port().to_be(),
sin_addr: addr,
.. unsafe { mem::zeroed() }
}))
@@ -110,7 +166,7 @@ impl FromSockAddr for net::SocketAddr {
((ip >> 8) as u8) & 0xff,
((ip >> 0) as u8) & 0xff);
- Some(net::SocketAddr::new(IpAddr::V4(ip), addr.sin_port))
+ Some(net::SocketAddr::new(IpAddr::V4(ip), Int::from_be(addr.sin_port)))
}
SockAddr::IpV6(_) => unimplemented!(),
_ => None,
@@ -134,10 +190,58 @@ impl FromSockAddr for path::PathBuf {
/*
*
+ * ===== IpAddr =====
+ *
+ */
+
+/// Convert to an IpAddr
+pub trait ToIpAddr {
+ fn to_ip_addr(self) -> Option<net::IpAddr>;
+}
+
+impl ToIpAddr for net::IpAddr {
+ fn to_ip_addr(self) -> Option<net::IpAddr> {
+ Some(self)
+ }
+}
+
+impl<'a> ToIpAddr for &'a net::IpAddr {
+ fn to_ip_addr(self) -> Option<net::IpAddr> {
+ Some(*self)
+ }
+}
+
+impl ToIpAddr for net::Ipv4Addr {
+ fn to_ip_addr(self) -> Option<net::IpAddr> {
+ Some(net::IpAddr::V4(self))
+ }
+}
+
+impl<'a> ToIpAddr for &'a net::Ipv4Addr {
+ fn to_ip_addr(self) -> Option<net::IpAddr> {
+ (*self).to_ip_addr()
+ }
+}
+
+impl ToIpAddr for net::Ipv6Addr {
+ fn to_ip_addr(self) -> Option<net::IpAddr> {
+ Some(net::IpAddr::V6(self))
+ }
+}
+
+impl<'a> ToIpAddr for &'a net::Ipv6Addr {
+ fn to_ip_addr(self) -> Option<net::IpAddr> {
+ (*self).to_ip_addr()
+ }
+}
+
+/*
+ *
* ===== InAddr =====
*
*/
+/// Convert to an in_addr
pub trait ToInAddr {
fn to_in_addr(self) -> Option<libc::in_addr>;
}
@@ -183,13 +287,12 @@ impl ToInAddr for net::Ipv4Addr {
use std::num::Int;
let addr = self.octets();
- Some(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))
- })
+ let ip = (((addr[0] as u32) << 24) |
+ ((addr[1] as u32) << 16) |
+ ((addr[2] as u32) << 8) |
+ ((addr[3] as u32) << 0)).to_be();
+
+ Some(in_addr { s_addr: ip })
}
}
diff --git a/src/sys/socket/consts.rs b/src/sys/socket/consts.rs
index 39bcd733..3131cfb8 100644
--- a/src/sys/socket/consts.rs
+++ b/src/sys/socket/consts.rs
@@ -4,20 +4,16 @@ pub use self::os::*;
mod os {
use libc::{c_int, uint8_t};
- pub type AddressFamily = c_int;
+ pub const AF_UNIX: c_int = 1;
+ pub const AF_LOCAL: c_int = AF_UNIX;
+ pub const AF_INET: c_int = 2;
+ pub const AF_INET6: c_int = 10;
- 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 const SOCK_STREAM: c_int = 1;
+ pub const SOCK_DGRAM: c_int = 2;
+ pub const SOCK_SEQPACKET: c_int = 5;
+ pub const SOCK_RAW: c_int = 3;
+ pub const SOCK_RDM: c_int = 4;
pub const SOL_IP: c_int = 0;
pub const SOL_SOCKET: c_int = 1;
@@ -94,20 +90,16 @@ mod os {
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 AF_UNIX: c_int = 1;
+ pub const AF_LOCAL: c_int = AF_UNIX;
+ pub const AF_INET: c_int = 2;
+ pub const AF_INET6: c_int = 30;
- 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 const SOCK_STREAM: c_int = 1;
+ pub const SOCK_DGRAM: c_int = 2;
+ pub const SOCK_SEQPACKET: c_int = 5;
+ pub const SOCK_RAW: c_int = 3;
+ pub const SOCK_RDM: c_int = 4;
pub const SOL_SOCKET: c_int = 0xffff;
pub const IPPROTO_IP: c_int = 0;
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index da29ae88..576bcaf4 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -1,3 +1,6 @@
+//! Socket interface functions
+//!
+//! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
use {NixError, NixResult, from_ffi};
use errno::Errno;
use features;
@@ -23,6 +26,8 @@ pub use self::addr::{
SockAddr,
ToSockAddr,
FromSockAddr,
+ AddressFamily,
+ ToIpAddr,
ToInAddr,
};
pub use libc::{
@@ -40,6 +45,16 @@ pub use self::multicast::{
};
pub use self::consts::*;
+#[derive(Copy, PartialEq, Eq, Debug)]
+#[repr(i32)]
+pub enum SockType {
+ Stream = consts::SOCK_STREAM,
+ Datagram = consts::SOCK_DGRAM,
+ SeqPacket = consts::SOCK_SEQPACKET,
+ Raw = consts::SOCK_RAW,
+ Rdm = consts::SOCK_RDM,
+}
+
// Extra flags - Supported by Linux 2.6.27, normalized on other platforms
bitflags!(
flags SockFlag: c_int {
@@ -48,7 +63,11 @@ bitflags!(
}
);
-pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> NixResult<Fd> {
+/// Create an endpoint for communication
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/socket.2.html)
+pub fn socket(domain: AddressFamily, ty: SockType, flags: SockFlag) -> NixResult<Fd> {
+ let mut ty = ty as c_int;
let feat_atomic = features::socket_atomic_cloexec();
if feat_atomic {
@@ -56,7 +75,7 @@ pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> NixRe
}
// TODO: Check the kernel version
- let res = unsafe { ffi::socket(domain, ty, 0) };
+ let res = unsafe { ffi::socket(domain as c_int, ty, 0) };
if res < 0 {
return Err(NixError::Sys(Errno::last()));
@@ -75,11 +94,17 @@ pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> NixRe
Ok(res)
}
+/// Listen for connections on a socket
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/listen.2.html)
pub fn listen(sockfd: Fd, backlog: usize) -> NixResult<()> {
let res = unsafe { ffi::listen(sockfd, backlog as c_int) };
from_ffi(res)
}
+/// Bind a name to a socket
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/bind.2.html)
pub fn bind<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
let res = unsafe {
try!(addr.with_sock_addr(|addr| {
@@ -94,6 +119,9 @@ pub fn bind<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
from_ffi(res)
}
+/// Accept a connection on a socket
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
pub fn accept(sockfd: Fd) -> NixResult<Fd> {
let res = unsafe { ffi::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
@@ -104,6 +132,9 @@ pub fn accept(sockfd: Fd) -> NixResult<Fd> {
Ok(res)
}
+/// Accept a connection on a socket
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub fn accept4(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
use libc::sockaddr;
@@ -131,6 +162,9 @@ pub fn accept4(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
}
}
+/// Accept a connection on a socket
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn accept4(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
accept4_polyfill(sockfd, flags)
@@ -155,6 +189,9 @@ fn accept4_polyfill(sockfd: Fd, flags: SockFlag) -> NixResult<Fd> {
Ok(res)
}
+/// Initiate a connection on a socket
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/connect.2.html)
pub fn connect<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
let res = unsafe {
try!(addr.with_sock_addr(|addr| {
@@ -169,69 +206,29 @@ pub fn connect<A: ToSockAddr>(sockfd: Fd, addr: &A) -> NixResult<()> {
from_ffi(res)
}
-mod sa_helpers {
- use std::mem;
- use libc::{sockaddr_storage, sockaddr_in, sockaddr_in6, sockaddr_un};
- use super::SockAddr;
-
- pub fn to_sockaddr_ipv4(addr: &sockaddr_storage) -> SockAddr {
- let sin : &sockaddr_in = unsafe { mem::transmute(addr) };
- SockAddr::IpV4( *sin )
- }
-
- pub fn to_sockaddr_ipv6(addr: &sockaddr_storage) -> SockAddr {
- let sin6 : &sockaddr_in6 = unsafe { mem::transmute(addr) };
- SockAddr::IpV6( *sin6 )
- }
-
- pub fn to_sockaddr_unix(addr: &sockaddr_storage) -> SockAddr {
- let sun : &sockaddr_un = unsafe { mem::transmute(addr) };
- SockAddr::Unix( *sun )
- }
-}
-
+/// Receive data from a connectionless or connection-oriented socket. Returns
+/// the number of bytes read and the socket address of the sender.
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/recvmsg.2.html)
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);
+ unsafe {
+ let addr: sockaddr_storage = mem::zeroed();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
- write!(f, "{}.{}.{}.{}:{}",
- (ip_addr >> 24) & 0xff,
- (ip_addr >> 16) & 0xff,
- (ip_addr >> 8) & 0xff,
- (ip_addr) & 0xff,
- port)
-}
+ let ret = ffi::recvfrom(
+ sockfd,
+ buf.as_ptr() as *mut c_void,
+ buf.len() as size_t,
+ 0,
+ mem::transmute(&addr),
+ &mut len as *mut socklen_t);
-impl fmt::Debug for SockAddr {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- SockAddr::IpV4(sin) => print_ipv4_addr(&sin, f),
- _ => unimplemented!()
+ if ret < 0 {
+ return Err(NixError::last());
}
+
+ sockaddr_storage_to_addr(&addr, len as usize)
+ .map(|addr| (ret as usize, addr))
}
}
@@ -249,12 +246,14 @@ fn sendto_sockaddr<T>(sockfd: Fd, buf: &[u8], flags: SockMessageFlags, addr: &T)
}
}
-pub fn sendto(sockfd: Fd, buf: &[u8], addr: &SockAddr, flags: SockMessageFlags) -> NixResult<usize> {
- let ret = match *addr {
- SockAddr::IpV4(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
- SockAddr::IpV6(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
- SockAddr::Unix(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
- };
+pub fn sendto<A: ToSockAddr>(sockfd: Fd, buf: &[u8], addr: &A, flags: SockMessageFlags) -> NixResult<usize> {
+ let ret = try!(addr.with_sock_addr(|addr| {
+ match *addr {
+ SockAddr::IpV4(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
+ SockAddr::IpV6(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
+ SockAddr::Unix(ref addr) => sendto_sockaddr(sockfd, buf, flags, addr),
+ }
+ }));
if ret < 0 {
Err(NixError::Sys(Errno::last()))
@@ -264,7 +263,7 @@ pub fn sendto(sockfd: Fd, buf: &[u8], addr: &SockAddr, flags: SockMessageFlags)
}
#[repr(C)]
-#[derive(Copy)]
+#[derive(Copy, Debug)]
pub struct linger {
pub l_onoff: c_int,
pub l_linger: c_int
@@ -276,7 +275,21 @@ pub struct linger {
*
*/
-/// Represents a socket option that can be accessed or set
+/// The protocol level at which to get / set socket options. Used as an
+/// argument to `getsockopt` and `setsockopt`.
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/setsockopt.2.html)
+#[repr(i32)]
+pub enum SockLevel {
+ Socket = SOL_SOCKET,
+ Tcp = IPPROTO_TCP,
+ Ip = IPPROTO_IP,
+ Ipv6 = IPPROTO_IPV6,
+ Udp = IPPROTO_UDP,
+}
+
+/// Represents a socket option that can be accessed or set. Used as an argument
+/// to `getsockopt` and `setsockopt`.
pub trait SockOpt : Copy + fmt::Debug {
/// Type of `getsockopt` return value
type Get;
@@ -292,78 +305,80 @@ pub trait SockOpt : Copy + fmt::Debug {
fn set(&self, fd: Fd, level: c_int, val: Self::Set) -> NixResult<()>;
}
-pub enum SockLevel {
- Socket,
- Tcp,
- Ip,
- Ipv6,
- Udp
-}
-
-impl SockLevel {
- fn as_cint(&self) -> c_int {
- use self::SockLevel::*;
-
- 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())
+ opt.get(fd, level as c_int)
}
/// 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)
+ opt.set(fd, level as c_int, val)
}
-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;
+/// Get the address of the peer connected to the socket `fd`.
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/getpeername.2.html)
+pub fn getpeername(fd: Fd) -> NixResult<SockAddr> {
+ unsafe {
+ let addr: sockaddr_storage = mem::uninitialized();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
- let ret = unsafe { ffi::getpeername(sockfd, mem::transmute(addr), &mut addrlen) };
- if ret < 0 {
- return Err(NixError::Sys(Errno::last()));
- }
+ let ret = ffi::getpeername(fd, mem::transmute(&addr), &mut len);
- Ok(addrlen == addrlen_expected)
-}
+ if ret < 0 {
+ return Err(NixError::last());
+ }
-pub fn getpeername(sockfd: Fd, addr: &mut SockAddr) -> NixResult<bool> {
- match *addr {
- SockAddr::IpV4(ref addr) => getpeername_sockaddr(sockfd, addr),
- SockAddr::IpV6(ref addr) => getpeername_sockaddr(sockfd, addr),
- SockAddr::Unix(ref addr) => getpeername_sockaddr(sockfd, addr)
+ sockaddr_storage_to_addr(&addr, len as usize)
}
}
-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;
+/// Get the current address to which the socket `fd` is bound.
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/getsockname.2.html)
+pub fn getsockname(fd: Fd) -> NixResult<SockAddr> {
+ unsafe {
+ let addr: sockaddr_storage = mem::uninitialized();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
- let ret = unsafe { ffi::getsockname(sockfd, mem::transmute(addr), &mut addrlen) };
- if ret < 0 {
- return Err(NixError::Sys(Errno::last()));
- }
+ let ret = ffi::getsockname(fd, mem::transmute(&addr), &mut len);
- Ok(addrlen == addrlen_expected)
+ if ret < 0 {
+ return Err(NixError::last());
+ }
+
+ sockaddr_storage_to_addr(&addr, len as usize)
+ }
}
-pub fn getsockname(sockfd: Fd, addr: &mut SockAddr) -> NixResult<bool> {
- match *addr {
- SockAddr::IpV4(ref addr) => getsockname_sockaddr(sockfd, addr),
- SockAddr::IpV6(ref addr) => getsockname_sockaddr(sockfd, addr),
- SockAddr::Unix(ref addr) => getsockname_sockaddr(sockfd, addr)
+unsafe fn sockaddr_storage_to_addr(
+ addr: &sockaddr_storage,
+ len: usize) -> NixResult<SockAddr> {
+
+ match addr.ss_family as c_int {
+ consts::AF_INET => {
+ assert!(len as usize == mem::size_of::<sockaddr_in>());
+ let ret = *(addr as *const _ as *const sockaddr_in);
+ Ok(SockAddr::IpV4(ret))
+ }
+ consts::AF_INET6 => {
+ assert!(len as usize == mem::size_of::<sockaddr_in6>());
+ Ok(SockAddr::IpV6(*(addr as *const _ as *const sockaddr_in6)))
+ }
+ consts::AF_UNIX => {
+ assert!(len as usize == mem::size_of::<sockaddr_un>());
+ Ok(SockAddr::Unix(*(addr as *const _ as *const sockaddr_un)))
+ }
+ af => panic!("unexpected address family {}", af),
}
}
+
+#[test]
+pub fn test_struct_sizes() {
+ use nixtest;
+ nixtest::assert_size_of::<sockaddr_storage>("sockaddr_storage");
+}
diff --git a/src/sys/socket/multicast.rs b/src/sys/socket/multicast.rs
new file mode 100644
index 00000000..6831a915
--- /dev/null
+++ b/src/sys/socket/multicast.rs
@@ -0,0 +1,44 @@
+
+use {NixResult, NixError};
+use super::addr::ToInAddr;
+use super::consts;
+use libc::in_addr;
+use std::fmt;
+
+#[repr(C)]
+#[derive(Copy)]
+pub struct ip_mreq {
+ pub imr_multiaddr: in_addr,
+ pub imr_interface: in_addr,
+}
+
+impl fmt::Debug for ip_mreq {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "ip_mreq {{ imr_multiaddr: {{ s_addr: 0x{:x} }}, imr_interface: {{ s_addr: 0x{:x} }} }}",
+ self.imr_multiaddr.s_addr, self.imr_interface.s_addr)
+ }
+}
+
+impl ip_mreq {
+ pub fn new<T: ToInAddr, U: ToInAddr>(group: T, interface: Option<U>) -> NixResult<ip_mreq> {
+ let group = match group.to_in_addr() {
+ Some(group) => group,
+ None => return Err(NixError::invalid_argument()),
+ };
+
+ let interface = match interface {
+ Some(interface) => {
+ match interface.to_in_addr() {
+ Some(interface) => interface,
+ None => return Err(NixError::invalid_argument()),
+ }
+ }
+ None => in_addr { s_addr: consts::INADDR_ANY },
+ };
+
+ Ok(ip_mreq {
+ imr_multiaddr: group,
+ imr_interface: interface,
+ })
+ }
+}
diff --git a/src/syscall.rs b/src/sys/syscall.rs
index 9e4979d6..cdf6c414 100644
--- a/src/syscall.rs
+++ b/src/sys/syscall.rs
@@ -1,3 +1,5 @@
+//! Indirect system call
+//!
use libc::c_int;
pub use self::arch::*;
diff --git a/src/sys/uio.rs b/src/sys/uio.rs
index 35ae6da3..0d2072b9 100644
--- a/src/sys/uio.rs
+++ b/src/sys/uio.rs
@@ -1,3 +1,6 @@
+// Silence invalid warnings due to rust-lang/rust#16719
+#![allow(improper_ctypes)]
+
use {NixResult, NixError};
use errno::Errno;
use fcntl::Fd;
diff --git a/src/unistd.rs b/src/unistd.rs
index dd1d8d1a..a407b26c 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -1,3 +1,5 @@
+//! Standard symbolic constants and types
+//!
use {NixError, NixResult, NixPath, from_ffi};
use errno::Errno;
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC};
@@ -354,7 +356,7 @@ pub fn unlink<P: NixPath>(path: P) -> NixResult<()> {
#[cfg(target_os = "linux")]
mod linux {
- use syscall::{syscall, SYSPIVOTROOT};
+ use sys::syscall::{syscall, SYSPIVOTROOT};
use errno::Errno;
use {NixError, NixResult, NixPath};
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index 1c80fad9..588ba815 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -1,8 +1,10 @@
-use nix::sys::socket::{SockAddr, ToSockAddr, FromSockAddr};
+use nix::sys::socket::{SockAddr, ToSockAddr, FromSockAddr, getsockname};
use std::{mem, net};
use std::num::Int;
use std::path::{Path, PathBuf};
use std::str::FromStr;
+use std::os::unix::AsRawFd;
+use ports::localhost;
#[test]
pub fn test_inetv4_addr_to_sock_addr() {
@@ -11,12 +13,14 @@ pub fn test_inetv4_addr_to_sock_addr() {
match addr {
SockAddr::IpV4(addr) => {
- assert_eq!(addr.sin_addr.s_addr, Int::from_be(2130706433));
- assert_eq!(addr.sin_port, 3000);
+ assert_eq!(addr.sin_addr.s_addr, 0x7f000001.to_be());
+ assert_eq!(addr.sin_port, 3000.to_be());
}
_ => panic!("nope"),
}
+ assert_eq!(addr.to_str(), "127.0.0.1:3000");
+
let inet = FromSockAddr::from_sock_addr(&addr).unwrap();
assert_eq!(actual, inet);
}
@@ -37,3 +41,14 @@ pub fn test_path_to_sock_addr() {
let path: PathBuf = FromSockAddr::from_sock_addr(&addr).unwrap();
assert_eq!(actual, &*path);
}
+
+#[test]
+pub fn test_getsockname() {
+ use std::net::TcpListener;
+
+ let addr = localhost();
+ let sock = TcpListener::bind(&*addr).unwrap();
+ let res = getsockname(sock.as_raw_fd()).unwrap();
+
+ assert_eq!(addr, res.to_str());
+}
diff --git a/test/test.rs b/test/test.rs
index 0fd45f0b..7c5a6b20 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -5,27 +5,30 @@ extern crate libc;
extern crate rand;
mod sys;
+mod test_nix_path;
mod test_stat;
mod test_unistd;
-use nix::NixPath;
+mod ports {
+ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
+ use std::sync::atomic::Ordering::SeqCst;
-#[test]
-fn test_nix_path() {
- fn cstr_to_bytes(cstr: &*const libc::c_char, len: usize) -> &[u8] {
+ // Helper for getting a unique port for the task run
+ // TODO: Reuse ports to not spam the system
+ static mut NEXT_PORT: AtomicUsize = ATOMIC_USIZE_INIT;
+ const FIRST_PORT: usize = 18080;
+
+ pub fn next_port() -> usize {
unsafe {
- let cstr = cstr as *const _ as *const *const u8;
- std::slice::from_raw_parts(*cstr, len)
+ // If the atomic was never used, set it to the initial port
+ NEXT_PORT.compare_and_swap(0, FIRST_PORT, SeqCst);
+
+ // Get and increment the port list
+ NEXT_PORT.fetch_add(1, SeqCst)
}
}
- let bytes = b"abcd";
- let ok = bytes.with_nix_path(|cstr| {
- assert_eq!(b"abcd\0", cstr_to_bytes(&cstr, 5));
- });
- assert!(ok.is_ok());
-
- let bytes = b"ab\0cd";
- let err = bytes.with_nix_path(|_| {});
- assert!(err.is_err());
+ pub fn localhost() -> String {
+ format!("127.0.0.1:{}", next_port())
+ }
}
diff --git a/test/test_nix_path.rs b/test/test_nix_path.rs
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/test_nix_path.rs