From 5790b9d61675eacd0fcfd21069ba583b9b953dc7 Mon Sep 17 00:00:00 2001 From: Josh Deprez Date: Fri, 26 Apr 2024 16:15:02 +1000 Subject: [PATCH] Use data in RI-Upds, add peer table to status --- aurp/routing_info.go | 72 +++++++---- main.go | 70 ++++++++--- router/peer.go | 284 +++++++++++++++++++++++++++++-------------- router/route.go | 30 ++++- router/rtmp.go | 2 + 5 files changed, 321 insertions(+), 137 deletions(-) diff --git a/aurp/routing_info.go b/aurp/routing_info.go index fa63626..ffbf616 100644 --- a/aurp/routing_info.go +++ b/aurp/routing_info.go @@ -21,6 +21,8 @@ import ( "fmt" "io" "strings" + + "github.com/sfiera/multitalk/pkg/ddp" ) type RIReqPacket struct { @@ -115,15 +117,15 @@ func parseNetworkTuples(p []byte) (NetworkTuples, error) { type NetworkTuple struct { Extended bool - RangeStart uint16 + RangeStart ddp.Network Distance uint8 - RangeEnd uint16 + RangeEnd ddp.Network // 0x00 for extended tuples } func (nt *NetworkTuple) WriteTo(w io.Writer) (int64, error) { a := acc(w) - a.write16(nt.RangeStart) + a.write16(uint16(nt.RangeStart)) if !nt.Extended { // non-extended tuple a.write8(nt.Distance) @@ -131,7 +133,7 @@ func (nt *NetworkTuple) WriteTo(w io.Writer) (int64, error) { } // extended tuple a.write8(nt.Distance | 0x80) - a.write16(nt.RangeEnd) + a.write16(uint16(nt.RangeEnd)) a.write8(0x00) return a.ret() } @@ -142,7 +144,7 @@ func parseNetworkTuple(p []byte) (NetworkTuple, []byte, error) { } var nt NetworkTuple - nt.RangeStart = binary.BigEndian.Uint16(p[:2]) + nt.RangeStart = ddp.Network(binary.BigEndian.Uint16(p[:2])) nt.RangeEnd = nt.RangeStart nt.Distance = p[2] nt.Extended = nt.Distance&0x80 != 0 @@ -156,7 +158,7 @@ func parseNetworkTuple(p []byte) (NetworkTuple, []byte, error) { } nt.Distance &^= 0x80 - nt.RangeEnd = binary.BigEndian.Uint16(p[3:5]) + nt.RangeEnd = ddp.Network(binary.BigEndian.Uint16(p[3:5])) return nt, p[6:], nil } @@ -188,15 +190,15 @@ func parseEventTuples(p []byte) (EventTuples, error) { type EventTuple struct { EventCode EventCode Extended bool - RangeStart uint16 + RangeStart ddp.Network Distance uint8 - RangeEnd uint16 + RangeEnd ddp.Network } func (et *EventTuple) WriteTo(w io.Writer) (int64, error) { a := acc(w) a.write8(uint8(et.EventCode)) - a.write16(et.RangeStart) + a.write16(uint16(et.RangeStart)) if !et.Extended { // non-extended tuple a.write8(et.Distance) @@ -204,7 +206,7 @@ func (et *EventTuple) WriteTo(w io.Writer) (int64, error) { } // extended tuple a.write8(et.Distance | 0x80) - a.write16(et.RangeEnd) + a.write16(uint16(et.RangeEnd)) return a.ret() } @@ -215,7 +217,7 @@ func parseEventTuple(p []byte) (EventTuple, []byte, error) { var et EventTuple et.EventCode = EventCode(p[0]) - et.RangeStart = binary.BigEndian.Uint16(p[1:3]) + et.RangeStart = ddp.Network(binary.BigEndian.Uint16(p[1:3])) et.RangeEnd = et.RangeStart et.Distance = p[3] et.Extended = et.Distance&0x80 != 0 @@ -229,28 +231,48 @@ func parseEventTuple(p []byte) (EventTuple, []byte, error) { } et.Distance &^= 0x80 - et.RangeEnd = binary.BigEndian.Uint16(p[4:6]) + et.RangeEnd = ddp.Network(binary.BigEndian.Uint16(p[4:6])) return et, p[6:], nil } type EventCode uint8 const ( + // Null event EventCodeNull EventCode = 0 - EventCodeNA EventCode = 1 - EventCodeND EventCode = 2 - EventCodeNRC EventCode = 3 - EventCodeNDC EventCode = 4 - EventCodeZC EventCode = 5 + + // Network added event + EventCodeNA EventCode = 1 + + // Network deleted event + EventCodeND EventCode = 2 + + // Network route change event + EventCodeNRC EventCode = 3 + + // Network distance change event + EventCodeNDC EventCode = 4 + + // Network zone change event + // Note: "The ZC event tuple is not yet defined." + EventCodeZC EventCode = 5 ) func (ec EventCode) String() string { - return map[EventCode]string{ - EventCodeNull: "null", - EventCodeNA: "network added", - EventCodeND: "network deleted", - EventCodeNRC: "network route change", - EventCodeNDC: "network distance change", - EventCodeZC: "zone name change", - }[ec] + switch ec { + case EventCodeNull: + return "null" + case EventCodeNA: + return "network added" + case EventCodeND: + return "network deleted" + case EventCodeNRC: + return "network route change" + case EventCodeNDC: + return "network distance change" + case EventCodeZC: + return "zone name change" + default: + return "unknown" + } } diff --git a/main.go b/main.go index f0eae76..08dcdd1 100644 --- a/main.go +++ b/main.go @@ -91,6 +91,27 @@ const zoneTableTemplate = ` ` +const peerTableTemplate = ` + + + + + + + + +{{range $peer := . }} + + + + + + +{{end}} + +
Configured addrRemote addrReceiver stateSender state
{{$peer.ConfiguredAddr}}{{$peer.RemoteAddr}}{{$peer.ReceiverState}}{{$peer.SenderState}}
+` + var hasPortRE = regexp.MustCompile(`:\d+$`) var configFilePath = flag.String("config", "jrouter.yaml", "Path to configuration file to use") @@ -136,12 +157,6 @@ func main() { log.Printf("EtherTalk configuration: %+v", cfg.EtherTalk) - peers := make(map[udpAddr]*router.Peer) - var nextConnID uint16 - for nextConnID == 0 { - nextConnID = uint16(rand.IntN(0x10000)) - } - ln, err := net.ListenUDP("udp4", &net.UDPAddr{Port: int(cfg.ListenPort)}) if err != nil { log.Fatalf("Couldn't listen on udp4:387: %v", err) @@ -208,6 +223,23 @@ func main() { }) // -------------------------------- Peers --------------------------------- + var peersMu sync.Mutex + peers := make(map[udpAddr]*router.Peer) + status.AddItem(ctx, "AURP Peers", peerTableTemplate, func(context.Context) (any, error) { + peersMu.Lock() + peerInfo := make([]*router.Peer, 0, len(peers)) + for _, p := range peers { + peerInfo = append(peerInfo, p) + } + peersMu.Unlock() + return peerInfo, nil + }) + + var nextConnID uint16 + for nextConnID == 0 { + nextConnID = uint16(rand.IntN(0x10000)) + } + var wg sync.WaitGroup goPeerHandler := func(p *router.Peer) { wg.Add(1) @@ -267,15 +299,17 @@ func main() { RemoteDI: aurp.IPDomainIdentifier(raddr.IP), LocalConnID: nextConnID, }, - UDPConn: ln, - RemoteAddr: raddr, - RecieveCh: make(chan aurp.Packet, 1024), - RoutingTable: routes, - ZoneTable: zones, - Reconnect: true, + UDPConn: ln, + ConfiguredAddr: peerStr, + RemoteAddr: raddr, + ReceiveCh: make(chan aurp.Packet, 1024), + RoutingTable: routes, + ZoneTable: zones, } aurp.Inc(&nextConnID) + peersMu.Lock() peers[udpAddrFromNet(raddr)] = peer + peersMu.Unlock() goPeerHandler(peer) } @@ -471,8 +505,14 @@ func main() { // Existing peer? ra := udpAddrFromNet(raddr) + peersMu.Lock() pr := peers[ra] if pr == nil { + if !cfg.OpenPeering { + log.Printf("AURP: Got packet from %v but it's not in my config and open peering is disabled; dropping the packet", raddr) + peersMu.Unlock() + continue + } // New peer! pr = &router.Peer{ Config: cfg, @@ -483,22 +523,22 @@ func main() { }, UDPConn: ln, RemoteAddr: raddr, - RecieveCh: make(chan aurp.Packet, 1024), + ReceiveCh: make(chan aurp.Packet, 1024), RoutingTable: routes, ZoneTable: zones, - Reconnect: false, } aurp.Inc(&nextConnID) peers[ra] = pr goPeerHandler(pr) } + peersMu.Unlock() switch dh.PacketType { case aurp.PacketTypeRouting: // It's AURP routing data. // Pass the packet to the goroutine in charge of this peer. select { - case pr.RecieveCh <- pkt: + case pr.ReceiveCh <- pkt: // That's it for us. case <-ctx.Done(): diff --git a/router/peer.go b/router/peer.go index cf50e9c..dfba5c8 100644 --- a/router/peer.go +++ b/router/peer.go @@ -21,6 +21,7 @@ import ( "context" "log" "net" + "sync" "time" "gitea.drjosh.dev/josh/jrouter/aurp" @@ -37,69 +38,122 @@ const ( updateTimer = 10 * time.Second ) -type receiverState int +type ReceiverState int const ( - rsUnconnected receiverState = iota - rsConnected - rsWaitForOpenRsp - rsWaitForRIRsp - rsWaitForTickleAck + ReceiverUnconnected ReceiverState = iota + ReceiverConnected + ReceiverWaitForOpenRsp + ReceiverWaitForRIRsp + ReceiverWaitForTickleAck ) -func (rs receiverState) String() string { +func (rs ReceiverState) String() string { switch rs { - case rsUnconnected: + case ReceiverUnconnected: return "unconnected" - case rsConnected: + case ReceiverConnected: return "connected" - case rsWaitForOpenRsp: + case ReceiverWaitForOpenRsp: return "waiting for Open-Rsp" - case rsWaitForRIRsp: + case ReceiverWaitForRIRsp: return "waiting for RI-Rsp" - case rsWaitForTickleAck: + case ReceiverWaitForTickleAck: return "waiting for Tickle-Ack" default: return "unknown" } } -type senderState int +type SenderState int const ( - ssUnconnected senderState = iota - ssConnected - ssWaitForRIRspAck - ssWaitForRIUpdAck - ssWaitForRDAck + SenderUnconnected SenderState = iota + SenderConnected + SenderWaitForRIRspAck + SenderWaitForRIUpdAck + SenderWaitForRDAck ) -func (ss senderState) String() string { +func (ss SenderState) String() string { switch ss { - case ssUnconnected: + case SenderUnconnected: return "unconnected" - case ssConnected: + case SenderConnected: return "connected" - case ssWaitForRIRspAck: + case SenderWaitForRIRspAck: return "waiting for RI-Ack for RI-Rsp" - case ssWaitForRIUpdAck: + case SenderWaitForRIUpdAck: return "waiting for RI-Ack for RI-Upd" - case ssWaitForRDAck: + case SenderWaitForRDAck: return "waiting for RI-Ack for RD" default: return "unknown" } } +// Peer handles the peering with a peer AURP router. type Peer struct { - Config *Config - Transport *aurp.Transport - UDPConn *net.UDPConn - RemoteAddr *net.UDPAddr - RecieveCh chan aurp.Packet + // Whole router config. + Config *Config + + // AURP-Tr state for producing packets. + Transport *aurp.Transport + + // Connection to reply to packets on. + UDPConn *net.UDPConn + + // The string that appeared in the config file / peer list file (with a + // ":387" appended as necessary). + // May be empty if this peer was not configured (it connected to us). + ConfiguredAddr string + + // The resolved address of the peer. + RemoteAddr *net.UDPAddr + + // Incoming packet channel. + ReceiveCh chan aurp.Packet + + // Routing table (the peer will add/remove/update routes) RoutingTable *RoutingTable - ZoneTable *ZoneTable - Reconnect bool + + // Zone table (the peer will add/remove/update zones) + ZoneTable *ZoneTable + + mu sync.RWMutex + rstate ReceiverState + sstate SenderState +} + +func (p *Peer) ReceiverState() ReceiverState { + p.mu.RLock() + defer p.mu.RUnlock() + return p.rstate +} + +func (p *Peer) SenderState() SenderState { + p.mu.RLock() + defer p.mu.RUnlock() + return p.sstate +} + +func (p *Peer) setRState(rstate ReceiverState) { + p.mu.Lock() + defer p.mu.Unlock() + p.rstate = rstate +} + +func (p *Peer) setSState(sstate SenderState) { + p.mu.Lock() + defer p.mu.Unlock() + p.sstate = sstate +} + +func (p *Peer) disconnect() { + p.mu.Lock() + defer p.mu.Unlock() + p.rstate = ReceiverUnconnected + p.sstate = SenderUnconnected } // Send encodes and sends pkt to the remote host. @@ -126,8 +180,7 @@ func (p *Peer) Handle(ctx context.Context) error { var lastRISent aurp.Packet - rstate := rsUnconnected - sstate := ssUnconnected + p.disconnect() // Write an Open-Req packet if _, err := p.Send(p.Transport.NewOpenReqPacket(nil)); err != nil { @@ -135,12 +188,12 @@ func (p *Peer) Handle(ctx context.Context) error { return err } - rstate = rsWaitForOpenRsp + p.setRState(ReceiverWaitForOpenRsp) for { select { case <-ctx.Done(): - if sstate == ssUnconnected { + if p.sstate == SenderUnconnected { // Return immediately return ctx.Err() } @@ -152,14 +205,14 @@ func (p *Peer) Handle(ctx context.Context) error { return ctx.Err() case <-rticker.C: - switch rstate { - case rsWaitForOpenRsp: + switch p.rstate { + case ReceiverWaitForOpenRsp: if time.Since(lastSend) <= sendRetryTimer { break } if sendRetries >= sendRetryLimit { log.Printf("AURP Peer: Send retry limit reached while waiting for Open-Rsp, closing connection") - rstate = rsUnconnected + p.setRState(ReceiverUnconnected) break } @@ -171,7 +224,7 @@ func (p *Peer) Handle(ctx context.Context) error { return err } - case rsConnected: + case ReceiverConnected: // Check LHFT, send tickle? if time.Since(lastHeardFrom) <= lastHeardFromTimer { break @@ -180,17 +233,17 @@ func (p *Peer) Handle(ctx context.Context) error { log.Printf("AURP Peer: Couldn't send Tickle: %v", err) return err } - rstate = rsWaitForTickleAck + p.setRState(ReceiverWaitForTickleAck) sendRetries = 0 lastSend = time.Now() - case rsWaitForTickleAck: + case ReceiverWaitForTickleAck: if time.Since(lastSend) <= sendRetryTimer { break } if sendRetries >= tickleRetryLimit { log.Printf("AURP Peer: Send retry limit reached while waiting for Tickle-Ack, closing connection") - rstate = rsUnconnected + p.setRState(ReceiverUnconnected) p.RoutingTable.DeletePeer(p) break } @@ -203,13 +256,13 @@ func (p *Peer) Handle(ctx context.Context) error { } // still in Wait For Tickle-Ack - case rsWaitForRIRsp: + case ReceiverWaitForRIRsp: if time.Since(lastSend) <= sendRetryTimer { break } if sendRetries >= sendRetryLimit { log.Printf("AURP Peer: Send retry limit reached while waiting for RI-Rsp, closing connection") - rstate = rsUnconnected + p.setRState(ReceiverUnconnected) p.RoutingTable.DeletePeer(p) break } @@ -223,10 +276,10 @@ func (p *Peer) Handle(ctx context.Context) error { } // still in Wait For RI-Rsp - case rsUnconnected: + case ReceiverUnconnected: // Data receiver is unconnected. If data sender is connected, // send a null RI-Upd to check if the sender is also unconnected - if sstate == ssConnected && time.Since(lastSend) > sendRetryTimer { + if p.sstate == SenderConnected && time.Since(lastSend) > sendRetryTimer { if sendRetries >= sendRetryLimit { log.Printf("AURP Peer: Send retry limit reached while probing sender connect, closing connection") } @@ -241,15 +294,24 @@ func (p *Peer) Handle(ctx context.Context) error { log.Printf("AURP Peer: Couldn't send RI-Upd packet: %v", err) return err } - sstate = ssWaitForRIUpdAck + p.setSState(SenderWaitForRIUpdAck) } - if p.Reconnect { + if p.ConfiguredAddr != "" { // Periodically try to reconnect, if this peer is in the config file if time.Since(lastReconnect) <= reconnectTimer { break } + // In case it's a DNS name, re-resolve it before reconnecting + raddr, err := net.ResolveUDPAddr("udp4", p.ConfiguredAddr) + if err != nil { + log.Printf("couldn't resolve UDP address, skipping: %v", err) + break + } + log.Printf("AURP Peer: resolved %q to %v", p.ConfiguredAddr, raddr) + p.RemoteAddr = raddr + lastReconnect = time.Now() sendRetries = 0 lastSend = time.Now() @@ -257,22 +319,22 @@ func (p *Peer) Handle(ctx context.Context) error { log.Printf("AURP Peer: Couldn't send Open-Req packet: %v", err) return err } - rstate = rsWaitForOpenRsp + p.setRState(ReceiverWaitForOpenRsp) } } case <-sticker.C: - switch sstate { - case ssUnconnected: + switch p.sstate { + case SenderUnconnected: // Do nothing - case ssConnected: + case SenderConnected: if time.Since(lastUpdate) <= updateTimer { break } // TODO: is there a routing update to send? - case ssWaitForRIRspAck, ssWaitForRIUpdAck: + case SenderWaitForRIRspAck, SenderWaitForRIUpdAck: if time.Since(lastSend) <= sendRetryTimer { break } @@ -282,7 +344,7 @@ func (p *Peer) Handle(ctx context.Context) error { } if sendRetries >= sendRetryLimit { log.Printf("AURP Peer: Send retry limit reached, closing connection") - sstate = ssUnconnected + p.setSState(SenderUnconnected) continue } sendRetries++ @@ -292,20 +354,20 @@ func (p *Peer) Handle(ctx context.Context) error { return err } - case ssWaitForRDAck: + case SenderWaitForRDAck: if time.Since(lastSend) <= sendRetryTimer { break } - sstate = ssUnconnected + p.setSState(SenderUnconnected) } - case pkt := <-p.RecieveCh: + case pkt := <-p.ReceiveCh: lastHeardFrom = time.Now() switch pkt := pkt.(type) { case *aurp.OpenReqPacket: - if sstate != ssUnconnected { - log.Printf("AURP Peer: Open-Req received but sender state is not unconnected (was %v)", sstate) + if p.sstate != SenderUnconnected { + log.Printf("AURP Peer: Open-Req received but sender state is not unconnected (was %v)", p.sstate) } // The peer tells us their connection ID in Open-Req. @@ -332,32 +394,32 @@ func (p *Peer) Handle(ctx context.Context) error { return err } if orsp.RateOrErrCode >= 0 { - sstate = ssConnected + p.setSState(SenderConnected) } // If receiver is unconnected, commence connecting - if rstate == rsUnconnected { + if p.rstate == ReceiverUnconnected { lastSend = time.Now() sendRetries = 0 if _, err := p.Send(p.Transport.NewOpenReqPacket(nil)); err != nil { log.Printf("AURP Peer: Couldn't send Open-Req packet: %v", err) return err } - rstate = rsWaitForOpenRsp + p.setRState(ReceiverWaitForOpenRsp) } case *aurp.OpenRspPacket: - if rstate != rsWaitForOpenRsp { - log.Printf("AURP Peer: Received Open-Rsp but was not waiting for one (receiver state was %v)", rstate) + if p.rstate != ReceiverWaitForOpenRsp { + log.Printf("AURP Peer: Received Open-Rsp but was not waiting for one (receiver state was %v)", p.rstate) } if pkt.RateOrErrCode < 0 { // It's an error code. log.Printf("AURP Peer: Open-Rsp error code from peer %v: %d", p.RemoteAddr.IP, pkt.RateOrErrCode) - rstate = rsUnconnected + p.setRState(ReceiverUnconnected) break } //log.Printf("AURP Peer: Data receiver is connected!") - rstate = rsConnected + p.setRState(ReceiverConnected) // Send an RI-Req sendRetries = 0 @@ -365,18 +427,18 @@ func (p *Peer) Handle(ctx context.Context) error { log.Printf("AURP Peer: Couldn't send RI-Req packet: %v", err) return err } - rstate = rsWaitForRIRsp + p.setRState(ReceiverWaitForRIRsp) case *aurp.RIReqPacket: - if sstate != ssConnected { - log.Printf("AURP Peer: Received RI-Req but was not expecting one (sender state was %v)", sstate) + if p.sstate != SenderConnected { + log.Printf("AURP Peer: Received RI-Req but was not expecting one (sender state was %v)", p.sstate) } nets := aurp.NetworkTuples{ { Extended: true, - RangeStart: uint16(p.Config.EtherTalk.NetStart), - RangeEnd: uint16(p.Config.EtherTalk.NetEnd), + RangeStart: p.Config.EtherTalk.NetStart, + RangeEnd: p.Config.EtherTalk.NetEnd, Distance: 0, }, } @@ -386,21 +448,21 @@ func (p *Peer) Handle(ctx context.Context) error { log.Printf("AURP Peer: Couldn't send RI-Rsp packet: %v", err) return err } - sstate = ssWaitForRIRspAck + p.setSState(SenderWaitForRIRspAck) case *aurp.RIRspPacket: - if rstate != rsWaitForRIRsp { - log.Printf("Received RI-Rsp but was not waiting for one (receiver state was %v)", rstate) + if p.rstate != ReceiverWaitForRIRsp { + log.Printf("Received RI-Rsp but was not waiting for one (receiver state was %v)", p.rstate) } log.Printf("AURP Peer: Learned about these networks: %v", pkt.Networks) for _, nt := range pkt.Networks { - p.RoutingTable.UpsertRoute( + p.RoutingTable.InsertRoute( + p, nt.Extended, ddp.Network(nt.RangeStart), ddp.Network(nt.RangeEnd), - p, nt.Distance+1, ) } @@ -413,26 +475,26 @@ func (p *Peer) Handle(ctx context.Context) error { } if pkt.Flags&aurp.RoutingFlagLast != 0 { // No longer waiting for an RI-Rsp - rstate = rsConnected + p.setRState(ReceiverConnected) } case *aurp.RIAckPacket: - switch sstate { - case ssWaitForRIRspAck: + switch p.sstate { + case SenderWaitForRIRspAck: // We sent an RI-Rsp, this is the RI-Ack we expected. - case ssWaitForRIUpdAck: + case SenderWaitForRIUpdAck: // We sent an RI-Upd, this is the RI-Ack we expected. - case ssWaitForRDAck: + case SenderWaitForRDAck: // We sent an RD... Why are we here? continue default: - log.Printf("AURP Peer: Received RI-Ack but was not waiting for one (sender state was %v)", sstate) + log.Printf("AURP Peer: Received RI-Ack but was not waiting for one (sender state was %v)", p.sstate) } - sstate = ssConnected + p.setSState(SenderConnected) sendRetries = 0 // If SZI flag is set, send ZI-Rsp (transaction) @@ -448,7 +510,7 @@ func (p *Peer) Handle(ctx context.Context) error { // TODO: Continue sending next RI-Rsp (streamed)? - if rstate == rsUnconnected { + if p.rstate == ReceiverUnconnected { // Receiver is unconnected, but their receiver sent us an // RI-Ack for something // Try to reconnect? @@ -458,23 +520,58 @@ func (p *Peer) Handle(ctx context.Context) error { log.Printf("AURP Peer: Couldn't send Open-Req packet: %v", err) return err } - rstate = rsWaitForOpenRsp + p.setRState(ReceiverWaitForOpenRsp) } case *aurp.RIUpdPacket: - // TODO: Integrate info into route table + + var ackFlag aurp.RoutingFlag + for _, et := range pkt.Events { log.Printf("AURP Peer: RI-Upd event %v", et) + switch et.EventCode { + case aurp.EventCodeNull: + // Do nothing except respond with RI-Ack + + case aurp.EventCodeNA: + if err := p.RoutingTable.InsertRoute( + p, + et.Extended, + et.RangeStart, + et.RangeEnd, + et.Distance+1, + ); err != nil { + log.Printf("AURP Peer: couldn't insert route: %v", err) + } + ackFlag = aurp.RoutingFlagSendZoneInfo + + case aurp.EventCodeND: + p.RoutingTable.DeletePeerNetwork(p, et.RangeStart) + + case aurp.EventCodeNDC: + p.RoutingTable.UpdateRouteDistance(p, et.RangeStart, et.Distance+1) + + case aurp.EventCodeNRC: + // "An exterior router sends a Network Route Change + // (NRC) event if the path to an exported network + // through its local internet changes to a path through + // a tunneling port, causing split-horizoned processing + // to eliminate that network’s routing information." + p.RoutingTable.DeletePeerNetwork(p, et.RangeStart) + + case aurp.EventCodeZC: + // "This event is reserved for future use." + } } - if _, err := p.Send(p.Transport.NewRIAckPacket(pkt.ConnectionID, pkt.Sequence, 0)); err != nil { + if _, err := p.Send(p.Transport.NewRIAckPacket(pkt.ConnectionID, pkt.Sequence, ackFlag)); err != nil { log.Printf("AURP Peer: Couldn't send RI-Ack: %v", err) return err } case *aurp.RDPacket: - if rstate == rsUnconnected || rstate == rsWaitForOpenRsp { - log.Printf("AURP Peer: Received RD but was not expecting one (receiver state was %v)", rstate) + if p.rstate == ReceiverUnconnected || p.rstate == ReceiverWaitForOpenRsp { + log.Printf("AURP Peer: Received RD but was not expecting one (receiver state was %v)", p.rstate) } log.Printf("AURP Peer: Router Down: error code %d %s", pkt.ErrorCode, pkt.ErrorCode) @@ -486,8 +583,7 @@ func (p *Peer) Handle(ctx context.Context) error { return err } // Connections closed - rstate = rsUnconnected - sstate = ssUnconnected + p.disconnect() case *aurp.ZIReqPacket: // TODO: split ZI-Rsp packets similarly to ZIP Replies @@ -529,10 +625,10 @@ func (p *Peer) Handle(ctx context.Context) error { } case *aurp.TickleAckPacket: - if rstate != rsWaitForTickleAck { - log.Printf("AURP Peer: Received Tickle-Ack but was not waiting for one (receiver state was %v)", rstate) + if p.rstate != ReceiverWaitForTickleAck { + log.Printf("AURP Peer: Received Tickle-Ack but was not waiting for one (receiver state was %v)", p.rstate) } - rstate = rsConnected + p.setRState(ReceiverConnected) } } } diff --git a/router/route.go b/router/route.go index 17207b6..a5b1c87 100644 --- a/router/route.go +++ b/router/route.go @@ -101,12 +101,36 @@ func (rt *RoutingTable) DeletePeer(peer *Peer) { } } -func (rt *RoutingTable) UpsertRoute(extended bool, netStart, netEnd ddp.Network, peer *Peer, metric uint8) error { +func (rt *RoutingTable) DeletePeerNetwork(peer *Peer, network ddp.Network) { + rt.mu.Lock() + defer rt.mu.Unlock() + + for route := range rt.routes { + if route.Peer == peer && route.NetStart == network { + delete(rt.routes, route) + } + } +} + +func (rt *RoutingTable) UpdateRouteDistance(peer *Peer, network ddp.Network, distance uint8) { + rt.mu.Lock() + defer rt.mu.Unlock() + + for route := range rt.routes { + if route.Peer == peer && route.NetStart == network { + route.Distance = distance + route.LastSeen = time.Now() + } + } +} + +func (rt *RoutingTable) InsertRoute(peer *Peer, extended bool, netStart, netEnd ddp.Network, metric uint8) error { if netStart > netEnd { return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd) } - - // TODO: handle the Update part of "Upsert" + if netStart != netEnd && !extended { + return fmt.Errorf("invalid network range [%d, %d] for nonextended network", netStart, netEnd) + } r := &Route{ Extended: extended, diff --git a/router/rtmp.go b/router/rtmp.go index 15fb52c..8a036a1 100644 --- a/router/rtmp.go +++ b/router/rtmp.go @@ -25,7 +25,9 @@ import ( "gitea.drjosh.dev/josh/jrouter/atalk" "gitea.drjosh.dev/josh/jrouter/atalk/rtmp" "gitea.drjosh.dev/josh/jrouter/status" + "github.com/google/gopacket/pcap" + "github.com/sfiera/multitalk/pkg/aarp" "github.com/sfiera/multitalk/pkg/ddp" "github.com/sfiera/multitalk/pkg/ethernet"