فهرست منبع

TCP - Socket in non blocking mode by default

Original patch for new connect function by Thomas Stalder.
Stéphane Raimbault 13 سال پیش
والد
کامیت
8dc21ddaf5
4فایلهای تغییر یافته به همراه55 افزوده شده و 21 حذف شده
  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) {