Skip to content

Commit 25ed29a

Browse files
committed
auto merge of #9000 : brson/rust/dns, r=anasazi
This exposes a very simple function for resolving host names. There's a lot more that needs to be done, but this is probably enough for servo to get started connecting to real websites again.
2 parents b650da1 + 807408b commit 25ed29a

File tree

11 files changed

+388
-15
lines changed

11 files changed

+388
-15
lines changed

src/libstd/rt/io/mod.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,7 @@ pub use self::extensions::WriterByteConversions;
269269
pub mod file;
270270

271271
/// Synchronous, non-blocking network I/O.
272-
pub mod net {
273-
pub mod tcp;
274-
pub mod udp;
275-
pub mod ip;
276-
#[cfg(unix)]
277-
pub mod unix;
278-
}
272+
pub mod net;
279273

280274
/// Readers and Writers for memory buffers and strings.
281275
pub mod mem;

src/libstd/rt/io/net/mod.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use option::{Option, Some, None};
12+
use result::{Ok, Err};
13+
use rt::io::io_error;
14+
use rt::io::net::ip::IpAddr;
15+
use rt::rtio::{IoFactory, IoFactoryObject};
16+
use rt::local::Local;
17+
18+
pub mod tcp;
19+
pub mod udp;
20+
pub mod ip;
21+
#[cfg(unix)]
22+
pub mod unix;
23+
24+
/// Simplistic name resolution
25+
pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
26+
/*!
27+
* Get the IP addresses for a given host name.
28+
*
29+
* Raises io_error on failure.
30+
*/
31+
32+
let ipaddrs = unsafe {
33+
let io: *mut IoFactoryObject = Local::unsafe_borrow();
34+
(*io).get_host_addresses(host)
35+
};
36+
37+
match ipaddrs {
38+
Ok(i) => Some(i),
39+
Err(ioerr) => {
40+
io_error::cond.raise(ioerr);
41+
None
42+
}
43+
}
44+
}
45+
46+
#[cfg(test)]
47+
mod test {
48+
use option::Some;
49+
use rt::io::net::ip::Ipv4Addr;
50+
use super::*;
51+
52+
#[test]
53+
fn dns_smoke_test() {
54+
let ipaddrs = get_host_addresses("localhost").unwrap();
55+
let mut found_local = false;
56+
let local_addr = &Ipv4Addr(127, 0, 0, 1);
57+
for addr in ipaddrs.iter() {
58+
found_local = found_local || addr == local_addr;
59+
}
60+
assert!(found_local);
61+
}
62+
}

src/libstd/rt/rtio.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub trait IoFactory {
7373
fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
7474
-> Result<~RtioFileStream, IoError>;
7575
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
76+
fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>;
7677
}
7778

7879
pub trait RtioTcpListener : RtioSocket {

src/libstd/rt/uv/addrinfo.rs

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use cast::transmute;
12+
use cell::Cell;
13+
use c_str::ToCStr;
14+
use libc::{c_int, c_void};
15+
use option::{Option, Some, None};
16+
use ptr::null;
17+
use rt::uv::uvll;
18+
use rt::uv::uvll::UV_GETADDRINFO;
19+
use rt::uv::{Loop, UvError, NativeHandle};
20+
use rt::uv::status_to_maybe_uv_error_with_loop;
21+
use rt::uv::net::UvAddrInfo;
22+
23+
type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option<UvError>);
24+
25+
pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);
26+
27+
pub struct RequestData {
28+
getaddrinfo_cb: Option<GetAddrInfoCallback>,
29+
}
30+
31+
impl GetAddrInfoRequest {
32+
pub fn new() -> GetAddrInfoRequest {
33+
let req = unsafe { uvll::malloc_req(UV_GETADDRINFO) };
34+
assert!(req.is_not_null());
35+
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
36+
req.install_req_data();
37+
return req;
38+
}
39+
40+
pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
41+
service: Option<&str>, hints: Option<UvAddrInfo>,
42+
cb: GetAddrInfoCallback) {
43+
44+
assert!(node.is_some() || service.is_some());
45+
46+
let (c_node, c_node_ptr) = match node {
47+
Some(n) => {
48+
let c_node = n.to_c_str();
49+
let c_node_ptr = c_node.with_ref(|r| r);
50+
(Some(c_node), c_node_ptr)
51+
}
52+
None => (None, null())
53+
};
54+
55+
let (c_service, c_service_ptr) = match service {
56+
Some(s) => {
57+
let c_service = s.to_c_str();
58+
let c_service_ptr = c_service.with_ref(|r| r);
59+
(Some(c_service), c_service_ptr)
60+
}
61+
None => (None, null())
62+
};
63+
64+
let cb = Cell::new(cb);
65+
let wrapper_cb: GetAddrInfoCallback = |req, addrinfo, err| {
66+
// Capture some heap values that need to stay alive for the
67+
// getaddrinfo call
68+
let _ = &c_node;
69+
let _ = &c_service;
70+
71+
let cb = cb.take();
72+
cb(req, addrinfo, err)
73+
};
74+
75+
// XXX: Implement hints
76+
assert!(hints.is_none());
77+
78+
self.get_req_data().getaddrinfo_cb = Some(wrapper_cb);
79+
80+
unsafe {
81+
assert!(0 == uvll::getaddrinfo(loop_.native_handle(),
82+
self.native_handle(),
83+
getaddrinfo_cb,
84+
c_node_ptr,
85+
c_service_ptr,
86+
null()));
87+
}
88+
89+
extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
90+
status: c_int,
91+
res: *uvll::addrinfo) {
92+
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
93+
let loop_ = req.get_loop();
94+
let err = status_to_maybe_uv_error_with_loop(loop_.native_handle(), status);
95+
let addrinfo = UvAddrInfo(res);
96+
let data = req.get_req_data();
97+
(*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err);
98+
unsafe {
99+
uvll::freeaddrinfo(res);
100+
}
101+
}
102+
}
103+
104+
fn get_loop(&self) -> Loop {
105+
unsafe {
106+
Loop {
107+
handle: uvll::get_loop_from_fs_req(self.native_handle())
108+
}
109+
}
110+
}
111+
112+
fn install_req_data(&mut self) {
113+
let req = self.native_handle() as *uvll::uv_getaddrinfo_t;
114+
let data = ~RequestData {
115+
getaddrinfo_cb: None
116+
};
117+
unsafe {
118+
let data = transmute::<~RequestData, *c_void>(data);
119+
uvll::set_data_for_req(req, data);
120+
}
121+
}
122+
123+
fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
124+
unsafe {
125+
let data = uvll::get_data_for_req(self.native_handle());
126+
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
127+
return &mut **data;
128+
}
129+
}
130+
131+
fn delete(self) {
132+
unsafe {
133+
let data = uvll::get_data_for_req(self.native_handle());
134+
let _data = transmute::<*c_void, ~RequestData>(data);
135+
uvll::set_data_for_req(self.native_handle(), null::<()>());
136+
uvll::free_req(self.native_handle());
137+
}
138+
}
139+
}
140+
141+
impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
142+
fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest {
143+
GetAddrInfoRequest(handle)
144+
}
145+
fn native_handle(&self) -> *uvll::uv_getaddrinfo_t {
146+
match self { &GetAddrInfoRequest(ptr) => ptr }
147+
}
148+
}
149+
150+
#[cfg(test)]
151+
mod test {
152+
use option::{Some, None};
153+
use rt::uv::Loop;
154+
use rt::uv::net::accum_sockaddrs;
155+
use rt::io::net::ip::{SocketAddr, Ipv4Addr};
156+
use super::*;
157+
158+
#[test]
159+
fn getaddrinfo_test() {
160+
let mut loop_ = Loop::new();
161+
let mut req = GetAddrInfoRequest::new();
162+
do req.getaddrinfo(&loop_, Some("localhost"), None, None) |_, addrinfo, _| {
163+
let sockaddrs = accum_sockaddrs(addrinfo);
164+
let mut found_local = false;
165+
let local_addr = &SocketAddr {
166+
ip: Ipv4Addr(127, 0, 0, 1),
167+
port: 0
168+
};
169+
for addr in sockaddrs.iter() {
170+
found_local = found_local || addr == local_addr;
171+
}
172+
assert!(found_local);
173+
}
174+
loop_.run();
175+
loop_.close();
176+
req.delete();
177+
}
178+
}

src/libstd/rt/uv/file.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,17 @@ impl NativeHandle<*uvll::uv_fs_t> for FsRequest {
139139
match self { &FsRequest(ptr) => ptr }
140140
}
141141
}
142-
fn sync_cleanup(loop_: &Loop, result: int)
143-
-> Result<int, UvError> {
144-
match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) {
145-
Some(err) => Err(err),
146-
None => Ok(result)
147-
}
142+
143+
fn sync_cleanup(loop_: &Loop, result: int)
144+
-> Result<int, UvError> {
145+
match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) {
146+
Some(err) => Err(err),
147+
None => Ok(result)
148148
}
149+
}
149150

150151
pub struct FileDescriptor(c_int);
152+
151153
impl FileDescriptor {
152154
fn new(fd: c_int) -> FileDescriptor {
153155
FileDescriptor(fd)

src/libstd/rt/uv/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub mod net;
7070
pub mod idle;
7171
pub mod timer;
7272
pub mod async;
73+
pub mod addrinfo;
7374

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

134135

135-
/// Callbacks used by StreamWatchers, set as custom data on the foreign handle
136+
/// Callbacks used by StreamWatchers, set as custom data on the foreign handle.
137+
/// XXX: Would be better not to have all watchers allocate room for all callback types.
136138
struct WatcherData {
137139
read_cb: Option<ReadCallback>,
138140
write_cb: Option<ConnectionCallback>,

src/libstd/rt/uv/net.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use vec;
2121
use str;
2222
use from_str::{FromStr};
2323

24+
pub struct UvAddrInfo(*uvll::addrinfo);
25+
2426
pub enum UvSocketAddr {
2527
UvIpv4SocketAddr(*sockaddr_in),
2628
UvIpv6SocketAddr(*sockaddr_in6),
@@ -95,6 +97,28 @@ pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr {
9597
uv_socket_addr_as_socket_addr(addr, util::id)
9698
}
9799

100+
// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
101+
pub fn accum_sockaddrs(addr: &UvAddrInfo) -> ~[SocketAddr] {
102+
unsafe {
103+
let &UvAddrInfo(addr) = addr;
104+
let mut addr = addr;
105+
106+
let mut addrs = ~[];
107+
loop {
108+
let uvaddr = sockaddr_to_UvSocketAddr((*addr).ai_addr);
109+
let rustaddr = uv_socket_addr_to_socket_addr(uvaddr);
110+
addrs.push(rustaddr);
111+
if (*addr).ai_next.is_not_null() {
112+
addr = (*addr).ai_next;
113+
} else {
114+
break;
115+
}
116+
}
117+
118+
return addrs;
119+
}
120+
}
121+
98122
#[cfg(test)]
99123
#[test]
100124
fn test_ip4_conversion() {

src/libstd/rt/uv/uvio.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ use rt::tube::Tube;
2929
use rt::task::SchedHome;
3030
use rt::uv::*;
3131
use rt::uv::idle::IdleWatcher;
32-
use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr};
32+
use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr, accum_sockaddrs};
33+
use rt::uv::addrinfo::GetAddrInfoRequest;
3334
use unstable::sync::Exclusive;
3435
use super::super::io::support::PathLike;
3536
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 {
596597
assert!(!result_cell.is_empty());
597598
return result_cell.take();
598599
}
600+
601+
fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError> {
602+
let result_cell = Cell::new_empty();
603+
let result_cell_ptr: *Cell<Result<~[IpAddr], IoError>> = &result_cell;
604+
let host_ptr: *&str = &host;
605+
let addrinfo_req = GetAddrInfoRequest::new();
606+
let addrinfo_req_cell = Cell::new(addrinfo_req);
607+
do task::unkillable { // FIXME(#8674)
608+
let scheduler: ~Scheduler = Local::take();
609+
do scheduler.deschedule_running_task_and_then |_, task| {
610+
let task_cell = Cell::new(task);
611+
let mut addrinfo_req = addrinfo_req_cell.take();
612+
unsafe {
613+
do addrinfo_req.getaddrinfo(self.uv_loop(),
614+
Some(*host_ptr),
615+
None, None) |_, addrinfo, err| {
616+
let res = match err {
617+
None => Ok(accum_sockaddrs(addrinfo).map(|addr| addr.ip.clone())),
618+
Some(err) => Err(uv_error_to_io_error(err))
619+
};
620+
(*result_cell_ptr).put_back(res);
621+
let scheduler: ~Scheduler = Local::take();
622+
scheduler.resume_blocked_task_immediately(task_cell.take());
623+
}
624+
}
625+
}
626+
}
627+
addrinfo_req.delete();
628+
assert!(!result_cell.is_empty());
629+
return result_cell.take();
630+
}
599631
}
600632

601633
pub struct UvTcpListener {

0 commit comments

Comments
 (0)