zhuhaow/NEKit

View on GitHub
src/Socket/ProxySocket/DirectProxySocket.swift

Summary

Maintainability
A
2 hrs
Test Coverage
import Foundation

/// This class just forwards data directly. 
/// - note: It is designed to work with tun2socks only.
public class DirectProxySocket: ProxySocket {
    enum DirectProxyReadStatus: CustomStringConvertible {
        case invalid,
        forwarding,
        stopped

        var description: String {
            switch self {
            case .invalid:
                return "invalid"
            case .forwarding:
                return "forwarding"
            case .stopped:
                return "stopped"
            }
        }
    }

    enum DirectProxyWriteStatus {
        case invalid,
        forwarding,
        stopped

        var description: String {
            switch self {
            case .invalid:
                return "invalid"
            case .forwarding:
                return "forwarding"
            case .stopped:
                return "stopped"
            }
        }
    }

    private var readStatus: DirectProxyReadStatus = .invalid
    private var writeStatus: DirectProxyWriteStatus = .invalid

    public var readStatusDescription: String {
        return readStatus.description
    }

    public var writeStatusDescription: String {
        return writeStatus.description
    }

    /**
     Begin reading and processing data from the socket.

     - note: Since there is nothing to read and process before forwarding data, this just calls `delegate?.didReceiveRequest`.
     */
    override public func openSocket() {
        super.openSocket()

        guard !isCancelled else {
            return
        }

        if let address = socket.destinationIPAddress, let port = socket.destinationPort {
            session = ConnectSession(host: address.presentation, port: Int(port.value))

            observer?.signal(.receivedRequest(session!, on: self))
            delegate?.didReceive(session: session!, from: self)
        } else {
            forceDisconnect()
        }
    }

    /**
     Response to the `AdapterSocket` on the other side of the `Tunnel` which has succefully connected to the remote server.
     
     - parameter adapter: The `AdapterSocket`.
     */
    override public func respondTo(adapter: AdapterSocket) {
        super.respondTo(adapter: adapter)

        guard !isCancelled else {
            return
        }

        readStatus = .forwarding
        writeStatus = .forwarding

        observer?.signal(.readyForForward(self))
        delegate?.didBecomeReadyToForwardWith(socket: self)
    }

    /**
     The socket did read some data.

     - parameter data:    The data read from the socket.
     - parameter from:    The socket where the data is read from.
     */
    override open func didRead(data: Data, from: RawTCPSocketProtocol) {
        super.didRead(data: data, from: from)
        delegate?.didRead(data: data, from: self)
    }

    /**
     The socket did send some data.

     - parameter data:    The data which have been sent to remote (acknowledged). Note this may not be available since the data may be released to save memory.
     - parameter by:    The socket where the data is sent out.
     */
    override open func didWrite(data: Data?, by: RawTCPSocketProtocol) {
        super.didWrite(data: data, by: by)
        delegate?.didWrite(data: data, by: self)
    }
}