1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

pub mod sys;
use std::any::Any;
use std::pin::Pin;

use base::RawDescriptor;
use cros_async::Executor;
use futures::Future;
pub use sys::VhostUserListener;

use crate::virtio::vhost::user::device::handler::DeviceRequestHandler;
use crate::virtio::vhost::user::device::handler::VhostUserDevice;
use crate::virtio::vhost::user::VhostUserDeviceBuilder;

/// Trait that the platform-specific type `VhostUserListener` needs to implement. It contains all
/// the methods that are ok to call from non-platform specific code.
pub trait VhostUserListenerTrait {
    /// Creates a VhostUserListener from `path`, which is a platform-specific string describing how
    /// to establish the vhost-user channel. For instance, it can be a path to a socket.
    ///
    /// `keep_rds` is a vector of `RawDescriptor`s to which the descriptors needed for this listener
    /// to operate properly will be added if it is `Some()`.
    fn new(
        path: &str,
        keep_rds: Option<&mut Vec<RawDescriptor>>,
    ) -> anyhow::Result<VhostUserListener>;

    /// Take and return resources owned by the parent process in case of a incoming fork.
    ///
    /// This method needs to be called only if you are going to use the listener in a jailed child
    /// process. In this case, the listener will belong to the child and the parent will drop it,
    /// but the child may lack the rights to drop some resources created at construction time. One
    /// such example is the socket file of a regular vhost-user device, that cannot be dropped by
    /// the child unless it gets extra permissions.
    ///
    /// This method returns an opaque object that, upon being dropped, will free these resources.
    /// That way, the child process does not need extra rights to clear them, and the parent can
    /// drop the listener after forking and just need to keep that object alive until the child
    /// exits to do housekeeping properly.
    ///
    /// The default implementation returns nothing as that's what most listeners would need anyway.
    fn take_parent_process_resources(&mut self) -> Option<Box<dyn Any>> {
        None
    }

    /// Returns a `Future` that processes requests for `handler`. The future exits when the
    /// front-end side disconnects or an error occurs.
    fn run_req_handler<'e>(
        self,
        handler: Box<dyn vmm_vhost::Backend>,
        ex: &'e Executor,
    ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>;

    /// Returns a `Future` that will process requests from `backend` when polled. The future exits
    /// when the front-end side disconnects or an error occurs.
    ///
    /// This is a legacy way to run devices - prefer `run_device`.
    fn run_backend<'e>(
        self,
        backend: impl VhostUserDevice + 'static,
        ex: &'e Executor,
    ) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + 'e>>
    where
        Self: Sized,
    {
        self.run_req_handler(Box::new(DeviceRequestHandler::new(backend)), ex)
    }

    /// Start processing requests for a `VhostUserDevice` on `listener`. Returns when the front-end
    /// side disconnects or an error occurs.
    fn run_device(self, ex: Executor, device: Box<dyn VhostUserDeviceBuilder>) -> anyhow::Result<()>
    where
        Self: Sized,
    {
        ex.run_until(self.run_req_handler(device.build(&ex).unwrap(), &ex))?
    }
}