5 io
::{self, ErrorKind, IoSlice, IoSliceMut}
,
7 net
::{Shutdown, SocketAddr}
,
9 sys_common
::net
::{getsockopt, setsockopt, sockaddr_to_addr}
,
10 sys_common
::{AsInner, FromInner, IntoInner}
,
14 use self::netc
::{sockaddr, socklen_t, MSG_PEEK}
;
15 use libc
::{c_int, c_void, size_t}
;
18 pub use super::super::abi
::sockets
::*;
21 pub type wrlen_t
= size_t
;
23 const READ_LIMIT
: usize = libc
::ssize_t
::MAX
as usize;
25 const fn max_iov() -> usize {
26 // Judging by the source code, it's unlimited, but specify a lower
27 // value just in case.
31 /// A file descriptor.
32 #[rustc_layout_scalar_valid_range_start(0)]
33 // libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
34 // 32-bit c_int. Below is -2, in two's complement, but that only works out
35 // because c_int is 32 bits.
36 #[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
43 fn new(fd
: c_int
) -> FileDesc
{
44 assert_ne
!(fd
, -1i32);
45 // Safety: we just asserted that the value is in the valid range and
46 // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
47 unsafe { FileDesc { fd }
}
51 fn raw(&self) -> c_int
{
55 /// Extracts the actual file descriptor without closing it.
57 fn into_raw(self) -> c_int
{
63 fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
64 let ret
= cvt(unsafe {
65 netc
::read(self.fd
, buf
.as_mut_ptr() as *mut c_void
, cmp
::min(buf
.len(), READ_LIMIT
))
70 fn read_vectored(&self, bufs
: &mut [IoSliceMut
<'_
>]) -> io
::Result
<usize> {
71 let ret
= cvt(unsafe {
74 bufs
.as_ptr() as *const netc
::iovec
,
75 cmp
::min(bufs
.len(), max_iov()) as c_int
,
82 fn is_read_vectored(&self) -> bool
{
86 fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
87 let ret
= cvt(unsafe {
88 netc
::write(self.fd
, buf
.as_ptr() as *const c_void
, cmp
::min(buf
.len(), READ_LIMIT
))
93 fn write_vectored(&self, bufs
: &[IoSlice
<'_
>]) -> io
::Result
<usize> {
94 let ret
= cvt(unsafe {
97 bufs
.as_ptr() as *const netc
::iovec
,
98 cmp
::min(bufs
.len(), max_iov()) as c_int
,
105 fn is_write_vectored(&self) -> bool
{
109 fn duplicate(&self) -> io
::Result
<FileDesc
> {
110 cvt(unsafe { netc::dup(self.fd) }
).map(Self::new
)
114 impl AsInner
<c_int
> for FileDesc
{
115 fn as_inner(&self) -> &c_int
{
120 impl Drop
for FileDesc
{
122 unsafe { netc::close(self.fd) }
;
127 pub trait IsMinusOne
{
128 fn is_minus_one(&self) -> bool
;
131 macro_rules
! impl_is_minus_one
{
132 ($
($t
:ident
)*) => ($
(impl IsMinusOne
for $t
{
133 fn is_minus_one(&self) -> bool
{
139 impl_is_minus_one
! { i8 i16 i32 i64 isize }
141 pub fn cvt
<T
: IsMinusOne
>(t
: T
) -> io
::Result
<T
> {
142 if t
.is_minus_one() { Err(last_error()) }
else { Ok(t) }
145 /// A variant of `cvt` for `getaddrinfo` which return 0 for a success.
146 pub fn cvt_gai(err
: c_int
) -> io
::Result
<()> {
150 let msg
: &dyn crate::fmt
::Display
= match err
{
151 netc
::EAI_NONAME
=> &"name or service not known",
152 netc
::EAI_SERVICE
=> &"service not supported",
153 netc
::EAI_FAIL
=> &"non-recoverable failure in name resolution",
154 netc
::EAI_MEMORY
=> &"memory allocation failure",
155 netc
::EAI_FAMILY
=> &"family not supported",
159 io
::ErrorKind
::Uncategorized
,
160 &format
!("failed to lookup address information: {msg}")[..],
165 /// Just to provide the same interface as sys/unix/net.rs
166 pub fn cvt_r
<T
, F
>(mut f
: F
) -> io
::Result
<T
>
174 /// Returns the last error from the network subsystem.
175 fn last_error() -> io
::Error
{
176 io
::Error
::from_raw_os_error(unsafe { netc::SOLID_NET_GetLastError() }
)
179 pub(super) fn error_name(er
: abi
::ER
) -> Option
<&'
static str> {
180 unsafe { CStr::from_ptr(netc::strerror(er)) }
.to_str().ok()
183 pub(super) fn decode_error_kind(er
: abi
::ER
) -> ErrorKind
{
184 let errno
= netc
::SOLID_NET_ERR_BASE
- er
;
185 match errno
as libc
::c_int
{
186 libc
::ECONNREFUSED
=> ErrorKind
::ConnectionRefused
,
187 libc
::ECONNRESET
=> ErrorKind
::ConnectionReset
,
188 libc
::EPERM
| libc
::EACCES
=> ErrorKind
::PermissionDenied
,
189 libc
::EPIPE
=> ErrorKind
::BrokenPipe
,
190 libc
::ENOTCONN
=> ErrorKind
::NotConnected
,
191 libc
::ECONNABORTED
=> ErrorKind
::ConnectionAborted
,
192 libc
::EADDRNOTAVAIL
=> ErrorKind
::AddrNotAvailable
,
193 libc
::EADDRINUSE
=> ErrorKind
::AddrInUse
,
194 libc
::ENOENT
=> ErrorKind
::NotFound
,
195 libc
::EINTR
=> ErrorKind
::Interrupted
,
196 libc
::EINVAL
=> ErrorKind
::InvalidInput
,
197 libc
::ETIMEDOUT
=> ErrorKind
::TimedOut
,
198 libc
::EEXIST
=> ErrorKind
::AlreadyExists
,
199 libc
::ENOSYS
=> ErrorKind
::Unsupported
,
200 libc
::ENOMEM
=> ErrorKind
::OutOfMemory
,
201 libc
::EAGAIN
=> ErrorKind
::WouldBlock
,
203 _
=> ErrorKind
::Uncategorized
,
209 pub struct Socket(FileDesc
);
212 pub fn new(addr
: &SocketAddr
, ty
: c_int
) -> io
::Result
<Socket
> {
213 let fam
= match *addr
{
214 SocketAddr
::V4(..) => netc
::AF_INET
,
215 SocketAddr
::V6(..) => netc
::AF_INET6
,
217 Socket
::new_raw(fam
, ty
)
220 pub fn new_raw(fam
: c_int
, ty
: c_int
) -> io
::Result
<Socket
> {
222 let fd
= cvt(netc
::socket(fam
, ty
, 0))?
;
223 let fd
= FileDesc
::new(fd
);
224 let socket
= Socket(fd
);
230 pub fn connect_timeout(&self, addr
: &SocketAddr
, timeout
: Duration
) -> io
::Result
<()> {
231 self.set_nonblocking(true)?
;
233 let (addrp
, len
) = addr
.into_inner();
234 cvt(netc
::connect(self.0.raw(), addrp
, len
))
236 self.set_nonblocking(false)?
;
239 Ok(_
) => return Ok(()),
240 // there's no ErrorKind for EINPROGRESS
241 Err(ref e
) if e
.raw_os_error() == Some(netc
::EINPROGRESS
) => {}
242 Err(e
) => return Err(e
),
245 if timeout
.as_secs() == 0 && timeout
.subsec_nanos() == 0 {
246 return Err(io
::const_io_error
!(
247 io
::ErrorKind
::InvalidInput
,
248 "cannot set a 0 duration timeout",
253 netc
::timeval { tv_sec: timeout.as_secs() as _, tv_usec: timeout.subsec_micros() as _ }
;
254 if timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0 {
258 let fds
= netc
::fd_set { num_fds: 1, fds: [self.0.raw()] }
;
260 let mut writefds
= fds
;
261 let mut errorfds
= fds
;
274 0 => Err(io
::const_io_error
!(io
::ErrorKind
::TimedOut
, "connection timed out")),
276 let can_write
= writefds
.num_fds
!= 0;
278 if let Some(e
) = self.take_error()?
{
287 pub fn accept(&self, storage
: *mut sockaddr
, len
: *mut socklen_t
) -> io
::Result
<Socket
> {
288 let fd
= cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) }
)?
;
289 let fd
= FileDesc
::new(fd
);
293 pub fn duplicate(&self) -> io
::Result
<Socket
> {
294 self.0.duplicate().map(Socket
)
297 fn recv_with_flags(&self, buf
: &mut [u8], flags
: c_int
) -> io
::Result
<usize> {
298 let ret
= cvt(unsafe {
299 netc
::recv(self.0.raw(), buf
.as_mut_ptr() as *mut c_void
, buf
.len(), flags
)
304 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
305 self.recv_with_flags(buf
, 0)
308 pub fn peek(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
309 self.recv_with_flags(buf
, MSG_PEEK
)
312 pub fn read_vectored(&self, bufs
: &mut [IoSliceMut
<'_
>]) -> io
::Result
<usize> {
313 self.0.read_vectored(bufs
)
317 pub fn is_read_vectored(&self) -> bool
{
318 self.0.is_read_vectored
()
321 fn recv_from_with_flags(
325 ) -> io
::Result
<(usize, SocketAddr
)> {
326 let mut storage
: netc
::sockaddr_storage
= unsafe { mem::zeroed() }
;
327 let mut addrlen
= mem
::size_of_val(&storage
) as netc
::socklen_t
;
332 buf
.as_mut_ptr() as *mut c_void
,
335 &mut storage
as *mut _
as *mut _
,
339 Ok((n
as usize, sockaddr_to_addr(&storage
, addrlen
as usize)?
))
342 pub fn recv_from(&self, buf
: &mut [u8]) -> io
::Result
<(usize, SocketAddr
)> {
343 self.recv_from_with_flags(buf
, 0)
346 pub fn peek_from(&self, buf
: &mut [u8]) -> io
::Result
<(usize, SocketAddr
)> {
347 self.recv_from_with_flags(buf
, MSG_PEEK
)
350 pub fn write(&self, buf
: &[u8]) -> io
::Result
<usize> {
354 pub fn write_vectored(&self, bufs
: &[IoSlice
<'_
>]) -> io
::Result
<usize> {
355 self.0.write_vectored(bufs
)
359 pub fn is_write_vectored(&self) -> bool
{
360 self.0.is_write_vectored
()
363 pub fn set_timeout(&self, dur
: Option
<Duration
>, kind
: c_int
) -> io
::Result
<()> {
364 let timeout
= match dur
{
366 if dur
.as_secs() == 0 && dur
.subsec_nanos() == 0 {
367 return Err(io
::const_io_error
!(
368 io
::ErrorKind
::InvalidInput
,
369 "cannot set a 0 duration timeout",
373 let secs
= if dur
.as_secs() > netc
::c_long
::MAX
as u64 {
376 dur
.as_secs() as netc
::c_long
378 let mut timeout
= netc
::timeval { tv_sec: secs, tv_usec: dur.subsec_micros() as _ }
;
379 if timeout
.tv_sec
== 0 && timeout
.tv_usec
== 0 {
384 None
=> netc
::timeval { tv_sec: 0, tv_usec: 0 }
,
386 setsockopt(self, netc
::SOL_SOCKET
, kind
, timeout
)
389 pub fn timeout(&self, kind
: c_int
) -> io
::Result
<Option
<Duration
>> {
390 let raw
: netc
::timeval
= getsockopt(self, netc
::SOL_SOCKET
, kind
)?
;
391 if raw
.tv_sec
== 0 && raw
.tv_usec
== 0 {
394 let sec
= raw
.tv_sec
as u64;
395 let nsec
= (raw
.tv_usec
as u32) * 1000;
396 Ok(Some(Duration
::new(sec
, nsec
)))
400 pub fn shutdown(&self, how
: Shutdown
) -> io
::Result
<()> {
401 let how
= match how
{
402 Shutdown
::Write
=> netc
::SHUT_WR
,
403 Shutdown
::Read
=> netc
::SHUT_RD
,
404 Shutdown
::Both
=> netc
::SHUT_RDWR
,
406 cvt(unsafe { netc::shutdown(self.0.raw(), how) }
)?
;
410 pub fn set_linger(&self, linger
: Option
<Duration
>) -> io
::Result
<()> {
411 let linger
= netc
::linger
{
412 l_onoff
: linger
.is_some() as netc
::c_int
,
413 l_linger
: linger
.unwrap_or_default().as_secs() as netc
::c_int
,
416 setsockopt(self, netc
::SOL_SOCKET
, netc
::SO_LINGER
, linger
)
419 pub fn linger(&self) -> io
::Result
<Option
<Duration
>> {
420 let val
: netc
::linger
= getsockopt(self, netc
::SOL_SOCKET
, netc
::SO_LINGER
)?
;
422 Ok((val
.l_onoff
!= 0).then(|| Duration
::from_secs(val
.l_linger
as u64)))
425 pub fn set_nodelay(&self, nodelay
: bool
) -> io
::Result
<()> {
426 setsockopt(self, netc
::IPPROTO_TCP
, netc
::TCP_NODELAY
, nodelay
as c_int
)
429 pub fn nodelay(&self) -> io
::Result
<bool
> {
430 let raw
: c_int
= getsockopt(self, netc
::IPPROTO_TCP
, netc
::TCP_NODELAY
)?
;
434 pub fn set_nonblocking(&self, nonblocking
: bool
) -> io
::Result
<()> {
435 let mut nonblocking
= nonblocking
as c_int
;
437 netc
::ioctl(*self.as_inner(), netc
::FIONBIO
, (&mut nonblocking
) as *mut c_int
as _
)
442 pub fn take_error(&self) -> io
::Result
<Option
<io
::Error
>> {
443 let raw
: c_int
= getsockopt(self, netc
::SOL_SOCKET
, netc
::SO_ERROR
)?
;
444 if raw
== 0 { Ok(None) }
else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
447 // This method is used by sys_common code to abstract over targets.
448 pub fn as_raw(&self) -> c_int
{
453 impl AsInner
<c_int
> for Socket
{
454 fn as_inner(&self) -> &c_int
{
459 impl FromInner
<c_int
> for Socket
{
460 fn from_inner(fd
: c_int
) -> Socket
{
461 Socket(FileDesc
::new(fd
))
465 impl IntoInner
<c_int
> for Socket
{
466 fn into_inner(self) -> c_int
{