Skip to content

Commit da45140

Browse files
authored
sys::sendfile adding solaris' sendfilev wrapper proposal. (#2207)
1 parent 3a20eef commit da45140

File tree

4 files changed

+123
-0
lines changed

4 files changed

+123
-0
lines changed

changelog/2207.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added `sendfilev` in sys::sendfile for solarish

src/sys/sendfile.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,42 @@ cfg_if! {
118118
)
119119
}
120120
}
121+
} else if #[cfg(solarish)] {
122+
use std::os::unix::io::BorrowedFd;
123+
use std::marker::PhantomData;
124+
125+
#[derive(Debug, Copy, Clone)]
126+
/// Mapping of the raw C sendfilevec_t struct
127+
pub struct SendfileVec<'fd> {
128+
raw: libc::sendfilevec_t,
129+
phantom: PhantomData<BorrowedFd<'fd>>
130+
}
131+
132+
impl<'fd> SendfileVec<'fd> {
133+
/// initialises SendfileVec to send data directly from the process's address space
134+
/// same in C with sfv_fd set to SFV_FD_SELF.
135+
pub fn newself(
136+
off: off_t,
137+
len: usize
138+
) -> Self {
139+
Self{raw: libc::sendfilevec_t{sfv_fd: libc::SFV_FD_SELF, sfv_flag: 0, sfv_off: off, sfv_len: len}, phantom: PhantomData}
140+
}
141+
142+
/// initialises SendfileVec to send data from `fd`.
143+
pub fn new(
144+
fd: BorrowedFd<'fd>,
145+
off: off_t,
146+
len: usize
147+
) -> SendfileVec<'fd> {
148+
Self{raw: libc::sendfilevec_t{sfv_fd: fd.as_raw_fd(), sfv_flag: 0, sfv_off:off, sfv_len: len}, phantom: PhantomData}
149+
}
150+
}
151+
152+
impl From<SendfileVec<'_>> for libc::sendfilevec_t {
153+
fn from<'fd>(vec: SendfileVec) -> libc::sendfilevec_t {
154+
vec.raw
155+
}
156+
}
121157
}
122158
}
123159

@@ -285,5 +321,30 @@ cfg_if! {
285321
};
286322
(Errno::result(return_code).and(Ok(())), len)
287323
}
324+
} else if #[cfg(solarish)] {
325+
/// Write data from the vec arrays to `out_sock` and returns a `Result` and a
326+
/// count of bytes written.
327+
///
328+
/// Each `SendfileVec` set needs to be instantiated either with `SendfileVec::new` or
329+
/// `SendfileVec::newself`.
330+
///
331+
/// The former allows to send data from a file descriptor through `fd`,
332+
/// from an offset `off` and for a given amount of data `len`.
333+
///
334+
/// The latter allows to send data from the process's address space, from an offset `off`
335+
/// and for a given amount of data `len`.
336+
///
337+
/// For more information, see
338+
/// [the sendfilev(3) man page.](https://illumos.org/man/3EXT/sendfilev)
339+
pub fn sendfilev<F: AsFd>(
340+
out_sock: F,
341+
vec: &[SendfileVec]
342+
) -> (Result<()>, usize) {
343+
let mut len = 0usize;
344+
let return_code = unsafe {
345+
libc::sendfilev(out_sock.as_fd().as_raw_fd(), vec.as_ptr() as *const libc::sendfilevec_t, vec.len() as i32, &mut len)
346+
};
347+
(Errno::result(return_code).and(Ok(())), len)
348+
}
288349
}
289350
}

test/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ mod test_sched;
4444
target_os = "freebsd",
4545
apple_targets,
4646
target_os = "linux",
47+
solarish
4748
))]
4849
mod test_sendfile;
4950
mod test_stat;

test/test_sendfile.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ cfg_if! {
1212
target_os = "dragonfly",
1313
target_os = "freebsd",
1414
apple_targets,
15+
solarish
1516
))] {
1617
use std::net::Shutdown;
1718
use std::os::unix::net::UnixStream;
@@ -204,3 +205,62 @@ fn test_sendfile_darwin() {
204205
assert_eq!(bytes_written as usize, bytes_read);
205206
assert_eq!(expected_string, read_string);
206207
}
208+
209+
#[cfg(solarish)]
210+
#[test]
211+
fn test_sendfilev() {
212+
use std::os::fd::AsFd;
213+
// Declare the content
214+
let header_strings =
215+
["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
216+
let body = "Xabcdef123456";
217+
let body_offset = 1usize;
218+
let trailer_strings = ["\n", "Served by Make Believe\n"];
219+
220+
// Write data to files
221+
let mut header_data = tempfile().unwrap();
222+
header_data
223+
.write_all(header_strings.concat().as_bytes())
224+
.unwrap();
225+
let mut body_data = tempfile().unwrap();
226+
body_data.write_all(body.as_bytes()).unwrap();
227+
let mut trailer_data = tempfile().unwrap();
228+
trailer_data
229+
.write_all(trailer_strings.concat().as_bytes())
230+
.unwrap();
231+
let (mut rd, wr) = UnixStream::pair().unwrap();
232+
let vec: &[SendfileVec] = &[
233+
SendfileVec::new(
234+
header_data.as_fd(),
235+
0,
236+
header_strings.iter().map(|s| s.len()).sum(),
237+
),
238+
SendfileVec::new(
239+
body_data.as_fd(),
240+
body_offset as off_t,
241+
body.len() - body_offset,
242+
),
243+
SendfileVec::new(
244+
trailer_data.as_fd(),
245+
0,
246+
trailer_strings.iter().map(|s| s.len()).sum(),
247+
),
248+
];
249+
250+
let (res, bytes_written) = sendfilev(&wr, vec);
251+
assert!(res.is_ok());
252+
wr.shutdown(Shutdown::Both).unwrap();
253+
254+
// Prepare the expected result
255+
let expected_string = header_strings.concat()
256+
+ &body[body_offset..]
257+
+ &trailer_strings.concat();
258+
259+
// Verify the message that was sent
260+
assert_eq!(bytes_written, expected_string.as_bytes().len());
261+
262+
let mut read_string = String::new();
263+
let bytes_read = rd.read_to_string(&mut read_string).unwrap();
264+
assert_eq!(bytes_written, bytes_read);
265+
assert_eq!(expected_string, read_string);
266+
}

0 commit comments

Comments
 (0)