Skip to content

Commit 1db783b

Browse files
committed
Finish implementing io::net::addrinfo
This fills in the `hints` structure and exposes libuv's full functionality for doing dns lookups.
1 parent bac9681 commit 1db783b

File tree

7 files changed

+262
-92
lines changed

7 files changed

+262
-92
lines changed

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

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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+
/*!
12+
13+
Synchronous DNS Resolution
14+
15+
Contains the functionality to perform DNS resolution in a style related to
16+
getaddrinfo()
17+
18+
*/
19+
20+
use option::{Option, Some, None};
21+
use result::{Ok, Err};
22+
use rt::io::io_error;
23+
use rt::io::net::ip::{SocketAddr, IpAddr};
24+
use rt::rtio::{IoFactory, IoFactoryObject};
25+
use rt::local::Local;
26+
27+
/// Hints to the types of sockets that are desired when looking up hosts
28+
pub enum SocketType {
29+
Stream, Datagram, Raw
30+
}
31+
32+
/// Flags which can be or'd into the `flags` field of a `Hint`. These are used
33+
/// to manipulate how a query is performed.
34+
///
35+
/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo`
36+
pub enum Flag {
37+
AddrConfig,
38+
All,
39+
CanonName,
40+
NumericHost,
41+
NumericServ,
42+
Passive,
43+
V4Mapped,
44+
}
45+
46+
/// A transport protocol associated with either a hint or a return value of
47+
/// `lookup`
48+
pub enum Protocol {
49+
TCP, UDP
50+
}
51+
52+
/// This structure is used to provide hints when fetching addresses for a
53+
/// remote host to control how the lookup is performed.
54+
///
55+
/// For details on these fields, see their corresponding definitions via
56+
/// `man -s 3 getaddrinfo`
57+
pub struct Hint {
58+
family: uint,
59+
socktype: Option<SocketType>,
60+
protocol: Option<Protocol>,
61+
flags: uint,
62+
}
63+
64+
pub struct Info {
65+
address: SocketAddr,
66+
family: uint,
67+
socktype: Option<SocketType>,
68+
protocol: Option<Protocol>,
69+
flags: uint,
70+
}
71+
72+
/// Easy name resolution. Given a hostname, returns the list of IP addresses for
73+
/// that hostname.
74+
///
75+
/// # Failure
76+
///
77+
/// On failure, this will raise on the `io_error` condition.
78+
pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
79+
lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip))
80+
}
81+
82+
/// Full-fleged resolution. This function will perform a synchronous call to
83+
/// getaddrinfo, controlled by the parameters
84+
///
85+
/// # Arguments
86+
///
87+
/// * hostname - an optional hostname to lookup against
88+
/// * servname - an optional service name, listed in the system services
89+
/// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this
90+
/// controls lookup
91+
///
92+
/// # Failure
93+
///
94+
/// On failure, this will raise on the `io_error` condition.
95+
pub fn lookup(hostname: Option<&str>, servname: Option<&str>,
96+
hint: Option<Hint>) -> Option<~[Info]> {
97+
let ipaddrs = unsafe {
98+
let io: *mut IoFactoryObject = Local::unsafe_borrow();
99+
(*io).get_host_addresses(hostname, servname, hint)
100+
};
101+
102+
match ipaddrs {
103+
Ok(i) => Some(i),
104+
Err(ioerr) => {
105+
io_error::cond.raise(ioerr);
106+
None
107+
}
108+
}
109+
}
110+
111+
#[cfg(test)]
112+
mod test {
113+
use option::Some;
114+
use rt::io::net::ip::Ipv4Addr;
115+
use super::*;
116+
117+
#[test]
118+
fn dns_smoke_test() {
119+
let ipaddrs = get_host_addresses("localhost").unwrap();
120+
let mut found_local = false;
121+
let local_addr = &Ipv4Addr(127, 0, 0, 1);
122+
for addr in ipaddrs.iter() {
123+
found_local = found_local || addr == local_addr;
124+
}
125+
assert!(found_local);
126+
}
127+
}

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

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,55 +8,11 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

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;
11+
pub use self::addrinfo::get_host_addresses;
1712

13+
pub mod addrinfo;
1814
pub mod tcp;
1915
pub mod udp;
2016
pub mod ip;
2117
#[cfg(unix)]
2218
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: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use option::*;
1313
use result::*;
1414
use libc::c_int;
1515

16+
use ai = rt::io::net::addrinfo;
1617
use rt::io::IoError;
1718
use super::io::process::ProcessConfig;
1819
use super::io::net::ip::{IpAddr, SocketAddr};
@@ -80,7 +81,8 @@ pub trait IoFactory {
8081
fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
8182
-> Result<~RtioFileStream, IoError>;
8283
fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
83-
fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError>;
84+
fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
85+
hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError>;
8486
fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError>;
8587
fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
8688
fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;

src/libstd/rt/uv/addrinfo.rs

Lines changed: 99 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ use rt::uv::uvll;
1818
use rt::uv::uvll::UV_GETADDRINFO;
1919
use rt::uv::{Loop, UvError, NativeHandle};
2020
use rt::uv::status_to_maybe_uv_error;
21-
use rt::uv::net::UvAddrInfo;
21+
use rt::uv::net;
22+
use ai = rt::io::net::addrinfo;
2223

23-
type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option<UvError>);
24+
type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &net::UvAddrInfo, Option<UvError>);
2425

2526
pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);
2627

@@ -38,7 +39,7 @@ impl GetAddrInfoRequest {
3839
}
3940

4041
pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
41-
service: Option<&str>, hints: Option<UvAddrInfo>,
42+
service: Option<&str>, hints: Option<ai::Hint>,
4243
cb: GetAddrInfoCallback) {
4344

4445
assert!(node.is_some() || service.is_some());
@@ -72,8 +73,37 @@ impl GetAddrInfoRequest {
7273
cb(req, addrinfo, err)
7374
};
7475

75-
// XXX: Implement hints
76-
assert!(hints.is_none());
76+
let hint = hints.map(|hint| unsafe {
77+
let mut flags = 0;
78+
do each_ai_flag |cval, aival| {
79+
if hint.flags & (aival as uint) != 0 {
80+
flags |= cval as i32;
81+
}
82+
}
83+
let socktype = match hint.socktype {
84+
Some(ai::Stream) => uvll::rust_SOCK_STREAM(),
85+
Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(),
86+
Some(ai::Raw) => uvll::rust_SOCK_RAW(),
87+
None => 0,
88+
};
89+
let protocol = match hint.protocol {
90+
Some(ai::UDP) => uvll::rust_IPPROTO_UDP(),
91+
Some(ai::TCP) => uvll::rust_IPPROTO_TCP(),
92+
_ => 0,
93+
};
94+
95+
uvll::addrinfo {
96+
ai_flags: flags,
97+
ai_family: hint.family as c_int,
98+
ai_socktype: socktype,
99+
ai_protocol: protocol,
100+
ai_addrlen: 0,
101+
ai_canonname: null(),
102+
ai_addr: null(),
103+
ai_next: null(),
104+
}
105+
});
106+
let hint_ptr = hint.as_ref().map_default(null(), |x| x as *uvll::addrinfo);
77107

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

@@ -83,15 +113,15 @@ impl GetAddrInfoRequest {
83113
getaddrinfo_cb,
84114
c_node_ptr,
85115
c_service_ptr,
86-
null()));
116+
hint_ptr));
87117
}
88118

89119
extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
90120
status: c_int,
91121
res: *uvll::addrinfo) {
92122
let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
93123
let err = status_to_maybe_uv_error(status);
94-
let addrinfo = UvAddrInfo(res);
124+
let addrinfo = net::UvAddrInfo(res);
95125
let data = req.get_req_data();
96126
(*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err);
97127
unsafe {
@@ -137,6 +167,66 @@ impl GetAddrInfoRequest {
137167
}
138168
}
139169

170+
fn each_ai_flag(f: &fn(c_int, ai::Flag)) {
171+
unsafe {
172+
f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig);
173+
f(uvll::rust_AI_ALL(), ai::All);
174+
f(uvll::rust_AI_CANONNAME(), ai::CanonName);
175+
f(uvll::rust_AI_NUMERICHOST(), ai::NumericHost);
176+
f(uvll::rust_AI_NUMERICSERV(), ai::NumericServ);
177+
f(uvll::rust_AI_PASSIVE(), ai::Passive);
178+
f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped);
179+
}
180+
}
181+
182+
// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
183+
pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] {
184+
unsafe {
185+
let &net::UvAddrInfo(addr) = addr;
186+
let mut addr = addr;
187+
188+
let mut addrs = ~[];
189+
loop {
190+
let uvaddr = net::sockaddr_to_UvSocketAddr((*addr).ai_addr);
191+
let rustaddr = net::uv_socket_addr_to_socket_addr(uvaddr);
192+
193+
let mut flags = 0;
194+
do each_ai_flag |cval, aival| {
195+
if (*addr).ai_flags & cval != 0 {
196+
flags |= aival as uint;
197+
}
198+
}
199+
200+
let protocol = match (*addr).ai_protocol {
201+
p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP),
202+
p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP),
203+
_ => None,
204+
};
205+
let socktype = match (*addr).ai_socktype {
206+
p if p == uvll::rust_SOCK_STREAM() => Some(ai::Stream),
207+
p if p == uvll::rust_SOCK_DGRAM() => Some(ai::Datagram),
208+
p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw),
209+
_ => None,
210+
};
211+
212+
addrs.push(ai::Info {
213+
address: rustaddr,
214+
family: (*addr).ai_family as uint,
215+
socktype: socktype,
216+
protocol: protocol,
217+
flags: flags,
218+
});
219+
if (*addr).ai_next.is_not_null() {
220+
addr = (*addr).ai_next;
221+
} else {
222+
break;
223+
}
224+
}
225+
226+
return addrs;
227+
}
228+
}
229+
140230
impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
141231
fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest {
142232
GetAddrInfoRequest(handle)
@@ -150,7 +240,6 @@ impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
150240
mod test {
151241
use option::{Some, None};
152242
use rt::uv::Loop;
153-
use rt::uv::net::accum_sockaddrs;
154243
use rt::io::net::ip::{SocketAddr, Ipv4Addr};
155244
use super::*;
156245

@@ -159,14 +248,14 @@ mod test {
159248
let mut loop_ = Loop::new();
160249
let mut req = GetAddrInfoRequest::new();
161250
do req.getaddrinfo(&loop_, Some("localhost"), None, None) |_, addrinfo, _| {
162-
let sockaddrs = accum_sockaddrs(addrinfo);
251+
let sockaddrs = accum_addrinfo(addrinfo);
163252
let mut found_local = false;
164253
let local_addr = &SocketAddr {
165254
ip: Ipv4Addr(127, 0, 0, 1),
166255
port: 0
167256
};
168257
for addr in sockaddrs.iter() {
169-
found_local = found_local || addr == local_addr;
258+
found_local = found_local || addr.address == *local_addr;
170259
}
171260
assert!(found_local);
172261
}

0 commit comments

Comments
 (0)