2023-02-11 20:49:42 +00:00
|
|
|
// This file Copyright © 2016-2023 Mnemosyne LLC.
|
2022-02-07 16:25:02 +00:00
|
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
2022-01-20 18:27:56 +00:00
|
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
|
|
// License text can be found in the licenses/ folder.
|
2016-09-05 19:06:26 +00:00
|
|
|
|
2021-10-17 20:17:18 +00:00
|
|
|
#include <ctime>
|
2021-12-15 21:25:42 +00:00
|
|
|
#include <string_view>
|
2022-08-06 19:27:37 +00:00
|
|
|
#include <iterator> // for std::back_inserter
|
2016-09-05 19:06:26 +00:00
|
|
|
|
2016-09-21 20:56:03 +00:00
|
|
|
#ifndef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
#include <sys/stat.h>
|
2016-09-21 20:56:03 +00:00
|
|
|
#endif
|
|
|
|
|
2023-04-16 20:34:19 +00:00
|
|
|
#include <fmt/core.h>
|
2022-03-14 04:43:35 +00:00
|
|
|
|
2023-04-14 19:33:23 +00:00
|
|
|
#include "libtransmission/transmission.h"
|
|
|
|
|
|
|
|
#include "libtransmission/crypto-utils.h" // for tr_rand_obj()
|
|
|
|
#include "libtransmission/error-types.h"
|
|
|
|
#include "libtransmission/error.h"
|
|
|
|
#include "libtransmission/file.h"
|
|
|
|
#include "libtransmission/log.h"
|
|
|
|
#include "libtransmission/platform.h"
|
|
|
|
#include "libtransmission/session-id.h"
|
|
|
|
#include "libtransmission/tr-strbuf.h" // for tr_pathbuf
|
|
|
|
#include "libtransmission/utils.h" // for _()
|
2016-09-05 19:06:26 +00:00
|
|
|
|
2021-11-13 00:10:04 +00:00
|
|
|
using namespace std::literals;
|
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
namespace
|
2016-09-05 19:06:26 +00:00
|
|
|
{
|
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
void get_lockfile_path(std::string_view session_id, tr_pathbuf& path)
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
fmt::format_to(std::back_inserter(path), FMT_STRING("{:s}/tr_session_id_{:s}"), tr_getSessionIdDir(), session_id);
|
2016-09-21 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
tr_sys_file_t create_lockfile(std::string_view session_id)
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
if (std::empty(session_id))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
return TR_BAD_SYS_FILE;
|
|
|
|
}
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
auto lockfile_path = tr_pathbuf{};
|
|
|
|
get_lockfile_path(session_id, lockfile_path);
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
tr_error* error = nullptr;
|
2022-08-06 19:27:37 +00:00
|
|
|
auto lockfile_fd = tr_sys_file_open(lockfile_path, TR_SYS_FILE_READ | TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600, &error);
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
if (lockfile_fd != TR_BAD_SYS_FILE)
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
if (tr_sys_file_lock(lockfile_fd, TR_SYS_FILE_LOCK_EX | TR_SYS_FILE_LOCK_NB, &error))
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
2017-04-19 12:04:45 +00:00
|
|
|
/* Allow any user to lock the file regardless of current umask */
|
2022-08-06 19:27:37 +00:00
|
|
|
fchmod(lockfile_fd, 0644);
|
2016-09-21 20:56:03 +00:00
|
|
|
#endif
|
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
else
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
tr_sys_file_close(lockfile_fd);
|
|
|
|
lockfile_fd = TR_BAD_SYS_FILE;
|
2016-09-21 20:56:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (error != nullptr)
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2022-03-14 04:43:35 +00:00
|
|
|
tr_logAddWarn(fmt::format(
|
2022-03-16 00:51:36 +00:00
|
|
|
_("Couldn't create '{path}': {error} ({error_code})"),
|
2022-08-06 19:27:37 +00:00
|
|
|
fmt::arg("path", lockfile_path),
|
2022-03-16 00:51:36 +00:00
|
|
|
fmt::arg("error", error->message),
|
|
|
|
fmt::arg("error_code", error->code)));
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_error_free(error);
|
2016-09-21 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
return lockfile_fd;
|
2016-09-21 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
void destroy_lockfile(tr_sys_file_t lockfile_fd, std::string_view session_id)
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
if (lockfile_fd != TR_BAD_SYS_FILE)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
tr_sys_file_close(lockfile_fd);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
if (!std::empty(session_id))
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
auto lockfile_path = tr_pathbuf{};
|
|
|
|
get_lockfile_path(session_id, lockfile_path);
|
|
|
|
tr_sys_path_remove(lockfile_path);
|
2016-09-21 20:56:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
#ifndef _WIN32
|
|
|
|
auto constexpr WouldBlock = EWOULDBLOCK;
|
|
|
|
#else
|
|
|
|
auto constexpr WouldBlock = ERROR_LOCK_VIOLATION;
|
|
|
|
#endif
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
} // namespace
|
2016-09-05 19:06:26 +00:00
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
tr_session_id::session_id_t tr_session_id::make_session_id()
|
2016-09-05 19:06:26 +00:00
|
|
|
{
|
2022-11-25 21:04:37 +00:00
|
|
|
auto session_id = tr_rand_obj<session_id_t>();
|
2022-08-06 19:27:37 +00:00
|
|
|
static auto constexpr Pool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"sv;
|
|
|
|
for (auto& chr : session_id)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
chr = Pool[static_cast<unsigned char>(chr) % std::size(Pool)];
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2022-08-06 19:27:37 +00:00
|
|
|
session_id.back() = '\0';
|
|
|
|
return session_id;
|
2016-09-05 19:06:26 +00:00
|
|
|
}
|
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
tr_session_id::~tr_session_id()
|
2016-09-05 19:06:26 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
destroy_lockfile(current_lock_file_, std::data(current_value_));
|
|
|
|
destroy_lockfile(previous_lock_file_, std::data(previous_value_));
|
|
|
|
}
|
2016-09-05 19:06:26 +00:00
|
|
|
|
2023-05-06 04:11:05 +00:00
|
|
|
bool tr_session_id::is_local(std::string_view session_id) noexcept
|
2022-08-06 19:27:37 +00:00
|
|
|
{
|
|
|
|
if (std::empty(session_id))
|
2016-09-05 19:06:26 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
auto is_local = bool{ false };
|
|
|
|
auto lockfile_path = tr_pathbuf{};
|
|
|
|
get_lockfile_path(session_id, lockfile_path);
|
|
|
|
tr_error* error = nullptr;
|
|
|
|
if (auto lockfile_fd = tr_sys_file_open(lockfile_path, TR_SYS_FILE_READ, 0, &error); lockfile_fd == TR_BAD_SYS_FILE)
|
|
|
|
{
|
|
|
|
if (TR_ERROR_IS_ENOENT(error->code))
|
|
|
|
{
|
|
|
|
tr_error_clear(&error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!tr_sys_file_lock(lockfile_fd, TR_SYS_FILE_LOCK_SH | TR_SYS_FILE_LOCK_NB, &error) && (error->code == WouldBlock))
|
|
|
|
{
|
|
|
|
is_local = true;
|
|
|
|
tr_error_clear(&error);
|
|
|
|
}
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
tr_sys_file_close(lockfile_fd);
|
|
|
|
}
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
if (error != nullptr)
|
|
|
|
{
|
|
|
|
tr_logAddWarn(fmt::format(
|
|
|
|
_("Couldn't open session lock file '{path}': {error} ({error_code})"),
|
|
|
|
fmt::arg("path", lockfile_path),
|
|
|
|
fmt::arg("error", error->message),
|
|
|
|
fmt::arg("error_code", error->code)));
|
|
|
|
tr_error_free(error);
|
2016-09-05 19:06:26 +00:00
|
|
|
}
|
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
return is_local;
|
2016-09-05 19:06:26 +00:00
|
|
|
}
|
2016-09-21 20:56:03 +00:00
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
std::string_view tr_session_id::sv() const noexcept
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
if (auto const now = get_current_time_(); now >= expires_at_)
|
2016-09-21 20:56:03 +00:00
|
|
|
{
|
2022-08-06 19:27:37 +00:00
|
|
|
destroy_lockfile(previous_lock_file_, std::data(previous_value_));
|
|
|
|
previous_value_ = current_value_;
|
|
|
|
previous_lock_file_ = current_lock_file_;
|
|
|
|
current_value_ = make_session_id();
|
|
|
|
current_lock_file_ = create_lockfile(std::data(current_value_));
|
|
|
|
expires_at_ = now + SessionIdDurationSec;
|
2016-09-21 20:56:03 +00:00
|
|
|
}
|
|
|
|
|
2022-08-06 19:27:37 +00:00
|
|
|
// -1 to strip the '\0'
|
|
|
|
return std::string_view{ std::data(current_value_), std::size(current_value_) - 1 };
|
|
|
|
}
|
|
|
|
|
|
|
|
char const* tr_session_id::c_str() const noexcept
|
|
|
|
{
|
|
|
|
return std::data(sv()); // current_value_ is zero-terminated
|
2016-09-21 20:56:03 +00:00
|
|
|
}
|