Skip to content

Commit c218694

Browse files
committed
std::rt: Add libuv bindings for getaddrinfo
1 parent b3f7f75 commit c218694

File tree

7 files changed

+288
-0
lines changed

7 files changed

+288
-0
lines changed

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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 rt::io::net::ip::IpAddr;
12+
13+
fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
14+
/*!
15+
* Get the IP addresses for a given host name.
16+
*
17+
* Raises io_error on failure.
18+
*/
19+
20+
fail!()
21+
}

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/mod.rs

Lines changed: 1 addition & 0 deletions
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,

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/uvll.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub type uv_timer_t = c_void;
7272
pub type uv_stream_t = c_void;
7373
pub type uv_fs_t = c_void;
7474
pub type uv_udp_send_t = c_void;
75+
pub type uv_getaddrinfo_t = c_void;
7576

7677
#[cfg(stage0)]
7778
pub type uv_idle_cb = *u8;
@@ -97,6 +98,8 @@ pub type uv_connection_cb = *u8;
9798
pub type uv_timer_cb = *u8;
9899
#[cfg(stage0)]
99100
pub type uv_write_cb = *u8;
101+
#[cfg(stage0)]
102+
pub type uv_getaddrinfo_cb = *u8;
100103

101104
#[cfg(not(stage0))]
102105
pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
@@ -137,12 +140,44 @@ pub type uv_timer_cb = extern "C" fn(handle: *uv_timer_t,
137140
#[cfg(not(stage0))]
138141
pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
139142
status: c_int);
143+
#[cfg(not(stage0))]
144+
pub type uv_getaddrinfo_cb = extern "C" fn(req: *uv_getaddrinfo_t,
145+
status: c_int,
146+
res: *addrinfo);
140147

141148
pub type sockaddr = c_void;
142149
pub type sockaddr_in = c_void;
143150
pub type sockaddr_in6 = c_void;
144151
pub type sockaddr_storage = c_void;
145152

153+
#[cfg(unix)]
154+
pub type socklen_t = c_int;
155+
156+
// XXX: This is a standard C type. Could probably be defined in libc
157+
#[cfg(unix)]
158+
pub struct addrinfo {
159+
ai_flags: c_int,
160+
ai_family: c_int,
161+
ai_socktype: c_int,
162+
ai_protocol: c_int,
163+
ai_addrlen: socklen_t,
164+
ai_addr: *sockaddr,
165+
ai_canonname: *char,
166+
ai_next: *addrinfo
167+
}
168+
169+
#[cfg(windows)]
170+
pub struct addrinfo {
171+
ai_flags: c_int,
172+
ai_family: c_int,
173+
ai_socktype: c_int,
174+
ai_protocol: c_int,
175+
ai_addrlen: size_t,
176+
ai_canonname: *char,
177+
ai_addr: *sockaddr,
178+
ai_next: *addrinfo
179+
}
180+
146181
#[deriving(Eq)]
147182
pub enum uv_handle_type {
148183
UV_UNKNOWN_HANDLE,
@@ -666,6 +701,11 @@ pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t {
666701

667702
rust_uv_get_loop_from_fs_req(req)
668703
}
704+
pub unsafe fn get_loop_from_getaddrinfo_req(req: *uv_getaddrinfo_t) -> *uv_loop_t {
705+
#[fixed_stack_segment]; #[inline(never)];
706+
707+
rust_uv_get_loop_from_getaddrinfo_req(req)
708+
}
669709
pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
670710
#[fixed_stack_segment]; #[inline(never)];
671711

@@ -721,6 +761,18 @@ pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
721761

722762
return rust_uv_get_len_from_buf(buf);
723763
}
764+
pub unsafe fn getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t,
765+
getaddrinfo_cb: uv_getaddrinfo_cb,
766+
node: *c_char, service: *c_char,
767+
hints: *addrinfo) -> c_int {
768+
#[fixed_stack_segment]; #[inline(never)];
769+
return rust_uv_getaddrinfo(loop_, req, getaddrinfo_cb, node, service, hints);
770+
}
771+
pub unsafe fn freeaddrinfo(ai: *addrinfo) {
772+
#[fixed_stack_segment]; #[inline(never)];
773+
rust_uv_freeaddrinfo(ai);
774+
}
775+
724776
pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
725777
let err = last_error(uv_loop);
726778
let err_ptr = ptr::to_unsafe_ptr(&err);
@@ -845,6 +897,7 @@ extern {
845897
fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
846898
fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
847899
fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;
900+
fn rust_uv_get_loop_from_getaddrinfo_req(req: *uv_fs_t) -> *uv_loop_t;
848901

849902
fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t;
850903
fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t;
@@ -857,4 +910,9 @@ extern {
857910
fn rust_uv_set_data_for_req(req: *c_void, data: *c_void);
858911
fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8;
859912
fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t;
913+
fn rust_uv_getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t,
914+
getaddrinfo_cb: uv_getaddrinfo_cb,
915+
node: *c_char, service: *c_char,
916+
hints: *addrinfo) -> c_int;
917+
fn rust_uv_freeaddrinfo(ai: *addrinfo);
860918
}

src/rt/rust_uv.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,3 +553,8 @@ extern "C" uv_loop_t*
553553
rust_uv_get_loop_from_fs_req(uv_fs_t* req) {
554554
return req->loop;
555555
}
556+
557+
extern "C" uv_loop_t*
558+
rust_uv_get_loop_from_getaddrinfo_req(uv_getaddrinfo_t* req) {
559+
return req->loop;
560+
}

src/rt/rustrt.def.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,4 @@ rust_take_change_dir_lock
192192
rust_drop_change_dir_lock
193193
rust_get_test_int
194194
rust_get_task
195+
rust_uv_get_loop_from_getaddrinfo_req

0 commit comments

Comments
 (0)