• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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