2024-04-12 16:14:27 +10:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"cmp"
|
|
|
|
"fmt"
|
|
|
|
"slices"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/sfiera/multitalk/pkg/ddp"
|
|
|
|
)
|
|
|
|
|
2024-04-14 13:44:35 +10:00
|
|
|
const maxRouteAge = 10 * time.Minute // TODO: confirm
|
|
|
|
|
2024-04-12 16:14:27 +10:00
|
|
|
type route struct {
|
2024-04-13 15:47:58 +10:00
|
|
|
extended bool
|
|
|
|
netStart ddp.Network
|
|
|
|
netEnd ddp.Network
|
|
|
|
peer *peer
|
|
|
|
metric uint8
|
|
|
|
last time.Time
|
2024-04-12 16:14:27 +10:00
|
|
|
}
|
|
|
|
|
2024-04-14 13:44:35 +10:00
|
|
|
type routingTable struct {
|
|
|
|
tableMu sync.Mutex
|
|
|
|
table map[ddp.Network][]*route
|
2024-04-13 15:47:58 +10:00
|
|
|
|
|
|
|
allRoutesMu sync.Mutex
|
2024-04-14 13:44:35 +10:00
|
|
|
allRoutes map[*route]struct{}
|
|
|
|
}
|
2024-04-12 16:14:27 +10:00
|
|
|
|
2024-04-14 13:44:35 +10:00
|
|
|
func (rt *routingTable) lookupRoute(network ddp.Network) *route {
|
|
|
|
rt.tableMu.Lock()
|
|
|
|
defer rt.tableMu.Unlock()
|
2024-04-12 16:14:27 +10:00
|
|
|
|
2024-04-14 13:44:35 +10:00
|
|
|
for _, rs := range rt.table[network] {
|
|
|
|
if time.Since(rs.last) > maxRouteAge {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return rs
|
2024-04-12 16:14:27 +10:00
|
|
|
}
|
2024-04-14 13:44:35 +10:00
|
|
|
return nil
|
2024-04-12 16:14:27 +10:00
|
|
|
}
|
|
|
|
|
2024-04-14 13:44:35 +10:00
|
|
|
func (rt *routingTable) upsertRoutes(extended bool, netStart, netEnd ddp.Network, peer *peer, metric uint8) error {
|
2024-04-12 16:14:27 +10:00
|
|
|
if netStart > netEnd {
|
|
|
|
return fmt.Errorf("invalid network range [%d, %d]", netStart, netEnd)
|
|
|
|
}
|
2024-04-14 13:44:35 +10:00
|
|
|
|
2024-04-12 16:14:27 +10:00
|
|
|
r := &route{
|
2024-04-13 15:47:58 +10:00
|
|
|
extended: extended,
|
|
|
|
netStart: netStart,
|
|
|
|
netEnd: netEnd,
|
|
|
|
peer: peer,
|
|
|
|
metric: metric,
|
|
|
|
last: time.Now(),
|
2024-04-12 16:14:27 +10:00
|
|
|
}
|
|
|
|
|
2024-04-14 13:44:35 +10:00
|
|
|
rt.allRoutesMu.Lock()
|
|
|
|
rt.allRoutes[r] = struct{}{}
|
|
|
|
rt.allRoutesMu.Unlock()
|
2024-04-13 15:47:58 +10:00
|
|
|
|
2024-04-14 13:44:35 +10:00
|
|
|
rt.tableMu.Lock()
|
|
|
|
defer rt.tableMu.Unlock()
|
2024-04-12 16:14:27 +10:00
|
|
|
for n := netStart; n <= netEnd; n++ {
|
2024-04-14 13:44:35 +10:00
|
|
|
rt.table[n] = append(rt.table[n], r)
|
|
|
|
slices.SortFunc(rt.table[n], func(r, s *route) int {
|
2024-04-12 16:14:27 +10:00
|
|
|
return cmp.Compare(r.metric, s.metric)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2024-04-14 13:44:35 +10:00
|
|
|
|
|
|
|
func (rt *routingTable) validRoutes() []*route {
|
|
|
|
rt.allRoutesMu.Lock()
|
|
|
|
defer rt.allRoutesMu.Unlock()
|
|
|
|
valid := make([]*route, 0, len(rt.allRoutes))
|
|
|
|
for r := range rt.allRoutes {
|
|
|
|
if r.peer == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if time.Since(r.last) > maxRouteAge {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
valid = append(valid, r)
|
|
|
|
}
|
2024-04-14 13:45:05 +10:00
|
|
|
return valid
|
2024-04-14 13:44:35 +10:00
|
|
|
}
|