From 5c064928aea65b17b52da06e26804a5742865d40 Mon Sep 17 00:00:00 2001 From: Dustin Lundquist Date: Tue, 22 Jan 2019 10:50:42 -0800 Subject: [PATCH] modbus: read only a single frame at a time When multiple modbus frames were queued in the socket buffer conn_read() would read until it completely drained the kernel's socket buffer or filled the connection buffer. The first modbus frame in the buffer is then processed and sent to the tty, then the buffer is reused for the reponse after it is received from the tty possibly overwritting any subsequent modbus request frames already read. Avoid this by maintaining pre-connection length to read, so we only read a single modbus frame at a time. --- src/conn.c | 2 +- src/conn.h | 1 + src/modbus.c | 4 +++- src/state.c | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/conn.c b/src/conn.c index 9c880ae..b605624 100644 --- a/src/conn.c +++ b/src/conn.c @@ -767,7 +767,7 @@ conn_loop(void) { rc = conn_read(curconn->sd, curconn->buf + curconn->ctr, - RQSTSIZE - curconn->ctr); + curconn->read_len - curconn->ctr); if (rc <= 0) { /* error - drop this connection and go to next queue element */ curconn = conn_close(curconn); diff --git a/src/conn.h b/src/conn.h index c8d042a..9b7c121 100644 --- a/src/conn.h +++ b/src/conn.h @@ -105,6 +105,7 @@ typedef struct conn_t int timeout; /* timeout value, secs */ struct sockaddr_in sockaddr; /* connection structure */ int ctr; /* counter of data in the buffer */ + int read_len; /* length of modbus frame to read */ unsigned char buf[HDRSIZE + BUFSIZE]; /* data buffer */ } conn_t; diff --git a/src/modbus.c b/src/modbus.c index 22b2cf5..4042fce 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -32,6 +32,7 @@ */ #include "modbus.h" +#include "conn.h" /* * Check CRC of MODBUS frame @@ -83,5 +84,6 @@ modbus_check_header(unsigned char *packet) return (MB_FRAME(packet, MB_PROTO_ID_H) == 0 && MB_FRAME(packet, MB_PROTO_ID_L) == 0 && MB_FRAME(packet, MB_LENGTH_H) == 0 && - MB_FRAME(packet, MB_LENGTH_L) > 0) ? RC_OK : RC_ERR; + MB_FRAME(packet, MB_LENGTH_L) > 0 && + MB_FRAME(packet, MB_LENGTH_L) < BUFSIZE - CRCSIZE) ? RC_OK : RC_ERR; } diff --git a/src/state.c b/src/state.c index 29e6e15..6698fdb 100644 --- a/src/state.c +++ b/src/state.c @@ -74,12 +74,14 @@ state_conn_set(conn_t *conn, int state) { case CONN_HEADER: conn->ctr = 0; + conn->read_len = HDRSIZE; #ifdef DEBUG logw(5, "conn[%s]: state now is CONN_HEADER", inet_ntoa(conn->sockaddr.sin_addr)); #endif break; case CONN_RQST_FUNC: + conn->read_len = HDRSIZE + MB_FRAME(conn->buf, MB_LENGTH_L); #ifdef DEBUG logw(5, "conn[%s]: state now is CONN_RQST_FUNC", inet_ntoa(conn->sockaddr.sin_addr));