xref: /drstd/src/std/sys/hermit/net.rs (revision 0fe3ff0054d3aec7fbf9bddecfecb10bc7d23a51)
1 #![allow(dead_code)]
2 
3 use crate::std::cmp;
4 use crate::std::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
5 use crate::std::mem;
6 use crate::std::net::{Shutdown, SocketAddr};
7 use crate::std::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
8 use crate::std::sys::hermit::fd::FileDesc;
9 use crate::std::sys::time::Instant;
10 use crate::std::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
11 use crate::std::sys_common::{AsInner, FromInner, IntoInner};
12 use crate::std::time::Duration;
13 
14 use core::ffi::c_int;
15 
16 #[allow(unused_extern_crates)]
17 pub extern crate hermit_abi as netc;
18 
19 pub use crate::std::sys::{cvt, cvt_r};
20 
21 pub type wrlen_t = usize;
22 
23 pub fn cvt_gai(err: i32) -> io::Result<()> {
24     if err == 0 {
25         return Ok(());
26     }
27 
28     let detail = "";
29 
30     Err(io::Error::new(
31         io::ErrorKind::Uncategorized,
32         &format!("failed to lookup address information: {detail}")[..],
33     ))
34 }
35 
36 pub fn init() {}
37 
38 #[derive(Debug)]
39 pub struct Socket(FileDesc);
40 
41 impl Socket {
42     pub fn new(addr: &SocketAddr, ty: i32) -> io::Result<Socket> {
43         let fam = match *addr {
44             SocketAddr::V4(..) => netc::AF_INET,
45             SocketAddr::V6(..) => netc::AF_INET6,
46         };
47         Socket::new_raw(fam, ty)
48     }
49 
50     pub fn new_raw(fam: i32, ty: i32) -> io::Result<Socket> {
51         let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?;
52         Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
53     }
54 
55     pub fn new_pair(_fam: i32, _ty: i32) -> io::Result<(Socket, Socket)> {
56         unimplemented!()
57     }
58 
59     pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
60         self.set_nonblocking(true)?;
61         let r = unsafe {
62             let (addr, len) = addr.into_inner();
63             cvt(netc::connect(self.as_raw_fd(), addr.as_ptr(), len))
64         };
65         self.set_nonblocking(false)?;
66 
67         match r {
68             Ok(_) => return Ok(()),
69             // there's no ErrorKind for EINPROGRESS :(
70             Err(ref e) if e.raw_os_error() == Some(netc::errno::EINPROGRESS) => {}
71             Err(e) => return Err(e),
72         }
73 
74         let mut pollfd = netc::pollfd {
75             fd: self.as_raw_fd(),
76             events: netc::POLLOUT,
77             revents: 0,
78         };
79 
80         if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
81             return Err(io::const_io_error!(
82                 io::ErrorKind::InvalidInput,
83                 "cannot set a 0 duration timeout",
84             ));
85         }
86 
87         let start = Instant::now();
88 
89         loop {
90             let elapsed = start.elapsed();
91             if elapsed >= timeout {
92                 return Err(io::const_io_error!(
93                     io::ErrorKind::TimedOut,
94                     "connection timed out"
95                 ));
96             }
97 
98             let timeout = timeout - elapsed;
99             let mut timeout = timeout
100                 .as_secs()
101                 .saturating_mul(1_000)
102                 .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
103             if timeout == 0 {
104                 timeout = 1;
105             }
106 
107             let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
108 
109             match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
110                 -1 => {
111                     let err = io::Error::last_os_error();
112                     if !err.is_interrupted() {
113                         return Err(err);
114                     }
115                 }
116                 0 => {}
117                 _ => {
118                     // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
119                     // for POLLHUP rather than read readiness
120                     if pollfd.revents & netc::POLLHUP != 0 {
121                         let e = self.take_error()?.unwrap_or_else(|| {
122                             io::const_io_error!(
123                                 io::ErrorKind::Uncategorized,
124                                 "no error set after POLLHUP",
125                             )
126                         });
127                         return Err(e);
128                     }
129 
130                     return Ok(());
131                 }
132             }
133         }
134     }
135 
136     pub fn accept(
137         &self,
138         storage: *mut netc::sockaddr,
139         len: *mut netc::socklen_t,
140     ) -> io::Result<Socket> {
141         let fd = cvt(unsafe { netc::accept(self.0.as_raw_fd(), storage, len) })?;
142         Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
143     }
144 
145     pub fn duplicate(&self) -> io::Result<Socket> {
146         let fd = cvt(unsafe { netc::dup(self.0.as_raw_fd()) })?;
147         Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
148     }
149 
150     fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: i32) -> io::Result<()> {
151         let ret = cvt(unsafe {
152             netc::recv(
153                 self.0.as_raw_fd(),
154                 buf.as_mut().as_mut_ptr() as *mut u8,
155                 buf.capacity(),
156                 flags,
157             )
158         })?;
159         unsafe {
160             buf.advance(ret as usize);
161         }
162         Ok(())
163     }
164 
165     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
166         let mut buf = BorrowedBuf::from(buf);
167         self.recv_with_flags(buf.unfilled(), 0)?;
168         Ok(buf.len())
169     }
170 
171     pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
172         let mut buf = BorrowedBuf::from(buf);
173         self.recv_with_flags(buf.unfilled(), netc::MSG_PEEK)?;
174         Ok(buf.len())
175     }
176 
177     pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> {
178         self.recv_with_flags(buf, 0)
179     }
180 
181     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
182         let mut size: isize = 0;
183 
184         for i in bufs.iter_mut() {
185             let ret: isize =
186                 cvt(unsafe { netc::read(self.0.as_raw_fd(), i.as_mut_ptr(), i.len()) })?;
187 
188             if ret != 0 {
189                 size += ret;
190             }
191         }
192 
193         Ok(size.try_into().unwrap())
194     }
195 
196     #[inline]
197     pub fn is_read_vectored(&self) -> bool {
198         true
199     }
200 
201     fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
202         let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
203         let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
204 
205         let n = cvt(unsafe {
206             netc::recvfrom(
207                 self.as_raw_fd(),
208                 buf.as_mut_ptr(),
209                 buf.len(),
210                 flags,
211                 &mut storage as *mut _ as *mut _,
212                 &mut addrlen,
213             )
214         })?;
215         Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
216     }
217 
218     pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
219         self.recv_from_with_flags(buf, 0)
220     }
221 
222     pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
223         self.recv_from_with_flags(buf, netc::MSG_PEEK)
224     }
225 
226     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
227         let sz = cvt(unsafe { netc::write(self.0.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
228         Ok(sz.try_into().unwrap())
229     }
230 
231     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
232         let mut size: isize = 0;
233 
234         for i in bufs.iter() {
235             size += cvt(unsafe { netc::write(self.0.as_raw_fd(), i.as_ptr(), i.len()) })?;
236         }
237 
238         Ok(size.try_into().unwrap())
239     }
240 
241     pub fn is_write_vectored(&self) -> bool {
242         true
243     }
244 
245     pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> {
246         let timeout = match dur {
247             Some(dur) => {
248                 if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
249                     return Err(io::const_io_error!(
250                         io::ErrorKind::InvalidInput,
251                         "cannot set a 0 duration timeout",
252                     ));
253                 }
254 
255                 let secs = if dur.as_secs() > netc::time_t::MAX as u64 {
256                     netc::time_t::MAX
257                 } else {
258                     dur.as_secs() as netc::time_t
259                 };
260                 let mut timeout = netc::timeval {
261                     tv_sec: secs,
262                     tv_usec: dur.subsec_micros() as netc::suseconds_t,
263                 };
264                 if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
265                     timeout.tv_usec = 1;
266                 }
267                 timeout
268             }
269             None => netc::timeval {
270                 tv_sec: 0,
271                 tv_usec: 0,
272             },
273         };
274 
275         setsockopt(self, netc::SOL_SOCKET, kind, timeout)
276     }
277 
278     pub fn timeout(&self, kind: i32) -> io::Result<Option<Duration>> {
279         let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
280         if raw.tv_sec == 0 && raw.tv_usec == 0 {
281             Ok(None)
282         } else {
283             let sec = raw.tv_sec as u64;
284             let nsec = (raw.tv_usec as u32) * 1000;
285             Ok(Some(Duration::new(sec, nsec)))
286         }
287     }
288 
289     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
290         let how = match how {
291             Shutdown::Write => netc::SHUT_WR,
292             Shutdown::Read => netc::SHUT_RD,
293             Shutdown::Both => netc::SHUT_RDWR,
294         };
295         cvt(unsafe { netc::shutdown_socket(self.as_raw_fd(), how) })?;
296         Ok(())
297     }
298 
299     pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
300         let linger = netc::linger {
301             l_onoff: linger.is_some() as i32,
302             l_linger: linger.unwrap_or_default().as_secs() as dlibc::c_int,
303         };
304 
305         setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger)
306     }
307 
308     pub fn linger(&self) -> io::Result<Option<Duration>> {
309         let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?;
310 
311         Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
312     }
313 
314     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
315         let value: i32 = if nodelay { 1 } else { 0 };
316         setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value)
317     }
318 
319     pub fn nodelay(&self) -> io::Result<bool> {
320         let raw: i32 = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
321         Ok(raw != 0)
322     }
323 
324     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
325         let mut nonblocking: i32 = if nonblocking { 1 } else { 0 };
326         cvt(unsafe {
327             netc::ioctl(
328                 self.as_raw_fd(),
329                 netc::FIONBIO,
330                 &mut nonblocking as *mut _ as *mut core::ffi::c_void,
331             )
332         })
333         .map(drop)
334     }
335 
336     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
337         unimplemented!()
338     }
339 
340     // This is used by sys_common code to abstract over Windows and Unix.
341     pub fn as_raw(&self) -> RawFd {
342         self.0.as_raw_fd()
343     }
344 }
345 
346 impl AsInner<FileDesc> for Socket {
347     #[inline]
348     fn as_inner(&self) -> &FileDesc {
349         &self.0
350     }
351 }
352 
353 impl IntoInner<FileDesc> for Socket {
354     fn into_inner(self) -> FileDesc {
355         self.0
356     }
357 }
358 
359 impl FromInner<FileDesc> for Socket {
360     fn from_inner(file_desc: FileDesc) -> Self {
361         Self(file_desc)
362     }
363 }
364 
365 impl AsFd for Socket {
366     fn as_fd(&self) -> BorrowedFd<'_> {
367         self.0.as_fd()
368     }
369 }
370 
371 impl AsRawFd for Socket {
372     #[inline]
373     fn as_raw_fd(&self) -> RawFd {
374         self.0.as_raw_fd()
375     }
376 }
377