room_member.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. // SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <atomic>
  4. #include <list>
  5. #include <mutex>
  6. #include <set>
  7. #include <thread>
  8. #include "common/assert.h"
  9. #include "common/socket_types.h"
  10. #include "enet/enet.h"
  11. #include "network/packet.h"
  12. #include "network/room_member.h"
  13. namespace Network {
  14. constexpr u32 ConnectionTimeoutMs = 5000;
  15. class RoomMember::RoomMemberImpl {
  16. public:
  17. ENetHost* client = nullptr; ///< ENet network interface.
  18. ENetPeer* server = nullptr; ///< The server peer the client is connected to
  19. /// Information about the clients connected to the same room as us.
  20. MemberList member_information;
  21. /// Information about the room we're connected to.
  22. RoomInformation room_information;
  23. /// The current game name, id and version
  24. GameInfo current_game_info;
  25. std::atomic<State> state{State::Idle}; ///< Current state of the RoomMember.
  26. void SetState(const State new_state);
  27. void SetError(const Error new_error);
  28. bool IsConnected() const;
  29. std::string nickname; ///< The nickname of this member.
  30. std::string username; ///< The username of this member.
  31. mutable std::mutex username_mutex; ///< Mutex for locking username.
  32. IPv4Address fake_ip; ///< The fake ip of this member.
  33. std::mutex network_mutex; ///< Mutex that controls access to the `client` variable.
  34. /// Thread that receives and dispatches network packets
  35. std::unique_ptr<std::thread> loop_thread;
  36. std::mutex send_list_mutex; ///< Mutex that controls access to the `send_list` variable.
  37. std::list<Packet> send_list; ///< A list that stores all packets to send the async
  38. template <typename T>
  39. using CallbackSet = std::set<CallbackHandle<T>>;
  40. std::mutex callback_mutex; ///< The mutex used for handling callbacks
  41. class Callbacks {
  42. public:
  43. template <typename T>
  44. CallbackSet<T>& Get();
  45. private:
  46. CallbackSet<ProxyPacket> callback_set_proxy_packet;
  47. CallbackSet<LDNPacket> callback_set_ldn_packet;
  48. CallbackSet<ChatEntry> callback_set_chat_messages;
  49. CallbackSet<StatusMessageEntry> callback_set_status_messages;
  50. CallbackSet<RoomInformation> callback_set_room_information;
  51. CallbackSet<State> callback_set_state;
  52. CallbackSet<Error> callback_set_error;
  53. CallbackSet<Room::BanList> callback_set_ban_list;
  54. };
  55. Callbacks callbacks; ///< All CallbackSets to all events
  56. void MemberLoop();
  57. void StartLoop();
  58. /**
  59. * Sends data to the room. It will be send on channel 0 with flag RELIABLE
  60. * @param packet The data to send
  61. */
  62. void Send(Packet&& packet);
  63. /**
  64. * Sends a request to the server, asking for permission to join a room with the specified
  65. * nickname and preferred fake ip.
  66. * @params nickname The desired nickname.
  67. * @params preferred_fake_ip The preferred IP address to use in the room, the NoPreferredIP
  68. * tells
  69. * @params password The password for the room
  70. * the server to assign one for us.
  71. */
  72. void SendJoinRequest(const std::string& nickname_,
  73. const IPv4Address& preferred_fake_ip = NoPreferredIP,
  74. const std::string& password = "", const std::string& token = "");
  75. /**
  76. * Extracts a MAC Address from a received ENet packet.
  77. * @param event The ENet event that was received.
  78. */
  79. void HandleJoinPacket(const ENetEvent* event);
  80. /**
  81. * Extracts RoomInformation and MemberInformation from a received ENet packet.
  82. * @param event The ENet event that was received.
  83. */
  84. void HandleRoomInformationPacket(const ENetEvent* event);
  85. /**
  86. * Extracts a ProxyPacket from a received ENet packet.
  87. * @param event The ENet event that was received.
  88. */
  89. void HandleProxyPackets(const ENetEvent* event);
  90. /**
  91. * Extracts an LdnPacket from a received ENet packet.
  92. * @param event The ENet event that was received.
  93. */
  94. void HandleLdnPackets(const ENetEvent* event);
  95. /**
  96. * Extracts a chat entry from a received ENet packet and adds it to the chat queue.
  97. * @param event The ENet event that was received.
  98. */
  99. void HandleChatPacket(const ENetEvent* event);
  100. /**
  101. * Extracts a system message entry from a received ENet packet and adds it to the system message
  102. * queue.
  103. * @param event The ENet event that was received.
  104. */
  105. void HandleStatusMessagePacket(const ENetEvent* event);
  106. /**
  107. * Extracts a ban list request response from a received ENet packet.
  108. * @param event The ENet event that was received.
  109. */
  110. void HandleModBanListResponsePacket(const ENetEvent* event);
  111. /**
  112. * Disconnects the RoomMember from the Room
  113. */
  114. void Disconnect();
  115. template <typename T>
  116. void Invoke(const T& data);
  117. template <typename T>
  118. CallbackHandle<T> Bind(std::function<void(const T&)> callback);
  119. };
  120. // RoomMemberImpl
  121. void RoomMember::RoomMemberImpl::SetState(const State new_state) {
  122. if (state != new_state) {
  123. state = new_state;
  124. Invoke<State>(state);
  125. }
  126. }
  127. void RoomMember::RoomMemberImpl::SetError(const Error new_error) {
  128. Invoke<Error>(new_error);
  129. }
  130. bool RoomMember::RoomMemberImpl::IsConnected() const {
  131. return state == State::Joining || state == State::Joined || state == State::Moderator;
  132. }
  133. void RoomMember::RoomMemberImpl::MemberLoop() {
  134. // Receive packets while the connection is open
  135. while (IsConnected()) {
  136. std::lock_guard lock(network_mutex);
  137. ENetEvent event;
  138. if (enet_host_service(client, &event, 5) > 0) {
  139. switch (event.type) {
  140. case ENET_EVENT_TYPE_RECEIVE:
  141. switch (event.packet->data[0]) {
  142. case IdProxyPacket:
  143. HandleProxyPackets(&event);
  144. break;
  145. case IdLdnPacket:
  146. HandleLdnPackets(&event);
  147. break;
  148. case IdChatMessage:
  149. HandleChatPacket(&event);
  150. break;
  151. case IdStatusMessage:
  152. HandleStatusMessagePacket(&event);
  153. break;
  154. case IdRoomInformation:
  155. HandleRoomInformationPacket(&event);
  156. break;
  157. case IdJoinSuccess:
  158. case IdJoinSuccessAsMod:
  159. // The join request was successful, we are now in the room.
  160. // If we joined successfully, there must be at least one client in the room: us.
  161. ASSERT_MSG(member_information.size() > 0,
  162. "We have not yet received member information.");
  163. HandleJoinPacket(&event); // Get the MAC Address for the client
  164. if (event.packet->data[0] == IdJoinSuccessAsMod) {
  165. SetState(State::Moderator);
  166. } else {
  167. SetState(State::Joined);
  168. }
  169. break;
  170. case IdModBanListResponse:
  171. HandleModBanListResponsePacket(&event);
  172. break;
  173. case IdRoomIsFull:
  174. SetState(State::Idle);
  175. SetError(Error::RoomIsFull);
  176. break;
  177. case IdNameCollision:
  178. SetState(State::Idle);
  179. SetError(Error::NameCollision);
  180. break;
  181. case IdIpCollision:
  182. SetState(State::Idle);
  183. SetError(Error::IpCollision);
  184. break;
  185. case IdVersionMismatch:
  186. SetState(State::Idle);
  187. SetError(Error::WrongVersion);
  188. break;
  189. case IdWrongPassword:
  190. SetState(State::Idle);
  191. SetError(Error::WrongPassword);
  192. break;
  193. case IdCloseRoom:
  194. SetState(State::Idle);
  195. SetError(Error::LostConnection);
  196. break;
  197. case IdHostKicked:
  198. SetState(State::Idle);
  199. SetError(Error::HostKicked);
  200. break;
  201. case IdHostBanned:
  202. SetState(State::Idle);
  203. SetError(Error::HostBanned);
  204. break;
  205. case IdModPermissionDenied:
  206. SetError(Error::PermissionDenied);
  207. break;
  208. case IdModNoSuchUser:
  209. SetError(Error::NoSuchUser);
  210. break;
  211. }
  212. enet_packet_destroy(event.packet);
  213. break;
  214. case ENET_EVENT_TYPE_DISCONNECT:
  215. if (state == State::Joined || state == State::Moderator) {
  216. SetState(State::Idle);
  217. SetError(Error::LostConnection);
  218. }
  219. break;
  220. case ENET_EVENT_TYPE_NONE:
  221. break;
  222. case ENET_EVENT_TYPE_CONNECT:
  223. // The ENET_EVENT_TYPE_CONNECT event can not possibly happen here because we're
  224. // already connected
  225. ASSERT_MSG(false, "Received unexpected connect event while already connected");
  226. break;
  227. }
  228. }
  229. std::list<Packet> packets;
  230. {
  231. std::lock_guard send_lock(send_list_mutex);
  232. packets.swap(send_list);
  233. }
  234. for (const auto& packet : packets) {
  235. ENetPacket* enetPacket = enet_packet_create(packet.GetData(), packet.GetDataSize(),
  236. ENET_PACKET_FLAG_RELIABLE);
  237. enet_peer_send(server, 0, enetPacket);
  238. }
  239. enet_host_flush(client);
  240. }
  241. Disconnect();
  242. };
  243. void RoomMember::RoomMemberImpl::StartLoop() {
  244. loop_thread = std::make_unique<std::thread>(&RoomMember::RoomMemberImpl::MemberLoop, this);
  245. }
  246. void RoomMember::RoomMemberImpl::Send(Packet&& packet) {
  247. std::lock_guard lock(send_list_mutex);
  248. send_list.push_back(std::move(packet));
  249. }
  250. void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname_,
  251. const IPv4Address& preferred_fake_ip,
  252. const std::string& password,
  253. const std::string& token) {
  254. Packet packet;
  255. packet.Write(static_cast<u8>(IdJoinRequest));
  256. packet.Write(nickname_);
  257. packet.Write(preferred_fake_ip);
  258. packet.Write(network_version);
  259. packet.Write(password);
  260. packet.Write(token);
  261. Send(std::move(packet));
  262. }
  263. void RoomMember::RoomMemberImpl::HandleRoomInformationPacket(const ENetEvent* event) {
  264. Packet packet;
  265. packet.Append(event->packet->data, event->packet->dataLength);
  266. // Ignore the first byte, which is the message id.
  267. packet.IgnoreBytes(sizeof(u8)); // Ignore the message type
  268. RoomInformation info{};
  269. packet.Read(info.name);
  270. packet.Read(info.description);
  271. packet.Read(info.member_slots);
  272. packet.Read(info.port);
  273. packet.Read(info.preferred_game.name);
  274. packet.Read(info.host_username);
  275. room_information.name = info.name;
  276. room_information.description = info.description;
  277. room_information.member_slots = info.member_slots;
  278. room_information.port = info.port;
  279. room_information.preferred_game = info.preferred_game;
  280. room_information.host_username = info.host_username;
  281. u32 num_members;
  282. packet.Read(num_members);
  283. member_information.resize(num_members);
  284. for (auto& member : member_information) {
  285. packet.Read(member.nickname);
  286. packet.Read(member.fake_ip);
  287. packet.Read(member.game_info.name);
  288. packet.Read(member.game_info.id);
  289. packet.Read(member.game_info.version);
  290. packet.Read(member.username);
  291. packet.Read(member.display_name);
  292. packet.Read(member.avatar_url);
  293. {
  294. std::lock_guard lock(username_mutex);
  295. if (member.nickname == nickname) {
  296. username = member.username;
  297. }
  298. }
  299. }
  300. Invoke(room_information);
  301. }
  302. void RoomMember::RoomMemberImpl::HandleJoinPacket(const ENetEvent* event) {
  303. Packet packet;
  304. packet.Append(event->packet->data, event->packet->dataLength);
  305. // Ignore the first byte, which is the message id.
  306. packet.IgnoreBytes(sizeof(u8)); // Ignore the message type
  307. // Parse the MAC Address from the packet
  308. packet.Read(fake_ip);
  309. }
  310. void RoomMember::RoomMemberImpl::HandleProxyPackets(const ENetEvent* event) {
  311. ProxyPacket proxy_packet{};
  312. Packet packet;
  313. packet.Append(event->packet->data, event->packet->dataLength);
  314. // Ignore the first byte, which is the message id.
  315. packet.IgnoreBytes(sizeof(u8)); // Ignore the message type
  316. // Parse the ProxyPacket from the packet
  317. u8 local_family;
  318. packet.Read(local_family);
  319. proxy_packet.local_endpoint.family = static_cast<Domain>(local_family);
  320. packet.Read(proxy_packet.local_endpoint.ip);
  321. packet.Read(proxy_packet.local_endpoint.portno);
  322. u8 remote_family;
  323. packet.Read(remote_family);
  324. proxy_packet.remote_endpoint.family = static_cast<Domain>(remote_family);
  325. packet.Read(proxy_packet.remote_endpoint.ip);
  326. packet.Read(proxy_packet.remote_endpoint.portno);
  327. u8 protocol_type;
  328. packet.Read(protocol_type);
  329. proxy_packet.protocol = static_cast<Protocol>(protocol_type);
  330. packet.Read(proxy_packet.broadcast);
  331. packet.Read(proxy_packet.data);
  332. Invoke<ProxyPacket>(proxy_packet);
  333. }
  334. void RoomMember::RoomMemberImpl::HandleLdnPackets(const ENetEvent* event) {
  335. LDNPacket ldn_packet{};
  336. Packet packet;
  337. packet.Append(event->packet->data, event->packet->dataLength);
  338. // Ignore the first byte, which is the message id.
  339. packet.IgnoreBytes(sizeof(u8)); // Ignore the message type
  340. u8 packet_type;
  341. packet.Read(packet_type);
  342. ldn_packet.type = static_cast<LDNPacketType>(packet_type);
  343. packet.Read(ldn_packet.local_ip);
  344. packet.Read(ldn_packet.remote_ip);
  345. packet.Read(ldn_packet.broadcast);
  346. packet.Read(ldn_packet.data);
  347. Invoke<LDNPacket>(ldn_packet);
  348. }
  349. void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) {
  350. Packet packet;
  351. packet.Append(event->packet->data, event->packet->dataLength);
  352. // Ignore the first byte, which is the message id.
  353. packet.IgnoreBytes(sizeof(u8));
  354. ChatEntry chat_entry{};
  355. packet.Read(chat_entry.nickname);
  356. packet.Read(chat_entry.username);
  357. packet.Read(chat_entry.message);
  358. Invoke<ChatEntry>(chat_entry);
  359. }
  360. void RoomMember::RoomMemberImpl::HandleStatusMessagePacket(const ENetEvent* event) {
  361. Packet packet;
  362. packet.Append(event->packet->data, event->packet->dataLength);
  363. // Ignore the first byte, which is the message id.
  364. packet.IgnoreBytes(sizeof(u8));
  365. StatusMessageEntry status_message_entry{};
  366. u8 type{};
  367. packet.Read(type);
  368. status_message_entry.type = static_cast<StatusMessageTypes>(type);
  369. packet.Read(status_message_entry.nickname);
  370. packet.Read(status_message_entry.username);
  371. Invoke<StatusMessageEntry>(status_message_entry);
  372. }
  373. void RoomMember::RoomMemberImpl::HandleModBanListResponsePacket(const ENetEvent* event) {
  374. Packet packet;
  375. packet.Append(event->packet->data, event->packet->dataLength);
  376. // Ignore the first byte, which is the message id.
  377. packet.IgnoreBytes(sizeof(u8));
  378. Room::BanList ban_list = {};
  379. packet.Read(ban_list.first);
  380. packet.Read(ban_list.second);
  381. Invoke<Room::BanList>(ban_list);
  382. }
  383. void RoomMember::RoomMemberImpl::Disconnect() {
  384. member_information.clear();
  385. room_information.member_slots = 0;
  386. room_information.name.clear();
  387. if (!server) {
  388. return;
  389. }
  390. enet_peer_disconnect(server, 0);
  391. ENetEvent event;
  392. while (enet_host_service(client, &event, ConnectionTimeoutMs) > 0) {
  393. switch (event.type) {
  394. case ENET_EVENT_TYPE_RECEIVE:
  395. enet_packet_destroy(event.packet); // Ignore all incoming data
  396. break;
  397. case ENET_EVENT_TYPE_DISCONNECT:
  398. server = nullptr;
  399. return;
  400. case ENET_EVENT_TYPE_NONE:
  401. case ENET_EVENT_TYPE_CONNECT:
  402. break;
  403. }
  404. }
  405. // didn't disconnect gracefully force disconnect
  406. enet_peer_reset(server);
  407. server = nullptr;
  408. }
  409. template <>
  410. RoomMember::RoomMemberImpl::CallbackSet<ProxyPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() {
  411. return callback_set_proxy_packet;
  412. }
  413. template <>
  414. RoomMember::RoomMemberImpl::CallbackSet<LDNPacket>& RoomMember::RoomMemberImpl::Callbacks::Get() {
  415. return callback_set_ldn_packet;
  416. }
  417. template <>
  418. RoomMember::RoomMemberImpl::CallbackSet<RoomMember::State>&
  419. RoomMember::RoomMemberImpl::Callbacks::Get() {
  420. return callback_set_state;
  421. }
  422. template <>
  423. RoomMember::RoomMemberImpl::CallbackSet<RoomMember::Error>&
  424. RoomMember::RoomMemberImpl::Callbacks::Get() {
  425. return callback_set_error;
  426. }
  427. template <>
  428. RoomMember::RoomMemberImpl::CallbackSet<RoomInformation>&
  429. RoomMember::RoomMemberImpl::Callbacks::Get() {
  430. return callback_set_room_information;
  431. }
  432. template <>
  433. RoomMember::RoomMemberImpl::CallbackSet<ChatEntry>& RoomMember::RoomMemberImpl::Callbacks::Get() {
  434. return callback_set_chat_messages;
  435. }
  436. template <>
  437. RoomMember::RoomMemberImpl::CallbackSet<StatusMessageEntry>&
  438. RoomMember::RoomMemberImpl::Callbacks::Get() {
  439. return callback_set_status_messages;
  440. }
  441. template <>
  442. RoomMember::RoomMemberImpl::CallbackSet<Room::BanList>&
  443. RoomMember::RoomMemberImpl::Callbacks::Get() {
  444. return callback_set_ban_list;
  445. }
  446. template <typename T>
  447. void RoomMember::RoomMemberImpl::Invoke(const T& data) {
  448. std::lock_guard lock(callback_mutex);
  449. CallbackSet<T> callback_set = callbacks.Get<T>();
  450. for (auto const& callback : callback_set) {
  451. (*callback)(data);
  452. }
  453. }
  454. template <typename T>
  455. RoomMember::CallbackHandle<T> RoomMember::RoomMemberImpl::Bind(
  456. std::function<void(const T&)> callback) {
  457. std::lock_guard lock(callback_mutex);
  458. CallbackHandle<T> handle;
  459. handle = std::make_shared<std::function<void(const T&)>>(callback);
  460. callbacks.Get<T>().insert(handle);
  461. return handle;
  462. }
  463. // RoomMember
  464. RoomMember::RoomMember() : room_member_impl{std::make_unique<RoomMemberImpl>()} {}
  465. RoomMember::~RoomMember() {
  466. ASSERT_MSG(!IsConnected(), "RoomMember is being destroyed while connected");
  467. if (room_member_impl->loop_thread) {
  468. Leave();
  469. }
  470. }
  471. RoomMember::State RoomMember::GetState() const {
  472. return room_member_impl->state;
  473. }
  474. const RoomMember::MemberList& RoomMember::GetMemberInformation() const {
  475. return room_member_impl->member_information;
  476. }
  477. const std::string& RoomMember::GetNickname() const {
  478. return room_member_impl->nickname;
  479. }
  480. const std::string& RoomMember::GetUsername() const {
  481. std::lock_guard lock(room_member_impl->username_mutex);
  482. return room_member_impl->username;
  483. }
  484. const IPv4Address& RoomMember::GetFakeIpAddress() const {
  485. ASSERT_MSG(IsConnected(), "Tried to get fake ip address while not connected");
  486. return room_member_impl->fake_ip;
  487. }
  488. RoomInformation RoomMember::GetRoomInformation() const {
  489. return room_member_impl->room_information;
  490. }
  491. void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port,
  492. u16 client_port, const IPv4Address& preferred_fake_ip,
  493. const std::string& password, const std::string& token) {
  494. // If the member is connected, kill the connection first
  495. if (room_member_impl->loop_thread && room_member_impl->loop_thread->joinable()) {
  496. Leave();
  497. }
  498. // If the thread isn't running but the ptr still exists, reset it
  499. else if (room_member_impl->loop_thread) {
  500. room_member_impl->loop_thread.reset();
  501. }
  502. if (!room_member_impl->client) {
  503. room_member_impl->client = enet_host_create(nullptr, 1, NumChannels, 0, 0);
  504. ASSERT_MSG(room_member_impl->client != nullptr, "Could not create client");
  505. }
  506. room_member_impl->SetState(State::Joining);
  507. ENetAddress address{};
  508. enet_address_set_host(&address, server_addr);
  509. address.port = server_port;
  510. room_member_impl->server =
  511. enet_host_connect(room_member_impl->client, &address, NumChannels, 0);
  512. if (!room_member_impl->server) {
  513. room_member_impl->SetState(State::Idle);
  514. room_member_impl->SetError(Error::UnknownError);
  515. return;
  516. }
  517. ENetEvent event{};
  518. int net = enet_host_service(room_member_impl->client, &event, ConnectionTimeoutMs);
  519. if (net > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
  520. room_member_impl->nickname = nick;
  521. room_member_impl->StartLoop();
  522. room_member_impl->SendJoinRequest(nick, preferred_fake_ip, password, token);
  523. SendGameInfo(room_member_impl->current_game_info);
  524. } else {
  525. enet_peer_disconnect(room_member_impl->server, 0);
  526. room_member_impl->SetState(State::Idle);
  527. room_member_impl->SetError(Error::CouldNotConnect);
  528. }
  529. }
  530. bool RoomMember::IsConnected() const {
  531. return room_member_impl->IsConnected();
  532. }
  533. void RoomMember::SendProxyPacket(const ProxyPacket& proxy_packet) {
  534. Packet packet;
  535. packet.Write(static_cast<u8>(IdProxyPacket));
  536. packet.Write(static_cast<u8>(proxy_packet.local_endpoint.family));
  537. packet.Write(proxy_packet.local_endpoint.ip);
  538. packet.Write(proxy_packet.local_endpoint.portno);
  539. packet.Write(static_cast<u8>(proxy_packet.remote_endpoint.family));
  540. packet.Write(proxy_packet.remote_endpoint.ip);
  541. packet.Write(proxy_packet.remote_endpoint.portno);
  542. packet.Write(static_cast<u8>(proxy_packet.protocol));
  543. packet.Write(proxy_packet.broadcast);
  544. packet.Write(proxy_packet.data);
  545. room_member_impl->Send(std::move(packet));
  546. }
  547. void RoomMember::SendLdnPacket(const LDNPacket& ldn_packet) {
  548. Packet packet;
  549. packet.Write(static_cast<u8>(IdLdnPacket));
  550. packet.Write(static_cast<u8>(ldn_packet.type));
  551. packet.Write(ldn_packet.local_ip);
  552. packet.Write(ldn_packet.remote_ip);
  553. packet.Write(ldn_packet.broadcast);
  554. packet.Write(ldn_packet.data);
  555. room_member_impl->Send(std::move(packet));
  556. }
  557. void RoomMember::SendChatMessage(const std::string& message) {
  558. Packet packet;
  559. packet.Write(static_cast<u8>(IdChatMessage));
  560. packet.Write(message);
  561. room_member_impl->Send(std::move(packet));
  562. }
  563. void RoomMember::SendGameInfo(const GameInfo& game_info) {
  564. room_member_impl->current_game_info = game_info;
  565. if (!IsConnected())
  566. return;
  567. Packet packet;
  568. packet.Write(static_cast<u8>(IdSetGameInfo));
  569. packet.Write(game_info.name);
  570. packet.Write(game_info.id);
  571. packet.Write(game_info.version);
  572. room_member_impl->Send(std::move(packet));
  573. }
  574. void RoomMember::SendModerationRequest(RoomMessageTypes type, const std::string& nickname) {
  575. ASSERT_MSG(type == IdModKick || type == IdModBan || type == IdModUnban,
  576. "type is not a moderation request");
  577. if (!IsConnected())
  578. return;
  579. Packet packet;
  580. packet.Write(static_cast<u8>(type));
  581. packet.Write(nickname);
  582. room_member_impl->Send(std::move(packet));
  583. }
  584. void RoomMember::RequestBanList() {
  585. if (!IsConnected())
  586. return;
  587. Packet packet;
  588. packet.Write(static_cast<u8>(IdModGetBanList));
  589. room_member_impl->Send(std::move(packet));
  590. }
  591. RoomMember::CallbackHandle<RoomMember::State> RoomMember::BindOnStateChanged(
  592. std::function<void(const RoomMember::State&)> callback) {
  593. return room_member_impl->Bind(callback);
  594. }
  595. RoomMember::CallbackHandle<RoomMember::Error> RoomMember::BindOnError(
  596. std::function<void(const RoomMember::Error&)> callback) {
  597. return room_member_impl->Bind(callback);
  598. }
  599. RoomMember::CallbackHandle<ProxyPacket> RoomMember::BindOnProxyPacketReceived(
  600. std::function<void(const ProxyPacket&)> callback) {
  601. return room_member_impl->Bind(callback);
  602. }
  603. RoomMember::CallbackHandle<LDNPacket> RoomMember::BindOnLdnPacketReceived(
  604. std::function<void(const LDNPacket&)> callback) {
  605. return room_member_impl->Bind(std::move(callback));
  606. }
  607. RoomMember::CallbackHandle<RoomInformation> RoomMember::BindOnRoomInformationChanged(
  608. std::function<void(const RoomInformation&)> callback) {
  609. return room_member_impl->Bind(callback);
  610. }
  611. RoomMember::CallbackHandle<ChatEntry> RoomMember::BindOnChatMessageRecieved(
  612. std::function<void(const ChatEntry&)> callback) {
  613. return room_member_impl->Bind(callback);
  614. }
  615. RoomMember::CallbackHandle<StatusMessageEntry> RoomMember::BindOnStatusMessageReceived(
  616. std::function<void(const StatusMessageEntry&)> callback) {
  617. return room_member_impl->Bind(callback);
  618. }
  619. RoomMember::CallbackHandle<Room::BanList> RoomMember::BindOnBanListReceived(
  620. std::function<void(const Room::BanList&)> callback) {
  621. return room_member_impl->Bind(callback);
  622. }
  623. template <typename T>
  624. void RoomMember::Unbind(CallbackHandle<T> handle) {
  625. std::lock_guard lock(room_member_impl->callback_mutex);
  626. room_member_impl->callbacks.Get<T>().erase(handle);
  627. }
  628. void RoomMember::Leave() {
  629. room_member_impl->SetState(State::Idle);
  630. room_member_impl->loop_thread->join();
  631. room_member_impl->loop_thread.reset();
  632. enet_host_destroy(room_member_impl->client);
  633. room_member_impl->client = nullptr;
  634. }
  635. template void RoomMember::Unbind(CallbackHandle<ProxyPacket>);
  636. template void RoomMember::Unbind(CallbackHandle<LDNPacket>);
  637. template void RoomMember::Unbind(CallbackHandle<RoomMember::State>);
  638. template void RoomMember::Unbind(CallbackHandle<RoomMember::Error>);
  639. template void RoomMember::Unbind(CallbackHandle<RoomInformation>);
  640. template void RoomMember::Unbind(CallbackHandle<ChatEntry>);
  641. template void RoomMember::Unbind(CallbackHandle<StatusMessageEntry>);
  642. template void RoomMember::Unbind(CallbackHandle<Room::BanList>);
  643. } // namespace Network