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::fs;
6 use std::os::unix::fs::FileTypeExt;
7 use std::os::unix::net::UnixStream;
8 use std::path::Path;
9 use std::path::PathBuf;
10 use std::pin::Pin;
11
12 use base::safe_descriptor_from_cmdline_fd;
13 use base::AsRawDescriptor;
14 use base::RawDescriptor;
15 use cros_async::Executor;
16 use futures::Future;
17 use futures::FutureExt;
18 use vmm_vhost::BackendServer;
19 use vmm_vhost::Connection;
20 use vmm_vhost::Error::SocketFromFdError;
21
22 use crate::virtio::vhost::user::device::connection::VhostUserConnectionTrait;
23 use crate::virtio::vhost::user::device::handler::sys::linux::run_handler;
24
25 /// Connection from connected socket
26 pub struct VhostUserStream(UnixStream);
27
path_is_socket(path: &Path) -> bool28 fn path_is_socket(path: &Path) -> bool {
29 match fs::metadata(path) {
30 Ok(metadata) => metadata.file_type().is_socket(),
31 Err(_) => false, // Assume not a socket if we can't get metadata
32 }
33 }
34
35 impl VhostUserStream {
36 /// Creates a new vhost-user listener from an existing connected socket file descriptor.
37 ///
38 /// # Errors
39 ///
40 /// Returns an error if:
41 /// - The provided file descriptor is not a socket.
42 /// - An error occurs while creating the underlying `SocketListener`.
new_socket_from_fd(socket_fd: RawDescriptor) -> anyhow::Result<Self>43 pub fn new_socket_from_fd(socket_fd: RawDescriptor) -> anyhow::Result<Self> {
44 let path = PathBuf::from(format!("/proc/self/fd/{}", socket_fd));
45 if !path_is_socket(&path) {
46 return Err(SocketFromFdError(path).into());
47 }
48
49 let safe_fd = safe_descriptor_from_cmdline_fd(&socket_fd)?;
50
51 let stream = UnixStream::from(safe_fd);
52
53 Ok(VhostUserStream(stream))
54 }
55 }
56
57 impl VhostUserConnectionTrait for VhostUserStream {
run_req_handler<'e>( self, handler: Box<dyn vmm_vhost::Backend>, ex: &'e Executor, ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>58 fn run_req_handler<'e>(
59 self,
60 handler: Box<dyn vmm_vhost::Backend>,
61 ex: &'e Executor,
62 ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>> {
63 async { stream_run_with_handler(self.0, handler, ex).await }.boxed_local()
64 }
65 }
66
67 impl AsRawDescriptor for VhostUserStream {
as_raw_descriptor(&self) -> RawDescriptor68 fn as_raw_descriptor(&self) -> RawDescriptor {
69 self.0.as_raw_descriptor()
70 }
71 }
72
stream_run_with_handler( stream: UnixStream, handler: Box<dyn vmm_vhost::Backend>, ex: &Executor, ) -> anyhow::Result<()>73 async fn stream_run_with_handler(
74 stream: UnixStream,
75 handler: Box<dyn vmm_vhost::Backend>,
76 ex: &Executor,
77 ) -> anyhow::Result<()> {
78 let req_handler = BackendServer::new(Connection::try_from(stream)?, handler);
79 run_handler(req_handler, ex).await
80 }
81