From bf68eede05cc825373dc59b2605b213968969d95 Mon Sep 17 00:00:00 2001 From: Maufeat Date: Wed, 17 Dec 2025 06:32:22 +0100 Subject: [PATCH] [bsd, ssl] fix connection between bsd:u and bsd:s and file descriptor copy (#3172) as seen in repeated epic games api connection in sonic Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3172 Reviewed-by: Caio Oliveira Reviewed-by: CamilleLaVey Co-authored-by: Maufeat Co-committed-by: Maufeat --- src/core/hle/service/sockets/bsd.cpp | 14 ++- src/core/hle/service/sockets/bsd.h | 2 +- src/core/hle/service/ssl/ssl.cpp | 124 +++++++++++++++------------ 3 files changed, 81 insertions(+), 59 deletions(-) diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index d6c06bb9b4..55b428e353 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -578,7 +578,7 @@ std::pair BSD::PollImpl(std::vector& write_buffer, std::span host_pollfds(fds.size()); - std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) { + std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [](PollFD pollfd) { Network::PollFD result; result.socket = file_descriptors[pollfd.fd]->socket.get(); result.events = Translate(pollfd.events); @@ -657,7 +657,11 @@ Errno BSD::ConnectImpl(s32 fd, std::span addr) { const auto result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); if (result != Errno::SUCCESS) { - LOG_ERROR(Service, "Connect fd={} failed with errno={}", fd, static_cast(result)); + if (result == Errno::INPROGRESS || result == Errno::AGAIN) { + LOG_DEBUG(Service, "Connect fd={} in progress (non-blocking), errno={}", fd, static_cast(result)); + } else { + LOG_ERROR(Service, "Connect fd={} failed with errno={}", fd, static_cast(result)); + } } else { LOG_INFO(Service, "Connect fd={} succeeded", fd); } @@ -967,7 +971,11 @@ Expected BSD::DuplicateSocketImpl(s32 fd) { return Unexpected(Errno::MFILE); } - file_descriptors[new_fd] = file_descriptors[fd]; + file_descriptors[new_fd] = FileDescriptor{ + .socket = file_descriptors[fd]->socket, + .flags = file_descriptors[fd]->flags, + .is_connection_based = file_descriptors[fd]->is_connection_based, + }; return new_fd; } diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index ccc6a7d7f2..77d17377ca 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -179,7 +179,7 @@ private: void BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept; - std::array, MAX_FD> file_descriptors; + static inline std::array, MAX_FD> file_descriptors{}; /// Callback to parse and handle a received wifi packet. void OnProxyPacketReceived(const Network::ProxyPacket& packet); diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index 0b0108bbd5..5a1ae0dbc9 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp @@ -157,22 +157,24 @@ private: auto bsd = system.ServiceManager().GetService("bsd:u"); ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; }); - // Based on https://switchbrew.org/wiki/SSL_services#SetSocketDescriptor + auto res = bsd->DuplicateSocketImpl(fd); + if (!res.has_value()) { + LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd); + return ResultInvalidSocket; + } + + const s32 duplicated_fd = *res; + if (do_not_close_socket) { - auto res = bsd->DuplicateSocketImpl(fd); - if (!res.has_value()) { - LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd); - return ResultInvalidSocket; - } - fd = *res; - fd_to_close = fd; - *out_fd = fd; + *out_fd = duplicated_fd; } else { *out_fd = -1; + fd_to_close = duplicated_fd; } - std::optional> sock = bsd->GetSocket(fd); + + std::optional> sock = bsd->GetSocket(duplicated_fd); if (!sock.has_value()) { - LOG_ERROR(Service_SSL, "invalid socket fd {}", fd); + LOG_ERROR(Service_SSL, "invalid socket fd {} after duplication", duplicated_fd); return ResultInvalidSocket; } socket = std::move(*sock); @@ -325,7 +327,19 @@ private: res = backend->GetServerCerts(&certs); if (res == ResultSuccess) { const std::vector certs_buf = SerializeServerCerts(certs); - ctx.WriteBuffer(certs_buf); + if (ctx.CanWriteBuffer()) { + const size_t buffer_size = ctx.GetWriteBufferSize(); + if (certs_buf.size() <= buffer_size) { + ctx.WriteBuffer(certs_buf); + } else { + LOG_WARNING(Service_SSL, "Certificate buffer too small: {} bytes needed, {} bytes available", + certs_buf.size(), buffer_size); + ctx.WriteBuffer(std::span(certs_buf.data(), buffer_size)); + } + } else { + LOG_DEBUG(Service_SSL, "No output buffer provided for certificates ({} bytes)", certs_buf.size()); + } + out.certs_count = static_cast(certs.size()); out.certs_size = static_cast(certs_buf.size()); } @@ -664,119 +678,119 @@ class ISslServiceForSystem final : public ServiceFramework {103, D<&ISslServiceForSystem::VerifySignature>, "VerifySignature"} }; // clang-format on - + RegisterHandlers(functions); }; - + Result CreateContext() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result GetContextCount() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result GetCertificates() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result GetCertificateBufSize() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result DebugIoctl() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result SetInterfaceVersion() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result FlushSessionCache() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result SetDebugOption() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result GetDebugOption() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result ClearTls12FallbackFlag() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result CreateContextForSystem() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result SetThreadCoreMask() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result GetThreadCoreMask() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; - + Result VerifySignature() { LOG_DEBUG(Service_SSL, "(STUBBED) called."); - + // TODO (jarrodnorwell) - + return ResultSuccess; }; };