diff --git a/socat.c b/socat.c index c674a3c..eb2c2dd 100644 --- a/socat.c +++ b/socat.c @@ -664,7 +664,6 @@ int socat(const char *address1, const char *address2) { */ int childleftdata(xiofile_t *xfd) { struct pollfd in; - int timeout = 0; /* milliseconds */ int retval; /* have to check if a child process died before, but left read data */ @@ -673,6 +672,7 @@ int childleftdata(xiofile_t *xfd) { XIO_RDSTREAM(xfd)->howtoend == END_CLOSE_KILL || XIO_RDSTREAM(xfd)->howtoend == END_SHUTDOWN_KILL) && XIO_RDSTREAM(xfd)->para.exec.pid == 0) { + struct timeval timeout = { 0, 0 }; if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) { in.fd = XIO_GETRDFD(xfd); @@ -680,7 +680,7 @@ int childleftdata(xiofile_t *xfd) { in.revents = 0; } do { - retval = xiopoll(&in, 1, timeout); + retval = xiopoll(&in, 1, &timeout); } while (retval < 0 && errno == EINTR); if (retval < 0) { @@ -767,7 +767,7 @@ int _socat(void) { XIO_GETRDFD(sock2), XIO_GETWRFD(sock2)); while (XIO_RDSTREAM(sock1)->eof <= 1 || XIO_RDSTREAM(sock2)->eof <= 1) { - int timeout; + struct timeval timeout, *to = NULL; Debug6("data loop: sock1->eof=%d, sock2->eof=%d, closing=%d, wasaction=%d, total_to={"F_tv_sec"."F_tv_usec"}", XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock2)->eof, @@ -799,21 +799,21 @@ int _socat(void) { if (polling) { /* there is a ignoreeof poll timeout, use it */ - timeout = 1000*socat_opts.pollintv.tv_sec + - socat_opts.pollintv.tv_usec/1000; /*!!! overflow?*/ + timeout = socat_opts.pollintv; + to = &timeout; } else if (socat_opts.total_timeout.tv_sec != 0 || socat_opts.total_timeout.tv_usec != 0) { /* there might occur a total inactivity timeout */ - timeout = 1000*socat_opts.total_timeout.tv_sec + - socat_opts.total_timeout.tv_usec/1000; + timeout = socat_opts.total_timeout; + to = &timeout; } else { - timeout = -1; /* forever */ + to = NULL; } if (closing>=1) { /* first eof already occurred, start end timer */ - timeout = 1000*socat_opts.closwait.tv_sec + - socat_opts.closwait.tv_usec/1000; + timeout = socat_opts.pollintv; + to = &timeout; closing = 2; } @@ -826,17 +826,18 @@ int _socat(void) { if (closing>=1) { /* first eof already occurred, start end timer */ - timeout = 1000*socat_opts.closwait.tv_sec + - socat_opts.closwait.tv_usec/1000; + timeout = socat_opts.closwait; + to = &timeout; closing = 2; } /* use the ignoreeof timeout if appropriate */ if (polling) { - int ptimeout = 1000*socat_opts.pollintv.tv_sec + - socat_opts.pollintv.tv_usec/1000; - if (closing == 0 || ptimeout < timeout) { - timeout = ptimeout; + if (closing == 0 || + (socat_opts.pollintv.tv_sec < timeout.tv_sec) || + ((socat_opts.pollintv.tv_sec == timeout.tv_sec) && + socat_opts.pollintv.tv_usec < timeout.tv_usec)) { + timeout = socat_opts.pollintv; } } @@ -880,7 +881,7 @@ int _socat(void) { fd2in->fd = -1; } /* frame 0: innermost part of the transfer loop: check FD status */ - retval = xiopoll(fds, 4, timeout); + retval = xiopoll(fds, 4, to); if (retval >= 0 || errno != EINTR) { break; } @@ -947,14 +948,14 @@ int _socat(void) { } mayrd2 = true; } - if (XIO_GETWRFD(sock1) >= 0 && (fd1out->revents)) { + if (XIO_GETWRFD(sock1) >= 0 && fd1out->fd >= 0 && fd1out->revents) { if (fd1out->revents & POLLNVAL) { Error1("poll(...[%d]: invalid request", fd1out->fd); return -1; } maywr1 = true; } - if (XIO_GETWRFD(sock2) >= 0 && (fd2out->revents)) { + if (XIO_GETWRFD(sock2) >= 0 && fd2out->fd >= 0 && fd2out->revents) { if (fd2out->revents & POLLNVAL) { Error1("poll(...[%d]: invalid request", fd2out->fd); return -1; diff --git a/sysutils.c b/sysutils.c index ed1a1fa..bd11f6d 100644 --- a/sysutils.c +++ b/sysutils.c @@ -413,12 +413,56 @@ const char *hstrerror(int err) { /* this function behaves like poll(). It tries to do so even when the poll() system call is not available. */ -int xiopoll(struct pollfd fds[], nfds_t nfds, int timeout) { +int xiopoll(struct pollfd fds[], nfds_t nfds, struct timeval *timeout) { + int i, n = 0; + int result = 0; + + while (true) { /* should be if (), but we want to break */ + fd_set readfds; + fd_set writefds; + fd_set exceptfds; + + FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); + for (i = 0; i < nfds; ++i) { + fds[i].revents = 0; + if (fds[i].fd < 0) { continue; } + if (fds[i].fd > FD_SETSIZE) { break; /* use poll */ } + if (fds[i].events & POLLIN) { + FD_SET(fds[i].fd, &readfds); n = MAX(n, fds[i].fd); } + if (fds[i].events & POLLOUT) { + FD_SET(fds[i].fd, &writefds); n = MAX(n, fds[i].fd); } + } + if (fds[i].fd > FD_SETSIZE) { break; /* use poll */ } + + result = Select(n+1, &readfds, &writefds, &exceptfds, timeout); + if (result < 0) { return result; } + for (i = 0; i < nfds; ++i) { + if (fds[i].fd < 0) { continue; } + if ((fds[i].events & POLLIN) && FD_ISSET(fds[i].fd, &readfds)) { + fds[i].revents |= POLLIN; ++result; + } + if ((fds[i].events & POLLOUT) && FD_ISSET(fds[i].fd, &writefds)) { + fds[i].revents |= POLLOUT; ++result; + } + } + return result; + } #if HAVE_POLL - return Poll(fds, nfds, timeout); + { + int ms = 0; + if (timeout == NULL) { + ms = -1; + } else { + ms = 1000*timeout->tv_sec + timeout->tv_usec/1000; + } + /*! timeout */ + return Poll(fds, nfds, ms); #else /* HAVE_POLL */ - /*!!! wrap around Select() */ + } else { + Error("poll() not available"); + return -1; #endif /* !HAVE_POLL */ + } } diff --git a/sysutils.h b/sysutils.h index f49b96b..3b30b96 100644 --- a/sysutils.h +++ b/sysutils.h @@ -74,7 +74,7 @@ extern int getusergroups(const char *user, gid_t *list, size_t *ngroups); extern const char *hstrerror(int err); #endif -extern int xiopoll(struct pollfd fds[], nfds_t nfds, int timeout); +extern int xiopoll(struct pollfd fds[], nfds_t nfds, struct timeval *timeout); extern int parseport(const char *portname, int proto); diff --git a/test.sh b/test.sh index a534a89..83c8aa9 100755 --- a/test.sh +++ b/test.sh @@ -5697,6 +5697,7 @@ if ! feat=$(testaddrs pty); then $PRINTF "test $F_n $TEST... ${YELLOW}$(echo $feat |tr a-z A-Z) not available${NORMAL}\n" $N numCANT=$((numCANT+1)) else +set -vx SIG="$(signum $signam)" te="$td/test$N.stderr" tpp="$td/test$N.ppid" @@ -5725,6 +5726,7 @@ else numFAIL=$((numFAIL+1)) fi wait +set +vx fi ;; # feat esac N=$((N+1)) diff --git a/xio-socket.c b/xio-socket.c index 006fe42..efe4f16 100644 --- a/xio-socket.c +++ b/xio-socket.c @@ -840,18 +840,17 @@ int _xioopen_connect(struct single *xfd, struct sockaddr *us, size_t uslen, if (errno == EINPROGRESS) { if (xfd->para.socket.connect_timeout.tv_sec != 0 || xfd->para.socket.connect_timeout.tv_usec != 0) { - int timeout; + struct timeval timeout; struct pollfd writefd; int result; Info4("connect(%d, %s, "F_Zd"): %s", xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)), themlen, strerror(errno)); - timeout = 1000*xfd->para.socket.connect_timeout.tv_sec + - xfd->para.socket.connect_timeout.tv_usec/1000; + timeout = xfd->para.socket.connect_timeout; writefd.fd = xfd->fd; writefd.events = (POLLIN|POLLHUP|POLLERR); - result = Poll(&writefd, 1, timeout); + result = xiopoll(&writefd, 1, &timeout); if (result < 0) { Msg3(level, "poll({%d,POLLIN|POLLHUP|POLLER},,%d): %s", xfd->fd, timeout, strerror(errno)); @@ -1319,7 +1318,7 @@ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags, } readfd.fd = xfd->fd; readfd.events = POLLIN; - if (Poll(&readfd, 1, -1) > 0) { + if (xiopoll(&readfd, 1, NULL) > 0) { break; } diff --git a/xio-udp.c b/xio-udp.c index f507e24..77ffdd6 100644 --- a/xio-udp.c +++ b/xio-udp.c @@ -205,7 +205,7 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts, sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff))); readfd.fd = fd->stream.fd; readfd.events = POLLIN|POLLERR; - while (Poll(&readfd, 1, -1) < 0) { + while (xiopoll(&readfd, 1, NULL) < 0) { if (errno != EINTR) break; }