use crate::io::{self, IoSlice, IoSliceMut};
use crate::mem;
use crate::net::{Shutdown, SocketAddr};
+use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::str;
use crate::sys::fd::FileDesc;
use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::{Duration, Instant};
-use libc::{c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK};
+use libc::{c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK};
+
+cfg_if::cfg_if! {
+ if #[cfg(target_vendor = "apple")] {
+ use libc::SO_LINGER_SEC as SO_LINGER;
+ } else {
+ use libc::SO_LINGER;
+ }
+}
pub use crate::sys::{cvt, cvt_r};
// We may need to trigger a glibc workaround. See on_resolver_failure() for details.
on_resolver_failure();
- if err == EAI_SYSTEM {
+ #[cfg(not(target_os = "espidf"))]
+ if err == libc::EAI_SYSTEM {
return Err(io::Error::last_os_error());
}
+ #[cfg(not(target_os = "espidf"))]
let detail = unsafe {
str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned()
};
+
+ #[cfg(target_os = "espidf")]
+ let detail = "";
+
Err(io::Error::new(
io::ErrorKind::Uncategorized,
&format!("failed to lookup address information: {}", detail)[..],
// flag to atomically create the socket and set it as
// CLOEXEC. On Linux this was added in 2.6.27.
let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?;
- Ok(Socket(FileDesc::new(fd)))
+ Ok(Socket(FileDesc::from_raw_fd(fd)))
} else {
let fd = cvt(libc::socket(fam, ty, 0))?;
- let fd = FileDesc::new(fd);
+ let fd = FileDesc::from_raw_fd(fd);
fd.set_cloexec()?;
let socket = Socket(fd);
))] {
// Like above, set cloexec atomically
cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
- Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))))
+ Ok((Socket(FileDesc::from_raw_fd(fds[0])), Socket(FileDesc::from_raw_fd(fds[1]))))
} else {
cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
- let a = FileDesc::new(fds[0]);
- let b = FileDesc::new(fds[1]);
+ let a = FileDesc::from_raw_fd(fds[0]);
+ let b = FileDesc::from_raw_fd(fds[1]);
a.set_cloexec()?;
b.set_cloexec()?;
Ok((Socket(a), Socket(b)))
self.set_nonblocking(true)?;
let r = unsafe {
let (addrp, len) = addr.into_inner();
- cvt(libc::connect(self.0.raw(), addrp, len))
+ cvt(libc::connect(self.as_raw_fd(), addrp, len))
};
self.set_nonblocking(false)?;
Err(e) => return Err(e),
}
- let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 };
+ let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 };
if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
return Err(io::Error::new_const(
target_os = "netbsd",
target_os = "openbsd",
))] {
- let fd = cvt_r(|| unsafe {
- libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
- })?;
- Ok(Socket(FileDesc::new(fd)))
+ unsafe {
+ let fd = cvt_r(|| libc::accept4(self.as_raw_fd(), storage, len, libc::SOCK_CLOEXEC))?;
+ Ok(Socket(FileDesc::from_raw_fd(fd)))
+ }
} else {
- let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
- let fd = FileDesc::new(fd);
- fd.set_cloexec()?;
- Ok(Socket(fd))
+ unsafe {
+ let fd = cvt_r(|| libc::accept(self.as_raw_fd(), storage, len))?;
+ let fd = FileDesc::from_raw_fd(fd);
+ fd.set_cloexec()?;
+ Ok(Socket(fd))
+ }
}
}
}
fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
let ret = cvt(unsafe {
- libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
+ libc::recv(self.as_raw_fd(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
})?;
Ok(ret as usize)
}
let n = cvt(unsafe {
libc::recvfrom(
- self.0.raw(),
+ self.as_raw_fd(),
buf.as_mut_ptr() as *mut c_void,
buf.len(),
flags,
target_os = "openbsd",
))]
pub fn recv_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
- let n = cvt(unsafe { libc::recvmsg(self.0.raw(), msg, libc::MSG_CMSG_CLOEXEC) })?;
+ let n = cvt(unsafe { libc::recvmsg(self.as_raw_fd(), msg, libc::MSG_CMSG_CLOEXEC) })?;
Ok(n as usize)
}
target_os = "openbsd",
))]
pub fn send_msg(&self, msg: &mut libc::msghdr) -> io::Result<usize> {
- let n = cvt(unsafe { libc::sendmsg(self.0.raw(), msg, 0) })?;
+ let n = cvt(unsafe { libc::sendmsg(self.as_raw_fd(), msg, 0) })?;
Ok(n as usize)
}
Shutdown::Read => libc::SHUT_RD,
Shutdown::Both => libc::SHUT_RDWR,
};
- cvt(unsafe { libc::shutdown(self.0.raw(), how) })?;
+ cvt(unsafe { libc::shutdown(self.as_raw_fd(), how) })?;
Ok(())
}
+ pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+ let linger = libc::linger {
+ l_onoff: linger.is_some() as libc::c_int,
+ l_linger: linger.map(|dur| dur.as_secs() as libc::c_int).unwrap_or_default(),
+ };
+
+ setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger)
+ }
+
+ pub fn linger(&self) -> io::Result<Option<Duration>> {
+ let val: libc::linger = getsockopt(self, libc::SOL_SOCKET, SO_LINGER)?;
+
+ Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
+ }
+
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int)
}
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking = nonblocking as libc::c_int;
- cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop)
+ cvt(unsafe { libc::ioctl(self.as_raw_fd(), libc::FIONBIO, &mut nonblocking) }).map(drop)
}
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
}
+
+ // This is used by sys_common code to abstract over Windows and Unix.
+ pub fn as_raw(&self) -> RawFd {
+ self.as_raw_fd()
+ }
+}
+
+impl AsInner<FileDesc> for Socket {
+ fn as_inner(&self) -> &FileDesc {
+ &self.0
+ }
+}
+
+impl IntoInner<FileDesc> for Socket {
+ fn into_inner(self) -> FileDesc {
+ self.0
+ }
+}
+
+impl FromInner<FileDesc> for Socket {
+ fn from_inner(file_desc: FileDesc) -> Self {
+ Self(file_desc)
+ }
+}
+
+impl AsFd for Socket {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_fd()
+ }
}
-impl AsInner<c_int> for Socket {
- fn as_inner(&self) -> &c_int {
- self.0.as_inner()
+impl AsRawFd for Socket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
}
}
-impl FromInner<c_int> for Socket {
- fn from_inner(fd: c_int) -> Socket {
- Socket(FileDesc::new(fd))
+impl IntoRawFd for Socket {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw_fd()
}
}
-impl IntoInner<c_int> for Socket {
- fn into_inner(self) -> c_int {
- self.0.into_raw()
+impl FromRawFd for Socket {
+ unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+ Self(FromRawFd::from_raw_fd(raw_fd))
}
}