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.
This commit is contained in:
Dustin Lundquist 2019-01-22 10:50:42 -08:00
parent 8a29a0e029
commit 5c064928ae
4 changed files with 7 additions and 2 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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));