소스 검색

Error conventions of POSIX systems and error recovery

- returns -1 on error and set errno
- error recovery system was flawed
- error recovery disabled by default
- remove a malloc
Stéphane Raimbault 15 년 전
부모
커밋
f0e7ad217d
9개의 변경된 파일744개의 추가작업 그리고 730개의 파일을 삭제
  1. 456 371
      modbus/modbus.c
  2. 54 154
      modbus/modbus.h
  3. 17 5
      tests/bandwidth-master.c
  4. 9 8
      tests/bandwidth-slave-many-up.c
  5. 15 13
      tests/bandwidth-slave-one.c
  6. 28 25
      tests/random-test-master.c
  7. 17 15
      tests/random-test-slave.c
  8. 129 126
      tests/unit-test-master.c
  9. 19 13
      tests/unit-test-slave.c

+ 456 - 371
modbus/modbus.c

@@ -41,6 +41,7 @@
 #include <sys/time.h>
 #include <unistd.h>
 #include <errno.h>
+#include <assert.h>
 #include <limits.h>
 #include <fcntl.h>
 
@@ -61,9 +62,8 @@
 #endif
 
 #include <config.h>
-#include <modbus/modbus.h>
 
-#define UNKNOWN_ERROR_MSG "Not defined in modbus specification"
+#include <modbus/modbus.h>
 
 /* Exported version */
 const unsigned int mb_version_major = MB_VERSION_MAJOR;
@@ -78,22 +78,6 @@ typedef struct {
         int t_id;
 } sft_t;
 
-static const uint8_t NB_TAB_ERROR_MSG = 12;
-static const char *TAB_ERROR_MSG[] = {
-        /* 0x00 */ UNKNOWN_ERROR_MSG,
-        /* 0x01 */ "Illegal function code",
-        /* 0x02 */ "Illegal data address",
-        /* 0x03 */ "Illegal data value",
-        /* 0x04 */ "Slave device or server failure",
-        /* 0x05 */ "Acknowledge",
-        /* 0x06 */ "Slave device or server busy",
-        /* 0x07 */ "Negative acknowledge",
-        /* 0x08 */ "Memory parity error",
-        /* 0x09 */ UNKNOWN_ERROR_MSG,
-        /* 0x0A */ "Gateway path unavailable",
-        /* 0x0B */ "Target device failed to respond"
-};
-
 /* Table of CRC values for high-order byte */
 static uint8_t table_crc_hi[] = {
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
@@ -169,42 +153,65 @@ static const int TAB_MAX_ADU_LENGTH[2] = {
         MAX_ADU_LENGTH_TCP,
 };
 
-/* Treats errors and flush or close connection if necessary */
-static void error_treat(modbus_param_t *mb_param, int code, const char *string)
-{
-        fprintf(stderr, "\nERROR %s (%0X)\n", string, -code);
+const char *modbus_strerror(int errnum) {
+        switch (errnum) {
+        case EMBXILFUN:
+                return "Illegal function";
+        case EMBXILADD:
+                return "Illegal data address";
+        case EMBXILVAL:
+                return "Illegal data value";
+        case EMBXSFAIL:
+                return "Slave device or server failure";
+        case EMBXACK:
+                return "Acknowledge";
+        case EMBXSBUSY:
+                return "Slave device or server is busy";
+        case EMBXNACK:
+                return "Negative acknowledge";
+        case EMBXMEMPAR:
+                return "Memory parity error";
+        case EMBXGPATH:
+                return "Gateway path unavailable";
+        case EMBXGTAR:
+                return "Target device failed to respond";
+        case EMBBADCRC:
+                return "Invalid CRC";
+        case EMBBADDATA:
+                return "Invalid data";
+        case EMBBADEXC:
+                return "Invalid exception code";
+        case EMBMDATA:
+                return "Too many data";
+        default:
+                return strerror(errnum);
+        }
+}
 
-        if (mb_param->error_handling == FLUSH_OR_CONNECT_ON_ERROR) {
-                switch (code) {
-                case INVALID_DATA:
-                case INVALID_CRC:
-                case INVALID_EXCEPTION_CODE:
-                        modbus_flush(mb_param);
-                        break;
-                case SELECT_FAILURE:
-                case SOCKET_FAILURE:
-                case CONNECTION_CLOSED:
-                        modbus_close(mb_param);
-                        modbus_connect(mb_param);
-                        break;
-                default:
-                        /* NOP */
-                        break;
+static void error_print(modbus_param_t *mb_param, const char *context)
+{
+        if (mb_param->debug) {
+                fprintf(stderr, "ERROR %s", modbus_strerror(errno));
+                if (context != NULL) {
+                        fprintf(stderr, ": %s\n", context);
+                } else {
+                        fprintf(stderr, "\n");
                 }
         }
 }
 
-void modbus_flush(modbus_param_t *mb_param)
+int modbus_flush(modbus_param_t *mb_param)
 {
+        int rc;
+
         if (mb_param->type_com == RTU) {
-                tcflush(mb_param->fd, TCIOFLUSH);
+                rc = tcflush(mb_param->fd, TCIOFLUSH);
         } else {
-                int ret;
                 do {
                         /* Extract the garbage from the socket */
                         char devnull[MAX_ADU_LENGTH_TCP];
 #if (!HAVE_DECL___CYGWIN__)
-                        ret = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, MSG_DONTWAIT);
+                        rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, MSG_DONTWAIT);
 #else
                         /* On Cygwin, it's a bit more complicated to not wait */
                         fd_set rfds;
@@ -214,19 +221,17 @@ void modbus_flush(modbus_param_t *mb_param)
                         tv.tv_usec = 0;
                         FD_ZERO(&rfds);
                         FD_SET(mb_param->fd, &rfds);
-                        ret = select(mb_param->fd+1, &rfds, NULL, NULL, &tv);
-                        if (ret > 0) {
-                                ret = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, 0);
-                        } else if (ret == -1) {
-                                /* error_treat() doesn't call modbus_flush() in
-                                   this case (avoid infinite loop) */
-                                error_treat(mb_param, SELECT_FAILURE, "Select failure");
+                        rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv);
+                        if (rc == -1) {
+                                return -1;
                         }
+
+                        rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, 0);
 #endif
-                        if (mb_param->debug && ret > 0) {
-                                printf("%d bytes flushed\n", ret);
+                        if (mb_param->debug && rc != -1) {
+                                printf("\n%d bytes flushed\n", rc);
                         }
-                } while (ret > 0);
+                } while (rc > 0);
         }
 }
 
@@ -288,12 +293,11 @@ static int build_query_basis_tcp(int slave, int function,
                                  uint8_t *query)
 {
 
-        /* Extract from MODBUS Messaging on TCP/IP Implementation
-           Guide V1.0b (page 23/46):
-           The transaction identifier is used to associate the future
-           response with the request. So, at a time, on a TCP
-           connection, this identifier must be unique.
-        */
+        /* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b
+           (page 23/46):
+           The transaction identifier is used to associate the future response
+           with the request. So, at a time, on a TCP connection, this identifier
+           must be unique. */
         static uint16_t t_id = 0;
 
         /* Transaction ID */
@@ -309,7 +313,7 @@ static int build_query_basis_tcp(int slave, int function,
         query[3] = 0;
 
         /* Length will be defined later by set_query_length_tcp at offsets 4
-         * and 5 */
+           and 5 */
 
         query[6] = slave;
         query[7] = function;
@@ -400,38 +404,39 @@ static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)
         return (crc_hi << 8 | crc_lo);
 }
 
-/* If CRC is correct returns msg_length else returns INVALID_CRC */
+/* The check_crc16 function shall return the message length if the CRC is
+   valid. Otherwise it shall return -1 and set errno to EMBADCRC. */
 static int check_crc16(modbus_param_t *mb_param,
                        uint8_t *msg,
                        const int msg_length)
 {
-        int ret;
-        uint16_t crc_calc;
+        uint16_t crc_calculated;
         uint16_t crc_received;
 
-        crc_calc = crc16(msg, msg_length - 2);
+        crc_calculated = crc16(msg, msg_length - 2);
         crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];
 
         /* Check CRC of msg */
-        if (crc_calc == crc_received) {
-                ret = msg_length;
+        if (crc_calculated == crc_received) {
+                return msg_length;
         } else {
-                char s_error[64];
-                sprintf(s_error,
-                        "invalid crc received %0X - crc_calc %0X",
-                        crc_received, crc_calc);
-                ret = INVALID_CRC;
-                error_treat(mb_param, ret, s_error);
+                if (mb_param->debug) {
+                        fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n",
+                                crc_received, crc_calculated);
+                }
+                if (mb_param->error_recovery) {
+                        modbus_flush(mb_param);
+                }
+                errno = EMBBADCRC;
+                return -1;
         }
-
-        return ret;
 }
 
 /* Sends a query/response over a serial or a TCP communication */
 static int modbus_send(modbus_param_t *mb_param, uint8_t *query,
                        int query_length)
 {
-        int ret;
+        int rc;
         uint16_t s_crc;
         int i;
 
@@ -449,19 +454,35 @@ static int modbus_send(modbus_param_t *mb_param, uint8_t *query,
                 printf("\n");
         }
 
-        if (mb_param->type_com == RTU)
-                ret = write(mb_param->fd, query, query_length);
-        else
-                ret = send(mb_param->fd, query, query_length, MSG_NOSIGNAL);
+        /* In recovery mode, the write command will be issued until to be
+           successful! Disabled by default.
+         */
+        do {
+                if (mb_param->type_com == RTU)
+                        rc = write(mb_param->fd, query, query_length);
+                else
+                        /* MSG_NOSIGNAL
+                           Requests not to send SIGPIPE on errors on stream oriented
+                           sockets when the other end breaks the connection.  The EPIPE
+                           error is still returned. */
+                        rc = send(mb_param->fd, query, query_length, MSG_NOSIGNAL);
+
+                if (rc == -1) {
+                        error_print(mb_param, NULL);
+                        if (mb_param->error_recovery && (errno == EBADF ||
+                            errno == ECONNRESET || errno == EPIPE)) {
+                                modbus_close(mb_param);
+                                modbus_connect(mb_param);
+                        }
+                }
+        } while (mb_param->error_recovery && rc == -1);
 
-        /* Return the number of bytes written (0 to n)
-           or SOCKET_FAILURE on error */
-        if ((ret == -1) || (ret != query_length)) {
-                ret = SOCKET_FAILURE;
-                error_treat(mb_param, ret, "Write socket failure");
+        if (rc > 0 && rc != query_length) {
+                errno = EMBBADDATA;
+                return -1;
         }
 
-        return ret;
+        return rc;
 }
 
 /* Computes the length of the header following the function code */
@@ -504,53 +525,68 @@ static int compute_query_length_data(modbus_param_t *mb_param, uint8_t *msg)
         return length;
 }
 
-#define WAIT_DATA()                                                                \
-{                                                                                  \
-    while ((select_ret = select(mb_param->fd+1, &rfds, NULL, NULL, &tv)) == -1) {  \
-            if (errno == EINTR) {                                                  \
-                    fprintf(stderr, "A non blocked signal was caught\n");          \
-                    /* Necessary after an error */                                 \
-                    FD_ZERO(&rfds);                                                \
-                    FD_SET(mb_param->fd, &rfds);                                   \
-            } else {                                                               \
-                    error_treat(mb_param, SELECT_FAILURE, "Select failure");       \
-                    return SELECT_FAILURE;                                         \
-            }                                                                      \
-    }                                                                              \
-                                                                                   \
-    if (select_ret == 0) {                                                         \
-            /* Timeout */                                                          \
-            if (msg_length == (TAB_HEADER_LENGTH[mb_param->type_com] + 2 +         \
-                               TAB_CHECKSUM_LENGTH[mb_param->type_com])) {         \
-                    /* Optimization allowed because exception response is          \
-                       the smallest trame in modbus protocol (3) so always         \
-                       raise a timeout error */                                    \
-                    return MB_EXCEPTION;                                           \
-            } else {                                                               \
-                    /* Call to error_treat is done later to manage exceptions */   \
-                    return SELECT_TIMEOUT;                                         \
-            }                                                                      \
-    }                                                                              \
+#define WAIT_DATA()                                                           \
+{                                                                             \
+    while ((s_rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv)) == -1) {   \
+            if (errno == EINTR) {                                             \
+                    if (mb_param->debug) {                                    \
+                            fprintf(stderr,                                   \
+                                    "A non blocked signal was caught\n");     \
+                    }                                                         \
+                    /* Necessary after an error */                            \
+                    FD_ZERO(&rfds);                                           \
+                    FD_SET(mb_param->fd, &rfds);                              \
+            } else {                                                          \
+                    error_print(mb_param, "select");                          \
+                    if (mb_param->error_recovery && (errno == EBADF)) {       \
+                            modbus_close(mb_param);                           \
+                            modbus_connect(mb_param);                         \
+                            errno = EBADF;                                    \
+                            return -1;                                        \
+                    } else {                                                  \
+                            return -1;                                        \
+                    }                                                         \
+            }                                                                 \
+    }                                                                         \
+                                                                              \
+    if (s_rc == 0) {                                                          \
+            /* Timeout */                                                     \
+            if (msg_length == (TAB_HEADER_LENGTH[mb_param->type_com] + 2 +    \
+                               TAB_CHECKSUM_LENGTH[mb_param->type_com])) {    \
+                    /* 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(mb_param, "select");                          \
+            }                                                                 \
+            return -1;                                                        \
+    }                                                                         \
 }
 
 /* Waits a reply from a modbus slave or a query from a modbus master.
    This function blocks if there is no replies (3 timeouts).
 
-   In
-   - msg_length_computed must be set to MSG_LENGTH_UNDEFINED if undefined
-
-   Out
-   - msg is an array of uint8_t to receive the message
-
-   On success, return the number of received characters. On error, return
-   a negative value.
+   The argument msg_length_computed must be set to MSG_LENGTH_UNDEFINED if
+   undefined.
+
+   The function shall return the number of received characters and the received
+   message in an array of uint8_t if successful. Otherwise it shall return -1
+   and errno is set to one of the values defined below:
+   - ECONNRESET
+   - EMBBADDATA
+   - EMBUNKEXC
+   - ETIMEDOUT
+   - read() or recv() error codes
 */
 static int receive_msg(modbus_param_t *mb_param,
                        int msg_length_computed,
                        uint8_t *msg)
 {
-        int select_ret;
-        int read_ret;
+        int s_rc;
+        int read_rc;
         fd_set rfds;
         struct timeval tv;
         int length_to_read;
@@ -591,32 +627,41 @@ static int receive_msg(modbus_param_t *mb_param,
 
         length_to_read = msg_length_computed;
 
-        select_ret = 0;
+        s_rc = 0;
         WAIT_DATA();
 
         p_msg = msg;
-        while (select_ret) {
+        while (s_rc) {
                 if (mb_param->type_com == RTU)
-                        read_ret = read(mb_param->fd, p_msg, length_to_read);
+                        read_rc = read(mb_param->fd, p_msg, length_to_read);
                 else
-                        read_ret = recv(mb_param->fd, p_msg, length_to_read, 0);
-
-                if (read_ret == 0) {
-                        return CONNECTION_CLOSED;
-                } else if (read_ret < 0) {
-                        /* The only negative possible value is -1 */
-                        error_treat(mb_param, SOCKET_FAILURE,
-                                    "Read socket failure");
-                        return SOCKET_FAILURE;
+                        read_rc = recv(mb_param->fd, p_msg, length_to_read, 0);
+
+                if (read_rc == 0) {
+                        errno = ECONNRESET;
+                        read_rc = -1;
+                }
+
+                if (read_rc == -1) {
+                        error_print(mb_param, "read");
+                        if (mb_param->error_recovery && (errno == ECONNRESET ||
+                            errno == ECONNREFUSED)) {
+                                modbus_close(mb_param);
+                                modbus_connect(mb_param);
+                                /* Could be removed by previous calls */
+                                errno = ECONNRESET;
+                                return -1;
+                        }
+                        return -1;
                 }
 
                 /* Sums bytes received */
-                msg_length += read_ret;
+                msg_length += read_rc;
 
                 /* Display the hex code of each character received */
                 if (mb_param->debug) {
                         int i;
-                        for (i=0; i < read_ret; i++)
+                        for (i=0; i < read_rc; i++)
                                 printf("<%.2X>", p_msg[i]);
                 }
 
@@ -639,8 +684,9 @@ static int receive_msg(modbus_param_t *mb_param,
                                 length_to_read = compute_query_length_data(mb_param, msg);
                                 msg_length_computed += length_to_read;
                                 if (msg_length_computed > TAB_MAX_ADU_LENGTH[mb_param->type_com]) {
-                                     error_treat(mb_param, INVALID_DATA, "Too many data");
-                                     return INVALID_DATA;
+                                        errno = EMBBADDATA;
+                                        error_print(mb_param, "too many data");
+                                        return -1;
                                 }
                                 state = COMPLETE;
                                 break;
@@ -651,7 +697,7 @@ static int receive_msg(modbus_param_t *mb_param,
                 }
 
                 /* Moves the pointer to receive other data */
-                p_msg = &(p_msg[read_ret]);
+                p_msg = &(p_msg[read_rc]);
 
                 if (length_to_read > 0) {
                         /* If no character at the buffer wait
@@ -662,7 +708,7 @@ static int receive_msg(modbus_param_t *mb_param,
                         WAIT_DATA();
                 } else {
                         /* All chars are received */
-                        select_ret = FALSE;
+                        s_rc = FALSE;
                 }
         }
 
@@ -683,11 +729,8 @@ static int receive_msg(modbus_param_t *mb_param,
    descriptor etablished with the master device in argument or -1 to use the
    internal one of modbus_param_t.
 
-   Returns:
-   - byte length of the message on success, or a negative error number if the
-     request fails
-   - query, message received
-*/
+   The modbus_slave_receive function shall return the request received and its
+   byte length if successul. Otherwise, it shall return -1 and errno is set. */
 int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query)
 {
         if (sockfd != -1) {
@@ -700,10 +743,8 @@ int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query)
 
 /* Receives the response and checks values (and checksum in RTU).
 
-   Returns:
-   - the number of values (bits or words) if success or the response
-     length if no value is returned
-   - less than 0 for exception errors
+   The function shall return the number of values (bits or words) and the
+   response if successful. Otherwise, its shall return -1 and errno is set.
 
    Note: all functions used to send or receive data with modbus return
    these values. */
@@ -711,13 +752,13 @@ static int modbus_receive(modbus_param_t *mb_param,
                           uint8_t *query,
                           uint8_t *response)
 {
-        int ret;
+        int rc;
         int response_length_computed;
         int offset = TAB_HEADER_LENGTH[mb_param->type_com];
 
         response_length_computed = compute_response_length(mb_param, query);
-        ret = receive_msg(mb_param, response_length_computed, response);
-        if (ret >= 0) {
+        rc = receive_msg(mb_param, response_length_computed, response);
+        if (rc != -1) {
                 /* GOOD RESPONSE */
                 int query_nb_value;
                 int response_nb_value;
@@ -748,7 +789,7 @@ static int modbus_receive(modbus_param_t *mb_param,
                         break;
                 case FC_REPORT_SLAVE_ID:
                         /* Report slave ID (bytes received) */
-                        query_nb_value = response_nb_value = ret;
+                        query_nb_value = response_nb_value = rc;
                         break;
                 default:
                         /* 1 Write functions & others */
@@ -756,58 +797,42 @@ static int modbus_receive(modbus_param_t *mb_param,
                 }
 
                 if (query_nb_value == response_nb_value) {
-                        ret = response_nb_value;
+                        rc = response_nb_value;
                 } else {
-                        char *s_error = malloc(64 * sizeof(char));
-                        sprintf(s_error, "Quantity not corresponding to the query (%d != %d)",
-                                response_nb_value, query_nb_value);
-                        ret = INVALID_DATA;
-                        error_treat(mb_param, ret, s_error);
-                        free(s_error);
+                        if (mb_param->debug) {
+                                fprintf(stderr,
+                                        "Quantity not corresponding to the query (%d != %d)\n",
+                                        response_nb_value, query_nb_value);
+                        }
+                        errno = EMBBADDATA;
+                        rc = -1;
                 }
-        } else if (ret == MB_EXCEPTION) {
+        } else if (errno == EMBUNKEXC) {
                 /* EXCEPTION CODE RECEIVED */
 
                 /* CRC must be checked here (not done in receive_msg) */
                 if (mb_param->type_com == RTU) {
-                        ret = check_crc16(mb_param, response, EXCEPTION_RESPONSE_LENGTH_RTU);
-                        if (ret < 0)
-                                return ret;
+                        rc = check_crc16(mb_param, response, EXCEPTION_RESPONSE_LENGTH_RTU);
+                        if (rc == -1)
+                                return -1;
                 }
 
                 /* Check for exception response.
                    0x80 + function is stored in the exception
                    response. */
                 if (0x80 + query[offset] == response[offset]) {
-
                         int exception_code = response[offset + 1];
-                        // FIXME check test
-                        if (exception_code < NB_TAB_ERROR_MSG) {
-                                error_treat(mb_param, -exception_code,
-                                            TAB_ERROR_MSG[response[offset + 1]]);
-                                /* RETURN THE EXCEPTION CODE */
-                                /* Modbus error code is negative */
-                                return -exception_code;
+                        if (exception_code < MODBUS_EXCEPTION_MAX) {
+                                errno = MODBUS_ENOBASE + exception_code;
                         } else {
-                                /* The chances are low to hit this
-                                   case but it can avoid a vicious
-                                   segfault */
-                                char *s_error = malloc(64 * sizeof(char));
-                                sprintf(s_error,
-                                        "Invalid exception code %d",
-                                        response[offset + 1]);
-                                error_treat(mb_param, INVALID_EXCEPTION_CODE,
-                                            s_error);
-                                free(s_error);
-                                return INVALID_EXCEPTION_CODE;
+                                errno = EMBBADEXC;
                         }
+                        error_print(mb_param, NULL);
+                        return -1;
                 }
-        } else {
-                /* Other errors */
-                error_treat(mb_param, ret, "receive_msg");
         }
 
-        return ret;
+        return rc;
 }
 
 static int response_io_status(int address, int nb,
@@ -845,7 +870,7 @@ static int response_exception(modbus_param_t *mb_param, sft_t *sft,
         response_length = build_response_basis(mb_param, sft, response);
 
         /* Positive exception code */
-        response[response_length++] = -exception_code;
+        response[response_length++] = exception_code;
 
         return response_length;
 }
@@ -856,8 +881,8 @@ static int response_exception(modbus_param_t *mb_param, sft_t *sft,
    If an error occurs, this function construct the response
    accordingly.
 */
-void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
-                         int query_length, modbus_mapping_t *mb_mapping)
+int modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
+                        int query_length, modbus_mapping_t *mb_mapping)
 {
         int offset = TAB_HEADER_LENGTH[mb_param->type_com];
         int slave = query[offset - 1];
@@ -873,7 +898,7 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                         printf("Request for slave %d ignored (not %d)\n",
                                slave, mb_param->slave);
                 }
-                return;
+                return 0;
         }
 
         sft.slave = slave;
@@ -890,10 +915,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
                 if ((address + nb) > mb_mapping->nb_coil_status) {
-                        printf("Illegal data address %0X in read_coil_status\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in read_coil_status\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                         resp_length = build_response_basis(mb_param, &sft, response);
                         response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
@@ -909,10 +937,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
                 if ((address + nb) > mb_mapping->nb_input_status) {
-                        printf("Illegal data address %0X in read_input_status\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in read_input_status\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                         resp_length = build_response_basis(mb_param, &sft, response);
                         response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
@@ -926,10 +957,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
                 if ((address + nb) > mb_mapping->nb_holding_registers) {
-                        printf("Illegal data address %0X in read_holding_registers\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in read_holding_registers\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                         int i;
 
@@ -948,10 +982,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
                 if ((address + nb) > mb_mapping->nb_input_registers) {
-                        printf("Illegal data address %0X in read_input_registers\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in read_input_registers\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                         int i;
 
@@ -966,9 +1003,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 break;
         case FC_FORCE_SINGLE_COIL:
                 if (address >= mb_mapping->nb_coil_status) {
-                        printf("Illegal data address %0X in force_singe_coil\n", address);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in force_singe_coil\n",
+                                        address);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                         int data = (query[offset + 3] << 8) + query[offset + 4];
 
@@ -982,18 +1023,25 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                                 memcpy(response, query, query_length);
                                 resp_length = query_length;
                         } else {
-                                printf("Illegal data value %0X in force_single_coil request at address %0X\n",
-                                       data, address);
-                                resp_length = response_exception(mb_param, &sft,
-                                                                 ILLEGAL_DATA_VALUE, response);
+                                if (mb_param->debug) {
+                                        fprintf(stderr, "Illegal data value %0X in force_single_coil request at address %0X\n",
+                                               data, address);
+                                }
+                                resp_length = response_exception(
+                                        mb_param, &sft,
+                                        MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, response);
                         }
                 }
                 break;
         case FC_PRESET_SINGLE_REGISTER:
                 if (address >= mb_mapping->nb_holding_registers) {
-                        printf("Illegal data address %0X in preset_holding_register\n", address);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in preset_holding_register\n",
+                                        address);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                         int data = (query[offset + 3] << 8) + query[offset + 4];
 
@@ -1006,10 +1054,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
                 if ((address + nb) > mb_mapping->nb_coil_status) {
-                        printf("Illegal data address %0X in force_multiple_coils\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in force_multiple_coils\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                         /* 6 = byte count */
                         set_bits_from_bytes(mb_mapping->tab_coil_status, address, nb, &query[offset + 6]);
@@ -1025,10 +1076,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
                 if ((address + nb) > mb_mapping->nb_holding_registers) {
-                        printf("Illegal data address %0X in preset_multiple_registers\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in preset_multiple_registers\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                         int i, j;
                         for (i = address, j = 6; i < address + nb; i++, j += 2) {
@@ -1046,18 +1100,25 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 break;
         case FC_READ_EXCEPTION_STATUS:
         case FC_REPORT_SLAVE_ID:
-                printf("Not implemented\n");
+                if (mb_param->debug) {
+                        fprintf(stderr, "FIXME Not implemented\n");
+                }
+                errno = ENOPROTOOPT;
+                return -1;
+                break;
+        default:
+                /* FIXME Invalid function exception */
                 break;
         }
 
-        modbus_send(mb_param, response, resp_length);
+        return modbus_send(mb_param, response, resp_length);
 }
 
 /* Reads IO status */
 static int read_io_status(modbus_param_t *mb_param, int function,
                           int start_addr, int nb, uint8_t *data_dest)
 {
-        int ret;
+        int rc;
         int query_length;
 
         uint8_t query[MIN_QUERY_LENGTH];
@@ -1066,19 +1127,19 @@ static int read_io_status(modbus_param_t *mb_param, int function,
         query_length = build_query_basis(mb_param, function,
                                          start_addr, nb, query);
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 int i, temp, bit;
                 int pos = 0;
                 int offset;
                 int offset_end;
 
-                ret = modbus_receive(mb_param, query, response);
-                if (ret < 0)
-                        return ret;
+                rc = modbus_receive(mb_param, query, response);
+                if (rc == -1)
+                        return -1;
 
                 offset = TAB_HEADER_LENGTH[mb_param->type_com];
-                offset_end = offset + ret;
+                offset_end = offset + rc;
                 for (i = offset; i < offset_end; i++) {
                         /* Shift reg hi_byte to temp */
                         temp = response[i + 2];
@@ -1091,7 +1152,7 @@ static int read_io_status(modbus_param_t *mb_param, int function,
                 }
         }
 
-        return ret;
+        return rc;
 }
 
 /* Reads the boolean status of coils and sets the array elements
@@ -1099,22 +1160,25 @@ static int read_io_status(modbus_param_t *mb_param, int function,
 int read_coil_status(modbus_param_t *mb_param, int start_addr,
                      int nb, uint8_t *data_dest)
 {
-        int status;
+        int rc;
 
         if (nb > MAX_STATUS) {
-                fprintf(stderr,
-                        "ERROR Too many coils status requested (%d > %d)\n",
-                        nb, MAX_STATUS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Too many coils status requested (%d > %d)\n",
+                                nb, MAX_STATUS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
 
-        status = read_io_status(mb_param, FC_READ_COIL_STATUS,
-                                start_addr, nb, data_dest);
-
-        if (status > 0)
-                status = nb;
+        rc = read_io_status(mb_param, FC_READ_COIL_STATUS, start_addr, nb,
+                            data_dest);
 
-        return status;
+        if (rc == -1)
+                return -1;
+        else
+                return nb;
 }
 
 
@@ -1122,61 +1186,67 @@ int read_coil_status(modbus_param_t *mb_param, int start_addr,
 int read_input_status(modbus_param_t *mb_param, int start_addr,
                       int nb, uint8_t *data_dest)
 {
-        int status;
+        int rc;
 
         if (nb > MAX_STATUS) {
-                fprintf(stderr,
-                        "ERROR Too many input status requested (%d > %d)\n",
-                       nb, MAX_STATUS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Too many input status requested (%d > %d)\n",
+                                nb, MAX_STATUS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
 
-        status = read_io_status(mb_param, FC_READ_INPUT_STATUS,
-                                start_addr, nb, data_dest);
+        rc = read_io_status(mb_param, FC_READ_INPUT_STATUS, start_addr,
+                            nb, data_dest);
 
-        if (status > 0)
-                status = nb;
-
-        return status;
+        if (rc == -1)
+                return -1;
+        else
+                return nb;
 }
 
 /* Reads the data from a modbus slave and put that data into an array */
 static int read_registers(modbus_param_t *mb_param, int function,
                           int start_addr, int nb, uint16_t *data_dest)
 {
-        int ret;
+        int rc;
         int query_length;
         uint8_t query[MIN_QUERY_LENGTH];
         uint8_t response[MAX_MESSAGE_LENGTH];
 
         if (nb > MAX_REGISTERS) {
-                fprintf(stderr,
-                        "ERROR Too many holding registers requested (%d > %d)\n",
-                        nb, MAX_REGISTERS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Too many holding registers requested (%d > %d)\n",
+                                nb, MAX_REGISTERS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
 
         query_length = build_query_basis(mb_param, function,
                                          start_addr, nb, query);
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 int offset;
                 int i;
 
-                ret = modbus_receive(mb_param, query, response);
+                rc = modbus_receive(mb_param, query, response);
 
                 offset = TAB_HEADER_LENGTH[mb_param->type_com];
 
-                /* If ret is negative, the loop is jumped ! */
-                for (i = 0; i < ret; i++) {
+                /* If rc is negative, the loop is jumped ! */
+                for (i = 0; i < rc; i++) {
                         /* shift reg hi_byte to temp OR with lo_byte */
                         data_dest[i] = (response[offset + 2 + (i << 1)] << 8) |
                                 response[offset + 3 + (i << 1)];
                 }
         }
 
-        return ret;
+        return rc;
 }
 
 /* Reads the holding registers in a slave and put the data into an
@@ -1187,10 +1257,13 @@ int read_holding_registers(modbus_param_t *mb_param,
         int status;
 
         if (nb > MAX_REGISTERS) {
-                fprintf(stderr,
-                        "ERROR Too many holding registers requested (%d > %d)\n",
-                        nb, MAX_REGISTERS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Too many holding registers requested (%d > %d)\n",
+                                nb, MAX_REGISTERS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
 
         status = read_registers(mb_param, FC_READ_HOLDING_REGISTERS,
@@ -1209,7 +1282,8 @@ int read_input_registers(modbus_param_t *mb_param, int start_addr, int nb,
                 fprintf(stderr,
                         "ERROR Too many input registers requested (%d > %d)\n",
                         nb, MAX_REGISTERS);
-                return INVALID_DATA;
+                errno = EMBMDATA;
+                return -1;
         }
 
         status = read_registers(mb_param, FC_READ_INPUT_REGISTERS,
@@ -1223,22 +1297,22 @@ int read_input_registers(modbus_param_t *mb_param, int start_addr, int nb,
 static int set_single(modbus_param_t *mb_param, int function,
                       int addr, int value)
 {
-        int ret;
+        int rc;
         int query_length;
         uint8_t query[MIN_QUERY_LENGTH];
 
         query_length = build_query_basis(mb_param, function,
                                          addr, value, query);
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 /* Used by force_single_coil and
                  * preset_single_register */
                 uint8_t response[MIN_QUERY_LENGTH];
-                ret = modbus_receive(mb_param, query, response);
+                rc = modbus_receive(mb_param, query, response);
         }
 
-        return ret;
+        return rc;
 }
 
 /* Turns ON or OFF a single coil in the slave device */
@@ -1270,7 +1344,7 @@ int preset_single_register(modbus_param_t *mb_param, int reg_addr, int value)
 int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
                          const uint8_t *data_src)
 {
-        int ret;
+        int rc;
         int i;
         int byte_count;
         int query_length;
@@ -1280,9 +1354,12 @@ int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
         uint8_t query[MAX_MESSAGE_LENGTH];
 
         if (nb > MAX_STATUS) {
-                fprintf(stderr, "ERROR Writing to too many coils (%d > %d)\n",
-                        nb, MAX_STATUS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr, "ERROR Writing to too many coils (%d > %d)\n",
+                                nb, MAX_STATUS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
 
         query_length = build_query_basis(mb_param, FC_FORCE_MULTIPLE_COILS,
@@ -1307,21 +1384,21 @@ int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
                 query_length++;
         }
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 uint8_t response[MAX_MESSAGE_LENGTH];
-                ret = modbus_receive(mb_param, query, response);
+                rc = modbus_receive(mb_param, query, response);
         }
 
 
-        return ret;
+        return rc;
 }
 
 /* Copies the values in the slave from the array given in argument */
 int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
                               const uint16_t *data_src)
 {
-        int ret;
+        int rc;
         int i;
         int query_length;
         int byte_count;
@@ -1329,10 +1406,13 @@ int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
         uint8_t query[MAX_MESSAGE_LENGTH];
 
         if (nb > MAX_REGISTERS) {
-                fprintf(stderr,
-                        "ERROR Trying to write to too many registers (%d > %d)\n",
-                        nb, MAX_REGISTERS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Trying to write to too many registers (%d > %d)\n",
+                                nb, MAX_REGISTERS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
 
         query_length = build_query_basis(mb_param, FC_PRESET_MULTIPLE_REGISTERS,
@@ -1345,19 +1425,19 @@ int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
                 query[query_length++] = data_src[i] & 0x00FF;
         }
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 uint8_t response[MAX_MESSAGE_LENGTH];
-                ret = modbus_receive(mb_param, query, response);
+                rc = modbus_receive(mb_param, query, response);
         }
 
-        return ret;
+        return rc;
 }
 
 /* Returns the slave id! */
 int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest)
 {
-        int ret;
+        int rc;
         int query_length;
         uint8_t query[MIN_QUERY_LENGTH];
 
@@ -1366,8 +1446,8 @@ int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest)
         /* HACKISH, start_addr and count are not used */
         query_length -= 4;
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 int i;
                 int offset;
                 int offset_end;
@@ -1375,18 +1455,18 @@ int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest)
 
                 /* Byte count, slave id, run indicator status,
                    additional data */
-                ret = modbus_receive(mb_param, query, response);
-                if (ret < 0)
-                        return ret;
+                rc = modbus_receive(mb_param, query, response);
+                if (rc == -1)
+                        return rc;
 
                 offset = TAB_HEADER_LENGTH[mb_param->type_com] - 1;
-                offset_end = offset + ret;
+                offset_end = offset + rc;
 
                 for (i = offset; i < offset_end; i++)
                         data_dest[i] = response[i];
         }
 
-        return ret;
+        return rc;
 }
 
 /* Initializes the modbus_param_t structure for RTU
@@ -1408,7 +1488,7 @@ void modbus_init_rtu(modbus_param_t *mb_param, const char *device,
         mb_param->data_bit = data_bit;
         mb_param->stop_bit = stop_bit;
         mb_param->type_com = RTU;
-        mb_param->error_handling = FLUSH_OR_CONNECT_ON_ERROR;
+        mb_param->error_recovery = FALSE;
         mb_param->slave = slave;
 }
 
@@ -1427,7 +1507,7 @@ void modbus_init_tcp(modbus_param_t *mb_param, const char *ip, int port, int sla
         strncpy(mb_param->ip, ip, sizeof(char)*16);
         mb_param->port = port;
         mb_param->type_com = TCP;
-        mb_param->error_handling = FLUSH_OR_CONNECT_ON_ERROR;
+        mb_param->error_recovery = FALSE;
         mb_param->slave = slave;
 }
 
@@ -1438,27 +1518,30 @@ void modbus_set_slave(modbus_param_t *mb_param, int slave)
         mb_param->slave = slave;
 }
 
-/* By default, the error handling mode used is FLUSH_OR_CONNECT_ON_ERROR.
+/*
+   When disabled (default), it is expected that the application will check for error
+   returns and deal with them as necessary. 
 
-   With FLUSH_OR_CONNECT_ON_ERROR, the library will attempt an immediate
-   reconnection which may hang for several seconds if the network to
-   the remote target unit is down.
+   It's not recommanded to enable error recovery for slave/server.
 
-   With NOP_ON_ERROR, it is expected that the application will
-   check for error returns and deal with them as necessary.
+   When enabled, the library will attempt an immediate reconnection which may
+   hang for several seconds if the network to the remote target unit is down.
+   The write will try a infinite close/connect loop until to be successful and
+   the select/read calls will just try to retablish the connection one time
+   then will return an error (if the connecton was down, the values to read are
+   certainly not available anymore after reconnection, except for slave/server).
 */
-void modbus_set_error_handling(modbus_param_t *mb_param,
-                               error_handling_t error_handling)
+int modbus_set_error_recovery(modbus_param_t *mb_param, int enabled)
 {
-        if (error_handling == FLUSH_OR_CONNECT_ON_ERROR ||
-            error_handling == NOP_ON_ERROR) {
-                mb_param->error_handling = error_handling;
+        if (enabled == TRUE || enabled == FALSE) {
+                mb_param->error_recovery = (uint8_t) enabled;
         } else {
-                fprintf(stderr,
-                        "Invalid setting for error handling (not changed)\n");
+                errno = EINVAL;
+                return -1;
         }
-}
 
+        return 0;
+}
 
 /* Sets up a serial port for RTU communications */
 static int modbus_connect_rtu(modbus_param_t *mb_param)
@@ -1467,8 +1550,8 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
         speed_t speed;
 
         if (mb_param->debug) {
-                fprintf(stderr, "Opening %s at %d bauds (%s)\n",
-                        mb_param->device, mb_param->baud, mb_param->parity);
+                printf("Opening %s at %d bauds (%s)\n",
+                       mb_param->device, mb_param->baud, mb_param->parity);
         }
 
         /* The O_NOCTTY flag tells UNIX that this program doesn't want
@@ -1479,7 +1562,7 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
            Timeouts are ignored in canonical input mode or when the
            NDELAY option is set on the file via open or fcntl */
         mb_param->fd = open(mb_param->device, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);
-        if (mb_param->fd < 0) {
+        if (mb_param->fd == -1) {
                 fprintf(stderr, "ERROR Can't open the device %s (%s)\n",
                         mb_param->device, strerror(errno));
                 return -1;
@@ -1529,15 +1612,16 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
                 break;
         default:
                 speed = B9600;
-                fprintf(stderr,
-                        "WARNING Unknown baud rate %d for %s (B9600 used)\n",
-                        mb_param->baud, mb_param->device);
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "WARNING Unknown baud rate %d for %s (B9600 used)\n",
+                                mb_param->baud, mb_param->device);
+                }
         }
 
         /* Set the baud rate */
         if ((cfsetispeed(&tios, speed) < 0) ||
             (cfsetospeed(&tios, speed) < 0)) {
-                perror("cfsetispeed/cfsetospeed\n");
                 return -1;
         }
 
@@ -1707,7 +1791,6 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
         tios.c_cc[VTIME] = 0;
 
         if (tcsetattr(mb_param->fd, TCSANOW, &tios) < 0) {
-                perror("tcsetattr\n");
                 return -1;
         }
 
@@ -1717,24 +1800,23 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
 /* Establishes a modbus TCP connection with a modbus slave */
 static int modbus_connect_tcp(modbus_param_t *mb_param)
 {
-        int ret;
+        int rc;
         int option;
         struct sockaddr_in addr;
 
         mb_param->fd = socket(PF_INET, SOCK_STREAM, 0);
-        if (mb_param->fd < 0) {
-                return mb_param->fd;
+        if (mb_param->fd == -1) {
+                return -1;
         }
 
         /* Set the TCP no delay flag */
         /* SOL_TCP = IPPROTO_TCP */
         option = 1;
-        ret = setsockopt(mb_param->fd, IPPROTO_TCP, TCP_NODELAY,
+        rc = setsockopt(mb_param->fd, IPPROTO_TCP, TCP_NODELAY,
                          (const void *)&option, sizeof(int));
-        if (ret < 0) {
-                perror("setsockopt TCP_NODELAY");
+        if (rc == -1) {
                 close(mb_param->fd);
-                return ret;
+                return -1;
         }
 
 #if (!HAVE_DECL___CYGWIN__)
@@ -1744,12 +1826,11 @@ static int modbus_connect_tcp(modbus_param_t *mb_param)
          **/
         /* Set the IP low delay option */
         option = IPTOS_LOWDELAY;
-        ret = setsockopt(mb_param->fd, IPPROTO_IP, IP_TOS,
+        rc = setsockopt(mb_param->fd, IPPROTO_IP, IP_TOS,
                          (const void *)&option, sizeof(int));
-        if (ret < 0) {
-                perror("setsockopt IP_TOS");
+        if (rc == -1) {
                 close(mb_param->fd);
-                return ret;
+                return -1;
         }
 #endif
 
@@ -1760,12 +1841,11 @@ static int modbus_connect_tcp(modbus_param_t *mb_param)
         addr.sin_family = AF_INET;
         addr.sin_port = htons(mb_param->port);
         addr.sin_addr.s_addr = inet_addr(mb_param->ip);
-        ret = connect(mb_param->fd, (struct sockaddr *)&addr,
+        rc = connect(mb_param->fd, (struct sockaddr *)&addr,
                       sizeof(struct sockaddr_in));
-        if (ret < 0) {
-                perror("connect");
+        if (rc == -1) {
                 close(mb_param->fd);
-                return ret;
+                return -1;
         }
 
         return 0;
@@ -1775,22 +1855,20 @@ static int modbus_connect_tcp(modbus_param_t *mb_param)
    Returns 0 on success or -1 on failure. */
 int modbus_connect(modbus_param_t *mb_param)
 {
-        int ret;
+        int rc;
 
         if (mb_param->type_com == RTU)
-                ret = modbus_connect_rtu(mb_param);
+                rc = modbus_connect_rtu(mb_param);
         else
-                ret = modbus_connect_tcp(mb_param);
+                rc = modbus_connect_tcp(mb_param);
 
-        return ret;
+        return rc;
 }
 
 /* Closes the file descriptor in RTU mode */
 static void modbus_close_rtu(modbus_param_t *mb_param)
 {
-        if (tcsetattr(mb_param->fd, TCSANOW, &(mb_param->old_tios)) < 0)
-                perror("tcsetattr");
-
+        tcsetattr(mb_param->fd, TCSANOW, &(mb_param->old_tios));
         close(mb_param->fd);
 }
 
@@ -1819,7 +1897,8 @@ void modbus_set_debug(modbus_param_t *mb_param, int boolean)
 /* Allocates 4 arrays to store coils, input status, input registers and
    holding registers. The pointers are stored in modbus_mapping structure.
 
-   Returns 0 on success and -1 on failure.
+   The modbus_mapping_new() function shall return 0 if successful. Otherwise it
+   shall return -1 and set errno to ENOMEM.
 */
 int modbus_mapping_new(modbus_mapping_t *mb_mapping,
                        int nb_coil_status, int nb_input_status,
@@ -1829,46 +1908,51 @@ int modbus_mapping_new(modbus_mapping_t *mb_mapping,
         mb_mapping->nb_coil_status = nb_coil_status;
         mb_mapping->tab_coil_status =
                 (uint8_t *) malloc(nb_coil_status * sizeof(uint8_t));
+        if (mb_mapping->tab_coil_status == NULL) {
+                errno = ENOMEM;
+                return -1;
+        }
         memset(mb_mapping->tab_coil_status, 0,
                nb_coil_status * sizeof(uint8_t));
-        if (mb_mapping->tab_coil_status == NULL)
-                return -1;
 
         /* 1X */
         mb_mapping->nb_input_status = nb_input_status;
         mb_mapping->tab_input_status =
                 (uint8_t *) malloc(nb_input_status * sizeof(uint8_t));
-        memset(mb_mapping->tab_input_status, 0,
-               nb_input_status * sizeof(uint8_t));
         if (mb_mapping->tab_input_status == NULL) {
                 free(mb_mapping->tab_coil_status);
+                errno = ENOMEM;
                 return -1;
         }
+        memset(mb_mapping->tab_input_status, 0,
+               nb_input_status * sizeof(uint8_t));
 
         /* 4X */
         mb_mapping->nb_holding_registers = nb_holding_registers;
         mb_mapping->tab_holding_registers =
                 (uint16_t *) malloc(nb_holding_registers * sizeof(uint16_t));
-        memset(mb_mapping->tab_holding_registers, 0,
-               nb_holding_registers * sizeof(uint16_t));
         if (mb_mapping->tab_holding_registers == NULL) {
                 free(mb_mapping->tab_coil_status);
                 free(mb_mapping->tab_input_status);
+                errno = ENOMEM;
                 return -1;
         }
+        memset(mb_mapping->tab_holding_registers, 0,
+               nb_holding_registers * sizeof(uint16_t));
 
         /* 3X */
         mb_mapping->nb_input_registers = nb_input_registers;
         mb_mapping->tab_input_registers =
                 (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t));
-        memset(mb_mapping->tab_input_registers, 0,
-               nb_input_registers * sizeof(uint16_t));
         if (mb_mapping->tab_input_registers == NULL) {
                 free(mb_mapping->tab_coil_status);
                 free(mb_mapping->tab_input_status);
                 free(mb_mapping->tab_holding_registers);
+                errno = ENOMEM;
                 return -1;
         }
+        memset(mb_mapping->tab_input_registers, 0,
+               nb_input_registers * sizeof(uint16_t));
 
         return 0;
 }
@@ -1890,15 +1974,13 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection)
         struct sockaddr_in addr;
 
         new_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-        if (new_socket < 0) {
-                perror("socket");
+        if (new_socket == -1) {
                 return -1;
         }
 
         yes = 1;
         if (setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR,
-                       (char *) &yes, sizeof(yes)) < 0) {
-                perror("setsockopt");
+                       (char *) &yes, sizeof(yes)) == -1) {
                 close(new_socket);
                 return -1;
         }
@@ -1908,14 +1990,12 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection)
         /* If the modbus port is < to 1024, we need the setuid root. */
         addr.sin_port = htons(mb_param->port);
         addr.sin_addr.s_addr = INADDR_ANY;
-        if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-                perror("bind");
+        if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
                 close(new_socket);
                 return -1;
         }
 
-        if (listen(new_socket, nb_connection) < 0) {
-                perror("listen");
+        if (listen(new_socket, nb_connection) == -1) {
                 close(new_socket);
                 return -1;
         }
@@ -1923,6 +2003,9 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection)
         return new_socket;
 }
 
+/* On success, the function return a non-negative integer that is a descriptor
+   for the accepted socket. On error, -1 is returned, and errno is set
+   appropriately. */
 int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket)
 {
         struct sockaddr_in addr;
@@ -1930,11 +2013,13 @@ int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket)
 
         addrlen = sizeof(struct sockaddr_in);
         mb_param->fd = accept(*socket, (struct sockaddr *)&addr, &addrlen);
-        if (mb_param->fd < 0) {
-                perror("accept");
+        if (mb_param->fd == -1) {
                 close(*socket);
                 *socket = 0;
-        } else {
+                return -1;
+        }
+
+        if (mb_param->debug) {
                 printf("The client %s is connected\n",
                        inet_ntoa(addr.sin_addr));
         }
@@ -1964,7 +2049,7 @@ void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value)
 
 /* Sets many input/coil status from a table of bytes (only the bits
    between address and address + nb_bits are set) */
-void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits,
+void set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits,
                          const uint8_t tab_byte[])
 {
         int i;
@@ -1980,13 +2065,13 @@ void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits,
 
 /* Gets the byte value from many input/coil status.
    To obtain a full byte, set nb_bits to 8. */
-uint8_t get_byte_from_bits(const uint8_t *src, int address, int nb_bits)
+uint8_t get_byte_from_bits(const uint8_t *src, int address, unsigned int nb_bits)
 {
         int i;
         uint8_t value = 0;
 
         if (nb_bits > 8) {
-                fprintf(stderr, "ERROR nb_bits is too big\n");
+                assert(nb_bits < 8);
                 nb_bits = 8;
         }
 

+ 54 - 154
modbus/modbus.h

@@ -120,36 +120,47 @@ extern "C" {
 #define FC_PRESET_MULTIPLE_REGISTERS 0x10
 #define FC_REPORT_SLAVE_ID           0x11
 
+/* Random number to avoid errno conflicts */
+#define MODBUS_ENOBASE 112345678
+
 /* Protocol exceptions */
-#define ILLEGAL_FUNCTION        -0x01
-#define ILLEGAL_DATA_ADDRESS    -0x02
-#define ILLEGAL_DATA_VALUE      -0x03
-#define SLAVE_DEVICE_FAILURE    -0x04
-#define SERVER_FAILURE          -0x04
-#define ACKNOWLEDGE             -0x05
-#define SLAVE_DEVICE_BUSY       -0x06
-#define SERVER_BUSY             -0x06
-#define NEGATIVE_ACKNOWLEDGE    -0x07
-#define MEMORY_PARITY_ERROR     -0x08
-#define GATEWAY_PROBLEM_PATH    -0x0A
-#define GATEWAY_PROBLEM_TARGET  -0x0B
-
-/* Local */
-#define INVALID_DATA            -0x10
-#define INVALID_CRC             -0x11
-#define INVALID_EXCEPTION_CODE  -0x12
-
-#define SELECT_TIMEOUT          -0x13
-#define SELECT_FAILURE          -0x14
-#define SOCKET_FAILURE          -0x15
-#define CONNECTION_CLOSED       -0x16
-#define MB_EXCEPTION             -0x17
+enum {
+        MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
+        MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
+        MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
+        MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
+        MODBUS_EXCEPTION_ACKNOWLEDGE,
+        MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
+        MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
+        MODBUS_EXCEPTION_MEMORY_PARITY,
+        MODBUS_EXCEPTION_NOT_DEFINED,
+        MODBUS_EXCEPTION_GATEWAY_PATH,
+        MODBUS_EXCEPTION_GATEWAY_TARGET,
+        MODBUS_EXCEPTION_MAX
+};
+
+#define EMBXILFUN  (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION)
+#define EMBXILADD  (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)
+#define EMBXILVAL  (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)
+#define EMBXSFAIL  (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)
+#define EMBXACK    (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE)
+#define EMBXSBUSY  (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)
+#define EMBXNACK   (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)
+#define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY)
+#define EMBXGPATH  (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH)
+#define EMBXGTAR   (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
+
+/* Native libmodbus error codes */
+#define EMBBADCRC  (EMBXGTAR + 1)
+#define EMBBADDATA (EMBXGTAR + 2)
+#define EMBBADEXC  (EMBXGTAR + 3)
+#define EMBUNKEXC  (EMBXGTAR + 4)
+#define EMBMDATA   (EMBXGTAR + 5)
 
 /* Internal using */
 #define MSG_LENGTH_UNDEFINED -1
 
 typedef enum { RTU=0, TCP } type_com_t;
-typedef enum { FLUSH_OR_CONNECT_ON_ERROR, NOP_ON_ERROR } error_handling_t;
 
 /* This structure is byte-aligned */
 typedef struct {
@@ -183,7 +194,7 @@ typedef struct {
         /* Parity: "even", "odd", "none" */
         char parity[5];
         /* In error_treat with TCP, do a reconnect or just dump the error */
-        uint8_t error_handling;
+        uint8_t error_recovery;
         /* IP address */
         char ip[16];
         /* Save old termios settings */
@@ -201,171 +212,60 @@ typedef struct {
         uint16_t *tab_holding_registers;
 } modbus_mapping_t;
 
+void modbus_init_rtu(modbus_param_t *mb_param, const char *device,
+                     int baud, const char *parity, int data_bit,
+                     int stop_bit, int slave);
+void modbus_init_tcp(modbus_param_t *mb_param, const char *ip_address, int port,
+                     int slave);
+void modbus_set_slave(modbus_param_t *mb_param, int slave);
+int modbus_set_error_recovery(modbus_param_t *mb_param, int enabled);
 
-/* All functions used for sending or receiving data return:
-   - the numbers of values (bits or word) if success (0 or more)
-   - less than 0 for exceptions errors
-*/
+int modbus_connect(modbus_param_t *mb_param);
+void modbus_close(modbus_param_t *mb_param);
+
+int modbus_flush(modbus_param_t *mb_param);
+void modbus_set_debug(modbus_param_t *mb_param, int boolean);
+
+const char *modbus_strerror(int errnum);
 
-/* Reads the boolean status of coils and sets the array elements in
-   the destination to TRUE or FALSE */
 int read_coil_status(modbus_param_t *mb_param, int start_addr, int nb,
                      uint8_t *dest);
-
-/* Same as read_coil_status but reads the slaves input table */
 int read_input_status(modbus_param_t *mb_param, int start_addr, int nb,
                       uint8_t *dest);
-
-/* Reads the holding registers in a slave and put the data into an
-   array */
 int read_holding_registers(modbus_param_t *mb_param, int start_addr, int nb,
                            uint16_t *dest);
-
-/* Reads the input registers in a slave and put the data into an
-   array */
 int read_input_registers(modbus_param_t *mb_param, int start_addr, int nb,
                          uint16_t *dest);
-
-/* Turns ON or OFF a single coil in the slave device */
 int force_single_coil(modbus_param_t *mb_param, int coil_addr, int state);
 
-/* Sets a value in one holding register in the slave device */
 int preset_single_register(modbus_param_t *mb_param, int reg_addr, int value);
-
-/* Sets/resets the coils in the slave from an array in argument */
 int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
                          const uint8_t *data);
-
-/* Copies the values in the slave from the array given in argument */
 int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
                               const uint16_t *data);
-
-/* Returns the slave id! */
 int report_slave_id(modbus_param_t *mb_param, uint8_t *dest);
 
-/* Initializes the modbus_param_t structure for RTU.
-   - device: "/dev/ttyS0"
-   - baud:   9600, 19200, 57600, 115200, etc
-   - parity: "even", "odd" or "none"
-   - data_bits: 5, 6, 7, 8
-   - stop_bits: 1, 2
-*/
-void modbus_init_rtu(modbus_param_t *mb_param, const char *device,
-                     int baud, const char *parity, int data_bit,
-                     int stop_bit, int slave);
-
-/* Initializes the modbus_param_t structure for TCP.
-   - ip: "192.168.0.5"
-   - port: 1099
-   - slave: 5
-
-   Set the port to MODBUS_TCP_DEFAULT_PORT to use the default one
-   (502). It's convenient to use a port number greater than or equal
-   to 1024 because it's not necessary to be root to use this port
-   number.
-*/
-void modbus_init_tcp(modbus_param_t *mb_param, const char *ip_address, int port,
-                     int slave);
-
-/* Define the slave number.
-   The special value MODBUS_BROADCAST_ADDRESS can be used. */
-void modbus_set_slave(modbus_param_t *mb_param, int slave);
-
-/* By default, the error handling mode used is CONNECT_ON_ERROR.
-
-   With FLUSH_OR_CONNECT_ON_ERROR, the library will attempt an immediate
-   reconnection which may hang for several seconds if the network to
-   the remote target unit is down.
-
-   With NOP_ON_ERROR, it is expected that the application will
-   check for network error returns and deal with them as necessary.
-
-   This function is only useful in TCP mode.
- */
-void modbus_set_error_handling(modbus_param_t *mb_param, error_handling_t error_handling);
-
-/* Establishes a modbus connexion.
-   Returns 0 on success or -1 on failure. */
-int modbus_connect(modbus_param_t *mb_param);
-
-/* Closes a modbus connection */
-void modbus_close(modbus_param_t *mb_param);
-
-/* Flush the pending request */
-void modbus_flush(modbus_param_t *mb_param);
-
-/* Activates the debug messages */
-void modbus_set_debug(modbus_param_t *mb_param, int boolean);
-
-/**
- * SLAVE/CLIENT FUNCTIONS
- **/
-
-/* Allocates 4 arrays to store coils, input status, input registers and
-   holding registers. The pointers are stored in modbus_mapping structure.
-
-   Returns 0 on success and -1 on failure
- */
 int modbus_mapping_new(modbus_mapping_t *mb_mapping,
                        int nb_coil_status, int nb_input_status,
                        int nb_holding_registers, int nb_input_registers);
-
-/* Frees the 4 arrays */
 void modbus_mapping_free(modbus_mapping_t *mb_mapping);
 
-/* Listens for any query from one or many modbus masters in TCP.
-
-   Returns: socket
- */
 int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection);
-
-/* Waits for a connection */
 int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket);
-
-/* Listens for any query from a modbus master in TCP, requires the socket file
-   descriptor etablished with the master device in argument or -1 to use the
-   internal one of modbus_param_t.
-
-   Returns:
-   - byte length of the message on success, or a negative error number if the
-     request fails
-   - query, message received
-*/
 int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query);
-
-/* Manages the received query.
-   Analyses the query and constructs a response.
-
-   If an error occurs, this function construct the response
-   accordingly.
-*/
-void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
-                         int query_length, modbus_mapping_t *mb_mapping);
-
-/* Closes a TCP socket */
+int modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
+                        int query_length, modbus_mapping_t *mb_mapping);
 void modbus_slave_close_tcp(int socket);
 
 /**
  * UTILS FUNCTIONS
  **/
 
-/* Sets many input/coil status from a single byte value (all 8 bits of
-   the byte value are set) */
 void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value);
-
-/* Sets many input/coil status from a table of bytes (only the bits
-   between address and address + nb_bits are set) */
-void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits,
+void set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits,
                          const uint8_t *tab_byte);
-
-/* Gets the byte value from many input/coil status.
-   To obtain a full byte, set nb_bits to 8. */
-uint8_t get_byte_from_bits(const uint8_t *src, int address, int nb_bits);
-
-/* Read a float from 4 bytes in Modbus format */
+uint8_t get_byte_from_bits(const uint8_t *src, int address, unsigned int nb_bits);
 float modbus_read_float(const uint16_t *src);
-
-/* Write a float to 4 bytes in Modbus format */
 void modbus_write_float(float real, uint16_t *dest);
 
 #ifdef __cplusplus

+ 17 - 5
tests/bandwidth-master.c

@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <time.h>
 #include <sys/time.h>
+#include <errno.h>
 
 #include <modbus/modbus.h>
 
@@ -44,18 +45,21 @@ int main(void)
         uint16_t *tab_rp_registers;
         modbus_param_t mb_param;
         int i;
-        int ret;
         int nb_points;
         double elapsed;
         uint32_t start;
         uint32_t end;
         uint32_t bytes;
         uint32_t rate;
+        int rc;
 
         /* TCP */
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
-        if (modbus_connect(&mb_param) == -1) {
-                exit(1);
+        rc = modbus_connect(&mb_param);
+        if (rc == -1) {
+                fprintf(stderr, "Connexion failed: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
 
         /* Allocate and initialize the memory to store the status */
@@ -71,7 +75,11 @@ int main(void)
         nb_points = MAX_STATUS;
         start = gettime_ms();
         for (i=0; i<NB_LOOPS; i++) {
-                ret = read_coil_status(&mb_param, 0, nb_points, tab_rp_status);
+                rc = read_coil_status(&mb_param, 0, nb_points, tab_rp_status);
+                if (rc == -1) {
+                        fprintf(stderr, modbus_strerror(errno));
+                        return -1;
+                }
         }
         end = gettime_ms();
         elapsed = end - start;
@@ -104,7 +112,11 @@ int main(void)
         nb_points = MAX_REGISTERS;
         start = gettime_ms();
         for (i=0; i<NB_LOOPS; i++) {
-                ret = read_holding_registers(&mb_param, 0, nb_points, tab_rp_registers);
+                rc = read_holding_registers(&mb_param, 0, nb_points, tab_rp_registers);
+                if (rc == -1) {
+                        fprintf(stderr, modbus_strerror(errno));
+                        return -1;
+                }
         }
         end = gettime_ms();
         elapsed = end - start;

+ 9 - 8
tests/bandwidth-slave-many-up.c

@@ -42,7 +42,7 @@ int main(void)
 {
         int master_socket;
         modbus_param_t mb_param;
-        int ret;
+        int rc;
         fd_set refset;
         fd_set rdset;
 
@@ -51,10 +51,11 @@ int main(void)
 
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
 
-        ret = modbus_mapping_new(&mb_mapping,  MAX_STATUS, 0, MAX_REGISTERS, 0);
-        if (ret < 0) {
-                fprintf(stderr, "Memory allocation failure\n");
-                exit(1);
+        rc = modbus_mapping_new(&mb_mapping,  MAX_STATUS, 0, MAX_REGISTERS, 0);
+        if (rc == -1) {
+                fprintf(stderr, "Failed to allocate the mapping: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
 
         slave_socket = modbus_slave_listen_tcp(&mb_param, NB_CONNECTION);
@@ -107,9 +108,9 @@ int main(void)
                                         /* An already connected master has sent a new query */
                                         uint8_t query[MAX_MESSAGE_LENGTH];
 
-                                        ret = modbus_slave_receive(&mb_param, master_socket, query);
-                                        if (ret >= 0) {
-                                                modbus_slave_manage(&mb_param, query, ret, &mb_mapping);
+                                        rc = modbus_slave_receive(&mb_param, master_socket, query);
+                                        if (rc != -1) {
+                                                modbus_slave_manage(&mb_param, query, rc, &mb_mapping);
                                         } else {
                                                 /* Connection closed by the client, end of server */
                                                 printf("Connection closed on socket %d\n", master_socket);

+ 15 - 13
tests/bandwidth-slave-one.c

@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include <modbus/modbus.h>
 
@@ -29,33 +30,34 @@ int main(void)
         int socket;
         modbus_param_t mb_param;
         modbus_mapping_t mb_mapping;
-        int ret;
+        int rc;
 
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
 
-        ret = modbus_mapping_new(&mb_mapping,  MAX_STATUS, 0, MAX_REGISTERS, 0);
-        if (ret < 0) {
-                fprintf(stderr, "Memory allocation failed\n");
-                exit(1);
+        rc = modbus_mapping_new(&mb_mapping,  MAX_STATUS, 0, MAX_REGISTERS, 0);
+        if (rc == -1) {
+                fprintf(stderr, "Failed to allocate the mapping: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
 
         socket = modbus_slave_listen_tcp(&mb_param, 1);
         modbus_slave_accept_tcp(&mb_param, &socket);
 
-        while (1) {
+        for(;;) {
                 uint8_t query[MAX_MESSAGE_LENGTH];
 
-                ret = modbus_slave_receive(&mb_param, -1, query);
-                if (ret >= 0) {
-                        modbus_slave_manage(&mb_param, query, ret, &mb_mapping);
-                } else if (ret == CONNECTION_CLOSED) {
-                        /* Connection closed by the client, end of server */
-                        break;
+                rc = modbus_slave_receive(&mb_param, -1, query);
+                if (rc >= 0) {
+                        modbus_slave_manage(&mb_param, query, rc, &mb_mapping);
                 } else {
-                        fprintf(stderr, "Error in modbus_listen (%d)\n", ret);
+                        /* Connection closed by the client or server */
+                        break;
                 }
         }
 
+        printf("Quit the loop: %s\n", modbus_strerror(errno));
+
         close(socket);
         modbus_mapping_free(&mb_mapping);
         modbus_close(&mb_param);

+ 28 - 25
tests/random-test-master.c

@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include <modbus/modbus.h>
 
@@ -45,7 +46,7 @@
  */
 int main(void)
 {
-        int ret;
+        int rc;
         int nb_fail;
         int nb_loop;
         int addr;
@@ -63,7 +64,9 @@ int main(void)
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_set_debug(&mb_param, TRUE);
         if (modbus_connect(&mb_param) == -1) {
-                exit(1);
+                fprintf(stderr, "Connection failed: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
 
         /* Allocate and initialize the different memory spaces */
@@ -94,16 +97,16 @@ int main(void)
                         nb = ADDRESS_END - addr;
 
                         /* SINGLE COIL */
-                        ret = force_single_coil(&mb_param, addr, tab_rq_status[0]);
-                        if (ret != 1) {
-                                printf("ERROR force_single_coil (%d)\n", ret);
+                        rc = force_single_coil(&mb_param, addr, tab_rq_status[0]);
+                        if (rc != 1) {
+                                printf("ERROR force_single_coil (%d)\n", rc);
                                 printf("Slave = %d, address = %d, value = %d\n",
                                        SLAVE, addr, tab_rq_status[0]);
                                 nb_fail++;
                         } else {
-                                ret = read_coil_status(&mb_param, addr, 1, tab_rp_status);
-                                if (ret != 1 || tab_rq_status[0] != tab_rp_status[0]) {
-                                        printf("ERROR read_coil_status single (%d)\n", ret);
+                                rc = read_coil_status(&mb_param, addr, 1, tab_rp_status);
+                                if (rc != 1 || tab_rq_status[0] != tab_rp_status[0]) {
+                                        printf("ERROR read_coil_status single (%d)\n", rc);
                                         printf("Slave = %d, address = %d\n",
                                                SLAVE, addr);
                                         nb_fail++;
@@ -111,15 +114,15 @@ int main(void)
                         }
 
                         /* MULTIPLE COILS */
-                        ret = force_multiple_coils(&mb_param, addr, nb, tab_rq_status);
-                        if (ret != nb) {
-                                printf("ERROR force_multiple_coils (%d)\n", ret);
+                        rc = force_multiple_coils(&mb_param, addr, nb, tab_rq_status);
+                        if (rc != nb) {
+                                printf("ERROR force_multiple_coils (%d)\n", rc);
                                 printf("Slave = %d, address = %d, nb = %d\n",
                                        SLAVE, addr, nb);
                                 nb_fail++;
                         } else {
-                                ret = read_coil_status(&mb_param, addr, nb, tab_rp_status);
-                                if (ret != nb) {
+                                rc = read_coil_status(&mb_param, addr, nb, tab_rp_status);
+                                if (rc != nb) {
                                         printf("ERROR read_coil_status\n");
                                         printf("Slave = %d, address = %d, nb = %d\n",
                                                SLAVE, addr, nb);
@@ -139,16 +142,16 @@ int main(void)
                         }
 
                         /* SINGLE REGISTER */
-                        ret = preset_single_register(&mb_param, addr, tab_rq_registers[0]);
-                        if (ret != 1) {
-                                printf("ERROR preset_single_register (%d)\n", ret);
+                        rc = preset_single_register(&mb_param, addr, tab_rq_registers[0]);
+                        if (rc != 1) {
+                                printf("ERROR preset_single_register (%d)\n", rc);
                                 printf("Slave = %d, address = %d, value = %d (0x%X)\n",
                                        SLAVE, addr, tab_rq_registers[0], tab_rq_registers[0]);
                                 nb_fail++;
                         } else {
-                                ret = read_holding_registers(&mb_param, addr, 1, tab_rp_registers);
-                                if (ret != 1) {
-                                        printf("ERROR read_holding_registers single (%d)\n", ret);
+                                rc = read_holding_registers(&mb_param, addr, 1, tab_rp_registers);
+                                if (rc != 1) {
+                                        printf("ERROR read_holding_registers single (%d)\n", rc);
                                         printf("Slave = %d, address = %d\n",
                                                SLAVE, addr);
                                         nb_fail++;
@@ -165,18 +168,18 @@ int main(void)
                         }
 
                         /* MULTIPLE REGISTERS */
-                        ret = preset_multiple_registers(&mb_param, addr, nb,
+                        rc = preset_multiple_registers(&mb_param, addr, nb,
                                                         tab_rq_registers);
-                        if (ret != nb) {
-                                printf("ERROR preset_multiple_registers (%d)\n", ret);
+                        if (rc != nb) {
+                                printf("ERROR preset_multiple_registers (%d)\n", rc);
                                 printf("Slave = %d, address = %d, nb = %d\n",
                                                SLAVE, addr, nb);
                                 nb_fail++;
                         } else {
-                                ret = read_holding_registers(&mb_param, addr, nb,
+                                rc = read_holding_registers(&mb_param, addr, nb,
                                                              tab_rp_registers);
-                                if (ret != nb) {
-                                        printf("ERROR read_holding_registers (%d)\n", ret);
+                                if (rc != nb) {
+                                        printf("ERROR read_holding_registers (%d)\n", rc);
                                         printf("Slave = %d, address = %d, nb = %d\n",
                                                SLAVE, addr, nb);
                                         nb_fail++;

+ 17 - 15
tests/random-test-slave.c

@@ -18,6 +18,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include <modbus/modbus.h>
 
@@ -28,36 +29,37 @@ int main(void)
         int socket;
         modbus_param_t mb_param;
         modbus_mapping_t mb_mapping;
-        int ret;
+        int rc;
 
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         /* modbus_set_debug(&mb_param, TRUE); */
 
-        ret = modbus_mapping_new(&mb_mapping, 500, 500, 500, 500);
-        if (ret < 0) {
-                fprintf(stderr, "Memory allocation failed\n");
-                exit(1);
+        rc = modbus_mapping_new(&mb_mapping, 500, 500, 500, 500);
+        if (rc == -1) {
+                fprintf(stderr, "Failed to allocate the mapping: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
 
         socket = modbus_slave_listen_tcp(&mb_param, 1);
         modbus_slave_accept_tcp(&mb_param, &socket);
 
-        while (1) {
+        for (;;) {
                 uint8_t query[MAX_MESSAGE_LENGTH];
-                int ret;
+                int rc;
 
-                ret = modbus_slave_receive(&mb_param, -1, query);
-                if (ret >= 0) {
-                        /* ret is the query size */
-                        modbus_slave_manage(&mb_param, query, ret, &mb_mapping);
-                } else if (ret == CONNECTION_CLOSED) {
-                        /* Connection closed by the client, end of server */
-                        break;
+                rc = modbus_slave_receive(&mb_param, -1, query);
+                if (rc != -1) {
+                        /* rc is the query size */
+                        modbus_slave_manage(&mb_param, query, rc, &mb_mapping);
                 } else {
-                        fprintf(stderr, "Error in modbus_listen (%d)\n", ret);
+                        /* Connection closed by the client or error */
+                        break;
                 }
         }
 
+        printf("Quit the loop: %s\n", modbus_strerror(errno));
+
         close(socket);
         modbus_mapping_free(&mb_mapping);
         modbus_close(&mb_param);

+ 129 - 126
tests/unit-test-master.c

@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include <modbus/modbus.h>
 #include "unit-test.h"
@@ -36,7 +37,7 @@ int main(void)
         uint8_t value;
         int address;
         int nb_points;
-        int ret;
+        int rc;
         float real;
 
         /* RTU parity : none, even, odd */
@@ -44,10 +45,12 @@ int main(void)
 
         /* TCP */
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
-/*        modbus_set_debug(&mb_param, TRUE); */
+        modbus_set_debug(&mb_param, TRUE);
 
         if (modbus_connect(&mb_param) == -1) {
-                exit(1);
+                fprintf(stderr, "Connection failed: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
 
         /* Allocate and initialize the memory to store the status */
@@ -70,20 +73,20 @@ int main(void)
         /** COIL STATUS **/
 
         /* Single */
-        ret = force_single_coil(&mb_param, UT_COIL_STATUS_ADDRESS, ON);
+        rc = force_single_coil(&mb_param, UT_COIL_STATUS_ADDRESS, ON);
         printf("1/2 force_single_coil: ");
-        if (ret == 1) {
+        if (rc == 1) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS, 1,
-                               tab_rp_status);
+        rc = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS, 1,
+                              tab_rp_status);
         printf("2/2 read_coil_status: ");
-        if (ret != 1) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != 1) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
         }
 
@@ -100,12 +103,12 @@ int main(void)
 
                 set_bits_from_bytes(tab_value, 0, UT_COIL_STATUS_NB_POINTS,
                                     UT_COIL_STATUS_TAB);
-                ret = force_multiple_coils(&mb_param,
-                                           UT_COIL_STATUS_ADDRESS,
-                                           UT_COIL_STATUS_NB_POINTS,
-                                           tab_value);
+                rc = force_multiple_coils(&mb_param,
+                                          UT_COIL_STATUS_ADDRESS,
+                                          UT_COIL_STATUS_NB_POINTS,
+                                          tab_value);
                 printf("1/2 force_multiple_coils: ");
-                if (ret == UT_COIL_STATUS_NB_POINTS) {
+                if (rc == UT_COIL_STATUS_NB_POINTS) {
                         printf("OK\n");
                 } else {
                         printf("FAILED\n");
@@ -113,11 +116,11 @@ int main(void)
                 }
         }
 
-        ret = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS,
-                               UT_COIL_STATUS_NB_POINTS, tab_rp_status);
+        rc = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS,
+                              UT_COIL_STATUS_NB_POINTS, tab_rp_status);
         printf("2/2 read_coil_status: ");
-        if (ret != UT_COIL_STATUS_NB_POINTS) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != UT_COIL_STATUS_NB_POINTS) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
         }
 
@@ -141,12 +144,12 @@ int main(void)
         /* End of multiple coils */
 
         /** INPUT STATUS **/
-        ret = read_input_status(&mb_param, UT_INPUT_STATUS_ADDRESS,
-                                UT_INPUT_STATUS_NB_POINTS, tab_rp_status);
+        rc = read_input_status(&mb_param, UT_INPUT_STATUS_ADDRESS,
+                               UT_INPUT_STATUS_NB_POINTS, tab_rp_status);
         printf("1/1 read_input_status: ");
 
-        if (ret != UT_INPUT_STATUS_NB_POINTS) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != UT_INPUT_STATUS_NB_POINTS) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
         }
 
@@ -171,22 +174,22 @@ int main(void)
         /** HOLDING REGISTERS **/
 
         /* Single register */
-        ret = preset_single_register(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS, 0x1234);
+        rc = preset_single_register(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS, 0x1234);
         printf("1/2 preset_single_register: ");
-        if (ret == 1) {
+        if (rc == 1) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     1, tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    1, tab_rp_registers);
         printf("2/2 read_holding_registers: ");
-        if (ret != 1) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != 1) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
         }
 
@@ -199,25 +202,25 @@ int main(void)
         /* End of single register */
 
         /* Many registers */
-        ret = preset_multiple_registers(&mb_param,
-                                        UT_HOLDING_REGISTERS_ADDRESS,
-                                        UT_HOLDING_REGISTERS_NB_POINTS,
-                                        UT_HOLDING_REGISTERS_TAB);
+        rc = preset_multiple_registers(&mb_param,
+                                       UT_HOLDING_REGISTERS_ADDRESS,
+                                       UT_HOLDING_REGISTERS_NB_POINTS,
+                                       UT_HOLDING_REGISTERS_TAB);
         printf("1/2 preset_multiple_registers: ");
-        if (ret == UT_HOLDING_REGISTERS_NB_POINTS) {
+        if (rc == UT_HOLDING_REGISTERS_NB_POINTS) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     UT_HOLDING_REGISTERS_NB_POINTS,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    UT_HOLDING_REGISTERS_NB_POINTS,
+                                    tab_rp_registers);
         printf("2/2 read_holding_registers: ");
-        if (ret != UT_HOLDING_REGISTERS_NB_POINTS) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != UT_HOLDING_REGISTERS_NB_POINTS) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
         }
 
@@ -234,13 +237,13 @@ int main(void)
 
 
         /** INPUT REGISTERS **/
-        ret = read_input_registers(&mb_param,
-                                   UT_INPUT_REGISTERS_ADDRESS,
-                                   UT_INPUT_REGISTERS_NB_POINTS,
-                                   tab_rp_registers);
+        rc = read_input_registers(&mb_param,
+                                  UT_INPUT_REGISTERS_ADDRESS,
+                                  UT_INPUT_REGISTERS_NB_POINTS,
+                                  tab_rp_registers);
         printf("1/1 read_input_registers: ");
-        if (ret != UT_INPUT_REGISTERS_NB_POINTS) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != UT_INPUT_REGISTERS_NB_POINTS) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
         }
 
@@ -284,83 +287,83 @@ int main(void)
         /* The mapping begins at 0 and ending at address + nb_points so
          * the addresses below are not valid. */
 
-        ret = read_coil_status(&mb_param,
-                               UT_COIL_STATUS_ADDRESS,
-                               UT_COIL_STATUS_NB_POINTS + 1,
-                               tab_rp_status);
+        rc = read_coil_status(&mb_param,
+                              UT_COIL_STATUS_ADDRESS,
+                              UT_COIL_STATUS_NB_POINTS + 1,
+                              tab_rp_status);
         printf("* read_coil_status: ");
-        if (ret == ILLEGAL_DATA_ADDRESS)
+        if (rc == -1 && errno == EMBXILADD)
                 printf("OK\n");
         else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = read_input_status(&mb_param,
-                                UT_INPUT_STATUS_ADDRESS,
-                                UT_INPUT_STATUS_NB_POINTS + 1,
-                                tab_rp_status);
+        rc = read_input_status(&mb_param,
+                               UT_INPUT_STATUS_ADDRESS,
+                               UT_INPUT_STATUS_NB_POINTS + 1,
+                               tab_rp_status);
         printf("* read_input_status: ");
-        if (ret == ILLEGAL_DATA_ADDRESS)
+        if (rc == -1 && errno == EMBXILADD)
                 printf("OK\n");
         else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     UT_HOLDING_REGISTERS_NB_POINTS + 1,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    UT_HOLDING_REGISTERS_NB_POINTS + 1,
+                                    tab_rp_registers);
         printf("* read_holding_registers: ");
-        if (ret == ILLEGAL_DATA_ADDRESS)
+        if (rc == -1 && errno == EMBXILADD)
                 printf("OK\n");
         else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = read_input_registers(&mb_param,
-                                   UT_INPUT_REGISTERS_ADDRESS,
-                                   UT_INPUT_REGISTERS_NB_POINTS + 1,
-                                   tab_rp_registers);
+        rc = read_input_registers(&mb_param,
+                                  UT_INPUT_REGISTERS_ADDRESS,
+                                  UT_INPUT_REGISTERS_NB_POINTS + 1,
+                                  tab_rp_registers);
         printf("* read_input_registers: ");
-        if (ret == ILLEGAL_DATA_ADDRESS)
+        if (rc == -1 && errno == EMBXILADD)
                 printf("OK\n");
         else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = force_single_coil(&mb_param,
-                                UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
-                                ON);
+        rc = force_single_coil(&mb_param,
+                               UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
+                               ON);
         printf("* force_single_coil: ");
-        if (ret == ILLEGAL_DATA_ADDRESS) {
+        if (rc == -1 && errno == EMBXILADD) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = force_multiple_coils(&mb_param,
-                                   UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
-                                   UT_COIL_STATUS_NB_POINTS,
-                                   tab_rp_status);
+        rc = force_multiple_coils(&mb_param,
+                                  UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
+                                  UT_COIL_STATUS_NB_POINTS,
+                                  tab_rp_status);
         printf("* force_multiple_coils: ");
-        if (ret == ILLEGAL_DATA_ADDRESS) {
+        if (rc == -1 && errno == EMBXILADD) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = preset_multiple_registers(&mb_param,
-                                        UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS,
-                                        UT_HOLDING_REGISTERS_NB_POINTS,
-                                        tab_rp_registers);
+        rc = preset_multiple_registers(&mb_param,
+                                       UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS,
+                                       UT_HOLDING_REGISTERS_NB_POINTS,
+                                       tab_rp_registers);
         printf("* preset_multiple_registers: ");
-        if (ret == ILLEGAL_DATA_ADDRESS) {
+        if (rc == -1 && errno == EMBXILADD) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
@@ -371,72 +374,72 @@ int main(void)
         /** TOO MANY DATA **/
         printf("\nTEST TOO MANY DATA ERROR:\n");
 
-        ret = read_coil_status(&mb_param,
-                               UT_COIL_STATUS_ADDRESS,
-                               MAX_STATUS + 1,
-                               tab_rp_status);
+        rc = read_coil_status(&mb_param,
+                              UT_COIL_STATUS_ADDRESS,
+                              MAX_STATUS + 1,
+                              tab_rp_status);
         printf("* read_coil_status: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = read_input_status(&mb_param,
-                                UT_INPUT_STATUS_ADDRESS,
-                                MAX_STATUS + 1,
-                                tab_rp_status);
+        rc = read_input_status(&mb_param,
+                               UT_INPUT_STATUS_ADDRESS,
+                               MAX_STATUS + 1,
+                               tab_rp_status);
         printf("* read_input_status: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     MAX_REGISTERS + 1,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    MAX_REGISTERS + 1,
+                                    tab_rp_registers);
         printf("* read_holding_registers: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = read_input_registers(&mb_param,
-                                   UT_INPUT_REGISTERS_ADDRESS,
-                                   MAX_REGISTERS + 1,
-                                   tab_rp_registers);
+        rc = read_input_registers(&mb_param,
+                                  UT_INPUT_REGISTERS_ADDRESS,
+                                  MAX_REGISTERS + 1,
+                                  tab_rp_registers);
         printf("* read_input_registers: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
                 goto close;
         }
 
-        ret = force_multiple_coils(&mb_param,
-                                   UT_COIL_STATUS_ADDRESS,
-                                   MAX_STATUS + 1,
-                                   tab_rp_status);
+        rc = force_multiple_coils(&mb_param,
+                                  UT_COIL_STATUS_ADDRESS,
+                                  MAX_STATUS + 1,
+                                  tab_rp_status);
         printf("* force_multiple_coils: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
         } else {
                 goto close;
                 printf("FAILED\n");
         }
 
-        ret = preset_multiple_registers(&mb_param,
-                                        UT_HOLDING_REGISTERS_ADDRESS,
-                                        MAX_REGISTERS + 1,
-                                        tab_rp_registers);
+        rc = preset_multiple_registers(&mb_param,
+                                       UT_HOLDING_REGISTERS_ADDRESS,
+                                       MAX_REGISTERS + 1,
+                                       tab_rp_registers);
         printf("* preset_multiple_registers: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
@@ -446,12 +449,12 @@ int main(void)
         /** SLAVE REPLY **/
         printf("\nTEST SLAVE REPLY:\n");
         modbus_set_slave(&mb_param, 18);
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS+1,
-                                     UT_HOLDING_REGISTERS_NB_POINTS,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS+1,
+                                    UT_HOLDING_REGISTERS_NB_POINTS,
+                                    tab_rp_registers);
         printf("1/2 No reply from slave %d: ", mb_param.slave);
-        if (ret == SELECT_TIMEOUT) {
+        if (rc == -1 && errno == ETIMEDOUT) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");
@@ -459,12 +462,12 @@ int main(void)
         }
 
         modbus_set_slave(&mb_param, MODBUS_BROADCAST_ADDRESS);
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     UT_HOLDING_REGISTERS_NB_POINTS,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    UT_HOLDING_REGISTERS_NB_POINTS,
+                                    tab_rp_registers);
         printf("2/2 Reply after a broadcast query: ");
-        if (ret == UT_HOLDING_REGISTERS_NB_POINTS) {
+        if (rc == UT_HOLDING_REGISTERS_NB_POINTS) {
                 printf("OK\n");
         } else {
                 goto close;
@@ -477,12 +480,12 @@ int main(void)
         /* Allocate only the required space */
         tab_rp_registers_bad = (uint16_t *) malloc(
                 UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL * sizeof(uint16_t));
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL,
-                                     tab_rp_registers_bad);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL,
+                                    tab_rp_registers_bad);
         printf("* read_holding_registers: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBBADDATA) {
                 printf("OK\n");
         } else {
                 printf("FAILED\n");

+ 19 - 13
tests/unit-test-slave.c

@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include <modbus/modbus.h>
 #include "unit-test.h"
@@ -28,20 +29,22 @@ int main(void)
         int socket;
         modbus_param_t mb_param;
         modbus_mapping_t mb_mapping;
-        int ret;
+        int rc;
         int i;
 
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_set_debug(&mb_param, TRUE);
+        modbus_set_error_recovery(&mb_param, TRUE);
 
-        ret = modbus_mapping_new(&mb_mapping,
+        rc = modbus_mapping_new(&mb_mapping,
                                  UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
                                  UT_INPUT_STATUS_ADDRESS + UT_INPUT_STATUS_NB_POINTS,
                                  UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS,
                                  UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB_POINTS);
-        if (ret < 0) {
-                printf("Memory allocation failed\n");
-                exit(1);
+        if (rc == -1) {
+                fprintf(stderr, "Failed to allocate the mapping: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
 
         /* Examples from PI_MODBUS_300.pdf.
@@ -61,11 +64,11 @@ int main(void)
         socket = modbus_slave_listen_tcp(&mb_param, 1);
         modbus_slave_accept_tcp(&mb_param, &socket);
 
-        while (1) {
+        for (;;) {
                 uint8_t query[MAX_MESSAGE_LENGTH];
 
-                ret = modbus_slave_receive(&mb_param, -1, query);
-                if (ret >= 0) {
+                rc = modbus_slave_receive(&mb_param, -1, query);
+                if (rc > 0) {
                         if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4])
                             == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) {
                                 /* Change the number of values (offset
@@ -74,15 +77,18 @@ int main(void)
                                 query[HEADER_LENGTH_TCP + 4] = UT_HOLDING_REGISTERS_NB_POINTS;
                         }
 
-                        modbus_slave_manage(&mb_param, query, ret, &mb_mapping);
-                } else if (ret == CONNECTION_CLOSED) {
-                        /* Connection closed by the client, end of server */
-                        break;
+                        rc = modbus_slave_manage(&mb_param, query, rc, &mb_mapping);
+                        if (rc == -1) {
+                                return -1;
+                        }
                 } else {
-                        fprintf(stderr, "Error in modbus_listen (%d)\n", ret);
+                        /* Connection closed by the client or error */
+                        break;
                 }
         }
 
+        printf("Quit the loop: %s\n", modbus_strerror(errno));
+
         close(socket);
         modbus_mapping_free(&mb_mapping);
         modbus_close(&mb_param);