1+ use std:: io:: ErrorKind ;
2+ use std:: net:: { SocketAddr , ToSocketAddrs } ;
3+ use wasip2:: sockets:: instance_network:: instance_network;
4+ use wasip2:: sockets:: network:: Ipv4SocketAddress ;
5+ use wasip2:: sockets:: tcp:: { IpAddressFamily , IpSocketAddress } ;
6+ use wasip2:: sockets:: tcp_create_socket:: create_tcp_socket;
17use wasip2:: {
28 io:: streams:: { InputStream , OutputStream } ,
39 sockets:: tcp:: TcpSocket ,
410} ;
511
12+ use super :: to_io_err;
613use crate :: io:: { self , AsyncInputStream , AsyncOutputStream } ;
14+ use crate :: runtime:: AsyncPollable ;
715
816/// A TCP stream between a local and a remote socket.
917pub struct TcpStream {
@@ -20,12 +28,61 @@ impl TcpStream {
2028 socket,
2129 }
2230 }
31+
32+ /// Opens a TCP connection to a remote host.
33+ ///
34+ /// `addr` is an address of the remote host. Anything which implements the
35+ /// [`ToSocketAddrs`] trait can be supplied as the address. If `addr`
36+ /// yields multiple addresses, connect will be attempted with each of the
37+ /// addresses until a connection is successful. If none of the addresses
38+ /// result in a successful connection, the error returned from the last
39+ /// connection attempt (the last address) is returned.
40+ pub async fn connect ( addr : impl ToSocketAddrs ) -> io:: Result < Self > {
41+ let addrs = addr. to_socket_addrs ( ) ?;
42+ let mut last_err = None ;
43+ for addr in addrs {
44+ match TcpStream :: connect_addr ( addr) . await {
45+ Ok ( stream) => return Ok ( stream) ,
46+ Err ( e) => last_err = Some ( e) ,
47+ }
48+ }
49+
50+ Err ( last_err. unwrap_or_else ( || {
51+ io:: Error :: new ( ErrorKind :: InvalidInput , "could not resolve to any address" )
52+ } ) )
53+ }
54+
55+ /// Establishes a connection to the specified `addr`.
56+ pub async fn connect_addr ( addr : SocketAddr ) -> io:: Result < Self > {
57+ let family = match addr {
58+ SocketAddr :: V4 ( _) => IpAddressFamily :: Ipv4 ,
59+ SocketAddr :: V6 ( _) => IpAddressFamily :: Ipv6 ,
60+ } ;
61+ let socket = create_tcp_socket ( family) . map_err ( to_io_err) ?;
62+ let network = instance_network ( ) ;
63+
64+ let remote_address = match addr {
65+ SocketAddr :: V4 ( addr) => {
66+ let ip = addr. ip ( ) . octets ( ) ;
67+ let address = ( ip[ 0 ] , ip[ 1 ] , ip[ 2 ] , ip[ 3 ] ) ;
68+ let port = addr. port ( ) ;
69+ IpSocketAddress :: Ipv4 ( Ipv4SocketAddress { port, address } )
70+ }
71+ SocketAddr :: V6 ( _) => todo ! ( "IPv6 not yet supported in `wstd::net::TcpStream`" ) ,
72+ } ;
73+ socket
74+ . start_connect ( & network, remote_address)
75+ . map_err ( to_io_err) ?;
76+ let pollable = AsyncPollable :: new ( socket. subscribe ( ) ) ;
77+ pollable. wait_for ( ) . await ;
78+ let ( input, output) = socket. finish_connect ( ) . map_err ( to_io_err) ?;
79+
80+ Ok ( TcpStream :: new ( input, output, socket) )
81+ }
82+
2383 /// Returns the socket address of the remote peer of this TCP connection.
2484 pub fn peer_addr ( & self ) -> io:: Result < String > {
25- let addr = self
26- . socket
27- . remote_address ( )
28- . map_err ( super :: tcp_listener:: to_io_err) ?;
85+ let addr = self . socket . remote_address ( ) . map_err ( to_io_err) ?;
2986 Ok ( format ! ( "{addr:?}" ) )
3087 }
3188
0 commit comments