Documentation
¶
Overview ¶
Package stack couples the link and transport layers to a byte stream.
A master and an outstation differ entirely at the application layer and barely at all below it: both frame fragments, both reassemble them, both answer link-layer requests. That shared plumbing lives here so neither session has to reimplement it, and so the two cannot drift apart.
A Stack is not safe for concurrent use, and is deliberately not made so. Sessions call it only from their own goroutine; their read goroutine hands raw octets across a channel rather than calling in directly. Locking the stack instead would make it possible to interleave a send with the processing of an inbound frame, and the link state machines are not interleavable — a frame count bit advanced from two places is a lost or duplicated fragment.
Index ¶
- Constants
- type Config
- type Received
- type Stack
- func (s *Stack) Busy() bool
- func (s *Stack) OnTimeout(w io.Writer) (failed bool, err error)
- func (s *Stack) Pending() bool
- func (s *Stack) Receive(w io.Writer, data []byte, fn func(Received)) error
- func (s *Stack) Reset()
- func (s *Stack) Send(w io.Writer, fragment []byte) error
- func (s *Stack) SendLinkStatusRequest(w io.Writer) error
- func (s *Stack) SendTo(w io.Writer, dest uint16, fragment []byte) error
- func (s *Stack) Stats() (link.Stats, transport.Stats)
Constants ¶
const ReadChunk = link.MaxFrameSize
ReadChunk is the size a session's read goroutine should use.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// LocalAddr and RemoteAddr are the link addresses of the two stations.
LocalAddr uint16
RemoteAddr uint16
// IsMaster sets the direction bit and selects which side answers what.
IsMaster bool
// SelfAddress accepts the discovery destination for outstations only.
SelfAddress bool
// UseConfirms enables link-layer confirmation. Over TCP this is normally
// off, since the transport already guarantees ordered delivery; over
// serial it is normally on.
UseConfirms bool
// MaxRetries is how many times a confirmed frame is retransmitted.
MaxRetries int
// MaxRxFragment caps a reassembled application fragment.
MaxRxFragment int
}
Config parameterises a stack.
type Received ¶
type Received struct {
// Fragment is a completed application fragment. It aliases the stack's
// reassembly buffer and is valid only for the duration of the callback.
Fragment []byte
// Source is the link address the fragment came from.
Source uint16
// Dest is the link address it was sent to, which may be a broadcast
// address. An outstation must answer a broadcast without echoing it.
Dest uint16
// Broadcast reports whether Dest was a broadcast address.
Broadcast bool
}
Received is what one completed fragment looks like.
type Stack ¶
type Stack struct {
// contains filtered or unexported fields
}
Stack owns the link and transport state for one connection.
It performs no I/O of its own and reads no clock: Send writes through a caller-supplied writer, Receive is fed octets the caller has already read, and link timeouts are reported by the caller through OnTimeout. That keeps the blocking, the goroutines and the timers in the session, where they can be cancelled.
func (*Stack) Busy ¶
Busy reports whether a fragment is still being transmitted, either awaiting a confirmation or with segments still to send.
func (*Stack) OnTimeout ¶
OnTimeout is called by the session when its link timer expires.
It retransmits the unacknowledged frame, or gives up once the retry budget is spent. The returned bool reports whether the transmission failed for good, which the session surfaces as a failed request rather than a silent stall.
func (*Stack) Pending ¶
Pending reports whether a confirmed frame is awaiting acknowledgement.
A session arms its link timer while this is true and calls Stack.OnTimeout when it fires. With confirmations disabled it is never true.
func (*Stack) Receive ¶
Receive feeds received octets, calling fn for each completed application fragment.
Link-layer replies — acknowledgements, link status — are written to w as they are produced, and an acknowledgement of our own confirmed frame releases the next segment.
func (*Stack) Reset ¶
func (s *Stack) Reset()
Reset clears all link and transport state, as when a connection is re-established. A fragment cannot span a connection and link state does not survive one.
func (*Stack) Send ¶
Send begins transmitting an application fragment.
With confirmations disabled every segment goes out immediately and the call completes the fragment. With them enabled only the first frame is sent; Stack.Pending then reports true until the peer acknowledges it, and the remaining segments follow as each acknowledgement arrives.
func (*Stack) SendLinkStatusRequest ¶
SendLinkStatusRequest sends a keep-alive.
An idle TCP connection tells you nothing: a peer that has gone away, or a firewall that has quietly dropped the flow, looks exactly like a peer with nothing to report. Asking for link status is how a session finds out before the next poll is due.
func (*Stack) SendTo ¶
SendTo frames a fragment addressed to a specific station, overriding the configured remote address.
An outstation needs this: it must answer whichever master addressed it, which is not necessarily the one in its configuration, and a broadcast request must be answered to the real source rather than to the broadcast address it arrived on.