diff options
Diffstat (limited to 'src/network/room.cpp')
| -rw-r--r-- | src/network/room.cpp | 84 |
1 files changed, 63 insertions, 21 deletions
diff --git a/src/network/room.cpp b/src/network/room.cpp index fbbaf8b93..261049ab0 100644 --- a/src/network/room.cpp +++ b/src/network/room.cpp | |||
| @@ -4,9 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <atomic> | 6 | #include <atomic> |
| 7 | #include <mutex> | ||
| 7 | #include <random> | 8 | #include <random> |
| 8 | #include <thread> | 9 | #include <thread> |
| 9 | #include <vector> | ||
| 10 | #include "enet/enet.h" | 10 | #include "enet/enet.h" |
| 11 | #include "network/packet.h" | 11 | #include "network/packet.h" |
| 12 | #include "network/room.h" | 12 | #include "network/room.h" |
| @@ -29,12 +29,14 @@ public: | |||
| 29 | 29 | ||
| 30 | struct Member { | 30 | struct Member { |
| 31 | std::string nickname; ///< The nickname of the member. | 31 | std::string nickname; ///< The nickname of the member. |
| 32 | std::string game_name; ///< The current game of the member | 32 | GameInfo game_info; ///< The current game of the member |
| 33 | MacAddress mac_address; ///< The assigned mac address of the member. | 33 | MacAddress mac_address; ///< The assigned mac address of the member. |
| 34 | ENetPeer* peer; ///< The remote peer. | 34 | ENetPeer* peer; ///< The remote peer. |
| 35 | }; | 35 | }; |
| 36 | using MemberList = std::vector<Member>; | 36 | using MemberList = std::vector<Member>; |
| 37 | MemberList members; ///< Information about the members of this room. | 37 | MemberList members; ///< Information about the members of this room |
| 38 | mutable std::mutex member_mutex; ///< Mutex for locking the members list | ||
| 39 | /// This should be a std::shared_mutex as soon as C++17 is supported | ||
| 38 | 40 | ||
| 39 | RoomImpl() | 41 | RoomImpl() |
| 40 | : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {} | 42 | : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {} |
| @@ -147,7 +149,7 @@ void Room::RoomImpl::ServerLoop() { | |||
| 147 | case IdJoinRequest: | 149 | case IdJoinRequest: |
| 148 | HandleJoinRequest(&event); | 150 | HandleJoinRequest(&event); |
| 149 | break; | 151 | break; |
| 150 | case IdSetGameName: | 152 | case IdSetGameInfo: |
| 151 | HandleGameNamePacket(&event); | 153 | HandleGameNamePacket(&event); |
| 152 | break; | 154 | break; |
| 153 | case IdWifiPacket: | 155 | case IdWifiPacket: |
| @@ -213,7 +215,10 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||
| 213 | member.nickname = nickname; | 215 | member.nickname = nickname; |
| 214 | member.peer = event->peer; | 216 | member.peer = event->peer; |
| 215 | 217 | ||
| 216 | members.push_back(std::move(member)); | 218 | { |
| 219 | std::lock_guard<std::mutex> lock(member_mutex); | ||
| 220 | members.push_back(std::move(member)); | ||
| 221 | } | ||
| 217 | 222 | ||
| 218 | // Notify everyone that the room information has changed. | 223 | // Notify everyone that the room information has changed. |
| 219 | BroadcastRoomInformation(); | 224 | BroadcastRoomInformation(); |
| @@ -223,12 +228,14 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||
| 223 | bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const { | 228 | bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const { |
| 224 | // A nickname is valid if it is not already taken by anybody else in the room. | 229 | // A nickname is valid if it is not already taken by anybody else in the room. |
| 225 | // TODO(B3N30): Check for empty names, spaces, etc. | 230 | // TODO(B3N30): Check for empty names, spaces, etc. |
| 231 | std::lock_guard<std::mutex> lock(member_mutex); | ||
| 226 | return std::all_of(members.begin(), members.end(), | 232 | return std::all_of(members.begin(), members.end(), |
| 227 | [&nickname](const auto& member) { return member.nickname != nickname; }); | 233 | [&nickname](const auto& member) { return member.nickname != nickname; }); |
| 228 | } | 234 | } |
| 229 | 235 | ||
| 230 | bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const { | 236 | bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const { |
| 231 | // A MAC address is valid if it is not already taken by anybody else in the room. | 237 | // A MAC address is valid if it is not already taken by anybody else in the room. |
| 238 | std::lock_guard<std::mutex> lock(member_mutex); | ||
| 232 | return std::all_of(members.begin(), members.end(), | 239 | return std::all_of(members.begin(), members.end(), |
| 233 | [&address](const auto& member) { return member.mac_address != address; }); | 240 | [&address](const auto& member) { return member.mac_address != address; }); |
| 234 | } | 241 | } |
| @@ -279,6 +286,7 @@ void Room::RoomImpl::SendCloseMessage() { | |||
| 279 | packet << static_cast<u8>(IdCloseRoom); | 286 | packet << static_cast<u8>(IdCloseRoom); |
| 280 | ENetPacket* enet_packet = | 287 | ENetPacket* enet_packet = |
| 281 | enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); | 288 | enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); |
| 289 | std::lock_guard<std::mutex> lock(member_mutex); | ||
| 282 | for (auto& member : members) { | 290 | for (auto& member : members) { |
| 283 | enet_peer_send(member.peer, 0, enet_packet); | 291 | enet_peer_send(member.peer, 0, enet_packet); |
| 284 | } | 292 | } |
| @@ -295,10 +303,14 @@ void Room::RoomImpl::BroadcastRoomInformation() { | |||
| 295 | packet << room_information.member_slots; | 303 | packet << room_information.member_slots; |
| 296 | 304 | ||
| 297 | packet << static_cast<u32>(members.size()); | 305 | packet << static_cast<u32>(members.size()); |
| 298 | for (const auto& member : members) { | 306 | { |
| 299 | packet << member.nickname; | 307 | std::lock_guard<std::mutex> lock(member_mutex); |
| 300 | packet << member.mac_address; | 308 | for (const auto& member : members) { |
| 301 | packet << member.game_name; | 309 | packet << member.nickname; |
| 310 | packet << member.mac_address; | ||
| 311 | packet << member.game_info.name; | ||
| 312 | packet << member.game_info.id; | ||
| 313 | } | ||
| 302 | } | 314 | } |
| 303 | 315 | ||
| 304 | ENetPacket* enet_packet = | 316 | ENetPacket* enet_packet = |
| @@ -335,11 +347,13 @@ void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) { | |||
| 335 | ENET_PACKET_FLAG_RELIABLE); | 347 | ENET_PACKET_FLAG_RELIABLE); |
| 336 | 348 | ||
| 337 | if (destination_address == BroadcastMac) { // Send the data to everyone except the sender | 349 | if (destination_address == BroadcastMac) { // Send the data to everyone except the sender |
| 350 | std::lock_guard<std::mutex> lock(member_mutex); | ||
| 338 | for (const auto& member : members) { | 351 | for (const auto& member : members) { |
| 339 | if (member.peer != event->peer) | 352 | if (member.peer != event->peer) |
| 340 | enet_peer_send(member.peer, 0, enet_packet); | 353 | enet_peer_send(member.peer, 0, enet_packet); |
| 341 | } | 354 | } |
| 342 | } else { // Send the data only to the destination client | 355 | } else { // Send the data only to the destination client |
| 356 | std::lock_guard<std::mutex> lock(member_mutex); | ||
| 343 | auto member = std::find_if(members.begin(), members.end(), | 357 | auto member = std::find_if(members.begin(), members.end(), |
| 344 | [destination_address](const Member& member) -> bool { | 358 | [destination_address](const Member& member) -> bool { |
| 345 | return member.mac_address == destination_address; | 359 | return member.mac_address == destination_address; |
| @@ -361,6 +375,8 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { | |||
| 361 | auto CompareNetworkAddress = [event](const Member member) -> bool { | 375 | auto CompareNetworkAddress = [event](const Member member) -> bool { |
| 362 | return member.peer == event->peer; | 376 | return member.peer == event->peer; |
| 363 | }; | 377 | }; |
| 378 | |||
| 379 | std::lock_guard<std::mutex> lock(member_mutex); | ||
| 364 | const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress); | 380 | const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress); |
| 365 | if (sending_member == members.end()) { | 381 | if (sending_member == members.end()) { |
| 366 | return; // Received a chat message from a unknown sender | 382 | return; // Received a chat message from a unknown sender |
| @@ -385,22 +401,32 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) { | |||
| 385 | in_packet.Append(event->packet->data, event->packet->dataLength); | 401 | in_packet.Append(event->packet->data, event->packet->dataLength); |
| 386 | 402 | ||
| 387 | in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type | 403 | in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type |
| 388 | std::string game_name; | 404 | GameInfo game_info; |
| 389 | in_packet >> game_name; | 405 | in_packet >> game_info.name; |
| 390 | auto member = | 406 | in_packet >> game_info.id; |
| 391 | std::find_if(members.begin(), members.end(), | 407 | |
| 392 | [event](const Member& member) -> bool { return member.peer == event->peer; }); | 408 | { |
| 393 | if (member != members.end()) { | 409 | std::lock_guard<std::mutex> lock(member_mutex); |
| 394 | member->game_name = game_name; | 410 | auto member = |
| 395 | BroadcastRoomInformation(); | 411 | std::find_if(members.begin(), members.end(), [event](const Member& member) -> bool { |
| 412 | return member.peer == event->peer; | ||
| 413 | }); | ||
| 414 | if (member != members.end()) { | ||
| 415 | member->game_info = game_info; | ||
| 416 | } | ||
| 396 | } | 417 | } |
| 418 | BroadcastRoomInformation(); | ||
| 397 | } | 419 | } |
| 398 | 420 | ||
| 399 | void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { | 421 | void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { |
| 400 | // Remove the client from the members list. | 422 | // Remove the client from the members list. |
| 401 | members.erase(std::remove_if(members.begin(), members.end(), | 423 | { |
| 402 | [client](const Member& member) { return member.peer == client; }), | 424 | std::lock_guard<std::mutex> lock(member_mutex); |
| 403 | members.end()); | 425 | members.erase( |
| 426 | std::remove_if(members.begin(), members.end(), | ||
| 427 | [client](const Member& member) { return member.peer == client; }), | ||
| 428 | members.end()); | ||
| 429 | } | ||
| 404 | 430 | ||
| 405 | // Announce the change to all clients. | 431 | // Announce the change to all clients. |
| 406 | enet_peer_disconnect(client, 0); | 432 | enet_peer_disconnect(client, 0); |
| @@ -437,6 +463,19 @@ const RoomInformation& Room::GetRoomInformation() const { | |||
| 437 | return room_impl->room_information; | 463 | return room_impl->room_information; |
| 438 | } | 464 | } |
| 439 | 465 | ||
| 466 | std::vector<Room::Member> Room::GetRoomMemberList() const { | ||
| 467 | std::vector<Room::Member> member_list; | ||
| 468 | std::lock_guard<std::mutex> lock(room_impl->member_mutex); | ||
| 469 | for (const auto& member_impl : room_impl->members) { | ||
| 470 | Member member; | ||
| 471 | member.nickname = member_impl.nickname; | ||
| 472 | member.mac_address = member_impl.mac_address; | ||
| 473 | member.game_info = member_impl.game_info; | ||
| 474 | member_list.push_back(member); | ||
| 475 | } | ||
| 476 | return member_list; | ||
| 477 | }; | ||
| 478 | |||
| 440 | void Room::Destroy() { | 479 | void Room::Destroy() { |
| 441 | room_impl->state = State::Closed; | 480 | room_impl->state = State::Closed; |
| 442 | room_impl->room_thread->join(); | 481 | room_impl->room_thread->join(); |
| @@ -447,7 +486,10 @@ void Room::Destroy() { | |||
| 447 | } | 486 | } |
| 448 | room_impl->room_information = {}; | 487 | room_impl->room_information = {}; |
| 449 | room_impl->server = nullptr; | 488 | room_impl->server = nullptr; |
| 450 | room_impl->members.clear(); | 489 | { |
| 490 | std::lock_guard<std::mutex> lock(room_impl->member_mutex); | ||
| 491 | room_impl->members.clear(); | ||
| 492 | } | ||
| 451 | room_impl->room_information.member_slots = 0; | 493 | room_impl->room_information.member_slots = 0; |
| 452 | room_impl->room_information.name.clear(); | 494 | room_impl->room_information.name.clear(); |
| 453 | } | 495 | } |