summary refs log tree commit diff
path: root/src/libstd/io/net/addrinfo.rs
blob: 8d5fd2b99fd7b6e2fdff9997ffe3bb8f0a27a722 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// 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()

*/

#![allow(missing_doc)]

use iter::Iterator;
use io::{IoResult, IoError};
use io::net::ip::{SocketAddr, IpAddr};
use option::{Option, Some, None};
use result::{Ok, Err};
use rt::rtio::{IoFactory, LocalIo};
use rt::rtio;
use vec::Vec;

/// 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 {
    pub family: uint,
    pub socktype: Option<SocketType>,
    pub protocol: Option<Protocol>,
    pub flags: uint,
}

pub struct Info {
    pub address: SocketAddr,
    pub family: uint,
    pub socktype: Option<SocketType>,
    pub protocol: Option<Protocol>,
    pub flags: uint,
}

/// Easy name resolution. Given a hostname, returns the list of IP addresses for
/// that hostname.
pub fn get_host_addresses(host: &str) -> IoResult<Vec<IpAddr>> {
    lookup(Some(host), None, None).map(|a| a.move_iter().map(|i| i.address.ip).collect())
}

/// 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
///
/// FIXME: this is not public because the `Hint` structure is not ready for public
///      consumption just yet.
#[allow(unused_variable)]
fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option<Hint>)
          -> IoResult<Vec<Info>> {
    let hint = hint.map(|Hint { family, socktype, protocol, flags }| {
        rtio::AddrinfoHint {
            family: family,
            socktype: 0, // FIXME: this should use the above variable
            protocol: 0, // FIXME: this should use the above variable
            flags: flags,
        }
    });
    match LocalIo::maybe_raise(|io| {
        io.get_host_addresses(hostname, servname, hint)
    }) {
        Ok(v) => Ok(v.move_iter().map(|info| {
            Info {
                address: SocketAddr {
                    ip: super::from_rtio(info.address.ip),
                    port: info.address.port,
                },
                family: info.family,
                socktype: None, // FIXME: this should use the above variable
                protocol: None, // FIXME: this should use the above variable
                flags: info.flags,
            }
        }).collect()),
        Err(e) => Err(IoError::from_rtio_error(e)),
    }
}

// Ignored on android since we cannot give tcp/ip
// permission without help of apk
#[cfg(test, not(target_os = "android"))]
mod test {
    iotest!(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);
    })

    iotest!(fn issue_10663() {
        // Something should happen here, but this certainly shouldn't cause
        // everything to die. The actual outcome we don't care too much about.
        get_host_addresses("example.com").unwrap();
    } #[ignore])
}