1 // Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 //! Traits and Structs for vhost-user slave. 5 6 use std::sync::Arc; 7 8 use super::connection::{Endpoint, Listener}; 9 use super::message::*; 10 use super::{Result, SlaveReqHandler, VhostUserSlaveReqHandler}; 11 12 /// Vhost-user slave side connection listener. 13 pub struct SlaveListener<S: VhostUserSlaveReqHandler> { 14 listener: Listener, 15 backend: Option<Arc<S>>, 16 } 17 18 /// Sets up a listener for incoming master connections, and handles construction 19 /// of a Slave on success. 20 impl<S: VhostUserSlaveReqHandler> SlaveListener<S> { 21 /// Create a unix domain socket for incoming master connections. new(listener: Listener, backend: Arc<S>) -> Result<Self>22 pub fn new(listener: Listener, backend: Arc<S>) -> Result<Self> { 23 Ok(SlaveListener { 24 listener, 25 backend: Some(backend), 26 }) 27 } 28 29 /// Accept an incoming connection from the master, returning Some(Slave) on 30 /// success, or None if the socket is nonblocking and no incoming connection 31 /// was detected accept(&mut self) -> Result<Option<SlaveReqHandler<S>>>32 pub fn accept(&mut self) -> Result<Option<SlaveReqHandler<S>>> { 33 if let Some(fd) = self.listener.accept()? { 34 return Ok(Some(SlaveReqHandler::new( 35 Endpoint::<MasterReq>::from_stream(fd), 36 self.backend.take().unwrap(), 37 ))); 38 } 39 Ok(None) 40 } 41 42 /// Change blocking status on the listener. set_nonblocking(&self, block: bool) -> Result<()>43 pub fn set_nonblocking(&self, block: bool) -> Result<()> { 44 self.listener.set_nonblocking(block) 45 } 46 } 47 48 #[cfg(test)] 49 mod tests { 50 use std::sync::Mutex; 51 52 use super::*; 53 use crate::vhost_user::dummy_slave::DummySlaveReqHandler; 54 55 #[test] test_slave_listener_set_nonblocking()56 fn test_slave_listener_set_nonblocking() { 57 let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new())); 58 let listener = 59 Listener::new("/tmp/vhost_user_lib_unit_test_slave_nonblocking", true).unwrap(); 60 let slave_listener = SlaveListener::new(listener, backend).unwrap(); 61 62 slave_listener.set_nonblocking(true).unwrap(); 63 slave_listener.set_nonblocking(false).unwrap(); 64 slave_listener.set_nonblocking(false).unwrap(); 65 slave_listener.set_nonblocking(true).unwrap(); 66 slave_listener.set_nonblocking(true).unwrap(); 67 } 68 69 #[cfg(feature = "vhost-user-master")] 70 #[test] test_slave_listener_accept()71 fn test_slave_listener_accept() { 72 use super::super::Master; 73 74 let path = "/tmp/vhost_user_lib_unit_test_slave_accept"; 75 let backend = Arc::new(Mutex::new(DummySlaveReqHandler::new())); 76 let listener = Listener::new(path, true).unwrap(); 77 let mut slave_listener = SlaveListener::new(listener, backend).unwrap(); 78 79 slave_listener.set_nonblocking(true).unwrap(); 80 assert!(slave_listener.accept().unwrap().is_none()); 81 assert!(slave_listener.accept().unwrap().is_none()); 82 83 let _master = Master::connect(path, 1).unwrap(); 84 let _slave = slave_listener.accept().unwrap().unwrap(); 85 } 86 } 87