1 // Copyright 2024 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::Context;
8 use base::AsRawDescriptor;
9 use base::RawDescriptor;
10 use cros_async::AsyncWrapper;
11 use cros_async::Executor;
12 use futures::Future;
13 use futures::FutureExt;
14 use vmm_vhost::connection::Listener;
15 use vmm_vhost::unix::SocketListener;
16 use vmm_vhost::BackendServer;
17
18 use crate::virtio::vhost::user::device::connection::VhostUserConnectionTrait;
19 use crate::virtio::vhost::user::device::handler::sys::linux::run_handler;
20
21 /// On Unix we can listen to a socket.
22 pub struct VhostUserListener(SocketListener);
23
24 impl VhostUserListener {
25 /// Create a vhost-user listener from a UNIX domain socket path.
new(path: &str) -> anyhow::Result<Self>26 pub fn new(path: &str) -> anyhow::Result<Self> {
27 let listener = SocketListener::new(path, true)?;
28
29 Ok(VhostUserListener(listener))
30 }
31 }
32
33 impl AsRawDescriptor for VhostUserListener {
as_raw_descriptor(&self) -> RawDescriptor34 fn as_raw_descriptor(&self) -> RawDescriptor {
35 self.0.as_raw_descriptor()
36 }
37 }
38
39 /// Attaches to an already bound socket via `listener` and handles incoming messages from the
40 /// VMM, which are dispatched to the device backend via the `VhostUserDevice` trait methods.
run_with_handler( mut listener: SocketListener, handler: Box<dyn vmm_vhost::Backend>, ex: &Executor, ) -> anyhow::Result<()>41 async fn run_with_handler(
42 mut listener: SocketListener,
43 handler: Box<dyn vmm_vhost::Backend>,
44 ex: &Executor,
45 ) -> anyhow::Result<()> {
46 listener.set_nonblocking(true)?;
47
48 loop {
49 // If the listener is not ready on the first call to `accept` and returns `None`, we
50 // temporarily convert it into an async I/O source and yield until it signals there is
51 // input data awaiting, before trying again.
52 match listener
53 .accept()
54 .context("failed to accept an incoming connection")?
55 {
56 Some(connection) => {
57 let req_handler = BackendServer::new(connection, handler);
58 return run_handler(req_handler, ex).await;
59 }
60 None => {
61 // Nobody is on the other end yet, wait until we get a connection.
62 let async_waiter = ex
63 .async_from(AsyncWrapper::new(listener))
64 .context("failed to create async waiter")?;
65 async_waiter.wait_readable().await?;
66
67 // Retrieve the listener back so we can use it again.
68 listener = async_waiter.into_source().into_inner();
69 }
70 }
71 }
72 }
73
74 impl VhostUserConnectionTrait for VhostUserListener {
run_req_handler<'e>( self, handler: Box<dyn vmm_vhost::Backend>, ex: &'e Executor, ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>75 fn run_req_handler<'e>(
76 self,
77 handler: Box<dyn vmm_vhost::Backend>,
78 ex: &'e Executor,
79 ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>> {
80 async { run_with_handler(self.0, handler, ex).await }.boxed_local()
81 }
82
take_parent_process_resources(&mut self) -> Option<Box<dyn std::any::Any>>83 fn take_parent_process_resources(&mut self) -> Option<Box<dyn std::any::Any>> {
84 self.0.take_resources_for_parent()
85 }
86 }
87