]> git.lizzy.rs Git - rust.git/blob - src/librustuv/addrinfo.rs
rustuv: Deal with the rtio changes
[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;
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: *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.with_ref(|r| r);
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.with_ref(|r| r);
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: null(),
66                 ai_addr: null(),
67                 ai_next: null(),
68             }
69         });
70         let hint_ptr = hint.as_ref().map_or(null(), |x| x as *libc::addrinfo);
71         let mut req = Request::new(uvll::UV_GETADDRINFO);
72
73         return match unsafe {
74             uvll::uv_getaddrinfo(loop_.handle, req.handle,
75                                  getaddrinfo_cb, c_node_ptr, c_service_ptr,
76                                  hint_ptr)
77         } {
78             0 => {
79                 req.defuse(); // uv callback now owns this request
80                 let mut cx = Ctx { slot: None, status: 0, addrinfo: None };
81
82                 wait_until_woken_after(&mut cx.slot, loop_, || {
83                     req.set_data(&cx);
84                 });
85
86                 match cx.status {
87                     0 => Ok(accum_addrinfo(cx.addrinfo.get_ref())),
88                     n => Err(UvError(n))
89                 }
90             }
91             n => Err(UvError(n))
92         };
93
94
95         extern fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
96                                  status: c_int,
97                                  res: *libc::addrinfo) {
98             let req = Request::wrap(req);
99             assert!(status != uvll::ECANCELED);
100             let cx: &mut Ctx = unsafe { req.get_data() };
101             cx.status = status;
102             cx.addrinfo = Some(Addrinfo { handle: res });
103
104             wakeup(&mut cx.slot);
105         }
106     }
107 }
108
109 impl Drop for Addrinfo {
110     fn drop(&mut self) {
111         unsafe { uvll::uv_freeaddrinfo(self.handle) }
112     }
113 }
114
115 // Traverse the addrinfo linked list, producing a vector of Rust socket addresses
116 pub fn accum_addrinfo(addr: &Addrinfo) -> Vec<rtio::AddrinfoInfo> {
117     unsafe {
118         let mut addr = addr.handle;
119
120         let mut addrs = Vec::new();
121         loop {
122             let rustaddr = net::sockaddr_to_addr(mem::transmute((*addr).ai_addr),
123                                                  (*addr).ai_addrlen as uint);
124
125             addrs.push(rtio::AddrinfoInfo {
126                 address: rustaddr,
127                 family: (*addr).ai_family as uint,
128                 socktype: 0,
129                 protocol: 0,
130                 flags: 0,
131             });
132             if (*addr).ai_next.is_not_null() {
133                 addr = (*addr).ai_next;
134             } else {
135                 break;
136             }
137         }
138
139         addrs
140     }
141 }