summaryrefslogtreecommitdiff
path: root/src/network/room.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/room.cpp')
-rw-r--r--src/network/room.cpp89
1 files changed, 66 insertions, 23 deletions
diff --git a/src/network/room.cpp b/src/network/room.cpp
index 8b7915bb7..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"
@@ -19,7 +19,7 @@ static constexpr u32 MaxConcurrentConnections = 10;
19class Room::RoomImpl { 19class Room::RoomImpl {
20public: 20public:
21 // This MAC address is used to generate a 'Nintendo' like Mac address. 21 // This MAC address is used to generate a 'Nintendo' like Mac address.
22 const MacAddress NintendoOUI = {0x00, 0x1F, 0x32, 0x00, 0x00, 0x00}; 22 const MacAddress NintendoOUI;
23 std::mt19937 random_gen; ///< Random number generator. Used for GenerateMacAddress 23 std::mt19937 random_gen; ///< Random number generator. Used for GenerateMacAddress
24 24
25 ENetHost* server = nullptr; ///< Network interface. 25 ENetHost* server = nullptr; ///< Network interface.
@@ -29,14 +29,17 @@ 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() : random_gen(std::random_device()()) {} 41 RoomImpl()
42 : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {}
40 43
41 /// Thread that receives and dispatches network packets 44 /// Thread that receives and dispatches network packets
42 std::unique_ptr<std::thread> room_thread; 45 std::unique_ptr<std::thread> room_thread;
@@ -146,7 +149,7 @@ void Room::RoomImpl::ServerLoop() {
146 case IdJoinRequest: 149 case IdJoinRequest:
147 HandleJoinRequest(&event); 150 HandleJoinRequest(&event);
148 break; 151 break;
149 case IdSetGameName: 152 case IdSetGameInfo:
150 HandleGameNamePacket(&event); 153 HandleGameNamePacket(&event);
151 break; 154 break;
152 case IdWifiPacket: 155 case IdWifiPacket:
@@ -212,7 +215,10 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
212 member.nickname = nickname; 215 member.nickname = nickname;
213 member.peer = event->peer; 216 member.peer = event->peer;
214 217
215 members.push_back(std::move(member)); 218 {
219 std::lock_guard<std::mutex> lock(member_mutex);
220 members.push_back(std::move(member));
221 }
216 222
217 // Notify everyone that the room information has changed. 223 // Notify everyone that the room information has changed.
218 BroadcastRoomInformation(); 224 BroadcastRoomInformation();
@@ -222,12 +228,14 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
222bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const { 228bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const {
223 // 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.
224 // 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);
225 return std::all_of(members.begin(), members.end(), 232 return std::all_of(members.begin(), members.end(),
226 [&nickname](const auto& member) { return member.nickname != nickname; }); 233 [&nickname](const auto& member) { return member.nickname != nickname; });
227} 234}
228 235
229bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const { 236bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const {
230 // 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);
231 return std::all_of(members.begin(), members.end(), 239 return std::all_of(members.begin(), members.end(),
232 [&address](const auto& member) { return member.mac_address != address; }); 240 [&address](const auto& member) { return member.mac_address != address; });
233} 241}
@@ -278,6 +286,7 @@ void Room::RoomImpl::SendCloseMessage() {
278 packet << static_cast<u8>(IdCloseRoom); 286 packet << static_cast<u8>(IdCloseRoom);
279 ENetPacket* enet_packet = 287 ENetPacket* enet_packet =
280 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);
281 for (auto& member : members) { 290 for (auto& member : members) {
282 enet_peer_send(member.peer, 0, enet_packet); 291 enet_peer_send(member.peer, 0, enet_packet);
283 } 292 }
@@ -294,10 +303,14 @@ void Room::RoomImpl::BroadcastRoomInformation() {
294 packet << room_information.member_slots; 303 packet << room_information.member_slots;
295 304
296 packet << static_cast<u32>(members.size()); 305 packet << static_cast<u32>(members.size());
297 for (const auto& member : members) { 306 {
298 packet << member.nickname; 307 std::lock_guard<std::mutex> lock(member_mutex);
299 packet << member.mac_address; 308 for (const auto& member : members) {
300 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 }
301 } 314 }
302 315
303 ENetPacket* enet_packet = 316 ENetPacket* enet_packet =
@@ -334,11 +347,13 @@ void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) {
334 ENET_PACKET_FLAG_RELIABLE); 347 ENET_PACKET_FLAG_RELIABLE);
335 348
336 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);
337 for (const auto& member : members) { 351 for (const auto& member : members) {
338 if (member.peer != event->peer) 352 if (member.peer != event->peer)
339 enet_peer_send(member.peer, 0, enet_packet); 353 enet_peer_send(member.peer, 0, enet_packet);
340 } 354 }
341 } 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);
342 auto member = std::find_if(members.begin(), members.end(), 357 auto member = std::find_if(members.begin(), members.end(),
343 [destination_address](const Member& member) -> bool { 358 [destination_address](const Member& member) -> bool {
344 return member.mac_address == destination_address; 359 return member.mac_address == destination_address;
@@ -360,6 +375,8 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) {
360 auto CompareNetworkAddress = [event](const Member member) -> bool { 375 auto CompareNetworkAddress = [event](const Member member) -> bool {
361 return member.peer == event->peer; 376 return member.peer == event->peer;
362 }; 377 };
378
379 std::lock_guard<std::mutex> lock(member_mutex);
363 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);
364 if (sending_member == members.end()) { 381 if (sending_member == members.end()) {
365 return; // Received a chat message from a unknown sender 382 return; // Received a chat message from a unknown sender
@@ -384,22 +401,32 @@ void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) {
384 in_packet.Append(event->packet->data, event->packet->dataLength); 401 in_packet.Append(event->packet->data, event->packet->dataLength);
385 402
386 in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type 403 in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
387 std::string game_name; 404 GameInfo game_info;
388 in_packet >> game_name; 405 in_packet >> game_info.name;
389 auto member = 406 in_packet >> game_info.id;
390 std::find_if(members.begin(), members.end(), 407
391 [event](const Member& member) -> bool { return member.peer == event->peer; }); 408 {
392 if (member != members.end()) { 409 std::lock_guard<std::mutex> lock(member_mutex);
393 member->game_name = game_name; 410 auto member =
394 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 }
395 } 417 }
418 BroadcastRoomInformation();
396} 419}
397 420
398void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { 421void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) {
399 // Remove the client from the members list. 422 // Remove the client from the members list.
400 members.erase(std::remove_if(members.begin(), members.end(), 423 {
401 [client](const Member& member) { return member.peer == client; }), 424 std::lock_guard<std::mutex> lock(member_mutex);
402 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 }
403 430
404 // Announce the change to all clients. 431 // Announce the change to all clients.
405 enet_peer_disconnect(client, 0); 432 enet_peer_disconnect(client, 0);
@@ -436,6 +463,19 @@ const RoomInformation& Room::GetRoomInformation() const {
436 return room_impl->room_information; 463 return room_impl->room_information;
437} 464}
438 465
466std::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
439void Room::Destroy() { 479void Room::Destroy() {
440 room_impl->state = State::Closed; 480 room_impl->state = State::Closed;
441 room_impl->room_thread->join(); 481 room_impl->room_thread->join();
@@ -446,7 +486,10 @@ void Room::Destroy() {
446 } 486 }
447 room_impl->room_information = {}; 487 room_impl->room_information = {};
448 room_impl->server = nullptr; 488 room_impl->server = nullptr;
449 room_impl->members.clear(); 489 {
490 std::lock_guard<std::mutex> lock(room_impl->member_mutex);
491 room_impl->members.clear();
492 }
450 room_impl->room_information.member_slots = 0; 493 room_impl->room_information.member_slots = 0;
451 room_impl->room_information.name.clear(); 494 room_impl->room_information.name.clear();
452} 495}