//------------------------------------------------------------------------------ /* This file is part of rippled: https://github.com/ripple/rippled Copyright (c) 2012, 2013 Ripple Labs Inc. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== #include #include #include #include #include #include #include #include #include #include #include #if defined(BEAST_LINUX) || defined(BEAST_MAC) || defined(BEAST_BSD) #include #endif namespace po = boost::program_options; namespace ripple { void setupServer () { #ifdef RLIMIT_NOFILE struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { if (rl.rlim_cur != rl.rlim_max) { rl.rlim_cur = rl.rlim_max; setrlimit(RLIMIT_NOFILE, &rl); } } #endif getApp().setup (); } void startServer () { // // Execute start up rpc commands. // if (getConfig ().RPC_STARTUP.isArray ()) { for (int i = 0; i != getConfig ().RPC_STARTUP.size (); ++i) { Json::Value const& jvCommand = getConfig ().RPC_STARTUP[i]; if (!getConfig ().QUIET) std::cerr << "Startup RPC: " << jvCommand << std::endl; RPCHandler rhHandler (getApp().getOPs ()); Resource::Charge loadType = Resource::feeReferenceRPC; Json::Value jvResult = rhHandler.doCommand (jvCommand, Role::ADMIN, loadType); if (!getConfig ().QUIET) std::cerr << "Result: " << jvResult << std::endl; } } getApp().run (); // Blocks till we get a stop RPC. } void printHelp (const po::options_description& desc) { std::cerr << SYSTEM_NAME "d [options] \n" << desc << std::endl << "Commands: \n" " account_info ||| [] [strict]\n" " account_lines |\"\" []\n" " account_offers | []\n" " account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary] [count] [descending]\n" " book_offers [ [ [ []]]]]\n" " connect []\n" " consensus_info\n" " get_counts\n" " json \n" " ledger [|current|closed|validated] [full]\n" " ledger_accept\n" " ledger_closed\n" " ledger_current\n" " ledger_request \n" " ledger_header \n" " logrotate \n" " peers\n" " proof_create [] []\n" " proof_solve \n" " proof_verify [] []\n" " random\n" " ripple ...\n" " ripple_path_find []\n" " server_info\n" " stop\n" " tx \n" " unl_add | []\n" " unl_delete |\n" " unl_list\n" " unl_load\n" " unl_network\n" " unl_reset\n" " validation_create [||]\n" " validation_seed [||]\n" " wallet_accounts \n" " wallet_add [] []\n" " wallet_claim [] []\n" " wallet_propose []\n" " wallet_seed [||]\n"; } //------------------------------------------------------------------------------ static void setupConfigForUnitTests (Config* config) { config->nodeDatabase = parseDelimitedKeyValueString ("type=memory"); config->ephemeralNodeDatabase = beast::StringPairArray (); config->importNodeDatabase = beast::StringPairArray (); } static int runUnitTests(std::string const& pattern, std::string const& argument) { // Config needs to be set up before creating Application setupConfigForUnitTests (&getConfig ()); // VFALCO TODO Remove dependence on constructing Application object std::unique_ptr app (make_Application (deprecatedLogs())); using namespace beast::unit_test; beast::debug_ostream stream; reporter r (stream); r.arg(argument); bool const failed (r.run_each_if ( global_suites(), match_auto (pattern))); if (failed) return EXIT_FAILURE; return EXIT_SUCCESS; } //------------------------------------------------------------------------------ int run (int argc, char** argv) { // Make sure that we have the right OpenSSL and Boost libraries. version::checkLibraryVersions(); FatalErrorReporter reporter; using namespace std; setCallingThreadName ("main"); int iResult = 0; po::variables_map vm; std::string importText; { importText += "Import an existing node database (specified in the ["; importText += ConfigSection::importNodeDatabase (); importText += "] configuration file section) into the current "; importText += "node database (specified in the ["; importText += ConfigSection::nodeDatabase (); importText += "] configuration file section)."; } // VFALCO TODO Replace boost program options with something from Beast. // // Set up option parsing. // po::options_description desc ("General Options"); desc.add_options () ("help,h", "Display this message.") ("conf", po::value (), "Specify the configuration file.") ("rpc", "Perform rpc command (default).") ("rpc_ip", po::value (), "Specify the IP address for RPC command. Format: [':']") ("rpc_port", po::value (), "Specify the port number for RPC command.") ("standalone,a", "Run with no peers.") ("unittest,u", po::value ()->implicit_value (""), "Perform unit tests.") ("unittest-arg", po::value ()->implicit_value (""), "Supplies argument to unit tests.") ("parameters", po::value< vector > (), "Specify comma separated parameters.") ("quiet,q", "Reduce diagnotics.") ("quorum", po::value (), "Set the validation quorum.") ("verbose,v", "Verbose logging.") ("load", "Load the current ledger from the local DB.") ("replay","Replay a ledger close.") ("ledger", po::value (), "Load the specified ledger and start from .") ("ledgerfile", po::value (), "Load the specified ledger file.") ("start", "Start from a fresh Ledger.") ("net", "Get the initial ledger from the network.") ("fg", "Run in the foreground.") ("import", importText.c_str ()) ("version", "Display the build version.") ; // Interpret positional arguments as --parameters. po::positional_options_description p; p.add ("parameters", -1); if (! RandomNumbers::getInstance ().initialize ()) { std::cerr << "Unable to add system entropy" << std::endl; iResult = 2; } if (!iResult) { // Parse options, if no error. try { po::store (po::command_line_parser (argc, argv) .options (desc) // Parse options. .positional (p) // Remainder as --parameters. .run (), vm); po::notify (vm); // Invoke option notify functions. } catch (...) { iResult = 1; } } if (!iResult && vm.count ("help")) { iResult = 1; } if (vm.count ("version")) { std::cout << "rippled version " << BuildInfo::getVersionString () << std::endl; return 0; } // Use a watchdog process unless we're invoking a stand alone type of mode // if (HaveSustain () && !iResult && !vm.count ("parameters") && !vm.count ("fg") && !vm.count ("standalone") && !vm.count ("unittest")) { std::string logMe = DoSustain (getConfig ().getDebugLogFile ().string()); if (!logMe.empty ()) std::cerr << logMe; } if (vm.count ("quiet")) { deprecatedLogs().severity(beast::Journal::kFatal); } else if (vm.count ("verbose")) { deprecatedLogs().severity(beast::Journal::kTrace); } else { deprecatedLogs().severity(beast::Journal::kInfo); } // Run the unit tests if requested. // The unit tests will exit the application with an appropriate return code. // if (vm.count ("unittest")) { std::string argument; if (vm.count("unittest-arg")) argument = vm["unittest-arg"].as(); return runUnitTests(vm["unittest"].as(), argument); } if (!iResult) { auto configFile = vm.count ("conf") ? vm["conf"].as () : std::string(); // config file, quiet flag. getConfig ().setup (configFile, bool (vm.count ("quiet"))); if (vm.count ("standalone")) { getConfig ().RUN_STANDALONE = true; getConfig ().LEDGER_HISTORY = 0; } } if (vm.count ("start")) getConfig ().START_UP = Config::FRESH; // Handle a one-time import option // if (vm.count ("import")) { getConfig ().doImport = true; } if (vm.count ("ledger")) { getConfig ().START_LEDGER = vm["ledger"].as (); if (vm.count("replay")) getConfig ().START_UP = Config::REPLAY; else getConfig ().START_UP = Config::LOAD; } else if (vm.count ("ledgerfile")) { getConfig ().START_LEDGER = vm["ledgerfile"].as (); getConfig ().START_UP = Config::LOAD_FILE; } else if (vm.count ("load")) { getConfig ().START_UP = Config::LOAD; } else if (vm.count ("net")) { getConfig ().START_UP = Config::NETWORK; if (getConfig ().VALIDATION_QUORUM < 2) getConfig ().VALIDATION_QUORUM = 2; } if (iResult == 0) { // These overrides must happen after the config file is loaded. // Override the RPC destination IP address // if (vm.count ("rpc_ip")) { // VFALCO TODO This is currently broken //getConfig ().setRpcIpAndOptionalPort (vm ["rpc_ip"].as ()); //getConfig().overwrite("rpc", "ip", vm["rpc_ip"].as()); } // Override the RPC destination port number // if (vm.count ("rpc_port")) { // VFALCO TODO This should be a short. // VFALCO TODO This is currently broken //getConfig ().setRpcPort (vm ["rpc_port"].as ()); //getConfig().overwrite("rpc", "port", vm["rpc_port"].as()); } if (vm.count ("quorum")) { getConfig ().VALIDATION_QUORUM = vm["quorum"].as (); if (getConfig ().VALIDATION_QUORUM < 0) iResult = 1; } } if (iResult == 0) { if (!vm.count ("parameters")) { // No arguments. Run server. std::unique_ptr app (make_Application (deprecatedLogs())); setupServer (); startServer (); } else { // Have a RPC command. setCallingThreadName ("rpc"); std::vector vCmd = vm["parameters"].as > (); iResult = RPCCall::fromCommandLine (vCmd); } } if (1 == iResult && !vm.count ("quiet")) printHelp (desc); return iResult; } }