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
14pub 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
29pub struct Passive;
31
32pub 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
80pub 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}