Răsfoiți Sursa

TCP - Socket in non blocking mode by default

Original patch for new connect function by Thomas Stalder.
Stéphane Raimbault 13 ani în urmă
părinte
comite
8dc21ddaf5
4 a modificat fișierele cu 55 adăugiri și 21 ștergeri
  1. 1 1
      src/modbus-private.h
  2. 4 4
      src/modbus-rtu.c
  3. 46 12
      src/modbus-tcp.c
  4. 4 4
      src/modbus.c

+ 1 - 1
src/modbus-private.h

@@ -109,7 +109,7 @@ typedef struct _modbus_backend {
     int (*connect) (modbus_t *ctx);
     void (*close) (modbus_t *ctx);
     int (*flush) (modbus_t *ctx);
-    int (*select) (modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length);
+    int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);
 } modbus_backend_t;
 
 struct _modbus {

+ 4 - 4
src/modbus-rtu.c

@@ -945,7 +945,7 @@ int _modbus_rtu_flush(modbus_t *ctx)
 #endif
 }
 
-int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds,
+int _modbus_rtu_select(modbus_t *ctx, fd_set *rset,
                        struct timeval *tv, int length_to_read)
 {
     int s_rc;
@@ -961,14 +961,14 @@ int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds,
         return -1;
     }
 #else
-    while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) {
+    while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1) {
         if (errno == EINTR) {
             if (ctx->debug) {
                 fprintf(stderr, "A non blocked signal was caught\n");
             }
             /* Necessary after an error */
-            FD_ZERO(rfds);
-            FD_SET(ctx->s, rfds);
+            FD_ZERO(rset);
+            FD_SET(ctx->s, rset);
         } else {
             return -1;
         }

+ 46 - 12
src/modbus-tcp.c

@@ -238,10 +238,37 @@ static int _modbus_tcp_set_ipv4_options(int s)
     return 0;
 }
 
+static int _connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen,
+                    struct timeval *tv)
+{
+    int rc;
+
+    rc = connect(sockfd, addr, addrlen);
+    if (rc == -1 && errno == EINPROGRESS) {
+        fd_set wset;
+        int err;
+        socklen_t errlen = sizeof(err);
+
+        FD_ZERO(&wset);
+        FD_SET(sockfd, &wset);
+        rc = select(sockfd + 1, NULL, &wset, NULL, tv);
+        if (rc < 0) {
+            /* Timeout or fail */
+            return -1;
+        }
+
+        /* The socket is available for writing if it returns 0 */
+        return getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen);
+    }
+    /* 0 or (-1 and errno != EINPROGRESS) */
+    return rc;
+}
+
 /* Establishes a modbus TCP connection with a Modbus server. */
 static int _modbus_tcp_connect(modbus_t *ctx)
 {
     int rc;
+    /* Specialized version of sockaddr for Internet socket address (same size) */
     struct sockaddr_in addr;
     modbus_tcp_t *ctx_tcp = ctx->backend_data;
     int flags = SOCK_STREAM;
@@ -256,6 +283,10 @@ static int _modbus_tcp_connect(modbus_t *ctx)
     flags |= SOCK_CLOEXEC;
 #endif
 
+#ifdef SOCK_NONBLOCK
+    flags |= SOCK_NONBLOCK;
+#endif
+
     ctx->s = socket(PF_INET, flags, 0);
     if (ctx->s == -1) {
         return -1;
@@ -274,8 +305,7 @@ static int _modbus_tcp_connect(modbus_t *ctx)
     addr.sin_family = AF_INET;
     addr.sin_port = htons(ctx_tcp->port);
     addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);
-    rc = connect(ctx->s, (struct sockaddr *)&addr,
-                 sizeof(struct sockaddr_in));
+    rc = _connect(ctx->s, (struct sockaddr *)&addr, sizeof(addr), &ctx->response_timeout);
     if (rc == -1) {
         close(ctx->s);
         return -1;
@@ -317,6 +347,10 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx)
         flags |= SOCK_CLOEXEC;
 #endif
 
+#ifdef SOCK_NONBLOCK
+        flags |= SOCK_NONBLOCK;
+#endif
+
         s = socket(ai_ptr->ai_family, flags, ai_ptr->ai_protocol);
         if (s < 0)
             continue;
@@ -324,8 +358,8 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx)
         if (ai_ptr->ai_family == AF_INET)
             _modbus_tcp_set_ipv4_options(s);
 
-        rc = connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
-        if (rc != 0) {
+        rc = _connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen, &ctx->response_timeout);
+        if (rc == -1) {
             close(s);
             continue;
         }
@@ -362,14 +396,14 @@ int _modbus_tcp_flush(modbus_t *ctx)
         rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, MSG_DONTWAIT);
 #else
         /* On Win32, it's a bit more complicated to not wait */
-        fd_set rfds;
+        fd_set rset;
         struct timeval tv;
 
         tv.tv_sec = 0;
         tv.tv_usec = 0;
-        FD_ZERO(&rfds);
-        FD_SET(ctx->s, &rfds);
-        rc = select(ctx->s+1, &rfds, NULL, NULL, &tv);
+        FD_ZERO(&rset);
+        FD_SET(ctx->s, &rset);
+        rc = select(ctx->s+1, &rset, NULL, NULL, &tv);
         if (rc == -1) {
             return -1;
         }
@@ -571,17 +605,17 @@ int modbus_tcp_pi_accept(modbus_t *ctx, int *socket)
     return ctx->s;
 }
 
-int _modbus_tcp_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int length_to_read)
+int _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_to_read)
 {
     int s_rc;
-    while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) {
+    while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1) {
         if (errno == EINTR) {
             if (ctx->debug) {
                 fprintf(stderr, "A non blocked signal was caught\n");
             }
             /* Necessary after an error */
-            FD_ZERO(rfds);
-            FD_SET(ctx->s, rfds);
+            FD_ZERO(rset);
+            FD_SET(ctx->s, rset);
         } else {
             return -1;
         }

+ 4 - 4
src/modbus.c

@@ -326,7 +326,7 @@ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg,
 int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
 {
     int rc;
-    fd_set rfds;
+    fd_set rset;
     struct timeval tv;
     struct timeval *p_tv;
     int length_to_read;
@@ -342,8 +342,8 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
     }
 
     /* Add a file descriptor to the set */
-    FD_ZERO(&rfds);
-    FD_SET(ctx->s, &rfds);
+    FD_ZERO(&rset);
+    FD_SET(ctx->s, &rset);
 
     /* We need to analyse the message step by step.  At the first step, we want
      * to reach the function code because all packets contain this
@@ -362,7 +362,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
     }
 
     while (length_to_read != 0) {
-        rc = ctx->backend->select(ctx, &rfds, p_tv, length_to_read);
+        rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read);
         if (rc == -1) {
             _error_print(ctx, "select");
             if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {