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