about summary refs log tree commit diff
path: root/src/libstd/rt/uv
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-15 20:37:39 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-10-24 14:21:56 -0700
commit1db783bdcf05954e066adf6cefbbc5ac72e13173 (patch)
tree3452ba6c392a17b576c8a4c91807e1fb12a68ce7 /src/libstd/rt/uv
parentbac96818580a97c049532e50702c2a8204e11754 (diff)
Finish implementing io::net::addrinfo
This fills in the `hints` structure and exposes libuv's full functionality for
doing dns lookups.
Diffstat (limited to 'src/libstd/rt/uv')
-rw-r--r--src/libstd/rt/uv/addrinfo.rs109
-rw-r--r--src/libstd/rt/uv/net.rs32
-rw-r--r--src/libstd/rt/uv/uvio.rs21
3 files changed, 117 insertions, 45 deletions
diff --git a/src/libstd/rt/uv/addrinfo.rs b/src/libstd/rt/uv/addrinfo.rs
index f2abcd3aca7..7556d7db665 100644
--- a/src/libstd/rt/uv/addrinfo.rs
+++ b/src/libstd/rt/uv/addrinfo.rs
@@ -18,9 +18,10 @@ use rt::uv::uvll;
 use rt::uv::uvll::UV_GETADDRINFO;
 use rt::uv::{Loop, UvError, NativeHandle};
 use rt::uv::status_to_maybe_uv_error;
-use rt::uv::net::UvAddrInfo;
+use rt::uv::net;
+use ai = rt::io::net::addrinfo;
 
-type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &UvAddrInfo, Option<UvError>);
+type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &net::UvAddrInfo, Option<UvError>);
 
 pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);
 
@@ -38,7 +39,7 @@ impl GetAddrInfoRequest {
     }
 
     pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
-                       service: Option<&str>, hints: Option<UvAddrInfo>,
+                       service: Option<&str>, hints: Option<ai::Hint>,
                        cb: GetAddrInfoCallback) {
 
         assert!(node.is_some() || service.is_some());
@@ -72,8 +73,37 @@ impl GetAddrInfoRequest {
             cb(req, addrinfo, err)
         };
 
-        // XXX: Implement hints
-        assert!(hints.is_none());
+        let hint = hints.map(|hint| unsafe {
+            let mut flags = 0;
+            do each_ai_flag |cval, aival| {
+                if hint.flags & (aival as uint) != 0 {
+                    flags |= cval as i32;
+                }
+            }
+            let socktype = match hint.socktype {
+                Some(ai::Stream) => uvll::rust_SOCK_STREAM(),
+                Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(),
+                Some(ai::Raw) => uvll::rust_SOCK_RAW(),
+                None => 0,
+            };
+            let protocol = match hint.protocol {
+                Some(ai::UDP) => uvll::rust_IPPROTO_UDP(),
+                Some(ai::TCP) => uvll::rust_IPPROTO_TCP(),
+                _ => 0,
+            };
+
+            uvll::addrinfo {
+                ai_flags: flags,
+                ai_family: hint.family as c_int,
+                ai_socktype: socktype,
+                ai_protocol: protocol,
+                ai_addrlen: 0,
+                ai_canonname: null(),
+                ai_addr: null(),
+                ai_next: null(),
+            }
+        });
+        let hint_ptr = hint.as_ref().map_default(null(), |x| x as *uvll::addrinfo);
 
         self.get_req_data().getaddrinfo_cb = Some(wrapper_cb);
 
@@ -83,7 +113,7 @@ impl GetAddrInfoRequest {
                                            getaddrinfo_cb,
                                            c_node_ptr,
                                            c_service_ptr,
-                                           null()));
+                                           hint_ptr));
         }
 
         extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
@@ -91,7 +121,7 @@ impl GetAddrInfoRequest {
                                      res: *uvll::addrinfo) {
             let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
             let err = status_to_maybe_uv_error(status);
-            let addrinfo = UvAddrInfo(res);
+            let addrinfo = net::UvAddrInfo(res);
             let data = req.get_req_data();
             (*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err);
             unsafe {
@@ -137,6 +167,66 @@ impl GetAddrInfoRequest {
     }
 }
 
+fn each_ai_flag(f: &fn(c_int, ai::Flag)) {
+    unsafe {
+        f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig);
+        f(uvll::rust_AI_ALL(), ai::All);
+        f(uvll::rust_AI_CANONNAME(), ai::CanonName);
+        f(uvll::rust_AI_NUMERICHOST(), ai::NumericHost);
+        f(uvll::rust_AI_NUMERICSERV(), ai::NumericServ);
+        f(uvll::rust_AI_PASSIVE(), ai::Passive);
+        f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped);
+    }
+}
+
+// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
+pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] {
+    unsafe {
+        let &net::UvAddrInfo(addr) = addr;
+        let mut addr = addr;
+
+        let mut addrs = ~[];
+        loop {
+            let uvaddr = net::sockaddr_to_UvSocketAddr((*addr).ai_addr);
+            let rustaddr = net::uv_socket_addr_to_socket_addr(uvaddr);
+
+            let mut flags = 0;
+            do each_ai_flag |cval, aival| {
+                if (*addr).ai_flags & cval != 0 {
+                    flags |= aival as uint;
+                }
+            }
+
+            let protocol = match (*addr).ai_protocol {
+                p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP),
+                p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP),
+                _ => None,
+            };
+            let socktype = match (*addr).ai_socktype {
+                p if p == uvll::rust_SOCK_STREAM() => Some(ai::Stream),
+                p if p == uvll::rust_SOCK_DGRAM() => Some(ai::Datagram),
+                p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw),
+                _ => None,
+            };
+
+            addrs.push(ai::Info {
+                address: rustaddr,
+                family: (*addr).ai_family as uint,
+                socktype: socktype,
+                protocol: protocol,
+                flags: flags,
+            });
+            if (*addr).ai_next.is_not_null() {
+                addr = (*addr).ai_next;
+            } else {
+                break;
+            }
+        }
+
+        return addrs;
+    }
+}
+
 impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
     fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest {
         GetAddrInfoRequest(handle)
@@ -150,7 +240,6 @@ impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
 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::*;
 
@@ -159,14 +248,14 @@ mod 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 sockaddrs = accum_addrinfo(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;
+                found_local = found_local || addr.address == *local_addr;
             }
             assert!(found_local);
         }
diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs
index 2e85900a3f2..e2f2510c487 100644
--- a/src/libstd/rt/uv/net.rs
+++ b/src/libstd/rt/uv/net.rs
@@ -27,7 +27,7 @@ pub enum UvSocketAddr {
     UvIpv6SocketAddr(*sockaddr_in6),
 }
 
-fn sockaddr_to_UvSocketAddr(addr: *uvll::sockaddr) -> UvSocketAddr {
+pub fn sockaddr_to_UvSocketAddr(addr: *uvll::sockaddr) -> UvSocketAddr {
     unsafe {
         assert!((is_ip4_addr(addr) || is_ip6_addr(addr)));
         assert!(!(is_ip4_addr(addr) && is_ip6_addr(addr)));
@@ -96,28 +96,6 @@ 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() {
@@ -232,13 +210,13 @@ impl StreamWatcher {
             data.connect_cb = Some(cb);
         }
 
-        unsafe {
+        return unsafe {
             static BACKLOG: c_int = 128; // XXX should be configurable
             match uvll::listen(self.native_handle(), BACKLOG, connection_cb) {
                 0 => Ok(()),
                 n => Err(UvError(n))
             }
-        }
+        };
 
         extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) {
             rtdebug!("connection_cb");
@@ -466,12 +444,12 @@ impl NativeHandle<*uvll::uv_udp_t> for UdpWatcher {
 }
 
 // uv_connect_t is a subclass of uv_req_t
-struct ConnectRequest(*uvll::uv_connect_t);
+pub struct ConnectRequest(*uvll::uv_connect_t);
 impl Request for ConnectRequest { }
 
 impl ConnectRequest {
 
-    fn new() -> ConnectRequest {
+    pub fn new() -> ConnectRequest {
         let connect_handle = unsafe { malloc_req(UV_CONNECT) };
         assert!(connect_handle.is_not_null());
         ConnectRequest(connect_handle as *uvll::uv_connect_t)
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index 6888aa23e99..bc9be40cde5 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -32,8 +32,8 @@ use rt::tube::Tube;
 use rt::task::SchedHome;
 use rt::uv::*;
 use rt::uv::idle::IdleWatcher;
-use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr, accum_sockaddrs};
-use rt::uv::addrinfo::GetAddrInfoRequest;
+use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr};
+use rt::uv::addrinfo::{GetAddrInfoRequest, accum_addrinfo};
 use unstable::sync::Exclusive;
 use path::{GenericPath, Path};
 use super::super::io::support::PathLike;
@@ -43,6 +43,7 @@ use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create,
              CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite,
              FileStat};
 use task;
+use ai = rt::io::net::addrinfo;
 
 #[cfg(test)] use container::Container;
 #[cfg(test)] use unstable::run_in_bare_thread;
@@ -658,12 +659,16 @@ impl IoFactory for UvIoFactory {
         return result_cell.take();
     }
 
-    fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError> {
+    fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
+                          hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError> {
         let result_cell = Cell::new_empty();
-        let result_cell_ptr: *Cell<Result<~[IpAddr], IoError>> = &result_cell;
-        let host_ptr: *&str = &host;
+        let result_cell_ptr: *Cell<Result<~[ai::Info], IoError>> = &result_cell;
+        let host_ptr: *Option<&str> = &host;
+        let servname_ptr: *Option<&str> = &servname;
+        let hint_ptr: *Option<ai::Hint> = &hint;
         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| {
@@ -671,10 +676,10 @@ impl IoFactory for UvIoFactory {
                 let mut addrinfo_req = addrinfo_req_cell.take();
                 unsafe {
                     do addrinfo_req.getaddrinfo(self.uv_loop(),
-                                                Some(*host_ptr),
-                                                None, None) |_, addrinfo, err| {
+                                                *host_ptr, *servname_ptr,
+                                                *hint_ptr) |_, addrinfo, err| {
                         let res = match err {
-                            None => Ok(accum_sockaddrs(addrinfo).map(|addr| addr.ip.clone())),
+                            None => Ok(accum_addrinfo(addrinfo)),
                             Some(err) => Err(uv_error_to_io_error(err))
                         };
                         (*result_cell_ptr).put_back(res);