diff --git a/src/common/settings.h b/src/common/settings.h index ca54239ec..8c769c5ff 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -663,12 +663,12 @@ struct Values { Setting airplane_mode{linkage, false, "airplane_mode", Category::Network}; Setting network_interface{linkage, std::string(), "network_interface", Category::Network}; - Setting lobby_api_url{linkage, "https://api.ynet-fun.xyz", "lobby_api_url", + Setting lobby_api_url{linkage, "api.ynet-fun.xyz", "lobby_api_url", Category::Network}; // WebService Setting enable_telemetry{linkage, false, "enable_telemetry", Category::WebService}; - Setting web_api_url{linkage, "https://api.ynet-fun.xyz", "web_api_url", + Setting web_api_url{linkage, "api.ynet-fun.xyz", "web_api_url", Category::WebService}; Setting citron_username{linkage, std::string(), "citron_username", Category::WebService}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1173462e5..8778364f0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -833,6 +833,9 @@ add_library(core STATIC hle/service/nim/nim.h hle/service/npns/npns.cpp hle/service/npns/npns.h + hle/service/nex/nex.cpp + hle/service/nex/nex.h + hle/service/nex/nex_results.h hle/service/ns/account_proxy_interface.cpp hle/service/ns/account_proxy_interface.h hle/service/ns/application_manager_interface.cpp diff --git a/src/core/hle/service/nex/nex.cpp b/src/core/hle/service/nex/nex.cpp new file mode 100644 index 000000000..d797a4b51 --- /dev/null +++ b/src/core/hle/service/nex/nex.cpp @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/nex/nex.h" +#include "core/hle/service/nex/nex_results.h" +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" +#include "common/logging/log.h" + +namespace Service::Nex { + +class INexService final : public ServiceFramework { +public: + explicit INexService(Core::System& system_) : ServiceFramework{system_, "nex"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &INexService::Initialize, "Initialize"}, + {1, &INexService::Finalize, "Finalize"}, + {2, &INexService::CreateClient, "CreateClient"}, + {3, &INexService::DestroyClient, "DestroyClient"}, + {4, &INexService::Connect, "Connect"}, + {5, &INexService::Disconnect, "Disconnect"}, + {10, &INexService::GetConnectionState, "GetConnectionState"}, + {11, &INexService::GetServerTime, "GetServerTime"}, + {20, &INexService::CreateMatchmakeSession, "CreateMatchmakeSession"}, + {21, &INexService::JoinMatchmakeSession, "JoinMatchmakeSession"}, + {22, &INexService::LeaveMatchmakeSession, "LeaveMatchmakeSession"}, + {30, &INexService::SendData, "SendData"}, + {31, &INexService::ReceiveData, "ReceiveData"}, + {40, &INexService::GetServiceURL, "GetServiceURL"}, + {41, &INexService::SetServiceURL, "SetServiceURL"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Initialize(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNexNotAvailable); + } + + void Finalize(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void CreateClient(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNexNotAvailable); + } + + void DestroyClient(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void Connect(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNexConnectionFailed); + } + + void Disconnect(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void GetConnectionState(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); // Not connected + } + + void GetServerTime(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultNexNotAvailable); + rb.Push(0); + } + + void CreateMatchmakeSession(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNexNotAvailable); + } + + void JoinMatchmakeSession(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNexNotAvailable); + } + + void LeaveMatchmakeSession(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void SendData(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNexNotAvailable); + } + + void ReceiveData(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNexNotAvailable); + } + + void GetServiceURL(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNexNotAvailable); + } + + void SetServiceURL(HLERequestContext& ctx) { + LOG_WARNING(Service, "(STUBBED) Nex service called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultNexNotAvailable); + } +}; + +void LoopProcess(Core::System& system) { + auto server_manager = std::make_unique(system); + + server_manager->RegisterNamedService("nex", std::make_shared(system)); + ServerManager::RunServer(std::move(server_manager)); +} + +} // namespace Service::Nex diff --git a/src/core/hle/service/nex/nex.h b/src/core/hle/service/nex/nex.h new file mode 100644 index 000000000..215271e9f --- /dev/null +++ b/src/core/hle/service/nex/nex.h @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Core { +class System; +} + +namespace Service::Nex { +void LoopProcess(Core::System& system); +} // namespace Service::Nex diff --git a/src/core/hle/service/nex/nex_results.h b/src/core/hle/service/nex/nex_results.h new file mode 100644 index 000000000..eedbb79ee --- /dev/null +++ b/src/core/hle/service/nex/nex_results.h @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" + +namespace Service::Nex { + +constexpr Result ResultNexNotAvailable{ErrorModule::Nex, 520}; +constexpr Result ResultNexConnectionFailed{ErrorModule::Nex, 1}; +constexpr Result ResultNexTimeout{ErrorModule::Nex, 2}; +constexpr Result ResultNexInvalidState{ErrorModule::Nex, 3}; +constexpr Result ResultNexNotInitialized{ErrorModule::Nex, 4}; + +} // namespace Service::Nex diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp index 9dbf0cc34..b512815b5 100644 --- a/src/core/hle/service/services.cpp +++ b/src/core/hle/service/services.cpp @@ -38,6 +38,7 @@ #include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nfp/nfp.h" #include "core/hle/service/ngc/ngc.h" +#include "core/hle/service/nex/nex.h" #include "core/hle/service/nifm/nifm.h" #include "core/hle/service/nim/nim.h" #include "core/hle/service/npns/npns.h" @@ -114,6 +115,7 @@ Services::Services(std::shared_ptr& sm, Core::System& system kernel.RunOnGuestCoreProcess("nfc", [&] { NFC::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("nfp", [&] { NFP::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("ngc", [&] { NGC::LoopProcess(system); }); + kernel.RunOnGuestCoreProcess("nex", [&] { Nex::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("nifm", [&] { NIFM::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("nim", [&] { NIM::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("npns", [&] { NPNS::LoopProcess(system); }); diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index a6ec2f1d7..9e278a651 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -788,8 +788,8 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector& o } if (level != static_cast(SocketLevel::SOCKET)) { - UNIMPLEMENTED_MSG("Unknown getsockopt level"); - return Errno::SUCCESS; + LOG_WARNING(Service, "(STUBBED) Unknown getsockopt level={}, returning INVAL", level); + return Errno::INVAL; } Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); @@ -819,32 +819,52 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span(SocketLevel::SOCKET)) { - UNIMPLEMENTED_MSG("Unknown setsockopt level"); - return Errno::SUCCESS; + LOG_WARNING(Service, "(STUBBED) Unknown setsockopt level={}, returning INVAL", level); + return Errno::INVAL; } Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); if (optname == OptName::LINGER) { - ASSERT(optval.size() == sizeof(Linger)); + if (optval.size() != sizeof(Linger)) { + LOG_WARNING(Service, "LINGER optval size mismatch: expected {}, got {}", sizeof(Linger), + optval.size()); + return Errno::INVAL; + } auto linger = GetValue(optval); - ASSERT(linger.onoff == 0 || linger.onoff == 1); + if (linger.onoff != 0 && linger.onoff != 1) { + LOG_WARNING(Service, "Invalid LINGER onoff value: {}", linger.onoff); + return Errno::INVAL; + } return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); } - ASSERT(optval.size() == sizeof(u32)); + if (optval.size() != sizeof(u32)) { + LOG_WARNING(Service, "optval size mismatch: expected {}, got {} for optname={}", sizeof(u32), + optval.size(), static_cast(optname)); + return Errno::INVAL; + } auto value = GetValue(optval); switch (optname) { case OptName::REUSEADDR: - ASSERT(value == 0 || value == 1); + if (value != 0 && value != 1) { + LOG_WARNING(Service, "Invalid REUSEADDR value: {}", value); + return Errno::INVAL; + } return Translate(socket->SetReuseAddr(value != 0)); case OptName::KEEPALIVE: - ASSERT(value == 0 || value == 1); + if (value != 0 && value != 1) { + LOG_WARNING(Service, "Invalid KEEPALIVE value: {}", value); + return Errno::INVAL; + } return Translate(socket->SetKeepAlive(value != 0)); case OptName::BROADCAST: - ASSERT(value == 0 || value == 1); + if (value != 0 && value != 1) { + LOG_WARNING(Service, "Invalid BROADCAST value: {}", value); + return Errno::INVAL; + } return Translate(socket->SetBroadcast(value != 0)); case OptName::SNDBUF: return Translate(socket->SetSndBuf(value)); @@ -858,8 +878,9 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span(optname), static_cast(optname)); + return Errno::INVAL; } } diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp index b56cec9cb..5f3c5a441 100644 --- a/src/core/hle/service/sockets/sockets_translate.cpp +++ b/src/core/hle/service/sockets/sockets_translate.cpp @@ -38,9 +38,12 @@ Errno Translate(Network::Errno value) { return Errno::CONNRESET; case Network::Errno::INPROGRESS: return Errno::INPROGRESS; + case Network::Errno::OTHER: + // Map OTHER to INVAL as a reasonable default for unknown errors + return Errno::INVAL; default: UNIMPLEMENTED_MSG("Unimplemented errno={}", value); - return Errno::SUCCESS; + return Errno::INVAL; } } diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp index 8af60a886..a71929a4c 100644 --- a/src/core/internal_network/network.cpp +++ b/src/core/internal_network/network.cpp @@ -158,6 +158,8 @@ Errno TranslateNativeError(int e, CallType call_type = CallType::Other) { return Errno::TIMEDOUT; case WSAEINPROGRESS: return Errno::INPROGRESS; + case WSAENOPROTOOPT: + return Errno::INVAL; default: UNIMPLEMENTED_MSG("Unimplemented errno={}", e); return Errno::OTHER; @@ -297,6 +299,8 @@ Errno TranslateNativeError(int e, CallType call_type = CallType::Other) { return Errno::TIMEDOUT; case EINPROGRESS: return Errno::INPROGRESS; + case ENOPROTOOPT: + return Errno::INVAL; default: UNIMPLEMENTED_MSG("Unimplemented errno={} ({})", e, strerror(e)); return Errno::OTHER;