import Foundation /** The base proxy server class. This proxy does not listen on any port. */ open class ProxyServer: NSObject, TunnelDelegate { typealias TunnelArray = [Tunnel] /// The port of proxy server. public let port: Port /// The address of proxy server. public let address: IPAddress? /// The type of the proxy server. /// /// This can be set to anything describing the proxy server. public let type: String /// The description of proxy server. open override var description: String { return "<\(type) address:\(String(describing: address)) port:\(port)>" } open var observer: Observer? var tunnels: TunnelArray = [] /** Create an instance of proxy server. - parameter address: The address of proxy server. - parameter port: The port of proxy server. - warning: If you are using Network Extension, you have to set address or you may not able to connect to the proxy server. */ public init(address: IPAddress?, port: Port) { self.address = address self.port = port type = "\(Swift.type(of: self))" super.init() self.observer = ObserverFactory.currentFactory?.getObserverForProxyServer(self) } /** Start the proxy server. - throws: The error occured when starting the proxy server. */ open func start() throws { QueueFactory.executeOnQueueSynchronizedly { GlobalIntializer.initalize() self.observer?.signal(.started(self)) } } /** Stop the proxy server. */ open func stop() { QueueFactory.executeOnQueueSynchronizedly { for tunnel in tunnels { tunnel.forceClose() } observer?.signal(.stopped(self)) } } /** Delegate method when the proxy server accepts a new ProxySocket from local. When implementing a concrete proxy server, e.g., HTTP proxy server, the server should listen on some port and then wrap the raw socket in a corresponding ProxySocket subclass, then call this method. - parameter socket: The accepted proxy socket. */ func didAcceptNewSocket(_ socket: ProxySocket) { observer?.signal(.newSocketAccepted(socket, onServer: self)) let tunnel = Tunnel(proxySocket: socket) tunnel.delegate = self tunnels.append(tunnel) tunnel.openTunnel() } // MARK: TunnelDelegate implementation /** Delegate method when a tunnel closed. The server will remote it internally. - parameter tunnel: The closed tunnel. */ func tunnelDidClose(_ tunnel: Tunnel) { observer?.signal(.tunnelClosed(tunnel, onServer: self)) guard let index = tunnels.firstIndex(of: tunnel) else { // things went strange return } tunnels.remove(at: index) } }