host/cxpslib/serveroptions.cpp (930 lines of code) (raw):
///
/// \file serveroptions.cpp
///
/// \brief implementation for server options
///
#include <fstream>
#include <stdexcept>
#include <cctype>
#include <boost/algorithm/string/trim.hpp>
#include <boost/thread.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/filesystem.hpp>
#include "serveroptions.h"
#include "errorexception.h"
#include "cxpslogger.h"
#include "strutils.h"
#include "createpaths.h"
#include "fiopipe.h"
#include "defaultdirs.h"
#include "genpassphrase.h"
#include "cxps.h"
#include "crypto.h"
// Copied from PortableHelpers.h
#ifdef SV_WINDOWS
#define FUNCTION_NAME __FUNCTION__
#else
#define FUNCTION_NAME __func__
#endif /* SV_WINDOWS */
#define THROW_ON_UNKNOWN_CS_MODE(csMode) do { \
if (csMode != CS_MODE_RCM && csMode != CS_MODE_LEGACY_CS) { \
std::stringstream ss; \
ss << "Unknown CS Mode : " << csMode << " - Method : " << FUNCTION_NAME << "()"; \
throw std::runtime_error(ss.str()); \
} \
} while (false)
int const DEFAULT_LOG_RETAIN_SIZE(1024*1024);
int const DEFAULT_LOG_SIZE(1024*1024*100);
inline void appendSlashIfNeeded(std::string& str)
{
if ('/' != str[str.size() - 1]
&& '\\' != str[str.size() - 1]
&& '*' != str[str.size() - 1]) { // paths that end in * say exlcude path and everything under it including subdirs
str.append("/");
}
}
static const
PSSettings::PSSettingsConfigurator::SubscriptionNum_t NOT_YET_SUBSCRIBED =
std::numeric_limits<PSSettings::PSSettingsConfigurator::SubscriptionNum_t>::max();
ServerOptions::ServerOptions(std::string const& fileName, std::string const& installDir)
: m_tunablesNotifSubscriptionNum(NOT_YET_SUBSCRIBED)
{
PSSettings::PSSettingsConfigurator& s_configurator = PSSettings::PSSettingsConfigurator::GetInstance();
try
{
if (GetCSMode() == CS_MODE_RCM) {
idempotentRestorePSState();
}
boost::filesystem::path conf;
if (fileName.empty()) {
throw ERROR_EXCEPTION << "configuration file was not specified";
}
if (installDir.empty()) {
m_defaultDir = fileName;
m_defaultDir.remove_filename();
} else {
m_defaultDir = installDir;
}
conf = fileName;
std::string lockFile(conf.string());
lockFile += ".lck";
if (!boost::filesystem::exists(lockFile)) {
std::ofstream tmpLockFile(lockFile.c_str());
}
boost::interprocess::file_lock fileLock(lockFile.c_str());
boost::interprocess::sharable_lock<boost::interprocess::file_lock> fileLockGuard(fileLock);
std::ifstream confFile(conf.string().c_str());
if (!confFile.good()) {
throw ERROR_EXCEPTION << "unable to open conf file " << conf.string() << ": " << errno;
}
std::string line; // assumes conf file lines are < 1024
while (confFile.good()) {
std::getline(confFile, line);
addOption(line);
}
if (id().empty() && (GetCSMode() == CS_MODE_RCM))
{
setIdFromPsConfig();
}
PSSettings::PSSettingsPtr cachedPSSettings = s_configurator.GetPSSettings();
if (cachedPSSettings)
{
m_tunablesPtr = cachedPSSettings->Tunables;
}
m_tunablesNotifSubscriptionNum =
s_configurator.SubscribeForTunablesChange(boost::bind(&ServerOptions::updateTunables, this, _1));
boost::filesystem::path requestDir = requestDefaultDir();
CreatePaths::createPathsAsNeeded(requestDir);
boost::filesystem::create_directory(requestDir);
buildAllowedDirs(requestDir);
buildExcludeDirs();
}
catch (...)
{
// Unsubscribe, if the subscription was successful
if (m_tunablesNotifSubscriptionNum != NOT_YET_SUBSCRIBED)
{
s_configurator.UnsubscribeForTunablesChange(m_tunablesNotifSubscriptionNum);
}
throw; //rethrow
}
}
ServerOptions::~ServerOptions()
{
PSSettings::PSSettingsConfigurator& s_configurator = PSSettings::PSSettingsConfigurator::GetInstance();
if (m_tunablesNotifSubscriptionNum != NOT_YET_SUBSCRIBED)
s_configurator.UnsubscribeForTunablesChange(m_tunablesNotifSubscriptionNum);
}
void ServerOptions::setIdFromPsConfig()
{
const boost::filesystem::path psConfFilePath(installDir() / ".." / "etc" / "ProcessServer.conf" );
const std::string psConfParamHostId("HostId");
try
{
boost::system::error_code ec;
if (boost::filesystem::exists(psConfFilePath.string(), ec))
{
boost::property_tree::ptree psconfparams;
std::ifstream localconffile(psConfFilePath.string().c_str());
boost::property_tree::json_parser::read_json(localconffile, psconfparams);
std::string psHostId = psconfparams.get<std::string>(psConfParamHostId);
if (!psHostId.empty())
{
boost::algorithm::trim(psHostId);
m_options["id"] = psHostId;
CXPS_LOG_ERROR_INFO("CS Mode RCM - HostId set from PS config file " << psConfFilePath << " as " << id());
}
else
{
CXPS_LOG_ERROR_INFO("CS Mode RCM - HostId key not found in PS config file " << psConfFilePath);
}
}
else
{
CXPS_LOG_ERROR_INFO("CS Mode RCM - failed to get HostId from PS config file " << psConfFilePath << " with error " << ec.message());
}
}
catch (const std::exception& e)
{
CXPS_LOG_ERROR_INFO("CS Mode RCM - failed to get HostId from PS config file " << psConfFilePath << " with exception " << e.what());
}
catch (...)
{
CXPS_LOG_ERROR_INFO("CS Mode RCM - failed to get HostId from PS config file " << psConfFilePath << " with unknown exception.");
}
return;
}
void ServerOptions::getAllowedDirsMapFromPSSettings(bool& isAccessControlEnabled, biosIdHostIdMap_t& biosIdHostIdMap, hostIdDirMap_t& hostIdLogRootDirMap, hostIdDirMap_t& hostIdTelemetryDirMap)
{
biosIdHostIdMap.clear();
hostIdLogRootDirMap.clear();
hostIdTelemetryDirMap.clear();
PSSettings::PSSettingsPtr psSettingsPtr = PSSettings::PSSettingsConfigurator::GetInstance().GetPSSettings();
if (psSettingsPtr != NULL)
{
isAccessControlEnabled = psSettingsPtr->IsAccessControlEnabled;
// Populate biosidhostidmap and hostIdLogRootDirMap from ps hostsettings.
boost::shared_ptr<PSSettings::PSSettingsHostwisePtrsMap> hostwisePtrsMap = psSettingsPtr->HostwiseSettings;
if (hostwisePtrsMap != NULL)
{
for (PSSettings::PSSettingsHostwisePtrsMap::iterator hostitr = hostwisePtrsMap->begin(); hostitr != hostwisePtrsMap->end(); hostitr++)
{
if (!hostitr->first.empty())
{
// hostitr->first holds the hostid and hostitr->second holds all host information
PSSettings::PSSettingsHostwisePtr hostwisePtr = hostitr->second;
if (hostwisePtr != NULL && !hostwisePtr->BiosId.empty())
{
// insert biosid in the map only if host info is available.
boost::algorithm::to_lower(hostwisePtr->BiosId);
biosIdHostIdMap.insert(std::make_pair(hostwisePtr->BiosId, hostitr->first));
hostIdLogRootDirMap.insert(std::make_pair(hostitr->first, hostwisePtr->LogRootFolder));
}
}
}
}
// Populate biosidhostidmap and hostIdTelemetryDirMap from ps telemetrysettings.
boost::shared_ptr<PSSettings::PSProtMacTelSettingsPtrsMap> telemetrySettingsPtr = psSettingsPtr->TelemetrySettings;
if (telemetrySettingsPtr != NULL)
{
for (PSSettings::PSProtMacTelSettingsPtrsMap::iterator itr = telemetrySettingsPtr->begin(); itr != telemetrySettingsPtr->end(); itr++)
{
PSSettings::PSProtMacTelSettingsPtr hostTelemetrySettingPtr = itr->second;
if (hostTelemetrySettingPtr != NULL)
{
boost::algorithm::to_lower(hostTelemetrySettingPtr->BiosId);
boost::algorithm::to_lower(hostTelemetrySettingPtr->HostId);
if (!biosIdHostIdMap.count(hostTelemetrySettingPtr->BiosId))
{
biosIdHostIdMap.insert(std::make_pair(hostTelemetrySettingPtr->BiosId, hostTelemetrySettingPtr->HostId));
}
hostIdTelemetryDirMap.insert(std::make_pair(hostTelemetrySettingPtr->HostId, hostTelemetrySettingPtr->TelemetryFolderPath));
}
}
}
}
}
ServerOptions::dirs_t const& ServerOptions::allowedDirs() const
{
return m_allowedDirs;
}
ServerOptions::dirs_t const& ServerOptions::excludeDirs() const
{
return m_excludeDirs;
}
bool ServerOptions::getFxAllowedDirs(ServerOptions::dirs_t& dirs)
{
boost::filesystem::directory_iterator iterEnd;
boost::filesystem::directory_iterator iter(fxAllowedDirsPath());
for (/* empty */; iter != iterEnd; ++iter) {
if (boost::filesystem::is_regular_file(iter->status())) {
std::ifstream iFile((*iter).path().string().c_str());
if (iFile.good()) {
std::string line;
std::getline(iFile, line);
std::replace(line.begin(), line.end(), '\\', '/');
typedef boost::tokenizer<boost::char_separator<char> > tokenizer_t;
boost::char_separator<char> sep(";");
tokenizer_t tokens(line, sep);
tokenizer_t::iterator iter(tokens.begin());
tokenizer_t::iterator iterEnd(tokens.end());
for (/* empty*/; iter != iterEnd; ++iter) {
std::string str(*iter);
appendSlashIfNeeded(str);
dirs.insert(str);
}
}
}
}
return true;
}
std::string ServerOptions::id() const
{
return getOption("id", false, std::string());
}
std::string ServerOptions::ipAddress() const
{
return getOption("ip", false, std::string());
}
std::string ServerOptions::port() const
{
return getOption("port", true, std::string());
}
std::string ServerOptions::sslPort() const
{
return getOption("ssl_port", true, std::string());
}
std::string ServerOptions::login() const
{
return getOption("login", true, std::string());
}
std::string ServerOptions::password() const
{
CSMode csMode = GetCSMode();
THROW_ON_UNKNOWN_CS_MODE(csMode);
std::string password;
if (csMode == CS_MODE_LEGACY_CS) {
password = getOption("ps_password", false, std::string());
if (password.empty()) {
password = securitylib::getPassphrase();
}
} else if (csMode == CS_MODE_RCM) {
password = getOption("encrypted_passphrase", false, std::string());
if (!password.empty()) {
password = securitylib::systemDecrypt(
securitylib::base64Decode(password.c_str(), (int)password.size()));
}
}
// TODO-SanKumar-1908: Cache the decrypted value to avoid repeated reads; May be applies to CS Mode as well.
return password;
}
bool ServerOptions::isRcmPSFirstTimeConfigured() const {
return getOption("rcm_ps_first_time_configured", false, false);
}
std::string ServerOptions::csIpAddress() const
{
return getOption("cs_ip_address", false, std::string());
}
std::string ServerOptions::csPort() const
{
return getOption("cs_port", false, std::string("80"));
}
std::string ServerOptions::csSslPort() const
{
return getOption("cs_ssl_port", false, std::string("443"));
}
std::string ServerOptions::csUrl() const
{
return getOption("cs_url", false, std::string("/ScoutAPI/CXAPI.php"));
}
std::string ServerOptions::cfsLocalName() const
{
// note this is actually only used on unix/linux (windows always uses loop back 127.0.0.1),
// so ok to default it to the unix/linux location.
return getOption("cfs_local_name", false, std::string("/usr/local/InMage/transport/cfs.ud"));
}
std::string ServerOptions::keyFilePassphrase() const
{
return getKeyFilePassphrase(getOption("key_file_passphrase", false, std::string("inmage")));
}
boost::filesystem::path ServerOptions::certificateFile() const
{
boost::filesystem::path path = getOption("ps_cert_file", false, boost::filesystem::path());
if (path.empty()) {
CSMode csMode = GetCSMode();
THROW_ON_UNKNOWN_CS_MODE(csMode);
if (csMode == CS_MODE_LEGACY_CS) {
path = securitylib::getCertDir();
} else if (csMode == CS_MODE_RCM) {
path = installDir();
path /= "private";
}
path /= "ps.crt";
}
return path;
}
boost::filesystem::path ServerOptions::keyFile() const
{
boost::filesystem::path path = getOption("ps_key_file", false, boost::filesystem::path());
if (path.empty()) {
CSMode csMode = GetCSMode();
THROW_ON_UNKNOWN_CS_MODE(csMode);
if (csMode == CS_MODE_LEGACY_CS) {
path = securitylib::getPrivateDir();
}
else if (csMode == CS_MODE_RCM) {
path = installDir();
path /= "private";
}
path /= "ps.key";
}
return path;
}
boost::filesystem::path ServerOptions::diffieHillmanFile() const
{
boost::filesystem::path path = getOption("ps_dh_file", false, boost::filesystem::path());
if (path.empty()) {
CSMode csMode = GetCSMode();
THROW_ON_UNKNOWN_CS_MODE(csMode);
if (csMode == CS_MODE_LEGACY_CS) {
path = securitylib::getPrivateDir();
}
else if (csMode == CS_MODE_RCM) {
path = installDir();
path /= "private";
}
path /= "ps.dh";
}
return path;
}
std::string ServerOptions::fingerprint() const
{
boost::filesystem::path path = getOption("ps_cert_fingerprint_file", false, std::string());
if (path.empty()) {
CSMode csMode = GetCSMode();
THROW_ON_UNKNOWN_CS_MODE(csMode);
if (csMode == CS_MODE_LEGACY_CS) {
path = securitylib::getFingerprintPathForPs();
}
else if (csMode == CS_MODE_RCM) {
path = installDir();
path /= "private";
path /= "ps.fingerprint";
}
}
std::ifstream fingerprintFile(path.string().c_str());
std::string fingerprint;
fingerprintFile >> fingerprint;
return fingerprint;
}
boost::filesystem::path ServerOptions::csCertFile() const
{
boost::filesystem::path path = getOption("cs_cert_file", false, boost::filesystem::path());
if (path.empty()) {
path = securitylib::getCertPath(csIpAddress(), csSslPort());
}
return path;
}
boost::filesystem::path ServerOptions::installDir() const
{
// NOTE: this is speical cased because the getOption for paths uses
// this to figure out the dir to prepend when a relative path is used
// so do not use getOption function here to avoid infinite loop if
// the install_dir has a relative path in the configuration file
// which is not actually allowed but could be done by accident
boost::filesystem::path defaultValue(m_defaultDir);
tagValue_t::const_iterator iter(m_options.find("install_dir"));
if (m_options.end() != iter) {
if (!(*iter).second.empty()) {
boost::filesystem::path pathName((*iter).second);
if (!pathName.has_root_path()) {
throw ERROR_EXCEPTION << "install_dir must be a full path name";
}
return (*iter).second;
}
}
return defaultValue;
}
boost::filesystem::path ServerOptions::requestDefaultDir() const
{
return getOption("request_default_dir", false, boost::filesystem::path(installDir() /= "data"));
}
boost::filesystem::path ServerOptions::fxAllowedDirsPath() const
{
return getOption("fx_allowed_dirs_path", false, boost::filesystem::path(DEFAULT_FX_ALLOWED_DIRS_PATH));
}
boost::filesystem::path ServerOptions::errorLogFile() const
{
return getOption("error_log", false, boost::filesystem::path(DEFAULT_LOG_DIR DEFAULT_NAME ".err.log"));
}
boost::filesystem::path ServerOptions::xferLogFile() const
{
return getOption("xfer_log", false, boost::filesystem::path(DEFAULT_LOG_DIR DEFAULT_NAME ".xfer.log"));
}
boost::filesystem::path ServerOptions::monitorLogFile() const
{
return getOption("monitor_log", false, boost::filesystem::path(DEFAULT_LOG_DIR DEFAULT_NAME ".monitor.log"));
}
boost::filesystem::path ServerOptions::cfsCacheFile() const
{
return getOption("cfs_cache_file", false, boost::filesystem::path(DEFAULT_LOG_DIR DEFAULT_NAME ".cfs.cache"));
}
ServerOptions::remapPrefixFromTo_t ServerOptions::remapFullPathPrefix() const
{
std::string fromTo = getOption("remap_full_path_prefix", false, std::string());
if (fromTo.empty()) {
return remapPrefixFromTo_t(std::make_pair(std::string(), std::string()));
}
// have a remap setting
std::string::size_type len(fromTo.size());
char stopChar;
// get <from prefix> start
// skip over leading white space
std::string::size_type fromStartIdx(0);
while (fromStartIdx < len && std::isspace(fromTo[fromStartIdx])) {
++fromStartIdx;
}
// check if <from prefix> enclosed in double quotes
if ('"' == fromTo[fromStartIdx]) {
++fromStartIdx;
// skip over any leading white space after a double quote
while (fromStartIdx < len && std::isspace(fromTo[fromStartIdx])) {
++fromStartIdx;
}
stopChar = '"';
} else {
stopChar = ' ';
}
// find <from prefix> end
std::string::size_type fromEndIdx(fromStartIdx);
while (fromEndIdx < len && (('"' == stopChar && '"' != fromTo[fromEndIdx]) || (' ' == stopChar && !std::isspace(fromTo[fromEndIdx])))) {
if ('\\' == fromTo[fromEndIdx]) {
fromTo[fromEndIdx] = '/'; // just to be safe convert backslash to slash
}
++fromEndIdx;
}
// this is where to start looking for the <to prefix>
std::string::size_type toStartIdx(fromEndIdx + 1);
// if the <from prefix> was enclosed in double quotes trim
// any trailing white space between <from prefix> and its
// closing double quote
if ('"' == stopChar && std::isspace(fromTo[fromEndIdx - 1])) {
do {
--fromEndIdx;
} while (std::isspace(fromTo[fromEndIdx]));
++fromEndIdx;
}
// skip all white space between <from prefix> and <to prefix>
while (toStartIdx < len && std::isspace(fromTo[toStartIdx])) {
++toStartIdx;
}
// check if <to prefix> enclosed in double quotes
if ('"' == fromTo[toStartIdx]) {
++toStartIdx;
// skip over any leading white space after a double quote
while (toStartIdx < len && std::isspace(fromTo[toStartIdx])) {
++toStartIdx;
}
stopChar = '"';
} else {
stopChar = ' ';
}
// find <to prefix> end
std::string::size_type toEndIdx(toStartIdx);
while (toEndIdx < len && (('"' == stopChar && '"' != fromTo[toEndIdx]) || (' ' == stopChar && !std::isspace(fromTo[toEndIdx])))) {
if ('\\' == fromTo[toEndIdx]) {
fromTo[toEndIdx] = '/'; // just to be safe convert backslash to slash
}
++toEndIdx;
}
// if the <to prefix> was enclosed in double quotes trim
// any trailing white space between <to prefix> and its
// closing double quote
if ('"' == stopChar && std::isspace(fromTo[toEndIdx - 1])) {
do {
--toEndIdx;
} while (std::isspace(fromTo[toEndIdx]));
++toEndIdx;
}
return remapPrefixFromTo_t(make_pair(std::string(fromTo.substr(fromStartIdx, fromEndIdx - fromStartIdx)),
std::string(fromTo.substr(toStartIdx, toEndIdx - toStartIdx))));
}
int ServerOptions::maxThreads() const
{
return (getOption("max_threads", false, 2) * boost::thread::hardware_concurrency());
}
int ServerOptions::maxBufferSizeBytes() const
{
return getOption("max_buffer_size_bytes", false, 1024*1024);
}
int ServerOptions::sendWindowSizeBytes() const
{
return getOption("send_window_size_bytes", false, 0);
}
int ServerOptions::receiveWindowSizeBytes() const
{
return getOption("receive_window_size_bytes", false, 0);
}
int ServerOptions::sessionTimeoutSeconds() const
{
return getOption("session_timeout_seconds", false, 60*5);
}
int ServerOptions::errorLogMaxSizeBytes() const
{
return getOption("error_log_max_size_bytes", false, DEFAULT_LOG_SIZE);
}
int ServerOptions::errorLogRotateCount() const
{
return getOption("error_log_rotate_count", false, 0);
}
int ServerOptions::errorLogRetainSizeBytes() const
{
return getOption("error_log_retain_size_bytes", false, DEFAULT_LOG_RETAIN_SIZE);
}
int ServerOptions::xferLogMaxSizeBytes() const
{
return getOption("xfer_log_max_size_bytes", false, DEFAULT_LOG_SIZE);
}
int ServerOptions::xferLogRotateCount() const
{
return getOption("xfer_log_rotate_count", false, 0);
}
int ServerOptions::xferLogRetainSizeBytes() const
{
return getOption("xfer_log_retain_size_bytes", false, DEFAULT_LOG_RETAIN_SIZE);
}
int ServerOptions::monitorLogMaxSizeBytes() const
{
return getOption("monitor_log_max_size_bytes", false, DEFAULT_LOG_SIZE);
}
int ServerOptions::monitorLogRotateCount() const
{
return getOption("monitor_log_rotate_count", false, 2);
}
int ServerOptions::monitorLogRetainSizeBytes() const
{
return getOption("monitor_log_retain_size_bytes", false, DEFAULT_LOG_RETAIN_SIZE);
}
int ServerOptions::initialReadSize() const
{
return getOption("init_read_size", false, 0);
}
int ServerOptions::monitorLogLevel() const
{
return getOption("monitor_log_level", false, MONITOR_LOG_LEVEL_2);
}
int ServerOptions::writeMode() const
{
return getOption("write_mode", false, (int)WRITE_MODE_NORMAL);
}
int ServerOptions::delaySessionDeleteSeconds() const
{
return getOption("delay_session_delete_seconds", false, 30);
}
int ServerOptions::cfsGetConnectInfoIntervalSeconds() const
{
return getOption("cfs_monitor_interval_seconds", false, 60);
}
int ServerOptions::cfsGetWorkerIntervalSeconds() const
{
return getOption("cfs_worker_interval_seconds", false, 60);
}
int ServerOptions::cfsMonitorIntervalSeconds() const
{
return getOption("cfs_get_connect_info_interval_seconds", false, 60);
}
int ServerOptions::cfsLocalPort() const
{
return getOption("cfs_port", false, 9082);
}
int ServerOptions::cfsLoginRetry() const
{
return getOption("cfs_login_retry", false, 3);
}
long ServerOptions::cnonceDurationSeconds() const
{
return getOption("cnonce_duration_seconds", false, 1800); // 15 minutes (more if cxps clock is behind client)
}
bool ServerOptions::errorLogWarningsEnabled() const
{
return getOption("error_log_warnings_enabled", false, false);
}
bool ServerOptions::xferLogEnabled() const
{
return getOption("xfer_log_enabled", false, false);
}
bool ServerOptions::monitorLogEnabled() const
{
return getOption("monitor_log_enabled", false, false);
}
bool ServerOptions::createPaths() const
{
return getOption("create_paths", false, false);
}
bool ServerOptions::copyOnRenameLinkFailure() const
{
return getOption("copy_on_rename_link_failure", false, false);
}
bool ServerOptions::checkForEmbeddedRequest() const
{
return getOption("check_for_embedded_request", false, false);
}
bool ServerOptions::cfsMode() const
{
return getOption("cfs_mode", false, false);
}
bool ServerOptions::cfsSecureLogin() const
{
return getOption("cfs_secure_login", false, true);
}
bool ServerOptions::cfsRejectNonSecureRequests() const
{
return getOption("cfs_reject_non_secure_requests", false, true);
}
bool ServerOptions::csUseSecure() const
{
return getOption("cs_use_secure", false, true);
}
bool ServerOptions::delayCfsFwdConnect() const
{
return getOption("delay_cfs_fwd_connect", false, false);
}
int ServerOptions::httpEnabled() const
{
return getOption("http_enabled", false, 0);
}
int ServerOptions::cumulativeThrottleTimeoutInSec() const
{
return getOption("cumulative_throttle_timeout_sec", false, 10);
}
float ServerOptions::cumulativeThrottleUsedSpaceThreshold() const
{
return getOption("cumulative_throttle_used_space_threshold_fraction", false, 0.8F);
}
unsigned long long ServerOptions::cumulativeThrottleThresholdInBytes() const
{
return getOption("cumulative_throttle_threshold_bytes", false, (unsigned long long)1024 * 1024 * 1024 * 50);
}
bool ServerOptions::enableSizeBasedCumulativeThrottle() const
{
return getOption("enable_size_based_cumulative_throttle", false, false);
}
bool ServerOptions::enableCumulativeThrottle() const
{
return getOption("enable_cumulative_throttle", false, true);
}
bool ServerOptions::enableDiffAndResyncThrottle() const
{
return getOption("enable_diff_resync_throttle", false, true);
}
int ServerOptions::diffResyncThrottleTimeoutInSec() const
{
return getOption("diff_resync_throttle_timeout_sec", false, 60);
}
unsigned long long ServerOptions::diffThrottleThresholdInBytes() const
{
return getOption("diff_throttle_threshold_bytes", false, (unsigned long long)1024 * 1024 * 1024 * 8);
}
unsigned long long ServerOptions::resyncThrottleThresholdInBytes() const
{
return getOption("resync_throttle_threshold_bytes", false, (unsigned long long)1024 * 1024 * 1024 * 8);
}
unsigned long long ServerOptions::defaultThrottleThresholdInBytes() const
{
return getOption("default_throttle_threshold_bytes", false, (unsigned long long)1024 * 1024 * 1024);
}
int ServerOptions::diffResyncThrottleCacheExpiryIntervalInSec() const
{
return getOption("diff_resync_throttle_cache_expiry_interval_sec", false, 60);
}
// cache for unprotected pairs is invalidated slowly as ideally we should not get any such request
int ServerOptions::nonProtectedPairPruneTimeoutInSec() const
{
return getOption("non_protected_pair_prune_timeout_sec", false, 300);
}
boost::tribool ServerOptions::inlineCompression() const
{
std::string inlineCompress = getOption("inline_compression", false, std::string("pair"));
if (inlineCompress == "none") {
return false;
}
if (inlineCompress == "all") {
return boost::indeterminate;
}
return true;
}
unsigned long ServerOptions::recycleHandleCount() const
{
return getOption("recycle_handle_count", false, (unsigned long)81920);
}
uint64_t ServerOptions::acceptRetryIntervalSecs() const
{
return getOption("accept_retry_interval_secs", false, 5ull);
}
uint64_t ServerOptions::psSettingsPollIntervalSecs() const
{
return getOption("ps_settings_poll_interval_secs", false, 60ull);
}
bool ServerOptions::psSettingsIncludesHeader() const
{
return getOption("ps_settings_includes_header", false, true);
}
bool ServerOptions::psSettingsEnforceMajorVersionCheck() const
{
return getOption("ps_settings_enforce_major_version_check", false, true);
}
bool ServerOptions::psSettingsEnforceMinorVersionCheck() const
{
return getOption("ps_settings_enforce_minor_version_check", false, false);
}
bool ServerOptions::psSettingsVerifyHeader() const
{
return getOption("ps_settings_verify_header", false, true);
}
std::string ServerOptions::getCaCertThumbprint() const
{
return getOption("cxps_ca_cert_thumbprint", false, std::string());
}
bool ServerOptions::useCertBasedClientAuth() const
{
return !getCaCertThumbprint().empty();
}
std::string ServerOptions::getAgentRepositoryPath() const
{
return m_agentRepositoryPath;
}
void ServerOptions::buildAllowedDirs(boost::filesystem::path const& requestDir)
{
ServerOptions::remapPrefixFromTo_t fromTo = remapFullPathPrefix();
std::string dirsOption = getOption("allowed_dirs", false, std::string());
std::replace(dirsOption.begin(), dirsOption.end(), '\\', '/');
typedef boost::tokenizer<boost::char_separator<char> > tokenizer_t;
boost::char_separator<char> sep(";");
tokenizer_t tokens(dirsOption, sep);
tokenizer_t::iterator iter(tokens.begin());
tokenizer_t::iterator iterEnd(tokens.end());
for (/* empty*/; iter != iterEnd; ++iter) {
if (IS_EQUAL(*iter, fromTo.first) || IS_EQUAL(*iter, fromTo.second)) {
std::string str(fromTo.first);
appendSlashIfNeeded(str);
m_allowedDirs.insert(str);
str = fromTo.second;
appendSlashIfNeeded(str);
m_allowedDirs.insert(str);
} else {
std::string str(*iter);
if (str.find("Software/Agents") != std::string::npos)
{
m_agentRepositoryPath = str;
CXPS_LOG_ERROR_INFO("m_agentRepositoryPath : " << m_agentRepositoryPath);
}
appendSlashIfNeeded(str);
m_allowedDirs.insert(str);
}
}
// play it safe and add default with out driver letter
m_allowedDirs.insert("/home/svsystems/");
if (boost::algorithm::istarts_with(fromTo.first, "/home/svsystems")) {
std::string str(fromTo.second);
appendSlashIfNeeded(str);
m_allowedDirs.insert(str);
}
if (!requestDir.empty()) {
std::string str(requestDir.string());
std::replace(str.begin(), str.end(), '\\', '/');
appendSlashIfNeeded(str);
m_allowedDirs.insert(str);
}
}
void ServerOptions::buildExcludeDirs()
{
ServerOptions::remapPrefixFromTo_t fromTo = remapFullPathPrefix();
dirs_t dirsAllowed = allowedDirs();
dirs_t::iterator allowedIter;
dirs_t::iterator allowedEnd(dirsAllowed.end());
std::string dirsOption = getOption("exclude_dirs", false, std::string());
std::replace(dirsOption.begin(), dirsOption.end(), '\\', '/');
typedef boost::tokenizer<boost::char_separator<char> > tokenizer_t;
boost::char_separator<char> sep(";");
tokenizer_t tokens(dirsOption, sep);
tokenizer_t::iterator iter(tokens.begin());
tokenizer_t::iterator iterEnd(tokens.end());
for (/* empty*/; iter != iterEnd; ++iter) {
boost::filesystem::path p(*iter);
if (!p.has_root_path()) {
allowedIter = dirsAllowed.begin();
for (/* empty */; allowedIter != allowedEnd; ++allowedIter) {
std::string dir(*allowedIter);
appendSlashIfNeeded(dir);
dir += *iter;
m_excludeDirs.insert(dir);
}
} else {
// full path need to check for remapping so that it can be added
if (STARTS_WITH(*iter, fromTo.first)) {
std::string str(*iter);
boost::algorithm::ireplace_first(str, fromTo.first, fromTo.second);
m_excludeDirs.insert(str);
} else if (STARTS_WITH(*iter, fromTo.second)) {
std::string str(*iter);
boost::algorithm::ireplace_first(str, fromTo.second, fromTo.first);
m_excludeDirs.insert(str);
}
std::string str(*iter);
m_excludeDirs.insert(str);
}
}
}
void ServerOptions::addOption(std::string line)
{
if ('#' != line[0] && '[' != line[0]) {
std::string data(line);
std::string::size_type idx = data.find_first_of("=");
if (std::string::npos != idx) {
std::string tag(data.substr(0, idx));
boost::algorithm::trim(tag);
std::string value(data.substr(idx + 1));
boost::algorithm::trim(value);
m_options.insert(std::make_pair(tag, value));
}
}
}
template <typename T>
T ServerOptions::getOption(char const* option, bool required, T defaultValue) const {
std::string value;
if (getOption(option, value)) {
try {
return boost::lexical_cast<T>(value);
} catch (...) {
// prevent exception from being thrown, default value will be returned
}
}
if (!required) {
return defaultValue;
}
throw ERROR_EXCEPTION << "required option " << option << " not specfied in configuration file";
}
bool ServerOptions::getOption(char const* option, bool required, bool defaultValue) const {
std::string value;
if (getOption(option, value)) {
try {
return (value == "yes");
} catch (...) {
// prevent exception from being thrown, default value will be returned
}
}
if (!required) {
return defaultValue;
}
throw ERROR_EXCEPTION << "required option " << option << " not specfied in configuration file";
}
std::string ServerOptions::getOption(char const* option, bool required, std::string const& defaultValue) const {
std::string value;
if (getOption(option, value)) {
return value;
}
if (!required) {
return defaultValue;
}
throw ERROR_EXCEPTION << "required option " << option << " not specfied in configuration file";
}
boost::filesystem::path ServerOptions::getOption(char const* option,
bool required,
boost::filesystem::path const& defaultValue) const {
std::string value;
boost::filesystem::path pathName;
if (getOption(option, value)) {
pathName = value;
if (!pathName.has_root_path()) {
pathName = installDir();
pathName /= value;
}
} else if (!required) {
if (!defaultValue.empty()) {
if (!defaultValue.has_root_path()) {
pathName = installDir();
}
pathName /= defaultValue;
}
} else {
throw ERROR_EXCEPTION << "required option " << option << " not specfied in configuration file";
}
return pathName;
}
bool ServerOptions::getOption(char const* option, std::string& value) const {
tagValue_t::const_iterator optionsIter(m_options.find(option));
if (m_options.end() != optionsIter && !optionsIter->second.empty()) {
value = optionsIter->second;
return true;
} else {
// Take a reference to the shared pointer, since it could be automically
// updated by another thread.
PSSettings::StringMapPtr tunMapPtr = m_tunablesPtr;
if (tunMapPtr) {
PSSettings::StringMap::const_iterator tunMapIter = tunMapPtr->find(option);
if (tunMapPtr->end() != tunMapIter && !tunMapIter->second.empty()) {
value = tunMapIter->second;
return true;
}
}
}
return false;
}
void ServerOptions::updateTunables(PSSettings::StringMapPtr latestTunables)
{
boost::atomic_exchange(&m_tunablesPtr, latestTunables);
}
std::string ServerOptions::getKeyFilePassphrase(std::string const& str) const
{
if (!boost::algorithm::starts_with(str, "exec:")) {
return str;
}
std::string::size_type idx = str.find_first_of(":");
if (std::string::npos == idx) {
return str;
}
std::string prog = boost::algorithm::trim_copy(str.substr(idx + 1));
std::string passphrase;
FIO::cmdArgs_t vargs;
vargs.push_back(prog.c_str());
vargs.push_back((char*)0);
FIO::FioPipe fioPipe(vargs);
char buffer[1024];
long bytes = 0;
bool wait = true;
do {
bytes = fioPipe.read(buffer, sizeof(buffer), wait);
if (bytes > 0) {
passphrase.append(buffer, bytes);
wait = false;
}
} while (bytes > 0);
if (!passphrase.empty()) {
boost::algorithm::trim(passphrase);
if ('"' == passphrase[0] && '"' == passphrase[passphrase.size() - 1]) {
return passphrase.substr(1, passphrase.size() - 2);
}
}
return passphrase;
}