Skip to content

libnative: Implement get_host_addresses. #11732

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 25, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions src/libnative/io/addrinfo.rs
Original file line number Diff line number Diff line change
@@ -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),
}
}
19 changes: 10 additions & 9 deletions src/libnative/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,29 @@

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;
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
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<T> = Result<T, IoError>;

Expand Down Expand Up @@ -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<ai::Hint>) -> IoResult<~[ai::Info]> {
Err(unimpl())
fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to keep up with tradition, could you move this to a net::io::addrinfo module?

hint: Option<ai::Hint>) -> IoResult<~[ai::Info]> {
addrinfo::GetAddrInfoRequest::run(host, servname, hint)
}

// filesystem operations
Expand Down
4 changes: 2 additions & 2 deletions src/libnative/io/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>());
Expand Down
45 changes: 5 additions & 40 deletions src/librustuv/addrinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand All @@ -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() };
Expand Down Expand Up @@ -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);
}
}
41 changes: 1 addition & 40 deletions src/librustuv/uvll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
16 changes: 11 additions & 5 deletions src/libstd/io/net/addrinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,21 +98,27 @@ 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);
for addr in ipaddrs.iter() {
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])
}
Loading