Documentation
¶
Overview ¶
Package disc pkg/dmsg/disc/client.go c1-net-dmsg
HTTP-based APIClient. Build-tag-gated to keep net/http out of the js/wasm build graph; the EntryReader/EntryWriter/APIClient interfaces live in interface.go (no build tag) so consumers like pkg/visor/visorconfig still see the type names under GOOS=js without dragging net/http in. See interface.go for the rationale.
Package disc pkg/dmsg/disc/entry.go c1-net-dmsg
Package disc pkg/dmsg/disc/entry_sign.go c1-net-dmsg
Package disc pkg/dmsg/disc/fallback.go c1-net-dmsg
Build-tag-gated off the WASM path because it imports pkg/logging (which wraps logrus, which transitively pulls encoding/json). FallbackClient is constructed only from pkg/dmsg/dmsgc at visor runtime; the WASM install-page graph doesn't reach it.
FallbackClient wraps two APIClients (primary + fallback) and tries the primary first; on error it transparently retries the same call against the fallback. Used by the visor's dmsg layer when an operator points the visor at a hypervisor-hosted dmsg-discovery proxy as primary, with the canonical public discovery as the safety-net fallback. Means visors stay reachable for lookups even when the hypervisor itself is offline, while still benefiting from the proxy's local-relay shortcut when it is online.
Package disc pkg/dmsg/disc/http_message.go c1-net-dmsg
HTTP-response message types used by the discovery service's HTTP API. Build-tag-gated alongside client.go to keep net/http out of the WASM build graph (see interface.go for rationale).
Package disc pkg/dmsg/disc/interface.go c1-net-dmsg
Holds the cross-build interface definitions (EntryReader, EntryWriter, APIClient) that callers depend on for type-checking regardless of whether they actually instantiate an HTTP client.
The HTTP implementation lives in client.go under //go:build !js; keeping the interfaces in their own file (with no build tag and no net/http import) means consumers like pkg/visor/visorconfig — which only need *Entry plus the interface shapes for type aliasing — can compile under GOOS=js GOARCH=wasm (TinyGo included) without the WASM build graph pulling in net/http and tripping over TinyGo 0.41.1's net/http stdlib bug.
Package disc pkg/dmsg/disc/json.go c1-net-dmsg
Package disc pkg/dmsg/disc/recursion.go c1-net-dmsg
Package disc pkg/dmsg/disc/testing.go c1-net-dmsg
Mock APIClient for tests. Build-tag-gated because it imports net/http (for status-code constants). See interface.go for the rationale on splitting net/http-using code from the WASM build.
Index ¶
- Variables
- func Copy(dst, src *Entry)
- func NewEntryValidationError(cause string) error
- type APIClient
- type Client
- type Entry
- type EntryReader
- type EntryValidationError
- type EntryWriter
- type FallbackClient
- func (f *FallbackClient) AllClientsByServer(ctx context.Context) (map[string][]*Entry, error)
- func (f *FallbackClient) AllEntries(ctx context.Context) ([]string, error)
- func (f *FallbackClient) AllServers(ctx context.Context) ([]*Entry, error)
- func (f *FallbackClient) AvailableServers(ctx context.Context) ([]*Entry, error)
- func (f *FallbackClient) ClientsByServer(ctx context.Context, serverPK cipher.PubKey) ([]*Entry, error)
- func (f *FallbackClient) DelEntry(ctx context.Context, entry *Entry) error
- func (f *FallbackClient) Entry(ctx context.Context, pk cipher.PubKey) (*Entry, error)
- func (f *FallbackClient) PostEntry(ctx context.Context, entry *Entry) error
- func (f *FallbackClient) PutEntry(ctx context.Context, sk cipher.SecKey, entry *Entry) error
- type HTTPMessage
- type Server
- type ServersFunc
Constants ¶
This section is empty.
Variables ¶
var ( // ErrKeyNotFound occurs in case when entry of public key is not found ErrKeyNotFound = errors.New("entry of public key is not found") // ErrNoAvailableServers occurs when dmsg client cannot find any delegated servers available for the given remote. ErrNoAvailableServers = errors.New("no delegated dmsg servers available for remote") // ErrUnexpected occurs in case when something unexpected happened ErrUnexpected = errors.New("something unexpected happened") ErrUnauthorized = errors.New("invalid signature") // ErrBadInput occurs in case of bad input ErrBadInput = errors.New("error bad input") // ErrValidationNonZeroSequence occurs in case when new entry has non-zero sequence ErrValidationNonZeroSequence = NewEntryValidationError("new entry has non-zero sequence") // ErrValidationNilEphemerals occurs in case when entry of client instance has nil ephemeral keys ErrValidationNilEphemerals = NewEntryValidationError("entry of client instance has nil ephemeral keys") // ErrValidationNilKeys occurs in case when entry Keys is nil ErrValidationNilKeys = NewEntryValidationError("entry Keys is nil") // ErrValidationNonNilEphemerals occurs in case when entry of server instance has non nil Keys.Ephemerals field ErrValidationNonNilEphemerals = NewEntryValidationError("entry of server instance has non nil Keys.Ephemerals field") // ErrValidationNoSignature occurs in case when entry has no signature ErrValidationNoSignature = NewEntryValidationError("entry has no signature") // ErrValidationNoVersion occurs in case when entry has no version ErrValidationNoVersion = NewEntryValidationError("entry has no version") // ErrValidationNoClientOrServer occurs in case when entry has neither client or server field ErrValidationNoClientOrServer = NewEntryValidationError("entry has neither client or server field") // ErrValidationWrongSequence occurs in case when sequence field of new entry is not sequence of old entry + 1 ErrValidationWrongSequence = NewEntryValidationError("sequence field of new entry is not sequence of old entry + 1") // ErrValidationWrongTime occurs in case when previous entry timestamp is not set before current entry timestamp ErrValidationWrongTime = NewEntryValidationError("advertised entry timestamp is not greater than previous") // ErrValidationOutdatedTime occurs when the timestamp provided is not recent enough. ErrValidationOutdatedTime = NewEntryValidationError("advertised entry has outdated timestamp") // ErrValidationServerAddress occurs in case when client want to advertise wrong Server address ErrValidationServerAddress = NewEntryValidationError("advertising localhost listening address is not allowed in production mode") // ErrValidationEmptyServerAddress occurs when a server entry is submitted with an empty address. ErrValidationEmptyServerAddress = NewEntryValidationError("server address cannot be empty") ErrUnauthorizedNetworkMonitor = errors.New("invalid network monitor key") )
var ( MsgEntrySet = HTTPMessage{Code: http.StatusOK, Message: "wrote a new entry"} MsgEntryUpdated = HTTPMessage{Code: http.StatusOK, Message: "wrote new entry iteration"} MsgEntryDeleted = HTTPMessage{Code: http.StatusOK, Message: "deleted entry"} )
Exposed Http messages
var ErrCircularDiscovery = errors.New("dmsg disc: circular lookup — a dmsg-addressed discovery cannot be reached from inside its own dial")
ErrCircularDiscovery is returned when answering a discovery request would require making one: the client is addressed over dmsg, and a dmsg dial is already in progress on this call chain waiting for the very entry being asked for.
It is a real configuration outcome, not a theoretical one. A dmsg-addressed discovery is reachable only because the dial that reaches it is short-cut by a seeded entry for the discovery's own key. Put a `dmsg://` URL in a field the code treats as plain HTTP, or lose the seed, and the short-cut is gone: the lookup dials, the dial looks up, and nothing bounds it. Observed on an Android visor whose config had `dmsg://…` under `dmsg.discovery` instead of `dmsg.discovery_dmsg` — it died with "fatal error: stack overflow" about six seconds into every start, restarting for as long as anyone left it running.
Failing the lookup turns that into an error the caller can log, retry, or surface. It cannot repair the configuration, and does not try to.
Functions ¶
func Copy ¶
func Copy(dst, src *Entry)
Copy performs a deep copy of two entries. It is safe to use with empty entries
func NewEntryValidationError ¶
NewEntryValidationError constructs a new validation error.
Types ¶
type APIClient ¶
type APIClient interface {
EntryReader
EntryWriter
AllEntries(ctx context.Context) ([]string, error)
AllClientsByServer(ctx context.Context) (map[string][]*Entry, error)
ClientsByServer(ctx context.Context, serverPK cipher.PubKey) ([]*Entry, error)
}
APIClient implements dmsg discovery API client.
func NewCXOServersClient ¶ added in v1.3.100
func NewCXOServersClient(primary APIClient, servers ServersFunc) APIClient
NewCXOServersClient fronts primary's AllServers with servers, such as a subscription to dmsg discovery's feed. Everything else, and AllServers when servers has no answer, goes to primary.
func NewFallbackClient ¶
NewFallbackClient returns an APIClient that tries `primary` first and falls back to `fallback` whenever primary returns a non-nil error. Both clients must be non-nil.
func NewHTTP ¶
NewHTTP constructs a new APIClient that communicates with discovery via http.
Defense-in-depth: an empty address (the operator dropped/blanked the discovery URL to force dmsg-only) must NOT build a host-less httpClient — that turns every request into "GET /dmsg-discovery/...: invalid host address" and spins the dmsg serve-loop retrier indefinitely. Return a no-op client that reports "no servers" cleanly so callers fall back to seeded / dmsg entries instead of hammering an invalid URL.
type Client ¶
type Client struct {
// DelegatedServers contains a list of delegated servers represented by their public keys.
DelegatedServers []cipher.PubKey `json:"delegated_servers"`
}
Client contains parameters for Client instances.
type Entry ¶
type Entry struct {
// The data structure's version.
Version string `json:"version"`
// An Entry of a given public key may need to iterate. This is the iteration sequence.
Sequence uint64 `json:"sequence"`
// Timestamp of the current iteration.
Timestamp int64 `json:"timestamp"`
// Static public key of an instance.
Static cipher.PubKey `json:"static"`
// Contains the instance's client meta if it's to be advertised as a DMSG Client.
Client *Client `json:"client,omitempty"`
// ClientType the instance's client_type meta if it's to be advertised as a DMSG Client.
ClientType string `json:"client_type,omitempty"`
// Contains the instance's server meta if it's to be advertised as a DMSG Server.
Server *Server `json:"server,omitempty"`
// Signature for proving authenticity of an Entry.
Signature string `json:"signature,omitempty"`
// Protocol is the lib that use for multiplexing.
Protocol string `json:"protocol,omitempty"`
}
Entry represents a Dmsg Node's entry in the Discovery database.
func NewClientEntry ¶
NewClientEntry is a convenience function that returns a valid client entry, but this entry should be signed with the private key before sending it to the server
func NewServerEntry ¶
NewServerEntry constructs a new Server entry.
func (*Entry) ValidateIteration ¶
ValidateIteration verifies Entry's Sequence against nextEntry.
func (*Entry) VerifySignature ¶
VerifySignature checks if the entry's signature matches its PubKey.
type EntryReader ¶
type EntryReader interface {
Entry(context.Context, cipher.PubKey) (*Entry, error)
AvailableServers(context.Context) ([]*Entry, error)
AllServers(context.Context) ([]*Entry, error)
}
EntryReader provides read-only access to discovery entries.
type EntryValidationError ¶
type EntryValidationError struct {
Cause string
}
EntryValidationError represents transient error caused by invalid data in Entry
func (EntryValidationError) Error ¶
func (e EntryValidationError) Error() string
type EntryWriter ¶
type EntryWriter interface {
PostEntry(context.Context, *Entry) error
PutEntry(context.Context, cipher.SecKey, *Entry) error
DelEntry(context.Context, *Entry) error
}
EntryWriter provides write access to discovery entries.
type FallbackClient ¶
type FallbackClient struct {
// contains filtered or unexported fields
}
FallbackClient implements APIClient by delegating to a primary client and falling back to a secondary on error.
func (*FallbackClient) AllClientsByServer ¶
AllClientsByServer tries primary, falls back on error.
func (*FallbackClient) AllEntries ¶
func (f *FallbackClient) AllEntries(ctx context.Context) ([]string, error)
AllEntries tries primary, falls back on error.
func (*FallbackClient) AllServers ¶
func (f *FallbackClient) AllServers(ctx context.Context) ([]*Entry, error)
AllServers tries primary, falls back on error.
func (*FallbackClient) AvailableServers ¶
func (f *FallbackClient) AvailableServers(ctx context.Context) ([]*Entry, error)
AvailableServers tries primary, falls back on error.
func (*FallbackClient) ClientsByServer ¶
func (f *FallbackClient) ClientsByServer(ctx context.Context, serverPK cipher.PubKey) ([]*Entry, error)
ClientsByServer tries primary, falls back on error.
func (*FallbackClient) DelEntry ¶
func (f *FallbackClient) DelEntry(ctx context.Context, entry *Entry) error
DelEntry tries primary, falls back on error.
type HTTPMessage ¶
HTTPMessage represents a message to be returned as an http response
func (HTTPMessage) String ¶
func (h HTTPMessage) String() string
type Server ¶
type Server struct {
// Address is the DMSG Server's reachable endpoint ("host:port").
// Historically an IPv4 or IPv6 address could go in this field
// either-or; with the dual-stack-within-record design (see #1525)
// Address now canonically carries the IPv4 endpoint and
// AddressV6 carries the IPv6 counterpart. Servers listening on
// only one family leave the other blank; servers listening on
// both populate both. Dialers prefer v6 with v4 fallback per
// RFC 8305.
Address string `json:"address"`
// AddressV6 is the optional IPv6 ("[host]:port") endpoint for
// dual-stack DMSG servers. Empty when the server is v4-only.
// Backward-compat: older servers omit this field; older clients
// ignore it; either side absent the field falls through to
// Address as today.
AddressV6 string `json:"address_v6,omitempty"`
// AddressUDP / AddressUDPV6 are the optional QUIC (UDP) endpoints a
// server also listens on (#2607 dmsg-over-QUIC). A QUIC-speaking server
// populates these alongside the TCP Address(es) and advertises
// Entry.Protocol="quic"; QUIC-capable clients dial these for a session
// with native QUIC stream multiplexing + an unreliable datagram channel,
// while clients/servers that don't know QUIC ignore the fields and use
// the TCP Address as today. Fully backward-compatible (omitempty +
// dual-listen). The UDP port may share the TCP port number.
AddressUDP string `json:"address_udp,omitempty"`
AddressUDPV6 string `json:"address_udp_v6,omitempty"`
// AddressWS is the optional WebSocket endpoint a server also listens on
// (dmsg-over-WebSocket). It carries a full ws:// or wss:// URL including
// path (e.g. "wss://dmsg1.skywire.skycoin.com/dmsg"). A WS connection is
// a net.Conn, so the session runs the SAME Noise+yamux stack as the TCP
// Address — WS is purely a browser-reachable / CDN-frontable / restrictive-
// network transport, orthogonal to Protocol (which still selects the mux).
// The primary consumer is a dmsg client compiled to js/wasm, which cannot
// open a raw TCP or UDP socket and so can only reach the mesh over WS.
// Backward-compatible: omitempty + older clients/servers ignore it.
AddressWS string `json:"address_ws,omitempty"`
// AddressWT is the optional WebTransport (HTTP/3-over-QUIC) endpoint a server
// also listens on (dmsg-over-WebTransport). It carries a full https:// URL
// including path (e.g. "https://1.2.3.4:8443/dmsg"). Like AddressWS it is a
// net.Conn-style single stream carrying the SAME Noise+yamux stack — the
// session is identical, only the underlying transport differs. WebTransport's
// value over WS is that a browser can reach it by BARE IP with no CA-issued
// certificate: the browser pins CertHashWT (below) in its WebTransport
// serverCertificateHashes constructor. Backward-compatible: omitempty + older
// clients/servers ignore it.
AddressWT string `json:"address_wt,omitempty"`
// CertHashWT is the lowercase-hex SHA-256 of the DER of the self-signed ECDSA
// certificate served on AddressWT. It is the value a browser pins in the
// WebTransport serverCertificateHashes option to reach AddressWT with no CA.
// The server rotates its cert (<=14-day validity, browser-enforced) and
// re-advertises this hash. Empty unless AddressWT is set.
CertHashWT string `json:"cert_hash_wt,omitempty"`
// CertHashWTNext is the hash of the certificate the server will serve
// after its next rotation. A browser pins both, so it keeps connecting
// across the rotation without looking the server up again. Empty from
// older servers and when AddressWT is unset.
CertHashWTNext string `json:"cert_hash_wt_next,omitempty"`
// AvailableSessions is the number of available sessions that the server can currently accept.
AvailableSessions int `json:"availableSessions"`
// ServerType of DMSG Server, be `official` of `community`
ServerType string `json:"serverType,omitempty"`
// DHTBootstrap indicates this server runs a DHT full node on port 100
// and can be used as a Kademlia bootstrap peer by visors.
DHTBootstrap bool `json:"dht_bootstrap,omitempty"`
}
Server contains parameters for Server instances.