poll: Improve checks for POLLHUP and POLLERR
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Этот коммит содержится в:
родитель
ab269f036e
Коммит
edc7b96b2f
69
src/poll.c
69
src/poll.c
@ -126,7 +126,23 @@ static poll_fn ssh_poll_emu;
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool bsd_socket_disconnected(int sock_err)
|
static bool bsd_socket_not_connected(int sock_err)
|
||||||
|
{
|
||||||
|
switch (sock_err) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
case WSAENOTCONN:
|
||||||
|
#else
|
||||||
|
case ENOTCONN:
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bsd_socket_reset(int sock_err)
|
||||||
{
|
{
|
||||||
switch (sock_err) {
|
switch (sock_err) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -134,6 +150,8 @@ static bool bsd_socket_disconnected(int sock_err)
|
|||||||
case WSAECONNRESET:
|
case WSAECONNRESET:
|
||||||
case WSAENETRESET:
|
case WSAENETRESET:
|
||||||
case WSAESHUTDOWN:
|
case WSAESHUTDOWN:
|
||||||
|
case WSAECONNREFUSED:
|
||||||
|
case WSAETIMEDOUT:
|
||||||
#else
|
#else
|
||||||
case ECONNABORTED:
|
case ECONNABORTED:
|
||||||
case ECONNRESET:
|
case ECONNRESET:
|
||||||
@ -148,6 +166,40 @@ static bool bsd_socket_disconnected(int sock_err)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static short bsd_socket_compute_revents(int fd, short events)
|
||||||
|
{
|
||||||
|
int save_errno = errno;
|
||||||
|
int sock_errno = errno;
|
||||||
|
char data[64] = {0};
|
||||||
|
short revents = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* support for POLLHUP */
|
||||||
|
#ifdef _WIN32
|
||||||
|
WSASetLastError(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret = recv(fd, data, 64, MSG_PEEK);
|
||||||
|
|
||||||
|
errno = save_errno;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
sock_errno = WSAGetLastError();
|
||||||
|
WSASetLastError(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret > 0 || bsd_socket_not_connected(sock_errno)) {
|
||||||
|
revents = (POLLIN | POLLRDNORM) & events;
|
||||||
|
} else if (ret == 0 || bsd_socket_reset(sock_errno)) {
|
||||||
|
errno = sock_errno;
|
||||||
|
revents = POLLHUP;
|
||||||
|
} else {
|
||||||
|
revents = POLLERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return revents;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a poll(2)-emulation using select for systems not providing a native
|
* This is a poll(2)-emulation using select for systems not providing a native
|
||||||
* poll implementation.
|
* poll implementation.
|
||||||
@ -235,19 +287,8 @@ static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout)
|
|||||||
fds[i].revents = 0;
|
fds[i].revents = 0;
|
||||||
|
|
||||||
if (FD_ISSET(fds[i].fd, &readfds)) {
|
if (FD_ISSET(fds[i].fd, &readfds)) {
|
||||||
int save_errno = errno;
|
fds[i].revents = bsd_socket_compute_revents(fds[i].fd,
|
||||||
char data[64] = {0};
|
fds[i].events);
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* support for POLLHUP */
|
|
||||||
ret = recv(fds[i].fd, data, 64, MSG_PEEK);
|
|
||||||
if ((ret == -1) && bsd_socket_disconnected(errno)) {
|
|
||||||
fds[i].revents |= POLLHUP;
|
|
||||||
} else {
|
|
||||||
fds[i].revents |= fds[i].events & (POLLIN | POLLRDNORM);
|
|
||||||
}
|
|
||||||
|
|
||||||
errno = save_errno;
|
|
||||||
}
|
}
|
||||||
if (FD_ISSET(fds[i].fd, &writefds)) {
|
if (FD_ISSET(fds[i].fd, &writefds)) {
|
||||||
fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND);
|
fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND);
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user