]> git.lizzy.rs Git - dragonfireclient.git/commitdiff
Clean up ClientInterface locking
authorJude Melton-Houghton <jwmhjwmh@gmail.com>
Wed, 2 Feb 2022 01:49:19 +0000 (20:49 -0500)
committersfan5 <sfan5@live.de>
Thu, 3 Feb 2022 10:43:51 +0000 (11:43 +0100)
src/clientiface.h
src/network/serverpackethandler.cpp
src/server.cpp

index b1591ddb027332181be646e3ca0a90e8478ba03b..1be9c972a5218be3657d0f3573d1fa740a132a83 100644 (file)
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "network/networkprotocol.h"
 #include "network/address.h"
 #include "porting.h"
+#include "threading/mutex_auto_lock.h"
 
 #include <list>
 #include <vector>
@@ -503,9 +504,13 @@ class ClientInterface {
 
        static std::string state2Name(ClientState state);
 protected:
-       //TODO find way to avoid this functions
-       void lock() { m_clients_mutex.lock(); }
-       void unlock() { m_clients_mutex.unlock(); }
+       class AutoLock {
+       public:
+               AutoLock(ClientInterface &iface): m_lock(iface.m_clients_mutex) {}
+
+       private:
+               RecursiveMutexAutoLock m_lock;
+       };
 
        RemoteClientMap& getClientList() { return m_clients; }
 
index 12dc2446049f86b87012c2cb1147466b1a665263..a983424ba54cc8dfa8bf32bc8c4bc2955784c289 100644 (file)
@@ -452,7 +452,7 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
                                ("GOTBLOCKS length is too short");
        }
 
-       m_clients.lock();
+       ClientInterface::AutoLock lock(m_clients);
        RemoteClient *client = m_clients.lockedGetClientNoEx(pkt->getPeerId());
 
        for (u16 i = 0; i < count; i++) {
@@ -460,7 +460,6 @@ void Server::handleCommand_GotBlocks(NetworkPacket* pkt)
                *pkt >> p;
                client->GotBlock(p);
        }
-       m_clients.unlock();
 }
 
 void Server::process_PlayerPos(RemotePlayer *player, PlayerSAO *playersao,
index 23a7dc5a0b8244c22cc071fad1ea0e052e8f3af5..df7083b6839a1e775e7d5dc683f7448a08e77998 100644 (file)
@@ -723,28 +723,29 @@ void Server::AsyncRunStep(bool initial_step)
                //infostream<<"Server: Checking added and deleted active objects"<<std::endl;
                MutexAutoLock envlock(m_env_mutex);
 
-               m_clients.lock();
-               const RemoteClientMap &clients = m_clients.getClientList();
-               ScopeProfiler sp(g_profiler, "Server: update objects within range");
+               {
+                       ClientInterface::AutoLock clientlock(m_clients);
+                       const RemoteClientMap &clients = m_clients.getClientList();
+                       ScopeProfiler sp(g_profiler, "Server: update objects within range");
 
-               m_player_gauge->set(clients.size());
-               for (const auto &client_it : clients) {
-                       RemoteClient *client = client_it.second;
+                       m_player_gauge->set(clients.size());
+                       for (const auto &client_it : clients) {
+                               RemoteClient *client = client_it.second;
 
-                       if (client->getState() < CS_DefinitionsSent)
-                               continue;
+                               if (client->getState() < CS_DefinitionsSent)
+                                       continue;
 
-                       // This can happen if the client times out somehow
-                       if (!m_env->getPlayer(client->peer_id))
-                               continue;
+                               // This can happen if the client times out somehow
+                               if (!m_env->getPlayer(client->peer_id))
+                                       continue;
 
-                       PlayerSAO *playersao = getPlayerSAO(client->peer_id);
-                       if (!playersao)
-                               continue;
+                               PlayerSAO *playersao = getPlayerSAO(client->peer_id);
+                               if (!playersao)
+                                       continue;
 
-                       SendActiveObjectRemoveAdd(client, playersao);
+                               SendActiveObjectRemoveAdd(client, playersao);
+                       }
                }
-               m_clients.unlock();
 
                // Write changes to the mod storage
                m_mod_storage_save_timer -= dtime;
@@ -787,63 +788,64 @@ void Server::AsyncRunStep(bool initial_step)
 
                m_aom_buffer_counter->increment(aom_count);
 
-               m_clients.lock();
-               const RemoteClientMap &clients = m_clients.getClientList();
-               // Route data to every client
-               std::string reliable_data, unreliable_data;
-               for (const auto &client_it : clients) {
-                       reliable_data.clear();
-                       unreliable_data.clear();
-                       RemoteClient *client = client_it.second;
-                       PlayerSAO *player = getPlayerSAO(client->peer_id);
-                       // Go through all objects in message buffer
-                       for (const auto &buffered_message : buffered_messages) {
-                               // If object does not exist or is not known by client, skip it
-                               u16 id = buffered_message.first;
-                               ServerActiveObject *sao = m_env->getActiveObject(id);
-                               if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
-                                       continue;
+               {
+                       ClientInterface::AutoLock clientlock(m_clients);
+                       const RemoteClientMap &clients = m_clients.getClientList();
+                       // Route data to every client
+                       std::string reliable_data, unreliable_data;
+                       for (const auto &client_it : clients) {
+                               reliable_data.clear();
+                               unreliable_data.clear();
+                               RemoteClient *client = client_it.second;
+                               PlayerSAO *player = getPlayerSAO(client->peer_id);
+                               // Go through all objects in message buffer
+                               for (const auto &buffered_message : buffered_messages) {
+                                       // If object does not exist or is not known by client, skip it
+                                       u16 id = buffered_message.first;
+                                       ServerActiveObject *sao = m_env->getActiveObject(id);
+                                       if (!sao || client->m_known_objects.find(id) == client->m_known_objects.end())
+                                               continue;
 
-                               // Get message list of object
-                               std::vector<ActiveObjectMessage>* list = buffered_message.second;
-                               // Go through every message
-                               for (const ActiveObjectMessage &aom : *list) {
-                                       // Send position updates to players who do not see the attachment
-                                       if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
-                                               if (sao->getId() == player->getId())
-                                                       continue;
-
-                                               // Do not send position updates for attached players
-                                               // as long the parent is known to the client
-                                               ServerActiveObject *parent = sao->getParent();
-                                               if (parent && client->m_known_objects.find(parent->getId()) !=
-                                                               client->m_known_objects.end())
-                                                       continue;
+                                       // Get message list of object
+                                       std::vector<ActiveObjectMessage>* list = buffered_message.second;
+                                       // Go through every message
+                                       for (const ActiveObjectMessage &aom : *list) {
+                                               // Send position updates to players who do not see the attachment
+                                               if (aom.datastring[0] == AO_CMD_UPDATE_POSITION) {
+                                                       if (sao->getId() == player->getId())
+                                                               continue;
+
+                                                       // Do not send position updates for attached players
+                                                       // as long the parent is known to the client
+                                                       ServerActiveObject *parent = sao->getParent();
+                                                       if (parent && client->m_known_objects.find(parent->getId()) !=
+                                                                       client->m_known_objects.end())
+                                                               continue;
+                                               }
+
+                                               // Add full new data to appropriate buffer
+                                               std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
+                                               char idbuf[2];
+                                               writeU16((u8*) idbuf, aom.id);
+                                               // u16 id
+                                               // std::string data
+                                               buffer.append(idbuf, sizeof(idbuf));
+                                               buffer.append(serializeString16(aom.datastring));
                                        }
-
-                                       // Add full new data to appropriate buffer
-                                       std::string &buffer = aom.reliable ? reliable_data : unreliable_data;
-                                       char idbuf[2];
-                                       writeU16((u8*) idbuf, aom.id);
-                                       // u16 id
-                                       // std::string data
-                                       buffer.append(idbuf, sizeof(idbuf));
-                                       buffer.append(serializeString16(aom.datastring));
                                }
-                       }
-                       /*
-                               reliable_data and unreliable_data are now ready.
-                               Send them.
-                       */
-                       if (!reliable_data.empty()) {
-                               SendActiveObjectMessages(client->peer_id, reliable_data);
-                       }
+                               /*
+                                       reliable_data and unreliable_data are now ready.
+                                       Send them.
+                               */
+                               if (!reliable_data.empty()) {
+                                       SendActiveObjectMessages(client->peer_id, reliable_data);
+                               }
 
-                       if (!unreliable_data.empty()) {
-                               SendActiveObjectMessages(client->peer_id, unreliable_data, false);
+                               if (!unreliable_data.empty()) {
+                                       SendActiveObjectMessages(client->peer_id, unreliable_data, false);
+                               }
                        }
                }
-               m_clients.unlock();
 
                // Clear buffered_messages
                for (auto &buffered_message : buffered_messages) {
@@ -1050,18 +1052,14 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
 {
        std::string playername;
        PlayerSAO *playersao = NULL;
-       m_clients.lock();
-       try {
+       {
+               ClientInterface::AutoLock clientlock(m_clients);
                RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_InitDone);
                if (client) {
                        playername = client->getName();
                        playersao = emergePlayer(playername.c_str(), peer_id, client->net_proto_version);
                }
-       } catch (std::exception &e) {
-               m_clients.unlock();
-               throw;
        }
-       m_clients.unlock();
 
        RemotePlayer *player = m_env->getPlayer(playername.c_str());
 
@@ -1233,13 +1231,12 @@ void Server::onMapEditEvent(const MapEditEvent &event)
 void Server::SetBlocksNotSent(std::map<v3s16, MapBlock *>& block)
 {
        std::vector<session_t> clients = m_clients.getClientIDs();
-       m_clients.lock();
+       ClientInterface::AutoLock clientlock(m_clients);
        // Set the modified blocks unsent for all the clients
        for (const session_t client_id : clients) {
                        if (RemoteClient *client = m_clients.lockedGetClientNoEx(client_id))
                                client->SetBlocksNotSent(block);
        }
-       m_clients.unlock();
 }
 
 void Server::peerAdded(con::Peer *peer)
@@ -1267,13 +1264,11 @@ bool Server::getClientConInfo(session_t peer_id, con::rtt_stat_type type, float*
 
 bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
 {
-       m_clients.lock();
+       ClientInterface::AutoLock clientlock(m_clients);
        RemoteClient* client = m_clients.lockedGetClientNoEx(peer_id, CS_Invalid);
 
-       if (!client) {
-               m_clients.unlock();
+       if (!client)
                return false;
-       }
 
        ret.state = client->getState();
        ret.addr = client->getAddress();
@@ -1288,8 +1283,6 @@ bool Server::getClientInfo(session_t peer_id, ClientInfo &ret)
 
        ret.lang_code = client->getLangCode();
 
-       m_clients.unlock();
-
        return true;
 }
 
@@ -2218,7 +2211,7 @@ void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
        pkt << p;
 
        std::vector<session_t> clients = m_clients.getClientIDs();
-       m_clients.lock();
+       ClientInterface::AutoLock clientlock(m_clients);
 
        for (session_t client_id : clients) {
                RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
@@ -2241,8 +2234,6 @@ void Server::sendRemoveNode(v3s16 p, std::unordered_set<u16> *far_players,
                // Send as reliable
                m_clients.send(client_id, 0, &pkt, true);
        }
-
-       m_clients.unlock();
 }
 
 void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_players,
@@ -2257,7 +2248,7 @@ void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_player
                        << (u8) (remove_metadata ? 0 : 1);
 
        std::vector<session_t> clients = m_clients.getClientIDs();
-       m_clients.lock();
+       ClientInterface::AutoLock clientlock(m_clients);
 
        for (session_t client_id : clients) {
                RemoteClient *client = m_clients.lockedGetClientNoEx(client_id);
@@ -2280,8 +2271,6 @@ void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set<u16> *far_player
                // Send as reliable
                m_clients.send(client_id, 0, &pkt, true);
        }
-
-       m_clients.unlock();
 }
 
 void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far_d_nodes)
@@ -2290,7 +2279,7 @@ void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far
        NodeMetadataList meta_updates_list(false);
        std::vector<session_t> clients = m_clients.getClientIDs();
 
-       m_clients.lock();
+       ClientInterface::AutoLock clientlock(m_clients);
 
        for (session_t i : clients) {
                RemoteClient *client = m_clients.lockedGetClientNoEx(i);
@@ -2331,8 +2320,6 @@ void Server::sendMetadataChanged(const std::list<v3s16> &meta_updates, float far
 
                meta_updates_list.clear();
        }
-
-       m_clients.unlock();
 }
 
 void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver,
@@ -2368,7 +2355,7 @@ void Server::SendBlocks(float dtime)
 
                std::vector<session_t> clients = m_clients.getClientIDs();
 
-               m_clients.lock();
+               ClientInterface::AutoLock clientlock(m_clients);
                for (const session_t client_id : clients) {
                        RemoteClient *client = m_clients.lockedGetClientNoEx(client_id, CS_Active);
 
@@ -2378,7 +2365,6 @@ void Server::SendBlocks(float dtime)
                        total_sending += client->getSendingCount();
                        client->GetNextBlocks(m_env,m_emerge, dtime, queue);
                }
-               m_clients.unlock();
        }
 
        // Sort.
@@ -2386,7 +2372,7 @@ void Server::SendBlocks(float dtime)
        // Lowest is most important.
        std::sort(queue.begin(), queue.end());
 
-       m_clients.lock();
+       ClientInterface::AutoLock clientlock(m_clients);
 
        // Maximal total count calculation
        // The per-client block sends is halved with the maximal online users
@@ -2415,7 +2401,6 @@ void Server::SendBlocks(float dtime)
                client->SentBlock(block_to_send.pos);
                total_sending++;
        }
-       m_clients.unlock();
 }
 
 bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
@@ -2424,15 +2409,12 @@ bool Server::SendBlock(session_t peer_id, const v3s16 &blockpos)
        if (!block)
                return false;
 
-       m_clients.lock();
+       ClientInterface::AutoLock clientlock(m_clients);
        RemoteClient *client = m_clients.lockedGetClientNoEx(peer_id, CS_Active);
-       if (!client || client->isBlockSent(blockpos)) {
-               m_clients.unlock();
+       if (!client || client->isBlockSent(blockpos))
                return false;
-       }
        SendBlockNoLock(peer_id, block, client->serialization_version,
                        client->net_proto_version);
-       m_clients.unlock();
 
        return true;
 }
@@ -3534,48 +3516,49 @@ bool Server::dynamicAddMedia(std::string filepath,
        legacy_pkt.putLongString(filedata);
 
        std::unordered_set<session_t> delivered, waiting;
-       m_clients.lock();
-       for (auto &pair : m_clients.getClientList()) {
-               if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) {
-                       /*
-                               If a client is in the DefinitionsSent state it is too late to
-                               transfer the file via sendMediaAnnouncement() but at the same
-                               time the client cannot accept a media push yet.
-                               Short of artificially delaying the joining process there is no
-                               way for the server to resolve this so we (currently) opt not to.
-                       */
-                       warningstream << "The media \"" << filename << "\" (dynamic) could "
-                               "not be delivered to " << pair.second->getName()
-                               << " due to a race condition." << std::endl;
-                       continue;
-               }
-               if (pair.second->getState() < CS_Active)
-                       continue;
+       {
+               ClientInterface::AutoLock clientlock(m_clients);
+               for (auto &pair : m_clients.getClientList()) {
+                       if (pair.second->getState() == CS_DefinitionsSent && !ephemeral) {
+                               /*
+                                       If a client is in the DefinitionsSent state it is too late to
+                                       transfer the file via sendMediaAnnouncement() but at the same
+                                       time the client cannot accept a media push yet.
+                                       Short of artificially delaying the joining process there is no
+                                       way for the server to resolve this so we (currently) opt not to.
+                               */
+                               warningstream << "The media \"" << filename << "\" (dynamic) could "
+                                       "not be delivered to " << pair.second->getName()
+                                       << " due to a race condition." << std::endl;
+                               continue;
+                       }
+                       if (pair.second->getState() < CS_Active)
+                               continue;
 
-               const auto proto_ver = pair.second->net_proto_version;
-               if (proto_ver < 39)
-                       continue;
+                       const auto proto_ver = pair.second->net_proto_version;
+                       if (proto_ver < 39)
+                               continue;
 
-               const session_t peer_id = pair.second->peer_id;
-               if (!to_player.empty() && getPlayerName(peer_id) != to_player)
-                       continue;
+                       const session_t peer_id = pair.second->peer_id;
+                       if (!to_player.empty() && getPlayerName(peer_id) != to_player)
+                               continue;
 
-               if (proto_ver < 40) {
-                       delivered.emplace(peer_id);
-                       /*
-                               The network layer only guarantees ordered delivery inside a channel.
-                               Since the very next packet could be one that uses the media, we have
-                               to push the media over ALL channels to ensure it is processed before
-                               it is used. In practice this means channels 1 and 0.
-                       */
-                       m_clients.send(peer_id, 1, &legacy_pkt, true);
-                       m_clients.send(peer_id, 0, &legacy_pkt, true);
-               } else {
-                       waiting.emplace(peer_id);
-                       Send(peer_id, &pkt);
+                       if (proto_ver < 40) {
+                               delivered.emplace(peer_id);
+                               /*
+                                       The network layer only guarantees ordered delivery inside a channel.
+                                       Since the very next packet could be one that uses the media, we have
+                                       to push the media over ALL channels to ensure it is processed before
+                                       it is used. In practice this means channels 1 and 0.
+                               */
+                               m_clients.send(peer_id, 1, &legacy_pkt, true);
+                               m_clients.send(peer_id, 0, &legacy_pkt, true);
+                       } else {
+                               waiting.emplace(peer_id);
+                               Send(peer_id, &pkt);
+                       }
                }
        }
-       m_clients.unlock();
 
        // Run callback for players that already had the file delivered (legacy-only)
        for (session_t peer_id : delivered) {