Documentation
¶
Overview ¶
Package iec104 is the module root of a pure Go implementation of IEC 60870-5-104, the TCP/IP telecontrol protocol used between control centres and substations, RTUs and generation assets.
Applications import the subpackages:
- github.com/otfabric/go-iec104/client: the controlling station (master): connect, STARTDT, interrogation, commands, clock synchronization, automatic reconnect
- github.com/otfabric/go-iec104/server: the controlled station (outstation): listener, sessions, request routing, spontaneous data
- github.com/otfabric/go-iec104/asdu: the ASDU model and codec, shared with IEC 60870-5-101
- github.com/otfabric/go-iec104/apci: APDU framing, I/S/U control fields, sequence numbers and the protocol parameters
This package holds what client and server share: the sentinel errors, the Logger and Metrics interfaces and the data transfer State.
Docs: README.md, API.md (public API), ERRORS.md (error semantics), OBSERVABILITY.md (logging and metrics), RELEASE.md (changelog).
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrClosed reports an operation on a client, server or session that // was closed by the application. ErrClosed = errors.New("iec104: closed") // ErrNotConnected reports an operation on a client that has no // established connection. ErrNotConnected = errors.New("iec104: not connected") // ErrConnectFailed reports that a client could not establish its // connection: the TCP dial or TLS handshake failed, or the controlled // station did not confirm STARTDT. The underlying error is wrapped // alongside it. ErrConnectFailed = errors.New("iec104: connect failed") // ErrNotStarted reports an attempt to send an ASDU while data transfer // is stopped: before STARTDT or after STOPDT. ErrNotStarted = errors.New("iec104: data transfer not started") // ErrConnectionLost reports that the peer closed the connection or the // transport failed. ErrConnectionLost = errors.New("iec104: connection lost") // ErrTimeout reports that the peer did not acknowledge an I frame or // confirm a U frame within t1. The connection is closed. ErrTimeout = errors.New("iec104: acknowledgement timeout (t1)") // ErrProtocol reports a peer that violated the protocol: a malformed // APDU, a sequence number error or a frame that is not allowed in the // current state. The connection is closed. ErrProtocol = errors.New("iec104: protocol violation") // ErrBusy reports a request that cannot be issued because an identical // one is still awaiting its confirmation. ErrBusy = errors.New("iec104: request already pending") // ErrInHandler reports a client request method (one that waits for the // station's answer) called from inside the client's Handler or state // handler. The answer could not be delivered while that call has not // returned; issue the request from another goroutine. ErrInHandler = errors.New("iec104: request from inside a handler") // ErrInvalidOption reports an option value a client or server cannot be // constructed with. Invalid protocol parameters are reported by the // apci and asdu packages (apci.ErrInvalidParams, asdu.ErrInvalidParams). ErrInvalidOption = errors.New("iec104: invalid option") )
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 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", "state", "type", "cause" 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 HandlerMetrics ¶
type HandlerMetrics interface {
// OnHandled is called after the handler returned, or panicked.
OnHandled(remote net.Addr, t asdu.TypeID, cause asdu.Cause, duration time.Duration)
}
HandlerMetrics is an optional extension of Metrics for a server. When the value given to server.WithMetrics also implements it, the server reports every ASDU it passed to the Handler and how long the handler took. Implementations must be safe for concurrent use and must not block.
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 ¶
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 ¶
NewStdLogger wraps a standard library logger. Each message is prefixed with its level. A nil l logs to os.Stderr with the standard flags.
type Metrics ¶
type Metrics interface {
// OnConnect is called when a transport connection is established.
OnConnect(remote net.Addr)
// OnDisconnect is called when a connection ends. err is nil when the
// application closed it.
OnDisconnect(remote net.Addr, err error)
// OnFrameSent is called after an APDU was written. size is its length
// on the wire in octets.
OnFrameSent(remote net.Addr, f apci.Frame, size int)
// OnFrameReceived is called for every APDU read from the peer.
OnFrameReceived(remote net.Addr, f apci.Frame, size int)
// OnDecodeError is called when a received ASDU could not be decoded
// and was dropped.
OnDecodeError(remote net.Addr, err error)
}
Metrics is an optional callback interface for observing connections and 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).
Embed NopMetrics to implement only the callbacks you need and to stay compatible when methods are added.
type NegativeError ¶
NegativeError reports that the controlled station answered a request with a negative confirmation or with one of the "unknown ..." causes of transmission.
func (*NegativeError) Cause ¶
func (e *NegativeError) Cause() asdu.Cause
Cause returns the cause of transmission of the rejection, for example asdu.CauseUnknownIOA, or asdu.CauseActivationCon for a plain negative confirmation.
type NopMetrics ¶
type NopMetrics struct{}
NopMetrics is a Metrics that does nothing. Embed it in your own type.
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) OnFrameReceived ¶
OnFrameReceived does nothing.
func (NopMetrics) OnFrameSent ¶
OnFrameSent does nothing.
type RequestMetrics ¶
type RequestMetrics interface {
// OnRequest is called before a request is sent.
OnRequest(remote net.Addr, t asdu.TypeID, ca asdu.CommonAddr)
// OnRequestDone is called with the final outcome. err is nil on
// success; classify failures with errors.Is and errors.As
// (*NegativeError, context.DeadlineExceeded, ErrConnectionLost, ...).
OnRequestDone(remote net.Addr, t asdu.TypeID, ca asdu.CommonAddr, 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, t asdu.TypeID, ca asdu.CommonAddr, 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 method call (Interrogate, Command, Read, ...).
The callbacks are request-level: 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 station, or nil while the client has never been connected. Implementations must be safe for concurrent use and must not block.
type State ¶
type State uint8
State is the state of a connection 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 // StateStopped means the connection is established and data transfer // is stopped (STOPDT): only U and S frames are exchanged. StateStopped // StateStarted means data transfer is started (STARTDT): I frames // flow. StateStarted )
Connection states.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package apci implements the IEC 60870-5-104 Application Protocol Control Information: APDU framing, the I/S/U control field formats, 15-bit sequence number arithmetic and the protocol parameters (k, w, t0..t3).
|
Package apci implements the IEC 60870-5-104 Application Protocol Control Information: APDU framing, the I/S/U control field formats, 15-bit sequence number arithmetic and the protocol parameters (k, w, t0..t3). |
|
Package asdu implements the Application Service Data Unit of the IEC 60870-5 companion standards: the data unit identifier, the information objects and elements of IEC 60870-5-101 clause 7, and their binary codec.
|
Package asdu implements the Application Service Data Unit of the IEC 60870-5 companion standards: the data unit identifier, the information objects and elements of IEC 60870-5-101 clause 7, and their binary codec. |
|
Package client implements the controlling station (master) of IEC 60870-5-104.
|
Package client implements the controlling station (master) of IEC 60870-5-104. |
|
Package e2e holds end-to-end tests of go-iec104 against itself: the client of this module as controlling station and the server of this module as controlled station, over real TCP (and TLS) connections on loopback.
|
Package e2e holds end-to-end tests of go-iec104 against itself: the client of this module as controlling station and the server of this module as controlled station, over real TCP (and TLS) connections on loopback. |
|
examples
|
|
|
client
command
Command client is a small IEC 60870-5-104 controlling station: it connects, runs a general interrogation, synchronizes the clock, optionally operates a switch and then prints whatever the station reports until interrupted.
|
Command client is a small IEC 60870-5-104 controlling station: it connects, runs a general interrogation, synchronizes the clock, optionally operates a switch and then prints whatever the station reports until interrupted. |
|
commands
command
Command commands shows command transmission from both sides: direct execution, select-before-operate, cancelling a selection, a set point with a time tag, and what a refusal looks like.
|
Command commands shows command transmission from both sides: direct execution, select-before-operate, cancelling a selection, a set point with a time tag, and what a refusal looks like. |
|
events
command
Command events shows how a station reports on its own: an event queue that keeps events while no control centre is connected and repeats what was not acknowledged, next to data that is simply sent to whoever listens.
|
Command events shows how a station reports on its own: an event queue that keeps events while no control centre is connected and repeats what was not acknowledged, next to data that is simply sent to whoever listens. |
|
files
command
Command files shows file transfer: a station that offers files, takes files and has a directory, and a controlling station that lists, fetches and delivers.
|
Command files shows file transfer: a station that offers files, takes files and has a directory, and a controlling station that lists, fetches and delivers. |
|
observability
command
Command observability shows what the library tells its application: structured logs, connection states and metrics, on both sides, and the options that make a client resilient (reconnect, retries, a start handler).
|
Command observability shows what the library tells its application: structured logs, connection states and metrics, on both sides, and the options that make a client resilient (reconnect, retries, a start handler). |
|
quickstart
command
Command quickstart is the smallest complete program: a controlled station with two points and a controlling station that interrogates it, in one process, over a real TCP connection on loopback.
|
Command quickstart is the smallest complete program: a controlled station with two points and a controlling station that interrogates it, in one process, over a real TCP connection on loopback. |
|
redundancy
command
Command redundancy shows a redundancy group: two connections to a station (here: two stations standing in for two paths), exactly one with data transfer started, failover when the active one is lost and a manual switchover.
|
Command redundancy shows a redundancy group: two connections to a station (here: two stations standing in for two paths), exactly one with data transfer started, failover when the active one is lost and a manual switchover. |
|
server
command
Command server is a small IEC 60870-5-104 controlled station: a handful of points, a switch that accepts single commands, and a measurement that changes every second and is reported spontaneously.
|
Command server is a small IEC 60870-5-104 controlled station: a handful of points, a switch that accepts single commands, and a measurement that changes every second and is reported spontaneously. |
|
tls
command
Command tls shows IEC 60870-5-104 over TLS (IEC 62351-3) with certificates on both sides: the station only accepts control centres whose certificate its authority signed, and tells them apart by it.
|
Command tls shows IEC 60870-5-104 over TLS (IEC 62351-3) with certificates on both sides: the station only accepts control centres whose certificate its authority signed, and tells them apart by it. |
|
internal
|
|
|
link
Package link implements the IEC 60870-5-104 connection state machine that the client and the server share: send and receive sequence numbers, the k/w flow control windows, the t1/t2/t3 timers and the STARTDT/STOPDT/ TESTFR procedures.
|
Package link implements the IEC 60870-5-104 connection state machine that the client and the server share: send and receive sequence numbers, the k/w flow control windows, the t1/t2/t3 timers and the STARTDT/STOPDT/ TESTFR procedures. |
|
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. |
|
testutil
Package testutil holds helpers shared by the client and server tests.
|
Package testutil holds helpers shared by the client and server tests. |
|
Package server implements the controlled station (outstation, slave) of IEC 60870-5-104.
|
Package server implements the controlled station (outstation, slave) of IEC 60870-5-104. |