From 2067f035be2eeab7e9b26124ebe67943d975d3b3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 17 May 2015 21:24:09 -0700 Subject: [PATCH 1/7] Reset doc root --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 3758e17..999ddcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //! Support for Unix domain socket clients and servers. #![warn(missing_docs)] -#![doc(html_root_url="https://sfackler.github.io/rust-unix-socket/doc/v0.4.0")] +#![doc(html_root_url="https://sfackler.github.io/rust-unix-socket/doc/master")] extern crate debug_builders; extern crate libc; From e4ac9630fd83e4d0b47c0a0c950136e3d4eed76a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 17 May 2015 21:25:53 -0700 Subject: [PATCH 2/7] Add crates.io badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b14067f..6785a57 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # rust-unix-socket -[![Build Status](https://travis-ci.org/sfackler/rust-unix-socket.svg?branch=master)](https://travis-ci.org/sfackler/rust-unix-socket) +[![Build Status](https://travis-ci.org/sfackler/rust-unix-socket.svg?branch=master)](https://travis-ci.org/sfackler/rust-unix-socket) [![Latest Version](https://img.shields.io/crates/v/unix_socket.svg)](https://crates.io/crates/unix_socket) Support for Unix domain socket clients and servers. From 878116afe4396de1e4bd89f33487976b1c9d0b26 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 31 May 2015 22:23:08 -0700 Subject: [PATCH 3/7] Stop uploading master docs --- .travis.yml | 6 ------ .travis/update_docs.sh | 16 ---------------- 2 files changed, 22 deletions(-) delete mode 100755 .travis/update_docs.sh diff --git a/.travis.yml b/.travis.yml index 5b12545..5a87a1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,9 +5,3 @@ rust: - stable script: - cargo test -- cargo doc --no-deps -after_success: -- test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && test $TRAVIS_RUST_VERSION == "stable" && ./.travis/update_docs.sh -env: - global: - secure: BA+yYeuttSM6B9spxJMdsxyWbIJGLR97X4/XbZ5XwQKcf+iWA7ykAXrM1AG+1FFrWQP8581HdElC7rF8gMdexXpE/kjurFxgFD4QHj/HAmZkCqyv85IaoV8YP4VZMLbzStFAo8kgQZzmSRJMPdbi5ic94sDeP+NJjbmeRbDPepY= diff --git a/.travis/update_docs.sh b/.travis/update_docs.sh deleted file mode 100755 index 737f384..0000000 --- a/.travis/update_docs.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -set -o errexit -o nounset - -git clone --branch gh-pages "https://$GH_TOKEN@github.com/${TRAVIS_REPO_SLUG}.git" deploy_docs -cd deploy_docs - -git config user.name "Steven Fackler" -git config user.email "sfackler@gmail.com" - -rm -rf doc/master -mv ../target/doc doc/master - -git add -A . -git commit -m "rebuild pages at ${TRAVIS_COMMIT}" -git push From cbb2841d78212b79942e88eaaa091b69b467db4e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 31 May 2015 22:23:51 -0700 Subject: [PATCH 4/7] tweak readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6785a57..b0a3c48 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ Support for Unix domain socket clients and servers. -Documentation is available [here](https://sfackler.github.io/rust-unix-socket/doc/master/unix_socket). +[Documentation](https://sfackler.github.io/rust-unix-socket/doc/master/unix_socket) From c8bbde15035a0fad8e2e8b872a56611d8f2dbb79 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 2 Jun 2015 20:10:08 -0700 Subject: [PATCH 5/7] Implement FromRawFd under a feature --- .travis.yml | 1 + Cargo.toml | 3 +++ src/lib.rs | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5a87a1b..c8b0d1a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,4 @@ rust: - stable script: - cargo test +- test $TRAVIS_RUST_VERSION != "nightly" || cargo test --features "from_raw_fd" diff --git a/Cargo.toml b/Cargo.toml index fcc02bf..89622da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,6 @@ debug-builders = "0.1" [dev-dependencies] tempdir = "0.3" + +[features] +from_raw_fd = [] diff --git a/src/lib.rs b/src/lib.rs index 999ddcc..f8dcb55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -351,6 +351,16 @@ impl AsRawFd for UnixStream { } } +#[cfg(feature = "from_raw_fd")] +impl std::os::unix::io::FromRawFd for UnixStream { + /// Requires the `from_raw_fd` feature. + unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { + UnixStream { + inner: Inner(fd) + } + } +} + /// A structure representing a Unix domain socket server. /// /// # Examples @@ -480,6 +490,16 @@ impl AsRawFd for UnixListener { } } +#[cfg(feature = "from_raw_fd")] +impl std::os::unix::io::FromRawFd for UnixListener { + /// Requires the `from_raw_fd` feature. + unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { + UnixListener { + inner: Inner(fd) + } + } +} + impl<'a> IntoIterator for &'a UnixListener { type Item = io::Result; type IntoIter = Incoming<'a>; From 78cf9a487798766534baf9e6fd34756e84ddf913 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 2 Jun 2015 21:00:52 -0700 Subject: [PATCH 6/7] Implement socket timeouts behind a feature --- .travis.yml | 2 +- Cargo.toml | 1 + src/lib.rs | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 202 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c8b0d1a..2c28d60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,4 @@ rust: - stable script: - cargo test -- test $TRAVIS_RUST_VERSION != "nightly" || cargo test --features "from_raw_fd" +- test $TRAVIS_RUST_VERSION != "nightly" || cargo test --features "from_raw_fd socket_timeout" diff --git a/Cargo.toml b/Cargo.toml index 89622da..d3a36ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,4 @@ tempdir = "0.3" [features] from_raw_fd = [] +socket_timeout = [] diff --git a/src/lib.rs b/src/lib.rs index f8dcb55..373f607 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ //! Support for Unix domain socket clients and servers. #![warn(missing_docs)] #![doc(html_root_url="https://sfackler.github.io/rust-unix-socket/doc/master")] +#![cfg_attr(feature = "socket_timeout", feature(duration))] +#![cfg_attr(all(test, feature = "socket_timeout"), feature(duration_span))] extern crate debug_builders; extern crate libc; @@ -25,6 +27,14 @@ extern "C" { proto: libc::c_int, sv: *mut [libc::c_int; 2]) -> libc::c_int; + + #[cfg(feature = "socket_timeout")] + fn getsockopt(socket: libc::c_int, + level: libc::c_int, + option_name: libc::c_int, + option_value: *mut libc::c_void, + option_len: *mut libc::c_void) + -> libc::c_int; } fn sun_path_offset() -> usize { @@ -288,6 +298,116 @@ impl UnixStream { SocketAddr::new(self.inner.0, libc::getpeername) } + /// Sets the read timeout for the socket. + /// + /// If the provided value is `None`, then `read` calls will block + /// indefinitely. It is an error to pass the zero `Duration` to this + /// method. + /// + /// Requires the `socket_timeout` feature. + #[cfg(feature = "socket_timeout")] + pub fn set_read_timeout(&self, timeout: Option) -> io::Result<()> { + self.set_timeout(timeout, libc::SO_RCVTIMEO) + } + + /// Sets the write timeout for the socket. + /// + /// If the provided value is `None`, then `write` calls will block + /// indefinitely. It is an error to pass the zero `Duration` to this + /// method. + /// + /// Requires the `socket_timeout` feature. + #[cfg(feature = "socket_timeout")] + pub fn set_write_timeout(&self, timeout: Option) -> io::Result<()> { + self.set_timeout(timeout, libc::SO_SNDTIMEO) + } + + #[cfg(feature = "socket_timeout")] + fn set_timeout(&self, dur: Option, kind: libc::c_int) + -> io::Result<()> { + let timeout = match dur { + Some(dur) => { + if dur.secs() == 0 && dur.extra_nanos() == 0 { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } + + let secs = if dur.secs() > libc::time_t::max_value() as u64 { + libc::time_t::max_value() + } else { + dur.secs() as libc::time_t + }; + let mut timeout = libc::timeval { + tv_sec: secs, + tv_usec: (dur.extra_nanos() / 1000) as libc::suseconds_t, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => { + libc::timeval { + tv_sec: 0, + tv_usec: 0, + } + } + }; + + let ret = unsafe { + libc::setsockopt(self.inner.0, + libc::SOL_SOCKET, + kind, + &timeout as *const _ as *const _, + mem::size_of::() as libc::socklen_t) + }; + if ret != 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + } + + /// Returns the read timeout of this socket. + /// + /// Requires the `socket_timeout` feature. + #[cfg(feature = "socket_timeout")] + pub fn read_timeout(&self) -> io::Result> { + self.timeout(libc::SO_RCVTIMEO) + } + + /// Returns the write timeout of this socket. + /// + /// Requires the `socket_timeout` feature. + #[cfg(feature = "socket_timeout")] + pub fn write_timeout(&self) -> io::Result> { + self.timeout(libc::SO_SNDTIMEO) + } + + #[cfg(feature = "socket_timeout")] + fn timeout(&self, kind: libc::c_int) -> io::Result> { + let timeout = unsafe { + let mut timeout: libc::timeval = mem::zeroed(); + let mut size = mem::size_of::() as libc::socklen_t; + let ret = getsockopt(self.inner.0, + libc::SOL_SOCKET, + kind, + &mut timeout as *mut _ as *mut _, + &mut size as *mut _ as *mut _); + if ret != 0 { + return Err(io::Error::last_os_error()); + } + timeout + }; + + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + Ok(None) + } else { + Ok(Some(std::time::Duration::new(timeout.tv_sec as u64, + (timeout.tv_usec as u32) * 1000))) + } + } + /// Shut down the read, write, or both halves of this connection. /// /// This function will cause all pending and future I/O calls on the @@ -689,4 +809,84 @@ mod test { Ok(_) => panic!("unexpected success"), } } + + #[test] + #[cfg(feature = "socket_timeout")] + fn timeouts() { + use std::time::Duration; + + let dir = or_panic!(TempDir::new("unix_socket")); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let stream = or_panic!(UnixStream::connect(&socket_path)); + let dur = Duration::new(15410, 0); + + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.read_timeout())); + + assert_eq!(None, or_panic!(stream.write_timeout())); + + or_panic!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.write_timeout())); + + or_panic!(stream.set_read_timeout(None)); + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_write_timeout(None)); + assert_eq!(None, or_panic!(stream.write_timeout())); + } + + #[test] + #[cfg(feature = "socket_timeout")] + fn test_read_timeout() { + use std::time::Duration; + + let dir = or_panic!(TempDir::new("unix_socket")); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + let wait = Duration::span(|| { + let kind = stream.read(&mut buf).err().expect("expected error").kind(); + assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut); + }); + assert!(wait > Duration::from_millis(400)); + assert!(wait < Duration::from_millis(1600)); + } + + #[test] + #[cfg(feature = "socket_timeout")] + fn test_read_with_timeout() { + use std::time::Duration; + + let dir = or_panic!(TempDir::new("unix_socket")); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut other_end = or_panic!(listener.accept()); + or_panic!(other_end.write_all(b"hello world")); + + let mut buf = [0; 11]; + or_panic!(stream.read(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let wait = Duration::span(|| { + let kind = stream.read(&mut buf).err().expect("expected error").kind(); + assert!(kind == io::ErrorKind::WouldBlock || kind == io::ErrorKind::TimedOut); + }); + assert!(wait > Duration::from_millis(400)); + assert!(wait < Duration::from_millis(1600)); + } } From fe66caf0e6ea3f9b4cae7fdee7464ed245937b63 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 2 Jun 2015 21:02:54 -0700 Subject: [PATCH 7/7] Release v0.4.1 --- Cargo.toml | 4 ++-- README.md | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3a36ac..030c59b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "unix_socket" -version = "0.4.0" +version = "0.4.1" authors = ["Steven Fackler "] license = "MIT" description = "Unix domain socket bindings" repository = "https://github.com/sfackler/rust-unix-socket" -documentation = "https://sfackler.github.io/rust-unix-socket/doc/v0.4.0/unix_socket" +documentation = "https://sfackler.github.io/rust-unix-socket/doc/v0.4.1/unix_socket" readme = "README.md" keywords = ["posix", "unix", "socket", "domain"] diff --git a/README.md b/README.md index b0a3c48..87ddee5 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ Support for Unix domain socket clients and servers. -[Documentation](https://sfackler.github.io/rust-unix-socket/doc/master/unix_socket) +[Documentation](https://sfackler.github.io/rust-unix-socket/doc/v0.4.1/unix_socket) diff --git a/src/lib.rs b/src/lib.rs index 373f607..f8b3aeb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //! Support for Unix domain socket clients and servers. #![warn(missing_docs)] -#![doc(html_root_url="https://sfackler.github.io/rust-unix-socket/doc/master")] +#![doc(html_root_url="https://sfackler.github.io/rust-unix-socket/doc/v0.4.1")] #![cfg_attr(feature = "socket_timeout", feature(duration))] #![cfg_attr(all(test, feature = "socket_timeout"), feature(duration_span))]