diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 32fd54c8e7510..5a70f9e97a1f3 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -157,6 +157,21 @@ impl TcpStream { super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream) } + /// Opens a TCP connection to a remote host using the specified local address. + /// + /// `addr` is an address of the remote host. Anything which implements + /// [`ToSocketAddrs`] trait can be supplied for the address; see this trait + /// documentation for concrete examples. + /// + /// If `addr` yields multiple addresses, `connect_from` will be attempted with + /// each of the addresses until a connection is successful. If none of + /// the addresses result in a successful connection, the error returned from + /// the last connection attempt (the last address) is returned. + #[unstable(feature = "tcpstream_connect_from", issue = "115710")] + pub fn connect_from(from: &SocketAddr, addr: A) -> io::Result { + super::each_addr(addr, |addr| net_imp::TcpStream::connect_from(from, addr)).map(TcpStream) + } + /// Opens a TCP connection to a remote host with a timeout. /// /// Unlike `connect`, `connect_timeout` takes a single [`SocketAddr`] since @@ -173,6 +188,21 @@ impl TcpStream { net_imp::TcpStream::connect_timeout(addr, timeout).map(TcpStream) } + /// Opens a TCP connection to a remote host using the specified local address with a timeout. + /// + /// Unlike `connect_from`, `connect_from_timeout` takes a single [`SocketAddr`] since + /// timeout must be applied to individual addresses. + /// + /// It is an error to pass a zero `Duration` to this function. + #[unstable(feature = "tcpstream_connect_from", issue = "115710")] + pub fn connect_from_timeout( + from: &SocketAddr, + addr: &SocketAddr, + timeout: Duration, + ) -> io::Result { + net_imp::TcpStream::connect_from_timeout(from, addr, timeout).map(TcpStream) + } + /// Returns the socket address of the remote peer of this TCP connection. /// /// # Examples diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 2976a9f578ede..f3745336a77e0 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -231,6 +231,21 @@ impl TcpStream { Ok(TcpStream { inner: sock }) } + pub fn connect_from(from: &SocketAddr, addr: io::Result<&SocketAddr>) -> io::Result { + let addr = addr?; + + init(); + + let sock = Socket::new(addr, c::SOCK_STREAM)?; + + let (from, len) = from.into_inner(); + cvt(unsafe { c::bind(sock.as_raw(), from.as_ptr(), len as _) })?; + + let (addr, len) = addr.into_inner(); + cvt_r(|| unsafe { c::connect(sock.as_raw(), addr.as_ptr(), len) })?; + Ok(TcpStream { inner: sock }) + } + pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { init(); @@ -239,6 +254,22 @@ impl TcpStream { Ok(TcpStream { inner: sock }) } + pub fn connect_from_timeout( + from: &SocketAddr, + addr: &SocketAddr, + timeout: Duration, + ) -> io::Result { + init(); + + let sock = Socket::new(addr, c::SOCK_STREAM)?; + + let (from, len) = from.into_inner(); + cvt(unsafe { c::bind(sock.as_raw(), from.as_ptr(), len as _) })?; + + sock.connect_timeout(addr, timeout)?; + Ok(TcpStream { inner: sock }) + } + #[inline] pub fn socket(&self) -> &Socket { &self.inner