20 #include <ripple/basics/FileUtilities.h>
21 #include <ripple/basics/Log.h>
22 #include <ripple/basics/StringUtilities.h>
23 #include <ripple/basics/contract.h>
24 #include <ripple/beast/core/LexicalCast.h>
25 #include <ripple/core/Config.h>
26 #include <ripple/core/ConfigSections.h>
27 #include <ripple/json/json_reader.h>
28 #include <ripple/net/HTTPClient.h>
29 #include <ripple/protocol/Feature.h>
30 #include <ripple/protocol/SystemParameters.h>
31 #include <boost/algorithm/string.hpp>
32 #include <boost/format.hpp>
33 #include <boost/predef.h>
34 #include <boost/regex.hpp>
35 #include <boost/system/error_code.hpp>
44 #include <sysinfoapi.h>
52 if (MEMORYSTATUSEX msx{
sizeof(MEMORYSTATUSEX)}; GlobalMemoryStatusEx(&msx))
63 #include <sys/sysinfo.h>
71 if (
struct sysinfo si; sysinfo(&si) == 0)
83 #include <sys/sysctl.h>
84 #include <sys/types.h>
92 int mib[] = {CTL_HW, HW_MEMSIZE};
94 size_t size =
sizeof(ram);
96 if (sysctl(mib, 2, &ram, &size, NULL, 0) == 0)
136 []() constexpr->bool {
137 std::underlying_type_t<SizedItem> idx = 0;
139 for (auto const& i : sizedItems)
141 if (static_cast<std::underlying_type_t<SizedItem>>(i.first) != idx)
149 "Mismatch between sized item enum & array indices");
156 #define SECTION_DEFAULT_NAME ""
166 boost::algorithm::replace_all(strData,
"\r\n",
"\n");
169 boost::algorithm::replace_all(strData,
"\r",
"\n");
171 boost::algorithm::split(vLines, strData, boost::algorithm::is_any_of(
"\n"));
177 secResult[strSection] = IniFileSections::mapped_type();
180 for (
auto& strValue : vLines)
183 boost::algorithm::trim(strValue);
185 if (strValue.empty() || strValue[0] ==
'#')
189 else if (strValue[0] ==
'[' && strValue[strValue.length() - 1] ==
']')
192 strSection = strValue.
substr(1, strValue.length() - 2);
193 secResult.
emplace(strSection, IniFileSections::mapped_type{});
198 if (!strValue.empty())
199 secResult[strSection].push_back(strValue);
206 IniFileSections::mapped_type*
209 if (
auto it = secSource.
find(strSection); it != secSource.
end())
210 return &(it->second);
224 if (pmtEntries && pmtEntries->size() == 1)
226 strValue = (*pmtEntries)[0];
232 JLOG(j.
warn()) <<
"Section '" << strSection <<
"': requires 1 line not "
233 << pmtEntries->
size() <<
" lines.";
245 char const*
const Config::configFileName =
"rippled.cfg";
246 char const*
const Config::databaseDirName =
"db";
247 char const*
const Config::validatorsFileName =
"validators.txt";
254 if (
auto const v =
std::getenv(name); v !=
nullptr)
261 : j_(
beast::Journal::getNullSink())
262 , ramSize_(detail::getMemorySize() / (1024 * 1024 * 1024))
271 QUIET = bQuiet || bSilent;
280 auto const& threshold =
284 threshold.second.begin(),
285 threshold.second.end(),
287 return (limit == 0) || (ramSize_ < limit);
290 assert(ns != threshold.second.end());
292 if (ns != threshold.second.end())
311 boost::filesystem::path dataDir;
324 if (!strConf.
empty())
325 strConfFile = strConf;
329 if (!strConf.
empty())
339 CONFIG_DIR = boost::filesystem::current_path();
346 auto strXdgConfigHome =
getEnvVar(
"XDG_CONFIG_HOME");
347 auto strXdgDataHome =
getEnvVar(
"XDG_DATA_HOME");
351 || (strHome.empty() &&
352 (strXdgConfigHome.empty() || strXdgDataHome.empty())))
358 if (strXdgConfigHome.empty())
361 strXdgConfigHome = strHome +
"/.config";
364 if (strXdgDataHome.empty())
367 strXdgDataHome = strHome +
"/.local/share";
372 dataDir = strXdgDataHome +
"/" +
systemName();
394 dataDir = boost::filesystem::path(dbPath);
399 if (!dataDir.empty())
401 boost::system::error_code ec;
402 boost::filesystem::create_directories(dataDir, ec);
405 Throw<std::runtime_error>(
406 boost::str(boost::format(
"Can not create %s") % dataDir));
408 legacy(
"database_path", boost::filesystem::absolute(dataDir).
string());
433 boost::system::error_code ec;
463 for (
auto& line : strVec)
466 if (
std::count(line.begin(), line.end(),
':') != 1)
472 if (result.
size() == line.size())
485 boost::filesystem::path p(dbPath);
486 legacy(
"database_path", boost::filesystem::absolute(p).
string());
494 if (strTemp ==
"main")
496 else if (strTemp ==
"testnet")
498 else if (strTemp ==
"devnet")
501 NETWORK_ID = beast::lexicalCastThrow<uint32_t>(strTemp);
509 PEERS_MAX = beast::lexicalCastThrow<std::size_t>(strTemp);
516 peers_in_max = beast::lexicalCastThrow<std::size_t>(strTemp);
517 if (*peers_in_max > 1000)
518 Throw<std::runtime_error>(
519 "Invalid value specified in [" SECTION_PEERS_IN_MAX
520 "] section; the value must be less or equal than 1000");
526 peers_out_max = beast::lexicalCastThrow<std::size_t>(strTemp);
527 if (*peers_out_max < 10 || *peers_out_max > 1000)
528 Throw<std::runtime_error>(
529 "Invalid value specified in [" SECTION_PEERS_OUT_MAX
530 "] section; the value must be in range 10-1000");
534 if ((peers_in_max && !peers_out_max) ||
535 (peers_out_max && !peers_in_max))
536 Throw<std::runtime_error>(
"Both sections [" SECTION_PEERS_IN_MAX
538 "and [" SECTION_PEERS_OUT_MAX
539 "] must be configured");
541 if (peers_in_max && peers_out_max)
550 if (boost::iequals(strTemp,
"tiny"))
552 else if (boost::iequals(strTemp,
"small"))
554 else if (boost::iequals(strTemp,
"medium"))
556 else if (boost::iequals(strTemp,
"large"))
558 else if (boost::iequals(strTemp,
"huge"))
562 4, beast::lexicalCastThrow<std::size_t>(strTemp));
569 ELB_SUPPORT = beast::lexicalCastThrow<bool>(strTemp);
575 SSL_VERIFY = beast::lexicalCastThrow<bool>(strTemp);
579 if (boost::iequals(strTemp,
"all"))
581 else if (boost::iequals(strTemp,
"trusted"))
583 else if (boost::iequals(strTemp,
"drop_untrusted"))
586 Throw<std::runtime_error>(
587 "Invalid value specified in [" SECTION_RELAY_VALIDATIONS
593 if (boost::iequals(strTemp,
"all"))
595 else if (boost::iequals(strTemp,
"trusted"))
597 else if (boost::iequals(strTemp,
"drop_untrusted"))
600 Throw<std::runtime_error>(
601 "Invalid value specified in [" SECTION_RELAY_PROPOSALS
605 if (
exists(SECTION_VALIDATION_SEED) &&
exists(SECTION_VALIDATOR_TOKEN))
606 Throw<std::runtime_error>(
"Cannot have both [" SECTION_VALIDATION_SEED
607 "] and [" SECTION_VALIDATOR_TOKEN
608 "] config sections");
622 if (boost::iequals(strTemp,
"full"))
625 else if (boost::iequals(strTemp,
"none"))
633 if (boost::iequals(strTemp,
"none"))
635 else if (boost::iequals(strTemp,
"full"))
638 FETCH_DEPTH = beast::lexicalCastThrow<std::uint32_t>(strTemp);
646 if (
exists(SECTION_VALIDATION_SEED) ||
exists(SECTION_VALIDATOR_TOKEN))
652 PATH_SEARCH = beast::lexicalCastThrow<int>(strTemp);
665 if (SWEEP_INTERVAL < 10 || SWEEP_INTERVAL > 600)
666 Throw<std::runtime_error>(
"Invalid " SECTION_SWEEP_INTERVAL
667 ": must be between 10 and 600 inclusive");
672 WORKERS = beast::lexicalCastThrow<int>(strTemp);
674 if (WORKERS < 1 || WORKERS > 1024)
675 Throw<std::runtime_error>(
676 "Invalid " SECTION_WORKERS
677 ": must be between 1 and 1024 inclusive.");
682 IO_WORKERS = beast::lexicalCastThrow<int>(strTemp);
684 if (IO_WORKERS < 1 || IO_WORKERS > 1024)
685 Throw<std::runtime_error>(
686 "Invalid " SECTION_IO_WORKERS
687 ": must be between 1 and 1024 inclusive.");
694 if (PREFETCH_WORKERS < 1 || PREFETCH_WORKERS > 1024)
695 Throw<std::runtime_error>(
696 "Invalid " SECTION_PREFETCH_WORKERS
697 ": must be between 1 and 1024 inclusive.");
701 COMPRESSION = beast::lexicalCastThrow<bool>(strTemp);
706 if (
exists(SECTION_REDUCE_RELAY))
708 auto sec =
section(SECTION_REDUCE_RELAY);
715 if (TX_RELAY_PERCENTAGE < 10 || TX_RELAY_PERCENTAGE > 100 ||
717 Throw<std::runtime_error>(
718 "Invalid " SECTION_REDUCE_RELAY
719 ", tx_min_peers must be greater or equal to 10"
720 ", tx_relay_percentage must be greater or equal to 10 "
721 "and less or equal to 100");
727 beast::lexicalCastThrow<int>(strTemp),
736 Throw<std::runtime_error>(
737 "Invalid " SECTION_SERVER_DOMAIN
738 ": the domain name does not appear to meet the requirements.");
744 if (
exists(SECTION_OVERLAY))
746 auto const sec =
section(SECTION_OVERLAY);
752 if (
auto val = sec.get(
"max_unknown_time"))
754 seconds{beast::lexicalCastThrow<std::uint32_t>(*val)};
758 Throw<std::runtime_error>(
759 "Invalid value 'max_unknown_time' in " SECTION_OVERLAY
760 ": must be of the form '<number>' representing seconds.");
764 Throw<std::runtime_error>(
765 "Invalid value 'max_unknown_time' in " SECTION_OVERLAY
766 ": the time must be between 300 and 1800 seconds, inclusive.");
770 if (
auto val = sec.get(
"max_diverged_time"))
772 seconds{beast::lexicalCastThrow<std::uint32_t>(*val)};
776 Throw<std::runtime_error>(
777 "Invalid value 'max_diverged_time' in " SECTION_OVERLAY
778 ": must be of the form '<number>' representing seconds.");
783 Throw<std::runtime_error>(
784 "Invalid value 'max_diverged_time' in " SECTION_OVERLAY
785 ": the time must be between 60 and 900 seconds, inclusive.");
790 secConfig, SECTION_AMENDMENT_MAJORITY_TIME, strTemp,
j_))
793 boost::regex
const re(
794 "^\\s*(\\d+)\\s*(minutes|hours|days|weeks)\\s*(\\s+.*)?$");
796 if (!boost::regex_match(strTemp, match, re))
797 Throw<std::runtime_error>(
798 "Invalid " SECTION_AMENDMENT_MAJORITY_TIME
799 ", must be: [0-9]+ [minutes|hours|days|weeks]");
802 beast::lexicalCastThrow<std::uint32_t>(match[1].str());
804 if (boost::iequals(match[2],
"minutes"))
806 else if (boost::iequals(match[2],
"hours"))
808 else if (boost::iequals(match[2],
"days"))
810 else if (boost::iequals(match[2],
"weeks"))
814 Throw<std::runtime_error>(
815 "Invalid " SECTION_AMENDMENT_MAJORITY_TIME
816 ", the minimum amount of time an amendment must hold a "
817 "majority is 15 minutes");
834 boost::filesystem::path validatorsFile;
838 validatorsFile = strTemp;
840 if (validatorsFile.empty())
841 Throw<std::runtime_error>(
842 "Invalid path specified in [" SECTION_VALIDATORS_FILE
"]");
844 if (!validatorsFile.is_absolute() && !
CONFIG_DIR.empty())
847 if (!boost::filesystem::exists(validatorsFile))
848 Throw<std::runtime_error>(
849 "The file specified in [" SECTION_VALIDATORS_FILE
852 validatorsFile.string());
855 !boost::filesystem::is_regular_file(validatorsFile) &&
856 !boost::filesystem::is_symlink(validatorsFile))
857 Throw<std::runtime_error>(
858 "Invalid file specified in [" SECTION_VALIDATORS_FILE
860 validatorsFile.string());
866 if (!validatorsFile.empty())
868 if (!boost::filesystem::exists(validatorsFile))
869 validatorsFile.clear();
871 !boost::filesystem::is_regular_file(validatorsFile) &&
872 !boost::filesystem::is_symlink(validatorsFile))
873 validatorsFile.clear();
877 if (!validatorsFile.empty() &&
878 boost::filesystem::exists(validatorsFile) &&
879 (boost::filesystem::is_regular_file(validatorsFile) ||
880 boost::filesystem::is_symlink(validatorsFile)))
882 boost::system::error_code ec;
886 Throw<std::runtime_error>(
887 "Failed to read '" + validatorsFile.string() +
"'." +
904 auto valSiteEntries =
908 section(SECTION_VALIDATOR_LIST_SITES).
append(*valSiteEntries);
916 if (!entries && !valKeyEntries && !valListKeys)
917 Throw<std::runtime_error>(
918 "The file specified in [" SECTION_VALIDATORS_FILE
920 "does not contain a [" SECTION_VALIDATORS
922 "[" SECTION_VALIDATOR_KEYS
924 "[" SECTION_VALIDATOR_LIST_KEYS
927 validatorsFile.string());
934 if (!
section(SECTION_VALIDATOR_LIST_SITES).lines().empty() &&
935 section(SECTION_VALIDATOR_LIST_KEYS).lines().empty())
937 Throw<std::runtime_error>(
939 "] config section is missing");
944 auto const part =
section(
"features");
945 for (
auto const& s : part.values())
950 Throw<std::runtime_error>(
951 "Unknown feature: " + s +
" in config file.");
967 Throw<std::runtime_error>(
968 "The minimum number of required peers (network_quorum) exceeds "
969 "the maximum number of allowed peers (peers_max)");
974 boost::filesystem::path
979 if (!log_file.empty() && !log_file.is_absolute())
983 log_file = boost::filesystem::absolute(log_file,
CONFIG_DIR);
986 if (!log_file.empty())
988 auto log_dir = log_file.parent_path();
990 if (!boost::filesystem::is_directory(log_dir))
992 boost::system::error_code ec;
993 boost::filesystem::create_directories(log_dir, ec);
999 std::cerr <<
"Unable to create log file path " << log_dir
1000 <<
": " << ec.message() <<
'\n';
1013 assert(!node || *node <= 4);
1025 setup.reference_fee = temp;
1030 setup.account_reserve = temp;
1032 setup.owner_reserve = temp;