stephane / libmodbus

A Modbus library for Linux, Mac OS, FreeBSD and Windows
http://libmodbus.org
GNU Lesser General Public License v2.1
3.3k stars 1.71k forks source link

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

Closed embeddedmz closed 1 year ago

embeddedmz commented 2 years ago

OS and/or distribution

Windows

Description

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 :

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)