vppn/peer/connhandler.go
2024-12-12 21:11:17 +01:00

122 lines
2.2 KiB
Go

package peer
import (
"fmt"
"log"
"runtime/debug"
"sync/atomic"
"time"
)
type connHandler struct {
// Communication.
mediatorUpdates chan byte
peerUpdates chan peerUpdate
pings chan wrapper[Ping]
pongs chan wrapper[Pong]
data *connData
}
func newConnHandler(
server bool,
peerIP byte,
routes [256]*atomic.Pointer[route],
encPrivKey []byte,
sender *safeConnSender,
) *connHandler {
d := &connData{
server: server,
pingTimer: time.NewTimer(pingInterval),
timeoutTimer: time.NewTimer(timeoutInterval),
routes: routes,
route: routes[peerIP],
peerIP: peerIP,
encPrivKey: encPrivKey,
buf: make([]byte, BUFFER_SIZE),
sender: sender,
}
h := &connHandler{
mediatorUpdates: make(chan byte, 1),
peerUpdates: make(chan peerUpdate, 1),
pings: make(chan wrapper[Ping], 1),
pongs: make(chan wrapper[Pong], 1),
data: d,
}
go h.mainLoop()
return h
}
func (h *connHandler) mainLoop() {
defer func() {
if r := recover(); r != nil {
fmt.Println("stacktrace from panic: \n" + string(debug.Stack()))
}
}()
var (
data = h.data
state = newConnNull(data)
name = state.Name()
)
for {
select {
case ip := <-h.mediatorUpdates:
state = state.HandleMediatorUpdate(ip)
case update := <-h.peerUpdates:
state = data.HandlePeerUpdate(state, update)
case w := <-h.pings:
state = state.HandlePing(w)
case w := <-h.pongs:
state = state.HandlePong(w)
case <-data.pingTimer.C:
state.HandleSendPing()
case <-data.timeoutTimer.C:
log.Printf("[%s] Connection timeout.", state.Name())
state = state.HandleTimeout()
}
if state.Name() != name {
log.Printf("[%03d] STATE: %s --> %s", data.peerIP, name, state.Name())
name = state.Name()
}
}
}
func (c *connHandler) UpdateMediator(ip byte) {
select {
case c.mediatorUpdates <- ip:
default:
}
}
func (c *connHandler) HandlePing(w wrapper[Ping]) {
select {
case c.pings <- w:
default:
}
}
func (c *connHandler) HandlePong(w wrapper[Pong]) {
select {
case c.pongs <- w:
default:
}
}
func (c *connHandler) UpdatePeer(update peerUpdate) {
select {
case c.peerUpdates <- update:
default:
}
}