summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/sys/mod.rs1
-rw-r--r--src/sys/sendfile.rs46
-rw-r--r--test/test.rs1
-rw-r--r--test/test_sendfile.rs47
5 files changed, 95 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3b097d6a..1235a71e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
(#[1564](https://github.com/nix-rust/nix/pull/1564))
- Added POSIX per-process timer support
(#[1622](https://github.com/nix-rust/nix/pull/1622))
+- Added `sendfile` on DragonFly.
+ (#[1615](https://github.com/nix-rust/nix/pull/1615))
### Changed
### Fixed
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index 654a4d87..0bd0bc9f 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -110,6 +110,7 @@ feature! {
}
#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "linux",
diff --git a/src/sys/sendfile.rs b/src/sys/sendfile.rs
index 1a87a680..5ec0b526 100644
--- a/src/sys/sendfile.rs
+++ b/src/sys/sendfile.rs
@@ -64,7 +64,8 @@ pub fn sendfile64(
}
cfg_if! {
- if #[cfg(any(target_os = "freebsd",
+ if #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
target_os = "ios",
target_os = "macos"))] {
use crate::sys::uio::IoVec;
@@ -184,6 +185,49 @@ cfg_if! {
};
(Errno::result(return_code).and(Ok(())), bytes_sent)
}
+ } else if #[cfg(target_os = "dragonfly")] {
+ /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`.
+ ///
+ /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if
+ /// an error occurs.
+ ///
+ /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket.
+ ///
+ /// If `offset` falls past the end of the file, the function returns success and zero bytes
+ /// written.
+ ///
+ /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of
+ /// file (EOF).
+ ///
+ /// `headers` and `trailers` specify optional slices of byte slices to be sent before and
+ /// after the data read from `in_fd`, respectively. The length of headers and trailers sent
+ /// is included in the returned count of bytes written. The values of `offset` and `count`
+ /// do not apply to headers or trailers.
+ ///
+ /// For more information, see
+ /// [the sendfile(2) man page.](https://leaf.dragonflybsd.org/cgi/web-man?command=sendfile&section=2)
+ pub fn sendfile(
+ in_fd: RawFd,
+ out_sock: RawFd,
+ offset: off_t,
+ count: Option<usize>,
+ headers: Option<&[&[u8]]>,
+ trailers: Option<&[&[u8]]>,
+ ) -> (Result<()>, off_t) {
+ let mut bytes_sent: off_t = 0;
+ let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
+ let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
+ let return_code = unsafe {
+ libc::sendfile(in_fd,
+ out_sock,
+ offset,
+ count.unwrap_or(0),
+ hdtr_ptr as *mut libc::sf_hdtr,
+ &mut bytes_sent as *mut off_t,
+ 0)
+ };
+ (Errno::result(return_code).and(Ok(())), bytes_sent)
+ }
} else if #[cfg(any(target_os = "ios", target_os = "macos"))] {
/// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to
/// `out_sock`.
diff --git a/test/test.rs b/test/test.rs
index 83cb4645..3cac48f7 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -33,6 +33,7 @@ mod test_pty;
target_os = "linux"))]
mod test_sched;
#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
target_os = "freebsd",
target_os = "ios",
target_os = "linux",
diff --git a/test/test_sendfile.rs b/test/test_sendfile.rs
index b6559d32..e56ff12f 100644
--- a/test/test_sendfile.rs
+++ b/test/test_sendfile.rs
@@ -8,7 +8,7 @@ use tempfile::tempfile;
cfg_if! {
if #[cfg(any(target_os = "android", target_os = "linux"))] {
use nix::unistd::{close, pipe, read};
- } else if #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] {
+ } else if #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos"))] {
use std::net::Shutdown;
use std::os::unix::net::UnixStream;
}
@@ -105,6 +105,51 @@ fn test_sendfile_freebsd() {
assert_eq!(expected_string, read_string);
}
+#[cfg(target_os = "dragonfly")]
+#[test]
+fn test_sendfile_dragonfly() {
+ // Declare the content
+ let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
+ let body = "Xabcdef123456";
+ let body_offset = 1;
+ let trailer_strings = vec!["\n", "Served by Make Believe\n"];
+
+ // Write the body to a file
+ let mut tmp = tempfile().unwrap();
+ tmp.write_all(body.as_bytes()).unwrap();
+
+ // Prepare headers and trailers for sendfile
+ let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect();
+ let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect();
+
+ // Prepare socket pair
+ let (mut rd, wr) = UnixStream::pair().unwrap();
+
+ // Call the test method
+ let (res, bytes_written) = sendfile(
+ tmp.as_raw_fd(),
+ wr.as_raw_fd(),
+ body_offset as off_t,
+ None,
+ Some(headers.as_slice()),
+ Some(trailers.as_slice()),
+ );
+ 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 as usize, bytes_read);
+ assert_eq!(expected_string, read_string);
+}
+
#[cfg(any(target_os = "ios", target_os = "macos"))]
#[test]
fn test_sendfile_darwin() {