p2p

package
v0.21.38 Latest Latest
Warning

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

Go to latest
Published: Nov 14, 2026 License: Apache-2.0 Imports: 37 Imported by: 0

Documentation

Index

Constants

View Source
const (
	PathHost  = "webrtc-host"
	PathSrflx = "webrtc-srflx" // through a NAT mapping (srflx/prflx)
	PathTURN  = "webrtc-turn"  // a TURN relay candidate
	PathRelay = "relay"        // the nfltr relay (ICE found no path, or --force-relay)

)

Data path names (the CLI's "data path:" line, the NAT lab's matrix).

View Source
const (
	RaceWon    = "won"    // the path chosen
	RaceLost   = "lost"   // ready, another chosen
	RaceFailed = "failed" // failed before the choice
	RaceLate   = "late"   // not ready when the choice was made
)

Race outcomes (RaceEntry.Outcome).

View Source
const PathTCP = "tcp-direct"

PathTCP is a file transfer on the direct TCP channel (same mutual HMAC and encryption as before WebRTC): the fast path on a LAN.

View Source
const RaceWebRTC = "webrtc"

RaceWebRTC is the data channel's RaceEntry.Path, whichever ICE path (DataPath.Path) it took.

Variables

View Source
var ErrE2EMismatch = errors.New("p2p: end-to-end key check failed: the two machines use different " +
	"A2A keys (--e2ee-key-file / NFLTR_A2A_E2EE_KEY_FILE: the root key, or a machine key of one of the two; set one on both, or none), " +
	"or something between them (the relay) replaced the keys")

ErrE2EMismatch is a failed key confirmation: the two sides derived different keys.

View Source
var ErrMuxOverrun = errors.New("p2p: relay stream path overrun: the peer sent past its credit")

ErrMuxOverrun is a read on a relay mux path whose peer sent past the path's window (a protocol violation: it ignored its credit). The path is failed after what arrived within the window; the other path is unaffected.

View Source
var ErrNoRoute = errors.New("p2p: could not establish direct connection (all candidates failed)")

ErrNoRoute is returned when all P2P connection attempts fail and no relay fallback is configured.

View Source
var ErrPeerRelay = errors.New("p2p: peer chose the server relay")

ErrPeerRelay is Connect's error, with AwaitConn, when the dialing side sent SignalRelay instead of a connection: the session continues on the server relay (NewServerRelayConn).

View Source
var ErrSTUNOff = errors.New("stun: no STUN server configured")

ErrSTUNOff is DiscoverExternalAddr's error when STUNServer is "".

View Source
var RTCWait = 10 * time.Second

RTCWait bounds how long the sender waits for the data channel to open before it falls back to the relay.

View Source
var STUNServer = "stun.l.google.com:19302"

STUNServer is the public STUN server used to discover the external (NAT-mapped) address of a local listener. Uses Google's free STUN service by default; "" turns discovery off (nfltr p2p with a private relay).

Functions

func AddDirectPath

func AddDirectPath(ctx context.Context, sc *SignalConn, ln *net.TCPListener, theirCandidates []string,
	token []byte, sessionID, role string,
) <-chan net.Conn

AddDirectPath tries the direct TCP channel (Connect) while signaling already flows over sc's relay path; on success the channel becomes another path. The returned channel yields the connection (nil if none) once the attempt ends.

func AwaitPeerClose

func AwaitPeerClose(conn net.Conn, d time.Duration)

AwaitPeerClose waits up to d for the peer to close conn (Read returns an error, io.EOF on a clean close), discarding what it reads. A receiver calls it after its ack: a sender closes only once it read the ack, so returning then means the ack was delivered. Without it a receiver that exited right after writing the ack could take the ack with it on the relay path (R3-G10: the file arrived intact, the sender exited 1 on "waiting for ack").

func Chat

func Chat(conn net.Conn, localTag, remoteTag string,
	stdin io.Reader, stdout io.Writer) error

Chat runs an interactive text chat session over the connection. localTag is the display name for locally-typed lines (e.g., "you"). remoteTag is the display name for received lines. stdin/stdout are the I/O streams; os.Stdin / os.Stdout in normal use.

func ConnID

func ConnID(c net.Conn) string

ConnID identifies an authenticated direct connection: a hash of both handshake challenges, the same on both ends whatever a NAT did to the addresses. "" for any other conn.

func Connect

func Connect(
	ctx context.Context,
	myListener *net.TCPListener,
	theirCandidates []string,
	token []byte,
	sessionID string,
	_ string,
	opts ...ConnectOption,
) (net.Conn, error)

Connect establishes a peer-to-peer TCP connection using the exchanged candidates. Both sides run it concurrently with the listener from GatherCandidates, the peer's candidates, the shared secret (E2E.DirectToken) and the session ID (HMAC context); role ("initiator"/"responder") names the side. Several connections can authenticate (several host IPs), so the two sides must keep the same one: the dialing side (AnnounceConn) keeps the highest ConnID it saw within a short window of the first and tells the other side (AwaitConn), which keeps exactly that connection. A side given neither option, or whose peer announces nothing (a peer that predates SignalSelect), keeps the highest ConnID it saw within that window, which two loaded peers can pick differently. myListener is closed before returning.

func DiscoverExternalAddr

func DiscoverExternalAddr(localPort int) (string, error)

DiscoverExternalAddr sends one STUN Binding Request from localPort to STUNServer and returns the server-reflexive address ("ip:port") observed by the STUN server. This is the "server-reflexive candidate" in ICE terminology — the external IP:port that peers outside the local NAT can try to reach.

func GatherCandidates

func GatherCandidates(_ context.Context) (*net.TCPListener, []string, error)

GatherCandidates opens a TCP listener on an OS-assigned port, gathers all local (host) candidates and the STUN server-reflexive candidate, and returns the listener together with the deduplicated candidate list.

The caller is responsible for closing the listener after negotiation.

func GatherHostCandidates

func GatherHostCandidates(port int) []string

GatherHostCandidates returns "ip:port" strings for every non-loopback IPv4 address on the local machine. These "host candidates" are directly reachable on the LAN without NAT traversal.

func ListenHostCandidates

func ListenHostCandidates() (*net.TCPListener, []string, error)

ListenHostCandidates is GatherCandidates without the STUN probe: the listener and its host candidates only. Calls and file transfers use it for the direct TCP channel, which only connects where host addresses reach (ICE covers NATs), so they never wait for STUN (up to 4 s when UDP to the STUN server is blocked).

func OpenBrowser

func OpenBrowser(url string) error

OpenBrowser opens the given URL in the default browser.

func OpenSignalStream

func OpenSignalStream(ctx context.Context, agent *rpcclient.Agent, targetAgentID string) (rpcclient.ClientStream, error)

OpenSignalStream opens a bidirectional p2p.v1 signal stream from the local agent to targetAgentID.

func ReceiveDir

func ReceiveDir(conn net.Conn, outputDir string) error

ReceiveDir receives a directory tar+gzip bundle and extracts it to outputDir.

func ReceiveFile

func ReceiveFile(conn net.Conn, outputDir string, progress ProgressFunc) (string, error)

ReceiveFile reads a file sent by SendFile and writes it to outputDir. Returns the local path of the written file.

func SendAnswer

func SendAnswer(stream rpcclient.ServerStream, msg *SignalMsg) error

SendAnswer transmits an answer over the provided ServerStream.

func SendDir

func SendDir(conn net.Conn, dirPath string, progress ProgressFunc) error

SendDir sends a directory as a gzip-compressed tar archive.

func SendFile

func SendFile(conn net.Conn, path string, progress ProgressFunc) error

SendFile sends a single file over an authenticated P2P net.Conn.

func SendHangupServer

func SendHangupServer(stream rpcclient.ServerStream, sessionID, reason string)

SendHangupServer sends a hangup message and closes the server stream.

func SendOffer

func SendOffer(stream rpcclient.ClientStream, msg *SignalMsg) error

SendOffer transmits an offer over the provided ClientStream.

func SendRelay

func SendRelay(stream rpcclient.ClientStream, sessionID string) error

SendRelay sends a relay signal on a ClientStream, indicating that the initiator wants to fall back to server-relayed data transfer.

Types

type CallServer

type CallServer struct {

	// TURN servers the page adds to its ICE servers beside STUN; nil means
	// none. Set before Run; validated with ValidateICEServers by the caller.
	TURN []turnwire.ICEServer
	// contains filtered or unexported fields
}

func NewCallServer

func NewCallServer(sig FrameConn, role, stunServer string, htmlFunc func() string) (*CallServer, error)

NewCallServer creates a CallServer bound to 127.0.0.1 with a random port. sig carries the signaling frames to the remote peer's CallServer. role is "initiator" or "responder". stunServer is the STUN server URL (e.g. "stun.l.google.com:19302"). htmlFunc returns the HTML page content to serve.

func (*CallServer) Close

func (s *CallServer) Close()

Close triggers shutdown of the call server.

func (*CallServer) Run

func (s *CallServer) Run(ctx context.Context) error

Run starts the HTTP server and blocks until the call ends (hangup, context cancellation, or the signaling ending). The caller should open the browser before or after calling Run.

func (*CallServer) URL

func (s *CallServer) URL() string

URL returns the localhost URL with auth token that should be opened in the browser.

type ConnectOption added in v0.19.11

type ConnectOption func(*connectConfig)

ConnectOption configures Connect.

func AnnounceConn added in v0.19.11

func AnnounceConn(stream rpcclient.ClientStream, sessionID string) ConnectOption

AnnounceConn makes Connect, on the dialing side, send the connection it keeps to the peer on the signaling stream (SignalSelect with Conn).

func AwaitConn added in v0.19.11

func AwaitConn(stream rpcclient.ServerStream) ConnectOption

AwaitConn makes Connect, on the other side, keep the connection the dialing side announced (AnnounceConn), read from the signaling stream. Another signal or the stream's end (a peer that predates SignalSelect) leaves Connect keeping its own pick; SignalRelay makes it return ErrPeerRelay.

type DataPath

type DataPath struct {
	Conn net.Conn
	Path string // PathHost, PathSrflx, PathTURN or PathRelay
	Pair string // selected ICE candidate pair ("srflx -> prflx"); empty on the relay
	// Race is the sender's race, one entry per path it raced (the
	// direct TCP channel when offered, the data channel, the relay),
	// in that order; nil on the receiver, which follows the choice, and
	// with forceRelay.
	Race []RaceEntry
}

DataPath is the conn a file transfer runs on and how it got there.

func OpenDataPath

func OpenDataPath(ctx context.Context, sc *SignalConn, mux *RelayMux, ice ICEConfig, tcp *TCPDirect, initiator, forceRelay bool) (*DataPath, error)

OpenDataPath races the direct TCP channel (tcp; nil for none) against a WebRTC data channel negotiated over sc, and returns a conn on whichever is ready first (TCP on a LAN, the data channel across NATs); when neither is within RTCWait, the relay stream's data conn. The initiator (the sender) chooses and tells the responder (FrameDataPath), which uses exactly that connection; the losing paths are closed. forceRelay skips both. sc keeps being read until it ends (late candidates), so the relay stream never stalls.

sc must come from E2E.SignalConn: the returned conn is that E2E's Secure conn on the chosen path, so every path carries only ciphertext.

type E2E

type E2E struct {
	// contains filtered or unexported fields
}

E2E is one side's end-to-end key exchange for one session.

func NewE2E

func NewE2E(sessionID string, initiator bool, responder string, pair Pair) (*E2E, error)

NewE2E starts this side's key exchange with a fresh ephemeral key. responder names the responder (the initiator: the agent it calls; the responder: its own name); pair is this end's A2A key, or nil (unpaired).

func (*E2E) Answer

func (e *E2E) Answer(offer, answer *SignalMsg) error

Answer (responder) completes the exchange with the offer's key and fills the answer's key and key confirmation.

func (*E2E) AwaitConfirm

func (e *E2E) AwaitConfirm(stream rpcclient.ServerStream) error

AwaitConfirm (responder) reads the initiator's key confirmation, the message after the answer.

func (*E2E) Complete

func (e *E2E) Complete(peerKey, peerKeyID string) error

Complete derives the session keys from the peer's public key and key id (its offer's or answer's KeyID).

func (*E2E) Confirm

func (e *E2E) Confirm() string

Confirm is this side's key confirmation. allow:wrapper

func (*E2E) DirectToken

func (e *E2E) DirectToken() []byte

DirectToken is the direct TCP channel's handshake secret (Connect, TCPDirect): known only to the two ends, never sent. allow:wrapper

func (*E2E) Fingerprint

func (e *E2E) Fingerprint() string

Fingerprint is the session fingerprint (80 bits) both CLIs print: the same on both machines unless something in the middle replaced the keys.

func (*E2E) FinishOffer

func (e *E2E) FinishOffer(stream rpcclient.ClientStream, answer *SignalMsg) error

FinishOffer (initiator) completes the exchange with the answer and checks its key confirmation, then sends this side's confirmation on stream, or a hangup naming the failure (the responder prints it).

func (*E2E) KeyID added in v0.21.18

func (e *E2E) KeyID() string

KeyID is this end's A2A key id for its offer or answer ("" the root key, or unpaired). allow:wrapper

func (*E2E) Paired

func (e *E2E) Paired() bool

Paired reports whether A2A keys authenticate the exchange.

func (*E2E) PublicKey

func (e *E2E) PublicKey() string

PublicKey is this side's public key for the offer or answer (hex). allow:wrapper

func (*E2E) Secure

func (e *E2E) Secure(c net.Conn) net.Conn

Secure wraps a session's data conn (any path: direct TCP, WebRTC data channel, the relay) in AES-256-GCM records: 4-byte big-endian length, then the sealed bytes, nonce = the record's sequence number. A record that does not authenticate (altered, reordered, replayed, or from another key) fails every later Read. The relay can still cut the stream short; transfers check the size and SHA-256 inside it.

func (*E2E) SignalConn

func (e *E2E) SignalConn(first FramePath) *SignalConn

SignalConn starts a SignalConn whose paths (first, and every AddPath) carry sealed frames: the relay sees only their sequence numbers and sizes. OpenDataPath secures the data path with the same E2E.

type Frame

type Frame struct {
	Type FrameType `json:"type"`
	// File/dir fields
	Name   string `json:"name,omitempty"`
	Size   int64  `json:"size,omitempty"`
	SHA256 string `json:"sha256,omitempty"`
	// Chat
	Text string `json:"text,omitempty"`
	// Ack / err
	Error string `json:"error,omitempty"`
	// Seq numbers signaling frames on a SignalConn (1, 2, …); the receiver
	// dedupes and orders by it. Unused on a byte-stream transfer.
	Seq uint64 `json:"seq,omitempty"`
}

Frame is the on-wire header for every P2P message. It is JSON-encoded, length-prefixed with a 4-byte big-endian uint32.

type FrameConn

type FrameConn interface {
	WriteFrame(*Frame) error
	ReadFrame() (*Frame, error)
}

CallServer is a local HTTP + WebSocket server that bridges a browser to the remote CLI for WebRTC signaling and text chat.

Architecture:

Browser ←WS→ CallServer ←FrameRTC/FrameChat→ SignalConn ←→ remote peer

Media flows directly via WebRTC (browser-to-browser) once signaling completes. The CallServer only relays signaling and text-chat frames. FrameConn carries a call's signaling frames between the two CLIs (a SignalConn: relay stream, plus the direct TCP channel once it connects).

type FramePath

type FramePath interface {
	WriteFrame(*Frame) error
	ReadFrame() (*Frame, error)
	Close() error
}

FramePath is one transport for signaling frames: the relay stream (RelayMux.SignalPath) or the direct TCP channel (TCPPath).

func TCPPath

func TCPPath(conn net.Conn) FramePath

TCPPath is a FramePath over a byte stream (the direct TCP channel): frames are length-prefixed JSON (writeFrame/readFrame).

type FrameType

type FrameType string

FrameType identifies the purpose of a framed message.

const (
	FrameFile     FrameType = "file"      // single file transfer (header + body)
	FrameDir      FrameType = "dir"       // tar+gzip bundle of a directory
	FrameChat     FrameType = "chat"      // UTF-8 text message
	FrameAck      FrameType = "ack"       // transfer confirmed by receiver
	FrameErr      FrameType = "err"       // error from receiver
	FrameDone     FrameType = "done"      // all transfers finished
	FrameRTC      FrameType = "rtc"       // WebRTC signaling (SDP/ICE) relayed via Text field
	FrameRTCReady FrameType = "rtc-ready" // browser connected to local WS, ready for WebRTC
	FrameDataPath FrameType = "path"      // file data path the sender chose (Text: pathWebRTC or pathRelay)
)

type ICEConfig

type ICEConfig struct {
	STUN string
	TURN []turnwire.ICEServer
	// contains filtered or unexported fields
}

ICEConfig is what a file transfer's WebRTC data path gathers with, the same ICE servers as a call: the STUN server ("host:port"; "" for none) and the TURN servers (relay-issued credentials or --turn).

type Meta

type Meta struct {
	// Op is the operation: "send-file", "send-dir", "chat", or "call". The
	// file's name, size and SHA-256 travel inside the encrypted data stream.
	Op string `json:"op"`
}

Meta describes the payload to be transferred in a P2P session.

type Pair added in v0.21.18

type Pair interface {
	KeyID() string
	Key(peerKeyID string) (key []byte, pairKeyID string, err error)
}

Pair is an end's A2A key for p2p sessions (spec/proverif p2p_e2e.pv). KeyID is its own key id, sent in its offer or answer ("" the owner's root key). Key is the pair key and the pair key id with a peer that presents peerKeyID: the root key between two root holders, else the machine end's key (a root holder derives it); an error refuses the session.

type ProgressFunc

type ProgressFunc func(transferred, total int64)

ProgressFunc is called periodically during a transfer with the number of bytes transferred so far and the total (0 = unknown).

type RaceEntry added in v0.20.0

type RaceEntry struct {
	Path    string        // PathTCP, RaceWebRTC or PathRelay
	Outcome string        // RaceWon, RaceLost, RaceFailed or RaceLate
	After   time.Duration // since the race began: when the path was ready or failed, else when the choice was made
}

RaceEntry is one path's part in the sender's race (DataPath.Race).

type RelayConn

type RelayConn struct {
	// contains filtered or unexported fields
}

RelayConn wraps a bidirectional A2A stream as a net.Conn so the existing P2P transfer/chat/call code can use it unchanged. Data is relayed through the server instead of flowing peer-to-peer.

func NewClientRelayConn

func NewClientRelayConn(stream rpcclient.ClientStream) *RelayConn

NewClientRelayConn wraps a ClientStream as a net.Conn for relay.

func NewServerRelayConn

func NewServerRelayConn(stream rpcclient.ServerStream) *RelayConn

NewServerRelayConn wraps a ServerStream as a net.Conn for relay.

func (*RelayConn) Close

func (rc *RelayConn) Close() error

Close implements net.Conn. On the client side it ends the stream's send half, as closing a TCP connection sends FIN, so the peer's Read returns io.EOF (AwaitPeerClose).

func (*RelayConn) LocalAddr

func (rc *RelayConn) LocalAddr() net.Addr

func (*RelayConn) Read

func (rc *RelayConn) Read(b []byte) (int, error)

Read implements net.Conn.

func (*RelayConn) RemoteAddr

func (rc *RelayConn) RemoteAddr() net.Addr

func (*RelayConn) SetDeadline

func (rc *RelayConn) SetDeadline(_ time.Time) error

func (*RelayConn) SetReadDeadline

func (rc *RelayConn) SetReadDeadline(_ time.Time) error

func (*RelayConn) SetWriteDeadline

func (rc *RelayConn) SetWriteDeadline(_ time.Time) error

func (*RelayConn) Write

func (rc *RelayConn) Write(b []byte) (int, error)

Write implements net.Conn. Chunks large writes to stay under gRPC limits.

type RelayMux

type RelayMux struct {
	// contains filtered or unexported fields
}

RelayMux splits one p2p.v1 relay stream, after the offer/answer, into a signaling path (sequenced Frames for a SignalConn) and a data byte stream (the file transfer's relay fallback). Every stream message starts with its kind byte.

Each path is flow-controlled on its own (signaling protocol 4): a sender sends only what the peer's reader has room for (the path's window) and waits for the reader's credit grants for more, so a slow reader slows only its own path's sender, the demux never waits, and the other path flows. Both ends must speak protocol 4: a peer below it never grants credit.

func NewClientRelayMux

func NewClientRelayMux(stream rpcclient.ClientStream) *RelayMux

NewClientRelayMux starts a mux on the initiator's stream.

func NewServerRelayMux

func NewServerRelayMux(stream rpcclient.ServerStream) *RelayMux

NewServerRelayMux starts a mux on the responder's stream.

func (*RelayMux) Close

func (m *RelayMux) Close() error

Close half-closes the stream (initiator) and stops delivering.

func (*RelayMux) DataConn

func (m *RelayMux) DataConn() *RelayConn

DataConn is the relay fallback for file data, as a byte stream on the same relay stream (RelayConn semantics: an empty message or the stream's end is io.EOF; Close half-closes the initiator's stream).

func (*RelayMux) SignalPath

func (m *RelayMux) SignalPath() FramePath

SignalPath is the mux's signaling FramePath. Closing it closes the mux.

type SignalConn

type SignalConn struct {
	// contains filtered or unexported fields
}

SignalConn carries the signaling frames between the two CLIs (a call's SDP, ICE candidates, chat fallback and hangup; a file transfer's WebRTC negotiation) over one or more paths at once: the relay stream from the first frame, and the direct TCP channel once it connects (AddPath).

Every frame gets the next sequence number and is written on every open path; a path that joins first carries the frames sent before it (the last maxAhead of them), so a frame still in flight on a path that breaks is carried by the newer one (spec/SignalConn.tla NoSilentLoss). The receiver delivers each sequence number once, in order: a copy of a number already delivered is dropped (dedupe by sequence number, never by payload: two identical frames are two frames), and a frame that overtook an earlier one (the direct path is faster than the relay) waits for it. So a path joining or failing mid-call loses and duplicates nothing. A path that fails is dropped; reads end (io.EOF) when the last path has ended.

func NewSignalConn

func NewSignalConn(first FramePath) *SignalConn

NewSignalConn starts a SignalConn of plain frames on its first path (a call's local test harness; sessions between two CLIs use E2E.SignalConn).

func (*SignalConn) AddPath

func (sc *SignalConn) AddPath(p FramePath)

AddPath adds a path: the frames sent so far and later frames are written on it too, and frames read from it are delivered (deduped and in order with the other paths).

func (*SignalConn) Close

func (sc *SignalConn) Close() error

Close closes every path.

func (*SignalConn) Paths

func (sc *SignalConn) Paths() int

Paths is the number of open paths.

func (*SignalConn) ReadFrame

func (sc *SignalConn) ReadFrame() (*Frame, error)

ReadFrame returns the next frame in sequence order; io.EOF once every path has ended or the SignalConn is closed.

func (*SignalConn) WriteFrame

func (sc *SignalConn) WriteFrame(f *Frame) error

WriteFrame numbers f and writes it on every open path. It fails only when no path took it; that ends the SignalConn (its number is spent, never reused or replayed to a later path).

type SignalMsg

type SignalMsg struct {
	Type SignalType `json:"type"`
	// Session is a UUID that uniquely identifies this P2P session.
	Session string `json:"session"`
	// Key is the sender's ephemeral X25519 public key (hex; offer and answer).
	Key string `json:"key,omitempty"`
	// KeyID is the sender's A2A key id (offer and answer; "" the owner's
	// root key, or unpaired): the relay's word; a root initiator's Pair
	// takes the answer's only for the machine it named, so a wrong one is
	// refused or fails the key confirmation (E2E.Complete; spec/proverif
	// p2p_e2e.pv Initiator).
	KeyID string `json:"key_id,omitempty"`
	// Confirm is a key confirmation (answer and SignalConfirm).
	Confirm string `json:"confirm,omitempty"`
	// Candidates is the list of "host:port" addresses that the peer will
	// accept connections on.  Both local IPs and the STUN-discovered external
	// address are included.
	Candidates []string `json:"candidates"`
	// Meta describes the intended transfer (file, dir, or chat).
	Meta *Meta `json:"meta,omitempty"`
	// Error is set in a hangup message to describe the failure reason.
	Error string `json:"error,omitempty"`
	// Conn is the ConnID of the direct connection the dialing side keeps
	// (SignalSelect).
	Conn string `json:"conn,omitempty"`
	// Proto is the sender's SignalProto (0 from a CLI that predates it).
	Proto int `json:"proto,omitempty"`
}

SignalMsg is the JSON envelope exchanged between peers during signaling. Both offer and answer are transmitted as the payload of an rpcclient stream message with message_type "p2p.v1".

func RecvSignal

func RecvSignal(stream rpcclient.ClientStream) (*SignalMsg, error)

RecvSignal reads a single SignalMsg from a ClientStream.

func RecvSignalServer

func RecvSignalServer(stream rpcclient.ServerStream) (*SignalMsg, error)

RecvSignalServer reads a single SignalMsg from a ServerStream.

type SignalType

type SignalType string

SignalType identifies the type of a signaling message exchanged during P2P session negotiation. The vocabulary mirrors WebRTC (offer / answer / hangup).

const (
	// SignalOffer is sent by the initiating peer.  It carries connection
	// candidates and the initiator's end-to-end public key.
	SignalOffer SignalType = "offer"
	// SignalAnswer is sent by the responding peer.  It carries that peer's
	// connection candidates, public key and key confirmation.
	SignalAnswer SignalType = "answer"
	// SignalConfirm is the initiator's key confirmation, the message after
	// the answer (E2E.FinishOffer).
	SignalConfirm SignalType = "confirm"
	// SignalSelect is the dialing side's choice among the direct
	// connections that authenticated (Conn: its ConnID), sent after the
	// answer (AnnounceConn). A peer that predates it never sends it, and its
	// peer then keeps its own pick.
	SignalSelect SignalType = "select"
	// SignalHangup terminates signaling before a direct connection is formed.
	SignalHangup SignalType = "hangup"

	// SignalProto is the signaling protocol a CLI speaks, in every offer and
	// answer. From 2, after the offer/answer the relay stream is a RelayMux:
	// sequenced signaling frames from the first message (a call starts at
	// once; the direct TCP channel joins later), and file data on a WebRTC
	// data channel (OpenDataPath). From 3, every session is end-to-end
	// encrypted (E2E): the offer and answer carry X25519 public keys instead
	// of a session token, the initiator confirms the keys, and the signaling
	// frames and the data stream are sealed on every path. From 4, each
	// RelayMux path is flow-controlled on its own: a reader grants credit as
	// it reads, so a slow data reader slows only the data sender and
	// signaling always flows. A peer below 4 is refused (a peer below 3 is
	// never served in the clear; one at 3 never grants credit, so its data
	// sender would wait forever). An older peer omits it (0).
	SignalProto = 4
)
const (
	// SignalRelay is sent by the initiator when direct P2P fails, instructing
	// both sides to relay data through the server's A2A channel.
	SignalRelay SignalType = "relay"
)

type TCPDirect

type TCPDirect struct {
	Listener   *net.TCPListener
	Candidates []string
	Token      []byte
	SessionID  string
}

TCPDirect is the direct TCP channel a file transfer races against WebRTC: this side's listener (from ListenHostCandidates), the peer's candidates, and the session's token and ID. nil: no race (--force-relay, or the peer sent no candidates).

Jump to

Keyboard shortcuts

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