summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp16
-rw-r--r--src/core/hle/service/hid/controllers/npad.h1
-rw-r--r--src/core/hle/service/hid/hid.cpp12
-rw-r--r--src/core/hle/service/nifm/nifm.cpp13
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/sockets/blocking_worker.h162
-rw-r--r--src/core/hle/service/sockets/bsd.cpp809
-rw-r--r--src/core/hle/service/sockets/bsd.h150
-rw-r--r--src/core/hle/service/sockets/sockets.cpp6
-rw-r--r--src/core/hle/service/sockets/sockets.h85
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp165
-rw-r--r--src/core/hle/service/sockets/sockets_translate.h48
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp2
-rw-r--r--src/input_common/gcadapter/gc_adapter.h2
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp14
-rw-r--r--src/yuzu/game_list_p.h32
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
577void 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
577void Controller_NPad::StartLRAssignmentMode() { 593void 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
672void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { 672void 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
14namespace Service::NIFM { 15namespace 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
26namespace 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 */
34template <class Service, class... Types>
35class BlockingWorker {
36 using This = BlockingWorker<Service, Types...>;
37 using WorkVariant = std::variant<std::monostate, Types...>;
38
39public:
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
94private:
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
133template <class Service, class... Types>
134class BlockingWorkerPool {
135 using Worker = BlockingWorker<Service, Types...>;
136
137public:
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
155private:
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
8namespace Service::Sockets { 22namespace Service::Sockets {
9 23
24namespace {
25
26bool 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
40void BSD::PollWork::Execute(BSD* bsd) {
41 std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
42}
43
44void 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
53void BSD::AcceptWork::Execute(BSD* bsd) {
54 std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
55}
56
57void 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
67void BSD::ConnectWork::Execute(BSD* bsd) {
68 bsd_errno = bsd->ConnectImpl(fd, addr);
69}
70
71void 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
78void BSD::RecvWork::Execute(BSD* bsd) {
79 std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
80}
81
82void 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
91void BSD::RecvFromWork::Execute(BSD* bsd) {
92 std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
93}
94
95void 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
108void BSD::SendWork::Execute(BSD* bsd) {
109 std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
110}
111
112void 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
119void BSD::SendToWork::Execute(BSD* bsd) {
120 std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
121}
122
123void 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
10void BSD::RegisterClient(Kernel::HLERequestContext& ctx) { 130void 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
19void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) { 139void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
@@ -26,20 +146,19 @@ void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
26 146
27void BSD::Socket(Kernel::HLERequestContext& ctx) { 147void 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
45void BSD::Select(Kernel::HLERequestContext& ctx) { 164void 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
174void 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
190void 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
55void BSD::Bind(Kernel::HLERequestContext& ctx) { 203void 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
65void BSD::Connect(Kernel::HLERequestContext& ctx) { 212void 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
225void 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
243void 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
75void BSD::Listen(Kernel::HLERequestContext& ctx) { 261void 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
271void 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
85void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) { 287void 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
311void 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
322void 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
338void 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
356void 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
95void BSD::SendTo(Kernel::HLERequestContext& ctx) { 372void 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}; 389void 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
105void BSD::Close(Kernel::HLERequestContext& ctx) { 403void 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
412template <typename Work>
413void 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
433std::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
462std::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
528std::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
556Errno 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
567Errno 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
579Errno 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
595Errno 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
611Errno 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
618std::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
644Errno 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
687Errno 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
695std::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
702std::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
747std::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
754std::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
772Errno 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
788s32 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
797bool 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
809bool 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
821void 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
115BSD::BSD(const char* name) : ServiceFramework(name) { 829BSD::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
17namespace Core {
18class System;
19}
20
21namespace Network {
22class Socket;
23}
9 24
10namespace Service::Sockets { 25namespace Service::Sockets {
11 26
12class BSD final : public ServiceFramework<BSD> { 27class BSD final : public ServiceFramework<BSD> {
13public: 28public:
14 explicit BSD(const char* name); 29 explicit BSD(Core::System& system, const char* name);
15 ~BSD() override; 30 ~BSD() override;
16 31
17private: 32private:
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
33class BSDCFG final : public ServiceFramework<BSDCFG> { 177class 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
11namespace Service::Sockets { 11namespace Service::Sockets {
12 12
13void InstallInterfaces(SM::ServiceManager& service_manager) { 13void 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
10namespace Core {
11class System;
12}
13
9namespace Service::Sockets { 14namespace Service::Sockets {
10 15
16enum class Errno : u32 {
17 SUCCESS = 0,
18 BADF = 9,
19 AGAIN = 11,
20 INVAL = 22,
21 MFILE = 24,
22 NOTCONN = 107,
23};
24
25enum class Domain : u32 {
26 INET = 2,
27};
28
29enum class Type : u32 {
30 STREAM = 1,
31 DGRAM = 2,
32 RAW = 3,
33 SEQPACKET = 5,
34};
35
36enum class Protocol : u32 {
37 UNSPECIFIED = 0,
38 ICMP = 1,
39 TCP = 6,
40 UDP = 17,
41};
42
43enum 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
53enum class ShutdownHow : s32 {
54 RD = 0,
55 WR = 1,
56 RDWR = 2,
57};
58
59enum class FcntlCmd : s32 {
60 GETFL = 3,
61 SETFL = 4,
62};
63
64struct SockAddrIn {
65 u8 len;
66 u8 family;
67 u16 portno;
68 std::array<u8, 4> ip;
69 std::array<u8, 8> zeroes;
70};
71
72struct PollFD {
73 s32 fd;
74 u16 events;
75 u16 revents;
76};
77
78struct Linger {
79 u32 onoff;
80 u32 linger;
81};
82
83constexpr u16 POLL_IN = 0x01;
84constexpr u16 POLL_PRI = 0x02;
85constexpr u16 POLL_OUT = 0x04;
86constexpr u16 POLL_ERR = 0x08;
87constexpr u16 POLL_HUP = 0x10;
88constexpr u16 POLL_NVAL = 0x20;
89
90constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
91
92constexpr 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.
12void InstallInterfaces(SM::ServiceManager& service_manager); 95void 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
13namespace Service::Sockets {
14
15Errno 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
35std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value) {
36 return {value.first, Translate(value.second)};
37}
38
39Network::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
49Domain 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
59Network::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
70Network::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
92u16 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
111u16 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
131Network::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
141SockAddrIn 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
151Network::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
13namespace Service::Sockets {
14
15/// Translate abstract errno to guest errno
16Errno Translate(Network::Errno value);
17
18/// Translate abstract return value errno pair to guest return value errno pair
19std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value);
20
21/// Translate guest domain to abstract domain
22Network::Domain Translate(Domain domain);
23
24/// Translate abstract domain to guest domain
25Domain Translate(Network::Domain domain);
26
27/// Translate guest type to abstract type
28Network::Type Translate(Type type);
29
30/// Translate guest protocol to abstract protocol
31Network::Protocol Translate(Type type, Protocol protocol);
32
33/// Translate abstract poll event flags to guest poll event flags
34u16 TranslatePollEventsToHost(u16 flags);
35
36/// Translate guest poll event flags to abstract poll event flags
37u16 TranslatePollEventsToGuest(u16 flags);
38
39/// Translate guest socket address structure to abstract socket address structure
40Network::SockAddrIn Translate(SockAddrIn value);
41
42/// Translate abstract socket address structure to guest socket address structure
43SockAddrIn Translate(Network::SockAddrIn value);
44
45/// Translate guest shutdown mode to abstract shutdown mode
46Network::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
286bool Adapter::DeviceConnected(std::size_t port) { 286bool 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
16class GCButton final : public Input::ButtonDevice { 16class GCButton final : public Input::ButtonDevice {
17public: 17public:
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:
30private: 30private:
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
36class GCAxisButton final : public Input::ButtonDevice { 36class GCAxisButton final : public Input::ButtonDevice {
37public: 37public:
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
150class GCAnalog final : public Input::AnalogDevice { 150class GCAnalog final : public Input::AnalogDevice {
151public: 151public:
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
50public: 50public:
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 */
66class GameListItemPath : public GameListItem { 66class GameListItemPath : public GameListItem {
67public: 67public:
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:
131class GameListItemCompat : public GameListItem { 135class GameListItemCompat : public GameListItem {
132 Q_DECLARE_TR_FUNCTIONS(GameListItemCompat) 136 Q_DECLARE_TR_FUNCTIONS(GameListItemCompat)
133public: 137public:
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 */
182class GameListItemSize : public GameListItem { 186class GameListItemSize : public GameListItem {
183public: 187public:
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
218class GameListDir : public GameListItem { 222class GameListDir : public GameListItem {
219public: 223public:
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)