summaryrefslogtreecommitdiff
path: root/src/core/network
diff options
context:
space:
mode:
authorGravatar spholz2021-08-12 21:32:53 +0200
committerGravatar spholz2021-08-12 21:32:53 +0200
commit1e98e738283ccb81303d29305188ac825ecfcba9 (patch)
tree3e82e0ce341efd5aad25584d381235365260dd1a /src/core/network
parentMerge branch 'yuzu-emu:master' into fix-lan-play (diff)
downloadyuzu-1e98e738283ccb81303d29305188ac825ecfcba9.tar.gz
yuzu-1e98e738283ccb81303d29305188ac825ecfcba9.tar.xz
yuzu-1e98e738283ccb81303d29305188ac825ecfcba9.zip
configuration: add option to select network interface
This commit renames the "Services" tab to "Network" and adds a combobox that allows the user to select the network interface that yuzu should use. This new setting is now used to get the local IP address in Network::GetHostIPv4Address. This prevents yuzu from selecting the wrong network interface and thus using the wrong IP address. The return type of Network::GetHostIPv4Adress has also been changed.
Diffstat (limited to 'src/core/network')
-rw-r--r--src/core/network/network.cpp43
-rw-r--r--src/core/network/network.h5
-rw-r--r--src/core/network/network_interface.cpp113
-rw-r--r--src/core/network/network_interface.h25
4 files changed, 164 insertions, 22 deletions
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index 7b038041e..67ecf57bd 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -10,8 +10,8 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11 11
12#ifdef _WIN32 12#ifdef _WIN32
13#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
14#include <winsock2.h> 13#include <winsock2.h>
14#include <ws2tcpip.h>
15#elif YUZU_UNIX 15#elif YUZU_UNIX
16#include <errno.h> 16#include <errno.h>
17#include <fcntl.h> 17#include <fcntl.h>
@@ -19,6 +19,7 @@
19#include <netinet/in.h> 19#include <netinet/in.h>
20#include <poll.h> 20#include <poll.h>
21#include <sys/socket.h> 21#include <sys/socket.h>
22#include <arpa/inet.h>
22#include <unistd.h> 23#include <unistd.h>
23#else 24#else
24#error "Unimplemented platform" 25#error "Unimplemented platform"
@@ -27,7 +28,9 @@
27#include "common/assert.h" 28#include "common/assert.h"
28#include "common/common_types.h" 29#include "common/common_types.h"
29#include "common/logging/log.h" 30#include "common/logging/log.h"
31#include "common/settings.h"
30#include "core/network/network.h" 32#include "core/network/network.h"
33#include "core/network/network_interface.h"
31#include "core/network/sockets.h" 34#include "core/network/sockets.h"
32 35
33namespace Network { 36namespace Network {
@@ -357,27 +360,27 @@ NetworkInstance::~NetworkInstance() {
357 Finalize(); 360 Finalize();
358} 361}
359 362
360std::pair<IPv4Address, Errno> GetHostIPv4Address() { 363std::optional<IPv4Address> GetHostIPv4Address() {
361 std::array<char, 256> name{}; 364 const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
362 if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) { 365 const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
363 return {IPv4Address{}, GetAndLogLastError()}; 366 ASSERT_MSG(network_interfaces.size() > 0, "GetAvailableNetworkInterfaces returned no interfaces");
364 }
365 367
366 hostent* const ent = gethostbyname(name.data());
367 if (!ent) {
368 return {IPv4Address{}, GetAndLogLastError()};
369 }
370 if (ent->h_addr_list == nullptr) {
371 UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list");
372 return {IPv4Address{}, Errno::SUCCESS};
373 }
374 if (ent->h_length != sizeof(in_addr)) {
375 UNIMPLEMENTED_MSG("Unexpected size={} in hostent->h_length", ent->h_length);
376 }
377 368
378 in_addr addr; 369 const auto res = std::ranges::find_if(network_interfaces,
379 std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr)); 370 [&selected_network_interface](const auto& interface) {
380 return {TranslateIPv4(addr), Errno::SUCCESS}; 371 return interface.name == selected_network_interface;
372 });
373
374 if (res != network_interfaces.end()) {
375 char ip_addr[16];
376 ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr);
377 LOG_INFO(Network, "IP address: {}", ip_addr);
378
379 return TranslateIPv4(res->ip_address);
380 } else {
381 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
382 return {};
383 }
381} 384}
382 385
383std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { 386std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
diff --git a/src/core/network/network.h b/src/core/network/network.h
index bd30f1899..cfa68d478 100644
--- a/src/core/network/network.h
+++ b/src/core/network/network.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <optional>
8#include <utility> 9#include <utility>
9 10
10#include "common/common_funcs.h" 11#include "common/common_funcs.h"
@@ -93,7 +94,7 @@ public:
93}; 94};
94 95
95/// @brief Returns host's IPv4 address 96/// @brief Returns host's IPv4 address
96/// @return Pair of an array of human ordered IPv4 address (e.g. 192.168.0.1) and an error code 97/// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array
97std::pair<IPv4Address, Errno> GetHostIPv4Address(); 98std::optional<IPv4Address> GetHostIPv4Address();
98 99
99} // namespace Network 100} // namespace Network
diff --git a/src/core/network/network_interface.cpp b/src/core/network/network_interface.cpp
new file mode 100644
index 000000000..bba4c8b26
--- /dev/null
+++ b/src/core/network/network_interface.cpp
@@ -0,0 +1,113 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <vector>
6
7#include "common/common_types.h"
8#include "common/logging/log.h"
9#include "common/string_util.h"
10#include "core/network/network_interface.h"
11
12#ifdef _WIN32
13#include <iphlpapi.h>
14#else
15#include <ifaddrs.h>
16#include <net/if.h>
17#include <cerrno>
18#endif
19
20namespace Network {
21
22#ifdef _WIN32
23
24std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
25 std::vector<NetworkInterface> result;
26
27 std::vector<u8> adapter_addresses_raw;
28 auto adapter_addresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_addresses_raw.data());
29 DWORD ret = ERROR_BUFFER_OVERFLOW;
30 DWORD buf_size = 0;
31
32 // retry up to 5 times
33 for (int i = 0; i < 5 && ret == ERROR_BUFFER_OVERFLOW; i++) {
34 ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER,
35 nullptr, adapter_addresses, &buf_size);
36
37 if (ret == ERROR_BUFFER_OVERFLOW) {
38 adapter_addresses_raw.resize(buf_size);
39 adapter_addresses =
40 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_addresses_raw.data());
41 } else {
42 break;
43 }
44 }
45
46 if (ret == NO_ERROR) {
47 for (auto current_address = adapter_addresses; current_address != nullptr;
48 current_address = current_address->Next) {
49 if (current_address->FirstUnicastAddress == nullptr ||
50 current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) {
51 continue;
52 }
53
54 if (current_address->OperStatus != IfOperStatusUp) {
55 continue;
56 }
57
58 const auto ip_addr = std::bit_cast<struct sockaddr_in>(
59 *current_address->FirstUnicastAddress->Address.lpSockaddr)
60 .sin_addr;
61
62 result.push_back(NetworkInterface{
63 .name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
64 .ip_address{ip_addr}
65 });
66 }
67 } else {
68 LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
69 }
70
71 return result;
72}
73
74#else
75
76std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
77 std::vector<NetworkInterface> result;
78
79 struct ifaddrs* ifaddr = nullptr;
80
81 if (getifaddrs(&ifaddr) != 0) {
82 LOG_ERROR(Network, "Failed to get network interfaces with getifaddrs: {}",
83 std::strerror(errno));
84 return result;
85 }
86
87 for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
88 if (ifa->ifa_addr == nullptr) {
89 continue;
90 }
91
92 if (ifa->ifa_addr->sa_family != AF_INET) {
93 continue;
94 }
95
96 if (!(ifa->ifa_flags & IFF_UP) || ifa->ifa_flags & IFF_LOOPBACK) {
97 continue;
98 }
99
100 result.push_back(NetworkInterface{
101 .name{ifa->ifa_name},
102 .ip_address{std::bit_cast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr}
103 });
104 }
105
106 freeifaddrs(ifaddr);
107
108 return result;
109}
110
111#endif
112
113} // namespace Network
diff --git a/src/core/network/network_interface.h b/src/core/network/network_interface.h
new file mode 100644
index 000000000..d7184e14a
--- /dev/null
+++ b/src/core/network/network_interface.h
@@ -0,0 +1,25 @@
1// Copyright 2021 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 <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};
22
23std::vector<NetworkInterface> GetAvailableNetworkInterfaces();
24
25} // namespace Network