Client & connection

SSHClient

Stateless entry point. SSHClient.Configuration is a typealias for SSHClientConfiguration.

public enum SSHClient {
    public typealias Configuration = SSHClientConfiguration

    public static func connect(configuration: SSHClientConfiguration) async throws -> SSHConnection
    public static func discoverAuthenticationMethods(
        configuration: SSHClientConfiguration
    ) async throws -> SSHAuthenticationDiscoveryResult

    public static func withConnection<Result>(
        _ configuration: SSHClientConfiguration,
        operation: (SSHConnection) async throws -> Result
    ) async throws -> Result
}

connect and discoverAuthenticationMethods also have callback variants. withConnection is async-only. A separate SSHClient.discoverHostKey entry point on Host trust performs a transport-only handshake to collect a server’s fingerprint before any authentication.

SSHClientConfiguration

public struct SSHClientConfiguration: Sendable {
    public var host: String
    public var port: UInt16
    public var username: String
    public var authentication: SSHAuthentication
    public var hostKeyPolicy: SSHHostKeyPolicy
    public var timeout: TimeInterval
    public var logHandler: SSHLogHandler?
    public var proxyRoute: SSHProxyRoute?
    public var algorithmProfile: SSHAlgorithmProfile

    public init(
        host: String,
        port: UInt16 = 22,
        username: String,
        authentication: SSHAuthentication,
        hostKeyPolicy: SSHHostKeyPolicy,
        timeout: TimeInterval = 30,
        logHandler: SSHLogHandler? = nil,
        proxyRoute: SSHProxyRoute? = nil,
        algorithmProfile: SSHAlgorithmProfile = .modern
    )

    public func diagnosticReport(
        phase: String = "configuration",
        metadata: [String: String] = [:],
        recentEvents: [SSHLogEvent] = []
    ) -> SSHDiagnosticReport
}

SSHProxyRoute

public enum SSHProxyRoute: Sendable {
    case socks5(SSHProxyEndpoint)
    case httpConnect(SSHProxyEndpoint)
    case proxyJump(SSHJumpHost)
}

SSHProxyEndpoint

public struct SSHProxyEndpoint: Sendable {
    public var host: String
    public var port: UInt16
    public var username: String?
    public var password: String?

    public init(host: String, port: UInt16, username: String? = nil, password: String? = nil)
}

SSHJumpHost

public struct SSHJumpHost: Sendable {
    public var host: String
    public var port: UInt16
    public var username: String
    public var authentication: SSHAuthentication
    public var hostKeyPolicy: SSHHostKeyPolicy
    public var timeout: TimeInterval
    public var algorithmProfile: SSHAlgorithmProfile

    public init(
        host: String,
        port: UInt16 = 22,
        username: String,
        authentication: SSHAuthentication,
        hostKeyPolicy: SSHHostKeyPolicy,
        timeout: TimeInterval = 30,
        algorithmProfile: SSHAlgorithmProfile = .modern
    )
}

SSHConnection

One SSHConnection owns one libssh session and runs one active high-level job at a time.

public final class SSHConnection: @unchecked Sendable {
    public var hostKeyFingerprint: SSHHostKeyFingerprint? { get }

    public func diagnosticReport(
        phase: String = "connected",
        metadata: [String: String] = [:],
        recentEvents: [SSHLogEvent] = []
    ) -> SSHDiagnosticReport

    public func execute(_ command: String) async throws -> SSHCommandResult
    public func openCommand(_ command: String) async throws -> SSHCommand

    public func openShell(
        terminalType: String = "xterm-256color",
        columns: UInt16 = 80,
        rows: UInt16 = 24,
        eventHandler: @escaping @Sendable (SSHShellEvent) -> Void
    ) async throws -> SSHShell

    public func openSFTP() async throws -> SFTPClient
    public func openDirectTCPChannel(host: String, port: UInt16) async throws -> SSHTunnelChannel

    public func startLocalForward(
        localHost: String = "127.0.0.1",
        localPort: UInt16 = 0,
        remoteHost: String,
        remotePort: UInt16
    ) async throws -> SSHPortForward

    public func startRemoteForward(
        remoteHost: String = "127.0.0.1",
        remotePort: UInt16 = 0,
        localHost: String,
        localPort: UInt16
    ) async throws -> SSHPortForward

    public func startDynamicForward(
        localHost: String = "127.0.0.1",
        localPort: UInt16 = 0,
        username: String? = nil,
        password: String? = nil
    ) async throws -> SSHPortForward

    public func close() async throws
}

Every method above (except diagnosticReport and the property) has a matching callback overload with callbackQueue: + completion:. The async overloads route Task cancellation into the same socket-shutdown path described in Architecture.