2019-07-17 19:37:18 +02:00
# include <cstring>
# include <functional>
# include <protocol/buffers.h>
# include <openssl/sha.h>
# include <netinet/in.h>
# include <bitset>
# include <tomcrypt.h>
# include <log/LogUtils.h>
# include <misc/digest.h>
# include <misc/base64.h>
2020-05-13 11:32:08 +02:00
# include <files/FileServer.h>
2019-07-21 10:43:26 +02:00
# include "./client/web/WebClient.h"
# include "./client/voice/VoiceClient.h"
# include "./client/InternalClient.h"
# include "./client/music/MusicClient.h"
2020-03-01 10:28:29 +01:00
# include "./client/query/QueryClient.h"
2019-07-17 19:37:18 +02:00
# include "music/MusicBotManager.h"
# include "server/VoiceServer.h"
# include "server/QueryServer.h"
# include "InstanceHandler.h"
# include "Configuration.h"
2020-01-26 18:04:38 +01:00
# include "VirtualServer.h"
2020-11-07 13:17:51 +01:00
# include "./rtc/lib.h"
2019-07-19 22:55:03 +02:00
# include "src/manager/ConversationManager.h"
2019-07-17 19:37:18 +02:00
# include <misc/sassert.h>
2020-09-15 01:18:35 +02:00
# include <src/manager/ActionLogger.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 : : protocol ;
using namespace ts : : buffer ;
# define ECC_TYPE_INDEX 5
# ifndef BUILD_VERSION
# define BUILD_VERSION "Unknown build"
# endif
2020-01-26 18:04:38 +01:00
VirtualServer : : VirtualServer ( uint16_t serverId , sql : : SqlManager * database ) : serverId ( serverId ) , sql ( database ) {
memtrack : : allocated < VirtualServer > ( this ) ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
bool VirtualServer : : initialize ( bool test_properties ) {
2020-01-24 02:57:58 +01:00
assert ( self . lock ( ) ) ;
2020-11-07 13:17:51 +01:00
this - > rtc_server_ = std : : make_unique < rtc : : Server > ( ) ;
2020-01-24 02:57:58 +01:00
this - > _properties = serverInstance - > databaseHelper ( ) - > loadServerProperties ( self . lock ( ) ) ;
this - > _properties - > registerNotifyHandler ( [ & ] ( Property & prop ) {
if ( prop . type ( ) = = property : : VIRTUALSERVER_DISABLE_IP_SAVING ) {
this - > _disable_ip_saving = prop . as < bool > ( ) ;
return ;
2020-05-13 11:32:08 +02:00
} else if ( prop . type ( ) = = property : : VIRTUALSERVER_CODEC_ENCRYPTION_MODE ) {
2020-01-24 02:57:58 +01:00
this - > _voice_encryption_mode = prop . as < int > ( ) ;
return ;
2020-05-13 11:32:08 +02:00
} else if ( prop . type ( ) = = property : : VIRTUALSERVER_MAX_UPLOAD_TOTAL_BANDWIDTH ) {
auto file_vs = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! file_vs ) return ;
file_vs - > max_networking_upload_bandwidth ( prop . as_save < int64_t > ( [ ] { return - 1 ; } ) ) ;
} else if ( prop . type ( ) = = property : : VIRTUALSERVER_MAX_DOWNLOAD_TOTAL_BANDWIDTH ) {
auto file_vs = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! file_vs ) return ;
file_vs - > max_networking_download_bandwidth ( prop . as_save < int64_t > ( [ ] { return - 1 ; } ) ) ;
2020-01-24 02:57:58 +01:00
}
2020-04-28 18:27:49 +02:00
std : : string sql { } ;
2020-01-24 02:57:58 +01:00
if ( prop . type ( ) = = property : : VIRTUALSERVER_HOST )
sql = " UPDATE `servers` SET `host` = :value WHERE `serverId` = :sid " ;
else if ( prop . type ( ) = = property : : VIRTUALSERVER_PORT )
sql = " UPDATE `servers` SET `port` = :value WHERE `serverId` = :sid " ;
if ( sql . empty ( ) ) return ;
sql : : command ( this - > sql , sql , variable { " :sid " , this - > getServerId ( ) } , variable { " :value " , prop . value ( ) } )
. executeLater ( ) . waitAndGetLater ( LOG_SQL_CMD , sql : : result { 1 , " future failed " } ) ;
} ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_PLATFORM ] = config : : server : : DefaultServerPlatform ;
this - > properties ( ) [ property : : VIRTUALSERVER_VERSION ] = config : : server : : DefaultServerVersion ;
this - > properties ( ) [ property : : VIRTUALSERVER_ID ] = serverId ;
this - > _disable_ip_saving = this - > properties ( ) [ property : : VIRTUALSERVER_DISABLE_IP_SAVING ] ;
2020-09-15 01:18:35 +02:00
/* initialize logging */
{
auto server_id = this - > serverId ;
auto sync_property = [ server_id ] ( Property & prop ) {
log : : LoggerGroup action_type ;
switch ( prop . type ( ) . property_index ) {
case property : : VIRTUALSERVER_LOG_SERVER :
action_type = log : : LoggerGroup : : SERVER ;
break ;
case property : : VIRTUALSERVER_LOG_CHANNEL :
action_type = log : : LoggerGroup : : CHANNEL ;
break ;
case property : : VIRTUALSERVER_LOG_CLIENT :
action_type = log : : LoggerGroup : : CLIENT ;
break ;
case property : : VIRTUALSERVER_LOG_FILETRANSFER :
action_type = log : : LoggerGroup : : FILES ;
break ;
case property : : VIRTUALSERVER_LOG_PERMISSIONS :
action_type = log : : LoggerGroup : : PERMISSION ;
break ;
case property : : VIRTUALSERVER_LOG_QUERY :
action_type = log : : LoggerGroup : : QUERY ;
break ;
default :
return ;
}
serverInstance - > action_logger ( ) - > toggle_logging_group ( server_id , action_type , prop . as_save < bool > ( [ ] { return true ; } ) ) ;
} ;
for ( const property : : VirtualServerProperties & property : {
property : : VIRTUALSERVER_LOG_SERVER ,
property : : VIRTUALSERVER_LOG_CHANNEL ,
property : : VIRTUALSERVER_LOG_CLIENT ,
property : : VIRTUALSERVER_LOG_FILETRANSFER ,
property : : VIRTUALSERVER_LOG_QUERY ,
property : : VIRTUALSERVER_LOG_PERMISSIONS
} ) {
auto prop = this - > _properties - > find ( property : : PROP_TYPE_SERVER , property ) ;
sync_property ( prop ) ;
}
this - > _properties - > registerNotifyHandler ( [ sync_property ] ( Property & prop ) {
sync_property ( prop ) ;
} ) ;
}
2020-01-24 02:57:58 +01:00
if ( ! properties ( ) [ property : : VIRTUALSERVER_KEYPAIR ] . as < std : : string > ( ) . empty ( ) ) {
debugMessage ( this - > serverId , " Importing server keypair " ) ;
this - > _serverKey = new ecc_key ;
auto bytes = base64 : : decode ( properties ( ) [ property : : VIRTUALSERVER_KEYPAIR ] . as < std : : string > ( ) ) ;
int err ;
if ( ( err = ecc_import ( reinterpret_cast < const unsigned char * > ( bytes . data ( ) ) , bytes . length ( ) , this - > _serverKey ) ) ! = CRYPT_OK ) {
logError ( this - > getServerId ( ) , " Cant import key. ({} => {}) " , err , error_to_string ( err ) ) ;
logError ( this - > serverId , " Could not import server keypair! {} ({}). Generating new one! " , err , error_to_string ( err ) ) ;
delete this - > _serverKey ;
this - > _serverKey = nullptr ;
properties ( ) [ property : : VIRTUALSERVER_KEYPAIR ] = " " ;
}
}
int err ;
if ( ! _serverKey ) {
debugMessage ( this - > serverId , " Generating new server keypair " ) ;
this - > _serverKey = new ecc_key ;
prng_state state { } ;
if ( ( err = ecc_make_key_ex ( & state , find_prng ( " sprng " ) , this - > _serverKey , & ltc_ecc_sets [ ECC_TYPE_INDEX ] ) ) ! = CRYPT_OK ) {
logError ( this - > serverId , " Could not generate a server keypair! {} ({}) " , err , error_to_string ( err ) ) ;
delete this - > _serverKey ;
this - > _serverKey = nullptr ;
return false ;
}
size_t bytesBufferLength = 1024 ;
char bytesBuffer [ bytesBufferLength ] ;
if ( ( err = ecc_export ( reinterpret_cast < unsigned char * > ( bytesBuffer ) , & bytesBufferLength , PK_PRIVATE , this - > _serverKey ) ) ! = CRYPT_OK ) {
logError ( this - > serverId , " Could not export the server keypair (private)! {} ({}) " , err , error_to_string ( err ) ) ;
delete this - > _serverKey ;
this - > _serverKey = nullptr ;
return false ;
}
properties ( ) [ property : : VIRTUALSERVER_KEYPAIR ] = base64_encode ( bytesBuffer , bytesBufferLength ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_CREATED ] = duration_cast < seconds > ( system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
}
if ( _serverKey ) {
size_t bufferLength = 265 ;
char buffer [ bufferLength ] ;
if ( ( err = ecc_export ( reinterpret_cast < unsigned char * > ( buffer ) , & bufferLength , PK_PUBLIC , this - > _serverKey ) ) ! = CRYPT_OK )
logError ( this - > serverId , " Could not generate server uid! (Could not export the server keypair (public)! {} ({})) " , err , error_to_string ( err ) ) ;
properties ( ) [ property : : VIRTUALSERVER_UNIQUE_IDENTIFIER ] = base64 : : encode ( digest : : sha1 ( base64 : : encode ( buffer , bufferLength ) ) ) ;
}
2020-11-07 13:17:51 +01:00
this - > conversation_manager_ = make_shared < conversation : : ConversationManager > ( this - > ref ( ) ) ;
this - > conversation_manager_ - > initialize ( this - > conversation_manager_ ) ;
2020-01-24 02:57:58 +01:00
channelTree = new ServerChannelTree ( self . lock ( ) , this - > sql ) ;
channelTree - > loadChannelsFromDatabase ( ) ;
this - > groups = new GroupManager ( self . lock ( ) , this - > sql , serverInstance - > getGroupManager ( ) ) ;
if ( ! this - > groups - > loadGroupFormDatabase ( ) ) { //TODO exception etc
logCritical ( this - > serverId , " Cant setup group manager! " ) ;
return false ;
}
2020-05-13 11:51:01 +02:00
channelTree - > deleteSemiPermanentChannels ( ) ;
2020-07-13 11:13:09 +02:00
if ( channelTree - > channel_count ( ) = = 0 ) {
2020-01-24 02:57:58 +01:00
logMessage ( this - > serverId , " Creating new channel tree (Copy from server 0) " ) ;
LOG_SQL_CMD ( sql : : command ( this - > getSql ( ) , " INSERT INTO `channels` (`serverId`, `channelId`, `type`, `parentId`) SELECT :serverId AS `serverId`, `channelId`, `type`, `parentId` FROM `channels` WHERE `serverId` = 0 " , variable { " :serverId " , this - > serverId } ) . execute ( ) ) ;
LOG_SQL_CMD ( sql : : command ( this - > getSql ( ) , " INSERT INTO `properties` (`serverId`, `type`, `id`, `key`, `value`) SELECT :serverId AS `serverId`, `type`, `id`, `key`, `value` FROM `properties` WHERE `serverId` = 0 AND `type` = :type " ,
variable { " :serverId " , this - > serverId } , variable { " :type " , property : : PROP_TYPE_CHANNEL } ) . execute ( ) ) ;
LOG_SQL_CMD ( sql : : command ( this - > getSql ( ) , " INSERT INTO `permissions` (`serverId`, `type`, `id`, `channelId`, `permId`, `value`, `grant`, `flag_skip`, `flag_negate`) "
" SELECT :serverId AS `serverId`, `type`, `id`, `channelId`, `permId`, `value`, `grant`, `flag_skip`, `flag_negate` FROM `permissions` WHERE `serverId` = 0 AND `type` = :type " ,
variable { " :serverId " , this - > serverId } , variable { " :type " , permission : : SQL_PERM_CHANNEL } ) . execute ( ) ) ;
channelTree - > loadChannelsFromDatabase ( ) ;
if ( channelTree - > channel_count ( ) = = 0 ) {
logCritical ( this - > serverId , " Failed to setup channel tree! " ) ;
2020-04-28 18:27:49 +02:00
return false ;
2020-01-24 02:57:58 +01:00
}
if ( ! channelTree - > getDefaultChannel ( ) ) {
logError ( this - > serverId , " Missing default channel! Using first one! " ) ;
channelTree - > setDefaultChannel ( channelTree - > channels ( ) . front ( ) ) ;
}
}
if ( ! channelTree - > getDefaultChannel ( ) ) channelTree - > setDefaultChannel ( * channelTree - > channels ( ) . begin ( ) ) ;
auto default_channel = channelTree - > getDefaultChannel ( ) ;
assert ( default_channel ) ;
if ( default_channel - > properties ( ) [ property : : CHANNEL_FLAG_PASSWORD ] . as < bool > ( ) )
default_channel - > properties ( ) [ property : : CHANNEL_FLAG_PASSWORD ] = false ;
2021-02-25 11:13:30 +01:00
this - > tokenManager = new token : : TokenManager ( this - > sql , this - > getServerId ( ) ) ;
this - > tokenManager - > initialize_cache ( ) ;
2020-01-24 02:57:58 +01:00
this - > complains = new ComplainManager ( this ) ;
if ( ! this - > complains - > loadComplains ( ) ) logError ( this - > serverId , " Could not load complains " ) ;
//Setup new server if needed
if ( this - > groups - > availableServerGroups ( false ) . empty ( ) | | this - > groups - > availableChannelGroups ( false ) . empty ( ) ) {
if ( ! this - > properties ( ) [ property : : VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY ] . as < string > ( ) . empty ( ) ) {
logCritical ( this - > getServerId ( ) , " Missing default groups. Applying permission reset! " ) ;
}
string token ;
if ( ! this - > resetPermissions ( token ) )
logCritical ( this - > serverId , " Failed to reset server permissions! This could be fatal! " ) ;
logMessageFmt ( true , this - > serverId , " ---------------------- Token ---------------------- " ) ;
logMessageFmt ( true , this - > serverId , " {:^51} " , " The server's serveradmin token: " ) ;
logMessageFmt ( true , this - > serverId , " {:^51} " , token ) ;
logMessageFmt ( true , this - > serverId , " " ) ;
logMessageFmt ( true , this - > serverId , " {:^51} " , " Note: This token could be used just once! " ) ;
logMessageFmt ( true , this - > serverId , " ---------------------- Token ---------------------- " ) ;
}
if ( test_properties )
this - > ensureValidDefaultGroups ( ) ;
letters = new letter : : LetterManager ( this ) ;
2020-11-07 13:17:51 +01:00
server_statistics_ = make_shared < stats : : ConnectionStatistics > ( serverInstance - > getStatistics ( ) ) ;
2020-01-24 02:57:58 +01:00
this - > serverRoot = std : : make_shared < InternalClient > ( this - > sql , self . lock ( ) , this - > properties ( ) [ property : : VIRTUALSERVER_NAME ] . as < string > ( ) , false ) ;
2021-02-21 20:28:59 +01:00
this - > serverRoot - > initialize_weak_reference ( this - > serverRoot ) ;
2020-01-24 02:57:58 +01:00
this - > properties ( ) . registerNotifyHandler ( [ & ] ( Property & property ) {
if ( property . type ( ) = = property : : VIRTUALSERVER_NAME ) static_pointer_cast < InternalClient > ( this - > serverRoot ) - > properties ( ) [ property : : CLIENT_NICKNAME ] = property . as < string > ( ) ;
} ) ;
this - > serverRoot - > server = nullptr ;
this - > serverAdmin = std : : make_shared < InternalClient > ( this - > sql , self . lock ( ) , " serveradmin " , true ) ;
2021-02-21 20:28:59 +01:00
this - > serverAdmin - > initialize_weak_reference ( this - > serverAdmin ) ;
2020-01-24 02:57:58 +01:00
DatabaseHelper : : assignDatabaseId ( this - > sql , this - > serverId , this - > serverAdmin ) ;
this - > serverAdmin - > server = nullptr ;
this - > registerInternalClient ( this - > serverAdmin ) ; /* lets assign server id 0 */
2020-05-13 11:32:08 +02:00
{
using ErrorType = file : : filesystem : : ServerCommandErrorType ;
auto file_vs = file : : server ( ) - > register_server ( this - > getServerId ( ) ) ;
auto initialize_result = file : : server ( ) - > file_system ( ) . initialize_server ( file_vs ) ;
if ( ! initialize_result - > wait_for ( std : : chrono : : seconds { 5 } ) ) {
logError ( this - > getServerId ( ) , " Failed to wait for file directory initialisation. " ) ;
} else if ( ! initialize_result - > succeeded ( ) ) {
switch ( initialize_result - > error ( ) . error_type ) {
case ErrorType : : FAILED_TO_CREATE_DIRECTORIES :
logError ( this - > getServerId ( ) , " Failed to create server file directories ({}). " , initialize_result - > error ( ) . error_message ) ;
break ;
case ErrorType : : UNKNOWN :
case ErrorType : : FAILED_TO_DELETE_DIRECTORIES :
logError ( this - > getServerId ( ) , " Failed to initialize server file directory due to an unknown error: {}/{} " ,
( int ) initialize_result - > error ( ) . error_type , initialize_result - > error ( ) . error_message ) ;
break ;
}
}
this - > properties ( ) [ property : : VIRTUALSERVER_FILEBASE ] = file : : server ( ) - > file_base_path ( ) ;
file_vs - > max_networking_download_bandwidth ( this - > properties ( ) [ property : : VIRTUALSERVER_MAX_DOWNLOAD_TOTAL_BANDWIDTH ] . as_save < int64_t > ( [ ] { return - 1 ; } ) ) ;
file_vs - > max_networking_upload_bandwidth ( this - > properties ( ) [ property : : VIRTUALSERVER_MAX_UPLOAD_TOTAL_BANDWIDTH ] . as_save < int64_t > ( [ ] { return - 1 ; } ) ) ;
}
2020-01-24 02:57:58 +01:00
this - > channelTree - > printChannelTree ( [ & ] ( std : : string msg ) { debugMessage ( this - > serverId , msg ) ; } ) ;
2020-11-07 13:17:51 +01:00
this - > music_manager_ = make_shared < music : : MusicBotManager > ( self . lock ( ) ) ;
this - > music_manager_ - > _self = this - > music_manager_ ;
this - > music_manager_ - > load_playlists ( ) ;
this - > music_manager_ - > load_bots ( ) ;
2020-01-24 02:57:58 +01:00
2020-05-13 11:32:08 +02:00
#if 0
2020-01-24 02:57:58 +01:00
if ( this - > properties ( ) [ property : : VIRTUALSERVER_ICON_ID ] ! = ( IconId ) 0 )
if ( ! serverInstance - > getFileServer ( ) - > iconExists ( self . lock ( ) , this - > properties ( ) [ property : : VIRTUALSERVER_ICON_ID ] ) ) {
debugMessage ( this - > getServerId ( ) , " Removing invalid icon id of server " ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_ICON_ID ] = 0 ;
2020-05-13 11:32:08 +02:00
}
# endif
2020-01-24 02:57:58 +01:00
for ( const auto & type : vector < property : : VirtualServerProperties > {
property : : VIRTUALSERVER_DOWNLOAD_QUOTA ,
property : : VIRTUALSERVER_UPLOAD_QUOTA ,
property : : VIRTUALSERVER_MAX_UPLOAD_TOTAL_BANDWIDTH ,
property : : VIRTUALSERVER_MAX_DOWNLOAD_TOTAL_BANDWIDTH ,
} ) {
2020-04-08 13:01:41 +02:00
const auto & info = property : : describe ( type ) ;
2020-01-24 02:57:58 +01:00
auto prop = this - > properties ( ) [ type ] ;
if ( prop . default_value ( ) = = prop . value ( ) ) continue ;
2020-04-08 13:01:41 +02:00
if ( ! info . validate_input ( this - > properties ( ) [ type ] . value ( ) ) ) {
this - > properties ( ) [ type ] = info . default_value ;
logMessage ( this - > getServerId ( ) , " Server property " + std : : string { info . name } + " contains an invalid value! Resetting it. " ) ;
2020-01-24 02:57:58 +01:00
}
}
/* lets cleanup the conversations for not existent channels */
2020-11-07 13:17:51 +01:00
this - > conversation_manager_ - > synchronize_channels ( ) ;
2020-01-24 02:57:58 +01:00
return true ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
VirtualServer : : ~ VirtualServer ( ) {
memtrack : : freed < VirtualServer > ( this ) ;
2019-07-17 19:37:18 +02:00
delete this - > tokenManager ;
delete this - > groups ;
delete this - > channelTree ;
delete this - > letters ;
delete this - > complains ;
2020-11-07 13:17:51 +01:00
this - > conversation_manager_ . reset ( ) ;
2019-07-17 19:37:18 +02:00
if ( this - > _serverKey ) ecc_free ( this - > _serverKey ) ;
delete this - > _serverKey ;
}
inline bool evaluateAddress4 ( const string & input , in_addr & address ) {
2020-01-24 02:57:58 +01:00
if ( input = = " 0.0.0.0 " ) {
address . s_addr = INADDR_ANY ;
return true ;
} ;
auto record = gethostbyname ( input . c_str ( ) ) ;
if ( ! record ) return false ;
address . s_addr = ( ( in_addr * ) record - > h_addr ) - > s_addr ;
return true ;
2019-07-17 19:37:18 +02:00
}
inline bool evaluateAddress6 ( const string & input , in6_addr & address ) {
2020-01-24 02:57:58 +01:00
if ( input = = " :: " ) {
address = IN6ADDR_ANY_INIT ;
return true ;
} ;
auto record = gethostbyname2 ( input . c_str ( ) , AF_INET6 ) ;
if ( ! record ) return false ;
address = * ( in6_addr * ) record - > h_addr ;
return true ;
2019-07-17 19:37:18 +02:00
}
inline string strip ( std : : string message ) {
2020-01-24 02:57:58 +01:00
while ( ! message . empty ( ) ) {
if ( message [ 0 ] = = ' ' )
message = message . substr ( 1 ) ;
else if ( message [ message . length ( ) - 1 ] = = ' ' )
message = message . substr ( 0 , message . length ( ) - 1 ) ;
else break ;
}
return message ;
2019-07-17 19:37:18 +02:00
}
inline vector < string > split_hosts ( const std : : string & message , char delimiter ) {
2020-01-24 02:57:58 +01:00
vector < string > result ;
size_t found , index = 0 ;
do {
found = message . find ( delimiter , index ) ;
result . push_back ( strip ( message . substr ( index , found - index ) ) ) ;
index = found + 1 ;
} while ( index ! = 0 ) ;
return result ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
bool VirtualServer : : start ( std : : string & error ) {
2019-07-17 19:37:18 +02:00
{
threads : : Mutex lock ( this - > stateLock ) ;
if ( this - > state ! = ServerState : : OFFLINE ) {
error = " Server isn't offline " ;
return false ;
}
2020-01-24 02:57:58 +01:00
this - > state = ServerState : : BOOTING ;
2019-07-17 19:37:18 +02:00
}
2020-01-24 02:57:58 +01:00
this - > serverRoot - > server = self . lock ( ) ;
this - > serverAdmin - > server = self . lock ( ) ;
2019-07-17 19:37:18 +02:00
{ //Client delete after server stop/start
2020-01-24 02:57:58 +01:00
lock_guard lock ( this - > clients . lock ) ;
for ( auto & client : this - > clients . clients ) {
if ( ! client ) continue ;
if ( client - > getType ( ) = = ClientType : : CLIENT_WEB | | client - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK ) {
client . reset ( ) ;
}
}
2019-07-17 19:37:18 +02:00
}
auto host = this - > properties ( ) [ property : : VIRTUALSERVER_HOST ] . as < string > ( ) ;
2020-01-24 02:57:58 +01:00
if ( config : : binding : : enforce_default_voice_host )
host = config : : binding : : DefaultVoiceHost ;
2019-07-17 19:37:18 +02:00
if ( host . empty ( ) ) {
error = " invalid host ( \" " + host + " \" ) " ;
2020-03-01 10:28:29 +01:00
this - > stop ( " failed to start " , true ) ;
2019-07-17 19:37:18 +02:00
return false ;
}
if ( this - > properties ( ) [ property : : VIRTUALSERVER_PORT ] . as < uint16_t > ( ) < = 0 ) {
error = " invalid port " ;
2020-03-01 10:28:29 +01:00
this - > stop ( " failed to start " , true ) ;
2019-07-17 19:37:18 +02:00
return false ;
}
2020-01-24 02:57:58 +01:00
deque < shared_ptr < VoiceServerBinding > > bindings ;
for ( const auto & address : split_hosts ( host , ' , ' ) ) {
auto entry = make_shared < VoiceServerBinding > ( ) ;
if ( net : : is_ipv4 ( address ) ) {
sockaddr_in addr { } ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . sin_family = AF_INET ;
addr . sin_port = htons ( this - > properties ( ) [ property : : VIRTUALSERVER_PORT ] . as < uint16_t > ( ) ) ;
if ( ! evaluateAddress4 ( address , addr . sin_addr ) ) {
logError ( this - > serverId , " Fail to resolve v4 address info for \" {} \" " , address ) ;
continue ;
}
memcpy ( & entry - > address , & addr , sizeof ( addr ) ) ;
} else if ( net : : is_ipv6 ( address ) ) {
sockaddr_in6 addr { } ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . sin6_family = AF_INET6 ;
addr . sin6_port = htons ( this - > properties ( ) [ property : : VIRTUALSERVER_PORT ] . as < uint16_t > ( ) ) ;
if ( ! evaluateAddress6 ( address , addr . sin6_addr ) ) {
logError ( this - > serverId , " Fail to resolve v6 address info for \" {} \" " , address ) ;
continue ;
}
memcpy ( & entry - > address , & addr , sizeof ( addr ) ) ;
} else {
logError ( this - > serverId , " Failed to determinate address type for \" {} \" " , address ) ;
continue ;
}
bindings . push_back ( entry ) ;
2019-07-17 19:37:18 +02:00
}
if ( bindings . empty ( ) ) {
2020-01-24 02:57:58 +01:00
error = " failed to resole any host! " ;
2020-03-01 10:28:29 +01:00
this - > stop ( " failed to start " , false ) ;
2020-01-24 02:57:58 +01:00
return false ;
}
2019-07-17 19:37:18 +02:00
//Setup voice server
udpVoiceServer = make_shared < VoiceServer > ( self . lock ( ) ) ;
if ( ! udpVoiceServer - > start ( bindings , error ) ) {
error = " could not start voice server. Message: " + error ;
2020-03-01 10:28:29 +01:00
this - > stop ( " failed to start " , false ) ;
2019-07-17 19:37:18 +02:00
return false ;
}
if ( ts : : config : : web : : activated & & serverInstance - > sslManager ( ) - > web_ssl_options ( ) ) {
2019-07-23 10:37:56 +02:00
string web_host_string = this - > properties ( ) [ property : : VIRTUALSERVER_WEB_HOST ] ;
if ( web_host_string . empty ( ) )
2020-01-24 02:57:58 +01:00
web_host_string = this - > properties ( ) [ property : : VIRTUALSERVER_HOST ] . as < string > ( ) ;
2019-07-23 10:37:56 +02:00
2020-01-24 02:57:58 +01:00
auto web_port = this - > properties ( ) [ property : : VIRTUALSERVER_WEB_PORT ] . as < uint16_t > ( ) ;
if ( web_port = = 0 )
web_port = this - > properties ( ) [ property : : VIRTUALSERVER_PORT ] . as < uint16_t > ( ) ;
2019-07-17 19:37:18 +02:00
2019-07-23 10:37:56 +02:00
startTimestamp = std : : chrono : : system_clock : : now ( ) ;
2019-07-17 19:37:18 +02:00
# ifdef COMPILE_WEB_CLIENT
webControlServer = new WebControlServer ( self . lock ( ) ) ;
2019-07-23 10:37:56 +02:00
2020-01-24 02:57:58 +01:00
auto web_bindings = net : : resolve_bindings ( web_host_string , web_port ) ;
deque < shared_ptr < WebControlServer : : Binding > > bindings ;
2019-07-23 10:37:56 +02:00
2020-01-24 02:57:58 +01:00
for ( auto & binding : web_bindings ) {
if ( ! get < 2 > ( binding ) . empty ( ) ) {
logError ( this - > serverId , " [Web] Failed to resolve binding for {}: {} " , get < 0 > ( binding ) , get < 2 > ( binding ) ) ;
continue ;
}
auto entry = make_shared < WebControlServer : : Binding > ( ) ;
memcpy ( & entry - > address , & get < 1 > ( binding ) , sizeof ( sockaddr_storage ) ) ;
2019-07-23 10:37:56 +02:00
2020-01-24 02:57:58 +01:00
entry - > file_descriptor = - 1 ;
entry - > event_accept = nullptr ;
bindings . push_back ( entry ) ;
}
2019-07-23 10:37:56 +02:00
2020-01-24 02:57:58 +01:00
logMessage ( this - > serverId , " [Web] Starting server on {}:{} " , web_host_string , web_port ) ;
2019-07-23 10:37:56 +02:00
if ( ! webControlServer - > start ( bindings , error ) ) {
2019-07-17 19:37:18 +02:00
error = " could not start web server. Message: " + error ;
2020-03-01 10:28:29 +01:00
this - > stop ( " failed to start " , false ) ;
2019-07-17 19:37:18 +02:00
return false ;
}
# endif
}
2021-02-21 21:56:52 +01:00
auto weak_this = this - > self ;
serverInstance - > general_task_executor ( ) - > schedule_repeating (
this - > tick_task_id ,
" server tick " + std : : to_string ( this - > serverId ) ,
std : : chrono : : milliseconds { 500 } ,
[ weak_this ] ( const auto & scheduled ) {
auto ref_self = weak_this . lock ( ) ;
if ( ref_self ) {
ref_self - > executeServerTick ( ) ;
}
}
) ;
2019-07-17 19:37:18 +02:00
properties ( ) [ property : : VIRTUALSERVER_CLIENTS_ONLINE ] = 0 ;
2020-01-24 02:57:58 +01:00
properties ( ) [ property : : VIRTUALSERVER_QUERYCLIENTS_ONLINE ] = 0 ;
2019-07-17 19:37:18 +02:00
properties ( ) [ property : : VIRTUALSERVER_CHANNELS_ONLINE ] = 0 ;
properties ( ) [ property : : VIRTUALSERVER_UPTIME ] = 0 ;
this - > startTimestamp = system_clock : : now ( ) ;
2020-11-07 13:17:51 +01:00
this - > music_manager_ - > cleanup_semi_bots ( ) ;
this - > music_manager_ - > connectBots ( ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
{
threads : : MutexLock lock ( this - > stateLock ) ;
this - > state = ServerState : : ONLINE ;
}
2019-07-17 19:37:18 +02:00
return true ;
}
2020-01-26 18:04:38 +01:00
std : : string VirtualServer : : publicServerKey ( ) {
2020-01-24 02:57:58 +01:00
size_t keyBufferLength = 265 ;
char keyBuffer [ keyBufferLength ] ;
if ( ecc_export ( ( unsigned char * ) keyBuffer , & keyBufferLength , PK_PUBLIC , this - > _serverKey ) ! = CRYPT_OK ) return " " ;
return base64 : : encode ( string ( keyBuffer , keyBufferLength ) ) ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
bool VirtualServer : : running ( ) {
2019-07-17 19:37:18 +02:00
return this - > state = = ServerState : : BOOTING | | this - > state = = ServerState : : ONLINE ;
}
2020-01-26 18:04:38 +01:00
void VirtualServer : : preStop ( const std : : string & reason ) {
2020-01-24 02:57:58 +01:00
{
threads : : MutexLock lock ( this - > stateLock ) ;
if ( ! this - > running ( ) & & this - > state ! = ServerState : : SUSPENDING ) return ;
this - > state = ServerState : : SUSPENDING ;
}
for ( const auto & cl : this - > getClients ( ) ) {
unique_lock channel_lock ( cl - > channel_lock ) ;
if ( cl - > currentChannel ) {
auto vc = dynamic_pointer_cast < VoiceClient > ( cl ) ;
if ( vc ) {
vc - > disconnect ( VREASON_SERVER_SHUTDOWN , reason , nullptr , false ) ;
} else {
cl - > notifyClientLeftView ( cl , nullptr , ViewReasonId : : VREASON_SERVER_SHUTDOWN , reason , nullptr , false ) ;
}
}
cl - > visibleClients . clear ( ) ;
cl - > mutedClients . clear ( ) ;
}
2019-07-17 19:37:18 +02:00
}
2020-03-01 10:28:29 +01:00
void VirtualServer : : stop ( const std : : string & reason , bool disconnect_query ) {
2020-01-24 02:57:58 +01:00
auto self_lock = this - > self . lock ( ) ;
assert ( self_lock ) ;
2019-07-17 19:37:18 +02:00
{
threads : : MutexLock lock ( this - > stateLock ) ;
if ( ! this - > running ( ) & & this - > state ! = ServerState : : SUSPENDING ) return ;
2020-01-24 02:57:58 +01:00
this - > state = ServerState : : SUSPENDING ;
2019-07-17 19:37:18 +02:00
}
2020-03-01 10:28:29 +01:00
this - > preStop ( reason ) ;
2019-07-17 19:37:18 +02:00
for ( const auto & cl : this - > getClients ( ) ) { //start disconnecting
if ( cl - > getType ( ) = = CLIENT_TEAMSPEAK | | cl - > getType ( ) = = CLIENT_TEASPEAK | | cl - > getType ( ) = = CLIENT_WEB ) {
2020-02-01 14:32:16 +01:00
cl - > close_connection ( chrono : : system_clock : : now ( ) + chrono : : seconds ( 1 ) ) ;
2019-07-17 19:37:18 +02:00
} else if ( cl - > getType ( ) = = CLIENT_QUERY ) {
2020-01-24 02:57:58 +01:00
threads : : MutexLock lock ( cl - > command_lock ) ;
cl - > currentChannel = nullptr ;
2019-07-17 19:37:18 +02:00
2020-03-01 10:28:29 +01:00
if ( disconnect_query ) {
auto qc = dynamic_pointer_cast < QueryClient > ( cl ) ;
2021-01-28 20:59:15 +01:00
qc - > disconnect_from_virtual_server ( " server disconnect " ) ;
2020-03-01 10:28:29 +01:00
}
2019-07-17 19:37:18 +02:00
} else if ( cl - > getType ( ) = = CLIENT_MUSIC ) {
2020-01-24 02:57:58 +01:00
cl - > disconnect ( " " ) ;
cl - > currentChannel = nullptr ;
2019-07-17 19:37:18 +02:00
} else if ( cl - > getType ( ) = = CLIENT_INTERNAL ) {
} else {
2019-11-23 21:16:55 +01:00
logError ( this - > serverId , " Got client with unknown type: " + to_string ( cl - > getType ( ) ) ) ;
2019-07-17 19:37:18 +02:00
}
}
2020-11-07 13:17:51 +01:00
this - > music_manager_ - > disconnectBots ( ) ;
2019-07-17 19:37:18 +02:00
2021-02-21 21:56:52 +01:00
serverInstance - > general_task_executor ( ) - > cancel_task ( this - > tick_task_id ) ;
this - > tick_task_id = 0 ;
2019-07-17 19:37:18 +02:00
if ( this - > udpVoiceServer ) this - > udpVoiceServer - > stop ( ) ;
this - > udpVoiceServer = nullptr ;
# ifdef COMPILE_WEB_CLIENT
if ( this - > webControlServer ) this - > webControlServer - > stop ( ) ;
delete this - > webControlServer ;
this - > webControlServer = nullptr ;
# endif
if ( this - > groups ) {
2020-01-24 02:57:58 +01:00
this - > groups - > clearCache ( ) ;
2019-07-17 19:37:18 +02:00
}
properties ( ) [ property : : VIRTUALSERVER_CLIENTS_ONLINE ] = 0 ;
2020-01-24 02:57:58 +01:00
properties ( ) [ property : : VIRTUALSERVER_QUERYCLIENTS_ONLINE ] = 0 ;
properties ( ) [ property : : VIRTUALSERVER_CHANNELS_ONLINE ] = 0 ;
properties ( ) [ property : : VIRTUALSERVER_UPTIME ] = 0 ;
{
threads : : MutexLock lock ( this - > stateLock ) ;
this - > state = ServerState : : OFFLINE ;
}
this - > serverRoot - > server = nullptr ;
this - > serverAdmin - > server = nullptr ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
size_t VirtualServer : : onlineClients ( ) {
2020-01-24 02:57:58 +01:00
size_t result = 0 ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
lock_guard lock ( this - > clients . lock ) ;
2019-07-17 19:37:18 +02:00
for ( const auto & cl : this - > clients . clients ) {
2020-01-24 02:57:58 +01:00
if ( ! cl )
continue ;
if ( cl - > getType ( ) = = CLIENT_TEAMSPEAK | | cl - > getType ( ) = = CLIENT_QUERY )
result + + ;
2019-07-17 19:37:18 +02:00
}
return result ;
}
2020-01-26 18:04:38 +01:00
OnlineClientReport VirtualServer : : onlineStats ( ) {
2019-07-17 19:37:18 +02:00
OnlineClientReport response { } ;
{
2020-01-24 02:57:58 +01:00
lock_guard lock ( this - > clients . lock ) ;
2019-07-17 19:37:18 +02:00
for ( const auto & cl : this - > clients . clients ) {
2020-01-24 02:57:58 +01:00
if ( ! cl ) continue ;
switch ( cl - > getType ( ) ) {
case CLIENT_TEAMSPEAK :
response . clients_ts + + ;
break ;
case CLIENT_WEB :
response . clients_web + + ;
break ;
case CLIENT_QUERY :
response . queries + + ;
break ;
case CLIENT_MUSIC :
response . bots + + ;
break ;
default :
break ;
}
2019-07-17 19:37:18 +02:00
}
}
return response ;
}
2020-02-01 14:32:16 +01:00
std : : shared_ptr < ConnectedClient > VirtualServer : : find_client_by_id ( uint16_t client_id ) {
2020-01-24 02:57:58 +01:00
lock_guard lock ( this - > clients . lock ) ;
if ( this - > clients . clients . size ( ) > client_id )
return this - > clients . clients [ client_id ] ;
else
return nullptr ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
deque < shared_ptr < ConnectedClient > > VirtualServer : : findClientsByCldbId ( uint64_t cldbId ) {
2020-01-24 02:57:58 +01:00
deque < shared_ptr < ConnectedClient > > result ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
lock_guard lock ( this - > clients . lock ) ;
for ( const auto & client : this - > clients . clients ) {
if ( ! client ) continue ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
if ( client - > getClientDatabaseId ( ) = = cldbId )
result . push_back ( client ) ;
}
return result ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
deque < shared_ptr < ConnectedClient > > VirtualServer : : findClientsByUid ( std : : string uid ) {
2020-01-24 02:57:58 +01:00
lock_guard lock ( this - > clients . lock ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
deque < shared_ptr < ConnectedClient > > result ;
2019-07-17 19:37:18 +02:00
for ( const auto & client : this - > clients . clients ) {
2020-01-24 02:57:58 +01:00
if ( ! client ) continue ;
2019-07-17 19:37:18 +02:00
if ( client - > getUid ( ) = = uid ) {
result . push_back ( client ) ;
}
}
return result ;
}
2020-01-26 18:04:38 +01:00
std : : shared_ptr < ConnectedClient > VirtualServer : : findClient ( std : : string name , bool ignoreCase ) {
2019-07-17 19:37:18 +02:00
if ( ignoreCase ) {
2020-01-24 02:57:58 +01:00
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , : : tolower ) ;
2019-07-17 19:37:18 +02:00
}
2020-01-24 02:57:58 +01:00
{
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
lock_guard lock ( this - > clients . lock ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
for ( const auto & client : this - > clients . clients ) {
if ( ! client ) continue ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
string clName = client - > getDisplayName ( ) ;
if ( ignoreCase ) {
std : : transform ( clName . begin ( ) , clName . end ( ) , clName . begin ( ) , : : tolower ) ;
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
if ( clName = = name )
return client ;
}
}
2019-07-17 19:37:18 +02:00
return nullptr ;
}
2020-01-26 18:04:38 +01:00
bool VirtualServer : : forEachClient ( std : : function < void ( std : : shared_ptr < ConnectedClient > ) > function ) {
2019-07-17 19:37:18 +02:00
for ( const auto & elm : this - > getClients ( ) ) {
2020-01-24 02:57:58 +01:00
shared_lock close_lock ( elm - > finalDisconnectLock , try_to_lock_t { } ) ;
if ( close_lock . owns_lock ( ) ) //If not locked than client is on the way to disconnect
if ( elm - > state = = ConnectionState : : CONNECTED & & elm - > getType ( ) ! = ClientType : : CLIENT_INTERNAL ) {
function ( elm ) ;
}
2019-07-17 19:37:18 +02:00
}
return true ;
}
2020-01-26 18:04:38 +01:00
std : : vector < std : : shared_ptr < ConnectedClient > > VirtualServer : : getClients ( ) {
2020-01-24 02:57:58 +01:00
vector < shared_ptr < ConnectedClient > > clients ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
{
lock_guard lock ( this - > clients . lock ) ;
clients . reserve ( this - > clients . count ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
for ( auto & client : this - > clients . clients ) {
if ( ! client ) continue ;
clients . push_back ( client ) ;
}
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
return clients ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
deque < shared_ptr < ConnectedClient > > VirtualServer : : getClientsByChannel ( std : : shared_ptr < BasicChannel > channel ) {
2019-07-17 19:37:18 +02:00
assert ( this ) ;
auto s_channel = dynamic_pointer_cast < ServerChannel > ( channel ) ;
if ( ! s_channel ) return { } ; /* what had we done wrong here... :D */
shared_lock client_lock ( s_channel - > client_lock ) ;
auto weak_clients = s_channel - > clients ;
2020-01-24 02:57:58 +01:00
client_lock . unlock ( ) ;
2019-07-17 19:37:18 +02:00
std : : deque < std : : shared_ptr < ConnectedClient > > result ;
for ( const auto & weak_client : weak_clients ) {
2020-01-24 02:57:58 +01:00
auto client = weak_client . lock ( ) ;
if ( ! client ) continue ;
if ( client - > connectionState ( ) ! = ConnectionState : : CONNECTED ) continue ;
if ( client - > getChannel ( ) ! = channel ) continue ; /* to be sure */
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
result . push_back ( move ( client ) ) ;
2019-07-17 19:37:18 +02:00
}
return result ;
}
2020-01-26 18:04:38 +01:00
deque < shared_ptr < ConnectedClient > > VirtualServer : : getClientsByChannelRoot ( const std : : shared_ptr < BasicChannel > & root , bool lock ) {
2020-01-24 02:57:58 +01:00
assert ( this ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
shared_lock channel_lock ( this - > channel_tree_lock , defer_lock ) ;
if ( lock )
channel_lock . lock ( ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
std : : deque < std : : shared_ptr < ConnectedClient > > result ;
for ( const auto & channel : this - > channelTree - > channels ( root ) ) {
auto clients = this - > getClientsByChannel ( channel ) ;
result . insert ( result . end ( ) , clients . begin ( ) , clients . end ( ) ) ;
}
2019-07-17 19:37:18 +02:00
return result ;
}
2020-01-26 18:04:38 +01:00
bool VirtualServer : : notifyServerEdited ( std : : shared_ptr < ConnectedClient > invoker , deque < string > keys ) {
2019-07-17 19:37:18 +02:00
if ( ! invoker ) return false ;
Command cmd ( " notifyserveredited " ) ;
cmd [ " invokerid " ] = invoker - > getClientId ( ) ;
cmd [ " invokername " ] = invoker - > getDisplayName ( ) ;
cmd [ " invokeruid " ] = invoker - > getUid ( ) ;
cmd [ " reasonid " ] = ViewReasonId : : VREASON_EDITED ;
for ( const auto & key : keys ) {
2020-04-08 13:01:41 +02:00
const auto & info = property : : find < property : : VirtualServerProperties > ( key ) ;
if ( info = = property : : VIRTUALSERVER_UNDEFINED ) {
2020-01-24 02:57:58 +01:00
logError ( this - > getServerId ( ) , " Tried to broadcast a server update with an unknown info: " + key ) ;
continue ;
}
cmd [ key ] = properties ( ) [ info ] . as < std : : string > ( ) ;
2019-07-17 19:37:18 +02:00
}
this - > forEachClient ( [ & cmd ] ( shared_ptr < ConnectedClient > client ) {
client - > sendCommand ( cmd ) ;
} ) ;
return true ;
}
2020-04-08 13:01:41 +02:00
bool VirtualServer : : notifyClientPropertyUpdates ( std : : shared_ptr < ConnectedClient > client , const deque < const property : : PropertyDescription * > & keys , bool selfNotify ) {
2020-05-21 09:48:11 +02:00
if ( keys . empty ( ) | | ! client ) return false ;
2019-07-17 19:37:18 +02:00
this - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & cl ) {
2020-05-21 09:48:11 +02:00
shared_lock client_channel_lock ( cl - > channel_lock ) ;
2019-07-17 19:37:18 +02:00
if ( cl - > isClientVisible ( client , false ) | | ( cl = = client & & selfNotify ) )
cl - > notifyClientUpdated ( client , keys , false ) ;
} ) ;
return true ;
}
2020-01-26 18:04:38 +01:00
void VirtualServer : : broadcastMessage ( std : : shared_ptr < ConnectedClient > invoker , std : : string message ) {
2019-07-17 19:37:18 +02:00
if ( ! invoker ) {
logCritical ( this - > serverId , " Tried to broadcast with an invalid invoker! " ) ;
return ;
}
this - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > cl ) {
2019-08-20 13:46:23 +02:00
cl - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_SERVER , invoker , 0 , 0 , system_clock : : now ( ) , message ) ;
2019-07-17 19:37:18 +02:00
} ) ;
}
2020-01-26 18:04:38 +01:00
std : : vector < std : : shared_ptr < GroupAssignment > > CalculateCache : : getGroupAssignments ( VirtualServer * server , ClientDbId cldbid , ClientType type ) {
2019-07-17 19:37:18 +02:00
if ( assignment_server_groups_set ) return assignment_server_groups ;
assignment_server_groups = server - > getGroupManager ( ) - > getServerGroups ( cldbid , type ) ;
assignment_server_groups_set = true ;
return assignment_server_groups ;
}
2020-01-26 18:04:38 +01:00
std : : shared_ptr < GroupAssignment > CalculateCache : : getChannelAssignment ( VirtualServer * server , ClientDbId client_dbid , ChannelId channel_id ) {
2019-07-17 19:37:18 +02:00
if ( this - > assignment_channel_group_set & & this - > assignment_channel_group_channel = = channel_id ) return this - > assignment_channel_group ;
auto channel = this - > getServerChannel ( server , channel_id ) ;
assignment_channel_group = channel ? server - > getGroupManager ( ) - > getChannelGroup ( client_dbid , channel , true ) : nullptr ;
assignment_channel_group_set = true ;
assignment_channel_group_channel = channel_id ;
return assignment_channel_group ;
}
2020-01-26 18:04:38 +01:00
std : : shared_ptr < BasicChannel > CalculateCache : : getServerChannel ( ts : : server : : VirtualServer * server , ts : : ChannelId channel_id ) {
2020-01-24 02:57:58 +01:00
if ( this - > last_server_channel = = channel_id )
return this - > server_channel ;
this - > last_server_channel = channel_id ;
this - > server_channel = server & & channel_id > 0 ? server - > getChannelTree ( ) - > findChannel ( channel_id ) : nullptr ;
return this - > server_channel ;
2019-07-17 19:37:18 +02:00
}
ts_always_inline bool channel_ignore_permission ( ts : : permission : : PermissionType type ) {
2020-01-24 02:57:58 +01:00
return permission : : i_icon_id = = type ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
vector < pair < ts : : permission : : PermissionType , ts : : permission : : v2 : : PermissionFlaggedValue > > VirtualServer : : calculate_permissions (
2020-01-24 02:57:58 +01:00
const std : : deque < permission : : PermissionType > & permissions ,
2020-01-26 14:21:34 +01:00
ClientDbId client_dbid ,
2020-01-24 02:57:58 +01:00
ClientType client_type ,
ChannelId channel_id ,
bool calculate_granted ,
std : : shared_ptr < CalculateCache > cache ) {
if ( permissions . empty ( ) ) return { } ;
vector < pair < ts : : permission : : PermissionType , ts : : permission : : v2 : : PermissionFlaggedValue > > result ;
result . reserve ( permissions . size ( ) ) ;
if ( ! cache ) {
cache = make_shared < CalculateCache > ( ) ;
}
if ( ! cache - > client_permissions ) {
cache - > client_permissions = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( self . lock ( ) , client_dbid ) ;
}
bool have_skip_permission = false ;
int skip_permission_type = - 1 ; /* -1 := unset | 0 := skip, not explicit | 1 := skip, explicit */
/*
* server_group_data [ 0 ] : = Server group id
* server_group_data [ 1 ] : = Skip flag
* server_group_data [ 2 ] : = Negate flag
* server_group_data [ 3 ] : = Permission value
*/
typedef std : : tuple < GroupId , bool , bool , permission : : PermissionValue > GroupData ;
bool server_group_data_initialized = false ;
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 = cache - > 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 - > serverId , " [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 : cache - > getGroupAssignments ( this , client_dbid , client_type ) ) {
auto group_permissions = assignment - > group - > 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 - > serverId , " [Permission] Found skip permission in client server group. Group: {} ({}), Value: {} " , assignment - > group - > groupId ( ) , assignment - > group - > name ( ) , have_skip_permission ) ;
break ;
}
}
}
}
} ;
auto initialize_group_data = [ & ] ( const permission : : PermissionType & permission_type ) {
server_group_data_initialized = true ;
active_server_group = nullptr ;
2020-06-16 12:57:20 +02:00
auto assigned_groups = cache - > getGroupAssignments ( this , client_dbid , client_type ) ;
server_group_data . resize ( assigned_groups . size ( ) ) ;
2020-01-24 02:57:58 +01:00
auto it = server_group_data . begin ( ) ;
2020-06-16 12:57:20 +02:00
for ( auto & group : assigned_groups ) {
2020-01-24 02:57:58 +01:00
auto group_permissions = group - > group - > permissions ( ) ;
auto permission_flags = group_permissions - > permission_flags ( permission_type ) ;
auto flag_set = calculate_granted ? permission_flags . grant_set : permission_flags . value_set ;
if ( ! flag_set )
continue ;
//TODO: Test if there is may a group channel permissions
auto value = group_permissions - > permission_values ( permission_type ) ;
* it = std : : make_tuple ( group - > group - > groupId ( ) , ( bool ) permission_flags . skip , ( bool ) permission_flags . negate , calculate_granted ? value . grant : value . value ) ;
it + + ;
}
if ( it = = server_group_data . begin ( ) )
return ; /* no server group has that permission */
server_group_data . erase ( it , server_group_data . end ( ) ) ; /* remove unneeded */
auto found_negate = false ;
for ( auto & group : server_group_data ) {
if ( std : : get < 2 > ( group ) ) {
found_negate = true ;
break ;
}
}
if ( found_negate ) {
server_group_data . erase ( remove_if ( server_group_data . begin ( ) , server_group_data . end ( ) , [ ] ( auto data ) { return ! std : : get < 2 > ( data ) ; } ) , server_group_data . end ( ) ) ;
logTrace ( this - > serverId , " [Permission] Found negate flag within server groups. Groups left: {} " , server_group_data . size ( ) ) ;
if ( server_group_data . empty ( ) )
logTrace ( this - > serverId , " [Permission] After non negated groups have been kicked out the negated groups are empty! This should not happen! Permission: {}, Client ID: {} " , permission_type , client_dbid ) ;
permission : : PermissionValue current_lowest = 0 ;
for ( auto & group : server_group_data ) {
if ( ! active_server_group | | ( std : : get < 3 > ( group ) < current_lowest & & std : : get < 3 > ( group ) ! = - 1 ) ) {
current_lowest = std : : get < 3 > ( group ) ;
active_server_group = & group ;
}
}
} else {
permission : : PermissionValue current_highest = 0 ;
for ( auto & group : server_group_data ) {
if ( ! active_server_group | | ( std : : get < 3 > ( group ) > current_highest | | std : : get < 3 > ( group ) = = - 1 ) ) {
current_highest = std : : get < 3 > ( group ) ;
active_server_group = & group ;
}
}
}
} ;
for ( const auto & permission : permissions ) {
server_group_data_initialized = false ; /* reset all group data */
auto client_permission_flags = cache - > client_permissions - > permission_flags ( permission ) ;
/* lets try to resolve the channel specific permission */
if ( channel_id > 0 & & client_permission_flags . channel_specific ) {
auto data = cache - > client_permissions - > channel_permission ( permission , 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 - > serverId , " [Permission] Calculation for client {} of permission {} returned {} (Client channel permission) " , client_dbid , permission : : resolvePermissionData ( permission ) - > name , data . values . value ) ;
continue ;
}
}
2020-06-16 12:57:20 +02:00
bool skip_channel_permissions = channel_id = = 0 ;
if ( ! skip_channel_permissions ) {
2020-01-24 02:57:58 +01:00
/* look if somewhere is the skip permission flag set */
2021-02-21 21:56:52 +01:00
if ( skip_permission_type = = - 1 ) { /* initialize skip flag */
2020-01-24 02:57:58 +01:00
calculate_skip ( ) ;
2021-02-21 21:56:52 +01:00
}
2020-06-16 12:57:20 +02:00
skip_channel_permissions = have_skip_permission ;
2020-01-24 02:57:58 +01:00
}
2020-06-16 12:57:20 +02:00
if ( ! skip_channel_permissions ) {
2020-01-24 02:57:58 +01:00
/* okey we've no global skip. Then now lookup the groups and the client permissions */
if ( calculate_granted ? client_permission_flags . grant_set : client_permission_flags . value_set ) {
/* okey the client has the permission, this counts */
2020-06-16 12:57:20 +02:00
skip_channel_permissions = client_permission_flags . skip ;
2020-01-24 02:57:58 +01:00
} else {
if ( ! server_group_data_initialized )
initialize_group_data ( permission ) ;
2020-06-16 12:57:20 +02:00
2020-01-24 02:57:58 +01:00
if ( active_server_group )
2020-06-16 12:57:20 +02:00
skip_channel_permissions = std : : get < 1 > ( * active_server_group ) ;
2020-01-24 02:57:58 +01:00
}
}
2020-06-16 12:57:20 +02:00
if ( ! skip_channel_permissions ) {
2020-01-24 02:57:58 +01:00
/* lookup the channel group */
{
auto channel_assignment = cache - > getChannelAssignment ( this , client_dbid , channel_id ) ;
if ( channel_assignment ) {
auto group_permissions = channel_assignment - > group - > permissions ( ) ;
auto permission_flags = group_permissions - > permission_flags ( permission ) ;
auto flag_set = calculate_granted ? permission_flags . grant_set : permission_flags . value_set ;
if ( flag_set ) {
auto value = group_permissions - > permission_values ( permission ) ;
result . push_back ( { permission , { calculate_granted ? value . grant : value . value , true } } ) ;
logTrace ( this - > serverId , " [Permission] Calculation for client {} of permission {} returned {} (Channel group permission) " , client_dbid , permission : : resolvePermissionData ( permission ) - > name , calculate_granted ? value . grant : value . value ) ;
continue ;
}
}
}
/* lookup the channel permissions. Whyever? */
{
auto channel = cache - > getServerChannel ( this , channel_id ) ;
if ( channel ) {
auto channel_permissions = channel - > permissions ( ) ;
auto data = calculate_granted ? channel_permissions - > permission_granted_flagged ( permission ) : channel_permissions - > permission_value_flagged ( permission ) ;
if ( data . has_value ) {
result . push_back ( { permission , { data . value , true } } ) ;
logTrace ( this - > serverId , " [Permission] Calculation for client {} of permission {} returned {} (Channel permission) " , client_dbid , permission : : resolvePermissionData ( permission ) - > name , data . value ) ;
continue ;
}
}
}
}
if ( calculate_granted ? client_permission_flags . grant_set : client_permission_flags . value_set ) {
auto client_value = cache - > client_permissions - > permission_values ( permission ) ;
result . push_back ( { permission , { calculate_granted ? client_value . grant : client_value . value , true } } ) ;
logTrace ( this - > serverId , " [Permission] Calculation for client {} of permission {} returned {} (Client permission) " , client_dbid , permission : : resolvePermissionData ( permission ) - > name , client_value . value ) ;
continue ;
}
if ( ! server_group_data_initialized )
initialize_group_data ( permission ) ;
if ( active_server_group ) {
result . push_back ( { permission , { get < 3 > ( * active_server_group ) , true } } ) ;
logTrace ( this - > serverId , " [Permission] Calculation for client {} of permission {} returned {} (Server group permission of group {}) " , client_dbid , permission : : resolvePermissionData ( permission ) - > name , get < 3 > ( * active_server_group ) , get < 0 > ( * active_server_group ) ) ;
continue ;
}
logTrace ( this - > serverId , " [Permission] Calculation for client {} of permission {} returned in no permission. " , client_dbid , permission : : resolvePermissionData ( permission ) - > name ) ;
result . push_back ( { permission , { permNotGranted , false } } ) ;
}
return result ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
permission : : v2 : : PermissionFlaggedValue VirtualServer : : calculate_permission (
2020-01-26 14:21:34 +01:00
permission : : PermissionType permission ,
ClientDbId cldbid ,
ClientType type ,
ChannelId channel ,
bool granted ,
2019-07-17 19:37:18 +02:00
std : : shared_ptr < CalculateCache > cache ) {
2020-01-26 14:21:34 +01:00
auto result = this - > calculate_permissions ( { permission } , cldbid , type , channel , granted , cache ) ;
if ( result . empty ( ) ) return { 0 , false } ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
return result . front ( ) . second ;
2019-11-09 18:53:53 +01:00
}
2020-01-26 18:04:38 +01:00
bool VirtualServer : : verifyServerPassword ( std : : string password , bool hashed ) {
2019-07-17 19:37:18 +02:00
if ( ! this - > properties ( ) [ property : : VIRTUALSERVER_FLAG_PASSWORD ] . as < bool > ( ) ) return true ;
if ( password . empty ( ) ) return false ;
if ( ! hashed ) {
char buffer [ SHA_DIGEST_LENGTH ] ;
SHA1 ( reinterpret_cast < const unsigned char * > ( password . data ( ) ) , password . length ( ) , reinterpret_cast < unsigned char * > ( buffer ) ) ;
password = base64_encode ( string ( buffer , SHA_DIGEST_LENGTH ) ) ;
}
return password = = this - > properties ( ) [ property : : VIRTUALSERVER_PASSWORD ] . as < std : : string > ( ) ;
}
2020-04-08 13:01:41 +02:00
VirtualServer : : NetworkReport VirtualServer : : generate_network_report ( ) {
double total_ping { 0 } , total_loss { 0 } ;
size_t pings_counted { 0 } , loss_counted { 0 } ;
2019-07-17 19:37:18 +02:00
2020-04-08 13:01:41 +02:00
this - > forEachClient ( [ & ] ( const std : : shared_ptr < ConnectedClient > & client ) {
if ( auto vc = dynamic_pointer_cast < VoiceClient > ( client ) ; vc ) {
total_ping + = vc - > current_ping ( ) . count ( ) ;
total_loss + = vc - > current_packet_loss ( ) ;
pings_counted + + ;
loss_counted + + ;
2020-01-24 18:24:04 +01:00
}
# ifdef COMPILE_WEB_CLIENT
2020-04-08 13:01:41 +02:00
else if ( client - > getType ( ) = = ClientType : : CLIENT_WEB ) {
pings_counted + + ;
total_ping + = duration_cast < milliseconds > ( dynamic_pointer_cast < WebClient > ( client ) - > client_ping ( ) ) . count ( ) ;
2020-01-24 02:57:58 +01:00
}
2020-01-24 18:24:04 +01:00
# endif
2019-07-17 19:37:18 +02:00
} ) ;
2020-04-08 13:01:41 +02:00
VirtualServer : : NetworkReport result { } ;
if ( loss_counted ) result . average_loss = total_loss / loss_counted ;
if ( pings_counted ) result . average_ping = total_ping / pings_counted ;
return result ;
2019-07-17 19:37:18 +02:00
}
2021-02-25 11:13:30 +01:00
bool VirtualServer : : resetPermissions ( std : : string & new_permission_token ) {
2020-03-23 10:58:07 +01:00
LOG_SQL_CMD ( sql : : command ( this - > sql , " DELETE FROM `permissions` WHERE `serverId` = :serverId AND `type` != :channel_type " , variable { " :serverId " , this - > serverId } , variable { " :channel_type " , permission : : SQL_PERM_CHANNEL } ) . execute ( ) ) ;
2020-01-24 02:57:58 +01:00
LOG_SQL_CMD ( sql : : command ( this - > sql , " DELETE FROM `assignedGroups` WHERE `serverId` = :serverId " , variable { " :serverId " , this - > serverId } ) . execute ( ) ) ;
LOG_SQL_CMD ( sql : : command ( this - > sql , " DELETE FROM `groups` WHERE `serverId` = :serverId " , variable { " :serverId " , this - > serverId } ) . execute ( ) ) ;
{
threads : : MutexLock lock ( this - > getGroupManager ( ) - > cacheLock ) ;
this - > getGroupManager ( ) - > deleteAllGroups ( ) ;
deque < shared_ptr < Group > > saved_groups ;
for ( const auto & group : serverInstance - > getGroupManager ( ) - > availableGroups ( false ) ) {
if ( group - > type ( ) ! = GroupType : : GROUP_TYPE_TEMPLATE ) continue ;
debugMessage ( this - > serverId , " Copy default group {{Id: {}, Type: {}, Target: {}, Name: {}}} to server " , group - > groupId ( ) , group - > type ( ) , group - > target ( ) , group - > name ( ) ) ;
this - > getGroupManager ( ) - > copyGroup ( group , GroupType : : GROUP_TYPE_NORMAL , group - > name ( ) , this - > serverId ) ;
}
}
//Server admin
auto default_server_admin = serverInstance - > getGroupManager ( ) - > findGroup ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP ] . as < GroupId > ( ) ) ;
auto default_server_music = serverInstance - > getGroupManager ( ) - > findGroup ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP ] . as < GroupId > ( ) ) ;
auto default_server_guest = serverInstance - > getGroupManager ( ) - > findGroup ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP ] . as < GroupId > ( ) ) ;
auto default_channel_admin = serverInstance - > getGroupManager ( ) - > findGroup ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP ] . as < GroupId > ( ) ) ;
auto default_channel_guest = serverInstance - > getGroupManager ( ) - > findGroup ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP ] . as < GroupId > ( ) ) ;
if ( ! default_server_guest ) {
logCritical ( 0 , " Missing default server guest template group! " ) ;
assert ( ! serverInstance - > getGroupManager ( ) - > availableChannelGroups ( ) . empty ( ) ) ;
default_server_guest = serverInstance - > getGroupManager ( ) - > availableServerGroups ( ) . front ( ) ;
logCritical ( 0 , " Using group {} as default server guest group for server {}. " , default_server_guest - > name ( ) , this - > serverId ) ;
}
if ( ! default_channel_admin ) {
logCritical ( 0 , " Missing default channel guest template group! " ) ;
assert ( ! serverInstance - > getGroupManager ( ) - > availableChannelGroups ( ) . empty ( ) ) ;
default_channel_admin = serverInstance - > getGroupManager ( ) - > availableChannelGroups ( ) . front ( ) ;
logCritical ( 0 , " Using group {} as channel server guest group for server {}. " , default_channel_admin - > name ( ) , this - > serverId ) ;
}
if ( ! default_server_music ) {
logCritical ( 0 , " Missing default channel guest template group! " ) ;
assert ( ! serverInstance - > getGroupManager ( ) - > availableChannelGroups ( ) . empty ( ) ) ;
default_server_music = serverInstance - > getGroupManager ( ) - > availableChannelGroups ( ) . front ( ) ;
logCritical ( 0 , " Using group {} as channel server guest group for server {}. " , default_server_music - > name ( ) , this - > serverId ) ;
}
if ( ! default_server_admin ) {
logCritical ( 0 , " Missing default server admin template group! Using default guest group ({}) " , default_server_guest - > name ( ) ) ;
default_server_admin = default_server_guest ;
}
if ( ! default_channel_admin ) {
logCritical ( 0 , " Missing default channel admin template group! Using default guest group ({}) " , default_channel_guest - > name ( ) ) ;
default_channel_admin = default_channel_guest ;
}
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_SERVER_GROUP ] = this - > getGroupManager ( ) - > findGroup ( GroupTarget : : GROUPTARGET_SERVER , default_server_guest - > name ( ) ) . front ( ) - > groupId ( ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_MUSIC_GROUP ] = this - > getGroupManager ( ) - > findGroup ( GroupTarget : : GROUPTARGET_SERVER , default_server_music - > name ( ) ) . front ( ) - > groupId ( ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] = this - > getGroupManager ( ) - > findGroup ( GroupTarget : : GROUPTARGET_CHANNEL , default_channel_admin - > name ( ) ) . front ( ) - > groupId ( ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] = this - > getGroupManager ( ) - > findGroup ( GroupTarget : : GROUPTARGET_CHANNEL , default_channel_guest - > name ( ) ) . front ( ) - > groupId ( ) ;
2021-02-25 11:13:30 +01:00
auto server_admin_group_id = this - > getGroupManager ( ) - > findGroup ( GroupTarget : : GROUPTARGET_SERVER , default_server_admin - > name ( ) ) . front ( ) - > groupId ( ) ;
auto token = this - > tokenManager - > create_token ( 0 , " Default server admin token " , 1 , std : : chrono : : system_clock : : time_point { } ) ;
if ( ! token ) {
logCritical ( this - > serverId , " Failed to register the default server admin token. " ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY ] = false ;
2020-01-24 02:57:58 +01:00
} else {
2021-02-25 11:13:30 +01:00
std : : vector < token : : TokenAction > actions { } ;
actions . push_back ( token : : TokenAction {
. id = 0 ,
. type = token : : ActionType : : AddServerGroup ,
. id1 = server_admin_group_id ,
. id2 = 0
} ) ;
this - > tokenManager - > add_token_actions ( token - > id , actions ) ;
new_permission_token = token - > token ;
this - > properties ( ) [ property : : VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY ] = token - > token ;
2020-01-24 02:57:58 +01:00
this - > properties ( ) [ property : : VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY ] = true ;
}
this - > ensureValidDefaultGroups ( ) ;
for ( const auto & client : this - > getClients ( ) ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_QUERY ) {
2019-07-17 19:37:18 +02:00
client - > notifyServerGroupList ( ) ;
client - > notifyChannelGroupList ( ) ;
2020-01-24 02:57:58 +01:00
}
if ( this - > notifyClientPropertyUpdates ( client , this - > getGroupManager ( ) - > update_server_group_property ( client , true , client - > getChannel ( ) ) ) ) {
2021-02-21 21:56:52 +01:00
client - > task_update_needed_permissions . enqueue ( ) ;
2020-01-24 02:57:58 +01:00
}
2021-02-21 21:56:52 +01:00
client - > task_update_channel_client_properties . enqueue ( ) ;
2020-01-24 02:57:58 +01:00
}
return true ;
2019-07-17 19:37:18 +02:00
}
2020-01-26 18:04:38 +01:00
void VirtualServer : : ensureValidDefaultGroups ( ) {
2020-01-24 02:57:58 +01:00
auto default_server_group = this - > getGroupManager ( ) - > defaultGroup ( GROUPTARGET_SERVER , true ) ;
if ( ! default_server_group ) {
logError ( this - > serverId , " Missing server's default server group! (Id: {}) " , this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_SERVER_GROUP ] . value ( ) ) ;
default_server_group = this - > getGroupManager ( ) - > availableServerGroups ( false ) . front ( ) ;
logError ( this - > serverId , " Using {} ({}) instead! " , default_server_group - > groupId ( ) , default_server_group - > name ( ) ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_SERVER_GROUP ] = default_server_group - > groupId ( ) ;
}
auto default_music_group = this - > getGroupManager ( ) - > defaultGroup ( GROUPTARGET_SERVER , true ) ;
if ( ! default_music_group ) {
logError ( this - > serverId , " Missing server's default music group! (Id: {}) " , this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_MUSIC_GROUP ] . value ( ) ) ;
default_music_group = default_server_group ;
logError ( this - > serverId , " Using {} ({}) instead! " , default_music_group - > groupId ( ) , default_music_group - > name ( ) ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_MUSIC_GROUP ] = default_music_group - > groupId ( ) ;
}
auto default_channel_group = this - > getGroupManager ( ) - > defaultGroup ( GROUPTARGET_CHANNEL , true ) ;
if ( ! default_channel_group ) {
logError ( this - > serverId , " Missing server's default channel group! (Id: {}) " , this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] . value ( ) ) ;
default_channel_group = this - > getGroupManager ( ) - > availableChannelGroups ( false ) . front ( ) ;
logError ( this - > serverId , " Using {} ({}) instead! " , default_channel_group - > groupId ( ) , default_channel_group - > name ( ) ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] = default_channel_group - > groupId ( ) ;
}
auto admin_channel_group = this - > getGroupManager ( ) - > findGroupLocal ( this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] . as_save < GroupId > ( ) ) ;
if ( ! admin_channel_group ) {
logError ( this - > serverId , " Missing server's default channel admin group! (Id: {}) " , this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] . value ( ) ) ;
admin_channel_group = this - > getGroupManager ( ) - > availableChannelGroups ( false ) . front ( ) ;
logError ( this - > serverId , " Using {} ({}) instead! " , admin_channel_group - > groupId ( ) , admin_channel_group - > name ( ) ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] = admin_channel_group - > groupId ( ) ;
}
2020-02-02 14:58:46 +01:00
}
2020-02-04 18:09:47 +01:00
void VirtualServer : : send_text_message ( const std : : shared_ptr < BasicChannel > & channel , const std : : shared_ptr < ConnectedClient > & sender , const std : : string & message ) {
2020-02-02 14:58:46 +01:00
assert ( channel ) ;
2020-02-04 18:09:47 +01:00
assert ( sender ) ;
2020-02-02 14:58:46 +01:00
2020-02-04 18:09:47 +01:00
auto client_id = sender - > getClientId ( ) ;
2020-02-02 14:58:46 +01:00
auto channel_id = channel - > channelId ( ) ;
auto now = chrono : : system_clock : : now ( ) ;
2020-10-04 15:04:25 +02:00
bool conversation_private ;
auto conversation_mode = channel - > properties ( ) [ property : : CHANNEL_CONVERSATION_MODE ] . as < ChannelConversationMode > ( ) ;
if ( conversation_mode = = ChannelConversationMode : : CHANNELCONVERSATIONMODE_NONE ) {
/* nothing to do */
return ;
} else {
conversation_private = conversation_mode = = ChannelConversationMode : : CHANNELCONVERSATIONMODE_PRIVATE ;
}
2020-02-02 14:58:46 +01:00
auto flag_password = channel - > properties ( ) [ property : : CHANNEL_FLAG_PASSWORD ] . as < bool > ( ) ;
for ( const auto & client : this - > getClients ( ) ) {
if ( client - > connectionState ( ) ! = ConnectionState : : CONNECTED )
continue ;
auto type = client - > getType ( ) ;
if ( type = = ClientType : : CLIENT_INTERNAL | | type = = ClientType : : CLIENT_MUSIC )
continue ;
auto own_channel = client - > currentChannel = = channel ;
if ( conversation_private & & ! own_channel )
continue ;
if ( type ! = ClientType : : CLIENT_TEAMSPEAK | | own_channel ) {
if ( ! own_channel & & & * client ! = client ) {
if ( flag_password )
continue ; /* TODO: Send notification about new message. The client then could request messages via message history */
2020-02-16 19:02:06 +01:00
if ( auto err_perm { client - > calculate_and_get_join_state ( channel ) } ; err_perm )
2020-02-02 14:58:46 +01:00
continue ;
}
2020-02-04 18:09:47 +01:00
client - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_CHANNEL , sender , client_id , channel_id , now , message ) ;
2020-02-02 14:58:46 +01:00
}
}
if ( ! conversation_private ) {
auto conversations = this - > conversation_manager ( ) ;
auto conversation = conversations - > get_or_create ( channel - > channelId ( ) ) ;
2020-02-16 13:35:29 +01:00
conversation - > register_message ( sender - > getClientDatabaseId ( ) , sender - > getUid ( ) , sender - > getDisplayName ( ) , now , message ) ;
2020-02-02 14:58:46 +01:00
}
2020-05-07 21:28:15 +02:00
}
void VirtualServer : : update_channel_from_permissions ( const std : : shared_ptr < BasicChannel > & channel , const std : : shared_ptr < ConnectedClient > & issuer ) {
bool require_view_update ;
auto property_updates = channel - > update_properties_from_permissions ( require_view_update ) ;
if ( ! property_updates . empty ( ) ) {
this - > forEachClient ( [ & ] ( const std : : shared_ptr < ConnectedClient > & cl ) {
shared_lock client_channel_lock ( cl - > channel_lock ) ;
cl - > notifyChannelEdited ( channel , property_updates , issuer , false ) ;
} ) ;
}
if ( require_view_update ) {
auto l_source = this - > channelTree - > findLinkedChannel ( channel - > channelId ( ) ) ;
this - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & cl ) {
/* server tree read lock still active */
auto l_target = ! cl - > currentChannel ? nullptr : cl - > server - > channelTree - > findLinkedChannel ( cl - > currentChannel - > channelId ( ) ) ;
sassert ( l_source ) ;
if ( cl - > currentChannel ) sassert ( l_target ) ;
{
unique_lock client_channel_lock ( cl - > channel_lock ) ;
deque < ChannelId > deleted ;
for ( const auto & [ flag_visible , channel ] : cl - > channels - > update_channel ( l_source , l_target ) ) {
if ( flag_visible ) {
cl - > notifyChannelShow ( channel - > channel ( ) , channel - > previous_channel ) ;
} else {
deleted . push_back ( channel - > channelId ( ) ) ;
}
}
if ( ! deleted . empty ( ) )
cl - > notifyChannelHide ( deleted , false ) ;
}
} ) ;
}
2019-07-17 19:37:18 +02:00
}