Help us shape the future of Go! Take the 2026 Go Developer Survey

dnp3

package module
v1.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 10 Imported by: 0

README

go-dnp3 - DNP3 (IEEE 1815) Master and Outstation Library for Go

Go Version Go Reference CI Status Interop Code Coverage

A pure Go implementation of DNP3 (IEEE 1815-2012), the SCADA protocol between masters and outstations in electric, water and oil and gas utilities. No cgo, no dependencies outside the standard library.

The library provides:

  • A client (master): integrity and event polls, reads of any group and range, unsolicited responses with confirmation and duplicate detection, controls (select-before-operate, direct operate, no-ack; relay output blocks, pattern control, set-points), time synchronization by the LAN and the non-LAN procedure, restarts, freezes (also at a time), assign class, device attributes of any set, file transfer, broadcasts, secure authentication
  • A server (outstation): a point database for every point type with deadbands and event classes, event buffers per master that survive reconnects, multi-fragment responses with confirmation, unsolicited responses with hold time and retries, select-before-operate with timeout and sequence checks, device attributes of any set, scheduled freezes, any number of masters and connections
  • The complete link layer (FT3 frames, CRCs, reset of link states, confirmed user data with the frame count bit, link status keep-alive) and the transport function, also on multi-drop channels
  • An application layer codec and object library for every group of IEEE 1815-2012 Annex A in use today: file control (g70), device attributes (g0) and the secure authentication objects (g120..g122) included
  • Secure Authentication v5 (IEEE 1815-2012 clause 7): the session key change with AES key wrap under a pre-shared update key, on every connection, at an interval and after an authentication failure; the outstation challenges critical requests, the master answers with an HMAC or sends them in aggressive mode; the outstation keeps the security statistics (g121, g122)
  • What production use needs: context.Context on every call, automatic reconnect with backoff, retries for the requests that are safe to repeat, automatic handling of the internal indications (restart, time, events, overflow), periodic polls, structured logging, metrics hooks, TCP, TLS, UDP and serial (any byte stream)
  • Verified against third-party stacks: as master and as outstation against Step Function I/O's dnp3, opendnp3, DSC go-dnp3 and dnp3py, in the containers of otfabric/dnp3-interop v0.5.1, over TCP, TLS, UDP and serial, with file transfer and Secure Authentication

Docs: API.md (public API) · ARCHITECTURE.md (packages, goroutines, protocol machines) · INTEROPERABILITY.md (what is implemented, clause by clause) · ERRORS.md (error semantics) · OBSERVABILITY.md (logging and metrics) · SECURITY.md · RELEASE.md (changelog)

Table of contents

go-dnp3 vs stepfunc dnp3, opendnp3 and DSC go-dnp3

go-dnp3 is tested against four other implementations, three of which this table compares (see Interop tests). Each suits different needs; the table shows where they differ, from their public sources, so you can pick the right one for your project.

Capability otfabric/go-dnp3 stepfunc dnp3 opendnp3 DSC go-dnp3
Language Go Rust (C, C++, .NET, Java bindings) C++ (Java, .NET bindings) Go
Licence MIT proprietary: non-commercial, non-production use; commercial licence otherwise Apache-2.0 GPL-3.0-or-later (copyleft: a program linking it is GPL)
Status maintained, v1 (semantic versioning) maintained, v1, commercial support end of life: archived 2022, 3.1.2 final maintained, pre-1.0 ("API not yet stable")
Master and outstation ✅ ✅ ✅ ✅
Unsolicited responses, both roles ✅ ✅ ✅ ✅
Select-before-operate, direct operate ✅ ✅ ✅ ✅
Direct operate no-ack, as master ✅ — in 1.7.0 (added in 1.8.0-M1) — ✅
LAN and non-LAN time synchronization ✅ ✅ ✅ ✅
Assign class, as outstation ✅ — ✅ ✅
File transfer (g70) ✅ both roles master — (codec only) ✅ both roles
Secure Authentication v5 ✅ session key change, challenges, aggressive mode, statistics — — symmetric subset with statistics, no aggressive mode
Outstation that dials the master ✅ dual end point (DialAndServe) ✅ TCP and TLS client ✅ on a TCP or TLS client channel ✅ over a TCP client channel
Several outstations behind one port or line ✅ by link address (server.Group) several outstations per TCP server, chosen by the master's IP address ✅ several stacks per channel ✅ multidrop package
Device attributes (g0) ✅ both roles, any set ✅ — ✅
Data sets (g85..g88) — (generic requests) — — ✅ outstation backend, master handler
TLS, UDP, serial ✅ (crypto/tls; serial as any byte stream) ✅ ✅ ✅
Request methods that return the response ✅ — async (futures) — callbacks ✅ controls, attributes, files; polls to a handler
Cancellation and deadlines per call ✅ context.Context futures — ✅ context.Context
Structured logging ✅ log/slog ✅ tracing own logger ✅ log/slog
Metrics ✅ callbacks (dnp3.Metrics) not documented — Stats() counters
Dependencies none (standard library) Tokio, tracing; rustls for TLS, tokio-serial for serial ASIO, exe4cpp, ser4cpp; OpenSSL for TLS standard library; go.bug.st/serial for serial
Tested against other stacks in CI ✅ the three and dnp3py, the features of the coverage matrix not documented not documented ✅ opendnp3
DNP Users Group IED conformance procedures (dnp3c) in CI ✅ 3.1r1 subset levels 2 and 3, 2.7 level 2, against a test outstation (not a certification) ✅ 3.1r1 subset level 3, 2.7 level 2 not documented ✅ 3.1r1 subset level 3, 2.7 level 2 (not a certification)

✅ = available · — = not available. For stepfunc dnp3 1.7.0, opendnp3 3.1.2 and DSC go-dnp3 v0.8.1, the versions go-dnp3 is tested against, from their source, documentation and licences and the dnp3-interop capability records, as of October 2026. If you spot an inaccuracy, please open an issue and we will correct it.

Install

go get github.com/otfabric/go-dnp3

Requires Go 1.23 or later. From v1.0.0 the API follows semantic versioning: a breaking change comes only with a new major version.

Project structure

Package What it is
dnp3 Shared types: sentinel and typed errors, Logger, Metrics, State
client The master
server The outstation and its point database
app Application layer codec and object library
transport Transport function: segmentation and reassembly
link Data link layer codec: FT3 frames, CRC, stream reader
secauth Secure Authentication v5: MACs and the data they protect

app, transport and link are pure codecs, useful on their own to analysers and test tools. See ARCHITECTURE.md.

Client quickstart

ctx := context.Background()
c, err := client.Dial(ctx, "10.0.0.5:20000",
    client.WithAddresses(1, 10), // master 1, outstation 10
    client.WithReconnect(client.Reconnect{}),
    client.WithRetry(client.Retry{Attempts: 3}),
)
if err != nil {
    log.Fatal(err)
}
defer c.Close()

// An integrity poll: events of classes 1..3, then all static data.
res, err := c.IntegrityPoll(ctx)
if err != nil {
    log.Fatal(err)
}
for _, m := range res.Measurements() {
    switch v := m.Value.(type) {
    case app.Analog:
        fmt.Printf("%s %d = %.2f %s\n", m.GV, m.Index, v.Value, v.Flags)
    case app.Binary:
        fmt.Printf("%s %d = %v\n", m.GV, m.Index, v.Value)
    }
}

// Select-before-operate of a breaker.
if _, err := c.Operate(ctx, client.SelectBeforeOperate, client.CROB(0, app.OpLatchOn, 0, 0)); err != nil {
    var ce *dnp3.CommandError
    if errors.As(err, &ce) {
        log.Printf("refused: %s", ce.Status)
    }
}

Unsolicited responses, and every response to an automatic or periodic poll, go to a client.Handler:

c, err := client.Dial(ctx, addr,
    client.WithHandler(client.HandlerFunc(func(info client.ResponseInfo, ms []client.Measurement) {
        for _, m := range ms {
            fmt.Println(info.Unsolicited, m.GV, m.Index, m.Value)
        }
    })),
    client.WithStartup(client.Startup{DisableUnsolicited: true, Integrity: true, EnableUnsolicited: []int{1, 2, 3}}),
    client.WithTimeSync(client.TimeSyncLAN), // when the outstation sets NEED_TIME
)

Server quickstart

breaker := server.HandlerFunc(func(ctx context.Context, c server.Command, op server.OperateType) app.CommandStatus {
    crob, ok := c.Value.(app.CROB)
    if !ok || c.Index != 0 || (crob.Op != app.OpLatchOn && crob.Op != app.OpLatchOff) {
        return app.StatusNotSupported
    }
    // ... operate the device ...
    return app.StatusSuccess
})
srv, err := server.New(
    server.WithAddress(10),
    server.WithMasters(1), // events are buffered for master 1 while it is away
    server.WithHandler(breaker),
    server.WithUnsolicited(server.Unsolicited{Enabled: true}),
)
if err != nil {
    log.Fatal(err)
}
db := srv.Database()
_ = db.AddBinaryInput(0, server.PointConfig{Class: 1}, app.Binary{Value: true, Flags: app.FlagOnline})
_ = db.AddAnalogInput(0, server.PointConfig{Class: 2, StaticVariation: 5, Deadband: 0.5}, app.Analog{Value: 230.1, Flags: app.FlagOnline})

go func() {
    // Updates produce events by change and deadband, in the order they occur.
    _ = db.UpdateAnalogInput(0, app.Analog{Value: 231.0, Flags: app.FlagOnline})
}()
log.Fatal(srv.ListenAndServe(":20000"))

Production features

Feature Client Server
Cancellation and deadlines every request takes a context.Context handler calls get a context canceled on Close
Reconnect WithReconnect: exponential backoff, startup sequence repeated masters reconnect; their association and events are kept
Retries WithRetry: READ, time, unsolicited and class functions only; controls, freezes, restarts and writes never the master's repeated request is answered with the same response, not executed twice
Timeouts WithResponseTimeout per fragment, link layer timeout and retries WithConfirmTimeout, WithSelectTimeout
Internal indications clears DEVICE_RESTART, integrity poll on restart and overflow, time sync on NEED_TIME, event poll on class bits DEVICE_RESTART, NEED_TIME, class events, overflow, broadcast and the request errors maintained; SetIndications for local control, device trouble
Flow control one request at a time, as DNP3 requires; WithQueueLimit bounds the waiting ones per-type event limits with oldest-first discard; bounded receive queues
Observability Logger, FieldLogger, ContextLogger, log/slog; Metrics, RequestMetrics; state handler Logger; Metrics, ServerMetrics
Security TLS, Secure Authentication v5 with aggressive mode and re-keying after a failure TLS, Secure Authentication v5 with a reply timeout and security statistics, master address filter

Transports

Transport Client Server
TCP default ListenAndServe, Serve
TLS WithTLS WithTLS with ListenAndServe, or a TLS listener with Serve
UDP WithStream(client.UDP(addr)) ServeUDP, or ServeUDPTo with the master's address
Serial, or any byte stream WithStream with an opener that returns the port ServeConn
Dual end point (the outstation connects) WithStream(client.Accept(l)) DialAndServe(ctx, masterAddr, server.Redial{})
Several outstations behind one port or line (multi-drop) one client per outstation address server.NewGroup(servers...) with ListenAndServe, Serve, ServeConn, ServeUDP

Serial ports are not opened by this module, so that it has no dependencies: open the port with a serial library, for example otfabric/go-serial, and hand it over:

c, err := client.Dial(ctx, "/dev/ttyUSB0", client.WithStream(func(ctx context.Context) (io.ReadWriteCloser, net.Addr, error) {
    p, err := serial.Open(&serial.Config{Address: "/dev/ttyUSB0", BaudRate: 19200})
    return p, nil, err
}))

Leave the port's read timeout at zero (blocking reads): a read that times out is a failing stream to the channel, which then closes. Inactivity is detected by the link layer's keep-alive instead (client.Link.KeepAlive).

The object model

Responses are decoded into app.Fragment values: headers (app.Header) with their objects (app.Object), each an index and a value. The values are a closed set of structs: app.Binary, app.DoubleBitBinary, app.Counter, app.Analog, app.CROB, app.AnalogOutput, app.OctetString, the file and authentication objects and a few more. One struct serves every variation of a kind of point; the header's app.GroupVariation (constants such as app.G30V5) says how it is encoded. Time stamps are app.Timestamp, DNP3's milliseconds since 1970, with conversions to and from time.Time.

Encoding an analog value into an integer variation rounds it; a value the variation cannot hold is sent as the nearest one with OVER_RANGE set, while a set-point that does not fit is refused. See the app package documentation.

Every group and variation the codec knows is listed in OBJECTS.md, generated like the codec's table from one catalog, app/catalog.json.

Error semantics

Errors are sentinels tested with errors.Is (dnp3.ErrTimeout, dnp3.ErrConnectionLost, dnp3.ErrNotConnected, dnp3.ErrClosed, ...) and typed errors for answers of the outstation, matched with errors.As: *dnp3.IINError (the request was refused), *dnp3.CommandError (a control was not executed), *dnp3.FileError and *dnp3.AuthError. Request methods return the response together with an IINError, so that what the outstation did report is not lost. See ERRORS.md.

Examples

Runnable programs under examples/: seven self-contained ones (quickstart, commands, events, files, secure, observability, dialout) that start both sides in one process, and a standalone server and client for trying the library against other implementations. See examples/README.md.

go run ./examples/quickstart

Development

make check   # format, lint, vet, vulnerability scan, race tests, coverage, examples
make test    # the tests with the race detector
make fuzz    # the codec and outstation fuzz targets (FUZZTIME=30s each by default)
make bench   # the codec benchmarks
make generate        # regenerate the code and OBJECTS.md from app/catalog.json
make upstream-watch  # compare the catalog with stepfunc dnp3, DSC go-dnp3 and dnp3-interop

Tests need nothing but Go: master and outstation run against each other and against scripted peers over loopback, including a chaos suite that corrupts, duplicates and drops octets on the line, and stress tests with many masters and concurrent requests. See CONTRIBUTING.md.

Conformance tests

make conformance runs the DNP Users Group's IED certification procedures against a test outstation built on the library: 3.1 rev 1 at subset levels 2 and 3, and 2.7 at level 2. It uses Step Function I/O's dnp3c 0.2.0, through otfabric/dnp3-interop's dnp3c runner. dnp3c and the runner are GPL-3.0 and not part of this repository; make conformance-image builds the runner's image from dnp3-interop's source, and it is not published. CI runs the same on every push. The results are not a certification. internal/cmd/conformance describes the setup and the Device Profile.

Interop tests

make interop runs go-dnp3 as master against the reference outstations, and the reference masters against go-dnp3's outstation, using the images of otfabric/dnp3-interop v0.5.1: the published ones pinned by digest, and the stepfunc one built locally by make interop-stepfunc from dnp3-interop's source at that release. Step Function I/O's licence allows testing with its library but not redistributing it, so its image is not published (dnp3-interop#19); the build fetches the crate from crates.io under that licence.

Reference Version Licence Roles tested
Step Function I/O dnp3 1.7.0 non-commercial, non-production master and outstation
opendnp3 3.1.2 Apache-2.0 master and outstation
DSC go-dnp3 v0.8.1 GPL-3.0-or-later master and outstation
dnp3py 0.6.0 MIT master and outstation (its outstation serves the dnp3py fixture only)

Both directions cover the integrity poll against the fixture's values and flags, reads of ranges and variations, every control case of the fixture (select-before-operate, select-required outputs, set-point ranges, unsupported codes and points), events and their confirmation, unsolicited responses, both time synchronization procedures, cold and warm restarts, freeze and clear, and assign class. The transports and procedures of dnp3-interop's contracts 1.1 to 1.3 are tested in both directions where a reference has the feature (see the matrix): TLS with mutual authentication (a test PKI is generated per run), UDP, serial lines (a pseudo-terminal in the container bridged to TCP), file transfer against the files fixture, and Secure Authentication with session key changes and the security statistics; also the requests without a response (DIRECT OPERATE NO ACK, the _NR freezes), reads of all objects of a group, and contract 1.2: the dual end point over TCP and TLS, frozen analog inputs, command events, time and interval, security statistic events, and the dnp3py fixture; and contract 1.3: device attribute sets, several controls in one request, scheduled freezes and analog freeze, deadbands, file append and authentication, event buffer overflow, link confirms and keep-alive, broadcast, the management functions and several outstations behind one port. The coverage matrix shows each feature per reference and direction. Deviations a reference has from the fixture are those dnp3-interop records as known bugs. Docker is needed; the images are consumed as published, except stepfunc's, which is built from dnp3-interop's source as described above.

The third-party code runs in its own container only: nothing of it is linked into go-dnp3.

Limitations

  • Secure Authentication: update keys are configured out of band. The remote update key change, user management (certificates, user status change) and AES-GMAC are not implemented; aggressive mode is verified between go-dnp3's ends only, as no reference stack in the interop suite has it. See SECURITY.md and the gaps.
  • Data sets, private registration objects and the virtual terminal (groups 83, 85..88, 90, 91 carried raw, except the one-octet data set characteristics g86v2; 112, 113 decoded) have no procedures: exchange them with the generic request methods.
  • Conformance: CI runs the DNP Users Group's IED certification procedures (dnp3c: 3.1 rev 1 at subset levels 2 and 3, 2.7 at level 2) against a test outstation built on the library, with the Device Profile in internal/cmd/conformance/device.ini. That is not a certification. go-dnp3 declares no subset level of its own, and the run does not cover what that profile leaves out: double-bit inputs in 3.1r1 (level 4 objects in dnp3c; the 2.7 run has them), serial and UDP, multi-drop, and the network tests of section 9.
  • UDP outstation: one socket serves one master at a time; a master behind another address takes it over when it sends.
  • Multi-fragment requests are not reassembled by the outstation: a request is one fragment.

License

MIT. The reference implementations the interop tests run are under their own licences and are not part of this module.

Documentation

Overview

Package dnp3 is the module root of a pure Go implementation of DNP3 (IEEE 1815-2012), the SCADA protocol between masters and outstations in electric, water and oil and gas utilities.

Applications import the subpackages:

This package holds what client and server share: the sentinel and typed errors, the Logger and Metrics interfaces and the channel State.

Docs: README.md, API.md (public API), ARCHITECTURE.md, ERRORS.md (error semantics), OBSERVABILITY.md (logging and metrics), INTEROPERABILITY.md (conformance and interop coverage), SECURITY.md, CONTRIBUTING.md, RELEASE.md (changelog).

Index

Constants

IINErrorBits are the internal indications that make a response an IINError.

Variables

View Source
var (
	// ErrClosed reports an operation on a client, server or association
	// that was closed by the application.
	ErrClosed = errors.New("dnp3: closed")

	// ErrNotConnected reports a request on a client that has no
	// established channel.
	ErrNotConnected = errors.New("dnp3: not connected")

	// ErrConnectFailed reports that a client could not establish its
	// channel: the dial, the TLS handshake or the opening of the serial
	// port failed. The underlying error is wrapped alongside it.
	ErrConnectFailed = errors.New("dnp3: connect failed")

	// ErrConnectionLost reports that the peer closed the channel or the
	// transport failed while a request was in progress.
	ErrConnectionLost = errors.New("dnp3: connection lost")

	// ErrTimeout reports that the peer did not answer within the response
	// timeout (client) or did not confirm within the confirm timeout
	// (server), or that a link layer confirmation did not arrive.
	ErrTimeout = errors.New("dnp3: timeout")

	// ErrProtocol reports a peer that violated the protocol: a response
	// whose objects do not match the request (a control echo that differs,
	// a missing or unexpected object, a wrong file block), or a link layer
	// answer that does not fit. A fragment with an unexpected sequence
	// number is ignored instead.
	ErrProtocol = errors.New("dnp3: protocol violation")

	// ErrBusy reports a request that cannot be issued because the
	// association has reached its queue limit.
	ErrBusy = errors.New("dnp3: too many pending requests")

	// ErrInvalidOption reports an option value a client or server cannot
	// be constructed with.
	ErrInvalidOption = errors.New("dnp3: invalid option")

	// ErrAuthentication reports a failure of secure authentication: a MAC
	// that does not verify, a key that is not initialized, or a challenge
	// that was not answered. An *[AuthError] carries the code the peer sent.
	ErrAuthentication = errors.New("dnp3: authentication failed")
)

Sentinel errors shared by the client and the server. They are usually wrapped with detail; test with errors.Is.

Functions

This section is empty.

Types

type AuthError

type AuthError struct {
	// Code is the error code of the g120v7 object.
	Code app.AuthErrorCode
	// User is the user number the error is about.
	User uint16
	// Text is the optional error text the peer sent.
	Text string
}

AuthError reports an authentication error object (g120v7) received from the peer. It matches ErrAuthentication with errors.Is.

func (*AuthError) Error

func (e *AuthError) Error() string

Error describes the failure, for example "dnp3: authentication error AUTHENTICATION_FAILED (user 1)".

func (*AuthError) Is

func (e *AuthError) Is(target error) bool

Is makes an AuthError match ErrAuthentication.

type CommandError

type CommandError struct {
	// GV is the object of the command, for example app.G12V1.
	GV app.GroupVariation
	// Index is the point index.
	Index uint32
	// Status is the status code of the echo.
	Status app.CommandStatus
}

CommandError reports a control the outstation did not execute: its echo carried a status other than SUCCESS.

func (*CommandError) Error

func (e *CommandError) Error() string

Error describes the failure, for example "dnp3: g12v1 index 3: command status NO_SELECT".

type ContextLogger

type ContextLogger interface {
	Logger

	DebugContext(ctx context.Context, msg string, keysAndValues ...any)
	InfoContext(ctx context.Context, msg string, keysAndValues ...any)
	WarnContext(ctx context.Context, msg string, keysAndValues ...any)
	ErrorContext(ctx context.Context, msg string, keysAndValues ...any)
}

ContextLogger extends Logger with context-aware structured logging, so that a handler can pick trace and span identifiers out of the context. When the Logger also implements ContextLogger, entries that belong to a request are logged with the context the request was called with.

type FieldLogger

type FieldLogger interface {
	Logger

	// With returns a logger that adds the given fields to every entry.
	With(keysAndValues ...any) FieldLogger

	DebugKV(msg string, keysAndValues ...any)
	InfoKV(msg string, keysAndValues ...any)
	WarnKV(msg string, keysAndValues ...any)
	ErrorKV(msg string, keysAndValues ...any)
}

FieldLogger extends Logger with structured key-value logging. When the Logger given to a client or server also implements FieldLogger, the library logs through it: every entry is a constant message plus fields such as "component", "remote", "outstation", "master" and "error", instead of one formatted string. NewSlogLogger returns such a logger.

keysAndValues alternate string keys and values, as in log/slog.

func NewSlogFieldLogger

func NewSlogFieldLogger(h slog.Handler) FieldLogger

NewSlogFieldLogger is NewSlogLogger with the result typed as a FieldLogger, for callers that want to add fields with With before handing the logger to a client or server. A nil handler returns a no-op logger.

type FileError

type FileError struct {
	// Op is the operation: "open", "close", "delete", "read", "write",
	// "abort", "info" or "authenticate".
	Op string
	// Status is the file status the outstation answered.
	Status app.FileStatus
	// Text is the optional text the outstation sent with the status.
	Text string
}

FileError reports a file operation the outstation refused.

func (*FileError) Error

func (e *FileError) Error() string

Error describes the failure, for example "dnp3: file open: FILE_NOT_FOUND".

type IINError

type IINError struct {
	// Function is the function code of the rejected request.
	Function app.FunctionCode
	// IIN is the internal indications of the response.
	IIN app.IIN
}

IINError reports that an outstation rejected a request: the response carried IIN2 bits that report an error (no function code support, object unknown, parameter error, already executing).

func (*IINError) Error

func (e *IINError) Error() string

Error describes the rejection, for example "dnp3: SELECT rejected: OBJECT_UNKNOWN".

type Logger

type Logger interface {
	Debugf(format string, args ...any)
	Infof(format string, args ...any)
	Warnf(format string, args ...any)
	Errorf(format string, args ...any)
}

Logger is the logging interface accepted by the client and the server. Implement it to integrate any logging library.

Logging is silent by default. Methods are invoked synchronously on the protocol path and must not block.

func NewSlogLogger

func NewSlogLogger(h slog.Handler) Logger

NewSlogLogger wraps a slog.Handler. The result implements FieldLogger and ContextLogger, so the library logs structured fields through it; messages are only built when the handler is enabled for their level. A nil handler returns a no-op logger.

func NewStdLogger

func NewStdLogger(l *log.Logger) Logger

NewStdLogger wraps a standard library logger. Each message is prefixed with its level. A nil l logs to os.Stderr with the standard flags.

func NopLogger

func NopLogger() Logger

NopLogger returns a Logger that discards everything.

type Metrics

type Metrics interface {
	// OnConnect is called when a transport connection is established or
	// a serial port opened.
	OnConnect(remote net.Addr)

	// OnDisconnect is called when a channel ends. err is nil when the
	// application closed it.
	OnDisconnect(remote net.Addr, err error)

	// OnFrameSent is called after a link frame was written. size is its
	// length on the wire in octets.
	OnFrameSent(remote net.Addr, f *link.Frame, size int)

	// OnFrameReceived is called for every link frame read from the peer.
	OnFrameReceived(remote net.Addr, f *link.Frame, size int)

	// OnFramingError is called when octets were skipped or a frame was
	// discarded: a bad start sequence, a CRC error, an invalid length.
	OnFramingError(remote net.Addr, err error)

	// OnFragmentSent is called after an application fragment was handed
	// to the transport function. size is its length in octets.
	OnFragmentSent(remote net.Addr, f *app.Fragment, size int)

	// OnFragmentReceived is called for every fragment that was
	// reassembled and decoded.
	OnFragmentReceived(remote net.Addr, f *app.Fragment, size int)

	// OnDecodeError is called when a reassembled fragment, or a segment,
	// could not be decoded and was dropped.
	OnDecodeError(remote net.Addr, err error)
}

Metrics is an optional callback interface for observing the channels and the traffic of a client or a server. A nil Metrics disables collection.

The methods are called synchronously on the protocol path, possibly from several goroutines at once; implementations must be safe for concurrent use and must not block (increment a counter, send on a buffered channel). Frames and fragments passed to them must not be retained or modified.

Embed NopMetrics to implement only the callbacks you need and to stay compatible when methods are added.

type NopMetrics

type NopMetrics struct{}

NopMetrics is a Metrics that does nothing. Embed it in your own type.

func (NopMetrics) OnConnect

func (NopMetrics) OnConnect(net.Addr)

OnConnect does nothing.

func (NopMetrics) OnDecodeError

func (NopMetrics) OnDecodeError(net.Addr, error)

OnDecodeError does nothing.

func (NopMetrics) OnDisconnect

func (NopMetrics) OnDisconnect(net.Addr, error)

OnDisconnect does nothing.

func (NopMetrics) OnFragmentReceived

func (NopMetrics) OnFragmentReceived(net.Addr, *app.Fragment, int)

OnFragmentReceived does nothing.

func (NopMetrics) OnFragmentSent

func (NopMetrics) OnFragmentSent(net.Addr, *app.Fragment, int)

OnFragmentSent does nothing.

func (NopMetrics) OnFrameReceived

func (NopMetrics) OnFrameReceived(net.Addr, *link.Frame, int)

OnFrameReceived does nothing.

func (NopMetrics) OnFrameSent

func (NopMetrics) OnFrameSent(net.Addr, *link.Frame, int)

OnFrameSent does nothing.

func (NopMetrics) OnFramingError

func (NopMetrics) OnFramingError(net.Addr, error)

OnFramingError does nothing.

type RequestMetrics

type RequestMetrics interface {
	// OnRequest is called before a request is sent.
	OnRequest(remote net.Addr, outstation uint16, fc app.FunctionCode)

	// OnRequestDone is called with the final outcome. err is nil on
	// success; classify failures with errors.Is and errors.As
	// (*IINError, *CommandError, ErrTimeout, ...).
	OnRequestDone(remote net.Addr, outstation uint16, fc app.FunctionCode, duration time.Duration, err error)

	// OnRetry is called when attempt (1 for the first) failed with err and
	// the request is about to be tried again.
	OnRetry(remote net.Addr, outstation uint16, fc app.FunctionCode, attempt int, err error)
}

RequestMetrics is an optional extension of Metrics for a client. When the value given to client.WithMetrics also implements it, the client reports every request: polls, commands, time synchronization, file operations.

OnRequest fires once before the first attempt and OnRequestDone once with the final outcome, whose duration includes retries and their delays. OnRetry fires for each attempt that failed and will be repeated.

remote is the address of the channel, or nil while the client has never been connected. outstation is the link address of the outstation.

type ServerMetrics

type ServerMetrics interface {
	// OnHandled is called after a request was handled, with the time
	// from its reception to the end of the handler calls.
	OnHandled(remote net.Addr, fc app.FunctionCode, duration time.Duration)

	// OnEventsDiscarded is called when an event buffer overflowed and n
	// events of the class (1..3) were discarded.
	OnEventsDiscarded(class int, n int)

	// OnUnsolicited is called after an unsolicited response was confirmed
	// (err == nil) or abandoned.
	OnUnsolicited(remote net.Addr, events int, err error)
}

ServerMetrics is an optional extension of Metrics for a server. When the value given to server.WithMetrics also implements it, the server reports every request it handled and every event it had to discard.

type State

type State uint8

State is the state of a channel as seen by one station.

const (
	// StateDisconnected means there is no transport connection.
	StateDisconnected State = iota
	// StateConnecting means the client is establishing or re-establishing
	// the transport connection.
	StateConnecting
	// StateConnected means the transport is open and frames flow.
	StateConnected
)

Channel states.

func (State) String

func (s State) String() string

String returns "disconnected", "connecting" or "connected".

Directories

Path Synopsis
Package app is the DNP3 application layer codec (IEEE 1815-2012 clause 4 and Annex A): fragments with their control octet, function code and internal indications, object headers with their qualifiers, and the object library.
Package app is the DNP3 application layer codec (IEEE 1815-2012 clause 4 and Annex A): fragments with their control octet, function code and internal indications, object headers with their qualifiers, and the object library.
Package client is the DNP3 master (IEEE 1815-2012).
Package client is the DNP3 master (IEEE 1815-2012).
examples
client command
Command client is a standalone master for trying the library against an outstation: it connects, runs the usual startup (disable unsolicited, integrity poll, enable unsolicited), synchronizes time when the outstation asks for it (NEED_TIME), optionally operates a binary output, and prints everything the outstation reports until interrupted.
Command client is a standalone master for trying the library against an outstation: it connects, runs the usual startup (disable unsolicited, integrity poll, enable unsolicited), synchronizes time when the outstation asks for it (NEED_TIME), optionally operates a binary output, and prints everything the outstation reports until interrupted.
commands command
Command commands shows controls: select-before-operate and direct operate of a control relay output block, a set-point, a direct operate without acknowledgement, and how a refused control surfaces as a *dnp3.CommandError.
Command commands shows controls: select-before-operate and direct operate of a control relay output block, a set-point, a direct operate without acknowledgement, and how a refused control surfaces as a *dnp3.CommandError.
dialout command
Command dialout shows the dual end point of IEEE 1815-2012: the outstation, behind a firewall that only lets it connect out, establishes the TCP connection to its master and re-establishes it when it is lost.
Command dialout shows the dual end point of IEEE 1815-2012: the outstation, behind a firewall that only lets it connect out, establishes the TCP connection to its master and re-establishes it when it is lost.
events command
Command events shows how changes reach the master: events per class, collected in a batch, reported unsolicited once the master enabled unsolicited responses, and confirmed.
Command events shows how changes reach the master: events per class, collected in a batch, reported unsolicited once the master enabled unsolicited responses, and confirmed.
files command
Command files shows file transfer (group 70): an outstation that serves a directory tree read-only with server.FSFileServer, and a master that lists a directory, reads a file and asks for a file's descriptor.
Command files shows file transfer (group 70): an outstation that serves a directory tree read-only with server.FSFileServer, and a master that lists a directory, reads a file and asks for a file's descriptor.
observability command
Command observability shows what a long-running program wires up: slog logging and metrics on both sides, a state handler, retries for reads, automatic reconnection, and periodic polls.
Command observability shows what a long-running program wires up: slog logging and metrics on both sides, a state handler, retries for reads, automatic reconnection, and periodic polls.
quickstart command
Command quickstart is the smallest complete program: an outstation with a few points and a master that runs an integrity poll against it, in one process, over a real TCP connection on loopback.
Command quickstart is the smallest complete program: an outstation with a few points and a master that runs an integrity poll against it, in one process, over a real TCP connection on loopback.
secure command
Command secure shows Secure Authentication version 5: both ends share an update key; the master wraps fresh session keys with it when it connects; the outstation then challenges every critical request and the master answers with an HMAC-SHA-256 MAC.
Command secure shows Secure Authentication version 5: both ends share an update key; the master wraps fresh session keys with it when it connects; the outstation then challenges every critical request and the master answers with an HMAC-SHA-256 MAC.
server command
Command server is a standalone outstation for trying the library against another master, a simulator or a test tool: binary and analog inputs, a counter, a controllable breaker and periodic updates, with unsolicited responses enabled.
Command server is a standalone outstation for trying the library against another master, a simulator or a test tool: binary and analog inputs, a counter, a controllable breaker and periodic updates, with unsolicited responses enabled.
internal
channel
Package channel runs the DNP3 data link layer procedures and the transport function over one byte stream: a TCP connection, a serial port or a UDP socket.
Package channel runs the DNP3 data link layer procedures and the transport function over one byte stream: a TCP connection, a serial port or a UDP socket.
cmd/conformance command
Command conformance is the device under test of the dnp3c conformance run (make conformance): a go-dnp3 outstation with a fixed database, and a control port through which dnp3-interop's dnp3c runner performs the steps a tester would otherwise perform by hand (restarts, configuration changes, input changes) and checks what the outstation reported against what it holds.
Command conformance is the device under test of the dnp3c conformance run (make conformance): a go-dnp3 outstation with a fixed database, and a control port through which dnp3-interop's dnp3c runner performs the steps a tester would otherwise perform by hand (restarts, configuration changes, input changes) and checks what the outstation reported against what it holds.
cmd/gencatalog command
Command gencatalog generates the code and documentation that follow from the DNP3 object catalog, app/catalog.json:
Command gencatalog generates the code and documentation that follow from the DNP3 object catalog, app/catalog.json:
cmd/upstreamwatch command
Command upstreamwatch tells whether the upstreams go-dnp3 follows have moved, and whether they still agree with it:
Command upstreamwatch tells whether the upstreams go-dnp3 follows have moved, and whether they still agree with it:
logx
Package logx is how the library writes its log entries: a constant message plus key-value fields.
Package logx is how the library writes its log entries: a constant message plus key-value fields.
Package link is the DNP3 data link layer codec (IEEE 1815-2012 clause 9): the FT3 frame format with its 16-bit CRCs, the control octet, the function codes and the addresses, and a Reader that reads frames from a byte stream and resynchronises after damage.
Package link is the DNP3 data link layer codec (IEEE 1815-2012 clause 9): the FT3 frame format with its 16-bit CRCs, the control octet, the function codes and the addresses, and a Reader that reads frames from a byte stream and resynchronises after damage.
Package secauth implements the cryptographic core of DNP3 Secure Authentication version 5 (IEEE 1815-2012 clause 7): the message authentication codes and the construction of the data they protect.
Package secauth implements the cryptographic core of DNP3 Secure Authentication version 5 (IEEE 1815-2012 clause 7): the message authentication codes and the construction of the data they protect.
Package server is the DNP3 outstation (IEEE 1815-2012).
Package server is the DNP3 outstation (IEEE 1815-2012).
Package transport is the DNP3 transport function (IEEE 1815-2012 clause 8): it splits application fragments into segments that fit one link frame and reassembles received segments into fragments.
Package transport is the DNP3 transport function (IEEE 1815-2012 clause 8): it splits application fragments into segments that fit one link frame and reassembles received segments into fragments.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL