Optimized 1.4.11
This commit is contained in:
parent
d52496600f
commit
c627690011
@ -1 +1 @@
|
|||||||
Subproject commit c3a2818a7f698f3a0efbf32426924299214106da
|
Subproject commit 71efb006ebdce2740e652306df36e34465a21dfc
|
@ -235,7 +235,7 @@ target_link_libraries(PermMapHelper
|
|||||||
|
|
||||||
SET(CPACK_PACKAGE_VERSION_MAJOR "1")
|
SET(CPACK_PACKAGE_VERSION_MAJOR "1")
|
||||||
SET(CPACK_PACKAGE_VERSION_MINOR "4")
|
SET(CPACK_PACKAGE_VERSION_MINOR "4")
|
||||||
SET(CPACK_PACKAGE_VERSION_PATCH "10")
|
SET(CPACK_PACKAGE_VERSION_PATCH "11")
|
||||||
if (BUILD_TYPE_NAME EQUAL OFF)
|
if (BUILD_TYPE_NAME EQUAL OFF)
|
||||||
SET(CPACK_PACKAGE_VERSION_DATA "beta")
|
SET(CPACK_PACKAGE_VERSION_DATA "beta")
|
||||||
elseif (BUILD_TYPE_NAME STREQUAL "")
|
elseif (BUILD_TYPE_NAME STREQUAL "")
|
||||||
|
@ -309,6 +309,32 @@ int main(int argc, char** argv) {
|
|||||||
logMessageFmt(true, LOG_GENERAL, strobf("[]---------------------------------------------------------[]").string());
|
logMessageFmt(true, LOG_GENERAL, strobf("[]---------------------------------------------------------[]").string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
rlimit rlimit{0, 0};
|
||||||
|
//forum.teaspeak.de/index.php?threads/2570/
|
||||||
|
constexpr auto seek_help_message = "Fore more help visit the forum and read this thread (https://forum.teaspeak.de/index.php?threads/2570/).";
|
||||||
|
if(getrlimit(RLIMIT_NOFILE, &rlimit) != 0) {
|
||||||
|
//prlimit -n4096 -p pid_of_process
|
||||||
|
logWarningFmt(true, LOG_INSTANCE, "Failed to get open file rlimit ({}). Please ensure its over 16384.", strerror(errno));
|
||||||
|
logWarningFmt(true, LOG_INSTANCE, seek_help_message);
|
||||||
|
} else {
|
||||||
|
const auto original = rlimit.rlim_cur;
|
||||||
|
rlimit.rlim_cur = std::max(rlimit.rlim_cur, std::min(rlimit.rlim_max, (rlim_t) 16384));
|
||||||
|
if(original != rlimit.rlim_cur) {
|
||||||
|
if(setrlimit(RLIMIT_NOFILE, &rlimit) != 0) {
|
||||||
|
logErrorFmt(true, LOG_INSTANCE, "Failed to set open file rlimit to {} ({}). Please ensure its over 16384.", rlimit.rlim_cur, strerror(errno));
|
||||||
|
logWarningFmt(true, LOG_INSTANCE, seek_help_message);
|
||||||
|
goto rlimit_updates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(rlimit.rlim_cur < 16384) {
|
||||||
|
logWarningFmt(true, LOG_INSTANCE, "Open file rlimit is bellow 16384 ({}). Please increase the system file descriptor limits.", rlimit.rlim_cur);
|
||||||
|
logWarningFmt(true, LOG_INSTANCE, seek_help_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rlimit_updates:;
|
||||||
|
}
|
||||||
|
|
||||||
logMessage(LOG_GENERAL, "Starting TeaSpeak-Server v{}", build::version()->string(true));
|
logMessage(LOG_GENERAL, "Starting TeaSpeak-Server v{}", build::version()->string(true));
|
||||||
logMessage(LOG_GENERAL, "Starting music providers");
|
logMessage(LOG_GENERAL, "Starting music providers");
|
||||||
|
|
||||||
|
@ -529,51 +529,66 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
CMD_CHK_AND_INC_FLOOD_POINTS(25);
|
CMD_CHK_AND_INC_FLOOD_POINTS(25);
|
||||||
CMD_CHK_PARM_COUNT(1);
|
CMD_CHK_PARM_COUNT(1);
|
||||||
|
|
||||||
//TODO: Use for this here the cache as well!
|
std::shared_ptr<TreeView::LinkedTreeEntry> parent = nullptr;
|
||||||
auto permission_cache = make_shared<CalculateCache>();
|
std::shared_ptr<BasicChannel> created_channel = nullptr, old_default_channel;
|
||||||
if (cmd[0].has("cpid") && cmd["cpid"].as<uint64_t>() != 0) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_child, 1, permission_cache);
|
|
||||||
if (cmd[0].has("channel_order")) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_with_sortorder, 1, permission_cache);
|
|
||||||
|
|
||||||
if(!cmd[0].has("channel_flag_permanent")) cmd[0]["channel_flag_permanent"] = false;
|
|
||||||
if(!cmd[0].has("channel_flag_semi_permanent")) cmd[0]["channel_flag_semi_permanent"] = false;
|
|
||||||
if(!cmd[0].has("channel_flag_default")) cmd[0]["channel_flag_default"] = false;
|
|
||||||
if(!cmd[0].has("channel_flag_password")) cmd[0]["channel_flag_password"] = false;
|
|
||||||
|
|
||||||
if (cmd[0]["channel_flag_permanent"].as<bool>()) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_permanent, 1, permission_cache);
|
|
||||||
else if (cmd[0]["channel_flag_semi_permanent"].as<bool>()) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_semi_permanent, 1, permission_cache);
|
|
||||||
else ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_temporary, 1, permission_cache);
|
|
||||||
|
|
||||||
if (!cmd[0]["channel_flag_permanent"].as<bool>() && !this->server) return command_result{error::parameter_invalid, "You can only create a permanent channel"};
|
|
||||||
|
|
||||||
if (cmd[0]["channel_flag_default"].as<bool>()) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_with_default, 1, permission_cache);
|
|
||||||
if (cmd[0]["channel_flag_password"].as<bool>()) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_with_password, 1, permission_cache);
|
|
||||||
else if(permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_create_modify_with_force_password, 0, false, permission_cache)))
|
|
||||||
return command_result{permission::b_channel_create_modify_with_force_password};
|
|
||||||
|
|
||||||
if(cmd[0].has("channel_password") && this->getType() == ClientType::CLIENT_QUERY)
|
|
||||||
cmd["channel_password"] = base64::decode(digest::sha1(cmd["channel_password"].string()));
|
|
||||||
if (cmd[0].has("channel_description")) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_with_description, 1, permission_cache);
|
|
||||||
if (cmd[0].has("channel_maxclients") || (cmd[0].has("channel_flag_maxclients_unlimited") && !cmd["channel_flag_maxclients_unlimited"].as<bool>())) {
|
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_with_maxclients, 1, permission_cache);
|
|
||||||
if(!cmd[0]["channel_flag_permanent"].as<bool>() && !cmd[0]["channel_flag_semi_permanent"].as<bool>()) {
|
|
||||||
cmd["channel_maxclients"] = -1;
|
|
||||||
cmd["channel_flag_maxclients_unlimited"] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cmd[0].has("channel_maxfamilyclients")) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_with_maxfamilyclients, 1, permission_cache);
|
|
||||||
if (cmd[0].has("channel_needed_talk_power")) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_with_needed_talk_power, 1, permission_cache);
|
|
||||||
if (cmd[0].has("channel_topic")) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_with_topic, 1, permission_cache);
|
|
||||||
|
|
||||||
auto target_tree = this->server ? this->server->channelTree : serverInstance->getChannelTree().get();
|
auto target_tree = this->server ? this->server->channelTree : serverInstance->getChannelTree().get();
|
||||||
auto& tree_lock = this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock();
|
auto& tree_lock = this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock();
|
||||||
unique_lock tree_channel_lock(tree_lock);
|
unique_lock tree_channel_lock(tree_lock);
|
||||||
|
|
||||||
|
if (cmd[0].has("cpid") && cmd["cpid"].as<ChannelId>() != 0 && cmd["cpid"].as<int>() != -1) {
|
||||||
|
parent = target_tree->findLinkedChannel(cmd["cpid"].as<ChannelId>());
|
||||||
|
if (!parent) return command_result{error::channel_invalid_id, "Cant resolve parent channel"};
|
||||||
|
}
|
||||||
|
ChannelId parent_channel_id = parent ? parent->entry->channelId() : 0;
|
||||||
|
|
||||||
|
#define test_permission(required, permission_type) \
|
||||||
|
do {\
|
||||||
|
if(!permission::v2::permission_granted(required, this->calculate_permission(permission_type, parent_channel_id, false, permission_cache))) \
|
||||||
|
return command_result{permission_type};\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: Use for this here the cache as well!
|
||||||
|
auto permission_cache = make_shared<CalculateCache>();
|
||||||
|
if(parent) test_permission(1, permission::b_channel_create_child);
|
||||||
|
if (cmd[0].has("channel_order")) test_permission(1, permission::b_channel_create_with_sortorder);
|
||||||
|
if(!cmd[0].has("channel_flag_permanent")) cmd[0]["channel_flag_permanent"] = false;
|
||||||
|
if(!cmd[0].has("channel_flag_semi_permanent")) cmd[0]["channel_flag_semi_permanent"] = false;
|
||||||
|
if(!cmd[0].has("channel_flag_default")) cmd[0]["channel_flag_default"] = false;
|
||||||
|
if(!cmd[0].has("channel_flag_password")) cmd[0]["channel_flag_password"] = false;
|
||||||
|
|
||||||
|
if (cmd[0]["channel_flag_permanent"].as<bool>()) test_permission(1, permission::b_channel_create_permanent);
|
||||||
|
else if (cmd[0]["channel_flag_semi_permanent"].as<bool>()) test_permission(1, permission::b_channel_create_semi_permanent);
|
||||||
|
else test_permission(1, permission::b_channel_create_temporary);
|
||||||
|
|
||||||
|
if (!cmd[0]["channel_flag_permanent"].as<bool>() && !this->server) return command_result{error::parameter_invalid, "You can only create a permanent channel"};
|
||||||
|
|
||||||
|
if (cmd[0]["channel_flag_default"].as<bool>()) test_permission(1, permission::b_channel_create_with_default);
|
||||||
|
if (cmd[0]["channel_flag_password"].as<bool>()) test_permission(1, permission::b_channel_create_with_password);
|
||||||
|
else if(permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_create_modify_with_force_password, parent_channel_id, false, permission_cache)))
|
||||||
|
return command_result{permission::b_channel_create_modify_with_force_password};
|
||||||
|
|
||||||
|
if(cmd[0].has("channel_password") && this->getType() == ClientType::CLIENT_QUERY)
|
||||||
|
cmd["channel_password"] = base64::decode(digest::sha1(cmd["channel_password"].string()));
|
||||||
|
if (cmd[0].has("channel_description")) test_permission(1, permission::b_channel_create_with_description);
|
||||||
|
if (cmd[0].has("channel_maxclients") || (cmd[0].has("channel_flag_maxclients_unlimited") && !cmd["channel_flag_maxclients_unlimited"].as<bool>())) {
|
||||||
|
test_permission(1, permission::b_channel_create_with_maxclients);
|
||||||
|
if(!cmd[0]["channel_flag_permanent"].as<bool>() && !cmd[0]["channel_flag_semi_permanent"].as<bool>()) {
|
||||||
|
cmd["channel_maxclients"] = -1;
|
||||||
|
cmd["channel_flag_maxclients_unlimited"] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cmd[0].has("channel_maxfamilyclients")) test_permission(1, permission::b_channel_create_with_maxfamilyclients);
|
||||||
|
if (cmd[0].has("channel_needed_talk_power")) test_permission(1,permission::b_channel_create_with_needed_talk_power);
|
||||||
|
if (cmd[0].has("channel_topic")) test_permission(1,permission::b_channel_create_with_topic);
|
||||||
|
|
||||||
if(cmd[0].has("channel_conversation_history_length")) {
|
if(cmd[0].has("channel_conversation_history_length")) {
|
||||||
auto value = cmd["channel_conversation_history_length"].as<int64_t>();
|
auto value = cmd["channel_conversation_history_length"].as<int64_t>();
|
||||||
if(value == 0) {
|
if(value == 0) {
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::b_channel_create_modify_conversation_history_unlimited, 1, permission_cache);
|
test_permission(1, permission::b_channel_create_modify_conversation_history_unlimited);
|
||||||
} else {
|
} else {
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::i_channel_create_modify_conversation_history_length, 1, permission_cache);
|
test_permission(1, permission::i_channel_create_modify_conversation_history_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,9 +600,10 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
else
|
else
|
||||||
cmd["channel_delete_delay"] = 0;
|
cmd["channel_delete_delay"] = 0;
|
||||||
} else {
|
} else {
|
||||||
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(permission::i_channel_create_modify_with_temp_delete_delay, cmd["channel_delete_delay"].as<permission::PermissionValue>(), permission_cache);
|
test_permission(cmd["channel_delete_delay"].as<permission::PermissionValue>(), permission::i_channel_create_modify_with_temp_delete_delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#undef test_permission
|
||||||
|
|
||||||
{
|
{
|
||||||
size_t created_total = 0, created_tmp = 0, created_semi = 0, created_perm = 0;
|
size_t created_total = 0, created_tmp = 0, created_semi = 0, created_perm = 0;
|
||||||
@ -607,14 +623,14 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
if(this->server && created_total >= this->server->properties()[property::VIRTUALSERVER_MAX_CHANNELS].as<uint64_t>())
|
if(this->server && created_total >= this->server->properties()[property::VIRTUALSERVER_MAX_CHANNELS].as<uint64_t>())
|
||||||
return command_result{error::channel_limit_reached};
|
return command_result{error::channel_limit_reached};
|
||||||
|
|
||||||
auto max_channels = this->calculate_permission(permission::i_client_max_channels, 0, false, permission_cache);
|
auto max_channels = this->calculate_permission(permission::i_client_max_channels, parent_channel_id, false, permission_cache);
|
||||||
if(max_channels.has_value) {
|
if(max_channels.has_value) {
|
||||||
if(!permission::v2::permission_granted(created_perm + created_semi + created_tmp + 1, max_channels))
|
if(!permission::v2::permission_granted(created_perm + created_semi + created_tmp + 1, max_channels))
|
||||||
return command_result{permission::i_client_max_channels};
|
return command_result{permission::i_client_max_channels};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd[0]["channel_flag_permanent"].as<bool>()) {
|
if (cmd[0]["channel_flag_permanent"].as<bool>()) {
|
||||||
max_channels = this->calculate_permission(permission::i_client_max_permanent_channels, 0, false, permission_cache);
|
max_channels = this->calculate_permission(permission::i_client_max_permanent_channels, parent_channel_id, false, permission_cache);
|
||||||
|
|
||||||
if(max_channels.has_value) {
|
if(max_channels.has_value) {
|
||||||
if(!permission::v2::permission_granted(created_perm + 1, max_channels))
|
if(!permission::v2::permission_granted(created_perm + 1, max_channels))
|
||||||
@ -622,7 +638,7 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cmd[0]["channel_flag_semi_permanent"].as<bool>()) {
|
else if (cmd[0]["channel_flag_semi_permanent"].as<bool>()) {
|
||||||
max_channels = this->calculate_permission(permission::i_client_max_semi_channels, 0, false, permission_cache);
|
max_channels = this->calculate_permission(permission::i_client_max_semi_channels, parent_channel_id, false, permission_cache);
|
||||||
|
|
||||||
if(max_channels.has_value) {
|
if(max_channels.has_value) {
|
||||||
if(!permission::v2::permission_granted(created_semi + 1, max_channels))
|
if(!permission::v2::permission_granted(created_semi + 1, max_channels))
|
||||||
@ -630,7 +646,7 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
max_channels = this->calculate_permission(permission::i_client_max_temporary_channels, 0, false, permission_cache);
|
max_channels = this->calculate_permission(permission::i_client_max_temporary_channels, parent_channel_id, false, permission_cache);
|
||||||
|
|
||||||
if(max_channels.has_value) {
|
if(max_channels.has_value) {
|
||||||
if(!permission::v2::permission_granted(created_tmp + 1, max_channels))
|
if(!permission::v2::permission_granted(created_tmp + 1, max_channels))
|
||||||
@ -640,20 +656,12 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO check voice (opus etc)
|
//TODO check voice (opus etc)
|
||||||
std::shared_ptr<TreeView::LinkedTreeEntry> parent = nullptr;
|
|
||||||
std::shared_ptr<BasicChannel> created_channel = nullptr, old_default_channel;
|
|
||||||
|
|
||||||
//bool enforce_permanent_parent = cmd[0]["channel_flag_default"].as<bool>(); //TODO check parents here
|
//bool enforce_permanent_parent = cmd[0]["channel_flag_default"].as<bool>(); //TODO check parents here
|
||||||
{ //Checkout the parent(s)
|
{ //Checkout the parent(s)
|
||||||
if (cmd[0].has("cpid") && cmd["cpid"].as<ChannelId>() != 0 && cmd["cpid"].as<int>() != -1) {
|
|
||||||
parent = target_tree->findLinkedChannel(cmd["cpid"].as<ChannelId>());
|
|
||||||
if (!parent) return command_result{error::channel_invalid_id, "Cant resolve parent channel"};
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
auto min_channel_deep = this->calculate_permission(permission::i_channel_min_depth, 0, false, permission_cache);
|
auto min_channel_deep = this->calculate_permission(permission::i_channel_min_depth, parent_channel_id, false, permission_cache);
|
||||||
auto max_channel_deep = this->calculate_permission(permission::i_channel_max_depth, 0, false, permission_cache);
|
auto max_channel_deep = this->calculate_permission(permission::i_channel_max_depth, parent_channel_id, false, permission_cache);
|
||||||
|
|
||||||
if(min_channel_deep.has_value || max_channel_deep.has_value) {
|
if(min_channel_deep.has_value || max_channel_deep.has_value) {
|
||||||
auto channel_deep = 0;
|
auto channel_deep = 0;
|
||||||
@ -704,8 +712,8 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
|||||||
created_channel->properties()[property::CHANNEL_CREATED_BY] = this->getClientDatabaseId();
|
created_channel->properties()[property::CHANNEL_CREATED_BY] = this->getClientDatabaseId();
|
||||||
|
|
||||||
{
|
{
|
||||||
auto default_modify_power = this->calculate_permission(permission::i_channel_modify_power, 0, false, permission_cache);
|
auto default_modify_power = this->calculate_permission(permission::i_channel_modify_power, parent_channel_id, false, permission_cache);
|
||||||
auto default_delete_power = this->calculate_permission(permission::i_channel_delete_power, 0, false, permission_cache);
|
auto default_delete_power = this->calculate_permission(permission::i_channel_delete_power, parent_channel_id, false, permission_cache);
|
||||||
|
|
||||||
auto permission_manager = created_channel->permissions();
|
auto permission_manager = created_channel->permissions();
|
||||||
permission_manager->set_permission(
|
permission_manager->set_permission(
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#include <misc/std_unique_ptr.h>
|
#include <misc/std_unique_ptr.h>
|
||||||
#include <log/LogUtils.h>
|
#include <log/LogUtils.h>
|
||||||
#include <pipes/rtc/PeerConnection.h>
|
|
||||||
#include <pipes/rtc/AudioStream.h>
|
|
||||||
#include <misc/endianness.h>
|
#include <misc/endianness.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#include "WebClient.h"
|
#include "WebClient.h"
|
||||||
#include "VoiceBridge.h"
|
#include "VoiceBridge.h"
|
||||||
|
|
||||||
@ -11,7 +10,7 @@ using namespace ts;
|
|||||||
using namespace ts::server;
|
using namespace ts::server;
|
||||||
using namespace ts::web;
|
using namespace ts::web;
|
||||||
|
|
||||||
void log(pipes::Logger::LogLevel level, const std::string& name, const std::string& message, ...) {
|
void VoiceBridge::callback_log(void* ptr, pipes::Logger::LogLevel level, const std::string& name, const std::string& message, ...) {
|
||||||
auto max_length = 1024 * 8;
|
auto max_length = 1024 * 8;
|
||||||
char buffer[max_length];
|
char buffer[max_length];
|
||||||
|
|
||||||
@ -20,7 +19,49 @@ void log(pipes::Logger::LogLevel level, const std::string& name, const std::stri
|
|||||||
max_length = vsnprintf(buffer, max_length, message.c_str(), args);
|
max_length = vsnprintf(buffer, max_length, message.c_str(), args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
|
||||||
debugMessage(LOG_GENERAL, "[WebRTC][{}][{}] {}", level, name, string(buffer));
|
auto bridge = (VoiceBridge*) ptr;
|
||||||
|
debugMessage(LOG_GENERAL, "{}[WebRTC][{}][{}] {}", CLIENT_STR_LOG_PREFIX_(bridge->owner()), level, name, string(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace gioloop {
|
||||||
|
void* main_loop_;
|
||||||
|
|
||||||
|
void*(*g_main_loop_new)(void* /* context */, bool /* is true */);
|
||||||
|
void(*g_main_loop_run)(void* /* loop */);
|
||||||
|
void(*g_main_loop_unref)(void* /* loop */);
|
||||||
|
void*(*g_main_loop_ref)(void* /* loop */);
|
||||||
|
|
||||||
|
bool initialized{false};
|
||||||
|
void initialize() {
|
||||||
|
if(initialized) return;
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
g_main_loop_new = (decltype(g_main_loop_new)) dlsym(nullptr, "g_main_loop_new");
|
||||||
|
g_main_loop_run = (decltype(g_main_loop_run)) dlsym(nullptr, "g_main_loop_run");
|
||||||
|
g_main_loop_ref = (decltype(g_main_loop_ref)) dlsym(nullptr, "g_main_loop_ref");
|
||||||
|
g_main_loop_unref = (decltype(g_main_loop_unref)) dlsym(nullptr, "g_main_loop_unref");
|
||||||
|
|
||||||
|
if(!g_main_loop_run || !g_main_loop_new || !g_main_loop_ref || !g_main_loop_unref) {
|
||||||
|
logWarning(LOG_INSTANCE, "Missing g_main_loop_new, g_main_loop_run, g_main_loop_ref or g_main_loop_unref functions. Could not spawn main loop.");
|
||||||
|
g_main_loop_run = nullptr;
|
||||||
|
g_main_loop_new = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
main_loop_ = g_main_loop_new(nullptr, false);
|
||||||
|
if(!main_loop_) {
|
||||||
|
logError(LOG_INSTANCE, "Failed to spawn new event loop for the web client.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::thread([]{
|
||||||
|
g_main_loop_run(main_loop_);
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<GMainLoop> loop() {
|
||||||
|
return std::shared_ptr<GMainLoop>{(GMainLoop*) g_main_loop_ref(main_loop_), g_main_loop_unref};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VoiceBridge::VoiceBridge(const shared_ptr<WebClient>& owner) : _owner(owner) {
|
VoiceBridge::VoiceBridge(const shared_ptr<WebClient>& owner) : _owner(owner) {
|
||||||
@ -48,14 +89,16 @@ VoiceBridge::VoiceBridge(const shared_ptr<WebClient>& owner) : _owner(owner) {
|
|||||||
config->nice_config->allow_ice_tcp = false;
|
config->nice_config->allow_ice_tcp = false;
|
||||||
config->nice_config->use_upnp = config::web::enable_upnp;
|
config->nice_config->use_upnp = config::web::enable_upnp;
|
||||||
|
|
||||||
//FIXME Use the internal thread or a shared worker
|
gioloop::initialize();
|
||||||
/* Not creating the thread here because DataPipes has a better impl with a join
|
config->nice_config->main_loop = gioloop::loop();
|
||||||
|
/*
|
||||||
config->nice_config->main_loop = std::shared_ptr<GMainLoop>(g_main_loop_new(nullptr, false), g_main_loop_unref);
|
config->nice_config->main_loop = std::shared_ptr<GMainLoop>(g_main_loop_new(nullptr, false), g_main_loop_unref);
|
||||||
std::thread(g_main_loop_run, config->nice_config->main_loop.get()).detach();
|
std::thread(g_main_loop_run, config->nice_config->main_loop.get()).detach();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
config->logger = make_shared<pipes::Logger>();
|
config->logger = make_shared<pipes::Logger>();
|
||||||
config->logger->callback_log = log;
|
config->logger->callback_log = VoiceBridge::callback_log;
|
||||||
|
config->logger->callback_argument = this;
|
||||||
//config->sctp.local_port = 5202; //Fire Fox don't support a different port :D
|
//config->sctp.local_port = 5202; //Fire Fox don't support a different port :D
|
||||||
|
|
||||||
this->connection = make_unique<rtc::PeerConnection>(config);
|
this->connection = make_unique<rtc::PeerConnection>(config);
|
||||||
@ -87,7 +130,7 @@ bool VoiceBridge::initialize(std::string &error) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this->connection->callback_new_stream = [&](const std::shared_ptr<rtc::Stream> &channel) { this->handle_media_stream(channel); }; //bind(&VoiceBridge::handle_media_stream, this, placeholders::_1); => crash
|
this->connection->callback_new_stream = [&](const std::shared_ptr<rtc::Channel> &channel) { this->handle_media_stream(channel); }; //bind(&VoiceBridge::handle_media_stream, this, placeholders::_1); => crash
|
||||||
this->connection->callback_setup_fail = [&](rtc::PeerConnection::ConnectionComponent comp, const std::string& reason) {
|
this->connection->callback_setup_fail = [&](rtc::PeerConnection::ConnectionComponent comp, const std::string& reason) {
|
||||||
debugMessage(this->server_id(), "{} WebRTC setup failed! Component {} ({})", CLIENT_STR_LOG_PREFIX_(this->owner()), comp, reason);
|
debugMessage(this->server_id(), "{} WebRTC setup failed! Component {} ({})", CLIENT_STR_LOG_PREFIX_(this->owner()), comp, reason);
|
||||||
if(this->callback_failed)
|
if(this->callback_failed)
|
||||||
@ -123,20 +166,25 @@ void VoiceBridge::execute_tick() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoiceBridge::handle_media_stream(const std::shared_ptr<rtc::Stream> &undefined_stream) {
|
void VoiceBridge::handle_media_stream(const std::shared_ptr<rtc::Channel> &undefined_stream) {
|
||||||
if(undefined_stream->type() == rtc::CHANTYPE_APPLICATION) {
|
if(undefined_stream->type() == rtc::CHANTYPE_APPLICATION) {
|
||||||
auto stream = dynamic_pointer_cast<rtc::ApplicationStream>(undefined_stream);
|
auto stream = dynamic_pointer_cast<rtc::ApplicationChannel>(undefined_stream);
|
||||||
if(!stream) return;
|
if(!stream) return;
|
||||||
|
|
||||||
stream->callback_datachannel_new = [&](const std::shared_ptr<rtc::DataChannel> &channel) { this->handle_data_channel(channel); }; //bind(&VoiceBridge::handle_data_channel, this, placeholders::_1); => may crash?
|
stream->callback_datachannel_new = [&](const std::shared_ptr<rtc::DataChannel> &channel) { this->handle_data_channel(channel); }; //bind(&VoiceBridge::handle_data_channel, this, placeholders::_1); => may crash?
|
||||||
} else if(undefined_stream->type() == rtc::CHANTYPE_AUDIO) {
|
} else if(undefined_stream->type() == rtc::CHANTYPE_AUDIO) {
|
||||||
auto stream = dynamic_pointer_cast<rtc::AudioStream>(undefined_stream);
|
auto stream = dynamic_pointer_cast<rtc::AudioChannel>(undefined_stream);
|
||||||
if(!stream) return;
|
if(!stream) return;
|
||||||
this->_audio_channel = stream;
|
this->_audio_channel = stream;
|
||||||
|
|
||||||
stream->register_local_extension("urn:ietf:params:rtp-hdrext:ssrc-audio-level");
|
stream->register_local_extension("urn:ietf:params:rtp-hdrext:ssrc-audio-level");
|
||||||
//bind(&VoiceBridge::handle_audio_data, this, placeholders::_1, placeholders::_2, placeholders::_3); => may crash?
|
for(const auto& codec : stream->list_codecs()) {
|
||||||
stream->incoming_data_handler = [&](const std::shared_ptr<rtc::AudioChannel> &channel, const pipes::buffer_view &data, size_t payload_offset) { this->handle_audio_data(channel, data, payload_offset); };
|
if(codec->type == rtc::codec::Codec::OPUS) {
|
||||||
|
codec->accepted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream->incoming_data_handler = [&](const std::shared_ptr<rtc::MediaChannel> &channel, const pipes::buffer_view &data, size_t payload_offset) { this->handle_audio_data(channel, data, payload_offset); };
|
||||||
} else {
|
} else {
|
||||||
logError(this->server_id(), "Got offer for unknown channel of type {}", undefined_stream->type());
|
logError(this->server_id(), "Got offer for unknown channel of type {}", undefined_stream->type());
|
||||||
}
|
}
|
||||||
@ -163,8 +211,8 @@ void VoiceBridge::handle_data_channel(const std::shared_ptr<rtc::DataChannel> &c
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoiceBridge::handle_audio_data(const std::shared_ptr<rtc::AudioChannel> &channel, const pipes::buffer_view &data, size_t payload_offset) {
|
void VoiceBridge::handle_audio_data(const std::shared_ptr<rtc::MediaChannel> &channel, const pipes::buffer_view &data, size_t payload_offset) {
|
||||||
if(channel->codec->type != rtc::codec::TypedAudio::OPUS) {
|
if(channel->codec->type != rtc::codec::Codec::OPUS) {
|
||||||
debugMessage(this->server_id(), "{} Got unknown codec ({})!", CLIENT_STR_LOG_PREFIX_(this->owner()), channel->codec->type);
|
debugMessage(this->server_id(), "{} Got unknown codec ({})!", CLIENT_STR_LOG_PREFIX_(this->owner()), channel->codec->type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -172,7 +220,7 @@ void VoiceBridge::handle_audio_data(const std::shared_ptr<rtc::AudioChannel> &ch
|
|||||||
auto ac = _audio_channel.lock();
|
auto ac = _audio_channel.lock();
|
||||||
if(!ac) return;
|
if(!ac) return;
|
||||||
|
|
||||||
for(const auto& ext : ac->list_extensions(0x02)) {
|
for(const auto& ext : ac->list_extensions(rtc::direction::incoming)) {
|
||||||
if(ext->name == "urn:ietf:params:rtp-hdrext:ssrc-audio-level") {
|
if(ext->name == "urn:ietf:params:rtp-hdrext:ssrc-audio-level") {
|
||||||
int level;
|
int level;
|
||||||
if(rtc::protocol::rtp_header_extension_parse_audio_level(data, ext->id, &level) == 0) {
|
if(rtc::protocol::rtp_header_extension_parse_audio_level(data, ext->id, &level) == 0) {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <pipes/rtc/PeerConnection.h>
|
#include <pipes/rtc/PeerConnection.h>
|
||||||
#include <pipes/rtc/ApplicationStream.h>
|
#include <pipes/rtc/channels/ApplicationChannel.h>
|
||||||
#include <pipes/rtc/AudioStream.h>
|
#include <pipes/rtc/channels/AudioChannel.h>
|
||||||
|
|
||||||
namespace ts {
|
namespace ts {
|
||||||
namespace server {
|
namespace server {
|
||||||
@ -36,19 +36,20 @@ namespace ts {
|
|||||||
|
|
||||||
void execute_tick();
|
void execute_tick();
|
||||||
private:
|
private:
|
||||||
|
static void callback_log(void* ptr, pipes::Logger::LogLevel level, const std::string& name, const std::string& message, ...);
|
||||||
|
|
||||||
inline int server_id();
|
inline int server_id();
|
||||||
inline std::shared_ptr<server::WebClient> owner();
|
inline std::shared_ptr<server::WebClient> owner();
|
||||||
|
|
||||||
void handle_media_stream(const std::shared_ptr<rtc::Stream>& /* stream */);
|
void handle_media_stream(const std::shared_ptr<rtc::Channel>& /* stream */);
|
||||||
void handle_data_channel(const std::shared_ptr<rtc::DataChannel> & /* channel */);
|
void handle_data_channel(const std::shared_ptr<rtc::DataChannel> & /* channel */);
|
||||||
void handle_audio_data(const std::shared_ptr<rtc::AudioChannel>& /* channel */, const pipes::buffer_view& /* buffer */, size_t /* payload offset */);
|
void handle_audio_data(const std::shared_ptr<rtc::MediaChannel>& /* channel */, const pipes::buffer_view& /* buffer */, size_t /* payload offset */);
|
||||||
|
|
||||||
std::weak_ptr<server::WebClient> _owner;
|
std::weak_ptr<server::WebClient> _owner;
|
||||||
std::chrono::system_clock::time_point offer_timestamp;
|
std::chrono::system_clock::time_point offer_timestamp;
|
||||||
std::unique_ptr<rtc::PeerConnection> connection;
|
std::unique_ptr<rtc::PeerConnection> connection;
|
||||||
std::shared_ptr<rtc::DataChannel> _voice_channel;
|
std::shared_ptr<rtc::DataChannel> _voice_channel;
|
||||||
std::weak_ptr<rtc::AudioStream> _audio_channel;
|
std::weak_ptr<rtc::AudioChannel> _audio_channel;
|
||||||
struct {
|
struct {
|
||||||
uint16_t packet_id = 0;
|
uint16_t packet_id = 0;
|
||||||
bool muted = true;
|
bool muted = true;
|
||||||
|
@ -476,8 +476,11 @@ void WebClient::handleMessage(const std::string &message) {
|
|||||||
auto vb_ptr = &*this->voice_bridge; /* read only no lock needed */
|
auto vb_ptr = &*this->voice_bridge; /* read only no lock needed */
|
||||||
std::thread([&, vb_ptr, lock = this->ref()]{
|
std::thread([&, vb_ptr, lock = this->ref()]{
|
||||||
unique_lock vbl{this->voice_bridge_lock};
|
unique_lock vbl{this->voice_bridge_lock};
|
||||||
if(&*this->voice_bridge == vb_ptr)
|
if(&*this->voice_bridge == vb_ptr) {
|
||||||
this->voice_bridge.release();
|
auto bridge = std::exchange(this->voice_bridge, nullptr);
|
||||||
|
vbl.unlock();
|
||||||
|
bridge.reset();
|
||||||
|
}
|
||||||
}).detach();
|
}).detach();
|
||||||
|
|
||||||
Json::Value response;
|
Json::Value response;
|
||||||
@ -551,7 +554,7 @@ void WebClient::handleMessage(const std::string &message) {
|
|||||||
this->sendJson(response);
|
this->sendJson(response);
|
||||||
}
|
}
|
||||||
} else if(subType == "ice") {
|
} else if(subType == "ice") {
|
||||||
shared_lock read_voice_bridge_lock(this->voice_bridge_lock);
|
std::shared_lock read_voice_bridge_lock{this->voice_bridge_lock};
|
||||||
if(!this->voice_bridge) {
|
if(!this->voice_bridge) {
|
||||||
debugMessage(this->getServerId(), "[{}] Received remote ICE candidate without having a voice bridge! Dropping candidate.", CLIENT_STR_LOG_PREFIX);
|
debugMessage(this->getServerId(), "[{}] Received remote ICE candidate without having a voice bridge! Dropping candidate.", CLIENT_STR_LOG_PREFIX);
|
||||||
return;
|
return;
|
||||||
@ -578,7 +581,7 @@ void WebClient::handleMessage(const std::string &message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(subType == "ice_finish") {
|
} else if(subType == "ice_finish") {
|
||||||
shared_lock read_voice_bridge_lock(this->voice_bridge_lock);
|
std::shared_lock read_voice_bridge_lock{this->voice_bridge_lock};
|
||||||
if(!this->voice_bridge) {
|
if(!this->voice_bridge) {
|
||||||
debugMessage(this->getServerId(), "[{}] Received remote ICE candidate without having a voice bridge! Dropping candidate.", CLIENT_STR_LOG_PREFIX);
|
debugMessage(this->getServerId(), "[{}] Received remote ICE candidate without having a voice bridge! Dropping candidate.", CLIENT_STR_LOG_PREFIX);
|
||||||
return;
|
return;
|
||||||
|
@ -222,7 +222,7 @@ namespace ts {
|
|||||||
|
|
||||||
class ConversationManager {
|
class ConversationManager {
|
||||||
public:
|
public:
|
||||||
ConversationManager(const std::shared_ptr<VirtualServer>& /* server */);
|
explicit ConversationManager(const std::shared_ptr<VirtualServer>& /* server */);
|
||||||
virtual ~ConversationManager();
|
virtual ~ConversationManager();
|
||||||
|
|
||||||
void initialize(const std::shared_ptr<ConversationManager>& _this);
|
void initialize(const std::shared_ptr<ConversationManager>& _this);
|
||||||
|
@ -473,8 +473,10 @@ namespace terminal {
|
|||||||
if(cmd.arguments.size() < 1) {
|
if(cmd.arguments.size() < 1) {
|
||||||
value = 1024;
|
value = 1024;
|
||||||
|
|
||||||
rlimit limit{1024, 10000};
|
rlimit rlimit{0, 0};
|
||||||
setrlimit(7, &limit);
|
getrlimit(RLIMIT_NOFILE, &rlimit);
|
||||||
|
logMessage("RLimit: {}/{}", rlimit.rlim_cur, rlimit.rlim_max);
|
||||||
|
//setrlimit(7, &limit);
|
||||||
} else if(cmd.larguments[0] == "clear") {
|
} else if(cmd.larguments[0] == "clear") {
|
||||||
logMessage("Clearup leaks");
|
logMessage("Clearup leaks");
|
||||||
for(auto& fd : fd_leaks)
|
for(auto& fd : fd_leaks)
|
||||||
|
Loading…
Reference in New Issue
Block a user