about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-09-04 18:51:14 -0700
committerBrian Anderson <banderson@mozilla.com>2013-09-05 14:22:15 -0700
commitc218694cece7c3018b4a809a52a35fcf3716d92e (patch)
treef7abe1b9d5c3f57310718e075590a8cba865e99a /src/libstd/rt
parentb3f7f758b1f3df8c1d2ded808492b452e4b0e1a0 (diff)
downloadrust-c218694cece7c3018b4a809a52a35fcf3716d92e.tar.gz
rust-c218694cece7c3018b4a809a52a35fcf3716d92e.zip
std::rt: Add libuv bindings for getaddrinfo
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/io/net/mod.rs21
-rw-r--r--src/libstd/rt/uv/addrinfo.rs178
-rw-r--r--src/libstd/rt/uv/mod.rs1
-rw-r--r--src/libstd/rt/uv/net.rs24
-rw-r--r--src/libstd/rt/uv/uvll.rs58
5 files changed, 282 insertions, 0 deletions
diff --git a/src/libstd/rt/io/net/mod.rs b/src/libstd/rt/io/net/mod.rs
new file mode 100644
index 00000000000..8f316364d27
--- /dev/null
+++ b/src/libstd/rt/io/net/mod.rs
@@ -0,0 +1,21 @@
+// 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 rt::io::net::ip::IpAddr;
+
+fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
+    /*!
+     * Get the IP addresses for a given host name.
+     *
+     * Raises io_error on failure.
+     */
+
+    fail!()
+}
diff --git a/src/libstd/rt/uv/addrinfo.rs b/src/libstd/rt/uv/addrinfo.rs
new file mode 100644
index 00000000000..00d1ab5aa9c
--- /dev/null
+++ b/src/libstd/rt/uv/addrinfo.rs
@@ -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();
+    }
+}
diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs
index ea4562068b4..b85b223468e 100644
--- a/src/libstd/rt/uv/mod.rs
+++ b/src/libstd/rt/uv/mod.rs
@@ -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,
diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs
index 3ff6e90e32d..4d54483f47f 100644
--- a/src/libstd/rt/uv/net.rs
+++ b/src/libstd/rt/uv/net.rs
@@ -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),
@@ -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() {
diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs
index d2e3b4176f9..977eae0c269 100644
--- a/src/libstd/rt/uv/uvll.rs
+++ b/src/libstd/rt/uv/uvll.rs
@@ -72,6 +72,7 @@ pub type uv_timer_t = c_void;
 pub type uv_stream_t = c_void;
 pub type uv_fs_t = c_void;
 pub type uv_udp_send_t = c_void;
+pub type uv_getaddrinfo_t = c_void;
 
 #[cfg(stage0)]
 pub type uv_idle_cb = *u8;
@@ -97,6 +98,8 @@ pub type uv_connection_cb = *u8;
 pub type uv_timer_cb = *u8;
 #[cfg(stage0)]
 pub type uv_write_cb = *u8;
+#[cfg(stage0)]
+pub type uv_getaddrinfo_cb = *u8;
 
 #[cfg(not(stage0))]
 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,
 #[cfg(not(stage0))]
 pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
                                      status: c_int);
+#[cfg(not(stage0))]
+pub type uv_getaddrinfo_cb = extern "C" fn(req: *uv_getaddrinfo_t,
+                                           status: c_int,
+                                           res: *addrinfo);
 
 pub type sockaddr = c_void;
 pub type sockaddr_in = c_void;
 pub type sockaddr_in6 = c_void;
 pub type sockaddr_storage = c_void;
 
+#[cfg(unix)]
+pub type socklen_t = c_int;
+
+// XXX: This is a standard C type. Could probably be defined in libc
+#[cfg(unix)]
+pub struct addrinfo {
+    ai_flags: c_int,
+    ai_family: c_int,
+    ai_socktype: c_int,
+    ai_protocol: c_int,
+    ai_addrlen: socklen_t,
+    ai_addr: *sockaddr,
+    ai_canonname: *char,
+    ai_next: *addrinfo
+}
+
+#[cfg(windows)]
+pub struct addrinfo {
+    ai_flags: c_int,
+    ai_family: c_int,
+    ai_socktype: c_int,
+    ai_protocol: c_int,
+    ai_addrlen: size_t,
+    ai_canonname: *char,
+    ai_addr: *sockaddr,
+    ai_next: *addrinfo
+}
+
 #[deriving(Eq)]
 pub enum uv_handle_type {
     UV_UNKNOWN_HANDLE,
@@ -666,6 +701,11 @@ pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t {
 
     rust_uv_get_loop_from_fs_req(req)
 }
+pub unsafe fn get_loop_from_getaddrinfo_req(req: *uv_getaddrinfo_t) -> *uv_loop_t {
+    #[fixed_stack_segment]; #[inline(never)];
+
+    rust_uv_get_loop_from_getaddrinfo_req(req)
+}
 pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
     #[fixed_stack_segment]; #[inline(never)];
 
@@ -721,6 +761,18 @@ pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
 
     return rust_uv_get_len_from_buf(buf);
 }
+pub unsafe fn getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t,
+               getaddrinfo_cb: uv_getaddrinfo_cb,
+               node: *c_char, service: *c_char,
+               hints: *addrinfo) -> c_int {
+    #[fixed_stack_segment]; #[inline(never)];
+    return rust_uv_getaddrinfo(loop_, req, getaddrinfo_cb, node, service, hints);
+}
+pub unsafe fn freeaddrinfo(ai: *addrinfo) {
+    #[fixed_stack_segment]; #[inline(never)];
+    rust_uv_freeaddrinfo(ai);
+}
+
 pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
     let err = last_error(uv_loop);
     let err_ptr = ptr::to_unsafe_ptr(&err);
@@ -845,6 +897,7 @@ extern {
     fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
     fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
     fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;
+    fn rust_uv_get_loop_from_getaddrinfo_req(req: *uv_fs_t) -> *uv_loop_t;
 
     fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t;
     fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t;
@@ -857,4 +910,9 @@ extern {
     fn rust_uv_set_data_for_req(req: *c_void, data: *c_void);
     fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8;
     fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t;
+    fn rust_uv_getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t,
+                           getaddrinfo_cb: uv_getaddrinfo_cb,
+                           node: *c_char, service: *c_char,
+                           hints: *addrinfo) -> c_int;
+    fn rust_uv_freeaddrinfo(ai: *addrinfo);
 }