| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License.. |
| |
| use core::mem; |
| use core::fmt; |
| use crate::ascii; |
| use crate::ffi::OsStr; |
| use crate::io::{self, Initializer, IoSlice, IoSliceMut}; |
| use crate::net::{self, Shutdown}; |
| use crate::os::unix::ffi::OsStrExt; |
| use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; |
| use crate::path::Path; |
| use crate::time::Duration; |
| use crate::sys::{self, cvt}; |
| use crate::sys::net::Socket; |
| use crate::sys_common::{self, AsInner, FromInner, IntoInner}; |
| |
| fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { |
| // Work with an actual instance of the type since using a null pointer is UB |
| let base = addr as *const _ as usize; |
| let path = &addr.sun_path as *const _ as usize; |
| path - base |
| } |
| |
| unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { |
| let mut addr: libc::sockaddr_un = mem::zeroed(); |
| addr.sun_family = libc::AF_UNIX as libc::sa_family_t; |
| |
| let bytes = path.as_os_str().as_bytes(); |
| |
| if bytes.contains(&0) { |
| return Err(io::Error::new( |
| io::ErrorKind::InvalidInput, |
| "paths may not contain interior null bytes", |
| )); |
| } |
| |
| if bytes.len() >= addr.sun_path.len() { |
| return Err(io::Error::new( |
| io::ErrorKind::InvalidInput, |
| "path must be shorter than SUN_LEN", |
| )); |
| } |
| for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) { |
| *dst = *src as libc::c_char; |
| } |
| // null byte for pathname addresses is already there because we zeroed the |
| // struct |
| |
| let mut len = sun_path_offset(&addr) + bytes.len(); |
| match bytes.get(0) { |
| Some(&0) | None => {} |
| Some(_) => len += 1, |
| } |
| Ok((addr, len as libc::socklen_t)) |
| } |
| |
| enum AddressKind<'a> { |
| Unnamed, |
| Pathname(&'a Path), |
| Abstract(&'a [u8]), |
| } |
| |
| /// An address associated with a Unix socket. |
| /// |
| #[derive(Clone)] |
| pub struct SocketAddr { |
| addr: libc::sockaddr_un, |
| len: libc::socklen_t, |
| } |
| |
| impl SocketAddr { |
| fn new<F>(f: F) -> io::Result<SocketAddr> |
| where |
| F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int, |
| { |
| unsafe { |
| let mut addr: libc::sockaddr_un = mem::zeroed(); |
| let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t; |
| cvt(f(&mut addr as *mut _ as *mut _, &mut len))?; |
| SocketAddr::from_parts(addr, len) |
| } |
| } |
| |
| fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> { |
| if len == 0 { |
| // When there is a datagram from unnamed unix socket |
| // linux returns zero bytes of address |
| len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address |
| } else if 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", |
| )); |
| } |
| |
| Ok(SocketAddr { addr, len }) |
| } |
| |
| /// Returns `true` if the address is unnamed. |
| /// |
| pub fn is_unnamed(&self) -> bool { |
| if let AddressKind::Unnamed = self.address() { true } else { false } |
| } |
| |
| /// Returns the contents of this address if it is a `pathname` address. |
| /// |
| pub fn as_pathname(&self) -> Option<&Path> { |
| if let AddressKind::Pathname(path) = self.address() { Some(path) } else { None } |
| } |
| |
| fn address(&self) -> AddressKind<'_> { |
| let len = self.len as usize - sun_path_offset(&self.addr); |
| let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; |
| |
| // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses |
| if len == 0 |
| { |
| AddressKind::Unnamed |
| } else if self.addr.sun_path[0] == 0 { |
| AddressKind::Abstract(&path[1..len]) |
| } else { |
| AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref()) |
| } |
| } |
| } |
| |
| impl fmt::Debug for SocketAddr { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| match self.address() { |
| AddressKind::Unnamed => write!(fmt, "(unnamed)"), |
| AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), |
| AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), |
| } |
| } |
| } |
| |
| struct AsciiEscaped<'a>(&'a [u8]); |
| |
| impl<'a> fmt::Display for AsciiEscaped<'a> { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| write!(fmt, "\"")?; |
| for byte in self.0.iter().cloned().flat_map(ascii::escape_default) { |
| write!(fmt, "{}", byte as char)?; |
| } |
| write!(fmt, "\"") |
| } |
| } |
| |
| /// A Unix stream socket. |
| /// |
| pub struct UnixStream(Socket); |
| |
| impl fmt::Debug for UnixStream { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| let mut builder = fmt.debug_struct("UnixStream"); |
| builder.field("fd", self.0.as_inner()); |
| if let Ok(addr) = self.local_addr() { |
| builder.field("local", &addr); |
| } |
| if let Ok(addr) = self.peer_addr() { |
| builder.field("peer", &addr); |
| } |
| builder.finish() |
| } |
| } |
| |
| impl UnixStream { |
| /// Connects to the socket named by `path`. |
| /// |
| pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> { |
| fn inner(path: &Path) -> io::Result<UnixStream> { |
| unsafe { |
| let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; |
| let (addr, len) = sockaddr_un(path)?; |
| |
| cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?; |
| Ok(UnixStream(inner)) |
| } |
| } |
| inner(path.as_ref()) |
| } |
| |
| /// Creates an unnamed pair of connected sockets. |
| /// |
| /// Returns two `UnixStream`s which are connected to each other. |
| /// |
| pub fn pair() -> io::Result<(UnixStream, UnixStream)> { |
| let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?; |
| Ok((UnixStream(i1), UnixStream(i2))) |
| } |
| |
| /// Creates a new independently owned handle to the underlying socket. |
| /// |
| /// The returned `UnixStream` is a reference to the same stream that this |
| /// object references. Both handles will read and write the same stream of |
| /// data, and options set on one stream will be propagated to the other |
| /// stream. |
| /// |
| pub fn try_clone(&self) -> io::Result<UnixStream> { |
| self.0.duplicate().map(UnixStream) |
| } |
| |
| /// Returns the socket address of the local half of this connection. |
| /// |
| pub fn local_addr(&self) -> io::Result<SocketAddr> { |
| SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) |
| } |
| |
| /// Returns the socket address of the remote half of this connection. |
| /// |
| pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
| SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) |
| } |
| |
| /// Sets the read timeout for the socket. |
| /// |
| /// If the provided value is [`None`], then [`read`] calls will block |
| /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this |
| /// method. |
| /// |
| /// [`None`]: ../../../../std/option/enum.Option.html#variant.None |
| /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err |
| /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read |
| /// [`Duration`]: ../../../../std/time/struct.Duration.html |
| /// |
| pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { |
| self.0.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. An [`Err`] is returned if the zero [`Duration`] is |
| /// passed to this method. |
| /// |
| /// [`None`]: ../../../../std/option/enum.Option.html#variant.None |
| /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err |
| /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write |
| /// [`Duration`]: ../../../../std/time/struct.Duration.html |
| /// |
| pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { |
| self.0.set_timeout(timeout, libc::SO_SNDTIMEO) |
| } |
| |
| /// Returns the read timeout of this socket. |
| /// |
| pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
| self.0.timeout(libc::SO_RCVTIMEO) |
| } |
| |
| /// Returns the write timeout of this socket. |
| /// |
| pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
| self.0.timeout(libc::SO_SNDTIMEO) |
| } |
| |
| /// Moves the socket into or out of nonblocking mode. |
| /// |
| pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
| self.0.set_nonblocking(nonblocking) |
| } |
| |
| /// Returns the value of the `SO_ERROR` option. |
| /// |
| pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
| self.0.take_error() |
| } |
| |
| /// Shuts down the read, write, or both halves of this connection. |
| /// |
| /// This function will cause all pending and future I/O calls on the |
| /// specified portions to immediately return with an appropriate value |
| /// (see the documentation of [`Shutdown`]). |
| /// |
| /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html |
| /// |
| pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { |
| self.0.shutdown(how) |
| } |
| } |
| |
| impl io::Read for UnixStream { |
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
| io::Read::read(&mut &*self, buf) |
| } |
| |
| fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
| io::Read::read_vectored(&mut &*self, bufs) |
| } |
| |
| #[inline] |
| unsafe fn initializer(&self) -> Initializer { |
| Initializer::nop() |
| } |
| } |
| |
| impl<'a> io::Read for &'a UnixStream { |
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
| self.0.read(buf) |
| } |
| |
| fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
| self.0.read_vectored(bufs) |
| } |
| |
| #[inline] |
| unsafe fn initializer(&self) -> Initializer { |
| Initializer::nop() |
| } |
| } |
| |
| impl io::Write for UnixStream { |
| fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| io::Write::write(&mut &*self, buf) |
| } |
| |
| fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
| io::Write::write_vectored(&mut &*self, bufs) |
| } |
| |
| fn flush(&mut self) -> io::Result<()> { |
| io::Write::flush(&mut &*self) |
| } |
| } |
| |
| impl<'a> io::Write for &'a UnixStream { |
| fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
| self.0.write(buf) |
| } |
| |
| fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
| self.0.write_vectored(bufs) |
| } |
| |
| fn flush(&mut self) -> io::Result<()> { |
| Ok(()) |
| } |
| } |
| |
| impl AsRawFd for UnixStream { |
| fn as_raw_fd(&self) -> RawFd { |
| *self.0.as_inner() |
| } |
| } |
| |
| impl FromRawFd for UnixStream { |
| unsafe fn from_raw_fd(fd: RawFd) -> UnixStream { |
| UnixStream(Socket::from_inner(fd)) |
| } |
| } |
| |
| impl IntoRawFd for UnixStream { |
| fn into_raw_fd(self) -> RawFd { |
| self.0.into_inner() |
| } |
| } |
| |
| impl AsRawFd for net::TcpStream { |
| fn as_raw_fd(&self) -> RawFd { |
| *self.as_inner().socket().as_inner() |
| } |
| } |
| |
| impl AsRawFd for net::TcpListener { |
| fn as_raw_fd(&self) -> RawFd { |
| *self.as_inner().socket().as_inner() |
| } |
| } |
| |
| impl AsRawFd for net::UdpSocket { |
| fn as_raw_fd(&self) -> RawFd { |
| *self.as_inner().socket().as_inner() |
| } |
| } |
| |
| impl FromRawFd for net::TcpStream { |
| unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { |
| let socket = sys::net::Socket::from_inner(fd); |
| net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) |
| } |
| } |
| |
| impl FromRawFd for net::TcpListener { |
| unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { |
| let socket = sys::net::Socket::from_inner(fd); |
| net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) |
| } |
| } |
| |
| impl FromRawFd for net::UdpSocket { |
| unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { |
| let socket = sys::net::Socket::from_inner(fd); |
| net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) |
| } |
| } |
| |
| impl IntoRawFd for net::TcpStream { |
| fn into_raw_fd(self) -> RawFd { |
| self.into_inner().into_socket().into_inner() |
| } |
| } |
| |
| impl IntoRawFd for net::TcpListener { |
| fn into_raw_fd(self) -> RawFd { |
| self.into_inner().into_socket().into_inner() |
| } |
| } |
| |
| impl IntoRawFd for net::UdpSocket { |
| fn into_raw_fd(self) -> RawFd { |
| self.into_inner().into_socket().into_inner() |
| } |
| } |
| |
| /// A structure representing a Unix domain socket server. |
| /// |
| pub struct UnixListener(Socket); |
| |
| impl fmt::Debug for UnixListener { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| let mut builder = fmt.debug_struct("UnixListener"); |
| builder.field("fd", self.0.as_inner()); |
| if let Ok(addr) = self.local_addr() { |
| builder.field("local", &addr); |
| } |
| builder.finish() |
| } |
| } |
| |
| impl UnixListener { |
| /// Creates a new `UnixListener` bound to the specified socket. |
| /// |
| pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> { |
| fn inner(path: &Path) -> io::Result<UnixListener> { |
| unsafe { |
| let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; |
| let (addr, len) = sockaddr_un(path)?; |
| |
| cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; |
| cvt(libc::listen(*inner.as_inner(), 128))?; |
| |
| Ok(UnixListener(inner)) |
| } |
| } |
| inner(path.as_ref()) |
| } |
| |
| /// Accepts a new incoming connection to this listener. |
| /// |
| /// This function will block the calling thread until a new Unix connection |
| /// is established. When established, the corresponding [`UnixStream`] and |
| /// the remote peer's address will be returned. |
| /// |
| pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { |
| let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; |
| let mut len = mem::size_of_val(&storage) as libc::socklen_t; |
| let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?; |
| let addr = SocketAddr::from_parts(storage, len)?; |
| Ok((UnixStream(sock), addr)) |
| } |
| |
| /// Creates a new independently owned handle to the underlying socket. |
| /// |
| /// The returned `UnixListener` is a reference to the same socket that this |
| /// object references. Both handles can be used to accept incoming |
| /// connections and options set on one listener will affect the other. |
| /// |
| pub fn try_clone(&self) -> io::Result<UnixListener> { |
| self.0.duplicate().map(UnixListener) |
| } |
| |
| /// Returns the local socket address of this listener. |
| /// |
| pub fn local_addr(&self) -> io::Result<SocketAddr> { |
| SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) |
| } |
| |
| /// Moves the socket into or out of nonblocking mode. |
| /// |
| pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
| self.0.set_nonblocking(nonblocking) |
| } |
| |
| /// Returns the value of the `SO_ERROR` option. |
| /// |
| pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
| self.0.take_error() |
| } |
| |
| /// Returns an iterator over incoming connections. |
| /// |
| /// The iterator will never return [`None`] and will also not yield the |
| /// peer's [`SocketAddr`] structure. |
| /// |
| /// [`None`]: ../../../../std/option/enum.Option.html#variant.None |
| /// [`SocketAddr`]: struct.SocketAddr.html |
| /// |
| pub fn incoming(&self) -> Incoming<'_> { |
| Incoming { listener: self } |
| } |
| } |
| |
| impl AsRawFd for UnixListener { |
| fn as_raw_fd(&self) -> RawFd { |
| *self.0.as_inner() |
| } |
| } |
| |
| impl FromRawFd for UnixListener { |
| unsafe fn from_raw_fd(fd: RawFd) -> UnixListener { |
| UnixListener(Socket::from_inner(fd)) |
| } |
| } |
| |
| impl IntoRawFd for UnixListener { |
| fn into_raw_fd(self) -> RawFd { |
| self.0.into_inner() |
| } |
| } |
| |
| impl<'a> IntoIterator for &'a UnixListener { |
| type Item = io::Result<UnixStream>; |
| type IntoIter = Incoming<'a>; |
| |
| fn into_iter(self) -> Incoming<'a> { |
| self.incoming() |
| } |
| } |
| |
| /// An iterator over incoming connections to a [`UnixListener`]. |
| /// |
| /// It will never return [`None`]. |
| /// |
| /// [`None`]: ../../../../std/option/enum.Option.html#variant.None |
| /// [`UnixListener`]: struct.UnixListener.html |
| /// |
| #[derive(Debug)] |
| pub struct Incoming<'a> { |
| listener: &'a UnixListener, |
| } |
| |
| impl<'a> Iterator for Incoming<'a> { |
| type Item = io::Result<UnixStream>; |
| |
| fn next(&mut self) -> Option<io::Result<UnixStream>> { |
| Some(self.listener.accept().map(|s| s.0)) |
| } |
| |
| fn size_hint(&self) -> (usize, Option<usize>) { |
| (usize::max_value(), None) |
| } |
| } |
| |
| /// A Unix datagram socket. |
| /// |
| pub struct UnixDatagram(Socket); |
| |
| impl fmt::Debug for UnixDatagram { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| let mut builder = fmt.debug_struct("UnixDatagram"); |
| builder.field("fd", self.0.as_inner()); |
| if let Ok(addr) = self.local_addr() { |
| builder.field("local", &addr); |
| } |
| if let Ok(addr) = self.peer_addr() { |
| builder.field("peer", &addr); |
| } |
| builder.finish() |
| } |
| } |
| |
| impl UnixDatagram { |
| /// Creates a Unix datagram socket bound to the given path. |
| /// |
| pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> { |
| fn inner(path: &Path) -> io::Result<UnixDatagram> { |
| unsafe { |
| let socket = UnixDatagram::unbound()?; |
| let (addr, len) = sockaddr_un(path)?; |
| |
| cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; |
| |
| Ok(socket) |
| } |
| } |
| inner(path.as_ref()) |
| } |
| |
| /// Creates a Unix Datagram socket which is not bound to any address. |
| /// |
| pub fn unbound() -> io::Result<UnixDatagram> { |
| let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?; |
| Ok(UnixDatagram(inner)) |
| } |
| |
| /// Creates an unnamed pair of connected sockets. |
| /// |
| /// Returns two `UnixDatagrams`s which are connected to each other. |
| /// |
| pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> { |
| let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?; |
| Ok((UnixDatagram(i1), UnixDatagram(i2))) |
| } |
| |
| /// Connects 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. |
| /// |
| /// [`send`]: #method.send |
| /// [`recv`]: #method.recv |
| /// [`recv_from`]: #method.recv_from |
| /// |
| pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { |
| fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> { |
| unsafe { |
| let (addr, len) = sockaddr_un(path)?; |
| |
| cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?; |
| |
| Ok(()) |
| } |
| } |
| inner(self, path.as_ref()) |
| } |
| |
| /// Creates a new independently owned handle to the underlying socket. |
| /// |
| /// The returned `UnixDatagram` is a reference to the same socket that this |
| /// object references. Both handles can be used to accept incoming |
| /// connections and options set on one side will affect the other. |
| /// |
| pub fn try_clone(&self) -> io::Result<UnixDatagram> { |
| self.0.duplicate().map(UnixDatagram) |
| } |
| |
| /// Returns the address of this socket. |
| /// |
| pub fn local_addr(&self) -> io::Result<SocketAddr> { |
| SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) }) |
| } |
| |
| /// Returns the address of this socket's peer. |
| /// |
| /// The [`connect`] method will connect the socket to a peer. |
| /// |
| /// [`connect`]: #method.connect |
| /// |
| pub fn peer_addr(&self) -> io::Result<SocketAddr> { |
| SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) |
| } |
| |
| /// Receives data from the socket. |
| /// |
| /// On success, returns the number of bytes read and the address from |
| /// whence the data came. |
| /// |
| pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { |
| let mut count = 0; |
| let addr = SocketAddr::new(|addr, len| unsafe { |
| count = libc::recvfrom( |
| *self.0.as_inner(), |
| buf.as_mut_ptr() as *mut _, |
| buf.len(), |
| 0, |
| addr, |
| len, |
| ); |
| if count > 0 { |
| 1 |
| } else if count == 0 { |
| 0 |
| } else { |
| -1 |
| } |
| })?; |
| |
| 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<usize> { |
| self.0.read(buf) |
| } |
| |
| /// Sends data on the socket to the specified address. |
| /// |
| /// On success, returns the number of bytes written. |
| /// |
| pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> { |
| fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result<usize> { |
| unsafe { |
| let (addr, len) = sockaddr_un(path)?; |
| |
| let count = cvt(libc::sendto( |
| *d.0.as_inner(), |
| buf.as_ptr() as *const _, |
| buf.len(), |
| libc::MSG_NOSIGNAL, |
| &addr as *const _ as *const _, |
| len, |
| ))?; |
| Ok(count as usize) |
| } |
| } |
| inner(self, buf, path.as_ref()) |
| } |
| |
| /// Sends data on the socket to the socket's peer. |
| /// |
| /// 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<usize> { |
| self.0.write(buf) |
| } |
| |
| /// Sets the read timeout for the socket. |
| /// |
| /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will |
| /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] |
| /// is passed to this method. |
| /// |
| /// [`None`]: ../../../../std/option/enum.Option.html#variant.None |
| /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err |
| /// [`recv`]: #method.recv |
| /// [`recv_from`]: #method.recv_from |
| /// [`Duration`]: ../../../../std/time/struct.Duration.html |
| /// |
| pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { |
| self.0.set_timeout(timeout, libc::SO_RCVTIMEO) |
| } |
| |
| /// Sets the write timeout for the socket. |
| /// |
| /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will |
| /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this |
| /// method. |
| /// |
| /// [`None`]: ../../../../std/option/enum.Option.html#variant.None |
| /// [`send`]: #method.send |
| /// [`send_to`]: #method.send_to |
| /// [`Duration`]: ../../../../std/time/struct.Duration.html |
| /// |
| pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> { |
| self.0.set_timeout(timeout, libc::SO_SNDTIMEO) |
| } |
| |
| /// Returns the read timeout of this socket. |
| /// |
| pub fn read_timeout(&self) -> io::Result<Option<Duration>> { |
| self.0.timeout(libc::SO_RCVTIMEO) |
| } |
| |
| /// Returns the write timeout of this socket. |
| /// |
| pub fn write_timeout(&self) -> io::Result<Option<Duration>> { |
| self.0.timeout(libc::SO_SNDTIMEO) |
| } |
| |
| /// Moves the socket into or out of nonblocking mode. |
| /// |
| pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { |
| self.0.set_nonblocking(nonblocking) |
| } |
| |
| /// Returns the value of the `SO_ERROR` option. |
| /// |
| pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
| self.0.take_error() |
| } |
| |
| /// Shut down the read, write, or both halves of this connection. |
| /// |
| /// This function will cause all pending and future I/O calls on the |
| /// specified portions to immediately return with an appropriate value |
| /// (see the documentation of [`Shutdown`]). |
| /// |
| pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { |
| self.0.shutdown(how) |
| } |
| } |
| |
| impl AsRawFd for UnixDatagram { |
| fn as_raw_fd(&self) -> RawFd { |
| *self.0.as_inner() |
| } |
| } |
| |
| impl FromRawFd for UnixDatagram { |
| unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram { |
| UnixDatagram(Socket::from_inner(fd)) |
| } |
| } |
| |
| impl IntoRawFd for UnixDatagram { |
| fn into_raw_fd(self) -> RawFd { |
| self.0.into_inner() |
| } |
| } |
| |
| mod libc { |
| pub use sgx_trts::libc::*; |
| pub use sgx_trts::libc::ocall::{connect, listen, bind, sendto, recvfrom, getsockname, getpeername}; |
| } |