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