libmodbus icon indicating copy to clipboard operation
libmodbus copied to clipboard

Recovery link is not handled for Modbus TCP on Windows and can cause an infinite loop

Open embeddedmz opened this issue 3 years ago • 0 comments

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 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 :

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)

  • 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.

embeddedmz avatar Jun 30 '22 12:06 embeddedmz