added check version support to remote mounts

This commit is contained in:
2025-09-22 10:36:36 -05:00
parent 63701e105a
commit 06f169293d
8 changed files with 127 additions and 41 deletions

View File

@@ -25,6 +25,7 @@
### Changes from v2.0.7-release ### Changes from v2.0.7-release
* Added check version support to remote mounts
* Fixed handling of `FALLOC_FL_KEEP_SIZE` on Linux * Fixed handling of `FALLOC_FL_KEEP_SIZE` on Linux
* Fixed intermittent client hang on remote mount server disconnect * Fixed intermittent client hang on remote mount server disconnect

View File

@@ -68,7 +68,8 @@ private:
[[nodiscard]] auto get_client() -> std::shared_ptr<client>; [[nodiscard]] auto get_client() -> std::shared_ptr<client>;
[[nodiscard]] auto handshake(client &cli) const -> bool; [[nodiscard]] auto handshake(client &cli, std::uint32_t &min_version) const
-> bool;
void put_client(std::shared_ptr<client> &cli); void put_client(std::shared_ptr<client> &cli);
@@ -78,6 +79,9 @@ private:
void resolve(); void resolve();
public: public:
[[nodiscard]] auto check_version(std::uint32_t client_version,
std::uint32_t &min_version) -> api_error;
[[nodiscard]] auto send(std::string_view method, std::uint32_t &service_flags) [[nodiscard]] auto send(std::string_view method, std::uint32_t &service_flags)
-> packet::error_type; -> packet::error_type;

View File

@@ -41,6 +41,9 @@ create_rocksdb(const app_config &cfg, const std::string &name,
[[nodiscard]] auto create_volume_label(provider_type prov) -> std::string; [[nodiscard]] auto create_volume_label(provider_type prov) -> std::string;
[[nodiscard]] auto get_attributes_from_meta(const api_meta_map &meta) -> DWORD; [[nodiscard]] auto get_attributes_from_meta(const api_meta_map &meta) -> DWORD;
[[nodiscard]] auto get_version_number(std::string_view version)
-> std::uint32_t;
} // namespace utils } // namespace utils
} // namespace repertory } // namespace repertory

View File

@@ -27,7 +27,6 @@
#include "utils/collection.hpp" #include "utils/collection.hpp"
#include "utils/common.hpp" #include "utils/common.hpp"
#include "utils/error_utils.hpp" #include "utils/error_utils.hpp"
#include "version.hpp"
using namespace repertory::comm; using namespace repertory::comm;
@@ -58,7 +57,8 @@ void packet_client::close(client &cli) {
boost::system::error_code err; boost::system::error_code err;
[[maybe_unused]] auto res = cli.socket.close(err); [[maybe_unused]] auto res = cli.socket.close(err);
} catch (...) { } catch (const std::exception &e) {
utils::error::raise_error(function_name, e, "connection handshake failed");
} }
} }
@@ -76,6 +76,39 @@ void packet_client::close_all() {
unique_id_ = utils::create_uuid_string(); unique_id_ = utils::create_uuid_string();
} }
auto packet_client::check_version(std::uint32_t client_version,
std::uint32_t &min_version) -> api_error {
try {
min_version = 0U;
boost::asio::io_context ctx{};
auto resolve_results = tcp::resolver(ctx).resolve(
cfg_.host_name_or_ip, std::to_string(cfg_.api_port));
client cli(ctx);
connect_with_deadline(ctx, cli.socket, resolve_results,
std::chrono::milliseconds(cfg_.conn_timeout_ms));
cli.socket.set_option(boost::asio::ip::tcp::no_delay(true));
cli.socket.set_option(boost::asio::socket_base::linger(false, 0));
cli.socket.set_option(boost::asio::socket_base::keep_alive(true));
if (not handshake(cli, min_version)) {
return api_error::comm_error;
}
if (client_version < min_version) {
return api_error::incompatible_version;
}
return api_error::success;
} catch (const std::exception &e) {
utils::error::raise_error(function_name, e, "connection handshake failed");
}
return api_error::error;
}
void packet_client::connect(client &cli) { void packet_client::connect(client &cli) {
try { try {
resolve(); resolve();
@@ -87,7 +120,8 @@ void packet_client::connect(client &cli) {
cli.socket.set_option(boost::asio::socket_base::linger(false, 0)); cli.socket.set_option(boost::asio::socket_base::linger(false, 0));
cli.socket.set_option(boost::asio::socket_base::keep_alive(true)); cli.socket.set_option(boost::asio::socket_base::keep_alive(true));
if (not handshake(cli)) { std::uint32_t min_version{};
if (not handshake(cli, min_version)) {
close(cli); close(cli);
return; return;
} }
@@ -131,14 +165,18 @@ auto packet_client::get_client() -> std::shared_ptr<packet_client::client> {
return nullptr; return nullptr;
} }
auto packet_client::handshake(client &cli) const -> bool { auto packet_client::handshake(client &cli, std::uint32_t &min_version) const
-> bool {
REPERTORY_USES_FUNCTION_NAME(); REPERTORY_USES_FUNCTION_NAME();
try { try {
min_version = 0U;
data_buffer buffer; data_buffer buffer;
{ {
packet tmp; packet tmp;
tmp.encode_top(utils::generate_random_string(packet_nonce_size)); tmp.encode(utils::get_version_number(REPERTORY_MIN_REMOTE_VERSION));
tmp.encode(utils::generate_random_string(packet_nonce_size));
tmp.to_buffer(buffer); tmp.to_buffer(buffer);
} }
@@ -146,6 +184,7 @@ auto packet_client::handshake(client &cli) const -> bool {
boost::asio::buffer(buffer), boost::asio::buffer(buffer),
std::chrono::milliseconds(cfg_.recv_timeout_ms)); std::chrono::milliseconds(cfg_.recv_timeout_ms));
packet response(buffer); packet response(buffer);
response.decode(min_version);
response.encrypt(cfg_.encryption_token, false); response.encrypt(cfg_.encryption_token, false);
response.to_buffer(buffer); response.to_buffer(buffer);
@@ -154,7 +193,7 @@ auto packet_client::handshake(client &cli) const -> bool {
std::chrono::milliseconds(cfg_.send_timeout_ms)); std::chrono::milliseconds(cfg_.send_timeout_ms));
return true; return true;
} catch (const std::exception &e) { } catch (const std::exception &e) {
repertory::utils::error::raise_error(function_name, e, "handlshake failed"); utils::error::raise_error(function_name, e, "handlshake failed");
} }
return false; return false;

View File

@@ -32,12 +32,12 @@
#include "types/repertory.hpp" #include "types/repertory.hpp"
#include "utils/error_utils.hpp" #include "utils/error_utils.hpp"
#include "utils/timeout.hpp" #include "utils/timeout.hpp"
#include "utils/utils.hpp"
using namespace repertory::comm; using namespace repertory::comm;
using std::thread; using std::thread;
namespace repertory { namespace repertory {
packet_server::packet_server(std::uint16_t port, std::string token, packet_server::packet_server(std::uint16_t port, std::string token,
std::uint8_t pool_size, closed_callback closed, std::uint8_t pool_size, closed_callback closed,
message_handler_callback message_handler) message_handler_callback message_handler)
@@ -91,7 +91,8 @@ auto packet_server::handshake(std::shared_ptr<connection> conn) const -> bool {
data_buffer buffer; data_buffer buffer;
packet request; packet request;
request.encode_top(conn->nonce); request.encode(utils::get_version_number(REPERTORY_MIN_REMOTE_VERSION));
request.encode(conn->nonce);
request.to_buffer(buffer); request.to_buffer(buffer);
auto to_read{buffer.size() + utils::encryption::encryption_header_size}; auto to_read{buffer.size() + utils::encryption::encryption_header_size};

View File

@@ -19,8 +19,6 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include "rocksdb/table.h"
#include "utils/utils.hpp" #include "utils/utils.hpp"
#include "app_config.hpp" #include "app_config.hpp"
@@ -90,4 +88,13 @@ auto create_volume_label(provider_type prov) -> std::string {
auto get_attributes_from_meta(const api_meta_map &meta) -> DWORD { auto get_attributes_from_meta(const api_meta_map &meta) -> DWORD {
return static_cast<DWORD>(utils::string::to_uint32(meta.at(META_ATTRIBUTES))); return static_cast<DWORD>(utils::string::to_uint32(meta.at(META_ATTRIBUTES)));
} }
auto get_repertory_version_number(std::string_view version) -> std::uint32_t {
auto parts = utils::string::split(version, '-', false);
parts = utils::string::split(parts.at(0U), '.', false);
return (utils::string::to_uint32(parts.at(0U)) << 24U) |
(utils::string::to_uint32(parts.at(1U)) << 16U) |
(utils::string::to_uint32(parts.at(2U)) << 8U);
}
} // namespace repertory::utils } // namespace repertory::utils

View File

@@ -23,17 +23,41 @@
#define REPERTORY_INCLUDE_CLI_CHECK_VERSION_HPP_ #define REPERTORY_INCLUDE_CLI_CHECK_VERSION_HPP_
#include "cli/common.hpp" #include "cli/common.hpp"
#include "comm/packet/packet_client.hpp"
#include "utils/utils.hpp"
#include "version.cpp"
namespace repertory::cli::actions { namespace repertory::cli::actions {
[[nodiscard]] inline auto check_version(std::vector<const char *> /* args */, [[nodiscard]] inline auto
const std::string &data_directory, check_version(const std::string &data_directory, provider_type prov,
provider_type prov, const std::string &remote_host, std::uint16_t remote_port)
const std::string & /*unique_id*/, -> exit_code {
std::string /*user*/, if (prov == provider_type::remote) {
std::string /*password*/) -> exit_code { app_config config(prov, data_directory);
auto remote_cfg = config.get_remote_config();
remote_cfg.host_name_or_ip = remote_host;
remote_cfg.api_port = remote_port;
config.set_remote_config(remote_cfg);
packet_client client(config.get_remote_config());
std::uint32_t min_version{};
auto client_version = utils::get_version_number(project_get_version());
auto ret = client.check_version(client_version, min_version);
if (ret == api_error::success) {
fmt::println("0\nSuccess:\n\tRequired: {}\n\tActual: {}", min_version,
client_version);
} else {
fmt::println("1\nFailed:\n\tRequired: {}\n\tActual: {}", min_version,
client_version);
}
return ret;
}
if (prov != provider_type::sia) { if (prov != provider_type::sia) {
fmt::println("Success:\n\tNo specific version is required for {} providers", fmt::println(
app_config::get_provider_display_name(prov)); "0\nSuccess:\n\tNo specific version is required for {} providers",
app_config::get_provider_display_name(prov));
return exit_code::success; return exit_code::success;
} }

View File

@@ -113,6 +113,7 @@ auto main(int argc, char **argv) -> int {
'_'), '_'),
}) })
: utils::path::absolute(data_directory); : utils::path::absolute(data_directory);
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << (e.what() == nullptr ? "Unable to parse port" std::cerr << (e.what() == nullptr ? "Unable to parse port"
: e.what()) : e.what())
@@ -145,32 +146,38 @@ auto main(int argc, char **argv) -> int {
} }
} }
int mount_result{}; if (utils::cli::has_option(args,
if (res == exit_code::success) { utils::cli::options::check_version_option)) {
res = exit_code::option_not_found; ret = static_cast<std::int32_t>(utils::cli::check_version(
for (std::size_t idx = 0U; data_directory, prov, remote_host, remote_port));
(res == exit_code::option_not_found) && } else {
(idx < utils::cli::options::option_list.size()); int mount_result{};
idx++) { if (res == exit_code::success) {
try { res = exit_code::option_not_found;
res = cli::actions::perform_action( for (std::size_t idx = 0U;
utils::cli::options::option_list[idx], args, data_directory, prov, (res == exit_code::option_not_found) &&
unique_id, user, password); (idx < utils::cli::options::option_list.size());
} catch (const std::exception &ex) { idx++) {
res = exit_code::exception; try {
} catch (...) { res = cli::actions::perform_action(
res = exit_code::exception; utils::cli::options::option_list[idx], args, data_directory,
prov, unique_id, user, password);
} catch (const std::exception &ex) {
res = exit_code::exception;
} catch (...) {
res = exit_code::exception;
}
}
if (res == exit_code::option_not_found) {
res = cli::actions::mount(args, data_directory, mount_result, prov,
remote_host, remote_port, unique_id);
} }
} }
if (res == exit_code::option_not_found) { ret = ((res == exit_code::mount_result) ? mount_result
res = cli::actions::mount(args, data_directory, mount_result, prov, : static_cast<std::int32_t>(res));
remote_host, remote_port, unique_id);
}
} }
ret = ((res == exit_code::mount_result) ? mount_result
: static_cast<std::int32_t>(res));
} }
repertory::project_cleanup(); repertory::project_cleanup();