Browse Source

[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 <caiooliveirafarias0@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Co-committed-by: Maufeat <sahyno1996@gmail.com>
pull/3174/head
Maufeat 5 days ago
committed by crueter
parent
commit
bf68eede05
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 14
      src/core/hle/service/sockets/bsd.cpp
  2. 2
      src/core/hle/service/sockets/bsd.h
  3. 124
      src/core/hle/service/ssl/ssl.cpp

14
src/core/hle/service/sockets/bsd.cpp

@ -578,7 +578,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
} }
std::vector<Network::PollFD> host_pollfds(fds.size()); std::vector<Network::PollFD> 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; Network::PollFD result;
result.socket = file_descriptors[pollfd.fd]->socket.get(); result.socket = file_descriptors[pollfd.fd]->socket.get();
result.events = Translate(pollfd.events); result.events = Translate(pollfd.events);
@ -657,7 +657,11 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
const auto result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); const auto result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
if (result != Errno::SUCCESS) { if (result != Errno::SUCCESS) {
LOG_ERROR(Service, "Connect fd={} failed with errno={}", fd, static_cast<int>(result));
if (result == Errno::INPROGRESS || result == Errno::AGAIN) {
LOG_DEBUG(Service, "Connect fd={} in progress (non-blocking), errno={}", fd, static_cast<int>(result));
} else {
LOG_ERROR(Service, "Connect fd={} failed with errno={}", fd, static_cast<int>(result));
}
} else { } else {
LOG_INFO(Service, "Connect fd={} succeeded", fd); LOG_INFO(Service, "Connect fd={} succeeded", fd);
} }
@ -967,7 +971,11 @@ Expected<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
return Unexpected(Errno::MFILE); 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; return new_fd;
} }

2
src/core/hle/service/sockets/bsd.h

@ -179,7 +179,7 @@ private:
void BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept; void BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept;
std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
static inline std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors{};
/// Callback to parse and handle a received wifi packet. /// Callback to parse and handle a received wifi packet.
void OnProxyPacketReceived(const Network::ProxyPacket& packet); void OnProxyPacketReceived(const Network::ProxyPacket& packet);

124
src/core/hle/service/ssl/ssl.cpp

@ -157,22 +157,24 @@ private:
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u"); auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; }); 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) { 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 { } else {
*out_fd = -1; *out_fd = -1;
fd_to_close = duplicated_fd;
} }
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(fd);
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(duplicated_fd);
if (!sock.has_value()) { 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; return ResultInvalidSocket;
} }
socket = std::move(*sock); socket = std::move(*sock);
@ -325,7 +327,19 @@ private:
res = backend->GetServerCerts(&certs); res = backend->GetServerCerts(&certs);
if (res == ResultSuccess) { if (res == ResultSuccess) {
const std::vector<u8> certs_buf = SerializeServerCerts(certs); const std::vector<u8> 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<const u8>(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<u32>(certs.size()); out.certs_count = static_cast<u32>(certs.size());
out.certs_size = static_cast<u32>(certs_buf.size()); out.certs_size = static_cast<u32>(certs_buf.size());
} }
@ -664,119 +678,119 @@ class ISslServiceForSystem final : public ServiceFramework<ISslServiceForSystem>
{103, D<&ISslServiceForSystem::VerifySignature>, "VerifySignature"} {103, D<&ISslServiceForSystem::VerifySignature>, "VerifySignature"}
}; };
// clang-format on // clang-format on
RegisterHandlers(functions); RegisterHandlers(functions);
}; };
Result CreateContext() { Result CreateContext() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result GetContextCount() { Result GetContextCount() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result GetCertificates() { Result GetCertificates() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result GetCertificateBufSize() { Result GetCertificateBufSize() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result DebugIoctl() { Result DebugIoctl() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result SetInterfaceVersion() { Result SetInterfaceVersion() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result FlushSessionCache() { Result FlushSessionCache() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result SetDebugOption() { Result SetDebugOption() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result GetDebugOption() { Result GetDebugOption() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result ClearTls12FallbackFlag() { Result ClearTls12FallbackFlag() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result CreateContextForSystem() { Result CreateContextForSystem() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result SetThreadCoreMask() { Result SetThreadCoreMask() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result GetThreadCoreMask() { Result GetThreadCoreMask() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
Result VerifySignature() { Result VerifySignature() {
LOG_DEBUG(Service_SSL, "(STUBBED) called."); LOG_DEBUG(Service_SSL, "(STUBBED) called.");
// TODO (jarrodnorwell) // TODO (jarrodnorwell)
return ResultSuccess; return ResultSuccess;
}; };
}; };

Loading…
Cancel
Save