X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Futil.cpp;h=5c4755152635d2c61e0aa2707e4bd3009ee4aaf0;hb=7f10522c4316abb9d7dc6c97e48436a22b1a19a1;hp=fb648a97212dc2c859ef1e7688d001f494cd5c0c;hpb=4b603f1cd6a0b8480c15555389077a4b401c2c7b;p=novacoin.git diff --git a/src/util.cpp b/src/util.cpp index fb648a9..5c47551 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,9 +1,10 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "headers.h" #include "strlcpy.h" +#include #include #include #include @@ -30,17 +31,7 @@ string strMiscWarning; bool fTestNet = false; bool fNoListen = false; bool fLogTimestamps = false; - - - - -// Workaround for "multiple definition of `_tls_used'" -// http://svn.boost.org/trac/boost/ticket/4258 -extern "C" void tss_cleanup_implemented() { } - - - - +CMedianFilter vTimeOffsets(200,0); // Init openssl library multithreading support static boost::interprocess::interprocess_mutex** ppmutexOpenSSL; @@ -64,7 +55,7 @@ public: ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex(); CRYPTO_set_locking_callback(locking_callback); -#ifdef __WXMSW__ +#ifdef WIN32 // Seed random number generator with screen scrape and other hardware sources RAND_screen(); #endif @@ -108,7 +99,7 @@ void RandAddSeedPerfmon() return; nLastPerfmon = GetTime(); -#ifdef __WXMSW__ +#ifdef WIN32 // Don't need this on Linux, OpenSSL automatically uses /dev/urandom // Seed with the entire set of perfmon data unsigned char pdata[250000]; @@ -132,7 +123,7 @@ uint64 GetRand(uint64 nMax) // The range of the random source must be a multiple of the modulus // to give every possible output value an equal possibility - uint64 nRange = (UINT64_MAX / nMax) * nMax; + uint64 nRange = (std::numeric_limits::max() / nMax) * nMax; uint64 nRand = 0; do RAND_bytes((unsigned char*)&nRand, sizeof(nRand)); @@ -198,7 +189,7 @@ inline int OutputDebugStringF(const char* pszFormat, ...) } } -#ifdef __WXMSW__ +#ifdef WIN32 if (fPrintToDebugger) { static CCriticalSection cs_OutputDebugStringF; @@ -264,7 +255,7 @@ int my_snprintf(char* buffer, size_t limit, const char* format, ...) return ret; } -string strprintf(const std::string &format, ...) +string real_strprintf(const std::string &format, int dummy, ...) { char buffer[50000]; char* p = buffer; @@ -273,7 +264,7 @@ string strprintf(const std::string &format, ...) loop { va_list arg_ptr; - va_start(arg_ptr, format); + va_start(arg_ptr, dummy); ret = _vsnprintf(p, limit, format.c_str(), arg_ptr); va_end(arg_ptr); if (ret >= 0 && ret < limit) @@ -291,13 +282,13 @@ string strprintf(const std::string &format, ...) return str; } -bool error(const std::string &format, ...) +bool error(const char *format, ...) { char buffer[50000]; int limit = sizeof(buffer); va_list arg_ptr; va_start(arg_ptr, format); - int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr); + int ret = _vsnprintf(buffer, limit, format, arg_ptr); va_end(arg_ptr); if (ret < 0 || ret >= limit) { @@ -387,7 +378,7 @@ bool ParseMoney(const char* pszIn, int64& nRet) for (; *p; p++) if (!isspace(*p)) return false; - if (strWhole.size() > 14) + if (strWhole.size() > 10) // guard against 63 bit overflow return false; if (nUnits < 0 || nUnits > COIN) return false; @@ -399,26 +390,36 @@ bool ParseMoney(const char* pszIn, int64& nRet) } -vector ParseHex(const char* psz) +static char phexdigit[256] = +{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1 + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; + +bool IsHex(const string& str) { - static char phexdigit[256] = - { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1 - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; + BOOST_FOREACH(unsigned char c, str) + { + if (phexdigit[c] < 0) + return false; + } + return (str.size() > 0) && (str.size()%2 == 0); +} +vector ParseHex(const char* psz) +{ // convert hex dump to vector vector vch; loop @@ -443,7 +444,22 @@ vector ParseHex(const string& str) return ParseHex(str.c_str()); } -void ParseParameters(int argc, char* argv[]) +static void InterpretNegativeSetting(string name, map& mapSettingsRet) +{ + // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set + if (name.find("-no") == 0) + { + std::string positive("-"); + positive.append(name.begin()+3, name.end()); + if (mapSettingsRet.count(positive) == 0) + { + bool value = !GetBoolArg(name); + mapSettingsRet[positive] = (value ? "1" : "0"); + } + } +} + +void ParseParameters(int argc, const char*const argv[]) { mapArgs.clear(); mapMultiArgs.clear(); @@ -457,18 +473,79 @@ void ParseParameters(int argc, char* argv[]) pszValue = strchr(psz, '='); *pszValue++ = '\0'; } - #ifdef __WXMSW__ + #ifdef WIN32 _strlwr(psz); if (psz[0] == '/') psz[0] = '-'; #endif if (psz[0] != '-') break; + mapArgs[psz] = pszValue; mapMultiArgs[psz].push_back(pszValue); } + + // New 0.6 features: + BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs) + { + 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; + } + + // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set + InterpretNegativeSetting(name, mapArgs); + } +} + +std::string GetArg(const std::string& strArg, const std::string& strDefault) +{ + if (mapArgs.count(strArg)) + return mapArgs[strArg]; + return strDefault; +} + +int64 GetArg(const std::string& strArg, int64 nDefault) +{ + if (mapArgs.count(strArg)) + return atoi64(mapArgs[strArg]); + return nDefault; +} + +bool GetBoolArg(const std::string& strArg, bool fDefault) +{ + if (mapArgs.count(strArg)) + { + if (mapArgs[strArg].empty()) + return true; + return (atoi(mapArgs[strArg]) != 0); + } + return fDefault; +} + +bool SoftSetArg(const std::string& strArg, const std::string& strValue) +{ + if (mapArgs.count(strArg)) + return false; + mapArgs[strArg] = strValue; + return true; +} + +bool SoftSetBoolArg(const std::string& strArg, bool fValue) +{ + if (fValue) + return SoftSetArg(strArg, std::string("1")); + else + return SoftSetArg(strArg, std::string("0")); } + string EncodeBase64(const unsigned char* pch, size_t len) { static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -648,7 +725,7 @@ bool WildcardMatch(const string& str, const string& mask) void FormatException(char* pszMessage, std::exception* pex, const char* pszThread) { -#ifdef __WXMSW__ +#ifdef WIN32 char pszModule[MAX_PATH]; pszModule[0] = '\0'; GetModuleFileNameA(NULL, pszModule, sizeof(pszModule)); @@ -680,17 +757,6 @@ void PrintException(std::exception* pex, const char* pszThread) throw; } -void ThreadOneMessageBox(string strMessage) -{ - // Skip message boxes if one is already open - static bool fMessageBoxOpen; - if (fMessageBoxOpen) - return; - fMessageBoxOpen = true; - ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION); - fMessageBoxOpen = false; -} - void PrintExceptionContinue(std::exception* pex, const char* pszThread) { char pszMessage[10000]; @@ -700,46 +766,23 @@ void PrintExceptionContinue(std::exception* pex, const char* pszThread) strMiscWarning = pszMessage; } - - - - - - - -#ifdef __WXMSW__ -typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate); - +#ifdef WIN32 string MyGetSpecialFolderPath(int nFolder, bool fCreate) { - char pszPath[MAX_PATH+100] = ""; - - // SHGetSpecialFolderPath isn't always available on old Windows versions - HMODULE hShell32 = LoadLibraryA("shell32.dll"); - if (hShell32) + char pszPath[MAX_PATH] = ""; + if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate)) { - PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath = - (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA"); - if (pSHGetSpecialFolderPath) - (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate); - FreeModule(hShell32); + return pszPath; } - - // Backup option - if (pszPath[0] == '\0') + else if (nFolder == CSIDL_STARTUP) { - if (nFolder == CSIDL_STARTUP) - { - strcpy(pszPath, getenv("USERPROFILE")); - strcat(pszPath, "\\Start Menu\\Programs\\Startup"); - } - else if (nFolder == CSIDL_APPDATA) - { - strcpy(pszPath, getenv("APPDATA")); - } + return string(getenv("USERPROFILE")) + "\\Start Menu\\Programs\\Startup"; } - - return pszPath; + else if (nFolder == CSIDL_APPDATA) + { + return getenv("APPDATA"); + } + return ""; } #endif @@ -748,7 +791,7 @@ string GetDefaultDataDir() // Windows: C:\Documents and Settings\username\Application Data\Bitcoin // Mac: ~/Library/Application Support/Bitcoin // Unix: ~/.bitcoin -#ifdef __WXMSW__ +#ifdef WIN32 // Windows return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin"; #else @@ -758,7 +801,7 @@ string GetDefaultDataDir() string strHome = pszHome; if (strHome[strHome.size()-1] != '/') strHome += '/'; -#ifdef __WXMAC_OSX__ +#ifdef MAC_OSX // Mac strHome += "Library/Application Support/"; filesystem::create_directory(strHome.c_str()); @@ -821,15 +864,28 @@ string GetConfigFile() return pathConfig.string(); } -void ReadConfigFile(map& mapSettingsRet, +bool ReadConfigFile(map& mapSettingsRet, map >& mapMultiSettingsRet) { namespace fs = boost::filesystem; namespace pod = boost::program_options::detail; + if (mapSettingsRet.count("-datadir")) + { + if (fs::is_directory(fs::system_complete(mapSettingsRet["-datadir"]))) + { + fs::path pathDataDir = fs::system_complete(mapSettingsRet["-datadir"]); + strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir)); + } + else + { + return false; + } + } + fs::ifstream streamConfig(GetConfigFile()); if (!streamConfig.good()) - return; + return true; // No bitcoin.conf file is OK set setOptions; setOptions.insert("*"); @@ -839,9 +895,14 @@ void ReadConfigFile(map& mapSettingsRet, // Don't overwrite existing settings so command line settings override bitcoin.conf string strKey = string("-") + it->string_key; if (mapSettingsRet.count(strKey) == 0) + { 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); + } mapMultiSettingsRet[strKey].push_back(it->value[0]); } + return true; } string GetPidFile() @@ -930,25 +991,22 @@ int64 GetAdjustedTime() return GetTime() + nTimeOffset; } -void AddTimeData(unsigned int ip, int64 nTime) +void AddTimeData(const CNetAddr& ip, int64 nTime) { int64 nOffsetSample = nTime - GetTime(); // Ignore duplicates - static set setKnown; + static set setKnown; if (!setKnown.insert(ip).second) return; // Add data - static vector vTimeOffsets; - if (vTimeOffsets.empty()) - vTimeOffsets.push_back(0); - vTimeOffsets.push_back(nOffsetSample); - printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60); + vTimeOffsets.input(nOffsetSample); + printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) { - sort(vTimeOffsets.begin(), vTimeOffsets.end()); - int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2]; + int64 nMedian = vTimeOffsets.median(); + std::vector vSorted = vTimeOffsets.sorted(); // Only let other nodes change our time by so much if (abs64(nMedian) < 70 * 60) { @@ -963,7 +1021,7 @@ void AddTimeData(unsigned int ip, int64 nTime) { // If nobody has a time different than ours but within 5 minutes of ours, give a warning bool fMatch = false; - BOOST_FOREACH(int64 nOffset, vTimeOffsets) + BOOST_FOREACH(int64 nOffset, vSorted) if (nOffset != 0 && abs64(nOffset) < 5 * 60) fMatch = true; @@ -973,13 +1031,16 @@ void AddTimeData(unsigned int ip, int64 nTime) string strMessage = _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly."); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1)); + ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION); } } } - BOOST_FOREACH(int64 n, vTimeOffsets) - printf("%+"PRI64d" ", n); - printf("| nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60); + if (fDebug) { + BOOST_FOREACH(int64 n, vSorted) + printf("%+"PRI64d" ", n); + printf("| "); + } + printf("nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60); } } @@ -990,7 +1051,6 @@ void AddTimeData(unsigned int ip, int64 nTime) - string FormatVersion(int nVersion) { if (nVersion%100 == 0) @@ -1001,7 +1061,7 @@ string FormatVersion(int nVersion) string FormatFullVersion() { - string s = FormatVersion(VERSION) + pszSubVer; + string s = FormatVersion(CLIENT_VERSION); if (VERSION_IS_BETA) { s += "-"; s += _("beta"); @@ -1009,6 +1069,17 @@ string FormatFullVersion() return s; } +// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014) +std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments) +{ + std::ostringstream ss; + ss << "/"; + ss << name << ":" << FormatVersion(nClientVersion); + if (!comments.empty()) + ss << "(" << boost::algorithm::join(comments, "; ") << ")"; + ss << "/"; + return ss.str(); +} @@ -1115,7 +1186,18 @@ static void pop_lock() void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine) { push_lock(this, CLockLocation(pszName, pszFile, nLine)); +#ifdef DEBUG_LOCKCONTENTION + bool result = mutex.try_lock(); + if (!result) + { + printf("LOCKCONTENTION: %s\n", pszName); + printf("Locker: %s:%d\n", pszFile, nLine); + mutex.lock(); + printf("Locked\n"); + } +#else mutex.lock(); +#endif } void CCriticalSection::Leave() { @@ -1132,9 +1214,19 @@ bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nL #else -void CCriticalSection::Enter(const char*, const char*, int) +void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine) { +#ifdef DEBUG_LOCKCONTENTION + bool result = mutex.try_lock(); + if (!result) + { + printf("LOCKCONTENTION: %s\n", pszName); + printf("Locker: %s:%d\n", pszFile, nLine); + mutex.lock(); + } +#else mutex.lock(); +#endif } void CCriticalSection::Leave() @@ -1149,3 +1241,4 @@ bool CCriticalSection::TryEnter(const char*, const char*, int) } #endif /* DEBUG_LOCKORDER */ +