@@ -13,6 +13,7 @@ use std::cast;
1313use std:: io:: net:: ip;
1414use std:: io;
1515use std:: mem;
16+ use std:: os;
1617use std:: ptr;
1718use std:: rt:: rtio;
1819use std:: sync:: arc:: UnsafeArc ;
@@ -144,6 +145,21 @@ fn last_error() -> io::IoError {
144145 super :: last_error ( )
145146}
146147
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+
147163#[ cfg( windows) ] unsafe fn close ( sock : sock_t ) { let _ = libc:: closesocket ( sock) ; }
148164#[ cfg( unix) ] unsafe fn close ( sock : sock_t ) { let _ = libc:: close ( sock) ; }
149165
@@ -271,8 +287,7 @@ impl TcpStream {
271287 fn connect_timeout ( fd : sock_t ,
272288 addrp : * libc:: sockaddr ,
273289 len : libc:: socklen_t ,
274- timeout : u64 ) -> IoResult < ( ) > {
275- use std:: os;
290+ timeout_ms : u64 ) -> IoResult < ( ) > {
276291 #[ cfg( unix) ] use INPROGRESS = libc:: EINPROGRESS ;
277292 #[ cfg( windows) ] use INPROGRESS = libc:: WSAEINPROGRESS ;
278293 #[ cfg( unix) ] use WOULDBLOCK = libc:: EWOULDBLOCK ;
@@ -289,12 +304,8 @@ impl TcpStream {
289304 os:: errno ( ) as int == WOULDBLOCK as int => {
290305 let mut set: c:: fd_set = unsafe { mem:: init ( ) } ;
291306 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" ) ) ,
298309 -1 => Err ( last_error ( ) ) ,
299310 _ => {
300311 let err: libc:: c_int = try!(
@@ -338,22 +349,14 @@ impl TcpStream {
338349 // Recalculate the timeout each iteration (it is generally
339350 // undefined what the value of the 'tv' is after select
340351 // 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)
348354 } )
349355 }
350356 #[ cfg( windows) ]
351357 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) }
357360 }
358361 }
359362
@@ -467,7 +470,7 @@ impl Drop for Inner {
467470////////////////////////////////////////////////////////////////////////////////
468471
469472pub struct TcpListener {
470- inner : UnsafeArc < Inner > ,
473+ inner : Inner ,
471474}
472475
473476impl TcpListener {
@@ -477,7 +480,7 @@ impl TcpListener {
477480 let ( addr, len) = addr_to_sockaddr ( addr) ;
478481 let addrp = & addr as * libc:: sockaddr_storage ;
479482 let inner = Inner { fd : fd } ;
480- let ret = TcpListener { inner : UnsafeArc :: new ( inner) } ;
483+ let ret = TcpListener { inner : inner } ;
481484 // On platforms with Berkeley-derived sockets, this allows
482485 // to quickly rebind a socket, without needing to wait for
483486 // the OS to clean up the previous one.
@@ -498,15 +501,12 @@ impl TcpListener {
498501 }
499502 }
500503
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 }
505505
506506 pub fn native_listen ( self , backlog : int ) -> IoResult < TcpAcceptor > {
507507 match unsafe { libc:: listen ( self . fd ( ) , backlog as libc:: c_int ) } {
508508 -1 => Err ( last_error ( ) ) ,
509- _ => Ok ( TcpAcceptor { listener : self } )
509+ _ => Ok ( TcpAcceptor { listener : self , deadline : 0 } )
510510 }
511511 }
512512}
@@ -525,12 +525,16 @@ impl rtio::RtioSocket for TcpListener {
525525
526526pub struct TcpAcceptor {
527527 listener : TcpListener ,
528+ deadline : u64 ,
528529}
529530
530531impl TcpAcceptor {
531532 pub fn fd ( & self ) -> sock_t { self . listener . fd ( ) }
532533
533534 pub fn native_accept ( & mut self ) -> IoResult < TcpStream > {
535+ if self . deadline != 0 {
536+ try!( self . accept_deadline ( ) ) ;
537+ }
534538 unsafe {
535539 let mut storage: libc:: sockaddr_storage = mem:: init ( ) ;
536540 let storagep = & mut storage as * mut libc:: sockaddr_storage ;
@@ -546,6 +550,25 @@ impl TcpAcceptor {
546550 }
547551 }
548552 }
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+ }
549572}
550573
551574impl rtio:: RtioSocket for TcpAcceptor {
@@ -561,6 +584,12 @@ impl rtio::RtioTcpAcceptor for TcpAcceptor {
561584
562585 fn accept_simultaneously ( & mut self ) -> IoResult < ( ) > { Ok ( ( ) ) }
563586 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+ }
564593}
565594
566595////////////////////////////////////////////////////////////////////////////////
0 commit comments