Direct TCP/IP Channels
Use a raw `direct-tcpip` channel when your Swift code itself should speak one forwarded TCP stream.
SSHConnection.openDirectTCPIPChannel(...) is the raw forwarding primitive in Traversio.
It is the right tool when:
- your Swift code wants one tunnel to one target
- you are comfortable speaking the target protocol yourself
- you want a direct byte stream instead of a listener created for other tools
If another local application should connect to a local port that Traversio exposes, use Local Port Forwarding instead.
Mental Model
your Swift code
-> one SSH direct-tcpip channel
-> one remote TCP serviceThis API opens one channel directly from your code. Local, dynamic, and remote forwarding create listener-based workflows.
A Concrete Example
Suppose an HTTP service is only reachable from the SSH server side:
- remote service:
127.0.0.1:8080 - goal: from Swift, send one HTTP request and parse the raw bytes
This is a good fit for a direct channel:
import Traversio
@available(macOS 26.0, iOS 26.0, *)
func fetchRemoteHealth(configuration: SSHClientConfiguration) async throws -> String {
let output = try await SSHClient.withConnection(configuration: configuration) { connection in
let channel = try await connection.openDirectTCPIPChannel(
targetHost: "127.0.0.1",
targetPort: 8080,
originatorAddress: "127.0.0.1",
originatorPort: 0
)
try await channel.write(
"GET /health HTTP/1.1\r\n" +
"Host: 127.0.0.1\r\n" +
"Connection: close\r\n\r\n"
)
try await channel.sendEOF()
return try await channel.collectDataUntilClose()
}
return String(decoding: output.data, as: UTF8.self)
}When This Is Better Than Local Port Forwarding
Choose openDirectTCPIPChannel(...) when:
- the caller is your own Swift code
- you only need one logical TCP conversation
- you want direct access to the byte stream and EOF events
Choose local forwarding when:
- another local client should connect to
127.0.0.1:<port> - you want
URLSession, a browser, or a database tool to treat the tunnel like a normal local endpoint
Parameters
What the main parameters mean:
targetHostandtargetPortidentify the remote TCP service the SSH server should connect tooriginatorAddressandoriginatorPortare origin metadata reported to the remote side
The defaults are usually enough when origin metadata is not important for the target service.
What You Get Back
SSHDirectTCPIPChannel exposes:
write(_:)write(_ string: String)sendEOF()close()readChunk()nextEvent()eventscollectDataUntilClose()
Use readChunk() or events consistently on a given channel. One read style per stream keeps the control flow predictable.
Support Status
This raw path is one of the better-understood forwarding pieces in the current release.
Current state:
- the direct channel data path is live-validated against a real local OpenSSH 9.6 target
- it remains an expert API for raw byte streams
- wrapper lifetime follows the owning
SSHConnection