343 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			343 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #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;
 | |
| 
 | |
| 
 | |
|         namespace conversation {
 | |
|         	class ConversationManager;
 | |
|         }
 | |
| 
 | |
|         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::v2::PermissionFlaggedValue calculatePermission2(permission::PermissionType, ClientDbId, ClientType type, ChannelId 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; }
 | |
| 			    inline std::shared_ptr<conversation::ConversationManager> conversation_manager() { return this->_conversation_manager; }
 | |
|             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;
 | |
|                 std::shared_ptr<conversation::ConversationManager> _conversation_manager;
 | |
| 
 | |
|                 sql::SqlManager* sql;
 | |
| 
 | |
|                 uint16_t serverId = 1;
 | |
| 
 | |
| 			    std::chrono::system_clock::time_point startTimestamp;
 | |
| 			    std::chrono::system_clock::time_point fileStatisticsTimestamp;
 | |
| 			    std::chrono::system_clock::time_point conversation_cache_cleanup_timestamp;
 | |
| 
 | |
|                 //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;
 | |
|         };
 | |
|     }
 | |
| } |