Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed MODBUS_ERROR_RECOVERY_LINK not working on Windows. #644

Merged
merged 4 commits into from Aug 17, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 41 additions & 1 deletion src/modbus.c
Expand Up @@ -183,6 +183,19 @@ static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)
if (rc == -1) {
_error_print(ctx, NULL);
if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
#ifdef _WIN32
const int wsa_err = WSAGetLastError();
if (wsa_err == WSAENETRESET || wsa_err == WSAENOTCONN || wsa_err == WSAENOTSOCK ||
wsa_err == WSAESHUTDOWN || wsa_err == WSAEHOSTUNREACH || wsa_err == WSAECONNABORTED ||
wsa_err == WSAECONNRESET || wsa_err == WSAETIMEDOUT) {
modbus_close(ctx);
_sleep_response_timeout(ctx);
modbus_connect(ctx);
} else {
_sleep_response_timeout(ctx);
modbus_flush(ctx);
}
#else
int saved_errno = errno;

if ((errno == EBADF || errno == ECONNRESET || errno == EPIPE)) {
Expand All @@ -194,6 +207,7 @@ static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)
modbus_flush(ctx);
}
errno = saved_errno;
#endif
}
}
} while ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
Expand Down Expand Up @@ -345,6 +359,9 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
int length_to_read;
int msg_length = 0;
_step_t step;
#ifdef _WIN32
int wsa_err;
#endif

if (ctx->debug) {
if (msg_type == MSG_INDICATION) {
Expand Down Expand Up @@ -387,6 +404,15 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
if (rc == -1) {
_error_print(ctx, "select");
if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
#ifdef _WIN32
wsa_err = WSAGetLastError();

// no equivalent to ETIMEDOUT when select fails on Windows
if (wsa_err == WSAENETDOWN || wsa_err == WSAENOTSOCK) {
modbus_close(ctx);
modbus_connect(ctx);
}
#else
int saved_errno = errno;

if (errno == ETIMEDOUT) {
Expand All @@ -397,6 +423,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
modbus_connect(ctx);
}
errno = saved_errno;
#endif
}
return -1;
}
Expand All @@ -409,7 +436,19 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)

if (rc == -1) {
_error_print(ctx, "read");
#ifdef _WIN32
wsa_err = WSAGetLastError();
if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
(ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_TCP) &&
(wsa_err == WSAENOTCONN || wsa_err == WSAENETRESET || wsa_err == WSAENOTSOCK ||
wsa_err == WSAESHUTDOWN || wsa_err == WSAECONNABORTED || wsa_err == WSAETIMEDOUT ||
wsa_err == WSAECONNRESET)) {
modbus_close(ctx);
modbus_connect(ctx);
}
#else
if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
(ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_TCP) &&
(errno == ECONNRESET || errno == ECONNREFUSED ||
errno == EBADF)) {
int saved_errno = errno;
Expand All @@ -418,6 +457,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
/* Could be removed by previous calls */
errno = saved_errno;
}
#endif
return -1;
}

Expand Down Expand Up @@ -1425,7 +1465,7 @@ int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint1
int rc;
int req_length;
/* The request length can not exceed _MIN_REQ_LENGTH - 2 and 4 bytes to
* store the masks. The ugly subtraction is there to remove the 'nb' value
* store the masks. The ugly substraction is there to remove the 'nb' value
* (2 bytes) which is not used. */
uint8_t req[_MIN_REQ_LENGTH + 2];

Expand Down