2019-07-17 19:37:18 +02:00
# pragma once
# include <deque>
# include <memory>
# include <functional>
# include <ThreadPool/ThreadPool.h>
# include <arpa/inet.h>
# include <BasicChannel.h>
# include <sqlite3.h>
# include <sql/SqlQuery.h>
# include "Group.h"
# include "Properties.h"
# include "query/Command.h"
# include "channel/ServerChannel.h"
# include "manager/BanManager.h"
# include "Definitions.h"
# include "ConnectionStatistics.h"
# include "manager/TokeManager.h"
# include "manager/ComplainManager.h"
# include "DatabaseHelper.h"
# include "manager/LetterManager.h"
# include "Configuration.h"
# include "protocol/ringbuffer.h"
# include <tomcrypt.h>
# undef byte
# ifdef COMPILE_WEB_CLIENT
# include "server/WebServer.h"
# endif
template < typename T , typename _Tp >
inline bool operator = = ( T * elm , const std : : shared_ptr < _Tp > & __a ) noexcept { return elm = = __a . get ( ) ; }
template < typename T , typename _Tp >
inline bool operator = = ( const std : : shared_ptr < _Tp > & __a , T * elm ) noexcept { return elm = = __a . get ( ) ; }
template < typename T , typename _Tp >
inline bool operator ! = ( T * elm , const std : : shared_ptr < _Tp > & __a ) noexcept { return elm ! = __a . get ( ) ; }
template < typename T , typename _Tp >
inline bool operator ! = ( const std : : shared_ptr < _Tp > & __a , T * elm ) noexcept { return elm ! = __a . get ( ) ; }
namespace ts {
class ServerChannelTree ;
namespace music {
class MusicBotManager ;
}
namespace server {
class ConnectedClient ;
class VoiceClient ;
class QueryClient ;
class WebClient ;
class InternalClient ;
class InstanceHandler ;
class VoiceServer ;
class QueryServer ;
class FileServer ;
class SpeakingClient ;
class WebControlServer ;
2019-07-19 22:55:03 +02:00
namespace conversation {
class ConversationManager ;
}
2019-07-17 19:37:18 +02:00
struct ServerState {
enum value {
OFFLINE ,
BOOTING ,
ONLINE ,
SUSPENDING ,
DELETING
} ;
inline static std : : string string ( value state ) {
switch ( state ) {
case ServerState : : OFFLINE :
return " offline " ;
case ServerState : : BOOTING :
return " booting " ;
case ServerState : : ONLINE :
return " online " ;
case ServerState : : SUSPENDING :
return " suspending " ;
case ServerState : : DELETING :
return " deleting " ;
default :
return " unknown " ;
}
}
} ;
struct OnlineClientReport {
uint16_t clients_ts = 0 ;
uint16_t clients_web = 0 ;
uint16_t queries = 0 ;
uint16_t bots = 0 ;
} ;
struct CalculateCache {
bool global_skip = false ;
bool global_skip_set = false ;
std : : shared_ptr < permission : : v2 : : PermissionManager > client_permissions ;
std : : vector < std : : shared_ptr < GroupAssignment > > assignment_server_groups ;
bool assignment_server_groups_set = false ;
ChannelId assignment_channel_group_channel ;
std : : shared_ptr < GroupAssignment > assignment_channel_group ;
bool assignment_channel_group_set = false ;
std : : shared_ptr < BasicChannel > server_channel ;
ChannelId last_server_channel = 0 ;
inline std : : vector < std : : shared_ptr < GroupAssignment > > getGroupAssignments ( TSServer * server , ClientDbId cldbid , ClientType type ) ;
inline std : : shared_ptr < GroupAssignment > getChannelAssignment ( TSServer * server , ClientDbId client_dbid , ChannelId channel ) ;
inline std : : shared_ptr < BasicChannel > getServerChannel ( TSServer * , ChannelId ) ;
} ;
class TSServer {
friend class WebClient ;
friend class DataClient ;
friend class VoiceClient ;
friend class MusicClient ;
friend class ConnectedClient ;
friend class InternalClient ;
friend class QueryServer ;
friend class QueryClient ;
friend class SpeakingClient ;
friend class music : : MusicBotManager ;
friend class InstanceHandler ;
friend class ServerManager ;
public :
TSServer ( ServerId serverId , sql : : SqlManager * ) ;
~ TSServer ( ) ;
bool initialize ( bool test_properties ) ;
bool start ( std : : string & error ) ;
bool running ( ) ;
void preStop ( const std : : string & ) ;
void stop ( const std : : string & reason = ts : : config : : messages : : serverStopped ) ;
size_t onlineClients ( ) ;
OnlineClientReport onlineStats ( ) ;
size_t onlineChannels ( ) { return this - > channelTree - > channel_count ( ) ; }
std : : shared_ptr < ConnectedClient > findClient ( sockaddr_in * addr ) ;
std : : shared_ptr < ConnectedClient > findClient ( ClientId clientId ) ;
std : : deque < std : : shared_ptr < ConnectedClient > > findClientsByCldbId ( ClientDbId cldbId ) ;
std : : deque < std : : shared_ptr < ConnectedClient > > findClientsByUid ( ClientUid uid ) ;
std : : shared_ptr < ConnectedClient > findClient ( std : : string name , bool ignoreCase = true ) ;
bool forEachClient ( std : : function < void ( std : : shared_ptr < ConnectedClient > ) > ) ;
//bool forEachClient(std::function<std::shared_ptr<VoiceClient>>, bool executeLaterIfLocked = true);
std : : vector < std : : shared_ptr < ConnectedClient > > getClients ( ) ;
std : : deque < std : : shared_ptr < ConnectedClient > > getClientsByChannel ( std : : shared_ptr < BasicChannel > ) ;
std : : deque < std : : shared_ptr < ConnectedClient > > getClientsByChannelRoot ( const std : : shared_ptr < BasicChannel > & , bool lock_channel_tree ) ;
template < typename ClType >
std : : vector < std : : shared_ptr < ClType > > getClientsByChannel ( const std : : shared_ptr < BasicChannel > & ch ) {
std : : vector < std : : shared_ptr < ClType > > result ;
for ( const auto & cl : this - > getClientsByChannel ( ch ) )
if ( std : : dynamic_pointer_cast < ClType > ( cl ) )
result . push_back ( std : : dynamic_pointer_cast < ClType > ( cl ) ) ;
return result ;
}
ecc_key * serverKey ( ) { return _serverKey ; }
std : : string publicServerKey ( ) ;
Properties & properties ( ) { return * this - > _properties ; }
inline sql : : SqlManager * getSql ( ) { return this - > sql ; }
sql : : AsyncSqlPool * getSqlPool ( ) { return this - > sql - > pool ; }
inline ServerId getServerId ( ) { return this - > serverId ; }
inline ServerChannelTree * getChannelTree ( ) { return this - > channelTree ; }
inline GroupManager * getGroupManager ( ) { return this - > groups ; }
bool notifyServerEdited ( std : : shared_ptr < ConnectedClient > , std : : deque < std : : string > keys ) ;
bool notifyClientPropertyUpdates ( std : : shared_ptr < ConnectedClient > , const std : : deque < std : : shared_ptr < property : : PropertyDescription > > & keys , bool selfNotify = true ) ; /* execute only with at least channel tree read lock! */
inline bool notifyClientPropertyUpdates ( const std : : shared_ptr < ConnectedClient > & client , const std : : deque < property : : ClientProperties > & keys , bool selfNotify = true ) {
if ( keys . empty ( ) ) return false ;
std : : deque < std : : shared_ptr < property : : PropertyDescription > > _keys ;
for ( const auto & key : keys ) _keys . push_back ( property : : impl : : info < property : : ClientProperties > ( key ) ) ;
return this - > notifyClientPropertyUpdates ( client , _keys , selfNotify ) ;
} ;
void broadcastMessage ( std : : shared_ptr < ConnectedClient > , std : : string message ) ;
# ifndef __deprecated
# define __deprecated __attribute__((deprecated))
# endif
__deprecated void registerInternalClient ( std : : shared_ptr < ConnectedClient > ) ;
__deprecated void unregisterInternalClient ( std : : shared_ptr < ConnectedClient > ) ;
std : : shared_ptr < ConnectedClient > getServerRoot ( ) { return this - > serverRoot ; }
std : : string getDisplayName ( ) { return properties ( ) [ property : : VIRTUALSERVER_NAME ] ; }
std : : shared_ptr < stats : : ConnectionStatistics > getServerStatistics ( ) { return serverStatistics ; }
std : : shared_ptr < VoiceServer > getVoiceServer ( ) { return this - > udpVoiceServer ; }
WebControlServer * getWebServer ( ) { return this - > webControlServer ; }
std : : deque < std : : pair < permission : : PermissionType , permission : : PermissionValue > > calculatePermissions (
permission : : PermissionTestType ,
ClientDbId ,
const std : : deque < permission : : PermissionType > & ,
ClientType type ,
const std : : shared_ptr < BasicChannel > & channel ,
std : : shared_ptr < CalculateCache > cache = nullptr ) ;
std : : vector < std : : pair < permission : : PermissionType , permission : : v2 : : PermissionFlaggedValue > > calculatePermissions2 (
ClientDbId /* client db id */ ,
const std : : deque < permission : : PermissionType > & /* permissions to calculate */ ,
ClientType type /* client type for default permissions */ ,
ChannelId /* target channel id */ ,
bool /* calculate granted */ ,
std : : shared_ptr < CalculateCache > cache = nullptr /* calculate cache */ ) ;
permission : : PermissionValue calculatePermission ( permission : : PermissionTestType , ClientDbId , permission : : PermissionType , ClientType type , const std : : shared_ptr < BasicChannel > & channel , std : : shared_ptr < CalculateCache > cache = nullptr ) ;
permission : : PermissionValue calculatePermissionGrant ( permission : : PermissionTestType , ClientDbId , permission : : PermissionType , ClientType type , const std : : shared_ptr < BasicChannel > & channel ) ;
bool verifyServerPassword ( std : : string , bool hashed = false ) ;
void testBanStateChange ( const std : : shared_ptr < ConnectedClient > & invoker ) ;
float averagePing ( ) ;
float averagePacketLoss ( ) ;
bool resetPermissions ( std : : string & ) ;
void ensureValidDefaultGroups ( ) ;
ServerState : : value getState ( ) { return this - > state ; }
bool could_default_create_channel ( ) ;
inline std : : shared_ptr < TSServer > ref ( ) { return this - > self . lock ( ) ; }
inline bool disable_ip_saving ( ) { return this - > _disable_ip_saving ; }
inline std : : chrono : : system_clock : : time_point start_timestamp ( ) { return this - > startTimestamp ; } ;
/* Note: Use only this method to disconnect the client and notify everybody else that he has been banned! */
void notify_client_ban ( const std : : shared_ptr < ConnectedClient > & /* client */ , const std : : shared_ptr < ConnectedClient > & /* invoker */ , const std : : string & /* reason */ , size_t /* length */ ) ;
void notify_client_kick (
const std : : shared_ptr < ConnectedClient > & /* client */ ,
const std : : shared_ptr < ConnectedClient > & /* invoker */ ,
const std : : string & /* reason */ ,
const std : : shared_ptr < BasicChannel > & /* target channel */
) ;
void client_move (
const std : : shared_ptr < ConnectedClient > & /* client */ ,
std : : shared_ptr < BasicChannel > /* target channel */ ,
const std : : shared_ptr < ConnectedClient > & /* invoker */ ,
const std : : string & /* reason */ ,
ViewReasonId /* reason id */ ,
bool /* notify the client */ ,
std : : unique_lock < std : : shared_mutex > & /* tree lock */
) ;
void delete_channel (
std : : shared_ptr < ServerChannel > /* target channel */ ,
const std : : shared_ptr < ConnectedClient > & /* invoker */ ,
const std : : string & /* kick message */ ,
std : : unique_lock < std : : shared_mutex > & /* tree lock */
) ;
inline int voice_encryption_mode ( ) { return this - > _voice_encryption_mode ; }
2019-07-19 22:55:03 +02:00
inline std : : shared_ptr < conversation : : ConversationManager > conversation_manager ( ) { return this - > _conversation_manager ; }
2019-07-17 19:37:18 +02:00
protected :
bool registerClient ( std : : shared_ptr < ConnectedClient > ) ;
bool unregisterClient ( std : : shared_ptr < ConnectedClient > , std : : string , std : : unique_lock < std : : shared_mutex > & channel_tree_lock ) ;
bool assignDefaultChannel ( const std : : shared_ptr < ConnectedClient > & , bool join ) ;
private :
std : : weak_ptr < TSServer > self ;
//Locks by tick, start and stop
threads : : Mutex stateLock ;
ServerState : : value state = ServerState : : OFFLINE ;
std : : chrono : : system_clock : : time_point lastTick ;
void executeServerTick ( ) ;
std : : shared_ptr < VoiceServer > udpVoiceServer = nullptr ;
WebControlServer * webControlServer = nullptr ;
token : : TokenManager * tokenManager = nullptr ;
ComplainManager * complains = nullptr ;
letter : : LetterManager * letters = nullptr ;
std : : shared_ptr < music : : MusicBotManager > musicManager ;
std : : shared_ptr < stats : : ConnectionStatistics > serverStatistics ;
2019-07-19 22:55:03 +02:00
std : : shared_ptr < conversation : : ConversationManager > _conversation_manager ;
2019-07-17 19:37:18 +02:00
sql : : SqlManager * sql ;
uint16_t serverId = 1 ;
std : : chrono : : system_clock : : time_point startTimestamp ;
std : : chrono : : system_clock : : time_point fileStatisticsTimestamp ;
2019-07-19 22:55:03 +02:00
std : : chrono : : system_clock : : time_point conversation_cache_cleanup_timestamp ;
2019-07-17 19:37:18 +02:00
//The client list
struct {
size_t count = 0 ;
std : : mutex lock ;
std : : vector < std : : shared_ptr < ConnectedClient > > clients ;
} clients ;
std : : recursive_mutex client_nickname_lock ;
//General server properties
ecc_key * _serverKey = nullptr ;
std : : shared_ptr < Properties > _properties ;
int _voice_encryption_mode = 2 ; /* */
ServerChannelTree * channelTree = nullptr ;
std : : shared_mutex channel_tree_lock ; /* lock if access channel tree! */
GroupManager * groups = nullptr ;
std : : shared_ptr < ConnectedClient > serverRoot = nullptr ;
std : : shared_ptr < ConnectedClient > serverAdmin = nullptr ;
threads : : Mutex join_attempts_lock ;
std : : map < std : : string , uint16_t > join_attempts ;
threads : : Mutex join_lock ;
std : : chrono : : system_clock : : time_point join_last_decrease ;
std : : chrono : : milliseconds spoken_time { 0 } ;
std : : chrono : : system_clock : : time_point spoken_time_timestamp ;
bool _disable_ip_saving = false ;
} ;
}
}