vppn/peer/state-server.go
2025-02-25 02:43:29 +01:00

128 lines
2.8 KiB
Go

package peer
import (
"net/netip"
"time"
)
type stateServer2 struct {
*peerData
lastSeen time.Time
synTraceID uint64 // Last syn trace ID.
}
func enterStateServer2(data *peerData) peerState {
data.staged.Up = false
data.staged.Relay = false
data.staged.Direct = false
data.staged.DirectAddr = netip.AddrPort{}
data.staged.PubSignKey = data.peer.PubSignKey
data.staged.ControlCipher = newControlCipher(data.privKey, data.peer.PubKey)
data.staged.DataCipher = nil
data.publish(data.staged)
data.pingTimer.Reset(pingInterval)
state := &stateServer2{peerData: data}
state.logf("==> Server")
return state
}
func (s *stateServer2) logf(str string, args ...any) {
s.peerData.logf("SRVR | "+str, args...)
}
func (s *stateServer2) OnMsg(raw any) peerState {
switch msg := raw.(type) {
case peerUpdateMsg:
return initPeerState(s.peerData, msg.Peer)
case controlMsg[packetInit]:
return s.onInit(msg)
case controlMsg[packetSyn]:
return s.onSyn(msg)
case controlMsg[packetProbe]:
return s.onProbe(msg)
case controlMsg[packetLocalDiscovery]:
return s
case pingTimerMsg:
return s.onPingTimer()
default:
s.logf("Ignoring message: %v", raw)
return s
}
}
func (s *stateServer2) onInit(msg controlMsg[packetInit]) peerState {
s.staged.Up = false
s.staged.Direct = msg.Packet.Direct
s.staged.DirectAddr = msg.SrcAddr
s.publish(s.staged)
init := packetInit{
TraceID: msg.Packet.TraceID,
Direct: s.staged.Direct,
Version: version,
}
s.Send(s.staged, init)
return s
}
func (s *stateServer2) onSyn(msg controlMsg[packetSyn]) peerState {
s.lastSeen = time.Now()
p := msg.Packet
// Before we can respond to this packet, we need to make sure the
// route is setup properly.
//
// The client will update the syn's TraceID whenever there's a change.
// The server will follow the client's request.
if p.TraceID != s.synTraceID || !s.staged.Up {
s.synTraceID = p.TraceID
s.staged.Up = true
s.staged.Direct = p.Direct
s.staged.DataCipher = newDataCipherFromKey(p.SharedKey)
s.staged.DirectAddr = msg.SrcAddr
s.publish(s.staged)
s.logf("Got SYN.")
}
// Always respond.
s.Send(s.staged, packetAck{
TraceID: p.TraceID,
ToAddr: s.staged.DirectAddr,
PossibleAddrs: s.pubAddrs.Get(),
})
if p.Direct {
return s
}
for _, addr := range msg.Packet.PossibleAddrs {
if !addr.IsValid() {
break
}
s.SendTo(packetProbe{TraceID: newTraceID()}, addr)
}
return s
}
func (s *stateServer2) onProbe(msg controlMsg[packetProbe]) peerState {
if msg.SrcAddr.IsValid() {
s.SendTo(packetProbe{TraceID: msg.Packet.TraceID}, msg.SrcAddr)
}
return s
}
func (s *stateServer2) onPingTimer() peerState {
if time.Since(s.lastSeen) > timeoutInterval && s.staged.Up {
s.staged.Up = false
s.publish(s.staged)
s.logf("Timeout.")
}
return s
}