Repository: stephane/libmodbus

Issue #736: With TCP, `modbus_connect()` returns -1 on timeout but does not set `errno`
Created: 2024-01-29T15:07:43Z
libmodbus version
3f9f17e (current master)
OS and/or distribution
Windows (but I believe the problem also exists on *NIX)
Environment
N/A
Description
With TCP, modbus_connect() returns -1 on timeout, but does not set errno.
The reason seems to be that the timeout is implemented via select(), where a timeout is not considered an error. The offending code is in lines 295–299 of modbus-tcp.c, which look like this:
        rc = select(sockfd + 1, NULL, &wset, NULL, &tv);
        if (rc <= 0) {
            /* Timeout or fail */
            return -1;
        }

Expected behavior or suggestion
errno == ETIMEDOUT

Duplicate issue #756: Bad error message "Operation now in progress" for connection timeouts after modbus_set_response_timeout()
Created: 2024-07-11T07:04:39Z
libmodbus version
$ git describe --tags
v3.1.10-6-g5c14f13

OS and/or distribution
Up to date Debian testing
Environment
AMD64
Description
Example program:
#include <errno.h>
#include <modbus.h>
#include <stdio.h>

int main(int, char*[]) {
    modbus_t *connection = modbus_new_tcp("1.2.3.4", 502);
    modbus_set_debug(connection, TRUE);
    modbus_set_response_timeout(connection, 1, 0);
    if (modbus_connect(connection) == -1) {
        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
    }
    modbus_free(connection);
    return 0;
}
How did I compile it?
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7302c8d..61309ee 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -8,11 +8,15 @@ noinst_PROGRAMS = \
        random-test-client \
        unit-test-server \
        unit-test-client \
+    foo \
        version
 
 common_ldflags = \
        $(top_builddir)/src/libmodbus.la
 
+foo_SOURCES = foo.c
+foo_LDADD = $(common_ldflags)
+
 bandwidth_server_one_SOURCES = bandwidth-server-one.c
 bandwidth_server_one_LDADD = $(common_ldflags)
 
Actual behavior if applicable
Running this on my Debian testing computer outputs:
Connecting to 1.2.3.4:502
Connection failed: Operation now in progress

Expected behavior or suggestion
I guess I would expect Connection timed out
Steps to reproduce the behavior (commands or source code)
After applying the above patch and saving the program in tests/foo.c:
./autogen.sh && configure && make && ./tests/foo

libmodbus output with debug mode enabled
Connecting to 1.2.3.4:502
Connection failed: Operation now in progress

Relevant part of strace output on the example program
write(1, "Connecting to 1.2.3.4:502\n", 26Connecting to 1.2.3.4:502
) = 26
connect(3, {sa_family=AF_INET, sin_port=htons(502), sin_addr=inet_addr("1.2.3.4")}, 16) = -1 EINPROGRESS (Die Operation ist jetzt in Bearbeitung)
pselect6(4, NULL, [3], NULL, {tv_sec=1, tv_nsec=0}, NULL) = 0 (Timeout)
close(3)                                = 0
write(2, "Connection failed: Operation now"..., 45Connection failed: Operation now in progress
) = 45
exit_group(0)                           = ?
+++ exited with 0 +++

Proposed patch to get a nicer output
diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c
index 0c57109..bfad109 100644
--- a/src/modbus-tcp.c
+++ b/src/modbus-tcp.c
@@ -293,8 +293,13 @@ static int _connect(int sockfd,
         FD_ZERO(&wset);
         FD_SET(sockfd, &wset);
         rc = select(sockfd + 1, NULL, &wset, NULL, &tv);
-        if (rc <= 0) {
-            /* Timeout or fail */
+        if (rc < 0) {
+            /* Fail */
+            return -1;
+        }
+        if (rc == 0) {
+            /* Timeout */
+            errno = ETIMEDOUT;
             return -1;
         }

Closing comment (2024-07-11T14:09:14Z): This one is a duplicate of #736 , but since I have a test case / reproducing program, I'll leave it to someone else to close this. Perhaps this information actually still helps.