about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libnative/io/addrinfo.rs117
-rw-r--r--src/libnative/io/mod.rs19
-rw-r--r--src/libnative/io/net.rs4
-rw-r--r--src/librustuv/addrinfo.rs45
-rw-r--r--src/librustuv/uvll.rs41
-rw-r--r--src/libstd/io/net/addrinfo.rs16
-rw-r--r--src/libstd/libc.rs48
7 files changed, 190 insertions, 100 deletions
diff --git a/src/libnative/io/addrinfo.rs b/src/libnative/io/addrinfo.rs
new file mode 100644
index 00000000000..5bdeaa17e74
--- /dev/null
+++ b/src/libnative/io/addrinfo.rs
@@ -0,0 +1,117 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ai = std::io::net::addrinfo;
+use std::c_str::CString;
+use std::cast;
+use std::io::IoError;
+use std::libc;
+use std::libc::{c_char, c_int};
+use std::ptr::null;
+
+use super::net::sockaddr_to_addr;
+
+pub struct GetAddrInfoRequest;
+
+impl GetAddrInfoRequest {
+    pub fn run(host: Option<&str>, servname: Option<&str>,
+               hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError> {
+        assert!(host.is_some() || servname.is_some());
+
+        let c_host = host.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str());
+        let c_serv = servname.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str());
+
+        let hint = hint.map(|hint| {
+            libc::addrinfo {
+                ai_flags: hint.flags as c_int,
+                ai_family: hint.family as c_int,
+                ai_socktype: 0,
+                ai_protocol: 0,
+                ai_addrlen: 0,
+                ai_canonname: null(),
+                ai_addr: null(),
+                ai_next: null()
+            }
+        });
+
+        let hint_ptr = hint.as_ref().map_or(null(), |x| x as *libc::addrinfo);
+        let res = null();
+
+        // Make the call
+        let s = unsafe {
+            let ch = if c_host.is_null() { null() } else { c_host.with_ref(|x| x) };
+            let cs = if c_serv.is_null() { null() } else { c_serv.with_ref(|x| x) };
+            getaddrinfo(ch, cs, hint_ptr, &res)
+        };
+
+        // Error?
+        if s != 0 {
+            return Err(get_error(s));
+        }
+
+        // Collect all the results we found
+        let mut addrs = ~[];
+        let mut rp = res;
+        while rp.is_not_null() {
+            unsafe {
+                let addr = match sockaddr_to_addr(cast::transmute((*rp).ai_addr),
+                                                  (*rp).ai_addrlen as uint) {
+                    Ok(a) => a,
+                    Err(e) => return Err(e)
+                };
+                addrs.push(ai::Info {
+                    address: addr,
+                    family: (*rp).ai_family as uint,
+                    socktype: None,
+                    protocol: None,
+                    flags: (*rp).ai_flags as uint
+                });
+
+                rp = (*rp).ai_next;
+            }
+        }
+
+        unsafe { freeaddrinfo(res); }
+
+        Ok(addrs)
+    }
+}
+
+extern "system" {
+    fn getaddrinfo(node: *c_char, service: *c_char,
+                   hints: *libc::addrinfo, res: **libc::addrinfo) -> c_int;
+    fn freeaddrinfo(res: *libc::addrinfo);
+    #[cfg(not(windows))]
+    fn gai_strerror(errcode: c_int) -> *c_char;
+    #[cfg(windows)]
+    fn WSAGetLastError() -> c_int;
+}
+
+#[cfg(windows)]
+fn get_error(_: c_int) -> IoError {
+    use super::translate_error;
+
+    unsafe {
+        translate_error(WSAGetLastError() as i32, true)
+    }
+}
+
+#[cfg(not(windows))]
+fn get_error(s: c_int) -> IoError {
+    use std::io;
+    use std::str::raw::from_c_str;
+
+    let err_str = unsafe { from_c_str(gai_strerror(s)) };
+    IoError {
+        kind: io::OtherIoError,
+        desc: "unable to resolve host",
+        detail: Some(err_str),
+    }
+}
diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs
index f3aca7820a5..1ef5987de0a 100644
--- a/src/libnative/io/mod.rs
+++ b/src/libnative/io/mod.rs
@@ -23,6 +23,11 @@
 
 use std::c_str::CString;
 use std::comm::SharedChan;
+use std::io;
+use std::io::IoError;
+use std::io::net::ip::SocketAddr;
+use std::io::process::ProcessConfig;
+use std::io::signal::Signum;
 use std::libc::c_int;
 use std::libc;
 use std::os;
@@ -30,11 +35,6 @@ use std::rt::rtio;
 use std::rt::rtio::{RtioTcpStream, RtioTcpListener, RtioUdpSocket,
                     RtioUnixListener, RtioPipe, RtioFileStream, RtioProcess,
                     RtioSignal, RtioTTY, CloseBehavior, RtioTimer};
-use std::io;
-use std::io::IoError;
-use std::io::net::ip::SocketAddr;
-use std::io::process::ProcessConfig;
-use std::io::signal::Signum;
 use ai = std::io::net::addrinfo;
 
 // Local re-exports
@@ -42,9 +42,10 @@ pub use self::file::FileDesc;
 pub use self::process::Process;
 
 // Native I/O implementations
+pub mod addrinfo;
 pub mod file;
-pub mod process;
 pub mod net;
+pub mod process;
 
 #[cfg(target_os = "macos")]
 #[cfg(target_os = "freebsd")]
@@ -202,9 +203,9 @@ impl rtio::IoFactory for IoFactory {
     fn unix_connect(&mut self, _path: &CString) -> IoResult<~RtioPipe> {
         Err(unimpl())
     }
-    fn get_host_addresses(&mut self, _host: Option<&str>, _servname: Option<&str>,
-                          _hint: Option<ai::Hint>) -> IoResult<~[ai::Info]> {
-        Err(unimpl())
+    fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
+                          hint: Option<ai::Hint>) -> IoResult<~[ai::Info]> {
+        addrinfo::GetAddrInfoRequest::run(host, servname, hint)
     }
 
     // filesystem operations
diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs
index adcd21f0ac4..9be4247b056 100644
--- a/src/libnative/io/net.rs
+++ b/src/libnative/io/net.rs
@@ -134,8 +134,8 @@ fn sockname(fd: sock_t,
     return sockaddr_to_addr(&storage, len as uint);
 }
 
-fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
-                    len: uint) -> IoResult<ip::SocketAddr> {
+pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
+                        len: uint) -> IoResult<ip::SocketAddr> {
     match storage.ss_family as libc::c_int {
         libc::AF_INET => {
             assert!(len as uint >= mem::size_of::<libc::sockaddr_in>());
diff --git a/src/librustuv/addrinfo.rs b/src/librustuv/addrinfo.rs
index aa4dda786e3..2740671c00d 100644
--- a/src/librustuv/addrinfo.rs
+++ b/src/librustuv/addrinfo.rs
@@ -10,6 +10,7 @@
 
 use ai = std::io::net::addrinfo;
 use std::cast;
+use std::libc;
 use std::libc::c_int;
 use std::ptr::null;
 use std::rt::task::BlockedTask;
@@ -19,7 +20,7 @@ use super::{Loop, UvError, Request, wait_until_woken_after, wakeup};
 use uvll;
 
 struct Addrinfo {
-    handle: *uvll::addrinfo,
+    handle: *libc::addrinfo,
 }
 
 struct Ctx {
@@ -62,7 +63,7 @@ impl GetAddrInfoRequest {
             let socktype = 0;
             let protocol = 0;
 
-            uvll::addrinfo {
+            libc::addrinfo {
                 ai_flags: flags,
                 ai_family: hint.family as c_int,
                 ai_socktype: socktype,
@@ -73,7 +74,7 @@ impl GetAddrInfoRequest {
                 ai_next: null(),
             }
         });
-        let hint_ptr = hint.as_ref().map_or(null(), |x| x as *uvll::addrinfo);
+        let hint_ptr = hint.as_ref().map_or(null(), |x| x as *libc::addrinfo);
         let mut req = Request::new(uvll::UV_GETADDRINFO);
 
         return match unsafe {
@@ -100,7 +101,7 @@ impl GetAddrInfoRequest {
 
         extern fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
                                  status: c_int,
-                                 res: *uvll::addrinfo) {
+                                 res: *libc::addrinfo) {
             let req = Request::wrap(req);
             assert!(status != uvll::ECANCELED);
             let cx: &mut Ctx = unsafe { req.get_data() };
@@ -182,39 +183,3 @@ pub fn accum_addrinfo(addr: &Addrinfo) -> ~[ai::Info] {
         return addrs;
     }
 }
-
-// cannot give tcp/ip permission without help of apk
-#[cfg(test, not(target_os="android"))]
-mod test {
-    use std::io::net::ip::{SocketAddr, Ipv4Addr};
-    use super::super::local_loop;
-    use super::GetAddrInfoRequest;
-
-    #[test]
-    fn getaddrinfo_test() {
-        let loop_ = &mut local_loop().loop_;
-        match GetAddrInfoRequest::run(loop_, Some("localhost"), None, None) {
-            Ok(infos) => {
-                let mut found_local = false;
-                let local_addr = &SocketAddr {
-                    ip: Ipv4Addr(127, 0, 0, 1),
-                    port: 0
-                };
-                for addr in infos.iter() {
-                    found_local = found_local || addr.address == *local_addr;
-                }
-                assert!(found_local);
-            }
-            Err(e) => fail!("{:?}", e),
-        }
-    }
-
-    #[test]
-    fn issue_10663() {
-        let loop_ = &mut local_loop().loop_;
-        // Something should happen here, but this certainly shouldn't cause
-        // everything to die. The actual outcome we don't care too much about.
-        GetAddrInfoRequest::run(loop_, Some("irc.n0v4.com"), None,
-                                None);
-    }
-}
diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs
index 0a6e23e9956..c2612d0ed18 100644
--- a/src/librustuv/uvll.rs
+++ b/src/librustuv/uvll.rs
@@ -30,7 +30,7 @@
 #[allow(non_camel_case_types)]; // C types
 
 use std::libc::{size_t, c_int, c_uint, c_void, c_char, c_double};
-use std::libc::{ssize_t, sockaddr, free};
+use std::libc::{ssize_t, sockaddr, free, addrinfo};
 use std::libc;
 use std::rt::global_heap::malloc_raw;
 
@@ -249,45 +249,6 @@ pub type uv_signal_cb = extern "C" fn(handle: *uv_signal_t,
                                       signum: c_int);
 pub type uv_fs_cb = extern "C" fn(req: *uv_fs_t);
 
-// XXX: This is a standard C type. Could probably be defined in libc
-#[cfg(target_os = "android")]
-#[cfg(target_os = "linux")]
-pub struct addrinfo {
-    ai_flags: c_int,
-    ai_family: c_int,
-    ai_socktype: c_int,
-    ai_protocol: c_int,
-    ai_addrlen: libc::socklen_t,
-    ai_addr: *sockaddr,
-    ai_canonname: *char,
-    ai_next: *addrinfo
-}
-
-#[cfg(target_os = "macos")]
-#[cfg(target_os = "freebsd")]
-pub struct addrinfo {
-    ai_flags: c_int,
-    ai_family: c_int,
-    ai_socktype: c_int,
-    ai_protocol: c_int,
-    ai_addrlen: libc::socklen_t,
-    ai_canonname: *char,
-    ai_addr: *sockaddr,
-    ai_next: *addrinfo
-}
-
-#[cfg(windows)]
-pub struct addrinfo {
-    ai_flags: c_int,
-    ai_family: c_int,
-    ai_socktype: c_int,
-    ai_protocol: c_int,
-    ai_addrlen: size_t,
-    ai_canonname: *char,
-    ai_addr: *sockaddr,
-    ai_next: *addrinfo
-}
-
 #[cfg(unix)] pub type uv_uid_t = libc::types::os::arch::posix88::uid_t;
 #[cfg(unix)] pub type uv_gid_t = libc::types::os::arch::posix88::gid_t;
 #[cfg(windows)] pub type uv_uid_t = libc::c_uchar;
diff --git a/src/libstd/io/net/addrinfo.rs b/src/libstd/io/net/addrinfo.rs
index fe29a112262..4a8529d0a0a 100644
--- a/src/libstd/io/net/addrinfo.rs
+++ b/src/libstd/io/net/addrinfo.rs
@@ -98,15 +98,15 @@ fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option<Hint>)
     LocalIo::maybe_raise(|io| io.get_host_addresses(hostname, servname, hint))
 }
 
-#[cfg(test)]
+// Ignored on android since we cannot give tcp/ip
+// permission without help of apk
+#[cfg(test, not(target_os = "android"))]
 mod test {
     use io::net::ip::Ipv4Addr;
     use prelude::*;
     use super::*;
 
-    #[test]
-    #[ignore(cfg(target_os="android"))] // cannot give tcp/ip permission without help of apk
-    fn dns_smoke_test() {
+    iotest!(fn dns_smoke_test() {
         let ipaddrs = get_host_addresses("localhost").unwrap();
         let mut found_local = false;
         let local_addr = &Ipv4Addr(127, 0, 0, 1);
@@ -114,5 +114,11 @@ mod test {
             found_local = found_local || addr == local_addr;
         }
         assert!(found_local);
-    }
+    })
+
+    iotest!(fn issue_10663() {
+        // Something should happen here, but this certainly shouldn't cause
+        // everything to die. The actual outcome we don't care too much about.
+        get_host_addresses("example.com");
+    } #[ignore])
 }
diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs
index 6f2d64ff668..a398835824b 100644
--- a/src/libstd/libc.rs
+++ b/src/libstd/libc.rs
@@ -267,7 +267,7 @@ pub mod types {
                 pub enum timezone {}
             }
             pub mod bsd44 {
-                use libc::types::os::arch::c95::c_uint;
+                use libc::types::os::arch::c95::{c_char, c_int, c_uint};
 
                 pub type socklen_t = u32;
                 pub type sa_family_t = u16;
@@ -309,6 +309,16 @@ pub mod types {
                     ipv6mr_multiaddr: in6_addr,
                     ipv6mr_interface: c_uint,
                 }
+                pub struct addrinfo {
+                    ai_flags: c_int,
+                    ai_family: c_int,
+                    ai_socktype: c_int,
+                    ai_protocol: c_int,
+                    ai_addrlen: socklen_t,
+                    ai_addr: *sockaddr,
+                    ai_canonname: *c_char,
+                    ai_next: *addrinfo
+                }
             }
         }
 
@@ -624,7 +634,7 @@ pub mod types {
                 pub enum timezone {}
             }
             pub mod bsd44 {
-                use libc::types::os::arch::c95::c_uint;
+                use libc::types::os::arch::c95::{c_char, c_int, c_uint};
 
                 pub type socklen_t = u32;
                 pub type sa_family_t = u8;
@@ -671,6 +681,16 @@ pub mod types {
                     ipv6mr_multiaddr: in6_addr,
                     ipv6mr_interface: c_uint,
                 }
+                pub struct addrinfo {
+                    ai_flags: c_int,
+                    ai_family: c_int,
+                    ai_socktype: c_int,
+                    ai_protocol: c_int,
+                    ai_addrlen: socklen_t,
+                    ai_canonname: *c_char,
+                    ai_addr: *sockaddr,
+                    ai_next: *addrinfo
+                }
             }
         }
 
@@ -811,7 +831,7 @@ pub mod types {
             }
 
             pub mod bsd44 {
-                use libc::types::os::arch::c95::{c_int, c_uint};
+                use libc::types::os::arch::c95::{c_char, c_int, c_uint, size_t};
 
                 pub type SOCKET = c_uint;
                 pub type socklen_t = c_int;
@@ -854,6 +874,16 @@ pub mod types {
                     ipv6mr_multiaddr: in6_addr,
                     ipv6mr_interface: c_uint,
                 }
+                pub struct addrinfo {
+                    ai_flags: c_int,
+                    ai_family: c_int,
+                    ai_socktype: c_int,
+                    ai_protocol: c_int,
+                    ai_addrlen: size_t,
+                    ai_canonname: *c_char,
+                    ai_addr: *sockaddr,
+                    ai_next: *addrinfo
+                }
             }
         }
 
@@ -1121,7 +1151,7 @@ pub mod types {
             }
 
             pub mod bsd44 {
-                use libc::types::os::arch::c95::{c_int, c_uint};
+                use libc::types::os::arch::c95::{c_char, c_int, c_uint};
 
                 pub type socklen_t = c_int;
                 pub type sa_family_t = u8;
@@ -1168,6 +1198,16 @@ pub mod types {
                     ipv6mr_multiaddr: in6_addr,
                     ipv6mr_interface: c_uint,
                 }
+                pub struct addrinfo {
+                    ai_flags: c_int,
+                    ai_family: c_int,
+                    ai_socktype: c_int,
+                    ai_protocol: c_int,
+                    ai_addrlen: socklen_t,
+                    ai_canonname: *c_char,
+                    ai_addr: *sockaddr,
+                    ai_next: *addrinfo
+                }
             }
         }