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