rippled
Config.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/FileUtilities.h>
21 #include <ripple/basics/Log.h>
22 #include <ripple/basics/contract.h>
23 #include <ripple/beast/core/LexicalCast.h>
24 #include <ripple/core/Config.h>
25 #include <ripple/core/ConfigSections.h>
26 #include <ripple/json/json_reader.h>
27 #include <ripple/net/HTTPClient.h>
28 #include <ripple/protocol/Feature.h>
29 #include <ripple/protocol/SystemParameters.h>
30 #include <boost/algorithm/string.hpp>
31 #include <boost/beast/core/string.hpp>
32 #include <boost/format.hpp>
33 #include <boost/regex.hpp>
34 #include <boost/system/error_code.hpp>
35 #include <algorithm>
36 #include <fstream>
37 #include <iostream>
38 #include <iterator>
39 
40 namespace ripple {
41 
44  // FIXME: We should document each of these items, explaining exactly
45  // what
46  // they control and whether there exists an explicit config
47  // option that can be used to override the default.
48  {SizedItem::sweepInterval, {{10, 30, 60, 90, 120}}},
49  {SizedItem::treeCacheSize, {{128000, 256000, 512000, 768000, 2048000}}},
50  {SizedItem::treeCacheAge, {{30, 60, 90, 120, 900}}},
51  {SizedItem::ledgerSize, {{32, 128, 256, 384, 768}}},
52  {SizedItem::ledgerAge, {{30, 90, 180, 240, 900}}},
53  {SizedItem::ledgerFetch, {{2, 3, 4, 5, 8}}},
54  {SizedItem::nodeCacheSize, {{16384, 32768, 131072, 262144, 524288}}},
55  {SizedItem::nodeCacheAge, {{60, 90, 120, 900, 1800}}},
56  {SizedItem::hashNodeDBCache, {{4, 12, 24, 64, 128}}},
57  {SizedItem::txnDBCache, {{4, 12, 24, 64, 128}}},
58  {SizedItem::lgrDBCache, {{4, 8, 16, 32, 128}}},
59  }};
60 
61 // Ensure that the order of entries in the table corresponds to the
62 // order of entries in the enum:
63 static_assert(
64  []() constexpr->bool {
65  std::underlying_type_t<SizedItem> idx = 0;
66 
67  for (auto const& i : sizedItems)
68  {
69  if (static_cast<std::underlying_type_t<SizedItem>>(i.first) != idx)
70  return false;
71 
72  ++idx;
73  }
74 
75  return true;
76  }(),
77  "Mismatch between sized item enum & array indices");
78 
79 //
80 // TODO: Check permissions on config file before using it.
81 //
82 
83 #define SECTION_DEFAULT_NAME ""
84 
86 parseIniFile(std::string const& strInput, const bool bTrim)
87 {
88  std::string strData(strInput);
90  IniFileSections secResult;
91 
92  // Convert DOS format to unix.
93  boost::algorithm::replace_all(strData, "\r\n", "\n");
94 
95  // Convert MacOS format to unix.
96  boost::algorithm::replace_all(strData, "\r", "\n");
97 
98  boost::algorithm::split(vLines, strData, boost::algorithm::is_any_of("\n"));
99 
100  // Set the default Section name.
101  std::string strSection = SECTION_DEFAULT_NAME;
102 
103  // Initialize the default Section.
104  secResult[strSection] = IniFileSections::mapped_type();
105 
106  // Parse each line.
107  for (auto& strValue : vLines)
108  {
109  if (bTrim)
110  boost::algorithm::trim(strValue);
111 
112  if (strValue.empty() || strValue[0] == '#')
113  {
114  // Blank line or comment, do nothing.
115  }
116  else if (strValue[0] == '[' && strValue[strValue.length() - 1] == ']')
117  {
118  // New Section.
119  strSection = strValue.substr(1, strValue.length() - 2);
120  secResult.emplace(strSection, IniFileSections::mapped_type{});
121  }
122  else
123  {
124  // Another line for Section.
125  if (!strValue.empty())
126  secResult[strSection].push_back(strValue);
127  }
128  }
129 
130  return secResult;
131 }
132 
133 IniFileSections::mapped_type*
134 getIniFileSection(IniFileSections& secSource, std::string const& strSection)
135 {
136  IniFileSections::iterator it;
137  IniFileSections::mapped_type* smtResult;
138  it = secSource.find(strSection);
139  if (it == secSource.end())
140  smtResult = nullptr;
141  else
142  smtResult = &(it->second);
143  return smtResult;
144 }
145 
146 bool
148  IniFileSections& secSource,
149  std::string const& strSection,
150  std::string& strValue,
151  beast::Journal j)
152 {
153  IniFileSections::mapped_type* pmtEntries =
154  getIniFileSection(secSource, strSection);
155  bool bSingle = pmtEntries && 1 == pmtEntries->size();
156 
157  if (bSingle)
158  {
159  strValue = (*pmtEntries)[0];
160  }
161  else if (pmtEntries)
162  {
163  JLOG(j.warn()) << boost::str(
164  boost::format("Section [%s]: requires 1 line not %d lines.") %
165  strSection % pmtEntries->size());
166  }
167 
168  return bSingle;
169 }
170 
171 //------------------------------------------------------------------------------
172 //
173 // Config (DEPRECATED)
174 //
175 //------------------------------------------------------------------------------
176 
177 char const* const Config::configFileName = "rippled.cfg";
178 char const* const Config::databaseDirName = "db";
179 char const* const Config::validatorsFileName = "validators.txt";
180 
181 static std::string
182 getEnvVar(char const* name)
183 {
184  std::string value;
185 
186  auto const v = getenv(name);
187 
188  if (v != nullptr)
189  value = v;
190 
191  return value;
192 }
193 
194 constexpr FeeUnit32 Config::TRANSACTION_FEE_BASE;
195 
196 void
197 Config::setupControl(bool bQuiet, bool bSilent, bool bStandalone)
198 {
199  QUIET = bQuiet || bSilent;
200  SILENT = bSilent;
201  RUN_STANDALONE = bStandalone;
202 }
203 
204 void
205 Config::setup(
206  std::string const& strConf,
207  bool bQuiet,
208  bool bSilent,
209  bool bStandalone)
210 {
211  boost::filesystem::path dataDir;
212  std::string strDbPath, strConfFile;
213 
214  // Determine the config and data directories.
215  // If the config file is found in the current working
216  // directory, use the current working directory as the
217  // config directory and that with "db" as the data
218  // directory.
219 
220  setupControl(bQuiet, bSilent, bStandalone);
221 
222  strDbPath = databaseDirName;
223 
224  if (!strConf.empty())
225  strConfFile = strConf;
226  else
227  strConfFile = configFileName;
228 
229  if (!strConf.empty())
230  {
231  // --conf=<path> : everything is relative that file.
232  CONFIG_FILE = strConfFile;
233  CONFIG_DIR = boost::filesystem::absolute(CONFIG_FILE);
234  CONFIG_DIR.remove_filename();
235  dataDir = CONFIG_DIR / strDbPath;
236  }
237  else
238  {
239  CONFIG_DIR = boost::filesystem::current_path();
240  CONFIG_FILE = CONFIG_DIR / strConfFile;
241  dataDir = CONFIG_DIR / strDbPath;
242 
243  // Construct XDG config and data home.
244  // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
245  std::string strHome = getEnvVar("HOME");
246  std::string strXdgConfigHome = getEnvVar("XDG_CONFIG_HOME");
247  std::string strXdgDataHome = getEnvVar("XDG_DATA_HOME");
248 
249  if (boost::filesystem::exists(CONFIG_FILE)
250  // Can we figure out XDG dirs?
251  || (strHome.empty() &&
252  (strXdgConfigHome.empty() || strXdgDataHome.empty())))
253  {
254  // Current working directory is fine, put dbs in a subdir.
255  }
256  else
257  {
258  if (strXdgConfigHome.empty())
259  {
260  // $XDG_CONFIG_HOME was not set, use default based on $HOME.
261  strXdgConfigHome = strHome + "/.config";
262  }
263 
264  if (strXdgDataHome.empty())
265  {
266  // $XDG_DATA_HOME was not set, use default based on $HOME.
267  strXdgDataHome = strHome + "/.local/share";
268  }
269 
270  CONFIG_DIR = strXdgConfigHome + "/" + systemName();
271  CONFIG_FILE = CONFIG_DIR / strConfFile;
272  dataDir = strXdgDataHome + "/" + systemName();
273 
274  if (!boost::filesystem::exists(CONFIG_FILE))
275  {
276  CONFIG_DIR = "/etc/opt/" + systemName();
277  CONFIG_FILE = CONFIG_DIR / strConfFile;
278  dataDir = "/var/opt/" + systemName();
279  }
280  }
281  }
282 
283  // Update default values
284  load();
285  {
286  // load() may have set a new value for the dataDir
287  std::string const dbPath(legacy("database_path"));
288  if (!dbPath.empty())
289  dataDir = boost::filesystem::path(dbPath);
290  else if (RUN_STANDALONE)
291  dataDir.clear();
292  }
293 
294  if (!dataDir.empty())
295  {
296  boost::system::error_code ec;
297  boost::filesystem::create_directories(dataDir, ec);
298 
299  if (ec)
300  Throw<std::runtime_error>(
301  boost::str(boost::format("Can not create %s") % dataDir));
302 
303  legacy("database_path", boost::filesystem::absolute(dataDir).string());
304  }
305 
306  HTTPClient::initializeSSLContext(*this, j_);
307 
308  if (RUN_STANDALONE)
309  LEDGER_HISTORY = 0;
310 }
311 
312 void
313 Config::load()
314 {
315  // NOTE: this writes to cerr because we want cout to be reserved
316  // for the writing of the json response (so that stdout can be part of a
317  // pipeline, for instance)
318  if (!QUIET)
319  std::cerr << "Loading: " << CONFIG_FILE << "\n";
320 
321  boost::system::error_code ec;
322  auto const fileContents = getFileContents(ec, CONFIG_FILE);
323 
324  if (ec)
325  {
326  std::cerr << "Failed to read '" << CONFIG_FILE << "'." << ec.value()
327  << ": " << ec.message() << std::endl;
328  return;
329  }
330 
331  loadFromString(fileContents);
332 }
333 
334 void
335 Config::loadFromString(std::string const& fileContents)
336 {
337  IniFileSections secConfig = parseIniFile(fileContents, true);
338 
339  build(secConfig);
340 
341  if (auto s = getIniFileSection(secConfig, SECTION_IPS))
342  IPS = *s;
343 
344  if (auto s = getIniFileSection(secConfig, SECTION_IPS_FIXED))
345  IPS_FIXED = *s;
346 
347  if (auto s = getIniFileSection(secConfig, SECTION_SNTP))
348  SNTP_SERVERS = *s;
349 
350  {
351  std::string dbPath;
352  if (getSingleSection(secConfig, "database_path", dbPath, j_))
353  {
354  boost::filesystem::path p(dbPath);
355  legacy("database_path", boost::filesystem::absolute(p).string());
356  }
357  }
358 
359  std::string strTemp;
360 
361  if (getSingleSection(secConfig, SECTION_PEER_PRIVATE, strTemp, j_))
362  PEER_PRIVATE = beast::lexicalCastThrow<bool>(strTemp);
363 
364  if (getSingleSection(secConfig, SECTION_PEERS_MAX, strTemp, j_))
365  PEERS_MAX = beast::lexicalCastThrow<std::size_t>(strTemp);
366 
367  if (getSingleSection(secConfig, SECTION_NODE_SIZE, strTemp, j_))
368  {
369  if (boost::iequals(strTemp, "tiny"))
370  NODE_SIZE = 0;
371  else if (boost::iequals(strTemp, "small"))
372  NODE_SIZE = 1;
373  else if (boost::iequals(strTemp, "medium"))
374  NODE_SIZE = 2;
375  else if (boost::iequals(strTemp, "large"))
376  NODE_SIZE = 3;
377  else if (boost::iequals(strTemp, "huge"))
378  NODE_SIZE = 4;
379  else
380  NODE_SIZE = std::min<std::size_t>(
381  4, beast::lexicalCastThrow<std::size_t>(strTemp));
382  }
383 
384  if (getSingleSection(secConfig, SECTION_SIGNING_SUPPORT, strTemp, j_))
385  signingEnabled_ = beast::lexicalCastThrow<bool>(strTemp);
386 
387  if (getSingleSection(secConfig, SECTION_ELB_SUPPORT, strTemp, j_))
388  ELB_SUPPORT = beast::lexicalCastThrow<bool>(strTemp);
389 
390  if (getSingleSection(secConfig, SECTION_WEBSOCKET_PING_FREQ, strTemp, j_))
391  WEBSOCKET_PING_FREQ =
392  std::chrono::seconds{beast::lexicalCastThrow<int>(strTemp)};
393 
394  getSingleSection(secConfig, SECTION_SSL_VERIFY_FILE, SSL_VERIFY_FILE, j_);
395  getSingleSection(secConfig, SECTION_SSL_VERIFY_DIR, SSL_VERIFY_DIR, j_);
396 
397  if (getSingleSection(secConfig, SECTION_SSL_VERIFY, strTemp, j_))
398  SSL_VERIFY = beast::lexicalCastThrow<bool>(strTemp);
399 
400  if (getSingleSection(secConfig, SECTION_RELAY_VALIDATIONS, strTemp, j_))
401  {
402  if (boost::iequals(strTemp, "all"))
403  RELAY_UNTRUSTED_VALIDATIONS = true;
404  else if (boost::iequals(strTemp, "trusted"))
405  RELAY_UNTRUSTED_VALIDATIONS = false;
406  else
407  Throw<std::runtime_error>(
408  "Invalid value specified in [" SECTION_RELAY_VALIDATIONS
409  "] section");
410  }
411 
412  if (getSingleSection(secConfig, SECTION_RELAY_PROPOSALS, strTemp, j_))
413  {
414  if (boost::iequals(strTemp, "all"))
415  RELAY_UNTRUSTED_PROPOSALS = true;
416  else if (boost::iequals(strTemp, "trusted"))
417  RELAY_UNTRUSTED_PROPOSALS = false;
418  else
419  Throw<std::runtime_error>(
420  "Invalid value specified in [" SECTION_RELAY_PROPOSALS
421  "] section");
422  }
423 
424  if (exists(SECTION_VALIDATION_SEED) && exists(SECTION_VALIDATOR_TOKEN))
425  Throw<std::runtime_error>("Cannot have both [" SECTION_VALIDATION_SEED
426  "] "
427  "and [" SECTION_VALIDATOR_TOKEN
428  "] config sections");
429 
430  if (getSingleSection(secConfig, SECTION_NETWORK_QUORUM, strTemp, j_))
431  NETWORK_QUORUM = beast::lexicalCastThrow<std::size_t>(strTemp);
432 
433  if (getSingleSection(secConfig, SECTION_FEE_ACCOUNT_RESERVE, strTemp, j_))
434  FEE_ACCOUNT_RESERVE = beast::lexicalCastThrow<std::uint64_t>(strTemp);
435 
436  if (getSingleSection(secConfig, SECTION_FEE_OWNER_RESERVE, strTemp, j_))
437  FEE_OWNER_RESERVE = beast::lexicalCastThrow<std::uint64_t>(strTemp);
438 
439  if (getSingleSection(secConfig, SECTION_FEE_DEFAULT, strTemp, j_))
440  FEE_DEFAULT = beast::lexicalCastThrow<std::uint64_t>(strTemp);
441 
442  if (getSingleSection(secConfig, SECTION_LEDGER_HISTORY, strTemp, j_))
443  {
444  if (boost::iequals(strTemp, "full"))
445  LEDGER_HISTORY = 1000000000u;
446  else if (boost::iequals(strTemp, "none"))
447  LEDGER_HISTORY = 0;
448  else
449  LEDGER_HISTORY = beast::lexicalCastThrow<std::uint32_t>(strTemp);
450  }
451 
452  if (getSingleSection(secConfig, SECTION_FETCH_DEPTH, strTemp, j_))
453  {
454  if (boost::iequals(strTemp, "none"))
455  FETCH_DEPTH = 0;
456  else if (boost::iequals(strTemp, "full"))
457  FETCH_DEPTH = 1000000000u;
458  else
459  FETCH_DEPTH = beast::lexicalCastThrow<std::uint32_t>(strTemp);
460 
461  if (FETCH_DEPTH < 10)
462  FETCH_DEPTH = 10;
463  }
464 
465  if (getSingleSection(secConfig, SECTION_PATH_SEARCH_OLD, strTemp, j_))
466  PATH_SEARCH_OLD = beast::lexicalCastThrow<int>(strTemp);
467  if (getSingleSection(secConfig, SECTION_PATH_SEARCH, strTemp, j_))
468  PATH_SEARCH = beast::lexicalCastThrow<int>(strTemp);
469  if (getSingleSection(secConfig, SECTION_PATH_SEARCH_FAST, strTemp, j_))
470  PATH_SEARCH_FAST = beast::lexicalCastThrow<int>(strTemp);
471  if (getSingleSection(secConfig, SECTION_PATH_SEARCH_MAX, strTemp, j_))
472  PATH_SEARCH_MAX = beast::lexicalCastThrow<int>(strTemp);
473 
474  if (getSingleSection(secConfig, SECTION_DEBUG_LOGFILE, strTemp, j_))
475  DEBUG_LOGFILE = strTemp;
476 
477  if (getSingleSection(secConfig, SECTION_WORKERS, strTemp, j_))
478  WORKERS = beast::lexicalCastThrow<std::size_t>(strTemp);
479 
480  if (getSingleSection(secConfig, SECTION_COMPRESSION, strTemp, j_))
481  COMPRESSION = beast::lexicalCastThrow<bool>(strTemp);
482 
483  // Do not load trusted validator configuration for standalone mode
484  if (!RUN_STANDALONE)
485  {
486  // If a file was explicitly specified, then throw if the
487  // path is malformed or if the file does not exist or is
488  // not a file.
489  // If the specified file is not an absolute path, then look
490  // for it in the same directory as the config file.
491  // If no path was specified, then look for validators.txt
492  // in the same directory as the config file, but don't complain
493  // if we can't find it.
494  boost::filesystem::path validatorsFile;
495 
496  if (getSingleSection(secConfig, SECTION_VALIDATORS_FILE, strTemp, j_))
497  {
498  validatorsFile = strTemp;
499 
500  if (validatorsFile.empty())
501  Throw<std::runtime_error>(
502  "Invalid path specified in [" SECTION_VALIDATORS_FILE "]");
503 
504  if (!validatorsFile.is_absolute() && !CONFIG_DIR.empty())
505  validatorsFile = CONFIG_DIR / validatorsFile;
506 
507  if (!boost::filesystem::exists(validatorsFile))
508  Throw<std::runtime_error>(
509  "The file specified in [" SECTION_VALIDATORS_FILE
510  "] "
511  "does not exist: " +
512  validatorsFile.string());
513 
514  else if (
515  !boost::filesystem::is_regular_file(validatorsFile) &&
516  !boost::filesystem::is_symlink(validatorsFile))
517  Throw<std::runtime_error>(
518  "Invalid file specified in [" SECTION_VALIDATORS_FILE
519  "]: " +
520  validatorsFile.string());
521  }
522  else if (!CONFIG_DIR.empty())
523  {
524  validatorsFile = CONFIG_DIR / validatorsFileName;
525 
526  if (!validatorsFile.empty())
527  {
528  if (!boost::filesystem::exists(validatorsFile))
529  validatorsFile.clear();
530  else if (
531  !boost::filesystem::is_regular_file(validatorsFile) &&
532  !boost::filesystem::is_symlink(validatorsFile))
533  validatorsFile.clear();
534  }
535  }
536 
537  if (!validatorsFile.empty() &&
538  boost::filesystem::exists(validatorsFile) &&
539  (boost::filesystem::is_regular_file(validatorsFile) ||
540  boost::filesystem::is_symlink(validatorsFile)))
541  {
542  boost::system::error_code ec;
543  auto const data = getFileContents(ec, validatorsFile);
544  if (ec)
545  {
546  Throw<std::runtime_error>(
547  "Failed to read '" + validatorsFile.string() + "'." +
548  std::to_string(ec.value()) + ": " + ec.message());
549  }
550 
551  auto iniFile = parseIniFile(data, true);
552 
553  auto entries = getIniFileSection(iniFile, SECTION_VALIDATORS);
554 
555  if (entries)
556  section(SECTION_VALIDATORS).append(*entries);
557 
558  auto valKeyEntries =
559  getIniFileSection(iniFile, SECTION_VALIDATOR_KEYS);
560 
561  if (valKeyEntries)
562  section(SECTION_VALIDATOR_KEYS).append(*valKeyEntries);
563 
564  auto valSiteEntries =
565  getIniFileSection(iniFile, SECTION_VALIDATOR_LIST_SITES);
566 
567  if (valSiteEntries)
568  section(SECTION_VALIDATOR_LIST_SITES).append(*valSiteEntries);
569 
570  auto valListKeys =
571  getIniFileSection(iniFile, SECTION_VALIDATOR_LIST_KEYS);
572 
573  if (valListKeys)
574  section(SECTION_VALIDATOR_LIST_KEYS).append(*valListKeys);
575 
576  if (!entries && !valKeyEntries && !valListKeys)
577  Throw<std::runtime_error>(
578  "The file specified in [" SECTION_VALIDATORS_FILE
579  "] "
580  "does not contain a [" SECTION_VALIDATORS
581  "], "
582  "[" SECTION_VALIDATOR_KEYS
583  "] or "
584  "[" SECTION_VALIDATOR_LIST_KEYS
585  "]"
586  " section: " +
587  validatorsFile.string());
588  }
589 
590  // Consolidate [validator_keys] and [validators]
591  section(SECTION_VALIDATORS)
592  .append(section(SECTION_VALIDATOR_KEYS).lines());
593 
594  if (!section(SECTION_VALIDATOR_LIST_SITES).lines().empty() &&
595  section(SECTION_VALIDATOR_LIST_KEYS).lines().empty())
596  {
597  Throw<std::runtime_error>(
598  "[" + std::string(SECTION_VALIDATOR_LIST_KEYS) +
599  "] config section is missing");
600  }
601  }
602 
603  {
604  auto const part = section("features");
605  for (auto const& s : part.values())
606  {
607  if (auto const f = getRegisteredFeature(s))
608  features.insert(*f);
609  else
610  Throw<std::runtime_error>(
611  "Unknown feature: " + s + " in config file.");
612  }
613  }
614 
615  // This doesn't properly belong here, but check to make sure that the
616  // value specified for network_quorum is achievable:
617  {
618  auto pm = PEERS_MAX;
619 
620  // FIXME this apparently magic value is actually defined as a constant
621  // elsewhere (see defaultMaxPeers) but we handle this check here.
622  if (pm == 0)
623  pm = 21;
624 
625  if (NETWORK_QUORUM > pm)
626  {
627  Throw<std::runtime_error>(
628  "The minimum number of required peers (network_quorum) exceeds "
629  "the maximum number of allowed peers (peers_max)");
630  }
631  }
632 }
633 
634 boost::filesystem::path
635 Config::getDebugLogFile() const
636 {
637  auto log_file = DEBUG_LOGFILE;
638 
639  if (!log_file.empty() && !log_file.is_absolute())
640  {
641  // Unless an absolute path for the log file is specified, the
642  // path is relative to the config file directory.
643  log_file = boost::filesystem::absolute(log_file, CONFIG_DIR);
644  }
645 
646  if (!log_file.empty())
647  {
648  auto log_dir = log_file.parent_path();
649 
650  if (!boost::filesystem::is_directory(log_dir))
651  {
652  boost::system::error_code ec;
653  boost::filesystem::create_directories(log_dir, ec);
654 
655  // If we fail, we warn but continue so that the calling code can
656  // decide how to handle this situation.
657  if (ec)
658  {
659  std::cerr << "Unable to create log file path " << log_dir
660  << ": " << ec.message() << '\n';
661  }
662  }
663  }
664 
665  return log_file;
666 }
667 
668 int
669 Config::getValueFor(SizedItem item, boost::optional<std::size_t> node) const
670 {
671  auto const index = static_cast<std::underlying_type_t<SizedItem>>(item);
672  assert(index < sizedItems.size());
673  assert(!node || *node <= 4);
674  return sizedItems.at(index).second.at(node.value_or(NODE_SIZE));
675 }
676 
677 } // namespace ripple
ripple::sizedItems
constexpr std::array< std::pair< SizedItem, std::array< int, 5 > >, 11 > sizedItems
Definition: Config.cpp:43
fstream
std::string
STL class.
ripple::SizedItem
SizedItem
Definition: Config.h:47
ripple::SizedItem::nodeCacheSize
@ nodeCacheSize
std::vector< std::string >
std::map::find
T find(T... args)
std::string::size
T size(T... args)
std::chrono::seconds
iterator
std::map::emplace
T emplace(T... args)
ripple::SizedItem::treeCacheAge
@ treeCacheAge
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
std::cerr
ripple::SizedItem::nodeCacheAge
@ nodeCacheAge
ripple::SizedItem::hashNodeDBCache
@ hashNodeDBCache
iostream
ripple::SizedItem::ledgerFetch
@ ledgerFetch
algorithm
std::underlying_type_t
std::to_string
T to_string(T... args)
std::array
STL class.
ripple::SizedItem::lgrDBCache
@ lgrDBCache
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::map
STL class.
ripple::getFileContents
std::string getFileContents(boost::system::error_code &ec, boost::filesystem::path const &sourcePath, boost::optional< std::size_t > maxSize=boost::none)
Definition: FileUtilities.cpp:25
ripple::SizedItem::txnDBCache
@ txnDBCache
ripple::parseIniFile
IniFileSections parseIniFile(std::string const &strInput, const bool bTrim)
Definition: Config.cpp:86
std::string::substr
T substr(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::getSingleSection
bool getSingleSection(IniFileSections &secSource, std::string const &strSection, std::string &strValue, beast::Journal j)
Definition: Config.cpp:147
std::endl
T endl(T... args)
ripple::getEnvVar
static std::string getEnvVar(char const *name)
Definition: Config.cpp:182
ripple::SizedItem::treeCacheSize
@ treeCacheSize
ripple::SizedItem::sweepInterval
@ sweepInterval
std::string::empty
T empty(T... args)
ripple::SizedItem::ledgerSize
@ ledgerSize
std::map::end
T end(T... args)
ripple::getIniFileSection
IniFileSections::mapped_type * getIniFileSection(IniFileSections &secSource, std::string const &strSection)
Definition: Config.cpp:134
ripple::SizedItem::ledgerAge
@ ledgerAge
ripple::IniFileSections
std::map< std::string, std::vector< std::string > > IniFileSections
Definition: BasicConfig.h:36
ripple::getRegisteredFeature
boost::optional< uint256 > getRegisteredFeature(std::string const &name)
Definition: Feature.cpp:140