Skip to content

Commit

Permalink
sys::sendfile adding solaris' sendfilev wrapper proposal.
Browse files Browse the repository at this point in the history
  • Loading branch information
devnexen committed Nov 25, 2023
1 parent 2afff81 commit 6f87e54
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 1 deletion.
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
71 changes: 70 additions & 1 deletion src/sys/sendfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::Result;
///
/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) for Linux,
/// see [the sendfile(2) man page.](https://docs.oracle.com/cd/E88353_01/html/E37843/sendfile-3c.html) for Solaris.
#[cfg(any(target_os = "android", target_os = "linux", target_os = "solaris", target_os = "illumos"))]
#[cfg(any(target_os = "android", target_os = "linux", solarish))]
pub fn sendfile<F1: AsFd, F2: AsFd>(
out_fd: F1,
in_fd: F2,
Expand Down Expand Up @@ -120,6 +120,49 @@ cfg_if! {
)
}
}
} else if #[cfg(solarish)] {
#[derive(Debug, Copy, Clone)]
/// Mapping of the raw C sendfilevec_t struct
/// no need to bother with `sfv_flag` since it needs to be always 0.
pub struct SendfileVec {
/// input file descriptor
pub fd: i32,
/// offset to read from
pub off: off_t,
/// size of the data to read
pub len: usize,
}

const SFV_FD_SELF: i32 = -2;

impl SendfileVec {
/// 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
) -> SendfileVec {
SendfileVec{fd: SFV_FD_SELF, off, len}
}

/// initialises SendfileVec to send data from `fd`.
pub fn new<F: AsFd>(
fd: F,
off: off_t,
len: usize
) -> SendfileVec {
SendfileVec{fd: fd.as_fd().as_raw_fd(), off, len}
}

fn tosendfilevec(&self) -> libc::sendfilevec_t {
libc::sendfilevec_t{
sfv_fd: self.fd,
sfv_flag: 0,
sfv_off: self.off,
sfv_len: self.len
}
}
}
}
}

Expand Down Expand Up @@ -287,5 +330,31 @@ 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' address space, from an offset `off`
/// and for a given amount of data `len`.
///
/// For more information, see
/// [the sendfilev{3) man page.](https://docs.oracle.com/cd/E86824_01/html/E54768/sendfilev-3ext.html)
pub fn sendfilev<F: AsFd>(
out_sock: F,
vec: Vec<SendfileVec>
) -> (Result<()>, usize) {
let rawvec: Vec<libc::sendfilevec_t> = vec.iter().map(|&v| v.tosendfilevec()).collect();
let mut len = 0usize;
let return_code = unsafe {
libc::sendfilev(out_sock.as_fd().as_raw_fd(), rawvec.as_ptr(), rawvec.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
55 changes: 55 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,57 @@ fn test_sendfile_darwin() {
assert_eq!(bytes_written as usize, bytes_read);
assert_eq!(expected_string, read_string);
}

#[cfg(solarish)]
#[test]
fn test_sendfilev() {
// 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: Vec<SendfileVec> = vec![
SendfileVec::new(
&header_data,
0,
header_strings.iter().map(|s| s.len()).sum(),
),
SendfileVec::new(&body_data, body_offset as off_t, body.len() - 1),
SendfileVec::new(
&trailer_data,
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 as usize, 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 6f87e54

Please sign in to comment.