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