133 lines
2.7 KiB
Go
133 lines
2.7 KiB
Go
package controlmessage
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/bluenviron/mediamtx/internal/protocols/moq/varint"
|
|
)
|
|
|
|
const typeSetup varint.Varint = 0x2F00
|
|
|
|
const (
|
|
setupOptionPath varint.Varint = 0x01
|
|
setupOptionAuthority varint.Varint = 0x05
|
|
)
|
|
|
|
// Setup is the SETUP control message.
|
|
// spec:
|
|
// * draft-17, section 9.4
|
|
// * draft-18/19, section 10.3
|
|
type Setup struct {
|
|
Path string
|
|
Authority string
|
|
}
|
|
|
|
func (*Setup) isMessage() {}
|
|
|
|
func (m *Setup) unmarshal(buf []byte) error {
|
|
var previousType uint64
|
|
for len(buf) > 0 {
|
|
var deltaType varint.Varint
|
|
n, err := deltaType.Unmarshal(buf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buf = buf[n:]
|
|
|
|
currentType := previousType + uint64(deltaType)
|
|
previousType = currentType
|
|
|
|
if currentType%2 == 0 { // even type: single varint value
|
|
var v varint.Varint
|
|
n, err = v.Unmarshal(buf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buf = buf[n:]
|
|
continue
|
|
}
|
|
|
|
// odd type: length-prefixed byte field
|
|
var l varint.Varint
|
|
n, err = l.Unmarshal(buf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buf = buf[n:]
|
|
|
|
if uint64(len(buf)) < uint64(l) {
|
|
return fmt.Errorf("not enough bytes for setup option")
|
|
}
|
|
|
|
value := string(buf[:int(l)])
|
|
buf = buf[int(l):]
|
|
|
|
switch varint.Varint(currentType) {
|
|
case setupOptionPath:
|
|
m.Path = value
|
|
|
|
case setupOptionAuthority:
|
|
m.Authority = value
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m Setup) marshalSize(t varint.Varint) int {
|
|
payloadSize := 0
|
|
var previousType varint.Varint
|
|
|
|
if m.Path != "" {
|
|
delta := setupOptionPath - previousType
|
|
payloadSize += delta.MarshalSize() +
|
|
varint.Varint(len(m.Path)).MarshalSize() +
|
|
len(m.Path)
|
|
previousType = setupOptionPath
|
|
}
|
|
|
|
if m.Authority != "" {
|
|
delta := setupOptionAuthority - previousType
|
|
payloadSize += delta.MarshalSize() +
|
|
varint.Varint(len(m.Authority)).MarshalSize() +
|
|
len(m.Authority)
|
|
}
|
|
|
|
return t.MarshalSize() + 2 + payloadSize
|
|
}
|
|
|
|
func (m Setup) marshalTo(buf []byte, t varint.Varint) int {
|
|
payloadSize := m.marshalSize(t) - t.MarshalSize() - 2
|
|
|
|
pos := t.MarshalTo(buf)
|
|
buf[pos] = byte(payloadSize >> 8)
|
|
buf[pos+1] = byte(payloadSize)
|
|
pos += 2
|
|
|
|
var previousType varint.Varint
|
|
|
|
if m.Path != "" {
|
|
delta := setupOptionPath - previousType
|
|
pos += delta.MarshalTo(buf[pos:])
|
|
pos += varint.Varint(len(m.Path)).MarshalTo(buf[pos:])
|
|
pos += copy(buf[pos:], m.Path)
|
|
previousType = setupOptionPath
|
|
}
|
|
|
|
if m.Authority != "" {
|
|
delta := setupOptionAuthority - previousType
|
|
pos += delta.MarshalTo(buf[pos:])
|
|
pos += varint.Varint(len(m.Authority)).MarshalTo(buf[pos:])
|
|
pos += copy(buf[pos:], m.Authority)
|
|
}
|
|
|
|
return pos
|
|
}
|
|
|
|
// Marshal implements Message.
|
|
func (m Setup) Marshal() []byte {
|
|
buf := make([]byte, m.marshalSize(typeSetup))
|
|
m.marshalTo(buf, typeSetup)
|
|
return buf
|
|
}
|