@@ -20,6 +20,7 @@ use str::from_utf8;
20
20
use sys:: c;
21
21
use sys:: net:: { cvt, cvt_r, cvt_gai, Socket , init, wrlen_t} ;
22
22
use sys_common:: { AsInner , FromInner , IntoInner } ;
23
+ use time:: Duration ;
23
24
24
25
////////////////////////////////////////////////////////////////////////////////
25
26
// sockaddr and misc bindings
@@ -35,16 +36,15 @@ fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
35
36
}
36
37
}
37
38
38
- #[ allow( dead_code) ]
39
39
fn getsockopt < T : Copy > ( sock : & Socket , opt : c_int ,
40
40
val : c_int ) -> io:: Result < T > {
41
41
unsafe {
42
42
let mut slot: T = mem:: zeroed ( ) ;
43
43
let mut len = mem:: size_of :: < T > ( ) as socklen_t ;
44
- let ret = try!( cvt ( c:: getsockopt ( * sock. as_inner ( ) , opt, val,
45
- & mut slot as * mut _ as * mut _ ,
46
- & mut len) ) ) ;
47
- assert_eq ! ( ret as usize , mem:: size_of:: <T >( ) ) ;
44
+ try!( cvt ( c:: getsockopt ( * sock. as_inner ( ) , opt, val,
45
+ & mut slot as * mut _ as * mut _ ,
46
+ & mut len) ) ) ;
47
+ assert_eq ! ( len as usize , mem:: size_of:: <T >( ) ) ;
48
48
Ok ( slot)
49
49
}
50
50
}
@@ -163,6 +163,92 @@ pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
163
163
}
164
164
}
165
165
166
+ ////////////////////////////////////////////////////////////////////////////////
167
+ // Timeouts
168
+ ////////////////////////////////////////////////////////////////////////////////
169
+
170
+ #[ cfg( target_os = "windows" ) ]
171
+ fn set_timeout ( socket : & Socket , dur : Option < Duration > , kind : libc:: c_int ) -> io:: Result < ( ) > {
172
+ let timeout = match dur {
173
+ Some ( dur) => {
174
+ if dur. secs ( ) == 0 && dur. extra_nanos ( ) == 0 {
175
+ return Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput ,
176
+ "cannot set a 0 duration timeout" ) ) ;
177
+ }
178
+
179
+ let mut timeout = if dur. secs ( ) > ( libc:: DWORD :: max_value ( ) / 1000 ) as u64 {
180
+ libc:: DWORD :: max_value ( )
181
+ } else {
182
+ ( dur. secs ( ) * 1000 ) as libc:: DWORD
183
+ } ;
184
+ timeout = timeout. saturating_add ( ( dur. extra_nanos ( ) / 1000000 ) as libc:: DWORD ) ;
185
+ if timeout == 0 {
186
+ timeout = 1 ;
187
+ }
188
+ timeout
189
+ }
190
+ None => 0
191
+ } ;
192
+ setsockopt ( socket, libc:: SOL_SOCKET , kind, timeout)
193
+ }
194
+
195
+ #[ cfg( not( target_os = "windows" ) ) ]
196
+ fn set_timeout ( socket : & Socket , dur : Option < Duration > , kind : libc:: c_int ) -> io:: Result < ( ) > {
197
+ let timeout = match dur {
198
+ Some ( dur) => {
199
+ if dur. secs ( ) == 0 && dur. extra_nanos ( ) == 0 {
200
+ return Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput ,
201
+ "cannot set a 0 duration timeout" ) ) ;
202
+ }
203
+
204
+ let secs = if dur. secs ( ) > libc:: time_t:: max_value ( ) as u64 {
205
+ libc:: time_t:: max_value ( )
206
+ } else {
207
+ dur. secs ( ) as libc:: time_t
208
+ } ;
209
+ let mut timeout = libc:: timeval {
210
+ tv_sec : secs,
211
+ tv_usec : ( dur. extra_nanos ( ) / 1000 ) as libc:: time_t ,
212
+ } ;
213
+ if timeout. tv_sec == 0 && timeout. tv_usec == 0 {
214
+ timeout. tv_usec = 1 ;
215
+ }
216
+ timeout
217
+ }
218
+ None => {
219
+ libc:: timeval {
220
+ tv_sec : 0 ,
221
+ tv_usec : 0 ,
222
+ }
223
+ }
224
+ } ;
225
+ setsockopt ( socket, libc:: SOL_SOCKET , kind, timeout)
226
+ }
227
+
228
+ #[ cfg( target_os = "windows" ) ]
229
+ fn timeout ( socket : & Socket , kind : libc:: c_int ) -> io:: Result < Option < Duration > > {
230
+ let raw: libc:: DWORD = try!( getsockopt ( socket, libc:: SOL_SOCKET , kind) ) ;
231
+ if raw == 0 {
232
+ Ok ( None )
233
+ } else {
234
+ let secs = raw / 1000 ;
235
+ let nsec = ( raw % 1000 ) * 1000000 ;
236
+ Ok ( Some ( Duration :: new ( secs as u64 , nsec as u32 ) ) )
237
+ }
238
+ }
239
+
240
+ #[ cfg( not( target_os = "windows" ) ) ]
241
+ fn timeout ( socket : & Socket , kind : libc:: c_int ) -> io:: Result < Option < Duration > > {
242
+ let raw: libc:: timeval = try!( getsockopt ( socket, libc:: SOL_SOCKET , kind) ) ;
243
+ if raw. tv_sec == 0 && raw. tv_usec == 0 {
244
+ Ok ( None )
245
+ } else {
246
+ let sec = raw. tv_sec as u64 ;
247
+ let nsec = ( raw. tv_usec as u32 ) * 1000 ;
248
+ Ok ( Some ( Duration :: new ( sec, nsec) ) )
249
+ }
250
+ }
251
+
166
252
////////////////////////////////////////////////////////////////////////////////
167
253
// TCP streams
168
254
////////////////////////////////////////////////////////////////////////////////
@@ -220,6 +306,22 @@ impl TcpStream {
220
306
Ok ( ( ) )
221
307
}
222
308
309
+ pub fn set_read_timeout ( & self , dur : Option < Duration > ) -> io:: Result < ( ) > {
310
+ set_timeout ( & self . inner , dur, libc:: SO_RCVTIMEO )
311
+ }
312
+
313
+ pub fn set_write_timeout ( & self , dur : Option < Duration > ) -> io:: Result < ( ) > {
314
+ set_timeout ( & self . inner , dur, libc:: SO_SNDTIMEO )
315
+ }
316
+
317
+ pub fn read_timeout ( & self ) -> io:: Result < Option < Duration > > {
318
+ timeout ( & self . inner , libc:: SO_RCVTIMEO )
319
+ }
320
+
321
+ pub fn write_timeout ( & self ) -> io:: Result < Option < Duration > > {
322
+ timeout ( & self . inner , libc:: SO_SNDTIMEO )
323
+ }
324
+
223
325
pub fn read ( & self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
224
326
self . inner . read ( buf)
225
327
}
@@ -471,6 +573,22 @@ impl UdpSocket {
471
573
pub fn duplicate ( & self ) -> io:: Result < UdpSocket > {
472
574
self . inner . duplicate ( ) . map ( |s| UdpSocket { inner : s } )
473
575
}
576
+
577
+ pub fn set_read_timeout ( & self , dur : Option < Duration > ) -> io:: Result < ( ) > {
578
+ set_timeout ( & self . inner , dur, libc:: SO_RCVTIMEO )
579
+ }
580
+
581
+ pub fn set_write_timeout ( & self , dur : Option < Duration > ) -> io:: Result < ( ) > {
582
+ set_timeout ( & self . inner , dur, libc:: SO_SNDTIMEO )
583
+ }
584
+
585
+ pub fn read_timeout ( & self ) -> io:: Result < Option < Duration > > {
586
+ timeout ( & self . inner , libc:: SO_RCVTIMEO )
587
+ }
588
+
589
+ pub fn write_timeout ( & self ) -> io:: Result < Option < Duration > > {
590
+ timeout ( & self . inner , libc:: SO_SNDTIMEO )
591
+ }
474
592
}
475
593
476
594
impl FromInner < Socket > for UdpSocket {
0 commit comments