From 269044136fa1d73a6bc1a764211cc18119bc1207 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Thu, 23 Apr 2020 05:39:46 -0700 Subject: sockets: connect bugfix and use poll in preference to select. * configure: cosmetics: change HAVE_SYS_SELECT to HAVE_SELECT, and log that the function rather than the header is being detected. * socket.c (fd_timeout): New function, implemented using poll or select. (to_connect): select logic replaced with fd_timeout. Bug fixed: connect requires polling for writability, not readability. If poll and select are not available, ignore timeout argument. (sock_accept): Use fd_timeout; fall back on non-timed-out accept if poll or select not available. --- configure | 4 +-- socket.c | 106 +++++++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 73 insertions(+), 37 deletions(-) diff --git a/configure b/configure index ef5f75ec..aa2a738e 100755 --- a/configure +++ b/configure @@ -3324,7 +3324,7 @@ else fi if [ $have_sockets ] ; then - printf "Checking whether we have ... " + printf "Checking for select ... " cat > conftest.c < @@ -3341,7 +3341,7 @@ int main(int argc, char **argv) ! if conftest; then printf "yes\n" - printf "#define HAVE_SYS_SELECT_H 1\n" >> config.h + printf "#define HAVE_SELECT 1\n" >> config.h else printf "no\n" fi diff --git a/socket.c b/socket.c index 546e5d7e..cda85e7e 100644 --- a/socket.c +++ b/socket.c @@ -39,7 +39,9 @@ #include #include "config.h" #include "alloca.h" -#if HAVE_SYS_SELECT_H +#if HAVE_POLL +#include +#elif HAVE_SELECT #include #endif #include "lib.h" @@ -702,25 +704,68 @@ static val sock_bind(val sock, val sockaddr) uw_throwf(socket_error_s, lit("sock-bind: cannot bind ~s"), sock, nao); } -static int to_connect(int fd, struct sockaddr *addr, socklen_t len, - val sock, val sockaddr, val timeout) +#if HAVE_POLL + +static int fd_timeout(int fd, val timeout, int write) { - if (!timeout) { + cnum ms = c_num(timeout) / 1000; + int pollms = (ms > INT_MAX) ? INT_MAX : ms; + struct pollfd pfd; int res; + if (write) + pfd.events = POLLOUT; + else + pfd.events = POLLIN; + + pfd.fd = fd; + sig_save_enable; - res = connect(fd, addr, len); + res = poll(&pfd, 1, pollms); sig_restore_enable; return res; - } else { - cnum u = c_num(timeout); +} + +#elif HAVE_SELECT + +static int fd_timeout(int fd, val timeout, int write) +{ + cnum us = c_num(timeout); struct timeval tv; + fd_set fds; + + tv.tv_sec = us / 1000000; + tv.tv_usec = us % 1000000; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + sig_save_enable; + + if (write) + res = select(fd + 1, 0 ,&rfds, 0, &tv); + else + res = select(fd + 1, &rfds, 0, 0, &tv); + + + sig_restore_enable; + + return res; +} + +#endif + +static int to_connect(int fd, struct sockaddr *addr, socklen_t len, + val sock, val sockaddr, val timeout) +{ + int res; + +#if HAVE_POLL || HAVE_SELECT + if (timeout) { int flags = fcntl(fd, F_GETFL); - int res; - fd_set rfds; if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) return -1; @@ -738,17 +783,7 @@ static int to_connect(int fd, struct sockaddr *addr, socklen_t len, break; } - tv.tv_sec = u / 1000000; - tv.tv_usec = u % 1000000; - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - - sig_save_enable; - - res = select(fd + 1, &rfds, 0, 0, &tv); - - sig_restore_enable; + res = fd_timeout(fd, timeout, 1); switch (res) { case -1: @@ -760,6 +795,17 @@ static int to_connect(int fd, struct sockaddr *addr, socklen_t len, return 0; } } +#else + (void) timeout; +#endif + + sig_save_enable; + + res = connect(fd, addr, len); + + sig_restore_enable; + + return res; } static val open_sockfd(val fd, val family, val type, val mode_str) @@ -875,22 +921,9 @@ static val sock_accept(val sock, val mode_str, val timeout_in) if (!sfd) goto badfd; +#if HAVE_POLL || HAVE_SELECT if (timeout) { - struct timeval tv; - cnum u = c_num(timeout); - fd_set rfds; - int res; - - tv.tv_sec = u / 1000000; - tv.tv_usec = u % 1000000; - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - - sig_save_enable; - - res = select(fd + 1, &rfds, 0, 0, &tv); - - sig_restore_enable; + int res = fd_timeout(fd, timeout, 0); switch (res) { case -1: @@ -901,6 +934,9 @@ static val sock_accept(val sock, val mode_str, val timeout_in) break; } } +#else + (void) timeout; +#endif if (type == num_fast(SOCK_DGRAM)) { struct dgram_stream *d = coerce(struct dgram_stream *, sock->co.handle); -- cgit v1.2.3