@@ -17,7 +17,8 @@ use str;
1717use sys:: fd:: FileDesc ;
1818use sys_common:: { AsInner , FromInner , IntoInner } ;
1919use sys_common:: net:: { getsockopt, setsockopt, sockaddr_to_addr} ;
20- use time:: Duration ;
20+ use time:: { Duration , Instant } ;
21+ use cmp;
2122
2223pub use sys:: { cvt, cvt_r} ;
2324pub extern crate libc as netc;
@@ -122,6 +123,70 @@ impl Socket {
122123 }
123124 }
124125
126+ pub fn connect_timeout ( & self , addr : & SocketAddr , timeout : Duration ) -> io:: Result < ( ) > {
127+ self . set_nonblocking ( true ) ?;
128+ let r = unsafe {
129+ let ( addrp, len) = addr. into_inner ( ) ;
130+ cvt ( libc:: connect ( self . 0 . raw ( ) , addrp, len) )
131+ } ;
132+ self . set_nonblocking ( false ) ?;
133+
134+ match r {
135+ Ok ( _) => return Ok ( ( ) ) ,
136+ // there's no ErrorKind for EINPROGRESS :(
137+ Err ( ref e) if e. raw_os_error ( ) == Some ( libc:: EINPROGRESS ) => { }
138+ Err ( e) => return Err ( e) ,
139+ }
140+
141+ let mut pollfd = libc:: pollfd {
142+ fd : self . 0 . raw ( ) ,
143+ events : libc:: POLLOUT ,
144+ revents : 0 ,
145+ } ;
146+
147+ if timeout. as_secs ( ) == 0 && timeout. subsec_nanos ( ) == 0 {
148+ return Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput ,
149+ "cannot set a 0 duration timeout" ) ) ;
150+ }
151+
152+ let start = Instant :: now ( ) ;
153+
154+ loop {
155+ let elapsed = start. elapsed ( ) ;
156+ if elapsed >= timeout {
157+ return Err ( io:: Error :: new ( io:: ErrorKind :: TimedOut , "connection timed out" ) ) ;
158+ }
159+
160+ let timeout = timeout - elapsed;
161+ let mut timeout = timeout. as_secs ( )
162+ . saturating_mul ( 1_000 )
163+ . saturating_add ( timeout. subsec_nanos ( ) as u64 / 1_000_000 ) ;
164+ if timeout == 0 {
165+ timeout = 1 ;
166+ }
167+
168+ let timeout = cmp:: min ( timeout, c_int:: max_value ( ) as u64 ) as c_int ;
169+
170+ match unsafe { libc:: poll ( & mut pollfd, 1 , timeout) } {
171+ -1 => {
172+ let err = io:: Error :: last_os_error ( ) ;
173+ if err. kind ( ) != io:: ErrorKind :: Interrupted {
174+ return Err ( err) ;
175+ }
176+ }
177+ 0 => { }
178+ _ => {
179+ if pollfd. revents & libc:: POLLOUT == 0 {
180+ if let Some ( e) = self . take_error ( ) ? {
181+ return Err ( e) ;
182+ }
183+ }
184+ return Ok ( ( ) ) ;
185+ }
186+ }
187+ }
188+ }
189+
125190 pub fn accept ( & self , storage : * mut sockaddr , len : * mut socklen_t )
126191 -> io:: Result < Socket > {
127192 // Unfortunately the only known way right now to accept a socket and
0 commit comments