From edc7b96b2fe130dc4e9565781ec5911c876eccf0 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 28 Nov 2018 08:47:00 +0100 Subject: poll: Improve checks for POLLHUP and POLLERR Signed-off-by: Andreas Schneider --- src/poll.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 14 deletions(-) (limited to 'src/poll.c') diff --git a/src/poll.c b/src/poll.c index e211b338..e3f5262e 100644 --- a/src/poll.c +++ b/src/poll.c @@ -126,7 +126,23 @@ static poll_fn ssh_poll_emu; #include #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) { #ifdef _WIN32 @@ -134,6 +150,8 @@ static bool bsd_socket_disconnected(int sock_err) case WSAECONNRESET: case WSAENETRESET: case WSAESHUTDOWN: + case WSAECONNREFUSED: + case WSAETIMEDOUT: #else case ECONNABORTED: case ECONNRESET: @@ -148,6 +166,40 @@ static bool bsd_socket_disconnected(int sock_err) 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 * poll implementation. @@ -235,19 +287,8 @@ static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) fds[i].revents = 0; if (FD_ISSET(fds[i].fd, &readfds)) { - int save_errno = errno; - char data[64] = {0}; - 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; + fds[i].revents = bsd_socket_compute_revents(fds[i].fd, + fds[i].events); } if (FD_ISSET(fds[i].fd, &writefds)) { fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND); -- cgit v1.2.3