stack

package
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Jun 8, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package stack is the SIP/2.0 signaling layer for pkg/sip.

It provides:

  • Message parsing and serialization (RFC 3261–style text format)
  • UDP datagram transport abstraction
  • A minimal signaling Endpoint (listen, parse, dispatch requests; pass responses to a hook; optional OnResponseSent after a successful response send for UAS server-tx binding)

This package intentionally does not implement full SIP transaction state machines, digest authentication, or TCP/TLS transports yet; those belong in higher layers built on top of Message + Endpoint.

Design goals:

  • No process-wide mutable defaults; configure via structs and context.
  • Read loop returns on non-timeout transport errors (after optional OnReadError logging).
  • SIP wire parsing (Parse/String/BodyBytesLen) and UDP signaling live in this package.

Audio codecs for RTP live in pkg/media/encoder (CreateEncode/CreateDecode); stack does not implement codecs.

Index

Constants

View Source
const (
	// RFC 3261 core
	MethodInvite   = "INVITE"
	MethodAck      = "ACK"
	MethodBye      = "BYE"
	MethodCancel   = "CANCEL"
	MethodOptions  = "OPTIONS"
	MethodRegister = "REGISTER"
	// RFC 3262 reliable provisional responses
	MethodPrack = "PRACK"
	// RFC 3265 / 6665 event state; RFC 3856 presence
	MethodSubscribe = "SUBSCRIBE"
	MethodNotify    = "NOTIFY"
	MethodPublish   = "PUBLISH"
	// RFC 6086 session-info; RFC 3515 transfer; RFC 3428 instant messages
	MethodInfo    = "INFO"
	MethodRefer   = "REFER"
	MethodMessage = "MESSAGE"
	// RFC 3311 mid-dialog parameter refresh
	MethodUpdate = "UPDATE"
)

SIP method names (RFC 3261 and common extensions), upper-case as on the wire.

IANA registry: https://www.iana.org/assignments/sip-methods/sip-methods.xhtml Not every deployment uses all of these; stack only needs constants for registration and builders.

Variables

This section is empty.

Functions

func BodyBytesLen

func BodyBytesLen(body string) int

BodyBytesLen returns the byte length of the body after CRLF normalization.

func IsSignalingNoiseDatagram

func IsSignalingNoiseDatagram(b []byte) bool

IsSignalingNoiseDatagram reports payloads that are never valid SIP but often hit a UDP signaling port: NAT / CRLF keepalives (e.g. "\r\n\r\n", RFC 5626 style), or whitespace-only pings. Parsing them yields "empty message" noise; callers may skip them silently.

func ParseCSeqNum

func ParseCSeqNum(cseq string) int

ParseCSeqNum returns the sequence number from a CSeq header value (e.g. "1 INVITE" -> 1).

func ParseRAck

func ParseRAck(h string) (rseq uint32, cseqNum int, method string, err error)

ParseRAck parses RAck header value (RFC 3262): "<rseq> <cseq-num> <method>"

func WithCSeqACK

func WithCSeqACK(inviteCSeq int) string

WithCSeqACK returns a CSeq header value for ACK matching an INVITE CSeq number.

Types

type DatagramTransport

type DatagramTransport interface {
	ReadFrom(ctx context.Context, buf []byte) (n int, addr *net.UDPAddr, err error)
	WriteTo(ctx context.Context, p []byte, addr *net.UDPAddr) (n int, err error)
	Close() error
	LocalAddr() net.Addr
	String() string
}

DatagramTransport is SIP message I/O over connectionless datagrams. Implementations must be safe for use from one reader and concurrent writers unless documented otherwise.

type Endpoint

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

Endpoint listens for SIP over UDP, parses datagrams, and dispatches requests. It provides context-aware Serve and non-timeout read errors exiting the loop (after optional OnReadError).

func NewEndpoint

func NewEndpoint(cfg EndpointConfig) *Endpoint

NewEndpoint constructs an endpoint. Call Open then Serve.

func (*Endpoint) AppendOnResponseSent

func (e *Endpoint) AppendOnResponseSent(fn func(*Message, *Message, *net.UDPAddr))

AppendOnResponseSent chains fn after the existing OnResponseSent callback. Call before Serve starts, or only from the setup goroutine (not concurrently with the read loop).

func (*Endpoint) Close

func (e *Endpoint) Close() error

Close closes the listen socket and unblocks Serve.

func (*Endpoint) DispatchRequest

func (e *Endpoint) DispatchRequest(req *Message, addr *net.UDPAddr) *Message

DispatchRequest runs the registered method handler (or NoRouteHandler) without sending on UDP. Used by alternate transports (e.g. TCP/TLS) that write responses themselves.

func (*Endpoint) InvokeOnSIPResponse

func (e *Endpoint) InvokeOnSIPResponse(resp *Message, addr *net.UDPAddr)

InvokeOnSIPResponse calls the configured OnSIPResponse hook (e.g. for responses received on TCP).

func (*Endpoint) ListenAddr

func (e *Endpoint) ListenAddr() net.Addr

ListenAddr returns the bound UDP address after Open, or nil.

func (*Endpoint) Open

func (e *Endpoint) Open() error

Open binds the UDP listen socket.

func (*Endpoint) RegisterHandler

func (e *Endpoint) RegisterHandler(method string, h HandlerFunc)

RegisterHandler registers a SIP method handler (method is case-insensitive).

func (*Endpoint) Send

func (e *Endpoint) Send(msg *Message, addr *net.UDPAddr) error

Send writes a SIP message to addr using the bound UDP socket.

func (*Endpoint) Serve

func (e *Endpoint) Serve(ctx context.Context) error

Serve runs the read/dispatch loop until ctx is cancelled, Close is called, or a non-timeout read error occurs (then returns a wrapped error after optional OnReadError). It returns ctx.Err() when the context was cancelled before a read completes.

func (*Endpoint) SetNoRouteHandler

func (e *Endpoint) SetNoRouteHandler(h HandlerFunc)

SetNoRouteHandler sets the fallback handler for unknown methods (same as EndpointConfig.NoRouteHandler).

func (*Endpoint) Transport

func (e *Endpoint) Transport() DatagramTransport

Transport returns the datagram transport after Open, or nil.

type EndpointConfig

type EndpointConfig struct {
	// Host and Port are the listen address (UDP IPv4).
	Host string
	Port int

	ReadBufSize  int           // default 65535
	ReadDeadline time.Duration // per read; default 1s (poll + responsive shutdown)
	// OnReadError is called once for non-timeout read errors before Serve returns.
	OnReadError func(err error)
	OnDatagram  func(raw []byte, addr *net.UDPAddr)
	OnParseErr  func(raw []byte, addr *net.UDPAddr, err error)
	OnRequest   func(req *Message, addr *net.UDPAddr)
	OnResponse  func(req *Message, resp *Message, addr *net.UDPAddr)
	// OnResponseSent is invoked after a response has been successfully sent to addr (UAS final + server tx).
	OnResponseSent func(req *Message, resp *Message, addr *net.UDPAddr)
	OnSIPResponse  func(resp *Message, addr *net.UDPAddr)
	// OnMessageSent is invoked after a message is written to the UDP socket (requests and responses).
	OnMessageSent  func(msg *Message, addr *net.UDPAddr)
	OnEvent        func(e Event)
	NoRouteHandler HandlerFunc
}

EndpointConfig configures a UDP signaling Endpoint.

type Event

type Event struct {
	Type     EventType
	Addr     *net.UDPAddr
	Raw      []byte
	Request  *Message
	Response *Message
	Err      error
}

Event is a lightweight observation from the read loop.

func (Event) RequestMethod

func (e Event) RequestMethod() string

RequestMethod returns the SIP method for events that carry a request (e.g. EventRequestReceived). Empty string if Request is nil.

func (Event) ResponseStatus

func (e Event) ResponseStatus() int

ResponseStatus returns the SIP status code for events that carry a response (e.g. EventResponseReceived). Zero if Response is nil.

type EventType

type EventType int

EventType identifies Endpoint telemetry events.

const (
	EventDatagramReceived EventType = iota
	EventParseError
	EventRequestReceived
	EventResponseReceived
	EventResponseSent
)

type HandlerFunc

type HandlerFunc func(msg *Message, addr *net.UDPAddr) *Message

HandlerFunc handles an incoming SIP request and returns a response (or nil to send nothing).

type Message

type Message struct {
	Method       string
	RequestURI   string
	StatusCode   int
	StatusText   string
	Version      string
	Headers      map[string]string   // first value per canonical header name
	HeadersMulti map[string][]string // all values per canonical header name (e.g. Via)
	Body         string
	IsRequest    bool
}

Message is a parsed SIP message (request or response).

func Parse

func Parse(raw string) (*Message, error)

Parse parses a raw SIP message into a Message. Header lines use ":"; body follows the first empty line. CRLF and bare LF are accepted.

Header folding (RFC 3261 continuation lines) is not implemented; folded headers may parse incorrectly.

func ReadMessage

func ReadMessage(r *bufio.Reader) (*Message, error)

ReadMessage reads one SIP message from r using CRLF framing (Content-Length when body present).

func (*Message) AddHeader

func (m *Message) AddHeader(name, value string)

AddHeader appends a header value (multi-value headers such as Via).

func (*Message) GetHeader

func (m *Message) GetHeader(name string) string

GetHeader returns the first header value for name (case-insensitive).

func (*Message) GetHeaders

func (m *Message) GetHeaders(name string) []string

GetHeaders returns all values for a header name (case-insensitive).

func (*Message) SetHeader

func (m *Message) SetHeader(name, value string)

SetHeader replaces a header with a single value.

func (*Message) String

func (m *Message) String() string

String serializes the message to SIP wire format (CRLF line endings).

type UDPTransport

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

UDPTransport adapts *net.UDPConn to DatagramTransport.

func NewUDPTransport

func NewUDPTransport(conn *net.UDPConn) *UDPTransport

NewUDPTransport wraps an existing UDP connection.

func (*UDPTransport) Close

func (t *UDPTransport) Close() error

func (*UDPTransport) LocalAddr

func (t *UDPTransport) LocalAddr() net.Addr

func (*UDPTransport) ReadFrom

func (t *UDPTransport) ReadFrom(ctx context.Context, buf []byte) (int, *net.UDPAddr, error)

ReadFrom reads a datagram. If ctx is cancelled, returns ctx.Err() without blocking indefinitely (requires SetReadDeadline on the conn by the caller, or Endpoint sets deadlines each iteration).

func (*UDPTransport) String

func (t *UDPTransport) String() string

func (*UDPTransport) WriteTo

func (t *UDPTransport) WriteTo(ctx context.Context, p []byte, addr *net.UDPAddr) (int, error)

Jump to

Keyboard shortcuts

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