// // Session.swift // sdlan // Session是增加了有效时间的 // Created by 安礼成 on 2025/7/14. // import Foundation import NIOCore import Darwin struct Session: @unchecked Sendable { enum AddressType: String, Hashable { case v4 case v6 init?(socketAddress: SocketAddress) { switch socketAddress { case .v4: self = .v4 case .v6: self = .v6 default: return nil } } init?(packetType: LayerPacket.PacketType) { switch packetType { case .arp, .ipv4: self = .v4 case .ipv6: self = .v6 default: return nil } } } // 在内部的通讯的ip地址, 整数格式 let dstMac: Data // 对端的主机在nat上映射的端口信息 let natAddress: SocketAddress // 当前会话对应的外层地址族 let addressType: AddressType // 最后使用时间 var lastTimestamp: Int32 init?(dstMac: Data, natAddress: SocketAddress) { guard let addressType = AddressType(socketAddress: natAddress) else { return nil } self.dstMac = dstMac self.natAddress = natAddress self.addressType = addressType self.lastTimestamp = Int32(Date().timeIntervalSince1970) } mutating func updateLastTimestamp(_ lastTimestamp: Int32) { self.lastTimestamp = lastTimestamp } } actor SessionManager { private var sessions: [Data: [Session.AddressType: Session]] = [:] // session的有效时间 private let ttl: Int32 = 10 func getSession(toAddress: Data, preferredType: Session.AddressType? = nil) -> Session? { let timestamp = Int32(Date().timeIntervalSince1970) guard var sessions = self.sessions[toAddress] else { return nil } sessions = sessions.filter { $0.value.lastTimestamp + ttl >= timestamp } guard !sessions.isEmpty else { self.sessions.removeValue(forKey: toAddress) return nil } guard var session = self.selectSession(in: sessions, preferredType: preferredType) else { self.sessions[toAddress] = sessions return nil } session.updateLastTimestamp(timestamp) sessions[session.addressType] = session self.sessions[toAddress] = sessions return session } func addSession(session: Session) { let timestamp = Int32(Date().timeIntervalSince1970) var sessions = self.sessions[session.dstMac, default: [:]] sessions = sessions.filter { $0.value.lastTimestamp + ttl >= timestamp && $0.key != session.addressType } sessions[session.addressType] = session self.sessions[session.dstMac] = sessions } func removeSession(dstMac: Data) { self.sessions.removeValue(forKey: dstMac) } private func selectSession(in sessions: [Session.AddressType: Session], preferredType: Session.AddressType?) -> Session? { if let preferredType { if let preferred = sessions[preferredType] { return preferred } } return sessions.values.max(by: { $0.lastTimestamp < $1.lastTimestamp }) } }