Skip to content
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

Simple DNS #9000

Closed
wants to merge 4 commits into from
Closed
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
8 changes: 1 addition & 7 deletions src/libstd/rt/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
62 changes: 62 additions & 0 deletions src/libstd/rt/io/net/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2013 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 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;

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.
*/

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);
}
}
1 change: 1 addition & 0 deletions src/libstd/rt/rtio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pub trait IoFactory {
fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
-> Result<~RtioFileStream, IoError>;
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>;
}

pub trait RtioTcpListener : RtioSocket {
Expand Down
178 changes: 178 additions & 0 deletions src/libstd/rt/uv/addrinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright 2013 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 cast::transmute;
use cell::Cell;
use c_str::ToCStr;
use libc::{c_int, c_void};
use option::{Option, Some, None};
use ptr::null;
use rt::uv::uvll;
use rt::uv::uvll::UV_GETADDRINFO;
use rt::uv::{Loop, UvError, NativeHandle};
use rt::uv::status_to_maybe_uv_error_with_loop;
use rt::uv::net::UvAddrInfo;

type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option<UvError>);

pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);

pub struct RequestData {
getaddrinfo_cb: Option<GetAddrInfoCallback>,
}

impl GetAddrInfoRequest {
pub fn new() -> GetAddrInfoRequest {
let req = unsafe { uvll::malloc_req(UV_GETADDRINFO) };
assert!(req.is_not_null());
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
req.install_req_data();
return req;
}

pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
service: Option<&str>, hints: Option<UvAddrInfo>,
cb: GetAddrInfoCallback) {

assert!(node.is_some() || service.is_some());

let (c_node, c_node_ptr) = match node {
Some(n) => {
let c_node = n.to_c_str();
let c_node_ptr = c_node.with_ref(|r| r);
(Some(c_node), c_node_ptr)
}
None => (None, null())
};

let (c_service, c_service_ptr) = match service {
Some(s) => {
let c_service = s.to_c_str();
let c_service_ptr = c_service.with_ref(|r| r);
(Some(c_service), c_service_ptr)
}
None => (None, null())
};

let cb = Cell::new(cb);
let wrapper_cb: GetAddrInfoCallback = |req, addrinfo, err| {
// Capture some heap values that need to stay alive for the
// getaddrinfo call
let _ = &c_node;
let _ = &c_service;

let cb = cb.take();
cb(req, addrinfo, err)
};

// XXX: Implement hints
assert!(hints.is_none());

self.get_req_data().getaddrinfo_cb = Some(wrapper_cb);

unsafe {
assert!(0 == uvll::getaddrinfo(loop_.native_handle(),
self.native_handle(),
getaddrinfo_cb,
c_node_ptr,
c_service_ptr,
null()));
}

extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
status: c_int,
res: *uvll::addrinfo) {
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
let loop_ = req.get_loop();
let err = status_to_maybe_uv_error_with_loop(loop_.native_handle(), status);
let addrinfo = UvAddrInfo(res);
let data = req.get_req_data();
(*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err);
unsafe {
uvll::freeaddrinfo(res);
}
}
}

fn get_loop(&self) -> Loop {
unsafe {
Loop {
handle: uvll::get_loop_from_fs_req(self.native_handle())
}
}
}

fn install_req_data(&mut self) {
let req = self.native_handle() as *uvll::uv_getaddrinfo_t;
let data = ~RequestData {
getaddrinfo_cb: None
};
unsafe {
let data = transmute::<~RequestData, *c_void>(data);
uvll::set_data_for_req(req, data);
}
}

fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
return &mut **data;
}
}

fn delete(self) {
unsafe {
let data = uvll::get_data_for_req(self.native_handle());
let _data = transmute::<*c_void, ~RequestData>(data);
uvll::set_data_for_req(self.native_handle(), null::<()>());
uvll::free_req(self.native_handle());
}
}
}

impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest {
GetAddrInfoRequest(handle)
}
fn native_handle(&self) -> *uvll::uv_getaddrinfo_t {
match self { &GetAddrInfoRequest(ptr) => ptr }
}
}

#[cfg(test)]
mod test {
use option::{Some, None};
use rt::uv::Loop;
use rt::uv::net::accum_sockaddrs;
use rt::io::net::ip::{SocketAddr, Ipv4Addr};
use super::*;

#[test]
fn getaddrinfo_test() {
let mut loop_ = Loop::new();
let mut req = GetAddrInfoRequest::new();
do req.getaddrinfo(&loop_, Some("localhost"), None, None) |_, addrinfo, _| {
let sockaddrs = accum_sockaddrs(addrinfo);
let mut found_local = false;
let local_addr = &SocketAddr {
ip: Ipv4Addr(127, 0, 0, 1),
port: 0
};
for addr in sockaddrs.iter() {
found_local = found_local || addr == local_addr;
}
assert!(found_local);
}
loop_.run();
loop_.close();
req.delete();
}
}
14 changes: 8 additions & 6 deletions src/libstd/rt/uv/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,17 @@ impl NativeHandle<*uvll::uv_fs_t> for FsRequest {
match self { &FsRequest(ptr) => ptr }
}
}
fn sync_cleanup(loop_: &Loop, result: int)
-> Result<int, UvError> {
match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) {
Some(err) => Err(err),
None => Ok(result)
}

fn sync_cleanup(loop_: &Loop, result: int)
-> Result<int, UvError> {
match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) {
Some(err) => Err(err),
None => Ok(result)
}
}

pub struct FileDescriptor(c_int);

impl FileDescriptor {
fn new(fd: c_int) -> FileDescriptor {
FileDescriptor(fd)
Expand Down
4 changes: 3 additions & 1 deletion src/libstd/rt/uv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub mod net;
pub mod idle;
pub mod timer;
pub mod async;
pub mod addrinfo;

/// XXX: Loop(*handle) is buggy with destructors. Normal structs
/// with dtors may not be destructured, but tuple structs can,
Expand Down Expand Up @@ -132,7 +133,8 @@ pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option
pub type UdpSendCallback = ~fn(UdpWatcher, Option<UvError>);


/// Callbacks used by StreamWatchers, set as custom data on the foreign handle
/// Callbacks used by StreamWatchers, set as custom data on the foreign handle.
/// XXX: Would be better not to have all watchers allocate room for all callback types.
struct WatcherData {
read_cb: Option<ReadCallback>,
write_cb: Option<ConnectionCallback>,
Expand Down
24 changes: 24 additions & 0 deletions src/libstd/rt/uv/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ use vec;
use str;
use from_str::{FromStr};

pub struct UvAddrInfo(*uvll::addrinfo);

pub enum UvSocketAddr {
UvIpv4SocketAddr(*sockaddr_in),
UvIpv6SocketAddr(*sockaddr_in6),
Expand Down Expand Up @@ -95,6 +97,28 @@ pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr {
uv_socket_addr_as_socket_addr(addr, util::id)
}

// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
pub fn accum_sockaddrs(addr: &UvAddrInfo) -> ~[SocketAddr] {
unsafe {
let &UvAddrInfo(addr) = addr;
let mut addr = addr;

let mut addrs = ~[];
loop {
let uvaddr = sockaddr_to_UvSocketAddr((*addr).ai_addr);
let rustaddr = uv_socket_addr_to_socket_addr(uvaddr);
addrs.push(rustaddr);
if (*addr).ai_next.is_not_null() {
addr = (*addr).ai_next;
} else {
break;
}
}

return addrs;
}
}

#[cfg(test)]
#[test]
fn test_ip4_conversion() {
Expand Down
34 changes: 33 additions & 1 deletion src/libstd/rt/uv/uvio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<~[IpAddr], IoError>> = &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 {
Expand Down
Loading