summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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