feat(plc4net): add serial and COTP transports - #2788
Conversation
1be917b to
0e00860
Compare
|
Hi @sruehl, the PR is ready for review now. This PR adds the serial and COTP transport layers required by plc4net, including connection lifecycle handling, COTP handshake and framing, serial-port configuration, and regression coverage for concurrent and malformed-frame scenarios. The build and all plc4net tests pass. Could you please take another look? Thank you |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
COTP shutdown races, blocked-write cancellation, disconnect handling, and oversized TPKT framing require correction.
Review effort: Balanced
Findings: 1
Open (5)
What changed in this PR
Adds reusable serial and COTP transports to PLC4Net, including configuration, framing, lifecycle handling, and regression tests.
Changes:
- Implements configurable RS-232/RS-485 transport.
- Implements COTP handshake, TPKT framing, segmentation, and diagnostics.
- Registers projects and adds transport tests.
| File | Description |
|---|---|
plc4net/transports/serial/SerialTransportInstance.cs |
Implements serial I/O lifecycle and buffering. |
plc4net/transports/serial/SerialTransportConfiguration.cs |
Defines serial settings. |
plc4net/transports/serial/SerialTransport.cs |
Parses and validates serial configuration. |
plc4net/transports/serial/serial.csproj |
Defines the serial project. |
plc4net/transports/cotp/TpktFrame.cs |
Implements TPKT framing helpers. |
plc4net/transports/cotp/CotpTransportInstance.cs |
Implements COTP protocol handling. |
plc4net/transports/cotp/CotpTransport.cs |
Wraps TCP with COTP transport creation. |
plc4net/transports/cotp/cotp.csproj |
Defines the COTP project. |
plc4net/test/spi-test/transports/SerialTransportConfigurationTests.cs |
Tests serial configuration. |
plc4net/test/spi-test/transports/CotpTransportInstanceTests.cs |
Tests COTP framing and lifecycle behavior. |
plc4net/test/spi-test/spi-test.csproj |
References new transport projects. |
plc4net/plc4net.sln |
Registers both projects. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Keep the handshake lock out of the blocking socket write. Writers are serialized by a dedicated lock, and Close() closes the inner transport before it takes the state lock, so a send stalled on a peer that stopped reading can no longer block Close() or the polling reads. - Revalidate that the handshake is still the current one before Open() publishes success, so a Close() that raced the Confirm is not undone. - Treat Disconnect Request, Disconnect Confirm (0xC0) and TPDU Error as session-ending: close the transport and report the teardown instead of leaving a session that looks usable. - Reject payloads that do not fit the 16-bit TPKT length field instead of silently truncating the length. - Correct the CotpTransport remarks about who performs the handshake and the framing.
- When the peer ends the COTP session (Disconnect Request, Disconnect Confirm or TPDU Error), keep the payload it already delivered readable instead of discarding it with the closed session. The transport still closes right away, so IsOpen turns false and Write() fails, but the teardown is reported only once no delivered bytes are left, or when a read asks for more than arrived. Write() and Open() now fail with the teardown reason instead of claiming that Open() was never called. - Reject a null inner transport with ArgumentNullException instead of a NullReferenceException. - Reject write-timeout=0 in the serial configuration: SerialPort only accepts a positive WriteTimeout or -1. - Add a test with two concurrent multi-fragment writers, which pins the write lock, and make the stalled-write test check how the blocked writer ends. Each fix is covered by a test that fails without it.



Summary
Context
This is the next transport-layer slice after the PLC4Net generator work. It is intentionally limited to reusable transports: Modbus RTU and S7 driver integration remain separate follow-up changes.
Validation
dotnet build plc4net/plc4net.sln --configuration Debug --no-restore --no-incremental --nologodotnet test plc4net/plc4net.sln --configuration Debug --no-build --no-restore --nologopython plc4net/tools/code-gen/generate_parsers.py --checkgit diff --check