aboutsummaryrefslogtreecommitdiff
path: root/src/poll.c
diff options
context:
space:
mode:
authorAndreas Schneider <asn@cryptomilk.org>2018-11-28 08:47:00 +0100
committerAndreas Schneider <asn@cryptomilk.org>2019-01-09 15:50:21 +0100
commitedc7b96b2fe130dc4e9565781ec5911c876eccf0 (patch)
tree77d2d782cac1cfda584e86b05c29bef8414af118 /src/poll.c
parentab269f036e5a7594ef250bd5ebf74e382718e43d (diff)
downloadlibssh-edc7b96b2fe130dc4e9565781ec5911c876eccf0.tar.gz
libssh-edc7b96b2fe130dc4e9565781ec5911c876eccf0.tar.xz
libssh-edc7b96b2fe130dc4e9565781ec5911c876eccf0.zip
poll: Improve checks for POLLHUP and POLLERR
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Diffstat (limited to 'src/poll.c')
-rw-r--r--src/poll.c69
1 files changed, 55 insertions, 14 deletions
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 <unistd.h>
#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);