Skip to content

Commit

Permalink
sys::sendfile adding solaris' sendfilev wrapper proposal. (#2207)
Browse files Browse the repository at this point in the history
  • Loading branch information
devnexen committed Dec 4, 2023
1 parent 3a20eef commit da45140
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog/2207.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added `sendfilev` in sys::sendfile for solarish
61 changes: 61 additions & 0 deletions src/sys/sendfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,42 @@ cfg_if! {
)
}
}
} else if #[cfg(solarish)] {
use std::os::unix::io::BorrowedFd;
use std::marker::PhantomData;

#[derive(Debug, Copy, Clone)]
/// Mapping of the raw C sendfilevec_t struct
pub struct SendfileVec<'fd> {
raw: libc::sendfilevec_t,
phantom: PhantomData<BorrowedFd<'fd>>
}

impl<'fd> SendfileVec<'fd> {
/// initialises SendfileVec to send data directly from the process's address space
/// same in C with sfv_fd set to SFV_FD_SELF.
pub fn newself(
off: off_t,
len: usize
) -> Self {
Self{raw: libc::sendfilevec_t{sfv_fd: libc::SFV_FD_SELF, sfv_flag: 0, sfv_off: off, sfv_len: len}, phantom: PhantomData}
}

/// initialises SendfileVec to send data from `fd`.
pub fn new(
fd: BorrowedFd<'fd>,
off: off_t,
len: usize
) -> SendfileVec<'fd> {
Self{raw: libc::sendfilevec_t{sfv_fd: fd.as_raw_fd(), sfv_flag: 0, sfv_off:off, sfv_len: len}, phantom: PhantomData}
}
}

impl From<SendfileVec<'_>> for libc::sendfilevec_t {
fn from<'fd>(vec: SendfileVec) -> libc::sendfilevec_t {
vec.raw
}
}
}
}

Expand Down Expand Up @@ -285,5 +321,30 @@ cfg_if! {
};
(Errno::result(return_code).and(Ok(())), len)
}
} else if #[cfg(solarish)] {
/// Write data from the vec arrays to `out_sock` and returns a `Result` and a
/// count of bytes written.
///
/// Each `SendfileVec` set needs to be instantiated either with `SendfileVec::new` or
/// `SendfileVec::newself`.
///
/// The former allows to send data from a file descriptor through `fd`,
/// from an offset `off` and for a given amount of data `len`.
///
/// The latter allows to send data from the process's address space, from an offset `off`
/// and for a given amount of data `len`.
///
/// For more information, see
/// [the sendfilev(3) man page.](https://illumos.org/man/3EXT/sendfilev)
pub fn sendfilev<F: AsFd>(
out_sock: F,
vec: &[SendfileVec]
) -> (Result<()>, usize) {
let mut len = 0usize;
let return_code = unsafe {
libc::sendfilev(out_sock.as_fd().as_raw_fd(), vec.as_ptr() as *const libc::sendfilevec_t, vec.len() as i32, &mut len)
};
(Errno::result(return_code).and(Ok(())), len)
}
}
}
1 change: 1 addition & 0 deletions test/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ mod test_sched;
target_os = "freebsd",
apple_targets,
target_os = "linux",
solarish
))]
mod test_sendfile;
mod test_stat;
Expand Down
60 changes: 60 additions & 0 deletions test/test_sendfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ cfg_if! {
target_os = "dragonfly",
target_os = "freebsd",
apple_targets,
solarish
))] {
use std::net::Shutdown;
use std::os::unix::net::UnixStream;
Expand Down Expand Up @@ -204,3 +205,62 @@ fn test_sendfile_darwin() {
assert_eq!(bytes_written as usize, bytes_read);
assert_eq!(expected_string, read_string);
}

#[cfg(solarish)]
#[test]
fn test_sendfilev() {
use std::os::fd::AsFd;
// Declare the content
let header_strings =
["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
let body = "Xabcdef123456";
let body_offset = 1usize;
let trailer_strings = ["\n", "Served by Make Believe\n"];

// Write data to files
let mut header_data = tempfile().unwrap();
header_data
.write_all(header_strings.concat().as_bytes())
.unwrap();
let mut body_data = tempfile().unwrap();
body_data.write_all(body.as_bytes()).unwrap();
let mut trailer_data = tempfile().unwrap();
trailer_data
.write_all(trailer_strings.concat().as_bytes())
.unwrap();
let (mut rd, wr) = UnixStream::pair().unwrap();
let vec: &[SendfileVec] = &[
SendfileVec::new(
header_data.as_fd(),
0,
header_strings.iter().map(|s| s.len()).sum(),
),
SendfileVec::new(
body_data.as_fd(),
body_offset as off_t,
body.len() - body_offset,
),
SendfileVec::new(
trailer_data.as_fd(),
0,
trailer_strings.iter().map(|s| s.len()).sum(),
),
];

let (res, bytes_written) = sendfilev(&wr, vec);
assert!(res.is_ok());
wr.shutdown(Shutdown::Both).unwrap();

// Prepare the expected result
let expected_string = header_strings.concat()
+ &body[body_offset..]
+ &trailer_strings.concat();

// Verify the message that was sent
assert_eq!(bytes_written, expected_string.as_bytes().len());

let mut read_string = String::new();
let bytes_read = rd.read_to_string(&mut read_string).unwrap();
assert_eq!(bytes_written, bytes_read);
assert_eq!(expected_string, read_string);
}

0 comments on commit da45140

Please sign in to comment.