Skip to content

Commit 6f87e54

Browse files
committed
sys::sendfile adding solaris' sendfilev wrapper proposal.
1 parent 2afff81 commit 6f87e54

File tree

4 files changed

+127
-1
lines changed

4 files changed

+127
-1
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: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::Result;
2222
///
2323
/// For more information, see [the sendfile(2) man page.](https://man7.org/linux/man-pages/man2/sendfile.2.html) for Linux,
2424
/// see [the sendfile(2) man page.](https://docs.oracle.com/cd/E88353_01/html/E37843/sendfile-3c.html) for Solaris.
25-
#[cfg(any(target_os = "android", target_os = "linux", target_os = "solaris", target_os = "illumos"))]
25+
#[cfg(any(target_os = "android", target_os = "linux", solarish))]
2626
pub fn sendfile<F1: AsFd, F2: AsFd>(
2727
out_fd: F1,
2828
in_fd: F2,
@@ -120,6 +120,49 @@ cfg_if! {
120120
)
121121
}
122122
}
123+
} else if #[cfg(solarish)] {
124+
#[derive(Debug, Copy, Clone)]
125+
/// Mapping of the raw C sendfilevec_t struct
126+
/// no need to bother with `sfv_flag` since it needs to be always 0.
127+
pub struct SendfileVec {
128+
/// input file descriptor
129+
pub fd: i32,
130+
/// offset to read from
131+
pub off: off_t,
132+
/// size of the data to read
133+
pub len: usize,
134+
}
135+
136+
const SFV_FD_SELF: i32 = -2;
137+
138+
impl SendfileVec {
139+
/// initialises SendfileVec to send data directly from the process's address space
140+
/// same in C with sfv_fd set to SFV_FD_SELF.
141+
pub fn newself(
142+
off: off_t,
143+
len: usize
144+
) -> SendfileVec {
145+
SendfileVec{fd: SFV_FD_SELF, off, len}
146+
}
147+
148+
/// initialises SendfileVec to send data from `fd`.
149+
pub fn new<F: AsFd>(
150+
fd: F,
151+
off: off_t,
152+
len: usize
153+
) -> SendfileVec {
154+
SendfileVec{fd: fd.as_fd().as_raw_fd(), off, len}
155+
}
156+
157+
fn tosendfilevec(&self) -> libc::sendfilevec_t {
158+
libc::sendfilevec_t{
159+
sfv_fd: self.fd,
160+
sfv_flag: 0,
161+
sfv_off: self.off,
162+
sfv_len: self.len
163+
}
164+
}
165+
}
123166
}
124167
}
125168

@@ -287,5 +330,31 @@ cfg_if! {
287330
};
288331
(Errno::result(return_code).and(Ok(())), len)
289332
}
333+
} else if #[cfg(solarish)] {
334+
/// Write data from the vec arrays to `out_sock` and returns a `Result` and a
335+
/// count of bytes written.
336+
///
337+
/// Each `SendfileVec` set needs to be instantiated either with `SendfileVec::new` or
338+
/// `SendfileVec::newself`.
339+
///
340+
/// The former allows to send data from a file descriptor through `fd`,
341+
/// from an offset `off` and for a given amount of data `len`.
342+
///
343+
/// The latter allows to send data from the process' address space, from an offset `off`
344+
/// and for a given amount of data `len`.
345+
///
346+
/// For more information, see
347+
/// [the sendfilev{3) man page.](https://docs.oracle.com/cd/E86824_01/html/E54768/sendfilev-3ext.html)
348+
pub fn sendfilev<F: AsFd>(
349+
out_sock: F,
350+
vec: Vec<SendfileVec>
351+
) -> (Result<()>, usize) {
352+
let rawvec: Vec<libc::sendfilevec_t> = vec.iter().map(|&v| v.tosendfilevec()).collect();
353+
let mut len = 0usize;
354+
let return_code = unsafe {
355+
libc::sendfilev(out_sock.as_fd().as_raw_fd(), rawvec.as_ptr(), rawvec.len() as i32, &mut len)
356+
};
357+
(Errno::result(return_code).and(Ok(())), len)
358+
}
290359
}
291360
}

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: 55 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,57 @@ 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+
// Declare the content
213+
let header_strings =
214+
["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
215+
let body = "Xabcdef123456";
216+
let body_offset = 1usize;
217+
let trailer_strings = ["\n", "Served by Make Believe\n"];
218+
219+
// Write data to files
220+
let mut header_data = tempfile().unwrap();
221+
header_data
222+
.write_all(header_strings.concat().as_bytes())
223+
.unwrap();
224+
let mut body_data = tempfile().unwrap();
225+
body_data.write_all(body.as_bytes()).unwrap();
226+
let mut trailer_data = tempfile().unwrap();
227+
trailer_data
228+
.write_all(trailer_strings.concat().as_bytes())
229+
.unwrap();
230+
let (mut rd, wr) = UnixStream::pair().unwrap();
231+
let vec: Vec<SendfileVec> = vec![
232+
SendfileVec::new(
233+
&header_data,
234+
0,
235+
header_strings.iter().map(|s| s.len()).sum(),
236+
),
237+
SendfileVec::new(&body_data, body_offset as off_t, body.len() - 1),
238+
SendfileVec::new(
239+
&trailer_data,
240+
0,
241+
trailer_strings.iter().map(|s| s.len()).sum(),
242+
),
243+
];
244+
245+
let (res, bytes_written) = sendfilev(&wr, vec);
246+
assert!(res.is_ok());
247+
wr.shutdown(Shutdown::Both).unwrap();
248+
249+
// Prepare the expected result
250+
let expected_string = header_strings.concat()
251+
+ &body[body_offset..]
252+
+ &trailer_strings.concat();
253+
254+
// Verify the message that was sent
255+
//assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
256+
257+
let mut read_string = String::new();
258+
let bytes_read = rd.read_to_string(&mut read_string).unwrap();
259+
assert_eq!(bytes_written, bytes_read);
260+
assert_eq!(expected_string, read_string);
261+
}

0 commit comments

Comments
 (0)