diff options
| author | langerhans <[email protected]> | 2019-06-09 19:49:48 +0200 |
|---|---|---|
| committer | langerhans <[email protected]> | 2019-06-09 19:51:03 +0200 |
| commit | d278efaccdc45e7155147d2c86a50f193eafdc07 (patch) | |
| tree | 05cf92afa059fafff80e460c1619edd5bec231b3 /src/util.cpp | |
| parent | Revert "Change fPIE to fPIC (#1420)" (#1447) (diff) | |
| parent | Mark 1.14 ready for release (diff) | |
| download | discoin-d278efaccdc45e7155147d2c86a50f193eafdc07.tar.xz discoin-d278efaccdc45e7155147d2c86a50f193eafdc07.zip | |
Merge branch '1.14-branding'
Diffstat (limited to 'src/util.cpp')
| -rw-r--r-- | src/util.cpp | 357 |
1 files changed, 227 insertions, 130 deletions
diff --git a/src/util.cpp b/src/util.cpp index ae948c19f..2cf6a3279 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -72,6 +72,10 @@ #include <sys/prctl.h> #endif +#ifdef HAVE_MALLOPT_ARENA_MAX +#include <malloc.h> +#endif + #include <boost/algorithm/string/case_conv.hpp> // for to_lower() #include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith() @@ -83,6 +87,7 @@ #include <boost/thread.hpp> #include <openssl/crypto.h> #include <openssl/rand.h> +#include <openssl/conf.h> // Work around clang compilation problem in Boost 1.46: // /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup @@ -98,24 +103,26 @@ namespace boost { using namespace std; +const char * const BITCOIN_CONF_FILENAME = "dogecoin.conf"; +const char * const BITCOIN_PID_FILENAME = "dogecoind.pid"; + +CCriticalSection cs_args; map<string, string> mapArgs; -map<string, vector<string> > mapMultiArgs; +static map<string, vector<string> > _mapMultiArgs; +const map<string, vector<string> >& mapMultiArgs = _mapMultiArgs; bool fDebug = false; bool fPrintToConsole = false; bool fPrintToDebugLog = true; -bool fDaemon = false; -bool fServer = false; -string strMiscWarning; - -bool fBloomFilters = true; -bool fLogTimestamps = false; -bool fLogIPs = false; -volatile bool fReopenDebugLog = false; + +bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; +bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; +bool fLogIPs = DEFAULT_LOGIPS; +std::atomic<bool> fReopenDebugLog(false); CTranslationInterface translationInterface; /** Init OpenSSL library multithreading support */ static CCriticalSection** ppmutexOpenSSL; -void locking_callback(int mode, int i, const char* file, int line) +void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS { if (mode & CRYPTO_LOCK) { ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]); @@ -136,6 +143,13 @@ public: ppmutexOpenSSL[i] = new CCriticalSection(); CRYPTO_set_locking_callback(locking_callback); + // OpenSSL can optionally load a config file which lists optional loadable modules and engines. + // We don't use them so we don't require the config. However some of our libs may call functions + // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing + // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be + // that the config appears to have been loaded and there are no modules/engines available. + OPENSSL_no_config(); + #ifdef WIN32 // Seed OpenSSL PRNG with current contents of the screen RAND_screen(); @@ -169,23 +183,52 @@ instance_of_cinit; */ static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; + /** - * We use boost::call_once() to make sure these are initialized - * in a thread-safe manner the first time called: + * We use boost::call_once() to make sure mutexDebugLog and + * vMsgsBeforeOpenLog are initialized in a thread-safe manner. + * + * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog + * are leaked on exit. This is ugly, but will be cleaned up by + * the OS/libc. When the shutdown sequence is fully audited and + * tested, explicit destruction of these objects can be implemented. */ static FILE* fileout = NULL; static boost::mutex* mutexDebugLog = NULL; +static list<string> *vMsgsBeforeOpenLog; + +static int FileWriteStr(const std::string &str, FILE *fp) +{ + return fwrite(str.data(), 1, str.size(), fp); +} static void DebugPrintInit() { - assert(fileout == NULL); assert(mutexDebugLog == NULL); + mutexDebugLog = new boost::mutex(); + vMsgsBeforeOpenLog = new list<string>; +} +void OpenDebugLog() +{ + boost::call_once(&DebugPrintInit, debugPrintInitFlag); + boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); + + assert(fileout == NULL); + assert(vMsgsBeforeOpenLog); boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; fileout = fopen(pathDebug.string().c_str(), "a"); - if (fileout) setbuf(fileout, NULL); // unbuffered + if (fileout) { + setbuf(fileout, NULL); // unbuffered + // dump buffered messages from before we opened the log + while (!vMsgsBeforeOpenLog->empty()) { + FileWriteStr(vMsgsBeforeOpenLog->front(), fileout); + vMsgsBeforeOpenLog->pop_front(); + } + } - mutexDebugLog = new boost::mutex(); + delete vMsgsBeforeOpenLog; + vMsgsBeforeOpenLog = NULL; } bool LogAcceptCategory(const char* category) @@ -202,80 +245,116 @@ bool LogAcceptCategory(const char* category) static boost::thread_specific_ptr<set<string> > ptrCategory; if (ptrCategory.get() == NULL) { - const vector<string>& categories = mapMultiArgs["-debug"]; - ptrCategory.reset(new set<string>(categories.begin(), categories.end())); - // thread_specific_ptr automatically deletes the set when the thread ends. + if (mapMultiArgs.count("-debug")) { + const vector<string>& categories = mapMultiArgs.at("-debug"); + ptrCategory.reset(new set<string>(categories.begin(), categories.end())); + // thread_specific_ptr automatically deletes the set when the thread ends. + } else + ptrCategory.reset(new set<string>()); } const set<string>& setCategories = *ptrCategory.get(); // if not debugging everything and not debugging specific category, LogPrint does nothing. if (setCategories.count(string("")) == 0 && + setCategories.count(string("1")) == 0 && setCategories.count(string(category)) == 0) return false; } return true; } +/** + * fStartedNewLine is a state variable held by the calling context that will + * suppress printing of the timestamp when multiple calls are made that don't + * end in a newline. Initialize it to true, and hold it, in the calling context. + */ +static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine) +{ + string strStamped; + + if (!fLogTimestamps) + return str; + + if (*fStartedNewLine) { + int64_t nTimeMicros = GetLogTimeMicros(); + strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros/1000000); + if (fLogTimeMicros) + strStamped += strprintf(".%06d", nTimeMicros%1000000); + strStamped += ' ' + str; + } else + strStamped = str; + + if (!str.empty() && str[str.size()-1] == '\n') + *fStartedNewLine = true; + else + *fStartedNewLine = false; + + return strStamped; +} + int LogPrintStr(const std::string &str) { int ret = 0; // Returns total number of characters written + static std::atomic_bool fStartedNewLine(true); + + string strTimestamped = LogTimestampStr(str, &fStartedNewLine); + if (fPrintToConsole) { // print to console - ret = fwrite(str.data(), 1, str.size(), stdout); + ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout); fflush(stdout); } - else if (fPrintToDebugLog && AreBaseParamsConfigured()) + else if (fPrintToDebugLog) { - static bool fStartedNewLine = true; boost::call_once(&DebugPrintInit, debugPrintInitFlag); - - if (fileout == NULL) - return ret; - boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); - // reopen the log file, if requested - if (fReopenDebugLog) { - fReopenDebugLog = false; - boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; - if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) - setbuf(fileout, NULL); // unbuffered + // buffer if we haven't opened the log yet + if (fileout == NULL) { + assert(vMsgsBeforeOpenLog); + ret = strTimestamped.length(); + vMsgsBeforeOpenLog->push_back(strTimestamped); } - - // Debug print useful for profiling - if (fLogTimestamps && fStartedNewLine) - ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); - if (!str.empty() && str[str.size()-1] == '\n') - fStartedNewLine = true; else - fStartedNewLine = false; - - ret = fwrite(str.data(), 1, str.size(), fileout); + { + // reopen the log file, if requested + if (fReopenDebugLog) { + fReopenDebugLog = false; + boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) + setbuf(fileout, NULL); // unbuffered + } + + ret = FileWriteStr(strTimestamped, fileout); + } } - return ret; } -static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet) +/** Interpret string as boolean, for argument parsing */ +static bool InterpretBool(const std::string& strValue) +{ + if (strValue.empty()) + return true; + return (atoi(strValue) != 0); +} + +/** Turn -noX into -X=0 */ +static void InterpretNegativeSetting(std::string& strKey, std::string& strValue) { - // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set - if (name.find("-no") == 0) + if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o') { - std::string positive("-"); - positive.append(name.begin()+3, name.end()); - if (mapSettingsRet.count(positive) == 0) - { - bool value = !GetBoolArg(name, false); - mapSettingsRet[positive] = (value ? "1" : "0"); - } + strKey = "-" + strKey.substr(3); + strValue = InterpretBool(strValue) ? "0" : "1"; } } void ParseParameters(int argc, const char* const argv[]) { + LOCK(cs_args); mapArgs.clear(); - mapMultiArgs.clear(); + _mapMultiArgs.clear(); for (int i = 1; i < argc; i++) { @@ -300,21 +379,22 @@ void ParseParameters(int argc, const char* const argv[]) // If both --foo and -foo are set, the last takes effect. if (str.length() > 1 && str[1] == '-') str = str.substr(1); + InterpretNegativeSetting(str, strValue); mapArgs[str] = strValue; - mapMultiArgs[str].push_back(strValue); + _mapMultiArgs[str].push_back(strValue); } +} - // New 0.6 features: - BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs) - { - // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set - InterpretNegativeSetting(entry.first, mapArgs); - } +bool IsArgSet(const std::string& strArg) +{ + LOCK(cs_args); + return mapArgs.count(strArg); } std::string GetArg(const std::string& strArg, const std::string& strDefault) { + LOCK(cs_args); if (mapArgs.count(strArg)) return mapArgs[strArg]; return strDefault; @@ -322,6 +402,7 @@ std::string GetArg(const std::string& strArg, const std::string& strDefault) int64_t GetArg(const std::string& strArg, int64_t nDefault) { + LOCK(cs_args); if (mapArgs.count(strArg)) return atoi64(mapArgs[strArg]); return nDefault; @@ -329,17 +410,15 @@ int64_t GetArg(const std::string& strArg, int64_t nDefault) bool GetBoolArg(const std::string& strArg, bool fDefault) { + LOCK(cs_args); if (mapArgs.count(strArg)) - { - if (mapArgs[strArg].empty()) - return true; - return (atoi(mapArgs[strArg]) != 0); - } + return InterpretBool(mapArgs[strArg]); return fDefault; } bool SoftSetArg(const std::string& strArg, const std::string& strValue) { + LOCK(cs_args); if (mapArgs.count(strArg)) return false; mapArgs[strArg] = strValue; @@ -354,6 +433,14 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue) return SoftSetArg(strArg, std::string("0")); } +void ForceSetArg(const std::string& strArg, const std::string& strValue) +{ + LOCK(cs_args); + mapArgs[strArg] = strValue; +} + + + static const int screenWidth = 79; static const int optIndent = 2; static const int msgIndent = 7; @@ -390,7 +477,6 @@ void PrintExceptionContinue(const std::exception* pex, const char* pszThread) std::string message = FormatException(pex, pszThread); LogPrintf("\n\n************************\n%s\n", message); fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); - strMiscWarning = message; } boost::filesystem::path GetDefaultDataDir() @@ -412,9 +498,7 @@ boost::filesystem::path GetDefaultDataDir() pathRet = fs::path(pszHome); #ifdef MAC_OSX // Mac - pathRet /= "Library/Application Support"; - TryCreateDirectory(pathRet); - return pathRet / "Dogecoin"; + return pathRet / "Library/Application Support/Dogecoin"; #else // Unix return pathRet / ".dogecoin"; @@ -439,8 +523,8 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) if (!path.empty()) return path; - if (mapArgs.count("-datadir")) { - path = fs::system_complete(mapArgs["-datadir"]); + if (IsArgSet("-datadir")) { + path = fs::system_complete(GetArg("-datadir", "")); if (!fs::is_directory(path)) { path = ""; return path; @@ -458,40 +542,42 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) void ClearDatadirCache() { + LOCK(csPathCached); + pathCached = boost::filesystem::path(); pathCachedNetSpecific = boost::filesystem::path(); } -boost::filesystem::path GetConfigFile() +boost::filesystem::path GetConfigFile(const std::string& confPath) { - boost::filesystem::path pathConfigFile(GetArg("-conf", "dogecoin.conf")); + boost::filesystem::path pathConfigFile(confPath); if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; return pathConfigFile; } -void ReadConfigFile(map<string, string>& mapSettingsRet, - map<string, vector<string> >& mapMultiSettingsRet) +void ReadConfigFile(const std::string& confPath) { - boost::filesystem::ifstream streamConfig(GetConfigFile()); + boost::filesystem::ifstream streamConfig(GetConfigFile(confPath)); if (!streamConfig.good()) return; // No bitcoin.conf file is OK - set<string> 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 bitcoin.conf - string strKey = string("-") + it->string_key; - if (mapSettingsRet.count(strKey) == 0) + LOCK(cs_args); + set<string> setOptions; + setOptions.insert("*"); + + for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) { - mapSettingsRet[strKey] = it->value[0]; - // interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set) - InterpretNegativeSetting(strKey, mapSettingsRet); + // Don't overwrite existing settings so command line settings override bitcoin.conf + string strKey = string("-") + it->string_key; + string strValue = it->value[0]; + InterpretNegativeSetting(strKey, strValue); + if (mapArgs.count(strKey) == 0) + mapArgs[strKey] = strValue; + _mapMultiArgs[strKey].push_back(strValue); } - mapMultiSettingsRet[strKey].push_back(it->value[0]); } // If datadir is changed in .conf file: ClearDatadirCache(); @@ -500,7 +586,7 @@ void ReadConfigFile(map<string, string>& mapSettingsRet, #ifndef WIN32 boost::filesystem::path GetPidFile() { - boost::filesystem::path pathPidFile(GetArg("-pid", "dogecoind.pid")); + boost::filesystem::path pathPidFile(GetArg("-pid", BITCOIN_PID_FILENAME)); if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile; return pathPidFile; } @@ -546,19 +632,19 @@ bool TryCreateDirectory(const boost::filesystem::path& p) return false; } -void FileCommit(FILE *fileout) +void FileCommit(FILE *file) { - fflush(fileout); // harmless if redundantly called + fflush(file); // harmless if redundantly called #ifdef WIN32 - HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(fileout)); + HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); FlushFileBuffers(hFile); #else #if defined(__linux__) || defined(__NetBSD__) - fdatasync(fileno(fileout)); + fdatasync(fileno(file)); #elif defined(__APPLE__) && defined(F_FULLFSYNC) - fcntl(fileno(fileout), F_FULLFSYNC, 0); + fcntl(fileno(file), F_FULLFSYNC, 0); #else - fsync(fileno(fileout)); + fsync(fileno(file)); #endif #endif } @@ -642,21 +728,25 @@ void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { void ShrinkDebugFile() { + // Amount of debug.log to save at end when shrinking (must fit in memory) + constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000; // Scroll debug.log if it's getting too big boost::filesystem::path pathLog = GetDataDir() / "debug.log"; FILE* file = fopen(pathLog.string().c_str(), "r"); - if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000) + // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE + // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes + if (file && boost::filesystem::file_size(pathLog) > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10)) { // Restart the file with some of the end - std::vector <char> vch(200000,0); + std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0); fseek(file, -((long)vch.size()), SEEK_END); - int nBytes = fread(begin_ptr(vch), 1, vch.size(), file); + int nBytes = fread(vch.data(), 1, vch.size(), file); fclose(file); file = fopen(pathLog.string().c_str(), "w"); if (file) { - fwrite(begin_ptr(vch), 1, nBytes, file); + fwrite(vch.data(), 1, nBytes, file); fclose(file); } } @@ -681,29 +771,7 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) } #endif -boost::filesystem::path GetTempPath() { -#if BOOST_FILESYSTEM_VERSION == 3 - return boost::filesystem::temp_directory_path(); -#else - // TODO: remove when we don't support filesystem v2 anymore - boost::filesystem::path path; -#ifdef WIN32 - char pszPath[MAX_PATH] = ""; - - if (GetTempPathA(MAX_PATH, pszPath)) - path = boost::filesystem::path(pszPath); -#else - path = boost::filesystem::path("/tmp"); -#endif - if (path.empty() || !boost::filesystem::is_directory(path)) { - LogPrintf("GetTempPath(): failed to find temp path\n"); - return boost::filesystem::path(""); - } - return path; -#endif -} - -void runCommand(std::string strCommand) +void runCommand(const std::string& strCommand) { int nErr = ::system(strCommand.c_str()); if (nErr) @@ -728,6 +796,16 @@ void RenameThread(const char* name) void SetupEnvironment() { +#ifdef HAVE_MALLOPT_ARENA_MAX + // glibc-specific: On 32-bit systems set the number of arenas to 1. + // By default, since glibc 2.10, the C library will create up to two heap + // arenas per core. This is known to cause excessive virtual address space + // usage in our usage. Work around it by setting the maximum number of + // arenas to 1. + if (sizeof(void*) == 4) { + mallopt(M_ARENA_MAX, 1); + } +#endif // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale // may be invalid, in which case the "C" locale is used as fallback. #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) @@ -745,15 +823,34 @@ void SetupEnvironment() boost::filesystem::path::imbue(loc); } -void SetThreadPriority(int nPriority) +bool SetupNetworking() { #ifdef WIN32 - SetThreadPriority(GetCurrentThread(), nPriority); -#else // WIN32 -#ifdef PRIO_THREAD - setpriority(PRIO_THREAD, 0, nPriority); -#else // PRIO_THREAD - setpriority(PRIO_PROCESS, 0, nPriority); -#endif // PRIO_THREAD -#endif // WIN32 + // Initialize Windows Sockets + WSADATA wsadata; + int ret = WSAStartup(MAKEWORD(2,2), &wsadata); + if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2) + return false; +#endif + return true; +} + +int GetNumCores() +{ +#if BOOST_VERSION >= 105600 + return boost::thread::physical_concurrency(); +#else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores + return boost::thread::hardware_concurrency(); +#endif } + +std::string CopyrightHolders(const std::string& strPrefix) +{ + std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION)); + + // Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident + if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) { + strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers"; + } + return strCopyrightHolders; +}
\ No newline at end of file |