Transport¶
A Transport represents a bidirectional, encrypted line of communication between two Visors (called Transport Edges).
Each transport is identified by a unique Transport ID (UUID) and has a Transport Type that identifies the underlying protocol implementation.
Transport Entry¶
A transport is represented in the Transport Discovery by an Entry:
// Entry is the unsigned representation of a Transport.
type Entry struct {
ID uuid.UUID `json:"t_id"`
Edges [2]cipher.PubKey `json:"edges"`
Type types.Type `json:"type"`
Label Label `json:"label"`
Latency float64 `json:"latency_ms,omitempty"`
Bandwidth uint64 `json:"bandwidth,omitempty"`
}
JSON representation:
{
"t_id": "e1808c31-6b23-d1d6-119c-ad1795238ff0",
"edges": [
"031d796272349d597d6d3130497ccd11cf8af12c7d186b1726358abfb49edad0c1",
"03bd9724f335c5eb5a1011e7862d4af28488102c8edffc84585cf0826ac4864b38"
],
"type": "stcpr",
"label": "automatic",
"latency_ms": 12.5,
"bandwidth": 1234567
}
Transport ID¶
The Transport ID is derived deterministically from the two edge public keys and the transport type. The edges are sorted in ascending order to ensure both sides compute the same ID.
Transport Types¶
| Type | Protocol | Address Resolution | NAT Traversal |
|---|---|---|---|
stcpr |
TCP | Address Resolver service | No (requires public IP or port forwarding) |
sudph |
UDP | Address Resolver service | Yes (UDP hole-punching) |
stcp |
TCP | Local PK-to-IP table | No |
dmsg |
DMSG relay | DMSG Discovery | Yes (relayed through DMSG server) |
Transport Labels¶
Labels identify the origin of a transport and control access via the Transport Setup Node:
| Label | Created by | TPS can list | TPS can remove |
|---|---|---|---|
skycoin |
Transport Setup Node | Yes | Yes (if no active route) |
automatic |
Public autoconnect | Yes | Yes (if no active route) |
user |
Manual CLI / hypervisor UI | No | No |
Signed Entry¶
Transports are registered in the Transport Discovery as SignedEntry:
type SignedEntry struct {
Entry *Entry `json:"entry"`
Signatures [2]cipher.Sig `json:"signatures"`
Registered int64 `json:"registered,omitempty"`
Latency *LatencyData `json:"latency,omitempty"`
Bandwidth *BandwidthData `json:"bandwidth,omitempty"`
Version string `json:"version,omitempty"`
}
type LatencyData struct {
Min int64 `json:"min"` // microseconds
Max int64 `json:"max"`
Avg int64 `json:"avg"`
}
type BandwidthData struct {
SentBytes uint64 `json:"sent_bytes"`
RecvBytes uint64 `json:"recv_bytes"`
}
The Latency and Bandwidth fields are updated on each transport re-registration (every 90 seconds). Latency is measured by transport-level ping; bandwidth is tracked per-packet by the managed transport.
Settlement Handshake¶
When a transport is established between two visors, a settlement handshake occurs:
- The initiator dials the remote visor using the transport-type-specific mechanism (TCP connect, UDP hole-punch, or DMSG relay)
- Both sides exchange signed
Entrydata including the agreed transport ID, type, and edges - The responder adopts the initiator's label so both ends agree on the transport's origin
- The initiator registers the
SignedEntrywith the Transport Discovery
Managed Transport¶
In the visor, each transport is wrapped in a ManagedTransport (pkg/transport/managed_transport.go) which provides:
- Read loop — reads packets from the underlying connection, intercepts transport-level ping/pong (route ID 0), forwards routing packets to the router
- Log loop — tracks sent/received bytes per packet, persists to CSV every 3 seconds
- Ping loop — sends transport-level ping every 30 seconds, measures RTT
- Latency stats — min/max/avg latency in milliseconds
- Bandwidth stats — cumulative sent/received bytes
The managed transport's lifecycle:
Serve(readCh)starts 4 goroutines: readLoop, logLoop, pingLoop, and the main serve loop- Packets from readLoop are sent to the router via
readCh - On close, the transport is deregistered from the Transport Discovery
Transport Interface¶
// Transport is the underlying network connection.
type Transport interface {
Read(p []byte) (n int, err error)
Write(p []byte) (n int, err error)
Close() error
LocalPK() cipher.PubKey
RemotePK() cipher.PubKey
Type() types.Type
SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
}
Network Client¶
Each transport type has a network.Client implementation that handles dialing and accepting connections: