]> git.lizzy.rs Git - rust.git/commitdiff
Finish implementing io::net::addrinfo
authorAlex Crichton <alex@alexcrichton.com>
Wed, 16 Oct 2013 03:37:39 +0000 (20:37 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Thu, 24 Oct 2013 21:21:56 +0000 (14:21 -0700)
This fills in the `hints` structure and exposes libuv's full functionality for
doing dns lookups.

src/libstd/rt/io/net/addrinfo.rs [new file with mode: 0644]
src/libstd/rt/io/net/mod.rs
src/libstd/rt/rtio.rs
src/libstd/rt/uv/addrinfo.rs
src/libstd/rt/uv/net.rs
src/libstd/rt/uv/uvio.rs
src/rt/rust_uv.cpp

diff --git a/src/libstd/rt/io/net/addrinfo.rs b/src/libstd/rt/io/net/addrinfo.rs
new file mode 100644 (file)
index 0000000..ae0d542
--- /dev/null
@@ -0,0 +1,127 @@
+// 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.
+
+/*!
+
+Synchronous DNS Resolution
+
+Contains the functionality to perform DNS resolution in a style related to
+getaddrinfo()
+
+*/
+
+use option::{Option, Some, None};
+use result::{Ok, Err};
+use rt::io::io_error;
+use rt::io::net::ip::{SocketAddr, IpAddr};
+use rt::rtio::{IoFactory, IoFactoryObject};
+use rt::local::Local;
+
+/// Hints to the types of sockets that are desired when looking up hosts
+pub enum SocketType {
+    Stream, Datagram, Raw
+}
+
+/// Flags which can be or'd into the `flags` field of a `Hint`. These are used
+/// to manipulate how a query is performed.
+///
+/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo`
+pub enum Flag {
+    AddrConfig,
+    All,
+    CanonName,
+    NumericHost,
+    NumericServ,
+    Passive,
+    V4Mapped,
+}
+
+/// A transport protocol associated with either a hint or a return value of
+/// `lookup`
+pub enum Protocol {
+    TCP, UDP
+}
+
+/// This structure is used to provide hints when fetching addresses for a
+/// remote host to control how the lookup is performed.
+///
+/// For details on these fields, see their corresponding definitions via
+/// `man -s 3 getaddrinfo`
+pub struct Hint {
+    family: uint,
+    socktype: Option<SocketType>,
+    protocol: Option<Protocol>,
+    flags: uint,
+}
+
+pub struct Info {
+    address: SocketAddr,
+    family: uint,
+    socktype: Option<SocketType>,
+    protocol: Option<Protocol>,
+    flags: uint,
+}
+
+/// Easy name resolution. Given a hostname, returns the list of IP addresses for
+/// that hostname.
+///
+/// # Failure
+///
+/// On failure, this will raise on the `io_error` condition.
+pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
+    lookup(Some(host), None, None).map(|a| a.map(|i| i.address.ip))
+}
+
+/// Full-fleged resolution. This function will perform a synchronous call to
+/// getaddrinfo, controlled by the parameters
+///
+/// # Arguments
+///
+/// * hostname - an optional hostname to lookup against
+/// * servname - an optional service name, listed in the system services
+/// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this
+///          controls lookup
+///
+/// # Failure
+///
+/// On failure, this will raise on the `io_error` condition.
+pub fn lookup(hostname: Option<&str>, servname: Option<&str>,
+              hint: Option<Hint>) -> Option<~[Info]> {
+    let ipaddrs = unsafe {
+        let io: *mut IoFactoryObject = Local::unsafe_borrow();
+        (*io).get_host_addresses(hostname, servname, hint)
+    };
+
+    match ipaddrs {
+        Ok(i) => Some(i),
+        Err(ioerr) => {
+            io_error::cond.raise(ioerr);
+            None
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use option::Some;
+    use rt::io::net::ip::Ipv4Addr;
+    use super::*;
+
+    #[test]
+    fn dns_smoke_test() {
+        let ipaddrs = get_host_addresses("localhost").unwrap();
+        let mut found_local = false;
+        let local_addr = &Ipv4Addr(127, 0, 0, 1);
+        for addr in ipaddrs.iter() {
+            found_local = found_local || addr == local_addr;
+        }
+        assert!(found_local);
+    }
+}
index f44e879a63a2aa58a2b822267c70aeebb44e3415..cf109167089d40ca6581ce6bdade64927d65dfc0 100644 (file)
@@ -8,55 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use option::{Option, Some, None};
-use result::{Ok, Err};
-use rt::io::io_error;
-use rt::io::net::ip::IpAddr;
-use rt::rtio::{IoFactory, IoFactoryObject};
-use rt::local::Local;
+pub use self::addrinfo::get_host_addresses;
 
+pub mod addrinfo;
 pub mod tcp;
 pub mod udp;
 pub mod ip;
 #[cfg(unix)]
 pub mod unix;
-
-/// Simplistic name resolution
-pub fn get_host_addresses(host: &str) -> Option<~[IpAddr]> {
-    /*!
-     * Get the IP addresses for a given host name.
-     *
-     * Raises io_error on failure.
-     */
-
-    let ipaddrs = unsafe {
-        let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).get_host_addresses(host)
-    };
-
-    match ipaddrs {
-        Ok(i) => Some(i),
-        Err(ioerr) => {
-            io_error::cond.raise(ioerr);
-            None
-        }
-    }
-}
-
-#[cfg(test)]
-mod test {
-    use option::Some;
-    use rt::io::net::ip::Ipv4Addr;
-    use super::*;
-
-    #[test]
-    fn dns_smoke_test() {
-        let ipaddrs = get_host_addresses("localhost").unwrap();
-        let mut found_local = false;
-        let local_addr = &Ipv4Addr(127, 0, 0, 1);
-        for addr in ipaddrs.iter() {
-            found_local = found_local || addr == local_addr;
-        }
-        assert!(found_local);
-    }
-}
index 0964f94d6d5281026804edca282af882356e064d..4a290ca46e50e196efdf7638cbb8055f373ec146 100644 (file)
@@ -13,6 +13,7 @@
 use result::*;
 use libc::c_int;
 
+use ai = rt::io::net::addrinfo;
 use rt::io::IoError;
 use super::io::process::ProcessConfig;
 use super::io::net::ip::{IpAddr, SocketAddr};
@@ -80,7 +81,8 @@ pub trait IoFactory {
     fn fs_open<P: PathLike>(&mut self, path: &P, fm: FileMode, fa: FileAccess)
         -> Result<~RtioFileStream, IoError>;
     fn fs_unlink<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
-    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>;
     fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError>;
     fn fs_mkdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
     fn fs_rmdir<P: PathLike>(&mut self, path: &P) -> Result<(), IoError>;
index f2abcd3aca7e35a5be7bd2059d76a47c705674fc..7556d7db665efca313d2808b77e6b18014ce6641 100644 (file)
 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 @@ pub fn new() -> 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 @@ pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
             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 @@ pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
                                            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 @@ extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
                                      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 @@ fn delete(self) {
     }
 }
 
+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 @@ fn native_handle(&self) -> *uvll::uv_getaddrinfo_t {
 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 @@ 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 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);
         }
index 2e85900a3f23ca1d1b2ebe106146be9311b80bee..e2f2510c48781cb7a64a3dd6b32b57206cd69688 100644 (file)
@@ -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 @@ pub fn listen(&mut self, cb: ConnectionCallback) -> Result<(), UvError> {
             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 @@ fn native_handle(&self) -> *uvll::uv_udp_t {
 }
 
 // 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)
index 6888aa23e99e7d2980be47794533e96f429b5860..bc9be40cde5630e44ab14e85fd575c548c20c601 100644 (file)
@@ -32,8 +32,8 @@
 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 @@
              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 @@ fn fs_stat<P: PathLike>(&mut self, path: &P) -> Result<FileStat, IoError> {
         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 @@ fn get_host_addresses(&mut self, host: &str) -> Result<~[IpAddr], IoError> {
                 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);
index 3e9b8ba136eaa05e31537fd48a800eba46328e3e..29d0800237b6bc14e6ed6052346ec8aa75ba4fb2 100644 (file)
@@ -637,3 +637,16 @@ extern "C" int
 rust_uv_pipe_init(uv_loop_t *loop, uv_pipe_t* p, int ipc) {
   return uv_pipe_init(loop, p, ipc);
 }
+
+extern "C" int rust_SOCK_STREAM()  { return SOCK_STREAM; }
+extern "C" int rust_SOCK_DGRAM()  { return SOCK_DGRAM; }
+extern "C" int rust_SOCK_RAW()  { return SOCK_RAW; }
+extern "C" int rust_IPPROTO_UDP()  { return IPPROTO_UDP; }
+extern "C" int rust_IPPROTO_TCP()  { return IPPROTO_TCP; }
+extern "C" int rust_AI_ADDRCONFIG()  { return AI_ADDRCONFIG; }
+extern "C" int rust_AI_ALL()  { return AI_ALL; }
+extern "C" int rust_AI_CANONNAME()  { return AI_CANONNAME; }
+extern "C" int rust_AI_NUMERICHOST()  { return AI_NUMERICHOST; }
+extern "C" int rust_AI_NUMERICSERV()  { return AI_NUMERICSERV; }
+extern "C" int rust_AI_PASSIVE()  { return AI_PASSIVE; }
+extern "C" int rust_AI_V4MAPPED()  { return AI_V4MAPPED; }