From 0948f54e65227a95d386e429f4e1356d7dd3fba7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 5 Sep 2013 14:16:17 -0700 Subject: [PATCH] std::rt: Add get_host_addresses function This is a very simplistic method for host name resolution. It converts a host name to a vector of IP addresses. Should be enough to get started. --- src/libstd/rt/io/mod.rs | 8 +------ src/libstd/rt/io/net/mod.rs | 45 +++++++++++++++++++++++++++++++++++-- src/libstd/rt/rtio.rs | 1 + src/libstd/rt/uv/uvio.rs | 34 +++++++++++++++++++++++++++- 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index d1919905236..5ceea877453 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -269,13 +269,7 @@ pub use self::extensions::WriterByteConversions; pub mod file; /// Synchronous, non-blocking network I/O. -pub mod net { - pub mod tcp; - pub mod udp; - pub mod ip; - #[cfg(unix)] - pub mod unix; -} +pub mod net; /// Readers and Writers for memory buffers and strings. pub mod mem; diff --git a/src/libstd/rt/io/net/mod.rs b/src/libstd/rt/io/net/mod.rs index 8f316364d27..f44e879a63a 100644 --- a/src/libstd/rt/io/net/mod.rs +++ b/src/libstd/rt/io/net/mod.rs @@ -8,14 +8,55 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use option::{Option, Some, None}; +use result::{Ok, Err}; +use rt::io::io_error; use rt::io::net::ip::IpAddr; +use rt::rtio::{IoFactory, IoFactoryObject}; +use rt::local::Local; -fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { +pub mod tcp; +pub mod udp; +pub mod ip; +#[cfg(unix)] +pub mod unix; + +/// Simplistic name resolution +pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> { /*! * Get the IP addresses for a given host name. * * Raises io_error on failure. */ - fail!() + let ipaddrs = unsafe { + let io: *mut IoFactoryObject = Local::unsafe_borrow(); + (*io).get_host_addresses(host) + }; + + match ipaddrs { + Ok(i) => Some(i), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } +} + +#[cfg(test)] +mod test { + use option::Some; + use rt::io::net::ip::Ipv4Addr; + use super::*; + + #[test] + 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); + } } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 6f1b33d1e21..c9c402baaf0 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -73,6 +73,7 @@ pub trait IoFactory { fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &P) -> Result<(), IoError>; + fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>; } pub trait RtioTcpListener : RtioSocket { diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index e37dfba0cc1..b225513e94f 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -29,7 +29,8 @@ use rt::tube::Tube; use rt::task::SchedHome; use rt::uv::*; use rt::uv::idle::IdleWatcher; -use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; +use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr, accum_sockaddrs}; +use rt::uv::addrinfo::GetAddrInfoRequest; use unstable::sync::Exclusive; use super::super::io::support::PathLike; use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, @@ -596,6 +597,37 @@ impl IoFactory for UvIoFactory { assert!(!result_cell.is_empty()); return result_cell.take(); } + + fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError> { + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + let host_ptr: *&str = &host; + let addrinfo_req = GetAddrInfoRequest::new(); + let addrinfo_req_cell = Cell::new(addrinfo_req); + do task::unkillable { // FIXME(#8674) + let scheduler: ~Scheduler = Local::take(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let mut addrinfo_req = addrinfo_req_cell.take(); + unsafe { + do addrinfo_req.getaddrinfo(self.uv_loop(), + Some(*host_ptr), + None, None) |_, addrinfo, err| { + let res = match err { + None => Ok(accum_sockaddrs(addrinfo).map(|addr| addr.ip.clone())), + Some(err) => Err(uv_error_to_io_error(err)) + }; + (*result_cell_ptr).put_back(res); + let scheduler: ~Scheduler = Local::take(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + } + } + } + addrinfo_req.delete(); + assert!(!result_cell.is_empty()); + return result_cell.take(); + } } pub struct UvTcpListener {