summaryrefslogtreecommitdiff
path: root/src/core/network
diff options
context:
space:
mode:
authorGravatar FearlessTobi2021-12-25 20:27:52 +0100
committerGravatar FearlessTobi2022-07-25 21:59:28 +0200
commit705f7db84dd85555a6aef1e136cf251725cef293 (patch)
treee110c6482a11d711d18515afce4fc50adcee76e7 /src/core/network
parentnetwork: Add initial files and enet dependency (diff)
downloadyuzu-705f7db84dd85555a6aef1e136cf251725cef293.tar.gz
yuzu-705f7db84dd85555a6aef1e136cf251725cef293.tar.xz
yuzu-705f7db84dd85555a6aef1e136cf251725cef293.zip
yuzu: Add ui files for multiplayer rooms
Diffstat (limited to 'src/core/network')
-rw-r--r--src/core/network/network.cpp637
-rw-r--r--src/core/network/network.h117
-rw-r--r--src/core/network/network_interface.cpp209
-rw-r--r--src/core/network/network_interface.h28
-rw-r--r--src/core/network/sockets.h94
5 files changed, 0 insertions, 1085 deletions
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
deleted file mode 100644
index fdafbea92..000000000
--- a/src/core/network/network.cpp
+++ /dev/null
@@ -1,637 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <cstring>
6#include <limits>
7#include <utility>
8#include <vector>
9
10#include "common/error.h"
11
12#ifdef _WIN32
13#include <winsock2.h>
14#include <ws2tcpip.h>
15#elif YUZU_UNIX
16#include <arpa/inet.h>
17#include <errno.h>
18#include <fcntl.h>
19#include <netdb.h>
20#include <netinet/in.h>
21#include <poll.h>
22#include <sys/socket.h>
23#include <unistd.h>
24#else
25#error "Unimplemented platform"
26#endif
27
28#include "common/assert.h"
29#include "common/common_types.h"
30#include "common/logging/log.h"
31#include "common/settings.h"
32#include "core/network/network.h"
33#include "core/network/network_interface.h"
34#include "core/network/sockets.h"
35
36namespace Network {
37
38namespace {
39
40#ifdef _WIN32
41
42using socklen_t = int;
43
44void Initialize() {
45 WSADATA wsa_data;
46 (void)WSAStartup(MAKEWORD(2, 2), &wsa_data);
47}
48
49void Finalize() {
50 WSACleanup();
51}
52
53sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
54 sockaddr_in result;
55
56#if YUZU_UNIX
57 result.sin_len = sizeof(result);
58#endif
59
60 switch (static_cast<Domain>(input.family)) {
61 case Domain::INET:
62 result.sin_family = AF_INET;
63 break;
64 default:
65 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.family);
66 result.sin_family = AF_INET;
67 break;
68 }
69
70 result.sin_port = htons(input.portno);
71
72 auto& ip = result.sin_addr.S_un.S_un_b;
73 ip.s_b1 = input.ip[0];
74 ip.s_b2 = input.ip[1];
75 ip.s_b3 = input.ip[2];
76 ip.s_b4 = input.ip[3];
77
78 sockaddr addr;
79 std::memcpy(&addr, &result, sizeof(addr));
80 return addr;
81}
82
83LINGER MakeLinger(bool enable, u32 linger_value) {
84 ASSERT(linger_value <= std::numeric_limits<u_short>::max());
85
86 LINGER value;
87 value.l_onoff = enable ? 1 : 0;
88 value.l_linger = static_cast<u_short>(linger_value);
89 return value;
90}
91
92bool EnableNonBlock(SOCKET fd, bool enable) {
93 u_long value = enable ? 1 : 0;
94 return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR;
95}
96
97Errno TranslateNativeError(int e) {
98 switch (e) {
99 case WSAEBADF:
100 return Errno::BADF;
101 case WSAEINVAL:
102 return Errno::INVAL;
103 case WSAEMFILE:
104 return Errno::MFILE;
105 case WSAENOTCONN:
106 return Errno::NOTCONN;
107 case WSAEWOULDBLOCK:
108 return Errno::AGAIN;
109 case WSAECONNREFUSED:
110 return Errno::CONNREFUSED;
111 case WSAEHOSTUNREACH:
112 return Errno::HOSTUNREACH;
113 case WSAENETDOWN:
114 return Errno::NETDOWN;
115 case WSAENETUNREACH:
116 return Errno::NETUNREACH;
117 default:
118 return Errno::OTHER;
119 }
120}
121
122#elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX
123
124using SOCKET = int;
125using WSAPOLLFD = pollfd;
126using ULONG = u64;
127
128constexpr SOCKET INVALID_SOCKET = -1;
129constexpr SOCKET SOCKET_ERROR = -1;
130
131constexpr int SD_RECEIVE = SHUT_RD;
132constexpr int SD_SEND = SHUT_WR;
133constexpr int SD_BOTH = SHUT_RDWR;
134
135void Initialize() {}
136
137void Finalize() {}
138
139sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
140 sockaddr_in result;
141
142 switch (static_cast<Domain>(input.family)) {
143 case Domain::INET:
144 result.sin_family = AF_INET;
145 break;
146 default:
147 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.family);
148 result.sin_family = AF_INET;
149 break;
150 }
151
152 result.sin_port = htons(input.portno);
153
154 result.sin_addr.s_addr = input.ip[0] | input.ip[1] << 8 | input.ip[2] << 16 | input.ip[3] << 24;
155
156 sockaddr addr;
157 std::memcpy(&addr, &result, sizeof(addr));
158 return addr;
159}
160
161int WSAPoll(WSAPOLLFD* fds, ULONG nfds, int timeout) {
162 return poll(fds, static_cast<nfds_t>(nfds), timeout);
163}
164
165int closesocket(SOCKET fd) {
166 return close(fd);
167}
168
169linger MakeLinger(bool enable, u32 linger_value) {
170 linger value;
171 value.l_onoff = enable ? 1 : 0;
172 value.l_linger = linger_value;
173 return value;
174}
175
176bool EnableNonBlock(int fd, bool enable) {
177 int flags = fcntl(fd, F_GETFL);
178 if (flags == -1) {
179 return false;
180 }
181 if (enable) {
182 flags |= O_NONBLOCK;
183 } else {
184 flags &= ~O_NONBLOCK;
185 }
186 return fcntl(fd, F_SETFL, flags) == 0;
187}
188
189Errno TranslateNativeError(int e) {
190 switch (e) {
191 case EBADF:
192 return Errno::BADF;
193 case EINVAL:
194 return Errno::INVAL;
195 case EMFILE:
196 return Errno::MFILE;
197 case ENOTCONN:
198 return Errno::NOTCONN;
199 case EAGAIN:
200 return Errno::AGAIN;
201 case ECONNREFUSED:
202 return Errno::CONNREFUSED;
203 case EHOSTUNREACH:
204 return Errno::HOSTUNREACH;
205 case ENETDOWN:
206 return Errno::NETDOWN;
207 case ENETUNREACH:
208 return Errno::NETUNREACH;
209 default:
210 return Errno::OTHER;
211 }
212}
213
214#endif
215
216Errno GetAndLogLastError() {
217#ifdef _WIN32
218 int e = WSAGetLastError();
219#else
220 int e = errno;
221#endif
222 const Errno err = TranslateNativeError(e);
223 if (err == Errno::AGAIN) {
224 return err;
225 }
226 LOG_ERROR(Network, "Socket operation error: {}", Common::NativeErrorToString(e));
227 return err;
228}
229
230int TranslateDomain(Domain domain) {
231 switch (domain) {
232 case Domain::INET:
233 return AF_INET;
234 default:
235 UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
236 return 0;
237 }
238}
239
240int TranslateType(Type type) {
241 switch (type) {
242 case Type::STREAM:
243 return SOCK_STREAM;
244 case Type::DGRAM:
245 return SOCK_DGRAM;
246 default:
247 UNIMPLEMENTED_MSG("Unimplemented type={}", type);
248 return 0;
249 }
250}
251
252int TranslateProtocol(Protocol protocol) {
253 switch (protocol) {
254 case Protocol::TCP:
255 return IPPROTO_TCP;
256 case Protocol::UDP:
257 return IPPROTO_UDP;
258 default:
259 UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
260 return 0;
261 }
262}
263
264SockAddrIn TranslateToSockAddrIn(sockaddr input_) {
265 sockaddr_in input;
266 std::memcpy(&input, &input_, sizeof(input));
267
268 SockAddrIn result;
269
270 switch (input.sin_family) {
271 case AF_INET:
272 result.family = Domain::INET;
273 break;
274 default:
275 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.sin_family);
276 result.family = Domain::INET;
277 break;
278 }
279
280 result.portno = ntohs(input.sin_port);
281
282 result.ip = TranslateIPv4(input.sin_addr);
283
284 return result;
285}
286
287short TranslatePollEvents(PollEvents events) {
288 short result = 0;
289
290 if (True(events & PollEvents::In)) {
291 events &= ~PollEvents::In;
292 result |= POLLIN;
293 }
294 if (True(events & PollEvents::Pri)) {
295 events &= ~PollEvents::Pri;
296#ifdef _WIN32
297 LOG_WARNING(Service, "Winsock doesn't support POLLPRI");
298#else
299 result |= POLLPRI;
300#endif
301 }
302 if (True(events & PollEvents::Out)) {
303 events &= ~PollEvents::Out;
304 result |= POLLOUT;
305 }
306
307 UNIMPLEMENTED_IF_MSG((u16)events != 0, "Unhandled guest events=0x{:x}", (u16)events);
308
309 return result;
310}
311
312PollEvents TranslatePollRevents(short revents) {
313 PollEvents result{};
314 const auto translate = [&result, &revents](short host, PollEvents guest) {
315 if ((revents & host) != 0) {
316 revents &= static_cast<short>(~host);
317 result |= guest;
318 }
319 };
320
321 translate(POLLIN, PollEvents::In);
322 translate(POLLPRI, PollEvents::Pri);
323 translate(POLLOUT, PollEvents::Out);
324 translate(POLLERR, PollEvents::Err);
325 translate(POLLHUP, PollEvents::Hup);
326
327 UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents);
328
329 return result;
330}
331
332template <typename T>
333Errno SetSockOpt(SOCKET fd, int option, T value) {
334 const int result =
335 setsockopt(fd, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value));
336 if (result != SOCKET_ERROR) {
337 return Errno::SUCCESS;
338 }
339 return GetAndLogLastError();
340}
341
342} // Anonymous namespace
343
344NetworkInstance::NetworkInstance() {
345 Initialize();
346}
347
348NetworkInstance::~NetworkInstance() {
349 Finalize();
350}
351
352std::optional<IPv4Address> GetHostIPv4Address() {
353 const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
354 const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
355 if (network_interfaces.size() == 0) {
356 LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
357 return {};
358 }
359
360 const auto res =
361 std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) {
362 return iface.name == selected_network_interface;
363 });
364
365 if (res != network_interfaces.end()) {
366 char ip_addr[16] = {};
367 ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr);
368 return TranslateIPv4(res->ip_address);
369 } else {
370 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
371 return {};
372 }
373}
374
375std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
376 const size_t num = pollfds.size();
377
378 std::vector<WSAPOLLFD> host_pollfds(pollfds.size());
379 std::transform(pollfds.begin(), pollfds.end(), host_pollfds.begin(), [](PollFD fd) {
380 WSAPOLLFD result;
381 result.fd = fd.socket->fd;
382 result.events = TranslatePollEvents(fd.events);
383 result.revents = 0;
384 return result;
385 });
386
387 const int result = WSAPoll(host_pollfds.data(), static_cast<ULONG>(num), timeout);
388 if (result == 0) {
389 ASSERT(std::all_of(host_pollfds.begin(), host_pollfds.end(),
390 [](WSAPOLLFD fd) { return fd.revents == 0; }));
391 return {0, Errno::SUCCESS};
392 }
393
394 for (size_t i = 0; i < num; ++i) {
395 pollfds[i].revents = TranslatePollRevents(host_pollfds[i].revents);
396 }
397
398 if (result > 0) {
399 return {result, Errno::SUCCESS};
400 }
401
402 ASSERT(result == SOCKET_ERROR);
403
404 return {-1, GetAndLogLastError()};
405}
406
407Socket::~Socket() {
408 if (fd == INVALID_SOCKET) {
409 return;
410 }
411 (void)closesocket(fd);
412 fd = INVALID_SOCKET;
413}
414
415Socket::Socket(Socket&& rhs) noexcept : fd{std::exchange(rhs.fd, INVALID_SOCKET)} {}
416
417Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
418 fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol));
419 if (fd != INVALID_SOCKET) {
420 return Errno::SUCCESS;
421 }
422
423 return GetAndLogLastError();
424}
425
426std::pair<Socket::AcceptResult, Errno> Socket::Accept() {
427 sockaddr addr;
428 socklen_t addrlen = sizeof(addr);
429 const SOCKET new_socket = accept(fd, &addr, &addrlen);
430
431 if (new_socket == INVALID_SOCKET) {
432 return {AcceptResult{}, GetAndLogLastError()};
433 }
434
435 AcceptResult result;
436 result.socket = std::make_unique<Socket>();
437 result.socket->fd = new_socket;
438
439 ASSERT(addrlen == sizeof(sockaddr_in));
440 result.sockaddr_in = TranslateToSockAddrIn(addr);
441
442 return {std::move(result), Errno::SUCCESS};
443}
444
445Errno Socket::Connect(SockAddrIn addr_in) {
446 const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in);
447 if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != SOCKET_ERROR) {
448 return Errno::SUCCESS;
449 }
450
451 return GetAndLogLastError();
452}
453
454std::pair<SockAddrIn, Errno> Socket::GetPeerName() {
455 sockaddr addr;
456 socklen_t addrlen = sizeof(addr);
457 if (getpeername(fd, &addr, &addrlen) == SOCKET_ERROR) {
458 return {SockAddrIn{}, GetAndLogLastError()};
459 }
460
461 ASSERT(addrlen == sizeof(sockaddr_in));
462 return {TranslateToSockAddrIn(addr), Errno::SUCCESS};
463}
464
465std::pair<SockAddrIn, Errno> Socket::GetSockName() {
466 sockaddr addr;
467 socklen_t addrlen = sizeof(addr);
468 if (getsockname(fd, &addr, &addrlen) == SOCKET_ERROR) {
469 return {SockAddrIn{}, GetAndLogLastError()};
470 }
471
472 ASSERT(addrlen == sizeof(sockaddr_in));
473 return {TranslateToSockAddrIn(addr), Errno::SUCCESS};
474}
475
476Errno Socket::Bind(SockAddrIn addr) {
477 const sockaddr addr_in = TranslateFromSockAddrIn(addr);
478 if (bind(fd, &addr_in, sizeof(addr_in)) != SOCKET_ERROR) {
479 return Errno::SUCCESS;
480 }
481
482 return GetAndLogLastError();
483}
484
485Errno Socket::Listen(s32 backlog) {
486 if (listen(fd, backlog) != SOCKET_ERROR) {
487 return Errno::SUCCESS;
488 }
489
490 return GetAndLogLastError();
491}
492
493Errno Socket::Shutdown(ShutdownHow how) {
494 int host_how = 0;
495 switch (how) {
496 case ShutdownHow::RD:
497 host_how = SD_RECEIVE;
498 break;
499 case ShutdownHow::WR:
500 host_how = SD_SEND;
501 break;
502 case ShutdownHow::RDWR:
503 host_how = SD_BOTH;
504 break;
505 default:
506 UNIMPLEMENTED_MSG("Unimplemented flag how={}", how);
507 return Errno::SUCCESS;
508 }
509 if (shutdown(fd, host_how) != SOCKET_ERROR) {
510 return Errno::SUCCESS;
511 }
512
513 return GetAndLogLastError();
514}
515
516std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
517 ASSERT(flags == 0);
518 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
519
520 const auto result =
521 recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0);
522 if (result != SOCKET_ERROR) {
523 return {static_cast<s32>(result), Errno::SUCCESS};
524 }
525
526 return {-1, GetAndLogLastError()};
527}
528
529std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) {
530 ASSERT(flags == 0);
531 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
532
533 sockaddr addr_in{};
534 socklen_t addrlen = sizeof(addr_in);
535 socklen_t* const p_addrlen = addr ? &addrlen : nullptr;
536 sockaddr* const p_addr_in = addr ? &addr_in : nullptr;
537
538 const auto result = recvfrom(fd, reinterpret_cast<char*>(message.data()),
539 static_cast<int>(message.size()), 0, p_addr_in, p_addrlen);
540 if (result != SOCKET_ERROR) {
541 if (addr) {
542 ASSERT(addrlen == sizeof(addr_in));
543 *addr = TranslateToSockAddrIn(addr_in);
544 }
545 return {static_cast<s32>(result), Errno::SUCCESS};
546 }
547
548 return {-1, GetAndLogLastError()};
549}
550
551std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
552 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
553 ASSERT(flags == 0);
554
555 const auto result = send(fd, reinterpret_cast<const char*>(message.data()),
556 static_cast<int>(message.size()), 0);
557 if (result != SOCKET_ERROR) {
558 return {static_cast<s32>(result), Errno::SUCCESS};
559 }
560
561 return {-1, GetAndLogLastError()};
562}
563
564std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
565 const SockAddrIn* addr) {
566 ASSERT(flags == 0);
567
568 const sockaddr* to = nullptr;
569 const int tolen = addr ? sizeof(sockaddr) : 0;
570 sockaddr host_addr_in;
571
572 if (addr) {
573 host_addr_in = TranslateFromSockAddrIn(*addr);
574 to = &host_addr_in;
575 }
576
577 const auto result = sendto(fd, reinterpret_cast<const char*>(message.data()),
578 static_cast<int>(message.size()), 0, to, tolen);
579 if (result != SOCKET_ERROR) {
580 return {static_cast<s32>(result), Errno::SUCCESS};
581 }
582
583 return {-1, GetAndLogLastError()};
584}
585
586Errno Socket::Close() {
587 [[maybe_unused]] const int result = closesocket(fd);
588 ASSERT(result == 0);
589 fd = INVALID_SOCKET;
590
591 return Errno::SUCCESS;
592}
593
594Errno Socket::SetLinger(bool enable, u32 linger) {
595 return SetSockOpt(fd, SO_LINGER, MakeLinger(enable, linger));
596}
597
598Errno Socket::SetReuseAddr(bool enable) {
599 return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0);
600}
601
602Errno Socket::SetKeepAlive(bool enable) {
603 return SetSockOpt<u32>(fd, SO_KEEPALIVE, enable ? 1 : 0);
604}
605
606Errno Socket::SetBroadcast(bool enable) {
607 return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0);
608}
609
610Errno Socket::SetSndBuf(u32 value) {
611 return SetSockOpt(fd, SO_SNDBUF, value);
612}
613
614Errno Socket::SetRcvBuf(u32 value) {
615 return SetSockOpt(fd, SO_RCVBUF, value);
616}
617
618Errno Socket::SetSndTimeo(u32 value) {
619 return SetSockOpt(fd, SO_SNDTIMEO, value);
620}
621
622Errno Socket::SetRcvTimeo(u32 value) {
623 return SetSockOpt(fd, SO_RCVTIMEO, value);
624}
625
626Errno Socket::SetNonBlock(bool enable) {
627 if (EnableNonBlock(fd, enable)) {
628 return Errno::SUCCESS;
629 }
630 return GetAndLogLastError();
631}
632
633bool Socket::IsOpened() const {
634 return fd != INVALID_SOCKET;
635}
636
637} // namespace Network
diff --git a/src/core/network/network.h b/src/core/network/network.h
deleted file mode 100644
index 10e5ef10d..000000000
--- a/src/core/network/network.h
+++ /dev/null
@@ -1,117 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <optional>
8
9#include "common/common_funcs.h"
10#include "common/common_types.h"
11
12#ifdef _WIN32
13#include <winsock2.h>
14#elif YUZU_UNIX
15#include <netinet/in.h>
16#endif
17
18namespace Network {
19
20class Socket;
21
22/// Error code for network functions
23enum class Errno {
24 SUCCESS,
25 BADF,
26 INVAL,
27 MFILE,
28 NOTCONN,
29 AGAIN,
30 CONNREFUSED,
31 HOSTUNREACH,
32 NETDOWN,
33 NETUNREACH,
34 OTHER,
35};
36
37/// Address families
38enum class Domain {
39 INET, ///< Address family for IPv4
40};
41
42/// Socket types
43enum class Type {
44 STREAM,
45 DGRAM,
46 RAW,
47 SEQPACKET,
48};
49
50/// Protocol values for sockets
51enum class Protocol {
52 ICMP,
53 TCP,
54 UDP,
55};
56
57/// Shutdown mode
58enum class ShutdownHow {
59 RD,
60 WR,
61 RDWR,
62};
63
64/// Array of IPv4 address
65using IPv4Address = std::array<u8, 4>;
66
67/// Cross-platform sockaddr structure
68struct SockAddrIn {
69 Domain family;
70 IPv4Address ip;
71 u16 portno;
72};
73
74/// Cross-platform poll fd structure
75
76enum class PollEvents : u16 {
77 // Using Pascal case because IN is a macro on Windows.
78 In = 1 << 0,
79 Pri = 1 << 1,
80 Out = 1 << 2,
81 Err = 1 << 3,
82 Hup = 1 << 4,
83 Nval = 1 << 5,
84};
85
86DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
87
88struct PollFD {
89 Socket* socket;
90 PollEvents events;
91 PollEvents revents;
92};
93
94class NetworkInstance {
95public:
96 explicit NetworkInstance();
97 ~NetworkInstance();
98};
99
100#ifdef _WIN32
101constexpr IPv4Address TranslateIPv4(in_addr addr) {
102 auto& bytes = addr.S_un.S_un_b;
103 return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
104}
105#elif YUZU_UNIX
106constexpr IPv4Address TranslateIPv4(in_addr addr) {
107 const u32 bytes = addr.s_addr;
108 return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),
109 static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)};
110}
111#endif
112
113/// @brief Returns host's IPv4 address
114/// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array
115std::optional<IPv4Address> GetHostIPv4Address();
116
117} // namespace Network
diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp
deleted file mode 100644
index 15ecc6abf..000000000
--- a/src/core/network/network_interface.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <fstream>
6#include <sstream>
7#include <vector>
8
9#include "common/bit_cast.h"
10#include "common/common_types.h"
11#include "common/logging/log.h"
12#include "common/settings.h"
13#include "common/string_util.h"
14#include "core/network/network_interface.h"
15
16#ifdef _WIN32
17#include <iphlpapi.h>
18#else
19#include <cerrno>
20#include <ifaddrs.h>
21#include <net/if.h>
22#endif
23
24namespace Network {
25
26#ifdef _WIN32
27
28std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
29 std::vector<IP_ADAPTER_ADDRESSES> adapter_addresses;
30 DWORD ret = ERROR_BUFFER_OVERFLOW;
31 DWORD buf_size = 0;
32
33 // retry up to 5 times
34 for (int i = 0; i < 5 && ret == ERROR_BUFFER_OVERFLOW; i++) {
35 ret = GetAdaptersAddresses(
36 AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS,
37 nullptr, adapter_addresses.data(), &buf_size);
38
39 if (ret != ERROR_BUFFER_OVERFLOW) {
40 break;
41 }
42
43 adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1);
44 }
45
46 if (ret != NO_ERROR) {
47 LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
48 return {};
49 }
50
51 std::vector<NetworkInterface> result;
52
53 for (auto current_address = adapter_addresses.data(); current_address != nullptr;
54 current_address = current_address->Next) {
55 if (current_address->FirstUnicastAddress == nullptr ||
56 current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) {
57 continue;
58 }
59
60 if (current_address->OperStatus != IfOperStatusUp) {
61 continue;
62 }
63
64 const auto ip_addr = Common::BitCast<struct sockaddr_in>(
65 *current_address->FirstUnicastAddress->Address.lpSockaddr)
66 .sin_addr;
67
68 ULONG mask = 0;
69 if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength,
70 &mask) != NO_ERROR) {
71 LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask");
72 continue;
73 }
74
75 struct in_addr gateway = {.S_un{.S_addr{0}}};
76 if (current_address->FirstGatewayAddress != nullptr &&
77 current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) {
78 gateway = Common::BitCast<struct sockaddr_in>(
79 *current_address->FirstGatewayAddress->Address.lpSockaddr)
80 .sin_addr;
81 }
82
83 result.emplace_back(NetworkInterface{
84 .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
85 .ip_address{ip_addr},
86 .subnet_mask = in_addr{.S_un{.S_addr{mask}}},
87 .gateway = gateway});
88 }
89
90 return result;
91}
92
93#else
94
95std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
96 struct ifaddrs* ifaddr = nullptr;
97
98 if (getifaddrs(&ifaddr) != 0) {
99 LOG_ERROR(Network, "Failed to get network interfaces with getifaddrs: {}",
100 std::strerror(errno));
101 return {};
102 }
103
104 std::vector<NetworkInterface> result;
105
106 for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
107 if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr) {
108 continue;
109 }
110
111 if (ifa->ifa_addr->sa_family != AF_INET) {
112 continue;
113 }
114
115 if ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) {
116 continue;
117 }
118
119 u32 gateway{};
120
121 std::ifstream file{"/proc/net/route"};
122 if (!file.is_open()) {
123 LOG_ERROR(Network, "Failed to open \"/proc/net/route\"");
124
125 result.emplace_back(NetworkInterface{
126 .name{ifa->ifa_name},
127 .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
128 .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
129 .gateway{in_addr{.s_addr = gateway}}});
130 continue;
131 }
132
133 // ignore header
134 file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
135
136 bool gateway_found = false;
137
138 for (std::string line; std::getline(file, line);) {
139 std::istringstream iss{line};
140
141 std::string iface_name;
142 iss >> iface_name;
143 if (iface_name != ifa->ifa_name) {
144 continue;
145 }
146
147 iss >> std::hex;
148
149 u32 dest{};
150 iss >> dest;
151 if (dest != 0) {
152 // not the default route
153 continue;
154 }
155
156 iss >> gateway;
157
158 u16 flags{};
159 iss >> flags;
160
161 // flag RTF_GATEWAY (defined in <linux/route.h>)
162 if ((flags & 0x2) == 0) {
163 continue;
164 }
165
166 gateway_found = true;
167 break;
168 }
169
170 if (!gateway_found) {
171 gateway = 0;
172 }
173
174 result.emplace_back(NetworkInterface{
175 .name{ifa->ifa_name},
176 .ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
177 .subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
178 .gateway{in_addr{.s_addr = gateway}}});
179 }
180
181 freeifaddrs(ifaddr);
182
183 return result;
184}
185
186#endif
187
188std::optional<NetworkInterface> GetSelectedNetworkInterface() {
189 const auto& selected_network_interface = Settings::values.network_interface.GetValue();
190 const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
191 if (network_interfaces.size() == 0) {
192 LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
193 return std::nullopt;
194 }
195
196 const auto res =
197 std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) {
198 return iface.name == selected_network_interface;
199 });
200
201 if (res == network_interfaces.end()) {
202 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
203 return std::nullopt;
204 }
205
206 return *res;
207}
208
209} // namespace Network
diff --git a/src/core/network/network_interface.h b/src/core/network/network_interface.h
deleted file mode 100644
index 9b98b6b42..000000000
--- a/src/core/network/network_interface.h
+++ /dev/null
@@ -1,28 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <optional>
7#include <string>
8#include <vector>
9
10#ifdef _WIN32
11#include <winsock2.h>
12#else
13#include <netinet/in.h>
14#endif
15
16namespace Network {
17
18struct NetworkInterface {
19 std::string name;
20 struct in_addr ip_address;
21 struct in_addr subnet_mask;
22 struct in_addr gateway;
23};
24
25std::vector<NetworkInterface> GetAvailableNetworkInterfaces();
26std::optional<NetworkInterface> GetSelectedNetworkInterface();
27
28} // namespace Network
diff --git a/src/core/network/sockets.h b/src/core/network/sockets.h
deleted file mode 100644
index f889159f5..000000000
--- a/src/core/network/sockets.h
+++ /dev/null
@@ -1,94 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <utility>
8
9#if defined(_WIN32)
10#elif !YUZU_UNIX
11#error "Platform not implemented"
12#endif
13
14#include "common/common_types.h"
15#include "core/network/network.h"
16
17// TODO: C++20 Replace std::vector usages with std::span
18
19namespace Network {
20
21class Socket {
22public:
23 struct AcceptResult {
24 std::unique_ptr<Socket> socket;
25 SockAddrIn sockaddr_in;
26 };
27
28 explicit Socket() = default;
29 ~Socket();
30
31 Socket(const Socket&) = delete;
32 Socket& operator=(const Socket&) = delete;
33
34 Socket(Socket&& rhs) noexcept;
35
36 // Avoid closing sockets implicitly
37 Socket& operator=(Socket&&) noexcept = delete;
38
39 Errno Initialize(Domain domain, Type type, Protocol protocol);
40
41 Errno Close();
42
43 std::pair<AcceptResult, Errno> Accept();
44
45 Errno Connect(SockAddrIn addr_in);
46
47 std::pair<SockAddrIn, Errno> GetPeerName();
48
49 std::pair<SockAddrIn, Errno> GetSockName();
50
51 Errno Bind(SockAddrIn addr);
52
53 Errno Listen(s32 backlog);
54
55 Errno Shutdown(ShutdownHow how);
56
57 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message);
58
59 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr);
60
61 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags);
62
63 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, const SockAddrIn* addr);
64
65 Errno SetLinger(bool enable, u32 linger);
66
67 Errno SetReuseAddr(bool enable);
68
69 Errno SetKeepAlive(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 YUZU_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