Skip to content

Commit

Permalink
Guide updates for 1.0 (#93)
Browse files Browse the repository at this point in the history
* fix links and references to DNP3

* tweak the supported functions

* update dependencies

* update the TCP server page

* update the TLS server page with info about the mode that doesn't require the x.509 role extension

* Add a C++ page

* fix broken C++ logging doc reference

* update the serial RTU page
  • Loading branch information
jadamcrain authored Aug 24, 2022
1 parent 9f54bc0 commit 0d68860
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 66 deletions.
2 changes: 1 addition & 1 deletion ffi/bindings/c/client_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Logger : public rodbus::Logger {
std::cout << message;
}
};
/// ANCHOR_END: client_state_callback
/// ANCHOR_END: logging_callback

/// ANCHOR: client_state_callback
class PrintingClientStateListener : public rodbus::ClientStateListener {
Expand Down
47 changes: 19 additions & 28 deletions guide/docs/about/dependencies.mdx
Original file line number Diff line number Diff line change
@@ -1,50 +1,41 @@
---
id: dependencies
title: Managing Open Source Dependencies
title: Open Source Dependencies
sidebar_label: Dependency Licenses
slug: /dependencies
---

import useBaseUrl from '@docusaurus/useBaseUrl';
import sitedata from '../../sitedata.json'

Because Rust's package manager `cargo` makes it easy to work with external dependencies, Rust's open-source ecosystem tends to be oriented towards many smaller
libraries. Our library only depends directly on a few third-party libraries; however, those libraries pull in dozens of sub-dependencies. Here's how we
manage our direct and indirect dependencies.
Rust's package manager (`cargo`) makes it easy to work with external dependencies. This is wonderful for development, but means that Rust applications
and libraries tend to have many dependencies.

## Automated License Checking
Our library only depends directly on a handful of third-party libraries; however, those libraries pull in dozens of their own dependencies. Here's how we manage
our direct and indirect dependencies.

We developed an automated tool called `complicense` to ensure that our binary distributions meet the legal requirements for third-party open source licenses.
This tool performs the following tasks:
## Dependency Whitelisting

* Analyzes each dependency's license against an allowed list of licenses. Our CI packaging will fail if add a dependency is added with a license that has not been pre-approved.
* Uses the Github API to automatically retrieve the license file for each project hosted on Github. Only a few projects don't have the proper metadata; the
license name and content for those are specified manually in the `complicense` configuration.
* Ignores projects that are 100% copyrighted by Step Function I/O (e.g., the DNP3 library itself).
* Produces a license report document called `dependencies.txt` that consolidates all the dependency and license information. We include this document in all of
our binary distributions to make it easy for you to comply with the open source licenses.
We use a dependency whitelist to ensure that we never incorporate dependencies into our builds unless they are manually approved. During each CI build, the following
checks are performed:

## Proprietary Compatible

All of our library's dependencies have licenses that are both mutually compatible and compatible with commercial/proprietary products. We don't allow the
incorporation of strong copyleft licenses such as the GPL. You can see a complete list of allowed licenses in <a href={`${sitedata.github_url}/blob/${sitedata.version}/deps-config.json`}>deps-config.json</a>.
* Check every dependency against the whitelist. Our CI packaging will fail if add a dependency is added with a license that has not been pre-approved.
* Produce a license report called `third-party-licenses.txt` that consolidates all the dependency and license information. We include this document in all of
our binary distributions.
* Ignore projects that are 100% copyrighted by Step Function I/O, e.g. the library itself and some dependencies we share between with our other protocol libraries.

## Licenses.txt
:::note
The license report file differs slightly for the Java library as it incorporates some additional components for the JNI functionality.
:::

`complicense` produces a detailed report called <a href={`${sitedata.github_url}/releases/download/${sitedata.version}/dependencies.txt`}>dependencies.txt</a> that includes the following
information for each dependency:

* Unique name of the library (Rust crate)
* Repository URL where the library is hosted
* Authors of the library as specified on [crates.io](https://crates.io/)
* Description of the library
* Name of the license(s) that apply to the crate
* Full license text, including any copyright notices present
## Proprietary Compatible

Some libraries choose to dual-license under multiple licenses and give users the choice of which license to use. In this case, the report only includes the text of the license returned by the Github API.
All dependencies of the library have licenses that are both mutually compatible and compatible with commercial/proprietary products. We don't allow the
incorporation of strong copyleft licenses such as the GPL. You can see a complete list of allowed dependencies and licenses in <a href={`${sitedata.github_url}/blob/${sitedata.version}/deps_config.json`}>deps_config.json</a>.

## Disclaimer

We've included this information because we take open source license compliance seriously. That said, this information and the `dependencies.txt` file are provided for your reference and do not constitute legal advice. Treat this information as a starting point so you can perform your own due diligence.
We've included this information because we take open source license compliance seriously. That said, this information and the `third-party-licenses.txt` file are provided for your reference and do not constitute legal advice. Treat this information as a starting point so you can perform your own due diligence.


28 changes: 7 additions & 21 deletions guide/docs/about/modbus.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@ it very popular in numerous applications. The standard itself is freely availabl
and serial communication, and more recently, has been defined for secure operation over TLS. Modbus is sometimes referred to as "Modicon Modbus" or just
"Modicon" for historical reasons.

Modbus is a simple request-response protocol, and the server component is completely stateless. This simplicity however frequently means that the application
has more responsibilities than stateful protocols such as DNP3 (IEEE-1815).

A client issues a request to the server, then the server performs the action and returns the matching response or an exception code. Clients and servers are
sometimes known as "masters" and "slaves" in older documents.
Modbus is a simple request-response protocol, and the server component is completely stateless. A client issues a request to the server, then the server
performs the action and returns the matching response or an exception code. Clients and servers are referred to as "masters" and "slaves" in the specification
and older documents, however, we avoid this terminology in our documentation.

```mermaid
sequenceDiagram
Expand Down Expand Up @@ -74,7 +72,7 @@ The endianness of how compound values are laid out in registers may also vary fr

## Function codes

The following table illustrates the Modbus public function code and their support status in our library:
The following table lists the functions currently supported by our library:

| Code | Description | Support |
| ---- | ----------------------------- | ------- |
Expand All @@ -84,26 +82,14 @@ The following table illustrates the Modbus public function code and their suppor
| 0x04 | Read input registers | ✔️ |
| 0x05 | Write single coil | ✔️ |
| 0x06 | Write single register | ✔️ |
| 0x07 | Read exception status ||
| 0x08 | Diagnostic ||
| 0x11 | Get com event counter ||
| 0x12 | Get com event log ||
| 0x15 | Write multiple coils | ✔️ |
| 0x16 | Write multiple registers | ✔️ |
| 0x17 | Report server ID ||
| 0x20 | Read file record ||
| 0x21 | Write file record ||
| 0x22 | Mask write register ||
| 0x23 | Read/write multiple registers ||
| 0x24 | Read FIFO queue ||
| 0x43 | Read device ID ||

The supported function codes are all that is required by the vast majority of applications using Modbus. We would consider adding support for additional
functions codes if requested by a potential customer.

These functions are all that is required for the vast majority of applications using Modbus. We would consider adding support for additional
functions codes if requested by a potential customer.

Modbus also allows user-defined function codes in the range 65 to 72 and 100 to 110. This library does not support adding user defined functions at this time,
but this could also be added if desired.
but could be added if desired.

## Exceptions

Expand Down
11 changes: 9 additions & 2 deletions guide/docs/api/server/rtu_server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ enforce this requirement, but a warning message is generated as a reminder that
## Creating a server

To create a RTU server, first build a `DeviceMap` for each unit ID to which the server will respond. The is similar to how it's done in the [TCP server](./tcp_server).
Then use the `create_rtu_server` factory method of the `Server` class. The created server will start listening on the serial port immediately.
Then use the `Server.CreateRtu` factory method to create the background task.

The `create_rtu_server` function takes the following arguments:
The `Server.CreateRtu` method takes the following arguments:

- `runtime`: tokio runtime used to drive the async process. See [Runtime](../runtime.mdx) for more details.
- `path`: path of the serial device.
Expand All @@ -44,6 +44,13 @@ The `create_rtu_server` function takes the following arguments:
- Stop bits
- Parity
- Flow control
- `port_retry_delay`: how long to wait before reopening after a failed open or port error.
- `map`: Map of unit ids and their corresponding callback handlers.
- `level`: Initial decoding level for the port which can be adjusted later via the returned Channel.

:::tip
The task handling the port is tolerant to the hardware device being added and removed from the system as might occur with USB to serial adapters.
:::

<Tabs
groupId="language"
Expand Down
11 changes: 6 additions & 5 deletions guide/docs/api/server/tcp_server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ slug: /api/server/tcp_server
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

## Network Model

Each TCP server instance is capable of processing requests for one or more unit IDs from multiple external clients.

```mermaid
Expand All @@ -30,15 +28,18 @@ The `DeviceMap` class is used to build the association between unit IDs and the
To create a server, first build a `DeviceMap` for each unit ID that the server will answer. Then use the `create_tcp_server` static method of the `Server` class.
The created server will start listening on the port immediately.

The `create_tcp_server` function takes the following arguments:
The `Server.CreateTcp` method takes the following arguments:

- `runtime`: tokio runtime used to drive the async process. See [Runtime](../runtime.mdx) for more details.
- `endpoint`: endpoint specified in the format `<address>:<port>`. Addresses may be any specified as any valid IPv4 or IPv6 local endpoint, such as:
- `address`: IP address of the adapter on which to listen. It may be any specified as any valid IPv4 or IPv6 local endpoint, such as:
- `127.0.0.1` for localhost only
- `0.0.0.0` for all adapters
- The IP address for a particular adapter
- `port`: port on which to listen for connection
- `filter`: `AddressFilter` which can be used to limit which external IPs may connect.
- `max_sessions`: maximum concurrent sessions allowed by the server. When the maximum number of sessions is reached, a new connection will end the oldest session
in order to limit resource usage.
in order to limit resource usage.
- `map`: Map of unit ids and their corresponding callback handlers.

<Tabs
groupId="language"
Expand Down
7 changes: 7 additions & 0 deletions guide/docs/api/server/tls_server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ Creating a TLS server for outstation instances is exactly the same process as a
except that an extra `TlsServerConfig` and an `AuthorizationHandler` is required. For more details about TLS
support and the configuration options, check the [TLS general information](../tls.mdx) page.

:::tip
A server mode of operation is also supported which does not require the client certificate to contain the role extension.

The example only demonstrate the `Server.CreateTlsWithAuthz` method, but there is a `Server.CreateTls` which does NOT take an `AuthorizationHandler` parameter
and allows an authenticated client to perform any Modbus operation.
:::

## Examples

### Certificate chain configuration
Expand Down
101 changes: 101 additions & 0 deletions guide/docs/languages/cpp_lang.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
id: cpp_bindings
title: C++ bindings
sidebar_label: C++
slug: /cpp_bindings
---

import useBaseUrl from '@docusaurus/useBaseUrl';
import sitedata from '../../sitedata.json'

Each [C package distribution](./c_lang.mdx) also includes C++ wrappers for easy usage. The `rodbus.hpp` file includes the public API
and a `src/rodbus.cpp` contains the companion code which maps the C++ API to the underlying C API.

## CMake Usage

The CMake package script includes a `rodbus_cpp` target that automatically links with the C bindings and builds the C++ wrapper code.

Make the find package script discoverable by adding it to the prefix path. Next, call `find_package`:

```cmake
# Define CMake project with CXX language
project(my_awesome_project LANGUAGES C CXX)
# Import the rodbus package
set(CMAKE_PREFIX_PATH ${DISTRIBUTION_PATH}/cmake)
find_package(rodbus REQUIRED)
# Create and link the executable w/ the c++ library
add_executable(my_awesome_project main.cpp)
target_link_libraries(my_awesome_project PRIVATE rodbus_cpp)
```

:::note
The `rodbus_cpp` CMake target is made available only if the `CXX` language is enabled. Languages can be enabled in the
[project()](https://cmake.org/cmake/help/latest/command/project.html) command or with a separate
[enable_language()](https://cmake.org/cmake/help/latest/command/enable_language.html) command.
:::

## Mapping

Most of the abstract concepts in the binding generator map directly to C++.

### Errors

All C API errors are transformed into a C++ exceptions containing the error enum. All exceptions derive from `std::logic_error`.

Other validations (e.g. checking that a moved class isn't used after the move) also throw `std::logic_error`.

:::warning
Uncaught exceptions thrown in callbacks will terminate the program. Always wrap your callback logic using `try/catch` syntax if there's a possibility the callback will throw.
:::

### Iterators

Iterators are wrapped in a class for easier manipulation. Iterating on them should done like so:

```cpp
while(iter.next()) {
auto value = iter.get();
}
```

The `next()` advances the iterator and returns `true` if a value is available. The `get()` returns the current value pointed, or throws
`std::logic_error` if the end was reached.

:::warning
The iterator wrapper does **not** copy and accumulate the values like in C# or Java. Therefore, an iterator should **never** be used outside of the callback.
Frequently, the iterator points to memory on the stack and will result in undefined behavior if it is used after the callback is complete.
:::

### Collections

Collections are taken through a constant reference to a `std::vector`. The elements will be copied internally.

### Classes

Classes have a opaque pointer inside and therefore cannot be copied. They can be moved around with `std::move`. If a method
is called on a moved class it throw a `std::logic_error`.

The class destructor will call the underlying C destructor automatically.

### Interfaces

Interfaces are abstract classes containing only pure virtual functions where every callback must be implemented. The destructor is virtual to allow proper cleanup.

Owned interfaces that are invoked asynchronously by the library are passed into the API as a `std::unique_ptr<T>`. Use `std::make_unique` to create these smart pointers.

Non-owned (synchronous) interfaces are passed by reference. There are also functional wrappers that take a lambda
function as an argument available in the `dnp3::functional` namespace.

### Async methods

C++ doesn't have a robust model for asynchronous computations in the standard library (yet). You can only extract a value
from a C++ `std::future` using the blocking `get` method and there is no way to chain asynchronously chain futures.

Asynchronous methods are mapped to callback interfaces with two methods:

* `on_complete` is called when the operation succeeds
* `on_failure` is called if an error occurs

If you already use an external futures library, it will be easy to use our callbacks to complete your futures.
14 changes: 5 additions & 9 deletions guide/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,17 @@ module.exports = {
},
{
label: 'Homepage',
href: 'https://stepfunc.io/products/libraries/dnp3/',
href: 'https://stepfunc.io/products/libraries/modbus/',
},
],
},
{
title: 'DNP3',
title: 'Modbus',
items: [
{
label: 'User Group',
to: 'https://dnp.org',
},
{
label: 'IEEE 1815-2012',
to: 'https://standards.ieee.org/standard/1815-2012.html',
},
label: 'Modbus.org',
to: 'https://modbus.org/',
}
],
},
],
Expand Down
1 change: 1 addition & 0 deletions guide/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module.exports = {
{
Bindings: [
'languages/c_bindings',
'languages/cpp_bindings',
'languages/java',
'languages/c_sharp',
]
Expand Down

0 comments on commit 0d68860

Please sign in to comment.