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