From d7fc028cd9715f600f9c217dee3bd327972101dc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 17 Jun 2015 22:37:33 -0700 Subject: [PATCH 1/8] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3beb117..f44ad02 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/v0.4.2/unix_socket) +[Documentation](https://sfackler.github.io/rust-unix-socket/doc/v0.4.3/unix_socket) From d0f47ae888267a718072c3be5eed42ba1f637097 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 23 Jun 2015 23:33:22 -0700 Subject: [PATCH 2/8] Move from_raw_fd docs so they render --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0848a64..e2ae1a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -472,8 +472,8 @@ impl AsRawFd for UnixStream { } #[cfg(feature = "from_raw_fd")] +/// Requires the `from_raw_fd` feature. 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) @@ -591,8 +591,8 @@ impl AsRawFd for UnixListener { } #[cfg(feature = "from_raw_fd")] +/// Requires the `from_raw_fd` feature. 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) @@ -772,8 +772,8 @@ impl AsRawFd for UnixDatagram { } #[cfg(feature = "from_raw_fd")] +/// Requires the `from_raw_fd` feature. impl std::os::unix::io::FromRawFd for UnixDatagram { - /// Requires the `from_raw_fd` feature. unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { UnixDatagram { inner: Inner(fd) From 232823d20fbe7901dfd80082461da11542bcfcc5 Mon Sep 17 00:00:00 2001 From: Paul Colomiets Date: Fri, 31 Jul 2015 14:59:54 +0300 Subject: [PATCH 3/8] Implement UnixDatagram::new() Datagram sockets may be created without being bind'ed. Then you can use `send_to` to send data throught the socket. This also required to handle zero-length addresses returned from recv_from (at least on linux) Also adds PartialEq/Eq for AddressKind (needed for tests) --- src/lib.rs | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e2ae1a8..e46240c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ use std::os::unix::io::{RawFd, AsRawFd}; use std::os::unix::ffi::OsStrExt; use std::fmt; use std::path::Path; +use std::mem::size_of; extern "C" { fn socketpair(domain: libc::c_int, @@ -202,7 +203,7 @@ unsafe fn sockaddr_un>(path: P) } /// The kind of an address associated with a Unix socket. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AddressKind<'a> { /// An unnamed address. Unnamed, @@ -237,7 +238,13 @@ impl SocketAddr { let mut len = mem::size_of::() as libc::socklen_t; try!(cvt(f(&mut addr as *mut _ as *mut _, &mut len))); - if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { + if len == 0 { + // When there is a datagram from unnamed unix socket + // linux returns zero bytes of address + len = sun_path_offset() as libc::socklen_t; // i.e. zero-length address + } else if (len as usize) < size_of::() || + addr.sun_family != libc::AF_UNIX as libc::sa_family_t + { return Err(io::Error::new(io::ErrorKind::InvalidInput, "file descriptor did not correspond to a Unix socket")); } @@ -672,6 +679,15 @@ impl UnixDatagram { } } + /// Creates a Unix Datagram socket which is not bound to any address + /// you may use send_to to send message (but probably can't receive) + pub fn new() -> io::Result { + let inner = try!(Inner::new(libc::SOCK_DGRAM)); + Ok(UnixDatagram { + inner: inner, + }) + } + /// Returns the address of this socket. pub fn local_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.inner.0, addr, len) }) @@ -790,7 +806,7 @@ mod test { use std::io::prelude::*; use self::tempdir::TempDir; - use {UnixListener, UnixStream, UnixDatagram}; + use {UnixListener, UnixStream, UnixDatagram, AddressKind}; macro_rules! or_panic { ($e:expr) => { @@ -1037,4 +1053,21 @@ mod test { or_panic!(sock2.recv_from(&mut buf)); assert_eq!(msg, &buf[..]); } + + #[test] + fn test_unnamed_unix_datagram() { + let dir = or_panic!(TempDir::new("unix_socket")); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::new()); + + let msg = b"hello world"; + or_panic!(sock2.send_to(msg, &path1)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert_eq!(addr.address(), AddressKind::Unnamed); + assert_eq!(msg, &buf[..]); + } } From e2c36c6a0c022ae3c7d391a7d9b60960ddc80309 Mon Sep 17 00:00:00 2001 From: Paul Colomiets Date: Mon, 3 Aug 2015 12:47:35 +0300 Subject: [PATCH 4/8] Implement `UnixDatagram::connect()` --- src/lib.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e46240c..75dc286 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -688,6 +688,22 @@ impl UnixDatagram { }) } + /// Creates a Unix Datagram socket which is connected to specified addresss + /// the socket is unnamed and similar to one created by `new()` except + /// it will send message to the specified addresss *by default* + pub fn connect>(path: P) -> io::Result { + unsafe { + let inner = try!(Inner::new(libc::SOCK_DGRAM)); + let (addr, len) = try!(sockaddr_un(path)); + + try!(cvt(libc::connect(inner.0, &addr as *const _ as *const _, len))); + + Ok(UnixDatagram { + inner: inner, + }) + } + } + /// Returns the address of this socket. pub fn local_addr(&self) -> io::Result { SocketAddr::new(|addr, len| unsafe { libc::getsockname(self.inner.0, addr, len) }) @@ -731,6 +747,21 @@ impl UnixDatagram { } } + /// Sends data on the socket to the default address. + /// + /// Default address is set when socket was created by `connect()` constructor + /// + /// On success, returns the number of bytes written. + pub fn send(&self, buf: &[u8]) -> io::Result { + unsafe { + let count = try!(cvt_s(libc::send(self.inner.0, + buf.as_ptr() as *const _, + calc_len(buf), + 0))); + Ok(count as usize) + } + } + /// Sets the read timeout for the socket. /// /// If the provided value is `None`, then `recv_from` calls will block @@ -1070,4 +1101,28 @@ mod test { assert_eq!(addr.address(), AddressKind::Unnamed); assert_eq!(msg, &buf[..]); } + + #[test] + fn test_connect_unix_datagram() { + let dir = or_panic!(TempDir::new("unix_socket")); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::connect(&path1)); + + // Check send() + let msg = b"hello there"; + or_panic!(sock2.send(msg)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert_eq!(addr.address(), AddressKind::Unnamed); + assert_eq!(msg, &buf[..]); + + // Send to should still work too + let msg = b"hello world"; + or_panic!(sock2.send_to(msg, &path1)); + or_panic!(sock1.recv_from(&mut buf)); + assert_eq!(msg, &buf[..]); + } } From e1d857525554158fd4ce13d42f081e4bcb6f9b18 Mon Sep 17 00:00:00 2001 From: Paul Colomiets Date: Thu, 6 Aug 2015 02:47:49 +0300 Subject: [PATCH 5/8] Made `UnixDatagram::connect()` a method instead of constructor --- src/lib.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 75dc286..d6c98cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -691,16 +691,15 @@ impl UnixDatagram { /// Creates a Unix Datagram socket which is connected to specified addresss /// the socket is unnamed and similar to one created by `new()` except /// it will send message to the specified addresss *by default* - pub fn connect>(path: P) -> io::Result { + pub fn connect>(&mut self, path: P) + -> io::Result<()> + { unsafe { - let inner = try!(Inner::new(libc::SOCK_DGRAM)); let (addr, len) = try!(sockaddr_un(path)); - try!(cvt(libc::connect(inner.0, &addr as *const _ as *const _, len))); + try!(cvt(libc::connect(self.inner.0, &addr as *const _ as *const _, len))); - Ok(UnixDatagram { - inner: inner, - }) + Ok(()) } } @@ -1106,23 +1105,32 @@ mod test { fn test_connect_unix_datagram() { let dir = or_panic!(TempDir::new("unix_socket")); let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::connect(&path1)); + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + let mut sock = or_panic!(UnixDatagram::new()); + or_panic!(sock.connect(&path1)); // Check send() let msg = b"hello there"; - or_panic!(sock2.send(msg)); + or_panic!(sock.send(msg)); let mut buf = [0; 11]; - let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); + let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); assert_eq!(usize, 11); assert_eq!(addr.address(), AddressKind::Unnamed); assert_eq!(msg, &buf[..]); + // Send to should still work too let msg = b"hello world"; - or_panic!(sock2.send_to(msg, &path1)); - or_panic!(sock1.recv_from(&mut buf)); + or_panic!(sock.send_to(msg, &path2)); + or_panic!(bsock2.recv_from(&mut buf)); assert_eq!(msg, &buf[..]); + + // Changing default socket works too + or_panic!(sock.connect(&path2)); + or_panic!(sock.send(msg)); + or_panic!(bsock2.recv_from(&mut buf)); } } From 637f0e08a4e55c293608a7fc9d90d6c81a86f7b3 Mon Sep 17 00:00:00 2001 From: Paul Colomiets Date: Thu, 6 Aug 2015 03:01:22 +0300 Subject: [PATCH 6/8] Implement `recv()` call for datagram sockets --- src/lib.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index d6c98cc..19ff53b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -729,6 +729,19 @@ impl UnixDatagram { Ok((count as usize, addr)) } + /// Receives data from the socket. + /// + /// On success, returns the number of bytes read + pub fn recv(&self, buf: &mut [u8]) -> io::Result { + unsafe { + let count = try!(cvt_s(libc::recv(self.inner.0, + buf.as_mut_ptr() as *mut _, + calc_len(buf), + 0))); + Ok(count as usize) + } + } + /// Sends data on the socket to the given address. /// /// On success, returns the number of bytes written. @@ -1133,4 +1146,21 @@ mod test { or_panic!(sock.send(msg)); or_panic!(bsock2.recv_from(&mut buf)); } + + #[test] + fn test_unix_datagram_recv() { + let dir = or_panic!(TempDir::new("unix_socket")); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let mut sock2 = or_panic!(UnixDatagram::new()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send_to(msg, &path1)); + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } } From 2e2bdfcd4e4422e9838f39e11bb63155fc9e73ae Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 5 Aug 2015 20:24:48 -0700 Subject: [PATCH 7/8] Tweak methods and docs before release --- src/lib.rs | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 19ff53b..ae8846d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -665,7 +665,7 @@ impl fmt::Debug for UnixDatagram { } impl UnixDatagram { - /// Creates a Unix datagram socket from the given path. + /// Creates a Unix datagram socket bound to the given path. pub fn bind>(path: P) -> io::Result { unsafe { let inner = try!(Inner::new(libc::SOCK_DGRAM)); @@ -679,19 +679,19 @@ impl UnixDatagram { } } - /// Creates a Unix Datagram socket which is not bound to any address - /// you may use send_to to send message (but probably can't receive) - pub fn new() -> io::Result { + /// Creates a Unix Datagram socket which is not bound to any address. + pub fn unbound() -> io::Result { let inner = try!(Inner::new(libc::SOCK_DGRAM)); Ok(UnixDatagram { inner: inner, }) } - /// Creates a Unix Datagram socket which is connected to specified addresss - /// the socket is unnamed and similar to one created by `new()` except - /// it will send message to the specified addresss *by default* - pub fn connect>(&mut self, path: P) + /// Connect the socket to the specified address. + /// + /// The `send` method may be used to send data to the specified address. + /// `recv` and `recv_from` will only receive data from that address. + pub fn connect>(&self, path: P) -> io::Result<()> { unsafe { @@ -731,18 +731,18 @@ impl UnixDatagram { /// Receives data from the socket. /// - /// On success, returns the number of bytes read + /// On success, returns the number of bytes read. pub fn recv(&self, buf: &mut [u8]) -> io::Result { unsafe { let count = try!(cvt_s(libc::recv(self.inner.0, - buf.as_mut_ptr() as *mut _, - calc_len(buf), - 0))); + buf.as_mut_ptr() as *mut _, + calc_len(buf), + 0))); Ok(count as usize) } } - /// Sends data on the socket to the given address. + /// Sends data on the socket to the specified address. /// /// On success, returns the number of bytes written. pub fn send_to>(&self, buf: &[u8], path: P) -> io::Result { @@ -759,9 +759,10 @@ impl UnixDatagram { } } - /// Sends data on the socket to the default address. + /// Sends data on the socket to the socket's peer. /// - /// Default address is set when socket was created by `connect()` constructor + /// The peer address may be set by the `connect` method, and this method + /// will return an error if the socket has not already been connected. /// /// On success, returns the number of bytes written. pub fn send(&self, buf: &[u8]) -> io::Result { @@ -1103,7 +1104,7 @@ mod test { let path1 = dir.path().join("sock1"); let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::new()); + let sock2 = or_panic!(UnixDatagram::unbound()); let msg = b"hello world"; or_panic!(sock2.send_to(msg, &path1)); @@ -1122,7 +1123,7 @@ mod test { let bsock1 = or_panic!(UnixDatagram::bind(&path1)); let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - let mut sock = or_panic!(UnixDatagram::new()); + let sock = or_panic!(UnixDatagram::unbound()); or_panic!(sock.connect(&path1)); // Check send() @@ -1153,7 +1154,7 @@ mod test { let path1 = dir.path().join("sock1"); let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let mut sock2 = or_panic!(UnixDatagram::new()); + let sock2 = or_panic!(UnixDatagram::unbound()); or_panic!(sock2.connect(&path1)); let msg = b"hello world"; From 1a5023e2870fe0d6d3014d561328dd0599e04ca3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 5 Aug 2015 20:28:49 -0700 Subject: [PATCH 8/8] Release v0.4.4 --- 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 061468e..d7acea1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "unix_socket" -version = "0.4.3" +version = "0.4.4" 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.3/unix_socket" +documentation = "https://sfackler.github.io/rust-unix-socket/doc/v0.4.4/unix_socket" readme = "README.md" keywords = ["posix", "unix", "socket", "domain"] diff --git a/README.md b/README.md index f44ad02..544dea3 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/v0.4.3/unix_socket) +[Documentation](https://sfackler.github.io/rust-unix-socket/doc/v0.4.4/unix_socket) diff --git a/src/lib.rs b/src/lib.rs index ae8846d..c35f640 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.3")] +#![doc(html_root_url="https://sfackler.github.io/rust-unix-socket/doc/v0.4.4")] #![cfg_attr(feature = "socket_timeout", feature(duration))] #![cfg_attr(all(test, feature = "socket_timeout"), feature(duration_span))]