]> git.lizzy.rs Git - rust.git/blob - src/librustuv/addrinfo.rs
Doc says to avoid mixing allocator instead of forbiding it
[rust.git] / src / librustuv / addrinfo.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use libc::c_int;
12 use libc;
13 use std::mem;
14 use std::ptr::{null, mut_null};
15 use std::rt::task::BlockedTask;
16 use std::rt::rtio;
17
18 use net;
19 use super::{Loop, UvError, Request, wait_until_woken_after, wakeup};
20 use uvll;
21
22 struct Addrinfo {
23     handle: *const libc::addrinfo,
24 }
25
26 struct Ctx {
27     slot: Option<BlockedTask>,
28     status: c_int,
29     addrinfo: Option<Addrinfo>,
30 }
31
32 pub struct GetAddrInfoRequest;
33
34 impl GetAddrInfoRequest {
35     pub fn run(loop_: &Loop, node: Option<&str>, service: Option<&str>,
36                hints: Option<rtio::AddrinfoHint>)
37         -> Result<Vec<rtio::AddrinfoInfo>, UvError>
38     {
39         assert!(node.is_some() || service.is_some());
40         let (_c_node, c_node_ptr) = match node {
41             Some(n) => {
42                 let c_node = n.to_c_str();
43                 let c_node_ptr = c_node.as_ptr();
44                 (Some(c_node), c_node_ptr)
45             }
46             None => (None, null())
47         };
48
49         let (_c_service, c_service_ptr) = match service {
50             Some(s) => {
51                 let c_service = s.to_c_str();
52                 let c_service_ptr = c_service.as_ptr();
53                 (Some(c_service), c_service_ptr)
54             }
55             None => (None, null())
56         };
57
58         let hint = hints.map(|hint| {
59             libc::addrinfo {
60                 ai_flags: 0,
61                 ai_family: hint.family as c_int,
62                 ai_socktype: 0,
63                 ai_protocol: 0,
64                 ai_addrlen: 0,
65                 ai_canonname: mut_null(),
66                 ai_addr: mut_null(),
67                 ai_next: mut_null(),
68             }
69         });
70         let hint_ptr = hint.as_ref().map_or(null(), |x| {
71             x as *const libc::addrinfo
72         });
73         let mut req = Request::new(uvll::UV_GETADDRINFO);
74
75         return match unsafe {
76             uvll::uv_getaddrinfo(loop_.handle, req.handle,
77                                  getaddrinfo_cb, c_node_ptr, c_service_ptr,
78                                  hint_ptr)
79         } {
80             0 => {
81                 req.defuse(); // uv callback now owns this request
82                 let mut cx = Ctx { slot: None, status: 0, addrinfo: None };
83
84                 wait_until_woken_after(&mut cx.slot, loop_, || {
85                     req.set_data(&mut cx);
86                 });
87
88                 match cx.status {
89                     0 => Ok(accum_addrinfo(cx.addrinfo.as_ref().unwrap())),
90                     n => Err(UvError(n))
91                 }
92             }
93             n => Err(UvError(n))
94         };
95
96
97         extern fn getaddrinfo_cb(req: *mut uvll::uv_getaddrinfo_t,
98                                  status: c_int,
99                                  res: *const libc::addrinfo) {
100             let req = Request::wrap(req);
101             assert!(status != uvll::ECANCELED);
102             let cx: &mut Ctx = unsafe { req.get_data() };
103             cx.status = status;
104             cx.addrinfo = Some(Addrinfo { handle: res });
105
106             wakeup(&mut cx.slot);
107         }
108     }
109 }
110
111 impl Drop for Addrinfo {
112     fn drop(&mut self) {
113         unsafe { uvll::uv_freeaddrinfo(self.handle as *mut _) }
114     }
115 }
116
117 // Traverse the addrinfo linked list, producing a vector of Rust socket addresses
118 pub fn accum_addrinfo(addr: &Addrinfo) -> Vec<rtio::AddrinfoInfo> {
119     unsafe {
120         let mut addr = addr.handle;
121
122         let mut addrs = Vec::new();
123         loop {
124             let rustaddr = net::sockaddr_to_addr(mem::transmute((*addr).ai_addr),
125                                                  (*addr).ai_addrlen as uint);
126
127             addrs.push(rtio::AddrinfoInfo {
128                 address: rustaddr,
129                 family: (*addr).ai_family as uint,
130                 socktype: 0,
131                 protocol: 0,
132                 flags: 0,
133             });
134             if (*addr).ai_next.is_not_null() {
135                 addr = (*addr).ai_next as *const _;
136             } else {
137                 break;
138             }
139         }
140
141         addrs
142     }
143 }