]> git.lizzy.rs Git - dragonfireclient.git/blob - src/modchannels.cpp
Fix use-after-free in node meta cleanup
[dragonfireclient.git] / src / modchannels.cpp
1 /*
2 Minetest
3 Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "modchannels.h"
21 #include <algorithm>
22 #include <cassert>
23 #include "util/basic_macros.h"
24
25 bool ModChannel::registerConsumer(session_t peer_id)
26 {
27
28         // ignore if peer_id already joined
29         if (CONTAINS(m_client_consumers, peer_id))
30                 return false;
31
32         m_client_consumers.push_back(peer_id);
33         return true;
34 }
35
36 bool ModChannel::removeConsumer(session_t peer_id)
37 {
38         bool found = false;
39         auto peer_removal_fct = [peer_id, &found](u16 p) {
40                 if (p == peer_id)
41                         found = true;
42
43                 return p == peer_id;
44         };
45
46         m_client_consumers.erase(
47                         std::remove_if(m_client_consumers.begin(),
48                                         m_client_consumers.end(), peer_removal_fct),
49                         m_client_consumers.end());
50
51         return found;
52 }
53
54 bool ModChannel::canWrite() const
55 {
56         return m_state == MODCHANNEL_STATE_READ_WRITE;
57 }
58
59 void ModChannel::setState(ModChannelState state)
60 {
61         assert(state != MODCHANNEL_STATE_INIT);
62
63         m_state = state;
64 }
65
66 bool ModChannelMgr::channelRegistered(const std::string &channel) const
67 {
68         return m_registered_channels.find(channel) != m_registered_channels.end();
69 }
70
71 ModChannel *ModChannelMgr::getModChannel(const std::string &channel)
72 {
73         if (!channelRegistered(channel))
74                 return nullptr;
75
76         return m_registered_channels[channel].get();
77 }
78
79 bool ModChannelMgr::canWriteOnChannel(const std::string &channel) const
80 {
81         const auto channel_it = m_registered_channels.find(channel);
82         if (channel_it == m_registered_channels.end()) {
83                 return false;
84         }
85
86         return channel_it->second->canWrite();
87 }
88
89 void ModChannelMgr::registerChannel(const std::string &channel)
90 {
91         m_registered_channels[channel] = std::make_unique<ModChannel>(channel);
92 }
93
94 bool ModChannelMgr::setChannelState(const std::string &channel, ModChannelState state)
95 {
96         if (!channelRegistered(channel))
97                 return false;
98
99         auto channel_it = m_registered_channels.find(channel);
100         channel_it->second->setState(state);
101
102         return true;
103 }
104
105 bool ModChannelMgr::removeChannel(const std::string &channel)
106 {
107         if (!channelRegistered(channel))
108                 return false;
109
110         m_registered_channels.erase(channel);
111         return true;
112 }
113
114 bool ModChannelMgr::joinChannel(const std::string &channel, session_t peer_id)
115 {
116         if (!channelRegistered(channel))
117                 registerChannel(channel);
118
119         return m_registered_channels[channel]->registerConsumer(peer_id);
120 }
121
122 bool ModChannelMgr::leaveChannel(const std::string &channel, session_t peer_id)
123 {
124         if (!channelRegistered(channel))
125                 return false;
126
127         // Remove consumer from channel
128         bool consumerRemoved = m_registered_channels[channel]->removeConsumer(peer_id);
129
130         // If channel is empty, remove it
131         if (m_registered_channels[channel]->getChannelPeers().empty()) {
132                 removeChannel(channel);
133         }
134         return consumerRemoved;
135 }
136
137 void ModChannelMgr::leaveAllChannels(session_t peer_id)
138 {
139         for (auto &channel_it : m_registered_channels)
140                 channel_it.second->removeConsumer(peer_id);
141 }
142
143 static std::vector<u16> empty_channel_list;
144 const std::vector<u16> &ModChannelMgr::getChannelPeers(const std::string &channel) const
145 {
146         const auto &channel_it = m_registered_channels.find(channel);
147         if (channel_it == m_registered_channels.end())
148                 return empty_channel_list;
149
150         return channel_it->second->getChannelPeers();
151 }