• 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 pub mod sys;
6 use std::any::Any;
7 use std::pin::Pin;
8 
9 use base::RawDescriptor;
10 use cros_async::Executor;
11 use futures::Future;
12 pub use sys::VhostUserListener;
13 
14 use crate::virtio::vhost::user::device::handler::DeviceRequestHandler;
15 use crate::virtio::vhost::user::device::handler::VhostUserDevice;
16 use crate::virtio::vhost::user::VhostUserDeviceBuilder;
17 
18 /// Trait that the platform-specific type `VhostUserListener` needs to implement. It contains all
19 /// the methods that are ok to call from non-platform specific code.
20 pub trait VhostUserListenerTrait {
21     /// Creates a VhostUserListener from `path`, which is a platform-specific string describing how
22     /// to establish the vhost-user channel. For instance, it can be a path to a socket.
23     ///
24     /// `keep_rds` is a vector of `RawDescriptor`s to which the descriptors needed for this listener
25     /// to operate properly will be added if it is `Some()`.
new( path: &str, keep_rds: Option<&mut Vec<RawDescriptor>>, ) -> anyhow::Result<VhostUserListener>26     fn new(
27         path: &str,
28         keep_rds: Option<&mut Vec<RawDescriptor>>,
29     ) -> anyhow::Result<VhostUserListener>;
30 
31     /// Take and return resources owned by the parent process in case of a incoming fork.
32     ///
33     /// This method needs to be called only if you are going to use the listener in a jailed child
34     /// process. In this case, the listener will belong to the child and the parent will drop it,
35     /// but the child may lack the rights to drop some resources created at construction time. One
36     /// such example is the socket file of a regular vhost-user device, that cannot be dropped by
37     /// the child unless it gets extra permissions.
38     ///
39     /// This method returns an opaque object that, upon being dropped, will free these resources.
40     /// That way, the child process does not need extra rights to clear them, and the parent can
41     /// drop the listener after forking and just need to keep that object alive until the child
42     /// exits to do housekeeping properly.
43     ///
44     /// The default implementation returns nothing as that's what most listeners would need anyway.
take_parent_process_resources(&mut self) -> Option<Box<dyn Any>>45     fn take_parent_process_resources(&mut self) -> Option<Box<dyn Any>> {
46         None
47     }
48 
49     /// Returns a `Future` that processes requests for `handler`. The future exits when the
50     /// front-end side disconnects or an error occurs.
run_req_handler<'e>( self, handler: Box<dyn vmm_vhost::Backend>, ex: &'e Executor, ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>51     fn run_req_handler<'e>(
52         self,
53         handler: Box<dyn vmm_vhost::Backend>,
54         ex: &'e Executor,
55     ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>;
56 
57     /// Returns a `Future` that will process requests from `backend` when polled. The future exits
58     /// when the front-end side disconnects or an error occurs.
59     ///
60     /// This is a legacy way to run devices - prefer `run_device`.
run_backend<'e>( self, backend: impl VhostUserDevice + 'static, ex: &'e Executor, ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>> where Self: Sized,61     fn run_backend<'e>(
62         self,
63         backend: impl VhostUserDevice + 'static,
64         ex: &'e Executor,
65     ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>
66     where
67         Self: Sized,
68     {
69         self.run_req_handler(Box::new(DeviceRequestHandler::new(backend)), ex)
70     }
71 
72     /// Start processing requests for a `VhostUserDevice` on `listener`. Returns when the front-end
73     /// side disconnects or an error occurs.
run_device(self, ex: Executor, device: Box<dyn VhostUserDeviceBuilder>) -> anyhow::Result<()> where Self: Sized,74     fn run_device(self, ex: Executor, device: Box<dyn VhostUserDeviceBuilder>) -> anyhow::Result<()>
75     where
76         Self: Sized,
77     {
78         ex.run_until(self.run_req_handler(device.build(&ex).unwrap(), &ex))?
79     }
80 }
81