Prevent running multiple hpcore instances from the same directory (#207)

This commit is contained in:
Chalith Desaman
2021-01-05 11:18:23 +05:30
committed by GitHub
parent 99e4296746
commit e8a3882176
5 changed files with 106 additions and 3 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -79,6 +79,7 @@ void deinit()
sc::deinit();
unl::deinit();
ledger::deinit();
conf::deinit();
}
void sig_exit_handler(int signum)

View File

@@ -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

View File

@@ -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