mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
Prevent running multiple hpcore instances from the same directory (#207)
This commit is contained in:
63
src/conf.cpp
63
src/conf.cpp
@@ -24,6 +24,8 @@ namespace conf
|
||||
|
||||
const static char *PATCH_FILE_NAME = "patch.cfg"; // Config patch filename.
|
||||
|
||||
bool init_success = false;
|
||||
|
||||
/**
|
||||
* Loads and initializes the contract config for execution. Must be called once during application startup.
|
||||
* @return 0 for success. -1 for failure.
|
||||
@@ -35,23 +37,42 @@ namespace conf
|
||||
// 2. Read and load the contract config into memory
|
||||
// 3. Update contract config if patch file exists.
|
||||
// 4. Validate the loaded config values
|
||||
// 5. Locking the config file at the startup.
|
||||
|
||||
if (validate_contract_dir_paths() == -1 ||
|
||||
read_config(cfg) == -1 ||
|
||||
apply_patch_changes(cfg.contract) == -1 ||
|
||||
validate_config(cfg) == -1)
|
||||
validate_config(cfg) == -1 ||
|
||||
set_config_lock() == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_success = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup any resources.
|
||||
*/
|
||||
void deinit()
|
||||
{
|
||||
if (init_success)
|
||||
{
|
||||
// Releases the config file lock at the termination.
|
||||
release_config_lock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and saves new signing keys in the contract config.
|
||||
*/
|
||||
int rekey()
|
||||
{
|
||||
// Locking the config file at the startup. To check whether there's any already running hp instances.
|
||||
if (set_config_lock() == -1)
|
||||
return -1;
|
||||
|
||||
// Load the contract config and re-save with the newly generated keys.
|
||||
contract_config cfg = {};
|
||||
if (read_config(cfg) != 0)
|
||||
@@ -66,6 +87,9 @@ namespace conf
|
||||
|
||||
std::cout << "New signing keys generated at " << ctx.config_file << std::endl;
|
||||
|
||||
// Releases the config file lock at the termination.
|
||||
release_config_lock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -874,4 +898,41 @@ namespace conf
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the config file. If already locked means there's another hpcore instance running in the same directory.
|
||||
* If so, log error and return, Otherwise lock the config.
|
||||
* @return Returns 0 if lock is successfully aquired, -1 on error.
|
||||
*/
|
||||
int set_config_lock()
|
||||
{
|
||||
ctx.config_fd = open(ctx.config_file.data(), O_RDWR, 444);
|
||||
if (ctx.config_fd == -1)
|
||||
return -1;
|
||||
|
||||
if (util::set_lock(ctx.config_fd, ctx.config_lock, true, 0, 0) == -1)
|
||||
{
|
||||
if (errno == EACCES || errno == EAGAIN)
|
||||
{
|
||||
std::cerr << "Another hpcore instance is already running in directory " << ctx.contract_dir << "\n";
|
||||
}
|
||||
// Close fd if lock aquiring failed.
|
||||
close(ctx.config_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releses the config file and closes the opened file descriptor.
|
||||
* @return Returns 0 if lock is successfully aquired, -1 on error.
|
||||
*/
|
||||
int release_config_lock()
|
||||
{
|
||||
const int res = util::release_lock(ctx.config_fd, ctx.config_lock);
|
||||
// Close fd in termination.
|
||||
close(ctx.config_fd);
|
||||
return res;
|
||||
}
|
||||
} // namespace conf
|
||||
|
||||
13
src/conf.hpp
13
src/conf.hpp
@@ -65,9 +65,9 @@ namespace conf
|
||||
std::string public_key; // Contract public key bytes
|
||||
std::string private_key; // Contract private key bytes
|
||||
ROLE role = ROLE::OBSERVER; // Configured startup role of the contract (Observer/validator).
|
||||
bool is_unl = false; // Indicate whether we are a unl node or not.
|
||||
bool is_unl = false; // Indicate whether we are a unl node or not.
|
||||
|
||||
std::string public_key_hex; // Contract hex public key
|
||||
std::string public_key_hex; // Contract hex public key
|
||||
std::string private_key_hex; // Contract hex private key
|
||||
bool full_history = false; // Whether full history mode is on/off.
|
||||
};
|
||||
@@ -147,6 +147,9 @@ namespace conf
|
||||
std::string config_file; // Full path to the contract config file
|
||||
std::string tls_key_file; // Full path to the tls private key file
|
||||
std::string tls_cert_file; // Full path to the tls certificate
|
||||
|
||||
int config_fd; // Config file file descriptor
|
||||
struct flock config_lock; // Config file record log
|
||||
};
|
||||
|
||||
// Holds all the contract config values.
|
||||
@@ -171,6 +174,8 @@ namespace conf
|
||||
|
||||
int init();
|
||||
|
||||
void deinit();
|
||||
|
||||
int rekey();
|
||||
|
||||
int create_contract();
|
||||
@@ -198,6 +203,10 @@ namespace conf
|
||||
int apply_patch_changes(contract_params &contract_config);
|
||||
|
||||
int validate_and_apply_patch_config(contract_params &contract_config, std::string_view mount_dir);
|
||||
|
||||
int set_config_lock();
|
||||
|
||||
int release_config_lock();
|
||||
} // namespace conf
|
||||
|
||||
#endif
|
||||
|
||||
@@ -79,6 +79,7 @@ void deinit()
|
||||
sc::deinit();
|
||||
unl::deinit();
|
||||
ledger::deinit();
|
||||
conf::deinit();
|
||||
}
|
||||
|
||||
void sig_exit_handler(int signum)
|
||||
|
||||
@@ -355,4 +355,33 @@ namespace util
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a record lock for the file descriptor. Lock is associated with the process (Not for forked child processes).
|
||||
* @param fd File descriptor to be locked.
|
||||
* @param lock File lock.
|
||||
* @param is_rwlock Whether the record lock is a write lock.
|
||||
* @param start Starting offset for the lock.
|
||||
* @param len Number of bytes to lock.
|
||||
* @return Returns 0 if lock is successfully aquired, -1 on error.
|
||||
*/
|
||||
int set_lock(const int fd, struct flock &lock, const bool is_rwlock, const off_t start, const off_t len)
|
||||
{
|
||||
lock.l_type = is_rwlock ? F_WRLCK : F_RDLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = start,
|
||||
lock.l_len = len;
|
||||
return fcntl(fd, F_SETLK, &lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the lock on file descriptor.
|
||||
* @param fd File descriptor to be released.
|
||||
* @param lock File lock.
|
||||
* @return Returns 0 if lock is successfully released, -1 on error.
|
||||
*/
|
||||
int release_lock(const int fd, struct flock &lock)
|
||||
{
|
||||
lock.l_type = F_UNLCK;
|
||||
return fcntl(fd, F_SETLKW, &lock);
|
||||
}
|
||||
} // namespace util
|
||||
|
||||
@@ -78,6 +78,9 @@ namespace util
|
||||
|
||||
int stoull(const std::string &str, uint64_t &result);
|
||||
|
||||
int set_lock(const int fd, struct flock &lock, const bool is_rwlock, const off_t start, const off_t len);
|
||||
|
||||
int release_lock(const int fd, struct flock &lock);
|
||||
} // namespace util
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user