jrouter/atalk/rtmp/data.go

89 lines
2.3 KiB
Go

package rtmp
import (
"encoding/binary"
"fmt"
"github.com/sfiera/multitalk/pkg/ddp"
)
// DataPacket represents an RTMP Data packet.
type DataPacket struct {
RouterAddr ddp.Addr
NetworkTuples []NetworkTuple
}
// NetworkTuple represents routing information.
type NetworkTuple struct {
Extended bool
RangeStart ddp.Network
RangeEnd ddp.Network
Distance uint8
}
// UnmarshalDataPacket unmarshals a DataPacket.
func UnmarshalDataPacket(data []byte) (*DataPacket, error) {
if len(data) < 7 || (len(data)-4)%3 != 0 {
return nil, fmt.Errorf("invalid input length %d for RTMP Data packet", len(data))
}
if data[2] != 8 {
return nil, fmt.Errorf("unsupported node ID length %d for RTMP Data packet", data[2])
}
dp := &DataPacket{
RouterAddr: ddp.Addr{
Network: ddp.Network(binary.BigEndian.Uint16(data[:2])),
Node: ddp.Node(data[3]),
},
}
data = data[4:]
first := true
for len(data) > 0 {
if len(data) < 3 {
return nil, fmt.Errorf("insufficient remaining input length %d for RTMP Data network tuple", len(data))
}
nt := NetworkTuple{
RangeStart: ddp.Network(binary.BigEndian.Uint16(data[:2])),
Distance: data[2],
}
data = data[3:]
if nt.RangeStart == 0 {
// if non-extended, first tuple should contain version
if !first {
return nil, fmt.Errorf("invalid RTMP network tuple range start 0")
}
// initial non-extended tuple with Distance field containing version
if nt.Distance != 0x82 {
return nil, fmt.Errorf("unsupported RTMP version %x", nt.Distance)
}
first = false
continue
}
nt.Extended = nt.Distance&0x80 != 0
if !nt.Extended {
// ordinary non-extended tuple
if first && nt.RangeStart != 0 {
return nil, fmt.Errorf("first RTMP network tuple is not version tuple")
}
dp.NetworkTuples = append(dp.NetworkTuples, nt)
continue
}
// extended tuple
if len(data) < 3 {
return nil, fmt.Errorf("insufficient remaining input length %d for RTMP Data extended network tuple", len(data))
}
nt.Distance &^= 0x80
nt.RangeEnd = ddp.Network(binary.BigEndian.Uint16(data[:2]))
if first {
if data[2] != 0x82 {
return nil, fmt.Errorf("unsupported RTMP version %x", data[2])
}
}
first = false
dp.NetworkTuples = append(dp.NetworkTuples, nt)
data = data[3:]
}
return dp, nil
}