Wrapper for NIOSSHClient (swift nio ssh client example)

Hi all. I'm trying to create a wrapper for the NIOSSHClient example that can be found in the apple/swift-nio-ssh repo. I want to use the ssh library to run commands on an ssh server from iOS in the following way:

let ssh = SwiftNioSshWrapper(host: "...", port: 22, user: "...", password: "...")
do {
    try ssh.run(command: "./script.sh")
} catch {
    print(error)
}

I was able to create that wrapper. But I can only use this once. If I try to create an instance for a second time, an exception is thrown (and the app crashes). For some reason closing the connection doesn't work as expected. I have uploaded my current wrapper to the following gist (adding it here would be too much of code). The wrapper is based on the main.swift file from the NIOSSHClient example. I have only removed the listener parts (and added some prints).

When I create an instance of SwiftNioSshWrapper and do run ssh.run(command:), then the command is actually executed on the connected ssh server. But then, the channel is not closed. closing is printed to the command line. child channel closed is not printed anymore.

Then line try! childChannel.closeFuture.wait() is blocking endlessly. Debugging the code, I was able to find the actual line that blocks in the NIOSSH library:

private func partnerWriteEOF() {
    print("func partnerWriteEOF")
    self.context?.close(mode: .output, promise: nil)
    print("func partnerWriteEOF closed")
}

The method partnerWriteEOF() never returns. I'm stuck here due to limited knowledge in Swift and SSH.

Can someone here help me to analyze the issue further? Or is there any idea on how to fix this properly?

1 Like