diff options
Diffstat (limited to 'src/util.cpp')
-rw-r--r-- | src/util.cpp | 479 |
1 files changed, 101 insertions, 378 deletions
diff --git a/src/util.cpp b/src/util.cpp index d8804c7291..08e3625b3d 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,9 +1,10 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // 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. +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "util.h" +#include "sync.h" #include "strlcpy.h" #include "version.h" #include "ui_interface.h" @@ -23,11 +24,11 @@ namespace boost { #include <boost/program_options/parsers.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> -#include <boost/interprocess/sync/interprocess_mutex.hpp> -#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp> #include <boost/foreach.hpp> +#include <boost/thread.hpp> #include <openssl/crypto.h> #include <openssl/rand.h> +#include <stdarg.h> #ifdef WIN32 #ifdef _MSC_VER @@ -43,17 +44,16 @@ namespace boost { #ifdef _WIN32_IE #undef _WIN32_IE #endif -#define _WIN32_IE 0x0400 +#define _WIN32_IE 0x0501 #define WIN32_LEAN_AND_MEAN 1 #ifndef NOMINMAX #define NOMINMAX #endif +#include <io.h> /* for _commit */ #include "shlobj.h" -#include "shlwapi.h" #endif using namespace std; -using namespace boost; map<string, string> mapArgs; map<string, vector<string> > mapMultiArgs; @@ -70,15 +70,17 @@ bool fTestNet = false; bool fNoListen = false; bool fLogTimestamps = false; CMedianFilter<int64> vTimeOffsets(200,0); +bool fReopenDebugLog = false; // Init openssl library multithreading support -static boost::interprocess::interprocess_mutex** ppmutexOpenSSL; +static CCriticalSection** ppmutexOpenSSL; void locking_callback(int mode, int i, const char* file, int line) { - if (mode & CRYPTO_LOCK) - ppmutexOpenSSL[i]->lock(); - else - ppmutexOpenSSL[i]->unlock(); + if (mode & CRYPTO_LOCK) { + ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]); + } else { + LEAVE_CRITICAL_SECTION(*ppmutexOpenSSL[i]); + } } // Init @@ -88,9 +90,9 @@ public: CInit() { // Init openssl library multithreading support - ppmutexOpenSSL = (boost::interprocess::interprocess_mutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(boost::interprocess::interprocess_mutex*)); + ppmutexOpenSSL = (CCriticalSection**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(CCriticalSection*)); for (int i = 0; i < CRYPTO_num_locks(); i++) - ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex(); + ppmutexOpenSSL[i] = new CCriticalSection(); CRYPTO_set_locking_callback(locking_callback); #ifdef WIN32 @@ -149,7 +151,7 @@ void RandAddSeedPerfmon() { RAND_add(pdata, nSize, nSize/100.0); memset(pdata, 0, nSize); - printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M", GetTime()).c_str(), nSize); + printf("RandAddSeed() %d bytes\n", nSize); } #endif } @@ -188,8 +190,6 @@ uint256 GetRandHash() - - inline int OutputDebugStringF(const char* pszFormat, ...) { int ret = 0; @@ -215,6 +215,16 @@ inline int OutputDebugStringF(const char* pszFormat, ...) if (fileout) { static bool fStartedNewLine = true; + static boost::mutex mutexDebugLog; + 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 + } // Debug print useful for profiling if (fLogTimestamps && fStartedNewLine) @@ -236,68 +246,30 @@ inline int OutputDebugStringF(const char* pszFormat, ...) { static CCriticalSection cs_OutputDebugStringF; - // accumulate a line at a time + // accumulate and output a line at a time { LOCK(cs_OutputDebugStringF); - static char pszBuffer[50000]; - static char* pend; - if (pend == NULL) - pend = pszBuffer; + static std::string buffer; + va_list arg_ptr; va_start(arg_ptr, pszFormat); - int limit = END(pszBuffer) - pend - 2; - int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr); + buffer += vstrprintf(pszFormat, arg_ptr); va_end(arg_ptr); - if (ret < 0 || ret >= limit) - { - pend = END(pszBuffer) - 2; - *pend++ = '\n'; - } - else - pend += ret; - *pend = '\0'; - char* p1 = pszBuffer; - char* p2; - while ((p2 = strchr(p1, '\n'))) + + int line_start = 0, line_end; + while((line_end = buffer.find('\n', line_start)) != -1) { - p2++; - char c = *p2; - *p2 = '\0'; - OutputDebugStringA(p1); - *p2 = c; - p1 = p2; + OutputDebugStringA(buffer.substr(line_start, line_end - line_start).c_str()); + line_start = line_end + 1; } - if (p1 != pszBuffer) - memmove(pszBuffer, p1, pend - p1 + 1); - pend -= (p1 - pszBuffer); + buffer.erase(0, line_start); } } #endif return ret; } - -// Safer snprintf -// - prints up to limit-1 characters -// - output string is always null terminated even if limit reached -// - return value is the number of characters actually printed -int my_snprintf(char* buffer, size_t limit, const char* format, ...) -{ - if (limit == 0) - return 0; - va_list arg_ptr; - va_start(arg_ptr, format); - int ret = _vsnprintf(buffer, limit, format, arg_ptr); - va_end(arg_ptr); - if (ret < 0 || ret >= (int)limit) - { - ret = limit - 1; - buffer[limit-1] = 0; - } - return ret; -} - -string real_strprintf(const std::string &format, int dummy, ...) +string vstrprintf(const std::string &format, va_list ap) { char buffer[50000]; char* p = buffer; @@ -306,7 +278,7 @@ string real_strprintf(const std::string &format, int dummy, ...) loop { va_list arg_ptr; - va_start(arg_ptr, dummy); + va_copy(arg_ptr, ap); ret = _vsnprintf(p, limit, format.c_str(), arg_ptr); va_end(arg_ptr); if (ret >= 0 && ret < limit) @@ -324,19 +296,22 @@ string real_strprintf(const std::string &format, int dummy, ...) return str; } +string real_strprintf(const std::string &format, int dummy, ...) +{ + va_list arg_ptr; + va_start(arg_ptr, dummy); + string str = vstrprintf(format, arg_ptr); + va_end(arg_ptr); + return str; +} + 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, arg_ptr); + std::string str = vstrprintf(format, arg_ptr); va_end(arg_ptr); - if (ret < 0 || ret >= limit) - { - buffer[limit-1] = 0; - } - printf("ERROR: %s\n", buffer); + printf("ERROR: %s\n", str.c_str()); return false; } @@ -500,7 +475,7 @@ static void InterpretNegativeSetting(string name, map<string, string>& mapSettin } } -void ParseParameters(int argc, const char*const argv[]) +void ParseParameters(int argc, const char* const argv[]) { mapArgs.clear(); mapMultiArgs.clear(); @@ -764,81 +739,55 @@ bool WildcardMatch(const string& str, const string& mask) -void FormatException(char* pszMessage, std::exception* pex, const char* pszThread) +static std::string FormatException(std::exception* pex, const char* pszThread) { #ifdef WIN32 - char pszModule[MAX_PATH]; - pszModule[0] = '\0'; + char pszModule[MAX_PATH] = ""; GetModuleFileNameA(NULL, pszModule, sizeof(pszModule)); #else const char* pszModule = "bitcoin"; #endif if (pex) - snprintf(pszMessage, 1000, + return strprintf( "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); else - snprintf(pszMessage, 1000, + return strprintf( "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); } void LogException(std::exception* pex, const char* pszThread) { - char pszMessage[10000]; - FormatException(pszMessage, pex, pszThread); - printf("\n%s", pszMessage); + std::string message = FormatException(pex, pszThread); + printf("\n%s", message.c_str()); } void PrintException(std::exception* pex, const char* pszThread) { - char pszMessage[10000]; - FormatException(pszMessage, pex, pszThread); - printf("\n\n************************\n%s\n", pszMessage); - fprintf(stderr, "\n\n************************\n%s\n", pszMessage); - strMiscWarning = pszMessage; + std::string message = FormatException(pex, pszThread); + printf("\n\n************************\n%s\n", message.c_str()); + fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); + strMiscWarning = message; throw; } void PrintExceptionContinue(std::exception* pex, const char* pszThread) { - char pszMessage[10000]; - FormatException(pszMessage, pex, pszThread); - printf("\n\n************************\n%s\n", pszMessage); - fprintf(stderr, "\n\n************************\n%s\n", pszMessage); - strMiscWarning = pszMessage; -} - -#ifdef WIN32 -boost::filesystem::path MyGetSpecialFolderPath(int nFolder, bool fCreate) -{ - namespace fs = boost::filesystem; - - char pszPath[MAX_PATH] = ""; - if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate)) - { - return fs::path(pszPath); - } - else if (nFolder == CSIDL_STARTUP) - { - return fs::path(getenv("USERPROFILE")) / "Start Menu" / "Programs" / "Startup"; - } - else if (nFolder == CSIDL_APPDATA) - { - return fs::path(getenv("APPDATA")); - } - return fs::path(""); + std::string message = FormatException(pex, pszThread); + printf("\n\n************************\n%s\n", message.c_str()); + fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); + strMiscWarning = message; } -#endif boost::filesystem::path GetDefaultDataDir() { namespace fs = boost::filesystem; - - // Windows: C:\Documents and Settings\username\Application Data\Bitcoin + // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin + // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin // Mac: ~/Library/Application Support/Bitcoin // Unix: ~/.bitcoin #ifdef WIN32 // Windows - return MyGetSpecialFolderPath(CSIDL_APPDATA, true) / "Bitcoin"; + return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin"; #else fs::path pathRet; char* pszHome = getenv("HOME"); @@ -849,7 +798,7 @@ boost::filesystem::path GetDefaultDataDir() #ifdef MAC_OSX // Mac pathRet /= "Library/Application Support"; - filesystem::create_directory(pathRet); + fs::create_directory(pathRet); return pathRet / "Bitcoin"; #else // Unix @@ -895,9 +844,7 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) boost::filesystem::path GetConfigFile() { - namespace fs = boost::filesystem; - - fs::path pathConfigFile(GetArg("-conf", "bitcoin.conf")); + boost::filesystem::path pathConfigFile(GetArg("-conf", "bitcoin.conf")); if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; return pathConfigFile; } @@ -905,24 +852,21 @@ boost::filesystem::path GetConfigFile() void ReadConfigFile(map<string, string>& mapSettingsRet, map<string, vector<string> >& mapMultiSettingsRet) { - namespace fs = boost::filesystem; - namespace pod = boost::program_options::detail; - - fs::ifstream streamConfig(GetConfigFile()); + boost::filesystem::ifstream streamConfig(GetConfigFile()); if (!streamConfig.good()) return; // No bitcoin.conf file is OK set<string> setOptions; setOptions.insert("*"); - for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) + 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) { mapSettingsRet[strKey] = it->value[0]; - // interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set) + // 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]); @@ -931,9 +875,7 @@ void ReadConfigFile(map<string, string>& mapSettingsRet, boost::filesystem::path GetPidFile() { - namespace fs = boost::filesystem; - - fs::path pathPidFile(GetArg("-pid", "bitcoind.pid")); + boost::filesystem::path pathPidFile(GetArg("-pid", "bitcoind.pid")); if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile; return pathPidFile; } @@ -948,6 +890,27 @@ void CreatePidFile(const boost::filesystem::path &path, pid_t pid) } } +bool RenameOver(boost::filesystem::path src, boost::filesystem::path dest) +{ +#ifdef WIN32 + return MoveFileExA(src.string().c_str(), dest.string().c_str(), + MOVEFILE_REPLACE_EXISTING); +#else + int rc = std::rename(src.string().c_str(), dest.string().c_str()); + return (rc == 0); +#endif /* WIN32 */ +} + +void FileCommit(FILE *fileout) +{ + fflush(fileout); // harmless if redundantly called +#ifdef WIN32 + _commit(_fileno(fileout)); +#else + fsync(fileno(fileout)); +#endif +} + int GetFilesize(FILE* file) { int nSavePos = ftell(file); @@ -1055,7 +1018,7 @@ void AddTimeData(const CNetAddr& 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()); - ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION); + uiInterface.ThreadSafeMessageBox(strMessage+" ", string("Bitcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION); } } } @@ -1101,258 +1064,18 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const } #ifdef WIN32 -boost::filesystem::path static StartupShortcutPath() -{ - return MyGetSpecialFolderPath(CSIDL_STARTUP, true) / "Bitcoin.lnk"; -} - -bool GetStartOnSystemStartup() -{ - return filesystem::exists(StartupShortcutPath()); -} - -bool SetStartOnSystemStartup(bool fAutoStart) -{ - // If the shortcut exists already, remove it for updating - boost::filesystem::remove(StartupShortcutPath()); - - if (fAutoStart) - { - CoInitialize(NULL); - - // Get a pointer to the IShellLink interface. - IShellLink* psl = NULL; - HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, - CLSCTX_INPROC_SERVER, IID_IShellLink, - reinterpret_cast<void**>(&psl)); - - if (SUCCEEDED(hres)) - { - // Get the current executable path - TCHAR pszExePath[MAX_PATH]; - GetModuleFileName(NULL, pszExePath, sizeof(pszExePath)); - - TCHAR pszArgs[5] = TEXT("-min"); - - // Set the path to the shortcut target - psl->SetPath(pszExePath); - PathRemoveFileSpec(pszExePath); - psl->SetWorkingDirectory(pszExePath); - psl->SetShowCmd(SW_SHOWMINNOACTIVE); - psl->SetArguments(pszArgs); - - // Query IShellLink for the IPersistFile interface for - // saving the shortcut in persistent storage. - IPersistFile* ppf = NULL; - hres = psl->QueryInterface(IID_IPersistFile, - reinterpret_cast<void**>(&ppf)); - if (SUCCEEDED(hres)) - { - WCHAR pwsz[MAX_PATH]; - // Ensure that the string is ANSI. - MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().string().c_str(), -1, pwsz, MAX_PATH); - // Save the link by calling IPersistFile::Save. - hres = ppf->Save(pwsz, TRUE); - ppf->Release(); - psl->Release(); - CoUninitialize(); - return true; - } - psl->Release(); - } - CoUninitialize(); - return false; - } - return true; -} - -#elif defined(LINUX) - -// Follow the Desktop Application Autostart Spec: -// http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html - -boost::filesystem::path static GetAutostartDir() +boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) { namespace fs = boost::filesystem; - char* pszConfigHome = getenv("XDG_CONFIG_HOME"); - if (pszConfigHome) return fs::path(pszConfigHome) / "autostart"; - char* pszHome = getenv("HOME"); - if (pszHome) return fs::path(pszHome) / ".config" / "autostart"; - return fs::path(); -} - -boost::filesystem::path static GetAutostartFilePath() -{ - return GetAutostartDir() / "bitcoin.desktop"; -} + char pszPath[MAX_PATH] = ""; -bool GetStartOnSystemStartup() -{ - boost::filesystem::ifstream optionFile(GetAutostartFilePath()); - if (!optionFile.good()) - return false; - // Scan through file for "Hidden=true": - string line; - while (!optionFile.eof()) + if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate)) { - getline(optionFile, line); - if (line.find("Hidden") != string::npos && - line.find("true") != string::npos) - return false; + return fs::path(pszPath); } - optionFile.close(); - - return true; -} -bool SetStartOnSystemStartup(bool fAutoStart) -{ - if (!fAutoStart) - boost::filesystem::remove(GetAutostartFilePath()); - else - { - char pszExePath[MAX_PATH+1]; - memset(pszExePath, 0, sizeof(pszExePath)); - if (readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1) == -1) - return false; - - boost::filesystem::create_directories(GetAutostartDir()); - - boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc); - if (!optionFile.good()) - return false; - // Write a bitcoin.desktop file to the autostart directory: - optionFile << "[Desktop Entry]\n"; - optionFile << "Type=Application\n"; - optionFile << "Name=Bitcoin\n"; - optionFile << "Exec=" << pszExePath << " -min\n"; - optionFile << "Terminal=false\n"; - optionFile << "Hidden=false\n"; - optionFile.close(); - } - return true; + printf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n"); + return fs::path(""); } -#else - -// TODO: OSX startup stuff; see: -// http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html - -bool GetStartOnSystemStartup() { return false; } -bool SetStartOnSystemStartup(bool fAutoStart) { return false; } - #endif - - - -#ifdef DEBUG_LOCKORDER -// -// Early deadlock detection. -// Problem being solved: -// Thread 1 locks A, then B, then C -// Thread 2 locks D, then C, then A -// --> may result in deadlock between the two threads, depending on when they run. -// Solution implemented here: -// Keep track of pairs of locks: (A before B), (A before C), etc. -// Complain if any thread trys to lock in a different order. -// - -struct CLockLocation -{ - CLockLocation(const char* pszName, const char* pszFile, int nLine) - { - mutexName = pszName; - sourceFile = pszFile; - sourceLine = nLine; - } - - std::string ToString() const - { - return mutexName+" "+sourceFile+":"+itostr(sourceLine); - } - -private: - std::string mutexName; - std::string sourceFile; - int sourceLine; -}; - -typedef std::vector< std::pair<void*, CLockLocation> > LockStack; - -static boost::interprocess::interprocess_mutex dd_mutex; -static std::map<std::pair<void*, void*>, LockStack> lockorders; -static boost::thread_specific_ptr<LockStack> lockstack; - - -static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2) -{ - printf("POTENTIAL DEADLOCK DETECTED\n"); - printf("Previous lock order was:\n"); - BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2) - { - if (i.first == mismatch.first) printf(" (1)"); - if (i.first == mismatch.second) printf(" (2)"); - printf(" %s\n", i.second.ToString().c_str()); - } - printf("Current lock order is:\n"); - BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1) - { - if (i.first == mismatch.first) printf(" (1)"); - if (i.first == mismatch.second) printf(" (2)"); - printf(" %s\n", i.second.ToString().c_str()); - } -} - -static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) -{ - bool fOrderOK = true; - if (lockstack.get() == NULL) - lockstack.reset(new LockStack); - - if (fDebug) printf("Locking: %s\n", locklocation.ToString().c_str()); - dd_mutex.lock(); - - (*lockstack).push_back(std::make_pair(c, locklocation)); - - if (!fTry) BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack)) - { - if (i.first == c) break; - - std::pair<void*, void*> p1 = std::make_pair(i.first, c); - if (lockorders.count(p1)) - continue; - lockorders[p1] = (*lockstack); - - std::pair<void*, void*> p2 = std::make_pair(c, i.first); - if (lockorders.count(p2)) - { - potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); - break; - } - } - dd_mutex.unlock(); -} - -static void pop_lock() -{ - if (fDebug) - { - const CLockLocation& locklocation = (*lockstack).rbegin()->second; - printf("Unlocked: %s\n", locklocation.ToString().c_str()); - } - dd_mutex.lock(); - (*lockstack).pop_back(); - dd_mutex.unlock(); -} - -void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) -{ - push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry); -} - -void LeaveCritical() -{ - pop_lock(); -} - -#endif /* DEBUG_LOCKORDER */ |