2019-09-20 17:29:55 -04:00

90 lines
2.5 KiB
Rust

use std::os::unix::io::{AsRawFd,RawFd};
use crate::system::{self,FileDesc};
use crate::devices::virtio_wl::{
consts::{VIRTIO_WL_VFD_WRITE, VIRTIO_WL_VFD_READ, IN_BUFFER_LEN},
Error, Result, VfdObject, VfdRecv,
};
pub struct VfdPipe {
vfd_id: u32,
flags: u32,
local: Option<FileDesc>,
remote: Option<FileDesc>,
}
impl VfdPipe {
pub fn new(vfd_id: u32, read_pipe: FileDesc, write_pipe: FileDesc, local_write: bool) -> Self {
if local_write {
VfdPipe { vfd_id, local: Some(write_pipe), remote: Some(read_pipe), flags: VIRTIO_WL_VFD_WRITE }
} else {
VfdPipe { vfd_id, local: Some(read_pipe), remote: Some(write_pipe), flags: VIRTIO_WL_VFD_READ}
}
}
pub fn local_only(vfd_id: u32, local_pipe: FileDesc, flags: u32) -> Self {
VfdPipe { vfd_id, local: Some(local_pipe), remote: None, flags }
}
pub fn create(vfd_id: u32, local_write: bool) -> Result<Self> {
let mut pipe_fds: [libc::c_int; 2] = [-1; 2];
unsafe {
if libc::pipe2(pipe_fds.as_mut_ptr(), libc::O_CLOEXEC) < 0 {
return Err(Error::CreatePipesFailed(system::Error::last_os_error()));
}
let read_pipe = FileDesc::new(pipe_fds[0]);
let write_pipe = FileDesc::new(pipe_fds[1]);
Ok(Self::new(vfd_id, read_pipe, write_pipe, local_write))
}
}
}
impl VfdObject for VfdPipe {
fn id(&self) -> u32 {
self.vfd_id
}
fn send_fd(&self) -> Option<RawFd> {
self.remote.as_ref().map(|p| p.as_raw_fd())
}
fn poll_fd(&self) -> Option<RawFd> {
self.local.as_ref().map(|p| p.as_raw_fd())
}
fn recv(&mut self) -> Result<Option<VfdRecv>> {
if let Some(pipe) = self.local.take() {
let mut buf = vec![0; IN_BUFFER_LEN];
let len = pipe.read(&mut buf[..IN_BUFFER_LEN])
.map_err(Error::PipeReceive)?;
buf.truncate(len);
if buf.len() > 0 {
self.local.replace(pipe);
return Ok(Some(VfdRecv::new(buf)));
}
}
Ok(None)
}
fn send(&mut self, data: &[u8]) -> Result<()> {
if let Some(pipe) = self.local.as_ref() {
pipe.write_all(data).map_err(Error::SendVfd)
} else {
Err(Error::InvalidSendVfd)
}
}
fn flags(&self) -> u32 {
self.flags
}
fn close(&mut self) -> Result<()> {
self.local = None;
self.remote = None;
Ok(())
}
}