diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/network/packet.cpp | 10 | ||||
| -rw-r--r-- | src/network/packet.h | 64 | ||||
| -rw-r--r-- | src/network/room.cpp | 94 | ||||
| -rw-r--r-- | src/network/room.h | 7 | ||||
| -rw-r--r-- | src/network/room_member.cpp | 97 | ||||
| -rw-r--r-- | src/network/room_member.h | 27 |
6 files changed, 185 insertions, 114 deletions
diff --git a/src/network/packet.cpp b/src/network/packet.cpp index b3a61d824..660e92c0d 100644 --- a/src/network/packet.cpp +++ b/src/network/packet.cpp | |||
| @@ -13,10 +13,6 @@ | |||
| 13 | 13 | ||
| 14 | namespace Network { | 14 | namespace Network { |
| 15 | 15 | ||
| 16 | Packet::Packet() : read_pos(0), is_valid(true) {} | ||
| 17 | |||
| 18 | Packet::~Packet() {} | ||
| 19 | |||
| 20 | void Packet::Append(const void* in_data, std::size_t size_in_bytes) { | 16 | void Packet::Append(const void* in_data, std::size_t size_in_bytes) { |
| 21 | if (in_data && (size_in_bytes > 0)) { | 17 | if (in_data && (size_in_bytes > 0)) { |
| 22 | std::size_t start = data.size(); | 18 | std::size_t start = data.size(); |
| @@ -39,7 +35,7 @@ void Packet::Clear() { | |||
| 39 | } | 35 | } |
| 40 | 36 | ||
| 41 | const void* Packet::GetData() const { | 37 | const void* Packet::GetData() const { |
| 42 | return !data.empty() ? &data[0] : NULL; | 38 | return !data.empty() ? &data[0] : nullptr; |
| 43 | } | 39 | } |
| 44 | 40 | ||
| 45 | void Packet::IgnoreBytes(u32 length) { | 41 | void Packet::IgnoreBytes(u32 length) { |
| @@ -54,8 +50,8 @@ bool Packet::EndOfPacket() const { | |||
| 54 | return read_pos >= data.size(); | 50 | return read_pos >= data.size(); |
| 55 | } | 51 | } |
| 56 | 52 | ||
| 57 | Packet::operator BoolType() const { | 53 | Packet::operator bool() const { |
| 58 | return is_valid ? &Packet::CheckSize : NULL; | 54 | return is_valid ? &Packet::CheckSize : nullptr; |
| 59 | } | 55 | } |
| 60 | 56 | ||
| 61 | Packet& Packet::operator>>(bool& out_data) { | 57 | Packet& Packet::operator>>(bool& out_data) { |
diff --git a/src/network/packet.h b/src/network/packet.h index 6d84cfbac..026271701 100644 --- a/src/network/packet.h +++ b/src/network/packet.h | |||
| @@ -10,14 +10,11 @@ | |||
| 10 | 10 | ||
| 11 | namespace Network { | 11 | namespace Network { |
| 12 | 12 | ||
| 13 | /// A class for serialize data for network transfer. It also handles endianess | 13 | /// A class that serializes data for network transfer. It also handles endianess |
| 14 | class Packet { | 14 | class Packet { |
| 15 | /// A bool-like type that cannot be converted to integer or pointer types | ||
| 16 | typedef bool (Packet::*BoolType)(std::size_t); | ||
| 17 | |||
| 18 | public: | 15 | public: |
| 19 | Packet(); | 16 | Packet() = default; |
| 20 | ~Packet(); | 17 | ~Packet() = default; |
| 21 | 18 | ||
| 22 | /** | 19 | /** |
| 23 | * Append data to the end of the packet | 20 | * Append data to the end of the packet |
| @@ -64,41 +61,8 @@ public: | |||
| 64 | * @return True if all data was read, false otherwise | 61 | * @return True if all data was read, false otherwise |
| 65 | */ | 62 | */ |
| 66 | bool EndOfPacket() const; | 63 | bool EndOfPacket() const; |
| 67 | /** | 64 | |
| 68 | * Test the validity of the packet, for reading | 65 | explicit operator bool() const; |
| 69 | * This operator allows to test the packet as a boolean | ||
| 70 | * variable, to check if a reading operation was successful. | ||
| 71 | * | ||
| 72 | * A packet will be in an invalid state if it has no more | ||
| 73 | * data to read. | ||
| 74 | * | ||
| 75 | * This behaviour is the same as standard C++ streams. | ||
| 76 | * | ||
| 77 | * Usage example: | ||
| 78 | * @code | ||
| 79 | * float x; | ||
| 80 | * packet >> x; | ||
| 81 | * if (packet) | ||
| 82 | * { | ||
| 83 | * // ok, x was extracted successfully | ||
| 84 | * } | ||
| 85 | * | ||
| 86 | * // -- or -- | ||
| 87 | * | ||
| 88 | * float x; | ||
| 89 | * if (packet >> x) | ||
| 90 | * { | ||
| 91 | * // ok, x was extracted successfully | ||
| 92 | * } | ||
| 93 | * @endcode | ||
| 94 | * | ||
| 95 | * Don't focus on the return type, it's equivalent to bool but | ||
| 96 | * it disallows unwanted implicit conversions to integer or | ||
| 97 | * pointer types. | ||
| 98 | * | ||
| 99 | * @return True if last data extraction from packet was successful | ||
| 100 | */ | ||
| 101 | operator BoolType() const; | ||
| 102 | 66 | ||
| 103 | /// Overloads of operator >> to read data from the packet | 67 | /// Overloads of operator >> to read data from the packet |
| 104 | Packet& operator>>(bool& out_data); | 68 | Packet& operator>>(bool& out_data); |
| @@ -135,10 +99,6 @@ public: | |||
| 135 | Packet& operator<<(const std::array<T, S>& data); | 99 | Packet& operator<<(const std::array<T, S>& data); |
| 136 | 100 | ||
| 137 | private: | 101 | private: |
| 138 | /// Disallow comparisons between packets | ||
| 139 | bool operator==(const Packet& right) const; | ||
| 140 | bool operator!=(const Packet& right) const; | ||
| 141 | |||
| 142 | /** | 102 | /** |
| 143 | * Check if the packet can extract a given number of bytes | 103 | * Check if the packet can extract a given number of bytes |
| 144 | * This function updates accordingly the state of the packet. | 104 | * This function updates accordingly the state of the packet. |
| @@ -148,14 +108,14 @@ private: | |||
| 148 | bool CheckSize(std::size_t size); | 108 | bool CheckSize(std::size_t size); |
| 149 | 109 | ||
| 150 | // Member data | 110 | // Member data |
| 151 | std::vector<char> data; ///< Data stored in the packet | 111 | std::vector<char> data; ///< Data stored in the packet |
| 152 | std::size_t read_pos; ///< Current reading position in the packet | 112 | std::size_t read_pos = 0; ///< Current reading position in the packet |
| 153 | bool is_valid; ///< Reading state of the packet | 113 | bool is_valid = true; ///< Reading state of the packet |
| 154 | }; | 114 | }; |
| 155 | 115 | ||
| 156 | template <typename T> | 116 | template <typename T> |
| 157 | Packet& Packet::operator>>(std::vector<T>& out_data) { | 117 | Packet& Packet::operator>>(std::vector<T>& out_data) { |
| 158 | for (u32 i = 0; i < out_data.size(); ++i) { | 118 | for (std::size_t i = 0; i < out_data.size(); ++i) { |
| 159 | T character = 0; | 119 | T character = 0; |
| 160 | *this >> character; | 120 | *this >> character; |
| 161 | out_data[i] = character; | 121 | out_data[i] = character; |
| @@ -165,7 +125,7 @@ Packet& Packet::operator>>(std::vector<T>& out_data) { | |||
| 165 | 125 | ||
| 166 | template <typename T, std::size_t S> | 126 | template <typename T, std::size_t S> |
| 167 | Packet& Packet::operator>>(std::array<T, S>& out_data) { | 127 | Packet& Packet::operator>>(std::array<T, S>& out_data) { |
| 168 | for (u32 i = 0; i < out_data.size(); ++i) { | 128 | for (std::size_t i = 0; i < out_data.size(); ++i) { |
| 169 | T character = 0; | 129 | T character = 0; |
| 170 | *this >> character; | 130 | *this >> character; |
| 171 | out_data[i] = character; | 131 | out_data[i] = character; |
| @@ -175,7 +135,7 @@ Packet& Packet::operator>>(std::array<T, S>& out_data) { | |||
| 175 | 135 | ||
| 176 | template <typename T> | 136 | template <typename T> |
| 177 | Packet& Packet::operator<<(const std::vector<T>& in_data) { | 137 | Packet& Packet::operator<<(const std::vector<T>& in_data) { |
| 178 | for (u32 i = 0; i < in_data.size(); ++i) { | 138 | for (std::size_t i = 0; i < in_data.size(); ++i) { |
| 179 | *this << in_data[i]; | 139 | *this << in_data[i]; |
| 180 | } | 140 | } |
| 181 | return *this; | 141 | return *this; |
| @@ -183,7 +143,7 @@ Packet& Packet::operator<<(const std::vector<T>& in_data) { | |||
| 183 | 143 | ||
| 184 | template <typename T, std::size_t S> | 144 | template <typename T, std::size_t S> |
| 185 | Packet& Packet::operator<<(const std::array<T, S>& in_data) { | 145 | Packet& Packet::operator<<(const std::array<T, S>& in_data) { |
| 186 | for (u32 i = 0; i < in_data.size(); ++i) { | 146 | for (std::size_t i = 0; i < in_data.size(); ++i) { |
| 187 | *this << in_data[i]; | 147 | *this << in_data[i]; |
| 188 | } | 148 | } |
| 189 | return *this; | 149 | return *this; |
diff --git a/src/network/room.cpp b/src/network/room.cpp index 0fdb5e68f..9af5b4ea0 100644 --- a/src/network/room.cpp +++ b/src/network/room.cpp | |||
| @@ -85,8 +85,8 @@ public: | |||
| 85 | * The packet has the structure: | 85 | * The packet has the structure: |
| 86 | * <MessageID>ID_ROOM_INFORMATION | 86 | * <MessageID>ID_ROOM_INFORMATION |
| 87 | * <String> room_name | 87 | * <String> room_name |
| 88 | * <uint32_t> member_slots: The max number of clients allowed in this room | 88 | * <u32> member_slots: The max number of clients allowed in this room |
| 89 | * <uint32_t> num_members: the number of currently joined clients | 89 | * <u32> num_members: the number of currently joined clients |
| 90 | * This is followed by the following three values for each member: | 90 | * This is followed by the following three values for each member: |
| 91 | * <String> nickname of that member | 91 | * <String> nickname of that member |
| 92 | * <MacAddress> mac_address of that member | 92 | * <MacAddress> mac_address of that member |
| @@ -113,6 +113,12 @@ public: | |||
| 113 | void HandleChatPacket(const ENetEvent* event); | 113 | void HandleChatPacket(const ENetEvent* event); |
| 114 | 114 | ||
| 115 | /** | 115 | /** |
| 116 | * Extracts the game name from a received ENet packet and broadcasts it. | ||
| 117 | * @param event The ENet event that was received. | ||
| 118 | */ | ||
| 119 | void HandleGameNamePacket(const ENetEvent* event); | ||
| 120 | |||
| 121 | /** | ||
| 116 | * Removes the client from the members list if it was in it and announces the change | 122 | * Removes the client from the members list if it was in it and announces the change |
| 117 | * to all other clients. | 123 | * to all other clients. |
| 118 | */ | 124 | */ |
| @@ -130,7 +136,9 @@ void Room::RoomImpl::ServerLoop() { | |||
| 130 | case IdJoinRequest: | 136 | case IdJoinRequest: |
| 131 | HandleJoinRequest(&event); | 137 | HandleJoinRequest(&event); |
| 132 | break; | 138 | break; |
| 133 | // TODO(B3N30): Handle the other message types | 139 | case IdSetGameName: |
| 140 | HandleGameNamePacket(&event); | ||
| 141 | break; | ||
| 134 | case IdWifiPacket: | 142 | case IdWifiPacket: |
| 135 | HandleWifiPacket(&event); | 143 | HandleWifiPacket(&event); |
| 136 | break; | 144 | break; |
| @@ -184,7 +192,7 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||
| 184 | member.nickname = nickname; | 192 | member.nickname = nickname; |
| 185 | member.peer = event->peer; | 193 | member.peer = event->peer; |
| 186 | 194 | ||
| 187 | members.push_back(member); | 195 | members.push_back(std::move(member)); |
| 188 | 196 | ||
| 189 | // Notify everyone that the room information has changed. | 197 | // Notify everyone that the room information has changed. |
| 190 | BroadcastRoomInformation(); | 198 | BroadcastRoomInformation(); |
| @@ -194,22 +202,14 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) { | |||
| 194 | bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const { | 202 | bool Room::RoomImpl::IsValidNickname(const std::string& nickname) const { |
| 195 | // A nickname is valid if it is not already taken by anybody else in the room. | 203 | // A nickname is valid if it is not already taken by anybody else in the room. |
| 196 | // TODO(B3N30): Check for empty names, spaces, etc. | 204 | // TODO(B3N30): Check for empty names, spaces, etc. |
| 197 | for (const Member& member : members) { | 205 | return std::all_of(members.begin(), members.end(), |
| 198 | if (member.nickname == nickname) { | 206 | [&nickname](const auto& member) { return member.nickname != nickname; }); |
| 199 | return false; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | return true; | ||
| 203 | } | 207 | } |
| 204 | 208 | ||
| 205 | bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const { | 209 | bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const { |
| 206 | // A MAC address is valid if it is not already taken by anybody else in the room. | 210 | // A MAC address is valid if it is not already taken by anybody else in the room. |
| 207 | for (const Member& member : members) { | 211 | return std::all_of(members.begin(), members.end(), |
| 208 | if (member.mac_address == address) { | 212 | [&address](const auto& member) { return member.mac_address != address; }); |
| 209 | return false; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | return true; | ||
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | void Room::RoomImpl::SendNameCollision(ENetPeer* client) { | 215 | void Room::RoomImpl::SendNameCollision(ENetPeer* client) { |
| @@ -248,7 +248,7 @@ void Room::RoomImpl::BroadcastRoomInformation() { | |||
| 248 | packet << room_information.name; | 248 | packet << room_information.name; |
| 249 | packet << room_information.member_slots; | 249 | packet << room_information.member_slots; |
| 250 | 250 | ||
| 251 | packet << static_cast<uint32_t>(members.size()); | 251 | packet << static_cast<u32>(members.size()); |
| 252 | for (const auto& member : members) { | 252 | for (const auto& member : members) { |
| 253 | packet << member.nickname; | 253 | packet << member.nickname; |
| 254 | packet << member.mac_address; | 254 | packet << member.mac_address; |
| @@ -262,10 +262,11 @@ void Room::RoomImpl::BroadcastRoomInformation() { | |||
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | MacAddress Room::RoomImpl::GenerateMacAddress() { | 264 | MacAddress Room::RoomImpl::GenerateMacAddress() { |
| 265 | MacAddress result_mac = NintendoOUI; | 265 | MacAddress result_mac = |
| 266 | NintendoOUI; // The first three bytes of each MAC address will be the NintendoOUI | ||
| 266 | std::uniform_int_distribution<> dis(0x00, 0xFF); // Random byte between 0 and 0xFF | 267 | std::uniform_int_distribution<> dis(0x00, 0xFF); // Random byte between 0 and 0xFF |
| 267 | do { | 268 | do { |
| 268 | for (int i = 3; i < result_mac.size(); ++i) { | 269 | for (size_t i = 3; i < result_mac.size(); ++i) { |
| 269 | result_mac[i] = dis(random_gen); | 270 | result_mac[i] = dis(random_gen); |
| 270 | } | 271 | } |
| 271 | } while (!IsValidMacAddress(result_mac)); | 272 | } while (!IsValidMacAddress(result_mac)); |
| @@ -273,9 +274,33 @@ MacAddress Room::RoomImpl::GenerateMacAddress() { | |||
| 273 | } | 274 | } |
| 274 | 275 | ||
| 275 | void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) { | 276 | void Room::RoomImpl::HandleWifiPacket(const ENetEvent* event) { |
| 276 | for (auto it = members.begin(); it != members.end(); ++it) { | 277 | Packet in_packet; |
| 277 | if (it->peer != event->peer) | 278 | in_packet.Append(event->packet->data, event->packet->dataLength); |
| 278 | enet_peer_send(it->peer, 0, event->packet); | 279 | in_packet.IgnoreBytes(sizeof(MessageID)); |
| 280 | in_packet.IgnoreBytes(sizeof(u8)); // WifiPacket Type | ||
| 281 | in_packet.IgnoreBytes(sizeof(u8)); // WifiPacket Channel | ||
| 282 | in_packet.IgnoreBytes(sizeof(MacAddress)); // WifiPacket Transmitter Address | ||
| 283 | MacAddress destination_address; | ||
| 284 | in_packet >> destination_address; | ||
| 285 | |||
| 286 | Packet out_packet; | ||
| 287 | out_packet.Append(event->packet->data, event->packet->dataLength); | ||
| 288 | ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(), | ||
| 289 | ENET_PACKET_FLAG_RELIABLE); | ||
| 290 | |||
| 291 | if (destination_address == BroadcastMac) { // Send the data to everyone except the sender | ||
| 292 | for (const auto& member : members) { | ||
| 293 | if (member.peer != event->peer) | ||
| 294 | enet_peer_send(member.peer, 0, event->packet); | ||
| 295 | } | ||
| 296 | } else { // Send the data only to the destination client | ||
| 297 | auto member = std::find_if(members.begin(), members.end(), | ||
| 298 | [destination_address](const Member& member) -> bool { | ||
| 299 | return member.mac_address == destination_address; | ||
| 300 | }); | ||
| 301 | if (member != members.end()) { | ||
| 302 | enet_peer_send(member->peer, 0, enet_packet); | ||
| 303 | } | ||
| 279 | } | 304 | } |
| 280 | enet_host_flush(server); | 305 | enet_host_flush(server); |
| 281 | } | 306 | } |
| @@ -287,7 +312,7 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { | |||
| 287 | in_packet.IgnoreBytes(sizeof(MessageID)); | 312 | in_packet.IgnoreBytes(sizeof(MessageID)); |
| 288 | std::string message; | 313 | std::string message; |
| 289 | in_packet >> message; | 314 | in_packet >> message; |
| 290 | auto CompareNetworkAddress = [&](const Member member) -> bool { | 315 | auto CompareNetworkAddress = [event](const Member member) -> bool { |
| 291 | return member.peer == event->peer; | 316 | return member.peer == event->peer; |
| 292 | }; | 317 | }; |
| 293 | const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress); | 318 | const auto sending_member = std::find_if(members.begin(), members.end(), CompareNetworkAddress); |
| @@ -309,13 +334,30 @@ void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { | |||
| 309 | enet_host_flush(server); | 334 | enet_host_flush(server); |
| 310 | } | 335 | } |
| 311 | 336 | ||
| 337 | void Room::RoomImpl::HandleGameNamePacket(const ENetEvent* event) { | ||
| 338 | Packet in_packet; | ||
| 339 | in_packet.Append(event->packet->data, event->packet->dataLength); | ||
| 340 | |||
| 341 | in_packet.IgnoreBytes(sizeof(MessageID)); | ||
| 342 | std::string game_name; | ||
| 343 | in_packet >> game_name; | ||
| 344 | auto member = | ||
| 345 | std::find_if(members.begin(), members.end(), | ||
| 346 | [event](const Member& member) -> bool { return member.peer == event->peer; }); | ||
| 347 | if (member != members.end()) { | ||
| 348 | member->game_name = game_name; | ||
| 349 | BroadcastRoomInformation(); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 312 | void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { | 353 | void Room::RoomImpl::HandleClientDisconnection(ENetPeer* client) { |
| 313 | // Remove the client from the members list. | 354 | // Remove the client from the members list. |
| 314 | members.erase(std::remove_if(members.begin(), members.end(), | 355 | members.erase(std::remove_if(members.begin(), members.end(), |
| 315 | [&](const Member& member) { return member.peer == client; }), | 356 | [client](const Member& member) { return member.peer == client; }), |
| 316 | members.end()); | 357 | members.end()); |
| 317 | 358 | ||
| 318 | // Announce the change to all clients. | 359 | // Announce the change to all clients. |
| 360 | enet_peer_disconnect(client, 0); | ||
| 319 | BroadcastRoomInformation(); | 361 | BroadcastRoomInformation(); |
| 320 | } | 362 | } |
| 321 | 363 | ||
| @@ -327,7 +369,6 @@ Room::~Room() = default; | |||
| 327 | void Room::Create(const std::string& name, const std::string& server_address, u16 server_port) { | 369 | void Room::Create(const std::string& name, const std::string& server_address, u16 server_port) { |
| 328 | ENetAddress address; | 370 | ENetAddress address; |
| 329 | address.host = ENET_HOST_ANY; | 371 | address.host = ENET_HOST_ANY; |
| 330 | enet_address_set_host(&address, server_address.c_str()); | ||
| 331 | address.port = server_port; | 372 | address.port = server_port; |
| 332 | 373 | ||
| 333 | room_impl->server = enet_host_create(&address, MaxConcurrentConnections, NumChannels, 0, 0); | 374 | room_impl->server = enet_host_create(&address, MaxConcurrentConnections, NumChannels, 0, 0); |
| @@ -357,6 +398,9 @@ void Room::Destroy() { | |||
| 357 | } | 398 | } |
| 358 | room_impl->room_information = {}; | 399 | room_impl->room_information = {}; |
| 359 | room_impl->server = nullptr; | 400 | room_impl->server = nullptr; |
| 401 | room_impl->members.clear(); | ||
| 402 | room_impl->room_information.member_slots = 0; | ||
| 403 | room_impl->room_information.name.clear(); | ||
| 360 | } | 404 | } |
| 361 | 405 | ||
| 362 | } // namespace Network | 406 | } // namespace Network |
diff --git a/src/network/room.h b/src/network/room.h index ca663058f..82e3dc62c 100644 --- a/src/network/room.h +++ b/src/network/room.h | |||
| @@ -19,13 +19,16 @@ struct RoomInformation { | |||
| 19 | u32 member_slots; ///< Maximum number of members in this room | 19 | u32 member_slots; ///< Maximum number of members in this room |
| 20 | }; | 20 | }; |
| 21 | 21 | ||
| 22 | using MacAddress = std::array<uint8_t, 6>; | 22 | using MacAddress = std::array<u8, 6>; |
| 23 | /// A special MAC address that tells the room we're joining to assign us a MAC address | 23 | /// A special MAC address that tells the room we're joining to assign us a MAC address |
| 24 | /// automatically. | 24 | /// automatically. |
| 25 | const MacAddress NoPreferredMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | 25 | const MacAddress NoPreferredMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; |
| 26 | 26 | ||
| 27 | // 802.11 broadcast MAC address | ||
| 28 | constexpr MacAddress BroadcastMac = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | ||
| 29 | |||
| 27 | // The different types of messages that can be sent. The first byte of each packet defines the type | 30 | // The different types of messages that can be sent. The first byte of each packet defines the type |
| 28 | typedef uint8_t MessageID; | 31 | using MessageID = u8; |
| 29 | enum RoomMessageTypes { | 32 | enum RoomMessageTypes { |
| 30 | IdJoinRequest = 1, | 33 | IdJoinRequest = 1, |
| 31 | IdJoinSuccess, | 34 | IdJoinSuccess, |
diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp index d68bb551d..ec67aa5be 100644 --- a/src/network/room_member.cpp +++ b/src/network/room_member.cpp | |||
| @@ -74,6 +74,11 @@ public: | |||
| 74 | * @param event The ENet event that was received. | 74 | * @param event The ENet event that was received. |
| 75 | */ | 75 | */ |
| 76 | void HandleChatPacket(const ENetEvent* event); | 76 | void HandleChatPacket(const ENetEvent* event); |
| 77 | |||
| 78 | /** | ||
| 79 | * Disconnects the RoomMember from the Room | ||
| 80 | */ | ||
| 81 | void Disconnect(); | ||
| 77 | }; | 82 | }; |
| 78 | 83 | ||
| 79 | // RoomMemberImpl | 84 | // RoomMemberImpl |
| @@ -92,7 +97,8 @@ void RoomMember::RoomMemberImpl::ReceiveLoop() { | |||
| 92 | std::lock_guard<std::mutex> lock(network_mutex); | 97 | std::lock_guard<std::mutex> lock(network_mutex); |
| 93 | ENetEvent event; | 98 | ENetEvent event; |
| 94 | if (enet_host_service(client, &event, 1000) > 0) { | 99 | if (enet_host_service(client, &event, 1000) > 0) { |
| 95 | if (event.type == ENET_EVENT_TYPE_RECEIVE) { | 100 | switch (event.type) { |
| 101 | case ENET_EVENT_TYPE_RECEIVE: | ||
| 96 | switch (event.packet->data[0]) { | 102 | switch (event.packet->data[0]) { |
| 97 | // TODO(B3N30): Handle the other message types | 103 | // TODO(B3N30): Handle the other message types |
| 98 | case IdChatMessage: | 104 | case IdChatMessage: |
| @@ -111,25 +117,21 @@ void RoomMember::RoomMemberImpl::ReceiveLoop() { | |||
| 111 | break; | 117 | break; |
| 112 | case IdNameCollision: | 118 | case IdNameCollision: |
| 113 | SetState(State::NameCollision); | 119 | SetState(State::NameCollision); |
| 114 | enet_packet_destroy(event.packet); | ||
| 115 | enet_peer_disconnect(server, 0); | ||
| 116 | enet_peer_reset(server); | ||
| 117 | return; | ||
| 118 | break; | 120 | break; |
| 119 | case IdMacCollision: | 121 | case IdMacCollision: |
| 120 | SetState(State::MacCollision); | 122 | SetState(State::MacCollision); |
| 121 | enet_packet_destroy(event.packet); | ||
| 122 | enet_peer_disconnect(server, 0); | ||
| 123 | enet_peer_reset(server); | ||
| 124 | return; | ||
| 125 | break; | 123 | break; |
| 126 | default: | 124 | default: |
| 127 | break; | 125 | break; |
| 128 | } | 126 | } |
| 129 | enet_packet_destroy(event.packet); | 127 | enet_packet_destroy(event.packet); |
| 128 | break; | ||
| 129 | case ENET_EVENT_TYPE_DISCONNECT: | ||
| 130 | SetState(State::LostConnection); | ||
| 130 | } | 131 | } |
| 131 | } | 132 | } |
| 132 | } | 133 | } |
| 134 | Disconnect(); | ||
| 133 | }; | 135 | }; |
| 134 | 136 | ||
| 135 | void RoomMember::RoomMemberImpl::StartLoop() { | 137 | void RoomMember::RoomMemberImpl::StartLoop() { |
| @@ -137,6 +139,7 @@ void RoomMember::RoomMemberImpl::StartLoop() { | |||
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | void RoomMember::RoomMemberImpl::Send(Packet& packet) { | 141 | void RoomMember::RoomMemberImpl::Send(Packet& packet) { |
| 142 | std::lock_guard<std::mutex> lock(network_mutex); | ||
| 140 | ENetPacket* enetPacket = | 143 | ENetPacket* enetPacket = |
| 141 | enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); | 144 | enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE); |
| 142 | enet_peer_send(server, 0, enetPacket); | 145 | enet_peer_send(server, 0, enetPacket); |
| @@ -165,7 +168,7 @@ void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* ev | |||
| 165 | room_information.name = info.name; | 168 | room_information.name = info.name; |
| 166 | room_information.member_slots = info.member_slots; | 169 | room_information.member_slots = info.member_slots; |
| 167 | 170 | ||
| 168 | uint32_t num_members; | 171 | u32 num_members; |
| 169 | packet >> num_members; | 172 | packet >> num_members; |
| 170 | member_information.resize(num_members); | 173 | member_information.resize(num_members); |
| 171 | 174 | ||
| @@ -198,7 +201,7 @@ void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) { | |||
| 198 | packet.IgnoreBytes(sizeof(MessageID)); | 201 | packet.IgnoreBytes(sizeof(MessageID)); |
| 199 | 202 | ||
| 200 | // Parse the WifiPacket from the BitStream | 203 | // Parse the WifiPacket from the BitStream |
| 201 | uint8_t frame_type; | 204 | u8 frame_type; |
| 202 | packet >> frame_type; | 205 | packet >> frame_type; |
| 203 | WifiPacket::PacketType type = static_cast<WifiPacket::PacketType>(frame_type); | 206 | WifiPacket::PacketType type = static_cast<WifiPacket::PacketType>(frame_type); |
| 204 | 207 | ||
| @@ -207,10 +210,10 @@ void RoomMember::RoomMemberImpl::HandleWifiPackets(const ENetEvent* event) { | |||
| 207 | packet >> wifi_packet.transmitter_address; | 210 | packet >> wifi_packet.transmitter_address; |
| 208 | packet >> wifi_packet.destination_address; | 211 | packet >> wifi_packet.destination_address; |
| 209 | 212 | ||
| 210 | uint32_t data_length; | 213 | u32 data_length; |
| 211 | packet >> data_length; | 214 | packet >> data_length; |
| 212 | 215 | ||
| 213 | std::vector<uint8_t> data(data_length); | 216 | std::vector<u8> data(data_length); |
| 214 | packet >> data; | 217 | packet >> data; |
| 215 | 218 | ||
| 216 | wifi_packet.data = std::move(data); | 219 | wifi_packet.data = std::move(data); |
| @@ -230,6 +233,33 @@ void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { | |||
| 230 | // TODO(B3N30): Invoke callbacks | 233 | // TODO(B3N30): Invoke callbacks |
| 231 | } | 234 | } |
| 232 | 235 | ||
| 236 | void RoomMember::RoomMemberImpl::Disconnect() { | ||
| 237 | member_information.clear(); | ||
| 238 | room_information.member_slots = 0; | ||
| 239 | room_information.name.clear(); | ||
| 240 | |||
| 241 | if (server) { | ||
| 242 | enet_peer_disconnect(server, 0); | ||
| 243 | } else { | ||
| 244 | return; | ||
| 245 | } | ||
| 246 | |||
| 247 | ENetEvent event; | ||
| 248 | while (enet_host_service(client, &event, ConnectionTimeoutMs) > 0) { | ||
| 249 | switch (event.type) { | ||
| 250 | case ENET_EVENT_TYPE_RECEIVE: | ||
| 251 | enet_packet_destroy(event.packet); // Ignore all incoming data | ||
| 252 | break; | ||
| 253 | case ENET_EVENT_TYPE_DISCONNECT: | ||
| 254 | server = nullptr; | ||
| 255 | return; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | // didn't disconnect gracefully force disconnect | ||
| 259 | enet_peer_reset(server); | ||
| 260 | server = nullptr; | ||
| 261 | } | ||
| 262 | |||
| 233 | // RoomMember | 263 | // RoomMember |
| 234 | RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} { | 264 | RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} { |
| 235 | room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0); | 265 | room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0); |
| @@ -249,16 +279,36 @@ const RoomMember::MemberList& RoomMember::GetMemberInformation() const { | |||
| 249 | return room_member_impl->member_information; | 279 | return room_member_impl->member_information; |
| 250 | } | 280 | } |
| 251 | 281 | ||
| 282 | const std::string& RoomMember::GetNickname() const { | ||
| 283 | return room_member_impl->nickname; | ||
| 284 | } | ||
| 285 | |||
| 286 | const MacAddress& RoomMember::GetMacAddress() const { | ||
| 287 | if (GetState() == State::Joined) | ||
| 288 | return room_member_impl->mac_address; | ||
| 289 | return MacAddress{}; | ||
| 290 | } | ||
| 291 | |||
| 252 | RoomInformation RoomMember::GetRoomInformation() const { | 292 | RoomInformation RoomMember::GetRoomInformation() const { |
| 253 | return room_member_impl->room_information; | 293 | return room_member_impl->room_information; |
| 254 | } | 294 | } |
| 255 | 295 | ||
| 256 | void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port, | 296 | void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port, |
| 257 | u16 client_port) { | 297 | u16 client_port) { |
| 298 | // If the member is connected, kill the connection first | ||
| 299 | if (room_member_impl->receive_thread && room_member_impl->receive_thread->joinable()) { | ||
| 300 | room_member_impl->SetState(State::Error); | ||
| 301 | room_member_impl->receive_thread->join(); | ||
| 302 | room_member_impl->receive_thread.reset(); | ||
| 303 | } | ||
| 304 | // If the thread isn't running but the ptr still exists, reset it | ||
| 305 | else if (room_member_impl->receive_thread) { | ||
| 306 | room_member_impl->receive_thread.reset(); | ||
| 307 | } | ||
| 308 | |||
| 258 | ENetAddress address{}; | 309 | ENetAddress address{}; |
| 259 | enet_address_set_host(&address, server_addr); | 310 | enet_address_set_host(&address, server_addr); |
| 260 | address.port = server_port; | 311 | address.port = server_port; |
| 261 | |||
| 262 | room_member_impl->server = | 312 | room_member_impl->server = |
| 263 | enet_host_connect(room_member_impl->client, &address, NumChannels, 0); | 313 | enet_host_connect(room_member_impl->client, &address, NumChannels, 0); |
| 264 | 314 | ||
| @@ -286,11 +336,11 @@ bool RoomMember::IsConnected() const { | |||
| 286 | void RoomMember::SendWifiPacket(const WifiPacket& wifi_packet) { | 336 | void RoomMember::SendWifiPacket(const WifiPacket& wifi_packet) { |
| 287 | Packet packet; | 337 | Packet packet; |
| 288 | packet << static_cast<MessageID>(IdWifiPacket); | 338 | packet << static_cast<MessageID>(IdWifiPacket); |
| 289 | packet << static_cast<uint8_t>(wifi_packet.type); | 339 | packet << static_cast<u8>(wifi_packet.type); |
| 290 | packet << wifi_packet.channel; | 340 | packet << wifi_packet.channel; |
| 291 | packet << wifi_packet.transmitter_address; | 341 | packet << wifi_packet.transmitter_address; |
| 292 | packet << wifi_packet.destination_address; | 342 | packet << wifi_packet.destination_address; |
| 293 | packet << static_cast<uint32_t>(wifi_packet.data.size()); | 343 | packet << static_cast<u32>(wifi_packet.data.size()); |
| 294 | packet << wifi_packet.data; | 344 | packet << wifi_packet.data; |
| 295 | room_member_impl->Send(packet); | 345 | room_member_impl->Send(packet); |
| 296 | } | 346 | } |
| @@ -302,16 +352,17 @@ void RoomMember::SendChatMessage(const std::string& message) { | |||
| 302 | room_member_impl->Send(packet); | 352 | room_member_impl->Send(packet); |
| 303 | } | 353 | } |
| 304 | 354 | ||
| 355 | void RoomMember::SendGameName(const std::string& game_name) { | ||
| 356 | Packet packet; | ||
| 357 | packet << static_cast<MessageID>(IdSetGameName); | ||
| 358 | packet << game_name; | ||
| 359 | room_member_impl->Send(packet); | ||
| 360 | } | ||
| 361 | |||
| 305 | void RoomMember::Leave() { | 362 | void RoomMember::Leave() { |
| 306 | ASSERT_MSG(room_member_impl->receive_thread != nullptr, "Must be in a room to leave it."); | 363 | room_member_impl->SetState(State::Idle); |
| 307 | { | ||
| 308 | std::lock_guard<std::mutex> lock(room_member_impl->network_mutex); | ||
| 309 | enet_peer_disconnect(room_member_impl->server, 0); | ||
| 310 | room_member_impl->SetState(State::Idle); | ||
| 311 | } | ||
| 312 | room_member_impl->receive_thread->join(); | 364 | room_member_impl->receive_thread->join(); |
| 313 | room_member_impl->receive_thread.reset(); | 365 | room_member_impl->receive_thread.reset(); |
| 314 | enet_peer_reset(room_member_impl->server); | ||
| 315 | } | 366 | } |
| 316 | 367 | ||
| 317 | } // namespace Network | 368 | } // namespace Network |
diff --git a/src/network/room_member.h b/src/network/room_member.h index 693aa4e7f..d874cc5e4 100644 --- a/src/network/room_member.h +++ b/src/network/room_member.h | |||
| @@ -15,13 +15,13 @@ namespace Network { | |||
| 15 | /// Information about the received WiFi packets. | 15 | /// Information about the received WiFi packets. |
| 16 | /// Acts as our own 802.11 header. | 16 | /// Acts as our own 802.11 header. |
| 17 | struct WifiPacket { | 17 | struct WifiPacket { |
| 18 | enum class PacketType { Beacon, Data, Management }; | 18 | enum class PacketType { Beacon, Data, Authentication, AssociationResponse }; |
| 19 | PacketType type; ///< The type of 802.11 frame, Beacon / Data. | 19 | PacketType type; ///< The type of 802.11 frame. |
| 20 | std::vector<uint8_t> data; ///< Raw 802.11 frame data, starting at the management frame header | 20 | std::vector<u8> data; ///< Raw 802.11 frame data, starting at the management frame header |
| 21 | /// for management frames. | 21 | /// for management frames. |
| 22 | MacAddress transmitter_address; ///< Mac address of the transmitter. | 22 | MacAddress transmitter_address; ///< Mac address of the transmitter. |
| 23 | MacAddress destination_address; ///< Mac address of the receiver. | 23 | MacAddress destination_address; ///< Mac address of the receiver. |
| 24 | uint8_t channel; ///< WiFi channel where this frame was transmitted. | 24 | u8 channel; ///< WiFi channel where this frame was transmitted. |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | /// Represents a chat message. | 27 | /// Represents a chat message. |
| @@ -70,6 +70,17 @@ public: | |||
| 70 | * Returns information about the members in the room we're currently connected to. | 70 | * Returns information about the members in the room we're currently connected to. |
| 71 | */ | 71 | */ |
| 72 | const MemberList& GetMemberInformation() const; | 72 | const MemberList& GetMemberInformation() const; |
| 73 | |||
| 74 | /** | ||
| 75 | * Returns the nickname of the RoomMember. | ||
| 76 | */ | ||
| 77 | const std::string& GetNickname() const; | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Returns the MAC address of the RoomMember. | ||
| 81 | */ | ||
| 82 | const MacAddress& GetMacAddress() const; | ||
| 83 | |||
| 73 | /** | 84 | /** |
| 74 | * Returns information about the room we're currently connected to. | 85 | * Returns information about the room we're currently connected to. |
| 75 | */ | 86 | */ |
| @@ -100,6 +111,12 @@ public: | |||
| 100 | void SendChatMessage(const std::string& message); | 111 | void SendChatMessage(const std::string& message); |
| 101 | 112 | ||
| 102 | /** | 113 | /** |
| 114 | * Sends the current game name to the room. | ||
| 115 | * @param game_name The game name. | ||
| 116 | */ | ||
| 117 | void SendGameName(const std::string& game_name); | ||
| 118 | |||
| 119 | /** | ||
| 103 | * Leaves the current room. | 120 | * Leaves the current room. |
| 104 | */ | 121 | */ |
| 105 | void Leave(); | 122 | void Leave(); |