• 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 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