diff --git a/aurp/aurp.go b/aurp/aurp.go index 7947eae..21d13c9 100644 --- a/aurp/aurp.go +++ b/aurp/aurp.go @@ -190,10 +190,12 @@ func ParsePacket(p []byte) (Packet, error) { }, nil case CmdCodeRIRsp: - return &RIRspPacket{ - Header: h, - RTMPData: p, - }, nil + rir, err := parseRIRsp(p) + if err != nil { + return nil, err + } + rir.Header = h + return rir, nil case CmdCodeRIAck: return &RIAckPacket{ diff --git a/aurp/ri.go b/aurp/ri.go deleted file mode 100644 index 9ca655d..0000000 --- a/aurp/ri.go +++ /dev/null @@ -1,115 +0,0 @@ -package aurp - -import ( - "encoding/binary" - "fmt" - "io" -) - -type RIReqPacket struct { - *Header -} - -type RIRspPacket struct { - *Header - - RTMPData []byte -} - -func (p *RIRspPacket) WriteTo(w io.Writer) (int64, error) { - a := acc(w) - a.writeTo(p.Header) - a.write(p.RTMPData) - return a.ret() -} - -type RIAckPacket struct { - *Header -} - -type RIUpdPacket struct { - *Header - - Events Events -} - -func (p *RIUpdPacket) WriteTo(w io.Writer) (int64, error) { - a := acc(w) - a.writeTo(p.Header) - a.writeTo(p.Events) - return a.ret() -} - -func parseRIUpd(p []byte) (*RIUpdPacket, error) { - var e Events - for len(p) > 0 { - et, nextp, err := parseEventTuple(p) - if err != nil { - return nil, fmt.Errorf("parsing event tuple %d: %w", len(e), err) - } - e = append(e, et) - p = nextp - } - return &RIUpdPacket{ - Events: e, - }, nil -} - -type Events []EventTuple - -func (e Events) WriteTo(w io.Writer) (int64, error) { - a := acc(w) - for _, et := range e { - a.writeTo(&et) - } - return a.ret() -} - -type EventTuple struct { - EventCode EventCode - RangeStart uint16 // or simply the network number - Distance uint8 - RangeEnd uint16 -} - -func (et *EventTuple) WriteTo(w io.Writer) (int64, error) { - a := acc(w) - a.write8(uint8(et.EventCode)) - a.write16(et.RangeStart) - a.write8(et.Distance) - if et.Distance&0x80 != 0 { // extended tuple - a.write16(et.RangeEnd) - } - return a.ret() -} - -func parseEventTuple(p []byte) (EventTuple, []byte, error) { - if len(p) < 4 { - return EventTuple{}, p, fmt.Errorf("insufficient input length %d for network event tuple", len(p)) - } - - var et EventTuple - et.EventCode = EventCode(p[0]) - et.RangeStart = binary.BigEndian.Uint16(p[1:3]) - et.Distance = p[3] - if et.Distance&0x80 == 0 { - return et, p[4:], nil - } - - if len(p) < 6 { - return EventTuple{}, p, fmt.Errorf("insufficient input length %d for extended network event tuple", len(p)) - } - et.RangeEnd = binary.BigEndian.Uint16(p[4:6]) - return et, p[6:], nil -} - -type EventCode uint8 - -const ( - EventCodeNull EventCode = 0 - EventCodeNA EventCode = 1 - EventCodeND EventCode = 2 - EventCodeNRC EventCode = 3 - EventCodeNDC EventCode = 4 - EventCodeZC EventCode = 5 -) diff --git a/aurp/route_info.go b/aurp/route_info.go new file mode 100644 index 0000000..2faa239 --- /dev/null +++ b/aurp/route_info.go @@ -0,0 +1,213 @@ +package aurp + +import ( + "encoding/binary" + "fmt" + "io" +) + +type RIReqPacket struct { + *Header +} + +type RIRspPacket struct { + *Header + + Networks NetworkTuples +} + +func (p *RIRspPacket) WriteTo(w io.Writer) (int64, error) { + a := acc(w) + a.writeTo(p.Header) + a.writeTo(p.Networks) + return a.ret() +} + +func parseRIRsp(p []byte) (*RIRspPacket, error) { + n, err := parseNetworkTuples(p) + if err != nil { + return nil, err + } + return &RIRspPacket{ + Networks: n, + }, nil +} + +type RIAckPacket struct { + *Header +} + +type RIUpdPacket struct { + *Header + + Events EventTuples +} + +func (p *RIUpdPacket) WriteTo(w io.Writer) (int64, error) { + a := acc(w) + a.writeTo(p.Header) + a.writeTo(p.Events) + return a.ret() +} + +func parseRIUpd(p []byte) (*RIUpdPacket, error) { + e, err := parseEventTuples(p) + if err != nil { + return nil, err + } + return &RIUpdPacket{ + Events: e, + }, nil +} + +type NetworkTuples []NetworkTuple + +func (n NetworkTuples) WriteTo(w io.Writer) (int64, error) { + a := acc(w) + for _, nt := range n { + a.writeTo(&nt) + } + return a.ret() +} + +func parseNetworkTuples(p []byte) (NetworkTuples, error) { + // Each network tuple is at least 3 bytes, so we need to store at most + // len(p)/3 of them. + n := make(NetworkTuples, 0, len(p)/3) + for len(p) > 0 { + nt, nextp, err := parseNetworkTuple(p) + if err != nil { + return nil, fmt.Errorf("parsing network tuple %d: %w", len(n), err) + } + n = append(n, nt) + p = nextp + } + return n, nil +} + +type NetworkTuple struct { + RangeStart uint16 + Distance uint8 + RangeEnd uint16 + // 0x00 for extended tuples +} + +func (nt *NetworkTuple) WriteTo(w io.Writer) (int64, error) { + a := acc(w) + a.write16(nt.RangeStart) + if nt.RangeStart == nt.RangeEnd { + // non-extended tuple + a.write8(nt.Distance) + return a.ret() + } + // extended tuple + a.write8(nt.Distance | 0x80) + a.write16(nt.RangeEnd) + a.write8(0x00) + return a.ret() +} + +func parseNetworkTuple(p []byte) (NetworkTuple, []byte, error) { + if len(p) < 3 { + return NetworkTuple{}, p, fmt.Errorf("insufficient input length %d for network tuple", len(p)) + } + + var nt NetworkTuple + nt.RangeStart = binary.BigEndian.Uint16(p[:2]) + nt.RangeEnd = nt.RangeStart + nt.Distance = p[2] + + if nt.Distance&0x80 == 0 { + return nt, p[3:], nil + } + + if len(p) < 6 { + return NetworkTuple{}, p, fmt.Errorf("insufficient input length %d for extended network tuple", len(p)) + } + + nt.Distance &^= 0x80 + nt.RangeEnd = binary.BigEndian.Uint16(p[3:5]) + return nt, p[6:], nil +} + +type EventTuples []EventTuple + +func (e EventTuples) WriteTo(w io.Writer) (int64, error) { + a := acc(w) + for _, et := range e { + a.writeTo(&et) + } + return a.ret() +} + +func parseEventTuples(p []byte) (EventTuples, error) { + // Each event tuple is at least 4 bytes, so we need to store at most + // len(p)/4 of them. + e := make(EventTuples, 0, len(p)/4) + for len(p) > 0 { + et, nextp, err := parseEventTuple(p) + if err != nil { + return nil, fmt.Errorf("parsing event tuple %d: %w", len(e), err) + } + e = append(e, et) + p = nextp + } + return e, nil +} + +type EventTuple struct { + EventCode EventCode + RangeStart uint16 + Distance uint8 + RangeEnd uint16 +} + +func (et *EventTuple) WriteTo(w io.Writer) (int64, error) { + a := acc(w) + a.write8(uint8(et.EventCode)) + a.write16(et.RangeStart) + if et.RangeStart == et.RangeEnd { + // non-extended tuple + a.write8(et.Distance) + return a.ret() + } + // extended tuple + a.write8(et.Distance | 0x80) + a.write16(et.RangeEnd) + return a.ret() +} + +func parseEventTuple(p []byte) (EventTuple, []byte, error) { + if len(p) < 4 { + return EventTuple{}, p, fmt.Errorf("insufficient input length %d for network event tuple", len(p)) + } + + var et EventTuple + et.EventCode = EventCode(p[0]) + et.RangeStart = binary.BigEndian.Uint16(p[1:3]) + et.RangeEnd = et.RangeStart + et.Distance = p[3] + + if et.Distance&0x80 == 0 { + return et, p[4:], nil + } + + if len(p) < 6 { + return EventTuple{}, p, fmt.Errorf("insufficient input length %d for extended network event tuple", len(p)) + } + + et.Distance &^= 0x80 + et.RangeEnd = binary.BigEndian.Uint16(p[4:6]) + return et, p[6:], nil +} + +type EventCode uint8 + +const ( + EventCodeNull EventCode = 0 + EventCodeNA EventCode = 1 + EventCodeND EventCode = 2 + EventCodeNRC EventCode = 3 + EventCodeNDC EventCode = 4 + EventCodeZC EventCode = 5 +)