Tickle handling

This commit is contained in:
Josh Deprez 2024-03-30 14:13:34 +11:00
parent b9ae3cc426
commit 520046d86a
Signed by: josh
SSH key fingerprint: SHA256:zZji7w1Ilh2RuUpbQcqkLPrqmRwpiCSycbF2EfKm6Kw
4 changed files with 146 additions and 86 deletions

View file

@ -1,14 +1,26 @@
package aurp package aurp
type ErrorCode = int16 type ErrorCode int16
// Various error codes. // Various error codes.
const ( const (
ErrCodeNormalClose = -1 ErrCodeNormalClose ErrorCode = -1
ErrCodeRoutingLoop = -2 ErrCodeRoutingLoop ErrorCode = -2
ErrCodeOutOfSync = -3 ErrCodeOutOfSync ErrorCode = -3
ErrCodeOptionNegotiation = -4 ErrCodeOptionNegotiation ErrorCode = -4
ErrCodeInvalidVersion = -5 ErrCodeInvalidVersion ErrorCode = -5
ErrCodeInsufficientResources = -6 ErrCodeInsufficientResources ErrorCode = -6
ErrCodeAuthentication = -7 ErrCodeAuthentication ErrorCode = -7
) )
func (e ErrorCode) String() string {
return map[ErrorCode]string{
ErrCodeNormalClose: "normal connection close",
ErrCodeRoutingLoop: "routing loop detected",
ErrCodeOutOfSync: "connection out of sync",
ErrCodeOptionNegotiation: "option-negotiation error",
ErrCodeInvalidVersion: "invalid version number",
ErrCodeInsufficientResources: "insufficient resources for connection",
ErrCodeAuthentication: "authentication error",
}[e]
}

View file

@ -110,3 +110,23 @@ func (tr *Transport) NewOpenRspPacket(envFlags RoutingFlag, rateOrErr int16, opt
Options: opts, Options: opts,
} }
} }
func (tr *Transport) NewTicklePacket() *TicklePacket {
return &TicklePacket{
Header: Header{
TrHeader: tr.transaction(tr.LocalConnID),
CommandCode: CmdCodeTickle,
Flags: 0,
},
}
}
func (tr *Transport) NewTickleAckPacket() *TickleAckPacket {
return &TickleAckPacket{
Header: Header{
TrHeader: tr.transaction(tr.RemoteConnID),
CommandCode: CmdCodeTickleAck,
Flags: 0,
},
}
}

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"flag" "flag"
"log" "log"
"net" "net"
@ -17,6 +18,8 @@ func main() {
flag.Parse() flag.Parse()
log.Println("jrouter") log.Println("jrouter")
ctx := context.Background()
cfg, err := loadConfig(*configFilePath) cfg, err := loadConfig(*configFilePath)
if err != nil { if err != nil {
log.Fatalf("Couldn't load configuration file: %v", err) log.Fatalf("Couldn't load configuration file: %v", err)
@ -83,7 +86,7 @@ func main() {
raddr: raddr, raddr: raddr,
recv: make(chan aurp.Packet, 1024), recv: make(chan aurp.Packet, 1024),
} }
go peer.handle() go peer.handle(ctx)
peers[udpAddrFromNet(raddr)] = peer peers[udpAddrFromNet(raddr)] = peer
} }
@ -127,7 +130,7 @@ func main() {
recv: make(chan aurp.Packet, 1024), recv: make(chan aurp.Packet, 1024),
} }
peers[ra] = pr peers[ra] = pr
go pr.handle() go pr.handle(ctx)
} }
// Pass the packet to the goroutine in charge of this peer. // Pass the packet to the goroutine in charge of this peer.

39
peer.go
View file

@ -2,8 +2,10 @@ package main
import ( import (
"bytes" "bytes"
"context"
"log" "log"
"net" "net"
"time"
"gitea.drjosh.dev/josh/jrouter/aurp" "gitea.drjosh.dev/josh/jrouter/aurp"
) )
@ -13,6 +15,8 @@ type peer struct {
conn *net.UDPConn conn *net.UDPConn
raddr *net.UDPAddr raddr *net.UDPAddr
recv chan aurp.Packet recv chan aurp.Packet
lastHeardFrom time.Time
} }
// send encodes and sends pkt to the remote host. // send encodes and sends pkt to the remote host.
@ -24,16 +28,33 @@ func (p *peer) send(pkt aurp.Packet) (int, error) {
return p.conn.WriteToUDP(b.Bytes(), p.raddr) return p.conn.WriteToUDP(b.Bytes(), p.raddr)
} }
func (p *peer) handle() { func (p *peer) handle(ctx context.Context) error {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
// Write an Open-Req packet // Write an Open-Req packet
n, err := p.send(p.tr.NewOpenReqPacket(nil)) n, err := p.send(p.tr.NewOpenReqPacket(nil))
if err != nil { if err != nil {
log.Printf("Couldn't send Open-Req packet: %v", err) log.Printf("Couldn't send Open-Req packet: %v", err)
return return err
} }
log.Printf("Sent Open-Req (len %d) to peer %v", n, p.raddr) log.Printf("Sent Open-Req (len %d) to peer %v", n, p.raddr)
for pkt := range p.recv { for {
select {
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:
// TODO: time-based state changes
// Check LHFT, send tickle?
if time.Since(p.lastHeardFrom) > 10*time.Second {
if _, err := p.send(p.tr.NewTicklePacket()); err != nil {
log.Printf("Couldn't send Tickle: %v", err)
}
}
case pkt := <-p.recv:
switch pkt := pkt.(type) { switch pkt := pkt.(type) {
case *aurp.AppleTalkPacket: case *aurp.AppleTalkPacket:
// Probably something like: // Probably something like:
@ -57,11 +78,11 @@ func (p *peer) handle() {
switch { switch {
case pkt.Version != 1: case pkt.Version != 1:
// Respond with Open-Rsp with unknown version error. // Respond with Open-Rsp with unknown version error.
orsp = p.tr.NewOpenRspPacket(0, aurp.ErrCodeInvalidVersion, nil) orsp = p.tr.NewOpenRspPacket(0, int16(aurp.ErrCodeInvalidVersion), nil)
case len(pkt.Options) > 0: case len(pkt.Options) > 0:
// Options? OPTIONS? We don't accept no stinkin' _options_ // Options? OPTIONS? We don't accept no stinkin' _options_
orsp = p.tr.NewOpenRspPacket(0, aurp.ErrCodeOptionNegotiation, nil) orsp = p.tr.NewOpenRspPacket(0, int16(aurp.ErrCodeOptionNegotiation), nil)
default: default:
// Accept it I guess. // Accept it I guess.
@ -100,6 +121,7 @@ func (p *peer) handle() {
case *aurp.RDPacket: case *aurp.RDPacket:
// TODO: Remove router from tables // TODO: Remove router from tables
// TODO: Close connection // TODO: Close connection
log.Printf("Router Down: error code %d %s", pkt.ErrorCode, pkt.ErrorCode)
case *aurp.ZIReqPacket: case *aurp.ZIReqPacket:
// TODO: Respond with ZI-Rsp // TODO: Respond with ZI-Rsp
@ -108,10 +130,13 @@ func (p *peer) handle() {
// TODO: Integrate info into zone table // TODO: Integrate info into zone table
case *aurp.TicklePacket: case *aurp.TicklePacket:
// TODO: Respond with TickleAck if _, err := p.send(p.tr.NewTickleAckPacket()); err != nil {
log.Printf("Couldn't send Tickle-Ack: %v", err)
}
case *aurp.TickleAckPacket: case *aurp.TickleAckPacket:
// TODO: Reset LHFT p.lastHeardFrom = time.Now()
}
} }
} }
} }