From 79683f7beb2e376fd018c010732b450415b23471 Mon Sep 17 00:00:00 2001 From: Dima Date: Thu, 20 Apr 2023 16:16:58 +0300 Subject: [PATCH 1/9] Add setting to enable internet Co-authored-by: PabloG02 --- app/src/main/cpp/skyline/common/android_settings.h | 1 + app/src/main/cpp/skyline/common/settings.h | 1 + app/src/main/java/emu/skyline/settings/EmulationSettings.kt | 1 + app/src/main/java/emu/skyline/settings/NativeSettings.kt | 2 ++ app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/emulation_preferences.xml | 5 +++++ 6 files changed, 11 insertions(+) diff --git a/app/src/main/cpp/skyline/common/android_settings.h b/app/src/main/cpp/skyline/common/android_settings.h index b422fa51..ffbe9bf6 100644 --- a/app/src/main/cpp/skyline/common/android_settings.h +++ b/app/src/main/cpp/skyline/common/android_settings.h @@ -36,6 +36,7 @@ namespace skyline { profilePictureValue = ktSettings.GetString("profilePictureValue"); systemLanguage = ktSettings.GetInt("systemLanguage"); systemRegion = ktSettings.GetInt("systemRegion"); + isInternetEnabled = ktSettings.GetBool("isInternetEnabled"); forceTripleBuffering = ktSettings.GetBool("forceTripleBuffering"); disableFrameThrottling = ktSettings.GetBool("disableFrameThrottling"); gpuDriver = ktSettings.GetString("gpuDriver"); diff --git a/app/src/main/cpp/skyline/common/settings.h b/app/src/main/cpp/skyline/common/settings.h index e14c5834..40336a73 100644 --- a/app/src/main/cpp/skyline/common/settings.h +++ b/app/src/main/cpp/skyline/common/settings.h @@ -64,6 +64,7 @@ namespace skyline { Setting profilePictureValue; //!< The profile picture path to be supplied to the guest Setting systemLanguage; //!< The system language Setting systemRegion; //!< The system region + Setting isInternetEnabled; //!< If emulator uses internet // Display Setting forceTripleBuffering; //!< If the presentation engine should always triple buffer even if the swapchain supports double buffering diff --git a/app/src/main/java/emu/skyline/settings/EmulationSettings.kt b/app/src/main/java/emu/skyline/settings/EmulationSettings.kt index 3ba61123..362992fe 100644 --- a/app/src/main/java/emu/skyline/settings/EmulationSettings.kt +++ b/app/src/main/java/emu/skyline/settings/EmulationSettings.kt @@ -29,6 +29,7 @@ class EmulationSettings private constructor(context : Context, prefName : String var profilePictureValue by sharedPreferences(context, "", prefName = prefName) var systemLanguage by sharedPreferences(context, 1, prefName = prefName) var systemRegion by sharedPreferences(context, -1, prefName = prefName) + var isInternetEnabled by sharedPreferences(context, false, prefName = prefName) // Audio var isAudioOutputDisabled by sharedPreferences(context, false, prefName = prefName) diff --git a/app/src/main/java/emu/skyline/settings/NativeSettings.kt b/app/src/main/java/emu/skyline/settings/NativeSettings.kt index ad75b564..7e6ab353 100644 --- a/app/src/main/java/emu/skyline/settings/NativeSettings.kt +++ b/app/src/main/java/emu/skyline/settings/NativeSettings.kt @@ -22,6 +22,7 @@ data class NativeSettings( var profilePictureValue : String, var systemLanguage : Int, var systemRegion : Int, + var isInternetEnabled : Boolean, // Audio var isAudioOutputDisabled : Boolean, @@ -52,6 +53,7 @@ data class NativeSettings( pref.profilePictureValue, pref.systemLanguage, pref.systemRegion, + pref.isInternetEnabled, pref.isAudioOutputDisabled, if (pref.gpuDriver == EmulationSettings.SYSTEM_GPU_DRIVER) "" else pref.gpuDriver, if (pref.gpuDriver == EmulationSettings.SYSTEM_GPU_DRIVER) "" else GpuDriverHelper.getLibraryName(context, pref.gpuDriver), diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 05426883..58af1f2f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -78,6 +78,7 @@ Profile Picture System Language System Region + The system will be able to use internet Display Show Performance Statistics diff --git a/app/src/main/res/xml/emulation_preferences.xml b/app/src/main/res/xml/emulation_preferences.xml index 7cb111a3..1a08e421 100644 --- a/app/src/main/res/xml/emulation_preferences.xml +++ b/app/src/main/res/xml/emulation_preferences.xml @@ -32,6 +32,11 @@ app:key="system_region" app:title="@string/system_region" app:useSimpleSummaryProvider="true" /> + Date: Thu, 20 Apr 2023 16:17:28 +0300 Subject: [PATCH 2/9] Stub ntc --- ...IEnsureNetworkClockAvailabilityService.cpp | 17 +++++++++++ .../IEnsureNetworkClockAvailabilityService.h | 29 +++++++++++++++++++ .../main/cpp/skyline/services/serviceman.cpp | 3 ++ 3 files changed, 49 insertions(+) create mode 100644 app/src/main/cpp/skyline/services/ntc/IEnsureNetworkClockAvailabilityService.cpp create mode 100644 app/src/main/cpp/skyline/services/ntc/IEnsureNetworkClockAvailabilityService.h diff --git a/app/src/main/cpp/skyline/services/ntc/IEnsureNetworkClockAvailabilityService.cpp b/app/src/main/cpp/skyline/services/ntc/IEnsureNetworkClockAvailabilityService.cpp new file mode 100644 index 00000000..6b131e10 --- /dev/null +++ b/app/src/main/cpp/skyline/services/ntc/IEnsureNetworkClockAvailabilityService.cpp @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "IEnsureNetworkClockAvailabilityService.h" +#include + +namespace skyline::service::ntc { + IEnsureNetworkClockAvailabilityService::IEnsureNetworkClockAvailabilityService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager), + finishNotificationEvent(std::make_shared(state, false)) {} + + Result IEnsureNetworkClockAvailabilityService::StartTask(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (!(*state.settings->isInternetEnabled)) + return result::NetworkTimeNotAvailable; + finishNotificationEvent->Signal(); + return {}; + } +} diff --git a/app/src/main/cpp/skyline/services/ntc/IEnsureNetworkClockAvailabilityService.h b/app/src/main/cpp/skyline/services/ntc/IEnsureNetworkClockAvailabilityService.h new file mode 100644 index 00000000..3dbf12dd --- /dev/null +++ b/app/src/main/cpp/skyline/services/ntc/IEnsureNetworkClockAvailabilityService.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include + +namespace skyline::service::ntc { + namespace result { + constexpr Result NetworkTimeNotAvailable{116, 1000}; + } + + /** + * @url https://switchbrew.org/wiki/NIM_services#IEnsureNetworkClockAvailabilityService + */ + class IEnsureNetworkClockAvailabilityService : public BaseService { + private: + std::shared_ptr finishNotificationEvent; + + public: + IEnsureNetworkClockAvailabilityService(const DeviceState &state, ServiceManager &manager); + + Result StartTask(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + SERVICE_DECL( + SFUNC(0x0, IEnsureNetworkClockAvailabilityService, StartTask) + ) + }; +} diff --git a/app/src/main/cpp/skyline/services/serviceman.cpp b/app/src/main/cpp/skyline/services/serviceman.cpp index 3381f64d..4976e4fc 100644 --- a/app/src/main/cpp/skyline/services/serviceman.cpp +++ b/app/src/main/cpp/skyline/services/serviceman.cpp @@ -57,6 +57,7 @@ #include "ro/IRoInterface.h" #include "mii/IStaticService.h" #include "olsc/IOlscServiceForApplication.h" +#include "ntc/IEnsureNetworkClockAvailabilityService.h" #include "serviceman.h" #define SERVICE_CASE(class, name, ...) \ @@ -124,6 +125,7 @@ namespace skyline::service { SERVICE_CASE(nfp::IUserManager, "nfp:user") SERVICE_CASE(nifm::IStaticService, "nifm:u") SERVICE_CASE(socket::IClient, "bsd:u") + SERVICE_CASE(socket::IClient, "bsd:s") SERVICE_CASE(socket::IManager, "nsd:u") SERVICE_CASE(socket::IManager, "nsd:a") SERVICE_CASE(socket::IResolver, "sfdnsres") @@ -144,6 +146,7 @@ namespace skyline::service { SERVICE_CASE(mii::IStaticService, "mii:e") SERVICE_CASE(mii::IStaticService, "mii:u") SERVICE_CASE(olsc::IOlscServiceForApplication, "olsc:u") + SERVICE_CASE(ntc::IEnsureNetworkClockAvailabilityService, "ntc") default: std::string_view nameString(span(reinterpret_cast(&name), sizeof(name)).as_string(true)); throw std::out_of_range(fmt::format("CreateService called with an unknown service name: {}", nameString)); From 37a68b41f1ab80ff489c082b14ddc2f39ffe00a0 Mon Sep 17 00:00:00 2001 From: Dima Date: Thu, 20 Apr 2023 16:26:21 +0300 Subject: [PATCH 3/9] Implement GetAddrInfoRequest Co-authored-by: PabloG02 --- .../services/socket/sfdnsres/IResolver.cpp | 169 ++++++++++++++++++ .../services/socket/sfdnsres/IResolver.h | 34 ++++ 2 files changed, 203 insertions(+) diff --git a/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.cpp b/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.cpp index 34adbbd6..f90ca091 100644 --- a/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.cpp +++ b/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.cpp @@ -2,7 +2,176 @@ // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) #include "IResolver.h" +#include +#include namespace skyline::service::socket { IResolver::IResolver(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} + + Result IResolver::GetAddrInfoRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + auto [dataSize, resultCode]{GetAddrInfoRequestImpl(request)}; + response.Push(resultCode); // errno + response.Push(AddrInfoErrorToNetDbError(resultCode)); // NetDBErrorCode + response.Push(dataSize); + return {}; + } + + Result IResolver::GetHostByNameRequestWithOptions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IResolver::GetAddrInfoRequestWithOptions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + auto [dataSize, resultCode]{GetAddrInfoRequestImpl(request)}; + response.Push(resultCode); // errno + response.Push(AddrInfoErrorToNetDbError(resultCode)); // NetDBErrorCode + response.Push(dataSize); + response.Push(0); + return {}; + } + + Result IResolver::GetNameInfoRequestWithOptions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + std::pair IResolver::GetAddrInfoRequestImpl(ipc::IpcRequest &request) { + auto hostname{request.inputBuf.at(0).as_string(true)}; + auto service{request.inputBuf.at(1).as_string(true)}; + + if (!(*state.settings->isInternetEnabled)) { + Logger::Info("Internet access disabled, DNS Blocked: {}", hostname); + return {0, -1}; + } + + addrinfo* result; + i32 resultCode = getaddrinfo(hostname.data(), service.data(), nullptr, &result); + + u32 dataSize{0}; + if (resultCode == 0 && result != nullptr) { + const std::vector& data = SerializeAddrInfo(result, resultCode, hostname); + dataSize = static_cast(data.size()); + request.outputBuf.at(0).copy_from(data); + freeaddrinfo(result); + } + return {dataSize, resultCode}; + } + + // https://github.com/yuzu-emu/yuzu/blob/ce8f4da63834be0179d98a7720dee47d65f3ec06/src/core/hle/service/sockets/sfdnsres.cpp#L76 + std::vector IResolver::SerializeAddrInfo(const addrinfo* addrinfo, i32 result_code, std::string_view host) { + std::vector data; + + auto* current{addrinfo}; + while (current != nullptr) { + struct SerializedResponseHeader { + u32 magic; + u32 flags; + u32 family; + u32 socketType; + u32 protocol; + u32 addressLength; + }; + static_assert(sizeof(SerializedResponseHeader) == 0x18); + + constexpr auto headerSize{sizeof(SerializedResponseHeader)}; + const auto addrSize{current->ai_addr && current->ai_addrlen > 0 ? current->ai_addrlen : 4}; + const auto canonnameSize{current->ai_canonname ? strlen(current->ai_canonname) + 1 : 1}; + + const auto lastSize{data.size()}; + data.resize(lastSize + headerSize + addrSize + canonnameSize); + + // Header in network byte order + SerializedResponseHeader header{}; + + constexpr auto HEADER_MAGIC{0xBEEFCAFE}; + header.magic = htonl(HEADER_MAGIC); + header.family = htonl(current->ai_family); + header.flags = htonl(current->ai_flags); + header.socketType = htonl(current->ai_socktype); + header.protocol = htonl(current->ai_protocol); + header.addressLength = current->ai_addr ? htonl((u32)current->ai_addrlen) : 0; + + auto* headerPtr{data.data() + lastSize}; + std::memcpy(headerPtr, &header, headerSize); + + if (header.addressLength == 0) { + std::memset(headerPtr + headerSize, 0, 4); + } else { + switch (current->ai_family) { + case AF_INET: { + struct SockAddrIn { + u16 sin_family; + u16 sin_port; + u32 sin_addr; + u8 sin_zero[8]; + }; + + SockAddrIn serializedAddr{}; + const auto addr{*reinterpret_cast(current->ai_addr)}; + serializedAddr.sin_port = htons(addr.sin_port); + serializedAddr.sin_family = htons(addr.sin_family); + serializedAddr.sin_addr = htonl(addr.sin_addr.s_addr); + std::memcpy(headerPtr + headerSize, &serializedAddr, sizeof(SockAddrIn)); + + char addrStringBuf[64]{}; + inet_ntop(AF_INET, &addr.sin_addr, addrStringBuf, std::size(addrStringBuf)); + Logger::Info("Resolved host '{}' to IPv4 address {}", host, addrStringBuf); + break; + } + case AF_INET6: { + struct SockAddrIn6 { + u16 sin6_family; + u16 sin6_port; + u32 sin6_flowinfo; + u8 sin6_addr[16]; + u32 sin6_scope_id; + }; + + SockAddrIn6 serializedAddr{}; + const auto addr{*reinterpret_cast(current->ai_addr)}; + serializedAddr.sin6_family = htons(addr.sin6_family); + serializedAddr.sin6_port = htons(addr.sin6_port); + serializedAddr.sin6_flowinfo = htonl(addr.sin6_flowinfo); + serializedAddr.sin6_scope_id = htonl(addr.sin6_scope_id); + std::memcpy(serializedAddr.sin6_addr, &addr.sin6_addr, sizeof(SockAddrIn6::sin6_addr)); + std::memcpy(headerPtr + headerSize, &serializedAddr, sizeof(SockAddrIn6)); + + char addrStringBuf[64]{}; + inet_ntop(AF_INET6, &addr.sin6_addr, addrStringBuf, std::size(addrStringBuf)); + Logger::Info("Resolved host '{}' to IPv6 address {}", host, addrStringBuf); + break; + } + default: + std::memcpy(headerPtr + headerSize, current->ai_addr, addrSize); + break; + } + } + if (current->ai_canonname) { + std::memcpy(headerPtr + addrSize, current->ai_canonname, canonnameSize); + } else { + *(headerPtr + headerSize + addrSize) = 0; + } + + current = current->ai_next; + } + + // 4-byte sentinel value + data.push_back(0); + data.push_back(0); + data.push_back(0); + data.push_back(0); + + return data; + } + + NetDbError IResolver::AddrInfoErrorToNetDbError(i32 result) { + switch (result) { + case 0: + return NetDbError::Success; + case EAI_AGAIN: + return NetDbError::TryAgain; + case EAI_NODATA: + return NetDbError::NoData; + default: + return NetDbError::HostNotFound; + } + } } diff --git a/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.h b/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.h index 37734d56..992a48ed 100644 --- a/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.h +++ b/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.h @@ -4,13 +4,47 @@ #pragma once #include +#include namespace skyline::service::socket { + enum class NetDbError : i32 { + Internal = -1, + Success = 0, + HostNotFound = 1, + TryAgain = 2, + NoRecovery = 3, + NoData = 4, + }; + /** * @url https://switchbrew.org/wiki/Sockets_services#sfdnsres */ class IResolver : public BaseService { public: IResolver(const DeviceState &state, ServiceManager &manager); + + /** + * @url https://switchbrew.org/wiki/Sockets_services#GetAddrInfoRequest + */ + Result GetAddrInfoRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result GetHostByNameRequestWithOptions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result GetAddrInfoRequestWithOptions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result GetNameInfoRequestWithOptions(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + std::pair GetAddrInfoRequestImpl(ipc::IpcRequest &request); + + std::vector SerializeAddrInfo(const addrinfo* addrinfo, i32 result_code, std::string_view host); + + NetDbError AddrInfoErrorToNetDbError(i32 result); + + SERVICE_DECL( + SFUNC(0x6, IResolver, GetAddrInfoRequest), + SFUNC(0xA, IResolver, GetHostByNameRequestWithOptions), + SFUNC(0xC, IResolver, GetAddrInfoRequestWithOptions), + SFUNC(0xD, IResolver, GetNameInfoRequestWithOptions) + ) }; } From 635f06bf5076ce849879ce1f684bb4771f7f763c Mon Sep 17 00:00:00 2001 From: Dima Date: Thu, 20 Apr 2023 16:27:49 +0300 Subject: [PATCH 4/9] Stub correctly some nifm calls --- .../cpp/skyline/services/nifm/IRequest.cpp | 11 +++++-- .../main/cpp/skyline/services/nifm/IRequest.h | 19 +++++++++++- .../services/socket/sfdnsres/IResolver.cpp | 30 +++++++++---------- .../services/socket/sfdnsres/IResolver.h | 2 -- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/app/src/main/cpp/skyline/services/nifm/IRequest.cpp b/app/src/main/cpp/skyline/services/nifm/IRequest.cpp index c627be49..1f00a180 100644 --- a/app/src/main/cpp/skyline/services/nifm/IRequest.cpp +++ b/app/src/main/cpp/skyline/services/nifm/IRequest.cpp @@ -3,6 +3,7 @@ #include #include "IRequest.h" +#include namespace skyline::service::nifm { namespace result { @@ -15,8 +16,10 @@ namespace skyline::service::nifm { BaseService(state, manager) {} Result IRequest::GetRequestState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - constexpr u32 Unsubmitted{1}; //!< The request has not been submitted - response.Push(Unsubmitted); + if (*state.settings->isInternetEnabled) + response.Push(RequestState::Accepted); + else + response.Push(RequestState::Invalid); return {}; } @@ -36,6 +39,10 @@ namespace skyline::service::nifm { return {}; } + Result IRequest::Cancel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + Result IRequest::Submit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { return {}; } diff --git a/app/src/main/cpp/skyline/services/nifm/IRequest.h b/app/src/main/cpp/skyline/services/nifm/IRequest.h index 5c3c15b5..49f19643 100644 --- a/app/src/main/cpp/skyline/services/nifm/IRequest.h +++ b/app/src/main/cpp/skyline/services/nifm/IRequest.h @@ -7,6 +7,17 @@ #include namespace skyline::service::nifm { + /** + * @url https://switchbrew.org/wiki/Network_Interface_services#RequestState + */ + enum class RequestState : u32 { + Invalid = 0, + Free = 1, + OnHold = 2, + Accepted = 3, + Blocking = 4, + }; + /** * @brief IRequest is used by applications to bring up a network * @url https://switchbrew.org/wiki/Network_Interface_services#IRequest @@ -37,6 +48,11 @@ namespace skyline::service::nifm { */ Result GetSystemEventReadableHandles(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @url https://switchbrew.org/wiki/Network_Interface_services#Cancel + */ + Result Cancel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @brief Submits a request to bring up a network * @url https://switchbrew.org/wiki/Network_Interface_services#Submit @@ -57,9 +73,10 @@ namespace skyline::service::nifm { SFUNC(0x0, IRequest, GetRequestState), SFUNC(0x1, IRequest, GetResult), SFUNC(0x2, IRequest, GetSystemEventReadableHandles), + SFUNC(0x3, IRequest, Cancel), SFUNC(0x4, IRequest, Submit), SFUNC(0xB, IRequest, SetConnectionConfirmationOption), SFUNC(0x15, IRequest, GetAppletInfo) - ) + ) }; } diff --git a/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.cpp b/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.cpp index f90ca091..94af59da 100644 --- a/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.cpp +++ b/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.cpp @@ -6,6 +6,19 @@ #include namespace skyline::service::socket { + static NetDbError AddrInfoErrorToNetDbError(i32 result) { + switch (result) { + case 0: + return NetDbError::Success; + case EAI_AGAIN: + return NetDbError::TryAgain; + case EAI_NODATA: + return NetDbError::NoData; + default: + return NetDbError::HostNotFound; + } + } + IResolver::IResolver(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} Result IResolver::GetAddrInfoRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { @@ -42,12 +55,12 @@ namespace skyline::service::socket { return {0, -1}; } - addrinfo* result; + addrinfo *result; i32 resultCode = getaddrinfo(hostname.data(), service.data(), nullptr, &result); u32 dataSize{0}; if (resultCode == 0 && result != nullptr) { - const std::vector& data = SerializeAddrInfo(result, resultCode, hostname); + const std::vector data = SerializeAddrInfo(result, resultCode, hostname); dataSize = static_cast(data.size()); request.outputBuf.at(0).copy_from(data); freeaddrinfo(result); @@ -161,17 +174,4 @@ namespace skyline::service::socket { return data; } - - NetDbError IResolver::AddrInfoErrorToNetDbError(i32 result) { - switch (result) { - case 0: - return NetDbError::Success; - case EAI_AGAIN: - return NetDbError::TryAgain; - case EAI_NODATA: - return NetDbError::NoData; - default: - return NetDbError::HostNotFound; - } - } } diff --git a/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.h b/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.h index 992a48ed..1cddf6a9 100644 --- a/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.h +++ b/app/src/main/cpp/skyline/services/socket/sfdnsres/IResolver.h @@ -38,8 +38,6 @@ namespace skyline::service::socket { std::vector SerializeAddrInfo(const addrinfo* addrinfo, i32 result_code, std::string_view host); - NetDbError AddrInfoErrorToNetDbError(i32 result); - SERVICE_DECL( SFUNC(0x6, IResolver, GetAddrInfoRequest), SFUNC(0xA, IResolver, GetHostByNameRequestWithOptions), From 54041ceba15aadc47dc7ac3f798d09ce2922bdc2 Mon Sep 17 00:00:00 2001 From: Dima Date: Mon, 24 Apr 2023 14:46:42 +0300 Subject: [PATCH 5/9] Implement GetCurrentIpConfigInfo Needed for almost every LAN game --- app/src/main/AndroidManifest.xml | 1 + app/src/main/cpp/skyline/jvm.cpp | 20 +++- app/src/main/cpp/skyline/jvm.h | 14 +++ .../skyline/services/nifm/IGeneralService.cpp | 96 ++++++++++++++++++- .../skyline/services/nifm/IGeneralService.h | 91 ++++++++++++++++++ .../java/emu/skyline/EmulationActivity.kt | 8 ++ 6 files changed, 226 insertions(+), 4 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d68f7da1..ee547a3e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> + GetMethodID(instanceClass, "closeKeyboard", "(Lemu/skyline/applet/swkbd/SoftwareKeyboardDialog;)V")}, showValidationResultId{environ->GetMethodID(instanceClass, "showValidationResult", "(Lemu/skyline/applet/swkbd/SoftwareKeyboardDialog;ILjava/lang/String;)I")}, getVersionCodeId{environ->GetMethodID(instanceClass, "getVersionCode", "()I")}, - getIntegerValueId{environ->GetMethodID(environ->FindClass("java/lang/Integer"), "intValue", "()I")} { + getIntegerValueId{environ->GetMethodID(environ->FindClass("java/lang/Integer"), "intValue", "()I")}, + getDhcpInfoId{environ->GetMethodID(instanceClass, "getDhcpInfo", "()Landroid/net/DhcpInfo;")} { env.Initialize(environ); } @@ -132,6 +133,23 @@ namespace skyline { return {static_cast(env->CallIntMethod(buttonInteger, getIntegerValueId)), input}; } + DhcpInfo JvmManager::GetDhcpInfo() { + jobject dhcpInfo{env->CallObjectMethod(instance, getDhcpInfoId)}; + jclass dhcpInfoClass{env->GetObjectClass(dhcpInfo)}; + jfieldID ipAddressFieldId{env->GetFieldID(dhcpInfoClass, "ipAddress", "I")}; + jfieldID subnetFieldId{env->GetFieldID(dhcpInfoClass, "netmask", "I")}; + jfieldID gatewayFieldId{env->GetFieldID(dhcpInfoClass, "gateway", "I")}; + jfieldID dns1FieldId{env->GetFieldID(dhcpInfoClass, "dns1", "I")}; + jfieldID dns2FieldId{env->GetFieldID(dhcpInfoClass, "dns2", "I")}; + + jint ipAddress{env->GetIntField(dhcpInfo, ipAddressFieldId)}; + jint subnet{env->GetIntField(dhcpInfo, subnetFieldId)}; + jint gateway{env->GetIntField(dhcpInfo, gatewayFieldId)}; + jint dns1{env->GetIntField(dhcpInfo, dns1FieldId)}; + jint dns2{env->GetIntField(dhcpInfo, dns2FieldId)}; + return DhcpInfo{ipAddress, subnet, gateway, dns1, dns2}; + } + void JvmManager::CloseKeyboard(jobject dialog) { env->CallVoidMethod(instance, closeKeyboardId, dialog); env->DeleteGlobalRef(dialog); diff --git a/app/src/main/cpp/skyline/jvm.h b/app/src/main/cpp/skyline/jvm.h index 535a307a..6f593a2b 100644 --- a/app/src/main/cpp/skyline/jvm.h +++ b/app/src/main/cpp/skyline/jvm.h @@ -7,6 +7,14 @@ #include namespace skyline { + struct DhcpInfo { + i32 ipAddress; + i32 subnet; + i32 gateway; + i32 dns1; + i32 dns2; + }; + /** * @brief A wrapper over std::string that supports construction using a JNI jstring */ @@ -182,6 +190,11 @@ namespace skyline { */ i32 GetVersionCode(); + /** + * @brief A call to EmulationActivity.getDhcpInfo in Kotlin + */ + DhcpInfo GetDhcpInfo(); + private: jmethodID initializeControllersId; jmethodID vibrateDeviceId; @@ -191,6 +204,7 @@ namespace skyline { jmethodID closeKeyboardId; jmethodID showValidationResultId; jmethodID getVersionCodeId; + jmethodID getDhcpInfoId; jmethodID getIntegerValueId; }; diff --git a/app/src/main/cpp/skyline/services/nifm/IGeneralService.cpp b/app/src/main/cpp/skyline/services/nifm/IGeneralService.cpp index 636c6c3a..4e6e11ac 100644 --- a/app/src/main/cpp/skyline/services/nifm/IGeneralService.cpp +++ b/app/src/main/cpp/skyline/services/nifm/IGeneralService.cpp @@ -4,8 +4,22 @@ #include "IScanRequest.h" #include "IRequest.h" #include "IGeneralService.h" +#include +#include namespace skyline::service::nifm { + /** + * @brief Converts integer value to an array of bytes ordered in little-endian format + */ + static std::array ConvertIntToByteArray(i32 value) { + std::array result{}; + result[0] = value & 0xFF; + result[1] = (value >> 8) & 0xFF; + result[2] = (value >> 16) & 0xFF; + result[3] = (value >> 24) & 0xFF; + return result; + } + IGeneralService::IGeneralService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} Result IGeneralService::CreateScanRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { @@ -18,13 +32,89 @@ namespace skyline::service::nifm { return {}; } + Result IGeneralService::GetCurrentNetworkProfile(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (!(*state.settings->isInternetEnabled)) + return result::NoInternetConnection; + + const UUID uuid{static_cast(0xdeadbeef) << 64}; + auto dhcpInfo{state.jvm->GetDhcpInfo()}; + + SfNetworkProfileData networkProfileData{ + .ipSettingData{ + .ipAddressSetting{ + true, + .currentAddress{ConvertIntToByteArray(dhcpInfo.ipAddress)}, + .subnetMask{ConvertIntToByteArray(dhcpInfo.subnet)}, + .gateway{ConvertIntToByteArray(dhcpInfo.gateway)}, + }, + .dnsSetting{ + true, + .primaryDns{ConvertIntToByteArray(dhcpInfo.dns1)}, + .secondaryDns{ConvertIntToByteArray(dhcpInfo.dns2)}, + }, + .proxySetting{ + false, + .port{}, + .proxyServer{}, + .automaticAuthEnabled{}, + .user{}, + .password{}, + }, + 1500, + }, + .uuid{uuid}, + .networkName{"Skyline Network"}, + .wirelessSettingData{ + 12, + .ssid{"Skyline Network"}, + .passphrase{"skylinepassword"}, + }, + }; + + request.outputBuf.at(0).as() = networkProfileData; + return {}; + } + Result IGeneralService::GetCurrentIpAddress(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return result::NoInternetConnection; + if (!(*state.settings->isInternetEnabled)) + return result::NoInternetConnection; + + auto dhcpInfo{state.jvm->GetDhcpInfo()}; + response.Push(ConvertIntToByteArray(dhcpInfo.ipAddress)); + return {}; + } + + Result IGeneralService::GetCurrentIpConfigInfo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (!(*state.settings->isInternetEnabled)) + return result::NoInternetConnection; + + auto dhcpInfo{state.jvm->GetDhcpInfo()}; + + struct IpConfigInfo { + IpAddressSetting ipAddressSetting; + DnsSetting dnsSetting; + }; + + IpConfigInfo ipConfigInfo{ + .ipAddressSetting{ + true, + .currentAddress{ConvertIntToByteArray(dhcpInfo.ipAddress)}, + .subnetMask{ConvertIntToByteArray(dhcpInfo.subnet)}, + .gateway{ConvertIntToByteArray(dhcpInfo.gateway)}, + }, + .dnsSetting{ + true, + .primaryDns{ConvertIntToByteArray(dhcpInfo.dns1)}, + .secondaryDns{ConvertIntToByteArray(dhcpInfo.dns2)}, + }, + }; + + response.Push(ipConfigInfo); + return {}; } Result IGeneralService::IsAnyInternetRequestAccepted(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - // We don't emulate networking so always return false - response.Push(false); + response.Push(*state.settings->isInternetEnabled); return {}; } } diff --git a/app/src/main/cpp/skyline/services/nifm/IGeneralService.h b/app/src/main/cpp/skyline/services/nifm/IGeneralService.h index efdce9d0..e5f94e85 100644 --- a/app/src/main/cpp/skyline/services/nifm/IGeneralService.h +++ b/app/src/main/cpp/skyline/services/nifm/IGeneralService.h @@ -4,11 +4,90 @@ #pragma once #include +#include "common/uuid.h" namespace skyline::service::nifm { namespace result { constexpr Result NoInternetConnection{110, 300}; } + + struct IpAddressSetting { + bool isAutomatic{}; + std::array currentAddress{}; + std::array subnetMask{}; + std::array gateway{}; + }; + static_assert(sizeof(IpAddressSetting) == 0xD); + + struct DnsSetting { + bool isAutomatic{}; + std::array primaryDns{}; + std::array secondaryDns{}; + }; + static_assert(sizeof(DnsSetting) == 0x9); + + struct ProxySetting { + bool enabled{}; + u8 _pad0_[0x1]; + u16 port{}; + std::array proxyServer{}; + bool automaticAuthEnabled{}; + std::array user{}; + std::array password{}; + u8 _pad1_[0x1]; + }; + static_assert(sizeof(ProxySetting) == 0xAA); + + struct IpSettingData { + IpAddressSetting ipAddressSetting{}; + DnsSetting dnsSetting{}; + ProxySetting proxySetting{}; + u16 mtu{}; + }; + static_assert(sizeof(IpSettingData) == 0xC2); + + struct SfWirelessSettingData { + u8 ssidLength{}; + std::array ssid{}; + u8 _unk0_[0x3]; + std::array passphrase{}; + }; + static_assert(sizeof(SfWirelessSettingData) == 0x65); + + struct NifmWirelessSettingData { + u8 ssidLength{}; + std::array ssid{}; + u8 _unk0_[0x1]; + u8 _pad0_[0x1]; + u32 _unk1_[0x2]; + std::array passphrase{}; + u8 _pad1_[0x3]; + }; + static_assert(sizeof(NifmWirelessSettingData) == 0x70); + + #pragma pack(push, 1) + struct SfNetworkProfileData { + IpSettingData ipSettingData{}; + UUID uuid{}; + std::array networkName{}; + u8 _unk0_[0x4]; + SfWirelessSettingData wirelessSettingData{}; + u8 _pad0_[0x1]; + }; + static_assert(sizeof(SfNetworkProfileData) == 0x17C); + + struct NifmNetworkProfileData { + UUID uuid{}; + std::array networkName{}; + u32 _unk0_[0x2]; + u8 _unk1_[0x2]; + u8 _pad0_[0x2]; + NifmWirelessSettingData wirelessSettingData{}; + IpSettingData ipSettingData{}; + }; + static_assert(sizeof(NifmNetworkProfileData) == 0x18E); + #pragma pack(pop) + /** * @brief IGeneralService is used by applications to control the network connection * @url https://switchbrew.org/wiki/Network_Interface_services#IGeneralService @@ -27,11 +106,21 @@ namespace skyline::service::nifm { */ Result CreateRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @url https://switchbrew.org/wiki/Network_Interface_services#GetCurrentNetworkProfile + */ + Result GetCurrentNetworkProfile(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @url https://switchbrew.org/wiki/Network_Interface_services#GetCurrentIpAddress */ Result GetCurrentIpAddress(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @url https://switchbrew.org/wiki/Network_Interface_services#GetCurrentIpConfigInfo + */ + Result GetCurrentIpConfigInfo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @url https://switchbrew.org/wiki/Network_Interface_services#IsAnyInternetRequestAccepted */ @@ -40,7 +129,9 @@ namespace skyline::service::nifm { SERVICE_DECL( SFUNC(0x1, IGeneralService, CreateScanRequest), SFUNC(0x4, IGeneralService, CreateRequest), + SFUNC(0x5, IGeneralService, GetCurrentNetworkProfile), SFUNC(0xC, IGeneralService, GetCurrentIpAddress), + SFUNC(0xF, IGeneralService, GetCurrentIpConfigInfo), SFUNC(0x15, IGeneralService, IsAnyInternetRequestAccepted) ) }; diff --git a/app/src/main/java/emu/skyline/EmulationActivity.kt b/app/src/main/java/emu/skyline/EmulationActivity.kt index 768df54c..83a5da04 100644 --- a/app/src/main/java/emu/skyline/EmulationActivity.kt +++ b/app/src/main/java/emu/skyline/EmulationActivity.kt @@ -18,6 +18,8 @@ import android.content.res.Configuration import android.graphics.PointF import android.graphics.drawable.Icon import android.hardware.display.DisplayManager +import android.net.DhcpInfo +import android.net.wifi.WifiManager import android.os.* import android.util.Log import android.util.Rational @@ -626,6 +628,12 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo return dialog.waitForSubmitOrCancel().let { arrayOf(if (it.cancelled) 1 else 0, it.text) } } + @Suppress("unused") + fun getDhcpInfo() : DhcpInfo { + val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + return wifiManager.dhcpInfo + } + @Suppress("unused") fun closeKeyboard(dialog : SoftwareKeyboardDialog) { runOnUiThread { dialog.dismiss() } From 688dea647d92cc6a039f05e182c04aeea7cfbb93 Mon Sep 17 00:00:00 2001 From: Dima Date: Thu, 20 Apr 2023 16:30:12 +0300 Subject: [PATCH 6/9] Stub some required calls Co-authored-by: PabloG02 --- app/CMakeLists.txt | 2 ++ .../services/account/IAsyncContext.cpp | 31 +++++++++++++++++ .../skyline/services/account/IAsyncContext.h | 34 +++++++++++++++++++ .../account/IManagerForApplication.cpp | 10 ++++++ .../services/account/IManagerForApplication.h | 6 ++++ .../services/pctl/IParentalControlService.cpp | 5 ++- .../services/pctl/IParentalControlService.h | 3 ++ .../skyline/services/socket/nsd/IManager.cpp | 4 +++ .../skyline/services/socket/nsd/IManager.h | 6 ++++ .../cpp/skyline/services/ssl/ISslContext.cpp | 4 +++ .../cpp/skyline/services/ssl/ISslContext.h | 8 ++++- 11 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 app/src/main/cpp/skyline/services/account/IAsyncContext.cpp create mode 100644 app/src/main/cpp/skyline/services/account/IAsyncContext.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 03a0209d..2b1a5c8f 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -376,6 +376,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/account/IAccountServiceForApplication.cpp ${source_DIR}/skyline/services/account/IManagerForApplication.cpp ${source_DIR}/skyline/services/account/IProfile.cpp + ${source_DIR}/skyline/services/account/IAsyncContext.cpp ${source_DIR}/skyline/services/friends/IServiceCreator.cpp ${source_DIR}/skyline/services/friends/IFriendService.cpp ${source_DIR}/skyline/services/friends/INotificationService.cpp @@ -400,6 +401,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/mii/IStaticService.cpp ${source_DIR}/skyline/services/mii/IDatabaseService.cpp ${source_DIR}/skyline/services/olsc/IOlscServiceForApplication.cpp + ${source_DIR}/skyline/services/ntc/IEnsureNetworkClockAvailabilityService.cpp ) target_include_directories(skyline PRIVATE ${source_DIR}/skyline) # target_precompile_headers(skyline PRIVATE ${source_DIR}/skyline/common.h) # PCH will currently break Intellisense diff --git a/app/src/main/cpp/skyline/services/account/IAsyncContext.cpp b/app/src/main/cpp/skyline/services/account/IAsyncContext.cpp new file mode 100644 index 00000000..58d084e2 --- /dev/null +++ b/app/src/main/cpp/skyline/services/account/IAsyncContext.cpp @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "IAsyncContext.h" + +namespace skyline::service::account { + IAsyncContext::IAsyncContext(const DeviceState &state, ServiceManager &manager) : BaseService{state, manager}, + systemEvent{std::make_shared(state, true)} {} + + Result IAsyncContext::GetSystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + auto handle{state.process->InsertItem(systemEvent)}; + Logger::Debug("System Event Handle: 0x{:X}", handle); + + response.copyHandles.push_back(handle); + return {}; + } + + Result IAsyncContext::Cancel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + systemEvent->Signal(); + return {}; + } + + Result IAsyncContext::HasDone(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + response.Push(1); + return {}; + } + + Result IAsyncContext::GetResult(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } +} diff --git a/app/src/main/cpp/skyline/services/account/IAsyncContext.h b/app/src/main/cpp/skyline/services/account/IAsyncContext.h new file mode 100644 index 00000000..318f0bcd --- /dev/null +++ b/app/src/main/cpp/skyline/services/account/IAsyncContext.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include + +namespace skyline::service::account { + /** + * @url https://switchbrew.org/wiki/Account_services#IAsyncContext + */ + class IAsyncContext : public BaseService { + private: + std::shared_ptr systemEvent; + + public: + IAsyncContext(const DeviceState &state, ServiceManager &manager); + + Result GetSystemEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result Cancel(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result HasDone(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result GetResult(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + SERVICE_DECL( + SFUNC(0x0, IAsyncContext, GetSystemEvent), + SFUNC(0x1, IAsyncContext, Cancel), + SFUNC(0x2, IAsyncContext, HasDone), + SFUNC(0x3, IAsyncContext, GetResult) + ) + }; +} diff --git a/app/src/main/cpp/skyline/services/account/IManagerForApplication.cpp b/app/src/main/cpp/skyline/services/account/IManagerForApplication.cpp index 460d0ca4..b3eaa50a 100644 --- a/app/src/main/cpp/skyline/services/account/IManagerForApplication.cpp +++ b/app/src/main/cpp/skyline/services/account/IManagerForApplication.cpp @@ -3,6 +3,7 @@ #include "IManagerForApplication.h" #include "IAccountServiceForApplication.h" +#include "IAsyncContext.h" namespace skyline::service::account { IManagerForApplication::IManagerForApplication(const DeviceState &state, ServiceManager &manager, std::vector &openedUsers) : BaseService(state, manager) { @@ -19,6 +20,15 @@ namespace skyline::service::account { return {}; } + Result IManagerForApplication::EnsureIdTokenCacheAsync(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + manager.RegisterService(SRVREG(IAsyncContext), session, response); + return {}; + } + + Result IManagerForApplication::LoadIdTokenCache(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + Result IManagerForApplication::StoreOpenContext(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { openedUsers->clear(); openedUsers->push_back(constant::DefaultUserId); diff --git a/app/src/main/cpp/skyline/services/account/IManagerForApplication.h b/app/src/main/cpp/skyline/services/account/IManagerForApplication.h index 2e28d134..01cac050 100644 --- a/app/src/main/cpp/skyline/services/account/IManagerForApplication.h +++ b/app/src/main/cpp/skyline/services/account/IManagerForApplication.h @@ -28,11 +28,17 @@ namespace skyline::service::account { */ Result GetAccountId(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + Result EnsureIdTokenCacheAsync(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result LoadIdTokenCache(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + Result StoreOpenContext(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); SERVICE_DECL( SFUNC(0x0, IManagerForApplication, CheckAvailability), SFUNC(0x1, IManagerForApplication, GetAccountId), + SFUNC(0x2, IManagerForApplication, EnsureIdTokenCacheAsync), + SFUNC(0x3, IManagerForApplication, LoadIdTokenCache), SFUNC(0xA0, IManagerForApplication, StoreOpenContext) ) }; diff --git a/app/src/main/cpp/skyline/services/pctl/IParentalControlService.cpp b/app/src/main/cpp/skyline/services/pctl/IParentalControlService.cpp index ef37aa2f..dbcd0bbd 100644 --- a/app/src/main/cpp/skyline/services/pctl/IParentalControlService.cpp +++ b/app/src/main/cpp/skyline/services/pctl/IParentalControlService.cpp @@ -11,7 +11,10 @@ namespace skyline::service::pctl { } Result IParentalControlService::CheckFreeCommunicationPermission(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - response.Push(0); + return {}; + } + + Result IParentalControlService::EndFreeCommunication(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { return {}; } diff --git a/app/src/main/cpp/skyline/services/pctl/IParentalControlService.h b/app/src/main/cpp/skyline/services/pctl/IParentalControlService.h index d1d9b6b2..62d116f5 100644 --- a/app/src/main/cpp/skyline/services/pctl/IParentalControlService.h +++ b/app/src/main/cpp/skyline/services/pctl/IParentalControlService.h @@ -21,11 +21,14 @@ namespace skyline::service::pctl { Result CheckFreeCommunicationPermission(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + Result EndFreeCommunication(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + Result IsFreeCommunicationAvailable(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); SERVICE_DECL( SFUNC(0x1, IParentalControlService, Initialize), SFUNC(0x3E9, IParentalControlService, CheckFreeCommunicationPermission), + SFUNC(0x3F9, IParentalControlService, EndFreeCommunication), SFUNC(0x3FA, IParentalControlService, IsFreeCommunicationAvailable) ) }; diff --git a/app/src/main/cpp/skyline/services/socket/nsd/IManager.cpp b/app/src/main/cpp/skyline/services/socket/nsd/IManager.cpp index bee2c293..e6f786ce 100644 --- a/app/src/main/cpp/skyline/services/socket/nsd/IManager.cpp +++ b/app/src/main/cpp/skyline/services/socket/nsd/IManager.cpp @@ -5,4 +5,8 @@ namespace skyline::service::socket { IManager::IManager(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} + + Result IManager::ResolveEx(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } } diff --git a/app/src/main/cpp/skyline/services/socket/nsd/IManager.h b/app/src/main/cpp/skyline/services/socket/nsd/IManager.h index cf29b075..01ef46ca 100644 --- a/app/src/main/cpp/skyline/services/socket/nsd/IManager.h +++ b/app/src/main/cpp/skyline/services/socket/nsd/IManager.h @@ -12,5 +12,11 @@ namespace skyline::service::socket { class IManager : public BaseService { public: IManager(const DeviceState &state, ServiceManager &manager); + + Result ResolveEx(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + SERVICE_DECL( + SFUNC(0x15, IManager, ResolveEx), + ) }; } diff --git a/app/src/main/cpp/skyline/services/ssl/ISslContext.cpp b/app/src/main/cpp/skyline/services/ssl/ISslContext.cpp index eb0adba7..04351d15 100644 --- a/app/src/main/cpp/skyline/services/ssl/ISslContext.cpp +++ b/app/src/main/cpp/skyline/services/ssl/ISslContext.cpp @@ -17,4 +17,8 @@ namespace skyline::service::ssl { response.Push(0); return {}; } + + Result ISslContext::RegisterInternalPki(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } } diff --git a/app/src/main/cpp/skyline/services/ssl/ISslContext.h b/app/src/main/cpp/skyline/services/ssl/ISslContext.h index 15dd589c..273734ab 100644 --- a/app/src/main/cpp/skyline/services/ssl/ISslContext.h +++ b/app/src/main/cpp/skyline/services/ssl/ISslContext.h @@ -19,8 +19,14 @@ namespace skyline::service::ssl { */ Result ImportServerPki(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @url https://switchbrew.org/wiki/SSL_services#RegisterInternalPki + */ + Result RegisterInternalPki(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + SERVICE_DECL( - SFUNC(0x4, ISslContext, ImportServerPki) + SFUNC(0x4, ISslContext, ImportServerPki), + SFUNC(0x8, ISslContext, RegisterInternalPki) ) }; } From 2097dbf9d91b167e01278db1ef297f0bb91e0f74 Mon Sep 17 00:00:00 2001 From: Dima Date: Thu, 20 Apr 2023 20:05:35 +0300 Subject: [PATCH 7/9] Stub IAuthorizationRequest --- app/CMakeLists.txt | 1 + .../account/IAuthorizationRequest.cpp | 23 +++++++++++++++ .../services/account/IAuthorizationRequest.h | 28 +++++++++++++++++++ .../account/IManagerForApplication.cpp | 6 ++++ .../services/account/IManagerForApplication.h | 3 ++ 5 files changed, 61 insertions(+) create mode 100644 app/src/main/cpp/skyline/services/account/IAuthorizationRequest.cpp create mode 100644 app/src/main/cpp/skyline/services/account/IAuthorizationRequest.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 2b1a5c8f..949c4792 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -377,6 +377,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/services/account/IManagerForApplication.cpp ${source_DIR}/skyline/services/account/IProfile.cpp ${source_DIR}/skyline/services/account/IAsyncContext.cpp + ${source_DIR}/skyline/services/account/IAuthorizationRequest.cpp ${source_DIR}/skyline/services/friends/IServiceCreator.cpp ${source_DIR}/skyline/services/friends/IFriendService.cpp ${source_DIR}/skyline/services/friends/INotificationService.cpp diff --git a/app/src/main/cpp/skyline/services/account/IAuthorizationRequest.cpp b/app/src/main/cpp/skyline/services/account/IAuthorizationRequest.cpp new file mode 100644 index 00000000..d64e6709 --- /dev/null +++ b/app/src/main/cpp/skyline/services/account/IAuthorizationRequest.cpp @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include "IAuthorizationRequest.h" +#include "IAsyncContext.h" + +namespace skyline::service::account { + IAuthorizationRequest::IAuthorizationRequest(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} + + Result IAuthorizationRequest::InvokeWithoutInteractionAsync(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + manager.RegisterService(SRVREG(IAsyncContext), session, response); + return {}; + } + + Result IAuthorizationRequest::IsAuthorized(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + response.Push(0); + return {}; + } + + Result IAuthorizationRequest::GetAuthorizationCode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } +} diff --git a/app/src/main/cpp/skyline/services/account/IAuthorizationRequest.h b/app/src/main/cpp/skyline/services/account/IAuthorizationRequest.h new file mode 100644 index 00000000..38863765 --- /dev/null +++ b/app/src/main/cpp/skyline/services/account/IAuthorizationRequest.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2023 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include + +namespace skyline::service::account { + /** + * @url https://switchbrew.org/wiki/Account_services#IAuthorizationRequest + */ + class IAuthorizationRequest : public BaseService { + public: + IAuthorizationRequest(const DeviceState &state, ServiceManager &manager); + + Result InvokeWithoutInteractionAsync(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result IsAuthorized(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result GetAuthorizationCode(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + SERVICE_DECL( + SFUNC(0xA, IAuthorizationRequest, InvokeWithoutInteractionAsync), + SFUNC(0x13, IAuthorizationRequest, IsAuthorized), + SFUNC(0x15, IAuthorizationRequest, GetAuthorizationCode) + ) + }; +} diff --git a/app/src/main/cpp/skyline/services/account/IManagerForApplication.cpp b/app/src/main/cpp/skyline/services/account/IManagerForApplication.cpp index b3eaa50a..52a2971f 100644 --- a/app/src/main/cpp/skyline/services/account/IManagerForApplication.cpp +++ b/app/src/main/cpp/skyline/services/account/IManagerForApplication.cpp @@ -4,6 +4,7 @@ #include "IManagerForApplication.h" #include "IAccountServiceForApplication.h" #include "IAsyncContext.h" +#include "IAuthorizationRequest.h" namespace skyline::service::account { IManagerForApplication::IManagerForApplication(const DeviceState &state, ServiceManager &manager, std::vector &openedUsers) : BaseService(state, manager) { @@ -29,6 +30,11 @@ namespace skyline::service::account { return {}; } + Result IManagerForApplication::CreateAuthorizationRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + manager.RegisterService(SRVREG(IAuthorizationRequest), session, response); + return {}; + } + Result IManagerForApplication::StoreOpenContext(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { openedUsers->clear(); openedUsers->push_back(constant::DefaultUserId); diff --git a/app/src/main/cpp/skyline/services/account/IManagerForApplication.h b/app/src/main/cpp/skyline/services/account/IManagerForApplication.h index 01cac050..7832d573 100644 --- a/app/src/main/cpp/skyline/services/account/IManagerForApplication.h +++ b/app/src/main/cpp/skyline/services/account/IManagerForApplication.h @@ -32,6 +32,8 @@ namespace skyline::service::account { Result LoadIdTokenCache(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + Result CreateAuthorizationRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + Result StoreOpenContext(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); SERVICE_DECL( @@ -39,6 +41,7 @@ namespace skyline::service::account { SFUNC(0x1, IManagerForApplication, GetAccountId), SFUNC(0x2, IManagerForApplication, EnsureIdTokenCacheAsync), SFUNC(0x3, IManagerForApplication, LoadIdTokenCache), + SFUNC(0x96, IManagerForApplication, CreateAuthorizationRequest), SFUNC(0xA0, IManagerForApplication, StoreOpenContext) ) }; From 64d914639f612403a9550b3444cb058b37952b52 Mon Sep 17 00:00:00 2001 From: Dima Date: Mon, 24 Apr 2023 17:10:53 +0300 Subject: [PATCH 8/9] Stub some ldn calls For now just stubs --- .../ldn/IUserLocalCommunicationService.cpp | 96 ++++++- .../ldn/IUserLocalCommunicationService.h | 262 +++++++++++++++++- 2 files changed, 352 insertions(+), 6 deletions(-) diff --git a/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.cpp b/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.cpp index 4b118c69..2770460a 100644 --- a/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.cpp +++ b/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.cpp @@ -2,6 +2,7 @@ // Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) #include "IUserLocalCommunicationService.h" +#include namespace skyline::service::ldn { IUserLocalCommunicationService::IUserLocalCommunicationService(const DeviceState &state, ServiceManager &manager) @@ -9,8 +10,39 @@ namespace skyline::service::ldn { event{std::make_shared(state, false)} {} Result IUserLocalCommunicationService::GetState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - static constexpr u32 StateNone{0x0}; - response.Push(StateNone); + response.Push(State::Error); + return {}; + } + + Result IUserLocalCommunicationService::GetNetworkInfo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (request.outputBuf.at(0).size() != sizeof(NetworkInfo)) { + Logger::Error("Invalid input"); + return result::InvalidInput; + } + + NetworkInfo networkInfo{}; + request.outputBuf.at(0).as() = networkInfo; + return {}; + } + + Result IUserLocalCommunicationService::GetIpv4Address(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::GetDisconnectReason(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + response.Push(DisconnectReason::None); + return {}; + } + + Result IUserLocalCommunicationService::GetSecurityParameter(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + SecurityParameter securityParameter{}; + response.Push(securityParameter); + return {}; + } + + Result IUserLocalCommunicationService::GetNetworkConfig(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + NetworkConfig networkConfig{}; + response.Push(networkConfig); return {}; } @@ -21,15 +53,71 @@ namespace skyline::service::ldn { return {}; } + Result IUserLocalCommunicationService::GetNetworkInfoLatestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + const size_t networkBuffferSize{request.outputBuf.at(0).size()}; + const size_t nodeBufferCount{request.outputBuf.at(1).size() / sizeof(NodeLatestUpdate)}; + + if (nodeBufferCount == 0 || networkBuffferSize != sizeof(NetworkInfo)) + return result::InvalidInput; + + NetworkInfo networkInfo{}; + std::vector latestUpdate(nodeBufferCount); + + request.outputBuf.at(0).as() = networkInfo; + request.outputBuf.at(1).copy_from(latestUpdate); + return {}; + } + + Result IUserLocalCommunicationService::Scan(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + const size_t networkInfoSize{request.outputBuf.at(0).size() / sizeof(NetworkInfo)}; + + if (networkInfoSize == 0) + return result::InvalidInput; + + std::vector networkInfos(networkInfoSize); + request.outputBuf.at(0).copy_from(networkInfos); + response.Push(0); + return {}; + } + + Result IUserLocalCommunicationService::OpenAccessPoint(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::CreateNetwork(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::CreateNetworkPrivate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::SetAdvertiseData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::OpenStation(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + Result IUserLocalCommunicationService::InitializeSystem(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return result::DeviceDisabled; + if (!*state.settings->isInternetEnabled) + return result::AirplaneModeEnabled; + + isInitialized = true; + return result::AirplaneModeEnabled; } Result IUserLocalCommunicationService::FinalizeSystem(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + isInitialized = false; return {}; } Result IUserLocalCommunicationService::InitializeSystem2(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return result::DeviceDisabled; + if (!*state.settings->isInternetEnabled) + return result::AirplaneModeEnabled; + + isInitialized = true; + return result::AirplaneModeEnabled; } } diff --git a/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.h b/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.h index fcedb2fe..4a54f78a 100644 --- a/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.h +++ b/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.h @@ -7,9 +7,194 @@ namespace skyline::service::ldn { namespace result { - static constexpr Result DeviceDisabled{203, 22}; + constexpr Result AirplaneModeEnabled{203, 23}; + constexpr Result InvalidInput{203, 96}; } + constexpr size_t SsidLengthMax = 32; + constexpr size_t UserNameBytesMax = 32; + constexpr i32 NodeCountMax = 8; + constexpr size_t AdvertiseDataSizeMax = 384; + constexpr size_t PassphraseLengthMax = 64; + + enum class State : u32 { + None, + Initialized, + AccessPointOpened, + AccessPointCreated, + StationOpened, + StationConnected, + Error, + }; + + enum class DisconnectReason : i16 { + Unknown = -1, + None, + User, + System, + DestroyedByUser, + DestroyedBySystemRequest, + Admin, + SignalLost, + }; + + enum class WifiChannel : i16 { + Default = 0, + Wifi24_1 = 1, + Wifi24_6 = 6, + Wifi24_11 = 11, + Wifi50_36 = 36, + Wifi50_40 = 40, + Wifi50_44 = 44, + Wifi50_48 = 48, + }; + + enum class LinkLevel : i8 { + Bad, + Low, + Good, + Excellent, + }; + + enum class PackedNetworkType : u8 { + None, + General, + Ldn, + All, + }; + + enum class SecurityMode : u16 { + All, + Retail, + Debug, + }; + + enum class AcceptPolicy : u8 { + AcceptAll, + RejectAll, + BlackList, + WhiteList, + }; + + enum class NodeStateChange : u8 { + None, + Connect, + Disconnect, + DisconnectAndConnect, + }; + + struct IntentId { + u64 localCommunicationId; + u8 _pad0_[0x2]; + u16 sceneId; + u8 _pad1_[0x4]; + }; + static_assert(sizeof(IntentId) == 0x10); + + struct SessionId { + u64 high; + u64 low; + }; + static_assert(sizeof(SessionId) == 0x10); + + struct NetworkId { + IntentId intentId; + SessionId sessionId; + }; + static_assert(sizeof(NetworkId) == 0x20); + + struct MacAddress { + std::array raw{}; + }; + static_assert(sizeof(MacAddress) == 0x6); + + struct Ssid { + u8 length{}; + std::array raw{}; + }; + static_assert(sizeof(Ssid) == 0x22); + + struct CommonNetworkInfo { + MacAddress bssid; + Ssid ssid; + WifiChannel channel; + LinkLevel linkLevel; + PackedNetworkType networkType; + u8 _pad0_[0x4]; + }; + static_assert(sizeof(CommonNetworkInfo) == 0x30); + + struct NodeInfo { + std::array ipv4Address; + MacAddress macAddress; + i8 nodeId; + u8 isConnected; + std::array username; + u8 _pad0_[0x1]; + i16 localCommunicationVersion; + u8 _pad1_[0x10]; + }; + static_assert(sizeof(NodeInfo) == 0x40); + + struct LdnNetworkInfo { + std::array securityParameter; + SecurityMode securityMode; + AcceptPolicy stationAcceptPolicy; + u8 hasActionFrame; + u8 _pad0_[0x2]; + u8 nodeCountMax; + u8 nodeCount; + std::array nodes; + u8 _pad1_[0x2]; + u16 advertiseDataSize; + std::array advertiseData; + u8 _pad2_[0x8C]; + u64 randomAuthenticationId; + }; + static_assert(sizeof(LdnNetworkInfo) == 0x430); + + struct NetworkInfo { + NetworkId networkId; + CommonNetworkInfo common; + LdnNetworkInfo ldn; + }; + static_assert(sizeof(NetworkInfo) == 0x480); + + struct SecurityConfig { + SecurityMode securityMode; + u16 passphraseSize; + std::array passphrase; + }; + static_assert(sizeof(SecurityConfig) == 0x44); + + struct SecurityParameter { + std::array data; + SessionId sessionId; + }; + static_assert(sizeof(SecurityParameter) == 0x20); + + struct UserConfig { + std::array username; + u8 _pad0_[0xF]; + }; + static_assert(sizeof(UserConfig) == 0x30); + + struct NetworkConfig { + IntentId intentId; + WifiChannel channel; + u8 nodeCountMax; + u8 _pad0_[0x1]; + u16 localCommunicationVersion; + u8 _pad1_[0xA]; + }; + static_assert(sizeof(NetworkConfig) == 0x20); + + struct NodeLatestUpdate { + NodeStateChange stateChange; + u8 _pad0_[0x7]; + }; + static_assert(sizeof(NodeLatestUpdate) == 0x8); + /** * @brief IUserLocalCommunicationService is used by applications to manage LDN sessions * @url https://switchbrew.org/wiki/LDN_services#IUserLocalCommunicationService @@ -17,6 +202,7 @@ namespace skyline::service::ldn { class IUserLocalCommunicationService : public BaseService { private: std::shared_ptr event; //!< The KEvent that is signalled on state changes + bool isInitialized{false}; public: IUserLocalCommunicationService(const DeviceState &state, ServiceManager &manager); @@ -26,11 +212,71 @@ namespace skyline::service::ldn { */ Result GetState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @url https://switchbrew.org/wiki/LDN_services#GetNetworkInfo + */ + Result GetNetworkInfo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#GetIpv4Address + */ + Result GetIpv4Address(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#GetDisconnectReason + */ + Result GetDisconnectReason(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#GetSecurityParameter + */ + Result GetSecurityParameter(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#GetNetworkConfig + */ + Result GetNetworkConfig(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @url https://switchbrew.org/wiki/LDN_services#AttachStateChangeEvent */ Result AttachStateChangeEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @url https://switchbrew.org/wiki/LDN_services#GetNetworkInfoLatestUpdate + */ + Result GetNetworkInfoLatestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#Scan + */ + Result Scan(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#OpenAccessPoint + */ + Result OpenAccessPoint(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#CreateNetwork + */ + Result CreateNetwork(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#CreateNetworkPrivate + */ + Result CreateNetworkPrivate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#SetAdvertiseData + */ + Result SetAdvertiseData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#OpenStation + */ + Result OpenStation(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @url https://switchbrew.org/wiki/LDN_services#InitializeSystem */ @@ -48,10 +294,22 @@ namespace skyline::service::ldn { SERVICE_DECL( SFUNC(0x0, IUserLocalCommunicationService, GetState), + SFUNC(0x1, IUserLocalCommunicationService, GetNetworkInfo), + SFUNC(0x2, IUserLocalCommunicationService, GetIpv4Address), + SFUNC(0x3, IUserLocalCommunicationService, GetDisconnectReason), + SFUNC(0x4, IUserLocalCommunicationService, GetSecurityParameter), + SFUNC(0x5, IUserLocalCommunicationService, GetNetworkConfig), SFUNC(0x64, IUserLocalCommunicationService, AttachStateChangeEvent), + SFUNC(0x65, IUserLocalCommunicationService, GetNetworkInfoLatestUpdate), + SFUNC(0x66, IUserLocalCommunicationService, Scan), + SFUNC(0xC8, IUserLocalCommunicationService, OpenAccessPoint), + SFUNC(0xCA, IUserLocalCommunicationService, CreateNetwork), + SFUNC(0xCB, IUserLocalCommunicationService, CreateNetworkPrivate), + SFUNC(0xCE, IUserLocalCommunicationService, SetAdvertiseData), + SFUNC(0x12C, IUserLocalCommunicationService, OpenStation), SFUNC(0x190, IUserLocalCommunicationService, InitializeSystem), SFUNC(0x191, IUserLocalCommunicationService, FinalizeSystem), - SFUNC(0x192, IUserLocalCommunicationService, InitializeSystem2), + SFUNC(0x192, IUserLocalCommunicationService, InitializeSystem2) ) }; } From b22471fb4612c444c228c503ea9fb1d2ae97f58d Mon Sep 17 00:00:00 2001 From: Dima Date: Thu, 20 Apr 2023 16:25:34 +0300 Subject: [PATCH 9/9] Implement required bsd calls Co-authored-by: PabloG02 --- .../skyline/services/socket/bsd/IClient.cpp | 207 ++++++++++++++++-- .../cpp/skyline/services/socket/bsd/IClient.h | 56 ++++- 2 files changed, 238 insertions(+), 25 deletions(-) diff --git a/app/src/main/cpp/skyline/services/socket/bsd/IClient.cpp b/app/src/main/cpp/skyline/services/socket/bsd/IClient.cpp index 316daaae..a2558e7b 100644 --- a/app/src/main/cpp/skyline/services/socket/bsd/IClient.cpp +++ b/app/src/main/cpp/skyline/services/socket/bsd/IClient.cpp @@ -1,13 +1,14 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) +#include #include "IClient.h" namespace skyline::service::socket { IClient::IClient(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {} Result IClient::RegisterClient(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - response.Push(0); + response.Push(0); return {}; } @@ -15,53 +16,185 @@ namespace skyline::service::socket { return {}; } - Result IClient::Select(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + Result IClient::Socket(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + i32 domain{request.Pop()}; + i32 type{request.Pop()}; + i32 protocol{request.Pop()}; + i32 fd{::socket(domain, type, protocol)}; + Logger::Info("File Descriptor {} with Domain {}, Type {}, Protocol {}", fd, domain, type, protocol); + if (fd == -1) + Logger::Error("Error creating socket: {}", strerror(errno)); + return PushBsdResult(response, fd, 0); } Result IClient::Poll(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fdsCount{request.Pop()}; + i32 timeout{request.Pop()}; + + if (fdsCount == 0) + return PushBsdResult(response, -1, 0); + + span outputBuf{request.outputBuf.at(0)}; + auto fds{span(reinterpret_cast(outputBuf.data()), static_cast(fdsCount))}; + i32 result{poll(fds.data(), static_cast(fdsCount), static_cast(timeout))}; + return PushBsdResult(response, result, errno); } Result IClient::Recv(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + i32 flags{request.Pop()}; + if (fcntl(fd, F_GETFL) == -1) + return PushBsdResult(response, -1, EBADF); + + bool shouldBlockAfterOperation{false}; + if (!(fcntl(fd, F_GETFL) & O_NONBLOCK) && (flags & MSG_EOR)) { + fcntl(fd, F_SETFL, O_NONBLOCK); + shouldBlockAfterOperation = true; + } + + ssize_t result{recv(fd, request.outputBuf.at(0).data(), request.outputBuf.at(0).size(), flags)}; + + if (shouldBlockAfterOperation) + fcntl(fd, F_SETFL, MSG_EOR); + return PushBsdResultErrno(response, result); } Result IClient::RecvFrom(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + i32 flags{request.Pop()}; + if (fcntl(fd, F_GETFL) == -1) + return PushBsdResult(response, -1, EBADF); + + bool shouldBlockAfterOperation{false}; + if (!(fcntl(fd, F_GETFL) & O_NONBLOCK) && (flags & MSG_EOR)) { + fcntl(fd, F_SETFL, O_NONBLOCK); + shouldBlockAfterOperation = true; + } + + sockaddr addrIn{}; + socklen_t addrLen{sizeof(addrIn)}; + span message{request.outputBuf.at(0)}; + ssize_t result{recvfrom(fd, message.data(), message.size(), 0, &addrIn, &addrLen)}; + + if (shouldBlockAfterOperation) + fcntl(fd, F_SETFL, MSG_EOR); + + request.outputBuf.at(0).copy_from(message); + if (!request.outputBuf.at(1).empty()) + request.outputBuf.at(1).copy_from(span{addrIn}); + response.Push(request.outputBuf.at(1).size()); + return PushBsdResultErrno(response, result); } Result IClient::Send(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + i32 flags{request.Pop()}; + + ssize_t result{send(fd, request.inputBuf.at(0).data(), request.inputBuf.at(0).size(), flags)}; + return PushBsdResultErrno(response, result); } Result IClient::SendTo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - response.Push(0); - return {}; + i32 fd{request.Pop()}; + i32 flags{request.Pop()}; + + sockaddr addrIn{request.inputBuf.at(1).as()}; + addrIn.sa_family = AF_INET; + ssize_t result{sendto(fd, request.inputBuf.at(0).data(), request.inputBuf.at(0).size(), flags, + &addrIn, sizeof(addrIn))}; + return PushBsdResultErrno(response, result); } Result IClient::Accept(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + sockaddr addr{}; + socklen_t addrLen{sizeof(addr)}; + i32 result{accept(fd, &addr, &addrLen)}; + if (errno != 0) + return PushBsdResult(response, -1, errno); + + request.outputBuf.at(0).copy_from(span{addr}); + response.Push(request.outputBuf.at(0).size()); + return PushBsdResult(response, result, errno); } Result IClient::Bind(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + sockaddr addr{request.inputBuf.at(0).as()}; + addr.sa_family = AF_INET; + + i32 result{bind(fd, &addr, sizeof(addr))}; + return PushBsdResult(response, 0, errno); } Result IClient::Connect(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + sockaddr addr{request.inputBuf.at(0).as()}; + addr.sa_family = AF_INET; + + i32 result{connect(fd, &addr, sizeof(addr))}; + return PushBsdResult(response, 0, errno); + } + + Result IClient::GetPeerName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + i32 fd{request.Pop()}; + sockaddr addr{}; + socklen_t addrLen{sizeof(addr)}; + i32 result{getpeername(fd, &addr, &addrLen)}; + request.outputBuf.at(0).copy_from(span{addr}); + response.Push(request.outputBuf.at(0).size()); + return PushBsdResult(response, 0, errno); + } + + Result IClient::GetSockName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + i32 fd{request.Pop()}; + sockaddr addr{}; + socklen_t addrLen{sizeof(addr)}; + i32 result{getsockname(fd, &addr, &addrLen)}; + request.outputBuf.at(0).copy_from(span{addr}); + response.Push(request.outputBuf.at(0).size()); + return PushBsdResult(response, 0, errno); + } + + Result IClient::GetSockOpt(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + i32 fd{request.Pop()}; + i32 level{request.Pop()}; + OptionName optionName{request.Pop()}; + socklen_t addrLen{sizeof(request.outputBuf.at(0))}; + i32 result{getsockopt(fd, level, GetOption(optionName), request.outputBuf.at(0).data(), &addrLen)}; + return PushBsdResult(response, 0, errno); } Result IClient::Listen(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + i32 backlog{request.Pop()}; + i32 result{listen(fd, backlog)}; + return PushBsdResult(response, 0, errno); + } + + Result IClient::Fcntl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + i32 fd{request.Pop()}; + i32 cmd{request.Pop()}; + i32 arg{request.Pop()}; + i32 result{fcntl(fd, cmd, arg)}; + return PushBsdResult(response, 0, errno); } Result IClient::SetSockOpt(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + i32 level{request.Pop()}; + OptionName optionName{request.Pop()}; + if (level == 0xFFFF) + level = SOL_SOCKET; + i32 result{setsockopt(fd, level, GetOption(optionName), request.inputBuf.at(0).data(), static_cast(request.inputBuf.at(0).size()))}; + return PushBsdResult(response, 0, errno); } Result IClient::Shutdown(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + i32 how{request.Pop()}; + i32 result{shutdown(fd, how)}; + return PushBsdResult(response, 0, errno); } Result IClient::ShutdownAllSockets(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { @@ -69,16 +202,52 @@ namespace skyline::service::socket { } Result IClient::Write(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return {}; + i32 fd{request.Pop()}; + i32 flags{request.Pop()}; + ssize_t result{send(fd, request.inputBuf.at(0).data(), request.inputBuf.at(0).size(), flags)}; + return PushBsdResultErrno(response, result); } Result IClient::Read(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - response.Push(0); - response.Push(0); - return {}; + i32 fd{request.Pop()}; + ssize_t result{recv(fd, request.outputBuf.at(0).data(), request.outputBuf.at(0).size(), 0)}; + return PushBsdResultErrno(response, result); } Result IClient::Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + i32 fd{request.Pop()}; + i32 result{close(fd)}; + return PushBsdResult(response, 0, errno); + } + + Result IClient::EventFd(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return PushBsdResult(response, 1, 0); + } + + Result IClient::PushBsdResult(ipc::IpcResponse &response, i32 result, i32 errorCode) { + if (errorCode != 0) + result = -1; + + response.Push(result); + response.Push(errorCode); return {}; } + + Result IClient::PushBsdResultErrno(ipc::IpcResponse &response, i64 result) { + response.Push(result); + response.Push(result == -1 ? errno : 0); + return {}; + } + + i32 IClient::GetOption(OptionName optionName) { + switch (optionName) { + case OptionName::ReuseAddr: return SO_REUSEADDR; + case OptionName::Broadcast: return SO_BROADCAST; + case OptionName::Linger: return SO_LINGER; + case OptionName::SndBuf: return SO_SNDBUF; + case OptionName::RcvBuf: return SO_RCVBUF; + case OptionName::SndTimeo: return SO_SNDTIMEO; + case OptionName::RcvTimeo: return SO_RCVTIMEO; + } + } } diff --git a/app/src/main/cpp/skyline/services/socket/bsd/IClient.h b/app/src/main/cpp/skyline/services/socket/bsd/IClient.h index 9ed6e0cb..45d55da1 100644 --- a/app/src/main/cpp/skyline/services/socket/bsd/IClient.h +++ b/app/src/main/cpp/skyline/services/socket/bsd/IClient.h @@ -4,8 +4,18 @@ #pragma once #include +#include namespace skyline::service::socket { + enum class OptionName : u32 { + ReuseAddr = 0x4, + Broadcast = 0x20, + Linger = 0x80, + SndBuf = 0x1001, + RcvBuf = 0x1002, + SndTimeo = 0x1005, + RcvTimeo = 0x1006, + }; /** * @brief IClient or bsd:u is used by applications create network sockets * @url https://switchbrew.org/wiki/Sockets_services#bsd:u.2C_bsd:s @@ -25,10 +35,7 @@ namespace skyline::service::socket { */ Result StartMonitoring(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); - /** - * @brief Selects the socket - */ - Result Select(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + Result Socket(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); /** * @brief Polls the socket for events @@ -70,11 +77,32 @@ namespace skyline::service::socket { */ Result Connect(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @brief Retrieves the address of the peer to which a socket is connected + */ + Result GetPeerName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Retrieves the current local address of the socket + */ + Result GetSockName(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @brief Retrieves socket options + */ + Result GetSockOpt(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @brief Places a socket in a state in which it is listening for an incoming connection */ Result Listen(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @brief Performs a control operation on an open file descriptor + * @url https://switchbrew.org/wiki/Sockets_services#Fcntl + */ + Result Fcntl(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @brief Manipulates the options associated with a socket */ @@ -105,10 +133,21 @@ namespace skyline::service::socket { */ Result Close(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + Result EventFd(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + Result PushBsdResult(ipc::IpcResponse &response, i32 result, i32 errorCode); + + Result PushBsdResultErrno(ipc::IpcResponse &response, i64 result); + + /** + * @brief Translates option name to a socket option + */ + i32 GetOption(OptionName optionName); + SERVICE_DECL( SFUNC(0x0, IClient, RegisterClient), SFUNC(0x1, IClient, StartMonitoring), - SFUNC(0x5, IClient, Select), + SFUNC(0x2, IClient, Socket), SFUNC(0x6, IClient, Poll), SFUNC(0x8, IClient, Recv), SFUNC(0x9, IClient, RecvFrom), @@ -117,13 +156,18 @@ namespace skyline::service::socket { SFUNC(0xC, IClient, Accept), SFUNC(0xD, IClient, Bind), SFUNC(0xE, IClient, Connect), + SFUNC(0xF, IClient, GetPeerName), + SFUNC(0x10, IClient, GetSockName), + SFUNC(0x11, IClient, GetSockOpt), SFUNC(0x12, IClient, Listen), + SFUNC(0x14, IClient, Fcntl), SFUNC(0x15, IClient, SetSockOpt), SFUNC(0x16, IClient, Shutdown), SFUNC(0x17, IClient, ShutdownAllSockets), SFUNC(0x18, IClient, Write), SFUNC(0x19, IClient, Read), - SFUNC(0x1A, IClient, Close) + SFUNC(0x1A, IClient, Close), + SFUNC(0x1F, IClient, EventFd) ) }; }