summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-07-11 22:37:47 -0300
committerGravatar ReinUsesLisp2020-07-28 01:48:42 -0300
commitf7d59f3e0e63a33e758b92a857ca4add0a8ee524 (patch)
tree4905a67f1571b61f949331a06a49dcbf356e7774 /src
parentservice/sockets: Add worker pool abstraction (diff)
downloadyuzu-f7d59f3e0e63a33e758b92a857ca4add0a8ee524.tar.gz
yuzu-f7d59f3e0e63a33e758b92a857ca4add0a8ee524.tar.xz
yuzu-f7d59f3e0e63a33e758b92a857ca4add0a8ee524.zip
services/bsd: Implement most of bsd:s
This implements: Socket, Poll, Accept, Bind, Connect, GetPeerName, GetSockName, Listen, Fcntl, SetSockOpt, Shutdown, Recv, RecvFrom, Send, SendTo, Write, and Close The implementation was done referencing: SwIPC, switchbrew, testing with libnx and inspecting its code, general information about bsd sockets online, and analysing official software. Not everything from these service calls is implemented, but everything that is not implemented will be logged in some way.
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/sockets/bsd.cpp804
-rw-r--r--src/core/hle/service/sockets/bsd.h148
-rw-r--r--src/core/hle/service/sockets/sockets.cpp6
-rw-r--r--src/core/hle/service/sockets/sockets.h6
5 files changed, 911 insertions, 55 deletions
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/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 8d4952c0e..1d20f33a4 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,658 @@ 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 const size_t length = std::min(read_buffer.size(), write_buffer.size());
469 std::vector<PollFD> fds(nfds);
470 std::memcpy(fds.data(), read_buffer.data(), length);
471
472 if (timeout >= 0) {
473 const s64 seconds = timeout / 1000;
474 const u64 nanoseconds = 1'000'000 * (static_cast<u64>(timeout) % 1000);
475
476 if (seconds < 0) {
477 return {-1, Errno::INVAL};
478 }
479 if (nanoseconds > 999'999'999) {
480 return {-1, Errno::INVAL};
481 }
482 } else if (timeout != -1) {
483 return {-1, Errno::INVAL};
484 }
485
486 for (PollFD& pollfd : fds) {
487 ASSERT(pollfd.revents == 0);
488
489 if (pollfd.fd > MAX_FD || pollfd.fd < 0) {
490 LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd);
491 pollfd.revents = 0;
492 return {0, Errno::SUCCESS};
493 }
494
495 std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
496 if (!descriptor) {
497 LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd);
498 pollfd.revents = POLL_NVAL;
499 return {0, Errno::SUCCESS};
500 }
501 }
502
503 std::vector<Network::PollFD> host_pollfds(fds.size());
504 std::transform(fds.begin(), fds.end(), host_pollfds.begin(), [this](PollFD pollfd) {
505 Network::PollFD result;
506 result.socket = file_descriptors[pollfd.fd]->socket.get();
507 result.events = TranslatePollEventsToHost(pollfd.events);
508 result.revents = 0;
509 return result;
510 });
511
512 const auto result = Network::Poll(host_pollfds, timeout);
513
514 const size_t num = host_pollfds.size();
515 for (size_t i = 0; i < num; ++i) {
516 fds[i].revents = TranslatePollEventsToGuest(host_pollfds[i].revents);
517 }
518 std::memcpy(write_buffer.data(), fds.data(), length);
519
520 return Translate(result);
521}
522
523std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
524 if (!IsFileDescriptorValid(fd)) {
525 return {-1, Errno::BADF};
526 }
527
528 const s32 new_fd = FindFreeFileDescriptorHandle();
529 if (new_fd < 0) {
530 LOG_ERROR(Service, "No more file descriptors available");
531 return {-1, Errno::MFILE};
532 }
533
534 FileDescriptor& descriptor = *file_descriptors[fd];
535 auto [result, bsd_errno] = descriptor.socket->Accept();
536 if (bsd_errno != Network::Errno::SUCCESS) {
537 return {-1, Translate(bsd_errno)};
538 }
539
540 FileDescriptor& new_descriptor = file_descriptors[new_fd].emplace();
541 new_descriptor.socket = std::move(result.socket);
542 new_descriptor.is_connection_based = descriptor.is_connection_based;
543
544 ASSERT(write_buffer.size() == sizeof(SockAddrIn));
545 const SockAddrIn guest_addr_in = Translate(result.sockaddr_in);
546 std::memcpy(write_buffer.data(), &guest_addr_in, sizeof(guest_addr_in));
547
548 return {new_fd, Errno::SUCCESS};
549}
550
551Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) {
552 if (!IsFileDescriptorValid(fd)) {
553 return Errno::BADF;
554 }
555 ASSERT(addr.size() == sizeof(SockAddrIn));
556 SockAddrIn addr_in;
557 std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
558
559 return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
560}
561
562Errno BSD::ConnectImpl(s32 fd, const std::vector<u8>& addr) {
563 if (!IsFileDescriptorValid(fd)) {
564 return Errno::BADF;
565 }
566
567 UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn));
568 SockAddrIn addr_in;
569 std::memcpy(&addr_in, addr.data(), sizeof(addr_in));
570
571 return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
572}
573
574Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
575 if (!IsFileDescriptorValid(fd)) {
576 return Errno::BADF;
577 }
578
579 const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetPeerName();
580 if (bsd_errno != Network::Errno::SUCCESS) {
581 return Translate(bsd_errno);
582 }
583 const SockAddrIn guest_addrin = Translate(addr_in);
584
585 ASSERT(write_buffer.size() == sizeof(guest_addrin));
586 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
587 return Translate(bsd_errno);
588}
589
590Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
591 if (!IsFileDescriptorValid(fd)) {
592 return Errno::BADF;
593 }
594
595 const auto [addr_in, bsd_errno] = file_descriptors[fd]->socket->GetSockName();
596 if (bsd_errno != Network::Errno::SUCCESS) {
597 return Translate(bsd_errno);
598 }
599 const SockAddrIn guest_addrin = Translate(addr_in);
600
601 ASSERT(write_buffer.size() == sizeof(guest_addrin));
602 std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin));
603 return Translate(bsd_errno);
604}
605
606Errno BSD::ListenImpl(s32 fd, s32 backlog) {
607 if (!IsFileDescriptorValid(fd)) {
608 return Errno::BADF;
609 }
610 return Translate(file_descriptors[fd]->socket->Listen(backlog));
611}
612
613std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
614 if (!IsFileDescriptorValid(fd)) {
615 return {-1, Errno::BADF};
616 }
617
618 FileDescriptor& descriptor = *file_descriptors[fd];
619
620 switch (cmd) {
621 case FcntlCmd::GETFL:
622 ASSERT(arg == 0);
623 return {descriptor.flags, Errno::SUCCESS};
624 case FcntlCmd::SETFL: {
625 const bool enable = (arg & FLAG_O_NONBLOCK) != 0;
626 const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
627 if (bsd_errno != Errno::SUCCESS) {
628 return {-1, bsd_errno};
629 }
630 descriptor.flags = arg;
631 return {0, Errno::SUCCESS};
632 }
633 default:
634 UNIMPLEMENTED_MSG("Unimplemented cmd={}", static_cast<int>(cmd));
635 return {-1, Errno::SUCCESS};
636 }
637}
638
639Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) {
640 UNIMPLEMENTED_IF(level != 0xffff); // SOL_SOCKET
641
642 if (!IsFileDescriptorValid(fd)) {
643 return Errno::BADF;
644 }
645
646 Network::Socket* const socket = file_descriptors[fd]->socket.get();
647
648 if (optname == OptName::LINGER) {
649 ASSERT(optlen == sizeof(Linger));
650 Linger linger;
651 std::memcpy(&linger, optval, sizeof(linger));
652 ASSERT(linger.onoff == 0 || linger.onoff == 1);
653
654 return Translate(socket->SetLinger(linger.onoff != 0, linger.linger));
655 }
656
657 ASSERT(optlen == sizeof(u32));
658 u32 value;
659 std::memcpy(&value, optval, sizeof(value));
660
661 switch (optname) {
662 case OptName::REUSEADDR:
663 ASSERT(value == 0 || value == 1);
664 return Translate(socket->SetReuseAddr(value != 0));
665 case OptName::BROADCAST:
666 ASSERT(value == 0 || value == 1);
667 return Translate(socket->SetBroadcast(value != 0));
668 case OptName::SNDBUF:
669 return Translate(socket->SetSndBuf(value));
670 case OptName::RCVBUF:
671 return Translate(socket->SetRcvBuf(value));
672 case OptName::SNDTIMEO:
673 return Translate(socket->SetSndTimeo(value));
674 case OptName::RCVTIMEO:
675 return Translate(socket->SetRcvTimeo(value));
676 default:
677 UNIMPLEMENTED_MSG("Unimplemented optname={}", static_cast<int>(optname));
678 return Errno::SUCCESS;
679 }
680}
681
682Errno BSD::ShutdownImpl(s32 fd, s32 how) {
683 if (!IsFileDescriptorValid(fd)) {
684 return Errno::BADF;
685 }
686 const Network::ShutdownHow host_how = Translate(static_cast<ShutdownHow>(how));
687 return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
688}
689
690std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
691 if (!IsFileDescriptorValid(fd)) {
692 return {-1, Errno::BADF};
693 }
694 return Translate(file_descriptors[fd]->socket->Recv(flags, message));
695}
696
697std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
698 std::vector<u8>& addr) {
699 if (!IsFileDescriptorValid(fd)) {
700 return {-1, Errno::BADF};
701 }
702
703 FileDescriptor& descriptor = *file_descriptors[fd];
704
705 Network::SockAddrIn addr_in{};
706 Network::SockAddrIn* p_addr_in = nullptr;
707 if (descriptor.is_connection_based) {
708 // Connection based file descriptors (e.g. TCP) zero addr
709 addr.clear();
710 } else {
711 p_addr_in = &addr_in;
712 }
713
714 // Apply flags
715 if ((flags & FLAG_MSG_DONTWAIT) != 0) {
716 flags &= ~FLAG_MSG_DONTWAIT;
717 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
718 descriptor.socket->SetNonBlock(true);
719 }
720 }
721
722 const auto [ret, bsd_errno] = Translate(descriptor.socket->RecvFrom(flags, message, p_addr_in));
723
724 // Restore original state
725 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
726 descriptor.socket->SetNonBlock(false);
727 }
728
729 if (p_addr_in) {
730 if (ret < 0) {
731 addr.clear();
732 } else {
733 ASSERT(addr.size() == sizeof(SockAddrIn));
734 const SockAddrIn result = Translate(addr_in);
735 std::memcpy(addr.data(), &result, sizeof(result));
736 }
737 }
738
739 return {ret, bsd_errno};
740}
741
742std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, const std::vector<u8>& message) {
743 if (!IsFileDescriptorValid(fd)) {
744 return {-1, Errno::BADF};
745 }
746 return Translate(file_descriptors[fd]->socket->Send(message, flags));
747}
748
749std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
750 const std::vector<u8>& addr) {
751 if (!IsFileDescriptorValid(fd)) {
752 return {-1, Errno::BADF};
753 }
754
755 Network::SockAddrIn addr_in;
756 Network::SockAddrIn* p_addr_in = nullptr;
757 if (!addr.empty()) {
758 ASSERT(addr.size() == sizeof(SockAddrIn));
759 SockAddrIn guest_addr_in;
760 std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in));
761 addr_in = Translate(guest_addr_in);
762 }
763
764 return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
765}
766
767Errno BSD::CloseImpl(s32 fd) {
768 if (!IsFileDescriptorValid(fd)) {
769 return Errno::BADF;
770 }
771
772 const Errno bsd_errno = Translate(file_descriptors[fd]->socket->Close());
773 if (bsd_errno != Errno::SUCCESS) {
774 return bsd_errno;
775 }
776
777 LOG_INFO(Service, "Close socket fd={}", fd);
778
779 file_descriptors[fd].reset();
780 return bsd_errno;
781}
782
783s32 BSD::FindFreeFileDescriptorHandle() noexcept {
784 for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
785 if (!file_descriptors[fd]) {
786 return fd;
787 }
788 }
789 return -1;
790}
791
792bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
793 if (fd > MAX_FD || fd < 0) {
794 LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
795 return false;
796 }
797 if (!file_descriptors[fd]) {
798 LOG_ERROR(Service, "File descriptor handle={} is not allocated", fd);
799 return false;
800 }
801 return true;
802}
803
804bool BSD::IsBlockingSocket(s32 fd) const noexcept {
805 // Inform invalid sockets as non-blocking
806 // This way we avoid using a worker thread as it will fail without blocking host
807 if (fd > MAX_FD || fd < 0) {
808 return false;
809 }
810 if (!file_descriptors[fd]) {
811 return false;
812 }
813 return (file_descriptors[fd]->flags & FLAG_O_NONBLOCK) != 0;
814}
815
816void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept {
108 IPC::ResponseBuilder rb{ctx, 4}; 817 IPC::ResponseBuilder rb{ctx, 4};
109 818
110 rb.Push(RESULT_SUCCESS); 819 rb.Push(RESULT_SUCCESS);
111 rb.Push<u32>(0); // ret 820 rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
112 rb.Push<u32>(0); // bsd errno 821 rb.PushEnum(bsd_errno);
113} 822}
114 823
115BSD::BSD(const char* name) : ServiceFramework(name) { 824BSD::BSD(Core::System& system, const char* name)
825 : ServiceFramework(name), worker_pool{system, this} {
116 // clang-format off 826 // clang-format off
117 static const FunctionInfo functions[] = { 827 static const FunctionInfo functions[] = {
118 {0, &BSD::RegisterClient, "RegisterClient"}, 828 {0, &BSD::RegisterClient, "RegisterClient"},
@@ -121,25 +831,25 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
121 {3, nullptr, "SocketExempt"}, 831 {3, nullptr, "SocketExempt"},
122 {4, nullptr, "Open"}, 832 {4, nullptr, "Open"},
123 {5, &BSD::Select, "Select"}, 833 {5, &BSD::Select, "Select"},
124 {6, nullptr, "Poll"}, 834 {6, &BSD::Poll, "Poll"},
125 {7, nullptr, "Sysctl"}, 835 {7, nullptr, "Sysctl"},
126 {8, nullptr, "Recv"}, 836 {8, &BSD::Recv, "Recv"},
127 {9, nullptr, "RecvFrom"}, 837 {9, &BSD::RecvFrom, "RecvFrom"},
128 {10, nullptr, "Send"}, 838 {10, &BSD::Send, "Send"},
129 {11, &BSD::SendTo, "SendTo"}, 839 {11, &BSD::SendTo, "SendTo"},
130 {12, nullptr, "Accept"}, 840 {12, &BSD::Accept, "Accept"},
131 {13, &BSD::Bind, "Bind"}, 841 {13, &BSD::Bind, "Bind"},
132 {14, &BSD::Connect, "Connect"}, 842 {14, &BSD::Connect, "Connect"},
133 {15, nullptr, "GetPeerName"}, 843 {15, &BSD::GetPeerName, "GetPeerName"},
134 {16, nullptr, "GetSockName"}, 844 {16, &BSD::GetSockName, "GetSockName"},
135 {17, nullptr, "GetSockOpt"}, 845 {17, nullptr, "GetSockOpt"},
136 {18, &BSD::Listen, "Listen"}, 846 {18, &BSD::Listen, "Listen"},
137 {19, nullptr, "Ioctl"}, 847 {19, nullptr, "Ioctl"},
138 {20, nullptr, "Fcntl"}, 848 {20, &BSD::Fcntl, "Fcntl"},
139 {21, &BSD::SetSockOpt, "SetSockOpt"}, 849 {21, &BSD::SetSockOpt, "SetSockOpt"},
140 {22, nullptr, "Shutdown"}, 850 {22, &BSD::Shutdown, "Shutdown"},
141 {23, nullptr, "ShutdownAllSockets"}, 851 {23, nullptr, "ShutdownAllSockets"},
142 {24, nullptr, "Write"}, 852 {24, &BSD::Write, "Write"},
143 {25, nullptr, "Read"}, 853 {25, nullptr, "Read"},
144 {26, &BSD::Close, "Close"}, 854 {26, &BSD::Close, "Close"},
145 {27, nullptr, "DuplicateSocket"}, 855 {27, nullptr, "DuplicateSocket"},
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 7e1a64015..357531951 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -4,32 +4,174 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string_view>
9#include <vector>
10
7#include "common/common_types.h" 11#include "common/common_types.h"
8#include "core/hle/kernel/hle_ipc.h" 12#include "core/hle/kernel/hle_ipc.h"
9#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
14#include "core/hle/service/sockets/blocking_worker.h"
10#include "core/hle/service/sockets/sockets.h" 15#include "core/hle/service/sockets/sockets.h"
11 16
17namespace Core {
18class System;
19}
20
21namespace Network {
22class Socket;
23}
24
12namespace Service::Sockets { 25namespace Service::Sockets {
13 26
14class BSD final : public ServiceFramework<BSD> { 27class BSD final : public ServiceFramework<BSD> {
15public: 28public:
16 explicit BSD(const char* name); 29 explicit BSD(Core::System& system, const char* name);
17 ~BSD() override; 30 ~BSD() override;
18 31
19private: 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
20 void RegisterClient(Kernel::HLERequestContext& ctx); 119 void RegisterClient(Kernel::HLERequestContext& ctx);
21 void StartMonitoring(Kernel::HLERequestContext& ctx); 120 void StartMonitoring(Kernel::HLERequestContext& ctx);
22 void Socket(Kernel::HLERequestContext& ctx); 121 void Socket(Kernel::HLERequestContext& ctx);
23 void Select(Kernel::HLERequestContext& ctx); 122 void Select(Kernel::HLERequestContext& ctx);
123 void Poll(Kernel::HLERequestContext& ctx);
124 void Accept(Kernel::HLERequestContext& ctx);
24 void Bind(Kernel::HLERequestContext& ctx); 125 void Bind(Kernel::HLERequestContext& ctx);
25 void Connect(Kernel::HLERequestContext& ctx); 126 void Connect(Kernel::HLERequestContext& ctx);
127 void GetPeerName(Kernel::HLERequestContext& ctx);
128 void GetSockName(Kernel::HLERequestContext& ctx);
26 void Listen(Kernel::HLERequestContext& ctx); 129 void Listen(Kernel::HLERequestContext& ctx);
130 void Fcntl(Kernel::HLERequestContext& ctx);
27 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);
28 void SendTo(Kernel::HLERequestContext& ctx); 136 void SendTo(Kernel::HLERequestContext& ctx);
137 void Write(Kernel::HLERequestContext& ctx);
29 void Close(Kernel::HLERequestContext& ctx); 138 void Close(Kernel::HLERequestContext& ctx);
30 139
31 /// Id to use for the next open file descriptor. 140 template <typename Work>
32 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;
33}; 175};
34 176
35class 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 55b110937..89a410076 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -7,6 +7,10 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Core {
11class System;
12}
13
10namespace Service::Sockets { 14namespace Service::Sockets {
11 15
12enum class Errno : u32 { 16enum class Errno : u32 {
@@ -88,6 +92,6 @@ constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
88constexpr u32 FLAG_O_NONBLOCK = 0x800; 92constexpr u32 FLAG_O_NONBLOCK = 0x800;
89 93
90/// Registers all Sockets services with the specified service manager. 94/// Registers all Sockets services with the specified service manager.
91void InstallInterfaces(SM::ServiceManager& service_manager); 95void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
92 96
93} // namespace Service::Sockets 97} // namespace Service::Sockets