diff --git a/AddressBook.cpp b/AddressBook.cpp index 00b735ae..754d314a 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -396,7 +396,7 @@ namespace client LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded"); } else - LogPrint (eLogWarning, "Addresbook: subscriptions.txt not found"); + LogPrint (eLogWarning, "Addresbook: subscriptions.txt not found in datadir"); } else LogPrint (eLogError, "Addressbook: subscriptions already loaded"); diff --git a/ClientContext.cpp b/ClientContext.cpp index 0d112894..53c442f0 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "Config.h" #include "util.h" #include "Log.h" #include "Identity.h" @@ -37,46 +38,58 @@ namespace client } std::shared_ptr localDestination; - // proxies - std::string proxyKeys = i2p::util::config::GetArg("-proxykeys", ""); - if (proxyKeys.length () > 0) - { - i2p::data::PrivateKeys keys; - LoadPrivateKeys (keys, proxyKeys); - localDestination = CreateNewLocalDestination (keys, false); + bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy); + if (httproxy) { + std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys); + std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr); + uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort); + LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort); + if (httpProxyKeys.length () > 0) + { + i2p::data::PrivateKeys keys; + LoadPrivateKeys (keys, httpProxyKeys); + localDestination = CreateNewLocalDestination (keys, false); + } + m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination); + m_HttpProxy->Start(); } - std::string httpProxyAddr = i2p::util::config::GetArg("-httpproxyaddress", "127.0.0.1"); - uint16_t httpProxyPort = i2p::util::config::GetArg("-httpproxyport", 4444); - LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort); - m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, localDestination); - m_HttpProxy->Start(); - std::string socksProxyAddr = i2p::util::config::GetArg("-socksproxyaddress", "127.0.0.1"); - uint16_t socksProxyPort = i2p::util::config::GetArg("-socksproxyport", 4447); - std::string socksOutProxyAddr = i2p::util::config::GetArg("-socksoutproxyaddress", ""); - uint16_t socksOutProxyPort = i2p::util::config::GetArg("-socksoutproxyport", 0); - LogPrint(eLogInfo, "Clients: starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort); - m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination); - m_SocksProxy->Start(); + bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy); + if (socksproxy) { + std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys); + std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr); + uint16_t socksProxyPort; i2p::config::GetOption("socksproxy.port", socksProxyPort); + std::string socksOutProxyAddr; i2p::config::GetOption("socksproxy.outproxy", socksOutProxyAddr); + uint16_t socksOutProxyPort; i2p::config::GetOption("socksproxy.outproxyport", socksOutProxyPort); + LogPrint(eLogInfo, "Clients: starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort); + if (socksProxyKeys.length () > 0) + { + i2p::data::PrivateKeys keys; + LoadPrivateKeys (keys, socksProxyKeys); + localDestination = CreateNewLocalDestination (keys, false); + } + m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxyAddr, socksOutProxyPort, localDestination); + m_SocksProxy->Start(); + } // I2P tunnels ReadTunnels (); // SAM - std::string samAddr = i2p::util::config::GetArg("-samaddress", "127.0.0.1"); - uint16_t samPort = i2p::util::config::GetArg("-samport", 0); - if (samPort) - { - LogPrint(eLogInfo, "Clients: starting SAM bridge at", samAddr, ":", samPort); + bool sam; i2p::config::GetOption("sam.enabled", sam); + if (sam) { + std::string samAddr; i2p::config::GetOption("sam.address", samAddr); + uint16_t samPort; i2p::config::GetOption("sam.port", samPort); + LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort); m_SamBridge = new SAMBridge (samAddr, samPort); m_SamBridge->Start (); } // BOB - std::string bobAddr = i2p::util::config::GetArg("-bobaddress", "127.0.0.1"); - uint16_t bobPort = i2p::util::config::GetArg("-bobport", 0); - if (bobPort) - { + bool bob; i2p::config::GetOption("bob.enabled", bob); + if (bob) { + std::string bobAddr; i2p::config::GetOption("bob.address", bobAddr); + uint16_t bobPort; i2p::config::GetOption("bob.port", bobPort); LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort); m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort); m_BOBCommandChannel->Start (); diff --git a/Config.cpp b/Config.cpp new file mode 100644 index 00000000..60af0319 --- /dev/null +++ b/Config.cpp @@ -0,0 +1,225 @@ +/* +* Copyright (c) 2013-2016, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Config.h" +#include "version.h" + +using namespace boost::program_options; + +namespace i2p { +namespace config { + options_description m_OptionsDesc; + variables_map m_Options; + + /* list of renamed options */ + std::map remapped_options = { + { "tunnelscfg", "tunconf" }, + { "v6", "ipv6" }, + { "httpaddress", "http.address" }, + { "httpport", "http.port" }, + { "httpproxyaddress", "httpproxy.address" }, + { "httpproxyport", "httpproxy.port" }, + { "socksproxyaddress", "socksproxy.address" }, + { "socksproxyport", "socksproxy.port" }, + { "samaddress", "sam.address" }, + { "samport", "sam.port" }, + { "bobaddress", "bob.address" }, + { "bobport", "bob.port" }, + { "i2pcontroladdress", "i2pcontrol.address" }, + { "i2pcontroladdress", "i2pcontrol.port" }, + { "proxykeys", "httpproxy.keys" }, + }; + /* list of options, that loose their argument and become simple switch */ + std::set boolean_options = { + "daemon", "floodfill", "notransit", "service", "ipv6" + }; + + /* this function is a solid piece of shit, remove it after 2.6.0 */ + std::pair old_syntax_parser(const std::string& s) { + std::string name = ""; + std::string value = ""; + std::size_t pos = 0; + /* shortcuts -- -h */ + if (s.length() == 2 && s.at(0) == '-' && s.at(1) != '-') + return make_pair(s.substr(1), ""); + /* old-style -- -log, /log, etc */ + if (s.at(0) == '/' || (s.at(0) == '-' && s.at(1) != '-')) { + if ((pos = s.find_first_of("= ")) != std::string::npos) { + name = s.substr(1, pos - 1); + value = s.substr(pos + 1); + } else { + name = s.substr(1, pos); + value = ""; + } + if (boolean_options.count(name) > 0 && value != "") + std::cerr << "args: don't give an argument to switch option: " << s << std::endl; + if (m_OptionsDesc.find_nothrow(name, false)) { + std::cerr << "args: option " << s << " style is DEPRECATED, use --" << name << " instead" << std::endl; + return std::make_pair(name, value); + } + if (remapped_options.count(name) > 0) { + name = remapped_options[name]; + std::cerr << "args: option " << s << " is DEPRECATED, use --" << name << " instead" << std::endl; + return std::make_pair(name, value); + } /* else */ + } + /* long options -- --help */ + if (s.substr(0, 2) == "--") { + if ((pos = s.find_first_of("= ")) != std::string::npos) { + name = s.substr(2, pos - 2); + value = s.substr(pos + 1); + } else { + name = s.substr(2, pos); + value = ""; + } + if (boolean_options.count(name) > 0 && value != "") { + std::cerr << "args: don't give an argument to switch option: " << s << std::endl; + value = ""; + } + if (m_OptionsDesc.find_nothrow(name, false)) + return std::make_pair(name, value); + if (remapped_options.count(name) > 0) { + name = remapped_options[name]; + std::cerr << "args: option " << s << " is DEPRECATED, use --" << name << " instead" << std::endl; + return std::make_pair(name, value); + } /* else */ + } + std::cerr << "args: unknown option -- " << s << std::endl; + return std::make_pair("", ""); + } + + void Init() { + options_description general("General options"); + general.add_options() + ("help", "Show this message") + ("conf", value()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf)") + ("tunconf", value()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg)") + ("pidfile", value()->default_value(""), "Write pidfile to given path") + ("log", value()->default_value(""), "Write logs to file instead stdout") + ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") + ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)") + ("host", value()->default_value(""), "External IP (deprecated)") + ("port", value()->default_value(4567), "Port to listen for incoming connections") + ("ipv6", value()->zero_tokens()->default_value(false), "Enable communication through ipv6") + ("daemon", value()->zero_tokens()->default_value(false), "Router will go to background after start") + ("service", value()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") + ("notransit", value()->zero_tokens()->default_value(false), "Router will not forward transit traffic") + ("floodfill", value()->zero_tokens()->default_value(false), "Router will try to become floodfill") + ("bandwidth", value()->default_value('O'), "Bandwidth limiting: L - 32kbps, O - 256Kbps, P - unlimited (ignored if floodfill)") + ; + + options_description httpserver("HTTP Server options"); + httpserver.add_options() + ("http.enabled", value()->default_value(true), "Enable or disable webconsole") + ("http.address", value()->default_value("127.0.0.1"), "Webconsole listen address") + ("http.port", value()->default_value(7070), "Webconsole listen port") + ; + + options_description httpproxy("HTTP Proxy options"); + httpproxy.add_options() + ("httpproxy.enabled", value()->default_value(true), "Enable or disable HTTP Proxy") + ("httpproxy.address", value()->default_value("127.0.0.1"), "HTTP Proxy listen address") + ("httpproxy.port", value()->default_value(4444), "HTTP Proxy listen port") + ("httpproxy.keys", value()->default_value("httpproxy-keys.dat"), "HTTP Proxy encryption keys") + ; + + options_description socksproxy("SOCKS Proxy options"); + socksproxy.add_options() + ("socksproxy.enabled", value()->default_value(true), "Enable or disable SOCKS Proxy") + ("socksproxy.address", value()->default_value("127.0.0.1"), "SOCKS Proxy listen address") + ("socksproxy.port", value()->default_value(4447), "SOCKS Proxy listen port") + ("socksproxy.keys", value()->default_value("socksproxy-keys.dat"), "SOCKS Proxy encryption keys") + ; + + options_description sam("SAM bridge options"); + sam.add_options() + ("sam.enabled", value()->default_value(false), "Enable or disable SAM Application bridge") + ("sam.address", value()->default_value("127.0.0.1"), "SAM listen address") + ("sam.port", value()->default_value(7656), "SAM listen port") + ; + + options_description bob("BOB options"); + bob.add_options() + ("bob.enabled", value()->default_value(false), "Enable or disable BOB command channel") + ("bob.address", value()->default_value("127.0.0.1"), "BOB listen address") + ("bob.port", value()->default_value(2827), "BOB listen port") + ; + + options_description i2pcontrol("I2PControl options"); + i2pcontrol.add_options() + ("i2pcontrol.enabled", value()->default_value(false), "Enable or disable I2P Control Protocol") + ("i2pcontrol.address", value()->default_value("127.0.0.1"), "I2PCP listen address") + ("i2pcontrol.port", value()->default_value(7650), "I2PCP listen port") + ("i2pcontrol.password", value()->default_value("itoopie"), "I2PCP access password") + ("i2pcontrol.cert", value()->default_value("i2pcontrol.crt.pem"), "I2PCP connection cerificate") + ("i2pcontrol.key", value()->default_value("i2pcontrol.key.pem"), "I2PCP connection cerificate key") + ; + + m_OptionsDesc + .add(general) + .add(httpserver) + .add(httpproxy) + .add(socksproxy) + .add(sam) + .add(bob) + .add(i2pcontrol) + ; + } + + void ParseCmdline(int argc, char* argv[]) { + try { + auto style = boost::program_options::command_line_style::unix_style + | boost::program_options::command_line_style::allow_long_disguise; + style &= ~ boost::program_options::command_line_style::allow_guessing; + store(parse_command_line(argc, argv, m_OptionsDesc, style, old_syntax_parser), m_Options); + } catch (boost::program_options::error e) { + std::cerr << "args: " << e.what() << std::endl; + exit(EXIT_FAILURE); + } + + if (m_Options.count("help") || m_Options.count("h")) { + std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl; + std::cout << m_OptionsDesc; + exit(EXIT_SUCCESS); + } + } + + void ParseConfig(const std::string& path) { + if (path == "") + return; + + std::ifstream config(path, std::ios::in); + + if (!config.is_open()) { + std::cerr << "missing/unreadable config file: " << path << std::endl; + exit(EXIT_FAILURE); + } + + try { + store(boost::program_options::parse_config_file(config, m_OptionsDesc), m_Options); + } catch (boost::program_options::error e) { + std::cerr << e.what() << std::endl; + exit(EXIT_FAILURE); + }; + } + + void Finalize() { + notify(m_Options); + }; +} // namespace config +} // namespace i2p diff --git a/Config.h b/Config.h new file mode 100644 index 00000000..51a12d70 --- /dev/null +++ b/Config.h @@ -0,0 +1,100 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include +#include + +/** + * Functions to parse and store i2pd parameters + * + * General usage flow: + * Init() -- early as possible + * ParseCmdline() -- somewhere close to main() + * ParseConfig() -- after detecting path to config + * Finalize() -- right after all Parse*() functions called + * GetOption() -- may be called after Finalize() + */ + +namespace i2p { +namespace config { + extern boost::program_options::variables_map m_Options; + + /** + * @brief Initialize list of acceptable parameters + * + * Should be called before any Parse* functions. + */ + void Init(); + + /** + * @brief Parse cmdline parameters, and show help if requested + * @param argc Cmdline arguments count, should be passed from main(). + * @param argv Cmdline parameters array, should be passed from main() + * + * If --help is given in parameters, shows it's list with description + * terminates the program with exitcode 0. + * + * In case of parameter misuse boost throws an exception. + * We internally handle type boost::program_options::unknown_option, + * and then terminate program with exitcode 1. + * + * Other exceptions will be passed to higher level. + */ + void ParseCmdline(int argc, char* argv[]); + + /** + * @brief Load and parse given config file + * @param path Path to config file + * + * If error occured when opening file path is points to, + * we show the error message and terminate program. + * + * In case of parameter misuse boost throws an exception. + * We internally handle type boost::program_options::unknown_option, + * and then terminate program with exitcode 1. + * + * Other exceptions will be passed to higher level. + */ + void ParseConfig(const std::string& path); + + /** + * @brief Used to combine options from cmdline, config and default values + */ + void Finalize(); + + /* @brief Accessor to parameters by name + * @param name Name of the requested parameter + * @param value Variable where to store option + * @return this function returns false if parameter not found + * + * @example uint16_t port; GetOption("sam.port", port); + */ + template + bool GetOption(const char *name, T& value) { + if (!m_Options.count(name)) + return false; + value = m_Options[name].as(); + return true; + } + + /** + * @brief Set value of given parameter + * @param name Name of settable parameter + * @param value New parameter value + * @return true if value set up successful, false otherwise + * + * @example uint16_t port = 2827; SetOption("bob.port", port); + */ + template + bool SetOption(const char *name, const T& value) { + if (!m_Options.count(name)) + return false; + m_Options[name] = value; + notify(m_Options); + return true; + } +} +} + +#endif // CONFIG_H diff --git a/Daemon.cpp b/Daemon.cpp index ee221080..ef74dff3 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -3,6 +3,7 @@ #include "Daemon.h" +#include "Config.h" #include "Log.h" #include "Base.h" #include "version.h" @@ -50,78 +51,106 @@ namespace i2p bool Daemon_Singleton::IsService () const { + bool service = false; #ifndef _WIN32 - return i2p::util::config::GetArg("-service", 0); -#else - return false; + i2p::config::GetOption("service", service); #endif + return service; } bool Daemon_Singleton::init(int argc, char* argv[]) { + std::string config = i2p::util::filesystem::GetConfigFile().string(); + std::string tunconf = i2p::util::filesystem::GetTunnelsConfigFile().string(); + std::string datadir = i2p::util::filesystem::GetDataDir().string(); + + LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); + LogPrint(eLogDebug, "FS: main config file: ", config); + LogPrint(eLogDebug, "FS: tunnels config: ", tunconf); + LogPrint(eLogDebug, "FS: data directory: ", datadir); + + i2p::config::Init(); + i2p::config::ParseCmdline(argc, argv); + i2p::config::ParseConfig(config); + i2p::config::Finalize(); + i2p::crypto::InitCrypto (); - i2p::util::config::OptionParser(argc, argv); i2p::context.Init (); - LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); - LogPrint(eLogDebug, "FS: data directory: ", i2p::util::filesystem::GetDataDir().string()); - i2p::util::config::ReadConfigFile(i2p::util::filesystem::GetConfigFile()); + i2p::config::GetOption("daemon", isDaemon); - isDaemon = i2p::util::config::GetArg("-daemon", 0); - isLogging = i2p::util::config::GetArg("-log", (int)isDaemon); + // temporary hack + std::string logs = ""; + i2p::config::GetOption("log", logs); + if (logs != "") + isLogging = true; - int port = i2p::util::config::GetArg("-port", 0); - if (port) - i2p::context.UpdatePort (port); - std::string host = i2p::util::config::GetArg("-host", ""); - if (host != "") + uint16_t port; i2p::config::GetOption("port", port); + LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port); + i2p::context.UpdatePort (port); + + std::string host; i2p::config::GetOption("host", host); + if (host != "") { + LogPrint(eLogInfo, "Daemon: address for incoming connections is ", host); i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host)); + } - i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0)); - i2p::context.SetAcceptsTunnels (!i2p::util::config::GetArg("-notransit", 0)); - bool isFloodfill = i2p::util::config::GetArg("-floodfill", 0); - i2p::context.SetFloodfill (isFloodfill); - auto bandwidth = i2p::util::config::GetArg("-bandwidth", ""); - if (bandwidth.length () > 0) - { - if (bandwidth[0] > 'O') - i2p::context.SetExtraBandwidth (); - else if (bandwidth[0] > 'L') - i2p::context.SetHighBandwidth (); - else - i2p::context.SetLowBandwidth (); - } - else if (isFloodfill) + bool ipv6; i2p::config::GetOption("ipv6", ipv6); + bool transit; i2p::config::GetOption("notransit", transit); + i2p::context.SetSupportsV6 (ipv6); + i2p::context.SetAcceptsTunnels (!transit); + + bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); + char bandwidth; i2p::config::GetOption("bandwidth", bandwidth); + + if (isFloodfill) { + LogPrint(eLogInfo, "Daemon: router will be floodfill, bandwidth set to 'extra'"); + i2p::context.SetFloodfill (true); i2p::context.SetExtraBandwidth (); - LogPrint(eLogDebug, "Daemon: CMD parameters:"); - for (int i = 0; i < argc; ++i) - LogPrint(eLogDebug, i, ": ", argv[i]); + } else if (bandwidth != '-') { + LogPrint(eLogInfo, "Daemon: bandwidth set to ", bandwidth); + switch (bandwidth) { + case 'P' : i2p::context.SetExtraBandwidth (); break; + case 'L' : i2p::context.SetHighBandwidth (); break; + default : i2p::context.SetLowBandwidth (); break; + } + } return true; } bool Daemon_Singleton::start() { - // initialize log if (isLogging) - { - std::string logfile_path = IsService () ? "/var/log/i2pd" : i2p::util::filesystem::GetDataDir().string(); + { + // set default to stdout + std::string logfile = ""; i2p::config::GetOption("logfile", logfile); + std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel); + if (isDaemon && logfile == "") { + // can't log to stdout, use autodetect of logfile + if (IsService ()) { + logfile = "/var/log"; + } else { + logfile = i2p::util::filesystem::GetDataDir().string(); + } #ifndef _WIN32 - logfile_path.append("/i2pd.log"); + logfile.append("/i2pd.log"); #else - logfile_path.append("\\i2pd.log"); + logfile.append("\\i2pd.log"); #endif - StartLog (logfile_path); + } + StartLog (logfile); + g_Log->SetLogLevel(loglevel); + } + + bool http; i2p::config::GetOption("http.enabled", http); + if (http) { + std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); + uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); + LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort); + d.httpServer = std::unique_ptr(new i2p::util::HTTPServer(httpAddr, httpPort)); + d.httpServer->Start(); } - else - StartLog (""); // write to stdout - g_Log->SetLogLevel(i2p::util::config::GetArg("-loglevel", "info")); - - std::string httpAddr = i2p::util::config::GetArg("-httpaddress", "127.0.0.1"); - uint16_t httpPort = i2p::util::config::GetArg("-httpport", 7070); - LogPrint(eLogInfo, "Daemon: staring HTTP Server at ", httpAddr, ":", httpPort); - d.httpServer = std::unique_ptr(new i2p::util::HTTPServer(httpAddr, httpPort)); - d.httpServer->Start(); LogPrint(eLogInfo, "Daemon: starting NetDB"); i2p::data::netdb.Start(); @@ -140,10 +169,10 @@ namespace i2p i2p::client::context.Start (); // I2P Control Protocol - std::string i2pcpAddr = i2p::util::config::GetArg("-i2pcontroladdress", "127.0.0.1"); - uint16_t i2pcpPort = i2p::util::config::GetArg("-i2pcontrolport", 0); - if (i2pcpPort) - { + bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol); + if (i2pcontrol) { + std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr); + uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort); LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort); d.m_I2PControlService = std::unique_ptr(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort)); d.m_I2PControlService->Start (); diff --git a/DaemonLinux.cpp b/DaemonLinux.cpp index 306fc7ca..89df5306 100644 --- a/DaemonLinux.cpp +++ b/DaemonLinux.cpp @@ -8,10 +8,10 @@ #include #include +#include "Config.h" #include "Log.h" #include "util.h" - void handle_signal(int sig) { switch (sig) @@ -28,7 +28,6 @@ void handle_signal(int sig) } } - namespace i2p { namespace util @@ -74,7 +73,7 @@ namespace i2p // Pidfile // this code is c-styled and a bit ugly, but we need fd for locking pidfile - pidfile = i2p::util::config::GetArg("-pidfile", ""); + std::string pidfile; i2p::config::GetOption("pidfile", pidfile); if (pidfile == "") { pidfile = IsService () ? "/var/run" : i2p::util::filesystem::GetDataDir().string(); pidfile.append("/i2pd.pid"); @@ -120,7 +119,6 @@ namespace i2p return Daemon_Singleton::stop(); } - } } diff --git a/DaemonWin32.cpp b/DaemonWin32.cpp index e09bf077..4ab65040 100644 --- a/DaemonWin32.cpp +++ b/DaemonWin32.cpp @@ -1,3 +1,4 @@ +#include "Config.h" #include "Daemon.h" #include "util.h" #include "Log.h" @@ -23,7 +24,7 @@ namespace i2p else isDaemon = 0; - std::string serviceControl = i2p::util::config::GetArg("-svcctl", ""); + std::string serviceControl; i2p::config::GetOption("svcctl", serviceControl); if (serviceControl == "install") { LogPrint(eLogInfo, "WinSVC: installing ", SERVICE_NAME, " as service"); diff --git a/I2PControl.cpp b/I2PControl.cpp index 94dd5c80..f6522339 100644 --- a/I2PControl.cpp +++ b/I2PControl.cpp @@ -1,5 +1,3 @@ -// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy -#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) #include #include #include @@ -8,10 +6,15 @@ #include #include #include + +// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy +#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) #if !GCC47_BOOST149 #include #endif + #include "Log.h" +#include "Config.h" #include "NetDb.h" #include "RouterContext.h" #include "Daemon.h" @@ -26,58 +29,56 @@ namespace i2p namespace client { I2PControlService::I2PControlService (const std::string& address, int port): - m_Password (I2P_CONTROL_DEFAULT_PASSWORD), m_IsRunning (false), m_Thread (nullptr), + m_IsRunning (false), m_Thread (nullptr), m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)), m_SSLContext (m_Service, boost::asio::ssl::context::sslv23), m_ShutdownTimer (m_Service) { - LoadConfig (); - // certificate + i2p::config::GetOption("i2pcontrol.password", m_Password); + + // certificate / keys + std::string i2pcp_crt; i2p::config::GetOption("i2pcontrol.cert", i2pcp_crt); + std::string i2pcp_key; i2p::config::GetOption("i2pcontrol.key", i2pcp_key); + // TODO: properly handle absolute paths auto path = GetPath (); - if (!boost::filesystem::exists (path)) - { - if (!boost::filesystem::create_directory (path)) - LogPrint (eLogError, "Failed to create i2pcontrol directory"); - } - if (!boost::filesystem::exists (path / I2P_CONTROL_KEY_FILE) || - !boost::filesystem::exists (path / I2P_CONTROL_CERT_FILE)) + if (!boost::filesystem::exists (path / i2pcp_crt) || + !boost::filesystem::exists (path / i2pcp_key)) { - // create new certificate - CreateCertificate (); - LogPrint (eLogInfo, "I2PControl certificates created"); + LogPrint (eLogInfo, "I2PControl: creating new certificate for control connection"); + CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str()); } m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); - m_SSLContext.use_certificate_file ((path / I2P_CONTROL_CERT_FILE).string (), boost::asio::ssl::context::pem); - m_SSLContext.use_private_key_file ((path / I2P_CONTROL_KEY_FILE).string (), boost::asio::ssl::context::pem); + m_SSLContext.use_certificate_file ((path / i2pcp_crt).string (), boost::asio::ssl::context::pem); + m_SSLContext.use_private_key_file ((path / i2pcp_crt).string (), boost::asio::ssl::context::pem); // handlers - m_MethodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlService::I2PControlHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_INFO] = &I2PControlService::RouterInfoHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler; - m_MethodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlService::NetworkSettingHandler; + m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler; + m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler; + m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler; + m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler; + m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler; + m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler; // I2PControl - m_I2PControlHandlers[I2P_CONTROL_I2PCONTROL_PASSWORD] = &I2PControlService::PasswordHandler; + m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler; // RouterInfo - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlService::UptimeHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlService::VersionHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_STATUS] = &I2PControlService::StatusHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS] = &I2PControlService::NetDbKnownPeersHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS] = &I2PControlService::NetDbActivePeersHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_STATUS] = &I2PControlService::NetStatusHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING] = &I2PControlService::TunnelsParticipatingHandler; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_IB_1S] = &I2PControlService::InboundBandwidth1S ; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_BW_OB_1S] = &I2PControlService::OutboundBandwidth1S ; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_TOTAL_RB] = &I2PControlService::NetTotalReceivedBytes; - m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_NET_TOTAL_SB] = &I2PControlService::NetTotalSentBytes; - - // RouterManager - m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN] = &I2PControlService::ShutdownHandler; - m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL] = &I2PControlService::ShutdownGracefulHandler; - m_RouterManagerHandlers[I2P_CONTROL_ROUTER_MANAGER_RESEED] = &I2PControlService::ReseedHandler; + m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler; + m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler; + m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler; + m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler; + m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler; + m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S; + m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S; + m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler; + m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler; + m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes; + m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes; + + // RouterManager + m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler; + m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler; + m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler; } I2PControlService::~I2PControlService () @@ -85,49 +86,6 @@ namespace client Stop (); } - void I2PControlService::LoadConfig () - { - auto path = GetPath (); - if (!boost::filesystem::exists (path)) - { - if (!boost::filesystem::create_directory (path)) - LogPrint (eLogError, "Failed to create i2pcontrol directory"); - } - boost::property_tree::ptree pt; - auto filename = path / I2P_CONTROL_CONFIG_FILE; - bool isNew = true; - if (boost::filesystem::exists (filename)) - { - try - { - boost::property_tree::read_ini (filename.string (), pt); - isNew = false; - } - catch (std::exception& ex) - { - LogPrint (eLogError, "Can't read ", filename, ": ", ex.what ()); - } - } - m_Password = pt.get (I2P_CONTROL_I2PCONTROL_PASSWORD, I2P_CONTROL_DEFAULT_PASSWORD); - if (isNew) SaveConfig (); - } - - void I2PControlService::SaveConfig () - { - boost::property_tree::ptree pt; - pt.put (I2P_CONTROL_I2PCONTROL_PASSWORD, m_Password); - auto filename = GetPath () / I2P_CONTROL_CONFIG_FILE; - // we take care about directory in LoadConfig - try - { - boost::property_tree::write_ini (filename.string (), pt); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "Can't write ", filename, ": ", ex.what ()); - } - } - void I2PControlService::Start () { if (!m_IsRunning) @@ -158,15 +116,12 @@ namespace client { while (m_IsRunning) { - try - { + try { m_Service.run (); - } - catch (std::exception& ex) - { - LogPrint (eLogError, "I2PControl: ", ex.what ()); - } - } + } catch (std::exception& ex) { + LogPrint (eLogError, "I2PControl: runtime exception: ", ex.what ()); + } + } } void I2PControlService::Accept () @@ -181,13 +136,12 @@ namespace client if (ecode != boost::asio::error::operation_aborted) Accept (); - if (!ecode) - { - LogPrint (eLogInfo, "New I2PControl request from ", socket->lowest_layer ().remote_endpoint ()); - Handshake (socket); + if (ecode) { + LogPrint (eLogError, "I2PControl: accept error: ", ecode.message ()); + return; } - else - LogPrint (eLogError, "I2PControl accept error: ", ecode.message ()); + LogPrint (eLogDebug, "I2PControl: new request from ", socket->lowest_layer ().remote_endpoint ()); + Handshake (socket); } void I2PControlService::Handshake (std::shared_ptr socket) @@ -198,13 +152,12 @@ namespace client void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr socket) { - if (!ecode) - { - //std::this_thread::sleep_for (std::chrono::milliseconds(5)); - ReadRequest (socket); - } - else - LogPrint (eLogError, "I2PControl handshake error: ", ecode.message ()); + if (ecode) { + LogPrint (eLogError, "I2PControl: handshake error: ", ecode.message ()); + return; + } + //std::this_thread::sleep_for (std::chrono::milliseconds(5)); + ReadRequest (socket); } void I2PControlService::ReadRequest (std::shared_ptr socket) @@ -224,12 +177,10 @@ namespace client size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf) { - if (ecode) - { - LogPrint (eLogError, "I2PControl read error: ", ecode.message ()); - } - else - { + if (ecode) { + LogPrint (eLogError, "I2PControl: read error: ", ecode.message ()); + return; + } else { try { bool isHtml = !memcmp (buf->data (), "POST", 4); @@ -264,14 +215,14 @@ namespace client boost::property_tree::ptree pt; boost::property_tree::read_json (ss, pt); - std::string method = pt.get(I2P_CONTROL_PROPERTY_METHOD); + std::string id = pt.get("id"); + std::string method = pt.get("method"); auto it = m_MethodHandlers.find (method); if (it != m_MethodHandlers.end ()) { std::ostringstream response; - response << "{\"id\":" << pt.get(I2P_CONTROL_PROPERTY_ID) << ",\"result\":{"; - - (this->*(it->second))(pt.get_child (I2P_CONTROL_PROPERTY_PARAMS), response); + response << "{\"id\":" << id << ",\"result\":{"; + (this->*(it->second))(pt.get_child ("params"), response); response << "},\"jsonrpc\":\"2.0\"}"; SendResponse (socket, buf, response, isHtml); } @@ -338,33 +289,34 @@ namespace client void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf) { - if (ecode) - LogPrint (eLogError, "I2PControl write error: ", ecode.message ()); + if (ecode) { + LogPrint (eLogError, "I2PControl: write error: ", ecode.message ()); + } } // handlers void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - int api = params.get (I2P_CONTROL_PARAM_API); - auto password = params.get (I2P_CONTROL_PARAM_PASSWORD); - LogPrint (eLogDebug, "I2PControl Authenticate API=", api, " Password=", password); + int api = params.get ("API"); + auto password = params.get ("Password"); + LogPrint (eLogDebug, "I2PControl: Authenticate API=", api, " Password=", password); if (password != m_Password) { LogPrint (eLogError, "I2PControl: Authenticate - Invalid password: ", password); return; } - InsertParam (results, I2P_CONTROL_PARAM_API, api); + InsertParam (results, "API", api); results << ","; std::string token = boost::lexical_cast(i2p::util::GetSecondsSinceEpoch ()); - m_Tokens.insert (token); - InsertParam (results, I2P_CONTROL_PARAM_TOKEN, token); - } + m_Tokens.insert (token); + InsertParam (results, "Token", token); + } void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - auto echo = params.get (I2P_CONTROL_PARAM_ECHO); + auto echo = params.get ("Echo"); LogPrint (eLogDebug, "I2PControl Echo Echo=", echo); - InsertParam (results, I2P_CONTROL_PARAM_RESULT, echo); + InsertParam (results, "Result", echo); } @@ -372,10 +324,9 @@ namespace client void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - LogPrint (eLogDebug, "I2PControl I2PControl"); for (auto& it: params) { - LogPrint (eLogDebug, it.first); + LogPrint (eLogDebug, "I2PControl: I2PControl request: ", it.first); auto it1 = m_I2PControlHandlers.find (it.first); if (it1 != m_I2PControlHandlers.end ()) { @@ -383,26 +334,24 @@ namespace client InsertParam (results, it.first, ""); } else - LogPrint (eLogError, "I2PControl I2PControl unknown request ", it.first); - } + LogPrint (eLogError, "I2PControl: I2PControl unknown request: ", it.first); + } } void I2PControlService::PasswordHandler (const std::string& value) { - LogPrint (eLogDebug, "I2PControl new password=", value); + LogPrint (eLogWarning, "I2PControl: new password=", value, ", to make it persistent you should update your config!"); m_Password = value; m_Tokens.clear (); - SaveConfig (); } // RouterInfo void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - LogPrint (eLogDebug, "I2PControl RouterInfo"); for (auto it = params.begin (); it != params.end (); it++) { - LogPrint (eLogDebug, it->first); + LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first); auto it1 = m_RouterInfoHandlers.find (it->first); if (it1 != m_RouterInfoHandlers.end ()) { @@ -410,87 +359,89 @@ namespace client (this->*(it1->second))(results); } else - LogPrint (eLogError, "I2PControl RouterInfo unknown request ", it->first); + LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first); } } void I2PControlService::UptimeHandler (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_UPTIME, (int)i2p::context.GetUptime ()*1000); + InsertParam (results, "i2p.router.uptime", (int)i2p::context.GetUptime ()*1000); } void I2PControlService::VersionHandler (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_VERSION, VERSION); - } + InsertParam (results, "i2p.router.version", VERSION); + } void I2PControlService::StatusHandler (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_STATUS, "???"); // TODO: + InsertParam (results, "i2p.router.status", "???"); // TODO: } void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS, i2p::data::netdb.GetNumRouters ()); + InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ()); } void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS, (int)i2p::transport::transports.GetPeers ().size ()); + InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ()); } void I2PControlService::NetStatusHandler (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_STATUS, (int)i2p::context.GetStatus ()); + InsertParam (results, "i2p.router.net.status", (int)i2p::context.GetStatus ()); } void I2PControlService::TunnelsParticipatingHandler (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING, (int)i2p::tunnel::tunnels.GetTransitTunnels ().size ()); + int transit = i2p::tunnel::tunnels.GetTransitTunnels ().size (); + InsertParam (results, "i2p.router.net.tunnels.participating", transit); } void I2PControlService::InboundBandwidth1S (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_IB_1S, (double)i2p::transport::transports.GetInBandwidth ()); + double bw = i2p::transport::transports.GetInBandwidth (); + InsertParam (results, "i2p.router.net.bw.inbound.1s", bw); } void I2PControlService::OutboundBandwidth1S (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_BW_OB_1S, (double)i2p::transport::transports.GetOutBandwidth ()); + double bw = i2p::transport::transports.GetOutBandwidth (); + InsertParam (results, "i2p.router.net.bw.outbound.1s", bw); } void I2PControlService::NetTotalReceivedBytes (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_TOTAL_RB, (double)i2p::transport::transports.GetTotalReceivedBytes ()); + InsertParam (results, "i2p.router.net.total.received.bytes", (double)i2p::transport::transports.GetTotalReceivedBytes ()); } void I2PControlService::NetTotalSentBytes (std::ostringstream& results) { - InsertParam (results, I2P_CONTROL_ROUTER_INFO_NET_TOTAL_SB, (double)i2p::transport::transports.GetTotalSentBytes ()); + InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ()); } // RouterManager void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - LogPrint (eLogDebug, "I2PControl RouterManager"); for (auto it = params.begin (); it != params.end (); it++) { - if (it != params.begin ()) results << ","; - LogPrint (eLogDebug, it->first); + if (it != params.begin ()) results << ","; + LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first); auto it1 = m_RouterManagerHandlers.find (it->first); - if (it1 != m_RouterManagerHandlers.end ()) - (this->*(it1->second))(results); - else - LogPrint (eLogError, "I2PControl RouterManager unknown request ", it->first); + if (it1 != m_RouterManagerHandlers.end ()) { + (this->*(it1->second))(results); + } else + LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first); } } void I2PControlService::ShutdownHandler (std::ostringstream& results) { - LogPrint (eLogInfo, "Shutdown requested"); - InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); + LogPrint (eLogInfo, "I2PControl: Shutdown requested"); + InsertParam (results, "Shutdown", ""); m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent m_ShutdownTimer.async_wait ( [](const boost::system::error_code& ecode) @@ -503,8 +454,8 @@ namespace client { i2p::context.SetAcceptsTunnels (false); int timeout = i2p::tunnel::tunnels.GetTransitTunnelsExpirationTimeout (); - LogPrint (eLogInfo, "Graceful shutdown requested. Will shutdown after ", timeout, " seconds"); - InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL, ""); + LogPrint (eLogInfo, "I2PControl: Graceful shutdown requested, ", timeout, " seconds remains"); + InsertParam (results, "ShutdownGraceful", ""); m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second m_ShutdownTimer.async_wait ( [](const boost::system::error_code& ecode) @@ -515,30 +466,30 @@ namespace client void I2PControlService::ReseedHandler (std::ostringstream& results) { - LogPrint (eLogInfo, "Reseed requested"); - InsertParam (results, I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN, ""); + LogPrint (eLogInfo, "I2PControl: Reseed requested"); + InsertParam (results, "Reseed", ""); i2p::data::netdb.Reseed (); } // network setting void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results) { - LogPrint (eLogDebug, "I2PControl NetworkSetting"); for (auto it = params.begin (); it != params.end (); it++) { - if (it != params.begin ()) results << ","; - LogPrint (eLogDebug, it->first); + if (it != params.begin ()) results << ","; + LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first); auto it1 = m_NetworkSettingHandlers.find (it->first); - if (it1 != m_NetworkSettingHandlers.end ()) - (this->*(it1->second))(it->second.data (), results); - else - LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it->first); + if (it1 != m_NetworkSettingHandlers.end ()) { + (this->*(it1->second))(it->second.data (), results); + } else + LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first); } } - // certificate - void I2PControlService::CreateCertificate () + // certificate + void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path) { + FILE *f = NULL; EVP_PKEY * pkey = EVP_PKEY_new (); RSA * rsa = RSA_new (); BIGNUM * e = BN_dup (i2p::crypto::GetRSAE ()); @@ -558,34 +509,30 @@ namespace client X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name X509_set_issuer_name (x509, name); // set issuer to ourselves X509_sign (x509, pkey, EVP_sha1 ()); // sign - // save key and certificate - // keys - auto filename = GetPath () / I2P_CONTROL_KEY_FILE; - FILE * f= fopen (filename.string ().c_str (), "wb"); - if (f) - { - PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL); + + // save cert + if ((f = fopen (crt_path, "wb")) != NULL) { + LogPrint (eLogInfo, "I2PControl: saving new cert to ", crt_path); + PEM_write_X509 (f, x509); fclose (f); + } else { + LogPrint (eLogError, "I2PControl: can't write cert: ", strerror(errno)); } - else - LogPrint (eLogError, "Can't open file ", filename); - // certificate - filename = GetPath () / I2P_CONTROL_CERT_FILE; - f= fopen (filename.string ().c_str (), "wb"); - if (f) - { - PEM_write_X509 (f, x509); + + // save key + if ((f = fopen (key_path, "wb")) != NULL) { + LogPrint (eLogInfo, "I2PControl: saving cert key to : ", key_path); + PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL); fclose (f); + } else { + LogPrint (eLogError, "I2PControl: can't write key: ", strerror(errno)); } - else - LogPrint (eLogError, "Can't open file ", filename); X509_free (x509); + } else { + LogPrint (eLogError, "I2PControl: can't create RSA key for certificate"); } - else - LogPrint (eLogError, "Couldn't create RSA key for certificate"); EVP_PKEY_free (pkey); } - } } diff --git a/I2PControl.h b/I2PControl.h index e6114968..18592068 100644 --- a/I2PControl.h +++ b/I2PControl.h @@ -22,56 +22,6 @@ namespace client const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024; typedef std::array I2PControlBuffer; - const char I2P_CONTROL_PATH[] = "ipcontrol"; - const char I2P_CONTROL_KEY_FILE[] = "key.pem"; - const char I2P_CONTROL_CERT_FILE[] = "cert.pem"; - const char I2P_CONTROL_CONFIG_FILE[] = "i2pcontrol.conf"; - const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie"; - - const char I2P_CONTROL_PROPERTY_ID[] = "id"; - const char I2P_CONTROL_PROPERTY_METHOD[] = "method"; - const char I2P_CONTROL_PROPERTY_PARAMS[] = "params"; - const char I2P_CONTROL_PROPERTY_RESULT[] = "result"; - - // methods - const char I2P_CONTROL_METHOD_AUTHENTICATE[] = "Authenticate"; - const char I2P_CONTROL_METHOD_ECHO[] = "Echo"; - const char I2P_CONTROL_METHOD_I2PCONTROL[] = "I2PControl"; - const char I2P_CONTROL_METHOD_ROUTER_INFO[] = "RouterInfo"; - const char I2P_CONTROL_METHOD_ROUTER_MANAGER[] = "RouterManager"; - const char I2P_CONTROL_METHOD_NETWORK_SETTING[] = "NetworkSetting"; - - // params - const char I2P_CONTROL_PARAM_API[] = "API"; - const char I2P_CONTROL_PARAM_PASSWORD[] = "Password"; - const char I2P_CONTROL_PARAM_TOKEN[] = "Token"; - const char I2P_CONTROL_PARAM_ECHO[] = "Echo"; - const char I2P_CONTROL_PARAM_RESULT[] = "Result"; - - // I2PControl - const char I2P_CONTROL_I2PCONTROL_ADDRESS[] = "i2pcontrol.address"; - const char I2P_CONTROL_I2PCONTROL_PASSWORD[] = "i2pcontrol.password"; - const char I2P_CONTROL_I2PCONTROL_PORT[] = "i2pcontrol.port"; - - // RouterInfo requests - const char I2P_CONTROL_ROUTER_INFO_UPTIME[] = "i2p.router.uptime"; - const char I2P_CONTROL_ROUTER_INFO_VERSION[] = "i2p.router.version"; - const char I2P_CONTROL_ROUTER_INFO_STATUS[] = "i2p.router.status"; - const char I2P_CONTROL_ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers"; - const char I2P_CONTROL_ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers"; - const char I2P_CONTROL_ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status"; - const char I2P_CONTROL_ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating"; - const char I2P_CONTROL_ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s"; - const char I2P_CONTROL_ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s"; - const char I2P_CONTROL_ROUTER_INFO_NET_TOTAL_RB[] = "i2p.router.net.total.received.bytes"; - const char I2P_CONTROL_ROUTER_INFO_NET_TOTAL_SB[] = "i2p.router.net.total.sent.bytes"; - - // RouterManager requests - const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN[] = "Shutdown"; - const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful"; - const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed"; - - // Certificate const long I2P_CONTROL_CERTIFICATE_VALIDITY = 365*10; // 10 years const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol"; const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P"; @@ -89,9 +39,6 @@ namespace client private: - void LoadConfig (); - void SaveConfig (); - void Run (); void Accept (); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); @@ -105,9 +52,8 @@ namespace client void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::shared_ptr socket, std::shared_ptr buf); - boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir() / I2P_CONTROL_PATH; }; - void CreateCertificate (); - + boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir(); }; + void CreateCertificate (const char *crt_path, const char *key_path); private: diff --git a/RouterContext.cpp b/RouterContext.cpp index 75406daf..7b793d64 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -1,5 +1,6 @@ #include #include +#include "Config.h" #include "Crypto.h" #include "Timestamp.h" #include "I2NPProtocol.h" @@ -43,11 +44,12 @@ namespace i2p { i2p::data::RouterInfo routerInfo; routerInfo.SetRouterIdentity (GetIdentity ()); - int port = i2p::util::config::GetArg("-port", 0); + uint16_t port; i2p::config::GetOption("port", port); if (!port) port = rand () % (30777 - 9111) + 9111; // I2P network ports range - routerInfo.AddSSUAddress (i2p::util::config::GetArg("-host", "127.0.0.1").c_str (), port, routerInfo.GetIdentHash ()); - routerInfo.AddNTCPAddress (i2p::util::config::GetArg("-host", "127.0.0.1").c_str (), port); + std::string host; i2p::config::GetOption("host", host); + routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); + routerInfo.AddNTCPAddress (host.c_str(), port); routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC routerInfo.SetProperty ("netId", std::to_string (I2PD_NET_ID)); diff --git a/api.cpp b/api.cpp index 9a9c5c46..cd527550 100644 --- a/api.cpp +++ b/api.cpp @@ -1,5 +1,6 @@ #include #include +#include "Config.h" #include "Log.h" #include "NetDb.h" #include "Transports.h" @@ -18,7 +19,9 @@ namespace api void InitI2P (int argc, char* argv[], const char * appName) { i2p::util::filesystem::SetAppName (appName); - i2p::util::config::OptionParser(argc, argv); + i2p::config::Init (); + i2p::config::ParseCmdline (argc, argv); + i2p::config::Finalize (); i2p::crypto::InitCrypto (); i2p::context.Init (); } diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index cbcfc275..71ce57ad 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -17,6 +17,7 @@ set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" ) set ( CMAKE_SOURCE_DIR ".." ) set (LIBI2PD_SRC + "${CMAKE_SOURCE_DIR}/Config.cpp" "${CMAKE_SOURCE_DIR}/Crypto.cpp" "${CMAKE_SOURCE_DIR}/Garlic.cpp" "${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp" diff --git a/debian/i2pd.conf b/debian/i2pd.conf index a6e9c23f..4a518916 100644 --- a/debian/i2pd.conf +++ b/debian/i2pd.conf @@ -1,16 +1,19 @@ -floodfill=0 -v6=0 +ipv6 -httpproxyaddress=127.0.0.1 -httpproxyport=4444 +[httpproxy] +address = 127.0.0.1 +port = 4444 # other services (disabled by default) # -# samaddress=127.0.0.1 -# samport=7656 +#[sam] +#address = 127.0.0.1 +#port = 7656 # -# bobaddress=127.0.0.1 -# bobport=2827 +#[bob] +#address = 127.0.0.1 +#port = 2827 # -# i2pcontroladdress=127.0.0.1 -# i2pcontrolport=7650 +#[i2pcontrol] +#address = 127.0.0.1 +#port = 7650 diff --git a/debian/i2pd.init b/debian/i2pd.init index 609a3407..d87aa000 100644 --- a/debian/i2pd.init +++ b/debian/i2pd.init @@ -46,7 +46,7 @@ do_start() start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" --test > /dev/null \ || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" -- \ - --service=1 --daemon=1 --log=1 --conf=$I2PCONF --tunnelscfg=$TUNCONF \ + --service --daemon --log --conf=$I2PCONF --tunconf=$TUNCONF \ --port=$I2PD_PORT $DAEMON_OPTS > /dev/null 2>&1 \ || return 2 return $? diff --git a/debian/i2pd.upstart b/debian/i2pd.upstart index 0527935d..d1536ea3 100644 --- a/debian/i2pd.upstart +++ b/debian/i2pd.upstart @@ -4,7 +4,7 @@ start on runlevel [2345] stop on runlevel [016] or unmounting-filesystem # these can be overridden in /etc/init/i2pd.override -env I2P_HOST="1.2.3.4" -env I2P_PORT="4567" +env I2PD_HOST="1.2.3.4" +env I2PD_PORT="4567" -exec /usr/sbin/i2pd --daemon=0 --log=1 --host=$I2P_HOST --port=$I2P_PORT +exec /usr/sbin/i2pd --daemon --log --host=$I2PD_HOST --port=$I2PD_PORT diff --git a/debian/postinst b/debian/postinst index 4be6bf3f..1de58c1e 100755 --- a/debian/postinst +++ b/debian/postinst @@ -1,6 +1,7 @@ #!/bin/sh set -e +LOGFILE='/var/log/i2pd.log' I2PDHOME='/var/lib/i2pd' I2PDUSER='i2pd' @@ -16,8 +17,9 @@ case "$1" in adduser --system --quiet --group --home $I2PDHOME $I2PDUSER fi - touch /var/log/i2pd.log - chown -f ${I2PDUSER}:adm /var/log/i2pd.log + touch $LOGFILE + chmod 640 $LOGFILE + chown -f ${I2PDUSER}:adm $LOGFILE mkdir -p -m0750 $I2PDHOME chown -f -R -P ${I2PDUSER}:${I2PDUSER} ${I2PDHOME} ;; diff --git a/docs/config_opts_after_2.3.0.md b/docs/config_opts_after_2.3.0.md new file mode 100644 index 00000000..1b2adcdb --- /dev/null +++ b/docs/config_opts_after_2.3.0.md @@ -0,0 +1,43 @@ +Изменения обработки параметров в релизах > 2.3.0 +------------------------------------------------ + +Система параметров отличается от того, что было ранее и достаточно сильно: + +* изменения имён и стиля параметров + +Все параметры теперь в виде --help (gnu-style), у некоторых есть шорткаты в виде -h (unix-style). +Это касается всех систем, в том числе винды. + +--daemon=1 и подобное -> просто --daemon, без параметра. Нет опции - false, есть - true +--notransit=1 -> --notransit, то же что и выше: есть опция - false, нет - true +--v6 -> --ipv6 (первое было похоже на версию какого-то своего протокола, типа socksproxy --v5) +--tunnelscfg -> --tunconf (имя параметра было слишком длинным, cfg переделан на conf - единообразно с --conf) +--sockskeys -> разделён на два, для socks и httpproxy по-отдельности + +* поддержка секций в основном конфиге + +Выглядит это так: + + # основные опции + pidfile = /var/run/i2pd.pid + # + # настройки конкретного модуля + [httproxy] + address = 1.2.3.4 + port = 4446 + keys = httproxy-keys.dat + # и так далее + [sam] + enabled = no + addresss = 127.0.0.2 + # ^^ переопределяется только адрес, остальное берётся из дефолта + +Точно так же сейчас работает конфиг туннелей: секция до точки - имя, после - параметр + +* поддержка выключения отдельных сервисов "на корню" см sam.enabled и подобное + +Это позволило задать дефолт для номера порта и не писать его руками для включения. + +* добавлен --help (см #110) + +* присутствует некая валидация параметров, --port=abcd - не прокатит, --port=100500 - тоже diff --git a/docs/configuration.md b/docs/configuration.md index 4fbdd559..56d57bc1 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -4,46 +4,68 @@ i2pd configuration Command line options -------------------- -* --port= - The port to listen on -* --httpaddress= - The address to listen on (HTTP server) -* --httpport= - The port to listen on (HTTP server) -* --loglevel= - Log messages above this level (debug, *info, warn, error) -* --pidfile= - Where to write pidfile (dont write by default) -* --daemon= - Enable or disable daemon mode. 1 for yes, 0 for no. 0 by default -* --log= - Enable or disable logging to the file. 1 for daemon, 0 for non-daemon by default -* --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove") -* --service= - 1 if uses system folders (/var/run/i2pd.pid, /var/log/i2pd/i2pd.log, /var/lib/i2pd). -* --v6= - 1 if supports communication through ipv6, off by default -* --floodfill= - 1 if router is floodfill, off by default -* --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited -* --notransit= - 1 if router doesn't accept transit tunnels at startup. 0 by default -* --httpproxyaddress= - The address to listen on (HTTP Proxy) -* --httpproxyport= - The port to listen on (HTTP Proxy) 4446 by default -* --socksproxyaddress= - The address to listen on (SOCKS Proxy) -* --socksproxyport= - The port to listen on (SOCKS Proxy). 4447 by default -* --proxykeys= - optional keys file for proxy local destination (both HTTP and SOCKS) -* --samaddress= - The address to listen on (SAM bridge) -* --samport= - Port of SAM bridge. Usually 7656. SAM is off if not specified -* --bobaddress= - The address to listen on (BOB command channel) -* --bobport= - Port of BOB command channel. Usually 2827. BOB is off if not specified -* --i2pcontroladdress= - The address to listen on (I2P control service) -* --i2pcontrolport= - Port of I2P control service. Usually 7650. I2PControl is off if not specified -* --tunnelscfg= - Tunnels Config file (default: ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg) * --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf) This parameter will be silently ignored if the specified config file does not exist. Options specified on the command line take precedence over those in the config file. +* --tunconf= - Tunnels Config file (default: ~/.i2pd/tunnels.cfg or /var/lib/i2pd/tunnels.cfg) +* --pidfile= - Where to write pidfile (dont write by default) +* --log - Enable or disable logging to file. 1 for yes, 0 for no. +* --logfile= - Path to logfile (stdout if not set, autodetect if daemon) +* --loglevel= - Log messages above this level (debug, *info, warn, error) +* --host= - The external IP (deprecated) +* --port= - The port to listen on +* --daemon - Enable or disable daemon mode. 1 for yes, 0 for no. +* --svcctl= - Windows service management (--svcctl="install" or --svcctl="remove") +* --service - Use system folders (/var/run/i2pd.pid, /var/log/i2pd.log, /var/lib/i2pd). +* --ipv6 - Enable communication through ipv6, off by default +* --notransit - Router will not accept transit tunnels at startup. 0 by default +* --floodfill - Router will be floodfill, off by default +* --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O - to 256Kbs/sec, P - unlimited + This option will be ignored if --floodfill given + +* --http.address= - The address to listen on (HTTP server) +* --http.port= - The port to listen on (HTTP server) + +* --httpproxy.address= - The address to listen on (HTTP Proxy) +* --httpproxy.port= - The port to listen on (HTTP Proxy) 4446 by default +* --httpproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS) + +* --socksproxy.address= - The address to listen on (SOCKS Proxy) +* --socksproxy.port= - The port to listen on (SOCKS Proxy). 4447 by default +* --socksproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS) +* --socksproxy.outproxy= - Address of outproxy. requests outside i2p will go there +* --socksproxy.outproxyport= - Outproxy remote port + +* --sam.address= - The address to listen on (SAM bridge) +* --sam.port= - Port of SAM bridge. Usually 7656. SAM is off if not specified + +* --bob.address= - The address to listen on (BOB command channel) +* --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified + +* --i2pcontrol.address= - The address to listen on (I2P control service) +* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified Config files ------------ INI-like, syntax is the following : = . Comments are "#", not ";" as you may expect. See [boost ticket](https://svn.boost.org/trac/boost/ticket/808) -All command-line parameters are allowed as keys, for example: +All command-line parameters are allowed as keys, but note for those which contains dot (.). + +For example: i2p.conf: - log = 1 - v6 = 0 + # comment + log = yes + ipv6 = yes + # settings for specific module + [httpproxy] + port = 4444 + # ^^ this will be --httproxy.port= in cmdline + # another one + [sam] + enabled = yes tunnels.cfg (filename of this config is subject of change): diff --git a/filelist.mk b/filelist.mk index 147ef259..ce3a12f5 100644 --- a/filelist.mk +++ b/filelist.mk @@ -8,9 +8,9 @@ LIB_SRC = \ LIB_CLIENT_SRC = \ AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \ - SAM.cpp SOCKS.cpp HTTPProxy.cpp + SAM.cpp SOCKS.cpp HTTPProxy.cpp Config.cpp # also: Daemon{Linux,Win32}.cpp will be added later DAEMON_SRC = \ - HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp + HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp Config.cpp i2pd.cpp diff --git a/util.cpp b/util.cpp index e894c44f..1ea5fcd7 100644 --- a/util.cpp +++ b/util.cpp @@ -13,6 +13,7 @@ #include #include #include +#include "Config.h" #include "util.h" #include "Log.h" @@ -66,86 +67,6 @@ namespace i2p { namespace util { - -namespace config -{ - std::map mapArgs; - - void OptionParser(int argc, const char* const argv[]) - { - mapArgs.clear(); - for (int i = 1; i < argc; i++) - { - std::string strKey (argv[i]); - std::string strValue; - size_t has_data = strKey.find('='); - if (has_data != std::string::npos) - { - strValue = strKey.substr(has_data+1); - strKey = strKey.substr(0, has_data); - } - -#ifdef WIN32 - boost::to_lower(strKey); - if (boost::algorithm::starts_with(strKey, "/")) - strKey = "-" + strKey.substr(1); -#endif - if (strKey[0] != '-') - break; - - mapArgs[strKey] = strValue; - } - - BOOST_FOREACH(PAIRTYPE(const std::string,std::string)& entry, mapArgs) - { - std::string name = entry.first; - - // interpret --foo as -foo (as long as both are not set) - if (name.find("--") == 0) - { - std::string singleDash(name.begin()+1, name.end()); - if (mapArgs.count(singleDash) == 0) - mapArgs[singleDash] = entry.second; - name = singleDash; - } - } - } - - std::string GetArg(const std::string& strArg, const std::string& strDefault) - { - if (mapArgs.count(strArg)) - return mapArgs[strArg]; - return strDefault; - } - - int GetArg(const std::string& strArg, int nDefault) - { - if (mapArgs.count(strArg)) - return atoi(mapArgs[strArg].c_str()); - return nDefault; - } - - void ReadConfigFile(boost::filesystem::path path) - { - boost::filesystem::ifstream streamConfig(path); - if (!streamConfig.good()) - return; // No i2pd.conf file is OK - - std::set setOptions; - setOptions.insert("*"); - - for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) - { - // Don't overwrite existing settings so command line settings override i2pd.conf - std::string strKey = std::string("-") + it->string_key; - if (mapArgs.count(strKey) == 0) - { - mapArgs[strKey] = it->value[0]; - } - } - } -} - namespace filesystem { std::string appName ("i2pd"); @@ -166,8 +87,10 @@ namespace filesystem // TODO: datadir parameter is useless because GetDataDir is called before OptionParser // and mapArgs is not initialized yet - /*if (i2p::util::config::mapArgs.count("-datadir")) - path = boost::filesystem::system_complete(i2p::util::config::mapArgs["-datadir"]); + /* + std::string datadir; i2p::config::GetOption("datadir", datadir); + if (datadir != "") + path = boost::filesystem::system_complete(datadir); else */ path = GetDefaultDataDir(); @@ -200,17 +123,34 @@ namespace filesystem boost::filesystem::path GetConfigFile() { - boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf")); - if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir() / pathConfigFile; - return pathConfigFile; + std::string config; i2p::config::GetOption("conf", config); + if (config != "") { + /* config file set with cmdline */ + boost::filesystem::path path(config); + return path; + } + /* else - try autodetect */ + boost::filesystem::path path("i2p.conf"); + path = GetDataDir() / path; + if (!boost::filesystem::exists(path)) + path = ""; /* reset */ + return path; } boost::filesystem::path GetTunnelsConfigFile() { - boost::filesystem::path pathTunnelsConfigFile(i2p::util::config::GetArg("-tunnelscfg", "tunnels.cfg")); - if (!pathTunnelsConfigFile.is_complete()) - pathTunnelsConfigFile = GetDataDir() / pathTunnelsConfigFile; - return pathTunnelsConfigFile; + std::string tunconf; i2p::config::GetOption("tunconf", tunconf); + if (tunconf != "") { + /* config file set with cmdline */ + boost::filesystem::path path(tunconf); + return path; + } + /* else - try autodetect */ + boost::filesystem::path path("tunnels.cfg"); + path = GetDataDir() / path; + if (!boost::filesystem::exists(path)) + path = ""; /* reset */ + return path; } boost::filesystem::path GetDefaultDataDir() @@ -225,7 +165,8 @@ namespace filesystem SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData); return boost::filesystem::path(std::string(localAppData) + "\\" + appName); #else /* UNIX */ - if (i2p::util::config::GetArg("-service", 0)) // use system folder + bool service; i2p::config::GetOption("service", service); + if (service) // use system folder return boost::filesystem::path(std::string ("/var/lib/") + appName); boost::filesystem::path pathRet; char* pszHome = getenv("HOME"); diff --git a/util.h b/util.h index 905c2a8d..0377ef8d 100644 --- a/util.h +++ b/util.h @@ -14,14 +14,6 @@ namespace i2p { namespace util { - namespace config - { - void OptionParser(int argc, const char* const argv[]); - int GetArg(const std::string& strArg, int nDefault); - std::string GetArg(const std::string& strArg, const std::string& strDefault); - void ReadConfigFile(boost::filesystem::path path); - } - namespace filesystem { void SetAppName (const std::string& name);