mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-25 05:03:05 +00:00
vmm_vhost: tidy up Endpoint API
`Endpoint` has mixture of raw socket methods and vhost-user message framing methods. This CL hides all of the raw socket methods so that the type is focused on message framing. The recv methods' names were changed to more closely match the send method names. The documentation for returned errors has been deleted because much of it was out of date. Change-Id: I55a4f8bea5902fafd8b52468e140de5aa61c5539 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/5066131 Commit-Queue: Frederick Mayle <fmayle@google.com> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
620687c9dc
commit
e44284f9de
5 changed files with 50 additions and 90 deletions
116
third_party/vmm_vhost/src/connection.rs
vendored
116
third_party/vmm_vhost/src/connection.rs
vendored
|
@ -83,7 +83,11 @@ fn advance_slices_mut(bufs: &mut &mut [&mut [u8]], mut count: usize) {
|
|||
}
|
||||
}
|
||||
|
||||
/// A vhost-user connection and related operations.
|
||||
/// A vhost-user connection at a low abstraction level. Provides methods for sending and receiving
|
||||
/// vhost-user message headers and bodies.
|
||||
///
|
||||
/// Builds on top of `PlatformEndpoint`, which provides methods for sending and receiving raw bytes
|
||||
/// and file descriptors (a thin cross-platform abstraction for unix domain sockets).
|
||||
pub struct Endpoint<R: Req>(pub(crate) PlatformEndpoint<R>);
|
||||
|
||||
impl<R: Req> From<SystemStream> for Endpoint<R> {
|
||||
|
@ -98,31 +102,6 @@ impl<R: Req> Endpoint<R> {
|
|||
PlatformEndpoint::connect(path).map(Self)
|
||||
}
|
||||
|
||||
/// Sends bytes from scatter-gather vectors with optional attached file descriptors.
|
||||
///
|
||||
/// # Return:
|
||||
/// * - number of bytes sent on success
|
||||
pub fn send_iovec(&mut self, iovs: &[IoSlice], fds: Option<&[RawDescriptor]>) -> Result<usize> {
|
||||
self.0.send_iovec(iovs, fds)
|
||||
}
|
||||
|
||||
/// Reads bytes into the given scatter/gather vectors with optional attached file.
|
||||
///
|
||||
/// # Arguements
|
||||
/// * `bufs` - A slice of buffers to store received data.
|
||||
/// * `allow_fd` - Indicates whether we can receive FDs.
|
||||
///
|
||||
/// # Return:
|
||||
/// * - (number of bytes received, [received files]) on success.
|
||||
/// * - `Error::Disconnect` if the client closed.
|
||||
pub fn recv_into_bufs(
|
||||
&mut self,
|
||||
bufs: &mut [IoSliceMut],
|
||||
allow_fd: bool,
|
||||
) -> Result<(usize, Option<Vec<File>>)> {
|
||||
self.0.recv_into_bufs(bufs, allow_fd)
|
||||
}
|
||||
|
||||
/// Constructs the slave request endpoint for self.
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -142,7 +121,7 @@ impl<R: Req> Endpoint<R> {
|
|||
/// cursor needs to be moved by `advance_slices()`.
|
||||
/// Once `IoSlice::advance_slices()` becomes stable, this should be updated.
|
||||
/// <https://github.com/rust-lang/rust/issues/62726>.
|
||||
pub fn send_iovec_all(
|
||||
fn send_iovec_all(
|
||||
&self,
|
||||
mut iovs: &mut [&[u8]],
|
||||
mut fds: Option<&[RawDescriptor]>,
|
||||
|
@ -171,16 +150,11 @@ impl<R: Req> Endpoint<R> {
|
|||
/// # Return:
|
||||
/// * - number of bytes sent on success
|
||||
#[cfg(test)]
|
||||
pub fn send_slice(&self, data: IoSlice, fds: Option<&[RawDescriptor]>) -> Result<usize> {
|
||||
fn send_slice(&self, data: IoSlice, fds: Option<&[RawDescriptor]>) -> Result<usize> {
|
||||
self.0.send_iovec(&[data], fds)
|
||||
}
|
||||
|
||||
/// Sends a header-only message with optional attached file descriptors.
|
||||
///
|
||||
/// # Return:
|
||||
/// * - number of bytes sent on success
|
||||
/// * - PartialMessage: received a partial message.
|
||||
/// * - backend specific errors
|
||||
pub fn send_header(
|
||||
&self,
|
||||
hdr: &VhostUserMsgHeader<R>,
|
||||
|
@ -191,13 +165,7 @@ impl<R: Req> Endpoint<R> {
|
|||
|
||||
/// Send a message with header and body. Optional file descriptors may be attached to
|
||||
/// the message.
|
||||
///
|
||||
/// # Return:
|
||||
/// * - number of bytes sent on success
|
||||
/// * - OversizedMsg: message size is too big.
|
||||
/// * - PartialMessage: received a partial message.
|
||||
/// * - backend specific errors
|
||||
pub fn send_message<T: Sized + AsBytes>(
|
||||
pub fn send_message<T: AsBytes>(
|
||||
&self,
|
||||
hdr: &VhostUserMsgHeader<R>,
|
||||
body: &T,
|
||||
|
@ -210,15 +178,8 @@ impl<R: Req> Endpoint<R> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Send a message with header, body and payload. Optional file descriptors
|
||||
/// may also be attached to the message.
|
||||
///
|
||||
/// # Return:
|
||||
/// * - number of bytes sent on success
|
||||
/// * - OversizedMsg: message size is too big.
|
||||
/// * - PartialMessage: received a partial message.
|
||||
/// * - IncorrectFds: wrong number of attached fds.
|
||||
/// * - backend specific errors
|
||||
/// Send a message with header and body. `payload` is appended to the end of the body. Optional
|
||||
/// file descriptors may also be attached to the message.
|
||||
pub fn send_message_with_payload<T: Sized + AsBytes>(
|
||||
&self,
|
||||
hdr: &VhostUserMsgHeader<R>,
|
||||
|
@ -252,7 +213,7 @@ impl<R: Req> Endpoint<R> {
|
|||
/// cursor needs to be moved by `advance_slices_mut()`.
|
||||
/// Once `IoSliceMut::advance_slices()` becomes stable, this should be updated.
|
||||
/// <https://github.com/rust-lang/rust/issues/62726>.
|
||||
pub fn recv_into_bufs_all(&self, mut bufs: &mut [&mut [u8]]) -> Result<Option<Vec<File>>> {
|
||||
fn recv_into_bufs_all(&self, mut bufs: &mut [&mut [u8]]) -> Result<Option<Vec<File>>> {
|
||||
let mut first_read = true;
|
||||
let mut rfds = None;
|
||||
|
||||
|
@ -294,16 +255,12 @@ impl<R: Req> Endpoint<R> {
|
|||
Ok((bytes, buf, files))
|
||||
}
|
||||
|
||||
/// Receive a header-only message with optional attached files.
|
||||
/// Note, only the first MAX_ATTACHED_FD_ENTRIES file descriptors will be
|
||||
/// accepted and all other file descriptor will be discard silently.
|
||||
/// Receive message header
|
||||
///
|
||||
/// # Return:
|
||||
/// * - (message header, [received files]) on success.
|
||||
/// * - Disconnect: the client closed the connection.
|
||||
/// * - PartialMessage: received a partial message.
|
||||
/// * - InvalidMessage: received a invalid message.
|
||||
/// * - backend specific errors
|
||||
/// Errors if the header is invalid.
|
||||
///
|
||||
/// Note, only the first MAX_ATTACHED_FD_ENTRIES file descriptors will be accepted and all
|
||||
/// other file descriptor will be discard silently.
|
||||
pub fn recv_header(&self) -> Result<(VhostUserMsgHeader<R>, Option<Vec<File>>)> {
|
||||
let mut hdr = VhostUserMsgHeader::default();
|
||||
let (bytes, files) = self.0.recv_into_bufs(
|
||||
|
@ -320,16 +277,25 @@ impl<R: Req> Endpoint<R> {
|
|||
Ok((hdr, files))
|
||||
}
|
||||
|
||||
/// Receive a message with optional attached file descriptors.
|
||||
/// Receive the body following the header `hdr`.
|
||||
pub fn recv_body_bytes(&self, hdr: &VhostUserMsgHeader<R>) -> Result<Vec<u8>> {
|
||||
// NOTE: `recv_into_bufs_all` is a noop when the buffer is empty, so `hdr.get_size() == 0`
|
||||
// works as expected.
|
||||
let mut body = vec![0; hdr.get_size().try_into().unwrap()];
|
||||
let files = self.recv_into_bufs_all(&mut [&mut body[..]])?;
|
||||
if files.is_some() {
|
||||
return Err(Error::InvalidMessage);
|
||||
}
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
/// Receive a message header and body.
|
||||
///
|
||||
/// Errors if the header or body is invalid.
|
||||
///
|
||||
/// Note, only the first MAX_ATTACHED_FD_ENTRIES file descriptors will be
|
||||
/// accepted and all other file descriptor will be discard silently.
|
||||
///
|
||||
/// # Return:
|
||||
/// * - (message header, message body, [received files]) on success.
|
||||
/// * - PartialMessage: received a partial message.
|
||||
/// * - InvalidMessage: received a invalid message.
|
||||
/// * - backend specific errors
|
||||
pub fn recv_body<T: AsBytes + FromBytes + VhostUserMsgValidator>(
|
||||
pub fn recv_message<T: AsBytes + FromBytes + VhostUserMsgValidator>(
|
||||
&self,
|
||||
) -> Result<(VhostUserMsgHeader<R>, T, Option<Vec<File>>)> {
|
||||
let mut hdr = VhostUserMsgHeader::default();
|
||||
|
@ -344,16 +310,14 @@ impl<R: Req> Endpoint<R> {
|
|||
Ok((hdr, body, files))
|
||||
}
|
||||
|
||||
/// Receive a message with optional payload and attached file descriptors.
|
||||
/// Note, only the first MAX_ATTACHED_FD_ENTRIES file descriptors will be
|
||||
/// accepted and all other file descriptor will be discard silently.
|
||||
/// Receive a message header and body, where the body includes a variable length payload at the
|
||||
/// end.
|
||||
///
|
||||
/// # Return:
|
||||
/// * - (message header, message body, payload, [received files]) on success.
|
||||
/// * - PartialMessage: received a partial message.
|
||||
/// * - InvalidMessage: received a invalid message.
|
||||
/// * - backend specific errors
|
||||
pub fn recv_payload_into_buf<T: AsBytes + FromBytes + VhostUserMsgValidator>(
|
||||
/// Errors if the header or body is invalid.
|
||||
///
|
||||
/// Note, only the first MAX_ATTACHED_FD_ENTRIES file descriptors will be accepted and all
|
||||
/// other file descriptor will be discard silently.
|
||||
pub fn recv_message_with_payload<T: AsBytes + FromBytes + VhostUserMsgValidator>(
|
||||
&self,
|
||||
) -> Result<(VhostUserMsgHeader<R>, T, Vec<u8>, Option<Vec<File>>)> {
|
||||
let mut hdr = VhostUserMsgHeader::default();
|
||||
|
|
14
third_party/vmm_vhost/src/master.rs
vendored
14
third_party/vmm_vhost/src/master.rs
vendored
|
@ -613,7 +613,7 @@ impl Master {
|
|||
if hdr.is_reply() {
|
||||
return Err(VhostUserError::InvalidParam);
|
||||
}
|
||||
let (reply, body, rfds) = self.main_sock.recv_body::<T>()?;
|
||||
let (reply, body, rfds) = self.main_sock.recv_message::<T>()?;
|
||||
if !reply.is_reply_for(hdr) || rfds.is_some() || !body.is_valid() {
|
||||
return Err(VhostUserError::InvalidMessage);
|
||||
}
|
||||
|
@ -628,7 +628,7 @@ impl Master {
|
|||
return Err(VhostUserError::InvalidParam);
|
||||
}
|
||||
|
||||
let (reply, body, files) = self.main_sock.recv_body::<T>()?;
|
||||
let (reply, body, files) = self.main_sock.recv_message::<T>()?;
|
||||
if !reply.is_reply_for(hdr) || files.is_none() || !body.is_valid() {
|
||||
return Err(VhostUserError::InvalidMessage);
|
||||
}
|
||||
|
@ -643,7 +643,7 @@ impl Master {
|
|||
return Err(VhostUserError::InvalidParam);
|
||||
}
|
||||
|
||||
let (reply, body, buf, files) = self.main_sock.recv_payload_into_buf::<T>()?;
|
||||
let (reply, body, buf, files) = self.main_sock.recv_message_with_payload::<T>()?;
|
||||
if !reply.is_reply_for(hdr) || files.is_some() || !body.is_valid() {
|
||||
return Err(VhostUserError::InvalidMessage);
|
||||
}
|
||||
|
@ -658,7 +658,7 @@ impl Master {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let (reply, body, rfds) = self.main_sock.recv_body::<VhostUserU64>()?;
|
||||
let (reply, body, rfds) = self.main_sock.recv_message::<VhostUserU64>()?;
|
||||
if !reply.is_reply_for(hdr) || rfds.is_some() || !body.is_valid() {
|
||||
return Err(VhostUserError::InvalidMessage);
|
||||
}
|
||||
|
@ -756,7 +756,7 @@ mod tests {
|
|||
let msg = VhostUserU64::new(0x15);
|
||||
peer.send_message(&hdr, &msg, None).unwrap();
|
||||
master.set_features(0x15).unwrap();
|
||||
let (_hdr, msg, rfds) = peer.recv_body::<VhostUserU64>().unwrap();
|
||||
let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
|
||||
assert!(rfds.is_none());
|
||||
let val = msg.value;
|
||||
assert_eq!(val, 0x15);
|
||||
|
@ -791,7 +791,7 @@ mod tests {
|
|||
assert!(rfds.is_none());
|
||||
|
||||
master.set_features(vfeatures).unwrap();
|
||||
let (_hdr, msg, rfds) = peer.recv_body::<VhostUserU64>().unwrap();
|
||||
let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
|
||||
assert!(rfds.is_none());
|
||||
let val = msg.value;
|
||||
assert_eq!(val, vfeatures);
|
||||
|
@ -806,7 +806,7 @@ mod tests {
|
|||
assert!(rfds.is_none());
|
||||
|
||||
master.set_protocol_features(pfeatures).unwrap();
|
||||
let (_hdr, msg, rfds) = peer.recv_body::<VhostUserU64>().unwrap();
|
||||
let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
|
||||
assert!(rfds.is_none());
|
||||
let val = msg.value;
|
||||
assert_eq!(val, pfeatures.bits());
|
||||
|
|
|
@ -303,8 +303,7 @@ impl<S: VhostUserMasterReqHandler> MasterReqHandler<S> {
|
|||
// . validate message body and optional payload
|
||||
let (hdr, files) = self.sub_sock.recv_header()?;
|
||||
self.check_attached_files(&hdr, &files)?;
|
||||
let mut buf = vec![0u8; hdr.get_size().try_into().unwrap()];
|
||||
self.sub_sock.recv_into_bufs_all(&mut [&mut buf[..]])?;
|
||||
let buf = self.sub_sock.recv_body_bytes(&hdr)?;
|
||||
let size = buf.len();
|
||||
|
||||
let res = match hdr.get_code() {
|
||||
|
|
2
third_party/vmm_vhost/src/slave_proxy.rs
vendored
2
third_party/vmm_vhost/src/slave_proxy.rs
vendored
|
@ -60,7 +60,7 @@ impl SlaveInternal {
|
|||
return Ok(0);
|
||||
}
|
||||
|
||||
let (reply, body, rfds) = self.sock.recv_body::<VhostUserU64>()?;
|
||||
let (reply, body, rfds) = self.sock.recv_message::<VhostUserU64>()?;
|
||||
if !reply.is_reply_for(hdr) || rfds.is_some() || !body.is_valid() {
|
||||
return Err(Error::InvalidMessage);
|
||||
}
|
||||
|
|
|
@ -667,10 +667,7 @@ impl<S: VhostUserSlaveReqHandler> SlaveReqHandler<S> {
|
|||
hdr: VhostUserMsgHeader<MasterReq>,
|
||||
files: Option<Vec<File>>,
|
||||
) -> Result<()> {
|
||||
let mut buf = vec![0u8; hdr.get_size().try_into().unwrap()];
|
||||
self.slave_req_helper
|
||||
.endpoint
|
||||
.recv_into_bufs_all(&mut [&mut buf[..]])?;
|
||||
let buf = self.slave_req_helper.endpoint.recv_body_bytes(&hdr)?;
|
||||
let size = buf.len();
|
||||
|
||||
match hdr.get_code() {
|
||||
|
|
Loading…
Reference in a new issue