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 std::pin::pin;
6
7 use anyhow::bail;
8 use anyhow::Context;
9 use anyhow::Result;
10 use base::info;
11 use base::AsRawDescriptor;
12 use base::SafeDescriptor;
13 use cros_async::AsyncWrapper;
14 use cros_async::Executor;
15 use futures::channel::oneshot;
16 use futures::future::FutureExt;
17 use vmm_vhost::Error as VhostError;
18 use vmm_vhost::FrontendServer;
19
20 use crate::virtio::vhost_user_frontend::handler::BackendReqHandler;
21 use crate::virtio::vhost_user_frontend::handler::BackendReqHandlerImpl;
22 use crate::virtio::vhost_user_frontend::Error;
23 use crate::virtio::vhost_user_frontend::Result as VhostResult;
24
create_backend_req_handler( h: BackendReqHandlerImpl, ) -> VhostResult<(BackendReqHandler, SafeDescriptor)>25 pub fn create_backend_req_handler(
26 h: BackendReqHandlerImpl,
27 ) -> VhostResult<(BackendReqHandler, SafeDescriptor)> {
28 FrontendServer::with_stream(h).map_err(Error::CreateBackendReqHandler)
29 }
30
31 /// Process requests from the backend.
32 ///
33 /// If `stop_rx` is sent a value, the function will exit at a well defined point so that
34 /// `run_backend_request_handler` can be re-invoked to resume processing the connection.
run_backend_request_handler( ex: &Executor, handler: &mut BackendReqHandler, mut stop_rx: oneshot::Receiver<()>, ) -> Result<()>35 pub async fn run_backend_request_handler(
36 ex: &Executor,
37 handler: &mut BackendReqHandler,
38 mut stop_rx: oneshot::Receiver<()>,
39 ) -> Result<()> {
40 let h = SafeDescriptor::try_from(handler as &dyn AsRawDescriptor)
41 .map(AsyncWrapper::new)
42 .context("failed to get safe descriptor for handler")?;
43 let handler_source = ex
44 .async_from(h)
45 .context("failed to create an async source")?;
46
47 let mut wait_readable_future = pin!(handler_source.wait_readable().fuse());
48
49 loop {
50 futures::select_biased! {
51 _ = stop_rx => return Ok(()),
52 r = wait_readable_future => {
53 r.context("failed to wait for the handler to become readable")?;
54 match handler.handle_request() {
55 Ok(_) => (),
56 Err(VhostError::ClientExit) => {
57 info!("vhost-user connection closed");
58 // Exit as the client closed the connection.
59 return Ok(());
60 }
61 Err(e) => {
62 bail!("failed to handle a vhost-user request: {}", e);
63 }
64 };
65 wait_readable_future.set(handler_source.wait_readable().fuse());
66 }
67 };
68 }
69 }
70