📄 conn.c
字号:
{ /* tty.timer is non-zero in TTY_PAUSE, TTY_RESP states */ t_out.tv_sec = tty.timer / 1000000ul; t_out.tv_usec = tty.timer % 1000000ul; } else { t_out.tv_usec = 0ul; if (cfg.conntimeout) t_out.tv_sec = min_timeout; /* minor timeout value */ else t_out.tv_sec = 10ul; /* XXX default timeout value */ } (void)gettimeofday(&ts, NULL); /* make timestamp */ #ifdef DEBUG log(7, "conn_loop(): select(): max_sd = %d, t_out = %06lu:%06lu ", max_sd, t_out.tv_sec, t_out.tv_usec);#endif rc = select(max_sd + 1, &sdsetrd, &sdsetwr, NULL, &t_out); if (rc < 0) { /* some error caused while select() */ if (errno == EINTR) continue; /* process signals */ /* unrecoverable error in select(), exiting */#ifdef LOG log(0, "conn_loop(): error in select() (%s)", strerror(errno));#endif break; } /* calculating elapsed time */ (void)gettimeofday(&tts, NULL); tval = 1000000ul * (tts.tv_sec - ts.tv_sec) + (tts.tv_usec - ts.tv_usec); /* modify tty timer */ if (tty.timer) { /* tty timer is active */ if (tty.timer <= tval) switch (tty.state) { /* timer expired */ case TTY_PAUSE: /* inter-request pause elapsed */ /* looking for connections in CONN_TTY state */ curconn = state_conn_search(&queue, actconn, CONN_TTY); if (curconn != NULL) conn_tty_start(&tty, curconn); else state_tty_set(&tty, TTY_READY); break; case TTY_RESP: /* checking for received data */ if (FD_ISSET(tty.fd, &sdsetrd)) break; /* response timeout handling */ if (!tty.ptrbuf) {/* there no bytes received */#ifdef DEBUG log(5, "tty: response timeout", tty.ptrbuf);#endif if (!tty.trynum) modbus_ex_write(actconn->buf, MB_EX_TIMEOUT); else { /* retry request */#ifdef DEBUG log(5, "tty: attempt to retry request (%u of %u)", cfg.maxtry - tty.trynum + 1, cfg.maxtry);#endif state_tty_set(&tty, TTY_RQST); break; } } else { /* some data received */#ifdef DEBUG log(5, "tty: response readed (total %d bytes)", tty.ptrbuf);#endif if (tty.ptrbuf >= MB_MIN_LEN && modbus_crc_correct(tty.rxbuf, tty.ptrbuf)) { /* received response is correct, make OpenMODBUS response */#ifdef DEBUG log(5, "tty: response is correct");#endif (void)memcpy((void *)(actconn->buf + HDRSIZE), (void *)tty.rxbuf, tty.ptrbuf - CRCSIZE); WORD_WR_BE(actconn->buf + MB_LENGTH_H, tty.ptrbuf - CRCSIZE); } else { /* received response is incomplete or CRC failed */#ifdef DEBUG log(5, "tty: response is incorrect");#endif if (!tty.trynum) modbus_ex_write(actconn->buf, MB_EX_CRC); else { /* retry request */#ifdef DEBUG log(5, "tty: attempt to retry request (%u of %u)", cfg.maxtry - tty.trynum + 1, cfg.maxtry);#endif state_tty_set(&tty, TTY_RQST); break; } } } /* switch connection to response state */ state_conn_set(actconn, CONN_RESP); /* make inter-request pause */ state_tty_set(&tty, TTY_PAUSE); break; } else tty.timer -= tval; } if (cfg.conntimeout) { /* expire staled connections */ tout += tval; tout_sec = tout / 1000000ul; if (tout_sec) { /* at least one second elapsed, check for staled connections */ len = queue.len; curconn = queue.beg; while (len--) { curconn->timeout -= tout_sec; if (curconn->timeout <= 0) { /* timeout expired */ if (curconn->state == CONN_TTY) { /* deadlock in CONN_TTY state, exiting */#ifdef LOG log(0, "conn[%s]: state CONN_TTY deadlock, exiting!", inet_ntoa(curconn->sockaddr.sin_addr));#endif exit (-1); } /* purge connection */#ifdef LOG log(2, "conn[%s]: timeout, closing connection", inet_ntoa(curconn->sockaddr.sin_addr));#endif curconn = conn_close(curconn); continue; } curconn = queue_next_elem(&queue, curconn); } tout = tout % 1000000ul; } } if (rc == 0) continue; /* timeout caused, we will do select() again */ /* checking for pending connections */ if (FD_ISSET(server_sd, &sdsetrd)) conn_open(); /* tty processing */ if (tty.state == TTY_RQST) if (FD_ISSET(tty.fd, &sdsetwr)) { rc = conn_write(tty.fd, tty.txbuf + tty.ptrbuf, tty.txlen - tty.ptrbuf); if (rc <= 0) { /* error - we can't continue... */#ifdef LOG log(0, "tty: error in write() (%s)", strerror(errno));#endif break; /* exiting... */ }#ifdef DEBUG log(7, "tty: written %d bytes", rc);#endif tty.ptrbuf += rc; if (tty.ptrbuf == tty.txlen) { /* request transmitting completed, switch to TTY_RESP */#ifdef DEBUG log(7, "tty: request written (total %d bytes)", tty.txlen);#endif state_tty_set(&tty, TTY_RESP); } } if (FD_ISSET(tty.fd, &sdsetrd)) { if (tty.state == TTY_RESP) { rc = conn_read(tty.fd, tty.rxbuf + tty.ptrbuf, tty.rxlen - tty.ptrbuf); if (rc <= 0) { /* error - we can't continue... */#ifdef LOG log(0, "tty: error in read() (%s)", strerror(errno));#endif break; /* exiting... */ }#ifdef DEBUG log(7, "tty: readed %d bytes", rc);#endif tty.ptrbuf += rc; if (tty.ptrbuf == tty.rxlen) { /* XXX still generating error response */ modbus_ex_write(actconn->buf, MB_EX_CRC); /* switch connection to response state */ state_conn_set(actconn, CONN_RESP); /* make inter-request pause */ state_tty_set(&tty, TTY_PAUSE); } else /* reset timer */ tty.timer = cfg.respwait * 1000l; } else { /* drop unexpected tty data */ if ((rc = conn_read(tty.fd, tty.rxbuf, BUFSIZE)) <= 0) { /* error - we can't continue... */#ifdef LOG log(0, "tty: error in read() (%s)", strerror(errno));#endif break; /* exiting... */ }#ifdef DEBUG log(7, "tty: dropped %d bytes", rc);#endif } } /* processing data on the sockets */ len = queue.len; curconn = queue.beg; while (len--) { switch (curconn->state) { case CONN_HEADER: case CONN_RQST: if (FD_ISSET(curconn->sd, &sdsetrd)) { rc = conn_read(curconn->sd, curconn->buf + curconn->ctr, RQSTSIZE - curconn->ctr); if (rc <= 0) { /* error - drop this connection and go to next queue element */ curconn = conn_close(curconn); break; } curconn->ctr += rc; if (curconn->state == CONN_HEADER) if (curconn->ctr >= HDRSIZE) { /* header received completely */ if (modbus_check_header(curconn->buf) != RC_OK) { /* header is damaged, drop connection */ curconn = conn_close(curconn); break; } state_conn_set(curconn, CONN_RQST); } if (curconn->state == CONN_RQST) if (curconn->ctr >= HDRSIZE + MB_HDR(curconn->buf, MB_LENGTH_L)) { /* ### packet received completely ### */ state_conn_set(curconn, CONN_TTY); if (tty.state == TTY_READY) conn_tty_start(&tty, curconn); } } curconn = queue_next_elem(&queue, curconn); break; case CONN_RESP: if (FD_ISSET(curconn->sd, &sdsetwr)) { rc = conn_write(curconn->sd, curconn->buf + curconn->ctr, MB_HDR(curconn->buf, MB_LENGTH_L) + HDRSIZE - curconn->ctr); if (rc <= 0) { /* error - drop this connection and go to next queue element */ curconn = conn_close(curconn); break; } curconn->ctr += rc; if (curconn->ctr == (MB_HDR(curconn->buf, MB_LENGTH_L) + HDRSIZE)) state_conn_set(curconn, CONN_HEADER); } curconn = queue_next_elem(&queue, curconn); break; } /* switch (curconn->state) */ } /* while (len--) */ } /* while (TRUE) */ /* XXX some cleanup must be here */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -