333 lines
14 KiB
C++
333 lines
14 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;
|
|
|
|
|
|
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; }
|
|
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;
|
|
|
|
sql::SqlManager* sql;
|
|
|
|
uint16_t serverId = 1;
|
|
|
|
std::chrono::system_clock::time_point startTimestamp;
|
|
std::chrono::system_clock::time_point fileStatisticsTimestamp;
|
|
|
|
//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;
|
|
};
|
|
}
|
|
} |