summary refs log tree commit diff
path: root/sys_util/src/sock_ctrl_msg.rs
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2017-08-02 15:02:28 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-08-03 01:11:01 -0700
commit7a9de27c36b9a5ea3e29b3508939c20e6a5c7779 (patch)
treea644cef688f79436b576e44bd9592c64fbc54972 /sys_util/src/sock_ctrl_msg.rs
parent3eddedd005c0333390e1eae4c2f0eb661790748e (diff)
downloadcrosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar
crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.gz
crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.bz2
crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.lz
crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.xz
crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.zst
crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.zip
sys_util: allow sock_ctrl_msg to be more flexible with iovecs
Because there are more than one kind of slice (typical &[T] and
VolatileSlice), the trait IntoIovec is added that any linear memory
region-like type can implement. This helps to reduce the number of
copies needed when dealing with volatile memory.

TEST=cargo test
BUG=chromium:738638

Change-Id: I86bbb693cb7a10ec85bafccf562c078167121c03
Reviewed-on: https://chromium-review.googlesource.com/599042
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'sys_util/src/sock_ctrl_msg.rs')
-rw-r--r--sys_util/src/sock_ctrl_msg.rs60
1 files changed, 49 insertions, 11 deletions
diff --git a/sys_util/src/sock_ctrl_msg.rs b/sys_util/src/sock_ctrl_msg.rs
index ddbfef8..2d4b91c 100644
--- a/sys_util/src/sock_ctrl_msg.rs
+++ b/sys_util/src/sock_ctrl_msg.rs
@@ -6,7 +6,9 @@ use std::fs::File;
 use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
 use std::os::unix::net::{UnixDatagram, UnixStream};
 
-use libc::{iovec, c_void};
+use libc::{c_void, iovec};
+
+use data_model::VolatileSlice;
 
 use {Result, Error};
 
@@ -56,6 +58,43 @@ impl ScmSocket for UnixStream {
     }
 }
 
+/// Trait for types that can be converted into an `iovec` that can be referenced by a syscall for
+/// the lifetime of this object.
+///
+/// This trait is unsafe because interfaces that use this trait depend on the base pointer and size
+/// being accurate.
+pub unsafe trait IntoIovec {
+    /// Gets the base pointer of this `iovec`.
+    fn as_ptr(&self) -> *const c_void;
+
+    /// Gets the size in bytes of this `iovec`.
+    fn size(&self) -> usize;
+}
+
+// Safe because this slice can not have another mutable reference and it's pointer and size are
+// guaranteed to be valid.
+unsafe impl<'a> IntoIovec for &'a [u8] {
+    fn as_ptr(&self) -> *const c_void {
+        self.as_ref().as_ptr() as *const c_void
+    }
+
+    fn size(&self) -> usize {
+        self.len()
+    }
+}
+
+// Safe because volatile slices are only ever accessed with other volatile interfaces and the
+// pointer and size are guaranteed to be accurate.
+unsafe impl<'a> IntoIovec for VolatileSlice<'a> {
+    fn as_ptr(&self) -> *const c_void {
+        self.as_ptr() as *const c_void
+    }
+
+    fn size(&self) -> usize {
+        self.size()
+    }
+}
+
 /// Used to send and receive messages with file descriptors on sockets that accept control messages
 /// (e.g. Unix domain sockets).
 pub struct Scm {
@@ -85,23 +124,22 @@ impl Scm {
     /// # Arguments
     ///
     /// * `socket` - A socket that supports socket control messages.
-    /// * `bufs` - A list of buffers to send on the `socket`. These will not be copied before
-    ///            `sendmsg` is called.
+    /// * `bufs` - A list of buffers to send on the `socket`.
     /// * `fds` - A list of file descriptors to be sent.
-    pub fn send<T: ScmSocket>(&mut self,
+    pub fn send<T: ScmSocket, D: IntoIovec>(&mut self,
                               socket: &T,
-                              bufs: &[&[u8]],
+                              bufs: &[D],
                               fds: &[RawFd])
                               -> Result<usize> {
         let cmsg_buf_len = cmsg_buffer_len(fds.len());
         self.cmsg_buffer.reserve(cmsg_buf_len);
         self.vecs.clear();
-        for buf in bufs {
+        for ref buf in bufs {
             self.vecs
                 .push(iovec {
-                          iov_base: buf.as_ptr() as *mut c_void,
-                          iov_len: buf.len(),
-                      });
+                    iov_base: buf.as_ptr() as *mut c_void,
+                    iov_len: buf.size(),
+              });
         }
         let write_count = unsafe {
             // Safe because we are giving scm_sendmsg only valid pointers and lengths and we check
@@ -241,7 +279,7 @@ mod tests {
 
         let mut scm = Scm::new(1);
         let evt = EventFd::new().expect("failed to create eventfd");
-        let write_count = scm.send(&s1, &[&[]], &[evt.as_raw_fd()])
+        let write_count = scm.send(&s1, &[[].as_ref()], &[evt.as_raw_fd()])
             .expect("failed to send fd");
 
         assert_eq!(write_count, 0);
@@ -270,7 +308,7 @@ mod tests {
 
         let mut scm = Scm::new(1);
         let evt = EventFd::new().expect("failed to create eventfd");
-        let write_count = scm.send(&s1, &[&[237]], &[evt.as_raw_fd()])
+        let write_count = scm.send(&s1, &[[237].as_ref()], &[evt.as_raw_fd()])
             .expect("failed to send fd");
 
         assert_eq!(write_count, 1);