diff --git a/Makefile b/Makefile index 240e4a3b..b5739c46 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transpor obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \ obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o INCFLAGS = -LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lpthread +LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LIBS = all: obj i2p diff --git a/i2p.cpp b/i2p.cpp index 5c0bd378..aed38cd0 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "Log.h" #include "base64.h" #include "Transports.h" @@ -14,7 +15,7 @@ int main( int argc, char* argv[] ) { - i2p::util::OptionParser(argc,argv); + i2p::util::config::OptionParser(argc,argv); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -22,10 +23,15 @@ int main( int argc, char* argv[] ) setlocale(LC_ALL, "Russian"); #endif + LogPrint("\n\n\n\ni2pd starting\n"); + LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string()); + i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs); + //TODO: This is an ugly workaround. fix it. //TODO: Autodetect public IP. - i2p::context.OverrideNTCPAddress(i2p::util::GetCharArg("--host", "127.0.0.1"), i2p::util::GetIntArg("--port", 17070)); - int httpport = i2p::util::GetIntArg("--httpport", 7070); + i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"), + i2p::util::config::GetArg("-port", 17070)); + int httpport = i2p::util::config::GetArg("-httpport", 7070); i2p::util::HTTPServer httpServer (httpport); diff --git a/util.cpp b/util.cpp index a33414ac..e988427c 100644 --- a/util.cpp +++ b/util.cpp @@ -3,7 +3,13 @@ #include #include #include +#include #include +#include +#include +#include +#include +#include #include "util.h" #include "Log.h" @@ -11,40 +17,160 @@ namespace i2p { namespace util { -std::map mapArgs; -void OptionParser(int argc, const char* const argv[]) +namespace config { - 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); - } - if (strKey[0] != '-') - break; - - mapArgs[strKey] = strValue; - } -} + std::map mapArgs; + std::map > mapMultiArgs; -int GetIntArg(const std::string& strArg, int nDefault) -{ - if (mapArgs.count(strArg)) - return atoi(mapArgs[strArg].c_str()); - return nDefault; + void OptionParser(int argc, const char* const argv[]) + { + mapArgs.clear(); + mapMultiArgs.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; + mapMultiArgs[strKey].push_back(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; + } + } + } + + const char* GetCharArg(const std::string& strArg, const std::string& nDefault) + { + if (mapArgs.count(strArg)) + return mapArgs[strArg].c_str(); + return nDefault.c_str(); + } + + 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; + } } -const char* GetCharArg(const std::string& strArg, const std::string& nDefault) +namespace filesystem { - if (mapArgs.count(strArg)) - return mapArgs[strArg].c_str(); - return nDefault.c_str(); + const boost::filesystem::path &GetDataDir() + { + + static boost::filesystem::path path; + + if (i2p::util::config::mapArgs.count("-datadir")) { + path = boost::filesystem::system_complete(i2p::util::config::mapArgs["-datadir"]); + } else { + path = GetDefaultDataDir(); + } + + if (!boost::filesystem::exists( path )) + { + // Create data directory + if (!boost::filesystem::create_directory( path )) + { + LogPrint("Failed to create data directory!"); + return ""; + } + } + if (!boost::filesystem::is_directory(path)) { + path = GetDefaultDataDir(); + } + return path; + } + + boost::filesystem::path GetConfigFile() + { + boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf")); + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir() / pathConfigFile; + return pathConfigFile; + } + + void ReadConfigFile(std::map& mapSettingsRet, + std::map >& mapMultiSettingsRet) + { + boost::filesystem::ifstream streamConfig(GetConfigFile()); + 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 (mapSettingsRet.count(strKey) == 0) + { + mapSettingsRet[strKey] = it->value[0]; + } + mapMultiSettingsRet[strKey].push_back(it->value[0]); + } + } + + boost::filesystem::path GetDefaultDataDir() + { + // Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd + // Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd + // Mac: ~/Library/Application Support/i2pd + // Unix: ~/.i2pd +#ifdef WIN32 + // Windows + return GetSpecialFolderPath(CSIDL_APPDATA) / "i2pd"; +#else + boost::filesystem::path pathRet; + char* pszHome = getenv("HOME"); + if (pszHome == NULL || strlen(pszHome) == 0) + pathRet = boost::filesystem::path("/"); + else + pathRet = boost::filesystem::path(pszHome); +#ifdef MAC_OSX + // Mac + pathRet /= "Library/Application Support"; + boost::filesystem::create_directory(pathRet); + return pathRet / "i2pd"; +#else + // Unix + return pathRet / ".i2pd"; +#endif +#endif + } } namespace http @@ -102,26 +228,26 @@ namespace http void url::parse(const std::string& url_s) { - const std::string prot_end("://"); - std::string::const_iterator prot_i = search(url_s.begin(), url_s.end(), - prot_end.begin(), prot_end.end()); - protocol_.reserve(distance(url_s.begin(), prot_i)); - transform(url_s.begin(), prot_i, - back_inserter(protocol_), - std::ptr_fun(tolower)); // protocol is icase - if( prot_i == url_s.end() ) - return; - advance(prot_i, prot_end.length()); - std::string::const_iterator path_i = find(prot_i, url_s.end(), '/'); - host_.reserve(distance(prot_i, path_i)); - transform(prot_i, path_i, - back_inserter(host_), - std::ptr_fun(tolower)); // host is icase - std::string::const_iterator query_i = find(path_i, url_s.end(), '?'); - path_.assign(path_i, query_i); - if( query_i != url_s.end() ) - ++query_i; - query_.assign(query_i, url_s.end()); + const std::string prot_end("://"); + std::string::const_iterator prot_i = search(url_s.begin(), url_s.end(), + prot_end.begin(), prot_end.end()); + protocol_.reserve(distance(url_s.begin(), prot_i)); + transform(url_s.begin(), prot_i, + back_inserter(protocol_), + std::ptr_fun(tolower)); // protocol is icase + if( prot_i == url_s.end() ) + return; + advance(prot_i, prot_end.length()); + std::string::const_iterator path_i = find(prot_i, url_s.end(), '/'); + host_.reserve(distance(prot_i, path_i)); + transform(prot_i, path_i, + back_inserter(host_), + std::ptr_fun(tolower)); // host is icase + std::string::const_iterator query_i = find(path_i, url_s.end(), '?'); + path_.assign(path_i, query_i); + if( query_i != url_s.end() ) + ++query_i; + query_.assign(query_i, url_s.end()); } } diff --git a/util.h b/util.h index 7643e0d0..7090294f 100644 --- a/util.h +++ b/util.h @@ -4,14 +4,31 @@ #include #include +#define PAIRTYPE(t1, t2) std::pair + namespace i2p { namespace util { - extern std::map mapArgs; - void OptionParser(int argc, const char* const argv[]); - int GetIntArg(const std::string& strArg, int nDefault); - const char* GetCharArg(const std::string& strArg, const std::string& nDefault); + namespace config + { + extern std::map mapArgs; + extern std::map > mapMultiArgs; + 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); + const char* GetCharArg(const std::string& strArg, const std::string& nDefault); + } + + namespace filesystem + { + const boost::filesystem::path &GetDataDir(); + boost::filesystem::path GetDefaultDataDir(); + boost::filesystem::path GetConfigFile(); + void ReadConfigFile(std::map& mapSettingsRet, + std::map >& mapMultiSettingsRet); + } + namespace http { std::string httpRequest(const std::string& address);