From 5aa31c43a0ab50208e58680cf5f29eec8ff76357 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 22 Jan 2014 15:38:19 -0500 Subject: [PATCH 1/3] libnative: Implement get_host_addresses. --- src/libnative/io/addrinfo.rs | 100 +++++++++++++++++++++++++++++++++++ src/libnative/io/mod.rs | 19 +++---- src/libnative/io/net.rs | 4 +- src/librustuv/addrinfo.rs | 9 ++-- src/librustuv/uvll.rs | 41 +------------- src/libstd/libc.rs | 48 +++++++++++++++-- 6 files changed, 162 insertions(+), 59 deletions(-) create mode 100644 src/libnative/io/addrinfo.rs diff --git a/src/libnative/io/addrinfo.rs b/src/libnative/io/addrinfo.rs new file mode 100644 index 00000000000..3e7ce59b69d --- /dev/null +++ b/src/libnative/io/addrinfo.rs @@ -0,0 +1,100 @@ +// 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 or the MIT license +// , 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; +use std::io::IoError; +use std::libc; +use std::libc::{c_char, c_int}; +use std::ptr::null; +use std::str::raw::from_c_str; + +use super::net::sockaddr_to_addr; + +pub struct GetAddrInfoRequest; + +impl GetAddrInfoRequest { + pub fn run(host: Option<&str>, servname: Option<&str>, + hint: Option) -> 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 { + let err_str = unsafe { from_c_str(gai_strerror(s)) }; + + return Err(IoError { + kind: io::OtherIoError, + desc: "unable to resolve host", + detail: Some(err_str), + }); + } + + // 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 { + fn getaddrinfo(node: *c_char, service: *c_char, + hints: *libc::addrinfo, res: **libc::addrinfo) -> c_int; + fn gai_strerror(errcode: c_int) -> *c_char; + fn freeaddrinfo(res: *libc::addrinfo); +} diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index f1bec440547..0bb80ba97fb 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; type IoResult = Result; @@ -186,9 +187,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) -> IoResult<~[ai::Info]> { - Err(unimpl()) + fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>, + hint: Option) -> 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 { +pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, + len: uint) -> IoResult { match storage.ss_family as libc::c_int { libc::AF_INET => { assert!(len as uint >= mem::size_of::()); diff --git a/src/librustuv/addrinfo.rs b/src/librustuv/addrinfo.rs index aa4dda786e3..2fe4819c789 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() }; diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs index 189a820cd3e..b1a74b84e7c 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/libc.rs b/src/libstd/libc.rs index 77ac226a7f1..fd59fb2382b 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 + } } } From a04cc4db2c077fd2fcf6e5bcca92eecb3cfa8380 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 22 Jan 2014 16:05:28 -0500 Subject: [PATCH 2/3] libstd: Use iotest! for for get_host_addresses. --- src/librustuv/addrinfo.rs | 36 ----------------------------------- src/libstd/io/net/addrinfo.rs | 16 +++++++++++----- 2 files changed, 11 insertions(+), 41 deletions(-) diff --git a/src/librustuv/addrinfo.rs b/src/librustuv/addrinfo.rs index 2fe4819c789..2740671c00d 100644 --- a/src/librustuv/addrinfo.rs +++ b/src/librustuv/addrinfo.rs @@ -183,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/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) 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]) } From adb512802057a89b4339651c90dca81e5dd96751 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 22 Jan 2014 20:54:36 -0800 Subject: [PATCH 3/3] libnative: Avoid gai_strerror on windows. --- src/libnative/io/addrinfo.rs | 39 ++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/libnative/io/addrinfo.rs b/src/libnative/io/addrinfo.rs index 3e7ce59b69d..5bdeaa17e74 100644 --- a/src/libnative/io/addrinfo.rs +++ b/src/libnative/io/addrinfo.rs @@ -11,12 +11,10 @@ use ai = std::io::net::addrinfo; use std::c_str::CString; use std::cast; -use std::io; use std::io::IoError; use std::libc; use std::libc::{c_char, c_int}; use std::ptr::null; -use std::str::raw::from_c_str; use super::net::sockaddr_to_addr; @@ -55,13 +53,7 @@ impl GetAddrInfoRequest { // Error? if s != 0 { - let err_str = unsafe { from_c_str(gai_strerror(s)) }; - - return Err(IoError { - kind: io::OtherIoError, - desc: "unable to resolve host", - detail: Some(err_str), - }); + return Err(get_error(s)); } // Collect all the results we found @@ -92,9 +84,34 @@ impl GetAddrInfoRequest { } } -extern { +extern "system" { fn getaddrinfo(node: *c_char, service: *c_char, hints: *libc::addrinfo, res: **libc::addrinfo) -> c_int; - fn gai_strerror(errcode: c_int) -> *c_char; 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), + } }