8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use ai = std:: rt:: io:: net:: addrinfo;
12
- use std:: libc:: c_int;
11
+ use std:: cast:: transmute;
12
+ use std:: cell:: Cell ;
13
+ use std:: libc:: { c_int, c_void} ;
13
14
use std:: ptr:: null;
14
- use std:: rt:: BlockedTask ;
15
- use std:: rt:: local:: Local ;
16
- use std:: rt:: sched:: Scheduler ;
15
+ use ai = std:: rt:: io:: net:: addrinfo;
17
16
18
- use net;
19
- use super :: { Loop , UvError , Request , wait_until_woken_after} ;
20
17
use uvll;
18
+ use uvll:: UV_GETADDRINFO ;
19
+ use super :: { Loop , UvError , NativeHandle , status_to_maybe_uv_error} ;
20
+ use net;
21
21
22
- struct Addrinfo {
23
- handle : * uvll:: addrinfo ,
24
- }
22
+ type GetAddrInfoCallback = ~fn ( GetAddrInfoRequest , & net:: UvAddrInfo , Option < UvError > ) ;
25
23
26
- struct Ctx {
27
- slot : Option < BlockedTask > ,
28
- status : c_int ,
29
- addrinfo : Option < Addrinfo > ,
30
- }
24
+ pub struct GetAddrInfoRequest ( * uvll:: uv_getaddrinfo_t ) ;
31
25
32
- pub struct GetAddrInfoRequest ;
26
+ pub struct RequestData {
27
+ priv getaddrinfo_cb : Option < GetAddrInfoCallback > ,
28
+ }
33
29
34
30
impl GetAddrInfoRequest {
35
- pub fn run ( loop_ : & Loop , node : Option < & str > , service : Option < & str > ,
36
- hints : Option < ai:: Hint > ) -> Result < ~[ ai:: Info ] , UvError > {
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
+ }
38
+
39
+ pub fn getaddrinfo ( & mut self , loop_ : & Loop , node : Option < & str > ,
40
+ service : Option < & str > , hints : Option < ai:: Hint > ,
41
+ cb : GetAddrInfoCallback ) {
42
+
37
43
assert ! ( node. is_some( ) || service. is_some( ) ) ;
38
- let ( _c_node, c_node_ptr) = match node {
44
+
45
+ let ( c_node, c_node_ptr) = match node {
39
46
Some ( n) => {
40
47
let c_node = n. to_c_str ( ) ;
41
48
let c_node_ptr = c_node. with_ref ( |r| r) ;
@@ -44,7 +51,7 @@ impl GetAddrInfoRequest {
44
51
None => ( None , null ( ) )
45
52
} ;
46
53
47
- let ( _c_service , c_service_ptr) = match service {
54
+ let ( c_service , c_service_ptr) = match service {
48
55
Some ( s) => {
49
56
let c_service = s. to_c_str ( ) ;
50
57
let c_service_ptr = c_service. with_ref ( |r| r) ;
@@ -53,13 +60,37 @@ impl GetAddrInfoRequest {
53
60
None => ( None , null ( ) )
54
61
} ;
55
62
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
+
56
74
let hint = hints. map ( |hint| {
57
75
let mut flags = 0 ;
58
76
do each_ai_flag |cval, aival| {
59
77
if hint. flags & ( aival as uint ) != 0 {
60
78
flags |= cval as i32 ;
61
79
}
62
80
}
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
+ */
63
94
let socktype = 0 ;
64
95
let protocol = 0 ;
65
96
@@ -75,48 +106,66 @@ impl GetAddrInfoRequest {
75
106
}
76
107
} ) ;
77
108
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
- }
92
109
93
- match cx. status {
94
- 0 => Ok ( accum_addrinfo ( cx. addrinfo . get_ref ( ) ) ) ,
95
- n => Err ( UvError ( n) )
96
- }
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) ;
97
131
}
98
- n => Err ( UvError ( n ) )
99
- } ;
132
+ }
133
+ }
100
134
135
+ fn get_loop ( & self ) -> Loop {
136
+ unsafe {
137
+ Loop {
138
+ handle : uvll:: get_loop_from_fs_req ( self . native_handle ( ) )
139
+ }
140
+ }
141
+ }
101
142
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 } ) ;
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
+ }
110
153
111
- let sched: ~Scheduler = Local :: take ( ) ;
112
- sched. resume_blocked_task_immediately ( cx. slot . take_unwrap ( ) ) ;
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;
113
159
}
114
160
}
115
- }
116
161
117
- impl Drop for Addrinfo {
118
- fn drop ( & mut self ) {
119
- unsafe { uvll:: uv_freeaddrinfo ( self . handle ) }
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
+ }
120
169
}
121
170
}
122
171
@@ -135,13 +184,15 @@ fn each_ai_flag(_f: &fn(c_int, ai::Flag)) {
135
184
}
136
185
137
186
// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
138
- pub fn accum_addrinfo( addr : & Addrinfo ) -> ~[ ai:: Info ] {
187
+ pub fn accum_addrinfo( addr : & net :: UvAddrInfo ) -> ~[ ai:: Info ] {
139
188
unsafe {
140
- let mut addr = addr. handle ;
189
+ let & net:: UvAddrInfo ( addr) = addr;
190
+ let mut addr = addr;
141
191
142
192
let mut addrs = ~[ ] ;
143
193
loop {
144
- let rustaddr = net:: sockaddr_to_socket_addr ( ( * addr) . ai_addr ) ;
194
+ let uvaddr = net:: sockaddr_to_UvSocketAddr ( ( * addr) . ai_addr ) ;
195
+ let rustaddr = net:: uv_socket_addr_to_socket_addr ( uvaddr) ;
145
196
146
197
let mut flags = 0 ;
147
198
do each_ai_flag |cval, aival| {
@@ -184,27 +235,39 @@ pub fn accum_addrinfo(addr: &Addrinfo) -> ~[ai::Info] {
184
235
}
185
236
}
186
237
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
+
187
247
#[ cfg( test) ]
188
248
mod test {
249
+ use Loop ;
189
250
use std:: rt:: io:: net:: ip:: { SocketAddr , Ipv4Addr } ;
190
251
use super :: * ;
191
- use super :: super :: local_loop;
192
252
193
253
#[ test]
194
254
fn getaddrinfo_test ( ) {
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) ;
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 ;
206
266
}
207
- Err ( e ) => fail ! ( "{:?}" , e ) ,
267
+ assert ! ( found_local ) ;
208
268
}
269
+ loop_. run ( ) ;
270
+ loop_. close ( ) ;
271
+ req. delete ( ) ;
209
272
}
210
273
}
0 commit comments