diff options
Diffstat (limited to 'sshconnect.c')
-rw-r--r-- | sshconnect.c | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/sshconnect.c b/sshconnect.c index 32bef7d07..8aac221d3 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -13,7 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include "includes.h" | 15 | #include "includes.h" |
16 | RCSID("$OpenBSD: sshconnect.c,v 1.140 2003/05/14 18:16:21 jakob Exp $"); | 16 | RCSID("$OpenBSD: sshconnect.c,v 1.141 2003/05/15 14:55:25 djm Exp $"); |
17 | 17 | ||
18 | #include <openssl/bn.h> | 18 | #include <openssl/bn.h> |
19 | 19 | ||
@@ -218,6 +218,71 @@ ssh_create_socket(int privileged, struct addrinfo *ai) | |||
218 | return sock; | 218 | return sock; |
219 | } | 219 | } |
220 | 220 | ||
221 | static int | ||
222 | timeout_connect(int sockfd, const struct sockaddr *serv_addr, | ||
223 | socklen_t addrlen, int timeout) | ||
224 | { | ||
225 | fd_set *fdset; | ||
226 | struct timeval tv; | ||
227 | socklen_t optlen; | ||
228 | int fdsetsz, optval, rc; | ||
229 | |||
230 | if (timeout <= 0) | ||
231 | return (connect(sockfd, serv_addr, addrlen)); | ||
232 | |||
233 | if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) | ||
234 | return (-1); | ||
235 | |||
236 | rc = connect(sockfd, serv_addr, addrlen); | ||
237 | if (rc == 0) | ||
238 | return (0); | ||
239 | if (errno != EINPROGRESS) | ||
240 | return (-1); | ||
241 | |||
242 | fdsetsz = howmany(sockfd + 1, NFDBITS) * sizeof(fd_mask); | ||
243 | fdset = (fd_set *)xmalloc(fdsetsz); | ||
244 | |||
245 | memset(fdset, '\0', fdsetsz); | ||
246 | FD_SET(sockfd, fdset); | ||
247 | tv.tv_sec = timeout; | ||
248 | tv.tv_usec = 0; | ||
249 | |||
250 | for(;;) { | ||
251 | rc = select(sockfd + 1, NULL, fdset, NULL, &tv); | ||
252 | if (rc != -1 || errno != EINTR) | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | switch(rc) { | ||
257 | case 0: | ||
258 | /* Timed out */ | ||
259 | errno = ETIMEDOUT; | ||
260 | return (-1); | ||
261 | case -1: | ||
262 | /* Select error */ | ||
263 | debug("select: %s", strerror(errno)); | ||
264 | return (-1); | ||
265 | case 1: | ||
266 | /* Completed or failed */ | ||
267 | optval = 0; | ||
268 | optlen = sizeof(optval); | ||
269 | if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, | ||
270 | &optlen) == -1) | ||
271 | debug("getsockopt: %s", strerror(errno)); | ||
272 | return (-1); | ||
273 | if (optval != 0) { | ||
274 | errno = optval; | ||
275 | return (-1); | ||
276 | } | ||
277 | break; | ||
278 | default: | ||
279 | /* Should not occur */ | ||
280 | fatal("Bogus return (%d) from select()", rc); | ||
281 | } | ||
282 | |||
283 | return (0); | ||
284 | } | ||
285 | |||
221 | /* | 286 | /* |
222 | * Opens a TCP/IP connection to the remote server on the given host. | 287 | * Opens a TCP/IP connection to the remote server on the given host. |
223 | * The address of the remote host will be returned in hostaddr. | 288 | * The address of the remote host will be returned in hostaddr. |
@@ -306,7 +371,8 @@ ssh_connect(const char *host, struct sockaddr_storage * hostaddr, | |||
306 | /* Any error is already output */ | 371 | /* Any error is already output */ |
307 | continue; | 372 | continue; |
308 | 373 | ||
309 | if (connect(sock, ai->ai_addr, ai->ai_addrlen) >= 0) { | 374 | if (timeout_connect(sock, ai->ai_addr, ai->ai_addrlen, |
375 | options.connection_timeout) >= 0) { | ||
310 | /* Successful connection. */ | 376 | /* Successful connection. */ |
311 | memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); | 377 | memcpy(hostaddr, ai->ai_addr, ai->ai_addrlen); |
312 | break; | 378 | break; |