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.