xref: /aosp_15_r20/external/crosvm/devices/src/virtio/vhost/user/device/connection/sys/linux/stream.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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