Send multiple RTMP data packets when routing table is big
This commit is contained in:
parent
52b08a83f1
commit
208b273bd1
2 changed files with 96 additions and 64 deletions
|
@ -39,6 +39,14 @@ type NetworkTuple struct {
|
||||||
Distance uint8
|
Distance uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nt *NetworkTuple) Size() int {
|
||||||
|
if nt.Extended {
|
||||||
|
return 6
|
||||||
|
} else {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Marshal marshals an RTMP Data packet.
|
// Marshal marshals an RTMP Data packet.
|
||||||
func (dp *DataPacket) Marshal() ([]byte, error) {
|
func (dp *DataPacket) Marshal() ([]byte, error) {
|
||||||
b := bytes.NewBuffer(nil)
|
b := bytes.NewBuffer(nil)
|
||||||
|
|
152
router/rtmp.go
152
router/rtmp.go
|
@ -118,37 +118,38 @@ func (m *RTMPMachine) Run(ctx context.Context, incomingCh <-chan *ddp.ExtPacket)
|
||||||
case 2, 3:
|
case 2, 3:
|
||||||
// Like the Data broadcast, but solicited by a request (RDR).
|
// Like the Data broadcast, but solicited by a request (RDR).
|
||||||
// TODO: handle split-horizon processing
|
// TODO: handle split-horizon processing
|
||||||
dataPkt := m.dataPacket(myAddr.Proto)
|
for _, dataPkt := range m.dataPackets(myAddr.Proto) {
|
||||||
|
dataPktRaw, err := dataPkt.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("RTMP: Couldn't marshal Data packet: %v", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
dataPktRaw, err := dataPkt.Marshal()
|
ddpPkt := &ddp.ExtPacket{
|
||||||
if err != nil {
|
ExtHeader: ddp.ExtHeader{
|
||||||
log.Printf("RTMP: Couldn't marshal Data packet: %v", err)
|
Size: uint16(len(dataPktRaw)) + atalk.DDPExtHeaderSize,
|
||||||
continue
|
Cksum: 0,
|
||||||
}
|
DstNet: pkt.SrcNet,
|
||||||
|
DstNode: pkt.SrcNode,
|
||||||
|
DstSocket: 1, // the RTMP socket
|
||||||
|
SrcNet: myAddr.Proto.Network,
|
||||||
|
SrcNode: myAddr.Proto.Node,
|
||||||
|
SrcSocket: 1, // the RTMP socket
|
||||||
|
Proto: ddp.ProtoRTMPResp,
|
||||||
|
},
|
||||||
|
Data: dataPktRaw,
|
||||||
|
}
|
||||||
|
|
||||||
ddpPkt := &ddp.ExtPacket{
|
if err := m.send(myAddr.Hardware, theirHWAddr, ddpPkt); err != nil {
|
||||||
ExtHeader: ddp.ExtHeader{
|
log.Printf("RTMP: Couldn't send Data response: %v", err)
|
||||||
Size: uint16(len(dataPktRaw)) + atalk.DDPExtHeaderSize,
|
break
|
||||||
Cksum: 0,
|
}
|
||||||
DstNet: pkt.SrcNet,
|
|
||||||
DstNode: pkt.SrcNode,
|
|
||||||
DstSocket: 1, // the RTMP socket
|
|
||||||
SrcNet: myAddr.Proto.Network,
|
|
||||||
SrcNode: myAddr.Proto.Node,
|
|
||||||
SrcSocket: 1, // the RTMP socket
|
|
||||||
Proto: ddp.ProtoRTMPResp,
|
|
||||||
},
|
|
||||||
Data: dataPktRaw,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := m.send(myAddr.Hardware, theirHWAddr, ddpPkt); err != nil {
|
|
||||||
log.Printf("RTMP: Couldn't send Data response: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case ddp.ProtoRTMPResp:
|
case ddp.ProtoRTMPResp:
|
||||||
// It's a peer router on the AppleTalk network!
|
// It's a peer router on the AppleTalk network!
|
||||||
// TODO: integrate this information with the routing table
|
// TODO: integrate this information with the routing table?
|
||||||
log.Print("RTMP: Got Response or Data")
|
log.Print("RTMP: Got Response or Data")
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -174,54 +175,77 @@ func (m *RTMPMachine) send(src, dst ethernet.Addr, ddpPkt *ddp.ExtPacket) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *RTMPMachine) broadcastData(myAddr aarp.AddrPair) error {
|
func (m *RTMPMachine) broadcastData(myAddr aarp.AddrPair) error {
|
||||||
dataPkt := m.dataPacket(myAddr.Proto)
|
for _, dataPkt := range m.dataPackets(myAddr.Proto) {
|
||||||
|
dataPktRaw, err := dataPkt.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("marshal Data packet: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
dataPktRaw, err := dataPkt.Marshal()
|
ddpPkt := &ddp.ExtPacket{
|
||||||
if err != nil {
|
ExtHeader: ddp.ExtHeader{
|
||||||
return fmt.Errorf("marshal Data packet: %v", err)
|
Size: uint16(len(dataPktRaw)) + atalk.DDPExtHeaderSize,
|
||||||
|
Cksum: 0,
|
||||||
|
DstNet: 0, // this network
|
||||||
|
DstNode: 0xff, // broadcast packet
|
||||||
|
DstSocket: 1, // the RTMP socket
|
||||||
|
SrcNet: myAddr.Proto.Network,
|
||||||
|
SrcNode: myAddr.Proto.Node,
|
||||||
|
SrcSocket: 1, // the RTMP socket
|
||||||
|
Proto: ddp.ProtoRTMPResp,
|
||||||
|
},
|
||||||
|
Data: dataPktRaw,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.send(myAddr.Hardware, ethertalk.AppleTalkBroadcast, ddpPkt); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
ddpPkt := &ddp.ExtPacket{
|
|
||||||
ExtHeader: ddp.ExtHeader{
|
|
||||||
Size: uint16(len(dataPktRaw)) + atalk.DDPExtHeaderSize,
|
|
||||||
Cksum: 0,
|
|
||||||
DstNet: 0, // this network
|
|
||||||
DstNode: 0xff, // broadcast packet
|
|
||||||
DstSocket: 1, // the RTMP socket
|
|
||||||
SrcNet: myAddr.Proto.Network,
|
|
||||||
SrcNode: myAddr.Proto.Node,
|
|
||||||
SrcSocket: 1, // the RTMP socket
|
|
||||||
Proto: ddp.ProtoRTMPResp,
|
|
||||||
},
|
|
||||||
Data: dataPktRaw,
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.send(myAddr.Hardware, ethertalk.AppleTalkBroadcast, ddpPkt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *RTMPMachine) dataPacket(myAddr ddp.Addr) *rtmp.DataPacket {
|
func (m *RTMPMachine) dataPackets(myAddr ddp.Addr) []*rtmp.DataPacket {
|
||||||
p := &rtmp.DataPacket{
|
// Build up a slice of routing tuples.
|
||||||
RouterAddr: myAddr,
|
routes := m.RoutingTable.ValidRoutes()
|
||||||
Extended: true,
|
tuples := make([]rtmp.NetworkTuple, 0, len(routes))
|
||||||
NetworkTuples: []rtmp.NetworkTuple{
|
for _, rt := range routes {
|
||||||
// "The first tuple in RTMP Data packets sent on extended
|
tuples = append(tuples, rtmp.NetworkTuple{
|
||||||
// networks ... indicates the network number range assigned
|
|
||||||
// to that network."
|
|
||||||
{
|
|
||||||
Extended: true,
|
|
||||||
RangeStart: m.Config.EtherTalk.NetStart,
|
|
||||||
RangeEnd: m.Config.EtherTalk.NetEnd,
|
|
||||||
Distance: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, rt := range m.RoutingTable.ValidRoutes() {
|
|
||||||
p.NetworkTuples = append(p.NetworkTuples, rtmp.NetworkTuple{
|
|
||||||
Extended: rt.Extended,
|
Extended: rt.Extended,
|
||||||
RangeStart: rt.NetStart,
|
RangeStart: rt.NetStart,
|
||||||
RangeEnd: rt.NetEnd,
|
RangeEnd: rt.NetEnd,
|
||||||
Distance: rt.Distance + 1,
|
Distance: rt.Distance + 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return p
|
// "The first tuple in RTMP Data packets sent on extended
|
||||||
|
// networks ... indicates the network number range assigned
|
||||||
|
// to that network."
|
||||||
|
// TODO: support non-extended local networks (LocalTalk)
|
||||||
|
first := rtmp.NetworkTuple{
|
||||||
|
Extended: true,
|
||||||
|
RangeStart: m.Config.EtherTalk.NetStart,
|
||||||
|
RangeEnd: m.Config.EtherTalk.NetEnd,
|
||||||
|
Distance: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
var packets []*rtmp.DataPacket
|
||||||
|
rem := tuples
|
||||||
|
for len(rem) > 0 {
|
||||||
|
chunk := []rtmp.NetworkTuple{first}
|
||||||
|
|
||||||
|
size := 10 // router network + 1 + router node ID + first tuple
|
||||||
|
for _, nt := range rem {
|
||||||
|
size += nt.Size()
|
||||||
|
if size > atalk.DDPMaxDataSize {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
chunk = append(chunk, nt)
|
||||||
|
}
|
||||||
|
rem = rem[len(chunk)-1:]
|
||||||
|
|
||||||
|
packets = append(packets, &rtmp.DataPacket{
|
||||||
|
RouterAddr: myAddr,
|
||||||
|
Extended: true,
|
||||||
|
NetworkTuples: chunk,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return packets
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue