session

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package session is the goroutine host for one RIST Simple-profile flow. It owns the real clock, the UDP sockets, and the timer wheel, and drives the sans-I/O flow core: a single event-loop goroutine is the sole owner of the flow.Flow (which is not safe for concurrent use), reader goroutines forward decoded packets to it over channels, and the loop performs the core's returned effects on the wire.

The loop selects over: inbound media (receiver), inbound RTCP, application input (sender Write), the flow's declarative timer, and a liveness ticker. After every input it drains the flow's effects — encoding and sending media and compound RTCP, (re)arming the timer, and queueing delivered payloads for Read — exactly once. Close stops every goroutine without leaks.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AdvParams

type AdvParams struct {
	// SendKey encrypts outbound media payloads (AES-CTR, payload-only); nil
	// disables encryption.
	SendKey *crypto.Key
	// RecvKey decrypts inbound media payloads; nil disables decryption. It must
	// be non-nil exactly when SendKey is (both derive from the same passphrase).
	RecvKey *crypto.Decryptor
	// GRESendKey / GRERecvKey encrypt and decrypt the Main-profile GRE control
	// substrate (the RTCP SDES handshake) when a secret is configured. They are
	// SEPARATE crypto instances from SendKey/RecvKey — GRE framing and adv media
	// advance independent IV/sequence state — derived from the same passphrase.
	// Both nil means a cleartext GRE substrate.
	GRESendKey *crypto.Key
	GRERecvKey *crypto.Decryptor
	// KeySize256 sets the GRE H bit for the encrypted control substrate (true
	// for a 256-bit AES key), mirroring MainParams.
	KeySize256 bool
	// Compression enables LZ4 payload compression on the media send path.
	Compression bool
	// VirtSrcPort and VirtDstPort are the reduced-overhead virtual ports encoded
	// into the optional Flow ID field on the media send path.
	VirtSrcPort uint16
	VirtDstPort uint16
}

AdvParams carries the Advanced-profile codec parameters. As with MainParams the public layer builds the PSK keys (so the session constructor stays infallible); nil keys mean cleartext Advanced (no encryption).

type Config

type Config struct {
	// Flow is the deterministic core's configuration.
	Flow flow.Config
	// SSRC is the base (even) flow SSRC the sender stamps; for a receiver it
	// is the reporter SSRC used in its RTCP until the media SSRC is learned.
	SSRC uint32
	// CNAME is the SDES canonical name advertised in compound RTCP.
	CNAME string
	// Bitmask selects the RFC 4585 bitmask NACK encoding instead of the
	// default RIST range NACK.
	Bitmask bool
	// KeepaliveInterval paces the host liveness check.
	KeepaliveInterval clock.Microseconds
	// SessionTimeout tears the session down after this much peer silence.
	SessionTimeout clock.Microseconds
	// Logf, when non-nil, receives diagnostic messages tagged with a severity
	// and a category. The host maps LogLevel/LogCategory to the public
	// ristgo.LogLevel/LogCategory (the session is decoupled from the public
	// package to avoid an import cycle).
	Logf func(level LogLevel, category LogCategory, format string, args ...any)

	// ErrClosed, ErrTimeout, ErrSessionTimeout, and ErrBufferOverflow are the
	// sentinel errors the session returns to the caller. The public layer
	// supplies its own identities so callers can match them with errors.Is;
	// this keeps the session decoupled from the public package (no import
	// cycle).
	ErrClosed         error
	ErrTimeout        error
	ErrSessionTimeout error
	ErrBufferOverflow error
	// ErrAuth is returned to the caller when the Main-profile EAP-SRP handshake
	// fails (wrong credentials or a refused proof). Supplied by the public layer.
	ErrAuth error
	// ErrOOBUnsupported is returned by WriteOOB/ReadOOB when the session has no
	// out-of-band channel (the Simple profile). Supplied by the public layer.
	ErrOOBUnsupported error

	// Main, when non-nil, selects the Main profile (VSF TR-06-2): the flow is
	// tunnelled over a single GRE port instead of the Simple even/odd RTP/RTCP
	// pair. nil means the Simple profile.
	Main *MainParams

	// Adv, when non-nil, selects the Advanced profile (VSF TR-06-3): a single
	// UDP port carrying RTP-based media (PT=127, 1 MHz) and native control
	// messages, with no GRE framing. At most one of Main/Adv is non-nil; both
	// nil means the Simple profile.
	Adv *AdvParams

	// Source adaptation (TR-06-4 Part 1, see adapt.go). AdaptLQM makes a
	// receiver emit periodic Link Quality Messages. RateController + OnRateAdapt,
	// when both set on a sender, feed each inbound LQM to the controller and
	// report the new encoder-rate target to the application. All three are off by
	// default, leaving non-adaptive sessions unchanged.
	AdaptLQM       bool
	RateController *adapt.Controller
	OnRateAdapt    func(kbps int)
}

Config carries the per-session parameters the host needs, already translated from the public ristgo.Config (kept separate to avoid an import cycle).

type LogCategory

type LogCategory int

LogCategory tags a session diagnostic by subsystem; the host maps it to the public ristgo.LogCategory.

const (
	CatSession LogCategory = iota
	CatCrypto
	CatSocket
	CatRTCP
	CatFlow
	CatBonding
)

Session log categories.

type LogLevel

type LogLevel int

LogLevel is the severity of a session diagnostic; the host maps it to the public ristgo.LogLevel. Values are ordered least-to-most severe.

const (
	LogDebug LogLevel = iota
	LogNote
	LogWarning
	LogError
)

Session log severities.

type MainParams

type MainParams struct {
	// SendKey encrypts outbound datagrams; nil disables encryption.
	SendKey *crypto.Key
	// RecvKey decrypts inbound datagrams; nil disables decryption. It must be
	// non-nil exactly when SendKey is (both derive from the same passphrase).
	RecvKey *crypto.Decryptor
	// KeySize256 sets the GRE H bit for outbound encrypted datagrams (true for
	// a 256-bit AES key). Meaningful only when SendKey is non-nil.
	KeySize256 bool
	// NPD enables null-packet-deletion suppression on the media encode path.
	NPD bool
	// VirtSrcPort and VirtDstPort are the reduced-overhead virtual ports.
	VirtSrcPort uint16
	VirtDstPort uint16

	// EAPClient, when non-nil, runs the EAP-SRP authenticatee handshake (a Main
	// sender authenticating to the peer); outbound media is held until it
	// succeeds. EAPServer, when non-nil, runs the authenticator handshake (a
	// Main receiver authenticating the peer); delivery is held until it
	// succeeds. At most one is set; both nil means no authentication.
	EAPClient *eap.Authenticatee
	EAPServer *eap.Authenticator

	// UseKeyAsPassphrase enables the EAP-SRP use_key_as_passphrase data-channel
	// keying: when SRP is configured WITHOUT a pre-shared Secret, the media PSK
	// keys are derived from the SRP session key K (both directions) on a
	// successful handshake and installed into the running codec. SendKey/RecvKey
	// are nil at construction in this mode (no secret); the handshake fills them.
	// Meaningful only when EAPClient or EAPServer is set.
	UseKeyAsPassphrase bool

	// EAPKeySize256 selects the AES key size derived from K under
	// use_key_as_passphrase: true for 256-bit (the libRIST default when no
	// aes-type is given, since _librist_crypto_psk_set_passphrase defaults
	// key_size to 256), false for 128-bit. Meaningful only when
	// UseKeyAsPassphrase is set.
	EAPKeySize256 bool

	// EAPKeyRotation is the key-rotation threshold for the K-derived send key
	// (packets per nonce; 0 = the library default). Meaningful only under
	// UseKeyAsPassphrase.
	EAPKeyRotation int
}

MainParams carries the Main-profile codec parameters. The public layer builds the PSK keys (so the session constructor stays infallible) and supplies the virtual ports; nil keys mean cleartext Main (no encryption).

type Session

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

Session hosts one flow. Construct it with NewSender or NewReceiver.

func NewAdvListenerSender

func NewAdvListenerSender(conn *socket.Conn, cfg Config) *Session

NewAdvListenerSender builds an Advanced-profile listener-sender that binds the single UDP port and learns the receiver from its inbound traffic. cfg.Adv must be set.

func NewAdvReceiver

func NewAdvReceiver(conn *socket.Conn, cfg Config) *Session

NewAdvReceiver builds an Advanced-profile receiver that reads media and control over the single UDP socket conn and learns the sender's address from inbound traffic. cfg.Adv must be set.

func NewAdvReceiverCaller

func NewAdvReceiverCaller(conn *socket.Conn, remote netip.AddrPort, cfg Config) *Session

NewAdvReceiverCaller builds an Advanced-profile caller-receiver that dials remote over the single UDP socket, announcing itself until the listening sender streams. cfg.Adv must be set.

func NewAdvSender

func NewAdvSender(conn *socket.Conn, remote netip.AddrPort, cfg Config) *Session

NewAdvSender builds an Advanced-profile sender that transmits RTP-based media and reads control over the single UDP socket conn, addressing remote. cfg.Adv must be set.

func NewBondedReceiver

func NewBondedReceiver(conns []*socket.Conn, group *bonding.Group, cfg Config) *Session

NewBondedReceiver builds a Simple-profile bonded receiver: one socket per path, all feeding flow into a single deduplicated ring. group must already have a path registered per conn (index = conn index); the constructor registers them if empty.

func NewBondedSender

func NewBondedSender(conn *socket.Conn, remotes [][2]netip.AddrPort, group *bonding.Group, cfg Config) *Session

NewBondedSender builds a Simple-profile bonded sender: one socket that duplicates every media datagram to each remote {media, rtcp} pair. conn is the local ephemeral socket; remotes are the per-path receiver addresses.

func NewListenerSender

func NewListenerSender(conn *socket.Conn, cfg Config) *Session

NewListenerSender builds a Simple-profile listener-sender: a sender that binds a well-known port and waits for a caller-receiver to announce itself, then streams. The peer is not seeded — peer.RTCP is learned from the receiver's inbound RTCP and peer.Media is inferred as its RTCP port − 1 (the even/odd rule) — so sendMedia holds the stream until a receiver is known.

func NewMainListenerSender

func NewMainListenerSender(conn *socket.Conn, cfg Config) *Session

NewMainListenerSender builds a Main-profile listener-sender that binds the single GRE port and learns the receiver from its inbound traffic. cfg.Main must be set.

func NewMainReceiver

func NewMainReceiver(conn *socket.Conn, cfg Config) *Session

NewMainReceiver builds a Main-profile receiver that reads media and feedback over the single GRE socket conn and learns the sender's address from inbound traffic. cfg.Main must be set.

func NewMainReceiverCaller

func NewMainReceiverCaller(conn *socket.Conn, remote netip.AddrPort, cfg Config) *Session

NewMainReceiverCaller builds a Main-profile caller-receiver that dials remote over the single GRE socket, announcing itself until the listening sender streams. cfg.Main must be set.

func NewMainSender

func NewMainSender(conn *socket.Conn, remote netip.AddrPort, cfg Config) *Session

NewMainSender builds a Main-profile sender that tunnels media and reads feedback over the single GRE socket conn, addressing remote. cfg.Main must be set.

func NewReceiver

func NewReceiver(conn *socket.Conn, cfg Config) *Session

NewReceiver builds a receiver-role session that reads RTP and RTCP on conn and learns the sender's return addresses from inbound traffic.

func NewReceiverCaller

func NewReceiverCaller(conn *socket.Conn, peerRTCP netip.AddrPort, cfg Config) *Session

NewReceiverCaller builds a Simple-profile caller-receiver: a receiver that dials a listening sender instead of binding a well-known port. It is seeded with the sender's RTCP address (peerRTCP) and announces itself immediately and every keepalive interval; the listening sender learns this receiver from those Receiver Reports and starts streaming. conn is an ephemeral even/odd socket pair so the sender can infer this receiver's media port as its RTCP port − 1.

func NewSender

func NewSender(conn *socket.Conn, mediaAddr, rtcpAddr netip.AddrPort, cfg Config) *Session

NewSender builds a sender-role session that transmits RTP to mediaAddr and compound RTCP to rtcpAddr, and reads feedback on conn's RTCP socket.

func (*Session) Authenticated

func (s *Session) Authenticated() bool

Authenticated reports whether the data channel is open: true for a Simple session or a Main session without EAP, and for a Main+EAP session once the EAP-SRP handshake has succeeded. It is safe to call concurrently.

func (*Session) Close

func (s *Session) Close() error

Close shuts the session down: it stops the event loop and reader goroutines, closes the sockets, and waits for every goroutine to exit. It is idempotent and safe to call concurrently with Read/Write.

func (*Session) Err

func (s *Session) Err() error

Err returns the reason the session closed, or nil if it is still open.

func (*Session) MediaPort

func (s *Session) MediaPort() int

MediaPort returns the local media (even) UDP port.

func (*Session) Read

func (s *Session) Read(buf []byte) (int, error)

Read returns the next in-order, ARQ-recovered media payload (receiver role). It has stream semantics: a payload larger than buf is returned across successive calls. It blocks until data is available, the read deadline passes (ErrTimeout), or the session closes (ErrClosed, after any buffered payloads are drained).

Read is not safe to call from multiple goroutines concurrently.

func (*Session) ReadOOB

func (s *Session) ReadOOB(buf []byte) (int, error)

ReadOOB returns the next received out-of-band datagram (Main/Advanced only). Unlike Read it is datagram-oriented: each call returns exactly one OOB payload, truncated to len(buf). It returns ErrOOBUnsupported on the Simple profile, and blocks until an OOB datagram arrives, the read deadline passes (ErrTimeout), or the session closes (ErrClosed, after draining buffered OOB).

func (*Session) SetReadDeadline

func (s *Session) SetReadDeadline(t time.Time)

SetReadDeadline sets the deadline for Read; a zero time clears it. A pending Read is woken so it observes the new deadline.

func (*Session) SetWriteDeadline

func (s *Session) SetWriteDeadline(t time.Time)

SetWriteDeadline sets the deadline for Write; a zero time clears it. A pending Write is woken so it observes the new deadline.

func (*Session) Stats

func (s *Session) Stats() flow.Stats

Stats returns the most recent snapshot of the flow's counters.

func (*Session) Write

func (s *Session) Write(p []byte) error

Write enqueues one application payload for transmission (sender role). It copies p — the flow retains the payload in its retransmit history, so the caller may reuse its buffer once Write returns. It blocks until the payload is accepted by the event loop (back-pressure when the loop is saturated), the write deadline passes (ErrTimeout), or the session closes (ErrClosed).

Write is not safe to call from multiple goroutines concurrently.

func (*Session) WriteOOB

func (s *Session) WriteOOB(p []byte) error

WriteOOB enqueues one out-of-band datagram for transmission (Main/Advanced profiles only). OOB rides the same socket as media but bypasses ARQ entirely — fire-and-forget, like libRIST's rist_oob_write. It returns ErrOOBUnsupported when the session has no OOB channel (the Simple profile). It blocks under back-pressure, honoring the write deadline (ErrTimeout) and close (ErrClosed).

Jump to

Keyboard shortcuts

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