c1c61d
diff -up stunnel-4.56/src/client.c.pollhup stunnel-4.56/src/client.c
c1c61d
--- stunnel-4.56/src/client.c.pollhup	2016-03-31 17:17:01.438314029 +0200
c1c61d
+++ stunnel-4.56/src/client.c	2016-03-31 17:25:48.573618470 +0200
c1c61d
@@ -595,35 +595,6 @@ static void transfer(CLI *c) {
c1c61d
             }
c1c61d
         }
c1c61d
 
c1c61d
-        /****************************** check for hangup conditions */
c1c61d
-        if(s_poll_hup(c->fds, c->sock_rfd->fd)) {
c1c61d
-            s_log(LOG_INFO, "Read socket closed (hangup)");
c1c61d
-            sock_open_rd=0;
c1c61d
-        }
c1c61d
-        if(s_poll_hup(c->fds, c->sock_wfd->fd)) {
c1c61d
-            if(c->ssl_ptr) {
c1c61d
-                s_log(LOG_ERR,
c1c61d
-                    "Write socket closed (hangup) with %d unsent byte(s)",
c1c61d
-                    c->ssl_ptr);
c1c61d
-                longjmp(c->err, 1); /* reset the socket */
c1c61d
-            }
c1c61d
-            s_log(LOG_INFO, "Write socket closed (hangup)");
c1c61d
-            sock_open_wr=0;
c1c61d
-        }
c1c61d
-        if(s_poll_hup(c->fds, c->ssl_rfd->fd) ||
c1c61d
-                s_poll_hup(c->fds, c->ssl_wfd->fd)) {
c1c61d
-            /* hangup -> buggy (e.g. Microsoft) peer:
c1c61d
-             * SSL socket closed without close_notify alert */
c1c61d
-            if(c->sock_ptr) {
c1c61d
-                s_log(LOG_ERR,
c1c61d
-                    "SSL socket closed (hangup) with %d unsent byte(s)",
c1c61d
-                    c->sock_ptr);
c1c61d
-                longjmp(c->err, 1); /* reset the socket */
c1c61d
-            }
c1c61d
-            s_log(LOG_INFO, "SSL socket closed (hangup)");
c1c61d
-            SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
c1c61d
-        }
c1c61d
-
c1c61d
         /****************************** retrieve results from c->fds */
c1c61d
         sock_can_rd=s_poll_canread(c->fds, c->sock_rfd->fd);
c1c61d
         sock_can_wr=s_poll_canwrite(c->fds, c->sock_wfd->fd);
c1c61d
@@ -828,6 +799,36 @@ static void transfer(CLI *c) {
c1c61d
             }
c1c61d
         }
c1c61d
 
c1c61d
+        /****************************** check for hangup conditions */
c1c61d
+        if(s_poll_rdhup(c->fds, c->sock_rfd->fd) &&
c1c61d
+                    !s_poll_canread(c->fds, c->sock_rfd->fd)) {
c1c61d
+            s_log(LOG_INFO, "Read socket closed (hangup)");
c1c61d
+            sock_open_rd=0;
c1c61d
+        }
c1c61d
+        if(s_poll_hup(c->fds, c->sock_wfd->fd)) {
c1c61d
+            if(c->ssl_ptr) {
c1c61d
+                s_log(LOG_ERR,
c1c61d
+                    "Write socket closed (hangup) with %d unsent byte(s)",
c1c61d
+                    c->ssl_ptr);
c1c61d
+                longjmp(c->err, 1); /* reset the socket */
c1c61d
+            }
c1c61d
+            s_log(LOG_INFO, "Write socket closed (hangup)");
c1c61d
+            sock_open_wr=0;
c1c61d
+        }
c1c61d
+        if((s_poll_hup(c->fds, c->ssl_rfd->fd) && !s_poll_canread(c->fds, c->sock_rfd->fd)) ||
c1c61d
+                s_poll_hup(c->fds, c->ssl_wfd->fd)) {
c1c61d
+            /* hangup -> buggy (e.g. Microsoft) peer:
c1c61d
+             * SSL socket closed without close_notify alert */
c1c61d
+            if(c->sock_ptr) {
c1c61d
+                s_log(LOG_ERR,
c1c61d
+                    "SSL socket closed (hangup) with %d unsent byte(s)",
c1c61d
+                    c->sock_ptr);
c1c61d
+                longjmp(c->err, 1); /* reset the socket */
c1c61d
+            }
c1c61d
+            s_log(LOG_INFO, "SSL socket closed (hangup)");
c1c61d
+            SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
c1c61d
+        }
c1c61d
+
c1c61d
         /****************************** check write shutdown conditions */
c1c61d
         if(sock_open_wr && SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN && !c->ssl_ptr) {
c1c61d
             sock_open_wr=0; /* no further write allowed */
c1c61d
diff -up stunnel-4.56/src/network.c.pollhup stunnel-4.56/src/network.c
c1c61d
--- stunnel-4.56/src/network.c.pollhup	2013-03-13 14:41:02.000000000 +0100
c1c61d
+++ stunnel-4.56/src/network.c	2016-03-31 17:25:48.574618494 +0200
c1c61d
@@ -79,8 +79,12 @@ void s_poll_add(s_poll_set *fds, int fd,
c1c61d
         fds->ufds[i].events=0;
c1c61d
         fds->nfds++;
c1c61d
     }
c1c61d
-    if(rd)
c1c61d
+    if(rd) {
c1c61d
         fds->ufds[i].events|=POLLIN;
c1c61d
+#ifdef POLLRDHUP
c1c61d
+        fds->ufds[i].events|=POLLRDHUP;
c1c61d
+#endif
c1c61d
+    }
c1c61d
     if(wr)
c1c61d
         fds->ufds[i].events|=POLLOUT;
c1c61d
 }
c1c61d
@@ -103,12 +107,27 @@ int s_poll_canwrite(s_poll_set *fds, int
c1c61d
     return 0; /* not listed in fds */
c1c61d
 }
c1c61d
 
c1c61d
+/* best doc: http://lxr.free-electrons.com/source/net/ipv4/tcp.c#L456 */
c1c61d
+
c1c61d
 int s_poll_hup(s_poll_set *fds, int fd) {
c1c61d
     unsigned int i;
c1c61d
 
c1c61d
     for(i=0; i<fds->nfds; i++)
c1c61d
         if(fds->ufds[i].fd==fd)
c1c61d
-            return fds->ufds[i].revents&POLLHUP;
c1c61d
+            return fds->ufds[i].revents&POLLHUP; /* read and write closed */
c1c61d
+    return 0; /* not listed in fds */
c1c61d
+}
c1c61d
+
c1c61d
+int s_poll_rdhup(s_poll_set *fds, int fd) {
c1c61d
+    unsigned int i;
c1c61d
+
c1c61d
+    for(i=0; i<fds->nfds; i++)
c1c61d
+        if(fds->ufds[i].fd==fd)
c1c61d
+#ifdef POLLRDHUP
c1c61d
+            return fds->ufds[i].revents&POLLRDHUP; /* read closed */
c1c61d
+#else
c1c61d
+            return fds->ufds[i].revents&POLLHUP; /* read and write closed */
c1c61d
+#endif
c1c61d
     return 0; /* not listed in fds */
c1c61d
 }
c1c61d
 
c1c61d
@@ -336,6 +355,12 @@ int s_poll_hup(s_poll_set *fds, int fd)
c1c61d
     return 0; /* FIXME: how to detect HUP condition with select()? */
c1c61d
 }
c1c61d
 
c1c61d
+int s_poll_rdhup(s_poll_set *fds, int fd) {
c1c61d
+    (void)fds; /* skip warning about unused parameter */
c1c61d
+    (void)fd; /* skip warning about unused parameter */
c1c61d
+    return 0; /* FIXME: how to detect RDHUP condition with select()? */
c1c61d
+}
c1c61d
+
c1c61d
 int s_poll_error(s_poll_set *fds, int fd) {
c1c61d
     /* error conditions are signaled as read, but apparently *not* in Winsock:
c1c61d
      * http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625%28v=vs.85%29.aspx */
c1c61d
diff -up stunnel-4.56/src/prototypes.h.pollhup stunnel-4.56/src/prototypes.h
c1c61d
--- stunnel-4.56/src/prototypes.h.pollhup	2013-03-19 18:30:55.000000000 +0100
c1c61d
+++ stunnel-4.56/src/prototypes.h	2016-03-31 17:25:48.574618494 +0200
c1c61d
@@ -385,6 +385,7 @@ void s_poll_add(s_poll_set *, int, int,
c1c61d
 int s_poll_canread(s_poll_set *, int);
c1c61d
 int s_poll_canwrite(s_poll_set *, int);
c1c61d
 int s_poll_hup(s_poll_set *, int);
c1c61d
+int s_poll_rdhup(s_poll_set *, int);
c1c61d
 int s_poll_error(s_poll_set *, int);
c1c61d
 int s_poll_wait(s_poll_set *, int, int);
c1c61d