diff --git a/guide/docs/about/dependencies.mdx b/guide/docs/about/dependencies.mdx index a285fc9e..484956f3 100644 --- a/guide/docs/about/dependencies.mdx +++ b/guide/docs/about/dependencies.mdx @@ -8,11 +8,9 @@ slug: /dependencies import useBaseUrl from '@docusaurus/useBaseUrl'; import sitedata from '../../sitedata.json' -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. +Rust's package manager (`cargo`) makes it easy to work with external dependencies. This is great for development, but means Rust applications and libraries tend to have many dependencies. -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. +Our library depends directly on a handful of third-party libraries, but those pull in dozens of their own. Here's how we manage dependencies. ## Dependency Allowlisting diff --git a/guide/docs/about/dnp3.mdx b/guide/docs/about/dnp3.mdx index 18880f7e..e95fe482 100644 --- a/guide/docs/about/dnp3.mdx +++ b/guide/docs/about/dnp3.mdx @@ -24,7 +24,7 @@ A DNP3 outstation is a field device that provides measurement data and controls * Capacitor banks * Voltage-regulators -If you use DNP3 over TCP/IP, the outstation typically acts as a TCP server. This lets it accept connections from one or more masters acting as a TCP client. +Over TCP/IP, the outstation typically acts as a server, accepting connections from one or more masters acting as TCP clients. :::note Unlike typical client/server architecture where multiple clients can access the same server, DNP3 statefully buffers event data for a specific master. @@ -33,8 +33,7 @@ If you plan to connect multiple masters to the same TCP endpoint, you must preco ### Virtual RTUs -You can also use a DNP3 outstation to transfer measurement and control data from a utility SCADA system to a historian or automation process. This is also known as a virtual remote terminal unit (RTU) since you implement it as a software -processor within the SCADA server without separate physical hardware. +A DNP3 outstation can transfer measurement and control data from a SCADA system to a historian or automation process. This is called a virtual RTU—a software processor within the SCADA server with no separate physical hardware. ```mermaid graph LR diff --git a/guide/docs/about/guide.mdx b/guide/docs/about/guide.mdx index 297e187e..36391cbf 100644 --- a/guide/docs/about/guide.mdx +++ b/guide/docs/about/guide.mdx @@ -28,8 +28,7 @@ Language-specific API documentation is available via the links below: ## IEEE-1815 -While this guide covers many DNP3 concepts, it is not a replacement for the DNP3 standard. If you plan to develop a product that uses DNP3, a copy of the -standard is indispensable. Purchase your copy from the [DNP3 Users Group](https://dnp.org) or [IEEE](https://standards.ieee.org/standard/1815-2012.html). +This guide covers many DNP3 concepts but is not a replacement for the standard. If you're developing a DNP3 product, the standard is indispensable. Purchase it from the [DNP3 Users Group](https://dnp.org) or [IEEE](https://standards.ieee.org/standard/1815-2012.html).
DNP3 logo diff --git a/guide/docs/about/interoperability.mdx b/guide/docs/about/interoperability.mdx index 3c8f3075..7c38170a 100644 --- a/guide/docs/about/interoperability.mdx +++ b/guide/docs/about/interoperability.mdx @@ -11,12 +11,12 @@ DNP3 defines four subset levels of interoperability: * `Level 2`: This adds several function codes and objects in order to support a simple RTU or data concentrator. * `Level 3`: This adds additional function codes and objects, most notably enable/disable of unsolicited reporting, in order to support complex RTUs/concentrators. * `Level 4`: This adds rarely-used features, such as floating-point analog variations, double-bit binary inputs, and device attributes. -* Please note that features like file transfer, datasets, and secure authentication do not belong to any subset level. +Features like file transfer, datasets, and secure authentication do not belong to any subset level. ### Current Support: Level 3 -Our library is currently `Level 3` compliant for both master and outstation. We will make it `Level 4` compliant in a future release. Please note that we already support a number of `Level 4` features, along with features that do not belong to a subset level including: +Our library is currently `Level 3` compliant for both master and outstation. `Level 4` compliance is planned for a future release. We already support a number of `Level 4` features, along with features outside subset levels: | Feature | Objects | Level | |---------------------------|---------------------------------------------------------|:----------:| diff --git a/guide/docs/api/logging.mdx b/guide/docs/api/logging.mdx index 75e54ef4..f6bd8d7f 100644 --- a/guide/docs/api/logging.mdx +++ b/guide/docs/api/logging.mdx @@ -8,7 +8,7 @@ slug: /api/logging import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -The library provides highly-contextual logging using the [tracing](https://crates.io/crates/tracing) crate. If you're using Rust, refer to the +The library uses the [tracing](https://crates.io/crates/tracing) crate for contextual logging. Rust users should refer to the tracing documentation for details. In comparison, the bindings use a rigid logging interface with a single callback method to record a message. Configurable options include: @@ -87,7 +87,7 @@ use. ## Example Output -The logs provide a wealth of contextual metadata so you can: +Logs include contextual metadata so you can: * Determine which communication session produced the message * Understand what state the software was in when the event occurred @@ -103,16 +103,14 @@ INFO DNP3-Master-TCP{endpoint="127.0.0.1:20000"}:Task{type=Function(DisableUnsol ## Protocol Decoding -Protocol decoding is configurable on a per-communication channel basis, such as all traffic on a TCP socket or a serial port. You can specify the -`DecodeLevel` when you create a master or outstation or adjust it at runtime. This struct controls the level of decoding (including none) that takes place for each layer of the -protocol stack, including: +Configure protocol decoding per communication channel (TCP socket, serial port, etc.) by setting `DecodeLevel` when creating a master or outstation, or adjust it at runtime. This controls decoding for each layer of the protocol stack: * Application-layer headers, object headers, and object values * Transport-layer header and payload * Link-layer header and payload * Physical-layer length and data bytes -Refer to the language-specific API documentation for the meaning of each enumeration value. The decoding can even show the value of individual fields within objects: +See the language-specific API documentation for enumeration values. Decoding can show individual field values within objects: ``` APP TX - ctrl: [fir: true fin: true con: false uns: false seq: 1] func: Write ... (len = 6) diff --git a/guide/docs/api/master/association_config.mdx b/guide/docs/api/master/association_config.mdx index a3e8f665..d242e34b 100644 --- a/guide/docs/api/master/association_config.mdx +++ b/guide/docs/api/master/association_config.mdx @@ -8,14 +8,14 @@ slug: /api/master/association/config import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -The `AssociationConfig` struct provides the configuration information you need to communicate with a particular outstation on the communication channel, including: +`AssociationConfig` configures communication with a particular outstation: * Timeout for responses on this association * Startup handshaking * If and how to perform time synchronization * Per-association task queue size -Note that the outstation address is provided as a separate argument when adding an association to a channel. +The outstation address is provided as a separate argument when adding an association to a channel. >Master: Response; ``` -If your outstation doesn't support unsolicited reporting, you can turn the DISABLE/ENABLE unsolicited requests off by setting -`AssociationConfig.DisableUnsolClasses` and `AssociationConfig.EnableUnsolClasses` to `EventClasses.None()`. The master will then skip unsolicited configuration during initialization, only performing the integrity poll. +If your outstation doesn't support unsolicited reporting, set `AssociationConfig.DisableUnsolClasses` and `AssociationConfig.EnableUnsolClasses` to `EventClasses.None()`. The master will skip unsolicited configuration and only perform the integrity poll. ## Scheduling -The following algorithm is used to schedule requests within an association: +Requests within an association are scheduled as follows: 1. User requests such as control operations get top priority. 2. The association then considers automatic and initialization tasks in this order: @@ -92,7 +91,7 @@ The following algorithm is used to schedule requests within an association: 3. Perform an integrity scan if configured to do so during initialization. 4. Perform automatic time synchronization if enabled, and the master observes the 'NEED_TIME IIN' bit in a response. 5. Enable unsolicited reporting if configured to do so during initialization. -3. Finally, the system will then execute periodic polls. +3. Periodic polls execute last. :::note The standard does not specify how requests should be scheduled for multiple associations on a channel. Our implementation uses a per-association task queue. The channel scheduler round-robins through the associations to ensure fair access. diff --git a/guide/docs/api/master/association_create.mdx b/guide/docs/api/master/association_create.mdx index 82fc033c..3729fb56 100644 --- a/guide/docs/api/master/association_create.mdx +++ b/guide/docs/api/master/association_create.mdx @@ -8,7 +8,7 @@ slug: /api/master/association/create import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -You can create associations on a `MasterChannel` by specifying configuration and callback interfaces. +Create associations on a `MasterChannel` by specifying configuration and callback interfaces. -The `AssociationId` struct that is returned when adding an association is just a token. While it's required to perform operations on a particular outstation on the channel, -you don't need to keep a reference to it unless you need it to perform operations later. Allowing the `AssociationId` to be garbage collected won't remove the association from the channel. +The returned `AssociationId` is just a token. It's required for operations on a particular outstation, but you don't need to keep a reference unless you need it later. Garbage collecting the `AssociationId` won't remove the association from the channel. ## Removing diff --git a/guide/docs/api/master/association_handler.mdx b/guide/docs/api/master/association_handler.mdx index a189cfd8..a1b7f059 100644 --- a/guide/docs/api/master/association_handler.mdx +++ b/guide/docs/api/master/association_handler.mdx @@ -8,10 +8,9 @@ slug: /api/master/association_handler import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -The `AssociationHandler` interface handles all the per-association callbacks that are unrelated to measurement data. It contains a single method (`get_current_time`) -to retrieve a UTC timestamp used to synchronize the time on the outstation. +`AssociationHandler` handles per-association callbacks unrelated to measurement data. It contains a single method (`get_current_time`) to retrieve a UTC timestamp for time synchronization. -Typically, you'd return the system time in `get_current_time` which is kept synchronized via NTP. However, you can use a different clock if desired. For example, you might want a data concentrator to receive time from an upstream DNP3 master while maintaining an offset from an internal clock. The examples below demonstrate how to implement an `AssociationHandler` that retrieves the system time. +Typically, return the system time (synchronized via NTP) in `get_current_time`. You can use a different clock if desired—for example, a data concentrator receiving time from an upstream DNP3 master. The examples below retrieve the system time. ```c -This is possible, but not part of the C example! +// Not demonstrated in this example. ``` @@ -111,7 +111,7 @@ values={[ ```c -This is possible, but not part of the C example! +// Not demonstrated in this example. ``` @@ -160,7 +160,7 @@ a background file transfer, accumulating the file data over possibly multiple bl of `FileInfo` instances. :::warning -The default limit for the size of directory file is 2048 bytes. This is a reasonable and safe limit, however, if its too +The default limit for the size of directory file is 2048 bytes. This is a reasonable and safe limit, however, if it's too small in your application you can raise this limit using the provided parameter in `DirReadConfig`. ::: @@ -184,7 +184,7 @@ values={[ ```c -This is possible, but not part of the C example! +// Not demonstrated in this example. ``` diff --git a/guide/docs/api/master/read_handler.mdx b/guide/docs/api/master/read_handler.mdx index ab184bb6..01cff725 100644 --- a/guide/docs/api/master/read_handler.mdx +++ b/guide/docs/api/master/read_handler.mdx @@ -8,8 +8,7 @@ slug: /api/master/read_handler import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -The `ReadHandler` interface is used to receive values from the outstation as it is received by the master. This callback interface is specified -for each association you create and is invoked for both unsolicited responses and responses to READ requests. +The `ReadHandler` interface receives measurement values from the outstation. Specify it for each association; it's invoked for both unsolicited responses and READ responses. When a response is parsed and determined to carry measurement data, `ReadHandler` callbacks are executed in the following order: @@ -35,9 +34,7 @@ Since responses may consist of multiple fragments, you can inspect the `Response in a response series. ::: -It is possible to send a read request with a specific `ReadHandler` by using the `MasterChannel::read_with_handler()` method. -All the response data associated with the request will be forwarded to the `ReadHandler` specified as an argument instead of -going to the handler specified at the creation of the association. +Use `MasterChannel::read_with_handler()` to send a read request with a specific `ReadHandler`. Response data goes to the specified handler instead of the association's default handler. ## Device Attributes diff --git a/guide/docs/api/master/tcp_client.mdx b/guide/docs/api/master/tcp_client.mdx index a469f38a..a9ed90b0 100644 --- a/guide/docs/api/master/tcp_client.mdx +++ b/guide/docs/api/master/tcp_client.mdx @@ -8,8 +8,7 @@ slug: /api/master/tcp_client import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -A `MasterChannel` presents the same interface once you create it, regardless of the underlying transport. You can create a TCP client channel using the runtime, -configuration data, and a callback to observe the status of the connection. +A `MasterChannel` presents the same interface regardless of transport. Create a TCP client channel using the runtime, configuration data, and a connection status callback. :` tuple where "host" is one of the following: +An `EndpointList` contains remote endpoints the master will try to connect to. It must have at least one entry; additional entries serve as backups. The channel round-robins through the list until connected. Each endpoint is a `:` tuple where "host" is: * IPv4 address * IPv6 address diff --git a/guide/docs/api/master/terminology.mdx b/guide/docs/api/master/terminology.mdx index e9325ff3..28ac8fac 100644 --- a/guide/docs/api/master/terminology.mdx +++ b/guide/docs/api/master/terminology.mdx @@ -8,12 +8,11 @@ slug: /api/master/terminology import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Master stations typically communicate with multiple outstations over multiple communication channels. We'll describe in the following sections how you can create different channel types, each of which can be used to talk to multiple outstations on the channel. +Master stations communicate with multiple outstations over multiple communication channels. The following sections describe how to create different channel types, each supporting multiple outstations. ## MasterChannel -You can create a `MasterChannel` using generic configuration combined with transport-specific options. Once created, all channel instances have the same API, -regardless of the underlying transport. +Create a `MasterChannel` using generic configuration combined with transport-specific options. All channel instances have the same API regardless of the underlying transport. ## Association diff --git a/guide/docs/api/outstation/configuration.mdx b/guide/docs/api/outstation/configuration.mdx index e0233761..9cb03b6c 100644 --- a/guide/docs/api/outstation/configuration.mdx +++ b/guide/docs/api/outstation/configuration.mdx @@ -14,11 +14,11 @@ You create outstations using three types of components: * Callback interfaces * Transport-specific configuration (e.g., TCP vs. serial parameters) -Let's look at the static configuration required to create an outstation. +The following static configuration is required to create an outstation. ### OutstationConfig -The `OutstationConfig` structure contains the parameters that modify the behavior of the outstation. The generated API documentation provides a definition for each field. All fields have default values except for the master and outstation link addresses. Keep in mind that we didn't optimize these default values for every use case; for example, you may need to adjust the timeout parameters for higher latency links. +`OutstationConfig` contains parameters that modify outstation behavior. See the generated API documentation for field definitions. All fields have defaults except the master and outstation link addresses. Defaults aren't optimized for every use case—you may need to adjust timeouts for higher latency links. :::note -Setting the number of events for a particular type to `0` ensures that you will never record or report events for that type. +Setting the event count to `0` for a type disables event recording and reporting for that type. ::: diff --git a/guide/docs/api/outstation/control_handler.mdx b/guide/docs/api/outstation/control_handler.mdx index 6ea10d9e..e787f48b 100644 --- a/guide/docs/api/outstation/control_handler.mdx +++ b/guide/docs/api/outstation/control_handler.mdx @@ -8,11 +8,10 @@ slug: /api/outstation/controls import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -The `ControlHandler` interface lets application code receive control requests. Each request begins with a call to `beginFragment` and ends -with a call to `endFragment`. These callbacks are helpful if you want the application to handle operations atomically or in batches of some sort. +The `ControlHandler` interface receives control requests. Each request begins with `beginFragment` and ends with `endFragment`, useful for handling operations atomically or in batches. Each `select` or `operate` callback returns a `CommandStatus` enum. The outstation response to a control message echoes the request data and this -status code is returned for every control in the message. The library actually builds the response message while making these callbacks. +status code is returned for every control in the message. The library actually builds the response message while making these callbacks. ## Handling SELECT @@ -27,8 +26,7 @@ sequenceDiagram Outstation->>Master: response; ``` -DNP3 masters can also use a "select-before-operate" strategy to execute controls. The rules for how outstations process these -two-pass control messages are complex. The library will handle all these rules for you automatically. +DNP3 masters can also use a "select-before-operate" strategy. The rules for processing these two-pass control messages are complex, but the library handles them automatically. ## Handling OPERATE @@ -38,9 +36,7 @@ The `operate*` methods of `ControlHandler` are called when the outstation receiv * `DIRECT_OPERATE` function code (single-pass control with response). * `DIRECT_OPERATE_NO_RESPONSE` function code (single-pass control without a response). -A reference to a `DatabaseHandle` also lets you update point values in response to a control request. While you would typically use it to update -`BinaryOutputStatus` and `AnalogOutputStatus` values, you can also use it to update other types if required by the application. For example, you might -maintain the number of control operations performed in a DNP3 counter value. +A `DatabaseHandle` reference lets you update point values in response to controls. Typically used for `BinaryOutputStatus` and `AnalogOutputStatus`, but you can update other types too—for example, tracking control operations in a counter. :::tip Every call to `DatabaseHandle.transaction` locks and unlocks a mutex. Since DNP3 can carry multiple controls in a single message, the most diff --git a/guide/docs/api/outstation/database.mdx b/guide/docs/api/outstation/database.mdx index f624b10d..5493dd11 100644 --- a/guide/docs/api/outstation/database.mdx +++ b/guide/docs/api/outstation/database.mdx @@ -8,20 +8,17 @@ slug: /api/outstation/database import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -You can use the `Database` class to manipulate the measurement types and values that the outstation exposes to the master. Note that while it's called a "database", it's really just -an in-memory data structure protected by a mutex. +Use the `Database` class to manage measurements the outstation exposes to the master. Despite the name, it's just an in-memory data structure protected by a mutex. All database operations are executed inside a transaction protected by a mutex. Operations within a transaction are applied to the database and the event buffers atomically. If unsolicited responses are enabled, the outstation will automatically decide if an unsolicited response should be sent at the end of the transaction. -The database may be accessed in a transaction in two different ways: +Access the database in a transaction two ways: -1. When measurement values need to be updated due to external changes, the user can call `Outstation.transaction` to acquire -a locked reference to the database and make changes. +1. Call `Outstation.transaction` to acquire a locked reference and make changes. -2. Callbacks on the `ControlHandler` provide a `DatabaseHandle` which also has an identical `transaction method`. Similarly, the freeze operations on -`OutstationApplication` provide this handle as well. +2. `ControlHandler` callbacks and `OutstationApplication` freeze operations provide a `DatabaseHandle` with an identical `transaction` method. :::tip Structure any common update code to operate on the `Database` type and not depend on `Outstation` or `DatabaseHandle`. @@ -29,7 +26,7 @@ Structure any common update code to operate on the `Database` type and not depen ## Adding Points -You must initialize the points before the outstation exposes any measurement data. While you should do this when you create the outstation, you can add points to a running outstation as well. Each measurement type has unique configuration including: +Initialize points before the outstation exposes measurement data. This is typically done at creation, but you can add points to a running outstation. Each measurement type has unique configuration: * An optional event class assignment for the point * Default static and event variations for the type @@ -40,7 +37,7 @@ The default static and event variations for each point type may not do what you some DNP3 event variations don't carry a timestamp. This can be confusing to new users who expect to see a timestamp value that changes as the outstation receives events. -Refer to the documentation for each variation to understand the data associated with it. +See the documentation for each variation to understand its data. ::: When you add a point, it is assigned the following default value with `RESTART` flags: @@ -53,9 +50,7 @@ When you add a point, it is assigned the following default value with `RESTART` Update the value after adding the point if you don't want a connecting master to see the points with a `RESTART` flag set. :::tip -The example code below only shows the definition of contiguous ranges of points, however, the library efficiently supports -using discontiguous ranges as well. In fact, no matter how you define the indices, the library always uses a [BTreeMap](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html) -to store static values and their configuration. +The examples show contiguous point ranges, but discontiguous ranges work efficiently too. The library uses a [BTreeMap](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html) internally regardless of how you define indices. ::: :`. Addresses may be specified as any valid IPv4 or IPv6 local endpoint, such as: +Create a `TCPServer` instance. Creating a server doesn't initiate `bind/listen` immediately. Specify endpoints as `
:` where address is any valid IPv4 or IPv6 local endpoint: * `127.0.0.1` for localhost only * `0.0.0.0` for all adapters diff --git a/guide/docs/api/runtime.mdx b/guide/docs/api/runtime.mdx index bf43e42b..bf3928bf 100644 --- a/guide/docs/api/runtime.mdx +++ b/guide/docs/api/runtime.mdx @@ -18,7 +18,7 @@ Tokio is a modern evolution of libraries like [libuv (C)](https://libuv.org/) an ## Lifetime -You must create a `Runtime` before any communication can take place. It is a shared resource for multiple communication sessions that is typically created just after initializing logging. It is also the last component to shut down; see below for more details about runtime shutdown. +Create a `Runtime` before any communication can take place. It's a shared resource for multiple sessions, typically created just after initializing logging and shut down last when exiting. :::note Rust users can share the runtime with other libraries that also use Tokio. The bindings don't currently support sharing a runtime, but this will be possible in a future release. @@ -88,7 +88,7 @@ a thread becomes unblocked. For example, when you receive a log message via a callback, a synchronous call to write the message to a file will block a thread. If this frequently occurs on all your pool threads, it can cause poor throughput or even task starvation. -For best results, avoid blocking whenever possible in your applications. Instead, you should defer blocking calls to dedicated worker threads, such as a user-managed thread that write log messages to file. +Avoid blocking in callbacks whenever possible. Defer blocking calls to dedicated worker threads, such as a separate thread that writes log messages to file. @@ -106,8 +106,7 @@ worker threads have been joined. A blocked worker thread can cause shutdown to deadlock. For example, if a communication channel makes a callback to user code that permanently blocks, `shutdown` will cause a deadlock. -If you cannot ensure a clean shutdown, you can use `Runtime.set_shutdown_timeout(..)` to put an upper -time limit on the eventual shut down. You would call this method immediately after creating the Runtime. +If you cannot ensure a clean shutdown, use `Runtime.set_shutdown_timeout(..)` to set an upper time limit. Call this method immediately after creating the Runtime. **Shutting down the runtime using a timeout can leak memory as worker threads will be aborted if the timeout occurs. Only use this method if you are exiting the process anyway.** @@ -166,7 +165,7 @@ Runtime shutdown is implicit when the runtime object gets destroyed. ``` :::note -If you don't call `Shutdown` before exiting, the JVM will shutdown the runtime in its finalize method. However, garbage collection is not deterministic, so your program may never properly exit. Make sure you explicitly shut down the runtime before exiting. +If you don't call `Shutdown` before exiting, the JVM will shutdown the runtime in its finalize method. However, garbage collection is not deterministic, so your program may never properly exit. Always explicitly shut down the runtime before exiting. ::: @@ -177,12 +176,8 @@ If you don't call `Shutdown` before exiting, the JVM will shutdown the runtime i ``` :::note -If you don't call `Shutdown` before exiting, the .NET runtime will shut down the runtime in its finalizer (also called the destructor). Again, you should explicitly shut down the runtime before exiting instead of relying on this behavior. +If you don't call `Shutdown` before exiting, the .NET runtime will shut down the runtime in its finalizer. Always explicitly shut down the runtime instead of relying on this behavior. ::: - - -:::tip - -::: \ No newline at end of file + \ No newline at end of file diff --git a/guide/docs/api/tls.mdx b/guide/docs/api/tls.mdx index b70e282b..69ea56ff 100644 --- a/guide/docs/api/tls.mdx +++ b/guide/docs/api/tls.mdx @@ -8,9 +8,7 @@ slug: /api/tls import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Masters and outstations may optionally use TLS which protects DNP3 communication by adding encryption and authentication. The DNP3 library uses -[rustls](https://github.com/rustls/rustls), a modern TLS library written in safe Rust. It does **not** depend on OpenSSL or other system libraries, but will -interoperate seamlessly with other implementations. +Masters and outstations can use TLS for encryption and authentication. The library uses [rustls](https://github.com/rustls/rustls), a modern TLS library written in safe Rust. It does **not** depend on OpenSSL or other system libraries, but interoperates seamlessly with other implementations. Rustls has been [reviewed](https://github.com/rustls/rustls/raw/main/audit/TLS-01-report.pdf) by a third party and is production ready. It [outperforms](https://jbp.io/2019/07/01/rustls-vs-openssl-performance.html) OpenSSL in almost every aspect and has the backing of the @@ -62,11 +60,10 @@ We recommend using TLS to secure DNP3 and caution the industry to avoid home-gro ## Configuration -TLS configuration is configured using the `TlsClientConfig` or `TlsServerConfig` structures. They are very similar and contain the following fields: +Configure TLS using `TlsClientConfig` or `TlsServerConfig`. Both contain these fields: - `name`: - * The client and the server both verify that the certificate presented by the peer is valid for this name. Check out the next section for the gory details on - name validation. + * Both client and server verify the peer's certificate is valid for this name. See the next section for name validation details. * The client will advertise this name through a Server Name Indication (SNI) extension in the `Client Hello`. - `peer_cert_path`: * Path to the unencrypted PEM file containing the trusted root certificate(s) or the peer self-signed certificate. @@ -94,7 +91,7 @@ definition of a valid name includes: - One or more labels separated by a single period - Labels are made of alphanumeric characters `[A-Za-z0-9]`, hyphens `-`, and underscores `_` -- A label cannot start or end with an hyphen `-` +- A label cannot start or end with a hyphen `-` - A label cannot be all numeric - A label cannot be empty - Maximum of 63 characters per label @@ -115,7 +112,7 @@ is still secure, but it is deprecated for new use cases. Unencrypted private keys may be stored in PKCS#1 or PKCS#8 formats: -* `----BEGIN RSA PRIVATE KEY-----` +* `-----BEGIN RSA PRIVATE KEY-----` * `-----BEGIN PRIVATE KEY-----` @@ -208,5 +205,5 @@ openssl req -x509 -newkey rsa:4096 -keyout ./master_key.pem -out ./master_cert.p ``` - Generate the outstation certificate: ``` -openssl req -x509 -newkey rsa:4096 -keyout ./outstation_key.pem -out ./outstation/entity2_cert.pem -subj "/C=US/ST=Oregon/L=Bend/O=Test/CN=DO NOT USE" -addext "subjectAltName=DNS:test.com" -nodes -days 365 +openssl req -x509 -newkey rsa:4096 -keyout ./outstation_key.pem -out ./outstation_cert.pem -subj "/C=US/ST=Oregon/L=Bend/O=Test/CN=DO NOT USE" -addext "subjectAltName=DNS:test.com" -nodes -days 365 ``` diff --git a/guide/docs/languages/bindings.mdx b/guide/docs/languages/bindings.mdx index 90c42332..4e113958 100644 --- a/guide/docs/languages/bindings.mdx +++ b/guide/docs/languages/bindings.mdx @@ -7,9 +7,7 @@ slug: /bindings import useBaseUrl from '@docusaurus/useBaseUrl'; -We wrote our core library in idiomatic Rust without any concern for how it would be bound into other languages. Consequently, keep in mind that the Rust API won't always -correlate 100% with the various binding APIs. This guide is still helpful for Rust users, but you should be aware that the guide is primarily written from -the perspective of the bindings. +The core library is written in idiomatic Rust without concern for binding to other languages. The Rust API won't always correlate 100% with the binding APIs. This guide is helpful for Rust users, but is primarily written from the perspective of the bindings. ## Generic Terminology diff --git a/guide/docs/languages/c_lang.mdx b/guide/docs/languages/c_lang.mdx index 855b1a19..ed09d056 100644 --- a/guide/docs/languages/c_lang.mdx +++ b/guide/docs/languages/c_lang.mdx @@ -95,7 +95,7 @@ target_link_libraries(my_awesome_project PRIVATE dnp3) ## Mapping -Many of the concepts built into higher-level languages are just design patterns or idioms in C. When you see these higher levels patterns discussed in this guide, you can use the idioms to understand how they map to C. +Many concepts built into higher-level languages are just design patterns or idioms in C. Use the idioms below to understand how they map to C. ### Classes @@ -138,7 +138,7 @@ typedef struct dnp3_logger_t * `on_destroy` is the destructor that cleans up the `ctx`. * `on_message` is a function pointer used to dispatch a log message. -Keep in mind that this example only contains a single method. Other interfaces will contain several methods. +This example only contains a single method. Other interfaces contain several methods. :::warning Always use [C99 struct initialization](https://en.cppreference.com/w/c/language/struct_initialization) when defining interfaces diff --git a/guide/docs/languages/cpp_lang.mdx b/guide/docs/languages/cpp_lang.mdx index c33c59ef..bb89124a 100644 --- a/guide/docs/languages/cpp_lang.mdx +++ b/guide/docs/languages/cpp_lang.mdx @@ -93,8 +93,8 @@ Collections are taken through a constant reference to a `std::vector`. The eleme ### 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`. +Classes have an 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 will throw a `std::logic_error`. The class destructor will call the underlying C destructor automatically. @@ -110,7 +110,7 @@ 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. +from a C++ `std::future` using the blocking `get` method and there is no way to asynchronously chain futures. Asynchronous methods are mapped to callback interfaces with two methods: