diff options
author | s_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b> | 2009-11-01 01:16:51 +0000 |
---|---|---|
committer | s_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b> | 2009-11-01 01:16:51 +0000 |
commit | 4ac57f013e20da2d0f87fff69625cbd4419089f3 (patch) | |
tree | 8120216e7ebfdc54244835dfa5650f1181b57025 | |
parent | 5750932cdf72ea9b5e64b8a05b43c42f5acb417d (diff) |
move debug.log and db.log to data dir, portable GetDataDir, optimize GetBalance, fix repaint bogdown, -addnode and -? switches
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@25 1a98c847-1fd6-4fd8-948a-caf3550aa51b
-rw-r--r-- | build.txt | 2 | ||||
-rw-r--r-- | db.cpp | 19 | ||||
-rw-r--r-- | irc.cpp | 7 | ||||
-rw-r--r-- | irc.h | 5 | ||||
-rw-r--r-- | main.cpp | 50 | ||||
-rw-r--r-- | main.h | 20 | ||||
-rw-r--r-- | net.cpp | 34 | ||||
-rw-r--r-- | net.h | 78 | ||||
-rw-r--r-- | ui.cpp | 457 | ||||
-rw-r--r-- | ui.h | 5 | ||||
-rw-r--r-- | util.cpp | 82 | ||||
-rw-r--r-- | util.h | 39 |
12 files changed, 416 insertions, 382 deletions
@@ -10,7 +10,7 @@ cryptographic software written by Eric Young (eay@cryptsoft.com). Compilers Supported
-------------------
-MinGW GCC
+MinGW GCC (v3.4.5)
Microsoft Visual C++ 6.0 SP6
@@ -61,18 +61,19 @@ CDB::CDB(const char* pszFile, const char* pszMode, bool fTxn) : pdb(NULL) {
if (fShutdown)
return;
- string strAppDir = GetAppDir();
- string strLogDir = strAppDir + "\\database";
+ string strDataDir = GetDataDir();
+ string strLogDir = strDataDir + "\\database";
_mkdir(strLogDir.c_str());
- printf("dbenv.open strAppDir=%s\n", strAppDir.c_str());
+ string strErrorFile = strDataDir + "\\db.log";
+ printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
dbenv.set_lg_dir(strLogDir.c_str());
dbenv.set_lg_max(10000000);
dbenv.set_lk_max_locks(10000);
dbenv.set_lk_max_objects(10000);
- dbenv.set_errfile(fopen("db.log", "a")); /// debug
+ dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
///dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); /// causes corruption
- ret = dbenv.open(strAppDir.c_str(),
+ ret = dbenv.open(strDataDir.c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
@@ -139,6 +140,8 @@ void DBFlush(bool fShutdown) // Flush log data to the actual data file
// on all files that are not in use
printf("DBFlush(%s)\n", fShutdown ? "true" : "false");
+ if (!fDbEnvInit)
+ return;
CRITICAL_BLOCK(cs_db)
{
dbenv.txn_checkpoint(0, 0, 0);
@@ -421,7 +424,7 @@ bool CAddrDB::LoadAddresses() while (fgets(psz, sizeof(psz), filein))
{
CAddress addr(psz, NODE_NETWORK);
- if (addr.ip != 0)
+ if (addr.IsValid())
{
AddAddress(*this, addr);
mapIRCAddresses.insert(make_pair(addr.GetKey(), addr));
@@ -676,10 +679,10 @@ void ThreadFlushWalletDB(void* parg) {
// Flush wallet.dat so it's self contained
nLastFlushed == nWalletDBUpdated;
- int64 nStart = PerformanceCounter();
+ int64 nStart = GetTimeMillis();
dbenv.txn_checkpoint(0, 0, 0);
dbenv.lsn_reset(strFile.c_str(), 0);
- printf("Flushed wallet.dat %15"PRI64d"\n", PerformanceCounter() - nStart);
+ printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
mapFileUseCount.erase(mi++);
}
}
@@ -40,7 +40,7 @@ bool DecodeAddress(string str, CAddress& addr) return false;
memcpy(&tmp, &vch[0], sizeof(tmp));
- addr = CAddress(tmp.ip, tmp.port);
+ addr = CAddress(tmp.ip, tmp.port, NODE_NETWORK);
return true;
}
@@ -163,6 +163,7 @@ void ThreadIRCSeed(void* parg) int nErrorWait = 10;
int nRetryWait = 10;
+ // IRC server blocks TOR users
if (fUseProxy && addrProxy.port == htons(9050))
return;
@@ -237,14 +238,14 @@ void ThreadIRCSeed(void* parg) {
// index 7 is limited to 16 characters
// could get full length name at index 10, but would be different from join messages
- strcpy(pszName, vWords[7].c_str());
+ strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
printf("IRC got who\n");
}
if (vWords[1] == "JOIN" && vWords[0].size() > 1)
{
// :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
- strcpy(pszName, vWords[0].c_str() + 1);
+ strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
if (strchr(pszName, '!'))
*strchr(pszName, '!') = '\0';
printf("IRC got join\n");
@@ -1,11 +1,6 @@ // Copyright (c) 2009 Satoshi Nakamoto
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
- -#ifndef __WXMSW__ -#define closesocket(s) close(s)
-typedef u_int SOCKET;
-#endif extern bool RecvLine(SOCKET hSocket, string& strLine);
extern void ThreadIRCSeed(void* parg);
@@ -42,7 +42,6 @@ map<uint160, vector<unsigned char> > mapPubKeys; CCriticalSection cs_mapKeys;
CKey keyUser;
-string strSetDataDir;
int nDropMessagesTest = 0;
// Settings
@@ -1361,52 +1360,17 @@ bool ScanMessageStart(Stream& s) }
}
-string GetAppDir()
-{
- string strDir;
- if (!strSetDataDir.empty())
- {
- strDir = strSetDataDir;
- }
- else if (getenv("APPDATA"))
- {
- strDir = strprintf("%s\\Bitcoin", getenv("APPDATA"));
- }
- else if (getenv("USERPROFILE"))
- {
- string strAppData = strprintf("%s\\Application Data", getenv("USERPROFILE"));
- static bool fMkdirDone;
- if (!fMkdirDone)
- {
- fMkdirDone = true;
- _mkdir(strAppData.c_str());
- }
- strDir = strprintf("%s\\Bitcoin", strAppData.c_str());
- }
- else
- {
- return ".";
- }
- static bool fMkdirDone;
- if (!fMkdirDone)
- {
- fMkdirDone = true;
- _mkdir(strDir.c_str());
- }
- return strDir;
-}
-
bool CheckDiskSpace(int64 nAdditionalBytes)
{
wxLongLong nFreeBytesAvailable = 0;
- if (!wxGetDiskSpace(wxStandardPaths::Get().GetDataDir(), NULL, &nFreeBytesAvailable))
+ if (!wxGetDiskSpace(GetDataDir(), NULL, &nFreeBytesAvailable))
{
printf("ERROR: wxGetDiskSpace() failed\n");
return true;
}
// Check for 15MB because database could create another 10MB log file at any time
- if (nFreeBytesAvailable < (int64)15000000 + nAdditionalBytes)
+ if (nFreeBytesAvailable.GetValue() < (int64)15000000 + nAdditionalBytes)
{
fShutdown = true;
wxMessageBox("Warning: Your disk space is low ", "Bitcoin", wxICON_EXCLAMATION);
@@ -1420,7 +1384,7 @@ FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszM {
if (nFile == -1)
return NULL;
- FILE* file = fopen(strprintf("%s\\blk%04d.dat", GetAppDir().c_str(), nFile).c_str(), pszMode);
+ FILE* file = fopen(strprintf("%s\\blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);
if (!file)
return NULL;
if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))
@@ -1719,7 +1683,7 @@ bool ProcessMessages(CNode* pfrom) if (strstr(e.what(), "CDataStream::read() : end of data"))
{
// Allow exceptions from underlength message on vRecv
- LogException(&e, "ProcessMessage()");
+ printf("ProcessMessage(%s, %d bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
}
else
PrintException(&e, "ProcessMessage()");
@@ -2512,7 +2476,7 @@ bool BitcoinMiner() int64 GetBalance()
{
- int64 nStart = PerformanceCounter();
+ int64 nStart = GetTimeMillis();
int64 nTotal = 0;
CRITICAL_BLOCK(cs_mapWallet)
@@ -2522,11 +2486,11 @@ int64 GetBalance() CWalletTx* pcoin = &(*it).second;
if (!pcoin->IsFinal() || pcoin->fSpent)
continue;
- nTotal += pcoin->GetCredit();
+ nTotal += pcoin->GetCredit(true);
}
}
- ///printf(" GetBalance() time = %15"PRI64d"\n", PerformanceCounter() - nStart);
+ //printf("GetBalance() %"PRI64d"ms\n", GetTimeMillis() - nStart);
return nTotal;
}
@@ -34,7 +34,6 @@ extern int nBestHeight; extern uint256 hashBestChain;
extern CBlockIndex* pindexBest;
extern unsigned int nTransactionsUpdated;
-extern string strSetDataDir;
extern int nDropMessagesTest;
// Settings
@@ -50,7 +49,6 @@ extern int nLimitProcessors; -string GetAppDir();
bool CheckDiskSpace(int64 nAdditionalBytes=0);
FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
FILE* AppendBlockFile(unsigned int& nFileRet);
@@ -405,10 +403,10 @@ public: {
// Time based nLockTime implemented in 0.1.6,
// do not use time based until most 0.1.5 nodes have upgraded.
- if (nBlockTime == 0)
- nBlockTime = GetAdjustedTime();
if (nLockTime == 0)
return true;
+ if (nBlockTime == 0)
+ nBlockTime = GetAdjustedTime();
if (nLockTime < (nLockTime < 500000000 ? nBestHeight : nBlockTime))
return true;
foreach(const CTxIn& txin, vin)
@@ -627,6 +625,8 @@ public: // memory only
mutable bool fMerkleVerified;
+ mutable bool fGetCreditCached;
+ mutable int64 nGetCreditCached;
CMerkleTx()
@@ -644,14 +644,22 @@ public: hashBlock = 0;
nIndex = -1;
fMerkleVerified = false;
+ fGetCreditCached = false;
+ nGetCreditCached = 0;
}
- int64 GetCredit() const
+ int64 GetCredit(bool fUseCache=false) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
if (IsCoinBase() && GetBlocksToMaturity() > 0)
return 0;
- return CTransaction::GetCredit();
+
+ // GetBalance can assume transactions in mapWallet won't change
+ if (fUseCache && fGetCreditCached)
+ return nGetCreditCached;
+ nGetCreditCached = CTransaction::GetCredit();
+ fGetCreditCached = true;
+ return nGetCreditCached;
}
IMPLEMENT_SERIALIZE
@@ -21,8 +21,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect); bool fClient = false;
uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK);
CAddress addrLocalHost(0, DEFAULT_PORT, nLocalServices);
-CNode nodeLocalHost(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));
-CNode* pnodeLocalHost = &nodeLocalHost;
+CNode* pnodeLocalHost = NULL;
uint64 nLocalHostNonce = 0;
bool fShutdown = false;
array<int, 10> vnThreadsRunning;
@@ -129,7 +128,7 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha strLine = wxString(strLine).Trim();
CAddress addr(strLine.c_str());
printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str());
- if (addr.ip == 0 || !addr.IsRoutable())
+ if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable())
return false;
ipRet = addr.ip;
return true;
@@ -740,10 +739,29 @@ void ThreadOpenConnections2(void* parg) printf("ThreadOpenConnections started\n");
// Connect to one specified address
- while (mapArgs.count("/connect"))
+ while (mapArgs.count("-connect"))
{
- OpenNetworkConnection(CAddress(mapArgs["/connect"].c_str()));
- Sleep(10000);
+ OpenNetworkConnection(CAddress(mapArgs["-connect"]));
+ for (int i = 0; i < 10; i++)
+ {
+ Sleep(1000);
+ CheckForShutdown(1);
+ }
+ }
+
+ // Connect to manually added nodes first
+ if (mapArgs.count("-addnode"))
+ {
+ foreach(string strAddr, mapMultiArgs["-addnode"])
+ {
+ CAddress addr(strAddr, NODE_NETWORK);
+ if (addr.IsValid())
+ {
+ OpenNetworkConnection(addr);
+ Sleep(1000);
+ CheckForShutdown(1);
+ }
+ }
}
// Initiate network connections
@@ -967,6 +985,8 @@ void ThreadMessageHandler2(void* parg) bool StartNode(string& strError)
{
+ if (pnodeLocalHost == NULL)
+ pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));
strError = "";
// Sockets startup
@@ -1031,7 +1051,7 @@ bool StartNode(string& strError) printf("%s\n", strError.c_str());
return false;
}
- printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str());
+ printf("bound to addrLocalHost = %s\n", addrLocalHost.ToString().c_str());
// Listen for incoming connections
if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR)
@@ -1,12 +1,6 @@ // Copyright (c) 2009 Satoshi Nakamoto
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
- -#ifndef __WXMSW__
-#define closesocket(s) close(s)
-#define INVALID_SOCKET (SOCKET)(~0)
-typedef u_int SOCKET;
-#endif class CMessageHeader;
class CAddress;
@@ -148,61 +142,73 @@ public: CAddress()
{
- nServices = 0;
- memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
- ip = 0;
- port = DEFAULT_PORT;
- nTime = GetAdjustedTime();
- nLastFailed = 0;
+ Init();
}
- CAddress(unsigned int ipIn, unsigned short portIn=DEFAULT_PORT, uint64 nServicesIn=0)
+ CAddress(unsigned int ipIn, unsigned short portIn=DEFAULT_PORT, uint64 nServicesIn=NODE_NETWORK)
{
- nServices = nServicesIn;
- memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
+ Init();
ip = ipIn;
port = portIn;
- nTime = GetAdjustedTime();
- nLastFailed = 0;
+ nServices = nServicesIn;
}
- explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=0)
+ explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=NODE_NETWORK)
{
- nServices = nServicesIn;
- memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
+ Init();
ip = sockaddr.sin_addr.s_addr;
port = sockaddr.sin_port;
- nTime = GetAdjustedTime();
- nLastFailed = 0;
+ nServices = nServicesIn;
}
- explicit CAddress(const char* pszIn, uint64 nServicesIn=0)
+ explicit CAddress(const char* pszIn, uint64 nServicesIn=NODE_NETWORK)
{
+ Init();
+ SetAddress(pszIn);
nServices = nServicesIn;
+ }
+
+ explicit CAddress(string strIn, uint64 nServicesIn=NODE_NETWORK)
+ {
+ Init();
+ SetAddress(strIn.c_str());
+ nServices = nServicesIn;
+ }
+
+ void Init()
+ {
+ nServices = NODE_NETWORK;
memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
ip = INADDR_NONE;
port = DEFAULT_PORT;
nTime = GetAdjustedTime();
nLastFailed = 0;
+ }
+ bool SetAddress(const char* pszIn)
+ {
+ ip = INADDR_NONE;
+ port = DEFAULT_PORT;
char psz[100];
- if (strlen(pszIn) > ARRAYLEN(psz)-1)
- return;
- strcpy(psz, pszIn);
+ strlcpy(psz, pszIn, sizeof(psz));
unsigned int a=0, b=0, c=0, d=0, e=0;
if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4)
- return;
+ return false;
char* pszPort = strchr(psz, ':');
if (pszPort)
{
*pszPort++ = '\0';
port = htons(atoi(pszPort));
- if (atoi(pszPort) > USHRT_MAX)
+ if (atoi(pszPort) < 0 || atoi(pszPort) > USHRT_MAX)
port = htons(USHRT_MAX);
- if (atoi(pszPort) < 0)
- port = htons(0);
}
ip = inet_addr(psz);
+ return IsValid();
+ }
+
+ bool SetAddress(string strIn)
+ {
+ return SetAddress(strIn.c_str());
}
IMPLEMENT_SERIALIZE
@@ -274,7 +280,17 @@ public: bool IsRoutable() const
{
- return !(GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) || GetByte(3) == 127 || GetByte(3) == 0);
+ return !(GetByte(3) == 10 ||
+ (GetByte(3) == 192 && GetByte(2) == 168) ||
+ GetByte(3) == 127 ||
+ GetByte(3) == 0 ||
+ ip == 0 ||
+ ip == INADDR_NONE);
+ }
+
+ bool IsValid() const
+ {
+ return (ip != 0 && ip != INADDR_NONE && port != htons(USHRT_MAX));
}
unsigned char GetByte(int n) const
@@ -25,7 +25,6 @@ DEFINE_EVENT_TYPE(wxEVT_TABLEDELETED) CMainFrame* pframeMain = NULL;
CMyTaskBarIcon* ptaskbaricon = NULL;
map<string, string> mapAddressBook;
-map<string, string> mapArgs;
bool fRandSendTest = false;
void RandSend();
extern int g_isPainting;
@@ -283,7 +282,6 @@ CMainFrame::CMainFrame(wxWindow* parent) : CMainFrameBase(parent) fRefreshListCtrl = false;
fRefreshListCtrlRunning = false;
fOnSetFocusAddress = false;
- pindexBestLast = NULL;
m_choiceFilter->SetSelection(0);
m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
m_listCtrl->SetFocus();
@@ -507,6 +505,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) string strStatus = FormatTxStatus(wtx);
map<string, string> mapValue = wtx.mapValue;
wtx.nLinesDisplayed = 1;
+ nListViewUpdated++;
// Filter
if (wtx.IsCoinBase())
@@ -712,48 +711,6 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) return true;
}
-void CMainFrame::RefreshStatus()
-{
- static int nLastTop;
- int nTop = max((int)m_listCtrl->GetTopItem(), 0);
- if (nTop == nLastTop && pindexBestLast == pindexBest)
- return;
-
- TRY_CRITICAL_BLOCK(cs_mapWallet)
- {
- int nStart = nTop;
- int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
- if (pindexBestLast == pindexBest)
- {
- if (nStart >= nLastTop && nStart < nLastTop + 100)
- nStart = nLastTop + 100;
- if (nEnd >= nLastTop && nEnd < nLastTop + 100)
- nEnd = nLastTop;
- }
- nLastTop = nTop;
- pindexBestLast = pindexBest;
-
- for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
- {
- uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
- if (mi == mapWallet.end())
- {
- printf("CMainFrame::RefreshStatus() : tx not found in mapWallet\n");
- continue;
- }
- CWalletTx& wtx = (*mi).second;
- if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
- {
- if (!InsertTransaction(wtx, false, nIndex))
- m_listCtrl->DeleteItem(nIndex--);
- }
- else
- m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
- }
- }
-}
-
void CMainFrame::RefreshListCtrl()
{
fRefreshListCtrl = true;
@@ -832,21 +789,104 @@ void CMainFrame::OnIdle(wxIdleEvent& event) }
}
+void CMainFrame::RefreshStatusColumn()
+{
+ static int nLastTop;
+ static CBlockIndex* pindexLastBest;
+ static unsigned int nLastRefreshed;
+
+ int nTop = max((int)m_listCtrl->GetTopItem(), 0);
+ if (nTop == nLastTop && pindexLastBest == pindexBest)
+ return;
+
+ TRY_CRITICAL_BLOCK(cs_mapWallet)
+ {
+ int nStart = nTop;
+ int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
+
+ if (pindexLastBest == pindexBest && nLastRefreshed == nListViewUpdated)
+ {
+ // If no updates, only need to do the part that moved onto the screen
+ if (nStart >= nLastTop && nStart < nLastTop + 100)
+ nStart = nLastTop + 100;
+ if (nEnd >= nLastTop && nEnd < nLastTop + 100)
+ nEnd = nLastTop;
+ }
+ nLastTop = nTop;
+ pindexLastBest = pindexBest;
+ nLastRefreshed = nListViewUpdated;
+
+ for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++)
+ {
+ uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1));
+ map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
+ if (mi == mapWallet.end())
+ {
+ printf("CMainFrame::RefreshStatusColumn() : tx not found in mapWallet\n");
+ continue;
+ }
+ CWalletTx& wtx = (*mi).second;
+ if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed)
+ {
+ if (!InsertTransaction(wtx, false, nIndex))
+ m_listCtrl->DeleteItem(nIndex--);
+ }
+ else
+ m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx));
+ }
+ }
+}
+
void CMainFrame::OnPaint(wxPaintEvent& event)
{
event.Skip();
}
-void DelayedRepaint(void* parg)
+
+unsigned int nNeedRepaint = 0;
+unsigned int nLastRepaint = 0;
+int64 nLastRepaintTime = 0;
+int64 nRepaintInterval = 500;
+
+void ThreadDelayedRepaint(void* parg)
{
- static bool fOneThread;
- if (fOneThread)
- return;
- fOneThread = true;
- Sleep(1000);
- printf("DelayedRepaint()\n");
- MainFrameRepaint();
- fOneThread = false;
+ while (!fShutdown)
+ {
+ if (nLastRepaint != nNeedRepaint && GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
+ {
+ nLastRepaint = nNeedRepaint;
+ if (pframeMain)
+ {
+ printf("DelayedRepaint\n");
+ wxPaintEvent event;
+ pframeMain->Refresh();
+ pframeMain->AddPendingEvent(event);
+ }
+ }
+ Sleep(nRepaintInterval);
+ }
+}
+
+void MainFrameRepaint()
+{
+ // This is called by network code that shouldn't access pframeMain
+ // directly because it could still be running after the UI is closed.
+ if (pframeMain)
+ {
+ // Don't repaint too often
+ static int64 nLastRepaintRequest;
+ if (GetTimeMillis() - nLastRepaintRequest < 100)
+ {
+ nNeedRepaint++;
+ return;
+ }
+ nLastRepaintRequest = GetTimeMillis();
+
+ printf("MainFrameRepaint\n");
+ wxPaintEvent event;
+ pframeMain->Refresh();
+ pframeMain->AddPendingEvent(event);
+ }
}
void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
@@ -854,43 +894,54 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) if (ptaskbaricon)
ptaskbaricon->UpdateTooltip();
- // Update listctrl contents
- if (!vWalletUpdated.empty())
+ //
+ // Slower stuff
+ //
+ static int nTransactionCount;
+ bool fPaintedBalance = false;
+ if (GetTimeMillis() - nLastRepaintTime >= nRepaintInterval)
{
- TRY_CRITICAL_BLOCK(cs_mapWallet)
+ nLastRepaint = nNeedRepaint;
+ nLastRepaintTime = GetTimeMillis();
+
+ // Update listctrl contents
+ if (!vWalletUpdated.empty())
{
- bool fInserted = false;
- foreach(uint256 hash, vWalletUpdated)
+ TRY_CRITICAL_BLOCK(cs_mapWallet)
{
- map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
- if (mi != mapWallet.end())
- fInserted |= InsertTransaction((*mi).second, false);
+ bool fInserted = false;
+ foreach(uint256 hash, vWalletUpdated)
+ {
+ map<uint256, CWalletTx>::iterator mi = mapWallet.find(hash);
+ if (mi != mapWallet.end())
+ fInserted |= InsertTransaction((*mi).second, false);
+ }
+ vWalletUpdated.clear();
+ if (fInserted)
+ m_listCtrl->ScrollList(0, INT_MAX);
}
- vWalletUpdated.clear();
- if (fInserted)
- m_listCtrl->ScrollList(0, INT_MAX);
}
- }
-
- // Update status column of visible items only
- RefreshStatus();
-
- // Balance total
- bool fRefreshed = false;
- static int nTransactionCount;
- TRY_CRITICAL_BLOCK(cs_mapWallet)
- {
- fRefreshed = true;
- m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
- // Count hidden and multi-line transactions
- nTransactionCount = 0;
- for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ // Balance total
+ TRY_CRITICAL_BLOCK(cs_mapWallet)
{
- CWalletTx& wtx = (*it).second;
- nTransactionCount += wtx.nLinesDisplayed;
+ fPaintedBalance = true;
+ m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " ");
+
+ // Count hidden and multi-line transactions
+ nTransactionCount = 0;
+ for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+ {
+ CWalletTx& wtx = (*it).second;
+ nTransactionCount += wtx.nLinesDisplayed;
+ }
}
}
+ if (!vWalletUpdated.empty() || !fPaintedBalance)
+ nNeedRepaint++;
+
+ // Update status column of visible items only
+ RefreshStatusColumn();
// Update status bar
string strGen = "";
@@ -903,13 +954,10 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount);
m_statusBar->SetStatusText(strStatus, 2);
- // mapWallet was locked, try again later
- if (!vWalletUpdated.empty() || !fRefreshed)
- _beginthread(DelayedRepaint, 0, NULL);
-
m_listCtrl->OnPaint(event);
}
+
void CrossThreadCall(wxCommandEvent& event)
{
if (pframeMain)
@@ -994,13 +1042,6 @@ void CMainFrame::OnMenuHelpAbout(wxCommandEvent& event) void CMainFrame::OnButtonSend(wxCommandEvent& event)
{
- /// debug test
- if (fRandSendTest)
- {
- RandSend();
- return;
- }
-
// Toolbar: Send
CSendDialog dialog(this);
dialog.ShowModal();
@@ -1684,8 +1725,8 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event) else
{
// Parse IP address
- CAddress addr(strAddress.c_str());
- if (addr.ip == 0)
+ CAddress addr(strAddress);
+ if (!addr.IsValid())
{
wxMessageBox("Invalid address ", "Send Coins");
return;
@@ -1818,14 +1859,6 @@ void CSendingDialog::OnPaint(wxPaintEvent& event) wxMessageBox("Transfer cancelled ", "Sending...", wxOK, this);
}
event.Skip();
-
- /// debug test
- if (fRandSendTest && fWorkDone && fSuccess)
- {
- Close();
- Sleep(1000);
- RandSend();
- }
}
@@ -3305,27 +3338,6 @@ bool CMyApp::OnInit() return false;
}
-map<string, string> ParseParameters(int argc, char* argv[])
-{
- map<string, string> mapArgs;
- for (int i = 0; i < argc; i++)
- {
- char psz[10000];
- strcpy(psz, argv[i]);
- char* pszValue = "";
- if (strchr(psz, '='))
- {
- pszValue = strchr(psz, '=');
- *pszValue++ = '\0';
- }
- strlwr(psz);
- if (psz[0] == '-')
- psz[0] = '/';
- mapArgs[psz] = pszValue;
- }
- return mapArgs;
-}
-
bool CMyApp::OnInit2()
{
#ifdef _MSC_VER
@@ -3337,10 +3349,27 @@ bool CMyApp::OnInit2() // Disable malfunctioning wxWidgets debug assertion
g_isPainting = 10000;
#endif
-
- //// debug print
- printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
- printf("Bitcoin version %d, Windows version %08x\n", VERSION, GetVersion());
+ wxImage::AddHandler(new wxPNGHandler);
+ SetAppName("Bitcoin");
+
+ ParseParameters(argc, argv);
+ if (mapArgs.count("-?") || mapArgs.count("--help"))
+ {
+ string strUsage =
+ "Usage: bitcoin [options]\t\t\t\t\t\t\n"
+ "Options:\n"
+ " -gen\t\t Generate coins\n"
+ " -gen=0\t\t Don't generate coins\n"
+ " -min\t\t Start minimized\n"
+ " -datadir=<dir>\t Specify data directory\n"
+ " -proxy=<ip:port>\t Connect through socks4 proxy,\n"
+ " \t\t e.g. -proxy=127.0.0.1:9050 to use TOR\n"
+ " -addnode=<ip>\t Add a node to connect to\n"
+ " -connect=<ip>\t Connect only to the specified node\n"
+ " -?\t\t This help message\n";
+ wxMessageBox(strUsage, "Bitcoin", wxOK);
+ exit(0);
+ }
//
// Limit to single instance per user
@@ -3382,31 +3411,31 @@ bool CMyApp::OnInit2() //
// Parameters
//
- wxImage::AddHandler(new wxPNGHandler);
- mapArgs = ParseParameters(argc, argv);
-
- if (mapArgs.count("/datadir"))
- strSetDataDir = mapArgs["/datadir"];
+ if (mapArgs.count("-datadir"))
+ strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));
- if (mapArgs.count("/debug"))
+ if (mapArgs.count("-debug"))
fDebug = true;
- if (mapArgs.count("/printtodebugger"))
+ if (mapArgs.count("-printtodebugger"))
fPrintToDebugger = true;
- if (mapArgs.count("/dropmessages"))
+ printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
+ printf("Bitcoin version %d, Windows version %08x\n", VERSION, GetVersion());
+
+ if (mapArgs.count("-dropmessages"))
{
- nDropMessagesTest = atoi(mapArgs["/dropmessages"]);
+ nDropMessagesTest = atoi(mapArgs["-dropmessages"]);
if (nDropMessagesTest == 0)
nDropMessagesTest = 20;
}
- if (mapArgs.count("/loadblockindextest"))
+ if (mapArgs.count("-loadblockindextest"))
{
CTxDB txdb("r");
txdb.LoadBlockIndex();
PrintBlockTree();
- ExitProcess(0);
+ exit(0);
}
//
@@ -3417,22 +3446,22 @@ bool CMyApp::OnInit2() int64 nStart;
printf("Loading addresses...\n");
- nStart = PerformanceCounter();
+ nStart = GetTimeMillis();
if (!LoadAddresses())
strErrors += "Error loading addr.dat \n";
- printf(" addresses %15"PRI64d"\n", PerformanceCounter() - nStart);
+ printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
printf("Loading block index...\n");
- nStart = PerformanceCounter();
+ nStart = GetTimeMillis();
if (!LoadBlockIndex())
strErrors += "Error loading blkindex.dat \n";
- printf(" block index %15"PRI64d"\n", PerformanceCounter() - nStart);
+ printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
printf("Loading wallet...\n");
- nStart = PerformanceCounter();
+ nStart = GetTimeMillis();
if (!LoadWallet(fFirstRun))
strErrors += "Error loading wallet.dat \n";
- printf(" wallet %15"PRI64d"\n", PerformanceCounter() - nStart);
+ printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
printf("Done loading\n");
@@ -3457,45 +3486,59 @@ bool CMyApp::OnInit2() //
// Parameters
//
- if (mapArgs.count("/printblockindex") || mapArgs.count("/printblocktree"))
+ if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree"))
{
PrintBlockTree();
OnExit();
return false;
}
- if (mapArgs.count("/proxy"))
+ if (mapArgs.count("-gen"))
+ {
+ if (mapArgs["-gen"].empty())
+ fGenerateBitcoins = true;
+ else
+ fGenerateBitcoins = atoi(mapArgs["-gen"].c_str());
+ }
+
+ if (mapArgs.count("-proxy"))
{
fUseProxy = true;
- addrProxy = CAddress(mapArgs["/proxy"].c_str());
- if (addrProxy.ip == INADDR_NONE)
+ addrProxy = CAddress(mapArgs["-proxy"]);
+ if (!addrProxy.IsValid())
{
- wxMessageBox("Invalid /proxy address", "Bitcoin");
+ wxMessageBox("Invalid -proxy address", "Bitcoin");
OnExit();
+ return false;
}
CWalletDB walletdb;
walletdb.WriteSetting("fUseProxy", fUseProxy);
walletdb.WriteSetting("addrProxy", addrProxy);
}
- if (mapArgs.count("/gen"))
+ if (mapArgs.count("-addnode"))
{
- if (mapArgs["/gen"].empty())
- fGenerateBitcoins = true;
- else
- fGenerateBitcoins = atoi(mapArgs["/gen"].c_str());
+ CAddrDB addrdb;
+ foreach(string strAddr, mapMultiArgs["-addnode"])
+ {
+ CAddress addr(strAddr, NODE_NETWORK);
+ if (addr.IsValid())
+ AddAddress(addrdb, addr);
+ }
}
//
// Create the main frame window
//
pframeMain = new CMainFrame(NULL);
- if (mapArgs.count("/min"))
+ if (mapArgs.count("-min"))
pframeMain->Iconize(true);
pframeMain->Show(true); // have to show first to get taskbar button to hide
pframeMain->Show(!fMinimizeToTray || !pframeMain->IsIconized());
ptaskbaricon->Show(fMinimizeToTray);
+ _beginthread(ThreadDelayedRepaint, 0, NULL);
+
if (!CheckDiskSpace())
{
OnExit();
@@ -3516,7 +3559,7 @@ bool CMyApp::OnInit2() //
// Tests
//
- if (argc >= 2 && stricmp(argv[1], "/send") == 0)
+ if (argc >= 2 && stricmp(argv[1], "-send") == 0)
{
int64 nValue = 1;
if (argc >= 3)
@@ -3525,7 +3568,7 @@ bool CMyApp::OnInit2() string strAddress;
if (argc >= 4)
strAddress = argv[3];
- CAddress addr(strAddress.c_str());
+ CAddress addr(strAddress);
CWalletTx wtx;
wtx.mapValue["to"] = strAddress;
@@ -3538,15 +3581,6 @@ bool CMyApp::OnInit2() return false;
}
- if (mapArgs.count("/randsendtest"))
- {
- if (!mapArgs["/randsendtest"].empty())
- _beginthread(ThreadRandSendTest, 0, new string(mapArgs["/randsendtest"]));
- else
- fRandSendTest = true;
- fDebug = true;
- }
-
return true;
}
@@ -3610,19 +3644,6 @@ void CMyApp::OnFatalException() -void MainFrameRepaint()
-{
- // This is called by network code that shouldn't access pframeMain
- // directly because it could still be running after the UI is closed.
- if (pframeMain)
- {
- printf("MainFrameRepaint()\n");
- wxPaintEvent event;
- pframeMain->Refresh();
- pframeMain->AddPendingEvent(event);
- }
-}
-
typedef WINSHELLAPI BOOL WINAPI (*PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
@@ -3666,7 +3687,7 @@ string StartupShortcutPath() bool GetStartOnSystemStartup()
{
- return FileExists(StartupShortcutPath().c_str());
+ return wxFileExists(StartupShortcutPath());
}
void SetStartOnSystemStartup(bool fAutoStart)
@@ -3727,79 +3748,3 @@ void SetStartOnSystemStartup(bool fAutoStart) -
-// randsendtest to bitcoin address
-void ThreadRandSendTest(void* parg)
-{
- string strAddress = *(string*)parg;
- uint160 hash160;
- if (!AddressToHash160(strAddress, hash160))
- {
- wxMessageBox(strprintf("ThreadRandSendTest: Bitcoin address '%s' not valid ", strAddress.c_str()));
- return;
- }
-
- while (!fShutdown)
- {
- Sleep(GetRand(30) * 1000 + 100);
-
- // Message
- CWalletTx wtx;
- wtx.mapValue["to"] = strAddress;
- wtx.mapValue["from"] = addrLocalHost.ToString();
- static int nRep;
- wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep);
-
- // Value
- int64 nValue = (GetRand(9) + 1) * 100 * CENT;
- if (GetBalance() < nValue)
- {
- wxMessageBox("Out of money ");
- while (GetBalance() < 1000)
- Sleep(1000);
- }
- nValue += (nRep % 100) * CENT;
-
- // Send to bitcoin address
- CScript scriptPubKey;
- scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG;
-
- if (fShutdown)
- return;
- if (!SendMoney(scriptPubKey, nValue, wtx))
- return;
- }
-}
-
-
-// randsendtest to any connected node
-void RandSend()
-{
- while (vNodes.empty())
- Sleep(1000);
- CAddress addr;
- CRITICAL_BLOCK(cs_vNodes)
- addr = vNodes[GetRand(vNodes.size())]->addr;
-
- // Message
- CWalletTx wtx;
- wtx.mapValue["to"] = addr.ToString();
- wtx.mapValue["from"] = addrLocalHost.ToString();
- static int nRep;
- wtx.mapValue["message"] = strprintf("randsendtest %d\n", ++nRep);
-
- // Value
- int64 nValue = (GetRand(999) + 1) * CENT;
- if (GetBalance() < nValue)
- {
- wxMessageBox("Out of money ");
- return;
- }
-
- // Send to IP address
- if (fShutdown)
- return;
- CSendingDialog* pdialog = new CSendingDialog(pframeMain, addr, nValue, wtx);
- if (!pdialog->Show())
- wxMessageBox("ShowModal Failed ");
-}
@@ -83,15 +83,14 @@ public: bool fRefreshListCtrl;
bool fRefreshListCtrlRunning;
bool fOnSetFocusAddress;
- CBlockIndex* pindexBestLast;
- set<uint256> setUnmaturedDisplayed;
+ unsigned int nListViewUpdated;
void OnCrossThreadCall(wxCommandEvent& event);
void InsertLine(bool fNew, int nIndex, uint256 hashKey, string strSort, const wxString& str1, const wxString& str2, const wxString& str3, const wxString& str4, const wxString& str5);
bool DeleteLine(uint256 hashKey);
bool InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex=-1);
void RefreshListCtrl();
- void RefreshStatus();
+ void RefreshStatusColumn();
};
@@ -5,9 +5,13 @@ #include "headers.h"
+map<string, string> mapArgs;
+map<string, vector<string> > mapMultiArgs;
bool fDebug = false;
bool fPrintToDebugger = false;
bool fPrintToConsole = false;
+char pszSetDataDir[MAX_PATH] = "";
+
@@ -68,6 +72,8 @@ void RandAddSeed() void RandAddSeedPerfmon()
{
+#ifdef __WXMSW__
+ // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// This can take up to 2 seconds, so only do it every 10 minutes
static int64 nLastPerfmon;
if (GetTime() < nLastPerfmon + 10 * 60)
@@ -95,6 +101,7 @@ void RandAddSeedPerfmon() strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime);
printf("%s RandAddSeed() %d bytes\n", pszTime, nSize);
}
+#endif
}
@@ -304,6 +311,32 @@ vector<unsigned char> ParseHex(const std::string& str) }
+void ParseParameters(int argc, char* argv[])
+{
+ mapArgs.clear();
+ mapMultiArgs.clear();
+ for (int i = 0; i < argc; i++)
+ {
+ char psz[10000];
+ strlcpy(psz, argv[i], sizeof(psz));
+ char* pszValue = "";
+ if (strchr(psz, '='))
+ {
+ pszValue = strchr(psz, '=');
+ *pszValue++ = '\0';
+ }
+ strlwr(psz);
+ #ifdef __WXMSW__
+ if (psz[0] == '/')
+ psz[0] = '-';
+ #endif
+ mapArgs[psz] = pszValue;
+ mapMultiArgs[psz].push_back(pszValue);
+ }
+}
+
+
+
@@ -346,15 +379,6 @@ void PrintException(std::exception* pex, const char* pszThread) -bool FileExists(const char* psz)
-{
-#ifdef WIN32
- return GetFileAttributes(psz) != -1;
-#else
- return access(psz, 0) != -1;
-#endif
-}
-
int GetFilesize(FILE* file)
{
int nSavePos = ftell(file);
@@ -365,6 +389,46 @@ int GetFilesize(FILE* file) return nFilesize;
}
+void GetDataDir(char* pszDir)
+{
+ // pszDir must be at least MAX_PATH length.
+ if (pszSetDataDir[0] != 0)
+ {
+ strlcpy(pszDir, pszSetDataDir, MAX_PATH);
+ static bool fMkdirDone;
+ if (!fMkdirDone)
+ {
+ fMkdirDone = true;
+ _mkdir(pszDir);
+ }
+ }
+ 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.
+ // wxStandardPaths::GetUserDataDir
+ // Return the directory for the user-dependent application data files:
+ // Unix: ~/.appname
+ // Windows: C:\Documents and Settings\username\Application Data\appname
+ // Mac: ~/Library/Application Support/appname
+ static char pszCachedDir[MAX_PATH];
+ if (pszCachedDir[0] == 0)
+ {
+ strlcpy(pszCachedDir, wxStandardPaths::Get().GetUserDataDir().c_str(), sizeof(pszCachedDir));
+ _mkdir(pszCachedDir);
+ }
+ strlcpy(pszDir, pszCachedDir, MAX_PATH);
+ }
+
+}
+
+string GetDataDir()
+{
+ char pszDir[MAX_PATH];
+ GetDataDir(pszDir);
+ return pszDir;
+}
+
@@ -54,16 +54,23 @@ inline T& REF(const T& val) return (T&)val;
}
+#ifndef __WXMSW__
+#define closesocket(s) close(s)
+#define INVALID_SOCKET (SOCKET)(~0)
+typedef u_int SOCKET;
+#endif
+extern map<string, string> mapArgs;
+extern map<string, vector<string> > mapMultiArgs;
extern bool fDebug;
extern bool fPrintToDebugger;
extern bool fPrintToConsole;
-extern map<string, string> mapArgs;
+extern char pszSetDataDir[MAX_PATH];
void RandAddSeed();
void RandAddSeedPerfmon();
@@ -77,8 +84,10 @@ string FormatMoney(int64 n, bool fPlus=false); bool ParseMoney(const char* pszIn, int64& nRet);
vector<unsigned char> ParseHex(const char* psz);
vector<unsigned char> ParseHex(const std::string& str);
-bool FileExists(const char* psz);
+void ParseParameters(int argc, char* argv[]);
int GetFilesize(FILE* file);
+void GetDataDir(char* pszDirRet);
+string GetDataDir();
uint64 GetRand(uint64 nMax);
int64 GetTime();
int64 GetAdjustedTime();
@@ -172,9 +181,14 @@ inline int OutputDebugStringF(const char* pszFormat, ...) if (!fPrintToConsole)
{
// print to debug.log
- FILE* fileout = fopen("debug.log", "a");
+ char pszFile[MAX_PATH+100];
+ GetDataDir(pszFile);
+ strlcat(pszFile, "\\debug.log", sizeof(pszFile));
+ FILE* fileout = fopen(pszFile, "a");
if (fileout)
{
+ //// Debug print useful for profiling
+ //fprintf(fileout, " %"PRI64d" ", wxGetLocalTimeMillis().GetValue());
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
ret = vfprintf(fileout, pszFormat, arg_ptr);
@@ -321,22 +335,25 @@ inline void PrintHex(vector<unsigned char> vch, const char* pszFormat="%s", bool {
printf(pszFormat, HexStr(vch, fSpaces).c_str());
}
- inline int64 PerformanceCounter()
{
- int64 nCounter = 0; + int64 nCounter = 0;
#ifdef __WXMSW__
- QueryPerformanceCounter((LARGE_INTEGER*)&nCounter); + QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
#else
- // this could be changed to reading /dev/urandom - timeval t; - gettimeofday(&t, NULL); - nCounter += t.tv_sec * 1000000 + t.tv_usec; + timeval t;
+ gettimeofday(&t, NULL);
+ nCounter = t.tv_sec * 1000000 + t.tv_usec;
#endif
return nCounter;
}
+inline int64 GetTimeMillis()
+{
+ return wxGetLocalTimeMillis().GetValue();
+}
+
#ifndef __WXMSW__
inline void Sleep(unsigned int nMilliseconds)
{
@@ -354,8 +371,10 @@ inline void Sleep(unsigned int nMilliseconds) inline void heapchk()
{
+#ifdef __WXMSW__
if (_heapchk() != _HEAPOK)
DebugBreak();
+#endif
}
// Randomize the stack to help protect against buffer overrun exploits
|