diff --git a/vhost_rs/src/vhost_user/connection.rs b/vhost_rs/src/vhost_user/connection.rs index 69439dd70..f0f28c98c 100644 --- a/vhost_rs/src/vhost_user/connection.rs +++ b/vhost_rs/src/vhost_user/connection.rs @@ -197,6 +197,45 @@ impl Endpoint { Ok(()) } + /// Send a message with header, body and config info. Optional file descriptors may be attached to + /// the message. + /// + /// # Return: + /// * - number of bytes sent on success + /// * - SocketRetry: temporary error caused by signals or short of resources. + /// * - SocketBroken: the underline socket is broken. + /// * - SocketError: other socket related errors. + /// * - PartialMessage: received a partial message. + pub fn send_config_message( + &mut self, + hdr: &VhostUserMsgHeader, + user_config: &VhostUserConfig, + buf: &mut [u8], + fds: Option<&[RawFd]>, + ) -> Result<()> { + // Safe because there can't be other mutable referance to hdr and body. + let iovs = unsafe { + [ + slice::from_raw_parts( + hdr as *const VhostUserMsgHeader as *const u8, + mem::size_of::>(), + ), + slice::from_raw_parts( + user_config as *const VhostUserConfig as *const u8, + mem::size_of::(), + ), + slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len()), + ] + }; + let bytes = self.send_iovec(&iovs[..], fds)?; + let total = + mem::size_of::>() + mem::size_of::() + buf.len(); + if bytes != total { + return Err(Error::PartialMessage); + } + Ok(()) + } + /// Send a message with header, body and payload. Optional file descriptors /// may also be attached to the message. /// diff --git a/vhost_rs/src/vhost_user/master.rs b/vhost_rs/src/vhost_user/master.rs index a7129a18d..28b6e99fd 100644 --- a/vhost_rs/src/vhost_user/master.rs +++ b/vhost_rs/src/vhost_user/master.rs @@ -360,7 +360,7 @@ impl VhostUserMaster for Master { // "Master payload: virtio device config space" // But what content should the payload contains for a get_config() request? // So current implementation doesn't conform to the spec. - let hdr = node.send_request_with_body(MasterReq::GET_CONFIG, &body, None)?; + let hdr = node.send_request_with_config_body(MasterReq::GET_CONFIG, &body, None)?; let (reply, buf, rfds) = node.recv_reply_with_payload::(&hdr)?; if rfds.is_some() { Endpoint::::close_rfds(rfds); @@ -480,6 +480,27 @@ impl MasterInternal { Ok(hdr) } + fn send_request_with_config_body( + &mut self, + code: MasterReq, + user_config: &VhostUserConfig, + fds: Option<&[RawFd]>, + ) -> VhostUserResult> { + if mem::size_of::() + user_config.size as usize > MAX_MSG_SIZE { + return Err(VhostUserError::InvalidParam); + } + self.check_state()?; + + let hdr = Self::new_request_header( + code, + mem::size_of::() as u32 + user_config.size, + ); + let mut buf = vec![0; user_config.size as usize]; + self.main_sock + .send_config_message(&hdr, user_config, &mut buf, fds)?; + Ok(hdr) + } + fn send_request_with_payload( &mut self, code: MasterReq, @@ -555,7 +576,7 @@ impl MasterInternal { if !reply.is_reply_for(hdr) || reply.get_size() as usize != mem::size_of::() + bytes || rfds.is_some() - || body.is_valid() + || !body.is_valid() { Endpoint::::close_rfds(rfds); return Err(VhostUserError::InvalidMessage);