fix Snapshot
This commit is contained in:
parent
153f172daf
commit
c5c06cbb1f
@ -19,11 +19,13 @@ actor ArpServer {
|
||||
|
||||
private var known_macs: [UInt32: ArpEntry] = [:]
|
||||
private let arpTTL: TimeInterval
|
||||
nonisolated private let snapshotPublisher: SnapshotPublisher<ArpSnapshot>
|
||||
|
||||
private var cleanupTask: Task<Void, Never>?
|
||||
|
||||
init(arpTTL: TimeInterval = 300) {
|
||||
self.arpTTL = arpTTL
|
||||
self.snapshotPublisher = SnapshotPublisher(initial: ArpSnapshot.empty())
|
||||
}
|
||||
|
||||
func start() {
|
||||
@ -46,6 +48,7 @@ actor ArpServer {
|
||||
|
||||
if entry.expireTime < Date().timeIntervalSince1970 {
|
||||
known_macs.removeValue(forKey: ip)
|
||||
self.publishSnapshot()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -55,19 +58,23 @@ actor ArpServer {
|
||||
func append(ip: UInt32, mac: Data) {
|
||||
let expireAt = Date().timeIntervalSince1970 + arpTTL
|
||||
self.known_macs[ip] = ArpEntry(mac: mac, expireTime: expireAt)
|
||||
self.publishSnapshot()
|
||||
}
|
||||
|
||||
func remove(ip: UInt32) {
|
||||
self.known_macs.removeValue(forKey: ip)
|
||||
self.publishSnapshot()
|
||||
}
|
||||
|
||||
func dropMacs(macs: [Data]) {
|
||||
self.known_macs = self.known_macs.filter { !macs.contains($0.value.mac) }
|
||||
self.publishSnapshot()
|
||||
}
|
||||
|
||||
func clear() {
|
||||
self.known_macs = [:]
|
||||
self.coolingDown = [:]
|
||||
self.publishSnapshot()
|
||||
}
|
||||
|
||||
func stop() {
|
||||
@ -95,12 +102,34 @@ actor ArpServer {
|
||||
if !targetMac.isEmpty {
|
||||
let expireAt = Date().timeIntervalSince1970 + arpTTL
|
||||
self.known_macs[targetIp] = ArpEntry(mac: targetMac, expireTime: expireAt)
|
||||
self.publishSnapshot()
|
||||
}
|
||||
}
|
||||
|
||||
nonisolated func snapshot() -> ArpSnapshot {
|
||||
return self.snapshotPublisher.current()
|
||||
}
|
||||
|
||||
private func cleanup() {
|
||||
let now = Date()
|
||||
self.coolingDown = self.coolingDown.filter { $0.value > now }
|
||||
let oldCount = self.known_macs.count
|
||||
self.known_macs = self.known_macs.filter { $0.value.expireTime >= now.timeIntervalSince1970 }
|
||||
if self.known_macs.count != oldCount {
|
||||
self.publishSnapshot()
|
||||
}
|
||||
}
|
||||
|
||||
private func publishSnapshot() {
|
||||
self.snapshotPublisher.publish(self.compileSnapshot())
|
||||
}
|
||||
|
||||
private func compileSnapshot() -> ArpSnapshot {
|
||||
let now = Date().timeIntervalSince1970
|
||||
let entries = self.known_macs.compactMapValues { entry in
|
||||
entry.expireTime >= now ? entry.mac : nil
|
||||
}
|
||||
return ArpSnapshot(entries: entries)
|
||||
}
|
||||
|
||||
deinit {
|
||||
24
Tun/Punchnet/Arp/ArpSnapshot.swift
Normal file
24
Tun/Punchnet/Arp/ArpSnapshot.swift
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// ArpSnapshot.swift
|
||||
// Tun
|
||||
//
|
||||
// Created by Codex on 2026/5/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class ArpSnapshot: Snapshot {
|
||||
private let entries: [UInt32: Data]
|
||||
|
||||
init(entries: [UInt32: Data]) {
|
||||
self.entries = entries
|
||||
}
|
||||
|
||||
func lookup(_ ip: UInt32) -> Data? {
|
||||
return self.entries[ip]
|
||||
}
|
||||
|
||||
static func empty() -> ArpSnapshot {
|
||||
return ArpSnapshot(entries: [:])
|
||||
}
|
||||
}
|
||||
@ -195,7 +195,7 @@ actor PacketOutboundActor {
|
||||
SDLLogger.log("[PacketOutboundActor] use exit_node: \(SDLUtil.int32ToIp(ip))", for: .trace)
|
||||
}
|
||||
|
||||
if let dstMac = await self.arpServer.query(ip: ip) {
|
||||
if let dstMac = self.arpServer.snapshot().lookup(ip) {
|
||||
SDLLogger.log("[PacketOutboundActor] dstIp: \(SDLUtil.int32ToIp(ip)), dst_mac is: \(SDLUtil.formatMacAddress(mac: dstMac))", for: .trace)
|
||||
await self.routeLayerPacket(dstMac: dstMac, type: type, data: data)
|
||||
} else {
|
||||
|
||||
@ -4,8 +4,9 @@
|
||||
//
|
||||
// Created by 安礼成 on 2026/2/5.
|
||||
//
|
||||
import Foundation
|
||||
|
||||
final class IdentitySnapshot {
|
||||
final class IdentitySnapshot: Snapshot {
|
||||
typealias IdentityID = UInt32
|
||||
|
||||
private let identityMap: [IdentityID: IdentityRuleMap]
|
||||
|
||||
10
Tun/Punchnet/Snapshot/Snapshot.swift
Normal file
10
Tun/Punchnet/Snapshot/Snapshot.swift
Normal file
@ -0,0 +1,10 @@
|
||||
//
|
||||
// Snapshot.swift
|
||||
// punchnet
|
||||
//
|
||||
// Created by 安礼成 on 2026/5/20.
|
||||
//
|
||||
|
||||
protocol Snapshot: AnyObject {
|
||||
|
||||
}
|
||||
@ -6,21 +6,21 @@
|
||||
//
|
||||
import Atomics
|
||||
|
||||
final class SnapshotPublisher<IdentitySnapshot: AnyObject> {
|
||||
private let atomic: ManagedAtomic<Unmanaged<IdentitySnapshot>>
|
||||
final class SnapshotPublisher<S: Snapshot> {
|
||||
private let atomic: ManagedAtomic<Unmanaged<S>>
|
||||
|
||||
init(initial snapshot: IdentitySnapshot) {
|
||||
init(initial snapshot: S) {
|
||||
self.atomic = ManagedAtomic(.passRetained(snapshot))
|
||||
}
|
||||
|
||||
func publish(_ snapshot: IdentitySnapshot) {
|
||||
func publish(_ snapshot: S) {
|
||||
let newRef = Unmanaged.passRetained(snapshot)
|
||||
let oldRef = atomic.exchange(newRef, ordering: .acquiring)
|
||||
oldRef.release()
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
func current() -> IdentitySnapshot {
|
||||
func current() -> S {
|
||||
atomic.load(ordering: .relaxed).takeUnretainedValue()
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user