diff options
| -rw-r--r-- | src/core/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 16 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/service/nifm/nifm.cpp | 13 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/sockets/blocking_worker.h | 162 | ||||
| -rw-r--r-- | src/core/hle/service/sockets/bsd.cpp | 809 | ||||
| -rw-r--r-- | src/core/hle/service/sockets/bsd.h | 150 | ||||
| -rw-r--r-- | src/core/hle/service/sockets/sockets.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/service/sockets/sockets.h | 85 | ||||
| -rw-r--r-- | src/core/hle/service/sockets/sockets_translate.cpp | 165 | ||||
| -rw-r--r-- | src/core/hle/service/sockets/sockets_translate.h | 48 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.cpp | 2 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.h | 2 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_poller.cpp | 14 | ||||
| -rw-r--r-- | src/yuzu/game_list_p.h | 32 |
17 files changed, 1438 insertions, 84 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c85c9485f..b96ca9374 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -491,6 +491,7 @@ add_library(core STATIC | |||
| 491 | hle/service/sm/controller.h | 491 | hle/service/sm/controller.h |
| 492 | hle/service/sm/sm.cpp | 492 | hle/service/sm/sm.cpp |
| 493 | hle/service/sm/sm.h | 493 | hle/service/sm/sm.h |
| 494 | hle/service/sockets/blocking_worker.h | ||
| 494 | hle/service/sockets/bsd.cpp | 495 | hle/service/sockets/bsd.cpp |
| 495 | hle/service/sockets/bsd.h | 496 | hle/service/sockets/bsd.h |
| 496 | hle/service/sockets/ethc.cpp | 497 | hle/service/sockets/ethc.cpp |
| @@ -501,6 +502,8 @@ add_library(core STATIC | |||
| 501 | hle/service/sockets/sfdnsres.h | 502 | hle/service/sockets/sfdnsres.h |
| 502 | hle/service/sockets/sockets.cpp | 503 | hle/service/sockets/sockets.cpp |
| 503 | hle/service/sockets/sockets.h | 504 | hle/service/sockets/sockets.h |
| 505 | hle/service/sockets/sockets_translate.cpp | ||
| 506 | hle/service/sockets/sockets_translate.h | ||
| 504 | hle/service/spl/csrng.cpp | 507 | hle/service/spl/csrng.cpp |
| 505 | hle/service/spl/csrng.h | 508 | hle/service/spl/csrng.h |
| 506 | hle/service/spl/module.cpp | 509 | hle/service/spl/module.cpp |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 45fde8df2..e742497e1 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -574,6 +574,22 @@ Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMo | |||
| 574 | return gyroscope_zero_drift_mode; | 574 | return gyroscope_zero_drift_mode; |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { | ||
| 578 | const auto npad_index_1 = NPadIdToIndex(npad_id_1); | ||
| 579 | const auto npad_index_2 = NPadIdToIndex(npad_id_2); | ||
| 580 | |||
| 581 | // If the controllers at both npad indices form a pair of left and right joycons, merge them. | ||
| 582 | // Otherwise, do nothing. | ||
| 583 | if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft && | ||
| 584 | connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) || | ||
| 585 | (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft && | ||
| 586 | connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) { | ||
| 587 | // Disconnect the joycon at the second id and connect the dual joycon at the first index. | ||
| 588 | DisconnectNPad(npad_id_2); | ||
| 589 | AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1); | ||
| 590 | } | ||
| 591 | } | ||
| 592 | |||
| 577 | void Controller_NPad::StartLRAssignmentMode() { | 593 | void Controller_NPad::StartLRAssignmentMode() { |
| 578 | // Nothing internally is used for lr assignment mode. Since we have the ability to set the | 594 | // Nothing internally is used for lr assignment mode. Since we have the ability to set the |
| 579 | // controller types from boot, it doesn't really matter about showing a selection screen | 595 | // controller types from boot, it doesn't really matter about showing a selection screen |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 75ce5b731..ad25c6fbf 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -134,6 +134,7 @@ public: | |||
| 134 | void ConnectAllDisconnectedControllers(); | 134 | void ConnectAllDisconnectedControllers(); |
| 135 | void ClearAllControllers(); | 135 | void ClearAllControllers(); |
| 136 | 136 | ||
| 137 | void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2); | ||
| 137 | void StartLRAssignmentMode(); | 138 | void StartLRAssignmentMode(); |
| 138 | void StopLRAssignmentMode(); | 139 | void StopLRAssignmentMode(); |
| 139 | bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); | 140 | bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 33416b5dd..bd3c2f26b 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -671,13 +671,15 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | |||
| 671 | 671 | ||
| 672 | void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { | 672 | void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { |
| 673 | IPC::RequestParser rp{ctx}; | 673 | IPC::RequestParser rp{ctx}; |
| 674 | const auto unknown_1{rp.Pop<u32>()}; | 674 | const auto npad_id_1{rp.Pop<u32>()}; |
| 675 | const auto unknown_2{rp.Pop<u32>()}; | 675 | const auto npad_id_2{rp.Pop<u32>()}; |
| 676 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 676 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 677 | 677 | ||
| 678 | LOG_WARNING(Service_HID, | 678 | LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", |
| 679 | "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", | 679 | npad_id_1, npad_id_2, applet_resource_user_id); |
| 680 | unknown_1, unknown_2, applet_resource_user_id); | 680 | |
| 681 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 682 | controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); | ||
| 681 | 683 | ||
| 682 | IPC::ResponseBuilder rb{ctx, 2}; | 684 | IPC::ResponseBuilder rb{ctx, 2}; |
| 683 | rb.Push(RESULT_SUCCESS); | 685 | rb.Push(RESULT_SUCCESS); |
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 01ddcdbd6..2e9d95195 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/hle/kernel/writable_event.h" | 9 | #include "core/hle/kernel/writable_event.h" |
| 10 | #include "core/hle/service/nifm/nifm.h" | 10 | #include "core/hle/service/nifm/nifm.h" |
| 11 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 12 | #include "core/network/network.h" | ||
| 12 | #include "core/settings.h" | 13 | #include "core/settings.h" |
| 13 | 14 | ||
| 14 | namespace Service::NIFM { | 15 | namespace Service::NIFM { |
| @@ -174,6 +175,16 @@ private: | |||
| 174 | IPC::ResponseBuilder rb{ctx, 2}; | 175 | IPC::ResponseBuilder rb{ctx, 2}; |
| 175 | rb.Push(RESULT_SUCCESS); | 176 | rb.Push(RESULT_SUCCESS); |
| 176 | } | 177 | } |
| 178 | void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) { | ||
| 179 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | ||
| 180 | |||
| 181 | const auto [ipv4, error] = Network::GetHostIPv4Address(); | ||
| 182 | UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS); | ||
| 183 | |||
| 184 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 185 | rb.Push(RESULT_SUCCESS); | ||
| 186 | rb.PushRaw(ipv4); | ||
| 187 | } | ||
| 177 | void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { | 188 | void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { |
| 178 | LOG_DEBUG(Service_NIFM, "called"); | 189 | LOG_DEBUG(Service_NIFM, "called"); |
| 179 | 190 | ||
| @@ -235,7 +246,7 @@ IGeneralService::IGeneralService(Core::System& system) | |||
| 235 | {9, nullptr, "SetNetworkProfile"}, | 246 | {9, nullptr, "SetNetworkProfile"}, |
| 236 | {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"}, | 247 | {10, &IGeneralService::RemoveNetworkProfile, "RemoveNetworkProfile"}, |
| 237 | {11, nullptr, "GetScanDataOld"}, | 248 | {11, nullptr, "GetScanDataOld"}, |
| 238 | {12, nullptr, "GetCurrentIpAddress"}, | 249 | {12, &IGeneralService::GetCurrentIpAddress, "GetCurrentIpAddress"}, |
| 239 | {13, nullptr, "GetCurrentAccessPointOld"}, | 250 | {13, nullptr, "GetCurrentAccessPointOld"}, |
| 240 | {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"}, | 251 | {14, &IGeneralService::CreateTemporaryNetworkProfile, "CreateTemporaryNetworkProfile"}, |
| 241 | {15, nullptr, "GetCurrentIpConfigInfo"}, | 252 | {15, nullptr, "GetCurrentIpConfigInfo"}, |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index fa5347af9..538f28495 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -246,7 +246,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { | |||
| 246 | PSC::InstallInterfaces(*sm); | 246 | PSC::InstallInterfaces(*sm); |
| 247 | PSM::InstallInterfaces(*sm); | 247 | PSM::InstallInterfaces(*sm); |
| 248 | Set::InstallInterfaces(*sm); | 248 | Set::InstallInterfaces(*sm); |
| 249 | Sockets::InstallInterfaces(*sm); | 249 | Sockets::InstallInterfaces(*sm, system); |
| 250 | SPL::InstallInterfaces(*sm); | 250 | SPL::InstallInterfaces(*sm); |
| 251 | SSL::InstallInterfaces(*sm); | 251 | SSL::InstallInterfaces(*sm); |
| 252 | Time::InstallInterfaces(system); | 252 | Time::InstallInterfaces(system); |
diff --git a/src/core/hle/service/sockets/blocking_worker.h b/src/core/hle/service/sockets/blocking_worker.h new file mode 100644 index 000000000..31ef6b821 --- /dev/null +++ b/src/core/hle/service/sockets/blocking_worker.h | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <memory> | ||
| 9 | #include <string> | ||
| 10 | #include <string_view> | ||
| 11 | #include <thread> | ||
| 12 | #include <variant> | ||
| 13 | #include <vector> | ||
| 14 | |||
| 15 | #include <fmt/format.h> | ||
| 16 | |||
| 17 | #include "common/assert.h" | ||
| 18 | #include "common/microprofile.h" | ||
| 19 | #include "common/thread.h" | ||
| 20 | #include "core/core.h" | ||
| 21 | #include "core/hle/kernel/hle_ipc.h" | ||
| 22 | #include "core/hle/kernel/kernel.h" | ||
| 23 | #include "core/hle/kernel/thread.h" | ||
| 24 | #include "core/hle/kernel/writable_event.h" | ||
| 25 | |||
| 26 | namespace Service::Sockets { | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Worker abstraction to execute blocking calls on host without blocking the guest thread | ||
| 30 | * | ||
| 31 | * @tparam Service Service where the work is executed | ||
| 32 | * @tparam ...Types Types of work to execute | ||
| 33 | */ | ||
| 34 | template <class Service, class... Types> | ||
| 35 | class BlockingWorker { | ||
| 36 | using This = BlockingWorker<Service, Types...>; | ||
| 37 | using WorkVariant = std::variant<std::monostate, Types...>; | ||
| 38 | |||
| 39 | public: | ||
| 40 | /// Create a new worker | ||
| 41 | static std::unique_ptr<This> Create(Core::System& system, Service* service, | ||
| 42 | std::string_view name) { | ||
| 43 | return std::unique_ptr<This>(new This(system, service, name)); | ||
| 44 | } | ||
| 45 | |||
| 46 | ~BlockingWorker() { | ||
| 47 | while (!is_available.load(std::memory_order_relaxed)) { | ||
| 48 | // Busy wait until work is finished | ||
| 49 | std::this_thread::yield(); | ||
| 50 | } | ||
| 51 | // Monostate means to exit the thread | ||
| 52 | work = std::monostate{}; | ||
| 53 | work_event.Set(); | ||
| 54 | thread.join(); | ||
| 55 | } | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Try to capture the worker to send work after a success | ||
| 59 | * @returns True when the worker has been successfully captured | ||
| 60 | */ | ||
| 61 | bool TryCapture() { | ||
| 62 | bool expected = true; | ||
| 63 | return is_available.compare_exchange_weak(expected, false, std::memory_order_relaxed, | ||
| 64 | std::memory_order_relaxed); | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * Send work to this worker abstraction | ||
| 69 | * @see TryCapture must be called before attempting to call this function | ||
| 70 | */ | ||
| 71 | template <class Work> | ||
| 72 | void SendWork(Work new_work) { | ||
| 73 | ASSERT_MSG(!is_available, "Trying to send work on a worker that's not captured"); | ||
| 74 | work = std::move(new_work); | ||
| 75 | work_event.Set(); | ||
| 76 | } | ||
| 77 | |||
| 78 | /// Generate a callback for @see SleepClientThread | ||
| 79 | template <class Work> | ||
| 80 | auto Callback() { | ||
| 81 | return [this](std::shared_ptr<Kernel::Thread>, Kernel::HLERequestContext& ctx, | ||
| 82 | Kernel::ThreadWakeupReason reason) { | ||
| 83 | ASSERT(reason == Kernel::ThreadWakeupReason::Signal); | ||
| 84 | std::get<Work>(work).Response(ctx); | ||
| 85 | is_available.store(true); | ||
| 86 | }; | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Get kernel event that will be signalled by the worker when the host operation finishes | ||
| 90 | std::shared_ptr<Kernel::WritableEvent> KernelEvent() const { | ||
| 91 | return kernel_event; | ||
| 92 | } | ||
| 93 | |||
| 94 | private: | ||
| 95 | explicit BlockingWorker(Core::System& system, Service* service, std::string_view name) { | ||
| 96 | auto pair = Kernel::WritableEvent::CreateEventPair(system.Kernel(), std::string(name)); | ||
| 97 | kernel_event = std::move(pair.writable); | ||
| 98 | thread = std::thread([this, &system, service, name] { Run(system, service, name); }); | ||
| 99 | } | ||
| 100 | |||
| 101 | void Run(Core::System& system, Service* service, std::string_view name) { | ||
| 102 | system.RegisterHostThread(); | ||
| 103 | |||
| 104 | const std::string thread_name = fmt::format("yuzu:{}", name); | ||
| 105 | MicroProfileOnThreadCreate(thread_name.c_str()); | ||
| 106 | Common::SetCurrentThreadName(thread_name.c_str()); | ||
| 107 | |||
| 108 | bool keep_running = true; | ||
| 109 | while (keep_running) { | ||
| 110 | work_event.Wait(); | ||
| 111 | |||
| 112 | const auto visit_fn = [service, &keep_running](auto&& w) { | ||
| 113 | using T = std::decay_t<decltype(w)>; | ||
| 114 | if constexpr (std::is_same_v<T, std::monostate>) { | ||
| 115 | keep_running = false; | ||
| 116 | } else { | ||
| 117 | w.Execute(service); | ||
| 118 | } | ||
| 119 | }; | ||
| 120 | std::visit(visit_fn, work); | ||
| 121 | |||
| 122 | kernel_event->Signal(); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | std::thread thread; | ||
| 127 | WorkVariant work; | ||
| 128 | Common::Event work_event; | ||
| 129 | std::shared_ptr<Kernel::WritableEvent> kernel_event; | ||
| 130 | std::atomic_bool is_available{true}; | ||
| 131 | }; | ||
| 132 | |||
| 133 | template <class Service, class... Types> | ||
| 134 | class BlockingWorkerPool { | ||
| 135 | using Worker = BlockingWorker<Service, Types...>; | ||
| 136 | |||
| 137 | public: | ||
| 138 | explicit BlockingWorkerPool(Core::System& system_, Service* service_) | ||
| 139 | : system{system_}, service{service_} {} | ||
| 140 | |||
| 141 | /// Returns a captured worker thread, creating new ones if necessary | ||
| 142 | Worker* CaptureWorker() { | ||
| 143 | for (auto& worker : workers) { | ||
| 144 | if (worker->TryCapture()) { | ||
| 145 | return worker.get(); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | auto new_worker = Worker::Create(system, service, fmt::format("BSD:{}", workers.size())); | ||
| 149 | [[maybe_unused]] const bool success = new_worker->TryCapture(); | ||
| 150 | ASSERT(success); | ||
| 151 | |||
| 152 | return workers.emplace_back(std::move(new_worker)).get(); | ||
| 153 | } | ||
| 154 | |||
| 155 | private: | ||
| 156 | Core::System& system; | ||
| 157 | Service* const service; | ||
| 158 | |||
| 159 | std::vector<std::unique_ptr<Worker>> workers; | ||
| 160 | }; | ||
| 161 | |||
| 162 | } // namespace Service::Sockets | ||
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 8d4952c0e..803505452 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp | |||
| @@ -2,18 +2,138 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <array> | ||
| 6 | #include <memory> | ||
| 7 | #include <string> | ||
| 8 | #include <utility> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include <fmt/format.h> | ||
| 12 | |||
| 13 | #include "common/microprofile.h" | ||
| 14 | #include "common/thread.h" | ||
| 5 | #include "core/hle/ipc_helpers.h" | 15 | #include "core/hle/ipc_helpers.h" |
| 16 | #include "core/hle/kernel/thread.h" | ||
| 6 | #include "core/hle/service/sockets/bsd.h" | 17 | #include "core/hle/service/sockets/bsd.h" |
| 18 | #include "core/hle/service/sockets/sockets_translate.h" | ||
| 19 | #include "core/network/network.h" | ||
| 20 | #include "core/network/sockets.h" | ||
| 7 | 21 | ||
| 8 | namespace Service::Sockets { | 22 | namespace Service::Sockets { |
| 9 | 23 | ||
| 24 | namespace { | ||
| 25 | |||
| 26 | bool IsConnectionBased(Type type) { | ||
| 27 | switch (type) { | ||
| 28 | case Type::STREAM: | ||
| 29 | return true; | ||
| 30 | case Type::DGRAM: | ||
| 31 | return false; | ||
| 32 | default: | ||
| 33 | UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type)); | ||
| 34 | return false; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | } // Anonymous namespace | ||
| 39 | |||
| 40 | void BSD::PollWork::Execute(BSD* bsd) { | ||
| 41 | std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout); | ||
| 42 | } | ||
| 43 | |||
| 44 | void BSD::PollWork::Response(Kernel::HLERequestContext& ctx) { | ||
| 45 | ctx.WriteBuffer(write_buffer); | ||
| 46 | |||
| 47 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 48 | rb.Push(RESULT_SUCCESS); | ||
| 49 | rb.Push<s32>(ret); | ||
| 50 | rb.PushEnum(bsd_errno); | ||
| 51 | } | ||
| 52 | |||
| 53 | void BSD::AcceptWork::Execute(BSD* bsd) { | ||
| 54 | std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer); | ||
| 55 | } | ||
| 56 | |||
| 57 | void BSD::AcceptWork::Response(Kernel::HLERequestContext& ctx) { | ||
| 58 | ctx.WriteBuffer(write_buffer); | ||
| 59 | |||
| 60 | IPC::ResponseBuilder rb{ctx, 5}; | ||
| 61 | rb.Push(RESULT_SUCCESS); | ||
| 62 | rb.Push<s32>(ret); | ||
| 63 | rb.PushEnum(bsd_errno); | ||
| 64 | rb.Push<u32>(static_cast<u32>(write_buffer.size())); | ||
| 65 | } | ||
| 66 | |||
| 67 | void BSD::ConnectWork::Execute(BSD* bsd) { | ||
| 68 | bsd_errno = bsd->ConnectImpl(fd, addr); | ||
| 69 | } | ||
| 70 | |||
| 71 | void BSD::ConnectWork::Response(Kernel::HLERequestContext& ctx) { | ||
| 72 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 73 | rb.Push(RESULT_SUCCESS); | ||
| 74 | rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1); | ||
| 75 | rb.PushEnum(bsd_errno); | ||
| 76 | } | ||
| 77 | |||
| 78 | void BSD::RecvWork::Execute(BSD* bsd) { | ||
| 79 | std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message); | ||
| 80 | } | ||
| 81 | |||
| 82 | void BSD::RecvWork::Response(Kernel::HLERequestContext& ctx) { | ||
| 83 | ctx.WriteBuffer(message); | ||
| 84 | |||
| 85 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 86 | rb.Push(RESULT_SUCCESS); | ||
| 87 | rb.Push<s32>(ret); | ||
| 88 | rb.PushEnum(bsd_errno); | ||
| 89 | } | ||
| 90 | |||
| 91 | void BSD::RecvFromWork::Execute(BSD* bsd) { | ||
| 92 | std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr); | ||
| 93 | } | ||
| 94 | |||
| 95 | void BSD::RecvFromWork::Response(Kernel::HLERequestContext& ctx) { | ||
| 96 | ctx.WriteBuffer(message, 0); | ||
| 97 | if (!addr.empty()) { | ||
| 98 | ctx.WriteBuffer(addr, 1); | ||
| 99 | } | ||
| 100 | |||
| 101 | IPC::ResponseBuilder rb{ctx, 5}; | ||
| 102 | rb.Push(RESULT_SUCCESS); | ||
| 103 | rb.Push<s32>(ret); | ||
| 104 | rb.PushEnum(bsd_errno); | ||
| 105 | rb.Push<u32>(static_cast<u32>(addr.size())); | ||
| 106 | } | ||
| 107 | |||
| 108 | void BSD::SendWork::Execute(BSD* bsd) { | ||
| 109 | std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message); | ||
| 110 | } | ||
| 111 | |||
| 112 | void BSD::SendWork::Response(Kernel::HLERequestContext& ctx) { | ||
| 113 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 114 | rb.Push(RESULT_SUCCESS); | ||
| 115 | rb.Push<s32>(ret); | ||
| 116 | rb.PushEnum(bsd_errno); | ||
| 117 | } | ||
| 118 | |||
| 119 | void BSD::SendToWork::Execute(BSD* bsd) { | ||
| 120 | std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr); | ||
| 121 | } | ||
| 122 | |||
| 123 | void BSD::SendToWork::Response(Kernel::HLERequestContext& ctx) { | ||
| 124 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 125 | rb.Push(RESULT_SUCCESS); | ||
| 126 | rb.Push<s32>(ret); | ||
| 127 | rb.PushEnum(bsd_errno); | ||
| 128 | } | ||
| 129 | |||
| 10 | void BSD::RegisterClient(Kernel::HLERequestContext& ctx) { | 130 | void BSD::RegisterClient(Kernel::HLERequestContext& ctx) { |
| 11 | LOG_WARNING(Service, "(STUBBED) called"); | 131 | LOG_WARNING(Service, "(STUBBED) called"); |
| 12 | 132 | ||
| 13 | IPC::ResponseBuilder rb{ctx, 3}; | 133 | IPC::ResponseBuilder rb{ctx, 3}; |
| 14 | 134 | ||
| 15 | rb.Push(RESULT_SUCCESS); | 135 | rb.Push(RESULT_SUCCESS); |
| 16 | rb.Push<u32>(0); // bsd errno | 136 | rb.Push<s32>(0); // bsd errno |
| 17 | } | 137 | } |
| 18 | 138 | ||
| 19 | void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) { | 139 | void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) { |
| @@ -26,20 +146,19 @@ void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) { | |||
| 26 | 146 | ||
| 27 | void BSD::Socket(Kernel::HLERequestContext& ctx) { | 147 | void BSD::Socket(Kernel::HLERequestContext& ctx) { |
| 28 | IPC::RequestParser rp{ctx}; | 148 | IPC::RequestParser rp{ctx}; |
| 149 | const u32 domain = rp.Pop<u32>(); | ||
| 150 | const u32 type = rp.Pop<u32>(); | ||
| 151 | const u32 protocol = rp.Pop<u32>(); | ||
| 29 | 152 | ||
| 30 | u32 domain = rp.Pop<u32>(); | 153 | LOG_DEBUG(Service, "called. domain={} type={} protocol={}", domain, type, protocol); |
| 31 | u32 type = rp.Pop<u32>(); | ||
| 32 | u32 protocol = rp.Pop<u32>(); | ||
| 33 | |||
| 34 | LOG_WARNING(Service, "(STUBBED) called domain={} type={} protocol={}", domain, type, protocol); | ||
| 35 | 154 | ||
| 36 | u32 fd = next_fd++; | 155 | const auto [fd, bsd_errno] = SocketImpl(static_cast<Domain>(domain), static_cast<Type>(type), |
| 156 | static_cast<Protocol>(protocol)); | ||
| 37 | 157 | ||
| 38 | IPC::ResponseBuilder rb{ctx, 4}; | 158 | IPC::ResponseBuilder rb{ctx, 4}; |
| 39 | |||
| 40 | rb.Push(RESULT_SUCCESS); | 159 | rb.Push(RESULT_SUCCESS); |
| 41 | rb.Push<u32>(fd); | 160 | rb.Push<s32>(fd); |
| 42 | rb.Push<u32>(0); // bsd errno | 161 | rb.PushEnum(bsd_errno); |
| 43 | } | 162 | } |
| 44 | 163 | ||
| 45 | void BSD::Select(Kernel::HLERequestContext& ctx) { | 164 | void BSD::Select(Kernel::HLERequestContext& ctx) { |
| @@ -52,67 +171,663 @@ void BSD::Select(Kernel::HLERequestContext& ctx) { | |||
| 52 | rb.Push<u32>(0); // bsd errno | 171 | rb.Push<u32>(0); // bsd errno |
| 53 | } | 172 | } |
| 54 | 173 | ||
| 174 | void BSD::Poll(Kernel::HLERequestContext& ctx) { | ||
| 175 | IPC::RequestParser rp{ctx}; | ||
| 176 | const s32 nfds = rp.Pop<s32>(); | ||
| 177 | const s32 timeout = rp.Pop<s32>(); | ||
| 178 | |||
| 179 | LOG_DEBUG(Service, "called. nfds={} timeout={}", nfds, timeout); | ||
| 180 | |||
| 181 | ExecuteWork(ctx, "BSD:Poll", timeout != 0, | ||
| 182 | PollWork{ | ||
| 183 | .nfds = nfds, | ||
| 184 | .timeout = timeout, | ||
| 185 | .read_buffer = ctx.ReadBuffer(), | ||
| 186 | .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()), | ||
| 187 | }); | ||
| 188 | } | ||
| 189 | |||
| 190 | void BSD::Accept(Kernel::HLERequestContext& ctx) { | ||
| 191 | IPC::RequestParser rp{ctx}; | ||
| 192 | const s32 fd = rp.Pop<s32>(); | ||
| 193 | |||
| 194 | LOG_DEBUG(Service, "called. fd={}", fd); | ||
| 195 | |||
| 196 | ExecuteWork(ctx, "BSD:Accept", IsBlockingSocket(fd), | ||
| 197 | AcceptWork{ | ||
| 198 | .fd = fd, | ||
| 199 | .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()), | ||
| 200 | }); | ||
| 201 | } | ||
| 202 | |||
| 55 | void BSD::Bind(Kernel::HLERequestContext& ctx) { | 203 | void BSD::Bind(Kernel::HLERequestContext& ctx) { |
| 56 | LOG_WARNING(Service, "(STUBBED) called"); | 204 | IPC::RequestParser rp{ctx}; |
| 205 | const s32 fd = rp.Pop<s32>(); | ||
| 57 | 206 | ||
| 58 | IPC::ResponseBuilder rb{ctx, 4}; | 207 | LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize()); |
| 59 | 208 | ||
| 60 | rb.Push(RESULT_SUCCESS); | 209 | BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer())); |
| 61 | rb.Push<u32>(0); // ret | ||
| 62 | rb.Push<u32>(0); // bsd errno | ||
| 63 | } | 210 | } |
| 64 | 211 | ||
| 65 | void BSD::Connect(Kernel::HLERequestContext& ctx) { | 212 | void BSD::Connect(Kernel::HLERequestContext& ctx) { |
| 66 | LOG_WARNING(Service, "(STUBBED) called"); | 213 | IPC::RequestParser rp{ctx}; |
| 214 | const s32 fd = rp.Pop<s32>(); | ||
| 67 | 215 | ||
| 68 | IPC::ResponseBuilder rb{ctx, 4}; | 216 | LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize()); |
| 217 | |||
| 218 | ExecuteWork(ctx, "BSD:Connect", IsBlockingSocket(fd), | ||
| 219 | ConnectWork{ | ||
| 220 | .fd = fd, | ||
| 221 | .addr = ctx.ReadBuffer(), | ||
| 222 | }); | ||
| 223 | } | ||
| 224 | |||
| 225 | void BSD::GetPeerName(Kernel::HLERequestContext& ctx) { | ||
| 226 | IPC::RequestParser rp{ctx}; | ||
| 227 | const s32 fd = rp.Pop<s32>(); | ||
| 228 | |||
| 229 | LOG_DEBUG(Service, "called. fd={}", fd); | ||
| 69 | 230 | ||
| 231 | std::vector<u8> write_buffer(ctx.GetWriteBufferSize()); | ||
| 232 | const Errno bsd_errno = GetPeerNameImpl(fd, write_buffer); | ||
| 233 | |||
| 234 | ctx.WriteBuffer(write_buffer); | ||
| 235 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 5}; | ||
| 70 | rb.Push(RESULT_SUCCESS); | 237 | rb.Push(RESULT_SUCCESS); |
| 71 | rb.Push<u32>(0); // ret | 238 | rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0); |
| 72 | rb.Push<u32>(0); // bsd errno | 239 | rb.PushEnum(bsd_errno); |
| 240 | rb.Push<u32>(static_cast<u32>(write_buffer.size())); | ||
| 241 | } | ||
| 242 | |||
| 243 | void BSD::GetSockName(Kernel::HLERequestContext& ctx) { | ||
| 244 | IPC::RequestParser rp{ctx}; | ||
| 245 | const s32 fd = rp.Pop<s32>(); | ||
| 246 | |||
| 247 | LOG_DEBUG(Service, "called. fd={}", fd); | ||
| 248 | |||
| 249 | std::vector<u8> write_buffer(ctx.GetWriteBufferSize()); | ||
| 250 | const Errno bsd_errno = GetSockNameImpl(fd, write_buffer); | ||
| 251 | |||
| 252 | ctx.WriteBuffer(write_buffer); | ||
| 253 | |||
| 254 | IPC::ResponseBuilder rb{ctx, 5}; | ||
| 255 | rb.Push(RESULT_SUCCESS); | ||
| 256 | rb.Push<s32>(bsd_errno != Errno::SUCCESS ? -1 : 0); | ||
| 257 | rb.PushEnum(bsd_errno); | ||
| 258 | rb.Push<u32>(static_cast<u32>(write_buffer.size())); | ||
| 73 | } | 259 | } |
| 74 | 260 | ||
| 75 | void BSD::Listen(Kernel::HLERequestContext& ctx) { | 261 | void BSD::Listen(Kernel::HLERequestContext& ctx) { |
| 76 | LOG_WARNING(Service, "(STUBBED) called"); | 262 | IPC::RequestParser rp{ctx}; |
| 263 | const s32 fd = rp.Pop<s32>(); | ||
| 264 | const s32 backlog = rp.Pop<s32>(); | ||
| 77 | 265 | ||
| 78 | IPC::ResponseBuilder rb{ctx, 4}; | 266 | LOG_DEBUG(Service, "called. fd={} backlog={}", fd, backlog); |
| 267 | |||
| 268 | BuildErrnoResponse(ctx, ListenImpl(fd, backlog)); | ||
| 269 | } | ||
| 270 | |||
| 271 | void BSD::Fcntl(Kernel::HLERequestContext& ctx) { | ||
| 272 | IPC::RequestParser rp{ctx}; | ||
| 273 | const s32 fd = rp.Pop<s32>(); | ||
| 274 | const s32 cmd = rp.Pop<s32>(); | ||
| 275 | const s32 arg = rp.Pop<s32>(); | ||
| 79 | 276 | ||
| 277 | LOG_DEBUG(Service, "called. fd={} cmd={} arg={}", fd, cmd, arg); | ||
| 278 | |||
| 279 | const auto [ret, bsd_errno] = FcntlImpl(fd, static_cast<FcntlCmd>(cmd), arg); | ||
| 280 | |||
| 281 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 80 | rb.Push(RESULT_SUCCESS); | 282 | rb.Push(RESULT_SUCCESS); |
| 81 | rb.Push<u32>(0); // ret | 283 | rb.Push<s32>(ret); |
| 82 | rb.Push<u32>(0); // bsd errno | 284 | rb.PushEnum(bsd_errno); |
| 83 | } | 285 | } |
| 84 | 286 | ||
| 85 | void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) { | 287 | void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) { |
| 86 | LOG_WARNING(Service, "(STUBBED) called"); | 288 | IPC::RequestParser rp{ctx}; |
| 87 | 289 | ||
| 88 | IPC::ResponseBuilder rb{ctx, 4}; | 290 | const s32 fd = rp.Pop<s32>(); |
| 291 | const u32 level = rp.Pop<u32>(); | ||
| 292 | const OptName optname = static_cast<OptName>(rp.Pop<u32>()); | ||
| 89 | 293 | ||
| 90 | rb.Push(RESULT_SUCCESS); | 294 | const std::vector<u8> buffer = ctx.ReadBuffer(); |
| 91 | rb.Push<u32>(0); // ret | 295 | const u8* optval = buffer.empty() ? nullptr : buffer.data(); |
| 92 | rb.Push<u32>(0); // bsd errno | 296 | size_t optlen = buffer.size(); |
| 297 | |||
| 298 | std::array<u64, 2> values; | ||
| 299 | if ((optname == OptName::SNDTIMEO || optname == OptName::RCVTIMEO) && buffer.size() == 8) { | ||
| 300 | std::memcpy(values.data(), buffer.data(), sizeof(values)); | ||
| 301 | optlen = sizeof(values); | ||
| 302 | optval = reinterpret_cast<const u8*>(values.data()); | ||
| 303 | } | ||
| 304 | |||
| 305 | LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level, | ||
| 306 | static_cast<u32>(optname), optlen); | ||
| 307 | |||
| 308 | BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval)); | ||
| 309 | } | ||
| 310 | |||
| 311 | void BSD::Shutdown(Kernel::HLERequestContext& ctx) { | ||
| 312 | IPC::RequestParser rp{ctx}; | ||
| 313 | |||
| 314 | const s32 fd = rp.Pop<s32>(); | ||
| 315 | const s32 how = rp.Pop<s32>(); | ||
| 316 | |||
| 317 | LOG_DEBUG(Service, "called. fd={} how={}", fd, how); | ||
| 318 | |||
| 319 | BuildErrnoResponse(ctx, ShutdownImpl(fd, how)); | ||
| 320 | } | ||
| 321 | |||
| 322 | void BSD::Recv(Kernel::HLERequestContext& ctx) { | ||
| 323 | IPC::RequestParser rp{ctx}; | ||
| 324 | |||
| 325 | const s32 fd = rp.Pop<s32>(); | ||
| 326 | const u32 flags = rp.Pop<u32>(); | ||
| 327 | |||
| 328 | LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetWriteBufferSize()); | ||
| 329 | |||
| 330 | ExecuteWork(ctx, "BSD:Recv", IsBlockingSocket(fd), | ||
| 331 | RecvWork{ | ||
| 332 | .fd = fd, | ||
| 333 | .flags = flags, | ||
| 334 | .message = std::vector<u8>(ctx.GetWriteBufferSize()), | ||
| 335 | }); | ||
| 336 | } | ||
| 337 | |||
| 338 | void BSD::RecvFrom(Kernel::HLERequestContext& ctx) { | ||
| 339 | IPC::RequestParser rp{ctx}; | ||
| 340 | |||
| 341 | const s32 fd = rp.Pop<s32>(); | ||
| 342 | const u32 flags = rp.Pop<u32>(); | ||
| 343 | |||
| 344 | LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={} addrlen={}", fd, flags, | ||
| 345 | ctx.GetWriteBufferSize(0), ctx.GetWriteBufferSize(1)); | ||
| 346 | |||
| 347 | ExecuteWork(ctx, "BSD:RecvFrom", IsBlockingSocket(fd), | ||
| 348 | RecvFromWork{ | ||
| 349 | .fd = fd, | ||
| 350 | .flags = flags, | ||
| 351 | .message = std::vector<u8>(ctx.GetWriteBufferSize(0)), | ||
| 352 | .addr = std::vector<u8>(ctx.GetWriteBufferSize(1)), | ||
| 353 | }); | ||
| 354 | } | ||
| 355 | |||
| 356 | void BSD::Send(Kernel::HLERequestContext& ctx) { | ||
| 357 | IPC::RequestParser rp{ctx}; | ||
| 358 | |||
| 359 | const s32 fd = rp.Pop<s32>(); | ||
| 360 | const u32 flags = rp.Pop<u32>(); | ||
| 361 | |||
| 362 | LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetReadBufferSize()); | ||
| 363 | |||
| 364 | ExecuteWork(ctx, "BSD:Send", IsBlockingSocket(fd), | ||
| 365 | SendWork{ | ||
| 366 | .fd = fd, | ||
| 367 | .flags = flags, | ||
| 368 | .message = ctx.ReadBuffer(), | ||
| 369 | }); | ||
| 93 | } | 370 | } |
| 94 | 371 | ||
| 95 | void BSD::SendTo(Kernel::HLERequestContext& ctx) { | 372 | void BSD::SendTo(Kernel::HLERequestContext& ctx) { |
| 96 | LOG_WARNING(Service, "(STUBBED) called"); | 373 | IPC::RequestParser rp{ctx}; |
| 374 | const s32 fd = rp.Pop<s32>(); | ||
| 375 | const u32 flags = rp.Pop<u32>(); | ||
| 376 | |||
| 377 | LOG_DEBUG(Service, "called. fd={} flags=0x{} len={} addrlen={}", fd, flags, | ||
| 378 | ctx.GetReadBufferSize(0), ctx.GetReadBufferSize(1)); | ||
| 379 | |||
| 380 | ExecuteWork(ctx, "BSD:SendTo", IsBlockingSocket(fd), | ||
| 381 | SendToWork{ | ||
| 382 | .fd = fd, | ||
| 383 | .flags = flags, | ||
| 384 | .message = ctx.ReadBuffer(0), | ||
| 385 | .addr = ctx.ReadBuffer(1), | ||
| 386 | }); | ||
| 387 | } | ||
| 97 | 388 | ||
| 98 | IPC::ResponseBuilder rb{ctx, 4}; | 389 | void BSD::Write(Kernel::HLERequestContext& ctx) { |
| 390 | IPC::RequestParser rp{ctx}; | ||
| 391 | const s32 fd = rp.Pop<s32>(); | ||
| 99 | 392 | ||
| 100 | rb.Push(RESULT_SUCCESS); | 393 | LOG_DEBUG(Service, "called. fd={} len={}", fd, ctx.GetReadBufferSize()); |
| 101 | rb.Push<u32>(0); // ret | 394 | |
| 102 | rb.Push<u32>(0); // bsd errno | 395 | ExecuteWork(ctx, "BSD:Write", IsBlockingSocket(fd), |
| 396 | SendWork{ | ||
| 397 | .fd = fd, | ||
| 398 | .flags = 0, | ||
| 399 | .message = ctx.ReadBuffer(), | ||
| 400 | }); | ||
| 103 | } | 401 | } |
| 104 | 402 | ||
| 105 | void BSD::Close(Kernel::HLERequestContext& ctx) { | 403 | void BSD::Close(Kernel::HLERequestContext& ctx) { |
| 106 | LOG_WARNING(Service, "(STUBBED) called"); | 404 | IPC::RequestParser rp{ctx}; |
| 405 | const s32 fd = rp.Pop<s32>(); | ||
| 406 | |||
| 407 | LOG_DEBUG(Service, "called. fd={}", fd); | ||
| 408 | |||
| 409 | BuildErrnoResponse(ctx, CloseImpl(fd)); | ||
| 410 | } | ||
| 411 | |||
| 412 | template <typename Work> | ||
| 413 | void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason, | ||
| 414 | bool is_blocking, Work work) { | ||
| 415 | if (!is_blocking) { | ||
| 416 | work.Execute(this); | ||
| 417 | work.Response(ctx); | ||
| 418 | return; | ||
| 419 | } | ||
| 420 | |||
| 421 | // Signal a dummy response to make IPC validation happy | ||
| 422 | // This will be overwritten by the SleepClientThread callback | ||
| 423 | work.Response(ctx); | ||
| 424 | |||
| 425 | auto worker = worker_pool.CaptureWorker(); | ||
| 426 | |||
| 427 | ctx.SleepClientThread(std::string(sleep_reason), std::numeric_limits<u64>::max(), | ||
| 428 | worker->Callback<Work>(), worker->KernelEvent()); | ||
| 429 | |||
| 430 | worker->SendWork(std::move(work)); | ||
| 431 | } | ||
| 432 | |||
| 433 | std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) { | ||
| 434 | if (type == Type::SEQPACKET) { | ||
| 435 | UNIMPLEMENTED_MSG("SOCK_SEQPACKET errno management"); | ||
| 436 | } else if (type == Type::RAW && (domain != Domain::INET || protocol != Protocol::ICMP)) { | ||
| 437 | UNIMPLEMENTED_MSG("SOCK_RAW errno management"); | ||
| 438 | } | ||
| 439 | |||
| 440 | [[maybe_unused]] const bool unk_flag = (static_cast<u32>(type) & 0x20000000) != 0; | ||
| 441 | UNIMPLEMENTED_IF_MSG(unk_flag, "Unknown flag in type"); | ||
| 442 | type = static_cast<Type>(static_cast<u32>(type) & ~0x20000000); | ||
| 443 | |||
| 444 | const s32 fd = FindFreeFileDescriptorHandle(); | ||
| 445 | if (fd < 0) { | ||
| 446 | LOG_ERROR(Service, "No more file descriptors available"); | ||
| 447 | return {-1, Errno::MFILE}; | ||
| 448 | } | ||
| 449 | |||
| 450 | FileDescriptor& descriptor = file_descriptors[fd].emplace(); | ||
| 451 | // ENONMEM might be thrown here | ||
| 452 | |||
| 453 | LOG_INFO(Service, "New socket fd={}", fd); | ||
| 454 | |||
| 455 | descriptor.socket = std::make_unique<Network::Socket>(); | ||
| 456 | descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol)); | ||
| 457 | descriptor.is_connection_based = IsConnectionBased(type); | ||
| 458 | |||
| 459 | return {fd, Errno::SUCCESS}; | ||
| 460 | } | ||
| 107 | 461 | ||
| 462 | std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer, | ||
| 463 | s32 nfds, s32 timeout) { | ||
| 464 | if (write_buffer.size() < nfds * sizeof(PollFD)) { | ||
| 465 | return {-1, Errno::INVAL}; | ||
| 466 | } | ||
| 467 | |||
| 468 | if (nfds == 0) { | ||
| 469 | // When no entries are provided, -1 is returned with errno zero | ||
| 470 | return {-1, Errno::SUCCESS}; | ||
| 471 | } | ||
| 472 | |||
| 473 | const size_t length = std::min(read_buffer.size(), write_buffer.size()); | ||
| 474 | std::vector<PollFD> fds(nfds); | ||
| 475 | std::memcpy(fds.data(), read_buffer.data(), length); | ||
| 476 | |||
| 477 | if (timeout >= 0) { | ||
| 478 | const s64 seconds = timeout / 1000; | ||
| 479 | const u64 nanoseconds = 1'000'000 * (static_cast<u64>(timeout) % 1000); | ||
| 480 | |||
| 481 | if (seconds < 0) { | ||
| 482 | return {-1, Errno::INVAL}; | ||
| 483 | } | ||
| 484 | if (nanoseconds > 999'999'999) { | ||
| 485 | return {-1, Errno::INVAL}; | ||
| 486 | } | ||
| 487 | } else if (timeout != -1) { | ||
| 488 | return {-1, Errno::INVAL}; | ||
| 489 | } | ||
| 490 | |||
| 491 | for (PollFD& pollfd : fds) { | ||
| 492 | ASSERT(pollfd.revents == 0); | ||
| 493 | |||
| 494 | if (pollfd.fd > MAX_FD || pollfd.fd < 0) { | ||
| 495 | LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd); | ||
| 496 | pollfd.revents = 0; | ||
| 497 | return {0, Errno::SUCCESS}; | ||
| 498 | } | ||
| 499 | |||
| 500 | std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd]; | ||
| 501 | if (!descriptor) { | ||
| 502 | LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd); | ||
| 503 | pollfd.revents = POLL_NVAL; | ||
| 504 | return {0, Errno::SUCCESS}; | ||
| 505 | } | ||
| 506 | } | ||
| 507 | |||
| 508 | std::vector<Network::PollFD> host_pollfds(fds.size()); | ||
| 509 | std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) { | ||
| 510 | Network::PollFD result; | ||
| 511 | result.socket = file_descriptors[pollfd.fd]->socket.get(); | ||
| 512 | result.events = TranslatePollEventsToHost(pollfd.events); | ||
| 513 | result.revents = 0; | ||
| 514 | return result; | ||
| 515 | }); | ||
| 516 | |||
| 517 | const auto result = Network::Poll(host_pollfds, timeout); | ||
| 518 | |||
| 519 | const size_t num = host_pollfds.size(); | ||
| 520 | for (size_t i = 0; i < num; ++i) { | ||
| 521 | fds[i].revents = TranslatePollEventsToGuest(host_pollfds[i].revents); | ||
| 522 | } | ||
| 523 | std::memcpy(write_buffer.data(), fds.data(), length); | ||
| 524 | |||
| 525 | return Translate(result); | ||
| 526 | } | ||
| 527 | |||
| 528 | std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) { | ||
| 529 | if (!IsFileDescriptorValid(fd)) { | ||
| 530 | return {-1, Errno::BADF}; | ||
| 531 | } | ||
| 532 | |||
| 533 | const s32 new_fd = FindFreeFileDescriptorHandle(); | ||
| 534 | if (new_fd < 0) { | ||
| 535 | LOG_ERROR(Service, "No more file descriptors available"); | ||
| 536 | return {-1, Errno::MFILE}; | ||
| 537 | } | ||
| 538 | |||
| 539 | FileDescriptor& descriptor = *file_descriptors[fd]; | ||
| 540 | auto [result, bsd_errno] = descriptor.socket->Accept(); | ||
| 541 | if (bsd_errno != Network::Errno::SUCCESS) { | ||
| 542 | return {-1, Translate(bsd_errno)}; | ||
| 543 | } | ||
| 544 | |||
| 545 | FileDescriptor& new_descriptor = file_descriptors[new_fd].emplace(); | ||
| 546 | new_descriptor.socket = std::move(result.socket); | ||
| 547 | new_descriptor.is_connection_based = descriptor.is_connection_based; | ||
| 548 | |||
| 549 | ASSERT(write_buffer.size() == sizeof(SockAddrIn)); | ||
| 550 | const SockAddrIn guest_addr_in = Translate(result.sockaddr_in); | ||
| 551 | std::memcpy(write_buffer.data(), &guest_addr_in, sizeof(guest_addr_in)); | ||
| 552 | |||
| 553 | return {new_fd, Errno::SUCCESS}; | ||
| 554 | } | ||
| 555 | |||
| 556 | Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) { | ||
| 557 | if (!IsFileDescriptorValid(fd)) { | ||
| 558 | return Errno::BADF; | ||
| 559 | } | ||
| 560 | ASSERT(addr.size() == sizeof(SockAddrIn)); | ||
| 561 | SockAddrIn addr_in; | ||
| 562 | std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); | ||
| 563 | |||
| 564 | return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); | ||
| 565 | } | ||
| 566 | |||
| 567 | Errno BSD::ConnectImpl(s32 fd, const std::vector<u8>& addr) { | ||
| 568 | if (!IsFileDescriptorValid(fd)) { | ||
| 569 | return Errno::BADF; | ||
| 570 | } | ||
| 571 | |||
| 572 | UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); | ||
| 573 | SockAddrIn addr_in; | ||
| 574 | std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); | ||
| 575 | |||
| 576 | return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); | ||
| 577 | } | ||
| 578 | |||
| 579 | Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) { | ||
| 580 | if (!IsFileDescriptorValid(fd)) { | ||
| 581 | return Errno::BADF; | ||
| 582 | } | ||
| 583 | |||
| 584 | const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName(); | ||
| 585 | if (bsd_errno != Network::Errno::SUCCESS) { | ||
| 586 | return Translate(bsd_errno); | ||
| 587 | } | ||
| 588 | const SockAddrIn guest_addrin = Translate(addr_in); | ||
| 589 | |||
| 590 | ASSERT(write_buffer.size() == sizeof(guest_addrin)); | ||
| 591 | std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); | ||
| 592 | return Translate(bsd_errno); | ||
| 593 | } | ||
| 594 | |||
| 595 | Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) { | ||
| 596 | if (!IsFileDescriptorValid(fd)) { | ||
| 597 | return Errno::BADF; | ||
| 598 | } | ||
| 599 | |||
| 600 | const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName(); | ||
| 601 | if (bsd_errno != Network::Errno::SUCCESS) { | ||
| 602 | return Translate(bsd_errno); | ||
| 603 | } | ||
| 604 | const SockAddrIn guest_addrin = Translate(addr_in); | ||
| 605 | |||
| 606 | ASSERT(write_buffer.size() == sizeof(guest_addrin)); | ||
| 607 | std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); | ||
| 608 | return Translate(bsd_errno); | ||
| 609 | } | ||
| 610 | |||
| 611 | Errno BSD::ListenImpl(s32 fd, s32 backlog) { | ||
| 612 | if (!IsFileDescriptorValid(fd)) { | ||
| 613 | return Errno::BADF; | ||
| 614 | } | ||
| 615 | return Translate(file_descriptors[fd]->socket->Listen(backlog)); | ||
| 616 | } | ||
| 617 | |||
| 618 | std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) { | ||
| 619 | if (!IsFileDescriptorValid(fd)) { | ||
| 620 | return {-1, Errno::BADF}; | ||
| 621 | } | ||
| 622 | |||
| 623 | FileDescriptor& descriptor = *file_descriptors[fd]; | ||
| 624 | |||
| 625 | switch (cmd) { | ||
| 626 | case FcntlCmd::GETFL: | ||
| 627 | ASSERT(arg == 0); | ||
| 628 | return {descriptor.flags, Errno::SUCCESS}; | ||
| 629 | case FcntlCmd::SETFL: { | ||
| 630 | const bool enable = (arg & FLAG_O_NONBLOCK) != 0; | ||
| 631 | const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable)); | ||
| 632 | if (bsd_errno != Errno::SUCCESS) { | ||
| 633 | return {-1, bsd_errno}; | ||
| 634 | } | ||
| 635 | descriptor.flags = arg; | ||
| 636 | return {0, Errno::SUCCESS}; | ||
| 637 | } | ||
| 638 | default: | ||
| 639 | UNIMPLEMENTED_MSG("Unimplemented cmd={}", static_cast<int>(cmd)); | ||
| 640 | return {-1, Errno::SUCCESS}; | ||
| 641 | } | ||
| 642 | } | ||
| 643 | |||
| 644 | Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) { | ||
| 645 | UNIMPLEMENTED_IF(level != 0xffff); // SOL_SOCKET | ||
| 646 | |||
| 647 | if (!IsFileDescriptorValid(fd)) { | ||
| 648 | return Errno::BADF; | ||
| 649 | } | ||
| 650 | |||
| 651 | Network::Socket* const socket = file_descriptors[fd]->socket.get(); | ||
| 652 | |||
| 653 | if (optname == OptName::LINGER) { | ||
| 654 | ASSERT(optlen == sizeof(Linger)); | ||
| 655 | Linger linger; | ||
| 656 | std::memcpy(&linger, optval, sizeof(linger)); | ||
| 657 | ASSERT(linger.onoff == 0 || linger.onoff == 1); | ||
| 658 | |||
| 659 | return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); | ||
| 660 | } | ||
| 661 | |||
| 662 | ASSERT(optlen == sizeof(u32)); | ||
| 663 | u32 value; | ||
| 664 | std::memcpy(&value, optval, sizeof(value)); | ||
| 665 | |||
| 666 | switch (optname) { | ||
| 667 | case OptName::REUSEADDR: | ||
| 668 | ASSERT(value == 0 || value == 1); | ||
| 669 | return Translate(socket->SetReuseAddr(value != 0)); | ||
| 670 | case OptName::BROADCAST: | ||
| 671 | ASSERT(value == 0 || value == 1); | ||
| 672 | return Translate(socket->SetBroadcast(value != 0)); | ||
| 673 | case OptName::SNDBUF: | ||
| 674 | return Translate(socket->SetSndBuf(value)); | ||
| 675 | case OptName::RCVBUF: | ||
| 676 | return Translate(socket->SetRcvBuf(value)); | ||
| 677 | case OptName::SNDTIMEO: | ||
| 678 | return Translate(socket->SetSndTimeo(value)); | ||
| 679 | case OptName::RCVTIMEO: | ||
| 680 | return Translate(socket->SetRcvTimeo(value)); | ||
| 681 | default: | ||
| 682 | UNIMPLEMENTED_MSG("Unimplemented optname={}", static_cast<int>(optname)); | ||
| 683 | return Errno::SUCCESS; | ||
| 684 | } | ||
| 685 | } | ||
| 686 | |||
| 687 | Errno BSD::ShutdownImpl(s32 fd, s32 how) { | ||
| 688 | if (!IsFileDescriptorValid(fd)) { | ||
| 689 | return Errno::BADF; | ||
| 690 | } | ||
| 691 | const Network::ShutdownHow host_how = Translate(static_cast<ShutdownHow>(how)); | ||
| 692 | return Translate(file_descriptors[fd]->socket->Shutdown(host_how)); | ||
| 693 | } | ||
| 694 | |||
| 695 | std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) { | ||
| 696 | if (!IsFileDescriptorValid(fd)) { | ||
| 697 | return {-1, Errno::BADF}; | ||
| 698 | } | ||
| 699 | return Translate(file_descriptors[fd]->socket->Recv(flags, message)); | ||
| 700 | } | ||
| 701 | |||
| 702 | std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, | ||
| 703 | std::vector<u8>& addr) { | ||
| 704 | if (!IsFileDescriptorValid(fd)) { | ||
| 705 | return {-1, Errno::BADF}; | ||
| 706 | } | ||
| 707 | |||
| 708 | FileDescriptor& descriptor = *file_descriptors[fd]; | ||
| 709 | |||
| 710 | Network::SockAddrIn addr_in{}; | ||
| 711 | Network::SockAddrIn* p_addr_in = nullptr; | ||
| 712 | if (descriptor.is_connection_based) { | ||
| 713 | // Connection based file descriptors (e.g. TCP) zero addr | ||
| 714 | addr.clear(); | ||
| 715 | } else { | ||
| 716 | p_addr_in = &addr_in; | ||
| 717 | } | ||
| 718 | |||
| 719 | // Apply flags | ||
| 720 | if ((flags & FLAG_MSG_DONTWAIT) != 0) { | ||
| 721 | flags &= ~FLAG_MSG_DONTWAIT; | ||
| 722 | if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) { | ||
| 723 | descriptor.socket->SetNonBlock(true); | ||
| 724 | } | ||
| 725 | } | ||
| 726 | |||
| 727 | const auto [ret, bsd_errno] = Translate(descriptor.socket->RecvFrom(flags, message, p_addr_in)); | ||
| 728 | |||
| 729 | // Restore original state | ||
| 730 | if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) { | ||
| 731 | descriptor.socket->SetNonBlock(false); | ||
| 732 | } | ||
| 733 | |||
| 734 | if (p_addr_in) { | ||
| 735 | if (ret < 0) { | ||
| 736 | addr.clear(); | ||
| 737 | } else { | ||
| 738 | ASSERT(addr.size() == sizeof(SockAddrIn)); | ||
| 739 | const SockAddrIn result = Translate(addr_in); | ||
| 740 | std::memcpy(addr.data(), &result, sizeof(result)); | ||
| 741 | } | ||
| 742 | } | ||
| 743 | |||
| 744 | return {ret, bsd_errno}; | ||
| 745 | } | ||
| 746 | |||
| 747 | std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, const std::vector<u8>& message) { | ||
| 748 | if (!IsFileDescriptorValid(fd)) { | ||
| 749 | return {-1, Errno::BADF}; | ||
| 750 | } | ||
| 751 | return Translate(file_descriptors[fd]->socket->Send(message, flags)); | ||
| 752 | } | ||
| 753 | |||
| 754 | std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message, | ||
| 755 | const std::vector<u8>& addr) { | ||
| 756 | if (!IsFileDescriptorValid(fd)) { | ||
| 757 | return {-1, Errno::BADF}; | ||
| 758 | } | ||
| 759 | |||
| 760 | Network::SockAddrIn addr_in; | ||
| 761 | Network::SockAddrIn* p_addr_in = nullptr; | ||
| 762 | if (!addr.empty()) { | ||
| 763 | ASSERT(addr.size() == sizeof(SockAddrIn)); | ||
| 764 | SockAddrIn guest_addr_in; | ||
| 765 | std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in)); | ||
| 766 | addr_in = Translate(guest_addr_in); | ||
| 767 | } | ||
| 768 | |||
| 769 | return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in)); | ||
| 770 | } | ||
| 771 | |||
| 772 | Errno BSD::CloseImpl(s32 fd) { | ||
| 773 | if (!IsFileDescriptorValid(fd)) { | ||
| 774 | return Errno::BADF; | ||
| 775 | } | ||
| 776 | |||
| 777 | const Errno bsd_errno = Translate(file_descriptors[fd]->socket->Close()); | ||
| 778 | if (bsd_errno != Errno::SUCCESS) { | ||
| 779 | return bsd_errno; | ||
| 780 | } | ||
| 781 | |||
| 782 | LOG_INFO(Service, "Close socket fd={}", fd); | ||
| 783 | |||
| 784 | file_descriptors[fd].reset(); | ||
| 785 | return bsd_errno; | ||
| 786 | } | ||
| 787 | |||
| 788 | s32 BSD::FindFreeFileDescriptorHandle() noexcept { | ||
| 789 | for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) { | ||
| 790 | if (!file_descriptors[fd]) { | ||
| 791 | return fd; | ||
| 792 | } | ||
| 793 | } | ||
| 794 | return -1; | ||
| 795 | } | ||
| 796 | |||
| 797 | bool BSD::IsFileDescriptorValid(s32 fd) const noexcept { | ||
| 798 | if (fd > MAX_FD || fd < 0) { | ||
| 799 | LOG_ERROR(Service, "Invalid file descriptor handle={}", fd); | ||
| 800 | return false; | ||
| 801 | } | ||
| 802 | if (!file_descriptors[fd]) { | ||
| 803 | LOG_ERROR(Service, "File descriptor handle={} is not allocated", fd); | ||
| 804 | return false; | ||
| 805 | } | ||
| 806 | return true; | ||
| 807 | } | ||
| 808 | |||
| 809 | bool BSD::IsBlockingSocket(s32 fd) const noexcept { | ||
| 810 | // Inform invalid sockets as non-blocking | ||
| 811 | // This way we avoid using a worker thread as it will fail without blocking host | ||
| 812 | if (fd > MAX_FD || fd < 0) { | ||
| 813 | return false; | ||
| 814 | } | ||
| 815 | if (!file_descriptors[fd]) { | ||
| 816 | return false; | ||
| 817 | } | ||
| 818 | return (file_descriptors[fd]->flags & FLAG_O_NONBLOCK) != 0; | ||
| 819 | } | ||
| 820 | |||
| 821 | void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept { | ||
| 108 | IPC::ResponseBuilder rb{ctx, 4}; | 822 | IPC::ResponseBuilder rb{ctx, 4}; |
| 109 | 823 | ||
| 110 | rb.Push(RESULT_SUCCESS); | 824 | rb.Push(RESULT_SUCCESS); |
| 111 | rb.Push<u32>(0); // ret | 825 | rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1); |
| 112 | rb.Push<u32>(0); // bsd errno | 826 | rb.PushEnum(bsd_errno); |
| 113 | } | 827 | } |
| 114 | 828 | ||
| 115 | BSD::BSD(const char* name) : ServiceFramework(name) { | 829 | BSD::BSD(Core::System& system, const char* name) |
| 830 | : ServiceFramework(name), worker_pool{system, this} { | ||
| 116 | // clang-format off | 831 | // clang-format off |
| 117 | static const FunctionInfo functions[] = { | 832 | static const FunctionInfo functions[] = { |
| 118 | {0, &BSD::RegisterClient, "RegisterClient"}, | 833 | {0, &BSD::RegisterClient, "RegisterClient"}, |
| @@ -121,25 +836,25 @@ BSD::BSD(const char* name) : ServiceFramework(name) { | |||
| 121 | {3, nullptr, "SocketExempt"}, | 836 | {3, nullptr, "SocketExempt"}, |
| 122 | {4, nullptr, "Open"}, | 837 | {4, nullptr, "Open"}, |
| 123 | {5, &BSD::Select, "Select"}, | 838 | {5, &BSD::Select, "Select"}, |
| 124 | {6, nullptr, "Poll"}, | 839 | {6, &BSD::Poll, "Poll"}, |
| 125 | {7, nullptr, "Sysctl"}, | 840 | {7, nullptr, "Sysctl"}, |
| 126 | {8, nullptr, "Recv"}, | 841 | {8, &BSD::Recv, "Recv"}, |
| 127 | {9, nullptr, "RecvFrom"}, | 842 | {9, &BSD::RecvFrom, "RecvFrom"}, |
| 128 | {10, nullptr, "Send"}, | 843 | {10, &BSD::Send, "Send"}, |
| 129 | {11, &BSD::SendTo, "SendTo"}, | 844 | {11, &BSD::SendTo, "SendTo"}, |
| 130 | {12, nullptr, "Accept"}, | 845 | {12, &BSD::Accept, "Accept"}, |
| 131 | {13, &BSD::Bind, "Bind"}, | 846 | {13, &BSD::Bind, "Bind"}, |
| 132 | {14, &BSD::Connect, "Connect"}, | 847 | {14, &BSD::Connect, "Connect"}, |
| 133 | {15, nullptr, "GetPeerName"}, | 848 | {15, &BSD::GetPeerName, "GetPeerName"}, |
| 134 | {16, nullptr, "GetSockName"}, | 849 | {16, &BSD::GetSockName, "GetSockName"}, |
| 135 | {17, nullptr, "GetSockOpt"}, | 850 | {17, nullptr, "GetSockOpt"}, |
| 136 | {18, &BSD::Listen, "Listen"}, | 851 | {18, &BSD::Listen, "Listen"}, |
| 137 | {19, nullptr, "Ioctl"}, | 852 | {19, nullptr, "Ioctl"}, |
| 138 | {20, nullptr, "Fcntl"}, | 853 | {20, &BSD::Fcntl, "Fcntl"}, |
| 139 | {21, &BSD::SetSockOpt, "SetSockOpt"}, | 854 | {21, &BSD::SetSockOpt, "SetSockOpt"}, |
| 140 | {22, nullptr, "Shutdown"}, | 855 | {22, &BSD::Shutdown, "Shutdown"}, |
| 141 | {23, nullptr, "ShutdownAllSockets"}, | 856 | {23, nullptr, "ShutdownAllSockets"}, |
| 142 | {24, nullptr, "Write"}, | 857 | {24, &BSD::Write, "Write"}, |
| 143 | {25, nullptr, "Read"}, | 858 | {25, nullptr, "Read"}, |
| 144 | {26, &BSD::Close, "Close"}, | 859 | {26, &BSD::Close, "Close"}, |
| 145 | {27, nullptr, "DuplicateSocket"}, | 860 | {27, nullptr, "DuplicateSocket"}, |
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 3098e3baf..357531951 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h | |||
| @@ -4,30 +4,174 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 8 | #include <string_view> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/kernel/hle_ipc.h" | 12 | #include "core/hle/kernel/hle_ipc.h" |
| 8 | #include "core/hle/service/service.h" | 13 | #include "core/hle/service/service.h" |
| 14 | #include "core/hle/service/sockets/blocking_worker.h" | ||
| 15 | #include "core/hle/service/sockets/sockets.h" | ||
| 16 | |||
| 17 | namespace Core { | ||
| 18 | class System; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Network { | ||
| 22 | class Socket; | ||
| 23 | } | ||
| 9 | 24 | ||
| 10 | namespace Service::Sockets { | 25 | namespace Service::Sockets { |
| 11 | 26 | ||
| 12 | class BSD final : public ServiceFramework<BSD> { | 27 | class BSD final : public ServiceFramework<BSD> { |
| 13 | public: | 28 | public: |
| 14 | explicit BSD(const char* name); | 29 | explicit BSD(Core::System& system, const char* name); |
| 15 | ~BSD() override; | 30 | ~BSD() override; |
| 16 | 31 | ||
| 17 | private: | 32 | private: |
| 33 | /// Maximum number of file descriptors | ||
| 34 | static constexpr size_t MAX_FD = 128; | ||
| 35 | |||
| 36 | struct FileDescriptor { | ||
| 37 | std::unique_ptr<Network::Socket> socket; | ||
| 38 | s32 flags = 0; | ||
| 39 | bool is_connection_based = false; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct PollWork { | ||
| 43 | void Execute(BSD* bsd); | ||
| 44 | void Response(Kernel::HLERequestContext& ctx); | ||
| 45 | |||
| 46 | s32 nfds; | ||
| 47 | s32 timeout; | ||
| 48 | std::vector<u8> read_buffer; | ||
| 49 | std::vector<u8> write_buffer; | ||
| 50 | s32 ret{}; | ||
| 51 | Errno bsd_errno{}; | ||
| 52 | }; | ||
| 53 | |||
| 54 | struct AcceptWork { | ||
| 55 | void Execute(BSD* bsd); | ||
| 56 | void Response(Kernel::HLERequestContext& ctx); | ||
| 57 | |||
| 58 | s32 fd; | ||
| 59 | std::vector<u8> write_buffer; | ||
| 60 | s32 ret{}; | ||
| 61 | Errno bsd_errno{}; | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct ConnectWork { | ||
| 65 | void Execute(BSD* bsd); | ||
| 66 | void Response(Kernel::HLERequestContext& ctx); | ||
| 67 | |||
| 68 | s32 fd; | ||
| 69 | std::vector<u8> addr; | ||
| 70 | Errno bsd_errno{}; | ||
| 71 | }; | ||
| 72 | |||
| 73 | struct RecvWork { | ||
| 74 | void Execute(BSD* bsd); | ||
| 75 | void Response(Kernel::HLERequestContext& ctx); | ||
| 76 | |||
| 77 | s32 fd; | ||
| 78 | u32 flags; | ||
| 79 | std::vector<u8> message; | ||
| 80 | s32 ret{}; | ||
| 81 | Errno bsd_errno{}; | ||
| 82 | }; | ||
| 83 | |||
| 84 | struct RecvFromWork { | ||
| 85 | void Execute(BSD* bsd); | ||
| 86 | void Response(Kernel::HLERequestContext& ctx); | ||
| 87 | |||
| 88 | s32 fd; | ||
| 89 | u32 flags; | ||
| 90 | std::vector<u8> message; | ||
| 91 | std::vector<u8> addr; | ||
| 92 | s32 ret{}; | ||
| 93 | Errno bsd_errno{}; | ||
| 94 | }; | ||
| 95 | |||
| 96 | struct SendWork { | ||
| 97 | void Execute(BSD* bsd); | ||
| 98 | void Response(Kernel::HLERequestContext& ctx); | ||
| 99 | |||
| 100 | s32 fd; | ||
| 101 | u32 flags; | ||
| 102 | std::vector<u8> message; | ||
| 103 | s32 ret{}; | ||
| 104 | Errno bsd_errno{}; | ||
| 105 | }; | ||
| 106 | |||
| 107 | struct SendToWork { | ||
| 108 | void Execute(BSD* bsd); | ||
| 109 | void Response(Kernel::HLERequestContext& ctx); | ||
| 110 | |||
| 111 | s32 fd; | ||
| 112 | u32 flags; | ||
| 113 | std::vector<u8> message; | ||
| 114 | std::vector<u8> addr; | ||
| 115 | s32 ret{}; | ||
| 116 | Errno bsd_errno{}; | ||
| 117 | }; | ||
| 118 | |||
| 18 | void RegisterClient(Kernel::HLERequestContext& ctx); | 119 | void RegisterClient(Kernel::HLERequestContext& ctx); |
| 19 | void StartMonitoring(Kernel::HLERequestContext& ctx); | 120 | void StartMonitoring(Kernel::HLERequestContext& ctx); |
| 20 | void Socket(Kernel::HLERequestContext& ctx); | 121 | void Socket(Kernel::HLERequestContext& ctx); |
| 21 | void Select(Kernel::HLERequestContext& ctx); | 122 | void Select(Kernel::HLERequestContext& ctx); |
| 123 | void Poll(Kernel::HLERequestContext& ctx); | ||
| 124 | void Accept(Kernel::HLERequestContext& ctx); | ||
| 22 | void Bind(Kernel::HLERequestContext& ctx); | 125 | void Bind(Kernel::HLERequestContext& ctx); |
| 23 | void Connect(Kernel::HLERequestContext& ctx); | 126 | void Connect(Kernel::HLERequestContext& ctx); |
| 127 | void GetPeerName(Kernel::HLERequestContext& ctx); | ||
| 128 | void GetSockName(Kernel::HLERequestContext& ctx); | ||
| 24 | void Listen(Kernel::HLERequestContext& ctx); | 129 | void Listen(Kernel::HLERequestContext& ctx); |
| 130 | void Fcntl(Kernel::HLERequestContext& ctx); | ||
| 25 | void SetSockOpt(Kernel::HLERequestContext& ctx); | 131 | void SetSockOpt(Kernel::HLERequestContext& ctx); |
| 132 | void Shutdown(Kernel::HLERequestContext& ctx); | ||
| 133 | void Recv(Kernel::HLERequestContext& ctx); | ||
| 134 | void RecvFrom(Kernel::HLERequestContext& ctx); | ||
| 135 | void Send(Kernel::HLERequestContext& ctx); | ||
| 26 | void SendTo(Kernel::HLERequestContext& ctx); | 136 | void SendTo(Kernel::HLERequestContext& ctx); |
| 137 | void Write(Kernel::HLERequestContext& ctx); | ||
| 27 | void Close(Kernel::HLERequestContext& ctx); | 138 | void Close(Kernel::HLERequestContext& ctx); |
| 28 | 139 | ||
| 29 | /// Id to use for the next open file descriptor. | 140 | template <typename Work> |
| 30 | u32 next_fd = 1; | 141 | void ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason, |
| 142 | bool is_blocking, Work work); | ||
| 143 | |||
| 144 | std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol); | ||
| 145 | std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer, | ||
| 146 | s32 nfds, s32 timeout); | ||
| 147 | std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer); | ||
| 148 | Errno BindImpl(s32 fd, const std::vector<u8>& addr); | ||
| 149 | Errno ConnectImpl(s32 fd, const std::vector<u8>& addr); | ||
| 150 | Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer); | ||
| 151 | Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer); | ||
| 152 | Errno ListenImpl(s32 fd, s32 backlog); | ||
| 153 | std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); | ||
| 154 | Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval); | ||
| 155 | Errno ShutdownImpl(s32 fd, s32 how); | ||
| 156 | std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); | ||
| 157 | std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, | ||
| 158 | std::vector<u8>& addr); | ||
| 159 | std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, const std::vector<u8>& message); | ||
| 160 | std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message, | ||
| 161 | const std::vector<u8>& addr); | ||
| 162 | Errno CloseImpl(s32 fd); | ||
| 163 | |||
| 164 | s32 FindFreeFileDescriptorHandle() noexcept; | ||
| 165 | bool IsFileDescriptorValid(s32 fd) const noexcept; | ||
| 166 | bool IsBlockingSocket(s32 fd) const noexcept; | ||
| 167 | |||
| 168 | void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept; | ||
| 169 | |||
| 170 | std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors; | ||
| 171 | |||
| 172 | BlockingWorkerPool<BSD, PollWork, AcceptWork, ConnectWork, RecvWork, RecvFromWork, SendWork, | ||
| 173 | SendToWork> | ||
| 174 | worker_pool; | ||
| 31 | }; | 175 | }; |
| 32 | 176 | ||
| 33 | class BSDCFG final : public ServiceFramework<BSDCFG> { | 177 | class BSDCFG final : public ServiceFramework<BSDCFG> { |
diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp index 08d2d306a..1d27f7906 100644 --- a/src/core/hle/service/sockets/sockets.cpp +++ b/src/core/hle/service/sockets/sockets.cpp | |||
| @@ -10,9 +10,9 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::Sockets { | 11 | namespace Service::Sockets { |
| 12 | 12 | ||
| 13 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 13 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { |
| 14 | std::make_shared<BSD>("bsd:s")->InstallAsService(service_manager); | 14 | std::make_shared<BSD>(system, "bsd:s")->InstallAsService(service_manager); |
| 15 | std::make_shared<BSD>("bsd:u")->InstallAsService(service_manager); | 15 | std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager); |
| 16 | std::make_shared<BSDCFG>()->InstallAsService(service_manager); | 16 | std::make_shared<BSDCFG>()->InstallAsService(service_manager); |
| 17 | 17 | ||
| 18 | std::make_shared<ETHC_C>()->InstallAsService(service_manager); | 18 | std::make_shared<ETHC_C>()->InstallAsService(service_manager); |
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h index ca8a6a7e0..89a410076 100644 --- a/src/core/hle/service/sockets/sockets.h +++ b/src/core/hle/service/sockets/sockets.h | |||
| @@ -4,11 +4,94 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | ||
| 7 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 8 | 9 | ||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 9 | namespace Service::Sockets { | 14 | namespace Service::Sockets { |
| 10 | 15 | ||
| 16 | enum class Errno : u32 { | ||
| 17 | SUCCESS = 0, | ||
| 18 | BADF = 9, | ||
| 19 | AGAIN = 11, | ||
| 20 | INVAL = 22, | ||
| 21 | MFILE = 24, | ||
| 22 | NOTCONN = 107, | ||
| 23 | }; | ||
| 24 | |||
| 25 | enum class Domain : u32 { | ||
| 26 | INET = 2, | ||
| 27 | }; | ||
| 28 | |||
| 29 | enum class Type : u32 { | ||
| 30 | STREAM = 1, | ||
| 31 | DGRAM = 2, | ||
| 32 | RAW = 3, | ||
| 33 | SEQPACKET = 5, | ||
| 34 | }; | ||
| 35 | |||
| 36 | enum class Protocol : u32 { | ||
| 37 | UNSPECIFIED = 0, | ||
| 38 | ICMP = 1, | ||
| 39 | TCP = 6, | ||
| 40 | UDP = 17, | ||
| 41 | }; | ||
| 42 | |||
| 43 | enum class OptName : u32 { | ||
| 44 | REUSEADDR = 0x4, | ||
| 45 | BROADCAST = 0x20, | ||
| 46 | LINGER = 0x80, | ||
| 47 | SNDBUF = 0x1001, | ||
| 48 | RCVBUF = 0x1002, | ||
| 49 | SNDTIMEO = 0x1005, | ||
| 50 | RCVTIMEO = 0x1006, | ||
| 51 | }; | ||
| 52 | |||
| 53 | enum class ShutdownHow : s32 { | ||
| 54 | RD = 0, | ||
| 55 | WR = 1, | ||
| 56 | RDWR = 2, | ||
| 57 | }; | ||
| 58 | |||
| 59 | enum class FcntlCmd : s32 { | ||
| 60 | GETFL = 3, | ||
| 61 | SETFL = 4, | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct SockAddrIn { | ||
| 65 | u8 len; | ||
| 66 | u8 family; | ||
| 67 | u16 portno; | ||
| 68 | std::array<u8, 4> ip; | ||
| 69 | std::array<u8, 8> zeroes; | ||
| 70 | }; | ||
| 71 | |||
| 72 | struct PollFD { | ||
| 73 | s32 fd; | ||
| 74 | u16 events; | ||
| 75 | u16 revents; | ||
| 76 | }; | ||
| 77 | |||
| 78 | struct Linger { | ||
| 79 | u32 onoff; | ||
| 80 | u32 linger; | ||
| 81 | }; | ||
| 82 | |||
| 83 | constexpr u16 POLL_IN = 0x01; | ||
| 84 | constexpr u16 POLL_PRI = 0x02; | ||
| 85 | constexpr u16 POLL_OUT = 0x04; | ||
| 86 | constexpr u16 POLL_ERR = 0x08; | ||
| 87 | constexpr u16 POLL_HUP = 0x10; | ||
| 88 | constexpr u16 POLL_NVAL = 0x20; | ||
| 89 | |||
| 90 | constexpr u32 FLAG_MSG_DONTWAIT = 0x80; | ||
| 91 | |||
| 92 | constexpr u32 FLAG_O_NONBLOCK = 0x800; | ||
| 93 | |||
| 11 | /// Registers all Sockets services with the specified service manager. | 94 | /// Registers all Sockets services with the specified service manager. |
| 12 | void InstallInterfaces(SM::ServiceManager& service_manager); | 95 | void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); |
| 13 | 96 | ||
| 14 | } // namespace Service::Sockets | 97 | } // namespace Service::Sockets |
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp new file mode 100644 index 000000000..2be8f642d --- /dev/null +++ b/src/core/hle/service/sockets/sockets_translate.cpp | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <utility> | ||
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/service/sockets/sockets.h" | ||
| 10 | #include "core/hle/service/sockets/sockets_translate.h" | ||
| 11 | #include "core/network/network.h" | ||
| 12 | |||
| 13 | namespace Service::Sockets { | ||
| 14 | |||
| 15 | Errno Translate(Network::Errno value) { | ||
| 16 | switch (value) { | ||
| 17 | case Network::Errno::SUCCESS: | ||
| 18 | return Errno::SUCCESS; | ||
| 19 | case Network::Errno::BADF: | ||
| 20 | return Errno::BADF; | ||
| 21 | case Network::Errno::AGAIN: | ||
| 22 | return Errno::AGAIN; | ||
| 23 | case Network::Errno::INVAL: | ||
| 24 | return Errno::INVAL; | ||
| 25 | case Network::Errno::MFILE: | ||
| 26 | return Errno::MFILE; | ||
| 27 | case Network::Errno::NOTCONN: | ||
| 28 | return Errno::NOTCONN; | ||
| 29 | default: | ||
| 30 | UNIMPLEMENTED_MSG("Unimplemented errno={}", static_cast<int>(value)); | ||
| 31 | return Errno::SUCCESS; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) { | ||
| 36 | return {value.first, Translate(value.second)}; | ||
| 37 | } | ||
| 38 | |||
| 39 | Network::Domain Translate(Domain domain) { | ||
| 40 | switch (domain) { | ||
| 41 | case Domain::INET: | ||
| 42 | return Network::Domain::INET; | ||
| 43 | default: | ||
| 44 | UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain)); | ||
| 45 | return {}; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | Domain Translate(Network::Domain domain) { | ||
| 50 | switch (domain) { | ||
| 51 | case Network::Domain::INET: | ||
| 52 | return Domain::INET; | ||
| 53 | default: | ||
| 54 | UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain)); | ||
| 55 | return {}; | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | Network::Type Translate(Type type) { | ||
| 60 | switch (type) { | ||
| 61 | case Type::STREAM: | ||
| 62 | return Network::Type::STREAM; | ||
| 63 | case Type::DGRAM: | ||
| 64 | return Network::Type::DGRAM; | ||
| 65 | default: | ||
| 66 | UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type)); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | Network::Protocol Translate(Type type, Protocol protocol) { | ||
| 71 | switch (protocol) { | ||
| 72 | case Protocol::UNSPECIFIED: | ||
| 73 | LOG_WARNING(Service, "Unspecified protocol, assuming protocol from type"); | ||
| 74 | switch (type) { | ||
| 75 | case Type::DGRAM: | ||
| 76 | return Network::Protocol::UDP; | ||
| 77 | case Type::STREAM: | ||
| 78 | return Network::Protocol::TCP; | ||
| 79 | default: | ||
| 80 | return Network::Protocol::TCP; | ||
| 81 | } | ||
| 82 | case Protocol::TCP: | ||
| 83 | return Network::Protocol::TCP; | ||
| 84 | case Protocol::UDP: | ||
| 85 | return Network::Protocol::UDP; | ||
| 86 | default: | ||
| 87 | UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol)); | ||
| 88 | return Network::Protocol::TCP; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | u16 TranslatePollEventsToHost(u16 flags) { | ||
| 93 | u16 result = 0; | ||
| 94 | const auto translate = [&result, &flags](u16 from, u16 to) { | ||
| 95 | if ((flags & from) != 0) { | ||
| 96 | flags &= ~from; | ||
| 97 | result |= to; | ||
| 98 | } | ||
| 99 | }; | ||
| 100 | translate(POLL_IN, Network::POLL_IN); | ||
| 101 | translate(POLL_PRI, Network::POLL_PRI); | ||
| 102 | translate(POLL_OUT, Network::POLL_OUT); | ||
| 103 | translate(POLL_ERR, Network::POLL_ERR); | ||
| 104 | translate(POLL_HUP, Network::POLL_HUP); | ||
| 105 | translate(POLL_NVAL, Network::POLL_NVAL); | ||
| 106 | |||
| 107 | UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags); | ||
| 108 | return result; | ||
| 109 | } | ||
| 110 | |||
| 111 | u16 TranslatePollEventsToGuest(u16 flags) { | ||
| 112 | u16 result = 0; | ||
| 113 | const auto translate = [&result, &flags](u16 from, u16 to) { | ||
| 114 | if ((flags & from) != 0) { | ||
| 115 | flags &= ~from; | ||
| 116 | result |= to; | ||
| 117 | } | ||
| 118 | }; | ||
| 119 | |||
| 120 | translate(Network::POLL_IN, POLL_IN); | ||
| 121 | translate(Network::POLL_PRI, POLL_PRI); | ||
| 122 | translate(Network::POLL_OUT, POLL_OUT); | ||
| 123 | translate(Network::POLL_ERR, POLL_ERR); | ||
| 124 | translate(Network::POLL_HUP, POLL_HUP); | ||
| 125 | translate(Network::POLL_NVAL, POLL_NVAL); | ||
| 126 | |||
| 127 | UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags); | ||
| 128 | return result; | ||
| 129 | } | ||
| 130 | |||
| 131 | Network::SockAddrIn Translate(SockAddrIn value) { | ||
| 132 | ASSERT(value.len == 0 || value.len == sizeof(value)); | ||
| 133 | |||
| 134 | Network::SockAddrIn result; | ||
| 135 | result.family = Translate(static_cast<Domain>(value.family)); | ||
| 136 | result.ip = value.ip; | ||
| 137 | result.portno = value.portno >> 8 | value.portno << 8; | ||
| 138 | return result; | ||
| 139 | } | ||
| 140 | |||
| 141 | SockAddrIn Translate(Network::SockAddrIn value) { | ||
| 142 | SockAddrIn result; | ||
| 143 | result.len = sizeof(result); | ||
| 144 | result.family = static_cast<u8>(Translate(value.family)); | ||
| 145 | result.portno = value.portno >> 8 | value.portno << 8; | ||
| 146 | result.ip = value.ip; | ||
| 147 | result.zeroes = {}; | ||
| 148 | return result; | ||
| 149 | } | ||
| 150 | |||
| 151 | Network::ShutdownHow Translate(ShutdownHow how) { | ||
| 152 | switch (how) { | ||
| 153 | case ShutdownHow::RD: | ||
| 154 | return Network::ShutdownHow::RD; | ||
| 155 | case ShutdownHow::WR: | ||
| 156 | return Network::ShutdownHow::WR; | ||
| 157 | case ShutdownHow::RDWR: | ||
| 158 | return Network::ShutdownHow::RDWR; | ||
| 159 | default: | ||
| 160 | UNIMPLEMENTED_MSG("Unimplemented how={}", static_cast<int>(how)); | ||
| 161 | return {}; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | } // namespace Service::Sockets | ||
diff --git a/src/core/hle/service/sockets/sockets_translate.h b/src/core/hle/service/sockets/sockets_translate.h new file mode 100644 index 000000000..8ed041e31 --- /dev/null +++ b/src/core/hle/service/sockets/sockets_translate.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <utility> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/service/sockets/sockets.h" | ||
| 11 | #include "core/network/network.h" | ||
| 12 | |||
| 13 | namespace Service::Sockets { | ||
| 14 | |||
| 15 | /// Translate abstract errno to guest errno | ||
| 16 | Errno Translate(Network::Errno value); | ||
| 17 | |||
| 18 | /// Translate abstract return value errno pair to guest return value errno pair | ||
| 19 | std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value); | ||
| 20 | |||
| 21 | /// Translate guest domain to abstract domain | ||
| 22 | Network::Domain Translate(Domain domain); | ||
| 23 | |||
| 24 | /// Translate abstract domain to guest domain | ||
| 25 | Domain Translate(Network::Domain domain); | ||
| 26 | |||
| 27 | /// Translate guest type to abstract type | ||
| 28 | Network::Type Translate(Type type); | ||
| 29 | |||
| 30 | /// Translate guest protocol to abstract protocol | ||
| 31 | Network::Protocol Translate(Type type, Protocol protocol); | ||
| 32 | |||
| 33 | /// Translate abstract poll event flags to guest poll event flags | ||
| 34 | u16 TranslatePollEventsToHost(u16 flags); | ||
| 35 | |||
| 36 | /// Translate guest poll event flags to abstract poll event flags | ||
| 37 | u16 TranslatePollEventsToGuest(u16 flags); | ||
| 38 | |||
| 39 | /// Translate guest socket address structure to abstract socket address structure | ||
| 40 | Network::SockAddrIn Translate(SockAddrIn value); | ||
| 41 | |||
| 42 | /// Translate abstract socket address structure to guest socket address structure | ||
| 43 | SockAddrIn Translate(Network::SockAddrIn value); | ||
| 44 | |||
| 45 | /// Translate guest shutdown mode to abstract shutdown mode | ||
| 46 | Network::ShutdownHow Translate(ShutdownHow how); | ||
| 47 | |||
| 48 | } // namespace Service::Sockets | ||
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 74759ea7d..c6c423c4b 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp | |||
| @@ -283,7 +283,7 @@ void Adapter::Reset() { | |||
| 283 | } | 283 | } |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | bool Adapter::DeviceConnected(std::size_t port) { | 286 | bool Adapter::DeviceConnected(std::size_t port) const { |
| 287 | return adapter_controllers_status[port] != ControllerTypes::None; | 287 | return adapter_controllers_status[port] != ControllerTypes::None; |
| 288 | } | 288 | } |
| 289 | 289 | ||
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index bed81915c..20e97d283 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h | |||
| @@ -76,7 +76,7 @@ public: | |||
| 76 | void EndConfiguration(); | 76 | void EndConfiguration(); |
| 77 | 77 | ||
| 78 | /// Returns true if there is a device connected to port | 78 | /// Returns true if there is a device connected to port |
| 79 | bool DeviceConnected(std::size_t port); | 79 | bool DeviceConnected(std::size_t port) const; |
| 80 | 80 | ||
| 81 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); | 81 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); |
| 82 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; | 82 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; |
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 1c8d8523a..92e9e8e89 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp | |||
| @@ -15,7 +15,7 @@ namespace InputCommon { | |||
| 15 | 15 | ||
| 16 | class GCButton final : public Input::ButtonDevice { | 16 | class GCButton final : public Input::ButtonDevice { |
| 17 | public: | 17 | public: |
| 18 | explicit GCButton(int port_, int button_, GCAdapter::Adapter* adapter) | 18 | explicit GCButton(int port_, int button_, const GCAdapter::Adapter* adapter) |
| 19 | : port(port_), button(button_), gcadapter(adapter) {} | 19 | : port(port_), button(button_), gcadapter(adapter) {} |
| 20 | 20 | ||
| 21 | ~GCButton() override; | 21 | ~GCButton() override; |
| @@ -30,13 +30,13 @@ public: | |||
| 30 | private: | 30 | private: |
| 31 | const int port; | 31 | const int port; |
| 32 | const int button; | 32 | const int button; |
| 33 | GCAdapter::Adapter* gcadapter; | 33 | const GCAdapter::Adapter* gcadapter; |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | class GCAxisButton final : public Input::ButtonDevice { | 36 | class GCAxisButton final : public Input::ButtonDevice { |
| 37 | public: | 37 | public: |
| 38 | explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, | 38 | explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, |
| 39 | GCAdapter::Adapter* adapter) | 39 | const GCAdapter::Adapter* adapter) |
| 40 | : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), | 40 | : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), |
| 41 | gcadapter(adapter), | 41 | gcadapter(adapter), |
| 42 | origin_value(static_cast<float>(adapter->GetOriginValue(port_, axis_))) {} | 42 | origin_value(static_cast<float>(adapter->GetOriginValue(port_, axis_))) {} |
| @@ -60,7 +60,7 @@ private: | |||
| 60 | const int axis; | 60 | const int axis; |
| 61 | float threshold; | 61 | float threshold; |
| 62 | bool trigger_if_greater; | 62 | bool trigger_if_greater; |
| 63 | GCAdapter::Adapter* gcadapter; | 63 | const GCAdapter::Adapter* gcadapter; |
| 64 | const float origin_value; | 64 | const float origin_value; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| @@ -149,8 +149,8 @@ void GCButtonFactory::EndConfiguration() { | |||
| 149 | 149 | ||
| 150 | class GCAnalog final : public Input::AnalogDevice { | 150 | class GCAnalog final : public Input::AnalogDevice { |
| 151 | public: | 151 | public: |
| 152 | GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter, | 152 | GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, |
| 153 | float range_) | 153 | const GCAdapter::Adapter* adapter, float range_) |
| 154 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), | 154 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), |
| 155 | origin_value_x(static_cast<float>(adapter->GetOriginValue(port_, axis_x_))), | 155 | origin_value_x(static_cast<float>(adapter->GetOriginValue(port_, axis_x_))), |
| 156 | origin_value_y(static_cast<float>(adapter->GetOriginValue(port_, axis_y_))), | 156 | origin_value_y(static_cast<float>(adapter->GetOriginValue(port_, axis_y_))), |
| @@ -212,7 +212,7 @@ private: | |||
| 212 | const int axis_x; | 212 | const int axis_x; |
| 213 | const int axis_y; | 213 | const int axis_y; |
| 214 | const float deadzone; | 214 | const float deadzone; |
| 215 | GCAdapter::Adapter* gcadapter; | 215 | const GCAdapter::Adapter* gcadapter; |
| 216 | const float origin_value_x; | 216 | const float origin_value_x; |
| 217 | const float origin_value_y; | 217 | const float origin_value_y; |
| 218 | const float range; | 218 | const float range; |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 0cd0054c8..92779a9c7 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -49,10 +49,10 @@ class GameListItem : public QStandardItem { | |||
| 49 | 49 | ||
| 50 | public: | 50 | public: |
| 51 | // used to access type from item index | 51 | // used to access type from item index |
| 52 | static const int TypeRole = Qt::UserRole + 1; | 52 | static constexpr int TypeRole = Qt::UserRole + 1; |
| 53 | static const int SortRole = Qt::UserRole + 2; | 53 | static constexpr int SortRole = Qt::UserRole + 2; |
| 54 | GameListItem() = default; | 54 | GameListItem() = default; |
| 55 | GameListItem(const QString& string) : QStandardItem(string) { | 55 | explicit GameListItem(const QString& string) : QStandardItem(string) { |
| 56 | setData(string, SortRole); | 56 | setData(string, SortRole); |
| 57 | } | 57 | } |
| 58 | }; | 58 | }; |
| @@ -65,10 +65,10 @@ public: | |||
| 65 | */ | 65 | */ |
| 66 | class GameListItemPath : public GameListItem { | 66 | class GameListItemPath : public GameListItem { |
| 67 | public: | 67 | public: |
| 68 | static const int TitleRole = SortRole + 1; | 68 | static constexpr int TitleRole = SortRole + 1; |
| 69 | static const int FullPathRole = SortRole + 2; | 69 | static constexpr int FullPathRole = SortRole + 2; |
| 70 | static const int ProgramIdRole = SortRole + 3; | 70 | static constexpr int ProgramIdRole = SortRole + 3; |
| 71 | static const int FileTypeRole = SortRole + 4; | 71 | static constexpr int FileTypeRole = SortRole + 4; |
| 72 | 72 | ||
| 73 | GameListItemPath() = default; | 73 | GameListItemPath() = default; |
| 74 | GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data, | 74 | GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data, |
| @@ -110,18 +110,22 @@ public: | |||
| 110 | const auto& row1 = row_data.at(UISettings::values.row_1_text_id); | 110 | const auto& row1 = row_data.at(UISettings::values.row_1_text_id); |
| 111 | const int row2_id = UISettings::values.row_2_text_id; | 111 | const int row2_id = UISettings::values.row_2_text_id; |
| 112 | 112 | ||
| 113 | if (role == SortRole) | 113 | if (role == SortRole) { |
| 114 | return row1.toLower(); | 114 | return row1.toLower(); |
| 115 | } | ||
| 115 | 116 | ||
| 116 | if (row2_id == 4) // None | 117 | // None |
| 118 | if (row2_id == 4) { | ||
| 117 | return row1; | 119 | return row1; |
| 120 | } | ||
| 118 | 121 | ||
| 119 | const auto& row2 = row_data.at(row2_id); | 122 | const auto& row2 = row_data.at(row2_id); |
| 120 | 123 | ||
| 121 | if (row1 == row2) | 124 | if (row1 == row2) { |
| 122 | return row1; | 125 | return row1; |
| 126 | } | ||
| 123 | 127 | ||
| 124 | return QString(row1 + QStringLiteral("\n ") + row2); | 128 | return QStringLiteral("%1\n %2").arg(row1, row2); |
| 125 | } | 129 | } |
| 126 | 130 | ||
| 127 | return GameListItem::data(role); | 131 | return GameListItem::data(role); |
| @@ -131,7 +135,7 @@ public: | |||
| 131 | class GameListItemCompat : public GameListItem { | 135 | class GameListItemCompat : public GameListItem { |
| 132 | Q_DECLARE_TR_FUNCTIONS(GameListItemCompat) | 136 | Q_DECLARE_TR_FUNCTIONS(GameListItemCompat) |
| 133 | public: | 137 | public: |
| 134 | static const int CompatNumberRole = SortRole; | 138 | static constexpr int CompatNumberRole = SortRole; |
| 135 | GameListItemCompat() = default; | 139 | GameListItemCompat() = default; |
| 136 | explicit GameListItemCompat(const QString& compatibility) { | 140 | explicit GameListItemCompat(const QString& compatibility) { |
| 137 | setData(type(), TypeRole); | 141 | setData(type(), TypeRole); |
| @@ -181,7 +185,7 @@ public: | |||
| 181 | */ | 185 | */ |
| 182 | class GameListItemSize : public GameListItem { | 186 | class GameListItemSize : public GameListItem { |
| 183 | public: | 187 | public: |
| 184 | static const int SizeRole = SortRole; | 188 | static constexpr int SizeRole = SortRole; |
| 185 | 189 | ||
| 186 | GameListItemSize() = default; | 190 | GameListItemSize() = default; |
| 187 | explicit GameListItemSize(const qulonglong size_bytes) { | 191 | explicit GameListItemSize(const qulonglong size_bytes) { |
| @@ -217,7 +221,7 @@ public: | |||
| 217 | 221 | ||
| 218 | class GameListDir : public GameListItem { | 222 | class GameListDir : public GameListItem { |
| 219 | public: | 223 | public: |
| 220 | static const int GameDirRole = Qt::UserRole + 2; | 224 | static constexpr int GameDirRole = Qt::UserRole + 2; |
| 221 | 225 | ||
| 222 | explicit GameListDir(UISettings::GameDir& directory, | 226 | explicit GameListDir(UISettings::GameDir& directory, |
| 223 | GameListItemType dir_type = GameListItemType::CustomDir) | 227 | GameListItemType dir_type = GameListItemType::CustomDir) |