Using SSH on Windows?

Has anyone managed to use SSH in Swift on Windows?

NIOSSH is not working because NIO itself doesn't support Windows.

I tried packages that wrap libssh2 but that expects that libssh2 is already installed on the target computer and I just can't require that for my users.

I could try to build and ship libssh2 myself but I have no idea how to do that. C/C++ interoperability examples have 1-2 files of C/C++. However libssh2 has dependencies on cryptography libraries like OpenSSL and I think I'd have to ship that too?

I would recommend that you do not use OpenSSL if possible and try to use the SChannel libraries from Windows. However, you would need to ship libssh2 for the time being until NIO is possible to use on Windows. From a quick glance at the library, the WinCNG backend should allow you to use BCrypt as the backing and avoid the OpenSSL dependency at the very least.

If you want an example of a more complex integration of C/C++ codebases I would recommend taking a look at GitHub - compnerd/swift-firebase: Swift Interface for Firebase which actually pulls in a very large set of C/C++ code and uses it with interop.

Thank you a lot! As someone who never compiled more than a single file of C/C++ this looks extremely complicated but at least it seems doable. The fact that it can be built with SPM and cmake is not mandatory gives me some hope.

It is curious to me why Swift doesn't have these pretty common dependencies wrapped when other languages released at almost the same time do (like Rust and Go). Is it technically harder to do it in Swift or there was just not much demand/contributions?

I know you started to port NIO to Windows some time ago but it wasn't completed. Do you know if there's a lot of work left to do for NIO to be usable on Windows? Or if we could see something in the next 1-2 years?

No, you will not escape CMake, libssh will need to be built with CMake, or you will have to make intrusive changes to build with SPM. The trick that swift-firebase takes is that the dependency is prebuilt as a nuget package that is then extracted and built against.

Which common dependencies? At least on Windows, the common dependencies would be the Windows SDK, which should pretty much be directly importable. The interop means that you don't really need to wrap the dependency, you just directly use it, and Swift will handle the FFI needed to use the library. It feels like I'm missing your point of what the wrapping here means.

I think that most of that work would need to be redone entirely. The last attempt was stalled when the suggestion was to create a separate project for supporting Windows in the image of swift-nio-transport-services. Such a project is a very large undertaking. Combined with the need to rework the entire NIO model to support that (the NIO model is based around BSD and the IO Completion Port model didn't seem to fit when I last tried), I don't think that without significant help from others it is likely to be feasible in the short term.

Don't take this as criticism, I know it's a huge effort to support Windows and it's a very different platform than MacOS and Linux.

Common dependencies to me mean dependencies on external systems and services. I don't think I know a single app that is entirely offline nowadays.

I'll give my concrete example to better illustrate this. I'm migrating a command line Rust app to Swift, Windows + Mac, that downloads some files from MSGraph and uploads them to a server using SFTP.

The first thing I remarked was that Swift has no MSGraph SDK when even languages like Haskell do. (again, not criticism, I know someone has to write it, I just wonder why no one did it in Swift when I couldn't find another language without at least some basic support).

Then I started writing a minimal one myself but async-http-client doesn't compile on Windows because of NIO and URLSession crashes pretty regularly because of timeout issues and socket reuse. Cancel `DispatchSource` before closing socket (#4791) by lxbndr · Pull Request #4859 · apple/swift-corelibs-foundation · GitHub

I tried using cURL but again, it seems I have to build it myself as I do with libssh, both depending on some crypto library.

But I digressed a bit, what I mean by wrapped libraries here is just Swift Packages that bundle a precompiled version of a C/C++ library and optionally add some Swift niceness over it.

For example, there are libraries for cURL (GitHub - khoi/curl-swift: libcurl wrapper for Swift) and SSH (GitHub - jakeheis/Shout: SSH made easy in Swift) but they expect cURL/libssh to be installed already on the target computer. I don't think that's a reasonable expectation when deploying client facing apps and I don't think there's another languages that does that. I also don't think most Swift developers will manage to use CMake, and a precompiled lib for each platform will solve this.

I think having this networking code rock solid would be good first step for building small apps on Windows. I imagine bigger apps might also need at least SQL wrappers and analytics, which are not yet easily usable from existing Swift Packages.

What you are describing is independent of the platform - each of these platforms is in the same boat for this.

There are libraries for networking which function. cURL is a very common one, but more importantly, there is Foundation which has URLSession. The timed paths are known to have some issues on Windows, but that is something that someone interested in improving the networking stack would need to look into (and seemingly might be related to the structure of Foundation's handling of the sockets). The work that @lxbndr has started on that is a good first step, but it does require some investigation whether it breaks some of the expectations around Foundation.

I've never even encountered MSGraph until this point. A cursory look seems to indicate that Microsoft does provide SDKs for it for .NET, Python, TypeScript. Perhaps you could petition them to provide a SDK for Swift? But, I agree with the general point of it would be great if vendors were to implicitly provide Swift libraries. Unfortunately, that is not in my control, and I instead focus on trying to make it easier for them to do so.

I think that this is a knowledge issue. cURL doesn't require you to build OpenSSL, it is happy to use S/Channel on Windows, which I would highly recommend. Doing so ensures that you are also tied into the system's CRL and GPO.

I think that we fundamentally disagree here. I think that it is perfectly reasonable for the packages to assume that the dependency is provided for. The application developer is responsible for determining the dependencies and what is vended as part of their application distribution.

As a concrete example, if you look at Arc, there are dependencies on a large number of C/C++ and Swift libraries. However, The Browser Company takes responsibility for their dependencies, builds, packages, and distributes them as appropriate. There are libraires which are expected to be provided by the user even: e.g. MSVCRT.

I don't agree with this - the toolchain itself depends on SQLite for llbuild, SPM, swift-driver. Both SPM and swift-driver are Swift packages which are routinely built and used.

From what I could understand from your response is that SPM makes it difficult to consume non-native, external packages. I think I would agree with that statement. Since you mentioned rust, AIUI, the answer to the same problem in rust is to use sys crates, where you build and package up the dependency. In the SPM world, the equivalent to this is system libraries (SE-0208). On Windows, the desire is to use nuget for system packages, but that work is incomplete (and there are other issues that I think are more important). However, patches to improve the nuget integration on Windows would be gladly welcomed :slight_smile:

Yes and no. A lot of packages are dependent on NIO, like the swift-nio-ssh that would solve my problem. Vapor, FluentKit, aws-sdk-swift and almost all server packages depend on NIO or don't work on Windows for other reasons.

I agree with the sentiment, it's why I wanted to write an SDK myself. However, without a stable foundation for networking or an easy way to integrate libs like cURL, it's quite hard to justify the investment.

I totally agree it's a knowledge issue and thank you for the suggestion, it doesn't seem that hard to build cURL with S/Channel as I initially thought. I'll see where this leads me.

I also think it's a bit of a context issue. The internal tools we use where I work at are all MacOS exclusive and sometimes Linux. We have no Windows knowledge. However, some department wanted to try using Windows and the business agreed that if it's not too much hassle, we can try to port some tools to Windows. That pretty much means that any new hire should install Swift in a Windows virtual machine, run swift build and be ready to go, as we do on other platforms. It also means that everyone should be able to touch this codebase, even if they're a junior developer, which is why cmake is a banned requirement.

The only acceptable exception to cmake for C/C++ dependencies is if someone can build a static library, wrap it in a swift package, and our other tools will just pull it and it will just work.

I agree with that. What I meant before is that me, as a swift package user, I want that package to provide everything it needs to build and function. I was looking at system libraries and it seems like the solution I'd like, but as you said, it seems incomplete on Windows. I had no idea nuget integration is planned, that seems awesome!

Thank you for taking your time for such detailed answers, I really appreciate it.

Just as a side-remark: I think everyone would like e.g. SwiftNIO to work on Windows (and this is a very good thing about Swift, that the community understands and likes the efforts made for Windows). That said, note that supporting Windows for network-centric libraries very often lags behind, take e.g Python with Flask+gunicorn which also does not run on Windows (and this is a very common combination for Python!), and for a very long time NGINX did not work on Windows (could be that it is still not as good as on Linux). I hope that more people will join the effort of making SwiftNIO run on Windows (I am not an expert here myself). Thanks to everyone helping :+1:

1 Like