summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar bunnei2022-09-02 10:24:32 -0700
committerGravatar GitHub2022-09-02 10:24:32 -0700
commit5addff8d59dbafb96af02319c24e3e162296336d (patch)
treeaf3d99b89ec3cf093e940eff2d9d8cb31e4faec8 /src/core
parentMerge pull request #8843 from Kelebek1/SILENCE_WENCH (diff)
parentAddress review comments (diff)
downloadyuzu-5addff8d59dbafb96af02319c24e3e162296336d.tar.gz
yuzu-5addff8d59dbafb96af02319c24e3e162296336d.tar.xz
yuzu-5addff8d59dbafb96af02319c24e3e162296336d.zip
Merge pull request #8822 from FearlessTobi/multiplayer-fixes
network: Fixes and improvements to the room feature
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/announce_multiplayer_session.cpp164
-rw-r--r--src/core/announce_multiplayer_session.h98
-rw-r--r--src/core/core.cpp9
-rw-r--r--src/core/hle/service/acc/acc.cpp2
-rw-r--r--src/core/hle/service/ldn/ldn_types.h16
-rw-r--r--src/core/hle/service/sockets/bsd.cpp6
-rw-r--r--src/core/internal_network/socket_proxy.cpp8
8 files changed, 34 insertions, 271 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8db9a3c65..25b39c52b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -2,8 +2,6 @@
2# SPDX-License-Identifier: GPL-2.0-or-later 2# SPDX-License-Identifier: GPL-2.0-or-later
3 3
4add_library(core STATIC 4add_library(core STATIC
5 announce_multiplayer_session.cpp
6 announce_multiplayer_session.h
7 arm/arm_interface.h 5 arm/arm_interface.h
8 arm/arm_interface.cpp 6 arm/arm_interface.cpp
9 arm/dynarmic/arm_dynarmic_32.cpp 7 arm/dynarmic/arm_dynarmic_32.cpp
diff --git a/src/core/announce_multiplayer_session.cpp b/src/core/announce_multiplayer_session.cpp
deleted file mode 100644
index 6737ce85a..000000000
--- a/src/core/announce_multiplayer_session.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5#include <future>
6#include <vector>
7#include "announce_multiplayer_session.h"
8#include "common/announce_multiplayer_room.h"
9#include "common/assert.h"
10#include "common/settings.h"
11#include "network/network.h"
12
13#ifdef ENABLE_WEB_SERVICE
14#include "web_service/announce_room_json.h"
15#endif
16
17namespace Core {
18
19// Time between room is announced to web_service
20static constexpr std::chrono::seconds announce_time_interval(15);
21
22AnnounceMultiplayerSession::AnnounceMultiplayerSession(Network::RoomNetwork& room_network_)
23 : room_network{room_network_} {
24#ifdef ENABLE_WEB_SERVICE
25 backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
26 Settings::values.yuzu_username.GetValue(),
27 Settings::values.yuzu_token.GetValue());
28#else
29 backend = std::make_unique<AnnounceMultiplayerRoom::NullBackend>();
30#endif
31}
32
33WebService::WebResult AnnounceMultiplayerSession::Register() {
34 auto room = room_network.GetRoom().lock();
35 if (!room) {
36 return WebService::WebResult{WebService::WebResult::Code::LibError,
37 "Network is not initialized", ""};
38 }
39 if (room->GetState() != Network::Room::State::Open) {
40 return WebService::WebResult{WebService::WebResult::Code::LibError, "Room is not open", ""};
41 }
42 UpdateBackendData(room);
43 WebService::WebResult result = backend->Register();
44 if (result.result_code != WebService::WebResult::Code::Success) {
45 return result;
46 }
47 LOG_INFO(WebService, "Room has been registered");
48 room->SetVerifyUID(result.returned_data);
49 registered = true;
50 return WebService::WebResult{WebService::WebResult::Code::Success, "", ""};
51}
52
53void AnnounceMultiplayerSession::Start() {
54 if (announce_multiplayer_thread) {
55 Stop();
56 }
57 shutdown_event.Reset();
58 announce_multiplayer_thread =
59 std::make_unique<std::thread>(&AnnounceMultiplayerSession::AnnounceMultiplayerLoop, this);
60}
61
62void AnnounceMultiplayerSession::Stop() {
63 if (announce_multiplayer_thread) {
64 shutdown_event.Set();
65 announce_multiplayer_thread->join();
66 announce_multiplayer_thread.reset();
67 backend->Delete();
68 registered = false;
69 }
70}
71
72AnnounceMultiplayerSession::CallbackHandle AnnounceMultiplayerSession::BindErrorCallback(
73 std::function<void(const WebService::WebResult&)> function) {
74 std::lock_guard lock(callback_mutex);
75 auto handle = std::make_shared<std::function<void(const WebService::WebResult&)>>(function);
76 error_callbacks.insert(handle);
77 return handle;
78}
79
80void AnnounceMultiplayerSession::UnbindErrorCallback(CallbackHandle handle) {
81 std::lock_guard lock(callback_mutex);
82 error_callbacks.erase(handle);
83}
84
85AnnounceMultiplayerSession::~AnnounceMultiplayerSession() {
86 Stop();
87}
88
89void AnnounceMultiplayerSession::UpdateBackendData(std::shared_ptr<Network::Room> room) {
90 Network::RoomInformation room_information = room->GetRoomInformation();
91 std::vector<AnnounceMultiplayerRoom::Member> memberlist = room->GetRoomMemberList();
92 backend->SetRoomInformation(room_information.name, room_information.description,
93 room_information.port, room_information.member_slots,
94 Network::network_version, room->HasPassword(),
95 room_information.preferred_game);
96 backend->ClearPlayers();
97 for (const auto& member : memberlist) {
98 backend->AddPlayer(member);
99 }
100}
101
102void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() {
103 // Invokes all current bound error callbacks.
104 const auto ErrorCallback = [this](WebService::WebResult result) {
105 std::lock_guard lock(callback_mutex);
106 for (auto callback : error_callbacks) {
107 (*callback)(result);
108 }
109 };
110
111 if (!registered) {
112 WebService::WebResult result = Register();
113 if (result.result_code != WebService::WebResult::Code::Success) {
114 ErrorCallback(result);
115 return;
116 }
117 }
118
119 auto update_time = std::chrono::steady_clock::now();
120 std::future<WebService::WebResult> future;
121 while (!shutdown_event.WaitUntil(update_time)) {
122 update_time += announce_time_interval;
123 auto room = room_network.GetRoom().lock();
124 if (!room) {
125 break;
126 }
127 if (room->GetState() != Network::Room::State::Open) {
128 break;
129 }
130 UpdateBackendData(room);
131 WebService::WebResult result = backend->Update();
132 if (result.result_code != WebService::WebResult::Code::Success) {
133 ErrorCallback(result);
134 }
135 if (result.result_string == "404") {
136 registered = false;
137 // Needs to register the room again
138 WebService::WebResult register_result = Register();
139 if (register_result.result_code != WebService::WebResult::Code::Success) {
140 ErrorCallback(register_result);
141 }
142 }
143 }
144}
145
146AnnounceMultiplayerRoom::RoomList AnnounceMultiplayerSession::GetRoomList() {
147 return backend->GetRoomList();
148}
149
150bool AnnounceMultiplayerSession::IsRunning() const {
151 return announce_multiplayer_thread != nullptr;
152}
153
154void AnnounceMultiplayerSession::UpdateCredentials() {
155 ASSERT_MSG(!IsRunning(), "Credentials can only be updated when session is not running");
156
157#ifdef ENABLE_WEB_SERVICE
158 backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
159 Settings::values.yuzu_username.GetValue(),
160 Settings::values.yuzu_token.GetValue());
161#endif
162}
163
164} // namespace Core
diff --git a/src/core/announce_multiplayer_session.h b/src/core/announce_multiplayer_session.h
deleted file mode 100644
index db790f7d2..000000000
--- a/src/core/announce_multiplayer_session.h
+++ /dev/null
@@ -1,98 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <atomic>
7#include <functional>
8#include <memory>
9#include <mutex>
10#include <set>
11#include <thread>
12#include "common/announce_multiplayer_room.h"
13#include "common/common_types.h"
14#include "common/thread.h"
15
16namespace Network {
17class Room;
18class RoomNetwork;
19} // namespace Network
20
21namespace Core {
22
23/**
24 * Instruments AnnounceMultiplayerRoom::Backend.
25 * Creates a thread that regularly updates the room information and submits them
26 * An async get of room information is also possible
27 */
28class AnnounceMultiplayerSession {
29public:
30 using CallbackHandle = std::shared_ptr<std::function<void(const WebService::WebResult&)>>;
31 AnnounceMultiplayerSession(Network::RoomNetwork& room_network_);
32 ~AnnounceMultiplayerSession();
33
34 /**
35 * Allows to bind a function that will get called if the announce encounters an error
36 * @param function The function that gets called
37 * @return A handle that can be used the unbind the function
38 */
39 CallbackHandle BindErrorCallback(std::function<void(const WebService::WebResult&)> function);
40
41 /**
42 * Unbind a function from the error callbacks
43 * @param handle The handle for the function that should get unbind
44 */
45 void UnbindErrorCallback(CallbackHandle handle);
46
47 /**
48 * Registers a room to web services
49 * @return The result of the registration attempt.
50 */
51 WebService::WebResult Register();
52
53 /**
54 * Starts the announce of a room to web services
55 */
56 void Start();
57
58 /**
59 * Stops the announce to web services
60 */
61 void Stop();
62
63 /**
64 * Returns a list of all room information the backend got
65 * @param func A function that gets executed when the async get finished, e.g. a signal
66 * @return a list of rooms received from the web service
67 */
68 AnnounceMultiplayerRoom::RoomList GetRoomList();
69
70 /**
71 * Whether the announce session is still running
72 */
73 bool IsRunning() const;
74
75 /**
76 * Recreates the backend, updating the credentials.
77 * This can only be used when the announce session is not running.
78 */
79 void UpdateCredentials();
80
81private:
82 void UpdateBackendData(std::shared_ptr<Network::Room> room);
83 void AnnounceMultiplayerLoop();
84
85 Common::Event shutdown_event;
86 std::mutex callback_mutex;
87 std::set<CallbackHandle> error_callbacks;
88 std::unique_ptr<std::thread> announce_multiplayer_thread;
89
90 /// Backend interface that logs fields
91 std::unique_ptr<AnnounceMultiplayerRoom::Backend> backend;
92
93 std::atomic_bool registered = false; ///< Whether the room has been registered
94
95 Network::RoomNetwork& room_network;
96};
97
98} // namespace Core
diff --git a/src/core/core.cpp b/src/core/core.cpp
index ea32a4a8d..e651ce100 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -319,10 +319,19 @@ struct System::Impl {
319 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) { 319 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
320 LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result); 320 LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result);
321 } 321 }
322
323 std::string title_version;
324 const FileSys::PatchManager pm(program_id, system.GetFileSystemController(),
325 system.GetContentProvider());
326 const auto metadata = pm.GetControlMetadata();
327 if (metadata.first != nullptr) {
328 title_version = metadata.first->GetVersionString();
329 }
322 if (auto room_member = room_network.GetRoomMember().lock()) { 330 if (auto room_member = room_network.GetRoomMember().lock()) {
323 Network::GameInfo game_info; 331 Network::GameInfo game_info;
324 game_info.name = name; 332 game_info.name = name;
325 game_info.id = program_id; 333 game_info.id = program_id;
334 game_info.version = title_version;
326 room_member->SendGameInfo(game_info); 335 room_member->SendGameInfo(game_info);
327 } 336 }
328 337
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index def105832..bb838e285 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -534,7 +534,7 @@ public:
534 534
535private: 535private:
536 void CheckAvailability(Kernel::HLERequestContext& ctx) { 536 void CheckAvailability(Kernel::HLERequestContext& ctx) {
537 LOG_WARNING(Service_ACC, "(STUBBED) called"); 537 LOG_DEBUG(Service_ACC, "(STUBBED) called");
538 IPC::ResponseBuilder rb{ctx, 3}; 538 IPC::ResponseBuilder rb{ctx, 3};
539 rb.Push(ResultSuccess); 539 rb.Push(ResultSuccess);
540 rb.Push(false); // TODO: Check when this is supposed to return true and when not 540 rb.Push(false); // TODO: Check when this is supposed to return true and when not
diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h
index 0c07a7397..6231e936d 100644
--- a/src/core/hle/service/ldn/ldn_types.h
+++ b/src/core/hle/service/ldn/ldn_types.h
@@ -113,7 +113,7 @@ enum class LinkLevel : s8 {
113 Bad, 113 Bad,
114 Low, 114 Low,
115 Good, 115 Good,
116 Excelent, 116 Excellent,
117}; 117};
118 118
119struct NodeLatestUpdate { 119struct NodeLatestUpdate {
@@ -145,11 +145,19 @@ struct NetworkId {
145static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size"); 145static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
146 146
147struct Ssid { 147struct Ssid {
148 u8 length; 148 u8 length{};
149 std::array<char, SsidLengthMax + 1> raw; 149 std::array<char, SsidLengthMax + 1> raw{};
150
151 Ssid() = default;
152
153 explicit Ssid(std::string_view data) {
154 length = static_cast<u8>(std::min(data.size(), SsidLengthMax));
155 data.copy(raw.data(), length);
156 raw[length] = 0;
157 }
150 158
151 std::string GetStringValue() const { 159 std::string GetStringValue() const {
152 return std::string(raw.data(), length); 160 return std::string(raw.data());
153 } 161 }
154}; 162};
155static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); 163static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size");
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index e08c3cb67..cc679cc81 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -933,7 +933,11 @@ BSD::BSD(Core::System& system_, const char* name)
933 } 933 }
934} 934}
935 935
936BSD::~BSD() = default; 936BSD::~BSD() {
937 if (auto room_member = room_network.GetRoomMember().lock()) {
938 room_member->Unbind(proxy_packet_received);
939 }
940}
937 941
938BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} { 942BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} {
939 // clang-format off 943 // clang-format off
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp
index 49d067f4c..0c746bd82 100644
--- a/src/core/internal_network/socket_proxy.cpp
+++ b/src/core/internal_network/socket_proxy.cpp
@@ -26,6 +26,12 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) {
26 closed) { 26 closed) {
27 return; 27 return;
28 } 28 }
29
30 if (!broadcast && packet.broadcast) {
31 LOG_INFO(Network, "Received broadcast packet, but not configured for broadcast mode");
32 return;
33 }
34
29 std::lock_guard guard(packets_mutex); 35 std::lock_guard guard(packets_mutex);
30 received_packets.push(packet); 36 received_packets.push(packet);
31} 37}
@@ -203,7 +209,7 @@ std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, const std::vector<u8>& mess
203 packet.local_endpoint = local_endpoint; 209 packet.local_endpoint = local_endpoint;
204 packet.remote_endpoint = *addr; 210 packet.remote_endpoint = *addr;
205 packet.protocol = protocol; 211 packet.protocol = protocol;
206 packet.broadcast = broadcast; 212 packet.broadcast = broadcast && packet.remote_endpoint.ip[3] == 255;
207 213
208 auto& ip = local_endpoint.ip; 214 auto& ip = local_endpoint.ip;
209 auto ipv4 = Network::GetHostIPv4Address(); 215 auto ipv4 = Network::GetHostIPv4Address();