// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved. // SPDX-License-Identifier: Apache-2.0 //! Traits and Structs for vhost-user slave. use std::sync::Arc; use super::connection::{Endpoint, Listener}; use super::message::*; use super::{Result, SlaveReqHandler, VhostUserSlaveReqHandler}; /// Vhost-user slave side connection listener. pub struct SlaveListener { listener: Listener, backend: Option>, } /// Sets up a listener for incoming master connections, and handles construction /// of a Slave on success. impl SlaveListener { /// Create a unix domain socket for incoming master connections. pub fn new(listener: Listener, backend: Arc) -> Result { Ok(SlaveListener { listener, backend: Some(backend), }) } /// Accept an incoming connection from the master, returning Some(Slave) on /// success, or None if the socket is nonblocking and no incoming connection /// was detected pub fn accept(&mut self) -> Result>> { if let Some(fd) = self.listener.accept()? { return Ok(Some(SlaveReqHandler::new( Endpoint::::from_stream(fd), self.backend.take().unwrap(), ))); } Ok(None) } /// Change blocking status on the listener. pub fn set_nonblocking(&self, block: bool) -> Result<()> { self.listener.set_nonblocking(block) } } #[cfg(test)] mod tests { use std::sync::Mutex; use super::*; use crate::vhost_user::dummy_slave::DummySlaveReqHandler; #[test] fn test_slave_listener_set_nonblocking() { let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new())); let listener = Listener::new("/tmp/vhost_user_lib_unit_test_slave_nonblocking", true).unwrap(); let slave_listener = SlaveListener::new(listener, backend).unwrap(); slave_listener.set_nonblocking(true).unwrap(); slave_listener.set_nonblocking(false).unwrap(); slave_listener.set_nonblocking(false).unwrap(); slave_listener.set_nonblocking(true).unwrap(); slave_listener.set_nonblocking(true).unwrap(); } #[cfg(feature = "vhost-user-master")] #[test] fn test_slave_listener_accept() { use super::super::Master; let path = "/tmp/vhost_user_lib_unit_test_slave_accept"; let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new())); let listener = Listener::new(path, true).unwrap(); let mut slave_listener = SlaveListener::new(listener, backend).unwrap(); slave_listener.set_nonblocking(true).unwrap(); assert!(slave_listener.accept().unwrap().is_none()); assert!(slave_listener.accept().unwrap().is_none()); let _master = Master::connect(path, 1).unwrap(); let _slave = slave_listener.accept().unwrap().unwrap(); } }