// // SDLanServer.swift // Tun // // Created by 安礼成 on 2024/1/31. // import Foundation import NIOCore import NIOPosix // 处理和sn-server服务器之间的通讯 final class SDLUDPHole: ChannelInboundHandler { typealias InboundIn = AddressedEnvelope struct SDLHoleDatagram { let remoteAddress: SocketAddress let message: SDLHoleMessage } enum State { case idle case running case stopped } private var state: State = .idle private let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) private var channel: Channel? let messageStream: AsyncThrowingStream private let messageContinuation: AsyncThrowingStream.Continuation init() throws { let (stream, continuation) = AsyncThrowingStream.makeStream(of: SDLHoleDatagram.self, bufferingPolicy: .bufferingNewest(2048)) self.messageStream = stream self.messageContinuation = continuation } func start() throws -> SocketAddress { guard self.state == .idle else { guard let localAddress = self.channel?.localAddress else { throw SDLUDPHoleError.invalidLocalAddress } return localAddress } let bootstrap = DatagramBootstrap(group: group) .channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1) .channelInitializer { channel in channel.pipeline.addHandler(self) } // 绑定到IPv4通配地址,只处理IPv4流量 let channel = try bootstrap.bind(host: "0.0.0.0", port: 0).wait() guard let localAddress = channel.localAddress else { throw SDLUDPHoleError.invalidLocalAddress } self.channel = channel self.state = .running return localAddress } // --MARK: ChannelInboundHandler delegate func channelRead(context: ChannelHandlerContext, data: NIOAny) { let envelope = unwrapInboundIn(data) var buffer = envelope.data let remoteAddress = envelope.remoteAddress do { if let message = try SDLHoleMessage.decode(buffer: &buffer) { self.messageContinuation.yield(SDLHoleDatagram(remoteAddress: remoteAddress, message: message)) } else { SDLLogger.log("[SDLUDPHole] decode message, get null", category: .udpHole) } } catch let err { SDLLogger.log("[SDLUDPHole] decode message, get error: \(err)", category: .udpHole) self.messageContinuation.finish(throwing: err) } } func channelInactive(context: ChannelHandlerContext) { self.messageContinuation.finish(throwing: SDLUDPHoleError.closed) } func errorCaught(context: ChannelHandlerContext, error: any Error) { context.close(promise: nil) self.messageContinuation.finish(throwing: SDLUDPHoleError.errorCaught) } // MARK: 处理写入逻辑 func send(type: SDLPacketType, data: Data, remoteAddress: SocketAddress) { guard self.state == .running, let channel = self.channel else { return } var buffer = channel.allocator.buffer(capacity: data.count + 1) buffer.writeBytes([type.rawValue]) buffer.writeBytes(data) let envelope = AddressedEnvelope(remoteAddress: remoteAddress, data: buffer) let promise = channel.eventLoop.makePromise(of: Void.self) channel.eventLoop.execute { channel.writeAndFlush(envelope, promise: promise) } promise.futureResult.whenFailure { [weak self] err in self?.messageContinuation.finish(throwing: SDLUDPHoleError.sendFaied(err)) } } func stop() { guard self.state != .stopped else { return } self.state = .stopped self.messageContinuation.finish() let channel = self.channel self.channel = nil try? channel?.close().wait() try? self.group.syncShutdownGracefully() SDLLogger.log("[SDLUDPHole] stopped", category: .udpHole) } deinit { SDLLogger.log("[SDLUDPHole] deinit", category: .udpHole) } }