• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use anyhow::Context;
6 use anyhow::Result;
7 use base::info;
8 use base::AsRawDescriptor;
9 use base::SafeDescriptor;
10 use cros_async::AsyncWrapper;
11 use cros_async::Executor;
12 use vmm_vhost::BackendServer;
13 use vmm_vhost::Error as VhostError;
14 
15 /// Performs the run loop for an already-constructor request handler.
run_handler<S>(mut backend_server: BackendServer<S>, ex: &Executor) -> Result<()> where S: vmm_vhost::Backend,16 pub async fn run_handler<S>(mut backend_server: BackendServer<S>, ex: &Executor) -> Result<()>
17 where
18     S: vmm_vhost::Backend,
19 {
20     let h = SafeDescriptor::try_from(&backend_server as &dyn AsRawDescriptor)
21         .map(AsyncWrapper::new)
22         .context("failed to get safe descriptor for handler")?;
23     let handler_source = ex
24         .async_from(h)
25         .context("failed to create an async source")?;
26 
27     loop {
28         handler_source
29             .wait_readable()
30             .await
31             .context("failed to wait for the handler to become readable")?;
32         let (hdr, files) = match backend_server.recv_header() {
33             Ok((hdr, files)) => (hdr, files),
34             Err(VhostError::ClientExit) => {
35                 info!("vhost-user connection closed");
36                 // Exit as the client closed the connection.
37                 return Ok(());
38             }
39             Err(e) => {
40                 return Err(e.into());
41             }
42         };
43 
44         if backend_server.needs_wait_for_payload(&hdr) {
45             handler_source
46                 .wait_readable()
47                 .await
48                 .context("failed to wait for the handler to become readable")?;
49         }
50         backend_server.process_message(hdr, files)?;
51     }
52 }
53 
54 #[cfg(test)]
55 pub mod test_helpers {
56     use std::os::unix::net::UnixStream;
57 
58     use tempfile::TempDir;
59     use vmm_vhost::connection::Listener;
60     use vmm_vhost::unix::SocketListener;
61     use vmm_vhost::BackendServer;
62 
setup() -> (SocketListener, TempDir)63     pub(crate) fn setup() -> (SocketListener, TempDir) {
64         let dir = tempfile::Builder::new()
65             .prefix("/tmp/vhost_test")
66             .tempdir()
67             .unwrap();
68         let mut path = dir.path().to_owned();
69         path.push("sock");
70         let listener = SocketListener::new(&path, true).unwrap();
71 
72         (listener, dir)
73     }
74 
connect(dir: tempfile::TempDir) -> UnixStream75     pub(crate) fn connect(dir: tempfile::TempDir) -> UnixStream {
76         let mut path = dir.path().to_owned();
77         path.push("sock");
78         UnixStream::connect(path).unwrap()
79     }
80 
listen<S: vmm_vhost::Backend>( mut listener: SocketListener, handler: S, ) -> BackendServer<S>81     pub(crate) fn listen<S: vmm_vhost::Backend>(
82         mut listener: SocketListener,
83         handler: S,
84     ) -> BackendServer<S> {
85         let connection = listener.accept().unwrap().unwrap();
86         BackendServer::new(connection, handler)
87     }
88 }
89