wasmer_wasix/net/
socket.rs

1use std::{
2    future::Future,
3    io,
4    mem::MaybeUninit,
5    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
6    pin::Pin,
7    sync::{Arc, RwLock},
8    task::{Context, Poll},
9    time::Duration,
10};
11
12use virtual_mio::InterestHandler;
13use virtual_net::{
14    NetworkError, VirtualIcmpSocket, VirtualNetworking, VirtualRawSocket, VirtualTcpBoundSocket,
15    VirtualTcpListener, VirtualTcpSocket, VirtualUdpSocket, net_error_into_io_err,
16};
17use wasmer_types::MemorySize;
18use wasmer_wasix_types::wasi::{Addressfamily, Errno, Rights, SockProto, Sockoption, Socktype};
19
20use crate::{VirtualTaskManager, net::net_error_into_wasi_err};
21
22#[derive(Debug)]
23pub enum InodeHttpSocketType {
24    /// Used to feed the bytes into the request itself
25    Request,
26    /// Used to receive the bytes from the HTTP server
27    Response,
28    /// Used to read the headers from the HTTP server
29    Headers,
30}
31
32type TcpConnectFuture<'a> =
33    Pin<Box<dyn Future<Output = Result<Box<dyn VirtualTcpSocket + Sync>, Errno>> + 'a>>;
34
35#[derive(Debug)]
36pub struct SocketProperties {
37    pub family: Addressfamily,
38    pub ty: Socktype,
39    pub pt: SockProto,
40    pub only_v6: bool,
41    pub reuse_port: bool,
42    pub reuse_addr: bool,
43    pub no_delay: Option<bool>,
44    pub keep_alive: Option<bool>,
45    pub dont_route: Option<bool>,
46    pub send_buf_size: Option<usize>,
47    pub recv_buf_size: Option<usize>,
48    pub write_timeout: Option<Duration>,
49    pub read_timeout: Option<Duration>,
50    pub accept_timeout: Option<Duration>,
51    pub connect_timeout: Option<Duration>,
52    pub handler: Option<Box<dyn InterestHandler + Send + Sync>>,
53}
54
55impl SocketProperties {
56    fn snapshot_for_bound(&self) -> Self {
57        Self {
58            family: self.family,
59            ty: self.ty,
60            pt: self.pt,
61            only_v6: self.only_v6,
62            reuse_port: self.reuse_port,
63            reuse_addr: self.reuse_addr,
64            no_delay: self.no_delay,
65            keep_alive: self.keep_alive,
66            dont_route: self.dont_route,
67            send_buf_size: self.send_buf_size,
68            recv_buf_size: self.recv_buf_size,
69            write_timeout: self.write_timeout,
70            read_timeout: self.read_timeout,
71            accept_timeout: self.accept_timeout,
72            connect_timeout: self.connect_timeout,
73            handler: None,
74        }
75    }
76}
77
78#[derive(Debug)]
79pub enum InodeSocketKind {
80    PreSocket {
81        props: SocketProperties,
82        addr: Option<SocketAddr>,
83    },
84    Icmp(Box<dyn VirtualIcmpSocket + Sync>),
85    Raw(Box<dyn VirtualRawSocket + Sync>),
86    TcpListener {
87        socket: Box<dyn VirtualTcpListener + Sync>,
88        accept_timeout: Option<Duration>,
89    },
90    TcpStream {
91        socket: Box<dyn VirtualTcpSocket + Sync>,
92        write_timeout: Option<Duration>,
93        read_timeout: Option<Duration>,
94    },
95    BoundTcp {
96        socket: Box<dyn VirtualTcpBoundSocket + Sync>,
97        props: SocketProperties,
98    },
99    UdpSocket {
100        socket: Box<dyn VirtualUdpSocket + Sync>,
101        peer: Option<SocketAddr>,
102    },
103    RemoteSocket {
104        props: SocketProperties,
105        local_addr: SocketAddr,
106        peer_addr: SocketAddr,
107        ttl: u32,
108        multicast_ttl: u32,
109        is_dead: bool,
110    },
111}
112
113pub enum WasiSocketOption {
114    Noop,
115    ReusePort,
116    ReuseAddr,
117    NoDelay,
118    DontRoute,
119    OnlyV6,
120    Broadcast,
121    MulticastLoopV4,
122    MulticastLoopV6,
123    Promiscuous,
124    Listening,
125    LastError,
126    KeepAlive,
127    Linger,
128    OobInline,
129    RecvBufSize,
130    SendBufSize,
131    RecvLowat,
132    SendLowat,
133    RecvTimeout,
134    SendTimeout,
135    ConnectTimeout,
136    AcceptTimeout,
137    Ttl,
138    MulticastTtlV4,
139    Type,
140    Proto,
141}
142
143impl TryFrom<Sockoption> for WasiSocketOption {
144    type Error = Errno;
145
146    fn try_from(opt: Sockoption) -> Result<Self, Self::Error> {
147        use WasiSocketOption::*;
148        match opt {
149            Sockoption::Noop => Ok(Noop),
150            Sockoption::ReusePort => Ok(ReusePort),
151            Sockoption::ReuseAddr => Ok(ReuseAddr),
152            Sockoption::NoDelay => Ok(NoDelay),
153            Sockoption::DontRoute => Ok(DontRoute),
154            Sockoption::OnlyV6 => Ok(OnlyV6),
155            Sockoption::Broadcast => Ok(Broadcast),
156            Sockoption::MulticastLoopV4 => Ok(MulticastLoopV4),
157            Sockoption::MulticastLoopV6 => Ok(MulticastLoopV6),
158            Sockoption::Promiscuous => Ok(Promiscuous),
159            Sockoption::Listening => Ok(Listening),
160            Sockoption::LastError => Ok(LastError),
161            Sockoption::KeepAlive => Ok(KeepAlive),
162            Sockoption::Linger => Ok(Linger),
163            Sockoption::OobInline => Ok(OobInline),
164            Sockoption::RecvBufSize => Ok(RecvBufSize),
165            Sockoption::SendBufSize => Ok(SendBufSize),
166            Sockoption::RecvLowat => Ok(RecvLowat),
167            Sockoption::SendLowat => Ok(SendLowat),
168            Sockoption::RecvTimeout => Ok(RecvTimeout),
169            Sockoption::SendTimeout => Ok(SendTimeout),
170            Sockoption::ConnectTimeout => Ok(ConnectTimeout),
171            Sockoption::AcceptTimeout => Ok(AcceptTimeout),
172            Sockoption::Ttl => Ok(Ttl),
173            Sockoption::MulticastTtlV4 => Ok(MulticastTtlV4),
174            Sockoption::Type => Ok(Type),
175            Sockoption::Proto => Ok(Proto),
176            _ => Err(Errno::Inval),
177        }
178    }
179}
180
181#[derive(Debug)]
182pub enum WasiSocketStatus {
183    Opening,
184    Opened,
185    Closed,
186    Failed,
187}
188
189#[derive(Debug, Copy, Clone, PartialEq, Eq)]
190pub enum TimeType {
191    ReadTimeout,
192    WriteTimeout,
193    AcceptTimeout,
194    ConnectTimeout,
195    BindTimeout,
196    Linger,
197}
198
199impl From<TimeType> for wasmer_journal::SocketOptTimeType {
200    fn from(value: TimeType) -> Self {
201        match value {
202            TimeType::ReadTimeout => Self::ReadTimeout,
203            TimeType::WriteTimeout => Self::WriteTimeout,
204            TimeType::AcceptTimeout => Self::AcceptTimeout,
205            TimeType::ConnectTimeout => Self::ConnectTimeout,
206            TimeType::BindTimeout => Self::BindTimeout,
207            TimeType::Linger => Self::Linger,
208        }
209    }
210}
211
212impl From<wasmer_journal::SocketOptTimeType> for TimeType {
213    fn from(value: wasmer_journal::SocketOptTimeType) -> Self {
214        use wasmer_journal::SocketOptTimeType;
215        match value {
216            SocketOptTimeType::ReadTimeout => TimeType::ReadTimeout,
217            SocketOptTimeType::WriteTimeout => TimeType::WriteTimeout,
218            SocketOptTimeType::AcceptTimeout => TimeType::AcceptTimeout,
219            SocketOptTimeType::ConnectTimeout => TimeType::ConnectTimeout,
220            SocketOptTimeType::BindTimeout => TimeType::BindTimeout,
221            SocketOptTimeType::Linger => TimeType::Linger,
222        }
223    }
224}
225
226#[derive(Debug)]
227pub(crate) struct InodeSocketProtected {
228    pub kind: InodeSocketKind,
229}
230
231#[derive(Debug)]
232pub(crate) struct InodeSocketInner {
233    pub protected: RwLock<InodeSocketProtected>,
234}
235
236#[derive(Debug, Clone)]
237pub struct InodeSocket {
238    pub(crate) inner: Arc<InodeSocketInner>,
239}
240
241impl InodeSocket {
242    pub fn new(kind: InodeSocketKind) -> Self {
243        let protected = InodeSocketProtected { kind };
244        Self {
245            inner: Arc::new(InodeSocketInner {
246                protected: RwLock::new(protected),
247            }),
248        }
249    }
250
251    pub fn poll_read_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
252        let mut inner = self.inner.protected.write().unwrap();
253        inner.poll_read_ready(cx)
254    }
255
256    pub fn poll_write_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
257        let mut inner = self.inner.protected.write().unwrap();
258        inner.poll_write_ready(cx)
259    }
260
261    // When a sendto or connect call comes in for a UDP "pre-socket", it must be bound to
262    // an ephemeral port automatically.
263    pub async fn auto_bind_udp(
264        &self,
265        tasks: &dyn VirtualTaskManager,
266        net: &dyn VirtualNetworking,
267    ) -> Result<Option<InodeSocket>, Errno> {
268        let timeout = self
269            .opt_time(TimeType::BindTimeout)
270            .ok()
271            .flatten()
272            .unwrap_or(Duration::from_secs(30));
273        let family = {
274            let inner = self.inner.protected.read().unwrap();
275            match &inner.kind {
276                InodeSocketKind::PreSocket { props, .. } if props.ty == Socktype::Dgram => {
277                    Some(props.family)
278                }
279                _ => None,
280            }
281        };
282        let Some(family) = family else {
283            return Ok(None);
284        };
285
286        let addr = match family {
287            Addressfamily::Inet4 => SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
288            Addressfamily::Inet6 => SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0),
289            _ => return Err(Errno::Notsup),
290        };
291
292        self.bind_internal(tasks, net, addr, timeout).await
293    }
294
295    pub async fn bind(
296        &self,
297        tasks: &dyn VirtualTaskManager,
298        net: &dyn VirtualNetworking,
299        set_addr: SocketAddr,
300    ) -> Result<Option<InodeSocket>, Errno> {
301        let timeout = self
302            .opt_time(TimeType::BindTimeout)
303            .ok()
304            .flatten()
305            .unwrap_or(Duration::from_secs(30));
306        self.bind_internal(tasks, net, set_addr, timeout).await
307    }
308
309    async fn bind_internal(
310        &self,
311        tasks: &dyn VirtualTaskManager,
312        net: &dyn VirtualNetworking,
313        set_addr: SocketAddr,
314        timeout: Duration,
315    ) -> Result<Option<InodeSocket>, Errno> {
316        enum PendingBind {
317            Tcp {
318                addr: SocketAddr,
319                props: SocketProperties,
320            },
321            Udp {
322                addr: SocketAddr,
323                reuse_port: bool,
324                reuse_addr: bool,
325            },
326        }
327
328        let bind = {
329            let mut inner = self.inner.protected.write().unwrap();
330            match &mut inner.kind {
331                InodeSocketKind::PreSocket { props, addr, .. } => {
332                    match props.family {
333                        Addressfamily::Inet4 => {
334                            if !set_addr.is_ipv4() {
335                                tracing::debug!(
336                                    "IP address is the wrong type IPv4 ({set_addr}) vs IPv6 family"
337                                );
338                                return Err(Errno::Inval);
339                            }
340                        }
341                        Addressfamily::Inet6 => {
342                            if !set_addr.is_ipv6() {
343                                tracing::debug!(
344                                    "IP address is the wrong type IPv6 ({set_addr}) vs IPv4 family"
345                                );
346                                return Err(Errno::Inval);
347                            }
348                        }
349                        _ => {
350                            return Err(Errno::Notsup);
351                        }
352                    }
353
354                    addr.replace(set_addr);
355                    let addr = (*addr).unwrap();
356
357                    match props.ty {
358                        Socktype::Stream => PendingBind::Tcp {
359                            addr,
360                            props: props.snapshot_for_bound(),
361                        },
362                        Socktype::Dgram => PendingBind::Udp {
363                            addr,
364                            reuse_port: props.reuse_port,
365                            reuse_addr: props.reuse_addr,
366                        },
367                        _ => return Err(Errno::Inval),
368                    }
369                }
370                InodeSocketKind::RemoteSocket {
371                    props,
372                    local_addr: addr,
373                    ..
374                } => {
375                    match props.family {
376                        Addressfamily::Inet4 => {
377                            if !set_addr.is_ipv4() {
378                                tracing::debug!(
379                                    "IP address is the wrong type IPv4 ({set_addr}) vs IPv6 family"
380                                );
381                                return Err(Errno::Inval);
382                            }
383                        }
384                        Addressfamily::Inet6 => {
385                            if !set_addr.is_ipv6() {
386                                tracing::debug!(
387                                    "IP address is the wrong type IPv6 ({set_addr}) vs IPv4 family"
388                                );
389                                return Err(Errno::Inval);
390                            }
391                        }
392                        _ => {
393                            return Err(Errno::Notsup);
394                        }
395                    }
396
397                    *addr = set_addr;
398                    let addr = *addr;
399
400                    match props.ty {
401                        Socktype::Stream => {
402                            // we already set the socket address - next we need a listen or connect so nothing
403                            // more to do at this time
404                            return Ok(None);
405                        }
406                        Socktype::Dgram => PendingBind::Udp {
407                            addr,
408                            reuse_port: props.reuse_port,
409                            reuse_addr: props.reuse_addr,
410                        },
411                        _ => return Err(Errno::Inval),
412                    }
413                }
414                InodeSocketKind::BoundTcp { .. } => return Err(Errno::Inval),
415                _ => return Err(Errno::Notsup),
416            }
417        };
418
419        match bind {
420            PendingBind::Tcp { addr, mut props } => {
421                tokio::select! {
422                    socket = net.bind_tcp(
423                        addr,
424                        props.only_v6,
425                        props.reuse_port,
426                        props.reuse_addr,
427                    ) => {
428                        match socket {
429                            Ok(socket) => {
430                                props.handler = {
431                                    let mut inner = self.inner.protected.write().unwrap();
432                                    match &mut inner.kind {
433                                        InodeSocketKind::PreSocket { props: live_props, .. } => {
434                                            live_props.handler.take()
435                                        }
436                                        _ => return Err(Errno::Inval),
437                                    }
438                                };
439                                Ok(Some(InodeSocket::new(InodeSocketKind::BoundTcp { socket, props })))
440                            }
441                            Err(NetworkError::Unsupported) => {
442                                tracing::debug!(
443                                    "bind_tcp unsupported by networking backend; leaving socket unbound"
444                                );
445                                let mut inner = self.inner.protected.write().unwrap();
446                                if let InodeSocketKind::PreSocket { addr, .. } = &mut inner.kind {
447                                    addr.take();
448                                }
449                                Err(Errno::Notsup)
450                            }
451                            Err(err) => {
452                                // Roll back the pre-set address so the socket stays unbound,
453                                // matching Linux semantics where a failed bind(2) leaves the
454                                // socket unbound.
455                                let mut inner = self.inner.protected.write().unwrap();
456                                if let InodeSocketKind::PreSocket { addr, .. } = &mut inner.kind {
457                                    addr.take();
458                                }
459                                Err(net_error_into_wasi_err(err))
460                            }
461                        }
462                    },
463                    _ = tasks.sleep_now(timeout) => {
464                        // Bind timed out; roll back the pre-set address for the same reason.
465                        let mut inner = self.inner.protected.write().unwrap();
466                        if let InodeSocketKind::PreSocket { addr, .. } = &mut inner.kind {
467                            addr.take();
468                        }
469                        Err(Errno::Timedout)
470                    }
471                }
472            }
473            PendingBind::Udp {
474                addr,
475                reuse_port,
476                reuse_addr,
477            } => {
478                tokio::select! {
479                    socket = net.bind_udp(addr, reuse_port, reuse_addr) => {
480                        match socket {
481                            Ok(socket) => Ok(Some(InodeSocket::new(InodeSocketKind::UdpSocket {
482                                socket,
483                                peer: None,
484                            }))),
485                            Err(err) => {
486                                let mut inner = self.inner.protected.write().unwrap();
487                                if let InodeSocketKind::PreSocket { addr, .. } = &mut inner.kind {
488                                    addr.take();
489                                }
490                                Err(net_error_into_wasi_err(err))
491                            }
492                        }
493                    },
494                    _ = tasks.sleep_now(timeout) => {
495                        let mut inner = self.inner.protected.write().unwrap();
496                        if let InodeSocketKind::PreSocket { addr, .. } = &mut inner.kind {
497                            addr.take();
498                        }
499                        Err(Errno::Timedout)
500                    }
501                }
502            }
503        }
504    }
505
506    pub async fn listen(
507        &self,
508        tasks: &dyn VirtualTaskManager,
509        net: &dyn VirtualNetworking,
510        _backlog: usize,
511    ) -> Result<Option<InodeSocket>, Errno> {
512        let timeout = self
513            .opt_time(TimeType::AcceptTimeout)
514            .ok()
515            .flatten()
516            .unwrap_or(Duration::from_secs(30));
517
518        let socket = {
519            let mut inner = self.inner.protected.write().unwrap();
520            match &mut inner.kind {
521                InodeSocketKind::PreSocket { props, addr, .. } => match props.ty {
522                    Socktype::Stream => {
523                        if addr.is_none() {
524                            tracing::warn!("wasi[?]::sock_listen - failed - address not set");
525                            return Err(Errno::Inval);
526                        }
527                        let addr = *addr.as_ref().unwrap();
528                        let only_v6 = props.only_v6;
529                        let reuse_port = props.reuse_port;
530                        let reuse_addr = props.reuse_addr;
531                        drop(inner);
532
533                        net.listen_tcp(addr, only_v6, reuse_port, reuse_addr)
534                    }
535                    ty => {
536                        tracing::warn!(
537                            "wasi[?]::sock_listen - failed - not supported(pre-socket:{:?})",
538                            ty
539                        );
540                        return Err(Errno::Notsup);
541                    }
542                },
543                InodeSocketKind::RemoteSocket {
544                    props,
545                    local_addr: addr,
546                    ..
547                } => match props.ty {
548                    Socktype::Stream => {
549                        let addr = *addr;
550                        let only_v6 = props.only_v6;
551                        let reuse_port = props.reuse_port;
552                        let reuse_addr = props.reuse_addr;
553                        drop(inner);
554
555                        net.listen_tcp(addr, only_v6, reuse_port, reuse_addr)
556                    }
557                    ty => {
558                        tracing::warn!(
559                            "wasi[?]::sock_listen - failed - not supported(remote-socket:{:?})",
560                            ty
561                        );
562                        return Err(Errno::Notsup);
563                    }
564                },
565                InodeSocketKind::BoundTcp { socket, .. } => {
566                    return Ok(Some(InodeSocket::new(InodeSocketKind::TcpListener {
567                        socket: socket.listen().map_err(net_error_into_wasi_err)?,
568                        accept_timeout: Some(timeout),
569                    })));
570                }
571                InodeSocketKind::Icmp(_) => {
572                    tracing::warn!("wasi[?]::sock_listen - failed - not supported(icmp)");
573                    return Err(Errno::Notsup);
574                }
575                InodeSocketKind::Raw(_) => {
576                    tracing::warn!("wasi[?]::sock_listen - failed - not supported(raw)");
577                    return Err(Errno::Notsup);
578                }
579                InodeSocketKind::TcpListener { .. } => {
580                    tracing::warn!(
581                        "wasi[?]::sock_listen - failed - already listening (tcp-listener)"
582                    );
583                    return Err(Errno::Notsup);
584                }
585                InodeSocketKind::TcpStream { .. } => {
586                    tracing::warn!("wasi[?]::sock_listen - failed - not supported(tcp-stream)");
587                    return Err(Errno::Notsup);
588                }
589                InodeSocketKind::UdpSocket { .. } => {
590                    tracing::warn!("wasi[?]::sock_listen - failed - not supported(udp-socket)");
591                    return Err(Errno::Notsup);
592                }
593            }
594        };
595
596        tokio::select! {
597            socket = socket => {
598                let socket = socket.map_err(net_error_into_wasi_err)?;
599                Ok(Some(InodeSocket::new(InodeSocketKind::TcpListener {
600                    socket,
601                    accept_timeout: Some(timeout),
602                })))
603            },
604            _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
605        }
606    }
607
608    pub async fn accept(
609        &self,
610        tasks: &dyn VirtualTaskManager,
611        nonblocking: bool,
612        timeout: Option<Duration>,
613    ) -> Result<(Box<dyn VirtualTcpSocket + Sync>, SocketAddr), Errno> {
614        struct SocketAccepter<'a> {
615            sock: &'a InodeSocket,
616            nonblocking: bool,
617            handler_registered: bool,
618        }
619        impl Drop for SocketAccepter<'_> {
620            fn drop(&mut self) {
621                if self.handler_registered {
622                    let mut inner = self.sock.inner.protected.write().unwrap();
623                    inner.remove_handler();
624                }
625            }
626        }
627        impl Future for SocketAccepter<'_> {
628            type Output = Result<(Box<dyn VirtualTcpSocket + Sync>, SocketAddr), Errno>;
629            fn poll(
630                mut self: Pin<&mut Self>,
631                cx: &mut std::task::Context<'_>,
632            ) -> std::task::Poll<Self::Output> {
633                loop {
634                    let mut inner = self.sock.inner.protected.write().unwrap();
635                    return match &mut inner.kind {
636                        InodeSocketKind::TcpListener { socket, .. } => match socket.try_accept() {
637                            Ok((child, addr)) => Poll::Ready(Ok((child, addr))),
638                            Err(NetworkError::WouldBlock) if self.nonblocking => {
639                                Poll::Ready(Err(Errno::Again))
640                            }
641                            Err(NetworkError::WouldBlock) if !self.handler_registered => {
642                                let res = socket.set_handler(cx.waker().into());
643                                if let Err(err) = res {
644                                    return Poll::Ready(Err(net_error_into_wasi_err(err)));
645                                }
646                                drop(inner);
647                                self.handler_registered = true;
648                                continue;
649                            }
650                            Err(NetworkError::WouldBlock) => Poll::Pending,
651                            Err(err) => Poll::Ready(Err(net_error_into_wasi_err(err))),
652                        },
653                        InodeSocketKind::PreSocket { .. } => Poll::Ready(Err(Errno::Notconn)),
654                        _ => Poll::Ready(Err(Errno::Notsup)),
655                    };
656                }
657            }
658        }
659
660        let acceptor = SocketAccepter {
661            sock: self,
662            nonblocking,
663            handler_registered: false,
664        };
665        if let Some(timeout) = timeout {
666            tokio::select! {
667                res = acceptor => res,
668                _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
669            }
670        } else {
671            acceptor.await
672        }
673    }
674
675    pub fn close(&self) -> Result<(), Errno> {
676        let mut inner = self.inner.protected.write().unwrap();
677        match &mut inner.kind {
678            InodeSocketKind::TcpListener { .. } => {}
679            InodeSocketKind::TcpStream { socket, .. } => {
680                socket.close().map_err(net_error_into_wasi_err)?;
681            }
682            InodeSocketKind::BoundTcp { .. } => {}
683            InodeSocketKind::Icmp(_) => {}
684            InodeSocketKind::UdpSocket { .. } => {}
685            InodeSocketKind::Raw(_) => {}
686            InodeSocketKind::PreSocket { .. } => return Err(Errno::Notconn),
687            InodeSocketKind::RemoteSocket { .. } => {}
688        };
689        Ok(())
690    }
691
692    pub async fn connect(
693        &mut self,
694        tasks: &dyn VirtualTaskManager,
695        net: &dyn VirtualNetworking,
696        peer: SocketAddr,
697        timeout: Option<std::time::Duration>,
698        nonblocking: bool,
699    ) -> Result<Option<InodeSocket>, Errno> {
700        let new_write_timeout;
701        let new_read_timeout;
702
703        let timeout = timeout
704            .or_else(|| self.opt_time(TimeType::ConnectTimeout).ok().flatten())
705            .unwrap_or(Duration::from_secs(30));
706
707        let handler;
708        let connect: TcpConnectFuture<'_> = {
709            let mut inner = self.inner.protected.write().unwrap();
710            match &mut inner.kind {
711                InodeSocketKind::PreSocket { props, addr, .. } => {
712                    handler = props.handler.take();
713                    new_write_timeout = props.write_timeout;
714                    new_read_timeout = props.read_timeout;
715                    match props.ty {
716                        Socktype::Stream => {
717                            let no_delay = props.no_delay;
718                            let keep_alive = props.keep_alive;
719                            let dont_route = props.dont_route;
720                            let addr = match addr {
721                                Some(a) => *a,
722                                None => {
723                                    let ip = match peer.is_ipv4() {
724                                        true => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
725                                        false => IpAddr::V6(Ipv6Addr::UNSPECIFIED),
726                                    };
727                                    SocketAddr::new(ip, 0)
728                                }
729                            };
730                            Box::pin(async move {
731                                let mut ret = net
732                                    .connect_tcp(addr, peer)
733                                    .await
734                                    .map_err(net_error_into_wasi_err)?;
735                                if let Some(no_delay) = no_delay {
736                                    ret.set_nodelay(no_delay).ok();
737                                }
738                                if let Some(keep_alive) = keep_alive {
739                                    ret.set_keepalive(keep_alive).ok();
740                                }
741                                if let Some(dont_route) = dont_route {
742                                    ret.set_dontroute(dont_route).ok();
743                                }
744                                if !nonblocking {
745                                    futures::future::poll_fn(|cx| ret.poll_write_ready(cx))
746                                        .await
747                                        .map_err(net_error_into_wasi_err)?;
748                                }
749                                Ok(ret)
750                            })
751                        }
752                        Socktype::Dgram => return Err(Errno::Inval),
753                        _ => return Err(Errno::Notsup),
754                    }
755                }
756                InodeSocketKind::BoundTcp { socket, props } => {
757                    handler = props.handler.take();
758                    new_write_timeout = props.write_timeout;
759                    new_read_timeout = props.read_timeout;
760                    match props.ty {
761                        Socktype::Stream => {
762                            let no_delay = props.no_delay;
763                            let keep_alive = props.keep_alive;
764                            let dont_route = props.dont_route;
765                            let mut ret = socket.connect(peer).map_err(net_error_into_wasi_err)?;
766                            if let Some(no_delay) = no_delay {
767                                ret.set_nodelay(no_delay).ok();
768                            }
769                            if let Some(keep_alive) = keep_alive {
770                                ret.set_keepalive(keep_alive).ok();
771                            }
772                            if let Some(dont_route) = dont_route {
773                                ret.set_dontroute(dont_route).ok();
774                            }
775                            Box::pin(async move {
776                                if !nonblocking {
777                                    futures::future::poll_fn(|cx| ret.poll_write_ready(cx))
778                                        .await
779                                        .map_err(net_error_into_wasi_err)?;
780                                }
781                                Ok(ret)
782                            })
783                        }
784                        Socktype::Dgram => return Err(Errno::Inval),
785                        _ => return Err(Errno::Notsup),
786                    }
787                }
788                InodeSocketKind::UdpSocket {
789                    peer: target_peer, ..
790                } => {
791                    target_peer.replace(peer);
792                    return Ok(None);
793                }
794                InodeSocketKind::RemoteSocket { peer_addr, .. } => {
795                    *peer_addr = peer;
796                    return Ok(None);
797                }
798                _ => return Err(Errno::Notsup),
799            }
800        };
801
802        let mut socket = tokio::select! {
803            res = connect => res?,
804            _ = tasks.sleep_now(timeout) => return Err(Errno::Timedout)
805        };
806
807        if let Some(handler) = handler {
808            socket
809                .set_handler(handler)
810                .map_err(net_error_into_wasi_err)?;
811        }
812
813        let socket = InodeSocket::new(InodeSocketKind::TcpStream {
814            socket,
815            write_timeout: new_write_timeout,
816            read_timeout: new_read_timeout,
817        });
818
819        Ok(Some(socket))
820    }
821
822    pub fn status(&self) -> Result<WasiSocketStatus, Errno> {
823        let inner = self.inner.protected.read().unwrap();
824        Ok(match &inner.kind {
825            InodeSocketKind::PreSocket { .. } => WasiSocketStatus::Opening,
826            InodeSocketKind::BoundTcp { .. } => WasiSocketStatus::Opened,
827            InodeSocketKind::TcpListener { .. } => WasiSocketStatus::Opened,
828            InodeSocketKind::TcpStream { socket, .. } => match socket.status() {
829                Ok(virtual_net::SocketStatus::Opening) => WasiSocketStatus::Opening,
830                Ok(virtual_net::SocketStatus::Opened) => WasiSocketStatus::Opened,
831                Ok(virtual_net::SocketStatus::Closed) => WasiSocketStatus::Closed,
832                Ok(virtual_net::SocketStatus::Failed) => WasiSocketStatus::Failed,
833                Err(_) => WasiSocketStatus::Failed,
834            },
835            InodeSocketKind::UdpSocket { .. } => WasiSocketStatus::Opened,
836            InodeSocketKind::RemoteSocket { is_dead, .. } => match is_dead {
837                true => WasiSocketStatus::Closed,
838                false => WasiSocketStatus::Opened,
839            },
840            _ => WasiSocketStatus::Failed,
841        })
842    }
843
844    pub fn last_error(&self) -> Result<Errno, Errno> {
845        self.status()?;
846
847        let inner = self.inner.protected.read().unwrap();
848        match &inner.kind {
849            InodeSocketKind::TcpStream { socket, .. } => socket
850                .last_error()
851                .map_err(net_error_into_wasi_err)
852                .map(|err| err.map(net_error_into_wasi_err).unwrap_or(Errno::Success)),
853            InodeSocketKind::RemoteSocket { is_dead, .. } if *is_dead => Ok(Errno::Connreset),
854            _ => Ok(Errno::Success),
855        }
856    }
857
858    pub fn addr_local(&self) -> Result<SocketAddr, Errno> {
859        let inner = self.inner.protected.read().unwrap();
860        Ok(match &inner.kind {
861            InodeSocketKind::PreSocket { props, addr, .. } => {
862                if let Some(addr) = addr {
863                    *addr
864                } else {
865                    SocketAddr::new(
866                        match props.family {
867                            Addressfamily::Inet4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
868                            Addressfamily::Inet6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED),
869                            _ => return Err(Errno::Inval),
870                        },
871                        0,
872                    )
873                }
874            }
875            InodeSocketKind::Icmp(sock) => sock.addr_local().map_err(net_error_into_wasi_err)?,
876            InodeSocketKind::TcpListener { socket, .. } => {
877                socket.addr_local().map_err(net_error_into_wasi_err)?
878            }
879            InodeSocketKind::TcpStream { socket, .. } => {
880                socket.addr_local().map_err(net_error_into_wasi_err)?
881            }
882            InodeSocketKind::BoundTcp { socket, .. } => {
883                socket.addr_local().map_err(net_error_into_wasi_err)?
884            }
885            InodeSocketKind::UdpSocket { socket, .. } => {
886                socket.addr_local().map_err(net_error_into_wasi_err)?
887            }
888            InodeSocketKind::RemoteSocket {
889                local_addr: addr, ..
890            } => *addr,
891            _ => return Err(Errno::Notsup),
892        })
893    }
894
895    pub fn addr_peer(&self) -> Result<SocketAddr, Errno> {
896        let inner = self.inner.protected.read().unwrap();
897        match &inner.kind {
898            InodeSocketKind::BoundTcp { .. } => Err(Errno::Notconn),
899            InodeSocketKind::PreSocket { props, .. } => Ok(SocketAddr::new(
900                match props.family {
901                    Addressfamily::Inet4 => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
902                    Addressfamily::Inet6 => IpAddr::V6(Ipv6Addr::UNSPECIFIED),
903                    _ => return Err(Errno::Inval),
904                },
905                0,
906            )),
907            InodeSocketKind::TcpStream { socket, .. } => {
908                socket.addr_peer().map_err(net_error_into_wasi_err)
909            }
910            InodeSocketKind::UdpSocket {
911                peer: Some(peer), ..
912            } => Ok(*peer),
913            InodeSocketKind::UdpSocket { socket, .. } => socket
914                .addr_peer()
915                .map_err(net_error_into_wasi_err)?
916                .ok_or(Errno::Notconn),
917            InodeSocketKind::RemoteSocket { peer_addr, .. } => Ok(*peer_addr),
918            _ => Err(Errno::Notsup),
919        }
920    }
921
922    pub fn set_opt_flag(&mut self, option: WasiSocketOption, val: bool) -> Result<(), Errno> {
923        let mut inner = self.inner.protected.write().unwrap();
924        match &mut inner.kind {
925            InodeSocketKind::PreSocket { props, .. }
926            | InodeSocketKind::BoundTcp { props, .. }
927            | InodeSocketKind::RemoteSocket { props, .. } => {
928                match option {
929                    WasiSocketOption::OnlyV6 => props.only_v6 = val,
930                    WasiSocketOption::ReusePort => props.reuse_port = val,
931                    WasiSocketOption::ReuseAddr => props.reuse_addr = val,
932                    WasiSocketOption::NoDelay => props.no_delay = Some(val),
933                    WasiSocketOption::KeepAlive => props.keep_alive = Some(val),
934                    WasiSocketOption::DontRoute => props.dont_route = Some(val),
935                    _ => return Err(Errno::Inval),
936                };
937            }
938            InodeSocketKind::Raw(sock) => match option {
939                WasiSocketOption::Promiscuous => {
940                    sock.set_promiscuous(val).map_err(net_error_into_wasi_err)?
941                }
942                _ => return Err(Errno::Inval),
943            },
944            InodeSocketKind::TcpStream { socket, .. } => match option {
945                WasiSocketOption::NoDelay => {
946                    socket.set_nodelay(val).map_err(net_error_into_wasi_err)?
947                }
948                WasiSocketOption::KeepAlive => {
949                    socket.set_keepalive(val).map_err(net_error_into_wasi_err)?
950                }
951                WasiSocketOption::DontRoute => {
952                    socket.set_dontroute(val).map_err(net_error_into_wasi_err)?
953                }
954                _ => return Err(Errno::Inval),
955            },
956            InodeSocketKind::TcpListener { .. } => return Err(Errno::Inval),
957            InodeSocketKind::UdpSocket { socket, .. } => match option {
958                WasiSocketOption::Broadcast => {
959                    socket.set_broadcast(val).map_err(net_error_into_wasi_err)?
960                }
961                WasiSocketOption::MulticastLoopV4 => socket
962                    .set_multicast_loop_v4(val)
963                    .map_err(net_error_into_wasi_err)?,
964                WasiSocketOption::MulticastLoopV6 => socket
965                    .set_multicast_loop_v6(val)
966                    .map_err(net_error_into_wasi_err)?,
967                _ => return Err(Errno::Inval),
968            },
969            _ => return Err(Errno::Notsup),
970        }
971        Ok(())
972    }
973
974    pub fn get_opt_flag(&self, option: WasiSocketOption) -> Result<bool, Errno> {
975        let mut inner = self.inner.protected.write().unwrap();
976        Ok(match &mut inner.kind {
977            InodeSocketKind::PreSocket { props, .. }
978            | InodeSocketKind::BoundTcp { props, .. }
979            | InodeSocketKind::RemoteSocket { props, .. } => match option {
980                WasiSocketOption::OnlyV6 => props.only_v6,
981                WasiSocketOption::ReusePort => props.reuse_port,
982                WasiSocketOption::ReuseAddr => props.reuse_addr,
983                WasiSocketOption::NoDelay => props.no_delay.unwrap_or_default(),
984                WasiSocketOption::KeepAlive => props.keep_alive.unwrap_or_default(),
985                _ => return Err(Errno::Inval),
986            },
987            InodeSocketKind::Raw(sock) => match option {
988                WasiSocketOption::Promiscuous => {
989                    sock.promiscuous().map_err(net_error_into_wasi_err)?
990                }
991                _ => return Err(Errno::Inval),
992            },
993            InodeSocketKind::TcpStream { socket, .. } => match option {
994                WasiSocketOption::NoDelay => socket.nodelay().map_err(net_error_into_wasi_err)?,
995                WasiSocketOption::KeepAlive => {
996                    socket.keepalive().map_err(net_error_into_wasi_err)?
997                }
998                WasiSocketOption::DontRoute => {
999                    socket.dontroute().map_err(net_error_into_wasi_err)?
1000                }
1001                _ => return Err(Errno::Inval),
1002            },
1003            InodeSocketKind::UdpSocket { socket, .. } => match option {
1004                WasiSocketOption::Broadcast => {
1005                    socket.broadcast().map_err(net_error_into_wasi_err)?
1006                }
1007                WasiSocketOption::MulticastLoopV4 => socket
1008                    .multicast_loop_v4()
1009                    .map_err(net_error_into_wasi_err)?,
1010                WasiSocketOption::MulticastLoopV6 => socket
1011                    .multicast_loop_v6()
1012                    .map_err(net_error_into_wasi_err)?,
1013                _ => return Err(Errno::Inval),
1014            },
1015            _ => return Err(Errno::Notsup),
1016        })
1017    }
1018
1019    pub fn set_send_buf_size(&mut self, size: usize) -> Result<(), Errno> {
1020        let mut inner = self.inner.protected.write().unwrap();
1021        match &mut inner.kind {
1022            InodeSocketKind::PreSocket { props, .. }
1023            | InodeSocketKind::BoundTcp { props, .. }
1024            | InodeSocketKind::RemoteSocket { props, .. } => {
1025                props.send_buf_size = Some(size);
1026            }
1027            InodeSocketKind::TcpStream { socket, .. } => {
1028                socket
1029                    .set_send_buf_size(size)
1030                    .map_err(net_error_into_wasi_err)?;
1031            }
1032            _ => return Err(Errno::Notsup),
1033        }
1034        Ok(())
1035    }
1036
1037    pub fn send_buf_size(&self) -> Result<usize, Errno> {
1038        let inner = self.inner.protected.read().unwrap();
1039        match &inner.kind {
1040            InodeSocketKind::PreSocket { props, .. }
1041            | InodeSocketKind::BoundTcp { props, .. }
1042            | InodeSocketKind::RemoteSocket { props, .. } => {
1043                Ok(props.send_buf_size.unwrap_or_default())
1044            }
1045            InodeSocketKind::TcpStream { socket, .. } => {
1046                socket.send_buf_size().map_err(net_error_into_wasi_err)
1047            }
1048            _ => Err(Errno::Notsup),
1049        }
1050    }
1051
1052    pub fn set_recv_buf_size(&mut self, size: usize) -> Result<(), Errno> {
1053        let mut inner = self.inner.protected.write().unwrap();
1054        match &mut inner.kind {
1055            InodeSocketKind::PreSocket { props, .. }
1056            | InodeSocketKind::BoundTcp { props, .. }
1057            | InodeSocketKind::RemoteSocket { props, .. } => {
1058                props.recv_buf_size = Some(size);
1059            }
1060            InodeSocketKind::TcpStream { socket, .. } => {
1061                socket
1062                    .set_recv_buf_size(size)
1063                    .map_err(net_error_into_wasi_err)?;
1064            }
1065            _ => return Err(Errno::Notsup),
1066        }
1067        Ok(())
1068    }
1069
1070    pub fn recv_buf_size(&self) -> Result<usize, Errno> {
1071        let inner = self.inner.protected.read().unwrap();
1072        match &inner.kind {
1073            InodeSocketKind::PreSocket { props, .. }
1074            | InodeSocketKind::BoundTcp { props, .. }
1075            | InodeSocketKind::RemoteSocket { props, .. } => {
1076                Ok(props.recv_buf_size.unwrap_or_default())
1077            }
1078            InodeSocketKind::TcpStream { socket, .. } => {
1079                socket.recv_buf_size().map_err(net_error_into_wasi_err)
1080            }
1081            _ => Err(Errno::Notsup),
1082        }
1083    }
1084
1085    pub fn set_linger(&mut self, linger: Option<std::time::Duration>) -> Result<(), Errno> {
1086        let mut inner = self.inner.protected.write().unwrap();
1087        match &mut inner.kind {
1088            InodeSocketKind::TcpStream { socket, .. } => {
1089                socket.set_linger(linger).map_err(net_error_into_wasi_err)
1090            }
1091            InodeSocketKind::RemoteSocket { .. } => Ok(()),
1092            InodeSocketKind::BoundTcp { .. } => Err(Errno::Io),
1093            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1094            _ => Err(Errno::Notsup),
1095        }
1096    }
1097
1098    pub fn linger(&self) -> Result<Option<std::time::Duration>, Errno> {
1099        let inner = self.inner.protected.read().unwrap();
1100        match &inner.kind {
1101            InodeSocketKind::TcpStream { socket, .. } => {
1102                socket.linger().map_err(net_error_into_wasi_err)
1103            }
1104            InodeSocketKind::BoundTcp { .. } => Err(Errno::Io),
1105            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1106            _ => Err(Errno::Notsup),
1107        }
1108    }
1109
1110    pub fn set_opt_time(
1111        &self,
1112        ty: TimeType,
1113        timeout: Option<std::time::Duration>,
1114    ) -> Result<(), Errno> {
1115        let mut inner = self.inner.protected.write().unwrap();
1116        match &mut inner.kind {
1117            InodeSocketKind::TcpStream {
1118                write_timeout,
1119                read_timeout,
1120                ..
1121            } => {
1122                match ty {
1123                    TimeType::WriteTimeout => *write_timeout = timeout,
1124                    TimeType::ReadTimeout => *read_timeout = timeout,
1125                    _ => return Err(Errno::Inval),
1126                }
1127                Ok(())
1128            }
1129            InodeSocketKind::TcpListener { accept_timeout, .. } => {
1130                match ty {
1131                    TimeType::AcceptTimeout => *accept_timeout = timeout,
1132                    _ => return Err(Errno::Inval),
1133                }
1134                Ok(())
1135            }
1136            InodeSocketKind::PreSocket { props, .. }
1137            | InodeSocketKind::BoundTcp { props, .. }
1138            | InodeSocketKind::RemoteSocket { props, .. } => {
1139                match ty {
1140                    TimeType::ConnectTimeout => props.connect_timeout = timeout,
1141                    TimeType::AcceptTimeout => props.accept_timeout = timeout,
1142                    TimeType::ReadTimeout => props.read_timeout = timeout,
1143                    TimeType::WriteTimeout => props.write_timeout = timeout,
1144                    _ => return Err(Errno::Io),
1145                }
1146                Ok(())
1147            }
1148            _ => Err(Errno::Notsup),
1149        }
1150    }
1151
1152    pub fn opt_time(&self, ty: TimeType) -> Result<Option<std::time::Duration>, Errno> {
1153        let inner = self.inner.protected.read().unwrap();
1154        match &inner.kind {
1155            InodeSocketKind::TcpStream {
1156                read_timeout,
1157                write_timeout,
1158                ..
1159            } => Ok(match ty {
1160                TimeType::ReadTimeout => *read_timeout,
1161                TimeType::WriteTimeout => *write_timeout,
1162                _ => return Err(Errno::Inval),
1163            }),
1164            InodeSocketKind::TcpListener { accept_timeout, .. } => Ok(match ty {
1165                TimeType::AcceptTimeout => *accept_timeout,
1166                _ => return Err(Errno::Inval),
1167            }),
1168            InodeSocketKind::PreSocket { props, .. }
1169            | InodeSocketKind::BoundTcp { props, .. }
1170            | InodeSocketKind::RemoteSocket { props, .. } => match ty {
1171                TimeType::ConnectTimeout => Ok(props.connect_timeout),
1172                TimeType::AcceptTimeout => Ok(props.accept_timeout),
1173                TimeType::ReadTimeout => Ok(props.read_timeout),
1174                TimeType::WriteTimeout => Ok(props.write_timeout),
1175                _ => Err(Errno::Inval),
1176            },
1177            _ => Err(Errno::Notsup),
1178        }
1179    }
1180
1181    pub fn set_ttl(&self, ttl: u32) -> Result<(), Errno> {
1182        let mut inner = self.inner.protected.write().unwrap();
1183        match &mut inner.kind {
1184            InodeSocketKind::BoundTcp { socket, .. } => {
1185                socket.set_ttl(ttl).map_err(net_error_into_wasi_err)
1186            }
1187            InodeSocketKind::TcpStream { socket, .. } => {
1188                socket.set_ttl(ttl).map_err(net_error_into_wasi_err)
1189            }
1190            InodeSocketKind::UdpSocket { socket, .. } => {
1191                socket.set_ttl(ttl).map_err(net_error_into_wasi_err)
1192            }
1193            InodeSocketKind::RemoteSocket { ttl: set_ttl, .. } => {
1194                *set_ttl = ttl;
1195                Ok(())
1196            }
1197            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1198            _ => Err(Errno::Notsup),
1199        }
1200    }
1201
1202    pub fn ttl(&self) -> Result<u32, Errno> {
1203        let inner = self.inner.protected.read().unwrap();
1204        match &inner.kind {
1205            InodeSocketKind::BoundTcp { socket, .. } => {
1206                socket.ttl().map_err(net_error_into_wasi_err)
1207            }
1208            InodeSocketKind::TcpStream { socket, .. } => {
1209                socket.ttl().map_err(net_error_into_wasi_err)
1210            }
1211            InodeSocketKind::UdpSocket { socket, .. } => {
1212                socket.ttl().map_err(net_error_into_wasi_err)
1213            }
1214            InodeSocketKind::RemoteSocket { ttl, .. } => Ok(*ttl),
1215            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1216            _ => Err(Errno::Notsup),
1217        }
1218    }
1219
1220    pub fn set_multicast_ttl_v4(&self, ttl: u32) -> Result<(), Errno> {
1221        let mut inner = self.inner.protected.write().unwrap();
1222        match &mut inner.kind {
1223            InodeSocketKind::UdpSocket { socket, .. } => socket
1224                .set_multicast_ttl_v4(ttl)
1225                .map_err(net_error_into_wasi_err),
1226            InodeSocketKind::RemoteSocket {
1227                multicast_ttl: set_ttl,
1228                ..
1229            } => {
1230                *set_ttl = ttl;
1231                Ok(())
1232            }
1233            InodeSocketKind::BoundTcp { .. } => Err(Errno::Io),
1234            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1235            _ => Err(Errno::Notsup),
1236        }
1237    }
1238
1239    pub fn multicast_ttl_v4(&self) -> Result<u32, Errno> {
1240        let inner = self.inner.protected.read().unwrap();
1241        match &inner.kind {
1242            InodeSocketKind::UdpSocket { socket, .. } => {
1243                socket.multicast_ttl_v4().map_err(net_error_into_wasi_err)
1244            }
1245            InodeSocketKind::RemoteSocket { multicast_ttl, .. } => Ok(*multicast_ttl),
1246            InodeSocketKind::BoundTcp { .. } => Err(Errno::Io),
1247            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1248            _ => Err(Errno::Notsup),
1249        }
1250    }
1251
1252    pub fn join_multicast_v4(&self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), Errno> {
1253        let mut inner = self.inner.protected.write().unwrap();
1254        match &mut inner.kind {
1255            InodeSocketKind::UdpSocket { socket, .. } => socket
1256                .join_multicast_v4(multiaddr, iface)
1257                .map_err(net_error_into_wasi_err),
1258            InodeSocketKind::RemoteSocket { .. } => Ok(()),
1259            InodeSocketKind::BoundTcp { .. } => Err(Errno::Io),
1260            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1261            _ => Err(Errno::Notsup),
1262        }
1263    }
1264
1265    pub fn leave_multicast_v4(&self, multiaddr: Ipv4Addr, iface: Ipv4Addr) -> Result<(), Errno> {
1266        let mut inner = self.inner.protected.write().unwrap();
1267        match &mut inner.kind {
1268            InodeSocketKind::UdpSocket { socket, .. } => socket
1269                .leave_multicast_v4(multiaddr, iface)
1270                .map_err(net_error_into_wasi_err),
1271            InodeSocketKind::RemoteSocket { .. } => Ok(()),
1272            InodeSocketKind::BoundTcp { .. } => Err(Errno::Io),
1273            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1274            _ => Err(Errno::Notsup),
1275        }
1276    }
1277
1278    pub fn join_multicast_v6(&self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), Errno> {
1279        let mut inner = self.inner.protected.write().unwrap();
1280        match &mut inner.kind {
1281            InodeSocketKind::UdpSocket { socket, .. } => socket
1282                .join_multicast_v6(multiaddr, iface)
1283                .map_err(net_error_into_wasi_err),
1284            InodeSocketKind::RemoteSocket { .. } => Ok(()),
1285            InodeSocketKind::BoundTcp { .. } => Err(Errno::Io),
1286            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1287            _ => Err(Errno::Notsup),
1288        }
1289    }
1290
1291    pub fn leave_multicast_v6(&mut self, multiaddr: Ipv6Addr, iface: u32) -> Result<(), Errno> {
1292        let mut inner = self.inner.protected.write().unwrap();
1293        match &mut inner.kind {
1294            InodeSocketKind::UdpSocket { socket, .. } => socket
1295                .leave_multicast_v6(multiaddr, iface)
1296                .map_err(net_error_into_wasi_err),
1297            InodeSocketKind::RemoteSocket { .. } => Ok(()),
1298            InodeSocketKind::BoundTcp { .. } => Err(Errno::Io),
1299            InodeSocketKind::PreSocket { .. } => Err(Errno::Io),
1300            _ => Err(Errno::Notsup),
1301        }
1302    }
1303
1304    pub async fn send(
1305        &self,
1306        tasks: &dyn VirtualTaskManager,
1307        buf: &[u8],
1308        timeout: Option<Duration>,
1309        nonblocking: bool,
1310    ) -> Result<usize, Errno> {
1311        struct SocketSender<'a, 'b> {
1312            inner: &'a InodeSocketInner,
1313            data: &'b [u8],
1314            nonblocking: bool,
1315            handler_registered: bool,
1316        }
1317        impl Drop for SocketSender<'_, '_> {
1318            fn drop(&mut self) {
1319                if self.handler_registered {
1320                    let mut inner = self.inner.protected.write().unwrap();
1321                    inner.remove_handler();
1322                }
1323            }
1324        }
1325        impl Future for SocketSender<'_, '_> {
1326            type Output = Result<usize, Errno>;
1327            fn poll(
1328                mut self: Pin<&mut Self>,
1329                cx: &mut std::task::Context<'_>,
1330            ) -> Poll<Self::Output> {
1331                loop {
1332                    let mut inner = self.inner.protected.write().unwrap();
1333                    let res = match &mut inner.kind {
1334                        InodeSocketKind::Raw(socket) => socket.try_send(self.data),
1335                        InodeSocketKind::TcpStream { socket, .. } => socket.try_send(self.data),
1336                        InodeSocketKind::UdpSocket { socket, peer } => {
1337                            if let Some(peer) = peer {
1338                                socket.try_send_to(self.data, *peer)
1339                            } else {
1340                                Err(NetworkError::NotConnected)
1341                            }
1342                        }
1343                        InodeSocketKind::PreSocket { .. } => {
1344                            return Poll::Ready(Err(Errno::Notconn));
1345                        }
1346                        InodeSocketKind::RemoteSocket { is_dead, .. } => {
1347                            return match is_dead {
1348                                true => Poll::Ready(Err(Errno::Connreset)),
1349                                false => Poll::Ready(Ok(self.data.len())),
1350                            };
1351                        }
1352                        _ => return Poll::Ready(Err(Errno::Notsup)),
1353                    };
1354                    return match res {
1355                        Ok(amt) => Poll::Ready(Ok(amt)),
1356                        Err(NetworkError::WouldBlock) if self.nonblocking => {
1357                            Poll::Ready(Err(Errno::Again))
1358                        }
1359                        Err(NetworkError::WouldBlock) if !self.handler_registered => {
1360                            inner
1361                                .set_handler(cx.waker().into())
1362                                .map_err(net_error_into_wasi_err)?;
1363                            drop(inner);
1364                            self.handler_registered = true;
1365                            continue;
1366                        }
1367                        Err(NetworkError::WouldBlock) => Poll::Pending,
1368                        Err(err) => Poll::Ready(Err(net_error_into_wasi_err(err))),
1369                    };
1370                }
1371            }
1372        }
1373
1374        let poller = SocketSender {
1375            inner: &self.inner,
1376            data: buf,
1377            nonblocking,
1378            handler_registered: false,
1379        };
1380        if let Some(timeout) = timeout {
1381            tokio::select! {
1382                res = poller => res,
1383                _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
1384            }
1385        } else {
1386            poller.await
1387        }
1388    }
1389
1390    pub async fn send_to<M: MemorySize>(
1391        &self,
1392        tasks: &dyn VirtualTaskManager,
1393        buf: &[u8],
1394        addr: SocketAddr,
1395        timeout: Option<Duration>,
1396        nonblocking: bool,
1397    ) -> Result<usize, Errno> {
1398        struct SocketSender<'a, 'b> {
1399            inner: &'a InodeSocketInner,
1400            data: &'b [u8],
1401            addr: SocketAddr,
1402            nonblocking: bool,
1403            handler_registered: bool,
1404        }
1405        impl Drop for SocketSender<'_, '_> {
1406            fn drop(&mut self) {
1407                if self.handler_registered {
1408                    let mut inner = self.inner.protected.write().unwrap();
1409                    inner.remove_handler();
1410                }
1411            }
1412        }
1413        impl Future for SocketSender<'_, '_> {
1414            type Output = Result<usize, Errno>;
1415            fn poll(
1416                mut self: Pin<&mut Self>,
1417                cx: &mut std::task::Context<'_>,
1418            ) -> Poll<Self::Output> {
1419                loop {
1420                    let mut inner = self.inner.protected.write().unwrap();
1421                    let res = match &mut inner.kind {
1422                        InodeSocketKind::Icmp(socket) => socket.try_send_to(self.data, self.addr),
1423                        InodeSocketKind::TcpStream { socket, .. } => socket.try_send(self.data),
1424                        InodeSocketKind::UdpSocket { socket, .. } => {
1425                            socket.try_send_to(self.data, self.addr)
1426                        }
1427                        InodeSocketKind::PreSocket { .. } => {
1428                            return Poll::Ready(Err(Errno::Notconn));
1429                        }
1430                        InodeSocketKind::RemoteSocket { is_dead, .. } => {
1431                            return match is_dead {
1432                                true => Poll::Ready(Err(Errno::Connreset)),
1433                                false => Poll::Ready(Ok(self.data.len())),
1434                            };
1435                        }
1436                        _ => return Poll::Ready(Err(Errno::Notsup)),
1437                    };
1438                    return match res {
1439                        Ok(amt) => Poll::Ready(Ok(amt)),
1440                        Err(NetworkError::WouldBlock) if self.nonblocking => {
1441                            Poll::Ready(Err(Errno::Again))
1442                        }
1443                        Err(NetworkError::WouldBlock) if !self.handler_registered => {
1444                            inner
1445                                .set_handler(cx.waker().into())
1446                                .map_err(net_error_into_wasi_err)?;
1447                            self.handler_registered = true;
1448                            drop(inner);
1449                            continue;
1450                        }
1451                        Err(NetworkError::WouldBlock) => Poll::Pending,
1452                        Err(err) => Poll::Ready(Err(net_error_into_wasi_err(err))),
1453                    };
1454                }
1455            }
1456        }
1457
1458        let poller = SocketSender {
1459            inner: &self.inner,
1460            data: buf,
1461            addr,
1462            nonblocking,
1463            handler_registered: false,
1464        };
1465        if let Some(timeout) = timeout {
1466            tokio::select! {
1467                res = poller => res,
1468                _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
1469            }
1470        } else {
1471            poller.await
1472        }
1473    }
1474
1475    pub async fn recv(
1476        &self,
1477        tasks: &dyn VirtualTaskManager,
1478        buf: &mut [MaybeUninit<u8>],
1479        timeout: Option<Duration>,
1480        nonblocking: bool,
1481        peek: bool,
1482    ) -> Result<usize, Errno> {
1483        struct SocketReceiver<'a, 'b> {
1484            inner: &'a InodeSocketInner,
1485            data: &'b mut [MaybeUninit<u8>],
1486            nonblocking: bool,
1487            peek: bool,
1488            handler_registered: bool,
1489        }
1490        impl Drop for SocketReceiver<'_, '_> {
1491            fn drop(&mut self) {
1492                if self.handler_registered {
1493                    let mut inner = self.inner.protected.write().unwrap();
1494                    inner.remove_handler();
1495                }
1496            }
1497        }
1498        impl Future for SocketReceiver<'_, '_> {
1499            type Output = Result<usize, Errno>;
1500            fn poll(
1501                mut self: Pin<&mut Self>,
1502                cx: &mut std::task::Context<'_>,
1503            ) -> Poll<Self::Output> {
1504                loop {
1505                    let peek = self.peek;
1506                    let mut inner = self.inner.protected.write().unwrap();
1507                    let res = match &mut inner.kind {
1508                        InodeSocketKind::Raw(socket) => socket.try_recv(self.data, peek),
1509                        InodeSocketKind::TcpStream { socket, .. } => {
1510                            socket.try_recv(self.data, peek)
1511                        }
1512                        InodeSocketKind::UdpSocket { socket, peer } => match peer {
1513                            Some(peer) => {
1514                                try_recv_from_connected_udp(socket.as_mut(), self.data, peek, peer)
1515                                    .map(|(amt, _)| amt)
1516                            }
1517                            None => socket.try_recv_from(self.data, peek).map(|(amt, _)| amt),
1518                        },
1519                        InodeSocketKind::RemoteSocket { is_dead, .. } => {
1520                            return match is_dead {
1521                                true => Poll::Ready(Ok(0)),
1522                                false => Poll::Pending,
1523                            };
1524                        }
1525                        InodeSocketKind::PreSocket { .. } => {
1526                            return Poll::Ready(Err(Errno::Notconn));
1527                        }
1528                        _ => return Poll::Ready(Err(Errno::Notsup)),
1529                    };
1530                    return match res {
1531                        Ok(amt) => Poll::Ready(Ok(amt)),
1532                        Err(NetworkError::WouldBlock) if self.nonblocking => {
1533                            Poll::Ready(Err(Errno::Again))
1534                        }
1535                        Err(NetworkError::WouldBlock) if !self.handler_registered => {
1536                            inner
1537                                .set_handler(cx.waker().into())
1538                                .map_err(net_error_into_wasi_err)?;
1539                            self.handler_registered = true;
1540                            drop(inner);
1541                            continue;
1542                        }
1543
1544                        Err(NetworkError::WouldBlock) => Poll::Pending,
1545                        Err(err) => Poll::Ready(Err(net_error_into_wasi_err(err))),
1546                    };
1547                }
1548            }
1549        }
1550
1551        let poller = SocketReceiver {
1552            inner: &self.inner,
1553            data: buf,
1554            nonblocking,
1555            peek,
1556            handler_registered: false,
1557        };
1558        if let Some(timeout) = timeout {
1559            tokio::select! {
1560                res = poller => res,
1561                _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
1562            }
1563        } else {
1564            poller.await
1565        }
1566    }
1567
1568    pub async fn recv_from(
1569        &self,
1570        tasks: &dyn VirtualTaskManager,
1571        buf: &mut [MaybeUninit<u8>],
1572        timeout: Option<Duration>,
1573        nonblocking: bool,
1574        peek: bool,
1575    ) -> Result<(usize, SocketAddr), Errno> {
1576        struct SocketReceiver<'a, 'b> {
1577            inner: &'a InodeSocketInner,
1578            data: &'b mut [MaybeUninit<u8>],
1579            nonblocking: bool,
1580            peek: bool,
1581            handler_registered: bool,
1582        }
1583        impl Drop for SocketReceiver<'_, '_> {
1584            fn drop(&mut self) {
1585                if self.handler_registered {
1586                    let mut inner = self.inner.protected.write().unwrap();
1587                    inner.remove_handler();
1588                }
1589            }
1590        }
1591        impl Future for SocketReceiver<'_, '_> {
1592            type Output = Result<(usize, SocketAddr), Errno>;
1593            fn poll(
1594                mut self: Pin<&mut Self>,
1595                cx: &mut std::task::Context<'_>,
1596            ) -> Poll<Self::Output> {
1597                let peek = self.peek;
1598                let mut inner = self.inner.protected.write().unwrap();
1599                loop {
1600                    let res = match &mut inner.kind {
1601                        InodeSocketKind::Icmp(socket) => socket.try_recv_from(self.data, peek),
1602                        InodeSocketKind::UdpSocket { socket, peer } => match peer {
1603                            Some(peer) => {
1604                                try_recv_from_connected_udp(socket.as_mut(), self.data, peek, peer)
1605                            }
1606                            None => socket.try_recv_from(self.data, peek),
1607                        },
1608                        InodeSocketKind::RemoteSocket {
1609                            is_dead, peer_addr, ..
1610                        } => {
1611                            return match is_dead {
1612                                true => Poll::Ready(Ok((0, *peer_addr))),
1613                                false => Poll::Pending,
1614                            };
1615                        }
1616                        InodeSocketKind::PreSocket { .. } => {
1617                            return Poll::Ready(Err(Errno::Notconn));
1618                        }
1619                        _ => return Poll::Ready(Err(Errno::Notsup)),
1620                    };
1621                    return match res {
1622                        Ok((amt, addr)) => Poll::Ready(Ok((amt, addr))),
1623                        Err(NetworkError::WouldBlock) if self.nonblocking => {
1624                            Poll::Ready(Err(Errno::Again))
1625                        }
1626                        Err(NetworkError::WouldBlock) if !self.handler_registered => {
1627                            inner
1628                                .set_handler(cx.waker().into())
1629                                .map_err(net_error_into_wasi_err)?;
1630                            self.handler_registered = true;
1631                            continue;
1632                        }
1633                        Err(NetworkError::WouldBlock) => Poll::Pending,
1634                        Err(err) => Poll::Ready(Err(net_error_into_wasi_err(err))),
1635                    };
1636                }
1637            }
1638        }
1639
1640        let poller = SocketReceiver {
1641            inner: &self.inner,
1642            data: buf,
1643            nonblocking,
1644            peek,
1645            handler_registered: false,
1646        };
1647        if let Some(timeout) = timeout {
1648            tokio::select! {
1649                res = poller => res,
1650                _ = tasks.sleep_now(timeout) => Err(Errno::Timedout)
1651            }
1652        } else {
1653            poller.await
1654        }
1655    }
1656
1657    pub fn shutdown(&mut self, how: std::net::Shutdown) -> Result<(), Errno> {
1658        let mut inner = self.inner.protected.write().unwrap();
1659        match &mut inner.kind {
1660            InodeSocketKind::TcpStream { socket, .. } => {
1661                socket.shutdown(how).map_err(net_error_into_wasi_err)?;
1662            }
1663            InodeSocketKind::RemoteSocket { .. } => return Ok(()),
1664            InodeSocketKind::BoundTcp { .. } => return Err(Errno::Notconn),
1665            InodeSocketKind::PreSocket { .. } => return Err(Errno::Notconn),
1666            _ => return Err(Errno::Notsup),
1667        }
1668        Ok(())
1669    }
1670
1671    pub async fn can_write(&self) -> bool {
1672        if let Ok(mut guard) = self.inner.protected.try_write() {
1673            #[allow(clippy::match_like_matches_macro)]
1674            match &mut guard.kind {
1675                InodeSocketKind::TcpStream { .. }
1676                | InodeSocketKind::BoundTcp { .. }
1677                | InodeSocketKind::UdpSocket { .. }
1678                | InodeSocketKind::Raw(..) => true,
1679                InodeSocketKind::RemoteSocket { is_dead, .. } => !(*is_dead),
1680                _ => false,
1681            }
1682        } else {
1683            false
1684        }
1685    }
1686
1687    pub fn is_dgram(&self) -> bool {
1688        let guard = self.inner.protected.read().unwrap();
1689        match &guard.kind {
1690            InodeSocketKind::UdpSocket { .. } => true,
1691            InodeSocketKind::RemoteSocket { props, .. } => props.ty == Socktype::Dgram,
1692            _ => false,
1693        }
1694    }
1695}
1696
1697/// On connected UDP sockets, discard datagrams not from the stored peer.
1698/// Linux filters these in the kernel; wasix stores the peer separately.
1699fn discard_non_matching_udp_datagrams(
1700    socket: &mut dyn VirtualUdpSocket,
1701    peer: &SocketAddr,
1702) -> Result<(), NetworkError> {
1703    let mut discard = [MaybeUninit::<u8>::uninit()];
1704    loop {
1705        match socket.try_recv_from(&mut discard, true) {
1706            Ok((_, addr)) if addr == *peer => return Ok(()),
1707            Ok(_) => match socket.try_recv_from(&mut discard, false) {
1708                Ok(_) => {}
1709                Err(NetworkError::WouldBlock) => {}
1710                Err(err) => return Err(err),
1711            },
1712            Err(NetworkError::WouldBlock) => return Ok(()),
1713            Err(err) => return Err(err),
1714        }
1715    }
1716}
1717
1718fn try_recv_from_connected_udp(
1719    socket: &mut dyn VirtualUdpSocket,
1720    data: &mut [MaybeUninit<u8>],
1721    peek: bool,
1722    peer: &SocketAddr,
1723) -> Result<(usize, SocketAddr), NetworkError> {
1724    discard_non_matching_udp_datagrams(socket, peer)?;
1725    loop {
1726        match socket.try_recv_from(data, peek) {
1727            Ok((amt, addr)) if addr == *peer => return Ok((amt, addr)),
1728            Ok(_) if peek => match socket.try_recv_from(data, false) {
1729                Ok(_) => {}
1730                Err(NetworkError::WouldBlock) => {}
1731                Err(err) => return Err(err),
1732            },
1733            Ok(_) => continue,
1734            Err(err) => return Err(err),
1735        }
1736    }
1737}
1738
1739impl InodeSocketProtected {
1740    pub fn remove_handler(&mut self) {
1741        match &mut self.kind {
1742            InodeSocketKind::TcpListener { socket, .. } => socket.remove_handler(),
1743            InodeSocketKind::TcpStream { socket, .. } => socket.remove_handler(),
1744            InodeSocketKind::UdpSocket { socket, .. } => socket.remove_handler(),
1745            InodeSocketKind::Raw(socket) => socket.remove_handler(),
1746            InodeSocketKind::Icmp(socket) => socket.remove_handler(),
1747            InodeSocketKind::PreSocket { props, .. } => {
1748                props.handler.take();
1749            }
1750            InodeSocketKind::BoundTcp { props, .. } => {
1751                props.handler.take();
1752            }
1753            InodeSocketKind::RemoteSocket { props, .. } => {
1754                props.handler.take();
1755            }
1756        }
1757    }
1758
1759    pub fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
1760        match &mut self.kind {
1761            InodeSocketKind::TcpListener { socket, .. } => socket.poll_read_ready(cx),
1762            InodeSocketKind::TcpStream { socket, .. } => socket.poll_read_ready(cx),
1763            InodeSocketKind::UdpSocket {
1764                socket,
1765                peer: Some(peer),
1766            } => loop {
1767                if let Err(err) = discard_non_matching_udp_datagrams(socket.as_mut(), peer) {
1768                    break Poll::Ready(Err(err));
1769                }
1770                match socket.poll_read_ready(cx) {
1771                    Poll::Pending => break Poll::Pending,
1772                    Poll::Ready(Err(err)) => break Poll::Ready(Err(err)),
1773                    Poll::Ready(Ok(n)) => {
1774                        let mut peek_buf = [MaybeUninit::<u8>::uninit()];
1775                        match socket.try_recv_from(&mut peek_buf, true) {
1776                            Ok((_, addr)) if addr == *peer => break Poll::Ready(Ok(n)),
1777                            Ok(_) => continue,
1778                            Err(NetworkError::WouldBlock) => break Poll::Pending,
1779                            Err(err) => break Poll::Ready(Err(err)),
1780                        }
1781                    }
1782                }
1783            },
1784            InodeSocketKind::UdpSocket { socket, peer: None } => socket.poll_read_ready(cx),
1785            InodeSocketKind::Raw(socket) => socket.poll_read_ready(cx),
1786            InodeSocketKind::Icmp(socket) => socket.poll_read_ready(cx),
1787            InodeSocketKind::BoundTcp { .. } => Poll::Pending,
1788            InodeSocketKind::PreSocket { .. } => Poll::Pending,
1789            InodeSocketKind::RemoteSocket { is_dead, .. } => match is_dead {
1790                true => Poll::Ready(Ok(0)),
1791                false => Poll::Pending,
1792            },
1793        }
1794        .map_err(net_error_into_io_err)
1795    }
1796
1797    pub fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
1798        match &mut self.kind {
1799            InodeSocketKind::TcpListener { socket, .. } => socket.poll_write_ready(cx),
1800            InodeSocketKind::TcpStream { socket, .. } => socket.poll_write_ready(cx),
1801            InodeSocketKind::UdpSocket { socket, .. } => socket.poll_write_ready(cx),
1802            InodeSocketKind::Raw(socket) => socket.poll_write_ready(cx),
1803            InodeSocketKind::Icmp(socket) => socket.poll_write_ready(cx),
1804            // Bound-but-not-connected TCP sockets are writable immediately on Linux.
1805            // Use a non-zero value so poll/select does not treat this as a hangup.
1806            InodeSocketKind::BoundTcp { .. } => Poll::Ready(Ok(1)),
1807            InodeSocketKind::PreSocket { .. } => Poll::Pending,
1808            InodeSocketKind::RemoteSocket { is_dead, .. } => match is_dead {
1809                true => Poll::Ready(Ok(0)),
1810                false => Poll::Pending,
1811            },
1812        }
1813        .map_err(net_error_into_io_err)
1814    }
1815
1816    pub fn set_handler(
1817        &mut self,
1818        handler: Box<dyn InterestHandler + Send + Sync>,
1819    ) -> virtual_net::Result<()> {
1820        match &mut self.kind {
1821            InodeSocketKind::TcpListener { socket, .. } => socket.set_handler(handler),
1822            InodeSocketKind::TcpStream { socket, .. } => socket.set_handler(handler),
1823            InodeSocketKind::UdpSocket { socket, .. } => socket.set_handler(handler),
1824            InodeSocketKind::Raw(socket) => socket.set_handler(handler),
1825            InodeSocketKind::Icmp(socket) => socket.set_handler(handler),
1826            InodeSocketKind::PreSocket { props, .. }
1827            | InodeSocketKind::BoundTcp { props, .. }
1828            | InodeSocketKind::RemoteSocket { props, .. } => {
1829                props.handler.replace(handler);
1830                Ok(())
1831            }
1832        }
1833    }
1834}
1835
1836// TODO: review allow...
1837#[allow(dead_code)]
1838pub(crate) fn all_socket_rights() -> Rights {
1839    Rights::FD_FDSTAT_SET_FLAGS
1840        .union(Rights::FD_FILESTAT_GET)
1841        .union(Rights::FD_READ)
1842        .union(Rights::FD_WRITE)
1843        .union(Rights::POLL_FD_READWRITE)
1844        .union(Rights::SOCK_SHUTDOWN)
1845        .union(Rights::SOCK_CONNECT)
1846        .union(Rights::SOCK_LISTEN)
1847        .union(Rights::SOCK_BIND)
1848        .union(Rights::SOCK_ACCEPT)
1849        .union(Rights::SOCK_RECV)
1850        .union(Rights::SOCK_SEND)
1851        .union(Rights::SOCK_ADDR_LOCAL)
1852        .union(Rights::SOCK_ADDR_REMOTE)
1853        .union(Rights::SOCK_RECV_FROM)
1854        .union(Rights::SOCK_SEND_TO)
1855}
1856
1857#[cfg(test)]
1858mod tests {
1859    use super::{InodeSocket, InodeSocketKind, SocketProperties, WasiSocketStatus};
1860    use std::{
1861        future::pending,
1862        mem::MaybeUninit,
1863        net::{Ipv4Addr, Shutdown, SocketAddr},
1864        pin::Pin,
1865        sync::{
1866            Arc,
1867            atomic::{AtomicUsize, Ordering},
1868        },
1869        task::{Context, Poll},
1870        time::Duration,
1871    };
1872    use virtual_mio::InterestHandler;
1873    use virtual_net::{
1874        NetworkError, Result as NetResult, SocketStatus, VirtualConnectedSocket, VirtualIoSource,
1875        VirtualNetworking, VirtualSocket, VirtualTcpBoundSocket, VirtualTcpSocket,
1876    };
1877    use wasmer_wasix_types::wasi::{Addressfamily, Errno, SockProto, Socktype};
1878
1879    #[derive(Debug)]
1880    struct MockTcpSocket {
1881        read_calls: Arc<AtomicUsize>,
1882        write_calls: Arc<AtomicUsize>,
1883        status: Arc<AtomicUsize>,
1884    }
1885
1886    const MOCK_STATUS_OPENING: usize = 0;
1887    const MOCK_STATUS_OPENED: usize = 1;
1888
1889    fn decode_mock_status(value: usize) -> SocketStatus {
1890        match value {
1891            MOCK_STATUS_OPENED => SocketStatus::Opened,
1892            _ => SocketStatus::Opening,
1893        }
1894    }
1895
1896    impl VirtualIoSource for MockTcpSocket {
1897        fn remove_handler(&mut self) {}
1898
1899        fn poll_read_ready(&mut self, _cx: &mut Context<'_>) -> Poll<NetResult<usize>> {
1900            self.read_calls.fetch_add(1, Ordering::Relaxed);
1901            Poll::Ready(Ok(3))
1902        }
1903
1904        fn poll_write_ready(&mut self, _cx: &mut Context<'_>) -> Poll<NetResult<usize>> {
1905            self.write_calls.fetch_add(1, Ordering::Relaxed);
1906            self.status.store(MOCK_STATUS_OPENED, Ordering::Relaxed);
1907            Poll::Ready(Ok(7))
1908        }
1909    }
1910
1911    impl VirtualSocket for MockTcpSocket {
1912        fn set_ttl(&mut self, _ttl: u32) -> NetResult<()> {
1913            Ok(())
1914        }
1915
1916        fn ttl(&self) -> NetResult<u32> {
1917            Ok(64)
1918        }
1919
1920        fn addr_local(&self) -> NetResult<SocketAddr> {
1921            Ok(SocketAddr::from((Ipv4Addr::LOCALHOST, 0)))
1922        }
1923
1924        fn status(&self) -> NetResult<SocketStatus> {
1925            Ok(decode_mock_status(self.status.load(Ordering::Relaxed)))
1926        }
1927
1928        fn set_handler(
1929            &mut self,
1930            _handler: Box<dyn InterestHandler + Send + Sync>,
1931        ) -> NetResult<()> {
1932            Ok(())
1933        }
1934    }
1935
1936    impl VirtualConnectedSocket for MockTcpSocket {
1937        fn set_linger(&mut self, _linger: Option<Duration>) -> NetResult<()> {
1938            Ok(())
1939        }
1940
1941        fn linger(&self) -> NetResult<Option<Duration>> {
1942            Ok(None)
1943        }
1944
1945        fn try_send(&mut self, _data: &[u8]) -> NetResult<usize> {
1946            Err(NetworkError::Unsupported)
1947        }
1948
1949        fn try_flush(&mut self) -> NetResult<()> {
1950            Err(NetworkError::Unsupported)
1951        }
1952
1953        fn close(&mut self) -> NetResult<()> {
1954            Ok(())
1955        }
1956
1957        fn try_recv(&mut self, _buf: &mut [MaybeUninit<u8>], _peek: bool) -> NetResult<usize> {
1958            Err(NetworkError::Unsupported)
1959        }
1960    }
1961
1962    impl VirtualTcpSocket for MockTcpSocket {
1963        fn set_recv_buf_size(&mut self, _size: usize) -> NetResult<()> {
1964            Ok(())
1965        }
1966
1967        fn recv_buf_size(&self) -> NetResult<usize> {
1968            Ok(0)
1969        }
1970
1971        fn set_send_buf_size(&mut self, _size: usize) -> NetResult<()> {
1972            Ok(())
1973        }
1974
1975        fn send_buf_size(&self) -> NetResult<usize> {
1976            Ok(0)
1977        }
1978
1979        fn set_nodelay(&mut self, _reuse: bool) -> NetResult<()> {
1980            Ok(())
1981        }
1982
1983        fn nodelay(&self) -> NetResult<bool> {
1984            Ok(true)
1985        }
1986
1987        fn set_keepalive(&mut self, _keepalive: bool) -> NetResult<()> {
1988            Ok(())
1989        }
1990
1991        fn keepalive(&self) -> NetResult<bool> {
1992            Ok(false)
1993        }
1994
1995        fn set_dontroute(&mut self, _keepalive: bool) -> NetResult<()> {
1996            Ok(())
1997        }
1998
1999        fn dontroute(&self) -> NetResult<bool> {
2000            Ok(false)
2001        }
2002
2003        fn addr_peer(&self) -> NetResult<SocketAddr> {
2004            Ok(SocketAddr::from((Ipv4Addr::LOCALHOST, 80)))
2005        }
2006
2007        fn shutdown(&mut self, _how: Shutdown) -> NetResult<()> {
2008            Ok(())
2009        }
2010
2011        fn is_closed(&self) -> bool {
2012            false
2013        }
2014    }
2015
2016    #[derive(Debug)]
2017    struct MockTcpBoundSocket {
2018        ttl: Arc<AtomicUsize>,
2019    }
2020
2021    impl VirtualTcpBoundSocket for MockTcpBoundSocket {
2022        fn addr_local(&self) -> NetResult<SocketAddr> {
2023            Ok(SocketAddr::from((Ipv4Addr::LOCALHOST, 0)))
2024        }
2025
2026        fn listen(&mut self) -> NetResult<Box<dyn virtual_net::VirtualTcpListener + Sync>> {
2027            Err(NetworkError::Unsupported)
2028        }
2029
2030        fn connect(
2031            &mut self,
2032            _peer: SocketAddr,
2033        ) -> NetResult<Box<dyn virtual_net::VirtualTcpSocket + Sync>> {
2034            Err(NetworkError::Unsupported)
2035        }
2036
2037        fn set_ttl(&mut self, ttl: u32) -> NetResult<()> {
2038            self.ttl.store(ttl as usize, Ordering::Relaxed);
2039            Ok(())
2040        }
2041
2042        fn ttl(&self) -> NetResult<u32> {
2043            Ok(self.ttl.load(Ordering::Relaxed) as u32)
2044        }
2045    }
2046
2047    #[derive(Debug)]
2048    struct PendingBindNetworking;
2049
2050    #[async_trait::async_trait]
2051    impl VirtualNetworking for PendingBindNetworking {
2052        async fn bind_tcp(
2053            &self,
2054            _addr: SocketAddr,
2055            _only_v6: bool,
2056            _reuse_port: bool,
2057            _reuse_addr: bool,
2058        ) -> NetResult<Box<dyn VirtualTcpBoundSocket + Sync>> {
2059            pending::<()>().await;
2060            unreachable!("pending bind_tcp future should never complete")
2061        }
2062    }
2063
2064    #[test]
2065    fn inode_socket_poll_write_ready_uses_write_path() {
2066        let read_calls = Arc::new(AtomicUsize::new(0));
2067        let write_calls = Arc::new(AtomicUsize::new(0));
2068        let status = Arc::new(AtomicUsize::new(MOCK_STATUS_OPENED));
2069        let mut inode = InodeSocket::new(InodeSocketKind::TcpStream {
2070            socket: Box::new(MockTcpSocket {
2071                read_calls: read_calls.clone(),
2072                write_calls: write_calls.clone(),
2073                status,
2074            }),
2075            write_timeout: None,
2076            read_timeout: None,
2077        });
2078
2079        let waker = futures::task::noop_waker();
2080        let mut cx = Context::from_waker(&waker);
2081        let ready = Pin::new(&mut inode).poll_write_ready(&mut cx);
2082
2083        assert!(matches!(ready, Poll::Ready(Ok(7))));
2084        assert_eq!(read_calls.load(Ordering::Relaxed), 0);
2085        assert_eq!(write_calls.load(Ordering::Relaxed), 1);
2086    }
2087
2088    #[test]
2089    fn inode_socket_status_tracks_tcp_socket_status() {
2090        let status = Arc::new(AtomicUsize::new(MOCK_STATUS_OPENING));
2091        let inode = InodeSocket::new(InodeSocketKind::TcpStream {
2092            socket: Box::new(MockTcpSocket {
2093                read_calls: Arc::new(AtomicUsize::new(0)),
2094                write_calls: Arc::new(AtomicUsize::new(0)),
2095                status: status.clone(),
2096            }),
2097            write_timeout: None,
2098            read_timeout: None,
2099        });
2100
2101        assert!(matches!(inode.status().unwrap(), WasiSocketStatus::Opening));
2102        status.store(MOCK_STATUS_OPENED, Ordering::Relaxed);
2103        assert!(matches!(inode.status().unwrap(), WasiSocketStatus::Opened));
2104    }
2105
2106    #[test]
2107    fn inode_socket_bound_tcp_forwards_ttl() {
2108        let ttl = Arc::new(AtomicUsize::new(64));
2109        let inode = InodeSocket::new(InodeSocketKind::BoundTcp {
2110            socket: Box::new(MockTcpBoundSocket { ttl: ttl.clone() }),
2111            props: SocketProperties {
2112                family: Addressfamily::Inet4,
2113                ty: Socktype::Stream,
2114                pt: SockProto::Tcp,
2115                only_v6: false,
2116                reuse_port: false,
2117                reuse_addr: false,
2118                no_delay: None,
2119                keep_alive: None,
2120                dont_route: None,
2121                send_buf_size: None,
2122                recv_buf_size: None,
2123                write_timeout: None,
2124                read_timeout: None,
2125                accept_timeout: None,
2126                connect_timeout: None,
2127                handler: None,
2128            },
2129        });
2130
2131        inode.set_ttl(42).unwrap();
2132        assert_eq!(inode.ttl().unwrap(), 42);
2133        assert_eq!(ttl.load(Ordering::Relaxed), 42);
2134    }
2135
2136    #[cfg(feature = "sys")]
2137    #[tokio::test(flavor = "current_thread")]
2138    async fn inode_socket_tcp_bind_respects_bind_timeout() {
2139        let inode = InodeSocket::new(InodeSocketKind::PreSocket {
2140            props: SocketProperties {
2141                family: Addressfamily::Inet4,
2142                ty: Socktype::Stream,
2143                pt: SockProto::Tcp,
2144                only_v6: false,
2145                reuse_port: false,
2146                reuse_addr: false,
2147                no_delay: None,
2148                keep_alive: None,
2149                dont_route: None,
2150                send_buf_size: None,
2151                recv_buf_size: None,
2152                write_timeout: None,
2153                read_timeout: None,
2154                accept_timeout: None,
2155                connect_timeout: None,
2156                handler: None,
2157            },
2158            addr: None,
2159        });
2160        let tasks = crate::runtime::task_manager::tokio::TokioTaskManager::default();
2161        let net = PendingBindNetworking;
2162
2163        let err = inode
2164            .bind_internal(
2165                &tasks,
2166                &net,
2167                SocketAddr::from((Ipv4Addr::LOCALHOST, 0)),
2168                Duration::from_millis(10),
2169            )
2170            .await
2171            .unwrap_err();
2172        assert_eq!(err, Errno::Timedout);
2173    }
2174}