Some code refactoring

This commit is contained in:
WolverinDEV 2021-04-14 14:57:04 +02:00
parent bf643b4797
commit 6b774d3a80
29 changed files with 610 additions and 468 deletions

View File

@ -56,7 +56,7 @@ find_package(CXXTerminal REQUIRED)
find_package(StringVariable REQUIRED)
find_package(yaml-cpp REQUIRED)
find_package(jsoncpp REQUIRED)
find_package(Ed25519 REQUIRED)
find_package(ed25519 REQUIRED)
find_package(DataPipes REQUIRED)
find_package(Opus REQUIRED)
find_package(spdlog REQUIRED)

View File

@ -267,7 +267,7 @@ target_link_libraries(TeaSpeakServer
tommath::static
jsoncpp_lib
${ed25519_LIBRARIES_STATIC}
${Ed25519_LIBRARIES_STATIC}
zstd::libzstd_static
)

View File

@ -96,7 +96,7 @@ void ClientPermissionCalculator::initialize_client(DataClient* client) {
this->virtual_server_id = client->getServerId();
this->client_database_id = client->getClientDatabaseId();
this->client_type = client->getType();
this->client_permissions = client->permissions();
this->client_permissions_ = client->permissions();
auto server = client->getServer();
if(server) {
@ -139,19 +139,8 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
std::vector<std::pair<PermissionType, PermissionFlaggedValue>> result;
result.reserve(permissions.size());
if(!this->client_permissions) {
this->client_permissions = serverInstance->databaseHelper()->loadClientPermissionManager(this->virtual_server_id, this->client_database_id);
if(!this->client_permissions) {
logCritical(this->virtual_server_id, "Failed to load client permissions for client {}", this->client_database_id);
for(size_t index{0}; index < permissions.size(); index++) {
result.emplace_back(permissions[index], PermissionFlaggedValue{ 0, false });
}
return result;
}
}
bool have_skip_permission{false};
int skip_permission_type{-1}; /* -1 := unset | 0 := skip, not explicit | 1 := skip, explicit */
auto client_permissions = this->client_permissions();
assert(client_permissions);
/*
* server_group_data[0] := Server group id
@ -164,34 +153,6 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
std::vector<GroupData> server_group_data;
GroupData* active_server_group;
/* function to calculate skip permission */
auto calculate_skip = [&]{
skip_permission_type = 0;
/* test for skip permission within the client permission manager */
{
auto skip_value = this->client_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions);
if(skip_value.has_value) {
have_skip_permission = skip_value.value == 1;
skip_permission_type = 1;
logTrace(this->virtual_server_id, "[Permission] Found skip permission in client permissions. Value: {}", have_skip_permission);
}
}
/* test for skip permission within all server groups */
if(skip_permission_type != 1) {
for(const auto& assignment : this->assigned_server_groups()) {
auto group_permissions = assignment->permissions();
auto flagged_value = group_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions);
if(flagged_value.has_value) {
have_skip_permission |= flagged_value.value == 1;
if(have_skip_permission) {
logTrace(this->virtual_server_id, "[Permission] Found skip permission in client server group. Group: {} ({}), Value: {}", assignment->group_id(), assignment->display_name(), have_skip_permission);
break;
}
}
}
}
};
auto initialize_group_data = [&](const permission::PermissionType& permission_type) {
server_group_data_initialized = true;
active_server_group = nullptr;
@ -253,10 +214,10 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
for(const auto& permission : permissions) {
server_group_data_initialized = false; /* reset all group data */
auto client_permission_flags = this->client_permissions->permission_flags(permission);
auto client_permission_flags = client_permissions->permission_flags(permission);
/* lets try to resolve the channel specific permission */
if(this->channel_id_ > 0 && client_permission_flags.channel_specific) {
auto data = this->client_permissions->channel_permission(permission, this->channel_id_);
auto data = client_permissions->channel_permission(permission, this->channel_id_);
if(calculate_granted ? data.flags.grant_set : data.flags.value_set) {
result.push_back({permission, {calculate_granted ? data.values.grant : data.values.value, true}});
logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned {} (Client channel permission)", this->client_database_id, permission::resolvePermissionData(permission)->name, data.values.value);
@ -265,16 +226,9 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
}
bool skip_channel_permissions = this->channel_id_ == 0;
bool skip_channel_permissions = this->channel_id_ == 0 || this->has_global_skip_permission();
if(!skip_channel_permissions) {
/* look if somewhere is the skip permission flag set */
if(skip_permission_type == -1) {/* initialize skip flag */
calculate_skip();
}
skip_channel_permissions = have_skip_permission;
}
if(!skip_channel_permissions) {
/* okey we've no global skip. Then now lookup the groups and the client permissions */
/* We dont have a global skip flag. Lets see if the target permission has skip enabled */
if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) {
/* okey the client has the permission, this counts */
skip_channel_permissions = client_permission_flags.skip;
@ -319,7 +273,7 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
}
if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) {
auto client_value = this->client_permissions->permission_values(permission);
auto client_value = client_permissions->permission_values(permission);
result.push_back({permission, {calculate_granted ? client_value.grant : client_value.value, true}});
logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned {} (Client permission)", this->client_database_id, permission::resolvePermissionData(permission)->name, client_value.value);
continue;
@ -336,12 +290,25 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
}
logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned in no permission.", this->client_database_id, permission::resolvePermissionData(permission)->name);
result.push_back({permission, {permNotGranted, false}});
result.push_back({permission, { permNotGranted, false }});
}
return result;
}
const std::shared_ptr<ts::permission::v2::PermissionManager> & ClientPermissionCalculator::client_permissions() {
if(!this->client_permissions_) {
this->client_permissions_ = serverInstance->databaseHelper()->loadClientPermissionManager(this->virtual_server_id, this->client_database_id);
if(!this->client_permissions_) {
logCritical(this->virtual_server_id, "Failed to load client permissions for client {}. Using empty permission set.", this->client_database_id);
this->client_permissions_ = std::make_shared<permission::v2::PermissionManager>();
}
}
return this->client_permissions_;
}
const std::vector<std::shared_ptr<groups::ServerGroup>>& ClientPermissionCalculator::assigned_server_groups() {
if(this->assigned_server_groups_.has_value()) {
return *this->assigned_server_groups_;
@ -391,4 +358,47 @@ const std::shared_ptr<groups::ChannelGroup>& ClientPermissionCalculator::assigne
*this->assigned_channel_group_ = channel_group;
return *this->assigned_channel_group_;
}
bool ClientPermissionCalculator::has_global_skip_permission() {
/* test for skip permission within the client permission manager */
{
auto client_permissions = this->client_permissions();
auto skip_value = client_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions);
if(skip_value.has_value) {
this->skip_enabled = std::make_optional(permission::v2::permission_granted(1, skip_value));
logTrace(this->virtual_server_id, "[Permission] Found skip permission in client permissions. Value: {}", *this->skip_enabled);
}
}
/* test for skip permission within all server groups */
if(!this->skip_enabled.has_value()) {
for(const auto& assignment : this->assigned_server_groups()) {
auto group_permissions = assignment->permissions();
auto flagged_value = group_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions);
if(flagged_value.has_value) {
this->skip_enabled = std::make_optional(permission::v2::permission_granted(1, flagged_value));
if(*this->skip_enabled) {
logTrace(this->virtual_server_id, "[Permission] Found skip permission in client server group. Group: {} ({})", assignment->group_id(), assignment->display_name());
break;
}
}
}
}
if(!this->skip_enabled.has_value()) {
this->skip_enabled = std::make_optional(false);
}
return *this->skip_enabled;
}
bool ClientPermissionCalculator::permission_granted(const permission::PermissionType &permission,
const permission::PermissionValue &required_value, bool granted) {
return this->permission_granted(permission, { required_value, true }, granted);
}
bool ClientPermissionCalculator::permission_granted(const permission::PermissionType &permission,
const permission::v2::PermissionFlaggedValue &required_value, bool granted) {
return permission::v2::permission_granted(required_value, this->calculate_permission(permission, granted));
}

View File

@ -40,7 +40,7 @@ namespace ts::server {
* @param granted
* @return
*/
permission::v2::PermissionFlaggedValue calculate_permission(
[[nodiscard]] permission::v2::PermissionFlaggedValue calculate_permission(
permission::PermissionType,
bool granted = false
);
@ -52,10 +52,37 @@ namespace ts::server {
* @param calculate_granted
* @return
*/
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions(
[[nodiscard]] std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions(
const std::deque<permission::PermissionType>&,
bool calculate_granted = false
);
/**
* Test if the target has the target permission granted.
* If the client does not have any value assigned for the permission `false` will be returned.
*/
[[nodiscard]] bool permission_granted(
const permission::PermissionType& /* target permission */,
const permission::PermissionValue& /* required value */,
bool /* granted permission */ = false
);
/**
* Test if the target has the target permission granted.
* If the client does not have any value assigned for the permission,
* `true` will be returned if the `required value` contains no value
* otherwise false will be returned.
*
* This method should be used when testing permissions which are allowed by default except if they're
* specified otherwise. An example permission would be if we're testing against the channel needed join power.
*/
[[nodiscard]] bool permission_granted(
const permission::PermissionType& /* target permission */,
const permission::v2::PermissionFlaggedValue& /* required value */,
bool /* granted permission */ = false
);
//const PermissionValue& required, const PermissionFlaggedValue& given, bool requires_given = true
private:
/* given fields */
ServerId virtual_server_id;
@ -68,10 +95,9 @@ namespace ts::server {
std::function<std::shared_ptr<groups::ServerGroup>()> default_server_group{[]{ return nullptr; }};
/* fields which will be set when calculating permissions */
std::shared_ptr<permission::v2::PermissionManager> client_permissions{};
std::shared_ptr<permission::v2::PermissionManager> client_permissions_{};
bool global_skip{false};
bool global_skip_set{false};
std::optional<bool> skip_enabled{};
std::optional<std::shared_ptr<groups::ChannelGroup>> assigned_channel_group_{};
std::optional<std::vector<std::shared_ptr<groups::ServerGroup>>> assigned_server_groups_{};
@ -81,5 +107,7 @@ namespace ts::server {
[[nodiscard]] const std::vector<std::shared_ptr<groups::ServerGroup>>& assigned_server_groups();
[[nodiscard]] const std::shared_ptr<groups::ChannelGroup>& assigned_channel_group();
[[nodiscard]] const std::shared_ptr<permission::v2::PermissionManager>& client_permissions();
[[nodiscard]] bool has_global_skip_permission();
};
}

View File

@ -175,7 +175,7 @@ void VirtualServer::unregisterInternalClient(std::shared_ptr<ConnectedClient> cl
}
bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& client, bool join) {
std::shared_lock server_channel_lock{this->channel_tree_lock};
std::shared_lock server_channel_lock{this->channel_tree_mutex};
std::shared_ptr<BasicChannel> channel{};
auto requested_channel_path = client->properties()[property::CLIENT_DEFAULT_CHANNEL].value();
@ -206,7 +206,7 @@ bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& clie
debugMessage(this->getServerId(), "{} Allowing client to join channel {} because the token he used explicitly allowed it.", client->getLoggingPrefix(), channel->channelId());
if(whitelist_entry->second != "ignore") {
if (!channel->passwordMatch(client_channel_password, true)) {
if (!channel->verify_password(std::make_optional(client_channel_password), true)) {
if (!permission::v2::permission_granted(1, client->calculate_permission(permission::b_channel_join_ignore_password, channel->channelId()))) {
channel = nullptr;
goto skip_permissions;
@ -222,7 +222,7 @@ bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& clie
goto skip_permissions;
}
if (!channel->passwordMatch(client->properties()[property::CLIENT_DEFAULT_CHANNEL_PASSWORD], true)) {
if (!channel->verify_password(std::make_optional(client->properties()[property::CLIENT_DEFAULT_CHANNEL_PASSWORD].value()), true)) {
if(!permission::v2::permission_granted(1, client->calculate_permission(permission::b_channel_join_ignore_password, channel->channelId()))) {
debugMessage(this->getServerId(), "{} Tried to join channel {} but hasn't given the right channel password.", client->getLoggingPrefix(), channel->channelId());
channel = nullptr;
@ -245,7 +245,7 @@ bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& clie
debugMessage(this->getServerId(), "{} Using channel {} as default client channel.", client->getLoggingPrefix(), channel->channelId());
if(join) {
server_channel_lock.unlock();
unique_lock server_channel_w_lock(this->channel_tree_lock);
unique_lock server_channel_w_lock(this->channel_tree_mutex);
this->client_move(client, channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_w_lock);
} else {
client->currentChannel = channel;
@ -268,14 +268,14 @@ void VirtualServer::testBanStateChange(const std::shared_ptr<ConnectedClient>& i
void VirtualServer::notify_client_ban(const shared_ptr<ConnectedClient> &target, const std::shared_ptr<ts::server::ConnectedClient> &invoker, const std::string &reason, size_t time) {
/* the target is not allowed to execute anything; Must before channel tree lock because the target may waits for us to finish the channel stuff */
lock_guard command_lock(target->command_lock);
unique_lock server_channel_lock(this->channel_tree_lock); /* we're "moving" a client! */
unique_lock server_channel_lock(this->channel_tree_mutex); /* we're "moving" a client! */
if(target->currentChannel) {
for(const auto& client : this->getClients()) {
if(!client || client == target)
continue;
unique_lock client_channel_lock(client->channel_lock);
unique_lock client_channel_lock(client->channel_tree_mutex);
if(client->isClientVisible(target, false))
client->notifyClientLeftViewBanned(target, reason, invoker, time, false);
}
@ -285,7 +285,7 @@ void VirtualServer::notify_client_ban(const shared_ptr<ConnectedClient> &target,
}
/* now disconnect the target itself */
unique_lock client_channel_lock(target->channel_lock);
unique_lock client_channel_lock(target->channel_tree_mutex);
target->notifyClientLeftViewBanned(target, reason, invoker, time, false);
target->currentChannel = nullptr;
}
@ -298,19 +298,19 @@ void VirtualServer::notify_client_kick(
if(target_channel) {
/* use the move! */
unique_lock server_channel_lock(this->channel_tree_lock, defer_lock);
unique_lock server_channel_lock(this->channel_tree_mutex, defer_lock);
this->client_move(target, target_channel, invoker, reason, ViewReasonId::VREASON_CHANNEL_KICK, true, server_channel_lock);
} else {
/* the target is not allowed to execute anything; Must before channel tree lock because the target may waits for us to finish the channel stuff */
lock_guard command_lock(target->command_lock);
unique_lock server_channel_lock(this->channel_tree_lock); /* we're "moving" a client! */
unique_lock server_channel_lock(this->channel_tree_mutex); /* we're "moving" a client! */
if(target->currentChannel) {
for(const auto& client : this->getClients()) {
if(!client || client == target)
continue;
unique_lock client_channel_lock(client->channel_lock);
unique_lock client_channel_lock(client->channel_tree_mutex);
if(client->isClientVisible(target, false))
client->notifyClientLeftViewKicked(target, nullptr, reason, invoker, false);
}
@ -323,7 +323,7 @@ void VirtualServer::notify_client_kick(
}
/* now disconnect the target itself */
unique_lock client_channel_lock(target->channel_lock);
unique_lock client_channel_lock(target->channel_tree_mutex);
target->notifyClientLeftViewKicked(target, nullptr, reason, invoker, false);
target->currentChannel = nullptr;
}
@ -361,7 +361,6 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
channel->deleted = true;
}
auto default_channel = this->channelTree->getDefaultChannel();
tree_lock.unlock();
deque<unique_lock<threads::Mutex>> command_locks;
for(const auto& client : clients) {
@ -373,7 +372,8 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
}
if(!tree_lock.owns_lock()) {
tree_lock.lock(); /* no clients left within that tree */
/* This case should never happen. client_move should never unlock the tree lock! */
tree_lock.lock();
}
command_locks.clear();
@ -384,8 +384,8 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
}
this->forEachClient([&](const shared_ptr<ConnectedClient>& client) {
unique_lock client_channel_lock(client->channel_lock);
client->notifyChannelDeleted(client->channels->delete_channel_root(channel), invoker);
unique_lock client_channel_lock(client->channel_tree_mutex);
client->notifyChannelDeleted(client->channel_tree->delete_channel_root(channel), invoker);
});
{
@ -451,11 +451,11 @@ void VirtualServer::client_move(
/* second step: show the target channel to the client if its not shown and let him subscibe to the channel */
if(target_channel && notify_client) {
unique_lock client_channel_lock(target->channel_lock);
unique_lock client_channel_lock(target->channel_tree_mutex);
bool success = false;
/* TODO: Use a bunk here and not a notify for every single */
for(const auto& channel : target->channels->show_channel(l_target_channel, success))
for(const auto& channel : target->channel_tree->show_channel(l_target_channel, success))
target->notifyChannelShow(channel->channel(), channel->previous_channel);
sassert(success);
if(!success)
@ -469,11 +469,11 @@ void VirtualServer::client_move(
this->forEachClient([&](const shared_ptr<ConnectedClient>& client) {
if (!notify_client && client == target) return;
unique_lock client_channel_lock(client->channel_lock);
auto chan_target = client->channels->find_channel(target_channel);
unique_lock client_channel_lock(client->channel_tree_mutex);
auto chan_target = client->channel_tree->find_channel(target_channel);
if(chan_target) {
auto chan_source = client->channels->find_channel(s_source_channel);
auto chan_source = client->channel_tree->find_channel(s_source_channel);
if(chan_source) {
if (chan_target->subscribed || client == target) {
if (client == target || client->isClientVisible(target, false)) {
@ -527,7 +527,7 @@ void VirtualServer::client_move(
if(!client || client == target)
continue;
unique_lock client_channel_lock(client->channel_lock);
unique_lock client_channel_lock(client->channel_tree_mutex);
if(client->isClientVisible(target, false))
client->notifyClientLeftView(target, nullptr, reason_id, reason_message, invoker, false);
}
@ -541,11 +541,9 @@ void VirtualServer::client_move(
TIMING_STEP(timings, "notify view");
target->currentChannel = target_channel;
server_channel_write_lock.unlock();
/* third step: update stuff for the client (remember: the client cant execute anything at the moment!) */
shared_lock server_channel_read_lock(this->channel_tree_lock);
unique_lock client_channel_lock(target->channel_lock);
unique_lock client_channel_lock{target->channel_tree_mutex};
TIMING_STEP(timings, "lock own tr");
if (s_source_channel) {
@ -573,7 +571,7 @@ void VirtualServer::client_move(
if(s_source_channel) {
deque<ChannelId> deleted;
for(const auto& channel : target->channels->test_channel(l_source_channel, l_target_channel)) {
for(const auto& channel : target->channel_tree->test_channel(l_source_channel, l_target_channel)) {
deleted.push_back(channel->channelId());
}
@ -586,7 +584,7 @@ void VirtualServer::client_move(
auto source_channel_sub_power = target->calculate_permission(permission::i_channel_subscribe_power, i_source_channel);
if(!s_source_channel->permission_granted(permission::i_channel_needed_subscribe_power, source_channel_sub_power, false)) {
auto source_channel_sub_power_ignore = target->calculate_permission(permission::b_channel_ignore_subscribe_power, i_source_channel);
if(!permission::v2::permission_granted(1, source_channel_sub_power_ignore, true)) {
if(!permission::v2::permission_granted(1, source_channel_sub_power_ignore)) {
logTrace(this->serverId, "Force unsubscribing of client {} for channel {}/{}. (Channel switch and no permissions)",
CLIENT_STR_LOG_PREFIX_(target), s_source_channel->name(),
i_source_channel

View File

@ -173,7 +173,7 @@ void VirtualServer::executeServerTick() {
{
BEGIN_TIMINGS();
unique_lock channel_lock(this->channel_tree_lock);
unique_lock channel_lock(this->channel_tree_mutex);
auto channels = this->channelTree->channels();
channel_lock.unlock();

View File

@ -616,7 +616,7 @@ void VirtualServer::preStop(const std::string& reason) {
}
for(const auto& cl : this->getClients()) {
unique_lock channel_lock(cl->channel_lock);
unique_lock channel_lock(cl->channel_tree_mutex);
if (cl->currentChannel) {
auto vc = dynamic_pointer_cast<VoiceClient>(cl);
if(vc) {
@ -822,22 +822,36 @@ std::vector<std::shared_ptr<ConnectedClient>> VirtualServer::getClients() {
return clients;
}
/* Note: This method **should** not lock the channel tree else we've a lot to do! */
deque<shared_ptr<ConnectedClient>> VirtualServer::getClientsByChannel(std::shared_ptr<BasicChannel> channel) {
assert(this);
auto s_channel = dynamic_pointer_cast<ServerChannel>(channel);
if(!s_channel) return {}; /* what had we done wrong here... :D */
assert(s_channel);
shared_lock client_lock(s_channel->client_lock);
if(!s_channel) {
return {};
}
std::shared_lock client_lock{s_channel->client_lock};
auto weak_clients = s_channel->clients;
client_lock.unlock();
std::deque<std::shared_ptr<ConnectedClient>> result;
for(const auto& weak_client : weak_clients) {
auto client = weak_client.lock();
if(!client) continue;
if(client->connectionState() != ConnectionState::CONNECTED) continue;
if(client->getChannel() != channel) continue; /* to be sure */
if(!client) {
continue;
}
if(client->connectionState() != ConnectionState::CONNECTED) {
continue;
}
if(client->getChannel() != channel) {
/* This should not happen! */
continue;
}
result.push_back(move(client));
}
@ -847,7 +861,7 @@ deque<shared_ptr<ConnectedClient>> VirtualServer::getClientsByChannel(std::share
deque<shared_ptr<ConnectedClient>> VirtualServer::getClientsByChannelRoot(const std::shared_ptr<BasicChannel> &root, bool lock) {
assert(this);
shared_lock channel_lock(this->channel_tree_lock, defer_lock);
shared_lock channel_lock(this->channel_tree_mutex, defer_lock);
if(lock)
channel_lock.lock();
@ -860,6 +874,41 @@ deque<shared_ptr<ConnectedClient>> VirtualServer::getClientsByChannelRoot(const
return result;
}
size_t VirtualServer::countChannelRootClients(const std::shared_ptr<BasicChannel> &root, size_t limit, bool lock_channel_tree) {
std::shared_lock channel_lock{this->channel_tree_mutex, defer_lock};
if(lock_channel_tree) {
channel_lock.lock();
}
size_t result{0};
for(const auto& channel : this->channelTree->channels(root)) {
auto channel_clients = this->getClientsByChannel(channel);
result += channel_clients.size();
if(result >= limit) {
return limit;
}
}
return result;
}
bool VirtualServer::isChannelRootEmpty(const std::shared_ptr<BasicChannel> &root, bool lock_channel_tree) {
std::shared_lock channel_lock{this->channel_tree_mutex, defer_lock};
if(lock_channel_tree) {
channel_lock.lock();
}
for(const auto& channel : this->channelTree->channels(root)) {
auto channel_clients = this->getClientsByChannel(channel);
if(!channel_clients.empty()) {
return false;
}
}
return true;
}
bool VirtualServer::notifyServerEdited(std::shared_ptr<ConnectedClient> invoker, deque<string> keys) {
if(!invoker) return false;
@ -886,7 +935,7 @@ bool VirtualServer::notifyServerEdited(std::shared_ptr<ConnectedClient> invoker,
bool VirtualServer::notifyClientPropertyUpdates(std::shared_ptr<ConnectedClient> client, const deque<const property::PropertyDescription*>& keys, bool selfNotify) {
if(keys.empty() || !client) return false;
this->forEachClient([&](const shared_ptr<ConnectedClient>& cl) {
shared_lock client_channel_lock(cl->channel_lock);
shared_lock client_channel_lock(cl->channel_tree_mutex);
if(cl->isClientVisible(client, false) || (cl == client && selfNotify))
cl->notifyClientUpdated(client, keys, false);
});
@ -1137,7 +1186,7 @@ void VirtualServer::update_channel_from_permissions(const std::shared_ptr<BasicC
if(!property_updates.empty()) {
this->forEachClient([&](const std::shared_ptr<ConnectedClient>& cl) {
shared_lock client_channel_lock(cl->channel_lock);
shared_lock client_channel_lock(cl->channel_tree_mutex);
cl->notifyChannelEdited(channel, property_updates, issuer, false);
});
}
@ -1151,10 +1200,10 @@ void VirtualServer::update_channel_from_permissions(const std::shared_ptr<BasicC
if(cl->currentChannel) sassert(l_target);
{
unique_lock client_channel_lock(cl->channel_lock);
unique_lock client_channel_lock(cl->channel_tree_mutex);
deque<ChannelId> deleted;
for(const auto& [flag_visible, channel] : cl->channels->update_channel(l_source, l_target)) {
for(const auto& [flag_visible, channel] : cl->channel_tree->update_channel(l_source, l_target)) {
if(flag_visible) {
cl->notifyChannelShow(channel->channel(), channel->previous_channel);
} else {

View File

@ -155,6 +155,8 @@ namespace ts {
std::vector<std::shared_ptr<ConnectedClient>> getClients();
std::deque<std::shared_ptr<ConnectedClient>> getClientsByChannel(std::shared_ptr<BasicChannel>);
std::deque<std::shared_ptr<ConnectedClient>> getClientsByChannelRoot(const std::shared_ptr<BasicChannel> &, bool lock_channel_tree);
[[nodiscard]] size_t countChannelRootClients(const std::shared_ptr<BasicChannel> &, size_t /* limit */, bool /* lock the channel tree */);
[[nodiscard]] bool isChannelRootEmpty(const std::shared_ptr<BasicChannel> &, bool lock_channel_tree);
template <typename ClType>
std::vector<std::shared_ptr<ClType>> getClientsByChannel(const std::shared_ptr<BasicChannel>& ch) {
@ -278,7 +280,7 @@ namespace ts {
inline int voice_encryption_mode() { return this->_voice_encryption_mode; }
inline std::shared_ptr<conversation::ConversationManager> conversation_manager() { return this->conversation_manager_; }
inline auto& get_channel_tree_lock() { return this->channel_tree_lock; }
inline auto& get_channel_tree_lock() { return this->channel_tree_mutex; }
void update_channel_from_permissions(const std::shared_ptr<BasicChannel>& /* channel */, const std::shared_ptr<ConnectedClient>& /* issuer */);
@ -333,7 +335,7 @@ namespace ts {
int _voice_encryption_mode = 2; /* */
ServerChannelTree* channelTree = nullptr;
std::shared_mutex channel_tree_lock; /* lock if access channel tree! */
std::shared_mutex channel_tree_mutex; /* lock if access channel tree! */
std::shared_ptr<groups::GroupManager> groups_manager_{};

View File

@ -13,7 +13,6 @@
#include "../InstanceHandler.h"
#include "../PermissionCalculator.h"
#include "../groups/GroupManager.h"
#include "../groups/Group.h"
#include <event.h>
using namespace std;
@ -28,7 +27,7 @@ ConnectedClient::ConnectedClient(sql::SqlManager* db, const std::shared_ptr<Virt
memset(&this->remote_address, 0, sizeof(this->remote_address));
connectionStatistics = make_shared<stats::ConnectionStatistics>(server ? server->getServerStatistics() : nullptr);
channels = make_shared<ClientChannelView>(this);
channel_tree = make_shared<ClientChannelView>(this);
}
ConnectedClient::~ConnectedClient() {
@ -234,8 +233,8 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
this->channels_view_power = permission_channel_view_power;
this->channels_ignore_view = permission_channel_ignore_view_power;
shared_lock server_channel_lock(server_ref->channel_tree_lock, defer_lock);
unique_lock client_channel_lock(this->channel_lock, defer_lock);
shared_lock server_channel_lock(server_ref->channel_tree_mutex, defer_lock);
unique_lock client_channel_lock(this->channel_tree_mutex, defer_lock);
if(lock_channel_tree) {
/* first read lock server channel tree */
@ -246,7 +245,7 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
/* might have been changed since we locked the tree */
if(channel) {
deque<ChannelId> deleted;
for(const auto& update_entry : this->channels->update_channel_path(server_ref->channelTree->tree_head(), server_ref->channelTree->find_linked_entry(channel->channelId()))) {
for(const auto& update_entry : this->channel_tree->update_channel_path(server_ref->channelTree->tree_head(), server_ref->channelTree->find_linked_entry(channel->channelId()))) {
if(update_entry.first) {
this->notifyChannelShow(update_entry.second->channel(), update_entry.second->previous_channel);
} else {
@ -272,7 +271,7 @@ void ConnectedClient::updateTalkRights(permission::v2::PermissionFlaggedValue ta
}
void ConnectedClient::resetIdleTime() {
this->idleTimestamp = chrono::system_clock::now();
this->idleTimestamp = std::chrono::system_clock::now();
}
void ConnectedClient::increaseFloodPoints(uint16_t num) {
@ -286,108 +285,129 @@ bool ConnectedClient::shouldFloodBlock() {
this->server->properties()[property::VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_COMMAND_BLOCK].as_or<uint16_t>(150);
}
std::deque<std::shared_ptr<BasicChannel>> ConnectedClient::subscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& targets, bool lock_channel, bool enforce) {
deque<std::shared_ptr<BasicChannel>> subscribed_channels;
void ConnectedClient::subscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& targets, bool lock_channel, bool enforce) {
std::deque<std::shared_ptr<BasicChannel>> subscribed_channels;
auto ref_server = this->server;
if(!ref_server)
return {};
if(!ref_server) {
return;
}
auto general_granted = enforce || permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_ignore_subscribe_power, 0));
{
shared_lock server_channel_lock(ref_server->channel_tree_lock, defer_lock);
unique_lock client_channel_lock(this->channel_lock, defer_lock);
std::shared_lock server_channel_lock{ref_server->channel_tree_mutex, defer_lock};
std::unique_lock client_channel_lock{this->channel_tree_mutex, defer_lock};
if(lock_channel) {
server_channel_lock.lock();
client_channel_lock.lock();
}
auto cache = make_shared<CalculateCache>();
for (const auto& channel : targets) {
auto local_channel = this->channels->find_channel(channel);
if(!local_channel) continue; //Not visible
if(local_channel->subscribed) continue; //Already subscribed
for (const auto& targetChannel : targets) {
auto local_channel = this->channel_tree->find_channel(targetChannel);
if(!local_channel) {
/* The target channel isn't visible. */
continue;
}
if(!general_granted && channel != this->currentChannel) {
auto granted_permission = this->calculate_permission(permission::i_channel_subscribe_power, channel->channelId());
if(local_channel->subscribed) {
/* We've already subscribed to that channel. */
continue;
}
if(!channel->permission_granted(permission::i_channel_needed_subscribe_power, granted_permission, false)) {
auto ignore_power = this->calculate_permission(permission::b_channel_ignore_subscribe_power, channel->channelId());
if(!ignore_power.has_value || ignore_power.value < 1)
if(!general_granted && targetChannel != this->currentChannel) {
auto required_subscribe_power = targetChannel->permissions()->permission_value_flagged(permission::i_channel_needed_subscribe_power);
required_subscribe_power.clear_flag_on_zero();
ClientPermissionCalculator permissionCalculator{this, targetChannel};
if(!permissionCalculator.permission_granted(permission::i_channel_subscribe_power, required_subscribe_power)) {
if(!permissionCalculator.permission_granted(permission::b_channel_ignore_subscribe_power, 1)) {
/* The target client hasn't permissions to view the channel nor ignore the subscribe power */
continue;
}
}
}
local_channel->subscribed = true;
subscribed_channels.push_back(channel);
subscribed_channels.push_back(targetChannel);
}
deque<shared_ptr<ConnectedClient>> visible_clients;
std::deque<shared_ptr<ConnectedClient>> visible_clients{};
for(const auto& target_channel : subscribed_channels) {
/* ref_server->getClientsByChannel only acquires channel client lock */
for(const auto& client : ref_server->getClientsByChannel(target_channel)) {
visible_clients.push_back(client);
}
/* getClientsByChannel() does not acquire the server channel tree mutex */
auto channel_clients = ref_server->getClientsByChannel(target_channel);
visible_clients.insert(visible_clients.end(), channel_clients.begin(), channel_clients.end());
}
this->notifyClientEnterView(visible_clients, ViewReasonSystem);
if(!visible_clients.empty()) {
this->notifyClientEnterView(visible_clients, ViewReasonSystem);
}
if (!subscribed_channels.empty())
if (!subscribed_channels.empty()) {
this->notifyChannelSubscribed(subscribed_channels);
}
}
return subscribed_channels;
}
std::deque<std::shared_ptr<BasicChannel>> ConnectedClient::unsubscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& targets, bool lock_channel) {
void ConnectedClient::unsubscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& targets, bool lock_channel) {
auto ref_server = this->server;
if(!ref_server)
return {};
deque<std::shared_ptr<BasicChannel> > unsubscribed_channels;
if(!ref_server) {
return;
}
std::deque<std::shared_ptr<BasicChannel> > unsubscribed_channels;
{
shared_lock server_channel_lock(ref_server->channel_tree_lock, defer_lock);
unique_lock client_channel_lock(this->channel_lock, defer_lock);
std::shared_lock server_channel_lock{ref_server->channel_tree_mutex, defer_lock};
std::unique_lock client_channel_lock{this->channel_tree_mutex, defer_lock};
if(lock_channel) {
server_channel_lock.lock();
client_channel_lock.lock();
}
for (const auto& channel : targets) {
if(this->currentChannel == channel) continue;
if(this->currentChannel == channel) {
/* Do not unsubscribe from our own channel. */
continue;
}
auto chan = this->channels->find_channel(channel);
if(!chan || !chan->subscribed) continue;
chan->subscribed = false;
auto local_channel = this->channel_tree->find_channel(channel);
if(!local_channel || !local_channel->subscribed) {
continue;
}
/* ref_server->getClientsByChannel only acquires channel client lock */
local_channel->subscribed = false;
/* getClientsByChannel() does not acquire the server channel tree mutex */
auto clients = this->server->getClientsByChannel(channel);
this->visibleClients.erase(std::remove_if(this->visibleClients.begin(), this->visibleClients.end(), [&, clients](const weak_ptr<ConnectedClient>& weak) {
auto c = weak.lock();
if(!c) {
logError(this->getServerId(), "{} Got \"dead\" client in visible client list! This can cause a remote client disconnect within the future!", CLIENT_STR_LOG_PREFIX);
this->visibleClients.erase(std::remove_if(this->visibleClients.begin(), this->visibleClients.end(), [&, clients](const std::weak_ptr<ConnectedClient>& weak) {
auto visible_client = weak.lock();
if(!visible_client) {
return true;
}
return std::find(clients.begin(), clients.end(), c) != clients.end();
return std::find(clients.begin(), clients.end(), visible_client) != clients.end();
}), this->visibleClients.end());
unsubscribed_channels.push_back(channel);
}
if (!unsubscribed_channels.empty())
if (!unsubscribed_channels.empty()) {
this->notifyChannelUnsubscribed(unsubscribed_channels);
}
}
return unsubscribed_channels;
}
bool ConnectedClient::isClientVisible(const std::shared_ptr<ts::server::ConnectedClient>& client, bool lock) {
auto client_list = this->getVisibleClients(lock);
for(const auto& entry : client_list)
if(entry.lock() == client)
std::shared_lock tree_lock(this->channel_tree_mutex, std::defer_lock);
if(lock) {
tree_lock.lock();
}
for(const auto& entry : this->visibleClients) {
if(entry.lock() == client) {
return true;
}
}
return false;
}
@ -714,18 +734,18 @@ inline void send_channels(ConnectedClient* client, ChannelIT begin, const Channe
}
void ConnectedClient::sendChannelList(bool lock_channel_tree) {
shared_lock server_channel_lock(this->server->channel_tree_lock, defer_lock);
unique_lock client_channel_lock(this->channel_lock, defer_lock);
shared_lock server_channel_lock(this->server->channel_tree_mutex, defer_lock);
unique_lock client_channel_lock(this->channel_tree_mutex, defer_lock);
if(lock_channel_tree) {
server_channel_lock.lock();
client_channel_lock.lock();
}
auto channels = this->channels->insert_channels(this->server->channelTree->tree_head(), true, false);
auto channels = this->channel_tree->insert_channels(this->server->channelTree->tree_head(), true, false);
if(this->currentChannel) {
bool send_success;
for(const auto& channel : this->channels->show_channel(this->server->channelTree->find_linked_entry(this->currentChannel->channelId()), send_success))
for(const auto& channel : this->channel_tree->show_channel(this->server->channelTree->find_linked_entry(this->currentChannel->channelId()), send_success))
channels.push_back(channel);
if(!send_success)
logCritical(this->getServerId(), "ConnectedClient::sendChannelList => failed to insert default channel!");
@ -768,23 +788,6 @@ void ConnectedClient::sendChannelList(bool lock_channel_tree) {
this->sendCommand(Command("channellistfinished"));
}
void ConnectedClient::sendChannelDescription(const std::shared_ptr<BasicChannel>& channel, bool lock) {
shared_lock tree_lock(this->channel_lock, defer_lock);
if(lock)
tree_lock.lock();
if(!this->channels->channel_visible(channel)) return;
auto limit = this->getType() == CLIENT_TEAMSPEAK ? 8192 : 131130;
auto description = channel->properties()[property::CHANNEL_DESCRIPTION].value();
Command cmd("notifychanneledited");
cmd["cid"] = channel->channelId();
cmd["reasonid"] = 9;
cmd["channel_description"] = description.size() > limit ? description.substr(0, limit) : description;
this->sendCommand(cmd, true);
}
void ConnectedClient::tick_server(const std::chrono::system_clock::time_point &time) {
ALARM_TIMER(A1, "ConnectedClient::tick", milliseconds(2));
if(this->state == ConnectionState::CONNECTED) {
@ -1067,7 +1070,7 @@ void ConnectedClient::update_displayed_client_groups(bool& server_groups_changed
server_group_assignments = "0";
}
std::unique_lock view_lock{this->channel_lock};
std::unique_lock view_lock{this->channel_tree_mutex};
this->cached_server_groups = server_groups;
}
@ -1134,7 +1137,7 @@ do { \
permission::PermissionType ConnectedClient::calculate_and_get_join_state(const std::shared_ptr<BasicChannel>& channel) {
std::shared_ptr<ViewEntry> ventry;
{
shared_lock view_lock(this->channel_lock);
shared_lock view_lock(this->channel_tree_mutex);
ventry = this->channel_view()->find_channel(channel);
if(!ventry) {
return permission::i_channel_view_power;

View File

@ -114,19 +114,18 @@ namespace ts {
inline std::shared_ptr<BasicChannel> getChannel(){ return this->currentChannel; }
inline ChannelId getChannelId(){ auto channel = this->currentChannel; return channel ? channel->channelId() : 0; }
//bool channelSubscribed(const std::shared_ptr<BasicChannel>&);
/* if lock_channel == false then channel_lock must be write locked! */
std::deque<std::shared_ptr<BasicChannel>> subscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& target, bool lock_channel, bool /* enforce */);
/* if lock_channel == false then channel_lock must be write locked! */
std::deque<std::shared_ptr<BasicChannel>> unsubscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& target, bool lock_channel);
/* If called without locking the client channel tree **must** be write locked */
void subscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& target, bool /* lock server and client channel tree */, bool /* enforce */);
/* If called without locking the client channel tree **must** be write locked */
void unsubscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& target, bool /* lock server and client channel tree */);
bool isClientVisible(const std::shared_ptr<ConnectedClient>&, bool /* lock channel lock */);
inline std::deque<std::weak_ptr<ConnectedClient>> getVisibleClients(bool lock_channel) {
std::shared_lock lock(this->channel_lock, std::defer_lock);
std::shared_lock lock(this->channel_tree_mutex, std::defer_lock);
if(lock_channel) {
lock.lock();
}
assert(mutex_shared_locked(this->channel_lock));
assert(mutex_shared_locked(this->channel_tree_mutex));
return this->visibleClients;
}
@ -305,12 +304,12 @@ namespace ts {
return this->connectionStatistics;
}
inline std::shared_ptr<ClientChannelView> channel_view() { return this->channels; }
inline std::shared_ptr<ClientChannelView> channel_view() { return this->channel_tree; }
[[nodiscard]] inline std::shared_ptr<ConnectedClient> ref() { return this->_this.lock(); }
[[nodiscard]] inline std::weak_ptr<ConnectedClient> weak_ref() { return this->_this; }
std::shared_mutex& get_channel_lock() { return this->channel_lock; }
std::shared_mutex& get_channel_lock() { return this->channel_tree_mutex; }
/* Attention: Ensure that channel_lock has been locked */
[[nodiscard]] inline std::vector<GroupId>& current_server_groups() { return this->cached_server_groups; }
@ -414,8 +413,8 @@ namespace ts {
bool block_flood = true;
FloodPoints floodPoints = 0;
std::shared_ptr<ClientChannelView> channels;
std::shared_mutex channel_lock;
std::shared_ptr<ClientChannelView> channel_tree{};
std::shared_mutex channel_tree_mutex{};
/* The permission overview which the client itself has (for basic client actions ) */
std::mutex client_needed_permissions_lock;
@ -690,7 +689,6 @@ namespace ts {
void sendChannelList(bool lock_channel_tree);
void sendServerInit();
void sendTSPermEditorWarning();
void sendChannelDescription(const std::shared_ptr<BasicChannel>&, bool lock_tree);
bool handleTextMessage(ChatMessageMode, std::string, const std::shared_ptr<ConnectedClient>& /* sender target */);

View File

@ -234,7 +234,7 @@ bool ConnectedClient::notifyServerGroupClientAdd(
/* Deny any client moves 'till we've send the notify */
std::shared_lock<std::shared_mutex> channel_tree_lock{};
if(this->server) {
channel_tree_lock = std::shared_lock{this->server->channel_tree_lock};
channel_tree_lock = std::shared_lock{this->server->channel_tree_mutex};
}
if(!this->isClientVisible(target_client, true)) {
@ -264,7 +264,7 @@ bool ConnectedClient::notifyServerGroupClientRemove(
/* Deny any client moves 'till we've send the notify */
std::shared_lock<std::shared_mutex> channel_tree_lock{};
if(this->server) {
channel_tree_lock = std::shared_lock{this->server->channel_tree_lock};
channel_tree_lock = std::shared_lock{this->server->channel_tree_mutex};
}
if(!this->isClientVisible(target_client, true)) {
@ -294,7 +294,7 @@ bool ConnectedClient::notifyClientChannelGroupChanged(std::optional<ts::command_
/* Deny any client moves 'till we've send the notify */
std::shared_lock<std::shared_mutex> channel_tree_lock{};
if(this->server) {
channel_tree_lock = std::shared_lock{this->server->channel_tree_lock};
channel_tree_lock = std::shared_lock{this->server->channel_tree_mutex};
}
/* No need to check if the channel is visible since if this is the case the client would not be visible as well. */
@ -442,8 +442,8 @@ bool ConnectedClient::notifyClientMoved(const shared_ptr<ConnectedClient> &clien
assert(client->getClientId() > 0);
assert(client->currentChannel);
assert(target_channel);
sassert(mutex_shared_locked(this->channel_lock));
sassert(mutex_shared_locked(client->channel_lock));
sassert(mutex_shared_locked(this->channel_tree_mutex));
sassert(mutex_shared_locked(client->channel_tree_mutex));
assert(this->isClientVisible(client, false) || &*client == this);
Command mv("notifyclientmoved");
@ -462,12 +462,12 @@ bool ConnectedClient::notifyClientMoved(const shared_ptr<ConnectedClient> &clien
}
bool ConnectedClient::notifyClientUpdated(const std::shared_ptr<ConnectedClient> &client, const deque<const property::PropertyDescription*> &props, bool lock) {
std::shared_lock channel_lock(this->channel_lock, defer_lock);
std::shared_lock channel_lock(this->channel_tree_mutex, defer_lock);
if(lock) {
channel_lock.lock();
}
sassert(mutex_shared_locked(this->channel_lock));
sassert(mutex_shared_locked(this->channel_tree_mutex));
if(!this->isClientVisible(client, false) && client != this)
return false;
@ -515,7 +515,7 @@ bool ConnectedClient::notifyClientChatClosed(const shared_ptr<ConnectedClient> &
}
bool ConnectedClient::notifyChannelMoved(const std::shared_ptr<BasicChannel> &channel, ChannelId order, const std::shared_ptr<ConnectedClient> &invoker) {
if(!channel || !this->channels->channel_visible(channel)) return false;
if(!channel || !this->channel_tree->channel_visible(channel)) return false;
Command notify("notifychannelmoved");
INVOKER(notify, invoker);
@ -546,13 +546,13 @@ bool ConnectedClient::notifyChannelHide(const std::deque<ChannelId> &channel_ids
if(channel_ids.empty()) return true;
if(this->getType() == ClientType::CLIENT_TEAMSPEAK) { //Voice hasnt that event
shared_lock server_channel_lock(this->server->channel_tree_lock, defer_lock);
unique_lock client_channel_lock(this->channel_lock, defer_lock);
shared_lock server_channel_lock(this->server->channel_tree_mutex, defer_lock);
unique_lock client_channel_lock(this->channel_tree_mutex, defer_lock);
if(lock_channel_tree) {
server_channel_lock.lock();
client_channel_lock.lock();
} else {
assert(mutex_locked(this->channel_lock));
assert(mutex_locked(this->channel_tree_mutex));
}
deque<shared_ptr<ConnectedClient>> clients_to_remove;
@ -611,7 +611,7 @@ bool ConnectedClient::notifyChannelShow(const std::shared_ptr<ts::BasicChannel>
}
bool ConnectedClient::notifyChannelDescriptionChanged(std::shared_ptr<BasicChannel> channel) {
if(!this->channels->channel_visible(channel)) return false;
if(!this->channel_tree->channel_visible(channel)) return false;
Command notifyDesChanges("notifychanneldescriptionchanged");
notifyDesChanges["cid"] = channel->channelId();
this->sendCommand(notifyDesChanges);
@ -619,7 +619,7 @@ bool ConnectedClient::notifyChannelDescriptionChanged(std::shared_ptr<BasicChann
}
bool ConnectedClient::notifyChannelPasswordChanged(std::shared_ptr<BasicChannel> channel) {
if(!this->channels->channel_visible(channel)) return false;
if(!this->channel_tree->channel_visible(channel)) return false;
Command notifyDesChanges("notifychannelpasswordchanged");
notifyDesChanges["cid"] = channel->channelId();
this->sendCommand(notifyDesChanges);
@ -630,7 +630,7 @@ bool ConnectedClient::notifyClientEnterView(const std::shared_ptr<ConnectedClien
sassert(client && client->getClientId() > 0);
sassert(to);
sassert(!lock_channel_tree); /* we don't support locking */
sassert(mutex_locked(this->channel_lock));
sassert(mutex_locked(this->channel_tree_mutex));
sassert(!this->isClientVisible(client, false) || &*client == this);
switch (reasonId) {
@ -676,9 +676,11 @@ bool ConnectedClient::notifyClientEnterView(const std::shared_ptr<ConnectedClien
}
bool ConnectedClient::notifyClientEnterView(const std::deque<std::shared_ptr<ConnectedClient>> &clients, const ts::ViewReasonSystemT &_vrs) {
if(clients.empty())
if(clients.empty()) {
return true;
assert(mutex_locked(this->channel_lock));
}
assert(mutex_locked(this->channel_tree_mutex));
Command cmd("notifycliententerview");
@ -691,8 +693,9 @@ bool ConnectedClient::notifyClientEnterView(const std::deque<std::shared_ptr<Con
while(it != clients.end()) {
auto client = *(it++);
if(this->isClientVisible(client, false))
if(this->isClientVisible(client, false)) {
continue;
}
auto channel = client->getChannel();
sassert(!channel || channel->channelId() != 0);
@ -731,7 +734,7 @@ bool ConnectedClient::notifyChannelEdited(
const std::vector<property::ChannelProperties> &properties,
const std::shared_ptr<ConnectedClient> &invoker,
bool) {
auto v_channel = this->channels->find_channel(channel->channelId());
auto v_channel = this->channel_tree->find_channel(channel->channelId());
if(!v_channel) return false; //Not visible? Important do not remove!
bool send_description_change{false};

View File

@ -43,7 +43,7 @@ bool SpeakingClient::shouldReceiveVoice(const std::shared_ptr<ConnectedClient> &
if(this->properties()[property::CLIENT_OUTPUT_MUTED].as_or<bool>(false)) return false;
{
shared_lock client_lock(this->channel_lock);
shared_lock client_lock(this->channel_tree_mutex);
for(const auto& entry : this->mutedClients)
if(entry.lock() == sender)
return false;
@ -55,7 +55,7 @@ bool SpeakingClient::shouldReceiveVoiceWhisper(const std::shared_ptr<ConnectedCl
if(!this->shouldReceiveVoice(sender))
return false;
return permission::v2::permission_granted(this->cpmerission_needed_whisper_power, sender->cpmerission_whisper_power, false);
return permission::v2::permission_granted(this->cpmerission_needed_whisper_power, sender->cpmerission_whisper_power);
}
bool SpeakingClient::should_handle_voice_packet(size_t) {
@ -396,16 +396,14 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) {
}
/* must be triggered while helding an execute lock */
//Note: Client permissions are may not really
void SpeakingClient::processJoin() {
TIMING_START(timings);
auto ref_server = this->server;
assert(ref_server);
this->resetIdleTime();
/* don't process any commands */
std::lock_guard command_lock_{this->command_lock};
auto ref_server = this->server;
assert(ref_server);
if(this->state != ConnectionState::INIT_HIGH) {
logError(this->getServerId(), "{} Invalid processJoin() connection state!", CLIENT_STR_LOG_PREFIX);
@ -507,10 +505,10 @@ void SpeakingClient::processJoin() {
this->properties()[property::CLIENT_CHANNEL_GROUP_ID] = "0";
this->properties()[property::CLIENT_TALK_POWER] = "0";
unique_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock server_channel_lock(this->server->channel_tree_mutex);
this->server->client_move(this->ref(), channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_lock);
if(this->getType() != ClientType::CLIENT_TEAMSPEAK) {
std::lock_guard own_channel_lock{this->channel_lock};
std::lock_guard own_channel_lock{this->channel_tree_mutex};
this->subscribeChannel({this->currentChannel}, false, true); /* su "improve" the TS3 clients join speed we send the channel clients a bit later, when the TS3 client gets his own client variables */
}
}
@ -571,7 +569,7 @@ void SpeakingClient::processLeave() {
if(server){
logMessage(this->getServerId(), "Voice client {}/{} ({}) from {} left.", this->getClientDatabaseId(), this->getUid(), this->getDisplayName(), this->getLoggingPeerIp() + ":" + to_string(this->getPeerPort()));
{
unique_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock server_channel_lock(this->server->channel_tree_mutex);
server->unregisterClient(ownLock, "disconnected", server_channel_lock); /* already moves client to void if needed */
}
server->music_manager_->cleanup_client_bots(this->getClientDatabaseId());
@ -822,7 +820,7 @@ command_result SpeakingClient::handleCommandBroadcastVideo(Command &command) {
switch(type) {
case rtc::VideoBroadcastType::Screen:
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_screen, this->getChannelId()), false)) {
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_screen, this->getChannelId()))) {
return ts::command_result{permission::b_video_screen};
}
@ -830,7 +828,7 @@ command_result SpeakingClient::handleCommandBroadcastVideo(Command &command) {
case rtc::VideoBroadcastType::Camera:
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_camera, this->getChannelId()), false)) {
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_camera, this->getChannelId()))) {
return ts::command_result{permission::b_video_camera};
}
@ -934,7 +932,7 @@ command_result SpeakingClient::handleCommandBroadcastVideoJoin(Command &cmd) {
auto permission_max_streams = this->calculate_permission(permission::i_video_max_streams, this->getChannelId());
if(permission_max_streams.has_value) {
if(!permission::v2::permission_granted(camera_streams + screen_streams, permission_max_streams, false)) {
if(!permission::v2::permission_granted(camera_streams + screen_streams, permission_max_streams)) {
return ts::command_result{permission::i_video_max_streams};
}
}
@ -943,7 +941,7 @@ command_result SpeakingClient::handleCommandBroadcastVideoJoin(Command &cmd) {
case rtc::VideoBroadcastType::Camera: {
const auto permission_max_camera_streams = this->calculate_permission(permission::i_video_max_camera_streams, this->getChannelId());
if(permission_max_camera_streams.has_value) {
if(!permission::v2::permission_granted(camera_streams, permission_max_camera_streams, false)) {
if(!permission::v2::permission_granted(camera_streams, permission_max_camera_streams)) {
return ts::command_result{permission::i_video_max_camera_streams};
}
}
@ -953,7 +951,7 @@ command_result SpeakingClient::handleCommandBroadcastVideoJoin(Command &cmd) {
case rtc::VideoBroadcastType::Screen: {
const auto permission_max_screen_streams = this->calculate_permission(permission::i_video_max_camera_streams, this->getChannelId());
if(permission_max_screen_streams.has_value) {
if(!permission::v2::permission_granted(screen_streams, permission_max_screen_streams, false)) {
if(!permission::v2::permission_granted(screen_streams, permission_max_screen_streams)) {
return ts::command_result{permission::i_video_max_screen_streams};
}
}

View File

@ -1,7 +1,7 @@
#include <memory>
#include "../../InstanceHandler.h"
#include "../../build.h"
#include "../../PermissionCalculator.h"
#include "../../manager/ActionLogger.h"
#include "../../manager/ConversationManager.h"
#include "../../manager/PermissionNameMapper.h"
@ -19,37 +19,53 @@
#include <cstdint>
#include "./bulk_parsers.h"
#include "helpers.h"
#include <Properties.h>
#include <bbcode/bbcodes.h>
#include <log/LogUtils.h>
#include <misc/base64.h>
#include <misc/digest.h>
#include <misc/sassert.h>
using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
/*
TODO: Log missing permissions?
{findError("parameter_invalid"), "could not resolve permission " + (cmd[index].has("permid") ? cmd[index]["permid"].as<string>() : cmd[index]["permsid"].as<string>())};
*/
command_result ConnectedClient::handleCommandChannelGetDescription(Command &cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(0);
RESOLVE_CHANNEL_R(cmd["cid"], true);
auto channel = dynamic_pointer_cast<BasicChannel>(l_channel->entry);
assert(channel);
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_ignore_description_view_power, channel->channelId()))) {
auto view_power = this->calculate_permission(permission::i_channel_description_view_power, channel->channelId());
if (!channel->permission_granted(permission::i_channel_needed_description_view_power, view_power, false))
return command_result{permission::i_channel_description_view_power};
std::shared_lock channel_lock{this->channel_tree_mutex};
if(!this->channel_tree->channel_visible(channel)) {
return ts::command_result{error::channel_invalid_id};
}
this->sendChannelDescription(channel, true);
ClientPermissionCalculator permission_calculator{this, channel};
if(!permission_calculator.permission_granted(permission::b_channel_ignore_description_view_power, 1)) {
auto required_view_power = channel->permissions()->permission_value_flagged(permission::i_channel_needed_description_view_power);
required_view_power.clear_flag_on_zero();
if(!permission_calculator.permission_granted(permission::i_channel_description_view_power, required_view_power)) {
return command_result{permission::i_channel_description_view_power};
}
}
auto channel_description = channel->properties()[property::CHANNEL_DESCRIPTION].value();
auto channel_description_limit = this->getType() == CLIENT_TEAMSPEAK ? 8192 : 131130;
if(channel_description.length() > channel_description_limit) {
channel_description = channel_description.substr(0, channel_description_limit - 3);
channel_description.append("...");
}
ts::command_builder notify{this->notify_response_command("notifychanneledited")};
notify.put_unchecked(0, "cid", channel->channelId());
notify.put_unchecked(0, "reasonid", "9");
notify.put_unchecked(0, "channel_description", channel_description);
this->sendCommand(notify);
return command_result{error::ok};
}
@ -57,31 +73,46 @@ command_result ConnectedClient::handleCommandChannelSubscribe(Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
bool flood_points = false;
deque<shared_ptr<BasicChannel>> channels;
bool flood_points{false};
std::deque<std::shared_ptr<BasicChannel>> target_channels{};
//target_channels.reserve(cmd.bulkCount());
ts::command_result_bulk result{};
result.emplace_result_n(cmd.bulkCount(), error::ok);
{
shared_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock client_channel_lock(this->channel_lock);
std::shared_lock server_channel_lock{this->server->channel_tree_mutex};
std::lock_guard client_channel_lock{this->channel_tree_mutex};
for (int index = 0; index < cmd.bulkCount(); index++) {
auto local_channel = this->channel_view()->find_channel(cmd[index]["cid"].as<ChannelId>());
if (!local_channel)
return command_result{error::channel_invalid_id, "Cant resolve channel"};
for (int index{0}; index < cmd.bulkCount(); index++) {
auto target_channel_id = cmd[index]["cid"].as<ChannelId>();
auto local_channel = this->channel_view()->find_channel(target_channel_id);
if (!local_channel) {
result.set_result(index, ts::command_result{error::channel_invalid_id});
continue;
}
auto channel = this->server->channelTree->findChannel(cmd[index]["cid"].as<ChannelId>());
if (!channel)
return command_result{error::channel_invalid_id, "Cant resolve channel"};
auto channel = this->server->channelTree->findChannel(target_channel_id);
if (!channel) {
result.set_result(index, ts::command_result{error::channel_invalid_id});
continue;
}
channels.push_back(channel);
if (!flood_points && system_clock::now() - local_channel->view_timestamp > seconds(5)) {
target_channels.push_back(channel);
if (!flood_points && std::chrono::system_clock::now() - local_channel->view_timestamp > seconds(5)) {
flood_points = true;
CMD_CHK_AND_INC_FLOOD_POINTS(15);
this->increaseFloodPoints(15);
if(this->shouldFloodBlock()) {
result.set_result(index, ts::command_result{error::ban_flooding});
continue;
}
}
}
if (!channels.empty())
this->subscribeChannel(channels, false, false);
if (!target_channels.empty()) {
this->subscribeChannel(target_channels, false, false);
}
}
return command_result{error::ok};
@ -92,8 +123,8 @@ command_result ConnectedClient::handleCommandChannelSubscribeAll(Command &cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(20);
{
shared_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock client_channel_lock(this->channel_lock);
std::shared_lock server_channel_lock{this->server->channel_tree_mutex};
std::lock_guard client_channel_lock{this->channel_tree_mutex};
this->subscribeChannel(this->server->channelTree->channels(), false, false);
this->subscribeToAll = true;
}
@ -104,20 +135,28 @@ command_result ConnectedClient::handleCommandChannelUnsubscribe(Command &cmd) {
CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
{
shared_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock client_channel_lock(this->channel_lock);
ts::command_result_bulk result{};
result.emplace_result_n(cmd.bulkCount(), error::ok);
deque<shared_ptr<BasicChannel>> channels;
{
std::shared_lock server_channel_lock{this->server->channel_tree_mutex};
std::lock_guard client_channel_lock{this->channel_tree_mutex};
std::deque<shared_ptr<BasicChannel>> channels{};
for (int index = 0; index < cmd.bulkCount(); index++) {
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel) continue;
if (!channel) {
result.set_result(index, ts::command_result{error::channel_invalid_id});
continue;
}
channels.push_front(channel);
}
this->unsubscribeChannel(channels, false);
}
return command_result{error::ok};
return command_result{std::move(result)};
}
command_result ConnectedClient::handleCommandChannelUnsubscribeAll(Command &cmd) {
@ -125,11 +164,12 @@ command_result ConnectedClient::handleCommandChannelUnsubscribeAll(Command &cmd)
CMD_CHK_AND_INC_FLOOD_POINTS(25);
{
shared_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock client_channel_lock(this->channel_lock);
std::shared_lock server_channel_lock{this->server->channel_tree_mutex};
std::lock_guard client_channel_lock{this->channel_tree_mutex};
this->unsubscribeChannel(this->server->channelTree->channels(), false);
this->subscribeToAll = false;
}
return command_result{error::ok};
}
@ -257,7 +297,7 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
CMD_CHK_PARM_COUNT(1);
auto target_tree = this->server ? this->server->channelTree : &*serverInstance->getChannelTree();
std::shared_lock channel_tree_read_lock{this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock()};
std::shared_lock channel_tree_read_lock{this->server ? this->server->channel_tree_mutex : serverInstance->getChannelTreeLock()};
ChannelId parent_channel_id = cmd[0].has("cpid") ? cmd["cpid"].as<ChannelId>() : 0;
#define test_permission(required, permission_type) \
@ -610,7 +650,7 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
if (created_channel->channelType() == ChannelType::temporary && (this->getType() == ClientType::CLIENT_TEAMSPEAK || this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEASPEAK)) {
channel_tree_read_lock.unlock();
std::unique_lock channel_tree_write_lock{this->server->channel_tree_lock};
std::unique_lock channel_tree_write_lock{this->server->channel_tree_mutex};
this->server->client_move(
this->ref(),
created_channel,
@ -990,8 +1030,8 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
}
}
auto channel_tree = server ? server->getChannelTree() : &*serverInstance->getChannelTree();
std::unique_lock channel_tree_lock{server ? server->channel_tree_lock : serverInstance->getChannelTreeLock()};
auto target_channel_tree = server ? server->getChannelTree() : &*serverInstance->getChannelTree();
std::unique_lock channel_tree_lock{server ? server->channel_tree_mutex : serverInstance->getChannelTreeLock()};
struct TemporaryCreatedChannel {
ServerChannelTree* channel_tree;
@ -1002,7 +1042,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
channel_tree->deleteChannelRoot(this->channel);
}
} temporary_created_channel{channel_tree, nullptr};
} temporary_created_channel{target_channel_tree, nullptr};
std::shared_ptr<TreeView::LinkedTreeEntry> linked_channel;
std::shared_ptr<ServerChannel> channel;
@ -1019,31 +1059,31 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
{
std::shared_ptr<BasicChannel> parent_channel{};
if(parent_id > 0) {
parent_channel = channel_tree->findChannel(parent_id);
parent_channel = target_channel_tree->findChannel(parent_id);
if(!parent_channel) {
return command_result{error::channel_invalid_id};
}
}
if(channel_tree->findChannel(channel_name, parent_channel)) {
if(target_channel_tree->findChannel(channel_name, parent_channel)) {
return ts::command_result{error::channel_name_inuse};
}
}
channel = dynamic_pointer_cast<ServerChannel>(channel_tree->createChannel(parent_id, order_id, channel_name));
channel = dynamic_pointer_cast<ServerChannel>(target_channel_tree->createChannel(parent_id, order_id, channel_name));
if(!channel) {
return command_result{error::vs_critical, "channel create failed"};
}
temporary_created_channel.channel = channel;
linked_channel = channel_tree->findLinkedChannel(channel->channelId());
linked_channel = target_channel_tree->findLinkedChannel(channel->channelId());
if(!linked_channel) {
return command_result{error::vs_critical, "missing linked channel"};
}
channel_id = channel->channelId();
} else {
linked_channel = channel_tree->findLinkedChannel(channel_id);
linked_channel = target_channel_tree->findLinkedChannel(channel_id);
channel = dynamic_pointer_cast<ServerChannel>(linked_channel->entry);
}
@ -1173,7 +1213,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
if(updating_name) {
auto new_name = changed_values[property::CHANNEL_NAME];
if(channel_tree->findChannel(new_name, channel->parent())) {
if(target_channel_tree->findChannel(new_name, channel->parent())) {
return ts::command_result{error::channel_name_inuse};
}
}
@ -1375,12 +1415,12 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
ChannelId previous_channel_id{0};
if(updating_sort_order) {
previous_channel_id = converter<ChannelId>::from_string_view(changed_values[property::CHANNEL_ORDER]);
auto previous_channel = channel_tree->findChannel(previous_channel_id);
auto previous_channel = target_channel_tree->findChannel(previous_channel_id);
if(!previous_channel && previous_channel_id != 0) {
return command_result{error::channel_invalid_id};
}
if(!channel_tree->move_channel(channel, channel->parent(), previous_channel)) {
if(!target_channel_tree->move_channel(channel, channel->parent(), previous_channel)) {
return ts::command_result{error::vs_critical, "failed to move channel"};
}
}
@ -1395,7 +1435,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
auto current_channel = children_left.front();
children_left.pop_front();
for (const auto &child : channel_tree->channels(current_channel, 1)) {
for (const auto &child : target_channel_tree->channels(current_channel, 1)) {
if (child == current_channel) {
continue;
}
@ -1415,7 +1455,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
std::shared_ptr<BasicChannel> old_default_channel{};
if(updating_default) {
old_default_channel = channel_tree->getDefaultChannel();
old_default_channel = target_channel_tree->getDefaultChannel();
if(old_default_channel) {
old_default_channel->properties()[property::CHANNEL_FLAG_DEFAULT] = false;
}
@ -1472,8 +1512,8 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
if(updating_sort_order) {
auto parent = channel->parent();
linked_parent_channel = parent ? channel_tree->findLinkedChannel(parent->channelId()) : nullptr;
linked_previous_channel = channel_tree->findLinkedChannel(channel->previousChannelId());
linked_parent_channel = parent ? target_channel_tree->findLinkedChannel(parent->channelId()) : nullptr;
linked_previous_channel = target_channel_tree->findLinkedChannel(channel->previousChannelId());
assert(!parent || linked_parent_channel);
assert(linked_previous_channel || channel->previousChannelId() == 0);
@ -1505,7 +1545,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
continue;
}
std::unique_lock client_tree_lock{client->channel_lock};
std::unique_lock client_tree_lock{client->channel_tree_mutex};
for(const auto& child_channel : child_channel_type_updates) {
client->notifyChannelEdited(child_channel, child_channel_type_property_updates, self_ref, false);
}
@ -1681,11 +1721,12 @@ command_result ConnectedClient::handleCommandChannelMove(Command &cmd) {
if (this->server) {
auto self_rev = this->ref();
this->server->forEachClient([&](const shared_ptr<ConnectedClient> &client) {
unique_lock channel_lock(client->channel_lock);
for (const auto &type_update : channel_type_updates)
unique_lock channel_lock(client->channel_tree_mutex);
for (const auto &type_update : channel_type_updates) {
client->notifyChannelEdited(type_update, {property::CHANNEL_FLAG_PERMANENT, property::CHANNEL_FLAG_SEMI_PERMANENT}, self_rev, false);
}
auto actions = client->channels->change_order(l_channel, l_parent, l_order);
auto actions = client->channel_tree->change_order(l_channel, l_parent, l_order);
std::deque<ChannelId> deletions;
for (const auto &action : actions) {
switch (action.first) {
@ -1705,8 +1746,10 @@ command_result ConnectedClient::handleCommandChannelMove(Command &cmd) {
break;
}
}
if (!deletions.empty())
if (!deletions.empty()) {
client->notifyChannelHide(deletions, false);
}
});
}
@ -2002,12 +2045,12 @@ command_result ConnectedClient::handleCommandChannelClientDelPerm(Command &cmd)
if (elm->currentChannel == channel) {
elm->task_update_channel_client_properties.enqueue();
} else if (update_view) {
unique_lock client_channel_lock(this->channel_lock);
unique_lock client_channel_lock(this->channel_tree_mutex);
auto elm_channel = elm->currentChannel;
if (elm_channel) {
deque<ChannelId> deleted;
for (const auto &update_entry : elm->channels->update_channel_path(l_channel, this->server->channelTree->findLinkedChannel(elm->currentChannel->channelId()))) {
for (const auto &update_entry : elm->channel_tree->update_channel_path(l_channel, this->server->channelTree->findLinkedChannel(elm->currentChannel->channelId()))) {
if (update_entry.first)
elm->notifyChannelShow(update_entry.second->channel(), update_entry.second->previous_channel);
else
@ -2070,12 +2113,12 @@ command_result ConnectedClient::handleCommandChannelClientAddPerm(Command &cmd)
if (elm->currentChannel == channel) {
elm->task_update_channel_client_properties.enqueue();
} else if (update_view) {
unique_lock client_channel_lock(this->channel_lock);
unique_lock client_channel_lock(this->channel_tree_mutex);
auto elm_channel = elm->currentChannel;
if (elm_channel) {
deque<ChannelId> deleted;
for (const auto &update_entry : elm->channels->update_channel_path(l_channel, this->server->channelTree->findLinkedChannel(elm->currentChannel->channelId()))) {
for (const auto &update_entry : elm->channel_tree->update_channel_path(l_channel, this->server->channelTree->findLinkedChannel(elm->currentChannel->channelId()))) {
if (update_entry.first)
elm->notifyChannelShow(update_entry.second->channel(), update_entry.second->previous_channel);
else

View File

@ -3,7 +3,6 @@
#include <vector>
#include <bitset>
#include <algorithm>
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../voice/VoiceClient.h"
@ -15,6 +14,7 @@
#include "../../manager/ConversationManager.h"
#include "../../manager/PermissionNameMapper.h"
#include "../../manager/ActionLogger.h"
#include "../../PermissionCalculator.h"
#include <cstdint>
#include "helpers.h"
@ -22,7 +22,6 @@
#include <Properties.h>
#include <log/LogUtils.h>
#include <misc/sassert.h>
#include <misc/base64.h>
#include <misc/hex.h>
#include <misc/rnd.h>
@ -39,7 +38,7 @@ command_result ConnectedClient::handleCommandClientGetVariables(Command &cmd) {
CMD_REQ_SERVER;
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
{
shared_lock tree_lock(this->channel_lock);
shared_lock tree_lock(this->channel_tree_mutex);
if (!client || (client.client != this && !this->isClientVisible(client.client, false)))
return command_result{error::client_invalid_id, ""};
@ -131,7 +130,7 @@ command_result ConnectedClient::handleCommandClientGetIds(Command &cmd) {
auto unique_id = cmd[index]["cluid"].as<string>();
for(const auto& entry : client_list) {
if(entry->getUid() == unique_id) {
if(!config::server::show_invisible_clients_as_online && !this->channels->channel_visible(entry->currentChannel, nullptr))
if(!config::server::show_invisible_clients_as_online && !this->channel_tree->channel_visible(entry->currentChannel, nullptr))
continue;
notify[result_index]["name"] = entry->getDisplayName();
@ -160,22 +159,20 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(10);
shared_lock server_channel_r_lock(this->server->channel_tree_lock);
std::unique_lock server_channel_lock{this->server->channel_tree_mutex};
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel) {
auto target_channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!target_channel) {
return command_result{error::channel_invalid_id};
}
auto permission_cache = make_shared<CalculateCache>();
auto& channel_whitelist = this->join_whitelisted_channel;
auto whitelist_entry = std::find_if(channel_whitelist.begin(), channel_whitelist.end(), [&](const auto& entry) { return entry.first == channel->channelId(); });
auto whitelist_entry = std::find_if(channel_whitelist.begin(), channel_whitelist.end(), [&](const auto& entry) { return entry.first == target_channel->channelId(); });
if(whitelist_entry != channel_whitelist.end()) {
debugMessage(this->getServerId(), "{} Allowing client to join channel {} because the token he used earlier explicitly allowed it.", this->getLoggingPrefix(), channel->channelId());
debugMessage(this->getServerId(), "{} Allowing client to join channel {} because the token he used earlier explicitly allowed it.", this->getLoggingPrefix(), target_channel->channelId());
if(whitelist_entry->second != "ignore") {
if (!channel->passwordMatch(cmd["cpw"], true)) {
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, channel->channelId()))) {
if (!target_channel->verify_password(cmd["cpw"].optional_string(), this->getType() != ClientType::CLIENT_QUERY)) {
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, target_channel->channelId()))) {
return command_result{error::channel_invalid_password};
}
}
@ -185,13 +182,13 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
cmd["cpw"] = "";
}
if (!channel->passwordMatch(cmd["cpw"], true)) {
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, channel->channelId()))) {
if (!target_channel->verify_password(cmd["cpw"].optional_string(), this->getType() != ClientType::CLIENT_QUERY)) {
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, target_channel->channelId()))) {
return command_result{error::channel_invalid_password};
}
}
auto permission_error = this->calculate_and_get_join_state(channel);
auto permission_error = this->calculate_and_get_join_state(target_channel);
if(permission_error != permission::unknown) {
return command_result{permission_error};
}
@ -201,7 +198,7 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
command_result_bulk result{};
result.reserve(cmd.bulkCount());
std::vector<ConnectedLockedClient<ConnectedClient>> clients{};
std::vector<ConnectedLockedClient<ConnectedClient>> target_clients{};
for(size_t index{0}; index < cmd.bulkCount(); index++) {
auto target_client_id = cmd[index]["clid"].as<ClientId>();
@ -217,7 +214,7 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
continue;
}
}
if(target_client->getChannel() == channel) {
if(target_client->getChannel() == target_channel) {
result.emplace_result(error::ok);
continue;
}
@ -227,96 +224,90 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
result.emplace_result(permission::i_client_move_power);
continue;
}
if(!permission::v2::permission_granted(target_client->calculate_permission(permission::i_client_needed_move_power, channel->channelId()), this->calculate_permission(permission::i_client_move_power, channel->channelId()))) {
if(!permission::v2::permission_granted(target_client->calculate_permission(permission::i_client_needed_move_power, target_channel->channelId()), this->calculate_permission(permission::i_client_move_power, target_channel->channelId()))) {
result.emplace_result(permission::i_client_move_power);
continue;
}
}
clients.emplace_back(std::move(target_client));
target_clients.emplace_back(std::move(target_client));
result.emplace_result(error::ok);
}
ClientPermissionCalculator own_permission_calculator{this, target_channel};
/* FIXME: Some kind of invite key frags to prevent limit checking! */
if (!channel->properties()[property::CHANNEL_FLAG_MAXCLIENTS_UNLIMITED].as_unchecked<bool>() || !channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED].as_unchecked<bool>()) {
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_maxclients, channel->channelId()))) {
if(!channel->properties()[property::CHANNEL_FLAG_MAXCLIENTS_UNLIMITED].as_unchecked<bool>()) {
auto maxClients = channel->properties()[property::CHANNEL_MAXCLIENTS].as_unchecked<int32_t>();
if (maxClients >= 0 && maxClients < this->server->getClientsByChannel(channel).size() + clients.size()) {
return command_result{error::channel_maxclients_reached};
}
}
if(!channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED].as_unchecked<bool>()) {
shared_ptr<BasicChannel> family_root;
if(channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED].as_unchecked<bool>()) {
family_root = channel;
while(family_root &&
family_root->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED].as_unchecked<bool>()) {
family_root = family_root->parent();
}
}
if(family_root && !family_root->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED]) { //Could not be CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED
auto maxClients = family_root->properties()[property::CHANNEL_MAXFAMILYCLIENTS].as_unchecked<int32_t>();
auto client_count = 0;
for(const auto& entry : this->server->getClientsByChannelRoot(channel, false)) {
if(entry.get() != this) {
client_count++; //Dont count the client itself
}
}
if (maxClients >= 0 && maxClients < client_count + clients.size()) {
return command_result{error::channel_maxfamily_reached};
}
}
}
if (!target_channel->properties()[property::CHANNEL_FLAG_MAXCLIENTS_UNLIMITED].as_or<bool>(true)) {
auto max_clients = target_channel->properties()[property::CHANNEL_MAXCLIENTS].as_or<uint32_t>(0);
auto channel_clients = this->server->getClientsByChannel(target_channel);
if(channel_clients.size() >= max_clients && !own_permission_calculator.permission_granted(permission::b_channel_join_ignore_maxclients, 1)) {
return command_result{error::channel_maxclients_reached};
}
}
server_channel_r_lock.unlock();
unique_lock server_channel_w_lock(this->server->channel_tree_lock);
std::vector<std::shared_ptr<BasicChannel>> channels{};
channels.reserve(clients.size());
if(!target_channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED].as_or<bool>(true)) {
auto base_channel{target_channel};
while(base_channel && base_channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED].as_or<bool>(false)) {
base_channel = base_channel->parent();
}
for(auto& client : clients) {
auto oldChannel = client->getChannel();
if(!oldChannel) {
if(base_channel) {
auto max_clients = target_channel->properties()[property::CHANNEL_MAXFAMILYCLIENTS].as_or<uint32_t>(0);
auto current_client_count = this->server->countChannelRootClients(target_channel, max_clients, false);
if(current_client_count >= max_clients && !own_permission_calculator.permission_granted(permission::b_channel_join_ignore_maxclients, 1)) {
return command_result{error::channel_maxfamily_reached};
}
} else {
/* This is kinda odd, I guess we've moved the channel and haven't cleared the inherited flag */
}
}
std::vector<std::shared_ptr<ServerChannel>> channels{};
channels.reserve(target_clients.size());
for(auto& client : target_clients) {
auto client_old_channel = dynamic_pointer_cast<ServerChannel>(client->getChannel());
if(!client_old_channel) {
continue;
}
this->server->client_move(
client.client,
channel,
target_channel,
client.client == this ? nullptr : this->ref(),
"",
client.client == this ? ViewReasonId::VREASON_USER_ACTION : ViewReasonId::VREASON_MOVED,
true,
server_channel_w_lock
server_channel_lock
);
serverInstance->action_logger()->client_channel_logger.log_client_move(this->getServerId(), this->ref(), client->ref(), channel->channelId(), channel->name(), oldChannel->channelId(), oldChannel->name());
serverInstance->action_logger()->client_channel_logger.log_client_move(this->getServerId(), this->ref(), client->ref(), target_channel->channelId(), target_channel->name(), client_old_channel->channelId(), client_old_channel->name());
if(std::find_if(channels.begin(), channels.end(), [&](const std::shared_ptr<BasicChannel>& channel) { return &*channel == &*oldChannel; }) == channels.end()) {
channels.push_back(oldChannel);
if(std::find_if(channels.begin(), channels.end(), [&](const std::shared_ptr<ServerChannel>& channel) { return &*channel == &*client_old_channel; }) == channels.end()) {
channels.push_back(client_old_channel);
}
}
for(const auto& oldChannel : channels) {
if(!server_channel_w_lock.owns_lock()) {
server_channel_w_lock.lock();
if(!server_channel_lock.owns_lock()) {
server_channel_lock.lock();
}
if(oldChannel->channelType() == ChannelType::temporary &&
oldChannel->properties()[property::CHANNEL_DELETE_DELAY].as_unchecked<int64_t>() == 0) {
if(this->server->getClientsByChannelRoot(oldChannel, false).empty()) {
this->server->delete_channel(dynamic_pointer_cast<ServerChannel>(oldChannel), this->ref(), "temporary auto delete", server_channel_w_lock, true);
}
if(oldChannel->channelType() != ChannelType::temporary) {
continue;
}
if(server_channel_w_lock.owns_lock()) {
server_channel_w_lock.unlock();
if(oldChannel->properties()[property::CHANNEL_DELETE_DELAY].as_unchecked<int64_t>() > 0) {
continue;
}
if(!this->server->isChannelRootEmpty(oldChannel, false)) {
continue;
}
this->server->delete_channel(oldChannel, this->ref(), "temporary auto delete", server_channel_lock, true);
}
return command_result{std::forward<command_result_bulk>(result)};
return command_result{std::move(result)};
}
command_result ConnectedClient::handleCommandClientPoke(Command &cmd) {
@ -388,7 +379,7 @@ command_result ConnectedClient::handleCommandClientChatClosed(Command &cmd) {
ConnectedLockedClient<ConnectedClient> client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
if (!client) return command_result{error::client_invalid_id};
{
unique_lock channel_lock(this->channel_lock);
unique_lock channel_lock(this->channel_tree_mutex);
this->open_private_conversations.erase(remove_if(this->open_private_conversations.begin(), this->open_private_conversations.end(), [&](const weak_ptr<ConnectedClient>& weak) {
return weak.lock() == client;
}), this->open_private_conversations.end());
@ -760,7 +751,7 @@ command_result ConnectedClient::handleCommandClientMute(Command &cmd) {
if (!client || client->getClientId() == this->getClientId()) return command_result{error::client_invalid_id};
{
unique_lock channel_lock(this->channel_lock);
unique_lock channel_lock(this->channel_tree_mutex);
for(const auto& weak : this->mutedClients)
if(weak.lock() == client) return command_result{error::ok};
this->mutedClients.push_back(client.client);
@ -780,7 +771,7 @@ command_result ConnectedClient::handleCommandClientUnmute(Command &cmd) {
if (!client || client->getClientId() == this->getClientId()) return command_result{error::client_invalid_id};
{
unique_lock channel_lock(this->channel_lock);
unique_lock channel_lock(this->channel_tree_mutex);
this->mutedClients.erase(std::remove_if(this->mutedClients.begin(), this->mutedClients.end(), [&](const weak_ptr<ConnectedClient>& weak) {
auto c = weak.lock();
return !c || c == client;

View File

@ -61,8 +61,10 @@ command_result ConnectedClient::handleCommandFTGetFileList(Command &cmd) {
if (!channel)
return command_result{error::channel_invalid_id};
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
auto channel_password = cmd["cpw"].optional_string();
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
}
if(!channel->permission_granted(permission::i_ft_needed_file_browse_power, this->calculate_permission(permission::i_ft_file_browse_power, channel->channelId()), true))
return command_result{permission::i_ft_file_browse_power};
@ -184,13 +186,15 @@ command_result ConnectedClient::handleCommandFTCreateDir(Command &cmd) {
if(!virtual_file_server) return command_result{error::file_virtual_server_not_registered};
auto& file_system = file::server()->file_system();
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel)
return command_result{error::channel_invalid_id};
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
auto channel_password = cmd["cpw"].optional_string();
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
}
if(!channel->permission_granted(permission::i_ft_needed_directory_create_power, this->calculate_permission(permission::i_ft_directory_create_power, channel->channelId()), true))
return command_result{permission::i_ft_directory_create_power};
@ -242,13 +246,15 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
auto file_path = cmd["path"].string();
std::shared_ptr<file::ExecuteResponse<file::filesystem::FileDeleteError, file::filesystem::FileDeleteResponse>> delete_response{};
if (cmd[0].has("cid") && cmd["cid"] != 0) {
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel)
return command_result{error::channel_invalid_id};
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
auto channel_password = cmd["cpw"].optional_string();
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
}
if(!channel->permission_granted(permission::i_ft_needed_file_delete_power, this->calculate_permission(permission::i_ft_file_delete_power, channel->channelId()), true))
return command_result{permission::i_ft_file_delete_power};
@ -447,7 +453,7 @@ command_result ConnectedClient::handleCommandFTGetFileInfo(ts::Command &cmd) {
currentChannel = this->server->channelTree->findChannel(cmd[index]["cid"].as<ChannelId>());
if(currentChannel) {
const auto password = cmd[index]["cpw"].string();
if (!currentChannel->passwordMatch(password) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, currentChannel->channelId()))) {
if (!currentChannel->verify_password(std::make_optional(password), this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, currentChannel->channelId()))) {
if(password.empty())
error_error = error::channel_invalid_password;
else
@ -667,13 +673,15 @@ command_result ConnectedClient::handleCommandFTInitUpload(ts::Command &cmd) {
ChannelId log_channel_id{0};
if(cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel)
return command_result{error::channel_invalid_id, "Cant resolve channel"};
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
auto channel_password = cmd["cpw"].optional_string();
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
}
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_upload_power, permission::i_ft_file_upload_power, true);
transfer_response = file::server()->file_transfer().initialize_channel_transfer(file::transfer::Transfer::DIRECTION_UPLOAD, virtual_file_server, channel->channelId(), info);
@ -810,13 +818,15 @@ command_result ConnectedClient::handleCommandFTInitDownload(ts::Command &cmd) {
ChannelId log_channel_id{0};
if(cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel)
return command_result{error::channel_invalid_id};
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
auto channel_password = cmd["cpw"].optional_string();
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
}
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_download_power, permission::i_ft_file_download_power, true);
transfer_response = file::server()->file_transfer().initialize_channel_transfer(file::transfer::Transfer::DIRECTION_DOWNLOAD, virtual_file_server, channel->channelId(), info);
@ -912,13 +922,15 @@ command_result ConnectedClient::handleCommandFTRenameFile(ts::Command &cmd) {
auto channel_id = cmd["cid"].as<ChannelId>();
auto target_channel_id = cmd[0].has("tcid") ? cmd["tcid"].as<ChannelId>() : channel_id;
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
auto channel = this->server->channelTree->findChannel(channel_id);
if (!channel)
return command_result{error::channel_invalid_id};
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
auto channel_password = cmd["cpw"].optional_string();
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
}
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_rename_power, permission::i_ft_file_rename_power, true);
@ -927,8 +939,10 @@ command_result ConnectedClient::handleCommandFTRenameFile(ts::Command &cmd) {
if (!targetChannel)
return command_result{error::channel_invalid_id};
if (!channel->passwordMatch(cmd["tcpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
return cmd["tcpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
auto channel_password = cmd["cpw"].optional_string();
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
}
ACTION_REQUIRES_CHANNEL_PERMISSION(targetChannel, permission::i_ft_needed_file_rename_power, permission::i_ft_file_rename_power, true);
}

View File

@ -5,8 +5,6 @@
#include <bitset>
#include <algorithm>
#include <openssl/sha.h>
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../../server/VoiceServer.h"
@ -23,11 +21,8 @@
#include "helpers.h"
#include "./bulk_parsers.h"
#include <log/LogUtils.h>
#include <misc/base64.h>
#include <misc/digest.h>
#include <misc/rnd.h>
#include <misc/scope_guard.h>
#include <bbcode/bbcodes.h>
using namespace std::chrono;

View File

@ -44,14 +44,14 @@ do { \
/* Helper methods for channel resolve */
#define RESOLVE_CHANNEL_R(command, force) \
auto channel_tree = this->server ? this->server->channelTree : serverInstance->getChannelTree().get();\
shared_lock channel_tree_read_lock(this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock());\
shared_lock channel_tree_read_lock(this->server ? this->server->channel_tree_mutex : serverInstance->getChannelTreeLock());\
auto channel_id = command.as<ChannelId>(); \
auto l_channel = channel_id ? channel_tree->findLinkedChannel(command.as<ChannelId>()) : nullptr; \
if (!l_channel && (channel_id != 0 || force)) return command_result{error::channel_invalid_id, "Cant resolve channel"}; \
#define RESOLVE_CHANNEL_W(command, force) \
auto channel_tree = this->server ? this->server->channelTree : serverInstance->getChannelTree().get();\
unique_lock channel_tree_write_lock(this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock());\
unique_lock channel_tree_write_lock(this->server ? this->server->channel_tree_mutex : serverInstance->getChannelTreeLock());\
auto channel_id = command.as<ChannelId>(); \
auto l_channel = channel_id ? channel_tree->findLinkedChannel(command.as<ChannelId>()) : nullptr; \
if (!l_channel && (channel_id != 0 || force)) return command_result{error::channel_invalid_id, "Cant resolve channel"}; \

View File

@ -462,7 +462,7 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
}
}
std::shared_lock server_channel_lock{this->server->channel_tree_lock}; /* ensure we dont get moved or somebody could move us */
std::shared_lock server_channel_lock{this->server->channel_tree_mutex}; /* ensure we dont get moved or somebody could move us */
auto channel_id = cmd["cid"].as<ChannelId>();
auto channel = this->server->channelTree->findChannel(channel_id);
if (!channel) {
@ -579,7 +579,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
bool chat_open{false};
{
std::unique_lock self_channel_lock{this->channel_lock};
std::unique_lock self_channel_lock{this->channel_tree_mutex};
this->open_private_conversations.erase(std::remove_if(this->open_private_conversations.begin(), this->open_private_conversations.end(), [](const weak_ptr<ConnectedClient>& weak) {
return !weak.lock();
}), this->open_private_conversations.end());
@ -597,7 +597,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
ACTION_REQUIRES_PERMISSION(permission::b_client_even_textmessage_send, 1, this->getChannelId());
}
if(!permission::v2::permission_granted(target->calculate_permission(permission::i_client_needed_private_textmessage_power, target->getClientId()), this->calculate_permission(permission::i_client_private_textmessage_power, this->getClientId()), false)) {
if(!permission::v2::permission_granted(target->calculate_permission(permission::i_client_needed_private_textmessage_power, target->getClientId()), this->calculate_permission(permission::i_client_private_textmessage_power, this->getClientId()))) {
return command_result{permission::i_client_private_textmessage_power};
}
@ -608,7 +608,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
}
{
std::unique_lock self_channel_lock{this->channel_lock};
std::unique_lock self_channel_lock{this->channel_tree_mutex};
this->open_private_conversations.push_back(target.client);
}
}
@ -636,7 +636,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
channel_id = this->currentChannel->channelId();
}
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_channel_textmessage_send, channel_id), false)) \
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_channel_textmessage_send, channel_id))) \
return command_result{permission::b_client_channel_textmessage_send};
if(channel == this->currentChannel) {
@ -917,9 +917,9 @@ command_result ConnectedClient::handleCommandBanClient(Command &cmd) {
ban_ids.push_back(_id);
}
auto b_ban_name = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_name, 0), false);
auto b_ban_ip = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_ip, 0), false);
auto b_ban_hwid = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_hwid, 0), false);
auto b_ban_name = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_name, 0));
auto b_ban_ip = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_ip, 0));
auto b_ban_hwid = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_hwid, 0));
auto max_ban_time = this->calculate_permission(permission::i_client_ban_max_bantime, 0);
if(!max_ban_time.has_value) return command_result{permission::i_client_ban_max_bantime};
@ -1351,7 +1351,7 @@ void check_token_action_permissions(const std::shared_ptr<ConnectedClient>& clie
if(permission::v2::permission_granted(1, client->calculate_permission(permission::b_channel_join_ignore_password, target_channel->channelId()))) {
action.text = "ignore";
} else if(!target_channel->passwordMatch(action.text, true)) {
} else if(!target_channel->verify_password(action.text, true)) {
action.type = ActionType::ActionIgnore;
result.set_result(index, ts::command_result{error::channel_invalid_password});
break;
@ -1374,8 +1374,11 @@ command_result ConnectedClient::handleCommandTokenAdd(Command &cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto client_tokens = this->server->tokenManager->client_token_count(this->getClientDatabaseId());
if(!permission::v2::permission_granted(client_tokens + 1, this->calculate_permission(permission::i_virtualserver_token_limit, 0), true)) {
return ts::command_result{permission::i_virtualserver_token_limit};
auto token_limit = this->calculate_permission(permission::i_virtualserver_token_limit, 0);
if(token_limit.has_value) {
if(!permission::v2::permission_granted(client_tokens + 1, token_limit)) {
return ts::command_result{permission::i_virtualserver_token_limit};
}
}
std::vector<token::TokenAction> actions{};
@ -1766,8 +1769,7 @@ command_result ConnectedClient::handleCommandVerifyChannelPassword(Command &cmd)
std::shared_ptr<BasicChannel> channel = (this->server ? this->server->channelTree : serverInstance->getChannelTree().get())->findChannel(cmd["cid"].as<ChannelId>());
if (!channel) return command_result{error::channel_invalid_id, "Cant resolve channel"};
std::string password = cmd["password"];
if (!channel->passwordMatch(password, false)) return command_result{error::server_invalid_password};
if (!channel->verify_password(cmd["password"].optional_string(), this->getType() != ClientType::CLIENT_QUERY)) return command_result{error::server_invalid_password};
return command_result{error::ok};
}
@ -3071,7 +3073,7 @@ command_result ConnectedClient::handleCommandConversationHistory(ts::Command &co
if(conversation_id > 0) {
/* test if we're able to see the channel */
{
shared_lock channel_view_lock(this->channel_lock);
shared_lock channel_view_lock(this->channel_tree_mutex);
auto channel = this->channel_view()->find_channel(conversation_id);
if(!channel)
return command_result{error::conversation_invalid_id};
@ -3091,16 +3093,14 @@ command_result ConnectedClient::handleCommandConversationHistory(ts::Command &co
/* test if there is a channel password or join power which denies that we see the conversation */
{
shared_lock channel_view_lock(ref_server->channel_tree_lock);
shared_lock channel_view_lock(ref_server->channel_tree_mutex);
auto channel = ref_server->getChannelTree()->findChannel(conversation_id);
if(!channel) /* should never happen! */
return command_result{error::conversation_invalid_id};
if(!command[0].has("cpw"))
command[0]["cpw"] = "";
if (!channel->passwordMatch(command["cpw"], true))
if (!channel->verify_password(command["cpw"].optional_string(), this->getType() != ClientType::CLIENT_QUERY)) {
ACTION_REQUIRES_PERMISSION(permission::b_channel_join_ignore_password, 1, channel->channelId());
}
auto error = this->calculate_and_get_join_state(channel);
if(error) return command_result{error};
@ -3197,7 +3197,7 @@ command_result ConnectedClient::handleCommandConversationFetch(ts::Command &cmd)
if(conversation_id > 0) {
/* test if we're able to see the channel */
{
shared_lock channel_view_lock(this->channel_lock);
shared_lock channel_view_lock(this->channel_tree_mutex);
auto channel = this->channel_view()->find_channel(conversation_id);
if(!channel) {
auto error = findError("conversation_invalid_id");
@ -3229,7 +3229,7 @@ command_result ConnectedClient::handleCommandConversationFetch(ts::Command &cmd)
/* test if there is a channel password or join power which denies that we see the conversation */
{
shared_lock channel_view_lock(ref_server->channel_tree_lock);
shared_lock channel_view_lock(ref_server->channel_tree_mutex);
auto channel = ref_server->getChannelTree()->findChannel(conversation_id);
if(!channel) { /* should never happen! */
auto error = findError("conversation_invalid_id");
@ -3238,16 +3238,14 @@ command_result ConnectedClient::handleCommandConversationFetch(ts::Command &cmd)
continue;
}
if(!bulk.has("cpw"))
bulk["cpw"] = "";
if (!channel->passwordMatch(bulk["cpw"], true))
if (!channel->verify_password( bulk.has("cpw") ? std::make_optional(bulk["cpw"].string()) : std::nullopt, this->getType() != ClientType::CLIENT_QUERY)) {
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, 1, channel->channelId()))) {
auto error = findError("channel_invalid_password");
result_bulk["error_id"] = error.errorId;
result_bulk["error_msg"] = error.message;
continue;
}
}
if(auto error_perm = this->calculate_and_get_join_state(channel); error_perm) {
auto error = findError("server_insufficeient_permissions");
@ -3296,7 +3294,7 @@ command_result ConnectedClient::handleCommandConversationMessageDelete(ts::Comma
/* test if we're able to see the channel */
{
shared_lock channel_view_lock(this->channel_lock);
shared_lock channel_view_lock(this->channel_tree_mutex);
auto channel = this->channel_view()->find_channel(current_conversation_id);
if(!channel)
return command_result{error::conversation_invalid_id};
@ -3304,16 +3302,14 @@ command_result ConnectedClient::handleCommandConversationMessageDelete(ts::Comma
/* test if there is a channel password or join power which denies that we see the conversation */
{
shared_lock channel_view_lock(ref_server->channel_tree_lock);
shared_lock channel_view_lock(ref_server->channel_tree_mutex);
auto channel = ref_server->getChannelTree()->findChannel(current_conversation_id);
if(!channel)
return command_result{error::conversation_invalid_id};
if(!bulk.has("cpw"))
bulk["cpw"] = "";
if (!channel->passwordMatch(bulk["cpw"], true))
if (!channel->verify_password( bulk.has("cpw") ? std::make_optional(bulk["cpw"].string()) : std::nullopt, this->getType() != ClientType::CLIENT_QUERY)) {
ACTION_REQUIRES_PERMISSION(permission::b_channel_join_ignore_password, 1, channel->channelId());
}
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_conversation_message_delete, channel->channelId())))
return command_result{permission::b_channel_conversation_message_delete};

View File

@ -112,7 +112,7 @@ command_result ConnectedClient::handleCommandMusicBotCreate(Command& cmd) {
return command_result{permission::b_client_music_create_temporary};
}
shared_lock server_channel_lock(this->server->channel_tree_lock);
shared_lock server_channel_lock(this->server->channel_tree_mutex);
auto channel = cmd[0].has("cid") ? this->server->channelTree->findChannel(cmd["cid"]) : this->currentChannel;
if(!channel) {
if(cmd[0].has("cid")) return command_result{error::channel_invalid_id};
@ -135,7 +135,7 @@ command_result ConnectedClient::handleCommandMusicBotCreate(Command& cmd) {
{
server_channel_lock.unlock();
unique_lock server_channel_w_lock(this->server->channel_tree_lock);
unique_lock server_channel_w_lock(this->server->channel_tree_mutex);
this->server->client_move(
bot,
channel,

View File

@ -137,7 +137,7 @@ void MusicClient::initialize_bot() {
this->server->registerClient(this->ref());
}
{
unique_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock server_channel_lock(this->server->channel_tree_mutex);
this->server->client_move(this->ref(), channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, true, server_channel_lock);
}
this->playback.volume_modifier = this->properties()[property::CLIENT_PLAYER_VOLUME];

View File

@ -618,7 +618,7 @@ void QueryClient::disconnect_from_virtual_server(const std::string& reason) {
auto old_server = std::exchange(this->server, nullptr);
if(old_server) {
{
std::unique_lock tree_lock(old_server->channel_tree_lock);
std::unique_lock tree_lock(old_server->channel_tree_mutex);
if(this->currentChannel) {
old_server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
}
@ -627,8 +627,8 @@ void QueryClient::disconnect_from_virtual_server(const std::string& reason) {
}
{
std::lock_guard channel_lock{this->channel_lock};
this->channels->reset();
std::lock_guard channel_lock{this->channel_tree_mutex};
this->channel_tree->reset();
this->currentChannel = nullptr;
}

View File

@ -243,7 +243,7 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
auto joined_channel = this->currentChannel;
if(this->server) {
{
unique_lock tree_lock(this->server->channel_tree_lock);
unique_lock tree_lock(this->server->channel_tree_mutex);
if(joined_channel) {
this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
}
@ -272,18 +272,18 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
target_server->registerClient(this->ref());
{
shared_lock server_tree_lock(target_server->channel_tree_lock);
shared_lock server_tree_lock(target_server->channel_tree_mutex);
if(joined_channel) /* needs only notify if we were already on that server within a channel */
target_server->notifyClientPropertyUpdates(this->ref(), deque<property::ClientProperties>{property::CLIENT_NICKNAME, property::CLIENT_UNIQUE_IDENTIFIER});
unique_lock client_tree_lock(this->channel_lock);
this->channels->reset();
this->channels->insert_channels(target_server->channelTree->tree_head(), true, false);
unique_lock client_tree_lock(this->channel_tree_mutex);
this->channel_tree->reset();
this->channel_tree->insert_channels(target_server->channelTree->tree_head(), true, false);
this->subscribeChannel(this->server->channelTree->channels(), false, false);
}
if(joined_channel) {
unique_lock tree_lock(this->server->channel_tree_lock);
unique_lock tree_lock(this->server->channel_tree_mutex);
if(joined_channel)
this->server->client_move(this->ref(), joined_channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
} else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1))) {
@ -311,7 +311,7 @@ command_result QueryClient::handleCommandLogout(Command &) {
auto joined = this->currentChannel;
if(this->server){
{
unique_lock tree_lock(this->server->channel_tree_lock);
unique_lock tree_lock(this->server->channel_tree_mutex);
if(joined)
this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
this->server->unregisterClient(this->ref(), "logout", tree_lock);
@ -326,16 +326,16 @@ command_result QueryClient::handleCommandLogout(Command &) {
this->server->registerClient(this->ref());
{
shared_lock server_channel_r_lock(this->server->channel_tree_lock);
unique_lock client_channel_lock(this->channel_lock);
shared_lock server_channel_r_lock(this->server->channel_tree_mutex);
unique_lock client_channel_lock(this->channel_tree_mutex);
this->channels->reset();
this->channels->insert_channels(this->server->channelTree->tree_head(), true, false);
this->channel_tree->reset();
this->channel_tree->insert_channels(this->server->channelTree->tree_head(), true, false);
this->subscribeChannel(this->server->channelTree->channels(), false, false);
}
if(joined) {
unique_lock server_channel_w_lock(this->server->channel_tree_lock, defer_lock);
unique_lock server_channel_w_lock(this->server->channel_tree_mutex, defer_lock);
this->server->client_move(this->ref(), joined, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_w_lock);
} else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1))) {
this->server->assignDefaultChannel(this->ref(), true);
@ -399,11 +399,11 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) {
this->server->registerClient(this->ref());
{
shared_lock server_channel_lock(target->channel_tree_lock);
unique_lock client_channel_lock(this->channel_lock);
shared_lock server_channel_lock(target->channel_tree_mutex);
unique_lock client_channel_lock(this->channel_tree_mutex);
this->subscribeToAll = true;
this->channels->insert_channels(this->server->channelTree->tree_head(), true, false);
this->channel_tree->insert_channels(this->server->channelTree->tree_head(), true, false);
this->subscribeChannel(this->server->channelTree->channels(), false, false);
}
@ -441,7 +441,7 @@ command_result QueryClient::handleCommandLeft(Command&) {
CMD_RESET_IDLE;
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_select_godmode, 1);
unique_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock server_channel_lock(this->server->channel_tree_mutex);
this->server->client_move(this->ref(), nullptr, nullptr, "leaving", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock);
return command_result{error::ok};
}
@ -536,8 +536,8 @@ command_result QueryClient::handleCommandChannelList(Command& cmd) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channel_list, 1);
int index = 0;
shared_lock channel_lock(this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock());
auto entries = this->server ? this->channels->channels() : serverInstance->getChannelTree()->channels();
shared_lock channel_lock(this->server ? this->server->channel_tree_mutex : serverInstance->getChannelTreeLock());
auto entries = this->server ? this->channel_tree->channels() : serverInstance->getChannelTree()->channels();
channel_lock.unlock();
command_builder result{"", 1024, entries.size()};

View File

@ -131,7 +131,7 @@ bool QueryClient::notifyChannelDeleted(const std::deque<ChannelId> &deque, const
bool QueryClient::notifyClientEnterView(const std::deque<std::shared_ptr<ConnectedClient>> &deque, const ViewReasonSystemT &t) {
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_JOIN)) {
assert(mutex_locked(this->channel_lock));
assert(mutex_locked(this->channel_tree_mutex));
this->visibleClients.insert(this->visibleClients.end(), deque.begin(), deque.end());
return true;
} else
@ -155,7 +155,7 @@ bool QueryClient::notifyClientMoved(const std::shared_ptr<ConnectedClient> &clie
bool QueryClient::notifyClientLeftView(const std::shared_ptr<ConnectedClient> &client, const std::shared_ptr<BasicChannel> &target_channel, ViewReasonId reasonId, const std::string &reasonMessage, std::shared_ptr<ConnectedClient> invoker,
bool lock_channel_tree) {
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
std::unique_lock tree_lock{this->channel_lock, std::defer_lock};
std::unique_lock tree_lock{this->channel_tree_mutex, std::defer_lock};
if(lock_channel_tree) {
tree_lock.lock();
}
@ -175,7 +175,7 @@ bool QueryClient::notifyClientLeftView(const std::shared_ptr<ConnectedClient> &c
bool QueryClient::notifyClientLeftView(const std::deque<std::shared_ptr<ConnectedClient>> &clients, const std::string &string, bool lock_channel_tree, const ViewReasonServerLeftT &t) {
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
std::unique_lock tree_lock{this->channel_lock, std::defer_lock};
std::unique_lock tree_lock{this->channel_tree_mutex, std::defer_lock};
if(lock_channel_tree) {
tree_lock.lock();
}
@ -195,7 +195,7 @@ bool QueryClient::notifyClientLeftView(const std::deque<std::shared_ptr<Connecte
bool QueryClient::notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClient> &client, const std::shared_ptr<BasicChannel> &target_channel, const std::string &message, std::shared_ptr<ConnectedClient> invoker, bool lock_channel_tree) {
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
std::unique_lock tree_lock{this->channel_lock, std::defer_lock};
std::unique_lock tree_lock{this->channel_tree_mutex, std::defer_lock};
if(lock_channel_tree) {
tree_lock.lock();
}
@ -215,7 +215,7 @@ bool QueryClient::notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClie
bool QueryClient::notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClient> &client, const std::string &message, std::shared_ptr<ConnectedClient> invoker, size_t length, bool lock_channel_tree) {
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
std::unique_lock tree_lock{this->channel_lock, std::defer_lock};
std::unique_lock tree_lock{this->channel_tree_mutex, std::defer_lock};
if(lock_channel_tree) {
tree_lock.lock();
}

View File

@ -139,7 +139,7 @@ bool VoiceClient::disconnect(ts::ViewReasonId reason_id, const std::string &reas
}
if(notify_viewer && this->server) {
unique_lock channel_lock(this->server->channel_tree_lock);
unique_lock channel_lock(this->server->channel_tree_mutex);
this->server->client_move(this->ref(), nullptr, invoker, reason, reason_id, false, channel_lock);
} else {
threads::MutexLock lock(this->command_lock);

View File

@ -110,12 +110,12 @@ command_result VoiceClient::handleCommandClientInit(Command &cmd) {
command_result VoiceClient::handleCommandClientDisconnect(Command& cmd) {
auto reason = cmd["reasonmsg"].size() > 0 ? cmd["reasonmsg"].as<string>() : "";
{
std::shared_lock own_lock{this->channel_lock};
std::shared_lock own_lock{this->channel_tree_mutex};
this->notifyClientLeftView(this->ref(), nullptr, VREASON_SERVER_LEFT, reason, nullptr, false); //Before we're moving us out of the channel tree!
}
if(this->state == CONNECTED) {
std::unique_lock channel_lock{this->server->channel_tree_lock};
std::unique_lock channel_lock{this->server->channel_tree_mutex};
this->server->client_move(this->ref(), nullptr, nullptr, reason, VREASON_SERVER_LEFT, true, channel_lock);
}
logMessage(this->getServerId(), "{} Got remote disconnect with the reason '{}'", CLIENT_STR_LOG_PREFIX, reason);

View File

@ -224,7 +224,7 @@ bool WebClient::close_connection(const std::chrono::system_clock::time_point& ti
if(this->server){
{
unique_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock server_channel_lock(this->server->channel_tree_mutex);
this->server->unregisterClient(this->ref(), "disconnected", server_channel_lock);
}
//this->server = nullptr;
@ -539,9 +539,9 @@ bool WebClient::disconnect(const std::string &reason) {
serverInstance->action_logger()->client_channel_logger.log_client_leave(this->getServerId(), this->ref(), old_channel->channelId(), old_channel->name());
}
{
unique_lock server_channel_lock(this->server->channel_tree_lock);
unique_lock server_channel_lock(this->server->channel_tree_mutex);
{
unique_lock own_lock(this->channel_lock);
unique_lock own_lock(this->channel_tree_mutex);
this->notifyClientLeftViewKicked(this->ref(), nullptr, reason, this->server->serverRoot, false);
}
this->server->client_move(this->ref(), nullptr, this->server->serverRoot, reason, ViewReasonId::VREASON_SERVER_KICK, false, server_channel_lock);

View File

@ -142,7 +142,7 @@ void MusicBotManager::deleteBot(std::shared_ptr<server::MusicClient> musicBot) {
MusicBotManager::adjustTickPool();
{
unique_lock server_channel_lock(handle->channel_tree_lock);
unique_lock server_channel_lock(handle->channel_tree_mutex);
handle->client_move(musicBot, nullptr, nullptr, "Music bot deleted", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock);
handle->unregisterClient(musicBot, "bot deleted", server_channel_lock);
}
@ -274,7 +274,7 @@ void MusicBotManager::disconnectBots() {
for(const auto& bot : this->music_bots) {
if(bot->currentChannel) {
unique_lock server_channel_lock(handle->channel_tree_lock);
unique_lock server_channel_lock(handle->channel_tree_mutex);
handle->client_move(bot, nullptr, nullptr, "Music bot deleted", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock);
}
bot->server = nullptr;

View File

@ -13,17 +13,31 @@ PlaylistPermissions::PlaylistPermissions(std::shared_ptr<permission::v2::Permiss
permission::v2::PermissionFlaggedValue PlaylistPermissions::calculate_client_specific_permissions(ts::permission::PermissionType permission, const std::shared_ptr<server::ConnectedClient>& client) {
auto val = this->_permissions->channel_permission(permission, client->getClientDatabaseId());
if(val.flags.value_set)
if(val.flags.value_set) {
return {val.values.value, true};
}
return client->calculate_permission(permission, 0);
}
permission::PermissionType PlaylistPermissions::client_has_permissions(
const std::shared_ptr<server::ConnectedClient> &client, ts::permission::PermissionType needed_permission, ts::permission::PermissionType granted_permission, uint8_t flags) {
if(this->is_playlist_owner(client->getClientDatabaseId())) return permission::ok;
const std::shared_ptr<server::ConnectedClient> &client,
ts::permission::PermissionType needed_permission,
ts::permission::PermissionType granted_permission,
uint8_t flags
) {
if(this->is_playlist_owner(client->getClientDatabaseId())) {
return permission::ok;
}
return permission::v2::permission_granted(
this->permission_manager()->permission_value_flagged(needed_permission),
this->calculate_client_specific_permissions(granted_permission, client),
(flags & do_no_require_granted) == 0) ? permission::ok : granted_permission;
const auto client_permission = this->calculate_client_specific_permissions(granted_permission, client);
auto playlist_permission = this->permission_manager()->permission_value_flagged(needed_permission);
if((flags & do_no_require_granted) == 0) {
playlist_permission.clear_flag_on_zero();
} else if(!playlist_permission.has_value) {
playlist_permission.value = 0;
playlist_permission.has_value = true;
}
return permission::v2::permission_granted(playlist_permission, client_permission) ? permission::ok : granted_permission;
}

2
shared

@ -1 +1 @@
Subproject commit 8dde5b1c23f0d84ca1b56a8c80389fb4e887b062
Subproject commit 8fb93d1d9d938b78dcf34e7f7953e3d41504d00f