Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plc4rs): Add transport layer with TCP/UDP implementations #2010

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

jsxs0
Copy link

@jsxs0 jsxs0 commented Feb 15, 2025

PLC4X Rust Implementation

This PR implements the initial transport layer and S7 protocol foundation in Rust. The implementation focuses on memory safety, performance, and maintainability.

Current Features:

Transport Layer (SPI)

  • Transport trait with async connect/read/write/close operations
  • TCP transport implementation with configuration support
  • UDP transport implementation
  • Comprehensive error handling with detailed messages
  • Retry mechanism with backoff support
  • Logging integration

Protocol Implementation

  • Zero-copy parsing using nom (in progress)
  • Type-safe protocol structures following s7.mspec
  • Memory-safe implementation with no unsafe code

Testing

  • Unit tests for transport implementations
  • Connection handling tests
  • Basic protocol parsing tests
  • Real-world usage examples

Next Steps:

  1. Complete S7 protocol parsing
  2. Add serial transport support
  3. Implement Maven integration
  4. Add XML-based test runners
  5. Expand documentation

Technical Details:

  • Uses tokio for async I/O
  • Follows Rust best practices for error handling
  • Implements retry and timeout configurations
  • Provides clear examples for both TCP and UDP usage

Looking forward to feedback on the transport layer implementation before proceeding with the full protocol implementation.

- Add async S7 protocol parsing with Tokio
- Implement fuzz testing infrastructure
- Add comprehensive documentation
- Set up CI/CD pipeline for Rust
@chrisdutz
Copy link
Contributor

Oh wow :-)

Welcome to the project ... this is really something super interesting for us. I had it on my todo list for way too long.

Do I understand the PR correctly, that you are currently manually implementing the types needed in order to create the driver? If yes, that's absolutely fine and usually the way I started porting PLC4X to other languages. Once you have most parts implemented, I will definitely help you port that to have that code generated. Please ping me, if you need help with that.

I know we have a super-ancient branch in our repo, where Julian once started working on something like that ... perhaps that could also be helpful for you? (https://github.com/apache/plc4x/tree/feature/plc4rs/plc4rust)

Chris

@jsxs0
Copy link
Author

jsxs0 commented Feb 15, 2025

@chrisdutz Thank you for the warm welcome, Chris!

Yes, you understood correctly - I'm currently implementing the core types manually to better understand the protocol intricacies and establish a solid foundation for the Rust implementation. This approach helps ensure we leverage Rust's type system and safety features effectively while maintaining high performance.

Thank you for pointing out Julian's branch - I'll definitely take a look at it. While starting fresh helped me understand the requirements better, there might be valuable insights there that could inform this implementation.

I'm very interested in learning more about the code generation approach you mentioned. Once I have the core types and parsing logic stabilized, I'd greatly appreciate your guidance on integrating with PLC4X's code generation system.

Currently focusing on:

  1. Zero-copy parsing with nom
  2. Type-safe protocol representations
  3. Async connection handling

I'm hoping to contribute this as part of GSoC 2025, so I wanted to get an early start to demonstrate commitment and gather community feedback. Would you prefer I continue with the manual implementation for now, or would you like to discuss code generation integration earlier in the process?

@chrisdutz
Copy link
Contributor

Cool :-)

This way I might even have some chance to start learning rust ;-)

As long as possible, it would be cool, if you could structurally stick to the structures as we define them in the s7 mspec, that will ensure that we can convert your manually written code into generated one a lot easier: https://github.com/apache/plc4x/blob/develop/protocols/s7/src/main/resources/protocols/s7/s7.mspec

Also when looking at the java implementation, don't let yourself be confused ... there is also a subscription protocol implemented in parallel in there, which complicates things quite a bit. Usually a reason why I like to start off with Modbus, for porting PLC4X to new languages ... it's definitely the simplest protocol.

@jsxs0
Copy link
Author

jsxs0 commented Feb 15, 2025

@chrisdutz Thanks Chris! Happy to help you get started with Rust too.

The s7.mspec is really helpful - I'll make sure my Rust structs follow these definitions closely. Makes sense about keeping it compatible with the code generation system.

About the subscription protocol - I think I'll start with just the basic S7 protocol first to keep things clean. I can look at Modbus too if you think that would be more helpful for understanding the overall architecture.

Let me update the current implementation to match the mspec and I'll push the changes soon.

@jsxs0
Copy link
Author

jsxs0 commented Feb 19, 2025

@chrisdutz I've made some changes:

  1. Is the alignment with s7.mspec correct, I mean, for parameter types?
  2. Are there any protocol features missing from this initial implementation?
  3. Is the error handling approach sufficient for industrial use?
  4. Should we add more specific test cases?

For now, I'm thinking of the following next steps:

  1. Add async connection handling
  2. Implement message serialization
  3. Add more protocol-specific error cases
  4. Expand test coverage
  5. Add documentation

@chrisdutz
Copy link
Contributor

I guess in order to review the actual code, it would probably help, if I understood Rust ;-)

I can give you some pointers to what's generally important when bringing plc4x to new languages:

  • Build an SPI, so a lot of the general purpose code can be shared among protocol-drivers
  • Support the concept of transports: serial, udp, tcp, (raw-socket) ... and "test"

The following would be for when the code-gen has generally been implemented:

  • Implement a runner to run the xml-based ParserSerializer tests (That are deployed along the mspec-protocol modules) against your generated code
  • Implement a runner to run the xml-based Integration tests (That are deployed along the mspec-protocol modules) against your driver

I'll try to have a look and play around with your driver. Thanks for contributing.

@chrisdutz
Copy link
Contributor

So from a quick look, I guess we'll need a Maven integration to allow a normal maven build to trigger the rust build, but I think we can borrow things from Julian's branch. Possibly I could create PRs for your PR ... Let me see which form of collaboration works best.

Add initial SPI layer for PLC4X Rust with:
- Transport trait with retry and logging support
- TCP transport implementation with configuration
- Basic error handling using thiserror
- Example showing TCP transport usage

This provides the foundation for protocol-specific implementations.
@jsxs0
Copy link
Author

jsxs0 commented Feb 20, 2025

@chrisdutz Hey Chris,

Added the initial SPI layer with a basic TCP transport implementation. Kept it focused for now:

  1. Transport trait with connect/read/write/close
  2. TCP implementation with retry support
  3. Basic config system for timeouts and TCP options
  4. Error handling and logging

Let me know if this looks OK as a starting point. Planning to add UDP and Serial support (in follow-up PRs).

@chrisdutz
Copy link
Contributor

Wie... Great stuff... I'll look at it ASAP, however it might take a bit as I'm traveling to a music festival over the weekend and next week is the last of my 2,5 month sabbatical... Still some things to finish. Just want you to know that you're not frustrated why I'm so slow... It's not lack of interest, it's too much stuff going on.

Looking forward to getting the time to have a deeper lookm

@ottlukas ottlukas added S7 https://plc4x.apache.org/users/protocols/s7.html feature labels Feb 20, 2025
@jsxs0
Copy link
Author

jsxs0 commented Feb 21, 2025

@chrisdutz No worries at all about the timing, Chris! Enjoy the music festival and your remaining sabbatical time.

While you're away, I'll focus on:

  1. Implementing UDP transport following the same pattern as TCP
  2. Starting on the Maven integration (using Julian's branch as reference)
  3. Adding more test cases, especially for error scenarios

I'll keep the changes small and focused to make review easier when you have time. Looking forward to your deeper look whenever you're back!

- Implement UDP transport following TCP pattern
- Add configuration support for UDP
- Update example to show both TCP and UDP usage
- Add basic UDP transport tests

This builds on the TCP transport to provide UDP support for the PLC4X Rust implementation.
@jsxs0 jsxs0 changed the title feat(rust): Add initial S7 protocol implementation feat(plc4rs): Add transport layer with TCP/UDP implementations Feb 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature S7 https://plc4x.apache.org/users/protocols/s7.html
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants