2019-07-17 19:37:18 +02:00
# include <iostream>
# include <algorithm>
# include <bitset>
# include <memory>
# include <Definitions.h>
# include <misc/sassert.h>
# include <misc/memtracker.h>
# include <log/LogUtils.h>
# include <ThreadPool/Timer.h>
2020-01-26 18:04:38 +01:00
# include "src/VirtualServer.h"
2019-07-17 19:37:18 +02:00
# include "voice/VoiceClient.h"
# include "../server/VoiceServer.h"
# include "../InstanceHandler.h"
# include "ConnectedClient.h"
2020-02-21 20:32:25 +01:00
# include <event.h>
2019-07-17 19:37:18 +02:00
using namespace std ;
using namespace std : : chrono ;
using namespace ts ;
using namespace ts : : server ;
using namespace ts : : token ;
extern ts : : server : : InstanceHandler * serverInstance ;
2020-01-26 18:04:38 +01:00
ConnectedClient : : ConnectedClient ( sql : : SqlManager * db , const std : : shared_ptr < VirtualServer > & server ) : DataClient ( db , server ) {
2020-01-24 02:57:58 +01:00
memtrack : : allocated < ConnectedClient > ( this ) ;
memset ( & this - > remote_address , 0 , sizeof ( this - > remote_address ) ) ;
2019-07-17 19:37:18 +02:00
2020-04-08 13:01:41 +02:00
connectionStatistics = make_shared < stats : : ConnectionStatistics > ( server ? server - > getServerStatistics ( ) : nullptr ) ;
2019-07-17 19:37:18 +02:00
channels = make_shared < ClientChannelView > ( this ) ;
}
ConnectedClient : : ~ ConnectedClient ( ) {
2020-01-24 02:57:58 +01:00
memtrack : : freed < ConnectedClient > ( this ) ;
2019-07-17 19:37:18 +02:00
}
2019-08-25 22:16:42 +02:00
std : : shared_ptr < ConnectionInfoData > ConnectedClient : : request_connection_info ( const std : : shared_ptr < ConnectedClient > & receiver , bool & send_temp ) {
2020-01-24 02:57:58 +01:00
auto & info = this - > connection_info ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
lock_guard info_lock ( info . lock ) ;
2019-07-17 19:37:18 +02:00
if ( info . data ) {
if ( chrono : : system_clock : : now ( ) - info . data_age < chrono : : seconds ( 1 ) )
return info . data ;
if ( chrono : : system_clock : : now ( ) - info . data_age > chrono : : seconds ( 5 ) ) //Data timeout
2020-01-24 02:57:58 +01:00
info . data = nullptr ;
2019-07-17 19:37:18 +02:00
}
2019-08-25 22:16:42 +02:00
if ( receiver ) {
2020-01-24 02:57:58 +01:00
info . receiver . erase ( std : : remove_if ( info . receiver . begin ( ) , info . receiver . end ( ) , [ & ] ( const weak_ptr < ConnectedClient > & weak ) {
auto locked = weak . lock ( ) ;
if ( locked = = receiver ) {
send_temp = true ;
return true ;
}
return ! locked ;
} ) , info . receiver . end ( ) ) ;
info . receiver . push_back ( receiver ) ;
2019-08-25 22:16:42 +02:00
}
2019-07-17 19:37:18 +02:00
if ( chrono : : system_clock : : now ( ) - info . last_requested > = chrono : : seconds ( 1 ) ) {
2020-01-24 02:57:58 +01:00
info . last_requested = chrono : : system_clock : : now ( ) ;
2019-07-17 19:37:18 +02:00
Command cmd ( " notifyconnectioninforequest " ) ;
string invoker ;
for ( const auto & weak_request : info . receiver ) {
2020-01-24 02:57:58 +01:00
auto request = weak_request . lock ( ) ;
if ( ! request ) continue ;
invoker + = ( invoker . empty ( ) ? " " : " , " ) + to_string ( request - > getClientId ( ) ) ;
2019-07-17 19:37:18 +02:00
}
cmd [ " invokerids " ] = invoker ;
this - > sendCommand ( cmd ) ;
}
return info . data ;
}
//Attention the client should be only read only locked!
void ConnectedClient : : updateChannelClientProperties ( bool lock_channel_tree , bool notify_self ) {
2020-01-24 02:57:58 +01:00
/* this->server may be null! */
2020-01-26 18:04:38 +01:00
shared_ptr < VirtualServer > server_ref = this - > server ;
2020-01-24 02:57:58 +01:00
2020-01-26 14:21:34 +01:00
auto permissions = this - > calculate_permissions ( {
2020-01-24 02:57:58 +01:00
permission : : i_client_talk_power ,
permission : : b_client_ignore_antiflood ,
permission : : i_channel_view_power ,
permission : : b_channel_ignore_view_power
2020-01-26 14:21:34 +01:00
} , this - > currentChannel ? this - > currentChannel - > channelId ( ) : 0 ) ;
permission : : v2 : : PermissionFlaggedValue
permission_talk_power { 0 , false } ,
permission_ignore_antiflood { 0 , false } ,
permission_channel_view_power { 0 , false } ,
permission_channel_ignore_view_power { 0 , false } ;
2020-01-24 02:57:58 +01:00
for ( const auto & perm : permissions ) {
if ( perm . first = = permission : : i_client_talk_power )
permission_talk_power = perm . second ;
else if ( perm . first = = permission : : b_client_ignore_antiflood )
permission_ignore_antiflood = perm . second ;
else if ( perm . first = = permission : : i_channel_view_power )
permission_channel_view_power = perm . second ;
else if ( perm . first = = permission : : b_channel_ignore_view_power )
permission_channel_ignore_view_power = perm . second ;
else sassert ( false ) ;
}
2019-07-17 19:37:18 +02:00
deque < property : : ClientProperties > notifyList ;
2020-01-24 02:57:58 +01:00
debugMessage ( this - > getServerId ( ) , " {} Got a channel talk power of {} Talk power set is {} " , CLIENT_STR_LOG_PREFIX , permission_talk_power , this - > properties ( ) [ property : : CLIENT_TALK_POWER ] . as < uint64_t > ( ) ) ;
2020-01-26 14:21:34 +01:00
if ( ( permission_talk_power . has_value ? permission_talk_power . value : 0 ) ! = this - > properties ( ) [ property : : CLIENT_TALK_POWER ] . as < uint64_t > ( ) ) { //We do not have to update tp if there's no channel
this - > properties ( ) [ property : : CLIENT_TALK_POWER ] = ( permission_talk_power . has_value ? permission_talk_power . value : 0 ) ;
2019-07-17 19:37:18 +02:00
notifyList . emplace_back ( property : : CLIENT_TALK_POWER ) ;
2020-01-24 02:57:58 +01:00
auto update = this - > properties ( ) [ property : : CLIENT_IS_TALKER ] . as < bool > ( ) | | this - > properties ( ) [ property : : CLIENT_TALK_REQUEST ] . as < int64_t > ( ) > 0 ;
if ( update & & this - > currentChannel ) {
2020-01-26 14:21:34 +01:00
if ( this - > currentChannel - > talk_power_granted ( permission_talk_power ) ) {
2020-01-24 02:57:58 +01:00
this - > properties ( ) [ property : : CLIENT_IS_TALKER ] = 0 ;
this - > properties ( ) [ property : : CLIENT_TALK_REQUEST ] = 0 ;
this - > properties ( ) [ property : : CLIENT_TALK_REQUEST_MSG ] = " " ;
notifyList . emplace_back ( property : : CLIENT_IS_TALKER ) ;
notifyList . emplace_back ( property : : CLIENT_TALK_REQUEST ) ;
notifyList . emplace_back ( property : : CLIENT_TALK_REQUEST_MSG ) ;
}
}
2019-07-17 19:37:18 +02:00
}
2020-01-24 02:57:58 +01:00
IconId iconId = 0 ;
2019-07-18 10:45:50 +02:00
auto local_permissions = this - > clientPermissions ;
2020-01-24 02:57:58 +01:00
if ( local_permissions ) {
permission : : v2 : : PermissionFlaggedValue value { 0 , false } ;
auto permission_flags = local_permissions - > permission_flags ( permission : : i_icon_id ) ;
if ( permission_flags . channel_specific & & this - > currentChannel ) {
auto val = local_permissions - > channel_permission ( permission : : i_icon_id , this - > currentChannel - > channelId ( ) ) ;
value = { val . values . value , val . flags . value_set } ;
}
if ( ! value . has_value )
value = local_permissions - > permission_value_flagged ( permission : : i_icon_id ) ;
if ( value . has_value )
iconId = value . value ;
}
logTrace ( this - > getServerId ( ) , " [CLIENT] Updating client icon from " + to_string ( this - > properties ( ) [ property : : CLIENT_ICON_ID ] . as < IconId > ( ) ) + " to " + to_string ( iconId ) ) ;
2020-05-13 11:32:08 +02:00
if ( this - > properties ( ) [ property : : CLIENT_ICON_ID ] . as < IconId > ( ) ! = iconId ) {
#if 0
2020-01-24 02:57:58 +01:00
if ( server_ref & & iconId ! = 0 ) {
auto dir = serverInstance - > getFileServer ( ) - > iconDirectory ( server_ref ) ;
if ( ! serverInstance - > getFileServer ( ) - > iconExists ( server_ref , iconId ) ) {
logMessage ( this - > getServerId ( ) , " [FILE] Missing client icon ( " + to_string ( iconId ) + " ). " ) ;
iconId = 0 ;
}
}
2020-05-13 11:32:08 +02:00
# endif
2019-07-17 19:37:18 +02:00
if ( this - > properties ( ) [ property : : CLIENT_ICON_ID ] . as < IconId > ( ) ! = iconId ) {
this - > properties ( ) [ property : : CLIENT_ICON_ID ] = ( IconId ) iconId ;
notifyList . emplace_back ( property : : CLIENT_ICON_ID ) ;
}
}
2020-02-15 14:03:46 +01:00
auto pSpeaker = this - > clientPermissions ? this - > clientPermissions - > channel_permission ( permission : : b_client_is_priority_speaker , this - > getChannelId ( ) ) : permission : : v2 : : empty_channel_permission ;
auto pSpeakerGranted = permission : : v2 : : permission_granted ( 1 , { pSpeaker . values . value , pSpeaker . flags . value_set } ) ;
if ( properties ( ) [ property : : CLIENT_IS_PRIORITY_SPEAKER ] . as < bool > ( ) ! = pSpeakerGranted ) {
properties ( ) [ property : : CLIENT_IS_PRIORITY_SPEAKER ] = pSpeakerGranted ;
2019-07-17 19:37:18 +02:00
notifyList . emplace_back ( property : : CLIENT_IS_PRIORITY_SPEAKER ) ;
}
2020-01-26 16:15:36 +01:00
block_flood = ! permission : : v2 : : permission_granted ( 1 , permission_ignore_antiflood ) ;
2019-07-17 19:37:18 +02:00
if ( server_ref )
2020-01-24 02:57:58 +01:00
server_ref - > notifyClientPropertyUpdates ( _this . lock ( ) , notifyList , notify_self ) ;
2020-07-28 18:36:32 +02:00
this - > updateTalkRights ( permission_talk_power ) ;
2020-01-24 02:57:58 +01:00
if ( ( this - > channels_view_power ! = permission_channel_view_power | | this - > channels_ignore_view ! = permission_channel_ignore_view_power ) & & notify_self & & this - > currentChannel & & server_ref ) {
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 ) ;
if ( lock_channel_tree ) {
/* first read lock server channel tree */
server_channel_lock . lock ( ) ;
client_channel_lock . lock ( ) ;
}
2020-04-29 10:34:22 +02:00
/* might have been changed since we locked the tree */
if ( this - > currentChannel ) {
deque < ChannelId > deleted ;
for ( const auto & update_entry : this - > channels - > update_channel_path ( server_ref - > channelTree - > tree_head ( ) , server_ref - > channelTree - > find_linked_entry ( this - > currentChannel - > channelId ( ) ) ) ) {
if ( update_entry . first )
this - > notifyChannelShow ( update_entry . second - > channel ( ) , update_entry . second - > previous_channel ) ;
else deleted . push_back ( update_entry . second - > channelId ( ) ) ;
}
if ( ! deleted . empty ( ) )
this - > notifyChannelHide ( deleted , false ) ; /* we've locked the tree before */
2020-01-24 02:57:58 +01:00
}
}
2019-07-17 19:37:18 +02:00
}
2020-07-28 18:36:32 +02:00
void ConnectedClient : : updateTalkRights ( permission : : v2 : : PermissionFlaggedValue talk_power ) {
2020-01-24 02:57:58 +01:00
bool flag = false ;
flag | = this - > properties ( ) [ property : : CLIENT_IS_TALKER ] . as < bool > ( ) ;
if ( ! flag & & this - > currentChannel ) {
2020-07-28 18:36:32 +02:00
flag = this - > currentChannel - > talk_power_granted ( talk_power ) ;
2020-01-24 02:57:58 +01:00
}
this - > allowedToTalk = flag ;
2019-07-17 19:37:18 +02:00
}
void ConnectedClient : : resetIdleTime ( ) {
this - > idleTimestamp = chrono : : system_clock : : now ( ) ;
}
void ConnectedClient : : increaseFloodPoints ( uint16_t num ) {
this - > floodPoints + = num ;
}
bool ConnectedClient : : shouldFloodBlock ( ) {
if ( ! this - > server ) return false ;
if ( ! this - > block_flood ) return false ;
return this - > floodPoints > this - > server - > properties ( ) [ property : : VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_COMMAND_BLOCK ] . as < uint16_t > ( ) ;
}
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 ;
auto ref_server = this - > server ;
if ( ! ref_server )
2020-01-24 02:57:58 +01:00
return { } ;
2019-07-17 19:37:18 +02:00
2020-01-26 14:21:34 +01:00
auto general_granted = enforce | | permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_ignore_subscribe_power , 0 ) ) ;
2020-01-24 02:57:58 +01:00
{
shared_lock server_channel_lock ( ref_server - > channel_tree_lock , defer_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock , 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
if ( ! general_granted & & channel ! = this - > currentChannel ) {
2020-01-26 14:21:34 +01:00
auto granted_permission = this - > calculate_permission ( permission : : i_channel_subscribe_power , channel - > channelId ( ) ) ;
2020-01-24 02:57:58 +01:00
if ( ! channel - > permission_granted ( permission : : i_channel_needed_subscribe_power , granted_permission , false ) ) {
2020-01-26 14:21:34 +01:00
auto ignore_power = this - > calculate_permission ( permission : : b_channel_ignore_subscribe_power , channel - > channelId ( ) ) ;
2020-01-24 02:57:58 +01:00
if ( ! ignore_power . has_value | | ignore_power . value < 1 )
continue ;
}
}
local_channel - > subscribed = true ;
subscribed_channels . push_back ( channel ) ;
}
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 ) ;
}
}
this - > notifyClientEnterView ( visible_clients , ViewReasonSystem ) ;
if ( ! subscribed_channels . empty ( ) )
this - > notifyChannelSubscribed ( subscribed_channels ) ;
}
2019-07-17 19:37:18 +02:00
return subscribed_channels ;
}
std : : deque < std : : shared_ptr < BasicChannel > > ConnectedClient : : unsubscribeChannel ( const std : : deque < std : : shared_ptr < BasicChannel > > & targets , bool lock_channel ) {
2020-01-24 02:57:58 +01:00
auto ref_server = this - > server ;
if ( ! ref_server )
return { } ;
2019-07-17 19:37:18 +02:00
deque < std : : shared_ptr < BasicChannel > > unsubscribed_channels ;
2020-01-24 02:57:58 +01:00
{
shared_lock server_channel_lock ( ref_server - > channel_tree_lock , defer_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock , defer_lock ) ;
if ( lock_channel ) {
server_channel_lock . lock ( ) ;
client_channel_lock . lock ( ) ;
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
for ( const auto & channel : targets ) {
if ( this - > currentChannel = = channel ) continue ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
auto chan = this - > channels - > find_channel ( channel ) ;
if ( ! chan | | ! chan - > subscribed ) continue ;
chan - > subscribed = false ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
/* ref_server->getClientsByChannel only acquires channel client lock */
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 ) ;
return true ;
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
return std : : find ( clients . begin ( ) , clients . end ( ) , c ) ! = clients . end ( ) ;
} ) , this - > visibleClients . end ( ) ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
unsubscribed_channels . push_back ( channel ) ;
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
if ( ! unsubscribed_channels . empty ( ) )
this - > notifyChannelUnsubscribed ( unsubscribed_channels ) ;
}
2019-07-17 19:37:18 +02:00
return unsubscribed_channels ;
}
bool ConnectedClient : : isClientVisible ( const std : : shared_ptr < ts : : server : : ConnectedClient > & client , bool lock ) {
2020-01-24 02:57:58 +01:00
for ( const auto & entry : this - > getVisibleClients ( lock ) )
if ( entry . lock ( ) = = client )
return true ;
return false ;
2019-07-17 19:37:18 +02:00
}
bool ConnectedClient : : notifyClientLeftView ( const std : : deque < std : : shared_ptr < ts : : server : : ConnectedClient > > & clients , const std : : string & reason , bool lock , const ts : : ViewReasonServerLeftT & _vrsl ) {
2020-01-24 02:57:58 +01:00
if ( clients . empty ( ) )
return true ;
if ( lock ) {
/* TODO: add locking of server channel tree in read mode and client tree in write mode! */
assert ( false ) ;
}
Command cmd ( " notifyclientleftview " ) ;
cmd [ " reasonmsg " ] = reason ;
cmd [ " reasonid " ] = ViewReasonId : : VREASON_SERVER_LEFT ;
cmd [ " ctid " ] = 0 ;
ChannelId current_channel_id = 0 ;
size_t index = 0 ;
auto it = clients . begin ( ) ;
while ( it ! = clients . end ( ) ) {
auto client = * it ;
assert ( client - > getClientId ( ) > 0 ) ;
assert ( client - > currentChannel | | & * client = = this ) ;
if ( ! client - > currentChannel )
continue ;
if ( current_channel_id ! = ( client - > currentChannel ? client - > currentChannel - > channelId ( ) : 0 ) ) {
if ( current_channel_id ! = 0 )
break ;
else
cmd [ index ] [ " cfid " ] = ( current_channel_id = client - > currentChannel - > channelId ( ) ) ;
}
cmd [ index ] [ " clid " ] = client - > getClientId ( ) ;
it + + ;
index + + ;
}
this - > visibleClients . erase ( std : : remove_if ( this - > visibleClients . begin ( ) , this - > visibleClients . end ( ) , [ & ] ( 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 ) ;
return true ;
}
return std : : find ( clients . begin ( ) , it , c ) ! = it ;
} ) , this - > visibleClients . end ( ) ) ;
this - > sendCommand ( cmd ) ;
if ( it ! = clients . end ( ) )
return this - > notifyClientLeftView ( { it , clients . end ( ) } , reason , false , _vrsl ) ;
return true ;
2019-07-17 19:37:18 +02:00
}
bool ConnectedClient : : notifyClientLeftView (
2020-01-24 02:57:58 +01:00
const shared_ptr < ConnectedClient > & client ,
const std : : shared_ptr < BasicChannel > & target_channel ,
ViewReasonId reason_id ,
const std : : string & reason_message ,
std : : shared_ptr < ConnectedClient > invoker ,
bool lock_channel_tree ) {
assert ( ! lock_channel_tree ) ; /* not supported yet! */
2020-04-03 19:26:22 +02:00
assert ( client = = this | | ( client & & client - > getClientId ( ) ! = 0 ) ) ;
2020-01-24 02:57:58 +01:00
assert ( client - > currentChannel | | & * client = = this ) ;
if ( client ! = this ) {
if ( reason_id = = VREASON_SERVER_STOPPED | | reason_id = = VREASON_SERVER_SHUTDOWN ) {
debugMessage ( this - > getServerId ( ) , " Replacing notify left reason " + to_string ( reason_id ) + " with " + to_string ( VREASON_SERVER_LEFT ) ) ;
reason_id = VREASON_SERVER_LEFT ;
}
}
/*
switch ( reasonId ) {
case ViewReasonId : : VREASON_MOVED :
case ViewReasonId : : VREASON_BAN :
case ViewReasonId : : VREASON_CHANNEL_KICK :
case ViewReasonId : : VREASON_SERVER_KICK :
case ViewReasonId : : VREASON_SERVER_SHUTDOWN :
case ViewReasonId : : VREASON_SERVER_STOPPED :
if ( reasonMessage . empty ( ) ) {
logCritical ( this - > getServerId ( ) , " {} ConnectedClient::notifyClientLeftView() => missing reason message for reason id {} " , CLIENT_STR_LOG_PREFIX , reasonId ) ;
reasonMessage = " <undefined> " ;
}
break ;
default :
break ;
}
*/
switch ( reason_id ) {
case ViewReasonId : : VREASON_MOVED :
case ViewReasonId : : VREASON_BAN :
case ViewReasonId : : VREASON_CHANNEL_KICK :
case ViewReasonId : : VREASON_SERVER_KICK :
if ( ! invoker ) {
logCritical ( this - > getServerId ( ) , " {} ConnectedClient::notifyClientLeftView() => missing invoker for reason id {} " , CLIENT_STR_LOG_PREFIX , reason_id ) ;
if ( this - > server )
invoker = this - > server - > serverRoot ;
}
break ;
default :
break ;
}
Command cmd ( " notifyclientleftview " ) ;
cmd [ " reasonmsg " ] = reason_message ;
cmd [ " reasonid " ] = reason_id ;
cmd [ " clid " ] = client - > getClientId ( ) ;
cmd [ " cfid " ] = client - > currentChannel ? client - > currentChannel - > channelId ( ) : 0 ;
cmd [ " ctid " ] = target_channel ? target_channel - > channelId ( ) : 0 ;
if ( invoker ) {
cmd [ " invokerid " ] = invoker - > getClientId ( ) ;
cmd [ " invokername " ] = invoker - > getDisplayName ( ) ;
cmd [ " invokeruid " ] = invoker - > getUid ( ) ;
}
/* TODO: Critical warn if the client hasn't been found? */
this - > visibleClients . erase ( std : : remove_if ( this - > visibleClients . begin ( ) , this - > visibleClients . end ( ) , [ & , client ] ( 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 ) ;
return true ;
}
return c = = client ;
} ) , this - > visibleClients . end ( ) ) ;
this - > sendCommand ( cmd ) ;
return true ;
2019-07-17 19:37:18 +02:00
}
bool ConnectedClient : : 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 ) {
2020-01-24 02:57:58 +01:00
assert ( ! lock_channel_tree ) ; /* not supported yet! */
assert ( client & & client - > getClientId ( ) ! = 0 ) ;
assert ( client - > currentChannel | | & * client = = this ) ;
/* TODO: Critical warn if the client hasn't been found? */
this - > visibleClients . erase ( std : : remove_if ( this - > visibleClients . begin ( ) , this - > visibleClients . end ( ) , [ & , client ] ( 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 ) ;
return true ;
}
return c = = client ;
} ) , this - > visibleClients . end ( ) ) ;
if ( ! invoker ) {
logCritical ( this - > getServerId ( ) , " {} ConnectedClient::notifyClientLeftViewKicked() => missing invoker for reason id {} " , CLIENT_STR_LOG_PREFIX , target_channel ? ViewReasonId : : VREASON_CHANNEL_KICK : ViewReasonId : : VREASON_SERVER_KICK ) ;
if ( this - > server )
invoker = this - > server - > serverRoot ;
}
2019-07-17 19:37:18 +02:00
Command cmd ( " notifyclientleftview " ) ;
cmd [ " clid " ] = client - > getClientId ( ) ;
cmd [ " cfid " ] = client - > currentChannel ? client - > currentChannel - > channelId ( ) : 0 ;
cmd [ " ctid " ] = target_channel ? target_channel - > channelId ( ) : 0 ;
cmd [ " reasonid " ] = ( uint8_t ) ( target_channel ? ViewReasonId : : VREASON_CHANNEL_KICK : ViewReasonId : : VREASON_SERVER_KICK ) ;
cmd [ " reasonmsg " ] = message ;
if ( invoker ) {
cmd [ " invokerid " ] = invoker - > getClientId ( ) ;
cmd [ " invokername " ] = invoker - > getDisplayName ( ) ;
cmd [ " invokeruid " ] = invoker - > getUid ( ) ;
}
this - > sendCommand ( cmd ) ;
return true ;
}
bool ConnectedClient : : notifyClientLeftViewBanned (
2020-01-24 02:57:58 +01:00
const shared_ptr < ConnectedClient > & client ,
const std : : string & message ,
std : : shared_ptr < ConnectedClient > invoker ,
size_t length ,
bool lock_channel_tree ) {
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
assert ( ! lock_channel_tree ) ; /* not supported yet! */
assert ( client & & client - > getClientId ( ) ! = 0 ) ;
assert ( client - > currentChannel | | & * client = = this ) ;
2019-07-17 19:37:18 +02:00
Command cmd ( " notifyclientleftview " ) ;
cmd [ " clid " ] = client - > getClientId ( ) ;
cmd [ " cfid " ] = client - > currentChannel ? client - > currentChannel - > channelId ( ) : 0 ;
cmd [ " ctid " ] = 0 ;
cmd [ " reasonid " ] = ViewReasonId : : VREASON_BAN ;
cmd [ " reasonmsg " ] = message ;
if ( invoker ) {
cmd [ " invokerid " ] = invoker - > getClientId ( ) ;
cmd [ " invokername " ] = invoker - > getDisplayName ( ) ;
cmd [ " invokeruid " ] = invoker - > getUid ( ) ;
}
if ( length > 0 ) {
2020-01-24 02:57:58 +01:00
cmd [ " bantime " ] = length ;
2019-07-17 19:37:18 +02:00
}
2020-01-24 02:57:58 +01:00
/* TODO: Critical warn if the client hasn't been found? */
this - > visibleClients . erase ( std : : remove_if ( this - > visibleClients . begin ( ) , this - > visibleClients . end ( ) , [ & , client ] ( 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 ) ;
return true ;
}
return c = = client ;
} ) , this - > visibleClients . end ( ) ) ;
2019-07-17 19:37:18 +02:00
this - > sendCommand ( cmd ) ;
return true ;
}
bool ConnectedClient : : sendNeededPermissions ( bool enforce ) {
2020-01-24 02:57:58 +01:00
if ( ! enforce & & this - > state ! = ConnectionState : : CONNECTED ) return false ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
if ( ! enforce & & chrono : : system_clock : : now ( ) - this - > lastNeededNotify < chrono : : seconds ( 5 ) & & this - > lastNeededPermissionNotifyChannel = = this - > currentChannel ) { //Dont spam these (hang up ui)
this - > requireNeededPermissionResend = true ;
return true ;
}
this - > lastNeededNotify = chrono : : system_clock : : now ( ) ;
this - > lastNeededPermissionNotifyChannel = this - > currentChannel ;
this - > requireNeededPermissionResend = false ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
return this - > notifyClientNeededPermissions ( ) ;
2019-07-17 19:37:18 +02:00
}
bool ConnectedClient : : notifyClientNeededPermissions ( ) {
Command cmd ( " notifyclientneededpermissions " ) ;
int index = 0 ;
2020-01-24 02:57:58 +01:00
unique_lock cache_lock ( this - > cached_permissions_lock ) ;
auto permissions = this - > cached_permissions ;
cache_lock . unlock ( ) ;
for ( const auto & value : permissions ) {
2020-02-22 14:14:44 +01:00
cmd [ index ] [ " permid " ] = value . first ;
cmd [ index + + ] [ " permvalue " ] = value . second . has_value ? value . second . value : 0 ;
2020-01-24 02:57:58 +01:00
}
2019-07-17 19:37:18 +02:00
2020-03-04 16:31:03 +01:00
if ( index = = 0 ) {
cmd [ index ] [ " permid " ] = permission : : i_client_talk_power ;
cmd [ index + + ] [ " permvalue " ] = 0 ;
}
2019-07-17 19:37:18 +02:00
this - > sendCommand ( cmd ) ;
return true ;
}
2020-07-13 11:13:09 +02:00
inline void write_command_result_error ( ts : : command_builder_bulk bulk , const command_result & result , const std : : string & errorCodeKey ) {
bulk . put_unchecked ( errorCodeKey , ( uint32_t ) result . error_code ( ) ) ;
2020-04-28 18:27:49 +02:00
bulk . put_unchecked ( " msg " , findError ( result . error_code ( ) ) . message ) ;
if ( result . is_permission_error ( ) )
bulk . put_unchecked ( " failed_permid " , ( uint32_t ) result . permission_id ( ) ) ;
}
2020-07-13 11:13:09 +02:00
inline void write_command_result_detailed ( ts : : command_builder_bulk bulk , const command_result & result , const std : : string & errorCodeKey ) {
2020-04-28 18:27:49 +02:00
auto details = result . details ( ) ;
2020-07-13 11:13:09 +02:00
bulk . put_unchecked ( errorCodeKey , ( uint32_t ) details - > error_id ) ;
2020-04-28 18:27:49 +02:00
bulk . put_unchecked ( " msg " , findError ( details - > error_id ) . message ) ;
for ( const auto & extra : details - > extra_properties )
bulk . put ( extra . first , extra . second ) ;
}
2020-01-25 23:42:37 +01:00
bool ConnectedClient : : notifyError ( const command_result & result , const std : : string & retCode ) {
2020-04-28 18:27:49 +02:00
ts : : command_builder command { " error " } ;
2019-07-17 19:37:18 +02:00
2020-07-13 11:13:09 +02:00
this - > writeCommandResult ( command , result ) ;
if ( ! retCode . empty ( ) )
command . put_unchecked ( 0 , " return_code " , retCode ) ;
this - > sendCommand ( command ) ;
return true ;
}
void ConnectedClient : : writeCommandResult ( ts : : command_builder & cmd_builder , const command_result & result , const std : : string & errorCodeKey ) {
2020-07-29 22:53:40 +02:00
result . build_error_response ( cmd_builder , errorCodeKey ) ;
2019-07-17 19:37:18 +02:00
}
inline std : : shared_ptr < ViewEntry > pop_view_entry ( std : : deque < std : : shared_ptr < ViewEntry > > & pool , ChannelId id ) {
for ( auto it = pool . begin ( ) ; it ! = pool . end ( ) ; it + + ) {
if ( ( * it ) - > channelId ( ) = = id ) {
auto handle = * it ;
pool . erase ( it ) ;
return handle ;
}
}
return nullptr ;
}
using ChannelIT = std : : deque < std : : shared_ptr < ViewEntry > > : : iterator ;
inline void send_channels ( ConnectedClient * client , ChannelIT begin , const ChannelIT & end , bool override_orderid ) {
2020-01-24 02:57:58 +01:00
if ( begin = = end )
return ;
2020-01-26 14:21:34 +01:00
ts : : command_builder builder { " channellist " , 512 , 6 } ;
2020-01-24 02:57:58 +01:00
size_t index = 0 ;
while ( begin ! = end ) {
auto channel = ( * begin ) - > channel ( ) ;
2020-01-28 21:01:02 +01:00
if ( ! channel ) {
begin + + ;
continue ;
}
2020-01-24 02:57:58 +01:00
for ( const auto & elm : channel - > properties ( ) . list_properties ( property : : FLAG_CHANNEL_VIEW , client - > getType ( ) = = CLIENT_TEAMSPEAK ? property : : FLAG_NEW : ( uint16_t ) 0 ) ) {
if ( elm . type ( ) = = property : : CHANNEL_ORDER )
2020-01-26 14:21:34 +01:00
builder . put_unchecked ( index , elm . type ( ) . name , override_orderid ? 0 : ( * begin ) - > previous_channel ) ;
2020-01-24 02:57:58 +01:00
else
2020-01-26 14:21:34 +01:00
builder . put_unchecked ( index , elm . type ( ) . name , elm . as < string > ( ) ) ;
2020-01-24 02:57:58 +01:00
}
begin + + ;
2020-01-28 21:01:02 +01:00
if ( + + index > 3 )
2020-01-24 02:57:58 +01:00
break ;
}
2020-01-28 21:01:02 +01:00
2020-04-24 22:04:07 +02:00
client - > sendCommand ( builder ) ;
2020-01-24 02:57:58 +01:00
if ( begin ! = end )
send_channels ( client , begin , end , override_orderid ) ;
2019-07-17 19:37:18 +02:00
}
void ConnectedClient : : sendChannelList ( bool lock_channel_tree ) {
2020-01-24 02:57:58 +01:00
shared_lock server_channel_lock ( this - > server - > channel_tree_lock , defer_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock , defer_lock ) ;
if ( lock_channel_tree ) {
server_channel_lock . lock ( ) ;
client_channel_lock . lock ( ) ;
}
2019-07-17 19:37:18 +02:00
auto channels = this - > channels - > insert_channels ( this - > server - > channelTree - > tree_head ( ) , true , false ) ;
if ( this - > currentChannel ) {
2020-01-24 02:57:58 +01:00
bool send_success ;
for ( const auto & channel : this - > channels - > 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! " ) ;
2019-07-17 19:37:18 +02:00
}
/*
2020-01-24 02:57:58 +01:00
this - > channels - > print ( ) ;
auto channels_left = channels ;
for ( const auto & channel : channels ) {
if ( channel - > previous_channel = = 0 ) continue ;
bool erased = false ;
bool own = true ;
for ( const auto & entry : channels_left ) {
if ( entry - > channelId ( ) = = channel - > channelId ( ) )
own = true ;
if ( entry - > channelId ( ) = = channel - > previous_channel ) {
channels_left . erase ( find ( channels_left . begin ( ) , channels_left . end ( ) , entry ) ) ;
erased = true ;
break ;
}
}
if ( ! erased | | ! own ) {
logCritical ( this - > getServerId ( ) , " Client {} would get an invalid channel order disconnect! Channel {} is not send before his channel! (Flags: erased := {} | own := {}) " , CLIENT_STR_LOG_PREFIX_ ( this ) , channel - > previous_channel , erased , own ) ;
}
}
2019-07-17 19:37:18 +02:00
*/
std : : deque < std : : shared_ptr < ViewEntry > > entry_channels { pop_view_entry ( channels , this - > currentChannel - > channelId ( ) ) } ;
while ( entry_channels . front ( ) ) entry_channels . push_front ( pop_view_entry ( channels , entry_channels . front ( ) - > parentId ( ) ) ) ;
entry_channels . pop_front ( ) ;
2020-01-24 02:57:58 +01:00
if ( entry_channels . empty ( ) )
logCritical ( this - > getServerId ( ) , " ConnectedClient::sendChannelList => invalid (empty) own channel path! " ) ;
2019-07-17 19:37:18 +02:00
2020-01-28 21:01:02 +01:00
send_channels ( this , entry_channels . begin ( ) , entry_channels . end ( ) , false ) ;
2020-01-24 02:57:58 +01:00
this - > notifyClientEnterView ( _this . lock ( ) , nullptr , " " , this - > currentChannel , ViewReasonId : : VREASON_SYSTEM , nullptr , false ) ; //Notify self after path is send
send_channels ( this , channels . begin ( ) , channels . end ( ) , false ) ;
2020-01-27 13:05:16 +01:00
//this->notifyClientEnterView(_this.lock(), nullptr, "", this->currentChannel, ViewReasonId::VREASON_SYSTEM, nullptr, false); //Notify self after path is send
2019-07-17 19:37:18 +02:00
this - > sendCommand ( Command ( " channellistfinished " ) ) ;
}
void ConnectedClient : : sendChannelDescription ( const std : : shared_ptr < BasicChannel > & channel , bool lock ) {
2020-01-24 02:57:58 +01:00
shared_lock tree_lock ( this - > channel_lock , defer_lock ) ;
if ( lock )
tree_lock . lock ( ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
if ( ! this - > channels - > channel_visible ( channel ) ) return ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
auto limit = this - > getType ( ) = = CLIENT_TEAMSPEAK ? 8192 : 131130 ;
2019-11-11 21:37:28 +01:00
2020-01-24 02:57:58 +01:00
auto description = channel - > properties ( ) [ property : : CHANNEL_DESCRIPTION ] . as < std : : string > ( ) ;
Command cmd ( " notifychanneledited " ) ;
2019-07-17 19:37:18 +02:00
cmd [ " cid " ] = channel - > channelId ( ) ;
cmd [ " reasonid " ] = 9 ;
2019-11-11 21:37:28 +01:00
cmd [ " channel_description " ] = description . size ( ) > limit ? description . substr ( 0 , limit ) : description ;
2019-07-17 19:37:18 +02:00
this - > sendCommand ( cmd , true ) ;
}
void ConnectedClient : : tick ( const std : : chrono : : system_clock : : time_point & time ) {
2020-01-24 02:57:58 +01:00
ALARM_TIMER ( A1 , " ConnectedClient::tick " , milliseconds ( 2 ) ) ;
if ( this - > state = = ConnectionState : : CONNECTED ) {
if ( this - > requireNeededPermissionResend )
this - > sendNeededPermissions ( false ) ;
if ( this - > lastOnlineTimestamp . time_since_epoch ( ) . count ( ) = = 0 ) {
this - > lastOnlineTimestamp = time ;
} else if ( time - this - > lastOnlineTimestamp > seconds ( 120 ) ) {
this - > properties ( ) [ property : : CLIENT_MONTH_ONLINE_TIME ] + = duration_cast < seconds > ( time - lastOnlineTimestamp ) . count ( ) ;
2019-07-17 19:37:18 +02:00
this - > properties ( ) [ property : : CLIENT_TOTAL_ONLINE_TIME ] + = duration_cast < seconds > ( time - lastOnlineTimestamp ) . count ( ) ;
lastOnlineTimestamp = time ;
2020-01-24 02:57:58 +01:00
}
if ( time - this - > lastTransfareTimestamp > seconds ( 5 ) ) {
lastTransfareTimestamp = time ;
auto update = this - > connectionStatistics - > mark_file_bytes ( ) ;
if ( update . first > 0 ) {
this - > properties ( ) [ property : : CLIENT_MONTH_BYTES_DOWNLOADED ] + = update . first ;
this - > properties ( ) [ property : : CLIENT_TOTAL_BYTES_DOWNLOADED ] + = update . first ;
}
if ( update . second > 0 ) {
this - > properties ( ) [ property : : CLIENT_MONTH_BYTES_UPLOADED ] + = update . second ;
this - > properties ( ) [ property : : CLIENT_TOTAL_BYTES_UPLOADED ] + = update . second ;
}
}
}
2020-04-08 13:01:41 +02:00
this - > connectionStatistics - > tick ( ) ;
2019-07-17 19:37:18 +02:00
}
void ConnectedClient : : sendServerInit ( ) {
Command command ( " initserver " ) ;
for ( const auto & prop : this - > server - > properties ( ) . list_properties ( property : : FLAG_SERVER_VIEW , this - > getType ( ) = = CLIENT_TEAMSPEAK ? property : : FLAG_NEW : ( uint16_t ) 0 ) ) {
2020-04-08 13:01:41 +02:00
command [ std : : string { prop . type ( ) . name } ] = prop . value ( ) ;
2019-07-17 19:37:18 +02:00
}
2020-01-24 02:57:58 +01:00
command [ " virtualserver_maxclients " ] = 32 ;
2019-07-17 19:37:18 +02:00
//Server stuff
command [ " client_talk_power " ] = this - > properties ( ) [ property : : CLIENT_TALK_POWER ] . as < string > ( ) ;
command [ " client_needed_serverquery_view_power " ] = this - > properties ( ) [ property : : CLIENT_NEEDED_SERVERQUERY_VIEW_POWER ] . as < string > ( ) ;
2020-01-24 02:57:58 +01:00
command [ " client_myteamspeak_id " ] = this - > properties ( ) [ property : : CLIENT_MYTEAMSPEAK_ID ] . as < string > ( ) ;
command [ " client_integrations " ] = this - > properties ( ) [ property : : CLIENT_INTEGRATIONS ] . as < string > ( ) ;
2019-07-17 19:37:18 +02:00
if ( ts : : config : : server : : DefaultServerLicense = = LicenseType : : LICENSE_AUTOMATIC_INSTANCE ) {
if ( serverInstance - > getVoiceServerManager ( ) - > usedSlots ( ) < = 32 )
command [ " lt " ] = LicenseType : : LICENSE_NONE ;
else if ( serverInstance - > getVoiceServerManager ( ) - > usedSlots ( ) < = 512 )
command [ " lt " ] = LicenseType : : LICENSE_NPL ;
else
command [ " lt " ] = LicenseType : : LICENSE_HOSTING ;
} else if ( ts : : config : : server : : DefaultServerLicense = = LicenseType : : LICENSE_AUTOMATIC_SERVER ) {
if ( this - > server - > properties ( ) [ property : : VIRTUALSERVER_MAXCLIENTS ] . as < size_t > ( ) < = 32 )
command [ " lt " ] = LicenseType : : LICENSE_NONE ;
else if ( this - > server - > properties ( ) [ property : : VIRTUALSERVER_MAXCLIENTS ] . as < size_t > ( ) < = 512 )
command [ " lt " ] = LicenseType : : LICENSE_NPL ;
else
command [ " lt " ] = LicenseType : : LICENSE_HOSTING ;
2019-10-20 12:09:28 +02:00
} else {
2020-01-24 02:57:58 +01:00
command [ " lt " ] = ts : : config : : server : : DefaultServerLicense ;
2019-10-20 12:09:28 +02:00
}
2020-01-24 02:57:58 +01:00
command [ " pv " ] = 6 ; //Protocol version
2019-07-17 19:37:18 +02:00
command [ " acn " ] = this - > getDisplayName ( ) ;
command [ " aclid " ] = this - > getClientId ( ) ;
2020-04-24 22:04:07 +02:00
this - > sendCommand ( command ) ;
2019-07-17 19:37:18 +02:00
}
bool ConnectedClient : : handleCommandFull ( Command & cmd , bool disconnectOnFail ) {
2020-01-24 02:57:58 +01:00
system_clock : : time_point start , end ;
start = system_clock : : now ( ) ;
2019-07-17 19:37:18 +02:00
# ifdef PKT_LOG_CMD
2019-10-14 16:30:34 +02:00
logTrace ( this - > getServerId ( ) = = 0 ? LOG_QUERY : this - > getServerId ( ) , " {}[Command][Client -> Server] Processing command: {} " , CLIENT_STR_LOG_PREFIX , cmd . build ( false ) ) ;
2019-07-17 19:37:18 +02:00
# endif
2020-01-25 23:42:37 +01:00
command_result result ;
2019-07-17 19:37:18 +02:00
try {
2020-05-07 21:28:15 +02:00
result . reset ( this - > handleCommand ( cmd ) ) ;
2020-07-31 17:35:14 +02:00
} catch ( command_value_cast_failed & ex ) {
auto message = ex . key ( ) + " at " + std : : to_string ( ex . index ( ) ) + " could not be casted to " + ex . target_type ( ) . name ( ) ;
if ( disconnectOnFail ) {
this - > disconnect ( message ) ;
return false ;
} else {
result . reset ( command_result { error : : parameter_convert , message } ) ;
}
} catch ( command_bulk_index_out_of_bounds_exception & ex ) {
auto message = " missing bulk for index " + std : : to_string ( ex . index ( ) ) ;
if ( disconnectOnFail ) {
this - > disconnect ( message ) ;
return false ;
} else {
result . reset ( command_result { error : : parameter_invalid_count , message } ) ;
}
} catch ( command_value_missing_exception & ex ) {
auto message = " missing value for " + ex . key ( ) + ( ex . bulk_index ( ) = = std : : string : : npos ? " " : " at " + std : : to_string ( ex . bulk_index ( ) ) ) ;
if ( disconnectOnFail ) {
this - > disconnect ( message ) ;
return false ;
} else {
result . reset ( command_result { error : : parameter_missing , message } ) ;
}
2019-07-17 19:37:18 +02:00
} catch ( invalid_argument & ex ) {
2020-01-25 23:42:37 +01:00
logWarning ( this - > getServerId ( ) , " {}[Command] Failed to handle command. Received invalid argument exception: {} " , CLIENT_STR_LOG_PREFIX , ex . what ( ) ) ;
2019-07-17 19:37:18 +02:00
if ( disconnectOnFail ) {
2020-01-24 02:57:58 +01:00
this - > disconnect ( " Invalid argument ( " + string ( ex . what ( ) ) + " ) " ) ;
2019-07-17 19:37:18 +02:00
return false ;
} else {
2020-05-07 21:28:15 +02:00
result . reset ( command_result { error : : parameter_convert , ex . what ( ) } ) ;
2019-07-17 19:37:18 +02:00
}
} catch ( exception & ex ) {
2020-01-25 23:42:37 +01:00
logWarning ( this - > getServerId ( ) , " {}[Command] Failed to handle command. Received exception with message: {} " , CLIENT_STR_LOG_PREFIX , ex . what ( ) ) ;
2019-07-17 19:37:18 +02:00
if ( disconnectOnFail ) {
this - > disconnect ( " Error while command handling ( " + string ( ex . what ( ) ) + " )! " ) ;
return false ;
} else {
2020-05-07 21:28:15 +02:00
result . reset ( command_result { error : : vs_critical } ) ;
2019-07-17 19:37:18 +02:00
}
} catch ( . . . ) {
2020-01-24 02:57:58 +01:00
this - > disconnect ( " Error while command handling! (unknown) " ) ;
return false ;
2019-07-17 19:37:18 +02:00
}
2020-01-25 23:42:37 +01:00
2019-07-17 19:37:18 +02:00
bool generateReturnStatus = false ;
2020-04-28 18:27:49 +02:00
if ( result . has_error ( ) | | this - > getType ( ) = = ClientType : : CLIENT_QUERY ) {
2019-07-17 19:37:18 +02:00
generateReturnStatus = true ;
} else if ( cmd [ " return_code " ] . size ( ) > 0 ) {
generateReturnStatus = ! cmd [ " return_code " ] . string ( ) . empty ( ) ;
}
if ( generateReturnStatus )
this - > notifyError ( result , cmd [ " return_code " ] . size ( ) > 0 ? cmd [ " return_code " ] . first ( ) . as < std : : string > ( ) : " " ) ;
2020-04-28 18:27:49 +02:00
if ( result . has_error ( ) & & this - > state = = ConnectionState : : INIT_HIGH )
2020-02-01 14:32:16 +01:00
this - > close_connection ( system_clock : : now ( ) ) ; //Disconnect now
2019-07-17 19:37:18 +02:00
for ( const auto & handler : postCommandHandler )
handler ( ) ;
2020-01-25 23:42:37 +01:00
2019-07-17 19:37:18 +02:00
postCommandHandler . clear ( ) ;
end = system_clock : : now ( ) ;
if ( end - start > milliseconds ( 10 ) ) {
2020-01-24 02:57:58 +01:00
if ( end - start > milliseconds ( 100 ) )
logError ( this - > getServerId ( ) , " Command handling of command {} needs {}ms. This could be an issue! " , cmd . command ( ) , duration_cast < milliseconds > ( end - start ) . count ( ) ) ;
else
logWarning ( this - > getServerId ( ) , " Command handling of command {} needs {}ms. " , cmd . command ( ) , duration_cast < milliseconds > ( end - start ) . count ( ) ) ;
2019-07-17 19:37:18 +02:00
}
2020-04-28 18:27:49 +02:00
result . release_data ( ) ;
2019-07-17 19:37:18 +02:00
return true ;
}
std : : shared_ptr < BanRecord > ConnectedClient : : resolveActiveBan ( const std : : string & ip_address ) {
2020-01-26 14:21:34 +01:00
if ( permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_ignore_bans , 0 ) ) ) return nullptr ;
2020-01-24 02:57:58 +01:00
//Check if manager banned
auto banManager = serverInstance - > banManager ( ) ;
shared_ptr < BanRecord > banEntry = nullptr ;
deque < shared_ptr < BanRecord > > entries ;
if ( ! banEntry ) {
banEntry = banManager - > findBanByName ( this - > server - > getServerId ( ) , this - > getDisplayName ( ) ) ;
if ( banEntry )
debugMessage ( this - > getServerId ( ) , " {} Resolved name ban ({}). Record id {}, server id {} " ,
CLIENT_STR_LOG_PREFIX ,
this - > getDisplayName ( ) ,
banEntry - > banId ,
banEntry - > serverId ) ;
}
if ( ! banEntry ) {
banEntry = banManager - > findBanByUid ( this - > server - > getServerId ( ) , this - > getUid ( ) ) ;
if ( banEntry )
debugMessage ( this - > getServerId ( ) , " {} Resolved uuid ban ({}). Record id {}, server id {} " ,
CLIENT_STR_LOG_PREFIX ,
this - > getUid ( ) ,
banEntry - > banId ,
banEntry - > serverId ) ;
}
if ( ! banEntry & & ! ip_address . empty ( ) ) {
banEntry = banManager - > findBanByIp ( this - > server - > getServerId ( ) , ip_address ) ;
if ( banEntry )
debugMessage ( this - > getServerId ( ) , " {} Resolved ip ban ({}). Record id {}, server id {} " ,
CLIENT_STR_LOG_PREFIX ,
ip_address ,
banEntry - > banId ,
banEntry - > serverId ) ;
}
auto vclient = dynamic_cast < VoiceClient * > ( this ) ;
if ( vclient )
if ( ! banEntry ) {
banEntry = banManager - > findBanByHwid ( this - > server - > getServerId ( ) , vclient - > getHardwareId ( ) ) ;
if ( banEntry )
debugMessage ( this - > getServerId ( ) , " {} Resolved hwid ban ({}). Record id {}, server id {} " ,
CLIENT_STR_LOG_PREFIX ,
vclient - > getHardwareId ( ) ,
banEntry - > banId ,
banEntry - > serverId ) ;
}
return banEntry ;
2019-07-17 19:37:18 +02:00
}
bool ConnectedClient : : update_cached_permissions ( ) {
2020-01-26 14:21:34 +01:00
auto values = this - > calculate_permissions ( permission : : neededPermissions , this - > currentChannel ? this - > currentChannel - > channelId ( ) : 0 ) ; /* copy the channel here so it does not change */
2020-01-24 02:57:58 +01:00
auto updated = false ;
{
lock_guard cached_lock ( this - > cached_permissions_lock ) ;
2020-01-26 14:21:34 +01:00
auto old_cached_permissions { this - > cached_permissions } ;
this - > cached_permissions = values ;
std : : sort ( this - > cached_permissions . begin ( ) , this - > cached_permissions . end ( ) , [ ] ( const auto & a , const auto & b ) { return a . first < b . first ; } ) ;
if ( this - > cached_permissions . size ( ) ! = old_cached_permissions . size ( ) )
updated = true ;
else {
for ( auto oit = old_cached_permissions . begin ( ) , nit = this - > cached_permissions . begin ( ) ; oit ! = old_cached_permissions . end ( ) ; oit + + , nit + + ) {
if ( oit - > first ! = nit - > first | | oit - > second ! = nit - > second ) {
updated = true ;
break ;
}
2020-01-24 02:57:58 +01:00
}
}
2020-01-26 14:21:34 +01:00
}
2020-01-24 02:57:58 +01:00
2020-01-26 14:21:34 +01:00
this - > cpmerission_whisper_power = { 0 , false } ;
this - > cpmerission_needed_whisper_power = { 0 , false } ;
for ( const auto & entry : values ) {
if ( entry . first = = permission : : i_client_whisper_power )
this - > cpmerission_whisper_power = entry . second ;
2020-02-01 14:32:16 +01:00
else if ( entry . first = = permission : : i_client_needed_whisper_power )
2020-01-26 14:21:34 +01:00
this - > cpmerission_needed_whisper_power = entry . second ;
2020-01-24 02:57:58 +01:00
}
return updated ;
2019-07-17 19:37:18 +02:00
}
void ConnectedClient : : sendTSPermEditorWarning ( ) {
2020-01-24 02:57:58 +01:00
if ( config : : voice : : warn_on_permission_editor ) {
if ( system_clock : : now ( ) - this - > command_times . servergrouplist > milliseconds ( 1000 ) ) return ;
if ( system_clock : : now ( ) - this - > command_times . channelgrouplist > milliseconds ( 1000 ) ) return ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
this - > command_times . last_notify = system_clock : : now ( ) ;
this - > notifyClientPoke ( this - > server - > serverRoot , config : : messages : : teamspeak_permission_editor ) ;
}
2019-07-17 19:37:18 +02:00
}
2020-01-26 14:21:34 +01:00
# define RESULT(perm_) \
2019-07-23 10:37:56 +02:00
do { \
2020-01-24 02:57:58 +01:00
ventry - > join_state_id = this - > join_state_id ; \
2020-01-26 14:21:34 +01:00
ventry - > join_permission_error = ( perm_ ) ; \
return perm_ ; \
2019-07-23 10:37:56 +02:00
} while ( 0 )
2020-01-26 14:21:34 +01:00
permission : : PermissionType ConnectedClient : : calculate_and_get_join_state ( const std : : shared_ptr < BasicChannel > & channel ) {
2020-01-24 02:57:58 +01:00
shared_ptr < ViewEntry > ventry ;
{
shared_lock view_lock ( this - > channel_lock ) ;
ventry = this - > channel_view ( ) - > find_channel ( channel ) ;
if ( ! ventry )
2020-01-26 14:21:34 +01:00
return permission : : i_channel_view_power ;
2020-01-24 02:57:58 +01:00
}
if ( ventry - > join_state_id = = this - > join_state_id )
2020-01-26 14:21:34 +01:00
return ventry - > join_permission_error ;
2020-01-24 02:57:58 +01:00
2020-01-26 14:21:34 +01:00
auto channel_id = channel - > channelId ( ) ;
2020-01-24 02:57:58 +01:00
auto permission_cache = make_shared < CalculateCache > ( ) ;
switch ( channel - > channelType ( ) ) {
case ChannelType : : permanent :
2020-01-26 14:21:34 +01:00
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_join_permanent , channel_id ) ) )
RESULT ( permission : : b_channel_join_permanent ) ;
2020-01-24 02:57:58 +01:00
break ;
case ChannelType : : semipermanent :
2020-01-26 14:21:34 +01:00
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_join_semi_permanent , channel_id ) ) )
RESULT ( permission : : b_channel_join_semi_permanent ) ;
2020-01-24 02:57:58 +01:00
break ;
case ChannelType : : temporary :
2020-01-26 14:21:34 +01:00
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_join_temporary , channel_id ) ) )
RESULT ( permission : : b_channel_join_temporary ) ;
2020-01-24 02:57:58 +01:00
break ;
}
2020-01-26 14:21:34 +01:00
if ( ! channel - > permission_granted ( permission : : i_channel_needed_join_power , this - > calculate_permission ( permission : : i_channel_join_power , channel_id ) , false ) ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_ignore_join_power , channel_id ) ) )
RESULT ( permission : : i_channel_join_power ) ;
2020-01-24 02:57:58 +01:00
}
2020-01-26 14:21:34 +01:00
if ( permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_is_sticky , this - > currentChannel ? this - > currentChannel - > channelId ( ) : 0 ) ) )
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_ignore_sticky , channel_id ) ) )
RESULT ( permission : : b_client_is_sticky ) ;
2020-02-16 19:02:06 +01:00
RESULT ( permission : : ok ) ;
2019-07-17 19:37:18 +02:00
}