Skip to content

Commit df8c14d

Browse files
committed
Change Socket::set_nosigpipe to accept a bool
Same as Socket::set_nonblocking. Also add test for it.
1 parent 29a1cdc commit df8c14d

File tree

3 files changed

+64
-11
lines changed

3 files changed

+64
-11
lines changed

src/socket.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ use crate::{Domain, Protocol, SockAddr, Type};
7878
///
7979
/// // On macOS and iOS set `NOSIGPIPE`.
8080
/// #[cfg(target_vendor = "apple")]
81-
/// socket.set_nosigpipe()?;
81+
/// socket.set_nosigpipe(true)?;
8282
///
8383
/// # drop(socket);
8484
/// # Ok(())

src/sys/unix.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#[cfg(not(target_os = "redox"))]
1010
use std::io::{IoSlice, IoSliceMut};
1111
use std::io::{Read, Write};
12-
use std::mem::{self, size_of_val, MaybeUninit};
12+
use std::mem::{self, size_of, size_of_val, MaybeUninit};
1313
use std::net::Shutdown;
1414
use std::net::{self, Ipv4Addr, Ipv6Addr};
1515
#[cfg(feature = "all")]
@@ -435,8 +435,15 @@ impl crate::Socket {
435435
///
436436
/// Only supported on Apple platforms (`target_vendor = "apple"`).
437437
#[cfg(all(feature = "all", target_vendor = "apple"))]
438-
pub fn set_nosigpipe(&self) -> io::Result<()> {
439-
unsafe { setsockopt(self.inner, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1i32) }
438+
pub fn set_nosigpipe(&self, nosigpipe: bool) -> io::Result<()> {
439+
unsafe {
440+
setsockopt::<c_int>(
441+
self.inner,
442+
libc::SOL_SOCKET,
443+
libc::SO_NOSIGPIPE,
444+
nosigpipe as _,
445+
)
446+
}
440447
}
441448
}
442449

@@ -467,7 +474,7 @@ fn fcntl_remove(fd: SysSocket, get_cmd: c_int, set_cmd: c_int, flag: c_int) -> i
467474
/// Caller must ensure `T` is the correct type for `opt` and `val`.
468475
unsafe fn getsockopt<T>(fd: SysSocket, opt: c_int, val: c_int) -> io::Result<T> {
469476
let mut payload: MaybeUninit<T> = MaybeUninit::uninit();
470-
let mut len = mem::size_of::<T>() as libc::socklen_t;
477+
let mut len = size_of::<T>() as libc::socklen_t;
471478
syscall!(getsockopt(
472479
fd,
473480
opt,
@@ -476,18 +483,15 @@ unsafe fn getsockopt<T>(fd: SysSocket, opt: c_int, val: c_int) -> io::Result<T>
476483
&mut len,
477484
))
478485
.map(|_| {
479-
debug_assert_eq!(len as usize, mem::size_of::<T>());
486+
debug_assert_eq!(len as usize, size_of::<T>());
480487
// Safety: `getsockopt` initialised `payload` for us.
481488
payload.assume_init()
482489
})
483490
}
484491

485492
/// Caller must ensure `T` is the correct type for `opt` and `val`.
486493
#[cfg(all(feature = "all", target_vendor = "apple"))]
487-
unsafe fn setsockopt<T>(fd: SysSocket, opt: c_int, val: c_int, payload: T) -> io::Result<()>
488-
where
489-
T: Copy,
490-
{
494+
unsafe fn setsockopt<T>(fd: SysSocket, opt: c_int, val: c_int, payload: T) -> io::Result<()> {
491495
let payload = &payload as *const T as *const c_void;
492496
syscall!(setsockopt(
493497
fd,
@@ -499,6 +503,15 @@ where
499503
.map(|_| ())
500504
}
501505

506+
/*
507+
setsockopt::<c_int>(
508+
self.inner,
509+
libc::SOL_SOCKET,
510+
libc::SO_NOSIGPIPE,
511+
nosigpipe as _,
512+
)
513+
*/
514+
502515
#[repr(transparent)] // Required during rewriting.
503516
pub struct Socket {
504517
fd: SysSocket,

tests/socket.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#[cfg(windows)]
1+
#[cfg(any(windows, all(feature = "all", target_vendor = "apple")))]
22
use std::io;
33
#[cfg(unix)]
44
use std::os::unix::io::AsRawFd;
@@ -142,3 +142,43 @@ where
142142
"FLAG_INHERIT option"
143143
);
144144
}
145+
146+
#[cfg(all(feature = "all", target_vendor = "apple"))]
147+
#[test]
148+
fn set_nosigpipe() {
149+
let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
150+
assert_flag_no_sigpipe(&socket, false);
151+
152+
socket.set_nosigpipe(true).unwrap();
153+
assert_flag_no_sigpipe(&socket, true);
154+
155+
socket.set_nosigpipe(false).unwrap();
156+
assert_flag_no_sigpipe(&socket, false);
157+
}
158+
159+
/// Assert that `SO_NOSIGPIPE` is set on `socket`.
160+
#[cfg(all(feature = "all", target_vendor = "apple"))]
161+
#[track_caller]
162+
pub fn assert_flag_no_sigpipe<S>(socket: &S, want: bool)
163+
where
164+
S: AsRawFd,
165+
{
166+
use std::mem::size_of;
167+
let mut flags: libc::c_int = 0;
168+
let mut length = size_of::<libc::c_int>() as libc::socklen_t;
169+
let res = unsafe {
170+
libc::getsockopt(
171+
socket.as_raw_fd(),
172+
libc::SOL_SOCKET,
173+
libc::SO_NOSIGPIPE,
174+
&mut flags as *mut _ as *mut _,
175+
&mut length,
176+
)
177+
};
178+
if res != 0 {
179+
let err = io::Error::last_os_error();
180+
panic!("unexpected error: {}", err);
181+
}
182+
assert_eq!(length as usize, size_of::<libc::c_int>());
183+
assert_eq!(flags, want as _, "non-blocking option");
184+
}

0 commit comments

Comments
 (0)