--- /dev/null
+// 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);
+ }
+}
// 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);
- }
-}
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};
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>;
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);
}
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());
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);
getaddrinfo_cb,
c_node_ptr,
c_service_ptr,
- null()));
+ hint_ptr));
}
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 {
}
}
+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)
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::*;
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);
}
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)));
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() {
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");
}
// 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)
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;
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;
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| {
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);
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; }