]> git.lizzy.rs Git - rust.git/commitdiff
Refactor net::each_addr/lookup_host to forward error from resolve
authorJethro Beekman <jethro@fortanix.com>
Tue, 18 Sep 2018 22:25:08 +0000 (15:25 -0700)
committerJethro Beekman <jethro@fortanix.com>
Thu, 6 Dec 2018 15:07:15 +0000 (20:37 +0530)
src/libstd/net/addr.rs
src/libstd/net/mod.rs
src/libstd/sys/cloudabi/shims/net.rs
src/libstd/sys/redox/net/mod.rs
src/libstd/sys/redox/net/tcp.rs
src/libstd/sys/redox/net/udp.rs
src/libstd/sys/unix/l4re.rs
src/libstd/sys/wasm/net.rs
src/libstd/sys_common/net.rs

index ff35325ab4fdaaacded38db1c1cb484410f67926..1ac0bdf922f885a598ef691c3a34ff5ef7d1a82e 100644 (file)
 use option;
 use sys::net::netc as c;
 use sys_common::{FromInner, AsInner, IntoInner};
-use sys_common::net::lookup_host;
+use sys_common::net::LookupHost;
 use vec;
 use iter;
 use slice;
+use convert::TryInto;
 
 /// An internet socket address, either IPv4 or IPv6.
 ///
@@ -863,9 +864,9 @@ fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
     }
 }
 
-fn resolve_socket_addr(s: &str, p: u16) -> io::Result<vec::IntoIter<SocketAddr>> {
-    let ips = lookup_host(s)?;
-    let v: Vec<_> = ips.map(|mut a| { a.set_port(p); a }).collect();
+fn resolve_socket_addr(lh: LookupHost) -> io::Result<vec::IntoIter<SocketAddr>> {
+    let p = lh.port();
+    let v: Vec<_> = lh.map(|mut a| { a.set_port(p); a }).collect();
     Ok(v.into_iter())
 }
 
@@ -885,7 +886,7 @@ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
             return Ok(vec![SocketAddr::V6(addr)].into_iter())
         }
 
-        resolve_socket_addr(host, port)
+        resolve_socket_addr((host, port).try_into()?)
     }
 }
 
@@ -899,22 +900,7 @@ fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
             return Ok(vec![addr].into_iter());
         }
 
-        macro_rules! try_opt {
-            ($e:expr, $msg:expr) => (
-                match $e {
-                    Some(r) => r,
-                    None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
-                                                      $msg)),
-                }
-            )
-        }
-
-        // split the string by ':' and convert the second part to u16
-        let mut parts_iter = self.rsplitn(2, ':');
-        let port_str = try_opt!(parts_iter.next(), "invalid socket address");
-        let host = try_opt!(parts_iter.next(), "invalid socket address");
-        let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
-        resolve_socket_addr(host, port)
+        resolve_socket_addr(self.try_into()?)
     }
 }
 
index be4bcee8a68aeb0f1c098670fb6cb3bc4c51ee71..ff579a5feb12dff1781534e8dd1f1a0f413f6905 100644 (file)
@@ -112,11 +112,15 @@ fn hton<I: NetInt>(i: I) -> I { i.to_be() }
 fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }
 
 fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
-    where F: FnMut(&SocketAddr) -> io::Result<T>
+    where F: FnMut(io::Result<&SocketAddr>) -> io::Result<T>
 {
+    let addrs = match addr.to_socket_addrs() {
+        Ok(addrs) => addrs,
+        Err(e) => return f(Err(e))
+    };
     let mut last_err = None;
-    for addr in addr.to_socket_addrs()? {
-        match f(&addr) {
+    for addr in addrs {
+        match f(Ok(&addr)) {
             Ok(l) => return Ok(l),
             Err(e) => last_err = Some(e),
         }
index 93eaf6a9e7d6970171ce5bf12463a07ffbc0ff07..7229e71d175213a0fdca195620d913e67fca97ca 100644 (file)
 use net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use time::Duration;
 use sys::{unsupported, Void};
+use convert::TryFrom;
 
 pub extern crate libc as netc;
 
 pub struct TcpStream(Void);
 
 impl TcpStream {
-    pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
+    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
         unsupported()
     }
 
@@ -105,7 +106,7 @@ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
 pub struct TcpListener(Void);
 
 impl TcpListener {
-    pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
         unsupported()
     }
 
@@ -155,7 +156,7 @@ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
 pub struct UdpSocket(Void);
 
 impl UdpSocket {
-    pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
         unsupported()
     }
 
@@ -271,7 +272,7 @@ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
 
-    pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
+    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
         match self.0 {}
     }
 }
@@ -284,6 +285,12 @@ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
 
 pub struct LookupHost(Void);
 
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        match self.0 {}
+    }
+}
+
 impl Iterator for LookupHost {
     type Item = SocketAddr;
     fn next(&mut self) -> Option<SocketAddr> {
@@ -291,6 +298,18 @@ fn next(&mut self) -> Option<SocketAddr> {
     }
 }
 
-pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
-    unsupported()
+impl<'a> TryFrom<&'a str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: &'a str) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+        unsupported()
+    }
 }
index 67f22231d5f7573c224f4a3b69203ac465d2b5a7..04a183f2417a9f997ea2d6c914bcc85ddc078dbe 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use fs::File;
-use io::{Error, Result, Read};
+use io::{Error, Read, self};
 use iter::Iterator;
 use net::{Ipv4Addr, SocketAddr, SocketAddrV4};
 use str::FromStr;
@@ -17,6 +17,7 @@
 use sys::syscall::EINVAL;
 use time::{self, Duration};
 use vec::{IntoIter, Vec};
+use convert::{TryFrom, TryInto};
 
 use self::dns::{Dns, DnsQuery};
 
 mod tcp;
 mod udp;
 
-pub struct LookupHost(IntoIter<SocketAddr>);
+pub struct LookupHost(IntoIter<SocketAddr>, u16);
+
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        self.1
+    }
+}
 
 impl Iterator for LookupHost {
     type Item = SocketAddr;
@@ -38,65 +45,93 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
-pub fn lookup_host(host: &str) -> Result<LookupHost> {
-    let mut ip_string = String::new();
-    File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?;
-    let ip: Vec<u8> = ip_string.trim().split('.').map(|part| part.parse::<u8>()
-                               .unwrap_or(0)).collect();
-
-    let mut dns_string = String::new();
-    File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?;
-    let dns: Vec<u8> = dns_string.trim().split('.').map(|part| part.parse::<u8>()
-                                 .unwrap_or(0)).collect();
-
-    if ip.len() == 4 && dns.len() == 4 {
-        let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap();
-        let tid = (time.subsec_nanos() >> 16) as u16;
-
-        let packet = Dns {
-            transaction_id: tid,
-            flags: 0x0100,
-            queries: vec![DnsQuery {
-                name: host.to_string(),
-                q_type: 0x0001,
-                q_class: 0x0001,
-            }],
-            answers: vec![]
-        };
-
-        let packet_data = packet.compile();
-
-        let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
-        let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]);
-        let socket = UdpSocket::bind(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0)))?;
-        socket.set_read_timeout(Some(Duration::new(5, 0)))?;
-        socket.set_write_timeout(Some(Duration::new(5, 0)))?;
-        socket.connect(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53)))?;
-        socket.send(&packet_data)?;
-
-        let mut buf = [0; 65536];
-        let count = socket.recv(&mut buf)?;
-
-        match Dns::parse(&buf[.. count]) {
-            Ok(response) => {
-                let mut addrs = vec![];
-                for answer in response.answers.iter() {
-                    if answer.a_type == 0x0001 && answer.a_class == 0x0001
-                       && answer.data.len() == 4
-                    {
-                        let answer_ip = Ipv4Addr::new(answer.data[0],
-                                                      answer.data[1],
-                                                      answer.data[2],
-                                                      answer.data[3]);
-                        addrs.push(SocketAddr::V4(SocketAddrV4::new(answer_ip, 0)));
-                    }
+impl<'a> TryFrom<&'a str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(s: &str) -> io::Result<LookupHost> {
+        macro_rules! try_opt {
+            ($e:expr, $msg:expr) => (
+                match $e {
+                    Some(r) => r,
+                    None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                                      $msg)),
                 }
-                Ok(LookupHost(addrs.into_iter()))
-            },
-            Err(_err) => Err(Error::from_raw_os_error(EINVAL))
+            )
+        }
+
+        // split the string by ':' and convert the second part to u16
+        let mut parts_iter = s.rsplitn(2, ':');
+        let port_str = try_opt!(parts_iter.next(), "invalid socket address");
+        let host = try_opt!(parts_iter.next(), "invalid socket address");
+        let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
+
+        (host, port).try_into()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
+        let mut ip_string = String::new();
+        File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?;
+        let ip: Vec<u8> = ip_string.trim().split('.').map(|part| part.parse::<u8>()
+                                   .unwrap_or(0)).collect();
+
+        let mut dns_string = String::new();
+        File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?;
+        let dns: Vec<u8> = dns_string.trim().split('.').map(|part| part.parse::<u8>()
+                                     .unwrap_or(0)).collect();
+
+        if ip.len() == 4 && dns.len() == 4 {
+            let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap();
+            let tid = (time.subsec_nanos() >> 16) as u16;
+
+            let packet = Dns {
+                transaction_id: tid,
+                flags: 0x0100,
+                queries: vec![DnsQuery {
+                    name: host.to_string(),
+                    q_type: 0x0001,
+                    q_class: 0x0001,
+                }],
+                answers: vec![]
+            };
+
+            let packet_data = packet.compile();
+
+            let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
+            let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]);
+            let socket = UdpSocket::bind(Ok(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0))))?;
+            socket.set_read_timeout(Some(Duration::new(5, 0)))?;
+            socket.set_write_timeout(Some(Duration::new(5, 0)))?;
+            socket.connect(Ok(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53))))?;
+            socket.send(&packet_data)?;
+
+            let mut buf = [0; 65536];
+            let count = socket.recv(&mut buf)?;
+
+            match Dns::parse(&buf[.. count]) {
+                Ok(response) => {
+                    let mut addrs = vec![];
+                    for answer in response.answers.iter() {
+                        if answer.a_type == 0x0001 && answer.a_class == 0x0001
+                           && answer.data.len() == 4
+                        {
+                            let answer_ip = Ipv4Addr::new(answer.data[0],
+                                                          answer.data[1],
+                                                          answer.data[2],
+                                                          answer.data[3]);
+                            addrs.push(SocketAddr::V4(SocketAddrV4::new(answer_ip, 0)));
+                        }
+                    }
+                    Ok(LookupHost(addrs.into_iter(), port))
+                },
+                Err(_err) => Err(Error::from_raw_os_error(EINVAL))
+            }
+        } else {
+            Err(Error::from_raw_os_error(EINVAL))
         }
-    } else {
-        Err(Error::from_raw_os_error(EINVAL))
     }
 }
 
index b5664908479cfbc342cb3a0dcceeeaa3bc1d581e..37457d87f331b6fe0affbb7008e0feb06aff7b9b 100644 (file)
@@ -24,8 +24,8 @@
 pub struct TcpStream(File);
 
 impl TcpStream {
-    pub fn connect(addr: &SocketAddr) -> Result<TcpStream> {
-        let path = format!("tcp:{}", addr);
+    pub fn connect(addr: Result<&SocketAddr>) -> Result<TcpStream> {
+        let path = format!("tcp:{}", addr?);
         let mut options = OpenOptions::new();
         options.read(true);
         options.write(true);
@@ -180,8 +180,8 @@ fn into_inner(self) -> File { self.0 }
 pub struct TcpListener(File);
 
 impl TcpListener {
-    pub fn bind(addr: &SocketAddr) -> Result<TcpListener> {
-        let path = format!("tcp:/{}", addr);
+    pub fn bind(addr: Result<&SocketAddr>) -> Result<TcpListener> {
+        let path = format!("tcp:/{}", addr?);
         let mut options = OpenOptions::new();
         options.read(true);
         options.write(true);
index 22af02079e79670699d8544caa20ef74df35df0e..85bfd425924934ed313116e3664eecbf1d126367 100644 (file)
@@ -25,8 +25,8 @@
 pub struct UdpSocket(File, UnsafeCell<Option<SocketAddr>>);
 
 impl UdpSocket {
-    pub fn bind(addr: &SocketAddr) -> Result<UdpSocket> {
-        let path = format!("udp:/{}", addr);
+    pub fn bind(addr: Result<&SocketAddr>) -> Result<UdpSocket> {
+        let path = format!("udp:/{}", addr?);
         let mut options = OpenOptions::new();
         options.read(true);
         options.write(true);
@@ -37,8 +37,8 @@ fn get_conn(&self) -> &mut Option<SocketAddr> {
         unsafe { &mut *(self.1.get()) }
     }
 
-    pub fn connect(&self, addr: &SocketAddr) -> Result<()> {
-        unsafe { *self.1.get() = Some(*addr) };
+    pub fn connect(&self, addr: Result<&SocketAddr>) -> Result<()> {
+        unsafe { *self.1.get() = Some(*addr?) };
         Ok(())
     }
 
index 21218489679393a92a655bf0012caa5ad242f962..bbb0fd45ba3dd5f6ff0346b4f373027c088bf3c7 100644 (file)
@@ -21,7 +21,7 @@ pub mod net {
     use sys_common::{AsInner, FromInner, IntoInner};
     use sys::fd::FileDesc;
     use time::Duration;
-
+    use convert::TryFrom;
 
     pub extern crate libc as netc;
 
@@ -118,7 +118,7 @@ pub struct TcpStream {
     }
 
     impl TcpStream {
-        pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
+        pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
             unimpl!();
         }
 
@@ -216,7 +216,7 @@ pub struct TcpListener {
     }
 
     impl TcpListener {
-        pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
+        pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
             unimpl!();
         }
 
@@ -278,7 +278,7 @@ pub struct UdpSocket {
     }
 
     impl UdpSocket {
-        pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
+        pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
             unimpl!();
         }
 
@@ -402,7 +402,7 @@ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
             unimpl!();
         }
 
-        pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
+        pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
             unimpl!();
         }
     }
@@ -431,11 +431,30 @@ fn next(&mut self) -> Option<SocketAddr> {
         }
     }
 
+    impl LookupHost {
+        pub fn port(&self) -> u16 {
+            unimpl!();
+        }
+    }
+
     unsafe impl Sync for LookupHost {}
     unsafe impl Send for LookupHost {}
 
-    pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
-        unimpl!();
+
+    impl<'a> TryFrom<&'a str> for LookupHost {
+        type Error = io::Error;
+
+        fn try_from(_v: &'a str) -> io::Result<LookupHost> {
+            unimpl!();
+        }
+    }
+
+    impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+        type Error = io::Error;
+
+        fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+            unimpl!();
+        }
     }
 }
 
index 03a5b2d779e1f633420f0f85e00f8bb29acb0250..e1c33b09cb420be121e0b323edb84f50cb313e49 100644 (file)
 use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
 use time::Duration;
 use sys::{unsupported, Void};
+use convert::TryFrom;
 
 pub struct TcpStream(Void);
 
 impl TcpStream {
-    pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
+    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
         unsupported()
     }
 
@@ -103,7 +104,7 @@ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
 pub struct TcpListener(Void);
 
 impl TcpListener {
-    pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
         unsupported()
     }
 
@@ -153,7 +154,7 @@ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
 pub struct UdpSocket(Void);
 
 impl UdpSocket {
-    pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
         unsupported()
     }
 
@@ -273,7 +274,7 @@ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
         match self.0 {}
     }
 
-    pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
+    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
         match self.0 {}
     }
 }
@@ -286,6 +287,12 @@ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
 
 pub struct LookupHost(Void);
 
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        match self.0 {}
+    }
+}
+
 impl Iterator for LookupHost {
     type Item = SocketAddr;
     fn next(&mut self) -> Option<SocketAddr> {
@@ -293,8 +300,20 @@ fn next(&mut self) -> Option<SocketAddr> {
     }
 }
 
-pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
-    unsupported()
+impl<'a> TryFrom<&'a str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: &'a str) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+        unsupported()
+    }
 }
 
 #[allow(nonstandard_style)]
index d09a233ed896f296529bbf597613a28285909639..dce2bf71cecab9fea0b43574301ae1e88d71b238 100644 (file)
@@ -20,6 +20,7 @@
 use sys::net::netc as c;
 use sys_common::{AsInner, FromInner, IntoInner};
 use time::Duration;
+use convert::{TryFrom, TryInto};
 
 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
           target_os = "ios", target_os = "macos",
@@ -129,6 +130,13 @@ fn to_ipv6mr_interface(value: u32) -> ::libc::c_uint {
 pub struct LookupHost {
     original: *mut c::addrinfo,
     cur: *mut c::addrinfo,
+    port: u16
+}
+
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        self.port
+    }
 }
 
 impl Iterator for LookupHost {
@@ -158,17 +166,45 @@ fn drop(&mut self) {
     }
 }
 
-pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
-    init();
+impl<'a> TryFrom<&'a str> for LookupHost {
+    type Error = io::Error;
 
-    let c_host = CString::new(host)?;
-    let mut hints: c::addrinfo = unsafe { mem::zeroed() };
-    hints.ai_socktype = c::SOCK_STREAM;
-    let mut res = ptr::null_mut();
-    unsafe {
-        cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)).map(|_| {
-            LookupHost { original: res, cur: res }
-        })
+    fn try_from(s: &str) -> io::Result<LookupHost> {
+        macro_rules! try_opt {
+            ($e:expr, $msg:expr) => (
+                match $e {
+                    Some(r) => r,
+                    None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                                      $msg)),
+                }
+            )
+        }
+
+        // split the string by ':' and convert the second part to u16
+        let mut parts_iter = s.rsplitn(2, ':');
+        let port_str = try_opt!(parts_iter.next(), "invalid socket address");
+        let host = try_opt!(parts_iter.next(), "invalid socket address");
+        let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
+
+        (host, port).try_into()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> {
+        init();
+
+        let c_host = CString::new(host)?;
+        let mut hints: c::addrinfo = unsafe { mem::zeroed() };
+        hints.ai_socktype = c::SOCK_STREAM;
+        let mut res = ptr::null_mut();
+        unsafe {
+            cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)).map(|_| {
+                LookupHost { original: res, cur: res, port }
+            })
+        }
     }
 }
 
@@ -181,7 +217,9 @@ pub struct TcpStream {
 }
 
 impl TcpStream {
-    pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
+    pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+        let addr = addr?;
+
         init();
 
         let sock = Socket::new(addr, c::SOCK_STREAM)?;
@@ -317,7 +355,9 @@ pub struct TcpListener {
 }
 
 impl TcpListener {
-    pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
+    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+        let addr = addr?;
+
         init();
 
         let sock = Socket::new(addr, c::SOCK_STREAM)?;
@@ -418,7 +458,9 @@ pub struct UdpSocket {
 }
 
 impl UdpSocket {
-    pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
+    pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+        let addr = addr?;
+
         init();
 
         let sock = Socket::new(addr, c::SOCK_DGRAM)?;
@@ -584,8 +626,8 @@ pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
         Ok(ret as usize)
     }
 
-    pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
-        let (addrp, len) = addr.into_inner();
+    pub fn connect(&self, addr: io::Result<&SocketAddr>) -> io::Result<()> {
+        let (addrp, len) = addr?.into_inner();
         cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(|_| ())
     }
 }
@@ -618,7 +660,7 @@ mod tests {
     #[test]
     fn no_lookup_host_duplicates() {
         let mut addrs = HashMap::new();
-        let lh = match lookup_host("localhost") {
+        let lh = match LookupHost::try_from(("localhost", 0)) {
             Ok(lh) => lh,
             Err(e) => panic!("couldn't resolve `localhost': {}", e)
         };