feat: Add SSL service with OpenSSL, Schannel, and SecureTransport backends, and related internal network and video core components.

This commit is contained in:
2025-12-30 00:55:29 -03:00
parent bd1d270e97
commit a71a82d3b7
7 changed files with 78 additions and 7 deletions

View File

@@ -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<Service::Sockets::BSD>("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) {

View File

@@ -38,6 +38,7 @@ public:
virtual Result Read(size_t* out_size, std::span<u8> data) = 0;
virtual Result Write(size_t* out_size, std::span<const u8> data) = 0;
virtual Result GetServerCerts(std::vector<std::vector<u8>>* out_certs) = 0;
virtual Result Pending(s32* out_pending) = 0;
};
Result CreateSSLConnectionBackend(std::unique_ptr<SSLConnectionBackend>* out_backend);

View File

@@ -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<Network::PollFD> 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);

View File

@@ -489,6 +489,27 @@ public:
return ResultSuccess;
}
Result Pending(s32* out_pending) override {
*out_pending = static_cast<s32>(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<Network::PollFD> 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);

View File

@@ -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<s32>(bufferSize);
return ResultSuccess;
}
Network::PollFD poll_fd{socket.get(), Network::PollEvents::In, Network::PollEvents::In};
std::vector<Network::PollFD> 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);
}

View File

@@ -891,6 +891,9 @@ std::pair<s32, Errno> Socket::SendTo(u32 flags, std::span<const u8> message,
}
Errno Socket::Close() {
if (fd == INVALID_SOCKET) {
return Errno::SUCCESS;
}
[[maybe_unused]] const int result = closesocket(fd);
if (result != 0) {
GetAndLogLastError();

View File

@@ -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));