From f5e635addaef59159bf6bc529b17954eda3684a1 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Sun, 31 Jul 2022 04:46:26 +0200 Subject: ldn: Initial implementation --- src/network/room.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++ src/network/room.h | 1 + src/network/room_member.cpp | 57 ++++++++++++++++++++++++++++++++++++++++ src/network/room_member.h | 35 ++++++++++++++++++++++++- 4 files changed, 155 insertions(+), 1 deletion(-) (limited to 'src/network') 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 @@ -211,6 +211,12 @@ public: */ void HandleProxyPacket(const ENetEvent* event); + /** + * Broadcasts this packet to all members except the sender. + * @param event The ENet event containing the data + */ + void HandleLdnPacket(const ENetEvent* event); + /** * Extracts a chat entry from a received ENet packet and adds it to the chat queue. * @param event The ENet event that was received. @@ -247,6 +253,9 @@ void Room::RoomImpl::ServerLoop() { case IdProxyPacket: HandleProxyPacket(&event); break; + case IdLdnPacket: + HandleLdnPacket(&event); + break; case IdChatMessage: HandleChatPacket(&event); break; @@ -861,6 +870,60 @@ void Room::RoomImpl::HandleProxyPacket(const ENetEvent* event) { enet_host_flush(server); } +void Room::RoomImpl::HandleLdnPacket(const ENetEvent* event) { + Packet in_packet; + in_packet.Append(event->packet->data, event->packet->dataLength); + + in_packet.IgnoreBytes(sizeof(u8)); // Message type + + in_packet.IgnoreBytes(sizeof(u8)); // LAN packet type + in_packet.IgnoreBytes(sizeof(IPv4Address)); // Local IP + + IPv4Address remote_ip; + in_packet.Read(remote_ip); // Remote IP + + bool broadcast; + in_packet.Read(broadcast); // Broadcast + + Packet out_packet; + out_packet.Append(event->packet->data, event->packet->dataLength); + ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(), + ENET_PACKET_FLAG_RELIABLE); + + const auto& destination_address = remote_ip; + if (broadcast) { // Send the data to everyone except the sender + std::lock_guard lock(member_mutex); + bool sent_packet = false; + for (const auto& member : members) { + if (member.peer != event->peer) { + sent_packet = true; + enet_peer_send(member.peer, 0, enet_packet); + } + } + + if (!sent_packet) { + enet_packet_destroy(enet_packet); + } + } else { + std::lock_guard lock(member_mutex); + auto member = std::find_if(members.begin(), members.end(), + [destination_address](const Member& member_entry) -> bool { + return member_entry.fake_ip == destination_address; + }); + if (member != members.end()) { + enet_peer_send(member->peer, 0, enet_packet); + } else { + LOG_ERROR(Network, + "Attempting to send to unknown IP address: " + "{}.{}.{}.{}", + destination_address[0], destination_address[1], destination_address[2], + destination_address[3]); + enet_packet_destroy(enet_packet); + } + } + enet_host_flush(server); +} + void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { Packet in_packet; 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 { IdRoomInformation, IdSetGameInfo, IdProxyPacket, + IdLdnPacket, IdChatMessage, IdNameCollision, 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: private: CallbackSet callback_set_proxy_packet; + CallbackSet callback_set_ldn_packet; CallbackSet callback_set_chat_messages; CallbackSet callback_set_status_messages; CallbackSet callback_set_room_information; @@ -107,6 +108,12 @@ public: */ void HandleProxyPackets(const ENetEvent* event); + /** + * Extracts an LdnPacket from a received ENet packet. + * @param event The ENet event that was received. + */ + void HandleLdnPackets(const ENetEvent* event); + /** * Extracts a chat entry from a received ENet packet and adds it to the chat queue. * @param event The ENet event that was received. @@ -166,6 +173,9 @@ void RoomMember::RoomMemberImpl::MemberLoop() { case IdProxyPacket: HandleProxyPackets(&event); break; + case IdLdnPacket: + HandleLdnPackets(&event); + break; case IdChatMessage: HandleChatPacket(&event); break; @@ -372,6 +382,27 @@ void RoomMember::RoomMemberImpl::HandleProxyPackets(const ENetEvent* event) { Invoke(proxy_packet); } +void RoomMember::RoomMemberImpl::HandleLdnPackets(const ENetEvent* event) { + LDNPacket ldn_packet{}; + Packet packet; + packet.Append(event->packet->data, event->packet->dataLength); + + // Ignore the first byte, which is the message id. + packet.IgnoreBytes(sizeof(u8)); // Ignore the message type + + u8 packet_type; + packet.Read(packet_type); + ldn_packet.type = static_cast(packet_type); + + packet.Read(ldn_packet.local_ip); + packet.Read(ldn_packet.remote_ip); + packet.Read(ldn_packet.broadcast); + + packet.Read(ldn_packet.data); + + Invoke(ldn_packet); +} + void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { Packet packet; packet.Append(event->packet->data, event->packet->dataLength); @@ -449,6 +480,11 @@ RoomMember::RoomMemberImpl::CallbackSet& RoomMember::RoomMemberImpl return callback_set_proxy_packet; } +template <> +RoomMember::RoomMemberImpl::CallbackSet& RoomMember::RoomMemberImpl::Callbacks::Get() { + return callback_set_ldn_packet; +} + template <> RoomMember::RoomMemberImpl::CallbackSet& RoomMember::RoomMemberImpl::Callbacks::Get() { @@ -607,6 +643,21 @@ void RoomMember::SendProxyPacket(const ProxyPacket& proxy_packet) { room_member_impl->Send(std::move(packet)); } +void RoomMember::SendLdnPacket(const LDNPacket& ldn_packet) { + Packet packet; + packet.Write(static_cast(IdLdnPacket)); + + packet.Write(static_cast(ldn_packet.type)); + + packet.Write(ldn_packet.local_ip); + packet.Write(ldn_packet.remote_ip); + packet.Write(ldn_packet.broadcast); + + packet.Write(ldn_packet.data); + + room_member_impl->Send(std::move(packet)); +} + void RoomMember::SendChatMessage(const std::string& message) { Packet packet; packet.Write(static_cast(IdChatMessage)); @@ -663,6 +714,11 @@ RoomMember::CallbackHandle RoomMember::BindOnProxyPacketReceived( return room_member_impl->Bind(callback); } +RoomMember::CallbackHandle RoomMember::BindOnLdnPacketReceived( + std::function callback) { + return room_member_impl->Bind(callback); +} + RoomMember::CallbackHandle RoomMember::BindOnRoomInformationChanged( std::function callback) { return room_member_impl->Bind(callback); @@ -699,6 +755,7 @@ void RoomMember::Leave() { } template void RoomMember::Unbind(CallbackHandle); +template void RoomMember::Unbind(CallbackHandle); template void RoomMember::Unbind(CallbackHandle); template void RoomMember::Unbind(CallbackHandle); template void RoomMember::Unbind(CallbackHandle); 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 { using AnnounceMultiplayerRoom::GameInfo; using AnnounceMultiplayerRoom::RoomInformation; -/// Information about the received WiFi packets. +enum class LDNPacketType : u8 { + Scan, + ScanResp, + Connect, + SyncNetwork, + Disconnect, + DestroyNetwork, +}; + +struct LDNPacket { + LDNPacketType type; + IPv4Address local_ip; + IPv4Address remote_ip; + bool broadcast; + std::vector data; +}; + +/// Information about the received proxy packets. struct ProxyPacket { SockAddrIn local_endpoint; SockAddrIn remote_endpoint; @@ -151,6 +168,12 @@ public: */ void SendProxyPacket(const ProxyPacket& packet); + /** + * Sends an LDN packet to the room. + * @param packet The WiFi packet to send. + */ + void SendLdnPacket(const LDNPacket& packet); + /** * Sends a chat message to the room. * @param message The contents of the message. @@ -204,6 +227,16 @@ public: CallbackHandle BindOnProxyPacketReceived( std::function callback); + /** + * Binds a function to an event that will be triggered every time an LDNPacket is received. + * The function wil be called everytime the event is triggered. + * The callback function must not bind or unbind a function. Doing so will cause a deadlock + * @param callback The function to call + * @return A handle used for removing the function from the registered list + */ + CallbackHandle BindOnLdnPacketReceived( + std::function callback); + /** * Binds a function to an event that will be triggered every time the RoomInformation changes. * The function wil be called every time the event is triggered. -- cgit v1.2.3 From 4213f1c126afda9c5235c868ded4e7d95438bffc Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Mon, 12 Sep 2022 22:39:18 +0200 Subject: Address some review comments --- src/core/hle/service/ldn/lan_discovery.cpp | 49 ++++++++++--------------- src/core/hle/service/ldn/lan_discovery.h | 17 +++++---- src/core/hle/service/ldn/ldn.cpp | 2 - src/core/hle/service/ldn/ldn_types.h | 14 +++---- src/core/internal_network/network_interface.cpp | 4 +- src/network/room_member.cpp | 2 +- src/yuzu/main.ui | 2 +- 7 files changed, 38 insertions(+), 52 deletions(-) (limited to 'src/network') diff --git a/src/core/hle/service/ldn/lan_discovery.cpp b/src/core/hle/service/ldn/lan_discovery.cpp index b04c99077..8f3c04550 100644 --- a/src/core/hle/service/ldn/lan_discovery.cpp +++ b/src/core/hle/service/ldn/lan_discovery.cpp @@ -35,12 +35,9 @@ void LanStation::OverrideInfo() { LANDiscovery::LANDiscovery(Network::RoomNetwork& room_network_) : stations({{{1, this}, {2, this}, {3, this}, {4, this}, {5, this}, {6, this}, {7, this}}}), - room_network{room_network_} { - LOG_INFO(Service_LDN, "LANDiscovery"); -} + room_network{room_network_} {} LANDiscovery::~LANDiscovery() { - LOG_INFO(Service_LDN, "~LANDiscovery"); if (inited) { Result rc = Finalize(); LOG_INFO(Service_LDN, "Finalize: {}", rc.raw); @@ -62,7 +59,7 @@ void LANDiscovery::InitNetworkInfo() { } void LANDiscovery::InitNodeStateChange() { - for (auto& node_update : nodeChanges) { + for (auto& node_update : node_changes) { node_update.state_change = NodeStateChange::None; } for (auto& node_state : node_last_states) { @@ -97,8 +94,8 @@ Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network, if (state == State::AccessPointCreated || state == State::StationConnected) { std::memcpy(&out_network, &network_info, sizeof(network_info)); for (std::size_t i = 0; i < buffer_count; i++) { - out_updates[i].state_change = nodeChanges[i].state_change; - nodeChanges[i].state_change = NodeStateChange::None; + out_updates[i].state_change = node_changes[i].state_change; + node_changes[i].state_change = NodeStateChange::None; } return ResultSuccess; } @@ -168,9 +165,9 @@ Result LANDiscovery::Scan(std::vector& networks, u16& count, return ResultSuccess; } -Result LANDiscovery::SetAdvertiseData(std::vector& data) { +Result LANDiscovery::SetAdvertiseData(std::span data) { std::scoped_lock lock{packet_mutex}; - std::size_t size = data.size(); + const std::size_t size = data.size(); if (size > AdvertiseDataSizeMax) { return ResultAdvertiseDataTooLarge; } @@ -288,7 +285,7 @@ Result LANDiscovery::DestroyNetwork() { ResetStations(); SetState(State::AccessPointOpened); - LanEvent(); + lan_event(); return ResultSuccess; } @@ -323,12 +320,12 @@ Result LANDiscovery::Disconnect() { } SetState(State::StationOpened); - LanEvent(); + lan_event(); return ResultSuccess; } -Result LANDiscovery::Initialize(LanEventFunc lan_event, bool listening) { +Result LANDiscovery::Initialize(LanEventFunc lan_event_, bool listening) { std::scoped_lock lock{packet_mutex}; if (inited) { return ResultSuccess; @@ -341,7 +338,7 @@ Result LANDiscovery::Initialize(LanEventFunc lan_event, bool listening) { } connected_clients.clear(); - LanEvent = lan_event; + lan_event = lan_event_; SetState(State::Initialized); @@ -408,13 +405,13 @@ void LANDiscovery::OnDisconnectFromHost() { host_ip = std::nullopt; if (state == State::StationConnected) { SetState(State::StationOpened); - LanEvent(); + lan_event(); } } void LANDiscovery::OnNetworkInfoChanged() { if (IsNodeStateChanged()) { - LanEvent(); + lan_event(); } return; } @@ -439,7 +436,6 @@ void LANDiscovery::SendPacket(Network::LDNPacketType type, const Data& data, packet.local_ip = GetLocalIp(); packet.remote_ip = remote_ip; - packet.data.clear(); packet.data.resize(sizeof(data)); std::memcpy(packet.data.data(), &data, sizeof(data)); SendPacket(packet); @@ -453,7 +449,6 @@ void LANDiscovery::SendPacket(Network::LDNPacketType type, Ipv4Address remote_ip packet.local_ip = GetLocalIp(); packet.remote_ip = remote_ip; - packet.data.clear(); SendPacket(packet); } @@ -465,7 +460,6 @@ void LANDiscovery::SendBroadcast(Network::LDNPacketType type, const Data& data) packet.broadcast = true; packet.local_ip = GetLocalIp(); - packet.data.clear(); packet.data.resize(sizeof(data)); std::memcpy(packet.data.data(), &data, sizeof(data)); SendPacket(packet); @@ -478,7 +472,6 @@ void LANDiscovery::SendBroadcast(Network::LDNPacketType type) { packet.broadcast = true; packet.local_ip = GetLocalIp(); - packet.data.clear(); SendPacket(packet); } @@ -581,9 +574,9 @@ bool LANDiscovery::IsNodeStateChanged() { for (int i = 0; i < NodeCountMax; i++) { if (nodes[i].is_connected != node_last_states[i]) { if (nodes[i].is_connected) { - nodeChanges[i].state_change |= NodeStateChange::Connect; + node_changes[i].state_change |= NodeStateChange::Connect; } else { - nodeChanges[i].state_change |= NodeStateChange::Disconnect; + node_changes[i].state_change |= NodeStateChange::Disconnect; } node_last_states[i] = nodes[i].is_connected; changed = true; @@ -598,15 +591,11 @@ bool LANDiscovery::IsFlagSet(ScanFilterFlag flag, ScanFilterFlag search_flag) co return (flag_value & search_flag_value) == search_flag_value; } -int LANDiscovery::GetStationCount() { - int count = 0; - for (const auto& station : stations) { - if (station.GetStatus() != NodeStatus::Disconnected) { - count++; - } - } - - return count; +int LANDiscovery::GetStationCount() const { + return static_cast( + std::count_if(stations.begin(), stations.end(), [](const auto& station) { + return station.GetStatus() != NodeStatus::Disconnected; + })); } MacAddress LANDiscovery::GetFakeMac() const { diff --git a/src/core/hle/service/ldn/lan_discovery.h b/src/core/hle/service/ldn/lan_discovery.h index 255342456..3833cd764 100644 --- a/src/core/hle/service/ldn/lan_discovery.h +++ b/src/core/hle/service/ldn/lan_discovery.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,7 @@ protected: class LANDiscovery { public: - typedef std::function LanEventFunc; + using LanEventFunc = std::function; LANDiscovery(Network::RoomNetwork& room_network_); ~LANDiscovery(); @@ -58,7 +59,7 @@ public: DisconnectReason GetDisconnectReason() const; Result Scan(std::vector& networks, u16& count, const ScanFilter& filter); - Result SetAdvertiseData(std::vector& data); + Result SetAdvertiseData(std::span data); Result OpenAccessPoint(); Result CloseAccessPoint(); @@ -74,7 +75,7 @@ public: u16 local_communication_version); Result Disconnect(); - Result Initialize(LanEventFunc lan_event = empty_func, bool listening = true); + Result Initialize(LanEventFunc lan_event_ = empty_func, bool listening = true); Result Finalize(); void ReceivePacket(const Network::LDNPacket& packet); @@ -94,7 +95,7 @@ protected: bool IsNodeStateChanged(); bool IsFlagSet(ScanFilterFlag flag, ScanFilterFlag search_flag) const; - int GetStationCount(); + int GetStationCount() const; MacAddress GetFakeMac() const; Result GetNodeInfo(NodeInfo& node, const UserConfig& user_config, u16 local_communication_version); @@ -109,12 +110,12 @@ protected: void SendPacket(const Network::LDNPacket& packet); static const LanEventFunc empty_func; - const Ssid fake_ssid{"YuzuFakeSsidForLdn"}; + static constexpr Ssid fake_ssid{"YuzuFakeSsidForLdn"}; bool inited{}; std::mutex packet_mutex; std::array stations; - std::array nodeChanges{}; + std::array node_changes{}; std::array node_last_states{}; std::unordered_map scan_results{}; NodeInfo node_info{}; @@ -124,9 +125,9 @@ protected: // TODO (flTobi): Should this be an std::set? std::vector connected_clients; - std::optional host_ip = std::nullopt; + std::optional host_ip; - LanEventFunc LanEvent; + LanEventFunc lan_event; Network::RoomNetwork& room_network; }; diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index 6537f49cf..ea3e7e55a 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp @@ -205,8 +205,6 @@ public: } void GetIpv4Address(Kernel::HLERequestContext& ctx) { - LOG_CRITICAL(Service_LDN, "called"); - const auto network_interface = Network::GetSelectedNetworkInterface(); if (!network_interface) { diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h index d6609fff5..44c2c773b 100644 --- a/src/core/hle/service/ldn/ldn_types.h +++ b/src/core/hle/service/ldn/ldn_types.h @@ -31,13 +31,7 @@ enum class NodeStateChange : u8 { DisconnectAndConnect, }; -inline NodeStateChange operator|(NodeStateChange a, NodeStateChange b) { - return static_cast(static_cast(a) | static_cast(b)); -} - -inline NodeStateChange operator|=(NodeStateChange& a, NodeStateChange b) { - return a = a | b; -} +DECLARE_ENUM_FLAG_OPERATORS(NodeStateChange) enum class ScanFilterFlag : u32 { None = 0, @@ -163,7 +157,7 @@ struct Ssid { Ssid() = default; - explicit Ssid(std::string_view data) { + constexpr explicit Ssid(std::string_view data) { length = static_cast(std::min(data.size(), SsidLengthMax)); data.copy(raw.data(), length); raw[length] = 0; @@ -176,6 +170,10 @@ struct Ssid { bool operator==(const Ssid& b) const { return (length == b.length) && (std::memcmp(raw.data(), b.raw.data(), length) == 0); } + + bool operator!=(const Ssid& b) const { + return !operator==(b); + } }; static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp index 858ae1cfb..057fd3661 100644 --- a/src/core/internal_network/network_interface.cpp +++ b/src/core/internal_network/network_interface.cpp @@ -188,7 +188,7 @@ std::vector GetAvailableNetworkInterfaces() { std::optional GetSelectedNetworkInterface() { const auto& selected_network_interface = Settings::values.network_interface.GetValue(); const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); - if (network_interfaces.size() == 0) { + if (network_interfaces.empty()) { LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces"); return std::nullopt; } @@ -209,7 +209,7 @@ std::optional GetSelectedNetworkInterface() { void SelectFirstNetworkInterface() { const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); - if (network_interfaces.size() == 0) { + if (network_interfaces.empty()) { return; } diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp index 572e55a5b..b94cb24ad 100644 --- a/src/network/room_member.cpp +++ b/src/network/room_member.cpp @@ -716,7 +716,7 @@ RoomMember::CallbackHandle RoomMember::BindOnProxyPacketReceived( RoomMember::CallbackHandle RoomMember::BindOnLdnPacketReceived( std::function callback) { - return room_member_impl->Bind(callback); + return room_member_impl->Bind(std::move(callback)); } RoomMember::CallbackHandle RoomMember::BindOnRoomInformationChanged( diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index de1545216..74d49dbd4 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -125,7 +125,7 @@ true - Multiplayer + &Multiplayer -- cgit v1.2.3