diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/ldn/lan_discovery.cpp | 644 | ||||
| -rw-r--r-- | src/core/hle/service/ldn/lan_discovery.h | 133 | ||||
| -rw-r--r-- | src/core/hle/service/ldn/ldn.cpp | 229 | ||||
| -rw-r--r-- | src/core/hle/service/ldn/ldn_types.h | 50 | ||||
| -rw-r--r-- | src/core/internal_network/socket_proxy.cpp | 8 | ||||
| -rw-r--r-- | src/dedicated_room/yuzu_room.cpp | 3 | ||||
| -rw-r--r-- | src/network/room.cpp | 63 | ||||
| -rw-r--r-- | src/network/room.h | 1 | ||||
| -rw-r--r-- | src/network/room_member.cpp | 57 | ||||
| -rw-r--r-- | src/network/room_member.h | 35 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/main.ui | 14 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/chat_room.cpp | 12 | ||||
| -rw-r--r-- | src/yuzu/multiplayer/state.cpp | 1 |
15 files changed, 1132 insertions, 124 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 806e7ff6c..52017878c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -500,6 +500,8 @@ add_library(core STATIC | |||
| 500 | hle/service/jit/jit.h | 500 | hle/service/jit/jit.h |
| 501 | hle/service/lbl/lbl.cpp | 501 | hle/service/lbl/lbl.cpp |
| 502 | hle/service/lbl/lbl.h | 502 | hle/service/lbl/lbl.h |
| 503 | hle/service/ldn/lan_discovery.cpp | ||
| 504 | hle/service/ldn/lan_discovery.h | ||
| 503 | hle/service/ldn/ldn_results.h | 505 | hle/service/ldn/ldn_results.h |
| 504 | hle/service/ldn/ldn.cpp | 506 | hle/service/ldn/ldn.cpp |
| 505 | hle/service/ldn/ldn.h | 507 | hle/service/ldn/ldn.h |
diff --git a/src/core/hle/service/ldn/lan_discovery.cpp b/src/core/hle/service/ldn/lan_discovery.cpp new file mode 100644 index 000000000..b04c99077 --- /dev/null +++ b/src/core/hle/service/ldn/lan_discovery.cpp | |||
| @@ -0,0 +1,644 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "core/hle/service/ldn/lan_discovery.h" | ||
| 5 | #include "core/internal_network/network.h" | ||
| 6 | #include "core/internal_network/network_interface.h" | ||
| 7 | |||
| 8 | namespace Service::LDN { | ||
| 9 | |||
| 10 | LanStation::LanStation(s8 node_id_, LANDiscovery* discovery_) | ||
| 11 | : node_info(nullptr), status(NodeStatus::Disconnected), node_id(node_id_), | ||
| 12 | discovery(discovery_) {} | ||
| 13 | |||
| 14 | LanStation::~LanStation() = default; | ||
| 15 | |||
| 16 | NodeStatus LanStation::GetStatus() const { | ||
| 17 | return status; | ||
| 18 | } | ||
| 19 | |||
| 20 | void LanStation::OnClose() { | ||
| 21 | LOG_INFO(Service_LDN, "OnClose {}", node_id); | ||
| 22 | Reset(); | ||
| 23 | discovery->UpdateNodes(); | ||
| 24 | } | ||
| 25 | |||
| 26 | void LanStation::Reset() { | ||
| 27 | status = NodeStatus::Disconnected; | ||
| 28 | }; | ||
| 29 | |||
| 30 | void LanStation::OverrideInfo() { | ||
| 31 | bool connected = GetStatus() == NodeStatus::Connected; | ||
| 32 | node_info->node_id = node_id; | ||
| 33 | node_info->is_connected = connected ? 1 : 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | LANDiscovery::LANDiscovery(Network::RoomNetwork& room_network_) | ||
| 37 | : stations({{{1, this}, {2, this}, {3, this}, {4, this}, {5, this}, {6, this}, {7, this}}}), | ||
| 38 | room_network{room_network_} { | ||
| 39 | LOG_INFO(Service_LDN, "LANDiscovery"); | ||
| 40 | } | ||
| 41 | |||
| 42 | LANDiscovery::~LANDiscovery() { | ||
| 43 | LOG_INFO(Service_LDN, "~LANDiscovery"); | ||
| 44 | if (inited) { | ||
| 45 | Result rc = Finalize(); | ||
| 46 | LOG_INFO(Service_LDN, "Finalize: {}", rc.raw); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | void LANDiscovery::InitNetworkInfo() { | ||
| 51 | network_info.common.bssid = GetFakeMac(); | ||
| 52 | network_info.common.channel = WifiChannel::Wifi24_6; | ||
| 53 | network_info.common.link_level = LinkLevel::Good; | ||
| 54 | network_info.common.network_type = PackedNetworkType::Ldn; | ||
| 55 | network_info.common.ssid = fake_ssid; | ||
| 56 | |||
| 57 | auto& nodes = network_info.ldn.nodes; | ||
| 58 | for (std::size_t i = 0; i < NodeCountMax; i++) { | ||
| 59 | nodes[i].node_id = static_cast<s8>(i); | ||
| 60 | nodes[i].is_connected = 0; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | void LANDiscovery::InitNodeStateChange() { | ||
| 65 | for (auto& node_update : nodeChanges) { | ||
| 66 | node_update.state_change = NodeStateChange::None; | ||
| 67 | } | ||
| 68 | for (auto& node_state : node_last_states) { | ||
| 69 | node_state = 0; | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | State LANDiscovery::GetState() const { | ||
| 74 | return state; | ||
| 75 | } | ||
| 76 | |||
| 77 | void LANDiscovery::SetState(State new_state) { | ||
| 78 | state = new_state; | ||
| 79 | } | ||
| 80 | |||
| 81 | Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network) const { | ||
| 82 | if (state == State::AccessPointCreated || state == State::StationConnected) { | ||
| 83 | std::memcpy(&out_network, &network_info, sizeof(network_info)); | ||
| 84 | return ResultSuccess; | ||
| 85 | } | ||
| 86 | |||
| 87 | return ResultBadState; | ||
| 88 | } | ||
| 89 | |||
| 90 | Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network, | ||
| 91 | std::vector<NodeLatestUpdate>& out_updates, | ||
| 92 | std::size_t buffer_count) { | ||
| 93 | if (buffer_count > NodeCountMax) { | ||
| 94 | return ResultInvalidBufferCount; | ||
| 95 | } | ||
| 96 | |||
| 97 | if (state == State::AccessPointCreated || state == State::StationConnected) { | ||
| 98 | std::memcpy(&out_network, &network_info, sizeof(network_info)); | ||
| 99 | for (std::size_t i = 0; i < buffer_count; i++) { | ||
| 100 | out_updates[i].state_change = nodeChanges[i].state_change; | ||
| 101 | nodeChanges[i].state_change = NodeStateChange::None; | ||
| 102 | } | ||
| 103 | return ResultSuccess; | ||
| 104 | } | ||
| 105 | |||
| 106 | return ResultBadState; | ||
| 107 | } | ||
| 108 | |||
| 109 | DisconnectReason LANDiscovery::GetDisconnectReason() const { | ||
| 110 | return disconnect_reason; | ||
| 111 | } | ||
| 112 | |||
| 113 | Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count, | ||
| 114 | const ScanFilter& filter) { | ||
| 115 | if (!IsFlagSet(filter.flag, ScanFilterFlag::NetworkType) || | ||
| 116 | filter.network_type <= NetworkType::All) { | ||
| 117 | if (!IsFlagSet(filter.flag, ScanFilterFlag::Ssid) && filter.ssid.length >= SsidLengthMax) { | ||
| 118 | return ResultBadInput; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | { | ||
| 123 | std::scoped_lock lock{packet_mutex}; | ||
| 124 | scan_results.clear(); | ||
| 125 | |||
| 126 | SendBroadcast(Network::LDNPacketType::Scan); | ||
| 127 | } | ||
| 128 | |||
| 129 | LOG_INFO(Service_LDN, "Waiting for scan replies"); | ||
| 130 | std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
| 131 | |||
| 132 | std::scoped_lock lock{packet_mutex}; | ||
| 133 | for (const auto& [key, info] : scan_results) { | ||
| 134 | if (count >= networks.size()) { | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (IsFlagSet(filter.flag, ScanFilterFlag::LocalCommunicationId)) { | ||
| 139 | if (filter.network_id.intent_id.local_communication_id != | ||
| 140 | info.network_id.intent_id.local_communication_id) { | ||
| 141 | continue; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | if (IsFlagSet(filter.flag, ScanFilterFlag::SessionId)) { | ||
| 145 | if (filter.network_id.session_id != info.network_id.session_id) { | ||
| 146 | continue; | ||
| 147 | } | ||
| 148 | } | ||
| 149 | if (IsFlagSet(filter.flag, ScanFilterFlag::NetworkType)) { | ||
| 150 | if (filter.network_type != static_cast<NetworkType>(info.common.network_type)) { | ||
| 151 | continue; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | if (IsFlagSet(filter.flag, ScanFilterFlag::Ssid)) { | ||
| 155 | if (filter.ssid != info.common.ssid) { | ||
| 156 | continue; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | if (IsFlagSet(filter.flag, ScanFilterFlag::SceneId)) { | ||
| 160 | if (filter.network_id.intent_id.scene_id != info.network_id.intent_id.scene_id) { | ||
| 161 | continue; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | networks[count++] = info; | ||
| 166 | } | ||
| 167 | |||
| 168 | return ResultSuccess; | ||
| 169 | } | ||
| 170 | |||
| 171 | Result LANDiscovery::SetAdvertiseData(std::vector<u8>& data) { | ||
| 172 | std::scoped_lock lock{packet_mutex}; | ||
| 173 | std::size_t size = data.size(); | ||
| 174 | if (size > AdvertiseDataSizeMax) { | ||
| 175 | return ResultAdvertiseDataTooLarge; | ||
| 176 | } | ||
| 177 | |||
| 178 | std::memcpy(network_info.ldn.advertise_data.data(), data.data(), size); | ||
| 179 | network_info.ldn.advertise_data_size = static_cast<u16>(size); | ||
| 180 | |||
| 181 | UpdateNodes(); | ||
| 182 | |||
| 183 | return ResultSuccess; | ||
| 184 | } | ||
| 185 | |||
| 186 | Result LANDiscovery::OpenAccessPoint() { | ||
| 187 | std::scoped_lock lock{packet_mutex}; | ||
| 188 | disconnect_reason = DisconnectReason::None; | ||
| 189 | if (state == State::None) { | ||
| 190 | return ResultBadState; | ||
| 191 | } | ||
| 192 | |||
| 193 | ResetStations(); | ||
| 194 | SetState(State::AccessPointOpened); | ||
| 195 | |||
| 196 | return ResultSuccess; | ||
| 197 | } | ||
| 198 | |||
| 199 | Result LANDiscovery::CloseAccessPoint() { | ||
| 200 | std::scoped_lock lock{packet_mutex}; | ||
| 201 | if (state == State::None) { | ||
| 202 | return ResultBadState; | ||
| 203 | } | ||
| 204 | |||
| 205 | if (state == State::AccessPointCreated) { | ||
| 206 | DestroyNetwork(); | ||
| 207 | } | ||
| 208 | |||
| 209 | ResetStations(); | ||
| 210 | SetState(State::Initialized); | ||
| 211 | |||
| 212 | return ResultSuccess; | ||
| 213 | } | ||
| 214 | |||
| 215 | Result LANDiscovery::OpenStation() { | ||
| 216 | std::scoped_lock lock{packet_mutex}; | ||
| 217 | disconnect_reason = DisconnectReason::None; | ||
| 218 | if (state == State::None) { | ||
| 219 | return ResultBadState; | ||
| 220 | } | ||
| 221 | |||
| 222 | ResetStations(); | ||
| 223 | SetState(State::StationOpened); | ||
| 224 | |||
| 225 | return ResultSuccess; | ||
| 226 | } | ||
| 227 | |||
| 228 | Result LANDiscovery::CloseStation() { | ||
| 229 | std::scoped_lock lock{packet_mutex}; | ||
| 230 | if (state == State::None) { | ||
| 231 | return ResultBadState; | ||
| 232 | } | ||
| 233 | |||
| 234 | if (state == State::StationConnected) { | ||
| 235 | Disconnect(); | ||
| 236 | } | ||
| 237 | |||
| 238 | ResetStations(); | ||
| 239 | SetState(State::Initialized); | ||
| 240 | |||
| 241 | return ResultSuccess; | ||
| 242 | } | ||
| 243 | |||
| 244 | Result LANDiscovery::CreateNetwork(const SecurityConfig& security_config, | ||
| 245 | const UserConfig& user_config, | ||
| 246 | const NetworkConfig& network_config) { | ||
| 247 | std::scoped_lock lock{packet_mutex}; | ||
| 248 | |||
| 249 | if (state != State::AccessPointOpened) { | ||
| 250 | return ResultBadState; | ||
| 251 | } | ||
| 252 | |||
| 253 | InitNetworkInfo(); | ||
| 254 | network_info.ldn.node_count_max = network_config.node_count_max; | ||
| 255 | network_info.ldn.security_mode = security_config.security_mode; | ||
| 256 | |||
| 257 | if (network_config.channel == WifiChannel::Default) { | ||
| 258 | network_info.common.channel = WifiChannel::Wifi24_6; | ||
| 259 | } else { | ||
| 260 | network_info.common.channel = network_config.channel; | ||
| 261 | } | ||
| 262 | |||
| 263 | std::independent_bits_engine<std::mt19937, 64, u64> bits_engine; | ||
| 264 | network_info.network_id.session_id.high = bits_engine(); | ||
| 265 | network_info.network_id.session_id.low = bits_engine(); | ||
| 266 | network_info.network_id.intent_id = network_config.intent_id; | ||
| 267 | |||
| 268 | NodeInfo& node0 = network_info.ldn.nodes[0]; | ||
| 269 | const Result rc2 = GetNodeInfo(node0, user_config, network_config.local_communication_version); | ||
| 270 | if (rc2.IsError()) { | ||
| 271 | return ResultAccessPointConnectionFailed; | ||
| 272 | } | ||
| 273 | |||
| 274 | SetState(State::AccessPointCreated); | ||
| 275 | |||
| 276 | InitNodeStateChange(); | ||
| 277 | node0.is_connected = 1; | ||
| 278 | UpdateNodes(); | ||
| 279 | |||
| 280 | return rc2; | ||
| 281 | } | ||
| 282 | |||
| 283 | Result LANDiscovery::DestroyNetwork() { | ||
| 284 | for (auto local_ip : connected_clients) { | ||
| 285 | SendPacket(Network::LDNPacketType::DestroyNetwork, local_ip); | ||
| 286 | } | ||
| 287 | |||
| 288 | ResetStations(); | ||
| 289 | |||
| 290 | SetState(State::AccessPointOpened); | ||
| 291 | LanEvent(); | ||
| 292 | |||
| 293 | return ResultSuccess; | ||
| 294 | } | ||
| 295 | |||
| 296 | Result LANDiscovery::Connect(const NetworkInfo& network_info_, const UserConfig& user_config, | ||
| 297 | u16 local_communication_version) { | ||
| 298 | std::scoped_lock lock{packet_mutex}; | ||
| 299 | if (network_info_.ldn.node_count == 0) { | ||
| 300 | return ResultInvalidNodeCount; | ||
| 301 | } | ||
| 302 | |||
| 303 | Result rc = GetNodeInfo(node_info, user_config, local_communication_version); | ||
| 304 | if (rc.IsError()) { | ||
| 305 | return ResultConnectionFailed; | ||
| 306 | } | ||
| 307 | |||
| 308 | Ipv4Address node_host = network_info_.ldn.nodes[0].ipv4_address; | ||
| 309 | std::reverse(std::begin(node_host), std::end(node_host)); // htonl | ||
| 310 | host_ip = node_host; | ||
| 311 | SendPacket(Network::LDNPacketType::Connect, node_info, *host_ip); | ||
| 312 | |||
| 313 | InitNodeStateChange(); | ||
| 314 | |||
| 315 | std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
| 316 | |||
| 317 | return ResultSuccess; | ||
| 318 | } | ||
| 319 | |||
| 320 | Result LANDiscovery::Disconnect() { | ||
| 321 | if (host_ip) { | ||
| 322 | SendPacket(Network::LDNPacketType::Disconnect, node_info, *host_ip); | ||
| 323 | } | ||
| 324 | |||
| 325 | SetState(State::StationOpened); | ||
| 326 | LanEvent(); | ||
| 327 | |||
| 328 | return ResultSuccess; | ||
| 329 | } | ||
| 330 | |||
| 331 | Result LANDiscovery::Initialize(LanEventFunc lan_event, bool listening) { | ||
| 332 | std::scoped_lock lock{packet_mutex}; | ||
| 333 | if (inited) { | ||
| 334 | return ResultSuccess; | ||
| 335 | } | ||
| 336 | |||
| 337 | for (auto& station : stations) { | ||
| 338 | station.discovery = this; | ||
| 339 | station.node_info = &network_info.ldn.nodes[station.node_id]; | ||
| 340 | station.Reset(); | ||
| 341 | } | ||
| 342 | |||
| 343 | connected_clients.clear(); | ||
| 344 | LanEvent = lan_event; | ||
| 345 | |||
| 346 | SetState(State::Initialized); | ||
| 347 | |||
| 348 | inited = true; | ||
| 349 | return ResultSuccess; | ||
| 350 | } | ||
| 351 | |||
| 352 | Result LANDiscovery::Finalize() { | ||
| 353 | std::scoped_lock lock{packet_mutex}; | ||
| 354 | Result rc = ResultSuccess; | ||
| 355 | |||
| 356 | if (inited) { | ||
| 357 | if (state == State::AccessPointCreated) { | ||
| 358 | DestroyNetwork(); | ||
| 359 | } | ||
| 360 | if (state == State::StationConnected) { | ||
| 361 | Disconnect(); | ||
| 362 | } | ||
| 363 | |||
| 364 | ResetStations(); | ||
| 365 | inited = false; | ||
| 366 | } | ||
| 367 | |||
| 368 | SetState(State::None); | ||
| 369 | |||
| 370 | return rc; | ||
| 371 | } | ||
| 372 | |||
| 373 | void LANDiscovery::ResetStations() { | ||
| 374 | for (auto& station : stations) { | ||
| 375 | station.Reset(); | ||
| 376 | } | ||
| 377 | connected_clients.clear(); | ||
| 378 | } | ||
| 379 | |||
| 380 | void LANDiscovery::UpdateNodes() { | ||
| 381 | u8 count = 0; | ||
| 382 | for (auto& station : stations) { | ||
| 383 | bool connected = station.GetStatus() == NodeStatus::Connected; | ||
| 384 | if (connected) { | ||
| 385 | count++; | ||
| 386 | } | ||
| 387 | station.OverrideInfo(); | ||
| 388 | } | ||
| 389 | network_info.ldn.node_count = count + 1; | ||
| 390 | |||
| 391 | for (auto local_ip : connected_clients) { | ||
| 392 | SendPacket(Network::LDNPacketType::SyncNetwork, network_info, local_ip); | ||
| 393 | } | ||
| 394 | |||
| 395 | OnNetworkInfoChanged(); | ||
| 396 | } | ||
| 397 | |||
| 398 | void LANDiscovery::OnSyncNetwork(const NetworkInfo& info) { | ||
| 399 | network_info = info; | ||
| 400 | if (state == State::StationOpened) { | ||
| 401 | SetState(State::StationConnected); | ||
| 402 | } | ||
| 403 | OnNetworkInfoChanged(); | ||
| 404 | } | ||
| 405 | |||
| 406 | void LANDiscovery::OnDisconnectFromHost() { | ||
| 407 | LOG_INFO(Service_LDN, "OnDisconnectFromHost state: {}", static_cast<int>(state)); | ||
| 408 | host_ip = std::nullopt; | ||
| 409 | if (state == State::StationConnected) { | ||
| 410 | SetState(State::StationOpened); | ||
| 411 | LanEvent(); | ||
| 412 | } | ||
| 413 | } | ||
| 414 | |||
| 415 | void LANDiscovery::OnNetworkInfoChanged() { | ||
| 416 | if (IsNodeStateChanged()) { | ||
| 417 | LanEvent(); | ||
| 418 | } | ||
| 419 | return; | ||
| 420 | } | ||
| 421 | |||
| 422 | Network::IPv4Address LANDiscovery::GetLocalIp() const { | ||
| 423 | Network::IPv4Address local_ip{0xFF, 0xFF, 0xFF, 0xFF}; | ||
| 424 | if (auto room_member = room_network.GetRoomMember().lock()) { | ||
| 425 | if (room_member->IsConnected()) { | ||
| 426 | local_ip = room_member->GetFakeIpAddress(); | ||
| 427 | } | ||
| 428 | } | ||
| 429 | return local_ip; | ||
| 430 | } | ||
| 431 | |||
| 432 | template <typename Data> | ||
| 433 | void LANDiscovery::SendPacket(Network::LDNPacketType type, const Data& data, | ||
| 434 | Ipv4Address remote_ip) { | ||
| 435 | Network::LDNPacket packet; | ||
| 436 | packet.type = type; | ||
| 437 | |||
| 438 | packet.broadcast = false; | ||
| 439 | packet.local_ip = GetLocalIp(); | ||
| 440 | packet.remote_ip = remote_ip; | ||
| 441 | |||
| 442 | packet.data.clear(); | ||
| 443 | packet.data.resize(sizeof(data)); | ||
| 444 | std::memcpy(packet.data.data(), &data, sizeof(data)); | ||
| 445 | SendPacket(packet); | ||
| 446 | } | ||
| 447 | |||
| 448 | void LANDiscovery::SendPacket(Network::LDNPacketType type, Ipv4Address remote_ip) { | ||
| 449 | Network::LDNPacket packet; | ||
| 450 | packet.type = type; | ||
| 451 | |||
| 452 | packet.broadcast = false; | ||
| 453 | packet.local_ip = GetLocalIp(); | ||
| 454 | packet.remote_ip = remote_ip; | ||
| 455 | |||
| 456 | packet.data.clear(); | ||
| 457 | SendPacket(packet); | ||
| 458 | } | ||
| 459 | |||
| 460 | template <typename Data> | ||
| 461 | void LANDiscovery::SendBroadcast(Network::LDNPacketType type, const Data& data) { | ||
| 462 | Network::LDNPacket packet; | ||
| 463 | packet.type = type; | ||
| 464 | |||
| 465 | packet.broadcast = true; | ||
| 466 | packet.local_ip = GetLocalIp(); | ||
| 467 | |||
| 468 | packet.data.clear(); | ||
| 469 | packet.data.resize(sizeof(data)); | ||
| 470 | std::memcpy(packet.data.data(), &data, sizeof(data)); | ||
| 471 | SendPacket(packet); | ||
| 472 | } | ||
| 473 | |||
| 474 | void LANDiscovery::SendBroadcast(Network::LDNPacketType type) { | ||
| 475 | Network::LDNPacket packet; | ||
| 476 | packet.type = type; | ||
| 477 | |||
| 478 | packet.broadcast = true; | ||
| 479 | packet.local_ip = GetLocalIp(); | ||
| 480 | |||
| 481 | packet.data.clear(); | ||
| 482 | SendPacket(packet); | ||
| 483 | } | ||
| 484 | |||
| 485 | void LANDiscovery::SendPacket(const Network::LDNPacket& packet) { | ||
| 486 | if (auto room_member = room_network.GetRoomMember().lock()) { | ||
| 487 | if (room_member->IsConnected()) { | ||
| 488 | room_member->SendLdnPacket(packet); | ||
| 489 | } | ||
| 490 | } | ||
| 491 | } | ||
| 492 | |||
| 493 | void LANDiscovery::ReceivePacket(const Network::LDNPacket& packet) { | ||
| 494 | std::scoped_lock lock{packet_mutex}; | ||
| 495 | switch (packet.type) { | ||
| 496 | case Network::LDNPacketType::Scan: { | ||
| 497 | LOG_INFO(Frontend, "Scan packet received!"); | ||
| 498 | if (state == State::AccessPointCreated) { | ||
| 499 | // Reply to the sender | ||
| 500 | SendPacket(Network::LDNPacketType::ScanResp, network_info, packet.local_ip); | ||
| 501 | } | ||
| 502 | break; | ||
| 503 | } | ||
| 504 | case Network::LDNPacketType::ScanResp: { | ||
| 505 | LOG_INFO(Frontend, "ScanResp packet received!"); | ||
| 506 | |||
| 507 | NetworkInfo info{}; | ||
| 508 | std::memcpy(&info, packet.data.data(), sizeof(NetworkInfo)); | ||
| 509 | scan_results.insert({info.common.bssid, info}); | ||
| 510 | |||
| 511 | break; | ||
| 512 | } | ||
| 513 | case Network::LDNPacketType::Connect: { | ||
| 514 | LOG_INFO(Frontend, "Connect packet received!"); | ||
| 515 | |||
| 516 | NodeInfo info{}; | ||
| 517 | std::memcpy(&info, packet.data.data(), sizeof(NodeInfo)); | ||
| 518 | |||
| 519 | connected_clients.push_back(packet.local_ip); | ||
| 520 | |||
| 521 | for (LanStation& station : stations) { | ||
| 522 | if (station.status != NodeStatus::Connected) { | ||
| 523 | *station.node_info = info; | ||
| 524 | station.status = NodeStatus::Connected; | ||
| 525 | break; | ||
| 526 | } | ||
| 527 | } | ||
| 528 | |||
| 529 | UpdateNodes(); | ||
| 530 | |||
| 531 | break; | ||
| 532 | } | ||
| 533 | case Network::LDNPacketType::Disconnect: { | ||
| 534 | LOG_INFO(Frontend, "Disconnect packet received!"); | ||
| 535 | |||
| 536 | connected_clients.erase( | ||
| 537 | std::remove(connected_clients.begin(), connected_clients.end(), packet.local_ip), | ||
| 538 | connected_clients.end()); | ||
| 539 | |||
| 540 | NodeInfo info{}; | ||
| 541 | std::memcpy(&info, packet.data.data(), sizeof(NodeInfo)); | ||
| 542 | |||
| 543 | for (LanStation& station : stations) { | ||
| 544 | if (station.status == NodeStatus::Connected && | ||
| 545 | station.node_info->mac_address == info.mac_address) { | ||
| 546 | station.OnClose(); | ||
| 547 | break; | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 551 | break; | ||
| 552 | } | ||
| 553 | case Network::LDNPacketType::DestroyNetwork: { | ||
| 554 | ResetStations(); | ||
| 555 | OnDisconnectFromHost(); | ||
| 556 | break; | ||
| 557 | } | ||
| 558 | case Network::LDNPacketType::SyncNetwork: { | ||
| 559 | if (state == State::StationOpened || state == State::StationConnected) { | ||
| 560 | LOG_INFO(Frontend, "SyncNetwork packet received!"); | ||
| 561 | NetworkInfo info{}; | ||
| 562 | std::memcpy(&info, packet.data.data(), sizeof(NetworkInfo)); | ||
| 563 | |||
| 564 | OnSyncNetwork(info); | ||
| 565 | } else { | ||
| 566 | LOG_INFO(Frontend, "SyncNetwork packet received but in wrong State!"); | ||
| 567 | } | ||
| 568 | |||
| 569 | break; | ||
| 570 | } | ||
| 571 | default: { | ||
| 572 | LOG_INFO(Frontend, "ReceivePacket unhandled type {}", static_cast<int>(packet.type)); | ||
| 573 | break; | ||
| 574 | } | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | bool LANDiscovery::IsNodeStateChanged() { | ||
| 579 | bool changed = false; | ||
| 580 | const auto& nodes = network_info.ldn.nodes; | ||
| 581 | for (int i = 0; i < NodeCountMax; i++) { | ||
| 582 | if (nodes[i].is_connected != node_last_states[i]) { | ||
| 583 | if (nodes[i].is_connected) { | ||
| 584 | nodeChanges[i].state_change |= NodeStateChange::Connect; | ||
| 585 | } else { | ||
| 586 | nodeChanges[i].state_change |= NodeStateChange::Disconnect; | ||
| 587 | } | ||
| 588 | node_last_states[i] = nodes[i].is_connected; | ||
| 589 | changed = true; | ||
| 590 | } | ||
| 591 | } | ||
| 592 | return changed; | ||
| 593 | } | ||
| 594 | |||
| 595 | bool LANDiscovery::IsFlagSet(ScanFilterFlag flag, ScanFilterFlag search_flag) const { | ||
| 596 | const auto flag_value = static_cast<u32>(flag); | ||
| 597 | const auto search_flag_value = static_cast<u32>(search_flag); | ||
| 598 | return (flag_value & search_flag_value) == search_flag_value; | ||
| 599 | } | ||
| 600 | |||
| 601 | int LANDiscovery::GetStationCount() { | ||
| 602 | int count = 0; | ||
| 603 | for (const auto& station : stations) { | ||
| 604 | if (station.GetStatus() != NodeStatus::Disconnected) { | ||
| 605 | count++; | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | return count; | ||
| 610 | } | ||
| 611 | |||
| 612 | MacAddress LANDiscovery::GetFakeMac() const { | ||
| 613 | MacAddress mac{}; | ||
| 614 | mac.raw[0] = 0x02; | ||
| 615 | mac.raw[1] = 0x00; | ||
| 616 | |||
| 617 | const auto ip = GetLocalIp(); | ||
| 618 | memcpy(mac.raw.data() + 2, &ip, sizeof(ip)); | ||
| 619 | |||
| 620 | return mac; | ||
| 621 | } | ||
| 622 | |||
| 623 | Result LANDiscovery::GetNodeInfo(NodeInfo& node, const UserConfig& userConfig, | ||
| 624 | u16 localCommunicationVersion) { | ||
| 625 | const auto network_interface = Network::GetSelectedNetworkInterface(); | ||
| 626 | |||
| 627 | if (!network_interface) { | ||
| 628 | LOG_ERROR(Service_LDN, "No network interface available"); | ||
| 629 | return ResultNoIpAddress; | ||
| 630 | } | ||
| 631 | |||
| 632 | node.mac_address = GetFakeMac(); | ||
| 633 | node.is_connected = 1; | ||
| 634 | std::memcpy(node.user_name.data(), userConfig.user_name.data(), UserNameBytesMax + 1); | ||
| 635 | node.local_communication_version = localCommunicationVersion; | ||
| 636 | |||
| 637 | Ipv4Address current_address = GetLocalIp(); | ||
| 638 | std::reverse(std::begin(current_address), std::end(current_address)); // ntohl | ||
| 639 | node.ipv4_address = current_address; | ||
| 640 | |||
| 641 | return ResultSuccess; | ||
| 642 | } | ||
| 643 | |||
| 644 | } // namespace Service::LDN | ||
diff --git a/src/core/hle/service/ldn/lan_discovery.h b/src/core/hle/service/ldn/lan_discovery.h new file mode 100644 index 000000000..255342456 --- /dev/null +++ b/src/core/hle/service/ldn/lan_discovery.h | |||
| @@ -0,0 +1,133 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <cstring> | ||
| 8 | #include <functional> | ||
| 9 | #include <memory> | ||
| 10 | #include <mutex> | ||
| 11 | #include <optional> | ||
| 12 | #include <random> | ||
| 13 | #include <thread> | ||
| 14 | #include <unordered_map> | ||
| 15 | |||
| 16 | #include "common/logging/log.h" | ||
| 17 | #include "common/socket_types.h" | ||
| 18 | #include "core/hle/result.h" | ||
| 19 | #include "core/hle/service/ldn/ldn_results.h" | ||
| 20 | #include "core/hle/service/ldn/ldn_types.h" | ||
| 21 | #include "network/network.h" | ||
| 22 | |||
| 23 | namespace Service::LDN { | ||
| 24 | |||
| 25 | class LANDiscovery; | ||
| 26 | |||
| 27 | class LanStation { | ||
| 28 | public: | ||
| 29 | LanStation(s8 node_id_, LANDiscovery* discovery_); | ||
| 30 | ~LanStation(); | ||
| 31 | |||
| 32 | void OnClose(); | ||
| 33 | NodeStatus GetStatus() const; | ||
| 34 | void Reset(); | ||
| 35 | void OverrideInfo(); | ||
| 36 | |||
| 37 | protected: | ||
| 38 | friend class LANDiscovery; | ||
| 39 | NodeInfo* node_info; | ||
| 40 | NodeStatus status; | ||
| 41 | s8 node_id; | ||
| 42 | LANDiscovery* discovery; | ||
| 43 | }; | ||
| 44 | |||
| 45 | class LANDiscovery { | ||
| 46 | public: | ||
| 47 | typedef std::function<void()> LanEventFunc; | ||
| 48 | |||
| 49 | LANDiscovery(Network::RoomNetwork& room_network_); | ||
| 50 | ~LANDiscovery(); | ||
| 51 | |||
| 52 | State GetState() const; | ||
| 53 | void SetState(State new_state); | ||
| 54 | |||
| 55 | Result GetNetworkInfo(NetworkInfo& out_network) const; | ||
| 56 | Result GetNetworkInfo(NetworkInfo& out_network, std::vector<NodeLatestUpdate>& out_updates, | ||
| 57 | std::size_t buffer_count); | ||
| 58 | |||
| 59 | DisconnectReason GetDisconnectReason() const; | ||
| 60 | Result Scan(std::vector<NetworkInfo>& networks, u16& count, const ScanFilter& filter); | ||
| 61 | Result SetAdvertiseData(std::vector<u8>& data); | ||
| 62 | |||
| 63 | Result OpenAccessPoint(); | ||
| 64 | Result CloseAccessPoint(); | ||
| 65 | |||
| 66 | Result OpenStation(); | ||
| 67 | Result CloseStation(); | ||
| 68 | |||
| 69 | Result CreateNetwork(const SecurityConfig& security_config, const UserConfig& user_config, | ||
| 70 | const NetworkConfig& network_config); | ||
| 71 | Result DestroyNetwork(); | ||
| 72 | |||
| 73 | Result Connect(const NetworkInfo& network_info_, const UserConfig& user_config, | ||
| 74 | u16 local_communication_version); | ||
| 75 | Result Disconnect(); | ||
| 76 | |||
| 77 | Result Initialize(LanEventFunc lan_event = empty_func, bool listening = true); | ||
| 78 | Result Finalize(); | ||
| 79 | |||
| 80 | void ReceivePacket(const Network::LDNPacket& packet); | ||
| 81 | |||
| 82 | protected: | ||
| 83 | friend class LanStation; | ||
| 84 | |||
| 85 | void InitNetworkInfo(); | ||
| 86 | void InitNodeStateChange(); | ||
| 87 | |||
| 88 | void ResetStations(); | ||
| 89 | void UpdateNodes(); | ||
| 90 | |||
| 91 | void OnSyncNetwork(const NetworkInfo& info); | ||
| 92 | void OnDisconnectFromHost(); | ||
| 93 | void OnNetworkInfoChanged(); | ||
| 94 | |||
| 95 | bool IsNodeStateChanged(); | ||
| 96 | bool IsFlagSet(ScanFilterFlag flag, ScanFilterFlag search_flag) const; | ||
| 97 | int GetStationCount(); | ||
| 98 | MacAddress GetFakeMac() const; | ||
| 99 | Result GetNodeInfo(NodeInfo& node, const UserConfig& user_config, | ||
| 100 | u16 local_communication_version); | ||
| 101 | |||
| 102 | Network::IPv4Address GetLocalIp() const; | ||
| 103 | template <typename Data> | ||
| 104 | void SendPacket(Network::LDNPacketType type, const Data& data, Ipv4Address remote_ip); | ||
| 105 | void SendPacket(Network::LDNPacketType type, Ipv4Address remote_ip); | ||
| 106 | template <typename Data> | ||
| 107 | void SendBroadcast(Network::LDNPacketType type, const Data& data); | ||
| 108 | void SendBroadcast(Network::LDNPacketType type); | ||
| 109 | void SendPacket(const Network::LDNPacket& packet); | ||
| 110 | |||
| 111 | static const LanEventFunc empty_func; | ||
| 112 | const Ssid fake_ssid{"YuzuFakeSsidForLdn"}; | ||
| 113 | |||
| 114 | bool inited{}; | ||
| 115 | std::mutex packet_mutex; | ||
| 116 | std::array<LanStation, StationCountMax> stations; | ||
| 117 | std::array<NodeLatestUpdate, NodeCountMax> nodeChanges{}; | ||
| 118 | std::array<u8, NodeCountMax> node_last_states{}; | ||
| 119 | std::unordered_map<MacAddress, NetworkInfo, MACAddressHash> scan_results{}; | ||
| 120 | NodeInfo node_info{}; | ||
| 121 | NetworkInfo network_info{}; | ||
| 122 | State state{State::None}; | ||
| 123 | DisconnectReason disconnect_reason{DisconnectReason::None}; | ||
| 124 | |||
| 125 | // TODO (flTobi): Should this be an std::set? | ||
| 126 | std::vector<Ipv4Address> connected_clients; | ||
| 127 | std::optional<Ipv4Address> host_ip = std::nullopt; | ||
| 128 | |||
| 129 | LanEventFunc LanEvent; | ||
| 130 | |||
| 131 | Network::RoomNetwork& room_network; | ||
| 132 | }; | ||
| 133 | } // namespace Service::LDN | ||
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index c11daff54..6537f49cf 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp | |||
| @@ -4,11 +4,13 @@ | |||
| 4 | #include <memory> | 4 | #include <memory> |
| 5 | 5 | ||
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/service/ldn/lan_discovery.h" | ||
| 7 | #include "core/hle/service/ldn/ldn.h" | 8 | #include "core/hle/service/ldn/ldn.h" |
| 8 | #include "core/hle/service/ldn/ldn_results.h" | 9 | #include "core/hle/service/ldn/ldn_results.h" |
| 9 | #include "core/hle/service/ldn/ldn_types.h" | 10 | #include "core/hle/service/ldn/ldn_types.h" |
| 10 | #include "core/internal_network/network.h" | 11 | #include "core/internal_network/network.h" |
| 11 | #include "core/internal_network/network_interface.h" | 12 | #include "core/internal_network/network_interface.h" |
| 13 | #include "network/network.h" | ||
| 12 | 14 | ||
| 13 | // This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent | 15 | // This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent |
| 14 | #undef CreateEvent | 16 | #undef CreateEvent |
| @@ -105,13 +107,13 @@ class IUserLocalCommunicationService final | |||
| 105 | public: | 107 | public: |
| 106 | explicit IUserLocalCommunicationService(Core::System& system_) | 108 | explicit IUserLocalCommunicationService(Core::System& system_) |
| 107 | : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew}, | 109 | : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew}, |
| 108 | service_context{system, "IUserLocalCommunicationService"}, room_network{ | 110 | service_context{system, "IUserLocalCommunicationService"}, |
| 109 | system_.GetRoomNetwork()} { | 111 | room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} { |
| 110 | // clang-format off | 112 | // clang-format off |
| 111 | static const FunctionInfo functions[] = { | 113 | static const FunctionInfo functions[] = { |
| 112 | {0, &IUserLocalCommunicationService::GetState, "GetState"}, | 114 | {0, &IUserLocalCommunicationService::GetState, "GetState"}, |
| 113 | {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"}, | 115 | {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"}, |
| 114 | {2, nullptr, "GetIpv4Address"}, | 116 | {2, &IUserLocalCommunicationService::GetIpv4Address, "GetIpv4Address"}, |
| 115 | {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"}, | 117 | {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"}, |
| 116 | {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"}, | 118 | {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"}, |
| 117 | {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"}, | 119 | {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"}, |
| @@ -119,7 +121,7 @@ public: | |||
| 119 | {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"}, | 121 | {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"}, |
| 120 | {102, &IUserLocalCommunicationService::Scan, "Scan"}, | 122 | {102, &IUserLocalCommunicationService::Scan, "Scan"}, |
| 121 | {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"}, | 123 | {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"}, |
| 122 | {104, nullptr, "SetWirelessControllerRestriction"}, | 124 | {104, &IUserLocalCommunicationService::SetWirelessControllerRestriction, "SetWirelessControllerRestriction"}, |
| 123 | {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"}, | 125 | {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"}, |
| 124 | {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"}, | 126 | {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"}, |
| 125 | {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"}, | 127 | {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"}, |
| @@ -148,16 +150,30 @@ public: | |||
| 148 | } | 150 | } |
| 149 | 151 | ||
| 150 | ~IUserLocalCommunicationService() { | 152 | ~IUserLocalCommunicationService() { |
| 153 | if (is_initialized) { | ||
| 154 | if (auto room_member = room_network.GetRoomMember().lock()) { | ||
| 155 | room_member->Unbind(ldn_packet_received); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 151 | service_context.CloseEvent(state_change_event); | 159 | service_context.CloseEvent(state_change_event); |
| 152 | } | 160 | } |
| 153 | 161 | ||
| 162 | /// Callback to parse and handle a received LDN packet. | ||
| 163 | void OnLDNPacketReceived(const Network::LDNPacket& packet) { | ||
| 164 | lan_discovery.ReceivePacket(packet); | ||
| 165 | } | ||
| 166 | |||
| 154 | void OnEventFired() { | 167 | void OnEventFired() { |
| 155 | state_change_event->GetWritableEvent().Signal(); | 168 | state_change_event->GetWritableEvent().Signal(); |
| 156 | } | 169 | } |
| 157 | 170 | ||
| 158 | void GetState(Kernel::HLERequestContext& ctx) { | 171 | void GetState(Kernel::HLERequestContext& ctx) { |
| 159 | State state = State::Error; | 172 | State state = State::Error; |
| 160 | LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state); | 173 | |
| 174 | if (is_initialized) { | ||
| 175 | state = lan_discovery.GetState(); | ||
| 176 | } | ||
| 161 | 177 | ||
| 162 | IPC::ResponseBuilder rb{ctx, 3}; | 178 | IPC::ResponseBuilder rb{ctx, 3}; |
| 163 | rb.Push(ResultSuccess); | 179 | rb.Push(ResultSuccess); |
| @@ -175,7 +191,7 @@ public: | |||
| 175 | } | 191 | } |
| 176 | 192 | ||
| 177 | NetworkInfo network_info{}; | 193 | NetworkInfo network_info{}; |
| 178 | const auto rc = ResultSuccess; | 194 | const auto rc = lan_discovery.GetNetworkInfo(network_info); |
| 179 | if (rc.IsError()) { | 195 | if (rc.IsError()) { |
| 180 | LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); | 196 | LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); |
| 181 | IPC::ResponseBuilder rb{ctx, 2}; | 197 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -183,28 +199,52 @@ public: | |||
| 183 | return; | 199 | return; |
| 184 | } | 200 | } |
| 185 | 201 | ||
| 186 | LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}", | ||
| 187 | network_info.common.ssid.GetStringValue(), network_info.ldn.node_count); | ||
| 188 | |||
| 189 | ctx.WriteBuffer<NetworkInfo>(network_info); | 202 | ctx.WriteBuffer<NetworkInfo>(network_info); |
| 190 | IPC::ResponseBuilder rb{ctx, 2}; | 203 | IPC::ResponseBuilder rb{ctx, 2}; |
| 191 | rb.Push(rc); | 204 | rb.Push(ResultSuccess); |
| 192 | } | 205 | } |
| 193 | 206 | ||
| 194 | void GetDisconnectReason(Kernel::HLERequestContext& ctx) { | 207 | void GetIpv4Address(Kernel::HLERequestContext& ctx) { |
| 195 | const auto disconnect_reason = DisconnectReason::None; | 208 | LOG_CRITICAL(Service_LDN, "called"); |
| 196 | 209 | ||
| 197 | LOG_WARNING(Service_LDN, "(STUBBED) called, disconnect_reason={}", disconnect_reason); | 210 | const auto network_interface = Network::GetSelectedNetworkInterface(); |
| 211 | |||
| 212 | if (!network_interface) { | ||
| 213 | LOG_ERROR(Service_LDN, "No network interface available"); | ||
| 214 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 215 | rb.Push(ResultNoIpAddress); | ||
| 216 | return; | ||
| 217 | } | ||
| 218 | |||
| 219 | Ipv4Address current_address{Network::TranslateIPv4(network_interface->ip_address)}; | ||
| 220 | Ipv4Address subnet_mask{Network::TranslateIPv4(network_interface->subnet_mask)}; | ||
| 221 | |||
| 222 | // When we're connected to a room, spoof the hosts IP address | ||
| 223 | if (auto room_member = room_network.GetRoomMember().lock()) { | ||
| 224 | if (room_member->IsConnected()) { | ||
| 225 | current_address = room_member->GetFakeIpAddress(); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | std::reverse(std::begin(current_address), std::end(current_address)); // ntohl | ||
| 230 | std::reverse(std::begin(subnet_mask), std::end(subnet_mask)); // ntohl | ||
| 231 | |||
| 232 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 233 | rb.Push(ResultSuccess); | ||
| 234 | rb.PushRaw(current_address); | ||
| 235 | rb.PushRaw(subnet_mask); | ||
| 236 | } | ||
| 198 | 237 | ||
| 238 | void GetDisconnectReason(Kernel::HLERequestContext& ctx) { | ||
| 199 | IPC::ResponseBuilder rb{ctx, 3}; | 239 | IPC::ResponseBuilder rb{ctx, 3}; |
| 200 | rb.Push(ResultSuccess); | 240 | rb.Push(ResultSuccess); |
| 201 | rb.PushEnum(disconnect_reason); | 241 | rb.PushEnum(lan_discovery.GetDisconnectReason()); |
| 202 | } | 242 | } |
| 203 | 243 | ||
| 204 | void GetSecurityParameter(Kernel::HLERequestContext& ctx) { | 244 | void GetSecurityParameter(Kernel::HLERequestContext& ctx) { |
| 205 | SecurityParameter security_parameter{}; | 245 | SecurityParameter security_parameter{}; |
| 206 | NetworkInfo info{}; | 246 | NetworkInfo info{}; |
| 207 | const Result rc = ResultSuccess; | 247 | const Result rc = lan_discovery.GetNetworkInfo(info); |
| 208 | 248 | ||
| 209 | if (rc.IsError()) { | 249 | if (rc.IsError()) { |
| 210 | LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); | 250 | LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); |
| @@ -217,8 +257,6 @@ public: | |||
| 217 | std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(), | 257 | std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(), |
| 218 | sizeof(SecurityParameter::data)); | 258 | sizeof(SecurityParameter::data)); |
| 219 | 259 | ||
| 220 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 221 | |||
| 222 | IPC::ResponseBuilder rb{ctx, 10}; | 260 | IPC::ResponseBuilder rb{ctx, 10}; |
| 223 | rb.Push(rc); | 261 | rb.Push(rc); |
| 224 | rb.PushRaw<SecurityParameter>(security_parameter); | 262 | rb.PushRaw<SecurityParameter>(security_parameter); |
| @@ -227,7 +265,7 @@ public: | |||
| 227 | void GetNetworkConfig(Kernel::HLERequestContext& ctx) { | 265 | void GetNetworkConfig(Kernel::HLERequestContext& ctx) { |
| 228 | NetworkConfig config{}; | 266 | NetworkConfig config{}; |
| 229 | NetworkInfo info{}; | 267 | NetworkInfo info{}; |
| 230 | const Result rc = ResultSuccess; | 268 | const Result rc = lan_discovery.GetNetworkInfo(info); |
| 231 | 269 | ||
| 232 | if (rc.IsError()) { | 270 | if (rc.IsError()) { |
| 233 | LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw); | 271 | LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw); |
| @@ -241,12 +279,6 @@ public: | |||
| 241 | config.node_count_max = info.ldn.node_count_max; | 279 | config.node_count_max = info.ldn.node_count_max; |
| 242 | config.local_communication_version = info.ldn.nodes[0].local_communication_version; | 280 | config.local_communication_version = info.ldn.nodes[0].local_communication_version; |
| 243 | 281 | ||
| 244 | LOG_WARNING(Service_LDN, | ||
| 245 | "(STUBBED) called, intent_id={}/{}, channel={}, node_count_max={}, " | ||
| 246 | "local_communication_version={}", | ||
| 247 | config.intent_id.local_communication_id, config.intent_id.scene_id, | ||
| 248 | config.channel, config.node_count_max, config.local_communication_version); | ||
| 249 | |||
| 250 | IPC::ResponseBuilder rb{ctx, 10}; | 282 | IPC::ResponseBuilder rb{ctx, 10}; |
| 251 | rb.Push(rc); | 283 | rb.Push(rc); |
| 252 | rb.PushRaw<NetworkConfig>(config); | 284 | rb.PushRaw<NetworkConfig>(config); |
| @@ -265,17 +297,17 @@ public: | |||
| 265 | const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate); | 297 | const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate); |
| 266 | 298 | ||
| 267 | if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) { | 299 | if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) { |
| 268 | LOG_ERROR(Service_LDN, "Invalid buffer size {}, {}", network_buffer_size, | 300 | LOG_ERROR(Service_LDN, "Invalid buffer, size = {}, count = {}", network_buffer_size, |
| 269 | node_buffer_count); | 301 | node_buffer_count); |
| 270 | IPC::ResponseBuilder rb{ctx, 2}; | 302 | IPC::ResponseBuilder rb{ctx, 2}; |
| 271 | rb.Push(ResultBadInput); | 303 | rb.Push(ResultBadInput); |
| 272 | return; | 304 | return; |
| 273 | } | 305 | } |
| 274 | 306 | ||
| 275 | NetworkInfo info; | 307 | NetworkInfo info{}; |
| 276 | std::vector<NodeLatestUpdate> latest_update(node_buffer_count); | 308 | std::vector<NodeLatestUpdate> latest_update(node_buffer_count); |
| 277 | 309 | ||
| 278 | const auto rc = ResultSuccess; | 310 | const auto rc = lan_discovery.GetNetworkInfo(info, latest_update, latest_update.size()); |
| 279 | if (rc.IsError()) { | 311 | if (rc.IsError()) { |
| 280 | LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); | 312 | LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); |
| 281 | IPC::ResponseBuilder rb{ctx, 2}; | 313 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -283,9 +315,6 @@ public: | |||
| 283 | return; | 315 | return; |
| 284 | } | 316 | } |
| 285 | 317 | ||
| 286 | LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}", | ||
| 287 | info.common.ssid.GetStringValue(), info.ldn.node_count); | ||
| 288 | |||
| 289 | ctx.WriteBuffer(info, 0); | 318 | ctx.WriteBuffer(info, 0); |
| 290 | ctx.WriteBuffer(latest_update, 1); | 319 | ctx.WriteBuffer(latest_update, 1); |
| 291 | 320 | ||
| @@ -317,92 +346,78 @@ public: | |||
| 317 | 346 | ||
| 318 | u16 count = 0; | 347 | u16 count = 0; |
| 319 | std::vector<NetworkInfo> network_infos(network_info_size); | 348 | std::vector<NetworkInfo> network_infos(network_info_size); |
| 349 | Result rc = lan_discovery.Scan(network_infos, count, scan_filter); | ||
| 320 | 350 | ||
| 321 | LOG_WARNING(Service_LDN, | 351 | LOG_INFO(Service_LDN, |
| 322 | "(STUBBED) called, channel={}, filter_scan_flag={}, filter_network_type={}", | 352 | "called, channel={}, filter_scan_flag={}, filter_network_type={}, is_private={}", |
| 323 | channel, scan_filter.flag, scan_filter.network_type); | 353 | channel, scan_filter.flag, scan_filter.network_type, is_private); |
| 324 | 354 | ||
| 325 | ctx.WriteBuffer(network_infos); | 355 | ctx.WriteBuffer(network_infos); |
| 326 | 356 | ||
| 327 | IPC::ResponseBuilder rb{ctx, 3}; | 357 | IPC::ResponseBuilder rb{ctx, 3}; |
| 328 | rb.Push(ResultSuccess); | 358 | rb.Push(rc); |
| 329 | rb.Push<u32>(count); | 359 | rb.Push<u32>(count); |
| 330 | } | 360 | } |
| 331 | 361 | ||
| 332 | void OpenAccessPoint(Kernel::HLERequestContext& ctx) { | 362 | void SetWirelessControllerRestriction(Kernel::HLERequestContext& ctx) { |
| 333 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | 363 | LOG_WARNING(Service_LDN, "(STUBBED) called"); |
| 334 | 364 | ||
| 335 | IPC::ResponseBuilder rb{ctx, 2}; | 365 | IPC::ResponseBuilder rb{ctx, 2}; |
| 336 | rb.Push(ResultSuccess); | 366 | rb.Push(ResultSuccess); |
| 337 | } | 367 | } |
| 338 | 368 | ||
| 369 | void OpenAccessPoint(Kernel::HLERequestContext& ctx) { | ||
| 370 | LOG_INFO(Service_LDN, "called"); | ||
| 371 | |||
| 372 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 373 | rb.Push(lan_discovery.OpenAccessPoint()); | ||
| 374 | } | ||
| 375 | |||
| 339 | void CloseAccessPoint(Kernel::HLERequestContext& ctx) { | 376 | void CloseAccessPoint(Kernel::HLERequestContext& ctx) { |
| 340 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | 377 | LOG_INFO(Service_LDN, "called"); |
| 341 | 378 | ||
| 342 | IPC::ResponseBuilder rb{ctx, 2}; | 379 | IPC::ResponseBuilder rb{ctx, 2}; |
| 343 | rb.Push(ResultSuccess); | 380 | rb.Push(lan_discovery.CloseAccessPoint()); |
| 344 | } | 381 | } |
| 345 | 382 | ||
| 346 | void CreateNetwork(Kernel::HLERequestContext& ctx) { | 383 | void CreateNetwork(Kernel::HLERequestContext& ctx) { |
| 347 | IPC::RequestParser rp{ctx}; | 384 | LOG_INFO(Service_LDN, "called"); |
| 348 | struct Parameters { | ||
| 349 | SecurityConfig security_config; | ||
| 350 | UserConfig user_config; | ||
| 351 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 352 | NetworkConfig network_config; | ||
| 353 | }; | ||
| 354 | static_assert(sizeof(Parameters) == 0x98, "Parameters has incorrect size."); | ||
| 355 | 385 | ||
| 356 | const auto parameters{rp.PopRaw<Parameters>()}; | 386 | CreateNetworkImpl(ctx); |
| 387 | } | ||
| 357 | 388 | ||
| 358 | LOG_WARNING(Service_LDN, | 389 | void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) { |
| 359 | "(STUBBED) called, passphrase_size={}, security_mode={}, " | 390 | LOG_INFO(Service_LDN, "called"); |
| 360 | "local_communication_version={}", | ||
| 361 | parameters.security_config.passphrase_size, | ||
| 362 | parameters.security_config.security_mode, | ||
| 363 | parameters.network_config.local_communication_version); | ||
| 364 | 391 | ||
| 365 | IPC::ResponseBuilder rb{ctx, 2}; | 392 | CreateNetworkImpl(ctx, true); |
| 366 | rb.Push(ResultSuccess); | ||
| 367 | } | 393 | } |
| 368 | 394 | ||
| 369 | void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) { | 395 | void CreateNetworkImpl(Kernel::HLERequestContext& ctx, bool is_private = false) { |
| 370 | IPC::RequestParser rp{ctx}; | 396 | IPC::RequestParser rp{ctx}; |
| 371 | struct Parameters { | ||
| 372 | SecurityConfig security_config; | ||
| 373 | SecurityParameter security_parameter; | ||
| 374 | UserConfig user_config; | ||
| 375 | NetworkConfig network_config; | ||
| 376 | }; | ||
| 377 | static_assert(sizeof(Parameters) == 0xB8, "Parameters has incorrect size."); | ||
| 378 | |||
| 379 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 380 | 397 | ||
| 381 | LOG_WARNING(Service_LDN, | 398 | const auto security_config{rp.PopRaw<SecurityConfig>()}; |
| 382 | "(STUBBED) called, passphrase_size={}, security_mode={}, " | 399 | [[maybe_unused]] const auto security_parameter{is_private ? rp.PopRaw<SecurityParameter>() |
| 383 | "local_communication_version={}", | 400 | : SecurityParameter{}}; |
| 384 | parameters.security_config.passphrase_size, | 401 | const auto user_config{rp.PopRaw<UserConfig>()}; |
| 385 | parameters.security_config.security_mode, | 402 | rp.Pop<u32>(); // Padding |
| 386 | parameters.network_config.local_communication_version); | 403 | const auto network_Config{rp.PopRaw<NetworkConfig>()}; |
| 387 | 404 | ||
| 388 | IPC::ResponseBuilder rb{ctx, 2}; | 405 | IPC::ResponseBuilder rb{ctx, 2}; |
| 389 | rb.Push(ResultSuccess); | 406 | rb.Push(lan_discovery.CreateNetwork(security_config, user_config, network_Config)); |
| 390 | } | 407 | } |
| 391 | 408 | ||
| 392 | void DestroyNetwork(Kernel::HLERequestContext& ctx) { | 409 | void DestroyNetwork(Kernel::HLERequestContext& ctx) { |
| 393 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | 410 | LOG_INFO(Service_LDN, "called"); |
| 394 | 411 | ||
| 395 | IPC::ResponseBuilder rb{ctx, 2}; | 412 | IPC::ResponseBuilder rb{ctx, 2}; |
| 396 | rb.Push(ResultSuccess); | 413 | rb.Push(lan_discovery.DestroyNetwork()); |
| 397 | } | 414 | } |
| 398 | 415 | ||
| 399 | void SetAdvertiseData(Kernel::HLERequestContext& ctx) { | 416 | void SetAdvertiseData(Kernel::HLERequestContext& ctx) { |
| 400 | std::vector<u8> read_buffer = ctx.ReadBuffer(); | 417 | std::vector<u8> read_buffer = ctx.ReadBuffer(); |
| 401 | 418 | ||
| 402 | LOG_WARNING(Service_LDN, "(STUBBED) called, size {}", read_buffer.size()); | ||
| 403 | |||
| 404 | IPC::ResponseBuilder rb{ctx, 2}; | 419 | IPC::ResponseBuilder rb{ctx, 2}; |
| 405 | rb.Push(ResultSuccess); | 420 | rb.Push(lan_discovery.SetAdvertiseData(read_buffer)); |
| 406 | } | 421 | } |
| 407 | 422 | ||
| 408 | void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) { | 423 | void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) { |
| @@ -420,17 +435,17 @@ public: | |||
| 420 | } | 435 | } |
| 421 | 436 | ||
| 422 | void OpenStation(Kernel::HLERequestContext& ctx) { | 437 | void OpenStation(Kernel::HLERequestContext& ctx) { |
| 423 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | 438 | LOG_INFO(Service_LDN, "called"); |
| 424 | 439 | ||
| 425 | IPC::ResponseBuilder rb{ctx, 2}; | 440 | IPC::ResponseBuilder rb{ctx, 2}; |
| 426 | rb.Push(ResultSuccess); | 441 | rb.Push(lan_discovery.OpenStation()); |
| 427 | } | 442 | } |
| 428 | 443 | ||
| 429 | void CloseStation(Kernel::HLERequestContext& ctx) { | 444 | void CloseStation(Kernel::HLERequestContext& ctx) { |
| 430 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | 445 | LOG_INFO(Service_LDN, "called"); |
| 431 | 446 | ||
| 432 | IPC::ResponseBuilder rb{ctx, 2}; | 447 | IPC::ResponseBuilder rb{ctx, 2}; |
| 433 | rb.Push(ResultSuccess); | 448 | rb.Push(lan_discovery.CloseStation()); |
| 434 | } | 449 | } |
| 435 | 450 | ||
| 436 | void Connect(Kernel::HLERequestContext& ctx) { | 451 | void Connect(Kernel::HLERequestContext& ctx) { |
| @@ -445,16 +460,13 @@ public: | |||
| 445 | 460 | ||
| 446 | const auto parameters{rp.PopRaw<Parameters>()}; | 461 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 447 | 462 | ||
| 448 | LOG_WARNING(Service_LDN, | 463 | LOG_INFO(Service_LDN, |
| 449 | "(STUBBED) called, passphrase_size={}, security_mode={}, " | 464 | "called, passphrase_size={}, security_mode={}, " |
| 450 | "local_communication_version={}", | 465 | "local_communication_version={}", |
| 451 | parameters.security_config.passphrase_size, | 466 | parameters.security_config.passphrase_size, |
| 452 | parameters.security_config.security_mode, | 467 | parameters.security_config.security_mode, parameters.local_communication_version); |
| 453 | parameters.local_communication_version); | ||
| 454 | 468 | ||
| 455 | const std::vector<u8> read_buffer = ctx.ReadBuffer(); | 469 | const std::vector<u8> read_buffer = ctx.ReadBuffer(); |
| 456 | NetworkInfo network_info{}; | ||
| 457 | |||
| 458 | if (read_buffer.size() != sizeof(NetworkInfo)) { | 470 | if (read_buffer.size() != sizeof(NetworkInfo)) { |
| 459 | LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!"); | 471 | LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!"); |
| 460 | IPC::ResponseBuilder rb{ctx, 2}; | 472 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -462,40 +474,47 @@ public: | |||
| 462 | return; | 474 | return; |
| 463 | } | 475 | } |
| 464 | 476 | ||
| 477 | NetworkInfo network_info{}; | ||
| 465 | std::memcpy(&network_info, read_buffer.data(), read_buffer.size()); | 478 | std::memcpy(&network_info, read_buffer.data(), read_buffer.size()); |
| 466 | 479 | ||
| 467 | IPC::ResponseBuilder rb{ctx, 2}; | 480 | IPC::ResponseBuilder rb{ctx, 2}; |
| 468 | rb.Push(ResultSuccess); | 481 | rb.Push(lan_discovery.Connect(network_info, parameters.user_config, |
| 482 | static_cast<u16>(parameters.local_communication_version))); | ||
| 469 | } | 483 | } |
| 470 | 484 | ||
| 471 | void Disconnect(Kernel::HLERequestContext& ctx) { | 485 | void Disconnect(Kernel::HLERequestContext& ctx) { |
| 472 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | 486 | LOG_INFO(Service_LDN, "called"); |
| 473 | 487 | ||
| 474 | IPC::ResponseBuilder rb{ctx, 2}; | 488 | IPC::ResponseBuilder rb{ctx, 2}; |
| 475 | rb.Push(ResultSuccess); | 489 | rb.Push(lan_discovery.Disconnect()); |
| 476 | } | 490 | } |
| 477 | void Initialize(Kernel::HLERequestContext& ctx) { | ||
| 478 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 479 | 491 | ||
| 492 | void Initialize(Kernel::HLERequestContext& ctx) { | ||
| 480 | const auto rc = InitializeImpl(ctx); | 493 | const auto rc = InitializeImpl(ctx); |
| 494 | if (rc.IsError()) { | ||
| 495 | LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw); | ||
| 496 | } | ||
| 481 | 497 | ||
| 482 | IPC::ResponseBuilder rb{ctx, 2}; | 498 | IPC::ResponseBuilder rb{ctx, 2}; |
| 483 | rb.Push(rc); | 499 | rb.Push(rc); |
| 484 | } | 500 | } |
| 485 | 501 | ||
| 486 | void Finalize(Kernel::HLERequestContext& ctx) { | 502 | void Finalize(Kernel::HLERequestContext& ctx) { |
| 487 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | 503 | if (auto room_member = room_network.GetRoomMember().lock()) { |
| 504 | room_member->Unbind(ldn_packet_received); | ||
| 505 | } | ||
| 488 | 506 | ||
| 489 | is_initialized = false; | 507 | is_initialized = false; |
| 490 | 508 | ||
| 491 | IPC::ResponseBuilder rb{ctx, 2}; | 509 | IPC::ResponseBuilder rb{ctx, 2}; |
| 492 | rb.Push(ResultSuccess); | 510 | rb.Push(lan_discovery.Finalize()); |
| 493 | } | 511 | } |
| 494 | 512 | ||
| 495 | void Initialize2(Kernel::HLERequestContext& ctx) { | 513 | void Initialize2(Kernel::HLERequestContext& ctx) { |
| 496 | LOG_WARNING(Service_LDN, "(STUBBED) called"); | ||
| 497 | |||
| 498 | const auto rc = InitializeImpl(ctx); | 514 | const auto rc = InitializeImpl(ctx); |
| 515 | if (rc.IsError()) { | ||
| 516 | LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw); | ||
| 517 | } | ||
| 499 | 518 | ||
| 500 | IPC::ResponseBuilder rb{ctx, 2}; | 519 | IPC::ResponseBuilder rb{ctx, 2}; |
| 501 | rb.Push(rc); | 520 | rb.Push(rc); |
| @@ -508,14 +527,26 @@ public: | |||
| 508 | return ResultAirplaneModeEnabled; | 527 | return ResultAirplaneModeEnabled; |
| 509 | } | 528 | } |
| 510 | 529 | ||
| 530 | if (auto room_member = room_network.GetRoomMember().lock()) { | ||
| 531 | ldn_packet_received = room_member->BindOnLdnPacketReceived( | ||
| 532 | [this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); }); | ||
| 533 | } else { | ||
| 534 | LOG_ERROR(Service_LDN, "Couldn't bind callback!"); | ||
| 535 | return ResultAirplaneModeEnabled; | ||
| 536 | } | ||
| 537 | |||
| 538 | lan_discovery.Initialize([&]() { OnEventFired(); }); | ||
| 511 | is_initialized = true; | 539 | is_initialized = true; |
| 512 | // TODO (flTobi): Change this to ResultSuccess when LDN is fully implemented | 540 | return ResultSuccess; |
| 513 | return ResultAirplaneModeEnabled; | ||
| 514 | } | 541 | } |
| 515 | 542 | ||
| 516 | KernelHelpers::ServiceContext service_context; | 543 | KernelHelpers::ServiceContext service_context; |
| 517 | Kernel::KEvent* state_change_event; | 544 | Kernel::KEvent* state_change_event; |
| 518 | Network::RoomNetwork& room_network; | 545 | Network::RoomNetwork& room_network; |
| 546 | LANDiscovery lan_discovery; | ||
| 547 | |||
| 548 | // Callback identifier for the OnLDNPacketReceived event. | ||
| 549 | Network::RoomMember::CallbackHandle<Network::LDNPacket> ldn_packet_received; | ||
| 519 | 550 | ||
| 520 | bool is_initialized{}; | 551 | bool is_initialized{}; |
| 521 | }; | 552 | }; |
diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h index 6231e936d..d6609fff5 100644 --- a/src/core/hle/service/ldn/ldn_types.h +++ b/src/core/hle/service/ldn/ldn_types.h | |||
| @@ -31,6 +31,14 @@ enum class NodeStateChange : u8 { | |||
| 31 | DisconnectAndConnect, | 31 | DisconnectAndConnect, |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | inline NodeStateChange operator|(NodeStateChange a, NodeStateChange b) { | ||
| 35 | return static_cast<NodeStateChange>(static_cast<u8>(a) | static_cast<u8>(b)); | ||
| 36 | } | ||
| 37 | |||
| 38 | inline NodeStateChange operator|=(NodeStateChange& a, NodeStateChange b) { | ||
| 39 | return a = a | b; | ||
| 40 | } | ||
| 41 | |||
| 34 | enum class ScanFilterFlag : u32 { | 42 | enum class ScanFilterFlag : u32 { |
| 35 | None = 0, | 43 | None = 0, |
| 36 | LocalCommunicationId = 1 << 0, | 44 | LocalCommunicationId = 1 << 0, |
| @@ -100,13 +108,13 @@ enum class AcceptPolicy : u8 { | |||
| 100 | 108 | ||
| 101 | enum class WifiChannel : s16 { | 109 | enum class WifiChannel : s16 { |
| 102 | Default = 0, | 110 | Default = 0, |
| 103 | wifi24_1 = 1, | 111 | Wifi24_1 = 1, |
| 104 | wifi24_6 = 6, | 112 | Wifi24_6 = 6, |
| 105 | wifi24_11 = 11, | 113 | Wifi24_11 = 11, |
| 106 | wifi50_36 = 36, | 114 | Wifi50_36 = 36, |
| 107 | wifi50_40 = 40, | 115 | Wifi50_40 = 40, |
| 108 | wifi50_44 = 44, | 116 | Wifi50_44 = 44, |
| 109 | wifi50_48 = 48, | 117 | Wifi50_48 = 48, |
| 110 | }; | 118 | }; |
| 111 | 119 | ||
| 112 | enum class LinkLevel : s8 { | 120 | enum class LinkLevel : s8 { |
| @@ -116,6 +124,11 @@ enum class LinkLevel : s8 { | |||
| 116 | Excellent, | 124 | Excellent, |
| 117 | }; | 125 | }; |
| 118 | 126 | ||
| 127 | enum class NodeStatus : u8 { | ||
| 128 | Disconnected, | ||
| 129 | Connected, | ||
| 130 | }; | ||
| 131 | |||
| 119 | struct NodeLatestUpdate { | 132 | struct NodeLatestUpdate { |
| 120 | NodeStateChange state_change; | 133 | NodeStateChange state_change; |
| 121 | INSERT_PADDING_BYTES(0x7); // Unknown | 134 | INSERT_PADDING_BYTES(0x7); // Unknown |
| @@ -159,19 +172,14 @@ struct Ssid { | |||
| 159 | std::string GetStringValue() const { | 172 | std::string GetStringValue() const { |
| 160 | return std::string(raw.data()); | 173 | return std::string(raw.data()); |
| 161 | } | 174 | } |
| 162 | }; | ||
| 163 | static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); | ||
| 164 | |||
| 165 | struct Ipv4Address { | ||
| 166 | union { | ||
| 167 | u32 raw{}; | ||
| 168 | std::array<u8, 4> bytes; | ||
| 169 | }; | ||
| 170 | 175 | ||
| 171 | std::string GetStringValue() const { | 176 | bool operator==(const Ssid& b) const { |
| 172 | return fmt::format("{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]); | 177 | return (length == b.length) && (std::memcmp(raw.data(), b.raw.data(), length) == 0); |
| 173 | } | 178 | } |
| 174 | }; | 179 | }; |
| 180 | static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); | ||
| 181 | |||
| 182 | using Ipv4Address = std::array<u8, 4>; | ||
| 175 | static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size"); | 183 | static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size"); |
| 176 | 184 | ||
| 177 | struct MacAddress { | 185 | struct MacAddress { |
| @@ -181,6 +189,14 @@ struct MacAddress { | |||
| 181 | }; | 189 | }; |
| 182 | static_assert(sizeof(MacAddress) == 0x6, "MacAddress is an invalid size"); | 190 | static_assert(sizeof(MacAddress) == 0x6, "MacAddress is an invalid size"); |
| 183 | 191 | ||
| 192 | struct MACAddressHash { | ||
| 193 | size_t operator()(const MacAddress& address) const { | ||
| 194 | u64 value{}; | ||
| 195 | std::memcpy(&value, address.raw.data(), sizeof(address.raw)); | ||
| 196 | return value; | ||
| 197 | } | ||
| 198 | }; | ||
| 199 | |||
| 184 | struct ScanFilter { | 200 | struct ScanFilter { |
| 185 | NetworkId network_id; | 201 | NetworkId network_id; |
| 186 | NetworkType network_type; | 202 | NetworkType network_type; |
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp index 0c746bd82..7d5d37bbc 100644 --- a/src/core/internal_network/socket_proxy.cpp +++ b/src/core/internal_network/socket_proxy.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/zstd_compression.h" | ||
| 9 | #include "core/internal_network/network.h" | 10 | #include "core/internal_network/network.h" |
| 10 | #include "core/internal_network/network_interface.h" | 11 | #include "core/internal_network/network_interface.h" |
| 11 | #include "core/internal_network/socket_proxy.h" | 12 | #include "core/internal_network/socket_proxy.h" |
| @@ -32,8 +33,11 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) { | |||
| 32 | return; | 33 | return; |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 36 | auto decompressed = packet; | ||
| 37 | decompressed.data = Common::Compression::DecompressDataZSTD(packet.data); | ||
| 38 | |||
| 35 | std::lock_guard guard(packets_mutex); | 39 | std::lock_guard guard(packets_mutex); |
| 36 | received_packets.push(packet); | 40 | received_packets.push(decompressed); |
| 37 | } | 41 | } |
| 38 | 42 | ||
| 39 | template <typename T> | 43 | template <typename T> |
| @@ -185,6 +189,8 @@ std::pair<s32, Errno> ProxySocket::Send(const std::vector<u8>& message, int flag | |||
| 185 | void ProxySocket::SendPacket(ProxyPacket& packet) { | 189 | void ProxySocket::SendPacket(ProxyPacket& packet) { |
| 186 | if (auto room_member = room_network.GetRoomMember().lock()) { | 190 | if (auto room_member = room_network.GetRoomMember().lock()) { |
| 187 | if (room_member->IsConnected()) { | 191 | if (room_member->IsConnected()) { |
| 192 | packet.data = Common::Compression::CompressDataZSTDDefault(packet.data.data(), | ||
| 193 | packet.data.size()); | ||
| 188 | room_member->SendProxyPacket(packet); | 194 | room_member->SendProxyPacket(packet); |
| 189 | } | 195 | } |
| 190 | } | 196 | } |
diff --git a/src/dedicated_room/yuzu_room.cpp b/src/dedicated_room/yuzu_room.cpp index 7b6deba41..8d8ac1ed7 100644 --- a/src/dedicated_room/yuzu_room.cpp +++ b/src/dedicated_room/yuzu_room.cpp | |||
| @@ -76,7 +76,8 @@ static constexpr char BanListMagic[] = "YuzuRoom-BanList-1"; | |||
| 76 | static constexpr char token_delimiter{':'}; | 76 | static constexpr char token_delimiter{':'}; |
| 77 | 77 | ||
| 78 | static void PadToken(std::string& token) { | 78 | static void PadToken(std::string& token) { |
| 79 | while (token.size() % 4 != 0) { | 79 | const auto remainder = token.size() % 3; |
| 80 | for (size_t i = 0; i < (3 - remainder); i++) { | ||
| 80 | token.push_back('='); | 81 | token.push_back('='); |
| 81 | } | 82 | } |
| 82 | } | 83 | } |
diff --git a/src/network/room.cpp b/src/network/room.cpp index 8c63b255b..dc5dbce7f 100644 --- a/src/network/room.cpp +++ b/src/network/room.cpp | |||
| @@ -212,6 +212,12 @@ public: | |||
| 212 | void HandleProxyPacket(const ENetEvent* event); | 212 | void HandleProxyPacket(const ENetEvent* event); |
| 213 | 213 | ||
| 214 | /** | 214 | /** |
| 215 | * Broadcasts this packet to all members except the sender. | ||
| 216 | * @param event The ENet event containing the data | ||
| 217 | */ | ||
| 218 | void HandleLdnPacket(const ENetEvent* event); | ||
| 219 | |||
| 220 | /** | ||
| 215 | * Extracts a chat entry from a received ENet packet and adds it to the chat queue. | 221 | * Extracts a chat entry from a received ENet packet and adds it to the chat queue. |
| 216 | * @param event The ENet event that was received. | 222 | * @param event The ENet event that was received. |
| 217 | */ | 223 | */ |
| @@ -247,6 +253,9 @@ void Room::RoomImpl::ServerLoop() { | |||
| 247 | case IdProxyPacket: | 253 | case IdProxyPacket: |
| 248 | HandleProxyPacket(&event); | 254 | HandleProxyPacket(&event); |
| 249 | break; | 255 | break; |
| 256 | case IdLdnPacket: | ||
| 257 | HandleLdnPacket(&event); | ||
| 258 | break; | ||
| 250 | case IdChatMessage: | 259 | case IdChatMessage: |
| 251 | HandleChatPacket(&event); | 260 | HandleChatPacket(&event); |
| 252 | break; | 261 | break; |
| @@ -861,6 +870,60 @@ void Room::RoomImpl::HandleProxyPacket(const ENetEvent* event) { | |||
| 861 | enet_host_flush(server); | 870 | enet_host_flush(server); |
| 862 | } | 871 | } |
| 863 | 872 | ||
| 873 | void Room::RoomImpl::HandleLdnPacket(const ENetEvent* event) { | ||
| 874 | Packet in_packet; | ||
| 875 | in_packet.Append(event->packet->data, event->packet->dataLength); | ||
| 876 | |||
| 877 | in_packet.IgnoreBytes(sizeof(u8)); // Message type | ||
| 878 | |||
| 879 | in_packet.IgnoreBytes(sizeof(u8)); // LAN packet type | ||
| 880 | in_packet.IgnoreBytes(sizeof(IPv4Address)); // Local IP | ||
| 881 | |||
| 882 | IPv4Address remote_ip; | ||
| 883 | in_packet.Read(remote_ip); // Remote IP | ||
| 884 | |||
| 885 | bool broadcast; | ||
| 886 | in_packet.Read(broadcast); // Broadcast | ||
| 887 | |||
| 888 | Packet out_packet; | ||
| 889 | out_packet.Append(event->packet->data, event->packet->dataLength); | ||
| 890 | ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(), | ||
| 891 | ENET_PACKET_FLAG_RELIABLE); | ||
| 892 | |||
| 893 | const auto& destination_address = remote_ip; | ||
| 894 | if (broadcast) { // Send the data to everyone except the sender | ||
| 895 | std::lock_guard lock(member_mutex); | ||
| 896 | bool sent_packet = false; | ||
| 897 | for (const auto& member : members) { | ||
| 898 | if (member.peer != event->peer) { | ||
| 899 | sent_packet = true; | ||
| 900 | enet_peer_send(member.peer, 0, enet_packet); | ||
| 901 | } | ||
| 902 | } | ||
| 903 | |||
| 904 | if (!sent_packet) { | ||
| 905 | enet_packet_destroy(enet_packet); | ||
| 906 | } | ||
| 907 | } else { | ||
| 908 | std::lock_guard lock(member_mutex); | ||
| 909 | auto member = std::find_if(members.begin(), members.end(), | ||
| 910 | [destination_address](const Member& member_entry) -> bool { | ||
| 911 | return member_entry.fake_ip == destination_address; | ||
| 912 | }); | ||
| 913 | if (member != members.end()) { | ||
| 914 | enet_peer_send(member->peer, 0, enet_packet); | ||
| 915 | } else { | ||
| 916 | LOG_ERROR(Network, | ||
| 917 | "Attempting to send to unknown IP address: " | ||
| 918 | "{}.{}.{}.{}", | ||
| 919 | destination_address[0], destination_address[1], destination_address[2], | ||
| 920 | destination_address[3]); | ||
| 921 | enet_packet_destroy(enet_packet); | ||
| 922 | } | ||
| 923 | } | ||
| 924 | enet_host_flush(server); | ||
| 925 | } | ||
| 926 | |||
| 864 | void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { | 927 | void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { |
| 865 | Packet in_packet; | 928 | Packet in_packet; |
| 866 | in_packet.Append(event->packet->data, event->packet->dataLength); | 929 | in_packet.Append(event->packet->data, event->packet->dataLength); |
diff --git a/src/network/room.h b/src/network/room.h index c2a4b1a70..edbd3ecfb 100644 --- a/src/network/room.h +++ b/src/network/room.h | |||
| @@ -40,6 +40,7 @@ enum RoomMessageTypes : u8 { | |||
| 40 | IdRoomInformation, | 40 | IdRoomInformation, |
| 41 | IdSetGameInfo, | 41 | IdSetGameInfo, |
| 42 | IdProxyPacket, | 42 | IdProxyPacket, |
| 43 | IdLdnPacket, | ||
| 43 | IdChatMessage, | 44 | IdChatMessage, |
| 44 | IdNameCollision, | 45 | IdNameCollision, |
| 45 | IdIpCollision, | 46 | IdIpCollision, |
diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp index 06818af78..572e55a5b 100644 --- a/src/network/room_member.cpp +++ b/src/network/room_member.cpp | |||
| @@ -58,6 +58,7 @@ public: | |||
| 58 | 58 | ||
| 59 | private: | 59 | private: |
| 60 | CallbackSet<ProxyPacket> callback_set_proxy_packet; | 60 | CallbackSet<ProxyPacket> callback_set_proxy_packet; |
| 61 | CallbackSet<LDNPacket> callback_set_ldn_packet; | ||
| 61 | CallbackSet<ChatEntry> callback_set_chat_messages; | 62 | CallbackSet<ChatEntry> callback_set_chat_messages; |
| 62 | CallbackSet<StatusMessageEntry> callback_set_status_messages; | 63 | CallbackSet<StatusMessageEntry> callback_set_status_messages; |
| 63 | CallbackSet<RoomInformation> callback_set_room_information; | 64 | CallbackSet<RoomInformation> callback_set_room_information; |
| @@ -108,6 +109,12 @@ public: | |||
| 108 | void HandleProxyPackets(const ENetEvent* event); | 109 | void HandleProxyPackets(const ENetEvent* event); |
| 109 | 110 | ||
| 110 | /** | 111 | /** |
| 112 | * Extracts an LdnPacket from a received ENet packet. | ||
| 113 | * @param event The ENet event that was received. | ||
| 114 | */ | ||
| 115 | void HandleLdnPackets(const ENetEvent* event); | ||
| 116 | |||
| 117 | /** | ||
| 111 | * Extracts a chat entry from a received ENet packet and adds it to the chat queue. | 118 | * Extracts a chat entry from a received ENet packet and adds it to the chat queue. |
| 112 | * @param event The ENet event that was received. | 119 | * @param event The ENet event that was received. |
| 113 | */ | 120 | */ |
| @@ -166,6 +173,9 @@ void RoomMember::RoomMemberImpl::MemberLoop() { | |||
| 166 | case IdProxyPacket: | 173 | case IdProxyPacket: |
| 167 | HandleProxyPackets(&event); | 174 | HandleProxyPackets(&event); |
| 168 | break; | 175 | break; |
| 176 | case IdLdnPacket: | ||
| 177 | HandleLdnPackets(&event); | ||
| 178 | break; | ||
| 169 | case IdChatMessage: | 179 | case IdChatMessage: |
| 170 | HandleChatPacket(&event); | 180 | HandleChatPacket(&event); |
| 171 | break; | 181 | break; |
| @@ -372,6 +382,27 @@ void RoomMember::RoomMemberImpl::HandleProxyPackets(const ENetEvent* event) { | |||
| 372 | Invoke<ProxyPacket>(proxy_packet); | 382 | Invoke<ProxyPacket>(proxy_packet); |
| 373 | } | 383 | } |
| 374 | 384 | ||
| 385 | void RoomMember::RoomMemberImpl::HandleLdnPackets(const ENetEvent* event) { | ||
| 386 | LDNPacket ldn_packet{}; | ||
| 387 | Packet packet; | ||
| 388 | packet.Append(event->packet->data, event->packet->dataLength); | ||
| 389 | |||
| 390 | // Ignore the first byte, which is the message id. | ||
| 391 | packet.IgnoreBytes(sizeof(u8)); // Ignore the message type | ||
| 392 | |||
| 393 | u8 packet_type; | ||
| 394 | packet.Read(packet_type); | ||
| 395 | ldn_packet.type = static_cast<LDNPacketType>(packet_type); | ||
| 396 | |||
| 397 | packet.Read(ldn_packet.local_ip); | ||
| 398 | packet.Read(ldn_packet.remote_ip); | ||
| 399 | packet.Read(ldn_packet.broadcast); | ||
| 400 | |||
| 401 | packet.Read(ldn_packet.data); | ||
| 402 | |||
| 403 | Invoke<LDNPacket>(ldn_packet); | ||
| 404 | } | ||
| 405 | |||
| 375 | void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { | 406 | void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { |
| 376 | Packet packet; | 407 | Packet packet; |
| 377 | packet.Append(event->packet->data, event->packet->dataLength); | 408 | packet.Append(event->packet->data, event->packet->dataLength); |
| @@ -450,6 +481,11 @@ RoomMember::RoomMemberImpl::CallbackSet<ProxyPacket>& RoomMember::RoomMemberImpl | |||
| 450 | } | 481 | } |
| 451 | 482 | ||
| 452 | template <> | 483 | template <> |
| 484 | RoomMember::RoomMemberImpl::CallbackSet<LDNPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() { | ||
| 485 | return callback_set_ldn_packet; | ||
| 486 | } | ||
| 487 | |||
| 488 | template <> | ||
| 453 | RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>& | 489 | RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>& |
| 454 | RoomMember::RoomMemberImpl::Callbacks::Get() { | 490 | RoomMember::RoomMemberImpl::Callbacks::Get() { |
| 455 | return callback_set_state; | 491 | return callback_set_state; |
| @@ -607,6 +643,21 @@ void RoomMember::SendProxyPacket(const ProxyPacket& proxy_packet) { | |||
| 607 | room_member_impl->Send(std::move(packet)); | 643 | room_member_impl->Send(std::move(packet)); |
| 608 | } | 644 | } |
| 609 | 645 | ||
| 646 | void RoomMember::SendLdnPacket(const LDNPacket& ldn_packet) { | ||
| 647 | Packet packet; | ||
| 648 | packet.Write(static_cast<u8>(IdLdnPacket)); | ||
| 649 | |||
| 650 | packet.Write(static_cast<u8>(ldn_packet.type)); | ||
| 651 | |||
| 652 | packet.Write(ldn_packet.local_ip); | ||
| 653 | packet.Write(ldn_packet.remote_ip); | ||
| 654 | packet.Write(ldn_packet.broadcast); | ||
| 655 | |||
| 656 | packet.Write(ldn_packet.data); | ||
| 657 | |||
| 658 | room_member_impl->Send(std::move(packet)); | ||
| 659 | } | ||
| 660 | |||
| 610 | void RoomMember::SendChatMessage(const std::string& message) { | 661 | void RoomMember::SendChatMessage(const std::string& message) { |
| 611 | Packet packet; | 662 | Packet packet; |
| 612 | packet.Write(static_cast<u8>(IdChatMessage)); | 663 | packet.Write(static_cast<u8>(IdChatMessage)); |
| @@ -663,6 +714,11 @@ RoomMember::CallbackHandle<ProxyPacket> RoomMember::BindOnProxyPacketReceived( | |||
| 663 | return room_member_impl->Bind(callback); | 714 | return room_member_impl->Bind(callback); |
| 664 | } | 715 | } |
| 665 | 716 | ||
| 717 | RoomMember::CallbackHandle<LDNPacket> RoomMember::BindOnLdnPacketReceived( | ||
| 718 | std::function<void(const LDNPacket&)> callback) { | ||
| 719 | return room_member_impl->Bind(callback); | ||
| 720 | } | ||
| 721 | |||
| 666 | RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged( | 722 | RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged( |
| 667 | std::function<void(const RoomInformation&)> callback) { | 723 | std::function<void(const RoomInformation&)> callback) { |
| 668 | return room_member_impl->Bind(callback); | 724 | return room_member_impl->Bind(callback); |
| @@ -699,6 +755,7 @@ void RoomMember::Leave() { | |||
| 699 | } | 755 | } |
| 700 | 756 | ||
| 701 | template void RoomMember::Unbind(CallbackHandle<ProxyPacket>); | 757 | template void RoomMember::Unbind(CallbackHandle<ProxyPacket>); |
| 758 | template void RoomMember::Unbind(CallbackHandle<LDNPacket>); | ||
| 702 | template void RoomMember::Unbind(CallbackHandle<RoomMember::State>); | 759 | template void RoomMember::Unbind(CallbackHandle<RoomMember::State>); |
| 703 | template void RoomMember::Unbind(CallbackHandle<RoomMember::Error>); | 760 | template void RoomMember::Unbind(CallbackHandle<RoomMember::Error>); |
| 704 | template void RoomMember::Unbind(CallbackHandle<RoomInformation>); | 761 | template void RoomMember::Unbind(CallbackHandle<RoomInformation>); |
diff --git a/src/network/room_member.h b/src/network/room_member.h index f578f7f6a..0d6417294 100644 --- a/src/network/room_member.h +++ b/src/network/room_member.h | |||
| @@ -17,7 +17,24 @@ namespace Network { | |||
| 17 | using AnnounceMultiplayerRoom::GameInfo; | 17 | using AnnounceMultiplayerRoom::GameInfo; |
| 18 | using AnnounceMultiplayerRoom::RoomInformation; | 18 | using AnnounceMultiplayerRoom::RoomInformation; |
| 19 | 19 | ||
| 20 | /// Information about the received WiFi packets. | 20 | enum class LDNPacketType : u8 { |
| 21 | Scan, | ||
| 22 | ScanResp, | ||
| 23 | Connect, | ||
| 24 | SyncNetwork, | ||
| 25 | Disconnect, | ||
| 26 | DestroyNetwork, | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct LDNPacket { | ||
| 30 | LDNPacketType type; | ||
| 31 | IPv4Address local_ip; | ||
| 32 | IPv4Address remote_ip; | ||
| 33 | bool broadcast; | ||
| 34 | std::vector<u8> data; | ||
| 35 | }; | ||
| 36 | |||
| 37 | /// Information about the received proxy packets. | ||
| 21 | struct ProxyPacket { | 38 | struct ProxyPacket { |
| 22 | SockAddrIn local_endpoint; | 39 | SockAddrIn local_endpoint; |
| 23 | SockAddrIn remote_endpoint; | 40 | SockAddrIn remote_endpoint; |
| @@ -152,6 +169,12 @@ public: | |||
| 152 | void SendProxyPacket(const ProxyPacket& packet); | 169 | void SendProxyPacket(const ProxyPacket& packet); |
| 153 | 170 | ||
| 154 | /** | 171 | /** |
| 172 | * Sends an LDN packet to the room. | ||
| 173 | * @param packet The WiFi packet to send. | ||
| 174 | */ | ||
| 175 | void SendLdnPacket(const LDNPacket& packet); | ||
| 176 | |||
| 177 | /** | ||
| 155 | * Sends a chat message to the room. | 178 | * Sends a chat message to the room. |
| 156 | * @param message The contents of the message. | 179 | * @param message The contents of the message. |
| 157 | */ | 180 | */ |
| @@ -205,6 +228,16 @@ public: | |||
| 205 | std::function<void(const ProxyPacket&)> callback); | 228 | std::function<void(const ProxyPacket&)> callback); |
| 206 | 229 | ||
| 207 | /** | 230 | /** |
| 231 | * Binds a function to an event that will be triggered every time an LDNPacket is received. | ||
| 232 | * The function wil be called everytime the event is triggered. | ||
| 233 | * The callback function must not bind or unbind a function. Doing so will cause a deadlock | ||
| 234 | * @param callback The function to call | ||
| 235 | * @return A handle used for removing the function from the registered list | ||
| 236 | */ | ||
| 237 | CallbackHandle<LDNPacket> BindOnLdnPacketReceived( | ||
| 238 | std::function<void(const LDNPacket&)> callback); | ||
| 239 | |||
| 240 | /** | ||
| 208 | * Binds a function to an event that will be triggered every time the RoomInformation changes. | 241 | * Binds a function to an event that will be triggered every time the RoomInformation changes. |
| 209 | * The function wil be called every time the event is triggered. | 242 | * The function wil be called every time the event is triggered. |
| 210 | * The callback function must not bind or unbind a function. Doing so will cause a deadlock | 243 | * The callback function must not bind or unbind a function. Doing so will cause a deadlock |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a85adc072..9dfa8d639 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -896,8 +896,8 @@ void GMainWindow::InitializeWidgets() { | |||
| 896 | } | 896 | } |
| 897 | 897 | ||
| 898 | // TODO (flTobi): Add the widget when multiplayer is fully implemented | 898 | // TODO (flTobi): Add the widget when multiplayer is fully implemented |
| 899 | // statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0); | 899 | statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0); |
| 900 | // statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0); | 900 | statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0); |
| 901 | 901 | ||
| 902 | tas_label = new QLabel(); | 902 | tas_label = new QLabel(); |
| 903 | tas_label->setObjectName(QStringLiteral("TASlabel")); | 903 | tas_label->setObjectName(QStringLiteral("TASlabel")); |
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index cdf31b417..60a8deab1 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui | |||
| @@ -120,6 +120,20 @@ | |||
| 120 | <addaction name="menu_Reset_Window_Size"/> | 120 | <addaction name="menu_Reset_Window_Size"/> |
| 121 | <addaction name="menu_View_Debugging"/> | 121 | <addaction name="menu_View_Debugging"/> |
| 122 | </widget> | 122 | </widget> |
| 123 | <widget class="QMenu" name="menu_Multiplayer"> | ||
| 124 | <property name="enabled"> | ||
| 125 | <bool>true</bool> | ||
| 126 | </property> | ||
| 127 | <property name="title"> | ||
| 128 | <string>Multiplayer</string> | ||
| 129 | </property> | ||
| 130 | <addaction name="action_View_Lobby"/> | ||
| 131 | <addaction name="action_Start_Room"/> | ||
| 132 | <addaction name="action_Connect_To_Room"/> | ||
| 133 | <addaction name="separator"/> | ||
| 134 | <addaction name="action_Show_Room"/> | ||
| 135 | <addaction name="action_Leave_Room"/> | ||
| 136 | </widget> | ||
| 123 | <widget class="QMenu" name="menu_Tools"> | 137 | <widget class="QMenu" name="menu_Tools"> |
| 124 | <property name="title"> | 138 | <property name="title"> |
| 125 | <string>&Tools</string> | 139 | <string>&Tools</string> |
diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp index 9e672f82e..dec9696c1 100644 --- a/src/yuzu/multiplayer/chat_room.cpp +++ b/src/yuzu/multiplayer/chat_room.cpp | |||
| @@ -61,7 +61,10 @@ public: | |||
| 61 | 61 | ||
| 62 | /// Format the message using the players color | 62 | /// Format the message using the players color |
| 63 | QString GetPlayerChatMessage(u16 player) const { | 63 | QString GetPlayerChatMessage(u16 player) const { |
| 64 | auto color = player_color[player % 16]; | 64 | const bool is_dark_theme = QIcon::themeName().contains(QStringLiteral("dark")) || |
| 65 | QIcon::themeName().contains(QStringLiteral("midnight")); | ||
| 66 | auto color = | ||
| 67 | is_dark_theme ? player_color_dark[player % 16] : player_color_default[player % 16]; | ||
| 65 | QString name; | 68 | QString name; |
| 66 | if (username.isEmpty() || username == nickname) { | 69 | if (username.isEmpty() || username == nickname) { |
| 67 | name = nickname; | 70 | name = nickname; |
| @@ -84,9 +87,12 @@ public: | |||
| 84 | } | 87 | } |
| 85 | 88 | ||
| 86 | private: | 89 | private: |
| 87 | static constexpr std::array<const char*, 16> player_color = { | 90 | static constexpr std::array<const char*, 16> player_color_default = { |
| 88 | {"#0000FF", "#FF0000", "#8A2BE2", "#FF69B4", "#1E90FF", "#008000", "#00FF7F", "#B22222", | 91 | {"#0000FF", "#FF0000", "#8A2BE2", "#FF69B4", "#1E90FF", "#008000", "#00FF7F", "#B22222", |
| 89 | "#DAA520", "#FF4500", "#2E8B57", "#5F9EA0", "#D2691E", "#9ACD32", "#FF7F50", "FFFF00"}}; | 92 | "#DAA520", "#FF4500", "#2E8B57", "#5F9EA0", "#D2691E", "#9ACD32", "#FF7F50", "#FFFF00"}}; |
| 93 | static constexpr std::array<const char*, 16> player_color_dark = { | ||
| 94 | {"#559AD1", "#4EC9A8", "#D69D85", "#C6C923", "#B975B5", "#D81F1F", "#7EAE39", "#4F8733", | ||
| 95 | "#F7CD8A", "#6FCACF", "#CE4897", "#8A2BE2", "#D2691E", "#9ACD32", "#FF7F50", "#152ccd"}}; | ||
| 90 | static constexpr char ping_color[] = "#FFFF00"; | 96 | static constexpr char ping_color[] = "#FFFF00"; |
| 91 | 97 | ||
| 92 | QString timestamp; | 98 | QString timestamp; |
diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp index 66e098296..3ad846028 100644 --- a/src/yuzu/multiplayer/state.cpp +++ b/src/yuzu/multiplayer/state.cpp | |||
| @@ -249,6 +249,7 @@ void MultiplayerState::ShowNotification() { | |||
| 249 | return; // Do not show notification if the chat window currently has focus | 249 | return; // Do not show notification if the chat window currently has focus |
| 250 | show_notification = true; | 250 | show_notification = true; |
| 251 | QApplication::alert(nullptr); | 251 | QApplication::alert(nullptr); |
| 252 | QApplication::beep(); | ||
| 252 | status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16)); | 253 | status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16)); |
| 253 | status_text->setText(tr("New Messages Received")); | 254 | status_text->setText(tr("New Messages Received")); |
| 254 | } | 255 | } |