client:
   47|      1|void *client(void *args){ 
   48|       |
   49|      1|    Fuzzer *fuzzer = (Fuzzer*)args;
   50|      1|    int sockfd;
   51|      1|    struct sockaddr_in serv_addr;
   52|       |
   53|      1|    sockfd = socket(AF_INET, SOCK_STREAM, 0);
   54|      1|    serv_addr.sin_family = AF_INET;
   55|      1|    serv_addr.sin_port = htons(fuzzer->port);
   56|      1|    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
   57|       |
   58|      1|    while(1){/* Try until connect*/
  ------------------
  |  Branch (58:11): [True: 1, Folded]
  ------------------
   59|      1|        if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
  ------------------
  |  Branch (59:13): [True: 0, False: 1]
  ------------------
   60|      0|            continue;
   61|      1|        }else{
   62|      1|            break;
   63|      1|        }
   64|      1|    }
   65|       |
   66|      1|    send(sockfd,fuzzer->buffer,fuzzer->size,0);
   67|       |
   68|      1|    close(sockfd);
   69|       |    pthread_exit(NULL);
   70|      1|}
LLVMFuzzerTestOneInput:
   72|     46|extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   73|       |
   74|     46|    if (size < kMinInputLength || size > kMaxInputLength){
  ------------------
  |  |   29|     92|#define kMinInputLength 9
  ------------------
                  if (size < kMinInputLength || size > kMaxInputLength){
  ------------------
  |  |   30|     41|#define kMaxInputLength MODBUS_RTU_MAX_ADU_LENGTH
  |  |  ------------------
  |  |  |  |   17|     41|#define MODBUS_RTU_MAX_ADU_LENGTH 256
  |  |  ------------------
  ------------------
  |  Branch (74:9): [True: 5, False: 41]
  |  Branch (74:35): [True: 40, False: 1]
  ------------------
   75|     45|        return 0;
   76|     45|    }
   77|       |
   78|      1|    Fuzzer *fuzzer = (Fuzzer*)malloc(sizeof(Fuzzer));
   79|      1|    fuzzer->port = PORT;
  ------------------
  |  |   28|      1|#define PORT 8080
  ------------------
   80|       |
   81|      1|    fuzzer->size = size;
   82|      1|    fuzzer->buffer = data;
   83|       |
   84|      1|    pthread_create(&fuzzer->thread, NULL,client,fuzzer);
   85|      1|    server(fuzzer);
   86|      1|    pthread_join(fuzzer->thread, NULL); /* Avoid UAF*/
   87|       |
   88|      1|    free(fuzzer);
   89|      1|    return 0;
   90|     46|}
server:
   93|      1|{
   94|      1|    int s = -1;
   95|      1|    modbus_t *ctx;
   96|      1|    modbus_mapping_t *mb_mapping;
   97|      1|    int rc;
   98|      1|    int i;
   99|      1|    uint8_t *query;
  100|       |
  101|      1|    ctx = modbus_new_tcp("127.0.0.1", fuzzer->port);
  102|      1|    query = malloc(MODBUS_TCP_MAX_ADU_LENGTH);
  ------------------
  |  |   40|      1|#define MODBUS_TCP_MAX_ADU_LENGTH 260
  ------------------
  103|       |
  104|      1|    mb_mapping = modbus_mapping_new_start_address(
  105|      1|        UT_BITS_ADDRESS, UT_BITS_NB,
  ------------------
  |  |   31|      1|#define UT_BITS_NB 0x25
  ------------------
  106|      1|        UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB,
  107|      1|        UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_MAX,
  108|      1|        UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB);
  109|      1|    if (mb_mapping == NULL) {
  ------------------
  |  Branch (109:9): [True: 0, False: 1]
  ------------------
  110|      0|        fprintf(stderr, "Failed to allocate the mapping: %s\n",
  111|      0|                modbus_strerror(errno));
  112|      0|        modbus_free(ctx);
  113|      0|        return -1;
  114|      0|    }
  115|       |
  116|       |    /* Initialize input values that's can be only done server side. */
  117|      1|    modbus_set_bits_from_bytes(mb_mapping->tab_input_bits, 0, UT_INPUT_BITS_NB,
  118|      1|                               UT_INPUT_BITS_TAB);
  119|       |
  120|       |    /* Initialize values of INPUT REGISTERS */
  121|      2|    for (i=0; i < UT_INPUT_REGISTERS_NB; i++) {
  ------------------
  |  Branch (121:15): [True: 1, False: 1]
  ------------------
  122|      1|        mb_mapping->tab_input_registers[i] = UT_INPUT_REGISTERS_TAB[i];
  123|      1|    }
  124|       |
  125|      1|    s = modbus_tcp_listen(ctx, 1);
  126|      1|    modbus_tcp_accept(ctx, &s);
  127|       |
  128|      1|    rc = modbus_receive(ctx, query);
  129|       |
  130|      1|    if (s != -1) {
  ------------------
  |  Branch (130:9): [True: 1, False: 0]
  ------------------
  131|      1|        close(s);
  132|      1|    }
  133|       |
  134|      1|    modbus_mapping_free(mb_mapping);
  135|      1|    free(query);
  136|       |    /* For RTU */
  137|      1|    modbus_close(ctx);
  138|      1|    modbus_free(ctx);
  139|       |
  140|      1|    return rc;
  141|      1|}

modbus_set_bits_from_bytes:
   48|      1|{
   49|      1|    unsigned int i;
   50|      1|    int shift = 0;
   51|       |
   52|     23|    for (i = idx; i < idx + nb_bits; i++) {
  ------------------
  |  Branch (52:19): [True: 22, False: 1]
  ------------------
   53|     22|        dest[i] = tab_byte[(i - idx) / 8] & (1 << shift) ? 1 : 0;
  ------------------
  |  Branch (53:19): [True: 14, False: 8]
  ------------------
   54|       |        /* gcc doesn't like: shift = (++shift) % 8; */
   55|     22|        shift++;
   56|     22|        shift %= 8;
   57|     22|    }
   58|      1|}

modbus_tcp_listen:
  576|      1|{
  577|      1|    int new_s;
  578|      1|    int enable;
  579|      1|    int flags;
  580|      1|    struct sockaddr_in addr;
  581|      1|    modbus_tcp_t *ctx_tcp;
  582|      1|    int rc;
  583|       |
  584|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (584:9): [True: 0, False: 1]
  ------------------
  585|      0|        errno = EINVAL;
  586|      0|        return -1;
  587|      0|    }
  588|       |
  589|      1|    ctx_tcp = ctx->backend_data;
  590|       |
  591|       |#ifdef OS_WIN32
  592|       |    if (_modbus_tcp_init_win32() == -1) {
  593|       |        return -1;
  594|       |    }
  595|       |#endif
  596|       |
  597|      1|    flags = SOCK_STREAM;
  598|       |
  599|      1|#ifdef SOCK_CLOEXEC
  600|      1|    flags |= SOCK_CLOEXEC;
  601|      1|#endif
  602|       |
  603|      1|    new_s = socket(PF_INET, flags, IPPROTO_TCP);
  604|      1|    if (new_s == -1) {
  ------------------
  |  Branch (604:9): [True: 0, False: 1]
  ------------------
  605|      0|        return -1;
  606|      0|    }
  607|       |
  608|      1|    enable = 1;
  609|       |#ifdef _WIN32
  610|       |    if (setsockopt(new_s, SOL_SOCKET, SO_REUSEADDR, (const char *)&enable, sizeof(enable)) == -1) {
  611|       |#else
  612|      1|    if (setsockopt(new_s, SOL_SOCKET, SO_REUSEADDR, (const void *)&enable, sizeof(enable)) == -1) {
  ------------------
  |  Branch (612:9): [True: 0, False: 1]
  ------------------
  613|      0|#endif
  614|      0|        close(new_s);
  615|      0|        return -1;
  616|      0|    }
  617|       |
  618|      1|    memset(&addr, 0, sizeof(addr));
  619|      1|    addr.sin_family = AF_INET;
  620|       |    /* If the modbus port is < to 1024, we need the setuid root. */
  621|      1|    addr.sin_port = htons(ctx_tcp->port);
  622|      1|    if (ctx_tcp->ip[0] == '0') {
  ------------------
  |  Branch (622:9): [True: 0, False: 1]
  ------------------
  623|       |        /* Listen any addresses */
  624|      0|        addr.sin_addr.s_addr = htonl(INADDR_ANY);
  625|      1|    } else {
  626|       |        /* Listen only specified IP address */
  627|      1|        rc = inet_pton(addr.sin_family, ctx_tcp->ip, &(addr.sin_addr));
  628|      1|        if (rc <= 0) {
  ------------------
  |  Branch (628:13): [True: 0, False: 1]
  ------------------
  629|      0|            if (ctx->debug) {
  ------------------
  |  Branch (629:17): [True: 0, False: 0]
  ------------------
  630|      0|                fprintf(stderr, "Invalid IP address: %s\n", ctx_tcp->ip);
  631|      0|            }
  632|      0|            close(new_s);
  633|      0|            return -1;
  634|      0|        }
  635|      1|    }
  636|       |
  637|      1|    if (bind(new_s, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
  ------------------
  |  Branch (637:9): [True: 0, False: 1]
  ------------------
  638|      0|        close(new_s);
  639|      0|        return -1;
  640|      0|    }
  641|       |
  642|      1|    if (listen(new_s, nb_connection) == -1) {
  ------------------
  |  Branch (642:9): [True: 0, False: 1]
  ------------------
  643|      0|        close(new_s);
  644|      0|        return -1;
  645|      0|    }
  646|       |
  647|      1|    return new_s;
  648|      1|}
modbus_tcp_accept:
  777|      1|{
  778|      1|    struct sockaddr_in addr;
  779|      1|    socklen_t addrlen;
  780|       |
  781|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (781:9): [True: 0, False: 1]
  ------------------
  782|      0|        errno = EINVAL;
  783|      0|        return -1;
  784|      0|    }
  785|       |
  786|      1|    addrlen = sizeof(addr);
  787|      1|#ifdef HAVE_ACCEPT4
  788|       |    /* Inherit socket flags and use accept4 call */
  789|      1|    ctx->s = accept4(*s, (struct sockaddr *) &addr, &addrlen, SOCK_CLOEXEC);
  790|       |#else
  791|       |    ctx->s = accept(*s, (struct sockaddr *) &addr, &addrlen);
  792|       |#endif
  793|       |
  794|      1|    if (ctx->s < 0) {
  ------------------
  |  Branch (794:9): [True: 0, False: 1]
  ------------------
  795|      0|        return -1;
  796|      0|    }
  797|       |
  798|      1|    if (ctx->s >= FD_SETSIZE) {
  ------------------
  |  Branch (798:9): [True: 0, False: 1]
  ------------------
  799|      0|        if (ctx->debug) {
  ------------------
  |  Branch (799:13): [True: 0, False: 0]
  ------------------
  800|      0|            fprintf(
  801|      0|                stderr,
  802|      0|                "ERROR Socket descriptor %d exceeds FD_SETSIZE (%d)\n",
  803|      0|                ctx->s,
  804|      0|                FD_SETSIZE);
  805|      0|        }
  806|      0|        close(ctx->s);
  807|      0|        ctx->s = -1;
  808|      0|        errno = EINVAL;
  809|      0|        return -1;
  810|      0|    }
  811|       |
  812|      1|    if (ctx->debug) {
  ------------------
  |  Branch (812:9): [True: 0, False: 1]
  ------------------
  813|      0|        char buf[INET_ADDRSTRLEN];
  814|      0|        if (inet_ntop(AF_INET, &(addr.sin_addr), buf, INET_ADDRSTRLEN) == NULL) {
  ------------------
  |  Branch (814:13): [True: 0, False: 0]
  ------------------
  815|      0|            fprintf(stderr, "Client connection accepted from unparsable IP.\n");
  816|      0|        } else {
  817|      0|            printf("Client connection accepted from %s.\n", buf);
  818|      0|        }
  819|      0|    }
  820|       |
  821|      1|    return ctx->s;
  822|      1|}
modbus_new_tcp:
  971|      1|{
  972|      1|    modbus_t *ctx;
  973|      1|    modbus_tcp_t *ctx_tcp;
  974|      1|    size_t dest_size;
  975|      1|    size_t ret_size;
  976|       |
  977|       |#if defined(OS_BSD)
  978|       |    /* MSG_NOSIGNAL is unsupported on *BSD so we install an ignore
  979|       |       handler for SIGPIPE. */
  980|       |    struct sigaction sa;
  981|       |
  982|       |    sa.sa_handler = SIG_IGN;
  983|       |    if (sigaction(SIGPIPE, &sa, NULL) < 0) {
  984|       |        /* The debug flag can't be set here... */
  985|       |        fprintf(stderr, "Could not install SIGPIPE handler.\n");
  986|       |        return NULL;
  987|       |    }
  988|       |#endif
  989|       |
  990|      1|    ctx = (modbus_t *) malloc(sizeof(modbus_t));
  991|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (991:9): [True: 0, False: 1]
  ------------------
  992|      0|        return NULL;
  993|      0|    }
  994|      1|    _modbus_init_common(ctx);
  995|       |
  996|       |    /* Could be changed after to reach a remote serial Modbus device */
  997|      1|    ctx->slave = MODBUS_TCP_SLAVE;
  ------------------
  |  |   35|      1|#define MODBUS_TCP_SLAVE        0xFF
  ------------------
  998|       |
  999|      1|    ctx->backend = &_modbus_tcp_backend;
 1000|       |
 1001|      1|    ctx->backend_data = (modbus_tcp_t *) malloc(sizeof(modbus_tcp_t));
 1002|      1|    if (ctx->backend_data == NULL) {
  ------------------
  |  Branch (1002:9): [True: 0, False: 1]
  ------------------
 1003|      0|        modbus_free(ctx);
 1004|      0|        errno = ENOMEM;
 1005|      0|        return NULL;
 1006|      0|    }
 1007|      1|    ctx_tcp = (modbus_tcp_t *) ctx->backend_data;
 1008|       |
 1009|      1|    if (ip != NULL) {
  ------------------
  |  Branch (1009:9): [True: 1, False: 0]
  ------------------
 1010|      1|        dest_size = sizeof(char) * 16;
 1011|      1|        ret_size = strlcpy(ctx_tcp->ip, ip, dest_size);
 1012|      1|        if (ret_size == 0) {
  ------------------
  |  Branch (1012:13): [True: 0, False: 1]
  ------------------
 1013|      0|            fprintf(stderr, "The IP string is empty\n");
 1014|      0|            modbus_free(ctx);
 1015|      0|            errno = EINVAL;
 1016|      0|            return NULL;
 1017|      0|        }
 1018|       |
 1019|      1|        if (ret_size >= dest_size) {
  ------------------
  |  Branch (1019:13): [True: 0, False: 1]
  ------------------
 1020|      0|            fprintf(stderr, "The IP string has been truncated\n");
 1021|      0|            modbus_free(ctx);
 1022|      0|            errno = EINVAL;
 1023|      0|            return NULL;
 1024|      0|        }
 1025|      1|    } else {
 1026|      0|        ctx_tcp->ip[0] = '0';
 1027|      0|    }
 1028|      1|    ctx_tcp->port = port;
 1029|      1|    ctx_tcp->t_id = 0;
 1030|       |
 1031|      1|    return ctx;
 1032|      1|}
modbus-tcp.c:_modbus_tcp_receive:
  186|      1|{
  187|      1|    return _modbus_receive_msg(ctx, req, MSG_INDICATION);
  188|      1|}
modbus-tcp.c:_modbus_tcp_recv:
  191|      1|{
  192|      1|    return recv(ctx->s, (char *) rsp, rsp_length, 0);
  193|      1|}
modbus-tcp.c:_modbus_tcp_check_integrity:
  196|      1|{
  197|      1|    return msg_length;
  198|      1|}
modbus-tcp.c:_modbus_tcp_is_connected:
  508|      1|{
  509|      1|    return ctx->s >= 0;
  510|      1|}
modbus-tcp.c:_modbus_tcp_close:
  514|      1|{
  515|      1|    if (ctx->s >= 0) {
  ------------------
  |  Branch (515:9): [True: 1, False: 0]
  ------------------
  516|       |        shutdown(ctx->s, SHUT_RDWR);
  517|      1|        close(ctx->s);
  518|      1|        ctx->s = -1;
  519|      1|    }
  520|      1|}
modbus-tcp.c:_modbus_tcp_select:
  874|      1|{
  875|      1|    int s_rc;
  876|      1|    while ((s_rc = select(ctx->s + 1, rset, NULL, NULL, tv)) == -1) {
  ------------------
  |  Branch (876:12): [True: 0, False: 1]
  ------------------
  877|      0|        if (errno == EINTR) {
  ------------------
  |  Branch (877:13): [True: 0, False: 0]
  ------------------
  878|      0|            if (ctx->debug) {
  ------------------
  |  Branch (878:17): [True: 0, False: 0]
  ------------------
  879|      0|                fprintf(stderr, "A non blocked signal was caught\n");
  880|      0|            }
  881|       |            /* Necessary after an error */
  882|      0|            FD_ZERO(rset);
  ------------------
  |  Branch (882:13): [Folded, False: 0]
  ------------------
  883|      0|            if (ctx->s < 0 || ctx->s >= FD_SETSIZE) {
  ------------------
  |  Branch (883:17): [True: 0, False: 0]
  |  Branch (883:31): [True: 0, False: 0]
  ------------------
  884|      0|                errno = EINVAL;
  885|      0|                return -1;
  886|      0|            }
  887|      0|            FD_SET(ctx->s, rset);
  888|      0|        } else {
  889|      0|            return -1;
  890|      0|        }
  891|      0|    }
  892|       |
  893|      1|    if (s_rc == 0) {
  ------------------
  |  Branch (893:9): [True: 0, False: 1]
  ------------------
  894|      0|        errno = ETIMEDOUT;
  895|      0|        return -1;
  896|      0|    }
  897|       |
  898|      1|    return s_rc;
  899|      1|}
modbus-tcp.c:_modbus_tcp_free:
  902|      1|{
  903|      1|    if (ctx->backend_data) {
  ------------------
  |  Branch (903:9): [True: 1, False: 0]
  ------------------
  904|      1|        free(ctx->backend_data);
  905|      1|    }
  906|      1|    free(ctx);
  907|      1|}

_modbus_receive_msg:
  359|      1|{
  360|      1|    int rc;
  361|      1|    fd_set rset;
  362|      1|    struct timeval tv;
  363|      1|    struct timeval *p_tv;
  364|      1|    unsigned int length_to_read;
  365|      1|    int msg_length = 0;
  366|      1|    _step_t step;
  367|       |#ifdef _WIN32
  368|       |    int wsa_err;
  369|       |#endif
  370|       |
  371|      1|    if (ctx->debug) {
  ------------------
  |  Branch (371:9): [True: 0, False: 1]
  ------------------
  372|      0|        if (msg_type == MSG_INDICATION) {
  ------------------
  |  Branch (372:13): [True: 0, False: 0]
  ------------------
  373|      0|            printf("Waiting for an indication...\n");
  374|      0|        } else {
  375|      0|            printf("Waiting for a confirmation...\n");
  376|      0|        }
  377|      0|    }
  378|       |
  379|      1|    if (!ctx->backend->is_connected(ctx)) {
  ------------------
  |  Branch (379:9): [True: 0, False: 1]
  ------------------
  380|      0|        if (ctx->debug) {
  ------------------
  |  Branch (380:13): [True: 0, False: 0]
  ------------------
  381|      0|            fprintf(stderr, "ERROR The connection is not established.\n");
  382|      0|        }
  383|      0|        return -1;
  384|      0|    }
  385|       |
  386|       |    /* Add a file descriptor to the set */
  387|      1|    FD_ZERO(&rset);
  ------------------
  |  Branch (387:5): [Folded, False: 1]
  ------------------
  388|      1|    if (ctx->s < 0 || ctx->s >= FD_SETSIZE) {
  ------------------
  |  Branch (388:9): [True: 0, False: 1]
  |  Branch (388:23): [True: 0, False: 1]
  ------------------
  389|      0|        if (ctx->debug) {
  ------------------
  |  Branch (389:13): [True: 0, False: 0]
  ------------------
  390|      0|            fprintf(stderr, "ERROR Invalid socket descriptor %d\n", ctx->s);
  391|      0|        }
  392|      0|        errno = EINVAL;
  393|      0|        return -1;
  394|      0|    }
  395|      1|    FD_SET(ctx->s, &rset);
  396|       |
  397|       |    /* We need to analyse the message step by step.  At the first step, we want
  398|       |     * to reach the function code because all packets contain this
  399|       |     * information. */
  400|      1|    step = _STEP_FUNCTION;
  401|      1|    length_to_read = ctx->backend->header_length + 1;
  402|       |
  403|      1|    if (msg_type == MSG_INDICATION) {
  ------------------
  |  Branch (403:9): [True: 1, False: 0]
  ------------------
  404|       |        /* Wait for a message, we don't know when the message will be received */
  405|      1|        if (ctx->indication_timeout.tv_sec == 0 && ctx->indication_timeout.tv_usec == 0) {
  ------------------
  |  Branch (405:13): [True: 1, False: 0]
  |  Branch (405:52): [True: 1, False: 0]
  ------------------
  406|       |            /* By default, the indication timeout isn't set */
  407|      1|            p_tv = NULL;
  408|      1|        } else {
  409|       |            /* Wait for an indication (name of a received request by a server, see schema)
  410|       |             */
  411|      0|            tv.tv_sec = ctx->indication_timeout.tv_sec;
  412|      0|            tv.tv_usec = ctx->indication_timeout.tv_usec;
  413|      0|            p_tv = &tv;
  414|      0|        }
  415|      1|    } else {
  416|      0|        tv.tv_sec = ctx->response_timeout.tv_sec;
  417|      0|        tv.tv_usec = ctx->response_timeout.tv_usec;
  418|      0|        p_tv = &tv;
  419|      0|    }
  420|       |
  421|      2|    while (length_to_read != 0) {
  ------------------
  |  Branch (421:12): [True: 1, False: 1]
  ------------------
  422|      1|        rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read);
  423|      1|        if (rc == -1) {
  ------------------
  |  Branch (423:13): [True: 0, False: 1]
  ------------------
  424|      0|            _error_print(ctx, "select");
  425|      0|            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
  ------------------
  |  Branch (425:17): [True: 0, False: 0]
  ------------------
  426|       |#ifdef _WIN32
  427|       |                wsa_err = WSAGetLastError();
  428|       |
  429|       |                // no equivalent to ETIMEDOUT when select fails on Windows
  430|       |                if (wsa_err == WSAENETDOWN || wsa_err == WSAENOTSOCK) {
  431|       |                    modbus_close(ctx);
  432|       |                    modbus_connect(ctx);
  433|       |                }
  434|       |#else
  435|      0|                int saved_errno = errno;
  436|       |
  437|      0|                if (errno == ETIMEDOUT) {
  ------------------
  |  Branch (437:21): [True: 0, False: 0]
  ------------------
  438|      0|                    _sleep_response_timeout(ctx);
  439|      0|                    modbus_flush(ctx);
  440|      0|                } else if (errno == EBADF) {
  ------------------
  |  Branch (440:28): [True: 0, False: 0]
  ------------------
  441|      0|                    modbus_close(ctx);
  442|      0|                    modbus_connect(ctx);
  443|      0|                }
  444|      0|                errno = saved_errno;
  445|      0|#endif
  446|      0|            }
  447|      0|            return -1;
  448|      0|        }
  449|       |
  450|      1|        rc = ctx->backend->recv(ctx, msg + msg_length, length_to_read);
  451|      1|        if (rc == 0) {
  ------------------
  |  Branch (451:13): [True: 0, False: 1]
  ------------------
  452|      0|            errno = ECONNRESET;
  453|      0|            rc = -1;
  454|      0|        }
  455|       |
  456|      1|        if (rc == -1) {
  ------------------
  |  Branch (456:13): [True: 0, False: 1]
  ------------------
  457|      0|            _error_print(ctx, "read");
  458|       |#ifdef _WIN32
  459|       |            wsa_err = WSAGetLastError();
  460|       |            if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
  461|       |                (wsa_err == WSAENOTCONN || wsa_err == WSAENETRESET ||
  462|       |                 wsa_err == WSAENOTSOCK || wsa_err == WSAESHUTDOWN ||
  463|       |                 wsa_err == WSAECONNABORTED || wsa_err == WSAETIMEDOUT ||
  464|       |                 wsa_err == WSAECONNRESET)) {
  465|       |                modbus_close(ctx);
  466|       |                modbus_connect(ctx);
  467|       |            }
  468|       |#else
  469|      0|            if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
  ------------------
  |  Branch (469:17): [True: 0, False: 0]
  ------------------
  470|      0|                (errno == ECONNRESET || errno == ECONNREFUSED || errno == EBADF)) {
  ------------------
  |  Branch (470:18): [True: 0, False: 0]
  |  Branch (470:41): [True: 0, False: 0]
  |  Branch (470:66): [True: 0, False: 0]
  ------------------
  471|      0|                int saved_errno = errno;
  472|      0|                modbus_close(ctx);
  473|      0|                modbus_connect(ctx);
  474|       |                /* Could be removed by previous calls */
  475|      0|                errno = saved_errno;
  476|      0|            }
  477|      0|#endif
  478|      0|            return -1;
  479|      0|        }
  480|       |
  481|       |        /* Display the hex code of each character received */
  482|      1|        if (ctx->debug) {
  ------------------
  |  Branch (482:13): [True: 0, False: 1]
  ------------------
  483|      0|            int i;
  484|      0|            for (i = 0; i < rc; i++)
  ------------------
  |  Branch (484:25): [True: 0, False: 0]
  ------------------
  485|      0|                printf("<%.2X>", msg[msg_length + i]);
  486|      0|        }
  487|       |
  488|       |        /* Sums bytes received */
  489|      1|        msg_length += rc;
  490|       |        /* Computes remaining bytes */
  491|      1|        length_to_read -= rc;
  492|       |
  493|      1|        if (length_to_read == 0) {
  ------------------
  |  Branch (493:13): [True: 1, False: 0]
  ------------------
  494|      1|            switch (step) {
  495|      1|            case _STEP_FUNCTION:
  ------------------
  |  Branch (495:13): [True: 1, False: 0]
  ------------------
  496|       |                /* Function code position */
  497|      1|                length_to_read = compute_meta_length_after_function(
  498|      1|                    msg[ctx->backend->header_length], msg_type);
  499|      1|                if (length_to_read != 0) {
  ------------------
  |  Branch (499:21): [True: 0, False: 1]
  ------------------
  500|      0|                    step = _STEP_META;
  501|      0|                    break;
  502|      0|                } /* else switches straight to the next step */
  503|      1|            case _STEP_META:
  ------------------
  |  Branch (503:13): [True: 0, False: 1]
  ------------------
  504|      1|                length_to_read = compute_data_length_after_meta(ctx, msg, msg_type);
  505|      1|                if ((msg_length + length_to_read) > ctx->backend->max_adu_length) {
  ------------------
  |  Branch (505:21): [True: 0, False: 1]
  ------------------
  506|      0|                    errno = EMBBADDATA;
  ------------------
  |  |  147|      0|#define EMBBADDATA  (EMBXGTAR + 2)
  |  |  ------------------
  |  |  |  |  143|      0|#define EMBXGTAR   (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
  |  |  |  |  ------------------
  |  |  |  |  |  |  116|      0|#define MODBUS_ENOBASE 112345678
  |  |  |  |  ------------------
  |  |  ------------------
  ------------------
  507|      0|                    _error_print(ctx, "too many data");
  508|      0|                    return -1;
  509|      0|                }
  510|      1|                step = _STEP_DATA;
  511|      1|                break;
  512|      0|            default:
  ------------------
  |  Branch (512:13): [True: 0, False: 1]
  ------------------
  513|      0|                break;
  514|      1|            }
  515|      1|        }
  516|       |
  517|      1|        if (length_to_read > 0 &&
  ------------------
  |  Branch (517:13): [True: 0, False: 1]
  ------------------
  518|      0|            (ctx->byte_timeout.tv_sec > 0 || ctx->byte_timeout.tv_usec > 0)) {
  ------------------
  |  Branch (518:14): [True: 0, False: 0]
  |  Branch (518:46): [True: 0, False: 0]
  ------------------
  519|       |            /* If there is no character in the buffer, the allowed timeout
  520|       |               interval between two consecutive bytes is defined by
  521|       |               byte_timeout */
  522|      0|            tv.tv_sec = ctx->byte_timeout.tv_sec;
  523|      0|            tv.tv_usec = ctx->byte_timeout.tv_usec;
  524|      0|            p_tv = &tv;
  525|      0|        }
  526|       |        /* else timeout isn't set again, the full response must be read before
  527|       |           expiration of response timeout (for CONFIRMATION only) */
  528|      1|    }
  529|       |
  530|      1|    if (ctx->debug)
  ------------------
  |  Branch (530:9): [True: 0, False: 1]
  ------------------
  531|      0|        printf("\n");
  532|       |
  533|      1|    return ctx->backend->check_integrity(ctx, msg, msg_length);
  534|      1|}
modbus_receive:
  538|      1|{
  539|      1|    if (ctx == NULL) {
  ------------------
  |  Branch (539:9): [True: 0, False: 1]
  ------------------
  540|      0|        errno = EINVAL;
  541|      0|        return -1;
  542|      0|    }
  543|       |
  544|      1|    return ctx->backend->receive(ctx, req);
  545|      1|}
_modbus_init_common:
 1773|      1|{
 1774|       |    /* Slave and socket are initialized to -1 */
 1775|      1|    ctx->slave = -1;
 1776|      1|    ctx->s = -1;
 1777|       |
 1778|      1|    ctx->debug = FALSE;
  ------------------
  |  |   47|      1|#define FALSE 0
  ------------------
 1779|      1|    ctx->error_recovery = MODBUS_ERROR_RECOVERY_NONE;
 1780|      1|    ctx->quirks = MODBUS_QUIRK_NONE;
 1781|       |
 1782|      1|    ctx->response_timeout.tv_sec = 0;
 1783|      1|    ctx->response_timeout.tv_usec = _RESPONSE_TIMEOUT;
  ------------------
  |  |   41|      1|#define _RESPONSE_TIMEOUT 500000
  ------------------
 1784|       |
 1785|      1|    ctx->byte_timeout.tv_sec = 0;
 1786|      1|    ctx->byte_timeout.tv_usec = _BYTE_TIMEOUT;
  ------------------
  |  |   42|      1|#define _BYTE_TIMEOUT     500000
  ------------------
 1787|       |
 1788|      1|    ctx->indication_timeout.tv_sec = 0;
 1789|      1|    ctx->indication_timeout.tv_usec = 0;
 1790|      1|}
modbus_close:
 1970|      1|{
 1971|      1|    if (ctx == NULL)
  ------------------
  |  Branch (1971:9): [True: 0, False: 1]
  ------------------
 1972|      0|        return;
 1973|       |
 1974|      1|    ctx->backend->close(ctx);
 1975|      1|}
modbus_free:
 1978|      1|{
 1979|      1|    if (ctx == NULL)
  ------------------
  |  Branch (1979:9): [True: 0, False: 1]
  ------------------
 1980|      0|        return;
 1981|       |
 1982|      1|    ctx->backend->free(ctx);
 1983|      1|}
modbus_mapping_new_start_address:
 2010|      1|{
 2011|      1|    modbus_mapping_t *mb_mapping;
 2012|       |
 2013|      1|    mb_mapping = (modbus_mapping_t *) malloc(sizeof(modbus_mapping_t));
 2014|      1|    if (mb_mapping == NULL) {
  ------------------
  |  Branch (2014:9): [True: 0, False: 1]
  ------------------
 2015|      0|        return NULL;
 2016|      0|    }
 2017|       |
 2018|       |    /* 0X */
 2019|      1|    mb_mapping->nb_bits = nb_bits;
 2020|      1|    mb_mapping->start_bits = start_bits;
 2021|      1|    if (nb_bits == 0) {
  ------------------
  |  Branch (2021:9): [True: 0, False: 1]
  ------------------
 2022|      0|        mb_mapping->tab_bits = NULL;
 2023|      1|    } else {
 2024|       |        /* Negative number raises a POSIX error */
 2025|      1|        mb_mapping->tab_bits = (uint8_t *) malloc(nb_bits * sizeof(uint8_t));
 2026|      1|        if (mb_mapping->tab_bits == NULL) {
  ------------------
  |  Branch (2026:13): [True: 0, False: 1]
  ------------------
 2027|      0|            free(mb_mapping);
 2028|      0|            return NULL;
 2029|      0|        }
 2030|      1|        memset(mb_mapping->tab_bits, 0, nb_bits * sizeof(uint8_t));
 2031|      1|    }
 2032|       |
 2033|       |    /* 1X */
 2034|      1|    mb_mapping->nb_input_bits = nb_input_bits;
 2035|      1|    mb_mapping->start_input_bits = start_input_bits;
 2036|      1|    if (nb_input_bits == 0) {
  ------------------
  |  Branch (2036:9): [True: 0, False: 1]
  ------------------
 2037|      0|        mb_mapping->tab_input_bits = NULL;
 2038|      1|    } else {
 2039|      1|        mb_mapping->tab_input_bits = (uint8_t *) malloc(nb_input_bits * sizeof(uint8_t));
 2040|      1|        if (mb_mapping->tab_input_bits == NULL) {
  ------------------
  |  Branch (2040:13): [True: 0, False: 1]
  ------------------
 2041|      0|            free(mb_mapping->tab_bits);
 2042|      0|            free(mb_mapping);
 2043|      0|            return NULL;
 2044|      0|        }
 2045|      1|        memset(mb_mapping->tab_input_bits, 0, nb_input_bits * sizeof(uint8_t));
 2046|      1|    }
 2047|       |
 2048|       |    /* 4X */
 2049|      1|    mb_mapping->nb_registers = nb_registers;
 2050|      1|    mb_mapping->start_registers = start_registers;
 2051|      1|    if (nb_registers == 0) {
  ------------------
  |  Branch (2051:9): [True: 0, False: 1]
  ------------------
 2052|      0|        mb_mapping->tab_registers = NULL;
 2053|      1|    } else {
 2054|      1|        mb_mapping->tab_registers = (uint16_t *) malloc(nb_registers * sizeof(uint16_t));
 2055|      1|        if (mb_mapping->tab_registers == NULL) {
  ------------------
  |  Branch (2055:13): [True: 0, False: 1]
  ------------------
 2056|      0|            free(mb_mapping->tab_input_bits);
 2057|      0|            free(mb_mapping->tab_bits);
 2058|      0|            free(mb_mapping);
 2059|      0|            return NULL;
 2060|      0|        }
 2061|      1|        memset(mb_mapping->tab_registers, 0, nb_registers * sizeof(uint16_t));
 2062|      1|    }
 2063|       |
 2064|       |    /* 3X */
 2065|      1|    mb_mapping->nb_input_registers = nb_input_registers;
 2066|      1|    mb_mapping->start_input_registers = start_input_registers;
 2067|      1|    if (nb_input_registers == 0) {
  ------------------
  |  Branch (2067:9): [True: 0, False: 1]
  ------------------
 2068|      0|        mb_mapping->tab_input_registers = NULL;
 2069|      1|    } else {
 2070|      1|        mb_mapping->tab_input_registers =
 2071|      1|            (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t));
 2072|      1|        if (mb_mapping->tab_input_registers == NULL) {
  ------------------
  |  Branch (2072:13): [True: 0, False: 1]
  ------------------
 2073|      0|            free(mb_mapping->tab_registers);
 2074|      0|            free(mb_mapping->tab_input_bits);
 2075|      0|            free(mb_mapping->tab_bits);
 2076|      0|            free(mb_mapping);
 2077|      0|            return NULL;
 2078|      0|        }
 2079|      1|        memset(mb_mapping->tab_input_registers, 0, nb_input_registers * sizeof(uint16_t));
 2080|      1|    }
 2081|       |
 2082|      1|    return mb_mapping;
 2083|      1|}
modbus_mapping_free:
 2096|      1|{
 2097|      1|    if (mb_mapping == NULL) {
  ------------------
  |  Branch (2097:9): [True: 0, False: 1]
  ------------------
 2098|      0|        return;
 2099|      0|    }
 2100|       |
 2101|      1|    free(mb_mapping->tab_input_registers);
 2102|      1|    free(mb_mapping->tab_registers);
 2103|      1|    free(mb_mapping->tab_input_bits);
 2104|      1|    free(mb_mapping->tab_bits);
 2105|      1|    free(mb_mapping);
 2106|      1|}
strlcpy:
 2122|      1|{
 2123|      1|    register char *d = dest;
 2124|      1|    register const char *s = src;
 2125|      1|    register size_t n = dest_size;
 2126|       |
 2127|       |    /* Copy as many bytes as will fit */
 2128|      1|    if (n != 0 && --n != 0) {
  ------------------
  |  Branch (2128:9): [True: 1, False: 0]
  |  Branch (2128:19): [True: 1, False: 0]
  ------------------
 2129|     10|        do {
 2130|     10|            if ((*d++ = *s++) == 0)
  ------------------
  |  Branch (2130:17): [True: 1, False: 9]
  ------------------
 2131|      1|                break;
 2132|     10|        } while (--n != 0);
  ------------------
  |  Branch (2132:18): [True: 9, False: 0]
  ------------------
 2133|      1|    }
 2134|       |
 2135|       |    /* Not enough room in dest, add NUL and traverse rest of src */
 2136|      1|    if (n == 0) {
  ------------------
  |  Branch (2136:9): [True: 0, False: 1]
  ------------------
 2137|      0|        if (dest_size != 0)
  ------------------
  |  Branch (2137:13): [True: 0, False: 0]
  ------------------
 2138|      0|            *d = '\0'; /* NUL-terminate dest */
 2139|      0|        while (*s++)
  ------------------
  |  Branch (2139:16): [True: 0, False: 0]
  ------------------
 2140|      0|            ;
 2141|      0|    }
 2142|       |
 2143|      1|    return (s - src - 1); /* count does not include NUL */
 2144|      1|}
modbus.c:compute_meta_length_after_function:
  274|      1|{
  275|      1|    int length;
  276|       |
  277|      1|    if (msg_type == MSG_INDICATION) {
  ------------------
  |  Branch (277:9): [True: 1, False: 0]
  ------------------
  278|      1|        if (function <= MODBUS_FC_WRITE_SINGLE_REGISTER) {
  ------------------
  |  |   68|      1|#define MODBUS_FC_WRITE_SINGLE_REGISTER    0x06
  ------------------
  |  Branch (278:13): [True: 0, False: 1]
  ------------------
  279|      0|            length = 4;
  280|      1|        } else if (function == MODBUS_FC_WRITE_MULTIPLE_COILS ||
  ------------------
  |  |   70|      2|#define MODBUS_FC_WRITE_MULTIPLE_COILS     0x0F
  ------------------
  |  Branch (280:20): [True: 0, False: 1]
  ------------------
  281|      1|                   function == MODBUS_FC_WRITE_MULTIPLE_REGISTERS) {
  ------------------
  |  |   71|      1|#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
  ------------------
  |  Branch (281:20): [True: 0, False: 1]
  ------------------
  282|      0|            length = 5;
  283|      1|        } else if (function == MODBUS_FC_MASK_WRITE_REGISTER) {
  ------------------
  |  |   73|      1|#define MODBUS_FC_MASK_WRITE_REGISTER      0x16
  ------------------
  |  Branch (283:20): [True: 0, False: 1]
  ------------------
  284|      0|            length = 6;
  285|      1|        } else if (function == MODBUS_FC_WRITE_AND_READ_REGISTERS) {
  ------------------
  |  |   74|      1|#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
  ------------------
  |  Branch (285:20): [True: 0, False: 1]
  ------------------
  286|      0|            length = 9;
  287|      1|        } else {
  288|       |            /* MODBUS_FC_READ_EXCEPTION_STATUS, MODBUS_FC_REPORT_SLAVE_ID */
  289|      1|            length = 0;
  290|      1|        }
  291|      1|    } else {
  292|       |        /* MSG_CONFIRMATION */
  293|      0|        switch (function) {
  294|      0|        case MODBUS_FC_WRITE_SINGLE_COIL:
  ------------------
  |  |   67|      0|#define MODBUS_FC_WRITE_SINGLE_COIL        0x05
  ------------------
  |  Branch (294:9): [True: 0, False: 0]
  ------------------
  295|      0|        case MODBUS_FC_WRITE_SINGLE_REGISTER:
  ------------------
  |  |   68|      0|#define MODBUS_FC_WRITE_SINGLE_REGISTER    0x06
  ------------------
  |  Branch (295:9): [True: 0, False: 0]
  ------------------
  296|      0|        case MODBUS_FC_WRITE_MULTIPLE_COILS:
  ------------------
  |  |   70|      0|#define MODBUS_FC_WRITE_MULTIPLE_COILS     0x0F
  ------------------
  |  Branch (296:9): [True: 0, False: 0]
  ------------------
  297|      0|        case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
  ------------------
  |  |   71|      0|#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
  ------------------
  |  Branch (297:9): [True: 0, False: 0]
  ------------------
  298|      0|            length = 4;
  299|      0|            break;
  300|      0|        case MODBUS_FC_MASK_WRITE_REGISTER:
  ------------------
  |  |   73|      0|#define MODBUS_FC_MASK_WRITE_REGISTER      0x16
  ------------------
  |  Branch (300:9): [True: 0, False: 0]
  ------------------
  301|      0|            length = 6;
  302|      0|            break;
  303|      0|        default:
  ------------------
  |  Branch (303:9): [True: 0, False: 0]
  ------------------
  304|      0|            length = 1;
  305|      0|        }
  306|      0|    }
  307|       |
  308|      1|    return length;
  309|      1|}
modbus.c:compute_data_length_after_meta:
  314|      1|{
  315|      1|    int function = msg[ctx->backend->header_length];
  316|      1|    int length;
  317|       |
  318|      1|    if (msg_type == MSG_INDICATION) {
  ------------------
  |  Branch (318:9): [True: 1, False: 0]
  ------------------
  319|      1|        switch (function) {
  320|      0|        case MODBUS_FC_WRITE_MULTIPLE_COILS:
  ------------------
  |  |   70|      0|#define MODBUS_FC_WRITE_MULTIPLE_COILS     0x0F
  ------------------
  |  Branch (320:9): [True: 0, False: 1]
  ------------------
  321|      0|        case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
  ------------------
  |  |   71|      0|#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
  ------------------
  |  Branch (321:9): [True: 0, False: 1]
  ------------------
  322|      0|            length = msg[ctx->backend->header_length + 5];
  323|      0|            break;
  324|      0|        case MODBUS_FC_WRITE_AND_READ_REGISTERS:
  ------------------
  |  |   74|      0|#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
  ------------------
  |  Branch (324:9): [True: 0, False: 1]
  ------------------
  325|      0|            length = msg[ctx->backend->header_length + 9];
  326|      0|            break;
  327|      1|        default:
  ------------------
  |  Branch (327:9): [True: 1, False: 0]
  ------------------
  328|      1|            length = 0;
  329|      1|        }
  330|      1|    } else {
  331|       |        /* MSG_CONFIRMATION */
  332|      0|        if (function <= MODBUS_FC_READ_INPUT_REGISTERS ||
  ------------------
  |  |   66|      0|#define MODBUS_FC_READ_INPUT_REGISTERS     0x04
  ------------------
  |  Branch (332:13): [True: 0, False: 0]
  ------------------
  333|      0|            function == MODBUS_FC_REPORT_SLAVE_ID ||
  ------------------
  |  |   72|      0|#define MODBUS_FC_REPORT_SLAVE_ID          0x11
  ------------------
  |  Branch (333:13): [True: 0, False: 0]
  ------------------
  334|      0|            function == MODBUS_FC_WRITE_AND_READ_REGISTERS) {
  ------------------
  |  |   74|      0|#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
  ------------------
  |  Branch (334:13): [True: 0, False: 0]
  ------------------
  335|      0|            length = msg[ctx->backend->header_length + 1];
  336|      0|        } else {
  337|      0|            length = 0;
  338|      0|        }
  339|      0|    }
  340|       |
  341|      1|    length += ctx->backend->checksum_length;
  342|       |
  343|      1|    return length;
  344|      1|}

