summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-07-11 21:42:56 -0300
committerGravatar ReinUsesLisp2020-07-19 04:12:40 -0300
commit51817f6e59e420536901e3225091894ea6ad1b25 (patch)
treefba868b13fcc9957cec4ffefcc8f03ad3be3d56a /src
parentMerge pull request #4322 from ReinUsesLisp/fix-dynstate (diff)
downloadyuzu-51817f6e59e420536901e3225091894ea6ad1b25.tar.gz
yuzu-51817f6e59e420536901e3225091894ea6ad1b25.tar.xz
yuzu-51817f6e59e420536901e3225091894ea6ad1b25.zip
core/network: Add network abstraction
This commit adds a network abstraction designed to implement bsd:s but at the same time work as a generic abstraction to implement any networking code we have to use from core. This is implemented on top of BSD sockets on Unix systems and winsock on Windows. The code is designed around winsocks having compatibility definitions to support both BSD and Windows sockets.
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt3
-rw-r--r--src/core/core.cpp4
-rw-r--r--src/core/network/network.cpp652
-rw-r--r--src/core/network/network.h87
-rw-r--r--src/core/network/sockets.h94
5 files changed, 840 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c42f95705..c85c9485f 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -586,6 +586,9 @@ add_library(core STATIC
586 memory/dmnt_cheat_vm.h 586 memory/dmnt_cheat_vm.h
587 memory.cpp 587 memory.cpp
588 memory.h 588 memory.h
589 network/network.cpp
590 network/network.h
591 network/sockets.h
589 perf_stats.cpp 592 perf_stats.cpp
590 perf_stats.h 593 perf_stats.h
591 reporter.cpp 594 reporter.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 69a1aa0a5..e598c0e2b 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -43,6 +43,7 @@
43#include "core/loader/loader.h" 43#include "core/loader/loader.h"
44#include "core/memory.h" 44#include "core/memory.h"
45#include "core/memory/cheat_engine.h" 45#include "core/memory/cheat_engine.h"
46#include "core/network/network.h"
46#include "core/perf_stats.h" 47#include "core/perf_stats.h"
47#include "core/reporter.h" 48#include "core/reporter.h"
48#include "core/settings.h" 49#include "core/settings.h"
@@ -394,6 +395,9 @@ struct System::Impl {
394 /// Telemetry session for this emulation session 395 /// Telemetry session for this emulation session
395 std::unique_ptr<Core::TelemetrySession> telemetry_session; 396 std::unique_ptr<Core::TelemetrySession> telemetry_session;
396 397
398 /// Network instance
399 Network::NetworkInstance network_instance;
400
397 ResultStatus status = ResultStatus::Success; 401 ResultStatus status = ResultStatus::Success;
398 std::string status_details = ""; 402 std::string status_details = "";
399 403
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
new file mode 100644
index 000000000..fb21b0a47
--- /dev/null
+++ b/src/core/network/network.cpp
@@ -0,0 +1,652 @@
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 <algorithm>
6#include <cstring>
7#include <limits>
8#include <utility>
9#include <vector>
10
11#ifdef _WIN32
12#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
13#include <winsock2.h>
14#elif __unix__
15#include <errno.h>
16#include <fcntl.h>
17#include <netdb.h>
18#include <poll.h>
19#include <unistd.h>
20#else
21#error "Unimplemented platform"
22#endif
23
24#include "common/assert.h"
25#include "common/common_types.h"
26#include "common/logging/log.h"
27#include "core/network/network.h"
28#include "core/network/sockets.h"
29
30namespace Network {
31
32namespace {
33
34#ifdef _WIN32
35
36using socklen_t = int;
37
38void Initialize() {
39 WSADATA wsa_data;
40 (void)WSAStartup(MAKEWORD(2, 2), &wsa_data);
41}
42
43void Finalize() {
44 WSACleanup();
45}
46
47constexpr IPv4Address TranslateIPv4(in_addr addr) {
48 auto& bytes = addr.S_un.S_un_b;
49 return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
50}
51
52sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
53 sockaddr_in result;
54
55#ifdef __unix__
56 result.sin_len = sizeof(result);
57#endif
58
59 switch (static_cast<Domain>(input.family)) {
60 case Domain::INET:
61 result.sin_family = AF_INET;
62 break;
63 default:
64 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family));
65 result.sin_family = AF_INET;
66 break;
67 }
68
69 result.sin_port = htons(input.portno);
70
71 auto& ip = result.sin_addr.S_un.S_un_b;
72 ip.s_b1 = input.ip[0];
73 ip.s_b2 = input.ip[1];
74 ip.s_b3 = input.ip[2];
75 ip.s_b4 = input.ip[3];
76
77 sockaddr addr;
78 std::memcpy(&addr, &result, sizeof(addr));
79 return addr;
80}
81
82LINGER MakeLinger(bool enable, u32 linger_value) {
83 ASSERT(linger_value <= std::numeric_limits<u_short>::max());
84
85 LINGER value;
86 value.l_onoff = enable ? 1 : 0;
87 value.l_linger = static_cast<u_short>(linger_value);
88 return value;
89}
90
91int LastError() {
92 return WSAGetLastError();
93}
94
95bool EnableNonBlock(SOCKET fd, bool enable) {
96 u_long value = enable ? 1 : 0;
97 return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR;
98}
99
100#elif __unix__ // ^ _WIN32 v __unix__
101
102using SOCKET = int;
103using WSAPOLLFD = pollfd;
104using ULONG = u64;
105
106constexpr SOCKET INVALID_SOCKET = -1;
107constexpr SOCKET SOCKET_ERROR = -1;
108
109constexpr int WSAEWOULDBLOCK = EAGAIN;
110constexpr int WSAENOTCONN = ENOTCONN;
111
112constexpr int SD_RECEIVE = SHUT_RD;
113constexpr int SD_SEND = SHUT_WR;
114constexpr int SD_BOTH = SHUT_RDWR;
115
116void Initialize() {}
117
118void Finalize() {}
119
120constexpr IPv4Address TranslateIPv4(in_addr addr) {
121 const u32 bytes = addr.s_addr;
122 return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),
123 static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)};
124}
125
126sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
127 sockaddr_in result;
128
129 switch (static_cast<Domain>(input.family)) {
130 case Domain::INET:
131 result.sin_family = AF_INET;
132 break;
133 default:
134 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family));
135 result.sin_family = AF_INET;
136 break;
137 }
138
139 result.sin_port = htons(input.portno);
140
141 result.sin_addr.s_addr = input.ip[0] | input.ip[1] << 8 | input.ip[2] << 16 | input.ip[3] << 24;
142
143 sockaddr addr;
144 std::memcpy(&addr, &result, sizeof(addr));
145 return addr;
146}
147
148int WSAPoll(WSAPOLLFD* fds, ULONG nfds, int timeout) {
149 return poll(fds, nfds, timeout);
150}
151
152int closesocket(SOCKET fd) {
153 return close(fd);
154}
155
156linger MakeLinger(bool enable, u32 linger_value) {
157 linger value;
158 value.l_onoff = enable ? 1 : 0;
159 value.l_linger = linger_value;
160 return value;
161}
162
163int LastError() {
164 return errno;
165}
166
167bool EnableNonBlock(int fd, bool enable) {
168 int flags = fcntl(fd, F_GETFD);
169 if (flags == -1) {
170 return false;
171 }
172 if (enable) {
173 flags |= O_NONBLOCK;
174 } else {
175 flags &= ~O_NONBLOCK;
176 }
177 return fcntl(fd, F_SETFD, flags) == 0;
178}
179
180#endif
181
182int TranslateDomain(Domain domain) {
183 switch (domain) {
184 case Domain::INET:
185 return AF_INET;
186 default:
187 UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain));
188 return 0;
189 }
190}
191
192int TranslateType(Type type) {
193 switch (type) {
194 case Type::STREAM:
195 return SOCK_STREAM;
196 case Type::DGRAM:
197 return SOCK_DGRAM;
198 default:
199 UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type));
200 return 0;
201 }
202}
203
204int TranslateProtocol(Protocol protocol) {
205 switch (protocol) {
206 case Protocol::TCP:
207 return IPPROTO_TCP;
208 case Protocol::UDP:
209 return IPPROTO_UDP;
210 default:
211 UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol));
212 return 0;
213 }
214}
215
216SockAddrIn TranslateToSockAddrIn(sockaddr input_) {
217 sockaddr_in input;
218 std::memcpy(&input, &input_, sizeof(input));
219
220 SockAddrIn result;
221
222 switch (input.sin_family) {
223 case AF_INET:
224 result.family = Domain::INET;
225 break;
226 default:
227 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.sin_family);
228 result.family = Domain::INET;
229 break;
230 }
231
232 result.portno = ntohs(input.sin_port);
233
234 result.ip = TranslateIPv4(input.sin_addr);
235
236 return result;
237}
238
239u16 TranslatePollEvents(u16 events) {
240 u16 result = 0;
241
242 if (events & POLL_IN) {
243 events &= ~POLL_IN;
244 result |= POLLIN;
245 }
246 if (events & POLL_PRI) {
247 events &= ~POLL_PRI;
248#ifdef _WIN32
249 LOG_WARNING(Service, "Winsock doesn't support POLLPRI");
250#else
251 result |= POLL_PRI;
252#endif
253 }
254 if (events & POLL_OUT) {
255 events &= ~POLL_OUT;
256 result |= POLLOUT;
257 }
258
259 UNIMPLEMENTED_IF_MSG(events != 0, "Unhandled guest events=0x{:x}", events);
260
261 return result;
262}
263
264u16 TranslatePollRevents(u16 revents) {
265 u16 result = 0;
266 const auto translate = [&result, &revents](int host, unsigned guest) {
267 if (revents & host) {
268 revents &= ~host;
269 result |= guest;
270 }
271 };
272
273 translate(POLLIN, POLL_IN);
274 translate(POLLPRI, POLL_PRI);
275 translate(POLLOUT, POLL_OUT);
276 translate(POLLERR, POLL_ERR);
277 translate(POLLHUP, POLL_HUP);
278
279 UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents);
280
281 return result;
282}
283
284template <typename T>
285Errno SetSockOpt(SOCKET fd, int option, T value) {
286 const int result =
287 setsockopt(fd, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value));
288 if (result != SOCKET_ERROR) {
289 return Errno::SUCCESS;
290 }
291 const int ec = LastError();
292 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
293 return Errno::SUCCESS;
294}
295
296} // Anonymous namespace
297
298NetworkInstance::NetworkInstance() {
299 Initialize();
300}
301
302NetworkInstance::~NetworkInstance() {
303 Finalize();
304}
305
306std::pair<IPv4Address, Errno> GetHostIPv4Address() {
307 std::array<char, 256> name{};
308 if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) {
309 UNIMPLEMENTED_MSG("Unhandled gethostname error");
310 return {IPv4Address{}, Errno::SUCCESS};
311 }
312
313 hostent* const ent = gethostbyname(name.data());
314 if (!ent) {
315 UNIMPLEMENTED_MSG("Unhandled gethostbyname error");
316 return {IPv4Address{}, Errno::SUCCESS};
317 }
318 if (ent->h_addr_list == nullptr) {
319 UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list");
320 return {IPv4Address{}, Errno::SUCCESS};
321 }
322 if (ent->h_length != sizeof(in_addr)) {
323 UNIMPLEMENTED_MSG("Unexpected size={} in hostent->h_length", ent->h_length);
324 }
325
326 in_addr addr;
327 std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr));
328 return {TranslateIPv4(addr), Errno::SUCCESS};
329}
330
331std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
332 const size_t num = pollfds.size();
333
334 std::vector<WSAPOLLFD> host_pollfds(pollfds.size());
335 std::transform(pollfds.begin(), pollfds.end(), host_pollfds.begin(), [](PollFD fd) {
336 WSAPOLLFD result;
337 result.fd = fd.socket->fd;
338 result.events = TranslatePollEvents(fd.events);
339 result.revents = 0;
340 return result;
341 });
342
343 const int result = WSAPoll(host_pollfds.data(), static_cast<ULONG>(num), timeout);
344 if (result == 0) {
345 ASSERT(std::all_of(host_pollfds.begin(), host_pollfds.end(),
346 [](WSAPOLLFD fd) { return fd.revents == 0; }));
347 return {0, Errno::SUCCESS};
348 }
349
350 for (size_t i = 0; i < num; ++i) {
351 pollfds[i].revents = TranslatePollRevents(host_pollfds[i].revents);
352 }
353
354 if (result > 0) {
355 return {result, Errno::SUCCESS};
356 }
357
358 ASSERT(result == SOCKET_ERROR);
359
360 const int ec = LastError();
361 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
362 return {-1, Errno::SUCCESS};
363}
364
365Socket::~Socket() {
366 if (fd == INVALID_SOCKET) {
367 return;
368 }
369 (void)closesocket(fd);
370 fd = INVALID_SOCKET;
371}
372
373Socket::Socket(Socket&& rhs) noexcept : fd{std::exchange(rhs.fd, INVALID_SOCKET)} {}
374
375Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
376 fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol));
377 if (fd != INVALID_SOCKET) {
378 return Errno::SUCCESS;
379 }
380
381 const int ec = LastError();
382 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
383 return Errno::SUCCESS;
384}
385
386std::pair<Socket::AcceptResult, Errno> Socket::Accept() {
387 sockaddr addr;
388 socklen_t addrlen = sizeof(addr);
389 const SOCKET new_socket = accept(fd, &addr, &addrlen);
390
391 if (new_socket == INVALID_SOCKET) {
392 const int ec = LastError();
393 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
394 return {AcceptResult{}, Errno::SUCCESS};
395 }
396
397 AcceptResult result;
398 result.socket = std::make_unique<Socket>();
399 result.socket->fd = new_socket;
400
401 ASSERT(addrlen == sizeof(sockaddr_in));
402 result.sockaddr_in = TranslateToSockAddrIn(addr);
403
404 return {std::move(result), Errno::SUCCESS};
405}
406
407Errno Socket::Connect(SockAddrIn addr_in) {
408 const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in);
409 if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != INVALID_SOCKET) {
410 return Errno::SUCCESS;
411 }
412
413 switch (const int ec = LastError()) {
414 case WSAEWOULDBLOCK:
415 LOG_DEBUG(Service, "EAGAIN generated");
416 return Errno::AGAIN;
417 default:
418 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
419 return Errno::SUCCESS;
420 }
421}
422
423std::pair<SockAddrIn, Errno> Socket::GetPeerName() {
424 sockaddr addr;
425 socklen_t addrlen = sizeof(addr);
426 if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) {
427 const int ec = LastError();
428 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
429 return {SockAddrIn{}, Errno::SUCCESS};
430 }
431
432 ASSERT(addrlen == sizeof(sockaddr_in));
433 return {TranslateToSockAddrIn(addr), Errno::SUCCESS};
434}
435
436std::pair<SockAddrIn, Errno> Socket::GetSockName() {
437 sockaddr addr;
438 socklen_t addrlen = sizeof(addr);
439 if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) {
440 const int ec = LastError();
441 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
442 return {SockAddrIn{}, Errno::SUCCESS};
443 }
444
445 ASSERT(addrlen == sizeof(sockaddr_in));
446 return {TranslateToSockAddrIn(addr), Errno::SUCCESS};
447}
448
449Errno Socket::Bind(SockAddrIn addr) {
450 const sockaddr addr_in = TranslateFromSockAddrIn(addr);
451 if (bind(fd, &addr_in, sizeof(addr_in)) != SOCKET_ERROR) {
452 return Errno::SUCCESS;
453 }
454
455 const int ec = LastError();
456 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
457 return Errno::SUCCESS;
458}
459
460Errno Socket::Listen(s32 backlog) {
461 if (listen(fd, backlog) != SOCKET_ERROR) {
462 return Errno::SUCCESS;
463 }
464
465 const int ec = LastError();
466 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
467 return Errno::SUCCESS;
468}
469
470Errno Socket::Shutdown(ShutdownHow how) {
471 int host_how = 0;
472 switch (how) {
473 case ShutdownHow::RD:
474 host_how = SD_RECEIVE;
475 break;
476 case ShutdownHow::WR:
477 host_how = SD_SEND;
478 break;
479 case ShutdownHow::RDWR:
480 host_how = SD_BOTH;
481 break;
482 default:
483 UNIMPLEMENTED_MSG("Unimplemented flag how={}", static_cast<int>(how));
484 return Errno::SUCCESS;
485 }
486 if (shutdown(fd, host_how) != SOCKET_ERROR) {
487 return Errno::SUCCESS;
488 }
489
490 switch (const int ec = LastError()) {
491 case WSAENOTCONN:
492 LOG_ERROR(Service, "ENOTCONN generated");
493 return Errno::NOTCONN;
494 default:
495 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
496 return Errno::SUCCESS;
497 }
498}
499
500std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
501 ASSERT(flags == 0);
502 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
503
504 const int result =
505 recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0);
506 if (result != SOCKET_ERROR) {
507 return {result, Errno::SUCCESS};
508 }
509
510 switch (const int ec = LastError()) {
511 case WSAEWOULDBLOCK:
512 LOG_DEBUG(Service, "EAGAIN generated");
513 return {-1, Errno::AGAIN};
514 case WSAENOTCONN:
515 LOG_ERROR(Service, "ENOTCONN generated");
516 return {-1, Errno::NOTCONN};
517 default:
518 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
519 return {0, Errno::SUCCESS};
520 }
521}
522
523std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) {
524 ASSERT(flags == 0);
525 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
526
527 sockaddr addr_in{};
528 socklen_t addrlen = sizeof(addr_in);
529 socklen_t* const p_addrlen = addr ? &addrlen : nullptr;
530 sockaddr* const p_addr_in = addr ? &addr_in : nullptr;
531
532 const int result = recvfrom(fd, reinterpret_cast<char*>(message.data()),
533 static_cast<int>(message.size()), 0, p_addr_in, p_addrlen);
534 if (result != SOCKET_ERROR) {
535 if (addr) {
536 ASSERT(addrlen == sizeof(addr_in));
537 *addr = TranslateToSockAddrIn(addr_in);
538 }
539 return {result, Errno::SUCCESS};
540 }
541
542 switch (const int ec = LastError()) {
543 case WSAEWOULDBLOCK:
544 LOG_DEBUG(Service, "EAGAIN generated");
545 return {-1, Errno::AGAIN};
546 case WSAENOTCONN:
547 LOG_ERROR(Service, "ENOTCONN generated");
548 return {-1, Errno::NOTCONN};
549 default:
550 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
551 return {-1, Errno::SUCCESS};
552 }
553}
554
555std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
556 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
557 ASSERT(flags == 0);
558
559 const int result = send(fd, reinterpret_cast<const char*>(message.data()),
560 static_cast<int>(message.size()), 0);
561 if (result != SOCKET_ERROR) {
562 return {result, Errno::SUCCESS};
563 }
564
565 const int ec = LastError();
566 switch (ec) {
567 case WSAEWOULDBLOCK:
568 LOG_DEBUG(Service, "EAGAIN generated");
569 return {-1, Errno::AGAIN};
570 case WSAENOTCONN:
571 LOG_ERROR(Service, "ENOTCONN generated");
572 return {-1, Errno::NOTCONN};
573 default:
574 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
575 return {-1, Errno::SUCCESS};
576 }
577}
578
579std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
580 const SockAddrIn* addr) {
581 ASSERT(flags == 0);
582
583 const sockaddr* to = nullptr;
584 const int tolen = addr ? 0 : sizeof(sockaddr);
585 sockaddr host_addr_in;
586
587 if (addr) {
588 host_addr_in = TranslateFromSockAddrIn(*addr);
589 to = &host_addr_in;
590 }
591
592 const int result = sendto(fd, reinterpret_cast<const char*>(message.data()),
593 static_cast<int>(message.size()), 0, to, tolen);
594 if (result != SOCKET_ERROR) {
595 return {result, Errno::SUCCESS};
596 }
597
598 const int ec = LastError();
599 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
600 return {-1, Errno::SUCCESS};
601}
602
603Errno Socket::Close() {
604 [[maybe_unused]] const int result = closesocket(fd);
605 ASSERT(result == 0);
606 fd = INVALID_SOCKET;
607
608 return Errno::SUCCESS;
609}
610
611Errno Socket::SetLinger(bool enable, u32 linger) {
612 return SetSockOpt(fd, SO_LINGER, MakeLinger(enable, linger));
613}
614
615Errno Socket::SetReuseAddr(bool enable) {
616 return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0);
617}
618
619Errno Socket::SetBroadcast(bool enable) {
620 return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0);
621}
622
623Errno Socket::SetSndBuf(u32 value) {
624 return SetSockOpt(fd, SO_SNDBUF, value);
625}
626
627Errno Socket::SetRcvBuf(u32 value) {
628 return SetSockOpt(fd, SO_RCVBUF, value);
629}
630
631Errno Socket::SetSndTimeo(u32 value) {
632 return SetSockOpt(fd, SO_SNDTIMEO, value);
633}
634
635Errno Socket::SetRcvTimeo(u32 value) {
636 return SetSockOpt(fd, SO_RCVTIMEO, value);
637}
638
639Errno Socket::SetNonBlock(bool enable) {
640 if (EnableNonBlock(fd, enable)) {
641 return Errno::SUCCESS;
642 }
643 const int ec = LastError();
644 UNREACHABLE_MSG("Unhandled host socket error={}", ec);
645 return Errno::SUCCESS;
646}
647
648bool Socket::IsOpened() const {
649 return fd != INVALID_SOCKET;
650}
651
652} // namespace Network
diff --git a/src/core/network/network.h b/src/core/network/network.h
new file mode 100644
index 000000000..0622e4593
--- /dev/null
+++ b/src/core/network/network.h
@@ -0,0 +1,87 @@
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 <array>
8#include <utility>
9
10#include "common/common_types.h"
11
12namespace Network {
13
14class Socket;
15
16/// Error code for network functions
17enum class Errno {
18 SUCCESS,
19 BADF,
20 INVAL,
21 MFILE,
22 NOTCONN,
23 AGAIN,
24};
25
26/// Address families
27enum class Domain {
28 INET, ///< Address family for IPv4
29};
30
31/// Socket types
32enum class Type {
33 STREAM,
34 DGRAM,
35 RAW,
36 SEQPACKET,
37};
38
39/// Protocol values for sockets
40enum class Protocol {
41 ICMP,
42 TCP,
43 UDP,
44};
45
46/// Shutdown mode
47enum class ShutdownHow {
48 RD,
49 WR,
50 RDWR,
51};
52
53/// Array of IPv4 address
54using IPv4Address = std::array<u8, 4>;
55
56/// Cross-platform sockaddr structure
57struct SockAddrIn {
58 Domain family;
59 IPv4Address ip;
60 u16 portno;
61};
62
63/// Cross-platform poll fd structure
64struct PollFD {
65 Socket* socket;
66 u16 events;
67 u16 revents;
68};
69
70constexpr u16 POLL_IN = 1 << 0;
71constexpr u16 POLL_PRI = 1 << 1;
72constexpr u16 POLL_OUT = 1 << 2;
73constexpr u16 POLL_ERR = 1 << 3;
74constexpr u16 POLL_HUP = 1 << 4;
75constexpr u16 POLL_NVAL = 1 << 5;
76
77class NetworkInstance {
78public:
79 explicit NetworkInstance();
80 ~NetworkInstance();
81};
82
83/// @brief Returns host's IPv4 address
84/// @return Pair of an array of human ordered IPv4 address (e.g. 192.168.0.1) and an error code
85std::pair<IPv4Address, Errno> GetHostIPv4Address();
86
87} // namespace Network
diff --git a/src/core/network/sockets.h b/src/core/network/sockets.h
new file mode 100644
index 000000000..7bdff0fe4
--- /dev/null
+++ b/src/core/network/sockets.h
@@ -0,0 +1,94 @@
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 <memory>
8#include <utility>
9
10#if defined(_WIN32)
11#include <winsock.h>
12#elif !defined(__unix__)
13#error "Platform not implemented"
14#endif
15
16#include "common/common_types.h"
17#include "core/network/network.h"
18
19// TODO: C++20 Replace std::vector usages with std::span
20
21namespace Network {
22
23class Socket {
24public:
25 struct AcceptResult {
26 std::unique_ptr<Socket> socket;
27 SockAddrIn sockaddr_in;
28 };
29
30 explicit Socket() = default;
31 ~Socket();
32
33 Socket(const Socket&) = delete;
34 Socket& operator=(const Socket&) = delete;
35
36 Socket(Socket&& rhs) noexcept;
37
38 // Avoid closing sockets implicitly
39 Socket& operator=(Socket&&) noexcept = delete;
40
41 Errno Initialize(Domain domain, Type type, Protocol protocol);
42
43 Errno Close();
44
45 std::pair<AcceptResult, Errno> Accept();
46
47 Errno Connect(SockAddrIn addr_in);
48
49 std::pair<SockAddrIn, Errno> GetPeerName();
50
51 std::pair<SockAddrIn, Errno> GetSockName();
52
53 Errno Bind(SockAddrIn addr);
54
55 Errno Listen(s32 backlog);
56
57 Errno Shutdown(ShutdownHow how);
58
59 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message);
60
61 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr);
62
63 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags);
64
65 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, const SockAddrIn* addr);
66
67 Errno SetLinger(bool enable, u32 linger);
68
69 Errno SetReuseAddr(bool enable);
70
71 Errno SetBroadcast(bool enable);
72
73 Errno SetSndBuf(u32 value);
74
75 Errno SetRcvBuf(u32 value);
76
77 Errno SetSndTimeo(u32 value);
78
79 Errno SetRcvTimeo(u32 value);
80
81 Errno SetNonBlock(bool enable);
82
83 bool IsOpened() const;
84
85#if defined(_WIN32)
86 SOCKET fd = INVALID_SOCKET;
87#elif defined(__unix__)
88 int fd = -1;
89#endif
90};
91
92std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout);
93
94} // namespace Network