diff --git a/configure.ac b/configure.ac index bbb655b0b..5e9642489 100644 --- a/configure.ac +++ b/configure.ac @@ -86,6 +86,7 @@ AC_CHECK_HEADERS([ \ netdb.h \ netinet/in.h \ netinet/tcp.h \ + poll.h \ sys/ioctl.h \ sys/params.h \ sys/socket.h \ @@ -104,7 +105,7 @@ AC_CHECK_DECLS([__CYGWIN__]) AC_SEARCH_LIBS(accept, network socket) # Checks for library functions. -AC_CHECK_FUNCS([accept4 getaddrinfo gettimeofday inet_pton inet_ntop select socket strerror strlcpy]) +AC_CHECK_FUNCS([accept4 getaddrinfo gettimeofday inet_pton inet_ntop poll select socket strerror strlcpy]) # Required for MinGW with GCC v4.8.1 on Win7 AC_DEFINE(WINVER, 0x0501, _) diff --git a/src/modbus-private.h b/src/modbus-private.h index 6cd342482..694096509 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -89,7 +89,7 @@ typedef struct _modbus_backend { unsigned int (*is_connected)(modbus_t *ctx); void (*close)(modbus_t *ctx); int (*flush)(modbus_t *ctx); - int (*select)(modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length); + int (*select)(modbus_t *ctx, struct timeval *tv, int msg_length); void (*free)(modbus_t *ctx); } modbus_backend_t; diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c index b7749230c..d938eae75 100644 --- a/src/modbus-rtu.c +++ b/src/modbus-rtu.c @@ -12,6 +12,9 @@ #ifndef _MSC_VER #include #endif +#if HAVE_POLL_H +#include +#endif #include "modbus-private.h" #include @@ -1130,7 +1133,7 @@ static int _modbus_rtu_flush(modbus_t *ctx) } static int -_modbus_rtu_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_to_read) +_modbus_rtu_select(modbus_t *ctx, struct timeval *tv, int length_to_read) { int s_rc; #if defined(_WIN32) @@ -1144,19 +1147,48 @@ _modbus_rtu_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_t if (s_rc < 0) { return -1; } + #else - while ((s_rc = select(ctx->s + 1, rset, NULL, NULL, tv)) == -1) { +#if HAVE_POLL + struct pollfd fds; + fds.fd = ctx->s; + fds.events = POLLIN; + fds.revents = 0; + while ((s_rc = poll(&fds, 1, (tv != NULL) ? tv->tv_sec * 1000 + tv->tv_usec / 1000 : -1)) == -1) { + if (errno == EINTR) { + if (ctx->debug) { + fprintf(stderr, "A non blocked signal was caught\n"); + } + } else if (errno != EAGAIN) { + return -1; + } + } +#else + fd_set rset; + + if (ctx->s >= FD_SETSIZE) { + if (ctx->debug) { + fprintf(stderr, "File descriptor greater than FD_SETSIZE passed to select() call\n"); + } + errno = EBADF; + return -1; + } + + FD_ZERO(&rset); + FD_SET(ctx->s, &rset); + while ((s_rc = select(ctx->s + 1, &rset, NULL, NULL, tv)) == -1) { if (errno == EINTR) { if (ctx->debug) { fprintf(stderr, "A non blocked signal was caught\n"); } /* Necessary after an error */ - FD_ZERO(rset); - FD_SET(ctx->s, rset); + FD_ZERO(&rset); + FD_SET(ctx->s, &rset); } else { return -1; } } +#endif if (s_rc == 0) { /* Timeout */ diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c index 8389eaedf..66d22c946 100644 --- a/src/modbus-tcp.c +++ b/src/modbus-tcp.c @@ -24,6 +24,10 @@ #include #include +#if HAVE_POLL_H +#include +#endif + #if defined(_WIN32) /* Already set in modbus-tcp.h but it seems order matters in VS2005 */ # include @@ -284,15 +288,30 @@ static int _connect(int sockfd, #else if (rc == -1 && errno == EINPROGRESS) { #endif - fd_set wset; int optval; socklen_t optlen = sizeof(optval); +#if HAVE_POLL + struct pollfd fds; + + /* Wait to be available in writing */ + fds.fd = sockfd; + fds.events = POLLOUT; + fds.revents = 0; + rc = poll(&fds, 1, (ro_tv != NULL) ? ro_tv->tv_sec * 1000 + ro_tv->tv_usec / 1000 : -1); +#else + fd_set wset; struct timeval tv = *ro_tv; + if (sockfd >= FD_SETSIZE) { + errno = EBADF; + return -1; + } + /* Wait to be available in writing */ FD_ZERO(&wset); FD_SET(sockfd, &wset); rc = select(sockfd + 1, NULL, &wset, NULL, &tv); +#endif if (rc <= 0) { /* Timeout or fail */ return -1; @@ -759,21 +778,49 @@ int modbus_tcp_pi_accept(modbus_t *ctx, int *s) } static int -_modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_to_read) +_modbus_tcp_select(modbus_t *ctx, struct timeval *tv, int length_to_read) { int s_rc; - while ((s_rc = select(ctx->s + 1, rset, NULL, NULL, tv)) == -1) { +#if HAVE_POLL + struct pollfd fds; + fds.fd = ctx->s; + fds.events = POLLIN; + fds.revents = 0; + while ((s_rc = poll(&fds, 1, (tv != NULL) ? tv->tv_sec * 1000 + tv->tv_usec / 1000 : -1)) == -1) { + if (errno == EINTR) { + if (ctx->debug) { + fprintf(stderr, "A non blocked signal was caught\n"); + } + } else if (errno != EAGAIN) { + return -1; + } + } +#else + fd_set rset; + + if (ctx->s >= FD_SETSIZE) { + if (ctx->debug) { + fprintf(stderr, "File descriptor greater than FD_SETSIZE passed to select() call\n"); + } + errno = EBADF; + return -1; + } + + FD_ZERO(&rset); + FD_SET(ctx->s, &rset); + while ((s_rc = select(ctx->s + 1, &rset, NULL, NULL, tv)) == -1) { if (errno == EINTR) { if (ctx->debug) { fprintf(stderr, "A non blocked signal was caught\n"); } /* Necessary after an error */ - FD_ZERO(rset); - FD_SET(ctx->s, rset); + FD_ZERO(&rset); + FD_SET(ctx->s, &rset); } else { return -1; } } +#endif if (s_rc == 0) { errno = ETIMEDOUT; diff --git a/src/modbus.c b/src/modbus.c index 0360d5ccd..77e09ecc4 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -350,7 +350,6 @@ compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) { int rc; - fd_set rset; struct timeval tv; struct timeval *p_tv; unsigned int length_to_read; @@ -375,10 +374,6 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) return -1; } - /* Add a file descriptor to the set */ - FD_ZERO(&rset); - FD_SET(ctx->s, &rset); - /* We need to analyse the message step by step. At the first step, we want * to reach the function code because all packets contain this * information. */ @@ -405,7 +400,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) } while (length_to_read != 0) { - rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read); + rc = ctx->backend->select(ctx, p_tv, length_to_read); if (rc == -1) { _error_print(ctx, "select"); if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {