If error recovery mode is set to MODBUS_ERROR_RECOVERY_LINKon a context created with modbus_new_tcp and the TCP connection is lost, the function static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length) will not return since it uses errno to decide when to break the do while loop.
A proper fix is to avoid this "if" instruction for Windows :
Do not bother using WSAGetLastError since it can return many values if send fails (https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send). Finally, if we want to have the same logic as Linux, we should use WSAGetLastError() value. The issue is that this function is also used by the RTU backed so it's not easy to fix since Windows doesn't use errno when there's an issue with Winsock or a serial port (do we need error recovery for RTU ?)
Below the return values of WSAGetLastError() that might correspond to EBADF, ECONNRESET and EPIPE :
WSAENETRESET
WSAENOTCONN
WSAENOTSOCK
WSAESHUTDOWN
WSAEHOSTUNREACH
WSAECONNABORTED
WSAECONNRESET
WSAETIMEDOUT
Steps to reproduce the behavior (commands or source code)
Set error recovery mode to MODBUS_ERROR_RECOVERY_LINK
Put a breakpoint on a an instruction that uses a function will communicate with a TCP Modbus server (e.g. ModRsSim2)
Before executing that function, close the TCP Modbus server (e.g. close ModRsSim2).
Continue executing the program, the libmodbus function is caught in an infinite loop.
OS and/or distribution
Windows
Description
If error recovery mode is set to
MODBUS_ERROR_RECOVERY_LINK
on a context created with modbus_new_tcp and the TCP connection is lost, the functionstatic int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)
will not return since it uses errno to decide when to break the do while loop.A proper fix is to avoid this "if" instruction for Windows :
if ((errno == EBADF || errno == ECONNRESET || errno == EPIPE)) {
Do not bother using WSAGetLastError since it can return many values if send fails (https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send). Finally, if we want to have the same logic as Linux, we should use WSAGetLastError() value. The issue is that this function is also used by the RTU backed so it's not easy to fix since Windows doesn't use errno when there's an issue with Winsock or a serial port (do we need error recovery for RTU ?)
Below the return values of WSAGetLastError() that might correspond to EBADF, ECONNRESET and EPIPE : WSAENETRESET WSAENOTCONN WSAENOTSOCK WSAESHUTDOWN WSAEHOSTUNREACH WSAECONNABORTED WSAECONNRESET WSAETIMEDOUT
Steps to reproduce the behavior (commands or source code)