8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use std:: cast:: transmute;
12
- use std:: cell:: Cell ;
13
- use std:: libc:: { c_int, c_void} ;
14
- use std:: ptr:: null;
15
11
use ai = std:: rt:: io:: net:: addrinfo;
12
+ use std:: libc:: c_int;
13
+ use std:: ptr:: null;
14
+ use std:: rt:: BlockedTask ;
15
+ use std:: rt:: local:: Local ;
16
+ use std:: rt:: sched:: Scheduler ;
16
17
17
- use uvll;
18
- use uvll:: UV_GETADDRINFO ;
19
- use super :: { Loop , UvError , NativeHandle , status_to_maybe_uv_error} ;
20
18
use net;
19
+ use super :: { Loop , UvError , Request , wait_until_woken_after} ;
20
+ use uvll;
21
21
22
- type GetAddrInfoCallback = ~fn ( GetAddrInfoRequest , & net:: UvAddrInfo , Option < UvError > ) ;
23
-
24
- pub struct GetAddrInfoRequest ( * uvll:: uv_getaddrinfo_t ) ;
25
-
26
- pub struct RequestData {
27
- priv getaddrinfo_cb : Option < GetAddrInfoCallback > ,
22
+ struct Addrinfo {
23
+ handle : * uvll:: addrinfo ,
28
24
}
29
25
30
- impl GetAddrInfoRequest {
31
- pub fn new ( ) -> GetAddrInfoRequest {
32
- let req = unsafe { uvll:: malloc_req ( UV_GETADDRINFO ) } ;
33
- assert ! ( req. is_not_null( ) ) ;
34
- let mut req: GetAddrInfoRequest = NativeHandle :: from_native_handle ( req) ;
35
- req. install_req_data ( ) ;
36
- return req;
37
- }
26
+ struct Ctx {
27
+ slot : Option < BlockedTask > ,
28
+ status : c_int ,
29
+ addrinfo : Option < Addrinfo > ,
30
+ }
38
31
39
- pub fn getaddrinfo ( & mut self , loop_ : & Loop , node : Option < & str > ,
40
- service : Option < & str > , hints : Option < ai:: Hint > ,
41
- cb : GetAddrInfoCallback ) {
32
+ pub struct GetAddrInfoRequest ;
42
33
34
+ impl GetAddrInfoRequest {
35
+ pub fn run ( loop_ : & Loop , node : Option < & str > , service : Option < & str > ,
36
+ hints : Option < ai:: Hint > ) -> Result < ~[ ai:: Info ] , UvError > {
43
37
assert ! ( node. is_some( ) || service. is_some( ) ) ;
44
-
45
- let ( c_node, c_node_ptr) = match node {
38
+ let ( _c_node, c_node_ptr) = match node {
46
39
Some ( n) => {
47
40
let c_node = n. to_c_str ( ) ;
48
41
let c_node_ptr = c_node. with_ref ( |r| r) ;
@@ -51,7 +44,7 @@ impl GetAddrInfoRequest {
51
44
None => ( None , null ( ) )
52
45
} ;
53
46
54
- let ( c_service , c_service_ptr) = match service {
47
+ let ( _c_service , c_service_ptr) = match service {
55
48
Some ( s) => {
56
49
let c_service = s. to_c_str ( ) ;
57
50
let c_service_ptr = c_service. with_ref ( |r| r) ;
@@ -60,37 +53,13 @@ impl GetAddrInfoRequest {
60
53
None => ( None , null ( ) )
61
54
} ;
62
55
63
- let cb = Cell :: new ( cb) ;
64
- let wrapper_cb: GetAddrInfoCallback = |req, addrinfo, err| {
65
- // Capture some heap values that need to stay alive for the
66
- // getaddrinfo call
67
- let _ = & c_node;
68
- let _ = & c_service;
69
-
70
- let cb = cb. take ( ) ;
71
- cb ( req, addrinfo, err)
72
- } ;
73
-
74
56
let hint = hints. map ( |hint| {
75
57
let mut flags = 0 ;
76
58
do each_ai_flag |cval, aival| {
77
59
if hint. flags & ( aival as uint ) != 0 {
78
60
flags |= cval as i32 ;
79
61
}
80
62
}
81
- /* XXX: do we really want to support these?
82
- let socktype = match hint.socktype {
83
- Some(ai::Stream) => uvll::rust_SOCK_STREAM(),
84
- Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(),
85
- Some(ai::Raw) => uvll::rust_SOCK_RAW(),
86
- None => 0,
87
- };
88
- let protocol = match hint.protocol {
89
- Some(ai::UDP) => uvll::rust_IPPROTO_UDP(),
90
- Some(ai::TCP) => uvll::rust_IPPROTO_TCP(),
91
- _ => 0,
92
- };
93
- */
94
63
let socktype = 0 ;
95
64
let protocol = 0 ;
96
65
@@ -106,66 +75,48 @@ impl GetAddrInfoRequest {
106
75
}
107
76
} ) ;
108
77
let hint_ptr = hint. as_ref ( ) . map_default ( null ( ) , |x| x as * uvll:: addrinfo ) ;
78
+ let mut req = Request :: new ( uvll:: UV_GETADDRINFO ) ;
79
+
80
+ return match unsafe {
81
+ uvll:: uv_getaddrinfo ( loop_. handle , req. handle ,
82
+ getaddrinfo_cb, c_node_ptr, c_service_ptr,
83
+ hint_ptr)
84
+ } {
85
+ 0 => {
86
+ req. defuse ( ) ; // uv callback now owns this request
87
+ let mut cx = Ctx { slot : None , status : 0 , addrinfo : None } ;
88
+
89
+ do wait_until_woken_after ( & mut cx. slot ) {
90
+ req. set_data ( & cx) ;
91
+ }
109
92
110
- self . get_req_data ( ) . getaddrinfo_cb = Some ( wrapper_cb) ;
111
-
112
- unsafe {
113
- assert ! ( 0 == uvll:: getaddrinfo( loop_. native_handle( ) ,
114
- self . native_handle( ) ,
115
- getaddrinfo_cb,
116
- c_node_ptr,
117
- c_service_ptr,
118
- hint_ptr) ) ;
119
- }
120
-
121
- extern "C" fn getaddrinfo_cb ( req : * uvll:: uv_getaddrinfo_t ,
122
- status : c_int ,
123
- res : * uvll:: addrinfo ) {
124
- let mut req: GetAddrInfoRequest = NativeHandle :: from_native_handle ( req) ;
125
- let err = status_to_maybe_uv_error ( status) ;
126
- let addrinfo = net:: UvAddrInfo ( res) ;
127
- let data = req. get_req_data ( ) ;
128
- ( * data. getaddrinfo_cb . get_ref ( ) ) ( req, & addrinfo, err) ;
129
- unsafe {
130
- uvll:: freeaddrinfo ( res) ;
93
+ match cx. status {
94
+ 0 => Ok ( accum_addrinfo ( cx. addrinfo . get_ref ( ) ) ) ,
95
+ n => Err ( UvError ( n) )
96
+ }
131
97
}
132
- }
133
- }
98
+ n => Err ( UvError ( n ) )
99
+ } ;
134
100
135
- fn get_loop ( & self ) -> Loop {
136
- unsafe {
137
- Loop {
138
- handle : uvll:: get_loop_from_fs_req ( self . native_handle ( ) )
139
- }
140
- }
141
- }
142
101
143
- fn install_req_data ( & mut self ) {
144
- let req = self . native_handle ( ) as * uvll:: uv_getaddrinfo_t ;
145
- let data = ~RequestData {
146
- getaddrinfo_cb : None
147
- } ;
148
- unsafe {
149
- let data = transmute :: < ~RequestData , * c_void > ( data) ;
150
- uvll:: set_data_for_req ( req, data) ;
151
- }
152
- }
102
+ extern fn getaddrinfo_cb ( req : * uvll:: uv_getaddrinfo_t ,
103
+ status : c_int ,
104
+ res : * uvll:: addrinfo ) {
105
+ let req = Request :: wrap ( req) ;
106
+ assert ! ( status != uvll:: ECANCELED ) ;
107
+ let cx: & mut Ctx = unsafe { req. get_data ( ) } ;
108
+ cx. status = status;
109
+ cx. addrinfo = Some ( Addrinfo { handle : res } ) ;
153
110
154
- fn get_req_data < ' r > ( & ' r mut self ) -> & ' r mut RequestData {
155
- unsafe {
156
- let data = uvll:: get_data_for_req ( self . native_handle ( ) ) ;
157
- let data = transmute :: < & * c_void , & mut ~RequestData > ( & data) ;
158
- return & mut * * data;
111
+ let sched: ~Scheduler = Local :: take ( ) ;
112
+ sched. resume_blocked_task_immediately ( cx. slot . take_unwrap ( ) ) ;
159
113
}
160
114
}
115
+ }
161
116
162
- fn delete ( self ) {
163
- unsafe {
164
- let data = uvll:: get_data_for_req ( self . native_handle ( ) ) ;
165
- let _data = transmute :: < * c_void , ~RequestData > ( data) ;
166
- uvll:: set_data_for_req ( self . native_handle ( ) , null :: < ( ) > ( ) ) ;
167
- uvll:: free_req ( self . native_handle ( ) ) ;
168
- }
117
+ impl Drop for Addrinfo {
118
+ fn drop ( & mut self ) {
119
+ unsafe { uvll:: uv_freeaddrinfo ( self . handle ) }
169
120
}
170
121
}
171
122
@@ -184,15 +135,13 @@ fn each_ai_flag(_f: &fn(c_int, ai::Flag)) {
184
135
}
185
136
186
137
// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
187
- pub fn accum_addrinfo( addr : & net :: UvAddrInfo ) -> ~[ ai:: Info ] {
138
+ pub fn accum_addrinfo( addr : & Addrinfo ) -> ~[ ai:: Info ] {
188
139
unsafe {
189
- let & net:: UvAddrInfo ( addr) = addr;
190
- let mut addr = addr;
140
+ let mut addr = addr. handle ;
191
141
192
142
let mut addrs = ~[ ] ;
193
143
loop {
194
- let uvaddr = net:: sockaddr_to_UvSocketAddr ( ( * addr) . ai_addr ) ;
195
- let rustaddr = net:: uv_socket_addr_to_socket_addr ( uvaddr) ;
144
+ let rustaddr = net:: sockaddr_to_socket_addr ( ( * addr) . ai_addr ) ;
196
145
197
146
let mut flags = 0 ;
198
147
do each_ai_flag |cval, aival| {
@@ -235,39 +184,27 @@ pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] {
235
184
}
236
185
}
237
186
238
- impl NativeHandle < * uvll:: uv_getaddrinfo_t > for GetAddrInfoRequest {
239
- fn from_native_handle ( handle : * uvll:: uv_getaddrinfo_t ) -> GetAddrInfoRequest {
240
- GetAddrInfoRequest ( handle)
241
- }
242
- fn native_handle ( & self ) -> * uvll:: uv_getaddrinfo_t {
243
- match self { & GetAddrInfoRequest ( ptr) => ptr }
244
- }
245
- }
246
-
247
187
#[ cfg( test) ]
248
188
mod test {
249
- use Loop ;
250
189
use std:: rt:: io:: net:: ip:: { SocketAddr , Ipv4Addr } ;
251
190
use super :: * ;
191
+ use super :: super :: local_loop;
252
192
253
193
#[ test]
254
194
fn getaddrinfo_test ( ) {
255
- let mut loop_ = Loop :: new ( ) ;
256
- let mut req = GetAddrInfoRequest :: new ( ) ;
257
- do req . getaddrinfo ( & loop_ , Some ( "localhost" ) , None , None ) |_ , addrinfo , _| {
258
- let sockaddrs = accum_addrinfo ( addrinfo ) ;
259
- let mut found_local = false ;
260
- let local_addr = & SocketAddr {
261
- ip : Ipv4Addr ( 127 , 0 , 0 , 1 ) ,
262
- port : 0
263
- } ;
264
- for addr in sockaddrs . iter ( ) {
265
- found_local = found_local || addr . address == * local_addr ;
195
+ match GetAddrInfoRequest :: run ( local_loop ( ) , Some ( "localhost" ) , None , None ) {
196
+ Ok ( infos ) => {
197
+ let mut found_local = false ;
198
+ let local_addr = & SocketAddr {
199
+ ip : Ipv4Addr ( 127 , 0 , 0 , 1 ) ,
200
+ port : 0
201
+ } ;
202
+ for addr in infos . iter ( ) {
203
+ found_local = found_local || addr . address == * local_addr ;
204
+ }
205
+ assert ! ( found_local) ;
266
206
}
267
- assert ! ( found_local ) ;
207
+ Err ( e ) => fail ! ( "{:?}" , e ) ,
268
208
}
269
- loop_. run ( ) ;
270
- loop_. close ( ) ;
271
- req. delete ( ) ;
272
209
}
273
210
}
0 commit comments