@@ -17,7 +17,8 @@ use str;
17
17
use sys:: fd:: FileDesc ;
18
18
use sys_common:: { AsInner , FromInner , IntoInner } ;
19
19
use sys_common:: net:: { getsockopt, setsockopt, sockaddr_to_addr} ;
20
- use time:: Duration ;
20
+ use time:: { Duration , Instant } ;
21
+ use cmp;
21
22
22
23
pub use sys:: { cvt, cvt_r} ;
23
24
pub extern crate libc as netc;
@@ -122,6 +123,70 @@ impl Socket {
122
123
}
123
124
}
124
125
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
+
125
190
pub fn accept ( & self , storage : * mut sockaddr , len : * mut socklen_t )
126
191
-> io:: Result < Socket > {
127
192
// Unfortunately the only known way right now to accept a socket and
0 commit comments