Start adding states
This commit is contained in:
parent
c52a434909
commit
78ad28d70f
3 changed files with 85 additions and 19 deletions
|
@ -111,6 +111,16 @@ func (tr *Transport) NewOpenRspPacket(envFlags RoutingFlag, rateOrErr int16, opt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tr *Transport) NewRIAckPacket(connID, seq uint16, szi RoutingFlag) *RIAckPacket {
|
||||||
|
return &RIAckPacket{
|
||||||
|
Header: Header{
|
||||||
|
TrHeader: tr.sequenced(connID, seq),
|
||||||
|
CommandCode: CmdCodeRIAck,
|
||||||
|
Flags: szi,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (tr *Transport) NewRDPacket(errCode ErrorCode) *RDPacket {
|
func (tr *Transport) NewRDPacket(errCode ErrorCode) *RDPacket {
|
||||||
return &RDPacket{
|
return &RDPacket{
|
||||||
Header: Header{
|
Header: Header{
|
||||||
|
|
15
main.go
15
main.go
|
@ -133,6 +133,21 @@ func main() {
|
||||||
|
|
||||||
log.Printf("The packet parsed succesfully as a %T", pkt)
|
log.Printf("The packet parsed succesfully as a %T", pkt)
|
||||||
|
|
||||||
|
if _, ok := pkt.(*aurp.AppleTalkPacket); ok {
|
||||||
|
// Probably something like:
|
||||||
|
//
|
||||||
|
// * parse the DDP header
|
||||||
|
// * check that this is headed for our local network
|
||||||
|
// * write the packet out in an EtherTalk frame
|
||||||
|
//
|
||||||
|
// or maybe if we were implementing a "central hub"
|
||||||
|
//
|
||||||
|
// * parse the DDP header
|
||||||
|
// * see if we know the network
|
||||||
|
// * forward to the peer with that network and lowest metric
|
||||||
|
log.Print("TODO: handle AppleTalk packets")
|
||||||
|
}
|
||||||
|
|
||||||
// Existing peer?
|
// Existing peer?
|
||||||
ra := udpAddrFromNet(raddr)
|
ra := udpAddrFromNet(raddr)
|
||||||
pr := peers[ra]
|
pr := peers[ra]
|
||||||
|
|
79
peer.go
79
peer.go
|
@ -10,6 +10,26 @@ import (
|
||||||
"gitea.drjosh.dev/josh/jrouter/aurp"
|
"gitea.drjosh.dev/josh/jrouter/aurp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type receiverState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
receiverStateUnconnected receiverState = iota
|
||||||
|
receiverStateConnected
|
||||||
|
receiverStateWaitForOpenRsp
|
||||||
|
receiverStateWaitForRIRsp
|
||||||
|
receiverStateWaitForTickleAck
|
||||||
|
)
|
||||||
|
|
||||||
|
type senderState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
senderStateUnconnected senderState = iota
|
||||||
|
senderStateConnected
|
||||||
|
senderStateWaitForRIAck1
|
||||||
|
senderStateWaitForRIAck2
|
||||||
|
senderStateWaitForRIAck3
|
||||||
|
)
|
||||||
|
|
||||||
type peer struct {
|
type peer struct {
|
||||||
tr *aurp.Transport
|
tr *aurp.Transport
|
||||||
conn *net.UDPConn
|
conn *net.UDPConn
|
||||||
|
@ -32,6 +52,9 @@ func (p *peer) handle(ctx context.Context) error {
|
||||||
|
|
||||||
lastHeardFrom := time.Now()
|
lastHeardFrom := time.Now()
|
||||||
|
|
||||||
|
rstate := receiverStateUnconnected
|
||||||
|
sstate := senderStateUnconnected
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -40,9 +63,14 @@ func (p *peer) handle(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
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)
|
||||||
|
|
||||||
|
rstate = receiverStateWaitForOpenRsp
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
if rstate == receiverStateUnconnected {
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
// Send a best-effort Router Down before returning
|
// Send a best-effort Router Down before returning
|
||||||
if _, err := p.send(p.tr.NewRDPacket(aurp.ErrCodeNormalClose)); err != nil {
|
if _, err := p.send(p.tr.NewRDPacket(aurp.ErrCodeNormalClose)); err != nil {
|
||||||
log.Printf("Couldn't send RD packet: %v", err)
|
log.Printf("Couldn't send RD packet: %v", err)
|
||||||
|
@ -50,32 +78,26 @@ func (p *peer) handle(ctx context.Context) error {
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
|
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
// TODO: time-based state changes
|
if rstate == receiverStateConnected {
|
||||||
// Check LHFT, send tickle?
|
// Check LHFT, send tickle?
|
||||||
if time.Since(lastHeardFrom) > 10*time.Second {
|
if time.Since(lastHeardFrom) > 10*time.Second {
|
||||||
if _, err := p.send(p.tr.NewTicklePacket()); err != nil {
|
if _, err := p.send(p.tr.NewTicklePacket()); err != nil {
|
||||||
log.Printf("Couldn't send Tickle: %v", err)
|
log.Printf("Couldn't send Tickle: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
rstate = receiverStateWaitForTickleAck
|
||||||
}
|
}
|
||||||
|
|
||||||
case pkt := <-p.recv:
|
case pkt := <-p.recv:
|
||||||
lastHeardFrom = time.Now()
|
lastHeardFrom = time.Now()
|
||||||
|
|
||||||
switch pkt := pkt.(type) {
|
switch pkt := pkt.(type) {
|
||||||
case *aurp.AppleTalkPacket:
|
|
||||||
// Probably something like:
|
|
||||||
//
|
|
||||||
// * parse the DDP header
|
|
||||||
// * check that this is headed for our local network
|
|
||||||
// * write the packet out in an EtherTalk frame
|
|
||||||
//
|
|
||||||
// or maybe if we were implementing a "central hub"
|
|
||||||
//
|
|
||||||
// * parse the DDP header
|
|
||||||
// * see if we know the network
|
|
||||||
// * forward to the peer with that network and lowest metric
|
|
||||||
|
|
||||||
case *aurp.OpenReqPacket:
|
case *aurp.OpenReqPacket:
|
||||||
|
if sstate != senderStateUnconnected {
|
||||||
|
log.Printf("Open-Req received but sender state is not Unconnected (was %d); ignoring packet", sstate)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
// The peer tells us their connection ID in Open-Req.
|
// The peer tells us their connection ID in Open-Req.
|
||||||
p.tr.RemoteConnID = pkt.ConnectionID
|
p.tr.RemoteConnID = pkt.ConnectionID
|
||||||
|
|
||||||
|
@ -100,12 +122,22 @@ func (p *peer) handle(ctx context.Context) error {
|
||||||
if _, err := p.send(orsp); err != nil {
|
if _, err := p.send(orsp); err != nil {
|
||||||
log.Printf("Couldn't send Open-Rsp: %v", err)
|
log.Printf("Couldn't send Open-Rsp: %v", err)
|
||||||
}
|
}
|
||||||
|
if orsp.RateOrErrCode >= 0 {
|
||||||
|
sstate = senderStateConnected
|
||||||
|
} else {
|
||||||
|
sstate = senderStateUnconnected
|
||||||
|
}
|
||||||
|
|
||||||
case *aurp.OpenRspPacket:
|
case *aurp.OpenRspPacket:
|
||||||
|
if rstate != receiverStateWaitForOpenRsp {
|
||||||
|
log.Printf("Received Open-Rsp but was not waiting for one (receiver state was %d)", rstate)
|
||||||
|
}
|
||||||
if pkt.RateOrErrCode < 0 {
|
if pkt.RateOrErrCode < 0 {
|
||||||
// It's an error code.
|
// It's an error code.
|
||||||
log.Printf("Open-Rsp error code from peer %v: %d", p.raddr.IP, pkt.RateOrErrCode)
|
log.Printf("Open-Rsp error code from peer %v: %d", p.raddr.IP, pkt.RateOrErrCode)
|
||||||
// Close the connection
|
// Close the connection
|
||||||
|
rstate = receiverStateUnconnected
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make other requests
|
// TODO: Make other requests
|
||||||
|
@ -128,6 +160,11 @@ func (p *peer) handle(ctx context.Context) error {
|
||||||
// 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)
|
log.Printf("Router Down: error code %d %s", pkt.ErrorCode, pkt.ErrorCode)
|
||||||
|
// Respond with RI-Ack
|
||||||
|
if _, err := p.send(p.tr.NewRIAckPacket(pkt.ConnectionID, pkt.Sequence, 0)); err != nil {
|
||||||
|
log.Printf("Couldn't send RI-Ack: %v", err)
|
||||||
|
}
|
||||||
|
rstate = receiverStateUnconnected
|
||||||
|
|
||||||
case *aurp.ZIReqPacket:
|
case *aurp.ZIReqPacket:
|
||||||
// TODO: Respond with ZI-Rsp
|
// TODO: Respond with ZI-Rsp
|
||||||
|
@ -142,7 +179,11 @@ func (p *peer) handle(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
case *aurp.TickleAckPacket:
|
case *aurp.TickleAckPacket:
|
||||||
// No need to do anything
|
if rstate != receiverStateWaitForTickleAck {
|
||||||
|
log.Printf("Received Tickle-Ack but was not waiting for one (receever state was %d)", rstate)
|
||||||
|
}
|
||||||
|
rstate = receiverStateConnected
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue