Przeglądaj źródła

Introduced select() operation for backends

Introduced the select() operation for backends as the WAIT_DATA macro
approach is not very extensible and causes trouble when adding platform-
specific codepaths.

Signed-off-by: Stéphane Raimbault <stephane.raimbault@gmail.com>
Tobias Doerffel 14 lat temu
rodzic
commit
31577bbb41
4 zmienionych plików z 97 dodań i 41 usunięć
  1. 1 0
      src/modbus-private.h
  2. 44 0
      src/modbus-rtu.c
  3. 44 0
      src/modbus-tcp.c
  4. 8 41
      src/modbus.c

+ 1 - 0
src/modbus-private.h

@@ -85,6 +85,7 @@ typedef struct _modbus_backend {
     int (*flush) (modbus_t *ctx);
     int (*listen) (modbus_t *ctx, int nb_connection);
     int (*accept) (modbus_t *ctx, int *socket);
+    int (*select) (modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length);
     int (*filter_request) (modbus_t *ctx, int slave);
 } modbus_backend_t;
 

+ 44 - 0
src/modbus-rtu.c

@@ -485,6 +485,49 @@ int _modbus_rtu_accept(modbus_t *ctx, int *socket)
     return -1;
 }
 
+int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length)
+{
+    int s_rc;
+    while ((s_rc = select(ctx->s+1, rfds, 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);
+        } else {
+            _error_print(ctx, "select");
+            if (ctx->error_recovery && (errno == EBADF)) {
+                modbus_close(ctx);
+                modbus_connect(ctx);
+                errno = EBADF;
+                return -1;
+            } else {
+                return -1;
+            }
+        }
+    }
+
+    if (s_rc == 0) {
+        /* Timeout */
+        if (msg_length == (ctx->backend->header_length + 2 +
+                           ctx->backend->checksum_length)) {
+            /* Optimization allowed because exception response is
+               the smallest trame in modbus protocol (3) so always
+               raise a timeout error.
+               Temporary error before exception analyze. */
+            errno = EMBUNKEXC;
+        } else {
+            errno = ETIMEDOUT;
+            _error_print(ctx, "select");
+        }
+        return -1;
+    }
+
+    return s_rc;
+}
+
 int _modbus_rtu_filter_request(modbus_t *ctx, int slave)
 {
     /* Filter on the Modbus unit identifier (slave) in RTU mode */
@@ -518,6 +561,7 @@ const modbus_backend_t _modbus_rtu_backend = {
     _modbus_rtu_flush,
     _modbus_rtu_listen,
     _modbus_rtu_accept,
+    _modbus_rtu_select,
     _modbus_rtu_filter_request
 };
 

+ 44 - 0
src/modbus-tcp.c

@@ -297,6 +297,49 @@ int _modbus_tcp_accept(modbus_t *ctx, int *socket)
     return ctx->s;
 }
 
+int _modbus_tcp_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length)
+{
+    int s_rc;
+    while ((s_rc = select(ctx->s+1, rfds, 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);
+        } else {
+            _error_print(ctx, "select");
+            if (ctx->error_recovery && (errno == EBADF)) {
+                modbus_close(ctx);
+                modbus_connect(ctx);
+                errno = EBADF;
+                return -1;
+            } else {
+                return -1;
+            }
+        }
+    }
+
+    if (s_rc == 0) {
+        /* Timeout */
+        if (msg_length == (ctx->backend->header_length + 2 +
+                           ctx->backend->checksum_length)) {
+            /* Optimization allowed because exception response is
+               the smallest trame in modbus protocol (3) so always
+               raise a timeout error.
+               Temporary error before exception analyze. */
+            errno = EMBUNKEXC;
+        } else {
+            errno = ETIMEDOUT;
+            _error_print(ctx, "select");
+        }
+        return -1;
+    }
+
+    return s_rc;
+}
+
 int _modbus_tcp_filter_request(modbus_t *ctx, int slave)
 {
     return 0;
@@ -320,6 +363,7 @@ const modbus_backend_t _modbus_tcp_backend = {
     _modbus_tcp_flush,
     _modbus_tcp_listen,
     _modbus_tcp_accept,
+    _modbus_tcp_select,
     _modbus_tcp_filter_request
 };
 

+ 8 - 41
src/modbus.c

@@ -226,44 +226,6 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg)
     return length;
 }
 
-#define WAIT_DATA() {                                                   \
-    while ((s_rc = select(ctx->s+1, &rfds, 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);                                      \
-        } else {                                                        \
-            _error_print(ctx, "select");                                 \
-            if (ctx->error_recovery && (errno == EBADF)) {              \
-                modbus_close(ctx);                                      \
-                modbus_connect(ctx);                                    \
-                errno = EBADF;                                          \
-                return -1;                                              \
-            } else {                                                    \
-                return -1;                                              \
-            }                                                           \
-        }                                                               \
-    }                                                                   \
-                                                                        \
-    if (s_rc == 0) {                                                    \
-        /* Timeout */                                                   \
-        if (msg_length == (ctx->backend->header_length + 2 +            \
-                           ctx->backend->checksum_length)) {            \
-            /* Optimization allowed because exception response is       \
-               the smallest trame in modbus protocol (3) so always      \
-               raise a timeout error.                                   \
-               Temporary error before exception analyze. */             \
-            errno = EMBUNKEXC;                                          \
-        } else {                                                        \
-            errno = ETIMEDOUT;                                          \
-            _error_print(ctx, "select");                                 \
-        }                                                               \
-        return -1;                                                      \
-    }                                                                   \
-}
 
 /* Waits a response from a modbus server or a request from a modbus client.
    This function blocks if there is no replies (3 timeouts).
@@ -330,8 +292,10 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
 
     length_to_read = msg_length_computed;
 
-    s_rc = 0;
-    WAIT_DATA();
+    s_rc = ctx->backend->select(ctx, &rfds, &tv, msg_length_computed, msg_length);
+    if (s_rc == -1) {
+        return -1;
+    }
 
     p_msg = msg;
     while (s_rc) {
@@ -405,7 +369,10 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
             tv.tv_sec = ctx->timeout_end.tv_sec;
             tv.tv_usec = ctx->timeout_end.tv_usec;
 
-            WAIT_DATA();
+            s_rc = ctx->backend->select(ctx, &rfds, &tv, msg_length_computed, msg_length);
+            if (s_rc == -1) {
+                return -1;
+            }
         } else {
             /* All chars are received */
             s_rc = FALSE;