@@ -13,6 +13,7 @@ use std::cast;
13
13
use std:: io:: net:: ip;
14
14
use std:: io;
15
15
use std:: mem;
16
+ use std:: os;
16
17
use std:: ptr;
17
18
use std:: rt:: rtio;
18
19
use std:: sync:: arc:: UnsafeArc ;
@@ -144,6 +145,21 @@ fn last_error() -> io::IoError {
144
145
super :: last_error ( )
145
146
}
146
147
148
+ fn ms_to_timeval ( ms : u64 ) -> libc:: timeval {
149
+ libc:: timeval {
150
+ tv_sec : ( ms / 1000 ) as libc:: time_t ,
151
+ tv_usec : ( ( ms % 1000 ) * 1000 ) as libc:: suseconds_t ,
152
+ }
153
+ }
154
+
155
+ fn timeout ( desc : & ' static str ) -> io:: IoError {
156
+ io:: IoError {
157
+ kind : io:: TimedOut ,
158
+ desc : desc,
159
+ detail : None ,
160
+ }
161
+ }
162
+
147
163
#[ cfg( windows) ] unsafe fn close ( sock : sock_t ) { let _ = libc:: closesocket ( sock) ; }
148
164
#[ cfg( unix) ] unsafe fn close ( sock : sock_t ) { let _ = libc:: close ( sock) ; }
149
165
@@ -271,8 +287,7 @@ impl TcpStream {
271
287
fn connect_timeout ( fd : sock_t ,
272
288
addrp : * libc:: sockaddr ,
273
289
len : libc:: socklen_t ,
274
- timeout : u64 ) -> IoResult < ( ) > {
275
- use std:: os;
290
+ timeout_ms : u64 ) -> IoResult < ( ) > {
276
291
#[ cfg( unix) ] use INPROGRESS = libc:: EINPROGRESS ;
277
292
#[ cfg( windows) ] use INPROGRESS = libc:: WSAEINPROGRESS ;
278
293
#[ cfg( unix) ] use WOULDBLOCK = libc:: EWOULDBLOCK ;
@@ -289,12 +304,8 @@ impl TcpStream {
289
304
os:: errno ( ) as int == WOULDBLOCK as int => {
290
305
let mut set: c:: fd_set = unsafe { mem:: init ( ) } ;
291
306
c:: fd_set ( & mut set, fd) ;
292
- match await ( fd, & mut set, timeout) {
293
- 0 => Err ( io:: IoError {
294
- kind : io:: TimedOut ,
295
- desc : "connection timed out" ,
296
- detail : None ,
297
- } ) ,
307
+ match await ( fd, & mut set, timeout_ms) {
308
+ 0 => Err ( timeout ( "connection timed out" ) ) ,
298
309
-1 => Err ( last_error ( ) ) ,
299
310
_ => {
300
311
let err: libc:: c_int = try!(
@@ -338,22 +349,14 @@ impl TcpStream {
338
349
// Recalculate the timeout each iteration (it is generally
339
350
// undefined what the value of the 'tv' is after select
340
351
// returns EINTR).
341
- let timeout = timeout - ( :: io:: timer:: now ( ) - start) ;
342
- let tv = libc:: timeval {
343
- tv_sec : ( timeout / 1000 ) as libc:: time_t ,
344
- tv_usec : ( ( timeout % 1000 ) * 1000 ) as libc:: suseconds_t ,
345
- } ;
346
- c:: select ( fd + 1 , ptr:: null ( ) , set as * mut _ as * _ ,
347
- ptr:: null ( ) , & tv)
352
+ let tv = ms_to_timeval ( timeout - ( :: io:: timer:: now ( ) - start) ) ;
353
+ c:: select ( fd + 1 , ptr:: null ( ) , & * set, ptr:: null ( ) , & tv)
348
354
} )
349
355
}
350
356
#[ cfg( windows) ]
351
357
fn await ( _fd : sock_t , set : & mut c:: fd_set , timeout : u64 ) -> libc:: c_int {
352
- let tv = libc:: timeval {
353
- tv_sec : ( timeout / 1000 ) as libc:: time_t ,
354
- tv_usec : ( ( timeout % 1000 ) * 1000 ) as libc:: suseconds_t ,
355
- } ;
356
- unsafe { c:: select ( 1 , ptr:: mut_null ( ) , set, ptr:: mut_null ( ) , & tv) }
358
+ let tv = ms_to_timeval ( timeout) ;
359
+ unsafe { c:: select ( 1 , ptr:: null ( ) , & * set, ptr:: null ( ) , & tv) }
357
360
}
358
361
}
359
362
@@ -467,7 +470,7 @@ impl Drop for Inner {
467
470
////////////////////////////////////////////////////////////////////////////////
468
471
469
472
pub struct TcpListener {
470
- inner : UnsafeArc < Inner > ,
473
+ inner : Inner ,
471
474
}
472
475
473
476
impl TcpListener {
@@ -477,7 +480,7 @@ impl TcpListener {
477
480
let ( addr, len) = addr_to_sockaddr ( addr) ;
478
481
let addrp = & addr as * libc:: sockaddr_storage ;
479
482
let inner = Inner { fd : fd } ;
480
- let ret = TcpListener { inner : UnsafeArc :: new ( inner) } ;
483
+ let ret = TcpListener { inner : inner } ;
481
484
// On platforms with Berkeley-derived sockets, this allows
482
485
// to quickly rebind a socket, without needing to wait for
483
486
// the OS to clean up the previous one.
@@ -498,15 +501,12 @@ impl TcpListener {
498
501
}
499
502
}
500
503
501
- pub fn fd ( & self ) -> sock_t {
502
- // This is just a read-only arc so the unsafety is fine
503
- unsafe { ( * self . inner . get ( ) ) . fd }
504
- }
504
+ pub fn fd ( & self ) -> sock_t { self . inner . fd }
505
505
506
506
pub fn native_listen ( self , backlog : int ) -> IoResult < TcpAcceptor > {
507
507
match unsafe { libc:: listen ( self . fd ( ) , backlog as libc:: c_int ) } {
508
508
-1 => Err ( last_error ( ) ) ,
509
- _ => Ok ( TcpAcceptor { listener : self } )
509
+ _ => Ok ( TcpAcceptor { listener : self , deadline : 0 } )
510
510
}
511
511
}
512
512
}
@@ -525,12 +525,16 @@ impl rtio::RtioSocket for TcpListener {
525
525
526
526
pub struct TcpAcceptor {
527
527
listener : TcpListener ,
528
+ deadline : u64 ,
528
529
}
529
530
530
531
impl TcpAcceptor {
531
532
pub fn fd ( & self ) -> sock_t { self . listener . fd ( ) }
532
533
533
534
pub fn native_accept ( & mut self ) -> IoResult < TcpStream > {
535
+ if self . deadline != 0 {
536
+ try!( self . accept_deadline ( ) ) ;
537
+ }
534
538
unsafe {
535
539
let mut storage: libc:: sockaddr_storage = mem:: init ( ) ;
536
540
let storagep = & mut storage as * mut libc:: sockaddr_storage ;
@@ -546,6 +550,25 @@ impl TcpAcceptor {
546
550
}
547
551
}
548
552
}
553
+
554
+ fn accept_deadline ( & mut self ) -> IoResult < ( ) > {
555
+ let mut set: c:: fd_set = unsafe { mem:: init ( ) } ;
556
+ c:: fd_set ( & mut set, self . fd ( ) ) ;
557
+
558
+ match retry ( || {
559
+ // If we're past the deadline, then pass a 0 timeout to select() so
560
+ // we can poll the status of the socket.
561
+ let now = :: io:: timer:: now ( ) ;
562
+ let ms = if self . deadline > now { 0 } else { self . deadline - now} ;
563
+ let tv = ms_to_timeval ( ms) ;
564
+ let n = if cfg ! ( windows) { 1 } else { self . fd ( ) as libc:: c_int + 1 } ;
565
+ unsafe { c:: select ( n, & set, ptr:: null ( ) , ptr:: null ( ) , & tv) }
566
+ } ) {
567
+ -1 => Err ( last_error ( ) ) ,
568
+ 0 => Err ( timeout ( "accept timed out" ) ) ,
569
+ _ => return Ok ( ( ) ) ,
570
+ }
571
+ }
549
572
}
550
573
551
574
impl rtio:: RtioSocket for TcpAcceptor {
@@ -561,6 +584,12 @@ impl rtio::RtioTcpAcceptor for TcpAcceptor {
561
584
562
585
fn accept_simultaneously ( & mut self ) -> IoResult < ( ) > { Ok ( ( ) ) }
563
586
fn dont_accept_simultaneously ( & mut self ) -> IoResult < ( ) > { Ok ( ( ) ) }
587
+ fn set_timeout ( & mut self , timeout : Option < u64 > ) {
588
+ self . deadline = match timeout {
589
+ None => 0 ,
590
+ Some ( t) => :: io:: timer:: now ( ) + t,
591
+ } ;
592
+ }
564
593
}
565
594
566
595
////////////////////////////////////////////////////////////////////////////////
0 commit comments