Skip to main content

Versioning

The underlying Rust library follows the semantic versioning specification. Refer to the specification for the meaning of the <major>.<minor>.<patch> fields of the version number when using the library in Rust.

Version numbers​

The following sections describe the meaning of the fields in the version number.

Major​

Major releases are for substantial breaking changes and should occur infrequently. They provide an opportunity to consolidate functionality that may have been added in an ad hoc manner in support of backwards compatibility in minor releases. Major releases may also add functionality that requires refactoring of the API.

Minor​

Minor releases are for introducing new functionality in a (mostly) backwards compatible manner:

  • Rust - API compatible per semver
  • C & C++ - API compatible
  • Java - API compatible
  • .NET - API compatible with the exception that we may add new methods to interfaces that need to be stubbed out
Why is .NET different?

C++, Java, Rust, and even C (via NULL) support a way of defining default methods on interfaces. This allows us to extend interfaces in minor releases without breaking source compatibility in these languages. .NET needs .NET Standard 2.1 for default interface methods, which .NET Framework doesn't support, so the bindings target .NET Standard 2.0 and can't use them. Version 2.0 will target .NET Standard 2.1 and drop .NET Framework, which removes this exception.

Patch​

Patch releases are only for fixing bugs that cannot wait for a minor release to be resolved. Patch releases, e.g. 1.0.0 -> 1.0.1, are API compatible in all languages. The C library (librodbus_ffi.so) will also be ABI compatible between patch versions.

The latest release, version 1.6.0-RC1, is available on GitHub.

Changelog​

1.6.0​

  • 🛡️ Hardened against panics. Lints deny common sources of panics, and CI proves that parsing, answering requests and formatting replies can't panic for any input.
  • 🔔 License update. The license now prohibits using the library to build or test other implementations of the protocol, including by mining it with AI tools or using it as an oracle, and reserves AI training. See #224.
  • 🔔 MinTlsVersion is a minimum. V1_2 now allows TLS 1.3, and V1_3 no longer allows TLS 1.2. See #212.
  • 🔔 A request's timeout covers sending it; one that can't be sent in time fails with Io(TimedOut) and the connection is reopened. See #215.
  • 🔔 A read whose range is empty or runs past address 0xFFFF fails with InvalidRange before anything is sent. See #235.
  • 🔔 Out-of-range settings, such as a zero timeout or queue size or reversed retry bounds, are adjusted to valid values. See #236, #241 and #302.
  • 🔔 Servers ignore requests for units they don't serve and validate requests as the standard requires. See #274, #277, #280 and #284.
  • 🔔 RTU readers resynchronize after a bad frame instead of reopening the port, and frames are separated by the required silence. See #269, #297 and #345.
  • 🔔 Ordinary traffic no longer logs warnings; received frames log under rodbus::common::frame. See #242, #243 and #346.
  • 🛡️ TLS client handshakes time out after 5 seconds, and a request's write is bounded by its timeout. See #215.
  • 🛡️ Bindings: a TLS server without an authorization handler applies its address filter, and roles containing NUL are refused. See #220 and #221.
  • ⭐ Channel::shutdown() and ServerHandle::shutdown() end a task while handles are still alive. See #198.
  • ⭐ Non-spawning create_*_server_task() functions return a ServerTask for the caller to spawn. See #188.
  • ⭐ Configuration and task types implement Debug, without key material. See #240.
  • ⭐ Prebuilt C/C++ bindings for 32-bit x86 Linux (i686-unknown-linux-gnu). See #370.
  • 🐛 The client ignores responses from a unit it didn't address. See #223.
  • 🐛 IPv4 address filters match IPv4-mapped peers on dual-stack servers. See #260.
  • 🐛 Bindings: a single coil write returns the WriteHandler's exception instead of always ILLEGAL_DATA_ADDRESS. See #364.
  • 🐛 Other fixes. See #218, #222 and #247.
  • 🔧 Channel request methods take &self. See #191.
  • 🔧 The prebuilt C/C++ and .NET library is about 25% smaller. See #298 and #319.
  • 🔧 The prebuilt bindings use AWS-LC for TLS on every platform, which adds post-quantum key exchange to the musl and 32-bit ARM libraries. See #359.
  • 📖 The guide is reorganized and corrected, with the same examples in every language. See #362 and #366.

1.5.0​

  • ⭐ Add non-spawning create_tcp_client_task_with_options(), create_tls_client_task_with_options(), and create_rtu_client_task() that return a ClientTask for the caller to spawn, enabling custom task instrumentation. See #180.
  • 🔒 Update rustls-webpki to 0.103.13 to resolve RUSTSEC-2026-0098, RUSTSEC-2026-0099, and RUSTSEC-2026-0104. The two name-constraint advisories (0098, 0099) are theoretically reachable during TLS handshake but require certificate misissuance to exploit; the CRL panic (0104) is unreachable as Rodbus does not use CRLs.
  • ⭐ TCP client performance optimizations: ~33% fewer heap allocations and ~3.4% fewer instructions per request, including an iterative MBAP parser and ExactSizeIterator impls for the response iterators. See #177.
  • 🐛 Fix a ReadBuffer shift condition that, in a rare buffer-full edge case, caused a spurious disconnect (no data corruption). See #177.
  • ⭐ Add configurable limit on consecutive client response timeouts. See #166.
  • 🔧 Use aws-lc-rs crypto provider for TLS on most platforms. See #164.
  • 🔧 Tunable connection logging to reduce verbosity during disrupted communication. See #163.
  • ⭐ Add spawn_tcp_client_task_with_options() with extensible ClientOptions builder API. See #161.
  • 🐛 Fix bad default upper limit in retry strategy. See #158.
  • 🔧 PartialEq and Debug consistently applied to public API. See #157.
  • ⭐ Support serde on configuration types with new serialization feature. See #156.
  • 🔧 rodbus-client modernization with serial support and improved error handling. See #152.

1.4.0​

  • 🔧 Avoid task spawning in client FFI methods. See #136.
  • 🔧 Requests in the client API now fail immediately while the client is connecting.

1.3.1​

  • 🐛 Fix issue with master channels not properly exiting and thrashing CPU. See #120.

1.3.0​

  • 🔧 Update to rustls 0.21 which allows peer names with IP addresses in the SAN extension.
  • 🔧 Move common TLS configuration to its own crate shared with our Modbus library.
  • ⭐ PEM parser now supports extracting PKCS#1 private keys, i.e. PEM files with BEGIN RSA PRIVATE KEY.
  • 📖 Documentation improvements in the bindings via oo-bindgen 0.8.3.

1.2.0​

  • ⭐ Add a mechanism to the bindings to shut down the Runtime with a timeout. See #110.

1.1.0​

  • ⭐ Enable TCP_NODELAY for client and server sockets. See #99.
  • ⭐ Enable full link-time optimization (LTO) in release builds. See #103.
  • ⭐ Add support for 3 MUSL Linux targets to C/C++ and .NET. See #104.
  • ⭐ Use only dependencies from crates.io allowing first release there. See #106.
  • ⭐ Internal refactoring to promote code reuse with DNP3. See: #100, #101, #102.

1.0.0​

  • ⭐ Add Modbus Security (TLS) support. See #52.
  • ⭐ Add RTU support. See #56.
  • ⭐ Dynamic protocol decoding. See #61.
  • ⭐ Resolve host names on client. See #68.
  • ⭐ Add communication channel state callbacks. See #77.
  • ⭐ TCP/TLS server can now filter incoming connections based on IP. See #87.
  • 🐛 Properly reset TCP connection retry timeout on success. See #82.

0.9.1​

  • Client callbacks are now not blocking. See #53.
  • 🐛 Fix leak of tracing::Span in bindings. See #53.
  • ⭐ Add Linux AArch64 support in Java and .NET. See #51.

0.9.0​

  • 🎉 First official release