diff --git a/aurp/aurp.go b/aurp/aurp.go index 036d620..91aedf1 100644 --- a/aurp/aurp.go +++ b/aurp/aurp.go @@ -424,6 +424,93 @@ 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 +) + // ParsePacket parses the body of a UDP packet for a domain header, and then // based on the packet type, an AURP-Tr header, an AURP routing header, and // then a particular packet type. @@ -489,6 +576,14 @@ func ParsePacket(p []byte) (Packet, error) { Header: h, }, nil + case CmdCodeRIUpd: + riu, err := parseRIUpd(p) + if err != nil { + return nil, err + } + riu.Header = h + return riu, nil + default: return nil, fmt.Errorf("unknown routing packet command code %d", h.CommandCode) }