Update
This commit is contained in:
parent
f3441e0115
commit
fd256411d1
@ -104,3 +104,4 @@ add_subdirectory(shared/)
|
||||
add_subdirectory(server/)
|
||||
add_subdirectory(license/)
|
||||
add_subdirectory(MusicBot/)
|
||||
add_subdirectory(file/)
|
25
file/CMakeLists.txt
Normal file
25
file/CMakeLists.txt
Normal 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)
|
286
file/include/files/FileServer.h
Normal file
286
file/include/files/FileServer.h
Normal 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();
|
||||
}
|
45
file/local_server/LocalFileServer.cpp
Normal file
45
file/local_server/LocalFileServer.cpp
Normal 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_;
|
||||
}
|
93
file/local_server/LocalFileServer.h
Normal file
93
file/local_server/LocalFileServer.h
Normal 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_{};
|
||||
};
|
||||
}
|
309
file/local_server/LocalFileSystem.cpp
Normal file
309
file/local_server/LocalFileSystem.cpp
Normal 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 ¤t_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);
|
||||
}
|
283
file/local_server/clnpath.cpp
Normal file
283
file/local_server/clnpath.cpp
Normal 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
|
6
file/local_server/clnpath.h
Normal file
6
file/local_server/clnpath.h
Normal 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
125
file/test/main.cpp
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -58,7 +58,7 @@ namespace ts {
|
||||
class InstanceHandler;
|
||||
class VoiceServer;
|
||||
class QueryServer;
|
||||
class FileServer;
|
||||
class LocalFileServer;
|
||||
class SpeakingClient;
|
||||
|
||||
class WebControlServer;
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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"};
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -1,5 +0,0 @@
|
||||
//
|
||||
// Created by WolverinDEV on 28/04/2020.
|
||||
//
|
||||
|
||||
#include "FileServer.h"
|
@ -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:
|
||||
};
|
||||
}
|
@ -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;
|
||||
|
@ -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();
|
@ -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();
|
@ -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) {
|
||||
|
@ -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 */);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user