asyncio/ip/
resolver.rs

1use prelude::{Protocol, SockAddr, Endpoint};
2use ffi::{socket, addrinfo, getaddrinfo, freeaddrinfo};
3use error::host_not_found;
4use core::{IoContext, AsIoContext, Socket};
5use async::Handler;
6use ip::{IpProtocol, IpEndpoint};
7use reactive_io::{AsAsyncFd, connect, async_connect_iterator};
8
9use std::io;
10use std::mem;
11use std::ffi::CString;
12use std::marker::PhantomData;
13
14/// A query to be passed to a resolver.
15pub trait ResolverQuery<P: Protocol> {
16    fn iter(self) -> io::Result<ResolverIter<P>>;
17}
18
19impl<P, N, S> ResolverQuery<P> for (P, N, S)
20    where P: Protocol,
21          N: AsRef<str>,
22          S: AsRef<str>,
23{
24    fn iter(self) -> io::Result<ResolverIter<P>> {
25        ResolverIter::new(&self.0, self.1.as_ref(), self.2.as_ref(), 0)
26    }
27}
28
29/// A query of the resolver for the passive mode.
30pub struct Passive;
31
32/// An iterator over the entries produced by a resolver.
33pub struct ResolverIter<P> {
34    ai: *mut addrinfo,
35    base: *mut addrinfo,
36    _marker: PhantomData<P>,
37}
38
39impl<P> Drop for ResolverIter<P> {
40    fn drop(&mut self) {
41        freeaddrinfo(self.base)
42    }
43}
44
45impl<P: Protocol> ResolverIter<P> {
46    pub fn new(pro: &P, host: &str, port: &str, flags: i32) -> io::Result<ResolverIter<P>> {
47        let host = try!(CString::new(host));
48        let port = try!(CString::new(port));
49        let ai = try!(getaddrinfo(pro, &host, &port, flags));
50        Ok(ResolverIter {
51            ai: ai,
52            base: ai,
53            _marker: PhantomData,
54        })
55    }
56}
57
58impl<P: Protocol> Iterator for ResolverIter<P> {
59    type Item = IpEndpoint<P>;
60
61    fn next(&mut self) -> Option<Self::Item> {
62        while !self.ai.is_null() {
63            unsafe {
64                let ai = &*self.ai;
65                let mut ep = IpEndpoint {
66                    ss: mem::transmute_copy(&*(ai.ai_addr as *const IpEndpoint<P>)),
67                    _marker: PhantomData,
68                };
69                ep.resize(ai.ai_addrlen as usize);
70                self.ai = ai.ai_next;
71                return Some(ep);
72            }
73        }
74        None
75    }
76}
77
78unsafe impl<P> Send for ResolverIter<P> {}
79
80/// An entry produced by a resolver.
81pub struct Resolver<P, S> {
82    ctx: IoContext,
83    _marker: PhantomData<(P, S)>,
84}
85
86impl<P: IpProtocol, S: Socket<P> + AsAsyncFd> Resolver<P, S> {
87    pub fn new(ctx: &IoContext) -> Resolver<P, S> {
88        Resolver {
89            ctx: ctx.clone(),
90            _marker: PhantomData,
91        }
92    }
93
94    pub fn async_connect<Q, F>(&self, query: Q, handler: F) -> F::Output
95        where Q: ResolverQuery<P>,
96              F: Handler<(S, IpEndpoint<P>), io::Error>,
97    {
98        match self.resolve(query) {
99            Ok(it) => async_connect_iterator(&self.ctx, it, handler),
100            Err(err) => handler.result(self.as_ctx(), Err(err)),
101        }
102    }
103
104    pub fn connect<Q>(&self, query: Q) -> io::Result<(S, IpEndpoint<P>)>
105        where Q: ResolverQuery<P>,
106    {
107        for ep in try!(self.resolve(query)) {
108            let pro = ep.protocol();
109            let soc = try!(socket(&pro));
110            let soc = unsafe { S::from_raw_fd(&self.ctx, pro, soc) };
111            if let Ok(_) = connect(&soc, &ep) {
112                return Ok((soc, ep));
113            }
114        }
115        Err(host_not_found())
116    }
117
118    pub fn resolve<Q>(&self, query: Q) -> io::Result<ResolverIter<P>>
119        where Q: ResolverQuery<P>,
120    {
121        query.iter()
122    }
123}
124
125unsafe impl<P, S> AsIoContext for Resolver<P, S> {
126    fn as_ctx(&self) -> &IoContext {
127        &self.ctx
128    }
129}