diff --git a/src/modbus-private.h b/src/modbus-private.h index 784a7f9..8c32c3f 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -85,6 +85,7 @@ typedef struct _modbus_backend { int (*flush) (modbus_t *ctx); int (*listen) (modbus_t *ctx, int nb_connection); int (*accept) (modbus_t *ctx, int *socket); + int (*select) (modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length); int (*filter_request) (modbus_t *ctx, int slave); } modbus_backend_t; diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c index a284e14..9b229f0 100644 --- a/src/modbus-rtu.c +++ b/src/modbus-rtu.c @@ -485,6 +485,49 @@ int _modbus_rtu_accept(modbus_t *ctx, int *socket) return -1; } +int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length) +{ + int s_rc; + while ((s_rc = select(ctx->s+1, rfds, 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(rfds); + FD_SET(ctx->s, rfds); + } else { + _error_print(ctx, "select"); + if (ctx->error_recovery && (errno == EBADF)) { + modbus_close(ctx); + modbus_connect(ctx); + errno = EBADF; + return -1; + } else { + return -1; + } + } + } + + if (s_rc == 0) { + /* Timeout */ + if (msg_length == (ctx->backend->header_length + 2 + + ctx->backend->checksum_length)) { + /* Optimization allowed because exception response is + the smallest trame in modbus protocol (3) so always + raise a timeout error. + Temporary error before exception analyze. */ + errno = EMBUNKEXC; + } else { + errno = ETIMEDOUT; + _error_print(ctx, "select"); + } + return -1; + } + + return s_rc; +} + int _modbus_rtu_filter_request(modbus_t *ctx, int slave) { /* Filter on the Modbus unit identifier (slave) in RTU mode */ @@ -518,6 +561,7 @@ const modbus_backend_t _modbus_rtu_backend = { _modbus_rtu_flush, _modbus_rtu_listen, _modbus_rtu_accept, + _modbus_rtu_select, _modbus_rtu_filter_request }; diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c index 4e9955d..e494e20 100644 --- a/src/modbus-tcp.c +++ b/src/modbus-tcp.c @@ -297,6 +297,49 @@ int _modbus_tcp_accept(modbus_t *ctx, int *socket) return ctx->s; } +int _modbus_tcp_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length) +{ + int s_rc; + while ((s_rc = select(ctx->s+1, rfds, 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(rfds); + FD_SET(ctx->s, rfds); + } else { + _error_print(ctx, "select"); + if (ctx->error_recovery && (errno == EBADF)) { + modbus_close(ctx); + modbus_connect(ctx); + errno = EBADF; + return -1; + } else { + return -1; + } + } + } + + if (s_rc == 0) { + /* Timeout */ + if (msg_length == (ctx->backend->header_length + 2 + + ctx->backend->checksum_length)) { + /* Optimization allowed because exception response is + the smallest trame in modbus protocol (3) so always + raise a timeout error. + Temporary error before exception analyze. */ + errno = EMBUNKEXC; + } else { + errno = ETIMEDOUT; + _error_print(ctx, "select"); + } + return -1; + } + + return s_rc; +} + int _modbus_tcp_filter_request(modbus_t *ctx, int slave) { return 0; @@ -320,6 +363,7 @@ const modbus_backend_t _modbus_tcp_backend = { _modbus_tcp_flush, _modbus_tcp_listen, _modbus_tcp_accept, + _modbus_tcp_select, _modbus_tcp_filter_request }; diff --git a/src/modbus.c b/src/modbus.c index 7a3198e..8a699a9 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -226,44 +226,6 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg) return length; } -#define WAIT_DATA() { \ - while ((s_rc = select(ctx->s+1, &rfds, 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(&rfds); \ - FD_SET(ctx->s, &rfds); \ - } else { \ - _error_print(ctx, "select"); \ - if (ctx->error_recovery && (errno == EBADF)) { \ - modbus_close(ctx); \ - modbus_connect(ctx); \ - errno = EBADF; \ - return -1; \ - } else { \ - return -1; \ - } \ - } \ - } \ - \ - if (s_rc == 0) { \ - /* Timeout */ \ - if (msg_length == (ctx->backend->header_length + 2 + \ - ctx->backend->checksum_length)) { \ - /* Optimization allowed because exception response is \ - the smallest trame in modbus protocol (3) so always \ - raise a timeout error. \ - Temporary error before exception analyze. */ \ - errno = EMBUNKEXC; \ - } else { \ - errno = ETIMEDOUT; \ - _error_print(ctx, "select"); \ - } \ - return -1; \ - } \ -} /* Waits a response from a modbus server or a request from a modbus client. This function blocks if there is no replies (3 timeouts). @@ -330,8 +292,10 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, length_to_read = msg_length_computed; - s_rc = 0; - WAIT_DATA(); + s_rc = ctx->backend->select(ctx, &rfds, &tv, msg_length_computed, msg_length); + if (s_rc == -1) { + return -1; + } p_msg = msg; while (s_rc) { @@ -405,7 +369,10 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, tv.tv_sec = ctx->timeout_end.tv_sec; tv.tv_usec = ctx->timeout_end.tv_usec; - WAIT_DATA(); + s_rc = ctx->backend->select(ctx, &rfds, &tv, msg_length_computed, msg_length); + if (s_rc == -1) { + return -1; + } } else { /* All chars are received */ s_rc = FALSE;