Skip to content

Commit ec8df47

Browse files
oskardrumsalexcrichton
authored andcommitted
Support Out-of-Band related functionality (#51)
* sys/unix/Socket: support OOBINLINE socket option * Socket: add flags argument where appropriate allow callers to specify flags for send/recv * Windows: set flags in send/recv for Read/Write * satisfy rustfmt * Socket: retain the current public interface Maintain send/recv's current signature and expose the flags argument via _with_flags methods
1 parent 75fe3f2 commit ec8df47

File tree

3 files changed

+193
-31
lines changed

3 files changed

+193
-31
lines changed

src/socket.rs

Lines changed: 134 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ use libc as c;
2020
#[cfg(windows)]
2121
use winapi::shared::ws2def as c;
2222

23+
#[cfg(any(unix, target_os = "redox"))]
24+
use libc::MSG_OOB;
25+
#[cfg(windows)]
26+
use winapi::um::winsock2::MSG_OOB;
27+
2328
use crate::sys;
2429
use crate::{Domain, Protocol, SockAddr, Socket, Type};
2530

@@ -213,7 +218,26 @@ impl Socket {
213218
///
214219
/// [`connect`]: #method.connect
215220
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
216-
self.inner.recv(buf)
221+
self.inner.recv(buf, 0)
222+
}
223+
224+
/// Identical to [`recv`] but allows for specification of arbitrary flags to the underlying
225+
/// `recv` call.
226+
///
227+
/// [`recv`]: #method.recv
228+
pub fn recv_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize> {
229+
self.inner.recv(buf, flags)
230+
}
231+
232+
/// Receives out-of-band (OOB) data on the socket from the remote address to
233+
/// which it is connected by setting the `MSG_OOB` flag for this call.
234+
///
235+
/// For more information, see [`recv`], [`out_of_band_inline`].
236+
///
237+
/// [`recv`]: #method.recv
238+
/// [`out_of_band_inline`]: #method.out_of_band_inline
239+
pub fn recv_out_of_band(&self, buf: &mut [u8]) -> io::Result<usize> {
240+
self.inner.recv(buf, MSG_OOB)
217241
}
218242

219243
/// Receives data on the socket from the remote adress to which it is
@@ -229,7 +253,15 @@ impl Socket {
229253
/// Receives data from the socket. On success, returns the number of bytes
230254
/// read and the address from whence the data came.
231255
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
232-
self.inner.recv_from(buf)
256+
self.inner.recv_from(buf, 0)
257+
}
258+
259+
/// Identical to [`recv_from`] but allows for specification of arbitrary flags to the underlying
260+
/// `recvfrom` call.
261+
///
262+
/// [`recv_from`]: #method.recv_from
263+
pub fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize> {
264+
self.inner.recv(buf, flags)
233265
}
234266

235267
/// Receives data from the socket, without removing it from the queue.
@@ -250,7 +282,26 @@ impl Socket {
250282
///
251283
/// On success returns the number of bytes that were sent.
252284
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
253-
self.inner.send(buf)
285+
self.inner.send(buf, 0)
286+
}
287+
288+
/// Identical to [`send`] but allows for specification of arbitrary flags to the underlying
289+
/// `send` call.
290+
///
291+
/// [`send`]: #method.send
292+
pub fn send_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize> {
293+
self.inner.send(buf, flags)
294+
}
295+
296+
/// Sends out-of-band (OOB) data on the socket to connected peer
297+
/// by setting the `MSG_OOB` flag for this call.
298+
///
299+
/// For more information, see [`send`], [`out_of_band_inline`].
300+
///
301+
/// [`send`]: #method.send
302+
/// [`out_of_band_inline`]: #method.out_of_band_inline
303+
pub fn send_out_of_band(&self, buf: &mut [u8]) -> io::Result<usize> {
304+
self.inner.send(buf, MSG_OOB)
254305
}
255306

256307
/// Sends data on the socket to the given address. On success, returns the
@@ -259,7 +310,15 @@ impl Socket {
259310
/// This is typically used on UDP or datagram-oriented sockets. On success
260311
/// returns the number of bytes that were sent.
261312
pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
262-
self.inner.send_to(buf, addr)
313+
self.inner.send_to(buf, 0, addr)
314+
}
315+
316+
/// Identical to [`send_to`] but allows for specification of arbitrary flags to the underlying
317+
/// `sendto` call.
318+
///
319+
/// [`send_to`]: #method.send_to
320+
pub fn send_to_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize> {
321+
self.inner.recv(buf, flags)
263322
}
264323

265324
// ================================================
@@ -628,6 +687,24 @@ impl Socket {
628687
self.inner.set_keepalive(keepalive)
629688
}
630689

690+
/// Returns the value of the `SO_OOBINLINE` flag of the underlying socket.
691+
/// For more information about this option, see [`set_out_of_band_inline`][link].
692+
///
693+
/// [link]: #method.set_out_of_band_inline
694+
pub fn out_of_band_inline(&self) -> io::Result<bool> {
695+
self.inner.out_of_band_inline()
696+
}
697+
698+
/// Sets the `SO_OOBINLINE` flag of the underlying socket.
699+
/// as per RFC6093, TCP sockets using the Urgent mechanism
700+
/// are encouraged to set this flag.
701+
///
702+
/// If this flag is not set, the `MSG_OOB` flag is needed
703+
/// while `recv`ing to aquire the out-of-band data.
704+
pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
705+
self.inner.set_out_of_band_inline(oob_inline)
706+
}
707+
631708
/// Check the value of the `SO_REUSEPORT` option on this socket.
632709
///
633710
/// This function is only available on Unix when the `reuseport` feature is
@@ -1003,4 +1080,57 @@ mod test {
10031080
assert!(result.is_ok());
10041081
assert!(result.unwrap());
10051082
}
1083+
1084+
#[test]
1085+
fn out_of_band_inline() {
1086+
let socket = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
1087+
1088+
assert_eq!(socket.out_of_band_inline().unwrap(), false);
1089+
1090+
socket.set_out_of_band_inline(true).unwrap();
1091+
assert_eq!(socket.out_of_band_inline().unwrap(), true);
1092+
}
1093+
1094+
#[test]
1095+
#[cfg(any(target_os = "windows", target_os = "linux"))]
1096+
fn out_of_band_send_recv() {
1097+
let s1 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
1098+
s1.bind(&"127.0.0.1:0".parse::<SocketAddr>().unwrap().into())
1099+
.unwrap();
1100+
let s1_addr = s1.local_addr().unwrap();
1101+
s1.listen(1).unwrap();
1102+
1103+
let s2 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
1104+
s2.connect(&s1_addr).unwrap();
1105+
1106+
let (s3, _) = s1.accept().unwrap();
1107+
1108+
let mut buf = [0; 10];
1109+
// send some plain inband data
1110+
s2.send(&mut buf).unwrap();
1111+
// send a single out of band byte
1112+
assert_eq!(s2.send_out_of_band(&mut [b"!"[0]]).unwrap(), 1);
1113+
// recv the OOB data first
1114+
assert_eq!(s3.recv_out_of_band(&mut buf).unwrap(), 1);
1115+
assert_eq!(buf[0], b"!"[0]);
1116+
assert_eq!(s3.recv(&mut buf).unwrap(), 10);
1117+
}
1118+
1119+
#[test]
1120+
fn tcp() {
1121+
let s1 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
1122+
s1.bind(&"127.0.0.1:0".parse::<SocketAddr>().unwrap().into())
1123+
.unwrap();
1124+
let s1_addr = s1.local_addr().unwrap();
1125+
s1.listen(1).unwrap();
1126+
1127+
let s2 = Socket::new(Domain::ipv4(), Type::stream(), None).unwrap();
1128+
s2.connect(&s1_addr).unwrap();
1129+
1130+
let (s3, _) = s1.accept().unwrap();
1131+
1132+
let mut buf = [0; 11];
1133+
assert_eq!(s2.send(&mut buf).unwrap(), 11);
1134+
assert_eq!(s3.recv(&mut buf).unwrap(), 11);
1135+
}
10061136
}

src/sys/unix.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -349,14 +349,14 @@ impl Socket {
349349
Ok(())
350350
}
351351

352-
pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
352+
pub fn recv(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
353353
unsafe {
354354
let n = cvt({
355355
libc::recv(
356356
self.fd,
357357
buf.as_mut_ptr() as *mut c_void,
358358
cmp::min(buf.len(), max_len()),
359-
0,
359+
flags,
360360
)
361361
})?;
362362
Ok(n as usize)
@@ -377,15 +377,11 @@ impl Socket {
377377
}
378378
}
379379

380-
pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
381-
self.recvfrom(buf, 0)
382-
}
383-
384380
pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SockAddr)> {
385-
self.recvfrom(buf, libc::MSG_PEEK)
381+
self.recv_from(buf, libc::MSG_PEEK)
386382
}
387383

388-
fn recvfrom(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> {
384+
pub fn recv_from(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SockAddr)> {
389385
unsafe {
390386
let mut storage: libc::sockaddr_storage = mem::zeroed();
391387
let mut addrlen = mem::size_of_val(&storage) as socklen_t;
@@ -405,28 +401,28 @@ impl Socket {
405401
}
406402
}
407403

408-
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
404+
pub fn send(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
409405
unsafe {
410406
let n = cvt({
411407
libc::send(
412408
self.fd,
413409
buf.as_ptr() as *const c_void,
414410
cmp::min(buf.len(), max_len()),
415-
MSG_NOSIGNAL,
411+
flags,
416412
)
417413
})?;
418414
Ok(n as usize)
419415
}
420416
}
421417

422-
pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
418+
pub fn send_to(&self, buf: &[u8], flags: c_int, addr: &SockAddr) -> io::Result<usize> {
423419
unsafe {
424420
let n = cvt({
425421
libc::sendto(
426422
self.fd,
427423
buf.as_ptr() as *const c_void,
428424
cmp::min(buf.len(), max_len()),
429-
MSG_NOSIGNAL,
425+
flags,
430426
addr.as_ptr(),
431427
addr.len(),
432428
)
@@ -744,6 +740,17 @@ impl Socket {
744740
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_REUSEPORT, reuse as c_int) }
745741
}
746742

743+
pub fn out_of_band_inline(&self) -> io::Result<bool> {
744+
unsafe {
745+
let raw: c_int = self.getsockopt(libc::SOL_SOCKET, libc::SO_OOBINLINE)?;
746+
Ok(raw != 0)
747+
}
748+
}
749+
750+
pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
751+
unsafe { self.setsockopt(libc::SOL_SOCKET, libc::SO_OOBINLINE, oob_inline as c_int) }
752+
}
753+
747754
unsafe fn setsockopt<T>(&self, opt: c_int, val: c_int, payload: T) -> io::Result<()>
748755
where
749756
T: Copy,
@@ -807,7 +814,7 @@ impl Write for Socket {
807814

808815
impl<'a> Write for &'a Socket {
809816
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
810-
self.send(buf)
817+
self.send(buf, 0)
811818
}
812819

813820
fn flush(&mut self) -> io::Result<()> {
@@ -1108,3 +1115,12 @@ fn test_ip() {
11081115
let ip = Ipv4Addr::new(127, 0, 0, 1);
11091116
assert_eq!(ip, from_s_addr(to_s_addr(&ip)));
11101117
}
1118+
1119+
#[test]
1120+
fn test_out_of_band_inline() {
1121+
let tcp = Socket::new(libc::AF_INET, libc::SOCK_STREAM, 0).unwrap();
1122+
assert_eq!(tcp.out_of_band_inline().unwrap(), false);
1123+
1124+
tcp.set_out_of_band_inline(true).unwrap();
1125+
assert_eq!(tcp.out_of_band_inline().unwrap(), true);
1126+
}

0 commit comments

Comments
 (0)