From a0626221a52056669c0b6d19b37d4189c1671fb7 Mon Sep 17 00:00:00 2001 From: B3n30 Date: Fri, 14 Jul 2017 09:20:39 +0200 Subject: [PATCH] Network: Made send async in RoomMember --- src/network/room.cpp | 35 +++++++++++++++++++++--- src/network/room.h | 6 ++++- src/network/room_member.cpp | 53 +++++++++++++++++++++++-------------- src/network/room_member.h | 1 + 4 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/network/room.cpp b/src/network/room.cpp index 9af5b4ea07..da16793120 100644 --- a/src/network/room.cpp +++ b/src/network/room.cpp @@ -73,6 +73,11 @@ public: */ void SendMacCollision(ENetPeer* client); + /** + * Sends a ID_ROOM_VERSION_MISMATCH message telling the client that the MAC is invalid. + */ + void SendVersionMismatch(ENetPeer* client); + /** * Notifies the member that its connection attempt was successful, * and it is now part of the room. @@ -170,6 +175,9 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { MacAddress preferred_mac; packet >> preferred_mac; + u32 client_version; + packet >> client_version; + if (!IsValidNickname(nickname)) { SendNameCollision(event->peer); return; @@ -186,6 +194,11 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { preferred_mac = GenerateMacAddress(); } + if (client_version != network_version) { + SendVersionMismatch(event->peer); + return; + } + // At this point the client is ready to be added to the room. Member member{}; member.mac_address = preferred_mac; @@ -232,6 +245,17 @@ void Room::RoomImpl::SendMacCollision(ENetPeer* client) { enet_host_flush(server); } +void Room::RoomImpl::SendVersionMismatch(ENetPeer* client) { + Packet packet; + packet << static_cast(IdVersionMismatch); + packet << network_version; + + ENetPacket* enet_packet = + enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); + enet_peer_send(client, 0, enet_packet); + enet_host_flush(server); +} + void Room::RoomImpl::SendJoinSuccess(ENetPeer* client, MacAddress mac_address) { Packet packet; packet << static_cast(IdJoinSuccess); @@ -291,7 +315,7 @@ void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) { if (destination_address == BroadcastMac) { // Send the data to everyone except the sender for (const auto& member : members) { if (member.peer != event->peer) - enet_peer_send(member.peer, 0, event->packet); + enet_peer_send(member.peer, 0, enet_packet); } } else { // Send the data only to the destination client auto member = std::find_if(members.begin(), members.end(), @@ -327,9 +351,9 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); - for (auto it = members.begin(); it != members.end(); ++it) { - if (it->peer != event->peer) - enet_peer_send(it->peer, 0, enet_packet); + for (const auto& member : members) { + if (member.peer != event->peer) + enet_peer_send(member.peer, 0, enet_packet); } enet_host_flush(server); } @@ -369,6 +393,9 @@ Room::~Room() = default; void Room::Create(const std::string& name, const std::string& server_address, u16 server_port) { ENetAddress address; address.host = ENET_HOST_ANY; + if (!server_address.empty()) { + enet_address_set_host(&address, server_address.c_str()); + } address.port = server_port; room_impl->server = enet_host_create(&address, MaxConcurrentConnections, NumChannels, 0, 0); diff --git a/src/network/room.h b/src/network/room.h index 82e3dc62ce..ffa17599d4 100644 --- a/src/network/room.h +++ b/src/network/room.h @@ -11,6 +11,8 @@ namespace Network { +constexpr u32 network_version = 1; ///< The version of this Room and RoomMember + constexpr u16 DefaultRoomPort = 1234; constexpr size_t NumChannels = 1; // Number of channels used for the connection @@ -37,7 +39,9 @@ enum RoomMessageTypes { IdWifiPacket, IdChatMessage, IdNameCollision, - IdMacCollision + IdMacCollision, + IdVersionMismatch, + IdCloseRoom }; /// This is what a server [person creating a server] would use. diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp index ec67aa5be7..f6f8b0475c 100644 --- a/src/network/room_member.cpp +++ b/src/network/room_member.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include "common/assert.h" @@ -33,8 +34,10 @@ public: std::mutex network_mutex; ///< Mutex that controls access to the `client` variable. /// Thread that receives and dispatches network packets - std::unique_ptr receive_thread; - void ReceiveLoop(); + std::unique_ptr loop_thread; + std::mutex send_list_mutex; ///< Mutex that controls access to the `send_list` variable. + std::list send_list; ///< A list that stores all packets to send the async + void MemberLoop(); void StartLoop(); /** @@ -91,7 +94,7 @@ bool RoomMember::RoomMemberImpl::IsConnected() const { return state == State::Joining || state == State::Joined; } -void RoomMember::RoomMemberImpl::ReceiveLoop() { +void RoomMember::RoomMemberImpl::MemberLoop() { // Receive packets while the connection is open while (IsConnected()) { std::lock_guard lock(network_mutex); @@ -121,6 +124,9 @@ void RoomMember::RoomMemberImpl::ReceiveLoop() { case IdMacCollision: SetState(State::MacCollision); break; + case IdVersionMismatch: + SetState(State::WrongVersion); + break; default: break; } @@ -128,22 +134,30 @@ void RoomMember::RoomMemberImpl::ReceiveLoop() { break; case ENET_EVENT_TYPE_DISCONNECT: SetState(State::LostConnection); + break; } } + { + std::lock_guard 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() { - receive_thread = std::make_unique(&RoomMember::RoomMemberImpl::ReceiveLoop, this); + loop_thread = std::make_unique(&RoomMember::RoomMemberImpl::MemberLoop, this); } void RoomMember::RoomMemberImpl::Send(Packet& packet) { - std::lock_guard lock(network_mutex); - ENetPacket* enetPacket = - enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); - enet_peer_send(server, 0, enetPacket); - enet_host_flush(client); + std::lock_guard lock(send_list_mutex); + send_list.push_back(std::move(packet)); } void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname, @@ -152,6 +166,7 @@ void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname, packet << static_cast(IdJoinRequest); packet << nickname; packet << preferred_mac; + packet << network_version; Send(packet); } @@ -238,11 +253,9 @@ void RoomMember::RoomMemberImpl::Disconnect() { room_information.member_slots = 0; room_information.name.clear(); - if (server) { - enet_peer_disconnect(server, 0); - } else { + if (!server) return; - } + enet_peer_disconnect(server, 0); ENetEvent event; while (enet_host_service(client, &event, ConnectionTimeoutMs) > 0) { @@ -296,14 +309,14 @@ RoomInformation RoomMember::GetRoomInformation() const { void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port, u16 client_port) { // If the member is connected, kill the connection first - if (room_member_impl->receive_thread && room_member_impl->receive_thread->joinable()) { + if (room_member_impl->loop_thread && room_member_impl->loop_thread->joinable()) { room_member_impl->SetState(State::Error); - room_member_impl->receive_thread->join(); - room_member_impl->receive_thread.reset(); + 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->receive_thread) { - room_member_impl->receive_thread.reset(); + else if (room_member_impl->loop_thread) { + room_member_impl->loop_thread.reset(); } ENetAddress address{}; @@ -361,8 +374,8 @@ void RoomMember::SendGameName(const std::string& game_name) { void RoomMember::Leave() { room_member_impl->SetState(State::Idle); - room_member_impl->receive_thread->join(); - room_member_impl->receive_thread.reset(); + room_member_impl->loop_thread->join(); + room_member_impl->loop_thread.reset(); } } // namespace Network diff --git a/src/network/room_member.h b/src/network/room_member.h index d874cc5e4d..6522f053cf 100644 --- a/src/network/room_member.h +++ b/src/network/room_member.h @@ -47,6 +47,7 @@ public: // Reasons why connection was rejected NameCollision, ///< Somebody is already using this name MacCollision, ///< Somebody is already using that mac-address + WrongVersion, ///< The room version is not the same as for this RoomMember CouldNotConnect ///< The room is not responding to a connection attempt };