diff options
author | James Rowe <jroweboy@gmail.com> | 2018-01-12 03:21:20 +0100 |
---|---|---|
committer | James Rowe <jroweboy@gmail.com> | 2018-01-13 03:11:03 +0100 |
commit | ebf9a784a9f7f4148a669dbb39e7cd50df779a14 (patch) | |
tree | d585685a1c0a34b903af1d086d62560bf56bb29f /src/network/room_member.cpp | |
parent | config: Default CPU core to Unicorn. (diff) | |
download | yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar.gz yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar.bz2 yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar.lz yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar.xz yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar.zst yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.zip |
Diffstat (limited to 'src/network/room_member.cpp')
-rw-r--r-- | src/network/room_member.cpp | 490 |
1 files changed, 0 insertions, 490 deletions
diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp deleted file mode 100644 index f229ec6fd..000000000 --- a/src/network/room_member.cpp +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <atomic> -#include <list> -#include <mutex> -#include <set> -#include <thread> -#include "common/assert.h" -#include "enet/enet.h" -#include "network/packet.h" -#include "network/room_member.h" - -namespace Network { - -constexpr u32 ConnectionTimeoutMs = 5000; - -class RoomMember::RoomMemberImpl { -public: - ENetHost* client = nullptr; ///< ENet network interface. - ENetPeer* server = nullptr; ///< The server peer the client is connected to - - /// Information about the clients connected to the same room as us. - MemberList member_information; - /// Information about the room we're connected to. - RoomInformation room_information; - - /// The current game name, id and version - GameInfo current_game_info; - - std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember. - void SetState(const State new_state); - bool IsConnected() const; - - std::string nickname; ///< The nickname of this member. - MacAddress mac_address; ///< The mac_address of this member. - - std::mutex network_mutex; ///< Mutex that controls access to the `client` variable. - /// Thread that receives and dispatches network packets - std::unique_ptr<std::thread> loop_thread; - std::mutex send_list_mutex; ///< Mutex that controls access to the `send_list` variable. - std::list<Packet> send_list; ///< A list that stores all packets to send the async - - template <typename T> - using CallbackSet = std::set<CallbackHandle<T>>; - std::mutex callback_mutex; ///< The mutex used for handling callbacks - - class Callbacks { - public: - template <typename T> - CallbackSet<T>& Get(); - - private: - CallbackSet<WifiPacket> callback_set_wifi_packet; - CallbackSet<ChatEntry> callback_set_chat_messages; - CallbackSet<RoomInformation> callback_set_room_information; - CallbackSet<State> callback_set_state; - }; - Callbacks callbacks; ///< All CallbackSets to all events - - void MemberLoop(); - - void StartLoop(); - - /** - * Sends data to the room. It will be send on channel 0 with flag RELIABLE - * @param packet The data to send - */ - void Send(Packet&& packet); - - /** - * Sends a request to the server, asking for permission to join a room with the specified - * nickname and preferred mac. - * @params nickname The desired nickname. - * @params preferred_mac The preferred MAC address to use in the room, the NoPreferredMac tells - * the server to assign one for us. - */ - void SendJoinRequest(const std::string& nickname, - const MacAddress& preferred_mac = NoPreferredMac); - - /** - * Extracts a MAC Address from a received ENet packet. - * @param event The ENet event that was received. - */ - void HandleJoinPacket(const ENetEvent* event); - /** - * Extracts RoomInformation and MemberInformation from a received RakNet packet. - * @param event The ENet event that was received. - */ - void HandleRoomInformationPacket(const ENetEvent* event); - - /** - * Extracts a WifiPacket from a received ENet packet. - * @param event The ENet event that was received. - */ - void HandleWifiPackets(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. - */ - void HandleChatPacket(const ENetEvent* event); - - /** - * Disconnects the RoomMember from the Room - */ - void Disconnect(); - - template <typename T> - void Invoke(const T& data); - - template <typename T> - CallbackHandle<T> Bind(std::function<void(const T&)> callback); -}; - -// RoomMemberImpl -void RoomMember::RoomMemberImpl::SetState(const State new_state) { - if (state != new_state) { - state = new_state; - Invoke<State>(state); - } -} - -bool RoomMember::RoomMemberImpl::IsConnected() const { - return state == State::Joining || state == State::Joined; -} - -void RoomMember::RoomMemberImpl::MemberLoop() { - // Receive packets while the connection is open - while (IsConnected()) { - std::lock_guard<std::mutex> lock(network_mutex); - ENetEvent event; - if (enet_host_service(client, &event, 100) > 0) { - switch (event.type) { - case ENET_EVENT_TYPE_RECEIVE: - switch (event.packet->data[0]) { - case IdWifiPacket: - HandleWifiPackets(&event); - break; - case IdChatMessage: - HandleChatPacket(&event); - break; - case IdRoomInformation: - HandleRoomInformationPacket(&event); - break; - case IdJoinSuccess: - // The join request was successful, we are now in the room. - // If we joined successfully, there must be at least one client in the room: us. - ASSERT_MSG(member_information.size() > 0, - "We have not yet received member information."); - HandleJoinPacket(&event); // Get the MAC Address for the client - SetState(State::Joined); - break; - case IdNameCollision: - SetState(State::NameCollision); - break; - case IdMacCollision: - SetState(State::MacCollision); - break; - case IdVersionMismatch: - SetState(State::WrongVersion); - break; - case IdCloseRoom: - SetState(State::LostConnection); - break; - } - enet_packet_destroy(event.packet); - break; - case ENET_EVENT_TYPE_DISCONNECT: - SetState(State::LostConnection); - break; - } - } - { - std::lock_guard<std::mutex> lock(send_list_mutex); - for (const auto& packet : send_list) { - ENetPacket* enetPacket = enet_packet_create(packet.GetData(), packet.GetDataSize(), - ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(server, 0, enetPacket); - } - enet_host_flush(client); - send_list.clear(); - } - } - Disconnect(); -}; - -void RoomMember::RoomMemberImpl::StartLoop() { - loop_thread = std::make_unique<std::thread>(&RoomMember::RoomMemberImpl::MemberLoop, this); -} - -void RoomMember::RoomMemberImpl::Send(Packet&& packet) { - std::lock_guard<std::mutex> lock(send_list_mutex); - send_list.push_back(std::move(packet)); -} - -void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname, - const MacAddress& preferred_mac) { - Packet packet; - packet << static_cast<u8>(IdJoinRequest); - packet << nickname; - packet << preferred_mac; - packet << network_version; - Send(std::move(packet)); -} - -void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* event) { - Packet packet; - packet.Append(event->packet->data, event->packet->dataLength); - - // Ignore the first byte, which is the message id. - packet.IgnoreBytes(sizeof(u8)); // Igonore the message type - - RoomInformation info{}; - packet >> info.name; - packet >> info.member_slots; - room_information.name = info.name; - room_information.member_slots = info.member_slots; - - u32 num_members; - packet >> num_members; - member_information.resize(num_members); - - for (auto& member : member_information) { - packet >> member.nickname; - packet >> member.mac_address; - packet >> member.game_info.name; - packet >> member.game_info.id; - } - Invoke(room_information); -} - -void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) { - Packet packet; - packet.Append(event->packet->data, event->packet->dataLength); - - // Ignore the first byte, which is the message id. - packet.IgnoreBytes(sizeof(u8)); // Igonore the message type - - // Parse the MAC Address from the packet - packet >> mac_address; - SetState(State::Joined); -} - -void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) { - WifiPacket wifi_packet{}; - Packet packet; - packet.Append(event->packet->data, event->packet->dataLength); - - // Ignore the first byte, which is the message id. - packet.IgnoreBytes(sizeof(u8)); // Igonore the message type - - // Parse the WifiPacket from the packet - u8 frame_type; - packet >> frame_type; - WifiPacket::PacketType type = static_cast<WifiPacket::PacketType>(frame_type); - - wifi_packet.type = type; - packet >> wifi_packet.channel; - packet >> wifi_packet.transmitter_address; - packet >> wifi_packet.destination_address; - - u32 data_length; - packet >> data_length; - - packet >> wifi_packet.data; - - Invoke<WifiPacket>(wifi_packet); -} - -void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { - Packet packet; - packet.Append(event->packet->data, event->packet->dataLength); - - // Ignore the first byte, which is the message id. - packet.IgnoreBytes(sizeof(u8)); - - ChatEntry chat_entry{}; - packet >> chat_entry.nickname; - packet >> chat_entry.message; - Invoke<ChatEntry>(chat_entry); -} - -void RoomMember::RoomMemberImpl::Disconnect() { - member_information.clear(); - room_information.member_slots = 0; - room_information.name.clear(); - - if (!server) - return; - enet_peer_disconnect(server, 0); - - ENetEvent event; - while (enet_host_service(client, &event, ConnectionTimeoutMs) > 0) { - switch (event.type) { - case ENET_EVENT_TYPE_RECEIVE: - enet_packet_destroy(event.packet); // Ignore all incoming data - break; - case ENET_EVENT_TYPE_DISCONNECT: - server = nullptr; - return; - } - } - // didn't disconnect gracefully force disconnect - enet_peer_reset(server); - server = nullptr; -} - -template <> -RoomMember::RoomMemberImpl::CallbackSet<WifiPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() { - return callback_set_wifi_packet; -} - -template <> -RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>& -RoomMember::RoomMemberImpl::Callbacks::Get() { - return callback_set_state; -} - -template <> -RoomMember::RoomMemberImpl::CallbackSet<RoomInformation>& -RoomMember::RoomMemberImpl::Callbacks::Get() { - return callback_set_room_information; -} - -template <> -RoomMember::RoomMemberImpl::CallbackSet<ChatEntry>& RoomMember::RoomMemberImpl::Callbacks::Get() { - return callback_set_chat_messages; -} - -template <typename T> -void RoomMember::RoomMemberImpl::Invoke(const T& data) { - std::lock_guard<std::mutex> lock(callback_mutex); - CallbackSet<T> callback_set = callbacks.Get<T>(); - for (auto const& callback : callback_set) - (*callback)(data); -} - -template <typename T> -RoomMember::CallbackHandle<T> RoomMember::RoomMemberImpl::Bind( - std::function<void(const T&)> callback) { - std::lock_guard<std::mutex> lock(callback_mutex); - CallbackHandle<T> handle; - handle = std::make_shared<std::function<void(const T&)>>(callback); - callbacks.Get<T>().insert(handle); - return handle; -} - -// RoomMember -RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} { - room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0); - ASSERT_MSG(room_member_impl->client != nullptr, "Could not create client"); -} - -RoomMember::~RoomMember() { - ASSERT_MSG(!IsConnected(), "RoomMember is being destroyed while connected"); - enet_host_destroy(room_member_impl->client); -} - -RoomMember::State RoomMember::GetState() const { - return room_member_impl->state; -} - -const RoomMember::MemberList& RoomMember::GetMemberInformation() const { - return room_member_impl->member_information; -} - -const std::string& RoomMember::GetNickname() const { - return room_member_impl->nickname; -} - -const MacAddress& RoomMember::GetMacAddress() const { - ASSERT_MSG(IsConnected(), "Tried to get MAC address while not connected"); - return room_member_impl->mac_address; -} - -RoomInformation RoomMember::GetRoomInformation() const { - return room_member_impl->room_information; -} - -void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port, - u16 client_port, const MacAddress& preferred_mac) { - // If the member is connected, kill the connection first - if (room_member_impl->loop_thread && room_member_impl->loop_thread->joinable()) { - room_member_impl->SetState(State::Error); - room_member_impl->loop_thread->join(); - room_member_impl->loop_thread.reset(); - } - // If the thread isn't running but the ptr still exists, reset it - else if (room_member_impl->loop_thread) { - room_member_impl->loop_thread.reset(); - } - - ENetAddress address{}; - enet_address_set_host(&address, server_addr); - address.port = server_port; - room_member_impl->server = - enet_host_connect(room_member_impl->client, &address, NumChannels, 0); - - if (!room_member_impl->server) { - room_member_impl->SetState(State::Error); - return; - } - - ENetEvent event{}; - int net = enet_host_service(room_member_impl->client, &event, ConnectionTimeoutMs); - if (net > 0 && event.type == ENET_EVENT_TYPE_CONNECT) { - room_member_impl->nickname = nick; - room_member_impl->SetState(State::Joining); - room_member_impl->StartLoop(); - room_member_impl->SendJoinRequest(nick, preferred_mac); - SendGameInfo(room_member_impl->current_game_info); - } else { - room_member_impl->SetState(State::CouldNotConnect); - } -} - -bool RoomMember::IsConnected() const { - return room_member_impl->IsConnected(); -} - -void RoomMember::SendWifiPacket(const WifiPacket& wifi_packet) { - Packet packet; - packet << static_cast<u8>(IdWifiPacket); - packet << static_cast<u8>(wifi_packet.type); - packet << wifi_packet.channel; - packet << wifi_packet.transmitter_address; - packet << wifi_packet.destination_address; - packet << wifi_packet.data; - room_member_impl->Send(std::move(packet)); -} - -void RoomMember::SendChatMessage(const std::string& message) { - Packet packet; - packet << static_cast<u8>(IdChatMessage); - packet << message; - room_member_impl->Send(std::move(packet)); -} - -void RoomMember::SendGameInfo(const GameInfo& game_info) { - room_member_impl->current_game_info = game_info; - if (!IsConnected()) - return; - - Packet packet; - packet << static_cast<u8>(IdSetGameInfo); - packet << game_info.name; - packet << game_info.id; - room_member_impl->Send(std::move(packet)); -} - -RoomMember::CallbackHandle<RoomMember::State> RoomMember::BindOnStateChanged( - std::function<void(const RoomMember::State&)> callback) { - return room_member_impl->Bind(callback); -} - -RoomMember::CallbackHandle<WifiPacket> RoomMember::BindOnWifiPacketReceived( - std::function<void(const WifiPacket&)> callback) { - return room_member_impl->Bind(callback); -} - -RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged( - std::function<void(const RoomInformation&)> callback) { - return room_member_impl->Bind(callback); -} - -RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved( - std::function<void(const ChatEntry&)> callback) { - return room_member_impl->Bind(callback); -} - -template <typename T> -void RoomMember::Unbind(CallbackHandle<T> handle) { - std::lock_guard<std::mutex> lock(room_member_impl->callback_mutex); - room_member_impl->callbacks.Get<T>().erase(handle); -} - -void RoomMember::Leave() { - room_member_impl->SetState(State::Idle); - room_member_impl->loop_thread->join(); - room_member_impl->loop_thread.reset(); -} - -template void RoomMember::Unbind(CallbackHandle<WifiPacket>); -template void RoomMember::Unbind(CallbackHandle<RoomMember::State>); -template void RoomMember::Unbind(CallbackHandle<RoomInformation>); -template void RoomMember::Unbind(CallbackHandle<ChatEntry>); - -} // namespace Network |