This commit is contained in:
WolverinDEV 2020-05-03 14:06:34 +02:00
parent f3441e0115
commit fd256411d1
43 changed files with 1370 additions and 244 deletions

View File

@ -103,4 +103,5 @@ add_definitions(-DINET -DINET6)
add_subdirectory(shared/)
add_subdirectory(server/)
add_subdirectory(license/)
add_subdirectory(MusicBot/)
add_subdirectory(MusicBot/)
add_subdirectory(file/)

25
file/CMakeLists.txt Normal file
View File

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.6)
project(TeaSpeak-Files)
#set(CMAKE_CXX_STANDARD 17)
#set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(TeaSpeak-FileServer STATIC
local_server/LocalFileServer.cpp
local_server/LocalFileSystem.cpp
local_server/clnpath.cpp
)
target_link_libraries(TeaSpeak-FileServer PUBLIC TeaSpeak ${StringVariable_LIBRARIES_STATIC} stdc++fs
libevent::core libevent::pthreads)
target_include_directories(TeaSpeak-FileServer PUBLIC include/)
add_executable(TeaSpeak-FileServerTest test/main.cpp)
target_link_libraries(TeaSpeak-FileServerTest PUBLIC TeaSpeak-FileServer
TeaMusic #Static (Must be in here, so we link against TeaMusic which uses C++11. That forbids GCC to use the newer glibc version)
CXXTerminal::static #Static
stdc++fs
)
add_executable(FileServer-CLNText local_server/clnpath.cpp)
target_compile_definitions(FileServer-CLNText PUBLIC -DCLN_EXEC)

View File

@ -0,0 +1,286 @@
#pragma once
#include <string>
#include <chrono>
#include <Definitions.h>
#include <condition_variable>
#include <variant>
#include <deque>
#include <functional>
namespace ts::server::file {
enum struct ExecuteStatus {
UNKNOWN,
WAITING,
SUCCESS,
ERROR
};
template<typename VariantType, typename T, std::size_t index = 0>
constexpr std::size_t variant_index() {
if constexpr (index == std::variant_size_v<VariantType>) {
return index;
} else if constexpr (std::is_same_v<std::variant_alternative_t<index, VariantType>, T>) {
return index;
} else {
return variant_index<VariantType, T, index + 1>();
}
}
struct EmptyExecuteResponse { };
template <class error_t, class response_t = EmptyExecuteResponse>
class ExecuteResponse {
typedef std::variant<EmptyExecuteResponse, error_t, response_t> variant_t;
public:
ExecuteStatus status{ExecuteStatus::WAITING};
[[nodiscard]] inline const auto& response() const { return std::get<response_t>(this->response_); }
template <typename = std::enable_if_t<!std::is_void<error_t>::value>>
[[nodiscard]] inline const error_t& error() const { return std::get<error_t>(this->response_); }
inline void wait() const {
std::unique_lock nlock{this->notify_mutex};
this->notify_cv.wait(nlock, [&]{ return this->status != ExecuteStatus::WAITING; });
}
template<typename _Rep, typename _Period>
[[nodiscard]] inline bool wait_for(const std::chrono::duration<_Rep, _Period>& time) const {
std::unique_lock nlock{this->notify_mutex};
return this->notify_cv.wait_for(nlock, time, [&]{ return this->status != ExecuteStatus::WAITING; });
}
template <typename... Args>
inline void emplace_success(Args&&... args) {
constexpr auto success_index = variant_index<variant_t, response_t>();
std::lock_guard rlock{this->notify_mutex};
this->response_.template emplace<success_index, Args...>(std::forward<Args>(args)...);
this->status = ExecuteStatus::SUCCESS;
this->notify_cv.notify_all();
}
template <typename... Args>
inline void emplace_fail(Args&&... args) {
constexpr auto error_index = variant_index<variant_t, error_t>();
std::lock_guard rlock{this->notify_mutex};
this->response_.template emplace<error_index, Args...>(std::forward<Args>(args)...);
this->status = ExecuteStatus::ERROR;
this->notify_cv.notify_all();
}
ExecuteResponse(std::mutex& notify_mutex, std::condition_variable& notify_cv)
: notify_mutex{notify_mutex}, notify_cv{notify_cv} {}
private:
variant_t response_{}; /* void* as default value so we don't initialize error_t or response_t */
std::mutex& notify_mutex;
std::condition_variable& notify_cv;
};
namespace filesystem {
template <typename ErrorCodes>
struct DetailedError {
ErrorCodes error_type{ErrorCodes::UNKNOWN};
std::string error_message{};
DetailedError(ErrorCodes type, std::string extraMessage) : error_type{type}, error_message{std::move(extraMessage)} {}
};
enum struct DirectoryQueryErrorType {
UNKNOWN,
PATH_EXCEEDS_ROOT_PATH,
PATH_IS_A_FILE,
PATH_DOES_NOT_EXISTS,
FAILED_TO_LIST_FILES,
MAX
};
constexpr std::array<std::string_view, (int) DirectoryQueryErrorType::MAX> directory_query_error_messages = {
"unknown error",
"path exceeds base path",
"path is a file",
"path does not exists",
"failed to list files"
};
typedef DetailedError<DirectoryQueryErrorType> DirectoryQueryError;
struct DirectoryEntry {
enum Type {
UNKNOWN,
DIRECTORY,
FILE
};
Type type{Type::UNKNOWN};
std::string name{};
std::chrono::system_clock::time_point modified_at{};
size_t size{0};
};
enum struct DirectoryModifyErrorType {
UNKNOWN,
PATH_EXCEEDS_ROOT_PATH,
PATH_ALREADY_EXISTS,
FAILED_TO_CREATE_DIRECTORIES
};
typedef DetailedError<DirectoryModifyErrorType> DirectoryModifyError;
enum struct FileModifyErrorType {
UNKNOWN,
PATH_EXCEEDS_ROOT_PATH,
TARGET_PATH_EXCEEDS_ROOT_PATH,
PATH_DOES_NOT_EXISTS,
TARGET_PATH_ALREADY_EXISTS,
FAILED_TO_DELETE_FILES,
FAILED_TO_RENAME_FILE,
SOME_FILES_ARE_LOCKED
};
typedef DetailedError<FileModifyErrorType> FileModifyError;
enum struct ServerCommandErrorType {
UNKNOWN,
FAILED_TO_CREATE_DIRECTORIES,
FAILED_TO_DELETE_DIRECTORIES
};
typedef DetailedError<ServerCommandErrorType> ServerCommandError;
class AbstractProvider {
public:
typedef ExecuteResponse<DirectoryQueryError, std::deque<DirectoryEntry>> directory_query_response_t;
/* server */
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<ServerCommandError>> initialize_server(ServerId /* server */) = 0;
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<ServerCommandError>> delete_server(ServerId /* server */) = 0;
/* channels */
[[nodiscard]] virtual std::shared_ptr<directory_query_response_t> query_channel_directory(ServerId /* server */, ChannelId /* channel */, const std::string& /* path */) = 0;
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<DirectoryModifyError>> create_channel_directory(ServerId /* server */, ChannelId /* channel */, const std::string& /* path */) = 0;
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<FileModifyError>> delete_channel_file(ServerId /* server */, ChannelId /* channel */, const std::string& /* path */) = 0;
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<FileModifyError>> rename_channel_file(ServerId /* server */, ChannelId /* channel */, const std::string& /* path */, const std::string& /* target */) = 0;
/* icons */
[[nodiscard]] virtual std::shared_ptr<directory_query_response_t> query_icon_directory(ServerId /* server */) = 0;
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<FileModifyError>> delete_icon(ServerId /* server */, const std::string& /* name */) = 0;
/* avatars */
[[nodiscard]] virtual std::shared_ptr<directory_query_response_t> query_avatar_directory(ServerId /* server */) = 0;
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<FileModifyError>> delete_avatar(ServerId /* server */, const std::string& /* name */) = 0;
private:
};
}
namespace transfer {
typedef uint32_t transfer_id;
struct Transfer {
transfer_id server_transfer_id{0};
transfer_id client_transfer_id{0};
ServerId server_id{0};
ClientId client_id{0};
ChannelId channel_id{0};
std::string transfer_key{};
std::chrono::system_clock::time_point initialized_timestamp{};
enum Direction {
DIRECTION_UNKNOWN,
DIRECTION_UPLOAD,
DIRECTION_DOWNLOAD
} direction{DIRECTION_UNKNOWN};
std::string transfer_hosts{}; /* comma separated list */
uint16_t transfer_port{0};
enum TargetType {
TARGET_TYPE_UNKNOWN,
TARGET_TYPE_CHANNEL_FILE,
TARGET_TYPE_ICON,
TARGET_TYPE_AVATAR
} target_type{TARGET_TYPE_UNKNOWN};
std::string target_file_path{};
int64_t max_bandwidth{-1};
size_t expected_file_size{0};
size_t file_offset{0};
};
struct TransferStatistics {
uint64_t bytes_send{0};
uint64_t bytes_received{0};
uint64_t delta_bytes_send{0};
uint64_t delta_bytes_received{0};
size_t current_offset{0};
size_t total_size{0};
};
struct TransferInitError {
enum Type {
UNKNOWN
} error_type{UNKNOWN};
std::string error_message{};
};
struct TransferActionError {
enum Type {
UNKNOWN,
UNKNOWN_TRANSFER
} error_type{UNKNOWN};
std::string error_message{};
};
struct TransferError {
enum Type {
UNKNOWN,
DISK_IO_ERROR,
NETWORK_IO_ERROR,
UNEXPECTED_CLIENT_EOF
} error_type{UNKNOWN};
std::string error_message{};
};
class AbstractProvider {
public:
struct TransferInfo {
std::string file_path{};
bool override_exiting{false}; /* only for upload valid */
size_t file_offset{0};
size_t expected_file_size{0};
int64_t max_bandwidth{-1};
};
virtual std::shared_ptr<ExecuteResponse<TransferInitError, std::shared_ptr<Transfer>>> initialize_channel_transfer(Transfer::Direction /* direction */, ServerId /* server */, ChannelId /* channel */, const TransferInfo& /* info */) = 0;
virtual std::shared_ptr<ExecuteResponse<TransferInitError, std::shared_ptr<Transfer>>> initialize_icon_transfer(Transfer::Direction /* direction */, ServerId /* server */, const TransferInfo& /* info */) = 0;
virtual std::shared_ptr<ExecuteResponse<TransferInitError, std::shared_ptr<Transfer>>> initialize_avatar_transfer(Transfer::Direction /* direction */, ServerId /* server */, const TransferInfo& /* info */) = 0;
virtual std::shared_ptr<ExecuteResponse<TransferActionError>> stop_transfer(transfer_id) = 0;
std::function<void(const std::shared_ptr<Transfer>&)> callback_transfer_timeout{}; /* client has not connected to that transfer */
std::function<void(const std::shared_ptr<Transfer>&)> callback_transfer_started{}; /* transfer has been started */
std::function<void(const std::shared_ptr<Transfer>&)> callback_transfer_finished{}; /* transfer has been finished */
std::function<void(const std::shared_ptr<Transfer>&, const TransferError&)> callback_transfer_aborted{}; /* an error happened while transfering the data */
std::function<void(const std::shared_ptr<Transfer>&, const TransferStatistics&)> callback_transfer_statistics{};
private:
};
}
class AbstractFileServer {
public:
[[nodiscard]] virtual filesystem::AbstractProvider& file_system() = 0;
private:
};
extern bool initialize(std::string& /* error */);
extern void finalize();
extern std::shared_ptr<AbstractFileServer> server();
}

View File

@ -0,0 +1,45 @@
//
// Created by WolverinDEV on 28/04/2020.
//
#include "./LocalFileServer.h"
using namespace ts::server;
using LocalFileServer = file::LocalFileServer;
std::shared_ptr<LocalFileServer> server_instance{};
bool file::initialize(std::string &error) {
server_instance = std::make_shared<LocalFileServer>();
if(!server_instance->initialize(error)) {
server_instance = nullptr;
return false;
}
return true;
}
void file::finalize() {
auto server = std::exchange(server_instance, nullptr);
if(!server) return;
server->finalize();
}
std::shared_ptr<file::AbstractFileServer> file::server() {
return server_instance;
}
LocalFileServer::~LocalFileServer() {}
bool LocalFileServer::initialize(std::string &error) {
if(!this->file_system_.initialize(error, "file-root/"))
return false;
return true;
}
void LocalFileServer::finalize() {
}
file::filesystem::AbstractProvider &LocalFileServer::file_system() {
return this->file_system_;
}

View File

@ -0,0 +1,93 @@
#pragma once
#include <files/FileServer.h>
#include <deque>
namespace ts::server::file {
namespace filesystem {
#ifdef FS_INCLUDED
namespace fs = std::experimental::filesystem;
#endif
class LocalFileSystem : public filesystem::AbstractProvider {
using FileModifyError = filesystem::FileModifyError;
using DirectoryModifyError = filesystem::DirectoryModifyError;
public:
virtual ~LocalFileSystem();
bool initialize(std::string & /* error */, const std::string & /* root path */);
void finalize();
void lock_file(const std::string& /* path */);
void unlock_file(const std::string& /* path */);
[[nodiscard]] inline const auto &root_path() const { return this->root_path_; }
std::shared_ptr<ExecuteResponse<ServerCommandError>> initialize_server(ServerId /* server */) override;
std::shared_ptr<ExecuteResponse<ServerCommandError>> delete_server(ServerId /* server */) override;
std::shared_ptr<directory_query_response_t>
query_channel_directory(ServerId id, ChannelId channelId, const std::string &string) override;
std::shared_ptr<ExecuteResponse<DirectoryModifyError>>
create_channel_directory(ServerId id, ChannelId channelId, const std::string &string) override;
std::shared_ptr<ExecuteResponse<FileModifyError>>
delete_channel_file(ServerId id, ChannelId channelId, const std::string &string) override;
std::shared_ptr<ExecuteResponse<FileModifyError>>
rename_channel_file(ServerId id, ChannelId channelId, const std::string &, const std::string &) override;
std::shared_ptr<directory_query_response_t> query_icon_directory(ServerId id) override;
std::shared_ptr<ExecuteResponse<FileModifyError>>
delete_icon(ServerId id, const std::string &string) override;
std::shared_ptr<directory_query_response_t> query_avatar_directory(ServerId id) override;
std::shared_ptr<ExecuteResponse<FileModifyError>>
delete_avatar(ServerId id, const std::string &string) override;
private:
#ifdef FS_INCLUDED
[[nodiscard]] fs::path server_path(ServerId);
[[nodiscard]] fs::path server_channel_path(ServerId, ChannelId);
[[nodiscard]] static bool exceeds_base_path(const fs::path& /* base */, const fs::path& /* target */);
[[nodiscard]] bool is_any_file_locked(const fs::path& /* base */, const std::string& /* path */, std::string& /* file (relative to the base) */);
[[nodiscard]] std::shared_ptr<ExecuteResponse<FileModifyError>>
delete_file(const fs::path& /* base */, const std::string &string);
[[nodiscard]] std::shared_ptr<directory_query_response_t>
query_directory(const fs::path& /* base */, const std::string &string, bool);
#endif
template <typename error_t, typename result_t = EmptyExecuteResponse>
std::shared_ptr<ExecuteResponse<error_t, result_t>> create_execute_response() {
return std::make_shared<ExecuteResponse<error_t, result_t>>(this->result_notify_mutex, this->result_notify_cv);
}
std::mutex result_notify_mutex{};
std::condition_variable result_notify_cv{};
std::string root_path_{};
std::mutex locked_files_mutex{};
std::deque<std::string> locked_files_{};
};
}
class LocalFileServer : public AbstractFileServer {
public:
virtual ~LocalFileServer();
[[nodiscard]] bool initialize(std::string& /* error */);
void finalize();
filesystem::AbstractProvider &file_system() override;
private:
filesystem::LocalFileSystem file_system_{};
};
}

View File

@ -0,0 +1,309 @@
//
// Created by WolverinDEV on 29/04/2020.
//
#include <experimental/filesystem>
#define FS_INCLUDED
#include <log/LogUtils.h>
#include "./LocalFileServer.h"
#include "clnpath.h"
using namespace ts::server::file;
using namespace ts::server::file::filesystem;
namespace fs = std::experimental::filesystem;
using directory_query_response_t = AbstractProvider::directory_query_response_t;
LocalFileSystem::~LocalFileSystem() = default;
bool LocalFileSystem::initialize(std::string &error_message, const std::string &root_path_string) {
auto root_path = fs::u8path(root_path_string);
std::error_code error{};
if(!fs::exists(root_path, error)) {
if(error)
logWarning(0, "Failed to check root path existence. Assuming it does not exist. ({}/{})", error.value(), error.message());
if(!fs::create_directories(root_path, error) || error) {
error_message = "Failed to create root file system at " + root_path_string + ": " + std::to_string(error.value()) + "/" + error.message();
return false;
}
}
auto croot = clnpath(fs::absolute(root_path).string());
logMessage(0, "Started file system root at {}", croot);
this->root_path_ = croot;
return true;
}
void LocalFileSystem::finalize() {}
fs::path LocalFileSystem::server_path(ts::ServerId id) {
return fs::u8path(this->root_path_) / fs::u8path("server_" + std::to_string(id));
}
fs::path LocalFileSystem::server_channel_path(ts::ServerId sid, ts::ChannelId cid) {
return this->server_path(sid) / fs::u8path("channel_" + std::to_string(cid));
}
bool LocalFileSystem::exceeds_base_path(const fs::path &base, const fs::path &target) {
auto rel_target = clnpath(target.string());
if(rel_target.starts_with("..")) return true;
auto base_string = clnpath(fs::absolute(base).string());
auto target_string = clnpath(fs::absolute(target).string());
return !target_string.starts_with(base_string);
}
bool LocalFileSystem::is_any_file_locked(const fs::path &base, const std::string &path, std::string &locked_file) {
auto c_path = clnpath(fs::absolute(base / fs::u8path(path)).string());
for(const auto& lfile : this->locked_files_) {
if(lfile.starts_with(c_path)) {
locked_file = lfile.substr(base.string().length());
return true;
}
}
return false;
}
std::shared_ptr<ExecuteResponse<ServerCommandError>> LocalFileSystem::initialize_server(ServerId id) {
auto path = this->server_path(id);
std::error_code error{};
auto response = this->create_execute_response<ServerCommandError>();
if(!fs::exists(path, error)) {
if(!fs::create_directories(path, error) || error) {
response->emplace_fail(ServerCommandErrorType::FAILED_TO_CREATE_DIRECTORIES, std::to_string(error.value()) + "/" + error.message());
return response;
}
}
//TODO: Copy the default icon
response->emplace_success();
return response;
}
std::shared_ptr<ExecuteResponse<ServerCommandError>> LocalFileSystem::delete_server(ServerId id) {
auto path = this->server_path(id);
std::error_code error{};
auto response = this->create_execute_response<ServerCommandError>();
//TODO: Stop all running file transfers!
if(fs::exists(path, error)) {
if(!fs::remove_all(path, error) || error) {
response->emplace_fail(ServerCommandErrorType::FAILED_TO_DELETE_DIRECTORIES, std::to_string(error.value()) + "/" + error.message());
return response;
}
}
response->emplace_success();
return response;
}
std::shared_ptr<directory_query_response_t> LocalFileSystem::query_directory(const fs::path &base,
const std::string &path,
bool allow_non_existance) {
std::error_code error{};
auto response = this->create_execute_response<DirectoryQueryError, std::deque<DirectoryEntry>>();
auto target_path = base / fs::u8path(path);
if(this->exceeds_base_path(base, target_path)) {
response->emplace_fail(DirectoryQueryErrorType::PATH_EXCEEDS_ROOT_PATH, "");
return response;
}
if(!fs::exists(target_path, error)) {
if(allow_non_existance)
response->emplace_success();
else
response->emplace_fail(DirectoryQueryErrorType::PATH_DOES_NOT_EXISTS, "");
return response;
} else if(error) {
logWarning(0, "Failed to check for file at {}: {}. Assuming it does not exists.", target_path.string(), error.value(), error.message());
response->emplace_fail(DirectoryQueryErrorType::PATH_DOES_NOT_EXISTS, "");
return response;
}
if(!fs::is_directory(target_path, error)) {
response->emplace_fail(DirectoryQueryErrorType::PATH_IS_A_FILE, "");
return response;
} else if(error) {
logWarning(0, "Failed to check for directory at {}: {}. Assuming its not a directory.", target_path.string(), error.value(), error.message());
response->emplace_fail(DirectoryQueryErrorType::PATH_IS_A_FILE, "");
return response;
}
std::deque<DirectoryEntry> entries{};
for(auto& entry : fs::directory_iterator(target_path, error)) {
auto status = entry.status(error);
if(error) {
logWarning(0, "Failed to query file status for {} ({}/{}). Skipping entry for directory query.", entry.path().string(), error.value(), error.message());
continue;
}
if(status.type() == fs::file_type::directory) {
auto& dentry = entries.emplace_back();
dentry.type = DirectoryEntry::DIRECTORY;
dentry.name = entry.path().filename();
dentry.modified_at = fs::last_write_time(entry.path(), error);
if(error)
logWarning(0, "Failed to query last write time for directory {} ({}/{})", entry.path().string(), error.value(), error.message());
dentry.size = 0;
} else if(status.type() == fs::file_type::regular) {
auto& dentry = entries.emplace_back();
dentry.type = DirectoryEntry::FILE;
dentry.name = entry.path().filename();
dentry.modified_at = fs::last_write_time(entry.path(), error);
if(error)
logWarning(0, "Failed to query last write time for file {} ({}/{}).", entry.path().string(), error.value(), error.message());
dentry.size = fs::file_size(entry.path(), error);
if(error)
logWarning(0, "Failed to query size for file {} ({}/{}).", entry.path().string(), error.value(), error.message());
} else {
logWarning(0, "Directory query listed an unknown file type for file {} ({}).", entry.path().string(), (int) status.type());
}
}
if(error && entries.empty()) {
response->emplace_fail(DirectoryQueryErrorType::FAILED_TO_LIST_FILES, std::to_string(error.value()) + "/" + error.message());
return response;
}
response->emplace_success(std::forward<decltype(entries)>(entries));
return response;
}
std::shared_ptr<directory_query_response_t> LocalFileSystem::query_icon_directory(ServerId id) {
return this->query_directory(this->server_path(id) / fs::u8path("icons"), "/", true);
}
std::shared_ptr<directory_query_response_t> LocalFileSystem::query_avatar_directory(ServerId id) {
return this->query_directory(this->server_path(id) / fs::u8path("avatars"), "/", true);
}
std::shared_ptr<directory_query_response_t> LocalFileSystem::query_channel_directory(ServerId id, ChannelId channelId, const std::string &path) {
return this->query_directory(this->server_channel_path(id, channelId), path, false);
}
std::shared_ptr<ExecuteResponse<DirectoryModifyError>> LocalFileSystem::create_channel_directory(ServerId id, ChannelId channelId, const std::string &path) {
auto channel_path_root = this->server_channel_path(id, channelId);
std::error_code error{};
auto response = this->create_execute_response<DirectoryModifyError>();
auto target_path = channel_path_root / fs::u8path(path);
if(this->exceeds_base_path(channel_path_root, target_path)) {
response->emplace_fail(DirectoryModifyErrorType::PATH_EXCEEDS_ROOT_PATH, "");
return response;
}
if(fs::exists(target_path, error)) {
response->emplace_fail(DirectoryModifyErrorType::PATH_ALREADY_EXISTS, "");
return response;
} else if(error) {
logWarning(0, "Failed to check for file at {}: {}. Assuming it does not exists.", target_path.string(), error.value(), error.message());
}
if(!fs::create_directories(target_path, error) || error) {
response->emplace_fail(DirectoryModifyErrorType::FAILED_TO_CREATE_DIRECTORIES, std::to_string(error.value()) + "/" + error.message());
return response;
}
response->emplace_success();
return response;
}
std::shared_ptr<ExecuteResponse<FileModifyError>> LocalFileSystem::rename_channel_file(ServerId id, ChannelId channelId, const std::string &current_path_string, const std::string &new_path_string) {
auto channel_path_root = this->server_channel_path(id, channelId);
std::error_code error{};
std::string locked_file{};
auto response = this->create_execute_response<FileModifyError>();
auto current_path = channel_path_root / fs::u8path(current_path_string);
auto target_path = channel_path_root / fs::u8path(new_path_string);
if(this->exceeds_base_path(channel_path_root, current_path)) {
response->emplace_fail(FileModifyErrorType::PATH_EXCEEDS_ROOT_PATH, "");
return response;
}
if(this->exceeds_base_path(channel_path_root, target_path)) {
response->emplace_fail(FileModifyErrorType::TARGET_PATH_EXCEEDS_ROOT_PATH, "");
return response;
}
if(!fs::exists(current_path, error)) {
response->emplace_fail(FileModifyErrorType::PATH_DOES_NOT_EXISTS, "");
return response;
} else if(error) {
logWarning(0, "Failed to check for file at {}: {}. Assuming it does not exists.", current_path.string(), error.value(), error.message());
response->emplace_fail(FileModifyErrorType::PATH_DOES_NOT_EXISTS, "");
return response;
}
if(fs::exists(target_path, error)) {
response->emplace_fail(FileModifyErrorType::TARGET_PATH_ALREADY_EXISTS, "");
return response;
} else if(error) {
logWarning(0, "Failed to check for file at {}: {}. Assuming it does exists.", current_path.string(), error.value(), error.message());
response->emplace_fail(FileModifyErrorType::TARGET_PATH_ALREADY_EXISTS, "");
return response;
}
if(this->is_any_file_locked(channel_path_root, current_path, locked_file)) {
response->emplace_fail(FileModifyErrorType::SOME_FILES_ARE_LOCKED, locked_file);
return response;
}
fs::rename(current_path, target_path, error);
if(error) {
response->emplace_fail(FileModifyErrorType::FAILED_TO_RENAME_FILE, std::to_string(error.value()) + "/" + error.message());
return response;
}
response->emplace_success();
return response;
}
std::shared_ptr<ExecuteResponse<FileModifyError>> LocalFileSystem::delete_file(const fs::path &base,
const std::string &path) {
std::error_code error{};
std::string locked_file{};
auto response = this->create_execute_response<FileModifyError>();
auto target_path = base / fs::u8path(path);
if(fs::exists(target_path, error)) {
response->emplace_fail(FileModifyErrorType::TARGET_PATH_ALREADY_EXISTS, "");
return response;
} else if(error) {
logWarning(0, "Failed to check for file at {}: {}. Assuming it does exists.", target_path.string(), error.value(), error.message());
response->emplace_fail(FileModifyErrorType::TARGET_PATH_ALREADY_EXISTS, "");
return response;
}
if(this->is_any_file_locked(base, path, locked_file)) {
response->emplace_fail(FileModifyErrorType::SOME_FILES_ARE_LOCKED, locked_file);
return response;
}
if(!fs::remove(target_path, error) || error) {
response->emplace_fail(FileModifyErrorType::FAILED_TO_DELETE_FILES, std::to_string(error.value()) + "/" + error.message());
return response;
}
response->emplace_success();
return response;
}
std::shared_ptr<ExecuteResponse<FileModifyError>> LocalFileSystem::delete_channel_file(ServerId id, ChannelId channelId, const std::string &path) {
return this->delete_file(this->server_channel_path(id, channelId), path);
}
std::shared_ptr<ExecuteResponse<FileModifyError>> LocalFileSystem::delete_icon(ServerId id, const std::string &icon) {
return this->delete_file(this->server_path(id) / fs::u8path("icons"), icon);
}
std::shared_ptr<ExecuteResponse<FileModifyError>> LocalFileSystem::delete_avatar(ServerId id, const std::string &avatar) {
return this->delete_file(this->server_path(id) / fs::u8path("avatars"), avatar);
}

View File

@ -0,0 +1,283 @@
//
// Created by WolverinDEV on 29/04/2020.
//
#include "clnpath.h"
#include <cstring>
#define MAX_PATH_ELEMENTS 128 /* Number of levels of directory */
void ts_clnpath(char *path)
{
char *src;
char *dst;
char c;
int slash = 0;
/* Convert multiple adjacent slashes to single slash */
src = dst = path;
while ((c = *dst++ = *src++) != '\0')
{
if (c == '/')
{
slash = 1;
while (*src == '/')
src++;
}
}
if (slash == 0)
return;
/* Remove "./" from "./xxx" but leave "./" alone. */
/* Remove "/." from "xxx/." but reduce "/." to "/". */
/* Reduce "xxx/./yyy" to "xxx/yyy" */
src = dst = (*path == '/') ? path + 1 : path;
while (src[0] == '.' && src[1] == '/' && src[2] != '\0')
src += 2;
while ((c = *dst++ = *src++) != '\0')
{
if (c == '/' && src[0] == '.' && (src[1] == '\0' || src[1] == '/'))
{
src++;
dst--;
}
}
if (path[0] == '/' && path[1] == '.' &&
(path[2] == '\0' || (path[2] == '/' && path[3] == '\0')))
path[1] = '\0';
/* Remove trailing slash, if any. There is at most one! */
/* dst is pointing one beyond terminating null */
if ((dst -= 2) > path && *dst == '/')
*dst++ = '\0';
}
bool ts_strequal(const char* a, const char* b) {
return strcmp(a, b) == 0;
}
int ts_tokenise(char* ostring, const char* del, char** result, int max_tokens) {
int num_tokens{0};
char* token, *string, *tofree;
tofree = string = strdup(ostring);
while ((token = strsep(&string, del)) != nullptr) {
result[num_tokens++] = strdup(token);
if(num_tokens > max_tokens)
break;
}
free(tofree);
return num_tokens;
}
/*
** clnpath2() is not part of the basic clnpath() function because it can
** change the meaning of a path name if there are symbolic links on the
** system. For example, suppose /usr/tmp is a symbolic link to /var/tmp.
** If the user supplies /usr/tmp/../abcdef as the directory name, clnpath
** would transform that to /usr/abcdef, not to /var/abcdef which is what
** the kernel would interpret it as.
*/
void ts_clnpath2(char *path)
{
char *token[MAX_PATH_ELEMENTS], *otoken[MAX_PATH_ELEMENTS];
int ntok, ontok;
ts_clnpath(path);
/* Reduce "<name>/.." to "/" */
ntok = ontok = ts_tokenise(path, "/", otoken, MAX_PATH_ELEMENTS);
memcpy(token, otoken, sizeof(char*) * ntok);
if (ntok > 1) {
for (int i = 0; i < ntok - 1; i++)
{
if (!ts_strequal(token[i], "..") && ts_strequal(token[i + 1], ".."))
{
if (*token[i] == '\0')
continue;
while (i < ntok - 1)
{
token[i] = token[i + 2];
i++;
}
ntok -= 2;
i = -1; /* Restart enclosing for loop */
}
}
}
/* Reassemble string */
char *dst = path;
if (ntok == 0)
{
*dst++ = '.';
*dst = '\0';
}
else
{
if (token[0][0] == '\0')
{
int i;
for (i = 1; i < ntok && ts_strequal(token[i], ".."); i++)
;
if (i > 1)
{
int j;
for (j = 1; i < ntok; i++)
token[j++] = token[i];
ntok = j;
}
}
if (ntok == 1 && token[0][0] == '\0')
{
*dst++ = '/';
*dst = '\0';
}
else
{
for (int i = 0; i < ntok; i++)
{
char *src = token[i];
while ((*dst++ = *src++) != '\0')
;
*(dst - 1) = '/';
}
*(dst - 1) = '\0';
}
}
for(int i{0}; i < ontok; i++)
::free(otoken[i]);
}
std::string clnpath(const std::string_view& data) {
std::string result{data};
ts_clnpath2(result.data());
auto index = result.find((char) 0);
if(index != std::string::npos)
result.resize(index);
return result;
}
#ifdef CLN_EXEC
typedef struct p1_test_case
{
const char *input;
const char *output;
} p1_test_case;
/* This stress tests the cleaning, concentrating on the boundaries. */
static const p1_test_case p1_tests[] =
{
{ "/", "/", },
{ "//", "/", },
{ "///", "/", },
{ "/.", "/", },
{ "/./", "/", },
{ "/./.", "/", },
{ "/././.profile", "/.profile", },
{ "./", ".", },
{ "./.", ".", },
{ "././", ".", },
{ "./././.profile", ".profile", },
{ "abc/.", "abc", },
{ "abc/./def", "abc/def", },
{ "./abc", "abc", },
{ "//abcd///./abcd////", "/abcd/abcd", },
{ "//abcd///././../defg///ddd//.", "/abcd/../defg/ddd", },
{ "/abcd/./../././defg/./././ddd", "/abcd/../defg/ddd", },
{ "//abcd//././../defg///ddd//.///", "/abcd/../defg/ddd", },
/* Most of these are minimal interest in phase 1 */
{ "/usr/tmp/clnpath.c", "/usr/tmp/clnpath.c", },
{ "/usr/tmp/", "/usr/tmp", },
{ "/bin/..", "/bin/..", },
{ "bin/..", "bin/..", },
{ "/bin/.", "/bin", },
{ "sub/directory", "sub/directory", },
{ "sub/directory/file", "sub/directory/file", },
{ "/part1/part2/../.././../", "/part1/part2/../../..", },
{ "/.././../usr//.//bin/./cc", "/../../usr/bin/cc", },
};
static void p1_tester(const void *data)
{
const p1_test_case *test = (const p1_test_case *)data;
char buffer[256];
strcpy(buffer, test->input);
ts_clnpath(buffer);
if (strcmp(buffer, test->output) == 0)
printf("<<%s>> cleans to <<%s>>\n", test->input, buffer);
else
{
fprintf(stderr, "<<%s>> - unexpected output from clnpath()\n", test->input);
fprintf(stderr, "Wanted <<%s>>\n", test->output);
fprintf(stderr, "Actual <<%s>>\n", buffer);
}
}
typedef struct p2_test_case
{
const char *input;
const char *output;
} p2_test_case;
static const p2_test_case p2_tests[] =
{
{ "/abcd/../defg/ddd", "/defg/ddd" },
{ "/bin/..", "/" },
{ "bin/..", "." },
{ "/usr/bin/..", "/usr" },
{ "/usr/bin/../..", "/" },
{ "usr/bin/../..", "." },
{ "../part/of/../the/way", "../part/the/way" },
{ "/../part/of/../the/way", "/part/the/way" },
{ "part1/part2/../../part3", "part3" },
{ "part1/part2/../../../part3", "../part3" },
{ "/part1/part2/../../../part3", "/part3" },
{ "/part1/part2/../../../", "/" },
{ "/../../usr/bin/cc", "/usr/bin/cc" },
{ "../../usr/bin/cc", "../../usr/bin/cc" },
{ "part1/./part2/../../part3", "part3" },
{ "./part1/part2/../../../part3", "../part3" },
{ "/part1/part2/.././../../part3", "/part3" },
{ "/part1/part2/../.././../", "/" },
{ "/.././..//./usr///bin/cc/", "/usr/bin/cc" },
{nullptr, nullptr}
};
static void p2_tester(const void *data)
{
auto test = (const p2_test_case *)data;
char buffer[256];
strcpy(buffer, test->input);
ts_clnpath2(buffer);
if (strcmp(buffer, test->output) == 0)
printf("<<%s>> cleans to <<%s>>\n", test->input, buffer);
else
{
fprintf(stderr, "<<%s>> - unexpected output from clnpath2()\n", test->input);
fprintf(stderr, "Wanted <<%s>>\n", test->output);
fprintf(stderr, "Actual <<%s>>\n", buffer);
}
}
int main() {
for(const auto& test : p1_tests) {
if(!test.input) break;
p1_tester(&test);
}
printf("------------------------------\n");
for(const auto& test : p2_tests) {
if(!test.input) break;
p2_tester(&test);
}
}
#endif

View File

@ -0,0 +1,6 @@
#pragma once
#include <string>
#include <string_view>
extern std::string clnpath(const std::string_view&);

125
file/test/main.cpp Normal file
View File

@ -0,0 +1,125 @@
//
// Created by WolverinDEV on 29/04/2020.
//
#include <files/FileServer.h>
#include <log/LogUtils.h>
#include <experimental/filesystem>
#include <local_server/clnpath.h>
namespace fs = std::experimental::filesystem;
using namespace ts::server;
struct Nothing {};
template <typename ErrorType, typename ResponseType>
inline void print_response(const std::string& message, const std::shared_ptr<file::ExecuteResponse<file::filesystem::DetailedError<ErrorType>, ResponseType>>& response) {
if(response->status == file::ExecuteStatus::ERROR)
logError(0, "{}: {} => {}", message, (int) response->error().error_type, response->error().error_message);
else if(response->status == file::ExecuteStatus::SUCCESS)
logMessage(0, "{}: success", message);
else
logWarning(0, "Unknown response state ({})!", (int) response->status);
}
inline void print_query(const std::string& message, const file::filesystem::AbstractProvider::directory_query_response_t& response) {
if(response.status == file::ExecuteStatus::ERROR)
logError(0, "{}: {} => {}", message, (int) response.error().error_type, response.error().error_message);
else if(response.status == file::ExecuteStatus::SUCCESS) {
const auto& entries = response.response();
logMessage(0, "{}: Found {} entries", message, entries.size());
for(auto& entry : entries) {
if(entry.type == file::filesystem::DirectoryEntry::FILE)
logMessage(0, " - File {}", entry.name);
else if(entry.type == file::filesystem::DirectoryEntry::DIRECTORY)
logMessage(0, " - Directory {}", entry.name);
else
logMessage(0, " - Unknown {}", entry.name);
logMessage(0, " Write timestamp: {}", std::chrono::floor<std::chrono::seconds>(entry.modified_at.time_since_epoch()).count());
logMessage(0, " Size: {}", entry.size);
}
} else
logWarning(0, "{}: Unknown response state ({})!", message, (int) response.status);
}
int main() {
std::string error{};
if(!file::initialize(error)) {
logError(0, "Failed to initialize file server: {}", error);
return 0;
}
logMessage(0, "File server started");
auto instance = file::server();
auto& fs = instance->file_system();
{
auto response = fs.initialize_server(0);
response->wait();
print_response("Server init result", response);
if(response->status != file::ExecuteStatus::SUCCESS)
return 0;
}
{
auto response = fs.create_channel_directory(0, 2, "/");
response->wait();
print_response("Channel dir create A", response);
}
{
auto response = fs.create_channel_directory(0, 2, "/test-folder/");
response->wait();
print_response("Channel dir create B", response);
}
{
auto response = fs.create_channel_directory(0, 2, "../test-folder/");
response->wait();
print_response("Channel dir create C", response);
}
{
auto response = fs.create_channel_directory(0, 2, "./test-folder/../test-folder-2");
response->wait();
print_response("Channel dir create D", response);
}
{
auto response = fs.query_channel_directory(0, 2, "/");
response->wait();
print_query("Channel query", *response);
}
{
auto response = fs.query_icon_directory(0);
response->wait();
print_query("Icons", *response);
}
{
auto response = fs.query_avatar_directory(0);
response->wait();
print_query("Avatars", *response);
}
{
auto response = fs.rename_channel_file(0, 2, "./test-folder/../test-folder-2", "./test-folder/../test-folder-3");
response->wait();
print_response("Folder rename A", response);
}
{
auto response = fs.rename_channel_file(0, 2, "./test-folder/../test-folder-3", "./test-folder/../test-folder-2");
response->wait();
print_response("Folder rename B", response);
}
//TODO: Test file locking
return 0;
}

View File

@ -65,7 +65,7 @@ set(SERVER_SOURCE_FILES
src/client/ConnectedClientNotifyHandler.cpp
src/VirtualServerManager.cpp
src/server/file/FileServer.cpp
src/server/file/LocalFileServer.cpp
src/channel/ServerChannel.cpp
src/channel/ClientChannelView.cpp
src/client/file/FileClient.cpp
@ -82,8 +82,6 @@ set(SERVER_SOURCE_FILES
src/client/query/QueryClientCommands.cpp
src/client/query/QueryClientNotify.cpp
src/file/FileServer.cpp
src/manager/IpListManager.cpp
src/ConnectionStatistics.cpp

View File

@ -10,7 +10,7 @@
#include "src/VirtualServer.h"
#include "src/InstanceHandler.h"
#include "src/server/QueryServer.h"
#include "src/server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "src/terminal/CommandHandler.h"
#include "src/client/InternalClient.h"
#include "src/SignalHandler.h"

View File

@ -6,7 +6,7 @@
#include "VirtualServer.h"
#include "src/client/ConnectedClient.h"
#include "InstanceHandler.h"
#include "src/server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
using namespace std;
using namespace std::chrono;

View File

@ -9,7 +9,7 @@
#include "InstanceHandler.h"
#include "src/client/InternalClient.h"
#include "src/server/QueryServer.h"
#include "src/server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "SignalHandler.h"
#include "src/manager/PermissionNameMapper.h"
#include <ThreadPool/Timer.h>
@ -281,19 +281,19 @@ bool InstanceHandler::startInstance() {
}
this->loadWebCertificate();
fileServer = new ts::server::FileServer();
fileServer = new ts::server::LocalFileServer();
{
auto bindings_string = this->properties()[property::SERVERINSTANCE_FILETRANSFER_HOST].as<string>();
auto port = this->properties()[property::SERVERINSTANCE_FILETRANSFER_PORT].as<uint16_t>();
auto ft_bindings = net::resolve_bindings(bindings_string, port);
deque<shared_ptr<FileServer::Binding>> bindings;
deque<shared_ptr<LocalFileServer::Binding>> bindings;
for(auto& binding : ft_bindings) {
if(!get<2>(binding).empty()) {
logError(LOG_FT, "Failed to resolve binding for {}: {}", get<0>(binding), get<2>(binding));
continue;
}
auto entry = make_shared<FileServer::Binding>();
auto entry = make_shared<LocalFileServer::Binding>();
memcpy(&entry->address, &get<1>(binding), sizeof(sockaddr_storage));
entry->file_descriptor = -1;

View File

@ -42,7 +42,7 @@ namespace ts {
std::shared_mutex& getChannelTreeLock() { return this->default_tree_lock; }
VirtualServerManager* getVoiceServerManager(){ return this->voiceServerManager; }
FileServer* getFileServer(){ return fileServer; }
LocalFileServer* getFileServer(){ return fileServer; }
QueryServer* getQueryServer(){ return queryServer; }
DatabaseHelper* databaseHelper(){ return this->dbHelper; }
BanManager* banManager(){ return this->banMgr; }
@ -110,7 +110,7 @@ namespace ts {
std::chrono::system_clock::time_point memcleanTimestamp;
SqlDataManager* sql;
FileServer* fileServer = nullptr;
LocalFileServer* fileServer = nullptr;
QueryServer* queryServer = nullptr;
VirtualServerManager* voiceServerManager = nullptr;
DatabaseHelper* dbHelper = nullptr;

View File

@ -6,7 +6,7 @@
#include "InstanceHandler.h"
#include "src/client/InternalClient.h"
#include "src/server/QueryServer.h"
#include "src/server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
using namespace std;
using namespace std::chrono;

View File

@ -18,7 +18,7 @@
#include "./client/query/QueryClient.h"
#include "music/MusicBotManager.h"
#include "server/VoiceServer.h"
#include "server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "server/QueryServer.h"
#include "InstanceHandler.h"
#include "Configuration.h"

View File

@ -58,7 +58,7 @@ namespace ts {
class InstanceHandler;
class VoiceServer;
class QueryServer;
class FileServer;
class LocalFileServer;
class SpeakingClient;
class WebControlServer;

View File

@ -4,7 +4,7 @@
#include "src/server/VoiceServer.h"
#include "src/client/query/QueryClient.h"
#include "InstanceHandler.h"
#include "src/server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "src/client/ConnectedClient.h"
#include <ThreadPool/ThreadHelper.h>

View File

@ -5,7 +5,7 @@
#include "misc/rnd.h"
#include "src/VirtualServer.h"
#include "src/client/ConnectedClient.h"
#include "src/server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "src/InstanceHandler.h"
#include "../manager/ConversationManager.h"

View File

@ -11,7 +11,7 @@
#include "src/VirtualServer.h"
#include "voice/VoiceClient.h"
#include "../server/VoiceServer.h"
#include "../server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "../InstanceHandler.h"
#include "ConnectedClient.h"

View File

@ -3,7 +3,7 @@
#include <algorithm>
#include "ConnectedClient.h"
#include "voice/VoiceClient.h"
#include "../server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "../server/VoiceServer.h"
#include "../InstanceHandler.h"
#include "../server/QueryServer.h"

View File

@ -4,7 +4,7 @@
#include <misc/hex.h>
#include "DataClient.h"
#include "ConnectedClient.h"
#include "src/server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "src/InstanceHandler.h"
#include "misc/base64.h"

View File

@ -51,6 +51,14 @@ void SpeakingClient::handlePacketVoice(const pipes::buffer_view& data, bool head
return;
}
#if 0
if(rand() % 10 == 0) {
logMessage(0, "Dropping audio packet");
return;
}
logMessage(0, "Received voice: Head: {} Fragmented: {}, length: {}", head, fragmented, data.length());
#endif
auto current_channel = this->currentChannel;
if(!current_channel) { return; }
if(!this->allowedToTalk) { return; }

View File

@ -5,7 +5,7 @@
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../../server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
@ -407,7 +407,7 @@ command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
ACTION_REQUIRES_GROUP_PERMISSION(channelGroup, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, true);
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, false);
if(!max_value.has_value) return command_result{permission::i_permission_modify_power};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0));
@ -1479,7 +1479,7 @@ command_result ConnectedClient::handleCommandChannelAddPerm(Command &cmd) {
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_channel_needed_permission_modify_power, permission::i_channel_permission_modify_power, true);
auto max_value = this->calculate_permission(permission::i_permission_modify_power, channel_id, true);
auto max_value = this->calculate_permission(permission::i_permission_modify_power, channel_id, false);
if(!max_value.has_value) return command_result{permission::i_permission_modify_power};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, channel_id));
@ -1796,7 +1796,7 @@ command_result ConnectedClient::handleCommandChannelClientAddPerm(Command &cmd)
ACTION_REQUIRES_PERMISSION(permission::i_client_permission_modify_power, required_permissions, channel_id);
}
auto max_value = this->calculate_permission(permission::i_permission_modify_power, channel_id, true);
auto max_value = this->calculate_permission(permission::i_permission_modify_power, channel_id, false);
if(!max_value.has_value) return command_result{permission::i_permission_modify_power};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, channel_id));

View File

@ -6,7 +6,7 @@
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../../server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
#include "../../InstanceHandler.h"
@ -964,7 +964,7 @@ command_result ConnectedClient::handleCommandClientAddPerm(Command &cmd) {
auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cldbid);
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_client_permission_modify_power, this->server->calculate_permission(permission::i_client_needed_permission_modify_power, cldbid, ClientType::CLIENT_TEAMSPEAK, 0));
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, true);
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, false);
if(!max_value.has_value) return command_result{permission::i_permission_modify_power};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0));

View File

@ -13,7 +13,7 @@
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../../server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
@ -229,13 +229,11 @@ command_result ConnectedClient::handleCommandFTInitUpload(Command &cmd) {
directory = serverInstance->getFileServer()->avatarDirectory(this->server);
cmd["name"] = "/avatar_" + this->getAvatarId();
} else {
cerr << "Unknown requested directory: " << cmd["path"].as<std::string>() << endl;
return command_result{error::not_implemented};
}
}
if (!directory || directory->type != file::FileType::DIRECTORY) { //Should not happen
cerr << "Invalid upload file path!" << endl;
return command_result{error::file_invalid_path, "could not resolve directory"};
}

View File

@ -13,7 +13,7 @@
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../../server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"

View File

@ -13,7 +13,7 @@
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../../server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"

View File

@ -13,7 +13,7 @@
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../../server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
@ -806,7 +806,7 @@ command_result ConnectedClient::handleCommandServerGroupAddPerm(Command &cmd) {
}
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, true);
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, false);
if(!max_value.has_value) return command_result{permission::i_permission_modify_power};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0));
@ -970,7 +970,7 @@ command_result ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
if(groups.empty())
return command_result{error::ok};
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, true);
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, false);
if(!max_value.has_value) return command_result{permission::i_permission_modify_power};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0));

View File

@ -1,5 +1,5 @@
#include <algorithm>
#include <src/server/file/FileServer.h>
#include <src/server/file/LocalFileServer.h>
#include <log/LogUtils.h>
#include "FileClient.h"
#include <src/InstanceHandler.h>
@ -15,7 +15,7 @@ using namespace ts::server;
namespace fs = std::experimental::filesystem;
#define BUFFER_SIZE (size_t) 2048
FileClient::FileClient(FileServer* handle, int socketFd) : handle(handle), clientFd(socketFd) {
FileClient::FileClient(LocalFileServer* handle, int socketFd) : handle(handle), clientFd(socketFd) {
memtrack::allocated<FileClient>(this);
this->last_io_action = system_clock::now();

View File

@ -3,7 +3,7 @@
#include <protocol/buffers.h>
#include <poll.h>
#include <fstream>
#include <src/server/file/FileServer.h>
#include <src/server/file/LocalFileServer.h>
#include <event.h>
#include <pipes/ws.h>
#include <pipes/ssl.h>
@ -14,7 +14,7 @@ namespace ts {
class ConnectedClient;
class ConnectedClient;
class FileServer;
class LocalFileServer;
enum FTType {
Unknown,
@ -28,7 +28,7 @@ namespace ts {
};
class FileClient {
friend class FileServer;
friend class LocalFileServer;
public:
enum TransferState {
T_INITIALIZE,
@ -45,7 +45,7 @@ namespace ts {
uint16_t length = 0;
};
FileClient(FileServer* handle, int socketFd);
FileClient(LocalFileServer* handle, int socketFd);
~FileClient();
void disconnect(std::chrono::milliseconds = std::chrono::milliseconds(5000));
@ -83,7 +83,7 @@ namespace ts {
void handle_ws_message(const pipes::WSMessage&);
bool handle_ts_message();
private:
FileServer* handle;
LocalFileServer* handle;
std::weak_ptr<FileClient> _this;
std::recursive_mutex bandwidth_lock;

View File

@ -1,6 +1,6 @@
#include <algorithm>
#include <memory>
#include <src/server/file/FileServer.h>
#include <src/server/file/LocalFileServer.h>
#include <log/LogUtils.h>
#include <misc/std_unique_ptr.h>
#include <pipes/buffer.h>

View File

@ -1,7 +1,7 @@
#include "ChannelProvider.h"
#include "../../MusicClient.h"
#include "../../../../InstanceHandler.h"
#include "../../../../server/file/FileServer.h"
#include "src/server/file/LocalFileServer.h"
#include "../../../../../../music/providers/ffmpeg/FFMpegProvider.h"

View File

@ -24,8 +24,20 @@ bool PuzzleManager::precompute_puzzles(size_t amount) {
}
std::shared_ptr<Puzzle> PuzzleManager::next_puzzle() {
std::lock_guard lock{this->cache_lock};
return this->cached_puzzles[this->cache_index++ % this->cached_puzzles.size()];
{
std::lock_guard lock{this->cache_lock};
auto it = this->cached_puzzles.begin() + (this->cache_index++ % this->cached_puzzles.size());
if((*it)->fail_count > 2) {
this->cached_puzzles.erase(it);
} else {
return *it;
}
}
std::random_device rd{};
std::mt19937 mt{rd()};
this->generate_puzzle(mt);
return this->next_puzzle();
}
inline void random_number(std::mt19937& generator, mp_int *result, int length){
@ -74,8 +86,18 @@ void PuzzleManager::generate_puzzle(std::mt19937& random_generator) {
mp_init_multi(&puzzle->x, &puzzle->n, &puzzle->result, nullptr);
generate_new:
random_number(random_generator, &puzzle->x, 64);
random_number(random_generator, &puzzle->n, 64);
static int x{0};
if(x++ == 0 || true) {
mp_set(&puzzle->x, 1);
mp_set(&puzzle->n, 1);
//random_number(random_generator, &puzzle->x, 64);
//random_number(random_generator, &puzzle->n, 64);
} else {
const static std::string_view n_{"\x01\x7a\xc5\x8d\x28\x7a\x61\x58\xf6\xe3\x98\x60\x2f\x81\x9c\x8a\x48\xc9\x20\xd1\x59\xe0\x24\x75\x91\x27\x9f\x52\x1e\x2c\x24\x85\xa9\xdc\x74\xfa\x0b\x36\xf9\x6c\x77\xa3\x7c\xf9\xbb\xf7\x04\xad\xa3\x84\x0d\x97\x25\x54\x19\x72\x4f\x8f\xfc\x66\xbe\x41\xda\x95"};
const static std::string_view x_{"\xd1\xef\xf0\x16\x34\x48\x56\x53\x15\x97\xa0\x28\xbd\x13\xce\xbf\xc2\xd6\x79\x9d\x21\x81\x83\x37\x8c\xe8\xee\xee\xa1\x22\xa4\xf5\x63\x33\x53\x0c\x38\x2f\x0a\x00\x53\x20\xc7\x93\x52\xa9\xd0\xc2\xfb\xbc\xc5\xc4\xc3\x54\xad\xcb\x49\x52\xc0\xd8\x97\x32\x94\xee"};
mp_read_unsigned_bin(&puzzle->x, (unsigned char*) x_.data(), x_.length());
mp_read_unsigned_bin(&puzzle->n, (unsigned char*) n_.data(), n_.length());
}
if(!solve_puzzle(puzzle))
goto generate_new;

View File

@ -8,15 +8,17 @@
namespace ts::server::udp {
struct Puzzle {
mp_int x;
mp_int n;
int level;
mp_int x{};
mp_int n{};
int level{0};
mp_int result;
mp_int result{};
uint8_t data_x[64];
uint8_t data_n[64];
uint8_t data_result[64];
uint8_t data_x[64]{0};
uint8_t data_n[64]{0};
uint8_t data_result[64]{0};
size_t fail_count{0};
};
class PuzzleManager {

View File

@ -1,5 +0,0 @@
//
// Created by WolverinDEV on 28/04/2020.
//
#include "FileServer.h"

View File

@ -1,124 +0,0 @@
#pragma once
#include <string>
#include <chrono>
#include <Definitions.h>
#include <condition_variable>
#include <variant>
#include <vector>
namespace ts::server::file {
enum struct ExecuteStatus {
UNKNOWN,
WAITING,
SUCCESS,
ERROR
};
template <typename error_t, typename response_t>
class ExecuteResponse {
public:
ExecuteStatus status{ExecuteStatus::UNKNOWN};
[[nodiscard]] inline const response_t& response() const { return std::get<response_t>(this->response_); }
[[nodiscard]] inline const response_t& error() const { return std::get<error_t>(this->response_); }
inline void wait() const {
std::unique_lock nlock{this->notify_mutex};
this->notify_cv.wait(nlock, [&]{ return this->status != ExecuteStatus::WAITING; });
}
template<typename _Rep, typename _Period>
[[nodiscard]] inline bool wait_for(const std::chrono::duration<_Rep, _Period>& time) const {
std::unique_lock nlock{this->notify_mutex};
return this->notify_cv.wait_for(nlock, time, [&]{ return this->status != ExecuteStatus::WAITING; });
}
private:
std::variant<error_t, response_t> response_{};
std::mutex& notify_mutex;
std::condition_variable& notify_cv;
};
namespace filesystem {
struct DirectoryQueryError {
enum Type {
UNKNOWN,
};
Type type{};
std::string extra_message{};
};
struct DirectoryEntry {
enum Type {
UNKNOWN,
DIRECTORY,
FILE
};
Type type{Type::UNKNOWN};
std::string name{};
std::chrono::system_clock::time_point created_at{};
std::chrono::system_clock::time_point modified_at{};
size_t size{0};
};
struct DirectoryModifyError {
enum Type {
UNKNOWN,
};
Type type{};
std::string extra_message{};
};
struct FileModifyError {
enum Type {
UNKNOWN,
};
Type type{};
std::string extra_message{};
};
class AbstractProvider {
public:
typedef ExecuteResponse<DirectoryQueryError, std::vector<DirectoryEntry>> directory_query_response_t;
/* channels */
[[nodiscard]] virtual std::shared_ptr<directory_query_response_t> query_channel_directory(ServerId /* server */, ChannelId /* channel */, const std::string& /* path */);
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<DirectoryModifyError, void>> create_channel_directory(ServerId /* server */, ChannelId /* channel */, const std::string& /* path */);
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<DirectoryModifyError, void>> delete_channel_directory(ServerId /* server */, ChannelId /* channel */, const std::string& /* path */);
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<FileModifyError, void>> delete_channel_file(ServerId /* server */, ChannelId /* channel */, const std::string& /* path */);
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<FileModifyError, void>> rename_channel_file(ServerId /* server */, ChannelId /* channel */, const std::string& /* path */);
/* icons */
[[nodiscard]] virtual std::shared_ptr<directory_query_response_t> query_icon_directory(ServerId /* server */);
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<FileModifyError, void>> delete_icon(ServerId /* server */, const std::string& /* name */);
/* avatars */
[[nodiscard]] virtual std::shared_ptr<directory_query_response_t> query_avatar_directory(ServerId /* server */);
[[nodiscard]] virtual std::shared_ptr<ExecuteResponse<FileModifyError, void>> delete_avatar(ServerId /* server */, const std::string& /* name */);
private:
};
}
namespace transfer {
class AbstractProvider {
public:
enum TransferDirection {
UPLOAD,
DOWNLOAD
};
void initialize_channel_transfer(TransferDirection /* direction */, ServerId /* server */, ChannelId /* channel */, const std::string& /* path */);
void initialize_icon_transfer(TransferDirection /* direction */, ServerId /* server */, ChannelId /* channel */, const std::string& /* path */);
void initialize_avatar_transfer(TransferDirection /* direction */, ServerId /* server */, ChannelId /* channel */, const std::string& /* path */);
private:
};
}
class AbstractFileServer {
public:
private:
};
}

View File

@ -252,8 +252,11 @@ void POWHandler::handle_puzzle_solve(const std::shared_ptr<ts::server::POWHandle
/* should we validate x,n and level as well? */
if(memcmp(client->rsa_challenge->data_result, &buffer[4 + 1 + 2 * 64 + 04 + 100], 64) != 0) {
#ifdef POW_ERROR
debugMessage(this->get_server_id(), "[POW][{}][Puzzle] Received an invalid puzzle solution! Resetting client", net::to_string(client->address));
debugMessage(this->get_server_id(), "[POW][{}][Puzzle] Received an invalid puzzle solution! Resetting client & puzzle", net::to_string(client->address));
#endif
constexpr static uint8_t empty_result[64]{0};
if(memcmp(empty_result, &buffer[4 + 1 + 2 * 64 + 04 + 100], 64) == 0)
client->rsa_challenge->fail_count++;
client->rsa_challenge.reset(); /* get another RSA challenge */
this->reset_client(client);
return;

View File

@ -1,4 +1,4 @@
#include "FileServer.h"
#include "LocalFileServer.h"
#include "src/client/file/FileClient.h"
#include "src/client/ConnectedClient.h"
#include <netinet/tcp.h>
@ -20,9 +20,9 @@ namespace fs = std::experimental::filesystem;
extern InstanceHandler* serverInstance;
FileServer::FileServer() {}
LocalFileServer::LocalFileServer() {}
FileServer::~FileServer() {
LocalFileServer::~LocalFileServer() {
stop();
}
@ -32,7 +32,7 @@ inline fs::path buildPath(std::string rootPath, std::shared_ptr<file::FileEntry>
return fs::u8path(rootPath + strPath);
}
std::shared_ptr<file::Directory> FileServer::createDirectory(std::string name, std::shared_ptr<file::Directory> parent) {
std::shared_ptr<file::Directory> LocalFileServer::createDirectory(std::string name, std::shared_ptr<file::Directory> parent) {
auto path = buildPath(this->rootPath, parent);
path += name;
std::error_code code{};
@ -44,17 +44,17 @@ std::shared_ptr<file::Directory> FileServer::createDirectory(std::string name, s
return static_pointer_cast<file::Directory>(this->findFile(path.string()));
}
bool FileServer::fileExists(std::shared_ptr<file::Directory> dir) {
bool LocalFileServer::fileExists(std::shared_ptr<file::Directory> dir) {
std::error_code code{};
return fs::exists(buildPath(this->rootPath, dir), code);
}
bool FileServer::fileExists(std::shared_ptr<file::File> file) {
bool LocalFileServer::fileExists(std::shared_ptr<file::File> file) {
std::error_code code{};
return fs::exists(buildPath(this->rootPath, file), code);
}
std::shared_ptr<file::FileEntry> FileServer::findFile(std::string path, std::shared_ptr<file::Directory> parent) {
std::shared_ptr<file::FileEntry> LocalFileServer::findFile(std::string path, std::shared_ptr<file::Directory> parent) {
if(path.find(this->rootPath) != 0) {
string strPath = (parent ? parent->path + "/" + parent->name : this->rootPath) + "/";
if(strPath.find(this->rootPath) != 0 && rootPath != strPath)
@ -85,7 +85,7 @@ std::shared_ptr<file::FileEntry> FileServer::findFile(std::string path, std::sha
return entry;
}
std::vector<std::shared_ptr<file::FileEntry>> FileServer::listFiles(std::shared_ptr<file::Directory> dir) {
std::vector<std::shared_ptr<file::FileEntry>> LocalFileServer::listFiles(std::shared_ptr<file::Directory> dir) {
if(!dir) return {};
auto directory = buildPath(this->rootPath, dir);
@ -129,7 +129,7 @@ std::vector<std::shared_ptr<file::FileEntry>> FileServer::listFiles(std::shared_
return result;
}
bool FileServer::deleteFile(std::shared_ptr<file::FileEntry> file) {
bool LocalFileServer::deleteFile(std::shared_ptr<file::FileEntry> file) {
std::error_code code{};
return fs::remove_all(fs::u8path(file->path + "/" + file->name), code) > 0 && !code;
}
@ -142,7 +142,7 @@ inline std::string randomString(uint length = 15, std::string charIndex = "abcde
return rs;
}
std::shared_ptr<file::FileTransfereKey> FileServer::generateDownloadTransferKey(std::string &errorMessage, std::string targetFile, size_t offset, const shared_ptr<ConnectedClient>& client) {
std::shared_ptr<file::FileTransfereKey> LocalFileServer::generateDownloadTransferKey(std::string &errorMessage, std::string targetFile, size_t offset, const shared_ptr<ConnectedClient>& client) {
auto file = this->findFile(targetFile, nullptr);
if(!file){
errorMessage = "file does not exists";
@ -188,7 +188,7 @@ std::shared_ptr<file::FileTransfereKey> FileServer::generateDownloadTransferKey(
return result;
}
std::shared_ptr<file::FileTransfereKey> FileServer::generateUploadTransferKey(std::string &errorMessage, std::string targetFile, size_t size, size_t offset, const shared_ptr<ConnectedClient>& client) {
std::shared_ptr<file::FileTransfereKey> LocalFileServer::generateUploadTransferKey(std::string &errorMessage, std::string targetFile, size_t size, size_t offset, const shared_ptr<ConnectedClient>& client) {
shared_ptr<file::FileTransfereKey> result = make_shared<file::FileTransfereKey>();
result->owner = client;
result->server = client->getServerId();
@ -221,7 +221,7 @@ std::shared_ptr<file::FileTransfereKey> FileServer::generateUploadTransferKey(st
return result;
}
std::shared_ptr<file::Directory> FileServer::resolveDirectory(const shared_ptr<VirtualServer> &server, std::shared_ptr<BasicChannel> channel, std::string subPath) {
std::shared_ptr<file::Directory> LocalFileServer::resolveDirectory(const shared_ptr<VirtualServer> &server, std::shared_ptr<BasicChannel> channel, std::string subPath) {
fs::path path = fs::u8path("server_" + to_string(server ? server->getServerId() : 0) + "/channel_" + to_string(channel->channelId()));
if(!findFile(path))
this->createDirectory(path.string(), nullptr);
@ -232,7 +232,7 @@ std::shared_ptr<file::Directory> FileServer::resolveDirectory(const shared_ptr<V
return static_pointer_cast<file::Directory>(ffile);
}
std::shared_ptr<file::Directory> FileServer::iconDirectory(const shared_ptr<VirtualServer> &server) {
std::shared_ptr<file::Directory> LocalFileServer::iconDirectory(const shared_ptr<VirtualServer> &server) {
fs::path root = fs::u8path(this->rootPath);
fs::path path = fs::u8path("server_" + to_string(server ? server->getServerId() : 0) + "/icons");
std::error_code code{};
@ -243,13 +243,13 @@ std::shared_ptr<file::Directory> FileServer::iconDirectory(const shared_ptr<Virt
return static_pointer_cast<file::Directory>(findFile(path.string()));
}
bool FileServer::iconExists(const shared_ptr<VirtualServer> &server, IconId icon) {
bool LocalFileServer::iconExists(const shared_ptr<VirtualServer> &server, IconId icon) {
if(icon == 0) return false;
if(icon < 1000) return true;
return this->findFile("icon_" + to_string(icon), this->iconDirectory(server)) != nullptr;
}
std::shared_ptr<file::Directory> FileServer::avatarDirectory(const shared_ptr<VirtualServer> &server) {
std::shared_ptr<file::Directory> LocalFileServer::avatarDirectory(const shared_ptr<VirtualServer> &server) {
fs::path path = fs::u8path("server_" + to_string(server ? server->getServerId() : 0) + "/avatars");
if(!findFile(path))
this->createDirectory(path.string(), nullptr);
@ -257,7 +257,7 @@ std::shared_ptr<file::Directory> FileServer::avatarDirectory(const shared_ptr<Vi
}
#define TS3_ICON_HASH "icon_1001"
void FileServer::setupServer(const shared_ptr<VirtualServer> &server) {
void LocalFileServer::setupServer(const shared_ptr<VirtualServer> &server) {
auto dir = iconDirectory(server);
if(!dir) {
logError(LOG_FT,"Failed to find icon directory for server {}", server ? server->getServerId() : 0);
@ -273,11 +273,11 @@ void FileServer::setupServer(const shared_ptr<VirtualServer> &server) {
}
}
std::string FileServer::server_file_base(const std::shared_ptr<ts::server::VirtualServer> &server) {
std::string LocalFileServer::server_file_base(const std::shared_ptr<ts::server::VirtualServer> &server) {
return rootPath + "/server_" + to_string(server->getServerId());
}
void FileServer::deleteServer(const shared_ptr<VirtualServer> &server) {
void LocalFileServer::deleteServer(const shared_ptr<VirtualServer> &server) {
fs::path path = fs::u8path(rootPath + "/server_" + to_string(server ? server->getServerId() : 0));
std::error_code code{};
if(fs::exists(path, code) && !code) {
@ -289,7 +289,7 @@ void FileServer::deleteServer(const shared_ptr<VirtualServer> &server) {
}
//The actual server!
bool FileServer::start(const std::deque<std::shared_ptr<FileServer::Binding>>& bindings, std::string& error) {
bool LocalFileServer::start(const std::deque<std::shared_ptr<LocalFileServer::Binding>>& bindings, std::string& error) {
if(this->running()) {
error = "server already running";
return false;
@ -355,7 +355,7 @@ bool FileServer::start(const std::deque<std::shared_ptr<FileServer::Binding>>& b
continue;
}
binding->event_accept = event_new(this->ioLoop, binding->file_descriptor, EV_READ | EV_PERSIST, [](int a, short b, void* c){ ((FileServer *) c)->on_client_accept(a, b, c); }, this);
binding->event_accept = event_new(this->ioLoop, binding->file_descriptor, EV_READ | EV_PERSIST, [](int a, short b, void* c){ ((LocalFileServer *) c)->on_client_accept(a, b, c); }, this);
event_add(binding->event_accept, nullptr);
this->bindings.push_back(binding);
}
@ -368,14 +368,14 @@ bool FileServer::start(const std::deque<std::shared_ptr<FileServer::Binding>>& b
}
for(int index = 0; index < 2; index++){
auto th = new threads::Thread(THREAD_SAVE_OPERATIONS | THREAD_EXECUTE_LATER, &FileServer::clientTickingExecutor, this);
auto th = new threads::Thread(THREAD_SAVE_OPERATIONS | THREAD_EXECUTE_LATER, &LocalFileServer::clientTickingExecutor, this);
th->name("Ticking FT #" + to_string(index)).execute();
this->tickingThreads.push_back(th);
}
return true;
}
void FileServer::stop() {
void LocalFileServer::stop() {
if(!this->running()) return;
active = false;
{
@ -449,7 +449,7 @@ if(close(file_descriptor) < 0) { \
debugMessage(LOG_FT, "[{}] Failed to close socket ({} | {}).", logging_address(remote_address), errno, strerror(errno)); \
}
void FileServer::on_client_accept(int _server_file_descriptor, short ev, void *arg) {
void LocalFileServer::on_client_accept(int _server_file_descriptor, short ev, void *arg) {
sockaddr_storage remote_address{};
memset(&remote_address, 0, sizeof(remote_address));
socklen_t address_length = sizeof(remote_address);
@ -559,7 +559,7 @@ void FileServer::on_client_accept(int _server_file_descriptor, short ev, void *a
logMessage(LOG_FT, "[{}] Remote peer connected. Initializing session.", logging_address(remote_address));
}
void FileServer::clientTickingExecutor() {
void LocalFileServer::clientTickingExecutor() {
while(this->running()){
shared_ptr<FileClient> client;
{
@ -575,7 +575,7 @@ void FileServer::clientTickingExecutor() {
}
}
std::deque<std::shared_ptr<FileClient>> FileServer::running_file_transfers(const std::shared_ptr<ts::server::ConnectedClient> &client) {
std::deque<std::shared_ptr<FileClient>> LocalFileServer::running_file_transfers(const std::shared_ptr<ts::server::ConnectedClient> &client) {
std::deque<std::shared_ptr<FileClient>> result;
{
@ -588,7 +588,7 @@ std::deque<std::shared_ptr<FileClient>> FileServer::running_file_transfers(const
return result;
}
std::deque<std::shared_ptr<file::FileTransfereKey>> FileServer::pending_file_transfers(const std::shared_ptr<ts::server::ConnectedClient> &client) {
std::deque<std::shared_ptr<file::FileTransfereKey>> LocalFileServer::pending_file_transfers(const std::shared_ptr<ts::server::ConnectedClient> &client) {
std::deque<std::shared_ptr<file::FileTransfereKey>> result;
for(const auto& key : this->pending_keys())
if(!client || key->owner.lock() == client)
@ -596,7 +596,7 @@ std::deque<std::shared_ptr<file::FileTransfereKey>> FileServer::pending_file_tra
return result;
}
void FileServer::tickFileClient(std::shared_ptr<FileClient> cl) {
void LocalFileServer::tickFileClient(std::shared_ptr<FileClient> cl) {
lock_guard<mutex> lock(this->tickingLock);
this->tickQueue.push_back(cl);
this->tickingCon.notify_one();
@ -613,7 +613,7 @@ struct TransfareGroup {
ssize_t max_bandwidth = -1;
};
void FileServer::instanceTick() {
void LocalFileServer::instanceTick() {
{
//tickQueue
auto client = this->connected_clients();

View File

@ -76,7 +76,7 @@ namespace ts {
class FileClient;
//FIXME Valid path
class FileServer {
class LocalFileServer {
friend class FileClient;
public:
struct Binding {
@ -87,8 +87,8 @@ namespace ts {
inline std::string as_string() { return net::to_string(address, true); }
};
FileServer();
~FileServer();
LocalFileServer();
~LocalFileServer();
bool start(const std::deque<std::shared_ptr<Binding>>& /* bindings */, std::string& /* error */);
void stop();

View File

@ -28,7 +28,12 @@ void TSWebClient::_handle_message_read(int file_descriptor, short, void *ptr_cli
const auto read = recv(file_descriptor, buffer.data_ptr(), buffer.length(), MSG_NOSIGNAL | MSG_DONTWAIT);
if(read <= 0) {
logError(client->server->getServerId(), "[WebList] Failed to read weblist response. ({} | {} => {})", read, errno, strerror(errno));
event_del_noblock(client->event_read);
{
std::lock_guard elock{client->event_mutex};
if(client->event_read)
event_del_noblock(client->event_read);
}
client->trigger_fail_later("failed to read!", true);
return;
}
@ -46,8 +51,11 @@ void TSWebClient::_handle_message_write(int file_descriptor, short, void *ptr_cl
buffer = std::move(client->write_buffer[0]);
client->write_buffer.pop_front();
if(!client->write_buffer.empty() && client->event_write)
event_add(client->event_write, nullptr);
if(!client->write_buffer.empty()) {
std::lock_guard elock{client->event_mutex};
if(client->event_write)
event_add(client->event_write, nullptr);
}
}
const auto write = sendto(file_descriptor, buffer.data_ptr(), buffer.length(), 0, (const sockaddr *) &client->remote_address, sizeof(sockaddr_in));
@ -60,8 +68,11 @@ void TSWebClient::_handle_message_write(int file_descriptor, short, void *ptr_cl
void TSWebClient::_handle_timeout(int, short, void *ptr_client) {
const auto client = (TSWebClient*) ptr_client;
if(client->event_timeout)
event_del_noblock(client->event_timeout);
{
std::lock_guard elock{client->event_mutex};
if(client->event_timeout)
event_del_noblock(client->event_timeout);
}
client->trigger_fail_later("timeout", true);
}
@ -76,12 +87,15 @@ void TSWebClient::unregister_events(bool blocking) {
}
};
if(this->event_timeout)
unregister(this->event_timeout);
if(this->event_read)
unregister(this->event_read);
if(this->event_write)
unregister(this->event_write);
std::unique_lock elock{this->event_mutex};
auto tevent = std::exchange(this->event_timeout, nullptr);
auto revent = std::exchange(this->event_read, nullptr);
auto wevent = std::exchange(this->event_write, nullptr);
elock.unlock();
if(tevent) unregister(tevent);
if(revent) unregister(revent);
if(wevent) unregister(wevent);
if(this->file_descriptor > 0) {
close(this->file_descriptor);
@ -90,6 +104,7 @@ void TSWebClient::unregister_events(bool blocking) {
}
void TSWebClient::reset_timeout(bool reschedule) {
std::lock_guard elock{this->event_mutex};
if(this->event_timeout) {
event_del(this->event_timeout);
if(reschedule) {

View File

@ -42,9 +42,10 @@ namespace ts {
std::deque<pipes::buffer> write_buffer{};
int file_descriptor{0};
struct event* event_read = nullptr;
struct event* event_write = nullptr;
struct event* event_timeout = nullptr;
std::mutex event_mutex{};
struct event* event_read{nullptr};
struct event* event_write{nullptr};
struct event* event_timeout{nullptr};
void unregister_events(bool /* blocking */);
void reset_timeout(bool /* reschedule */);

View File

@ -1,24 +1,59 @@
#include <tommath.h>
#include <cassert>
#include <tomcrypt.h>
#include <iostream>
#include <string_view>
//#define STANDALONE
#ifndef STANDALONE
#include <cassert>
#endif
//c++ -I. --std=c++1z test.cpp ./libtommath.a -o test
#ifdef STANDALONE
int main() {
#else
void testTomMath(){
mp_int x{};
mp_init(&x);
mp_read_radix(&x, "2280880776330203449294339386427307168808659578661428574166839717243346815923951250209099128371839254311904649344289668000305972691071196233379180504231889", 10);
#endif
{
mp_int x{}, n{}, exp{}, r{};
mp_init_multi(&x, &n, &exp, &r, nullptr);
mp_2expt(&exp, 1000);
mp_int n{};
mp_init(&n);
mp_read_radix(&n, "436860662135489324843442078840868871476482593772359054106809367217662215065650065606351911592188139644751920724885335056877706082800496073391354240530016", 10);
mp_read_radix(&x, "2280880776330203449294339386427307168808659578661428574166839717243346815923951250209099128371839254311904649344289668000305972691071196233379180504231889", 10);
mp_read_radix(&n, "436860662135489324843442078840868871476482593772359054106809367217662215065650065606351911592188139644751920724885335056877706082800496073391354240530016", 10);
mp_int exp{};
mp_init(&exp);
mp_2expt(&exp, 1000);
auto err = mp_exptmod(&x, &exp, &n, &r);
#ifdef STANDALONE
std::cout << "Series A: " << err << ", expected != 0\n";
#else
//assert(err != MP_OKAY); //if this method succeed than tommath failed. Unknown why but it is so
#endif
mp_clear_multi(&x, &n, &exp, &r, nullptr);
}
{
mp_int x{}, n{}, exp{}, r{};
mp_init_multi(&x, &n, &exp, &r, nullptr);
mp_2expt(&exp, 1000);
#if 0
const static std::string_view n_{"\x01\x7a\xc5\x8d\x28\x7a\x61\x58\xf6\xe3\x98\x60\x2f\x81\x9c\x8a\x48\xc9\x20\xd1\x59\xe0\x24\x75\x91\x27\x9f\x52\x1e\x2c\x24\x85\xa9\xdc\x74\xfa\x0b\x36\xf9\x6c\x77\xa3\x7c\xf9\xbb\xf7\x04\xad\xa3\x84\x0d\x97\x25\x54\x19\x72\x4f\x8f\xfc\x66\xbe\x41\xda\x95"};
const static std::string_view x_{"\xd1\xef\xf0\x16\x34\x48\x56\x53\x15\x97\xa0\x28\xbd\x13\xce\xbf\xc2\xd6\x79\x9d\x21\x81\x83\x37\x8c\xe8\xee\xee\xa1\x22\xa4\xf5\x63\x33\x53\x0c\x38\x2f\x0a\x00\x53\x20\xc7\x93\x52\xa9\xd0\xc2\xfb\xbc\xc5\xc4\xc3\x54\xad\xcb\x49\x52\xc0\xd8\x97\x32\x94\xee"};
mp_read_unsigned_bin(&x, (unsigned char*) x_.data(), x_.length());
mp_read_unsigned_bin(&n, (unsigned char*) n_.data(), n_.length());
#else
const static std::string_view n_{"017ac58d287a6158f6e398602f819c8a48c920d159e0247591279f521e2c2485a9dc74fa0b36f96c77a37cf9bbf704ada3840d97255419724f8ffc66be41da95"};
const static std::string_view x_{"d1eff016344856531597a028bd13cebfc2d6799d218183378ce8eeeea122a4f56333530c382f0a005320c79352a9d0c2fbbcc5c4c354adcb4952c0d8973294ee"};
mp_read_radix(&x, x_.data(), 16);
mp_read_radix(&n, n_.data(), 16);
#endif
mp_int r{};
mp_init(&r);
assert(mp_exptmod(&x, &exp, &n, &r) != CRYPT_OK); //if this method succeed than tommath failed. Unknown why but it is so
auto err = mp_exptmod(&x, &exp, &n, &r);
#ifdef STANDALONE
std::cout << "Series B: " << err << ", expected != 0\n";
#else
//assert(err != MP_OKAY); //if this method succeed than tommath failed. Unknown why but it is so
#endif
mp_clear_multi(&x, &n, &exp, &r, nullptr);
mp_clear_multi(&x, &n, &exp, &r, nullptr);
}
}