Skip to content

ModbusTCP returns Status_Processing in blocking mode on Linux #14

@mambuehl

Description

@mambuehl

Hi @serhmarch
Thank you for sharing your library!

I think I might found an issue in the TCP client in blocking mode.

Environment

  • ModbusLib Version: v0.4.9
  • Compiler: aarch64-none-linux-gnu, 14.2rel1
  • Platform: aarch64, Linux 64 bit, kernel 6.12.63-v8-16k

Description

There seems to be an issue on Linux with the Modbus TCP client in blocking mode.
When the connection is lost while awaiting a response from the server, ModbusClientPort::readHoldingRegisters() returns Status_Processing.
This results in blocked communication during further requests, where all requests return Status_Processing after the configured timeout. This situation remains until the kernel destroys the socket itself. (about 15 minutes)

In non-blocking mode this is not an issue. No matter at what point the connection is lost, the lib returns an error and further requests are successful again.

The issue can be reproduced by using clumsy, setting a lag/delay of 1000 ms, and then click RST next packet when a request was sent, but before the response is received.

Used config:

Modbus::TcpSettings settings;
settings.host = "<server ip address>";
settings.port = 502;
settings.timeout = 5000;
client_ = Modbus::createClientPort(Modbus::TCP, &settings, true)

uint16_t data = 0;
status = client_.readHoldingRegisters(1, 12, 1, &data);
if (Modbus::StatusIsProcessing(status)) {
    // I think this should never be reached, but it does.
    // If further requests are made, they all time out and arrive here
}

Root cause

I think the issue is in ModbusTcpPort::read() in ModbusTcpPort_unix.cpp:
In case STATE_WAIT_FOR_READ_ALL:, the last else block:

else
{
    int e = errno;
    if (e != EWOULDBLOCK)
    {
        close();
        ....
    }
}

If errno is EWOULDBLOCK (== EAGAIN), the socket is not closed and Status_Processing is returned.
This in turn slips through the state machine StatusCode ModbusClientPort::process() in ModbusClientPort.cpp:
Where case STATE_READ: does

r = d->port->read();
if (StatusIsProcessing(r))
    return r;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions