summaryrefslogtreecommitdiff
path: root/src/network/room.cpp
diff options
context:
space:
mode:
authorGravatar James Rowe2018-01-11 19:21:20 -0700
committerGravatar James Rowe2018-01-12 19:11:03 -0700
commitebf9a784a9f7f4148a669dbb39e7cd50df779a14 (patch)
treed585685a1c0a34b903af1d086d62560bf56bb29f /src/network/room.cpp
parentconfig: Default CPU core to Unicorn. (diff)
downloadyuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar.gz
yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.tar.xz
yuzu-ebf9a784a9f7f4148a669dbb39e7cd50df779a14.zip
Massive removal of unused modules
Diffstat (limited to 'src/network/room.cpp')
-rw-r--r--src/network/room.cpp497
1 files changed, 0 insertions, 497 deletions
diff --git a/src/network/room.cpp b/src/network/room.cpp
deleted file mode 100644
index 261049ab0..000000000
--- a/src/network/room.cpp
+++ /dev/null
@@ -1,497 +0,0 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <atomic>
7#include <mutex>
8#include <random>
9#include <thread>
10#include "enet/enet.h"
11#include "network/packet.h"
12#include "network/room.h"
13
14namespace Network {
15
16/// Maximum number of concurrent connections allowed to this room.
17static constexpr u32 MaxConcurrentConnections = 10;
18
19class Room::RoomImpl {
20public:
21 // This MAC address is used to generate a 'Nintendo' like Mac address.
22 const MacAddress NintendoOUI;
23 std::mt19937 random_gen; ///< Random number generator. Used for GenerateMacAddress
24
25 ENetHost* server = nullptr; ///< Network interface.
26
27 std::atomic<State> state{State::Closed}; ///< Current state of the room.
28 RoomInformation room_information; ///< Information about this room.
29
30 struct Member {
31 std::string nickname; ///< The nickname of the member.
32 GameInfo game_info; ///< The current game of the member
33 MacAddress mac_address; ///< The assigned mac address of the member.
34 ENetPeer* peer; ///< The remote peer.
35 };
36 using MemberList = std::vector<Member>;
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
40
41 RoomImpl()
42 : random_gen(std::random_device()()), NintendoOUI{0x00, 0x1F, 0x32, 0x00, 0x00, 0x00} {}
43
44 /// Thread that receives and dispatches network packets
45 std::unique_ptr<std::thread> room_thread;
46
47 /// Thread function that will receive and dispatch messages until the room is destroyed.
48 void ServerLoop();
49 void StartLoop();
50
51 /**
52 * Parses and answers a room join request from a client.
53 * Validates the uniqueness of the username and assigns the MAC address
54 * that the client will use for the remainder of the connection.
55 */
56 void HandleJoinRequest(const ENetEvent* event);
57
58 /**
59 * Returns whether the nickname is valid, ie. isn't already taken by someone else in the room.
60 */
61 bool IsValidNickname(const std::string& nickname) const;
62
63 /**
64 * Returns whether the MAC address is valid, ie. isn't already taken by someone else in the
65 * room.
66 */
67 bool IsValidMacAddress(const MacAddress& address) const;
68
69 /**
70 * Sends a ID_ROOM_NAME_COLLISION message telling the client that the name is invalid.
71 */
72 void SendNameCollision(ENetPeer* client);
73
74 /**
75 * Sends a ID_ROOM_MAC_COLLISION message telling the client that the MAC is invalid.
76 */
77 void SendMacCollision(ENetPeer* client);
78
79 /**
80 * Sends a ID_ROOM_VERSION_MISMATCH message telling the client that the version is invalid.
81 */
82 void SendVersionMismatch(ENetPeer* client);
83
84 /**
85 * Notifies the member that its connection attempt was successful,
86 * and it is now part of the room.
87 */
88 void SendJoinSuccess(ENetPeer* client, MacAddress mac_address);
89
90 /**
91 * Notifies the members that the room is closed,
92 */
93 void SendCloseMessage();
94
95 /**
96 * Sends the information about the room, along with the list of members
97 * to every connected client in the room.
98 * The packet has the structure:
99 * <MessageID>ID_ROOM_INFORMATION
100 * <String> room_name
101 * <u32> member_slots: The max number of clients allowed in this room
102 * <u32> num_members: the number of currently joined clients
103 * This is followed by the following three values for each member:
104 * <String> nickname of that member
105 * <MacAddress> mac_address of that member
106 * <String> game_name of that member
107 */
108 void BroadcastRoomInformation();
109
110 /**
111 * Generates a free MAC address to assign to a new client.
112 * The first 3 bytes are the NintendoOUI 0x00, 0x1F, 0x32
113 */
114 MacAddress GenerateMacAddress();
115
116 /**
117 * Broadcasts this packet to all members except the sender.
118 * @param event The ENet event containing the data
119 */
120 void HandleWifiPacket(const ENetEvent* event);
121
122 /**
123 * Extracts a chat entry from a received ENet packet and adds it to the chat queue.
124 * @param event The ENet event that was received.
125 */
126 void HandleChatPacket(const ENetEvent* event);
127
128 /**
129 * Extracts the game name from a received ENet packet and broadcasts it.
130 * @param event The ENet event that was received.
131 */
132 void HandleGameNamePacket(const ENetEvent* event);
133
134 /**
135 * Removes the client from the members list if it was in it and announces the change
136 * to all other clients.
137 */
138 void HandleClientDisconnection(ENetPeer* client);
139};
140
141// RoomImpl
142void Room::RoomImpl::ServerLoop() {
143 while (state != State::Closed) {
144 ENetEvent event;
145 if (enet_host_service(server, &event, 100) > 0) {
146 switch (event.type) {
147 case ENET_EVENT_TYPE_RECEIVE:
148 switch (event.packet->data[0]) {
149 case IdJoinRequest:
150 HandleJoinRequest(&event);
151 break;
152 case IdSetGameInfo:
153 HandleGameNamePacket(&event);
154 break;
155 case IdWifiPacket:
156 HandleWifiPacket(&event);
157 break;
158 case IdChatMessage:
159 HandleChatPacket(&event);
160 break;
161 }
162 enet_packet_destroy(event.packet);
163 break;
164 case ENET_EVENT_TYPE_DISCONNECT:
165 HandleClientDisconnection(event.peer);
166 break;
167 }
168 }
169 }
170 // Close the connection to all members:
171 SendCloseMessage();
172}
173
174void Room::RoomImpl::StartLoop() {
175 room_thread = std::make_unique<std::thread>(&Room::RoomImpl::ServerLoop, this);
176}
177
178void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
179 Packet packet;
180 packet.Append(event->packet->data, event->packet->dataLength);
181 packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
182 std::string nickname;
183 packet >> nickname;
184
185 MacAddress preferred_mac;
186 packet >> preferred_mac;
187
188 u32 client_version;
189 packet >> client_version;
190
191 if (!IsValidNickname(nickname)) {
192 SendNameCollision(event->peer);
193 return;
194 }
195
196 if (preferred_mac != NoPreferredMac) {
197 // Verify if the preferred mac is available
198 if (!IsValidMacAddress(preferred_mac)) {
199 SendMacCollision(event->peer);
200 return;
201 }
202 } else {
203 // Assign a MAC address of this client automatically
204 preferred_mac = GenerateMacAddress();
205 }
206
207 if (client_version != network_version) {
208 SendVersionMismatch(event->peer);
209 return;
210 }
211
212 // At this point the client is ready to be added to the room.
213 Member member{};
214 member.mac_address = preferred_mac;
215 member.nickname = nickname;
216 member.peer = event->peer;
217
218 {
219 std::lock_guard<std::mutex> lock(member_mutex);
220 members.push_back(std::move(member));
221 }
222
223 // Notify everyone that the room information has changed.
224 BroadcastRoomInformation();
225 SendJoinSuccess(event->peer, preferred_mac);
226}
227
228bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const {
229 // A nickname is valid if it is not already taken by anybody else in the room.
230 // TODO(B3N30): Check for empty names, spaces, etc.
231 std::lock_guard<std::mutex> lock(member_mutex);
232 return std::all_of(members.begin(), members.end(),
233 [&nickname](const auto& member) { return member.nickname != nickname; });
234}
235
236bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const {
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);
239 return std::all_of(members.begin(), members.end(),
240 [&address](const auto& member) { return member.mac_address != address; });
241}
242
243void Room::RoomImpl::SendNameCollision(ENetPeer* client) {
244 Packet packet;
245 packet << static_cast<u8>(IdNameCollision);
246
247 ENetPacket* enet_packet =
248 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
249 enet_peer_send(client, 0, enet_packet);
250 enet_host_flush(server);
251}
252
253void Room::RoomImpl::SendMacCollision(ENetPeer* client) {
254 Packet packet;
255 packet << static_cast<u8>(IdMacCollision);
256
257 ENetPacket* enet_packet =
258 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
259 enet_peer_send(client, 0, enet_packet);
260 enet_host_flush(server);
261}
262
263void Room::RoomImpl::SendVersionMismatch(ENetPeer* client) {
264 Packet packet;
265 packet << static_cast<u8>(IdVersionMismatch);
266 packet << network_version;
267
268 ENetPacket* enet_packet =
269 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
270 enet_peer_send(client, 0, enet_packet);
271 enet_host_flush(server);
272}
273
274void Room::RoomImpl::SendJoinSuccess(ENetPeer* client, MacAddress mac_address) {
275 Packet packet;
276 packet << static_cast<u8>(IdJoinSuccess);
277 packet << mac_address;
278 ENetPacket* enet_packet =
279 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
280 enet_peer_send(client, 0, enet_packet);
281 enet_host_flush(server);
282}
283
284void Room::RoomImpl::SendCloseMessage() {
285 Packet packet;
286 packet << static_cast<u8>(IdCloseRoom);
287 ENetPacket* enet_packet =
288 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
289 std::lock_guard<std::mutex> lock(member_mutex);
290 for (auto& member : members) {
291 enet_peer_send(member.peer, 0, enet_packet);
292 }
293 enet_host_flush(server);
294 for (auto& member : members) {
295 enet_peer_disconnect(member.peer, 0);
296 }
297}
298
299void Room::RoomImpl::BroadcastRoomInformation() {
300 Packet packet;
301 packet << static_cast<u8>(IdRoomInformation);
302 packet << room_information.name;
303 packet << room_information.member_slots;
304
305 packet << static_cast<u32>(members.size());
306 {
307 std::lock_guard<std::mutex> lock(member_mutex);
308 for (const auto& member : members) {
309 packet << member.nickname;
310 packet << member.mac_address;
311 packet << member.game_info.name;
312 packet << member.game_info.id;
313 }
314 }
315
316 ENetPacket* enet_packet =
317 enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
318 enet_host_broadcast(server, 0, enet_packet);
319 enet_host_flush(server);
320}
321
322MacAddress Room::RoomImpl::GenerateMacAddress() {
323 MacAddress result_mac =
324 NintendoOUI; // The first three bytes of each MAC address will be the NintendoOUI
325 std::uniform_int_distribution<> dis(0x00, 0xFF); // Random byte between 0 and 0xFF
326 do {
327 for (size_t i = 3; i < result_mac.size(); ++i) {
328 result_mac[i] = dis(random_gen);
329 }
330 } while (!IsValidMacAddress(result_mac));
331 return result_mac;
332}
333
334void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) {
335 Packet in_packet;
336 in_packet.Append(event->packet->data, event->packet->dataLength);
337 in_packet.IgnoreBytes(sizeof(u8)); // Message type
338 in_packet.IgnoreBytes(sizeof(u8)); // WifiPacket Type
339 in_packet.IgnoreBytes(sizeof(u8)); // WifiPacket Channel
340 in_packet.IgnoreBytes(sizeof(MacAddress)); // WifiPacket Transmitter Address
341 MacAddress destination_address;
342 in_packet >> destination_address;
343
344 Packet out_packet;
345 out_packet.Append(event->packet->data, event->packet->dataLength);
346 ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(),
347 ENET_PACKET_FLAG_RELIABLE);
348
349 if (destination_address == BroadcastMac) { // Send the data to everyone except the sender
350 std::lock_guard<std::mutex> lock(member_mutex);
351 for (const auto& member : members) {
352 if (member.peer != event->peer)
353 enet_peer_send(member.peer, 0, enet_packet);
354 }
355 } else { // Send the data only to the destination client
356 std::lock_guard<std::mutex> lock(member_mutex);
357 auto member = std::find_if(members.begin(), members.end(),
358 [destination_address](const Member& member) -> bool {
359 return member.mac_address == destination_address;
360 });
361 if (member != members.end()) {
362 enet_peer_send(member->peer, 0, enet_packet);
363 }
364 }
365 enet_host_flush(server);
366}
367
368void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) {
369 Packet in_packet;
370 in_packet.Append(event->packet->data, event->packet->dataLength);
371
372 in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
373 std::string message;
374 in_packet >> message;
375 auto CompareNetworkAddress = [event](const Member member) -> bool {
376 return member.peer == event->peer;
377 };
378
379 std::lock_guard<std::mutex> lock(member_mutex);
380 const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress);
381 if (sending_member == members.end()) {
382 return; // Received a chat message from a unknown sender
383 }
384
385 Packet out_packet;
386 out_packet << static_cast<u8>(IdChatMessage);
387 out_packet << sending_member->nickname;
388 out_packet << message;
389
390 ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(),
391 ENET_PACKET_FLAG_RELIABLE);
392 for (const auto& member : members) {
393 if (member.peer != event->peer)
394 enet_peer_send(member.peer, 0, enet_packet);
395 }
396 enet_host_flush(server);
397}
398
399void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) {
400 Packet in_packet;
401 in_packet.Append(event->packet->data, event->packet->dataLength);
402
403 in_packet.IgnoreBytes(sizeof(u8)); // Igonore the message type
404 GameInfo game_info;
405 in_packet >> game_info.name;
406 in_packet >> game_info.id;
407
408 {
409 std::lock_guard<std::mutex> lock(member_mutex);
410 auto member =
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 }
417 }
418 BroadcastRoomInformation();
419}
420
421void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) {
422 // Remove the client from the members list.
423 {
424 std::lock_guard<std::mutex> lock(member_mutex);
425 members.erase(
426 std::remove_if(members.begin(), members.end(),
427 [client](const Member& member) { return member.peer == client; }),
428 members.end());
429 }
430
431 // Announce the change to all clients.
432 enet_peer_disconnect(client, 0);
433 BroadcastRoomInformation();
434}
435
436// Room
437Room::Room() : room_impl{std::make_unique<RoomImpl>()} {}
438
439Room::~Room() = default;
440
441void Room::Create(const std::string& name, const std::string& server_address, u16 server_port) {
442 ENetAddress address;
443 address.host = ENET_HOST_ANY;
444 if (!server_address.empty()) {
445 enet_address_set_host(&address, server_address.c_str());
446 }
447 address.port = server_port;
448
449 room_impl->server = enet_host_create(&address, MaxConcurrentConnections, NumChannels, 0, 0);
450 // TODO(B3N30): Allow specifying the maximum number of concurrent connections.
451 room_impl->state = State::Open;
452
453 room_impl->room_information.name = name;
454 room_impl->room_information.member_slots = MaxConcurrentConnections;
455 room_impl->StartLoop();
456}
457
458Room::State Room::GetState() const {
459 return room_impl->state;
460}
461
462const RoomInformation& Room::GetRoomInformation() const {
463 return room_impl->room_information;
464}
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
479void Room::Destroy() {
480 room_impl->state = State::Closed;
481 room_impl->room_thread->join();
482 room_impl->room_thread.reset();
483
484 if (room_impl->server) {
485 enet_host_destroy(room_impl->server);
486 }
487 room_impl->room_information = {};
488 room_impl->server = nullptr;
489 {
490 std::lock_guard<std::mutex> lock(room_impl->member_mutex);
491 room_impl->members.clear();
492 }
493 room_impl->room_information.member_slots = 0;
494 room_impl->room_information.name.clear();
495}
496
497} // namespace Network