version 1.281, 2017/06/24 05:35:05 |
version 1.282, 2017/06/24 05:37:44 |
|
|
#include <fcntl.h> |
#include <fcntl.h> |
#include <netdb.h> |
#include <netdb.h> |
#include <paths.h> |
#include <paths.h> |
|
#include <poll.h> |
#include <signal.h> |
#include <signal.h> |
#include <pwd.h> |
#include <pwd.h> |
#include <stdio.h> |
#include <stdio.h> |
|
|
return sock; |
return sock; |
} |
} |
|
|
|
/* |
|
* Wait up to *timeoutp milliseconds for fd to be readable. Updates |
|
* *timeoutp with time remaining. |
|
* Returns 0 if fd ready or -1 on timeout or error (see errno). |
|
*/ |
static int |
static int |
timeout_connect(int sockfd, const struct sockaddr *serv_addr, |
waitrfd(int fd, int *timeoutp) |
socklen_t addrlen, int *timeoutp) |
|
{ |
{ |
fd_set *fdset; |
struct pollfd pfd; |
struct timeval tv, t_start; |
struct timeval t_start; |
socklen_t optlen; |
int oerrno, r; |
int optval, rc, result = -1; |
|
|
|
gettimeofday(&t_start, NULL); |
gettimeofday(&t_start, NULL); |
|
pfd.fd = fd; |
if (*timeoutp <= 0) { |
pfd.events = POLLIN; |
result = connect(sockfd, serv_addr, addrlen); |
for (; *timeoutp >= 0;) { |
goto done; |
r = poll(&pfd, 1, *timeoutp); |
|
oerrno = errno; |
|
ms_subtract_diff(&t_start, timeoutp); |
|
errno = oerrno; |
|
if (r > 0) |
|
return 0; |
|
else if (r == -1 && errno != EAGAIN) |
|
return -1; |
|
else if (r == 0) |
|
break; |
} |
} |
|
/* timeout */ |
|
errno = ETIMEDOUT; |
|
return -1; |
|
} |
|
|
set_nonblock(sockfd); |
static int |
rc = connect(sockfd, serv_addr, addrlen); |
timeout_connect(int sockfd, const struct sockaddr *serv_addr, |
if (rc == 0) { |
socklen_t addrlen, int *timeoutp) |
unset_nonblock(sockfd); |
{ |
result = 0; |
int optval = 0; |
goto done; |
socklen_t optlen = sizeof(optval); |
} |
|
if (errno != EINPROGRESS) { |
|
result = -1; |
|
goto done; |
|
} |
|
|
|
fdset = xcalloc(howmany(sockfd + 1, NFDBITS), |
/* No timeout: just do a blocking connect() */ |
sizeof(fd_mask)); |
if (*timeoutp <= 0) |
FD_SET(sockfd, fdset); |
return connect(sockfd, serv_addr, addrlen); |
ms_to_timeval(&tv, *timeoutp); |
|
|
|
for (;;) { |
set_nonblock(sockfd); |
rc = select(sockfd + 1, NULL, fdset, NULL, &tv); |
if (connect(sockfd, serv_addr, addrlen) == 0) { |
if (rc != -1 || errno != EINTR) |
/* Succeeded already? */ |
break; |
|
} |
|
|
|
switch (rc) { |
|
case 0: |
|
/* Timed out */ |
|
errno = ETIMEDOUT; |
|
break; |
|
case -1: |
|
/* Select error */ |
|
debug("select: %s", strerror(errno)); |
|
break; |
|
case 1: |
|
/* Completed or failed */ |
|
optval = 0; |
|
optlen = sizeof(optval); |
|
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, |
|
&optlen) == -1) { |
|
debug("getsockopt: %s", strerror(errno)); |
|
break; |
|
} |
|
if (optval != 0) { |
|
errno = optval; |
|
break; |
|
} |
|
result = 0; |
|
unset_nonblock(sockfd); |
unset_nonblock(sockfd); |
break; |
return 0; |
default: |
} else if (errno != EINPROGRESS) |
/* Should not occur */ |
return -1; |
fatal("Bogus return (%d) from select()", rc); |
|
} |
|
|
|
free(fdset); |
if (waitrfd(sockfd, timeoutp) == -1) |
|
return -1; |
|
|
done: |
/* Completed or failed */ |
if (result == 0 && *timeoutp > 0) { |
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1) { |
ms_subtract_diff(&t_start, timeoutp); |
debug("getsockopt: %s", strerror(errno)); |
if (*timeoutp <= 0) { |
return -1; |
errno = ETIMEDOUT; |
|
result = -1; |
|
} |
|
} |
} |
|
if (optval != 0) { |
return (result); |
errno = optval; |
|
return -1; |
|
} |
|
unset_nonblock(sockfd); |
|
return 0; |
} |
} |
|
|
/* |
/* |
|
|
int connection_out = packet_get_connection_out(); |
int connection_out = packet_get_connection_out(); |
u_int i, n; |
u_int i, n; |
size_t len; |
size_t len; |
int fdsetsz, remaining, rc; |
int rc; |
struct timeval t_start, t_remaining; |
|
fd_set *fdset; |
|
|
|
fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask); |
|
fdset = xcalloc(1, fdsetsz); |
|
|
|
send_client_banner(connection_out, 0); |
send_client_banner(connection_out, 0); |
|
|
/* Read other side's version identification. */ |
/* Read other side's version identification. */ |
remaining = timeout_ms; |
|
for (n = 0;;) { |
for (n = 0;;) { |
for (i = 0; i < sizeof(buf) - 1; i++) { |
for (i = 0; i < sizeof(buf) - 1; i++) { |
if (timeout_ms > 0) { |
if (timeout_ms > 0) { |
gettimeofday(&t_start, NULL); |
rc = waitrfd(connection_in, &timeout_ms); |
ms_to_timeval(&t_remaining, remaining); |
if (rc == -1 && errno == ETIMEDOUT) { |
FD_SET(connection_in, fdset); |
|
rc = select(connection_in + 1, fdset, NULL, |
|
fdset, &t_remaining); |
|
ms_subtract_diff(&t_start, &remaining); |
|
if (rc == 0 || remaining <= 0) |
|
fatal("Connection timed out during " |
fatal("Connection timed out during " |
"banner exchange"); |
"banner exchange"); |
if (rc == -1) { |
} else if (rc == -1) { |
if (errno == EINTR) |
fatal("%s: %s", |
continue; |
__func__, strerror(errno)); |
fatal("ssh_exchange_identification: " |
|
"select: %s", strerror(errno)); |
|
} |
} |
} |
} |
|
|
len = atomicio(read, connection_in, &buf[i], 1); |
len = atomicio(read, connection_in, &buf[i], 1); |
|
|
if (len != 1 && errno == EPIPE) |
if (len != 1 && errno == EPIPE) |
fatal("ssh_exchange_identification: " |
fatal("ssh_exchange_identification: " |
"Connection closed by remote host"); |
"Connection closed by remote host"); |
|
|
debug("ssh_exchange_identification: %s", buf); |
debug("ssh_exchange_identification: %s", buf); |
} |
} |
server_version_string = xstrdup(buf); |
server_version_string = xstrdup(buf); |
free(fdset); |
|
|
|
/* |
/* |
* Check that the versions match. In future this might accept |
* Check that the versions match. In future this might accept |