2019-07-17 19:37:18 +02:00
# include <cstring>
# include <functional>
# include <protocol/buffers.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>
2021-02-28 19:03:41 +01:00
# include "./groups/GroupManager.h"
2021-03-07 19:17:20 +01:00
# include "./PermissionCalculator.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 ( ) ) ;
2021-02-28 19:03:41 +01:00
std : : string error { } ;
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 ) {
2021-03-01 14:16:44 +01:00
this - > _disable_ip_saving = prop . as_or < bool > ( false ) ;
2020-01-24 02:57:58 +01:00
return ;
2020-05-13 11:32:08 +02:00
} else if ( prop . type ( ) = = property : : VIRTUALSERVER_CODEC_ENCRYPTION_MODE ) {
2021-03-01 14:16:44 +01:00
this - > _voice_encryption_mode = prop . as_or < int > ( 0 ) ;
2020-01-24 02:57:58 +01:00
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 ;
2021-03-01 14:16:44 +01:00
file_vs - > max_networking_upload_bandwidth ( prop . as_or < int64_t > ( - 1 ) ) ;
2020-05-13 11:32:08 +02:00
} else if ( prop . type ( ) = = property : : VIRTUALSERVER_MAX_DOWNLOAD_TOTAL_BANDWIDTH ) {
auto file_vs = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! file_vs ) return ;
2021-03-01 14:16:44 +01:00
file_vs - > max_networking_download_bandwidth ( prop . as_or < int64_t > ( - 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 ;
}
2021-03-01 14:16:44 +01:00
serverInstance - > action_logger ( ) - > toggle_logging_group ( server_id , action_type ,
prop . as_or < bool > ( true ) ) ;
2020-09-15 01:18:35 +02:00
} ;
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
} ) {
2021-03-01 14:16:44 +01:00
auto prop = this - > _properties - > get ( property : : PROP_TYPE_SERVER , property ) ;
2020-09-15 01:18:35 +02:00
sync_property ( prop ) ;
}
this - > _properties - > registerNotifyHandler ( [ sync_property ] ( Property & prop ) {
sync_property ( prop ) ;
} ) ;
}
2021-03-01 14:16:44 +01:00
if ( ! properties ( ) [ property : : VIRTUALSERVER_KEYPAIR ] . value ( ) . empty ( ) ) {
2020-01-24 02:57:58 +01:00
debugMessage ( this - > serverId , " Importing server keypair " ) ;
this - > _serverKey = new ecc_key ;
2021-03-01 14:16:44 +01:00
auto bytes = base64 : : decode ( properties ( ) [ property : : VIRTUALSERVER_KEYPAIR ] . value ( ) ) ;
2020-01-24 02:57:58 +01:00
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 ( ) ;
2021-02-28 19:03:41 +01:00
this - > groups_manager_ = std : : make_shared < groups : : GroupManager > ( this - > getSql ( ) , this - > getServerId ( ) , serverInstance - > group_manager ( ) ) ;
if ( ! this - > groups_manager_ - > initialize ( this - > groups_manager_ , error ) ) {
logCritical ( this - > getServerId ( ) , " Failed to initialize group manager: {} " , error ) ;
2020-01-24 02:57:58 +01:00
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 ) ;
2021-03-01 14:16:44 +01:00
if ( default_channel - > properties ( ) [ property : : CHANNEL_FLAG_PASSWORD ] . as_or < bool > ( false ) )
2020-01-24 02:57:58 +01:00
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 " ) ;
2021-02-28 19:03:41 +01:00
{
using groups : : GroupLoadResult ;
bool initialize_groups { false } ;
switch ( this - > groups_manager_ - > server_groups ( ) - > load_data ( true ) ) {
case GroupLoadResult : : SUCCESS :
break ;
case GroupLoadResult : : NO_GROUPS :
initialize_groups = true ;
break ;
case GroupLoadResult : : DATABASE_ERROR :
logError ( this - > getServerId ( ) , " Failed to load server groups (Database error) " ) ;
return false ;
}
switch ( this - > groups_manager_ - > channel_groups ( ) - > load_data ( true ) ) {
case GroupLoadResult : : SUCCESS :
break ;
case GroupLoadResult : : NO_GROUPS :
initialize_groups = true ;
break ;
case GroupLoadResult : : DATABASE_ERROR :
logError ( this - > getServerId ( ) , " Failed to load channel groups (Database error) " ) ;
return false ;
}
if ( ! this - > groups_manager_ - > assignments ( ) . load_data ( error ) ) {
logError ( this - > getServerId ( ) , " Failed to load group assignments: {} " , error ) ;
return false ;
}
if ( initialize_groups ) {
2021-03-01 19:22:15 +01:00
if ( ! this - > properties ( ) [ property : : VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY ] . value ( ) . empty ( ) ) {
2021-02-28 19:03:41 +01:00
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 ---------------------- " ) ;
2020-01-24 02:57:58 +01:00
}
}
2021-02-28 19:03:41 +01:00
2020-01-24 02:57:58 +01:00
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
2021-03-01 14:16:44 +01:00
this - > serverRoot = std : : make_shared < InternalClient > ( this - > sql , self . lock ( ) ,
this - > properties ( ) [ property : : VIRTUALSERVER_NAME ] . value ( ) , false ) ;
2021-02-21 20:28:59 +01:00
this - > serverRoot - > initialize_weak_reference ( this - > serverRoot ) ;
2021-03-01 14:37:03 +01:00
this - > properties ( ) - > registerNotifyHandler ( [ & ] ( Property & property ) {
2021-03-01 14:16:44 +01:00
if ( property . type ( ) = = property : : VIRTUALSERVER_NAME ) {
static_pointer_cast < InternalClient > ( this - > serverRoot ) - > properties ( ) [ property : : CLIENT_NICKNAME ] = property . value ( ) ;
}
2020-01-24 02:57:58 +01:00
} ) ;
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 ( ) ;
2021-03-01 14:16:44 +01:00
file_vs - > max_networking_download_bandwidth (
this - > properties ( ) [ property : : VIRTUALSERVER_MAX_DOWNLOAD_TOTAL_BANDWIDTH ] . as_or < int64_t > ( - 1 ) ) ;
file_vs - > max_networking_upload_bandwidth (
this - > properties ( ) [ property : : VIRTUALSERVER_MAX_UPLOAD_TOTAL_BANDWIDTH ] . as_or < int64_t > ( - 1 ) ) ;
2020-05-13 11:32:08 +02:00
}
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 ( ) ;
2021-03-07 19:17:20 +01:00
{
auto ref_self = this - > self ;
this - > task_notify_channel_group_list = multi_shot_task { serverInstance - > general_task_executor ( ) , " server notify channel group list " , [ ref_self ] {
auto this_ = ref_self . lock ( ) ;
if ( this_ ) {
this_ - > forEachClient ( [ ] ( const std : : shared_ptr < ConnectedClient > & client ) {
std : : optional < ts : : command_builder > generated_notify { } ;
client - > notifyChannelGroupList ( generated_notify , true ) ;
} ) ;
}
} } ;
this - > task_notify_server_group_list = multi_shot_task { serverInstance - > general_task_executor ( ) , " server notify server group list " , [ ref_self ] {
auto this_ = ref_self . lock ( ) ;
if ( this_ ) {
this_ - > forEachClient ( [ ] ( const std : : shared_ptr < ConnectedClient > & client ) {
std : : optional < ts : : command_builder > generated_notify { } ;
client - > notifyServerGroupList ( generated_notify , true ) ;
} ) ;
}
} } ;
}
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 - > 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
}
2021-03-01 14:16:44 +01:00
auto host = this - > properties ( ) [ property : : VIRTUALSERVER_HOST ] . value ( ) ;
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 ;
}
2021-03-01 14:16:44 +01:00
if ( this - > properties ( ) [ property : : VIRTUALSERVER_PORT ] . as_or < uint16_t > ( 0 ) < = 0 ) {
2019-07-17 19:37:18 +02:00
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 ;
2021-03-01 14:16:44 +01:00
addr . sin_port = htons ( this - > properties ( ) [ property : : VIRTUALSERVER_PORT ] . as_or < uint16_t > ( 0 ) ) ;
2020-01-24 02:57:58 +01:00
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 ;
2021-03-01 14:16:44 +01:00
addr . sin6_port = htons ( this - > properties ( ) [ property : : VIRTUALSERVER_PORT ] . as_or < uint16_t > ( 0 ) ) ;
2020-01-24 02:57:58 +01:00
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 ( ) )
2021-03-01 14:16:44 +01:00
web_host_string = this - > properties ( ) [ property : : VIRTUALSERVER_HOST ] . as_or < string > ( 0 ) ;
2019-07-23 10:37:56 +02:00
2021-03-01 14:16:44 +01:00
auto web_port = this - > properties ( ) [ property : : VIRTUALSERVER_WEB_PORT ] . as_or < uint16_t > ( 0 ) ;
2020-01-24 02:57:58 +01:00
if ( web_port = = 0 )
2021-03-01 14:16:44 +01:00
web_port = this - > properties ( ) [ property : : VIRTUALSERVER_PORT ] . as_or < uint16_t > ( 0 ) ;
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
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 :
2021-03-01 14:37:03 +01:00
case CLIENT_TEASPEAK :
2020-01-24 02:57:58 +01:00
response . clients_ts + + ;
break ;
case CLIENT_WEB :
response . clients_web + + ;
break ;
case CLIENT_QUERY :
response . queries + + ;
break ;
case CLIENT_MUSIC :
response . bots + + ;
break ;
2021-03-01 14:37:03 +01:00
case CLIENT_INTERNAL :
case MAX :
2020-01-24 02:57:58 +01:00
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 { } ) ;
2021-03-07 19:17:20 +01:00
if ( close_lock . owns_lock ( ) ) {
//If not locked than client is on the way to disconnect
2020-01-24 02:57:58 +01:00
if ( elm - > state = = ConnectionState : : CONNECTED & & elm - > getType ( ) ! = ClientType : : CLIENT_INTERNAL ) {
function ( elm ) ;
}
2021-03-07 19:17:20 +01:00
}
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 ;
}
2021-03-01 14:16:44 +01:00
cmd [ key ] = properties ( ) [ info ] . value ( ) ;
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
} ) ;
}
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 ) {
2021-03-07 19:17:20 +01:00
ClientPermissionCalculator calculator { this - > ref ( ) , client_dbid , client_type , channel_id } ;
return calculator . calculate_permissions ( permissions , calculate_granted ) ;
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 ) {
2021-03-07 19:17:20 +01:00
if ( ! this - > properties ( ) [ property : : VIRTUALSERVER_FLAG_PASSWORD ] . as_or < bool > ( false ) ) {
return true ;
}
if ( password . empty ( ) ) {
return false ;
}
2019-07-17 19:37:18 +02:00
2021-03-07 19:17:20 +01:00
if ( ! hashed ) {
password = base64 : : encode ( digest : : sha1 ( password ) ) ;
2019-07-17 19:37:18 +02:00
}
2021-03-01 14:16:44 +01:00
return password = = this - > properties ( ) [ property : : VIRTUALSERVER_PASSWORD ] . value ( ) ;
2019-07-17 19:37:18 +02:00
}
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 ) {
2021-03-07 19:17:20 +01:00
std : : map < GroupId , GroupId > server_group_mapping { } ;
std : : map < GroupId , GroupId > channel_group_mapping { } ;
2020-01-24 02:57:58 +01:00
{
2021-03-11 14:12:12 +01:00
this - > group_manager ( ) - > server_groups ( ) - > reset_groups ( server_group_mapping ) ;
this - > group_manager ( ) - > channel_groups ( ) - > reset_groups ( channel_group_mapping ) ;
2021-03-07 19:17:20 +01:00
this - > group_manager ( ) - > assignments ( ) . reset_all ( ) ;
2020-01-24 02:57:58 +01:00
}
2021-03-07 19:17:20 +01:00
/* assign the properties */
{
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_SERVER_GROUP ] =
server_group_mapping [ serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP ] . as_or < GroupId > ( 0 ) ] ;
2020-01-24 02:57:58 +01:00
2021-03-07 19:17:20 +01:00
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_MUSIC_GROUP ] =
server_group_mapping [ serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP ] . as_or < GroupId > ( 0 ) ] ;
2020-01-24 02:57:58 +01:00
2021-03-07 19:17:20 +01:00
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] =
channel_group_mapping [ serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP ] . as_or < GroupId > ( 0 ) ] ;
2020-01-24 02:57:58 +01:00
2021-03-07 19:17:20 +01:00
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] =
channel_group_mapping [ serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP ] . as_or < GroupId > ( 0 ) ] ;
2020-01-24 02:57:58 +01:00
}
2021-03-07 19:17:20 +01:00
{
2021-02-25 11:13:30 +01:00
this - > properties ( ) [ property : : VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY ] = false ;
2021-03-07 19:17:20 +01:00
auto admin_group_id = server_group_mapping [ serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP ] . as_or < GroupId > ( 0 ) ] ;
auto admin_group = this - > group_manager ( ) - > server_groups ( ) - > find_group ( groups : : GroupCalculateMode : : GLOBAL , admin_group_id ) ;
if ( ! admin_group ) {
logCritical ( this - > getServerId ( ) , " Missing default server admin group. Don't generate a new token. " ) ;
new_permission_token = " missing server admin group " ;
} else {
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. " ) ;
} else {
std : : vector < token : : TokenAction > actions { } ;
actions . push_back ( token : : TokenAction {
. id = 0 ,
. type = token : : ActionType : : AddServerGroup ,
. id1 = admin_group - > 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 ;
this - > properties ( ) [ property : : VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY ] = true ;
}
}
2020-01-24 02:57:58 +01:00
}
2021-03-07 19:17:20 +01:00
2020-01-24 02:57:58 +01:00
this - > ensureValidDefaultGroups ( ) ;
for ( const auto & client : this - > getClients ( ) ) {
2021-03-07 19:17:20 +01:00
client - > task_update_displayed_groups . enqueue ( ) ;
client - > task_update_needed_permissions . enqueue ( ) ;
2021-02-21 21:56:52 +01:00
client - > task_update_channel_client_properties . enqueue ( ) ;
2020-01-24 02:57:58 +01:00
}
2021-03-07 19:17:20 +01:00
this - > task_notify_channel_group_list . enqueue ( ) ;
this - > task_notify_server_group_list . 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 ( ) {
2021-03-11 14:12:12 +01:00
/* TODO: FIXME: Impl! */
#if 0
2021-02-28 19:03:41 +01:00
auto default_server_group = this - > group_manager ( ) - > defaultGroup ( GROUPTARGET_SERVER , true ) ;
2020-01-24 02:57:58 +01:00
if ( ! default_server_group ) {
logError ( this - > serverId , " Missing server's default server group! (Id: {}) " , this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_SERVER_GROUP ] . value ( ) ) ;
2021-02-28 19:03:41 +01:00
default_server_group = this - > group_manager ( ) - > availableServerGroups ( false ) . front ( ) ;
2020-01-24 02:57:58 +01:00
logError ( this - > serverId , " Using {} ({}) instead! " , default_server_group - > groupId ( ) , default_server_group - > name ( ) ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_SERVER_GROUP ] = default_server_group - > groupId ( ) ;
}
2021-02-28 19:03:41 +01:00
auto default_music_group = this - > group_manager ( ) - > defaultGroup ( GROUPTARGET_SERVER , true ) ;
2020-01-24 02:57:58 +01:00
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 ( ) ;
}
2021-02-28 19:03:41 +01:00
auto default_channel_group = this - > group_manager ( ) - > defaultGroup ( GROUPTARGET_CHANNEL , true ) ;
2020-01-24 02:57:58 +01:00
if ( ! default_channel_group ) {
logError ( this - > serverId , " Missing server's default channel group! (Id: {}) " , this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] . value ( ) ) ;
2021-02-28 19:03:41 +01:00
default_channel_group = this - > group_manager ( ) - > availableChannelGroups ( false ) . front ( ) ;
2020-01-24 02:57:58 +01:00
logError ( this - > serverId , " Using {} ({}) instead! " , default_channel_group - > groupId ( ) , default_channel_group - > name ( ) ) ;
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] = default_channel_group - > groupId ( ) ;
}
2021-03-01 19:22:15 +01:00
auto admin_channel_group = this - > group_manager ( ) - > findGroupLocal (
2021-03-01 14:16:44 +01:00
this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] . as_or < GroupId > ( 0 ) ) ;
2020-01-24 02:57:58 +01:00
if ( ! admin_channel_group ) {
logError ( this - > serverId , " Missing server's default channel admin group! (Id: {}) " , this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] . value ( ) ) ;
2021-02-28 19:03:41 +01:00
admin_channel_group = this - > group_manager ( ) - > availableChannelGroups ( false ) . front ( ) ;
2020-01-24 02:57:58 +01:00
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 ( ) ;
}
2021-03-11 14:12:12 +01:00
# endif
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 ;
2021-03-01 14:16:44 +01:00
auto conversation_mode = channel - > properties ( ) [ property : : CHANNEL_CONVERSATION_MODE ] . as_or < ChannelConversationMode > ( ChannelConversationMode : : CHANNELCONVERSATIONMODE_PRIVATE ) ;
2020-10-04 15:04:25 +02:00
if ( conversation_mode = = ChannelConversationMode : : CHANNELCONVERSATIONMODE_NONE ) {
/* nothing to do */
return ;
} else {
conversation_private = conversation_mode = = ChannelConversationMode : : CHANNELCONVERSATIONMODE_PRIVATE ;
}
2021-03-01 14:16:44 +01:00
auto flag_password = channel - > properties ( ) [ property : : CHANNEL_FLAG_PASSWORD ] . as_or < bool > ( false ) ;
2020-02-02 14:58:46 +01:00
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 ( ) ) ;
}
}
2021-03-07 19:17:20 +01:00
if ( ! deleted . empty ( ) ) {
2020-05-07 21:28:15 +02:00
cl - > notifyChannelHide ( deleted , false ) ;
2021-03-07 19:17:20 +01:00
}
2020-05-07 21:28:15 +02:00
}
} ) ;
}
2021-02-28 19:03:41 +01:00
}
std : : shared_ptr < groups : : ChannelGroup > VirtualServer : : default_channel_group ( ) {
2021-03-07 19:17:20 +01:00
auto group_id = this - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] . as_or < GroupId > ( 0 ) ;
2021-02-28 19:03:41 +01:00
auto group = this - > group_manager ( ) - > channel_groups ( ) - > find_group ( groups : : GroupCalculateMode : : GLOBAL , group_id ) ;
if ( ! group ) {
auto groups = this - > group_manager ( ) - > channel_groups ( ) - > available_groups ( groups : : GroupCalculateMode : : GLOBAL ) ;
/* TODO: Log warning? */
group = groups . back ( ) ;
}
return group ;
2019-07-17 19:37:18 +02:00
}