Page MenuHomePhabricator

No OneTemporary

diff --git a/src/init.cpp b/src/init.cpp
index b701e90e91..a9d9eb71c2 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1,727 +1,715 @@
// 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.
#include "headers.h"
#include "db.h"
#include "bitcoinrpc.h"
#include "net.h"
#include "init.h"
#include "strlcpy.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
#define _BITCOIN_QT_PLUGINS_INCLUDED
#define __INSURE__
#include <QtPlugin>
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
#endif
using namespace std;
using namespace boost;
CWallet* pwalletMain;
//////////////////////////////////////////////////////////////////////////////
//
// Shutdown
//
void ExitTimeout(void* parg)
{
#ifdef WIN32
Sleep(5000);
ExitProcess(0);
#endif
}
void Shutdown(void* parg)
{
static CCriticalSection cs_Shutdown;
static bool fTaken;
bool fFirstThread = false;
TRY_CRITICAL_BLOCK(cs_Shutdown)
{
fFirstThread = !fTaken;
fTaken = true;
}
static bool fExit;
if (fFirstThread)
{
fShutdown = true;
nTransactionsUpdated++;
DBFlush(false);
StopNode();
DBFlush(true);
boost::filesystem::remove(GetPidFile());
UnregisterWallet(pwalletMain);
delete pwalletMain;
CreateThread(ExitTimeout, NULL);
Sleep(50);
printf("Bitcoin exiting\n\n");
fExit = true;
exit(0);
}
else
{
while (!fExit)
Sleep(500);
Sleep(100);
ExitThread(0);
}
}
void HandleSIGTERM(int)
{
fRequestShutdown = true;
}
//////////////////////////////////////////////////////////////////////////////
//
// Start
//
#if !defined(QT_GUI)
int main(int argc, char* argv[])
{
bool fRet = false;
fRet = AppInit(argc, argv);
if (fRet && fDaemon)
return 0;
return 1;
}
#endif
bool AppInit(int argc, char* argv[])
{
bool fRet = false;
try
{
fRet = AppInit2(argc, argv);
}
catch (std::exception& e) {
PrintException(&e, "AppInit()");
} catch (...) {
PrintException(NULL, "AppInit()");
}
if (!fRet)
Shutdown(NULL);
return fRet;
}
bool AppInit2(int argc, char* argv[])
{
#ifdef _MSC_VER
// Turn off microsoft heap dump noise
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
#endif
#if _MSC_VER >= 1400
// Disable confusing "helpful" text message on abort, ctrl-c
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
#ifndef WIN32
umask(077);
#endif
#ifndef WIN32
// Clean shutdown on SIGTERM
struct sigaction sa;
sa.sa_handler = HandleSIGTERM;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
#endif
//
// Parameters
//
- // If Qt is used, parameters are parsed in qt/bitcoin.cpp's main()
+ // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
#if !defined(QT_GUI)
ParseParameters(argc, argv);
-#endif
-
- if (mapArgs.count("-datadir"))
+ if (!ReadConfigFile(mapArgs, mapMultiArgs))
{
- if (filesystem::is_directory(filesystem::system_complete(mapArgs["-datadir"])))
- {
- filesystem::path pathDataDir = filesystem::system_complete(mapArgs["-datadir"]);
- strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir));
- }
- else
- {
- fprintf(stderr, "Error: Specified directory does not exist\n");
- Shutdown(NULL);
- }
+ fprintf(stderr, "Error: Specified directory does not exist\n");
+ Shutdown(NULL);
}
-
-
- ReadConfigFile(mapArgs, mapMultiArgs); // Must be done after processing datadir
+#endif
if (mapArgs.count("-?") || mapArgs.count("--help"))
{
string strUsage = string() +
_("Bitcoin version") + " " + FormatFullVersion() + "\n\n" +
_("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
" bitcoind [options] \t " + "\n" +
" bitcoind [options] <command> [params]\t " + _("Send command to -server or bitcoind") + "\n" +
" bitcoind [options] help \t\t " + _("List commands") + "\n" +
" bitcoind [options] help <command> \t\t " + _("Get help for a command") + "\n" +
_("Options:") + "\n" +
" -conf=<file> \t\t " + _("Specify configuration file (default: bitcoin.conf)") + "\n" +
" -pid=<file> \t\t " + _("Specify pid file (default: bitcoind.pid)") + "\n" +
" -gen \t\t " + _("Generate coins") + "\n" +
" -gen=0 \t\t " + _("Don't generate coins") + "\n" +
" -min \t\t " + _("Start minimized") + "\n" +
" -splash \t\t " + _("Show splash screen on startup (default: 1)") + "\n" +
" -datadir=<dir> \t\t " + _("Specify data directory") + "\n" +
" -timeout=<n> \t " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> \t " + _("Connect through socks4 proxy") + "\n" +
" -dns \t " + _("Allow DNS lookups for addnode and connect") + "\n" +
" -port=<port> \t\t " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" +
" -maxconnections=<n>\t " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" +
" -addnode=<ip> \t " + _("Add a node to connect to and attempt to keep the connection open") + "\n" +
" -connect=<ip> \t\t " + _("Connect only to the specified node") + "\n" +
" -irc \t " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen \t " + _("Accept connections from outside (default: 1)") + "\n" +
#ifdef QT_GUI
" -lang=<lang> \t\t " + _("Set language, for example \"de_DE\" (default: system locale)") + "\n" +
#endif
" -dnsseed \t " + _("Find peers using DNS lookup (default: 1)") + "\n" +
" -banscore=<n> \t " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
" -bantime=<n> \t " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
" -maxreceivebuffer=<n>\t " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)") + "\n" +
" -maxsendbuffer=<n>\t " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)") + "\n" +
#ifdef USE_UPNP
#if USE_UPNP
" -upnp \t " + _("Use Universal Plug and Play to map the listening port (default: 1)") + "\n" +
#else
" -upnp \t " + _("Use Universal Plug and Play to map the listening port (default: 0)") + "\n" +
#endif
#endif
" -paytxfee=<amt> \t " + _("Fee per KB to add to transactions you send") + "\n" +
#ifdef QT_GUI
" -server \t\t " + _("Accept command line and JSON-RPC commands") + "\n" +
#endif
#if !defined(WIN32) && !defined(QT_GUI)
" -daemon \t\t " + _("Run in the background as a daemon and accept commands") + "\n" +
#endif
" -testnet \t\t " + _("Use the test network") + "\n" +
" -debug \t\t " + _("Output extra debugging information") + "\n" +
" -logtimestamps \t " + _("Prepend debug output with timestamp") + "\n" +
" -printtoconsole \t " + _("Send trace/debug info to console instead of debug.log file") + "\n" +
#ifdef WIN32
" -printtodebugger \t " + _("Send trace/debug info to debugger") + "\n" +
#endif
" -rpcuser=<user> \t " + _("Username for JSON-RPC connections") + "\n" +
" -rpcpassword=<pw>\t " + _("Password for JSON-RPC connections") + "\n" +
" -rpcport=<port> \t\t " + _("Listen for JSON-RPC connections on <port> (default: 8332)") + "\n" +
" -rpcallowip=<ip> \t\t " + _("Allow JSON-RPC connections from specified IP address") + "\n" +
" -rpcconnect=<ip> \t " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
" -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)") + "\n" +
" -rescan \t " + _("Rescan the block chain for missing wallet transactions") + "\n";
#ifdef USE_SSL
strUsage += string() +
_("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n" +
" -rpcssl \t " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n" +
" -rpcsslcertificatechainfile=<file.cert>\t " + _("Server certificate file (default: server.cert)") + "\n" +
" -rpcsslprivatekeyfile=<file.pem> \t " + _("Server private key (default: server.pem)") + "\n" +
" -rpcsslciphers=<ciphers> \t " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)") + "\n";
#endif
strUsage += string() +
" -? \t\t " + _("This help message") + "\n";
// Remove tabs
strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
#if defined(QT_GUI) && defined(WIN32)
// On windows, show a message box, as there is no stderr
wxMessageBox(strUsage, "Usage");
#else
fprintf(stderr, "%s", strUsage.c_str());
#endif
return false;
}
fTestNet = GetBoolArg("-testnet");
if (fTestNet)
{
SoftSetBoolArg("-irc", true);
}
fDebug = GetBoolArg("-debug");
#if !defined(WIN32) && !defined(QT_GUI)
fDaemon = GetBoolArg("-daemon");
#else
fDaemon = false;
#endif
if (fDaemon)
fServer = true;
else
fServer = GetBoolArg("-server");
/* force fServer when running without GUI */
#if !defined(QT_GUI)
fServer = true;
#endif
fPrintToConsole = GetBoolArg("-printtoconsole");
fPrintToDebugger = GetBoolArg("-printtodebugger");
fLogTimestamps = GetBoolArg("-logtimestamps");
#ifndef QT_GUI
for (int i = 1; i < argc; i++)
if (!IsSwitchChar(argv[i][0]) && !(strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0))
fCommandLine = true;
if (fCommandLine)
{
int ret = CommandLineRPC(argc, argv);
exit(ret);
}
#endif
#if !defined(WIN32) && !defined(QT_GUI)
if (fDaemon)
{
// Daemonize
pid_t pid = fork();
if (pid < 0)
{
fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
return false;
}
if (pid > 0)
{
CreatePidFile(GetPidFile(), pid);
return true;
}
pid_t sid = setsid();
if (sid < 0)
fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
}
#endif
if (!fDebug && !pszSetDataDir[0])
ShrinkDebugFile();
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
printf("Bitcoin version %s\n", FormatFullVersion().c_str());
printf("Default data directory %s\n", GetDefaultDataDir().c_str());
if (GetBoolArg("-loadblockindextest"))
{
CTxDB txdb("r");
txdb.LoadBlockIndex();
PrintBlockTree();
return false;
}
// Make sure only a single bitcoin process is using the data directory.
string strLockFile = GetDataDir() + "/.lock";
FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
if (file) fclose(file);
static boost::interprocess::file_lock lock(strLockFile.c_str());
if (!lock.try_lock())
{
wxMessageBox(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin is probably already running."), GetDataDir().c_str()), "Bitcoin");
return false;
}
std::ostringstream strErrors;
//
// Load data files
//
if (fDaemon)
fprintf(stdout, "bitcoin server starting\n");
int64 nStart;
InitMessage(_("Loading addresses..."));
printf("Loading addresses...\n");
nStart = GetTimeMillis();
if (!LoadAddresses())
strErrors << _("Error loading addr.dat") << "\n";
printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
InitMessage(_("Loading block index..."));
printf("Loading block index...\n");
nStart = GetTimeMillis();
if (!LoadBlockIndex())
strErrors << _("Error loading blkindex.dat") << "\n";
printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
InitMessage(_("Loading wallet..."));
printf("Loading wallet...\n");
nStart = GetTimeMillis();
bool fFirstRun;
pwalletMain = new CWallet("wallet.dat");
int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
if (nLoadWalletRet != DB_LOAD_OK)
{
if (nLoadWalletRet == DB_CORRUPT)
strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
else if (nLoadWalletRet == DB_TOO_NEW)
strErrors << _("Error loading wallet.dat: Wallet requires newer version of Bitcoin") << "\n";
else if (nLoadWalletRet == DB_NEED_REWRITE)
{
strErrors << _("Wallet needed to be rewritten: restart Bitcoin to complete") << "\n";
wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
return false;
}
else
strErrors << _("Error loading wallet.dat") << "\n";
}
printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
RegisterWallet(pwalletMain);
CBlockIndex *pindexRescan = pindexBest;
if (GetBoolArg("-rescan"))
pindexRescan = pindexGenesisBlock;
else
{
CWalletDB walletdb("wallet.dat");
CBlockLocator locator;
if (walletdb.ReadBestBlock(locator))
pindexRescan = locator.GetBlockIndex();
}
if (pindexBest != pindexRescan)
{
InitMessage(_("Rescanning..."));
printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
pwalletMain->ScanForWalletTransactions(pindexRescan, true);
printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart);
}
InitMessage(_("Done loading"));
printf("Done loading\n");
//// debug print
printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
printf("nBestHeight = %d\n", nBestHeight);
printf("setKeyPool.size() = %d\n", pwalletMain->setKeyPool.size());
printf("mapWallet.size() = %d\n", pwalletMain->mapWallet.size());
printf("mapAddressBook.size() = %d\n", pwalletMain->mapAddressBook.size());
if (!strErrors.str().empty())
{
wxMessageBox(strErrors.str(), "Bitcoin", wxOK | wxICON_ERROR);
return false;
}
// Add wallet transactions that aren't already in a block to mapTransactions
pwalletMain->ReacceptWalletTransactions();
// Note: Bitcoin-QT stores several settings in the wallet, so we want
// to load the wallet BEFORE parsing command-line arguments, so
// the command-line/bitcoin.conf settings override GUI setting.
//
// Parameters
//
if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree"))
{
PrintBlockTree();
return false;
}
if (mapArgs.count("-timeout"))
{
int nNewTimeout = GetArg("-timeout", 5000);
if (nNewTimeout > 0 && nNewTimeout < 600000)
nConnectTimeout = nNewTimeout;
}
if (mapArgs.count("-printblock"))
{
string strMatch = mapArgs["-printblock"];
int nFound = 0;
for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
{
uint256 hash = (*mi).first;
if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
{
CBlockIndex* pindex = (*mi).second;
CBlock block;
block.ReadFromDisk(pindex);
block.BuildMerkleTree();
block.print();
printf("\n");
nFound++;
}
}
if (nFound == 0)
printf("No blocks matching %s were found\n", strMatch.c_str());
return false;
}
if (mapArgs.count("-proxy"))
{
fUseProxy = true;
addrProxy = CService(mapArgs["-proxy"], 9050);
if (!addrProxy.IsValid())
{
wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
return false;
}
}
bool fTor = (fUseProxy && addrProxy.GetPort() == 9050);
if (fTor)
{
// Use SoftSetBoolArg here so user can override any of these if they wish.
// Note: the GetBoolArg() calls for all of these must happen later.
SoftSetBoolArg("-listen", false);
SoftSetBoolArg("-irc", false);
SoftSetBoolArg("-dnsseed", false);
SoftSetBoolArg("-upnp", false);
SoftSetBoolArg("-dns", false);
}
fAllowDNS = GetBoolArg("-dns");
fNoListen = !GetBoolArg("-listen", true);
// This code can be removed once a super-majority of the network has upgraded.
if (GetBoolArg("-bip16", true))
{
if (fTestNet)
SoftSetArg("-paytoscripthashtime", "1329264000"); // Feb 15
else
SoftSetArg("-paytoscripthashtime", "1330578000"); // Mar 1
// Put "/P2SH/" in the coinbase so everybody can tell when
// a majority of miners support it
const char* pszP2SH = "/P2SH/";
COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
}
else
{
const char* pszP2SH = "NOP2SH";
COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
}
if (!fNoListen)
{
std::string strError;
if (!BindListenPort(strError))
{
wxMessageBox(strError, "Bitcoin");
return false;
}
}
if (mapArgs.count("-addnode"))
{
BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
{
CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS));
addr.nTime = 0; // so it won't relay unless successfully connected
if (addr.IsValid())
AddAddress(addr);
}
}
if (mapArgs.count("-paytxfee"))
{
if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
{
wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
return false;
}
if (nTransactionFee > 0.25 * COIN)
wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
}
//
// Start the node
//
if (!CheckDiskSpace())
return false;
RandAddSeedPerfmon();
if (!CreateThread(StartNode, NULL))
wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
if (fServer)
CreateThread(ThreadRPCServer, NULL);
#ifdef QT_GUI
if(GetStartOnSystemStartup())
SetStartOnSystemStartup(true); // Remove startup links to bitcoin-wx
#endif
#if !defined(QT_GUI)
while (1)
Sleep(5000);
#endif
return true;
}
#ifdef WIN32
string StartupShortcutPath()
{
return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
}
bool GetStartOnSystemStartup()
{
return filesystem::exists(StartupShortcutPath().c_str());
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
// If the shortcut exists already, remove it for updating
remove(StartupShortcutPath().c_str());
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().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 GetAutostartDir()
{
namespace fs = boost::filesystem;
char* pszConfigHome = getenv("XDG_CONFIG_HOME");
if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
char* pszHome = getenv("HOME");
if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
return fs::path();
}
boost::filesystem::path GetAutostartFilePath()
{
return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");
}
bool GetStartOnSystemStartup()
{
boost::filesystem::ifstream optionFile(GetAutostartFilePath());
if (!optionFile.good())
return false;
// Scan through file for "Hidden=true":
string line;
while (!optionFile.eof())
{
getline(optionFile, line);
if (line.find("Hidden") != string::npos &&
line.find("true") != string::npos)
return false;
}
optionFile.close();
return true;
}
bool SetStartOnSystemStartup(bool fAutoStart)
{
if (!fAutoStart)
{
#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
unlink(GetAutostartFilePath().string().c_str());
#else
unlink(GetAutostartFilePath().native_file_string().c_str());
#endif
}
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;
}
#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
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 03b89f06fc..5e79f6ec98 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -1,259 +1,280 @@
/*
* W.J. van der Laan 20011-2012
*/
#include "bitcoingui.h"
#include "clientmodel.h"
#include "walletmodel.h"
#include "optionsmodel.h"
#include "headers.h"
#include "init.h"
#include "qtipcserver.h"
#include <QApplication>
#include <QMessageBox>
#include <QThread>
#include <QTextCodec>
#include <QLocale>
#include <QTranslator>
#include <QSplashScreen>
#include <QLibraryInfo>
#include <boost/interprocess/ipc/message_queue.hpp>
// Need a global reference for the notifications to find the GUI
BitcoinGUI *guiref;
QSplashScreen *splashref;
int MyMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
{
// Message from AppInit2(), always in main thread before main window is constructed
QMessageBox::critical(0, QString::fromStdString(caption),
QString::fromStdString(message),
QMessageBox::Ok, QMessageBox::Ok);
return 4;
}
int ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style, wxWindow* parent, int x, int y)
{
// Message from network thread
if(guiref)
{
QMetaObject::invokeMethod(guiref, "error", Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)));
}
else
{
printf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
}
return 4;
}
bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption, wxWindow* parent)
{
if(!guiref)
return false;
if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
return true;
bool payFee = false;
// Call slot on GUI thread.
// If called from another thread, use a blocking QueuedConnection.
Qt::ConnectionType connectionType = Qt::DirectConnection;
if(QThread::currentThread() != QCoreApplication::instance()->thread())
{
connectionType = Qt::BlockingQueuedConnection;
}
QMetaObject::invokeMethod(guiref, "askFee", connectionType,
Q_ARG(qint64, nFeeRequired),
Q_ARG(bool*, &payFee));
return payFee;
}
void ThreadSafeHandleURL(const std::string& strURL)
{
if(!guiref)
return;
// Call slot on GUI thread.
// If called from another thread, use a blocking QueuedConnection.
Qt::ConnectionType connectionType = Qt::DirectConnection;
if(QThread::currentThread() != QCoreApplication::instance()->thread())
{
connectionType = Qt::BlockingQueuedConnection;
}
QMetaObject::invokeMethod(guiref, "handleURL", connectionType,
Q_ARG(QString, QString::fromStdString(strURL)));
}
void CalledSetStatusBar(const std::string& strText, int nField)
{
// Only used for built-in mining, which is disabled, simple ignore
}
void UIThreadCall(boost::function0<void> fn)
{
// Only used for built-in mining, which is disabled, simple ignore
}
void MainFrameRepaint()
{
if(guiref)
QMetaObject::invokeMethod(guiref, "refreshStatusBar", Qt::QueuedConnection);
}
void InitMessage(const std::string &message)
{
if(splashref)
{
splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(255,255,200));
QApplication::instance()->processEvents();
}
}
/*
Translate string to current locale using Qt.
*/
std::string _(const char* psz)
{
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
}
#ifndef BITCOIN_QT_TEST
int main(int argc, char *argv[])
{
// Do this early as we don't want to bother initializing if we are just calling IPC
for (int i = 1; i < argc; i++)
{
if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0)
{
const char *strURL = argv[i];
try {
boost::interprocess::message_queue mq(boost::interprocess::open_only, "BitcoinURL");
if(mq.try_send(strURL, strlen(strURL), 0))
exit(0);
else
break;
}
catch (boost::interprocess::interprocess_exception &ex) {
break;
}
}
}
// Internal string conversion is all UTF-8
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
Q_INIT_RESOURCE(bitcoin);
QApplication app(argc, argv);
+ // Command-line options take precedence:
ParseParameters(argc, argv);
+ // ... then bitcoin.conf:
+ if (!ReadConfigFile(mapArgs, mapMultiArgs))
+ {
+ fprintf(stderr, "Error: Specified directory does not exist\n");
+ return 1;
+ }
+
+ // Application identification (must be set before OptionsModel is initialized,
+ // as it is used to locate QSettings)
+ app.setOrganizationName("Bitcoin");
+ app.setOrganizationDomain("bitcoin.org");
+ if(GetBoolArg("-testnet")) // Separate UI settings for testnet
+ app.setApplicationName("Bitcoin-Qt-testnet");
+ else
+ app.setApplicationName("Bitcoin-Qt");
+
+ // ... then GUI settings:
+ OptionsModel optionsModel;
+
// Get desired locale ("en_US") from command line or system locale
QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString()));
// Load language files for configured locale:
// - First load the translator for the base language, without territory
// - Then load the more specific locale translator
QString lang = lang_territory;
lang.truncate(lang_territory.lastIndexOf('_')); // "en"
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
qtTranslatorBase.load(QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" + lang);
if (!qtTranslatorBase.isEmpty())
app.installTranslator(&qtTranslatorBase);
qtTranslator.load(QLibraryInfo::location(QLibraryInfo::TranslationsPath) + "/qt_" + lang_territory);
if (!qtTranslator.isEmpty())
app.installTranslator(&qtTranslator);
translatorBase.load(":/translations/"+lang);
if (!translatorBase.isEmpty())
app.installTranslator(&translatorBase);
translator.load(":/translations/"+lang_territory);
if (!translator.isEmpty())
app.installTranslator(&translator);
- app.setApplicationName(QApplication::translate("main", "Bitcoin-Qt"));
-
QSplashScreen splash(QPixmap(":/images/splash"), 0);
if (GetBoolArg("-splash", true) && !GetBoolArg("-min"))
{
splash.show();
splash.setAutoFillBackground(true);
splashref = &splash;
}
app.processEvents();
app.setQuitOnLastWindowClosed(false);
try
{
if(AppInit2(argc, argv))
{
{
// Put this in a block, so that BitcoinGUI is cleaned up properly before
// calling Shutdown() in case of exceptions.
+
+ optionsModel.Upgrade(); // Must be done after AppInit2
+
BitcoinGUI window;
if (splashref)
splash.finish(&window);
- OptionsModel optionsModel(pwalletMain);
+
ClientModel clientModel(&optionsModel);
WalletModel walletModel(pwalletMain, &optionsModel);
guiref = &window;
window.setClientModel(&clientModel);
window.setWalletModel(&walletModel);
// If -min option passed, start window minimized.
if(GetBoolArg("-min"))
{
window.showMinimized();
}
else
{
window.show();
}
// Place this here as guiref has to be defined if we dont want to lose URLs
ipcInit();
// Check for URL in argv
for (int i = 1; i < argc; i++)
{
if (strlen(argv[i]) > 7 && strncasecmp(argv[i], "bitcoin:", 8) == 0)
{
const char *strURL = argv[i];
try {
boost::interprocess::message_queue mq(boost::interprocess::open_only, "BitcoinURL");
mq.try_send(strURL, strlen(strURL), 0);
}
catch (boost::interprocess::interprocess_exception &ex) {
}
}
}
app.exec();
guiref = 0;
}
Shutdown(NULL);
}
else
{
return 1;
}
} catch (std::exception& e) {
PrintException(&e, "Runaway exception");
} catch (...) {
PrintException(NULL, "Runaway exception");
}
return 0;
}
#endif // BITCOIN_QT_TEST
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index dd69093897..417e2b8646 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -1,163 +1,237 @@
#include "optionsmodel.h"
#include "bitcoinunits.h"
+#include <QSettings>
#include "headers.h"
#include "init.h"
-OptionsModel::OptionsModel(CWallet *wallet, QObject *parent) :
- QAbstractListModel(parent),
- wallet(wallet),
- nDisplayUnit(BitcoinUnits::BTC),
- bDisplayAddresses(false)
+OptionsModel::OptionsModel(QObject *parent) :
+ QAbstractListModel(parent)
{
- // Read our specific settings from the wallet db
- CWalletDB walletdb(wallet->strWalletFile);
- walletdb.ReadSetting("nDisplayUnit", nDisplayUnit);
- walletdb.ReadSetting("bDisplayAddresses", bDisplayAddresses);
+ Init();
}
+void OptionsModel::Init()
+{
+ QSettings settings;
+
+ // These are QT-only settings:
+ nDisplayUnit = settings.value("nDisplayUnit", BitcoinUnits::BTC).toInt();
+ bDisplayAddresses = settings.value("bDisplayAddresses", false).toBool();
+ fMinimizeToTray = settings.value("fMinimizeToTray", false).toBool();
+ fMinimizeOnClose = settings.value("fMinimizeOnClose", false).toBool();
+ nTransactionFee = settings.value("nTransactionFee").toLongLong();
+
+ // These are shared with core bitcoin; we want
+ // command-line options to override the GUI settings:
+ if (settings.contains("fUseUPnP"))
+ SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool());
+ if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool())
+ SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString());
+}
+
+bool OptionsModel::Upgrade()
+{
+ QSettings settings;
+
+ if (settings.contains("bImportFinished"))
+ return false; // Already upgraded
+
+ settings.setValue("bImportFinished", true);
+
+ // Move settings from old wallet.dat (if any):
+ CWalletDB walletdb("wallet.dat");
+
+ QList<QString> intOptions;
+ intOptions << "nDisplayUnit" << "nTransactionFee";
+ foreach(QString key, intOptions)
+ {
+ int value = 0;
+ if (walletdb.ReadSetting(key.toStdString(), value))
+ {
+ settings.setValue(key, value);
+ walletdb.EraseSetting(key.toStdString());
+ }
+ }
+ QList<QString> boolOptions;
+ boolOptions << "bDisplayAddresses" << "fMinimizeToTray" << "fMinimizeOnClose" << "fUseProxy" << "fUseUPnP";
+ foreach(QString key, boolOptions)
+ {
+ bool value = false;
+ if (walletdb.ReadSetting(key.toStdString(), value))
+ {
+ settings.setValue(key, value);
+ walletdb.EraseSetting(key.toStdString());
+ }
+ }
+ try
+ {
+ CAddress addrProxyAddress;
+ if (walletdb.ReadSetting("addrProxy", addrProxyAddress))
+ {
+ addrProxy = addrProxyAddress;
+ settings.setValue("addrProxy", addrProxy.ToStringIP().c_str());
+ walletdb.EraseSetting("addrProxy");
+ }
+ }
+ catch (std::ios_base::failure &e)
+ {
+ // 0.6.0rc1 saved this as a CService, which causes failure when parsing as a CAddress
+ if (walletdb.ReadSetting("addrProxy", addrProxy))
+ {
+ settings.setValue("addrProxy", addrProxy.ToStringIP().c_str());
+ walletdb.EraseSetting("addrProxy");
+ }
+ }
+ Init();
+
+ return true;
+}
+
+
int OptionsModel::rowCount(const QModelIndex & parent) const
{
return OptionIDRowCount;
}
QVariant OptionsModel::data(const QModelIndex & index, int role) const
{
if(role == Qt::EditRole)
{
+ QSettings settings;
switch(index.row())
{
case StartAtStartup:
return QVariant(GetStartOnSystemStartup());
case MinimizeToTray:
return QVariant(fMinimizeToTray);
case MapPortUPnP:
- return QVariant(fUseUPnP);
+ return settings.value("fUseUPnP", GetBoolArg("-upnp", true));
case MinimizeOnClose:
return QVariant(fMinimizeOnClose);
case ConnectSOCKS4:
- return QVariant(fUseProxy);
+ return settings.value("fUseProxy", false);
case ProxyIP:
return QVariant(QString::fromStdString(addrProxy.ToStringIP()));
case ProxyPort:
return QVariant(addrProxy.GetPort());
case Fee:
return QVariant(nTransactionFee);
case DisplayUnit:
return QVariant(nDisplayUnit);
case DisplayAddresses:
return QVariant(bDisplayAddresses);
default:
return QVariant();
}
}
return QVariant();
}
bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
bool successful = true; /* set to false on parse error */
if(role == Qt::EditRole)
{
- CWalletDB walletdb(wallet->strWalletFile);
+ QSettings settings;
switch(index.row())
{
case StartAtStartup:
successful = SetStartOnSystemStartup(value.toBool());
break;
case MinimizeToTray:
fMinimizeToTray = value.toBool();
- walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);
+ settings.setValue("fMinimizeToTray", fMinimizeToTray);
break;
case MapPortUPnP:
- fUseUPnP = value.toBool();
- walletdb.WriteSetting("fUseUPnP", fUseUPnP);
-#ifdef USE_UPNP
- MapPort(fUseUPnP);
-#endif
+ {
+ bool bUseUPnP = value.toBool();
+ settings.setValue("fUseUPnP", bUseUPnP);
+ MapPort(bUseUPnP);
+ }
break;
case MinimizeOnClose:
fMinimizeOnClose = value.toBool();
- walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);
+ settings.setValue("fMinimizeOnClose", fMinimizeOnClose);
break;
case ConnectSOCKS4:
fUseProxy = value.toBool();
- walletdb.WriteSetting("fUseProxy", fUseProxy);
+ settings.setValue("fUseProxy", fUseProxy);
break;
case ProxyIP:
{
// Use CAddress to parse and check IP
CNetAddr addr(value.toString().toStdString());
if (addr.IsValid())
{
addrProxy.SetIP(addr);
- walletdb.WriteSetting("addrProxy", CAddress(addrProxy));
+ settings.setValue("addrProxy", addrProxy.ToStringIP().c_str());
}
else
{
successful = false;
}
}
break;
case ProxyPort:
{
int nPort = atoi(value.toString().toAscii().data());
if (nPort > 0 && nPort < std::numeric_limits<unsigned short>::max())
{
addrProxy.SetPort(nPort);
- walletdb.WriteSetting("addrProxy", CAddress(addrProxy));
+ settings.setValue("addrProxy", addrProxy.ToStringIP().c_str());
}
else
{
successful = false;
}
}
break;
case Fee: {
nTransactionFee = value.toLongLong();
- walletdb.WriteSetting("nTransactionFee", nTransactionFee);
+ settings.setValue("nTransactionFee", nTransactionFee);
}
break;
case DisplayUnit: {
int unit = value.toInt();
nDisplayUnit = unit;
- walletdb.WriteSetting("nDisplayUnit", nDisplayUnit);
+ settings.setValue("nDisplayUnit", nDisplayUnit);
emit displayUnitChanged(unit);
}
case DisplayAddresses: {
bDisplayAddresses = value.toBool();
- walletdb.WriteSetting("bDisplayAddresses", bDisplayAddresses);
+ settings.setValue("bDisplayAddresses", bDisplayAddresses);
}
default:
break;
}
}
emit dataChanged(index, index);
return successful;
}
qint64 OptionsModel::getTransactionFee()
{
return nTransactionFee;
}
bool OptionsModel::getMinimizeToTray()
{
return fMinimizeToTray;
}
bool OptionsModel::getMinimizeOnClose()
{
return fMinimizeOnClose;
}
int OptionsModel::getDisplayUnit()
{
return nDisplayUnit;
}
bool OptionsModel::getDisplayAddresses()
{
return bDisplayAddresses;
}
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index 775362d636..0be70f8935 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -1,56 +1,59 @@
#ifndef OPTIONSMODEL_H
#define OPTIONSMODEL_H
#include <QAbstractListModel>
-class CWallet;
-
/** Interface from QT to configuration data structure for bitcoin client.
To QT, the options are presented as a list with the different options
laid out vertically.
This can be changed to a tree once the settings become sufficiently
complex.
*/
class OptionsModel : public QAbstractListModel
{
Q_OBJECT
public:
- explicit OptionsModel(CWallet *wallet, QObject *parent = 0);
+ explicit OptionsModel(QObject *parent = 0);
enum OptionID {
StartAtStartup, // bool
MinimizeToTray, // bool
MapPortUPnP, // bool
MinimizeOnClose, // bool
ConnectSOCKS4, // bool
ProxyIP, // QString
ProxyPort, // QString
Fee, // qint64
DisplayUnit, // BitcoinUnits::Unit
DisplayAddresses, // bool
OptionIDRowCount
};
+ void Init();
+
+ /* Migrate settings from wallet.dat after app initialization */
+ bool Upgrade(); /* returns true if settings upgraded */
+
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
/* Explicit getters */
qint64 getTransactionFee();
bool getMinimizeToTray();
bool getMinimizeOnClose();
int getDisplayUnit();
bool getDisplayAddresses();
private:
- // Wallet stores persistent options
- CWallet *wallet;
int nDisplayUnit;
bool bDisplayAddresses;
+ bool fMinimizeToTray;
+ bool fMinimizeOnClose;
signals:
void displayUnitChanged(int unit);
public slots:
};
#endif // OPTIONSMODEL_H
diff --git a/src/util.cpp b/src/util.cpp
index f1af91de27..88d70cd38f 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -1,1274 +1,1288 @@
// 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.
#include "headers.h"
#include "strlcpy.h"
#include <boost/algorithm/string/join.hpp>
#include <boost/program_options/detail/config_file.hpp>
#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>
using namespace std;
using namespace boost;
map<string, string> mapArgs;
map<string, vector<string> > mapMultiArgs;
bool fDebug = false;
bool fPrintToConsole = false;
bool fPrintToDebugger = false;
char pszSetDataDir[MAX_PATH] = "";
bool fRequestShutdown = false;
bool fShutdown = false;
bool fDaemon = false;
bool fServer = false;
bool fCommandLine = false;
string strMiscWarning;
bool fTestNet = false;
bool fNoListen = false;
bool fLogTimestamps = false;
CMedianFilter<int64> vTimeOffsets(200,0);
// Workaround for "multiple definition of `_tls_used'"
// http://svn.boost.org/trac/boost/ticket/4258
extern "C" void tss_cleanup_implemented() { }
// Init openssl library multithreading support
static boost::interprocess::interprocess_mutex** ppmutexOpenSSL;
void locking_callback(int mode, int i, const char* file, int line)
{
if (mode & CRYPTO_LOCK)
ppmutexOpenSSL[i]->lock();
else
ppmutexOpenSSL[i]->unlock();
}
// Init
class CInit
{
public:
CInit()
{
// Init openssl library multithreading support
ppmutexOpenSSL = (boost::interprocess::interprocess_mutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(boost::interprocess::interprocess_mutex*));
for (int i = 0; i < CRYPTO_num_locks(); i++)
ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex();
CRYPTO_set_locking_callback(locking_callback);
#ifdef WIN32
// Seed random number generator with screen scrape and other hardware sources
RAND_screen();
#endif
// Seed random number generator with performance counter
RandAddSeed();
}
~CInit()
{
// Shutdown openssl library multithreading support
CRYPTO_set_locking_callback(NULL);
for (int i = 0; i < CRYPTO_num_locks(); i++)
delete ppmutexOpenSSL[i];
OPENSSL_free(ppmutexOpenSSL);
}
}
instance_of_cinit;
void RandAddSeed()
{
// Seed with CPU performance counter
int64 nCounter = GetPerformanceCounter();
RAND_add(&nCounter, sizeof(nCounter), 1.5);
memset(&nCounter, 0, sizeof(nCounter));
}
void RandAddSeedPerfmon()
{
RandAddSeed();
// This can take up to 2 seconds, so only do it every 10 minutes
static int64 nLastPerfmon;
if (GetTime() < nLastPerfmon + 10 * 60)
return;
nLastPerfmon = GetTime();
#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];
memset(pdata, 0, sizeof(pdata));
unsigned long nSize = sizeof(pdata);
long ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
RegCloseKey(HKEY_PERFORMANCE_DATA);
if (ret == ERROR_SUCCESS)
{
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);
}
#endif
}
uint64 GetRand(uint64 nMax)
{
if (nMax == 0)
return 0;
// The range of the random source must be a multiple of the modulus
// to give every possible output value an equal possibility
uint64 nRange = (std::numeric_limits<uint64>::max() / nMax) * nMax;
uint64 nRand = 0;
do
RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
while (nRand >= nRange);
return (nRand % nMax);
}
int GetRandInt(int nMax)
{
return GetRand(nMax);
}
inline int OutputDebugStringF(const char* pszFormat, ...)
{
int ret = 0;
if (fPrintToConsole)
{
// print to console
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
ret = vprintf(pszFormat, arg_ptr);
va_end(arg_ptr);
}
else
{
// print to debug.log
static FILE* fileout = NULL;
if (!fileout)
{
char pszFile[MAX_PATH+100];
GetDataDir(pszFile);
strlcat(pszFile, "/debug.log", sizeof(pszFile));
fileout = fopen(pszFile, "a");
if (fileout) setbuf(fileout, NULL); // unbuffered
}
if (fileout)
{
static bool fStartedNewLine = true;
// Debug print useful for profiling
if (fLogTimestamps && fStartedNewLine)
fprintf(fileout, "%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
if (pszFormat[strlen(pszFormat) - 1] == '\n')
fStartedNewLine = true;
else
fStartedNewLine = false;
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
ret = vfprintf(fileout, pszFormat, arg_ptr);
va_end(arg_ptr);
}
}
#ifdef WIN32
if (fPrintToDebugger)
{
static CCriticalSection cs_OutputDebugStringF;
// accumulate a line at a time
CRITICAL_BLOCK(cs_OutputDebugStringF)
{
static char pszBuffer[50000];
static char* pend;
if (pend == NULL)
pend = pszBuffer;
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
int limit = END(pszBuffer) - pend - 2;
int ret = _vsnprintf(pend, limit, 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'))
{
p2++;
char c = *p2;
*p2 = '\0';
OutputDebugStringA(p1);
*p2 = c;
p1 = p2;
}
if (p1 != pszBuffer)
memmove(pszBuffer, p1, pend - p1 + 1);
pend -= (p1 - pszBuffer);
}
}
#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 >= limit)
{
ret = limit - 1;
buffer[limit-1] = 0;
}
return ret;
}
string strprintf(const std::string &format, ...)
{
char buffer[50000];
char* p = buffer;
int limit = sizeof(buffer);
int ret;
loop
{
va_list arg_ptr;
va_start(arg_ptr, format);
ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
va_end(arg_ptr);
if (ret >= 0 && ret < limit)
break;
if (p != buffer)
delete[] p;
limit *= 2;
p = new char[limit];
if (p == NULL)
throw std::bad_alloc();
}
string str(p, p+ret);
if (p != buffer)
delete[] p;
return str;
}
bool error(const std::string &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);
va_end(arg_ptr);
if (ret < 0 || ret >= limit)
{
ret = limit - 1;
buffer[limit-1] = 0;
}
printf("ERROR: %s\n", buffer);
return false;
}
void ParseString(const string& str, char c, vector<string>& v)
{
if (str.empty())
return;
string::size_type i1 = 0;
string::size_type i2;
loop
{
i2 = str.find(c, i1);
if (i2 == str.npos)
{
v.push_back(str.substr(i1));
return;
}
v.push_back(str.substr(i1, i2-i1));
i1 = i2+1;
}
}
string FormatMoney(int64 n, bool fPlus)
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
int64 n_abs = (n > 0 ? n : -n);
int64 quotient = n_abs/COIN;
int64 remainder = n_abs%COIN;
string str = strprintf("%"PRI64d".%08"PRI64d, quotient, remainder);
// Right-trim excess 0's before the decimal point:
int nTrim = 0;
for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i)
++nTrim;
if (nTrim)
str.erase(str.size()-nTrim, nTrim);
if (n < 0)
str.insert((unsigned int)0, 1, '-');
else if (fPlus && n > 0)
str.insert((unsigned int)0, 1, '+');
return str;
}
bool ParseMoney(const string& str, int64& nRet)
{
return ParseMoney(str.c_str(), nRet);
}
bool ParseMoney(const char* pszIn, int64& nRet)
{
string strWhole;
int64 nUnits = 0;
const char* p = pszIn;
while (isspace(*p))
p++;
for (; *p; p++)
{
if (*p == '.')
{
p++;
int64 nMult = CENT*10;
while (isdigit(*p) && (nMult > 0))
{
nUnits += nMult * (*p++ - '0');
nMult /= 10;
}
break;
}
if (isspace(*p))
break;
if (!isdigit(*p))
return false;
strWhole.insert(strWhole.end(), *p);
}
for (; *p; p++)
if (!isspace(*p))
return false;
if (strWhole.size() > 10) // guard against 63 bit overflow
return false;
if (nUnits < 0 || nUnits > COIN)
return false;
int64 nWhole = atoi64(strWhole);
int64 nValue = nWhole*COIN + nUnits;
nRet = nValue;
return true;
}
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)
{
BOOST_FOREACH(unsigned char c, str)
{
if (phexdigit[c] < 0)
return false;
}
return (str.size() > 0) && (str.size()%2 == 0);
}
vector<unsigned char> ParseHex(const char* psz)
{
// convert hex dump to vector
vector<unsigned char> vch;
loop
{
while (isspace(*psz))
psz++;
char c = phexdigit[(unsigned char)*psz++];
if (c == (char)-1)
break;
unsigned char n = (c << 4);
c = phexdigit[(unsigned char)*psz++];
if (c == (char)-1)
break;
n |= c;
vch.push_back(n);
}
return vch;
}
vector<unsigned char> ParseHex(const string& str)
{
return ParseHex(str.c_str());
}
static void InterpretNegativeSetting(string name, map<string, string>& 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();
for (int i = 1; i < argc; i++)
{
char psz[10000];
strlcpy(psz, argv[i], sizeof(psz));
char* pszValue = (char*)"";
if (strchr(psz, '='))
{
pszValue = strchr(psz, '=');
*pszValue++ = '\0';
}
#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+/";
string strRet="";
strRet.reserve((len+2)/3*4);
int mode=0, left=0;
const unsigned char *pchEnd = pch+len;
while (pch<pchEnd)
{
int enc = *(pch++);
switch (mode)
{
case 0: // we have no bits
strRet += pbase64[enc >> 2];
left = (enc & 3) << 4;
mode = 1;
break;
case 1: // we have two bits
strRet += pbase64[left | (enc >> 4)];
left = (enc & 15) << 2;
mode = 2;
break;
case 2: // we have four bits
strRet += pbase64[left | (enc >> 6)];
strRet += pbase64[enc & 63];
mode = 0;
break;
}
}
if (mode)
{
strRet += pbase64[left];
strRet += '=';
if (mode == 1)
strRet += '=';
}
return strRet;
}
string EncodeBase64(const string& str)
{
return EncodeBase64((const unsigned char*)str.c_str(), str.size());
}
vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
{
static const int decode64_table[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, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
-1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
if (pfInvalid)
*pfInvalid = false;
vector<unsigned char> vchRet;
vchRet.reserve(strlen(p)*3/4);
int mode = 0;
int left = 0;
while (1)
{
int dec = decode64_table[*p];
if (dec == -1) break;
p++;
switch (mode)
{
case 0: // we have no bits and get 6
left = dec;
mode = 1;
break;
case 1: // we have 6 bits and keep 4
vchRet.push_back((left<<2) | (dec>>4));
left = dec & 15;
mode = 2;
break;
case 2: // we have 4 bits and get 6, we keep 2
vchRet.push_back((left<<4) | (dec>>2));
left = dec & 3;
mode = 3;
break;
case 3: // we have 2 bits and get 6
vchRet.push_back((left<<6) | dec);
mode = 0;
break;
}
}
if (pfInvalid)
switch (mode)
{
case 0: // 4n base64 characters processed: ok
break;
case 1: // 4n+1 base64 character processed: impossible
*pfInvalid = true;
break;
case 2: // 4n+2 base64 characters processed: require '=='
if (left || p[0] != '=' || p[1] != '=' || decode64_table[p[2]] != -1)
*pfInvalid = true;
break;
case 3: // 4n+3 base64 characters processed: require '='
if (left || p[0] != '=' || decode64_table[p[1]] != -1)
*pfInvalid = true;
break;
}
return vchRet;
}
string DecodeBase64(const string& str)
{
vector<unsigned char> vchRet = DecodeBase64(str.c_str());
return string((const char*)&vchRet[0], vchRet.size());
}
bool WildcardMatch(const char* psz, const char* mask)
{
loop
{
switch (*mask)
{
case '\0':
return (*psz == '\0');
case '*':
return WildcardMatch(psz, mask+1) || (*psz && WildcardMatch(psz+1, mask));
case '?':
if (*psz == '\0')
return false;
break;
default:
if (*psz != *mask)
return false;
break;
}
psz++;
mask++;
}
}
bool WildcardMatch(const string& str, const string& mask)
{
return WildcardMatch(str.c_str(), mask.c_str());
}
void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
{
#ifdef WIN32
char pszModule[MAX_PATH];
pszModule[0] = '\0';
GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
#else
const char* pszModule = "bitcoin";
#endif
if (pex)
snprintf(pszMessage, 1000,
"EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
else
snprintf(pszMessage, 1000,
"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);
}
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;
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];
FormatException(pszMessage, pex, pszThread);
printf("\n\n************************\n%s\n", pszMessage);
fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
strMiscWarning = pszMessage;
}
#ifdef WIN32
typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
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)
{
PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =
(PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");
if (pSHGetSpecialFolderPath)
(*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);
FreeModule(hShell32);
}
// Backup option
if (pszPath[0] == '\0')
{
if (nFolder == CSIDL_STARTUP)
{
strcpy(pszPath, getenv("USERPROFILE"));
strcat(pszPath, "\\Start Menu\\Programs\\Startup");
}
else if (nFolder == CSIDL_APPDATA)
{
strcpy(pszPath, getenv("APPDATA"));
}
}
return pszPath;
}
#endif
string GetDefaultDataDir()
{
// Windows: C:\Documents and Settings\username\Application Data\Bitcoin
// Mac: ~/Library/Application Support/Bitcoin
// Unix: ~/.bitcoin
#ifdef WIN32
// Windows
return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
#else
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
pszHome = (char*)"/";
string strHome = pszHome;
if (strHome[strHome.size()-1] != '/')
strHome += '/';
#ifdef MAC_OSX
// Mac
strHome += "Library/Application Support/";
filesystem::create_directory(strHome.c_str());
return strHome + "Bitcoin";
#else
// Unix
return strHome + ".bitcoin";
#endif
#endif
}
void GetDataDir(char* pszDir)
{
// pszDir must be at least MAX_PATH length.
int nVariation;
if (pszSetDataDir[0] != 0)
{
strlcpy(pszDir, pszSetDataDir, MAX_PATH);
nVariation = 0;
}
else
{
// This can be called during exceptions by printf, so we cache the
// value so we don't have to do memory allocations after that.
static char pszCachedDir[MAX_PATH];
if (pszCachedDir[0] == 0)
strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir));
strlcpy(pszDir, pszCachedDir, MAX_PATH);
nVariation = 1;
}
if (fTestNet)
{
char* p = pszDir + strlen(pszDir);
if (p > pszDir && p[-1] != '/' && p[-1] != '\\')
*p++ = '/';
strcpy(p, "testnet");
nVariation += 2;
}
static bool pfMkdir[4];
if (!pfMkdir[nVariation])
{
pfMkdir[nVariation] = true;
boost::filesystem::create_directory(pszDir);
}
}
string GetDataDir()
{
char pszDir[MAX_PATH];
GetDataDir(pszDir);
return pszDir;
}
string GetConfigFile()
{
namespace fs = boost::filesystem;
fs::path pathConfig(GetArg("-conf", "bitcoin.conf"));
if (!pathConfig.is_complete())
pathConfig = fs::path(GetDataDir()) / pathConfig;
return pathConfig.string();
}
-void ReadConfigFile(map<string, string>& mapSettingsRet,
+bool ReadConfigFile(map<string, string>& mapSettingsRet,
map<string, vector<string> >& 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<string> setOptions;
setOptions.insert("*");
for (pod::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)
InterpretNegativeSetting(strKey, mapSettingsRet);
}
mapMultiSettingsRet[strKey].push_back(it->value[0]);
}
+ return true;
}
string GetPidFile()
{
namespace fs = boost::filesystem;
fs::path pathConfig(GetArg("-pid", "bitcoind.pid"));
if (!pathConfig.is_complete())
pathConfig = fs::path(GetDataDir()) / pathConfig;
return pathConfig.string();
}
void CreatePidFile(string pidFile, pid_t pid)
{
FILE* file = fopen(pidFile.c_str(), "w");
if (file)
{
fprintf(file, "%d\n", pid);
fclose(file);
}
}
int GetFilesize(FILE* file)
{
int nSavePos = ftell(file);
int nFilesize = -1;
if (fseek(file, 0, SEEK_END) == 0)
nFilesize = ftell(file);
fseek(file, nSavePos, SEEK_SET);
return nFilesize;
}
void ShrinkDebugFile()
{
// Scroll debug.log if it's getting too big
string strFile = GetDataDir() + "/debug.log";
FILE* file = fopen(strFile.c_str(), "r");
if (file && GetFilesize(file) > 10 * 1000000)
{
// Restart the file with some of the end
char pch[200000];
fseek(file, -sizeof(pch), SEEK_END);
int nBytes = fread(pch, 1, sizeof(pch), file);
fclose(file);
file = fopen(strFile.c_str(), "w");
if (file)
{
fwrite(pch, 1, nBytes, file);
fclose(file);
}
}
}
//
// "Never go to sea with two chronometers; take one or three."
// Our three time sources are:
// - System clock
// - Median of other nodes's clocks
// - The user (asking the user to fix the system clock if the first two disagree)
//
static int64 nMockTime = 0; // For unit testing
int64 GetTime()
{
if (nMockTime) return nMockTime;
return time(NULL);
}
void SetMockTime(int64 nMockTimeIn)
{
nMockTime = nMockTimeIn;
}
static int64 nTimeOffset = 0;
int64 GetAdjustedTime()
{
return GetTime() + nTimeOffset;
}
void AddTimeData(const CNetAddr& ip, int64 nTime)
{
int64 nOffsetSample = nTime - GetTime();
// Ignore duplicates
static set<CNetAddr> setKnown;
if (!setKnown.insert(ip).second)
return;
// Add data
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)
{
int64 nMedian = vTimeOffsets.median();
std::vector<int64> vSorted = vTimeOffsets.sorted();
// Only let other nodes change our time by so much
if (abs64(nMedian) < 70 * 60)
{
nTimeOffset = nMedian;
}
else
{
nTimeOffset = 0;
static bool fDone;
if (!fDone)
{
// If nobody has a time different than ours but within 5 minutes of ours, give a warning
bool fMatch = false;
BOOST_FOREACH(int64 nOffset, vSorted)
if (nOffset != 0 && abs64(nOffset) < 5 * 60)
fMatch = true;
if (!fMatch)
{
fDone = true;
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));
}
}
}
if (fDebug) {
BOOST_FOREACH(int64 n, vSorted)
printf("%+"PRI64d" ", n);
printf("| ");
}
printf("nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
}
}
string FormatVersion(int nVersion)
{
if (nVersion%100 == 0)
return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100);
else
return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100);
}
string FormatFullVersion()
{
string s = FormatVersion(CLIENT_VERSION);
if (VERSION_IS_BETA) {
s += "-";
s += _("beta");
}
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<std::string>& comments)
{
std::ostringstream ss;
ss << "/";
ss << name << ":" << FormatVersion(nClientVersion);
if (!comments.empty())
ss << "(" << boost::algorithm::join(comments, "; ") << ")";
ss << "/";
return ss.str();
}
#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<CCriticalSection*, CLockLocation> > LockStack;
static boost::interprocess::interprocess_mutex dd_mutex;
static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lockorders;
static boost::thread_specific_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCriticalSection*>& mismatch, const LockStack& s1, const LockStack& s2)
{
printf("POTENTIAL DEADLOCK DETECTED\n");
printf("Previous lock order was:\n");
BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, 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(CCriticalSection*, 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(CCriticalSection* c, const CLockLocation& locklocation)
{
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));
BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, (*lockstack))
{
if (i.first == c) break;
std::pair<CCriticalSection*, CCriticalSection*> p1 = std::make_pair(i.first, c);
if (lockorders.count(p1))
continue;
lockorders[p1] = (*lockstack);
std::pair<CCriticalSection*, CCriticalSection*> 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 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()
{
mutex.unlock();
pop_lock();
}
bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nLine)
{
push_lock(this, CLockLocation(pszName, pszFile, nLine));
bool result = mutex.try_lock();
if (!result) pop_lock();
return result;
}
#else
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()
{
mutex.unlock();
}
bool CCriticalSection::TryEnter(const char*, const char*, int)
{
bool result = mutex.try_lock();
return result;
}
#endif /* DEBUG_LOCKORDER */
diff --git a/src/util.h b/src/util.h
index ddc8791b38..31d3275290 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,732 +1,732 @@
// 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.
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
#include "uint256.h"
#ifndef WIN32
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include <map>
#include <vector>
#include <string>
#include <boost/thread.hpp>
#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
#include <boost/date_time/gregorian/gregorian_types.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <openssl/sha.h>
#include <openssl/ripemd.h>
#include "netbase.h"
typedef long long int64;
typedef unsigned long long uint64;
#define loop for (;;)
#define BEGIN(a) ((char*)&(a))
#define END(a) ((char*)&((&(a))[1]))
#define UBEGIN(a) ((unsigned char*)&(a))
#define UEND(a) ((unsigned char*)&((&(a))[1]))
#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0]))
#define printf OutputDebugStringF
#ifdef snprintf
#undef snprintf
#endif
#define snprintf my_snprintf
#ifndef PRI64d
#if defined(_MSC_VER) || defined(__MSVCRT__)
#define PRI64d "I64d"
#define PRI64u "I64u"
#define PRI64x "I64x"
#else
#define PRI64d "lld"
#define PRI64u "llu"
#define PRI64x "llx"
#endif
#endif
// This is needed because the foreach macro can't get over the comma in pair<t1, t2>
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
// Align by increasing pointer, must have extra space at end of buffer
template <size_t nBytes, typename T>
T* alignup(T* p)
{
union
{
T* ptr;
size_t n;
} u;
u.ptr = p;
u.n = (u.n + (nBytes-1)) & ~(nBytes-1);
return u.ptr;
}
#ifdef WIN32
#define MSG_NOSIGNAL 0
#define MSG_DONTWAIT 0
#ifndef S_IRUSR
#define S_IRUSR 0400
#define S_IWUSR 0200
#endif
#define unlink _unlink
#else
#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d)
#define strlwr(psz) to_lower(psz)
#define _strlwr(psz) to_lower(psz)
#define MAX_PATH 1024
#define Beep(n1,n2) (0)
inline void Sleep(int64 n)
{
boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(n));
}
#endif
#if !defined(QT_GUI)
inline const char* _(const char* psz)
{
return psz;
}
#endif
extern std::map<std::string, std::string> mapArgs;
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
extern bool fDebug;
extern bool fPrintToConsole;
extern bool fPrintToDebugger;
extern char pszSetDataDir[MAX_PATH];
extern bool fRequestShutdown;
extern bool fShutdown;
extern bool fDaemon;
extern bool fServer;
extern bool fCommandLine;
extern std::string strMiscWarning;
extern bool fTestNet;
extern bool fNoListen;
extern bool fLogTimestamps;
void RandAddSeed();
void RandAddSeedPerfmon();
int OutputDebugStringF(const char* pszFormat, ...);
int my_snprintf(char* buffer, size_t limit, const char* format, ...);
std::string strprintf(const std::string &format, ...);
bool error(const std::string &format, ...);
void LogException(std::exception* pex, const char* pszThread);
void PrintException(std::exception* pex, const char* pszThread);
void PrintExceptionContinue(std::exception* pex, const char* pszThread);
void ParseString(const std::string& str, char c, std::vector<std::string>& v);
std::string FormatMoney(int64 n, bool fPlus=false);
bool ParseMoney(const std::string& str, int64& nRet);
bool ParseMoney(const char* pszIn, int64& nRet);
std::vector<unsigned char> ParseHex(const char* psz);
std::vector<unsigned char> ParseHex(const std::string& str);
bool IsHex(const std::string& str);
std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
std::string DecodeBase64(const std::string& str);
std::string EncodeBase64(const unsigned char* pch, size_t len);
std::string EncodeBase64(const std::string& str);
void ParseParameters(int argc, const char*const argv[]);
bool WildcardMatch(const char* psz, const char* mask);
bool WildcardMatch(const std::string& str, const std::string& mask);
int GetFilesize(FILE* file);
void GetDataDir(char* pszDirRet);
std::string GetConfigFile();
std::string GetPidFile();
void CreatePidFile(std::string pidFile, pid_t pid);
-void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
+bool ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
#ifdef WIN32
std::string MyGetSpecialFolderPath(int nFolder, bool fCreate);
#endif
std::string GetDefaultDataDir();
std::string GetDataDir();
void ShrinkDebugFile();
int GetRandInt(int nMax);
uint64 GetRand(uint64 nMax);
int64 GetTime();
void SetMockTime(int64 nMockTimeIn);
int64 GetAdjustedTime();
std::string FormatFullVersion();
std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
void AddTimeData(const CNetAddr& ip, int64 nTime);
// Wrapper to automatically initialize mutex
class CCriticalSection
{
protected:
boost::interprocess::interprocess_recursive_mutex mutex;
public:
explicit CCriticalSection() { }
~CCriticalSection() { }
void Enter(const char* pszName, const char* pszFile, int nLine);
void Leave();
bool TryEnter(const char* pszName, const char* pszFile, int nLine);
};
// Automatically leave critical section when leaving block, needed for exception safety
class CCriticalBlock
{
protected:
CCriticalSection* pcs;
public:
CCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
{
pcs = &csIn;
pcs->Enter(pszName, pszFile, nLine);
}
operator bool() const
{
return true;
}
~CCriticalBlock()
{
pcs->Leave();
}
};
#define CRITICAL_BLOCK(cs) \
if (CCriticalBlock criticalblock = CCriticalBlock(cs, #cs, __FILE__, __LINE__))
#define ENTER_CRITICAL_SECTION(cs) \
(cs).Enter(#cs, __FILE__, __LINE__)
#define LEAVE_CRITICAL_SECTION(cs) \
(cs).Leave()
class CTryCriticalBlock
{
protected:
CCriticalSection* pcs;
public:
CTryCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine)
{
pcs = (csIn.TryEnter(pszName, pszFile, nLine) ? &csIn : NULL);
}
operator bool() const
{
return Entered();
}
~CTryCriticalBlock()
{
if (pcs)
{
pcs->Leave();
}
}
bool Entered() const { return pcs != NULL; }
};
#define TRY_CRITICAL_BLOCK(cs) \
if (CTryCriticalBlock criticalblock = CTryCriticalBlock(cs, #cs, __FILE__, __LINE__))
// This is exactly like std::string, but with a custom allocator.
// (secure_allocator<> is defined in serialize.h)
typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
inline std::string i64tostr(int64 n)
{
return strprintf("%"PRI64d, n);
}
inline std::string itostr(int n)
{
return strprintf("%d", n);
}
inline int64 atoi64(const char* psz)
{
#ifdef _MSC_VER
return _atoi64(psz);
#else
return strtoll(psz, NULL, 10);
#endif
}
inline int64 atoi64(const std::string& str)
{
#ifdef _MSC_VER
return _atoi64(str.c_str());
#else
return strtoll(str.c_str(), NULL, 10);
#endif
}
inline int atoi(const std::string& str)
{
return atoi(str.c_str());
}
inline int roundint(double d)
{
return (int)(d > 0 ? d + 0.5 : d - 0.5);
}
inline int64 roundint64(double d)
{
return (int64)(d > 0 ? d + 0.5 : d - 0.5);
}
inline int64 abs64(int64 n)
{
return (n >= 0 ? n : -n);
}
template<typename T>
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
{
if (itbegin == itend)
return "";
const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
std::string str;
str.reserve((pend-pbegin) * (fSpaces ? 3 : 2));
for (const unsigned char* p = pbegin; p != pend; p++)
str += strprintf((fSpaces && p != pend-1 ? "%02x " : "%02x"), *p);
return str;
}
inline std::string HexStr(const std::vector<unsigned char>& vch, bool fSpaces=false)
{
return HexStr(vch.begin(), vch.end(), fSpaces);
}
template<typename T>
std::string HexNumStr(const T itbegin, const T itend, bool f0x=true)
{
if (itbegin == itend)
return "";
const unsigned char* pbegin = (const unsigned char*)&itbegin[0];
const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]);
std::string str = (f0x ? "0x" : "");
str.reserve(str.size() + (pend-pbegin) * 2);
for (const unsigned char* p = pend-1; p >= pbegin; p--)
str += strprintf("%02x", *p);
return str;
}
inline std::string HexNumStr(const std::vector<unsigned char>& vch, bool f0x=true)
{
return HexNumStr(vch.begin(), vch.end(), f0x);
}
template<typename T>
void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSpaces=true)
{
printf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str());
}
inline void PrintHex(const std::vector<unsigned char>& vch, const char* pszFormat="%s", bool fSpaces=true)
{
printf(pszFormat, HexStr(vch, fSpaces).c_str());
}
inline int64 GetPerformanceCounter()
{
int64 nCounter = 0;
#ifdef WIN32
QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
#else
timeval t;
gettimeofday(&t, NULL);
nCounter = t.tv_sec * 1000000 + t.tv_usec;
#endif
return nCounter;
}
inline int64 GetTimeMillis()
{
return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) -
boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
}
inline std::string DateTimeStrFormat(const char* pszFormat, int64 nTime)
{
time_t n = nTime;
struct tm* ptmTime = gmtime(&n);
char pszTime[200];
strftime(pszTime, sizeof(pszTime), pszFormat, ptmTime);
return pszTime;
}
template<typename T>
void skipspaces(T& it)
{
while (isspace(*it))
++it;
}
inline bool IsSwitchChar(char c)
{
#ifdef WIN32
return c == '-' || c == '/';
#else
return c == '-';
#endif
}
/**
* Return string argument or default value
*
* @param strArg Argument to get (e.g. "-foo")
* @param default (e.g. "1")
* @return command-line argument or default value
*/
std::string GetArg(const std::string& strArg, const std::string& strDefault);
/**
* Return integer argument or default value
*
* @param strArg Argument to get (e.g. "-foo")
* @param default (e.g. 1)
* @return command-line argument (0 if invalid number) or default value
*/
int64 GetArg(const std::string& strArg, int64 nDefault);
/**
* Return boolean argument or default value
*
* @param strArg Argument to get (e.g. "-foo")
* @param default (true or false)
* @return command-line argument or default value
*/
bool GetBoolArg(const std::string& strArg, bool fDefault=false);
/**
* Set an argument if it doesn't already have a value
*
* @param strArg Argument to set (e.g. "-foo")
* @param strValue Value (e.g. "1")
* @return true if argument gets set, false if it already had a value
*/
bool SoftSetArg(const std::string& strArg, const std::string& strValue);
/**
* Set a boolean argument if it doesn't already have a value
*
* @param strArg Argument to set (e.g. "-foo")
* @param fValue Value (e.g. false)
* @return true if argument gets set, false if it already had a value
*/
bool SoftSetBoolArg(const std::string& strArg, bool fValue);
// Randomize the stack to help protect against buffer overrun exploits
#define IMPLEMENT_RANDOMIZE_STACK(ThreadFn) \
{ \
static char nLoops; \
if (nLoops <= 0) \
nLoops = GetRand(20) + 1; \
if (nLoops-- > 1) \
{ \
ThreadFn; \
return; \
} \
}
#define CATCH_PRINT_EXCEPTION(pszFn) \
catch (std::exception& e) { \
PrintException(&e, (pszFn)); \
} catch (...) { \
PrintException(NULL, (pszFn)); \
}
template<typename T1>
inline uint256 Hash(const T1 pbegin, const T1 pend)
{
static unsigned char pblank[1];
uint256 hash1;
SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
uint256 hash2;
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
template<typename T1, typename T2>
inline uint256 Hash(const T1 p1begin, const T1 p1end,
const T2 p2begin, const T2 p2end)
{
static unsigned char pblank[1];
uint256 hash1;
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
SHA256_Final((unsigned char*)&hash1, &ctx);
uint256 hash2;
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
template<typename T1, typename T2, typename T3>
inline uint256 Hash(const T1 p1begin, const T1 p1end,
const T2 p2begin, const T2 p2end,
const T3 p3begin, const T3 p3end)
{
static unsigned char pblank[1];
uint256 hash1;
SHA256_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, (p1begin == p1end ? pblank : (unsigned char*)&p1begin[0]), (p1end - p1begin) * sizeof(p1begin[0]));
SHA256_Update(&ctx, (p2begin == p2end ? pblank : (unsigned char*)&p2begin[0]), (p2end - p2begin) * sizeof(p2begin[0]));
SHA256_Update(&ctx, (p3begin == p3end ? pblank : (unsigned char*)&p3begin[0]), (p3end - p3begin) * sizeof(p3begin[0]));
SHA256_Final((unsigned char*)&hash1, &ctx);
uint256 hash2;
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
template<typename T>
uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
{
// Most of the time is spent allocating and deallocating CDataStream's
// buffer. If this ever needs to be optimized further, make a CStaticStream
// class with its buffer on the stack.
CDataStream ss(nType, nVersion);
ss.reserve(10000);
ss << obj;
return Hash(ss.begin(), ss.end());
}
inline uint160 Hash160(const std::vector<unsigned char>& vch)
{
uint256 hash1;
SHA256(&vch[0], vch.size(), (unsigned char*)&hash1);
uint160 hash2;
RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
// Median filter over a stream of values
// Returns the median of the last N numbers
template <typename T> class CMedianFilter
{
private:
std::vector<T> vValues;
std::vector<T> vSorted;
int nSize;
public:
CMedianFilter(int size, T initial_value):
nSize(size)
{
vValues.reserve(size);
vValues.push_back(initial_value);
vSorted = vValues;
}
void input(T value)
{
if(vValues.size() == nSize)
{
vValues.erase(vValues.begin());
}
vValues.push_back(value);
vSorted.resize(vValues.size());
std::copy(vValues.begin(), vValues.end(), vSorted.begin());
std::sort(vSorted.begin(), vSorted.end());
}
T median() const
{
int size = vSorted.size();
assert(size>0);
if(size & 1) // Odd number of elements
{
return vSorted[size/2];
}
else // Even number of elements
{
return (vSorted[size/2-1] + vSorted[size/2]) / 2;
}
}
int size() const
{
return vValues.size();
}
std::vector<T> sorted () const
{
return vSorted;
}
};
// Note: It turns out we might have been able to use boost::thread
// by using TerminateThread(boost::thread.native_handle(), 0);
#ifdef WIN32
typedef HANDLE pthread_t;
inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
{
DWORD nUnused = 0;
HANDLE hthread =
CreateThread(
NULL, // default security
0, // inherit stack size from parent
(LPTHREAD_START_ROUTINE)pfn, // function pointer
parg, // argument
0, // creation option, start immediately
&nUnused); // thread identifier
if (hthread == NULL)
{
printf("Error: CreateThread() returned %d\n", GetLastError());
return (pthread_t)0;
}
if (!fWantHandle)
{
CloseHandle(hthread);
return (pthread_t)-1;
}
return hthread;
}
inline void SetThreadPriority(int nPriority)
{
SetThreadPriority(GetCurrentThread(), nPriority);
}
#else
inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
{
pthread_t hthread = 0;
int ret = pthread_create(&hthread, NULL, (void*(*)(void*))pfn, parg);
if (ret != 0)
{
printf("Error: pthread_create() returned %d\n", ret);
return (pthread_t)0;
}
if (!fWantHandle)
{
pthread_detach(hthread);
return (pthread_t)-1;
}
return hthread;
}
#define THREAD_PRIORITY_LOWEST PRIO_MAX
#define THREAD_PRIORITY_BELOW_NORMAL 2
#define THREAD_PRIORITY_NORMAL 0
#define THREAD_PRIORITY_ABOVE_NORMAL 0
inline void SetThreadPriority(int nPriority)
{
// It's unclear if it's even possible to change thread priorities on Linux,
// but we really and truly need it for the generation threads.
#ifdef PRIO_THREAD
setpriority(PRIO_THREAD, 0, nPriority);
#else
setpriority(PRIO_PROCESS, 0, nPriority);
#endif
}
inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode)
{
return (pthread_cancel(hthread) == 0);
}
inline void ExitThread(size_t nExitCode)
{
pthread_exit((void*)nExitCode);
}
#endif
inline bool AffinityBugWorkaround(void(*pfn)(void*))
{
#ifdef WIN32
// Sometimes after a few hours affinity gets stuck on one processor
DWORD_PTR dwProcessAffinityMask = -1;
DWORD_PTR dwSystemAffinityMask = -1;
GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask);
DWORD dwPrev1 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
DWORD dwPrev2 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask);
if (dwPrev2 != dwProcessAffinityMask)
{
printf("AffinityBugWorkaround() : SetThreadAffinityMask=%d, ProcessAffinityMask=%d, restarting thread\n", dwPrev2, dwProcessAffinityMask);
if (!CreateThread(pfn, NULL))
printf("Error: CreateThread() failed\n");
return true;
}
#endif
return false;
}
inline uint32_t ByteReverse(uint32_t value)
{
value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
return (value<<16) | (value>>16);
}
#endif

File Metadata

Mime Type
text/x-diff
Expires
Sun, Mar 2, 09:06 (1 d, 1 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187162
Default Alt Text
(99 KB)

Event Timeline