forked from suyu/suyu
Network: Made send async in RoomMember
This commit is contained in:
parent
859be35d54
commit
a0626221a5
4 changed files with 70 additions and 25 deletions
|
@ -73,6 +73,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void SendMacCollision(ENetPeer* client);
|
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,
|
* Notifies the member that its connection attempt was successful,
|
||||||
* and it is now part of the room.
|
* and it is now part of the room.
|
||||||
|
@ -170,6 +175,9 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
|
||||||
MacAddress preferred_mac;
|
MacAddress preferred_mac;
|
||||||
packet >> preferred_mac;
|
packet >> preferred_mac;
|
||||||
|
|
||||||
|
u32 client_version;
|
||||||
|
packet >> client_version;
|
||||||
|
|
||||||
if (!IsValidNickname(nickname)) {
|
if (!IsValidNickname(nickname)) {
|
||||||
SendNameCollision(event->peer);
|
SendNameCollision(event->peer);
|
||||||
return;
|
return;
|
||||||
|
@ -186,6 +194,11 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
|
||||||
preferred_mac = GenerateMacAddress();
|
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.
|
// At this point the client is ready to be added to the room.
|
||||||
Member member{};
|
Member member{};
|
||||||
member.mac_address = preferred_mac;
|
member.mac_address = preferred_mac;
|
||||||
|
@ -232,6 +245,17 @@ void Room::RoomImpl::SendMacCollision(ENetPeer* client) {
|
||||||
enet_host_flush(server);
|
enet_host_flush(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Room::RoomImpl::SendVersionMismatch(ENetPeer* client) {
|
||||||
|
Packet packet;
|
||||||
|
packet << static_cast<MessageID>(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) {
|
void Room::RoomImpl::SendJoinSuccess(ENetPeer* client, MacAddress mac_address) {
|
||||||
Packet packet;
|
Packet packet;
|
||||||
packet << static_cast<MessageID>(IdJoinSuccess);
|
packet << static_cast<MessageID>(IdJoinSuccess);
|
||||||
|
@ -291,7 +315,7 @@ void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) {
|
||||||
if (destination_address == BroadcastMac) { // Send the data to everyone except the sender
|
if (destination_address == BroadcastMac) { // Send the data to everyone except the sender
|
||||||
for (const auto& member : members) {
|
for (const auto& member : members) {
|
||||||
if (member.peer != event->peer)
|
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
|
} else { // Send the data only to the destination client
|
||||||
auto member = std::find_if(members.begin(), members.end(),
|
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(),
|
ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(),
|
||||||
ENET_PACKET_FLAG_RELIABLE);
|
ENET_PACKET_FLAG_RELIABLE);
|
||||||
for (auto it = members.begin(); it != members.end(); ++it) {
|
for (const auto& member : members) {
|
||||||
if (it->peer != event->peer)
|
if (member.peer != event->peer)
|
||||||
enet_peer_send(it->peer, 0, enet_packet);
|
enet_peer_send(member.peer, 0, enet_packet);
|
||||||
}
|
}
|
||||||
enet_host_flush(server);
|
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) {
|
void Room::Create(const std::string& name, const std::string& server_address, u16 server_port) {
|
||||||
ENetAddress address;
|
ENetAddress address;
|
||||||
address.host = ENET_HOST_ANY;
|
address.host = ENET_HOST_ANY;
|
||||||
|
if (!server_address.empty()) {
|
||||||
|
enet_address_set_host(&address, server_address.c_str());
|
||||||
|
}
|
||||||
address.port = server_port;
|
address.port = server_port;
|
||||||
|
|
||||||
room_impl->server = enet_host_create(&address, MaxConcurrentConnections, NumChannels, 0, 0);
|
room_impl->server = enet_host_create(&address, MaxConcurrentConnections, NumChannels, 0, 0);
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
|
||||||
|
constexpr u32 network_version = 1; ///< The version of this Room and RoomMember
|
||||||
|
|
||||||
constexpr u16 DefaultRoomPort = 1234;
|
constexpr u16 DefaultRoomPort = 1234;
|
||||||
constexpr size_t NumChannels = 1; // Number of channels used for the connection
|
constexpr size_t NumChannels = 1; // Number of channels used for the connection
|
||||||
|
|
||||||
|
@ -37,7 +39,9 @@ enum RoomMessageTypes {
|
||||||
IdWifiPacket,
|
IdWifiPacket,
|
||||||
IdChatMessage,
|
IdChatMessage,
|
||||||
IdNameCollision,
|
IdNameCollision,
|
||||||
IdMacCollision
|
IdMacCollision,
|
||||||
|
IdVersionMismatch,
|
||||||
|
IdCloseRoom
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is what a server [person creating a server] would use.
|
/// This is what a server [person creating a server] would use.
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <list>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
@ -33,8 +34,10 @@ public:
|
||||||
|
|
||||||
std::mutex network_mutex; ///< Mutex that controls access to the `client` variable.
|
std::mutex network_mutex; ///< Mutex that controls access to the `client` variable.
|
||||||
/// Thread that receives and dispatches network packets
|
/// Thread that receives and dispatches network packets
|
||||||
std::unique_ptr<std::thread> receive_thread;
|
std::unique_ptr<std::thread> loop_thread;
|
||||||
void ReceiveLoop();
|
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
|
||||||
|
void MemberLoop();
|
||||||
void StartLoop();
|
void StartLoop();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,7 +94,7 @@ bool RoomMember::RoomMemberImpl::IsConnected() const {
|
||||||
return state == State::Joining || state == State::Joined;
|
return state == State::Joining || state == State::Joined;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomMember::RoomMemberImpl::ReceiveLoop() {
|
void RoomMember::RoomMemberImpl::MemberLoop() {
|
||||||
// Receive packets while the connection is open
|
// Receive packets while the connection is open
|
||||||
while (IsConnected()) {
|
while (IsConnected()) {
|
||||||
std::lock_guard<std::mutex> lock(network_mutex);
|
std::lock_guard<std::mutex> lock(network_mutex);
|
||||||
|
@ -121,6 +124,9 @@ void RoomMember::RoomMemberImpl::ReceiveLoop() {
|
||||||
case IdMacCollision:
|
case IdMacCollision:
|
||||||
SetState(State::MacCollision);
|
SetState(State::MacCollision);
|
||||||
break;
|
break;
|
||||||
|
case IdVersionMismatch:
|
||||||
|
SetState(State::WrongVersion);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -128,22 +134,30 @@ void RoomMember::RoomMemberImpl::ReceiveLoop() {
|
||||||
break;
|
break;
|
||||||
case ENET_EVENT_TYPE_DISCONNECT:
|
case ENET_EVENT_TYPE_DISCONNECT:
|
||||||
SetState(State::LostConnection);
|
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();
|
Disconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
void RoomMember::RoomMemberImpl::StartLoop() {
|
void RoomMember::RoomMemberImpl::StartLoop() {
|
||||||
receive_thread = std::make_unique<std::thread>(&RoomMember::RoomMemberImpl::ReceiveLoop, this);
|
loop_thread = std::make_unique<std::thread>(&RoomMember::RoomMemberImpl::MemberLoop, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomMember::RoomMemberImpl::Send(Packet& packet) {
|
void RoomMember::RoomMemberImpl::Send(Packet& packet) {
|
||||||
std::lock_guard<std::mutex> lock(network_mutex);
|
std::lock_guard<std::mutex> lock(send_list_mutex);
|
||||||
ENetPacket* enetPacket =
|
send_list.push_back(std::move(packet));
|
||||||
enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
|
|
||||||
enet_peer_send(server, 0, enetPacket);
|
|
||||||
enet_host_flush(client);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname,
|
void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname,
|
||||||
|
@ -152,6 +166,7 @@ void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname,
|
||||||
packet << static_cast<MessageID>(IdJoinRequest);
|
packet << static_cast<MessageID>(IdJoinRequest);
|
||||||
packet << nickname;
|
packet << nickname;
|
||||||
packet << preferred_mac;
|
packet << preferred_mac;
|
||||||
|
packet << network_version;
|
||||||
Send(packet);
|
Send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,11 +253,9 @@ void RoomMember::RoomMemberImpl::Disconnect() {
|
||||||
room_information.member_slots = 0;
|
room_information.member_slots = 0;
|
||||||
room_information.name.clear();
|
room_information.name.clear();
|
||||||
|
|
||||||
if (server) {
|
if (!server)
|
||||||
enet_peer_disconnect(server, 0);
|
|
||||||
} else {
|
|
||||||
return;
|
return;
|
||||||
}
|
enet_peer_disconnect(server, 0);
|
||||||
|
|
||||||
ENetEvent event;
|
ENetEvent event;
|
||||||
while (enet_host_service(client, &event, ConnectionTimeoutMs) > 0) {
|
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,
|
void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port,
|
||||||
u16 client_port) {
|
u16 client_port) {
|
||||||
// If the member is connected, kill the connection first
|
// 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->SetState(State::Error);
|
||||||
room_member_impl->receive_thread->join();
|
room_member_impl->loop_thread->join();
|
||||||
room_member_impl->receive_thread.reset();
|
room_member_impl->loop_thread.reset();
|
||||||
}
|
}
|
||||||
// If the thread isn't running but the ptr still exists, reset it
|
// If the thread isn't running but the ptr still exists, reset it
|
||||||
else if (room_member_impl->receive_thread) {
|
else if (room_member_impl->loop_thread) {
|
||||||
room_member_impl->receive_thread.reset();
|
room_member_impl->loop_thread.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
ENetAddress address{};
|
ENetAddress address{};
|
||||||
|
@ -361,8 +374,8 @@ void RoomMember::SendGameName(const std::string& game_name) {
|
||||||
|
|
||||||
void RoomMember::Leave() {
|
void RoomMember::Leave() {
|
||||||
room_member_impl->SetState(State::Idle);
|
room_member_impl->SetState(State::Idle);
|
||||||
room_member_impl->receive_thread->join();
|
room_member_impl->loop_thread->join();
|
||||||
room_member_impl->receive_thread.reset();
|
room_member_impl->loop_thread.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Network
|
} // namespace Network
|
||||||
|
|
|
@ -47,6 +47,7 @@ public:
|
||||||
// Reasons why connection was rejected
|
// Reasons why connection was rejected
|
||||||
NameCollision, ///< Somebody is already using this name
|
NameCollision, ///< Somebody is already using this name
|
||||||
MacCollision, ///< Somebody is already using that mac-address
|
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
|
CouldNotConnect ///< The room is not responding to a connection attempt
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue