| use std::io; | |
| use std::os::unix::net::UnixStream; | |
| use crate::conn::Connection; | |
| use crate::conn::ConnectionExt; | |
| // TODO: Remove PeekExt once rust-lang/rust#73761 is stabilized | |
| trait PeekExt { | |
| fn peek(&self, buf: &mut [u8]) -> io::Result<usize>; | |
| } | |
| impl PeekExt for UnixStream { | |
| #[cfg(feature = "paranoid_unsafe")] | |
| #[allow(clippy::panic)] | |
| fn peek(&self, _buf: &mut [u8]) -> io::Result<usize> { | |
| panic!("cannot use `UnixStream::peek` with `paranoid_unsafe` until rust-lang/rust#73761 is stabilized"); | |
| } | |
| #[cfg(not(feature = "paranoid_unsafe"))] | |
| #[allow(non_camel_case_types)] | |
| fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { | |
| use core::ffi::c_void; | |
| use std::os::unix::io::AsRawFd; | |
| // Define some libc types inline (to avoid bringing in entire libc dep) | |
| // every platform supported by the libc crate uses c_int = i32 | |
| type c_int = i32; | |
| type size_t = usize; | |
| type ssize_t = isize; | |
| const MSG_PEEK: c_int = 2; | |
| extern "C" { | |
| fn recv(socket: c_int, buf: *mut c_void, len: size_t, flags: c_int) -> ssize_t; | |
| } | |
| // from std/sys/unix/mod.rs | |
| pub fn cvt(t: isize) -> io::Result<isize> { | |
| if t == -1 { | |
| Err(io::Error::last_os_error()) | |
| } else { | |
| Ok(t) | |
| } | |
| } | |
| // from std/sys/unix/net.rs | |
| let ret = cvt(unsafe { | |
| recv( | |
| self.as_raw_fd(), | |
| buf.as_mut_ptr() as *mut c_void, | |
| buf.len(), | |
| MSG_PEEK, | |
| ) | |
| })?; | |
| Ok(ret as usize) | |
| } | |
| } | |
| impl Connection for UnixStream { | |
| type Error = std::io::Error; | |
| fn write(&mut self, byte: u8) -> Result<(), Self::Error> { | |
| use std::io::Write; | |
| Write::write_all(self, &[byte]) | |
| } | |
| fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> { | |
| use std::io::Write; | |
| Write::write_all(self, buf) | |
| } | |
| fn flush(&mut self) -> Result<(), Self::Error> { | |
| use std::io::Write; | |
| Write::flush(self) | |
| } | |
| } | |
| impl ConnectionExt for UnixStream { | |
| fn read(&mut self) -> Result<u8, Self::Error> { | |
| use std::io::Read; | |
| self.set_nonblocking(false)?; | |
| let mut buf = [0u8]; | |
| match Read::read_exact(self, &mut buf) { | |
| Ok(_) => Ok(buf[0]), | |
| Err(e) => Err(e), | |
| } | |
| } | |
| fn peek(&mut self) -> Result<Option<u8>, Self::Error> { | |
| self.set_nonblocking(true)?; | |
| let mut buf = [0u8]; | |
| match PeekExt::peek(self, &mut buf) { | |
| Ok(_) => Ok(Some(buf[0])), | |
| Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => Ok(None), | |
| Err(e) => Err(e), | |
| } | |
| } | |
| } |