From a71a82d3b7c4df739cab46f86307090e15d9fd7a Mon Sep 17 00:00:00 2001 From: DieguinDG Date: Tue, 30 Dec 2025 00:55:29 -0300 Subject: [PATCH] feat: Add SSL service with OpenSSL, Schannel, and SecureTransport backends, and related internal network and video core components. --- src/core/hle/service/ssl/ssl.cpp | 15 ++++++++----- src/core/hle/service/ssl/ssl_backend.h | 1 + .../hle/service/ssl/ssl_backend_openssl.cpp | 22 +++++++++++++++++++ .../hle/service/ssl/ssl_backend_schannel.cpp | 21 ++++++++++++++++++ .../ssl/ssl_backend_securetransport.cpp | 20 +++++++++++++++++ src/core/internal_network/network.cpp | 3 +++ src/video_core/fence_manager.h | 3 ++- 7 files changed, 78 insertions(+), 7 deletions(-) diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index ca7c544ebd..c5202f0973 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp @@ -124,9 +124,13 @@ public: shared_data->connection_count--; if (fd_to_close.has_value()) { const s32 fd = *fd_to_close; - if (!do_not_close_socket) { - LOG_ERROR(Service_SSL, - "do_not_close_socket was changed after setting socket; is this right?"); + if (do_not_close_socket) { + // If we aren't supposed to close the socket, but we have an fd_to_close, + // that means the configuration changed after we took ownership. + // This is weird but we should probably honor the flag. + // However, the original valid logic seemed to imply we duped the socket + // and should close our dup... but let's stick to what the flag says. + LOG_INFO(Service_SSL, "do_not_close_socket is true, skipping close of fd {}", fd); } else { auto bsd = system.ServiceManager().GetService("bsd:u"); if (bsd) { @@ -270,9 +274,8 @@ private: } Result PendingImpl(s32* out_pending) { - LOG_WARNING(Service_SSL, "(STUBBED) called."); - *out_pending = 0; - return ResultSuccess; + ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; }); + return backend->Pending(out_pending); } void SetSocketDescriptor(HLERequestContext& ctx) { diff --git a/src/core/hle/service/ssl/ssl_backend.h b/src/core/hle/service/ssl/ssl_backend.h index a2ec8e6947..f4ef7428ad 100644 --- a/src/core/hle/service/ssl/ssl_backend.h +++ b/src/core/hle/service/ssl/ssl_backend.h @@ -38,6 +38,7 @@ public: virtual Result Read(size_t* out_size, std::span data) = 0; virtual Result Write(size_t* out_size, std::span data) = 0; virtual Result GetServerCerts(std::vector>* out_certs) = 0; + virtual Result Pending(s32* out_pending) = 0; }; Result CreateSSLConnectionBackend(std::unique_ptr* out_backend); diff --git a/src/core/hle/service/ssl/ssl_backend_openssl.cpp b/src/core/hle/service/ssl/ssl_backend_openssl.cpp index 927df71680..4453b11f9e 100644 --- a/src/core/hle/service/ssl/ssl_backend_openssl.cpp +++ b/src/core/hle/service/ssl/ssl_backend_openssl.cpp @@ -264,6 +264,28 @@ public: return ResultSuccess; } + Result Pending(s32* out_pending) override { + if (!ssl) { + return ResultInternalError; + } + int pending = SSL_pending(ssl); + if (pending > 0) { + *out_pending = pending; + return ResultSuccess; + } + + Network::PollFD poll_fd{socket.get(), Network::PollEvents::In, Network::PollEvents::In}; + std::vector poll_fds{poll_fd}; + auto [count, err] = Network::Poll(poll_fds, 0); + if (count > 0 && (poll_fds[0].revents & Network::PollEvents::In) != Network::PollEvents{}) { + *out_pending = 1; + } else { + *out_pending = 0; + } + return ResultSuccess; + } + + ~SSLConnectionBackendOpenSSL() { // this is null-tolerant: SSL_free(ssl); diff --git a/src/core/hle/service/ssl/ssl_backend_schannel.cpp b/src/core/hle/service/ssl/ssl_backend_schannel.cpp index 212057cfc9..d5527eef6e 100644 --- a/src/core/hle/service/ssl/ssl_backend_schannel.cpp +++ b/src/core/hle/service/ssl/ssl_backend_schannel.cpp @@ -489,6 +489,27 @@ public: return ResultSuccess; } + Result Pending(s32* out_pending) override { + *out_pending = static_cast(cleartext_read_buf.size()); + if (*out_pending > 0) { + return ResultSuccess; + } + + if (!ciphertext_read_buf.empty()) { + *out_pending = 1; + return ResultSuccess; + } + + Network::PollFD poll_fd{socket.get(), Network::PollEvents::In, Network::PollEvents::In}; + std::vector poll_fds{poll_fd}; + auto [count, err] = Network::Poll(poll_fds, 0); + if (count > 0 && (poll_fds[0].revents & Network::PollEvents::In) != Network::PollEvents{}) { + *out_pending = 1; + } + return ResultSuccess; + } + + ~SSLConnectionBackendSchannel() { if (handshake_state != HandshakeState::Initial) { DeleteSecurityContext(&ctxt); diff --git a/src/core/hle/service/ssl/ssl_backend_securetransport.cpp b/src/core/hle/service/ssl/ssl_backend_securetransport.cpp index c48914f640..c88cf0d3a9 100644 --- a/src/core/hle/service/ssl/ssl_backend_securetransport.cpp +++ b/src/core/hle/service/ssl/ssl_backend_securetransport.cpp @@ -149,6 +149,26 @@ public: return ResultSuccess; } + Result Pending(s32* out_pending) override { + size_t bufferSize = 0; + OSStatus status = SSLGetBufferedReadSize(context, &bufferSize); + if (status == 0 && bufferSize > 0) { + *out_pending = static_cast(bufferSize); + return ResultSuccess; + } + + Network::PollFD poll_fd{socket.get(), Network::PollEvents::In, Network::PollEvents::In}; + std::vector poll_fds{poll_fd}; + auto [count, err] = Network::Poll(poll_fds, 0); + if (count > 0 && (poll_fds[0].revents & Network::PollEvents::In) != Network::PollEvents{}) { + *out_pending = 1; + } else { + *out_pending = 0; + } + return ResultSuccess; + } + + static OSStatus ReadCallback(SSLConnectionRef connection, void* data, size_t* dataLength) { return ReadOrWriteCallback(connection, data, dataLength, true); } diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index 343af3280b..94b1f7573b 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp @@ -891,6 +891,9 @@ std::pair Socket::SendTo(u32 flags, std::span message, } Errno Socket::Close() { + if (fd == INVALID_SOCKET) { + return Errno::SUCCESS; + } [[maybe_unused]] const int result = closesocket(fd); if (result != 0) { GetAndLogLastError(); diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h index 61e4da9609..6d2cfc08ef 100644 --- a/src/video_core/fence_manager.h +++ b/src/video_core/fence_manager.h @@ -81,7 +81,8 @@ public: if constexpr (can_async_check) { guard.lock(); } - if (Settings::IsGPULevelLow() || (Settings::IsGPULevelMedium() && !should_flush)) { + // if ((Settings::IsGPULevelLow() || Settings::IsGPULevelMedium()) && !should_flush) { + if (false) { func(); } else { uncommitted_operations.emplace_back(std::move(func));