use std::os::unix::io::IntoRawFd;
use base::AsRawDescriptor;
use base::FromRawDescriptor;
use base::RawDescriptor;
use base::SafeDescriptor;
use crate::master_req_handler::MasterReqHandler;
use crate::Result;
use crate::VhostUserMasterReqHandler;
impl<S: VhostUserMasterReqHandler> AsRawDescriptor for MasterReqHandler<S> {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.sub_sock.as_raw_descriptor()
}
}
impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
pub fn with_stream(backend: S) -> Result<Self> {
Self::new(
backend,
Box::new(|stream|
unsafe {
SafeDescriptor::from_raw_descriptor(stream.into_raw_fd())
}),
)
}
}
#[cfg(test)]
mod tests {
use base::AsRawDescriptor;
use base::Descriptor;
use base::FromRawDescriptor;
use base::INVALID_DESCRIPTOR;
use super::*;
use crate::message::VhostUserFSSlaveMsg;
use crate::HandlerResult;
use crate::Slave;
use crate::SystemStream;
use crate::VhostUserMasterReqHandler;
struct MockMasterReqHandler {}
impl VhostUserMasterReqHandler for MockMasterReqHandler {
fn fs_slave_map(
&mut self,
_fs: &VhostUserFSSlaveMsg,
_fd: &dyn AsRawDescriptor,
) -> HandlerResult<u64> {
Ok(0)
}
fn fs_slave_unmap(&mut self, _fs: &VhostUserFSSlaveMsg) -> HandlerResult<u64> {
Err(std::io::Error::from_raw_os_error(libc::ENOSYS))
}
}
#[test]
fn test_new_master_req_handler() {
let backend = MockMasterReqHandler {};
let mut handler = MasterReqHandler::with_stream(backend).unwrap();
let tx_descriptor = handler.take_tx_descriptor();
assert!(tx_descriptor.as_raw_descriptor() >= 0);
assert!(handler.as_raw_descriptor() != INVALID_DESCRIPTOR);
}
#[test]
fn test_master_slave_req_handler() {
let backend = MockMasterReqHandler {};
let mut handler = MasterReqHandler::with_stream(backend).unwrap();
let tx_descriptor = handler.take_tx_descriptor();
let fd = unsafe { libc::dup(tx_descriptor.as_raw_descriptor()) };
if fd < 0 {
panic!("failed to duplicated tx fd!");
}
let stream = unsafe { SystemStream::from_raw_descriptor(fd) };
let mut fs_cache = Slave::from_stream(stream);
std::thread::spawn(move || {
let res = handler.handle_request().unwrap();
assert_eq!(res, 0);
handler.handle_request().unwrap_err();
});
fs_cache
.fs_slave_map(&VhostUserFSSlaveMsg::default(), &Descriptor(fd))
.unwrap();
fs_cache
.fs_slave_unmap(&VhostUserFSSlaveMsg::default())
.unwrap();
}
#[test]
fn test_master_slave_req_handler_with_ack() {
let backend = MockMasterReqHandler {};
let mut handler = MasterReqHandler::with_stream(backend).unwrap();
handler.set_reply_ack_flag(true);
let tx_descriptor = handler.take_tx_descriptor();
let fd = unsafe { libc::dup(tx_descriptor.as_raw_descriptor()) };
if fd < 0 {
panic!("failed to duplicated tx fd!");
}
let stream = unsafe { SystemStream::from_raw_descriptor(fd) };
let mut fs_cache = Slave::from_stream(stream);
std::thread::spawn(move || {
let res = handler.handle_request().unwrap();
assert_eq!(res, 0);
handler.handle_request().unwrap_err();
});
fs_cache.set_reply_ack_flag(true);
fs_cache
.fs_slave_map(&VhostUserFSSlaveMsg::default(), &Descriptor(fd))
.unwrap();
fs_cache
.fs_slave_unmap(&VhostUserFSSlaveMsg::default())
.unwrap_err();
}
}