• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::abi;
2 use crate::{
3     cmp,
4     ffi::CStr,
5     io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut},
6     mem,
7     net::{Shutdown, SocketAddr},
8     ptr, str,
9     sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr},
10     sys_common::{AsInner, FromInner, IntoInner},
11     time::Duration,
12 };
13 
14 use self::netc::{sockaddr, socklen_t, MSG_PEEK};
15 use libc::{c_int, c_void, size_t};
16 
17 pub mod netc {
18     pub use super::super::abi::sockets::*;
19 }
20 
21 pub type wrlen_t = size_t;
22 
23 const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
24 
max_iov() -> usize25 const fn max_iov() -> usize {
26     // Judging by the source code, it's unlimited, but specify a lower
27     // value just in case.
28     1024
29 }
30 
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)]
37 struct FileDesc {
38     fd: c_int,
39 }
40 
41 impl FileDesc {
42     #[inline]
new(fd: c_int) -> FileDesc43     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 } }
48     }
49 
50     #[inline]
raw(&self) -> c_int51     fn raw(&self) -> c_int {
52         self.fd
53     }
54 
55     /// Extracts the actual file descriptor without closing it.
56     #[inline]
into_raw(self) -> c_int57     fn into_raw(self) -> c_int {
58         let fd = self.fd;
59         mem::forget(self);
60         fd
61     }
62 
read(&self, buf: &mut [u8]) -> io::Result<usize>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))
66         })?;
67         Ok(ret as usize)
68     }
69 
read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize>70     fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
71         let ret = cvt(unsafe {
72             netc::readv(
73                 self.fd,
74                 bufs.as_ptr() as *const netc::iovec,
75                 cmp::min(bufs.len(), max_iov()) as c_int,
76             )
77         })?;
78         Ok(ret as usize)
79     }
80 
81     #[inline]
is_read_vectored(&self) -> bool82     fn is_read_vectored(&self) -> bool {
83         true
84     }
85 
write(&self, buf: &[u8]) -> io::Result<usize>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))
89         })?;
90         Ok(ret as usize)
91     }
92 
write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize>93     fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
94         let ret = cvt(unsafe {
95             netc::writev(
96                 self.fd,
97                 bufs.as_ptr() as *const netc::iovec,
98                 cmp::min(bufs.len(), max_iov()) as c_int,
99             )
100         })?;
101         Ok(ret as usize)
102     }
103 
104     #[inline]
is_write_vectored(&self) -> bool105     fn is_write_vectored(&self) -> bool {
106         true
107     }
108 
duplicate(&self) -> io::Result<FileDesc>109     fn duplicate(&self) -> io::Result<FileDesc> {
110         cvt(unsafe { netc::dup(self.fd) }).map(Self::new)
111     }
112 }
113 
114 impl AsInner<c_int> for FileDesc {
115     #[inline]
as_inner(&self) -> &c_int116     fn as_inner(&self) -> &c_int {
117         &self.fd
118     }
119 }
120 
121 impl Drop for FileDesc {
drop(&mut self)122     fn drop(&mut self) {
123         unsafe { netc::close(self.fd) };
124     }
125 }
126 
127 #[doc(hidden)]
128 pub trait IsMinusOne {
is_minus_one(&self) -> bool129     fn is_minus_one(&self) -> bool;
130 }
131 
132 macro_rules! impl_is_minus_one {
133     ($($t:ident)*) => ($(impl IsMinusOne for $t {
134         fn is_minus_one(&self) -> bool {
135             *self == -1
136         }
137     })*)
138 }
139 
140 impl_is_minus_one! { i8 i16 i32 i64 isize }
141 
cvt<T: IsMinusOne>(t: T) -> io::Result<T>142 pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
143     if t.is_minus_one() { Err(last_error()) } else { Ok(t) }
144 }
145 
146 /// A variant of `cvt` for `getaddrinfo` which return 0 for a success.
cvt_gai(err: c_int) -> io::Result<()>147 pub fn cvt_gai(err: c_int) -> io::Result<()> {
148     if err == 0 {
149         Ok(())
150     } else {
151         let msg: &dyn crate::fmt::Display = match err {
152             netc::EAI_NONAME => &"name or service not known",
153             netc::EAI_SERVICE => &"service not supported",
154             netc::EAI_FAIL => &"non-recoverable failure in name resolution",
155             netc::EAI_MEMORY => &"memory allocation failure",
156             netc::EAI_FAMILY => &"family not supported",
157             _ => &err,
158         };
159         Err(io::Error::new(
160             io::ErrorKind::Uncategorized,
161             &format!("failed to lookup address information: {msg}")[..],
162         ))
163     }
164 }
165 
166 /// Just to provide the same interface as sys/unix/net.rs
cvt_r<T, F>(mut f: F) -> io::Result<T> where T: IsMinusOne, F: FnMut() -> T,167 pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
168 where
169     T: IsMinusOne,
170     F: FnMut() -> T,
171 {
172     cvt(f())
173 }
174 
175 /// Returns the last error from the network subsystem.
last_error() -> io::Error176 fn last_error() -> io::Error {
177     io::Error::from_raw_os_error(unsafe { netc::SOLID_NET_GetLastError() })
178 }
179 
error_name(er: abi::ER) -> Option<&'static str>180 pub(super) fn error_name(er: abi::ER) -> Option<&'static str> {
181     unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok()
182 }
183 
decode_error_kind(er: abi::ER) -> ErrorKind184 pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind {
185     let errno = netc::SOLID_NET_ERR_BASE - er;
186     match errno as libc::c_int {
187         libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
188         libc::ECONNRESET => ErrorKind::ConnectionReset,
189         libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
190         libc::EPIPE => ErrorKind::BrokenPipe,
191         libc::ENOTCONN => ErrorKind::NotConnected,
192         libc::ECONNABORTED => ErrorKind::ConnectionAborted,
193         libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
194         libc::EADDRINUSE => ErrorKind::AddrInUse,
195         libc::ENOENT => ErrorKind::NotFound,
196         libc::EINTR => ErrorKind::Interrupted,
197         libc::EINVAL => ErrorKind::InvalidInput,
198         libc::ETIMEDOUT => ErrorKind::TimedOut,
199         libc::EEXIST => ErrorKind::AlreadyExists,
200         libc::ENOSYS => ErrorKind::Unsupported,
201         libc::ENOMEM => ErrorKind::OutOfMemory,
202         libc::EAGAIN => ErrorKind::WouldBlock,
203 
204         _ => ErrorKind::Uncategorized,
205     }
206 }
207 
init()208 pub fn init() {}
209 
210 pub struct Socket(FileDesc);
211 
212 impl Socket {
new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket>213     pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
214         let fam = match *addr {
215             SocketAddr::V4(..) => netc::AF_INET,
216             SocketAddr::V6(..) => netc::AF_INET6,
217         };
218         Socket::new_raw(fam, ty)
219     }
220 
new_raw(fam: c_int, ty: c_int) -> io::Result<Socket>221     pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
222         unsafe {
223             let fd = cvt(netc::socket(fam, ty, 0))?;
224             let fd = FileDesc::new(fd);
225             let socket = Socket(fd);
226 
227             Ok(socket)
228         }
229     }
230 
connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()>231     pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
232         self.set_nonblocking(true)?;
233         let r = unsafe {
234             let (addr, len) = addr.into_inner();
235             cvt(netc::connect(self.0.raw(), addr.as_ptr(), len))
236         };
237         self.set_nonblocking(false)?;
238 
239         match r {
240             Ok(_) => return Ok(()),
241             // there's no ErrorKind for EINPROGRESS
242             Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {}
243             Err(e) => return Err(e),
244         }
245 
246         if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
247             return Err(io::const_io_error!(
248                 io::ErrorKind::InvalidInput,
249                 "cannot set a 0 duration timeout",
250             ));
251         }
252 
253         let mut timeout =
254             netc::timeval { tv_sec: timeout.as_secs() as _, tv_usec: timeout.subsec_micros() as _ };
255         if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
256             timeout.tv_usec = 1;
257         }
258 
259         let fds = netc::fd_set { num_fds: 1, fds: [self.0.raw()] };
260 
261         let mut writefds = fds;
262         let mut errorfds = fds;
263 
264         let n = unsafe {
265             cvt(netc::select(
266                 self.0.raw() + 1,
267                 ptr::null_mut(),
268                 &mut writefds,
269                 &mut errorfds,
270                 &mut timeout,
271             ))?
272         };
273 
274         match n {
275             0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")),
276             _ => {
277                 let can_write = writefds.num_fds != 0;
278                 if !can_write {
279                     if let Some(e) = self.take_error()? {
280                         return Err(e);
281                     }
282                 }
283                 Ok(())
284             }
285         }
286     }
287 
accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket>288     pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
289         let fd = cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) })?;
290         let fd = FileDesc::new(fd);
291         Ok(Socket(fd))
292     }
293 
duplicate(&self) -> io::Result<Socket>294     pub fn duplicate(&self) -> io::Result<Socket> {
295         self.0.duplicate().map(Socket)
296     }
297 
recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()>298     fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
299         let ret = cvt(unsafe {
300             netc::recv(self.0.raw(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags)
301         })?;
302         unsafe {
303             buf.advance(ret as usize);
304         }
305         Ok(())
306     }
307 
read(&self, buf: &mut [u8]) -> io::Result<usize>308     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
309         let mut buf = BorrowedBuf::from(buf);
310         self.recv_with_flags(buf.unfilled(), 0)?;
311         Ok(buf.len())
312     }
313 
peek(&self, buf: &mut [u8]) -> io::Result<usize>314     pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
315         let mut buf = BorrowedBuf::from(buf);
316         self.recv_with_flags(buf.unfilled(), MSG_PEEK)?;
317         Ok(buf.len())
318     }
319 
read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()>320     pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
321         self.recv_with_flags(buf, 0)
322     }
323 
read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize>324     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
325         self.0.read_vectored(bufs)
326     }
327 
328     #[inline]
is_read_vectored(&self) -> bool329     pub fn is_read_vectored(&self) -> bool {
330         self.0.is_read_vectored()
331     }
332 
recv_from_with_flags( &self, buf: &mut [u8], flags: c_int, ) -> io::Result<(usize, SocketAddr)>333     fn recv_from_with_flags(
334         &self,
335         buf: &mut [u8],
336         flags: c_int,
337     ) -> io::Result<(usize, SocketAddr)> {
338         let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
339         let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
340 
341         let n = cvt(unsafe {
342             netc::recvfrom(
343                 self.0.raw(),
344                 buf.as_mut_ptr() as *mut c_void,
345                 buf.len(),
346                 flags,
347                 &mut storage as *mut _ as *mut _,
348                 &mut addrlen,
349             )
350         })?;
351         Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
352     }
353 
recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)>354     pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
355         self.recv_from_with_flags(buf, 0)
356     }
357 
peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)>358     pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
359         self.recv_from_with_flags(buf, MSG_PEEK)
360     }
361 
write(&self, buf: &[u8]) -> io::Result<usize>362     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
363         self.0.write(buf)
364     }
365 
write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize>366     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
367         self.0.write_vectored(bufs)
368     }
369 
370     #[inline]
is_write_vectored(&self) -> bool371     pub fn is_write_vectored(&self) -> bool {
372         self.0.is_write_vectored()
373     }
374 
set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()>375     pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
376         let timeout = match dur {
377             Some(dur) => {
378                 if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
379                     return Err(io::const_io_error!(
380                         io::ErrorKind::InvalidInput,
381                         "cannot set a 0 duration timeout",
382                     ));
383                 }
384 
385                 let secs = if dur.as_secs() > netc::c_long::MAX as u64 {
386                     netc::c_long::MAX
387                 } else {
388                     dur.as_secs() as netc::c_long
389                 };
390                 let mut timeout = netc::timeval { tv_sec: secs, tv_usec: dur.subsec_micros() as _ };
391                 if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
392                     timeout.tv_usec = 1;
393                 }
394                 timeout
395             }
396             None => netc::timeval { tv_sec: 0, tv_usec: 0 },
397         };
398         setsockopt(self, netc::SOL_SOCKET, kind, timeout)
399     }
400 
timeout(&self, kind: c_int) -> io::Result<Option<Duration>>401     pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
402         let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
403         if raw.tv_sec == 0 && raw.tv_usec == 0 {
404             Ok(None)
405         } else {
406             let sec = raw.tv_sec as u64;
407             let nsec = (raw.tv_usec as u32) * 1000;
408             Ok(Some(Duration::new(sec, nsec)))
409         }
410     }
411 
shutdown(&self, how: Shutdown) -> io::Result<()>412     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
413         let how = match how {
414             Shutdown::Write => netc::SHUT_WR,
415             Shutdown::Read => netc::SHUT_RD,
416             Shutdown::Both => netc::SHUT_RDWR,
417         };
418         cvt(unsafe { netc::shutdown(self.0.raw(), how) })?;
419         Ok(())
420     }
421 
set_linger(&self, linger: Option<Duration>) -> io::Result<()>422     pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
423         let linger = netc::linger {
424             l_onoff: linger.is_some() as netc::c_int,
425             l_linger: linger.unwrap_or_default().as_secs() as netc::c_int,
426         };
427 
428         setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger)
429     }
430 
linger(&self) -> io::Result<Option<Duration>>431     pub fn linger(&self) -> io::Result<Option<Duration>> {
432         let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?;
433 
434         Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
435     }
436 
set_nodelay(&self, nodelay: bool) -> io::Result<()>437     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
438         setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int)
439     }
440 
nodelay(&self) -> io::Result<bool>441     pub fn nodelay(&self) -> io::Result<bool> {
442         let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
443         Ok(raw != 0)
444     }
445 
set_nonblocking(&self, nonblocking: bool) -> io::Result<()>446     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
447         let mut nonblocking = nonblocking as c_int;
448         cvt(unsafe {
449             netc::ioctl(*self.as_inner(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _)
450         })
451         .map(drop)
452     }
453 
take_error(&self) -> io::Result<Option<io::Error>>454     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
455         let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?;
456         if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
457     }
458 
459     // This method is used by sys_common code to abstract over targets.
as_raw(&self) -> c_int460     pub fn as_raw(&self) -> c_int {
461         *self.as_inner()
462     }
463 }
464 
465 impl AsInner<c_int> for Socket {
466     #[inline]
as_inner(&self) -> &c_int467     fn as_inner(&self) -> &c_int {
468         self.0.as_inner()
469     }
470 }
471 
472 impl FromInner<c_int> for Socket {
from_inner(fd: c_int) -> Socket473     fn from_inner(fd: c_int) -> Socket {
474         Socket(FileDesc::new(fd))
475     }
476 }
477 
478 impl IntoInner<c_int> for Socket {
into_inner(self) -> c_int479     fn into_inner(self) -> c_int {
480         self.0.into_raw()
481     }
482 }
483