From cc0b4c3b62367a2aebe5fc1f4d0ed4b97e9c2ac9 Mon Sep 17 00:00:00 2001 From: s_nakamoto Date: Thu, 29 Oct 2009 02:52:48 +0000 Subject: [PATCH] addr relaying fixes, proxy option and privacy patches, detect connect to self, non-final tx locktime changes, fix hide unconfirmed generated --- build.txt | 12 +- db.cpp | 19 +++- headers.h | 2 + irc.cpp | 10 +- key.h | 2 +- main.cpp | 71 +++++++++--- main.h | 16 ++- makefile | 4 +- net.cpp | 173 ++++++++++++++++------------ net.h | 131 ++++++++++++++++++++- serialize.h | 2 +- strlcpy.h | 84 ++++++++++++++ ui.cpp | 223 ++++++++++++++++++++++++++++-------- ui.h | 8 +- uibase.cpp | 51 ++++++++- uibase.h | 98 ++++++++-------- uiproject.fbp | 308 +++++++++++++++++++++++++++++++++++++++++++++++++- util.cpp | 170 +++++++++++++++++++--------- util.h | 164 ++++++++++++++++----------- 19 files changed, 1209 insertions(+), 339 deletions(-) create mode 100644 strlcpy.h diff --git a/build.txt b/build.txt index b6b526f1bcdc5..f510055767103 100644 --- a/build.txt +++ b/build.txt @@ -1,4 +1,4 @@ -BitCoin v0.1.6 ALPHA +BitCoin v0.1.6 BETA Copyright (c) 2009 Satoshi Nakamoto Distributed under the MIT/X11 software license, see the accompanying @@ -19,10 +19,10 @@ Dependencies Libraries you need to obtain separately to build: default path download -wxWidgets \wxWidgets http://www.wxwidgets.org/downloads/ -OpenSSL \OpenSSL http://www.openssl.org/source/ -Berkeley DB \DB http://www.oracle.com/technology/software/products/berkeley-db/index.html -Boost \Boost http://www.boost.org/users/download/ +wxWidgets \wxwidgets http://www.wxwidgets.org/downloads/ +OpenSSL \openssl http://www.openssl.org/source/ +Berkeley DB \db http://www.oracle.com/technology/software/products/berkeley-db/index.html +Boost \boost http://www.boost.org/users/download/ Their licenses: wxWidgets LGPL 2.1 with very liberal exceptions @@ -75,7 +75,7 @@ If you want to use it with MSVC, generate the .lib file Berkeley DB ----------- Using MinGW and MSYS: -cd \DB\build_unix +cd \db\build_unix sh ../dist/configure --enable-mingw --enable-cxx make diff --git a/db.cpp b/db.cpp index a9f5b7953cc58..315e93b73aa28 100644 --- a/db.cpp +++ b/db.cpp @@ -121,10 +121,12 @@ void CDB::Close() pdb->close(0); delete pdb; pdb = NULL; - dbenv.txn_checkpoint(0, 0, 0); CRITICAL_BLOCK(cs_db) + { + dbenv.txn_checkpoint(0, 0, 0); --mapFileUseCount[strFile]; + } RandAddSeed(); } @@ -376,11 +378,11 @@ bool CTxDB::LoadBlockIndex() { if (pindexGenesisBlock == NULL) return true; - return error("CTxDB::LoadBlockIndex() : hashBestChain not found\n"); + return error("CTxDB::LoadBlockIndex() : hashBestChain not found"); } if (!mapBlockIndex.count(hashBestChain)) - return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found\n"); + return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,14).c_str(), nBestHeight); @@ -500,16 +502,15 @@ bool CReviewDB::WriteReviews(uint256 hash, const vector& vReviews) CWalletDB::~CWalletDB() { // Flush whenever all handles to wallet.dat are closed - Close(); CRITICAL_BLOCK(cs_db) { + Close(); // close includes a txn_checkpoint map::iterator mi = mapFileUseCount.find(strFile); if (mi != mapFileUseCount.end()) { int nRefCount = (*mi).second; if (nRefCount == 0) { - dbenv.txn_checkpoint(0, 0, 0); dbenv.lsn_reset(strFile.c_str(), 0); mapFileUseCount.erase(mi++); } @@ -600,6 +601,9 @@ bool CWalletDB::LoadWallet(vector& vchDefaultKeyRet) if (strKey == "nLimitProcessors") ssValue >> nLimitProcessors; if (strKey == "fMinimizeToTray") ssValue >> fMinimizeToTray; if (strKey == "fMinimizeOnClose") ssValue >> fMinimizeOnClose; + if (strKey == "fUseProxy") ssValue >> fUseProxy; + if (strKey == "addrProxy") ssValue >> addrProxy; + } } } @@ -610,6 +614,9 @@ bool CWalletDB::LoadWallet(vector& vchDefaultKeyRet) printf("addrIncoming = %s\n", addrIncoming.ToString().c_str()); printf("fMinimizeToTray = %d\n", fMinimizeToTray); printf("fMinimizeOnClose = %d\n", fMinimizeOnClose); + printf("fUseProxy = %d\n", fUseProxy); + printf("addrProxy = %s\n", addrProxy.ToString().c_str()); + // The transaction fee setting won't be needed for many years to come. // Setting it to zero here in case they set it to something in an earlier version. @@ -639,7 +646,7 @@ bool LoadWallet(bool& fFirstRunRet) else { // Create new keyUser and set as default key - RandAddSeed(true); + RandAddSeedPerfmon(); keyUser.MakeNewKey(); if (!AddKey(keyUser)) return false; diff --git a/headers.h b/headers.h index f7e88e0c671eb..29b16fb7809b6 100644 --- a/headers.h +++ b/headers.h @@ -5,6 +5,7 @@ #ifdef _MSC_VER #pragma warning(disable:4786) #pragma warning(disable:4804) +#pragma warning(disable:4805) #pragma warning(disable:4717) #endif #ifdef _WIN32_WINNT @@ -62,6 +63,7 @@ using namespace boost; +#include "strlcpy.h" #include "serialize.h" #include "uint256.h" #include "util.h" diff --git a/irc.cpp b/irc.cpp index cfc9464aa7eec..707b4fe19f8a2 100644 --- a/irc.cpp +++ b/irc.cpp @@ -163,6 +163,9 @@ void ThreadIRCSeed(void* parg) int nErrorWait = 10; int nRetryWait = 10; + if (fUseProxy && addrProxy.port == htons(9050)) + return; + while (!fShutdown) { CAddress addrConnect("216.155.130.130:6667"); @@ -191,9 +194,10 @@ void ThreadIRCSeed(void* parg) return; } - string strMyName = EncodeAddress(addrLocalHost); - - if (!addrLocalHost.IsRoutable()) + string strMyName; + if (addrLocalHost.IsRoutable() && !fUseProxy) + strMyName = EncodeAddress(addrLocalHost); + else strMyName = strprintf("x%u", GetRand(1000000000)); diff --git a/key.h b/key.h index 39ca86d31784e..71fce64a2aea0 100644 --- a/key.h +++ b/key.h @@ -35,7 +35,7 @@ class key_error : public std::runtime_error }; -// secure_allocator is defined is serialize.h +// secure_allocator is defined in serialize.h typedef vector > CPrivKey; diff --git a/main.cpp b/main.cpp index dbdee70211335..710b7892009c5 100644 --- a/main.cpp +++ b/main.cpp @@ -415,6 +415,10 @@ bool CTransaction::AcceptTransaction(CTxDB& txdb, bool fCheckInputs, bool* pfMis if (!CheckTransaction()) return error("AcceptTransaction() : CheckTransaction failed"); + // To help v0.1.5 clients who would see it as negative number. please delete this later. + if (nLockTime > INT_MAX) + return error("AcceptTransaction() : not accepting nLockTime beyond 2038"); + // Do we already have it? uint256 hash = GetHash(); CRITICAL_BLOCK(cs_mapTransactions) @@ -1214,6 +1218,12 @@ bool CBlock::AcceptBlock() if (nTime <= pindexPrev->GetMedianTimePast()) return error("AcceptBlock() : block's timestamp is too early"); + // Check that all transactions are finalized (starting around 30 Nov 2009) + if (nBestHeight > 31000) // 25620 + 5320 + foreach(const CTransaction& tx, vtx) + if (!tx.IsFinal(nTime)) + return error("AcceptBlock() : contains a non-final transaction"); + // Check proof of work if (nBits != GetNextWorkRequired(pindexPrev)) return error("AcceptBlock() : incorrect proof of work"); @@ -1649,7 +1659,7 @@ bool ProcessMessages(CNode* pfrom) CDataStream& vRecv = pfrom->vRecv; if (vRecv.empty()) return true; - printf("ProcessMessages(%d bytes)\n", vRecv.size()); + //printf("ProcessMessages(%d bytes)\n", vRecv.size()); // // Message format @@ -1692,7 +1702,7 @@ bool ProcessMessages(CNode* pfrom) { // Rewind and wait for rest of message ///// need a mechanism to give up waiting for overlong message size error - printf("MESSAGE-BREAK\n"); + //printf("message-break\n"); vRecv.insert(vRecv.begin(), BEGIN(hdr), END(hdr)); Sleep(100); break; @@ -1711,7 +1721,20 @@ bool ProcessMessages(CNode* pfrom) fRet = ProcessMessage(pfrom, strCommand, vMsg); CheckForShutdown(2); } - CATCH_PRINT_EXCEPTION("ProcessMessage()") + catch (std::ios_base::failure& e) { + if (strstr(e.what(), "CDataStream::read() : end of data")) + { + // Allow exceptions from underlength message on vRecv + LogException(&e, "ProcessMessage()"); + } + else + PrintException(&e, "ProcessMessage()"); + } catch (std::exception& e) { + PrintException(&e, "ProcessMessage()"); + } catch (...) { + PrintException(NULL, "ProcessMessage()"); + } + if (!fRet) printf("ProcessMessage(%s, %d bytes) FAILED\n", strCommand.c_str(), nMessageSize); } @@ -1726,7 +1749,8 @@ bool ProcessMessages(CNode* pfrom) bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { static map > mapReuseKey; - printf("received: %-12s (%d bytes)\n", strCommand.c_str(), vRecv.size()); + RandAddSeedPerfmon(); + printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size()); if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) { printf("dropmessages DROPPING RECV MESSAGE\n"); @@ -1735,18 +1759,32 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) + if (strCommand == "version") { - // Can only do this once + // Each connection can only send one version message if (pfrom->nVersion != 0) return false; int64 nTime; CAddress addrMe; + CAddress addrFrom; + uint64 nNonce = 1; vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; + if (pfrom->nVersion >= 106 && !vRecv.empty()) + vRecv >> addrFrom >> nNonce; if (pfrom->nVersion == 0) return false; + // Disconnect if we connected to ourself + if (nNonce == nLocalHostNonce) + { + pfrom->fDisconnect = true; + pfrom->vRecv.clear(); + pfrom->vSend.clear(); + return true; + } + pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION)); pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION)); @@ -1767,6 +1805,8 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), uint256(0)); } + pfrom->fSuccessfullyConnected = true; + printf("version message: version %d\n", pfrom->nVersion); } @@ -1800,16 +1840,16 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (fShutdown) return true; AddAddress(addrdb, addr); - if (addr.IsRoutable() && addr.ip != addrLocalHost.ip) + pfrom->AddAddressKnown(addr); + if (!pfrom->fGetAddr && addr.IsRoutable()) { // Put on lists to send to other nodes - pfrom->setAddrKnown.insert(addr); CRITICAL_BLOCK(cs_vNodes) foreach(CNode* pnode, vNodes) - if (!pnode->setAddrKnown.count(addr)) - pnode->vAddrToSend.push_back(addr); + pnode->PushAddress(addr); } } + pfrom->fGetAddr = false; } @@ -2009,7 +2049,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) return true; const CAddress& addr = item.second; if (addr.nTime > nSince) - pfrom->vAddrToSend.push_back(addr); + pfrom->PushAddress(addr); } } } @@ -2108,8 +2148,11 @@ bool SendMessages(CNode* pto) vector vAddrToSend; vAddrToSend.reserve(pto->vAddrToSend.size()); foreach(const CAddress& addr, pto->vAddrToSend) - if (!pto->setAddrKnown.count(addr)) + { + // returns true if wasn't already contained in the set + if (pto->setAddrKnown.insert(addr).second) vAddrToSend.push_back(addr); + } pto->vAddrToSend.clear(); if (!vAddrToSend.empty()) pto->PushMessage("addr", vAddrToSend); @@ -2193,7 +2236,7 @@ void GenerateBitcoins(bool fGenerate) if (fLimitProcessors && nProcessors > nLimitProcessors) nProcessors = nLimitProcessors; int nAddThreads = nProcessors - vnThreadsRunning[3]; - printf("starting %d bitcoinminer threads\n", nAddThreads); + printf("Starting %d BitcoinMiner threads\n", nAddThreads); for (int i = 0; i < nAddThreads; i++) if (_beginthread(ThreadBitcoinMiner, 0, NULL) == -1) printf("Error: _beginthread(ThreadBitcoinMiner) failed\n"); @@ -2207,7 +2250,7 @@ void ThreadBitcoinMiner(void* parg) try { bool fRet = BitcoinMiner(); - printf("BitcoinMiner returned %s\n\n\n", fRet ? "true" : "false"); + printf("BitcoinMiner returned %s\n", fRet ? "true" : "false"); vnThreadsRunning[3]--; } catch (std::exception& e) { @@ -2737,7 +2780,7 @@ bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew) else strError = "Error: Transaction creation failed "; wxMessageBox(strError, "Sending..."); - return error("SendMoney() : %s\n", strError.c_str()); + return error("SendMoney() : %s", strError.c_str()); } if (!CommitTransactionSpent(wtxNew, key)) { diff --git a/main.h b/main.h index 6b11285e5edfc..958f7a5f1c529 100644 --- a/main.h +++ b/main.h @@ -366,7 +366,7 @@ class CTransaction int nVersion; vector vin; vector vout; - int nLockTime; + unsigned int nLockTime; CTransaction() @@ -401,9 +401,15 @@ class CTransaction return SerializeHash(*this); } - bool IsFinal() const + bool IsFinal(int64 nBlockTime=0) const { - if (nLockTime == 0 || nLockTime < nBestHeight) + // 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 (nLockTime < (nLockTime < 500000000 ? nBestHeight : nBlockTime)) return true; foreach(const CTxIn& txin, vin) if (!txin.IsFinal()) @@ -686,8 +692,9 @@ class CWalletTx : public CMerkleTx char fSpent; //// probably need to sign the order info so know it came from payer - // memory only + // memory only UI hints mutable unsigned int nTimeDisplayed; + mutable int nLinesDisplayed; CWalletTx() @@ -712,6 +719,7 @@ class CWalletTx : public CMerkleTx fFromMe = false; fSpent = false; nTimeDisplayed = 0; + nLinesDisplayed = 0; } IMPLEMENT_SERIALIZE diff --git a/makefile b/makefile index 64bb7730479fb..2d932f02cd158 100644 --- a/makefile +++ b/makefile @@ -17,8 +17,8 @@ endif -INCLUDEPATHS=-I"/boost" -I"/DB/build_unix" -I"/OpenSSL/include" -I"/wxWidgets/lib/vc_lib/mswd" -I"/wxWidgets/include" -LIBPATHS=-L"/DB/build_unix" -L"/OpenSSL/out" -L"/wxWidgets/lib/gcc_lib" +INCLUDEPATHS=-I"/boost" -I"/db/build_unix" -I"/openssl/include" -I"/wxwidgets/lib/vc_lib/mswd" -I"/wxwidgets/include" +LIBPATHS=-L"/db/build_unix" -L"/openssl/out" -L"/wxwidgets/lib/gcc_lib" LIBS= \ -l db_cxx \ -l eay32 \ diff --git a/net.cpp b/net.cpp index db138e13a56e5..22b84f9dee34e 100644 --- a/net.cpp +++ b/net.cpp @@ -8,6 +8,7 @@ void ThreadMessageHandler2(void* parg); void ThreadSocketHandler2(void* parg); void ThreadOpenConnections2(void* parg); +bool OpenNetworkConnection(const CAddress& addrConnect); @@ -22,8 +23,10 @@ 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; +uint64 nLocalHostNonce = 0; bool fShutdown = false; array vnThreadsRunning; +SOCKET hListenSocket = INVALID_SOCKET; vector vNodes; CCriticalSection cs_vNodes; @@ -34,9 +37,11 @@ deque > vRelayExpiration; CCriticalSection cs_mapRelay; map mapAlreadyAskedFor; +// Settings +int fUseProxy = false; +CAddress addrProxy("127.0.0.1:9050"); -CAddress addrProxy; bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet) { @@ -47,7 +52,7 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet) return false; bool fRoutable = !(addrConnect.GetByte(3) == 10 || (addrConnect.GetByte(3) == 192 && addrConnect.GetByte(2) == 168)); - bool fProxy = (addrProxy.ip && fRoutable); + bool fProxy = (fUseProxy && fRoutable); struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr()); if (connect(hSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) @@ -69,18 +74,18 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet) if (ret != nSize) { closesocket(hSocket); - return error("Error sending to proxy\n"); + return error("Error sending to proxy"); } char pchRet[8]; if (recv(hSocket, pchRet, 8, 0) != 8) { closesocket(hSocket); - return error("Error reading proxy response\n"); + return error("Error reading proxy response"); } if (pchRet[1] != 0x5a) { closesocket(hSocket); - return error("Proxy returned error %d\n", pchRet[1]); + return error("Proxy returned error %d", pchRet[1]); } printf("Proxy connection established %s\n", addrConnect.ToStringLog().c_str()); } @@ -95,7 +100,7 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha { SOCKET hSocket; if (!ConnectSocket(addrConnect, hSocket)) - return error("GetMyExternalIP() : connection to %s failed\n", addrConnect.ToString().c_str()); + return error("GetMyExternalIP() : connection to %s failed", addrConnect.ToString().c_str()); send(hSocket, pszGet, strlen(pszGet), 0); @@ -131,7 +136,7 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha } } closesocket(hSocket); - return error("GetMyExternalIP() : connection closed\n"); + return error("GetMyExternalIP() : connection closed"); } @@ -141,6 +146,9 @@ bool GetMyExternalIP(unsigned int& ipRet) char* pszGet; char* pszKeyword; + if (fUseProxy) + return false; + for (int nLookup = 0; nLookup <= 1; nLookup++) for (int nHost = 1; nHost <= 2; nHost++) { @@ -416,14 +424,14 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) } } -void CNode::Disconnect() +void CNode::DoDisconnect() { printf("disconnecting node %s\n", addr.ToStringLog().c_str()); closesocket(hSocket); // If outbound and never got version message, mark address as failed - if (!fInbound && nVersion == 0) + if (!fInbound && !fSuccessfullyConnected) CRITICAL_BLOCK(cs_mapAddresses) mapAddresses[addr.GetKey()].nLastFailed = GetTime(); @@ -458,18 +466,18 @@ void ThreadSocketHandler(void* parg) loop { - vnThreadsRunning[0] = true; + vnThreadsRunning[0]++; CheckForShutdown(0); try { ThreadSocketHandler2(parg); - vnThreadsRunning[0] = false; + vnThreadsRunning[0]--; } catch (std::exception& e) { - vnThreadsRunning[0] = false; + vnThreadsRunning[0]--; PrintException(&e, "ThreadSocketHandler()"); } catch (...) { - vnThreadsRunning[0] = false; + vnThreadsRunning[0]--; PrintException(NULL, "ThreadSocketHandler()"); } Sleep(5000); @@ -479,7 +487,6 @@ void ThreadSocketHandler(void* parg) void ThreadSocketHandler2(void* parg) { printf("ThreadSocketHandler started\n"); - SOCKET hListenSocket = *(SOCKET*)parg; list vNodesDisconnected; int nPrevNodeCount = 0; @@ -498,7 +505,7 @@ void ThreadSocketHandler2(void* parg) { // remove from vNodes vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end()); - pnode->Disconnect(); + pnode->DoDisconnect(); // hold in disconnected pool until all refs are released pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 5 * 60); @@ -562,9 +569,9 @@ void ThreadSocketHandler2(void* parg) } } - vnThreadsRunning[0] = false; + vnThreadsRunning[0]--; int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, NULL, &timeout); - vnThreadsRunning[0] = true; + vnThreadsRunning[0]++; CheckForShutdown(0); if (nSelect == SOCKET_ERROR) { @@ -577,7 +584,6 @@ void ThreadSocketHandler2(void* parg) } Sleep(timeout.tv_usec/1000); } - RandAddSeed(); //// debug print //foreach(CNode* pnode, vNodes) @@ -711,18 +717,18 @@ void ThreadOpenConnections(void* parg) loop { - vnThreadsRunning[1] = true; + vnThreadsRunning[1]++; CheckForShutdown(1); try { ThreadOpenConnections2(parg); - vnThreadsRunning[1] = false; + vnThreadsRunning[1]--; } catch (std::exception& e) { - vnThreadsRunning[1] = false; + vnThreadsRunning[1]--; PrintException(&e, "ThreadOpenConnections()"); } catch (...) { - vnThreadsRunning[1] = false; + vnThreadsRunning[1]--; PrintException(NULL, "ThreadOpenConnections()"); } Sleep(5000); @@ -733,6 +739,13 @@ void ThreadOpenConnections2(void* parg) { printf("ThreadOpenConnections started\n"); + // Connect to one specified address + while (mapArgs.count("/connect")) + { + OpenNetworkConnection(CAddress(mapArgs["/connect"].c_str())); + Sleep(10000); + } + // Initiate network connections int nTry = 0; bool fIRCOnly = false; @@ -740,14 +753,14 @@ void ThreadOpenConnections2(void* parg) loop { // Wait - vnThreadsRunning[1] = false; + vnThreadsRunning[1]--; Sleep(500); while (vNodes.size() >= nMaxConnections || vNodes.size() >= mapAddresses.size()) { CheckForShutdown(1); Sleep(2000); } - vnThreadsRunning[1] = true; + vnThreadsRunning[1]++; CheckForShutdown(1); @@ -835,43 +848,48 @@ void ThreadOpenConnections2(void* parg) // Once we've chosen an IP, we'll try every given port before moving on foreach(const CAddress& addrConnect, (*mi).second) - { - // - // Initiate outbound network connection - // - CheckForShutdown(1); - if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip)) - continue; + if (OpenNetworkConnection(addrConnect)) + break; + } +} - vnThreadsRunning[1] = false; - CNode* pnode = ConnectNode(addrConnect); - vnThreadsRunning[1] = true; - CheckForShutdown(1); - if (!pnode) - continue; - pnode->fNetworkNode = true; +bool OpenNetworkConnection(const CAddress& addrConnect) +{ + // + // Initiate outbound network connection + // + CheckForShutdown(1); + if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip)) + return false; - if (addrLocalHost.IsRoutable()) - { - // Advertise our address - vector vAddrToSend; - vAddrToSend.push_back(addrLocalHost); - pnode->PushMessage("addr", vAddrToSend); - } + vnThreadsRunning[1]--; + CNode* pnode = ConnectNode(addrConnect); + vnThreadsRunning[1]++; + CheckForShutdown(1); + if (!pnode) + return false; + pnode->fNetworkNode = true; - // Get as many addresses as we can - pnode->PushMessage("getaddr"); + if (addrLocalHost.IsRoutable() && !fUseProxy) + { + // Advertise our address + vector vAddrToSend; + vAddrToSend.push_back(addrLocalHost); + pnode->PushMessage("addr", vAddrToSend); + } - ////// should the one on the receiving end do this too? - // Subscribe our local subscription list - const unsigned int nHops = 0; - for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++) - if (pnodeLocalHost->vfSubscribe[nChannel]) - pnode->PushMessage("subscribe", nChannel, nHops); + // Get as many addresses as we can + pnode->PushMessage("getaddr"); + pnode->fGetAddr = true; // don't relay the results of the getaddr - break; - } - } + ////// should the one on the receiving end do this too? + // Subscribe our local subscription list + const unsigned int nHops = 0; + for (unsigned int nChannel = 0; nChannel < pnodeLocalHost->vfSubscribe.size(); nChannel++) + if (pnodeLocalHost->vfSubscribe[nChannel]) + pnode->PushMessage("subscribe", nChannel, nHops); + + return true; } @@ -887,18 +905,18 @@ void ThreadMessageHandler(void* parg) loop { - vnThreadsRunning[2] = true; + vnThreadsRunning[2]++; CheckForShutdown(2); try { ThreadMessageHandler2(parg); - vnThreadsRunning[2] = false; + vnThreadsRunning[2]--; } catch (std::exception& e) { - vnThreadsRunning[2] = false; + vnThreadsRunning[2]--; PrintException(&e, "ThreadMessageHandler()"); } catch (...) { - vnThreadsRunning[2] = false; + vnThreadsRunning[2]--; PrintException(NULL, "ThreadMessageHandler()"); } Sleep(5000); @@ -931,9 +949,9 @@ void ThreadMessageHandler2(void* parg) } // Wait and allow messages to bunch up - vnThreadsRunning[2] = false; + vnThreadsRunning[2]--; Sleep(100); - vnThreadsRunning[2] = true; + vnThreadsRunning[2]++; CheckForShutdown(2); } } @@ -982,7 +1000,7 @@ bool StartNode(string& strError) printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str()); // Create socket for listening for incoming connections - SOCKET hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + hListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (hListenSocket == INVALID_SOCKET) { strError = strprintf("Error: Couldn't open socket for incoming connections (socket returned error %d)", WSAGetLastError()); @@ -1024,13 +1042,21 @@ bool StartNode(string& strError) } // Get our external IP address for incoming connections - if (addrIncoming.ip) - addrLocalHost.ip = addrIncoming.ip; - - if (GetMyExternalIP(addrLocalHost.ip)) + if (fUseProxy) { - addrIncoming = addrLocalHost; - CWalletDB().WriteSetting("addrIncoming", addrIncoming); + // Proxies can't take incoming connections + addrLocalHost.ip = CAddress("0.0.0.0").ip; + } + else + { + if (addrIncoming.ip) + addrLocalHost.ip = addrIncoming.ip; + + if (GetMyExternalIP(addrLocalHost.ip)) + { + addrIncoming = addrLocalHost; + CWalletDB().WriteSetting("addrIncoming", addrIncoming); + } } // Get addresses from IRC and advertise ours @@ -1040,7 +1066,7 @@ bool StartNode(string& strError) // // Start threads // - if (_beginthread(ThreadSocketHandler, 0, new SOCKET(hListenSocket)) == -1) + if (_beginthread(ThreadSocketHandler, 0, NULL) == -1) { strError = "Error: _beginthread(ThreadSocketHandler) failed"; printf("%s\n", strError.c_str()); @@ -1094,10 +1120,15 @@ void CheckForShutdown(int n) if (fShutdown) { if (n != -1) - vnThreadsRunning[n] = false; + if (--vnThreadsRunning[n] < 0) + vnThreadsRunning[n] = 0; if (n == 0) + { foreach(CNode* pnode, vNodes) closesocket(pnode->hSocket); + closesocket(hListenSocket); + } + printf("Thread %d exiting\n", n); _endthread(); } } diff --git a/net.h b/net.h index 334100422fe13..a0b2929daabc0 100644 --- a/net.h +++ b/net.h @@ -174,7 +174,7 @@ class CAddress { nServices = nServicesIn; memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); - ip = 0; + ip = INADDR_NONE; port = DEFAULT_PORT; nTime = GetAdjustedTime(); nLastFailed = 0; @@ -183,7 +183,7 @@ class CAddress if (strlen(pszIn) > ARRAYLEN(psz)-1) return; strcpy(psz, pszIn); - unsigned int a, b, c, d, e; + 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; char* pszPort = strchr(psz, ':'); @@ -191,6 +191,10 @@ class CAddress { *pszPort++ = '\0'; port = htons(atoi(pszPort)); + if (atoi(pszPort) > USHRT_MAX) + port = htons(USHRT_MAX); + if (atoi(pszPort) < 0) + port = htons(0); } ip = inet_addr(psz); } @@ -215,6 +219,11 @@ class CAddress a.port == b.port); } + friend inline bool operator!=(const CAddress& a, const CAddress& b) + { + return (!(a == b)); + } + friend inline bool operator<(const CAddress& a, const CAddress& b) { int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)); @@ -277,6 +286,11 @@ class CAddress return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); } + string ToStringPort() const + { + return strprintf("%u", ntohs(port)); + } + string ToStringLog() const { return ""; @@ -416,6 +430,7 @@ extern bool fClient; extern uint64 nLocalServices; extern CAddress addrLocalHost; extern CNode* pnodeLocalHost; +extern uint64 nLocalHostNonce; extern bool fShutdown; extern array vnThreadsRunning; extern vector vNodes; @@ -426,6 +441,9 @@ extern map mapRelay; extern deque > vRelayExpiration; extern CCriticalSection cs_mapRelay; extern map mapAlreadyAskedFor; + +// Settings +extern int fUseProxy; extern CAddress addrProxy; @@ -448,6 +466,7 @@ class CNode bool fClient; bool fInbound; bool fNetworkNode; + bool fSuccessfullyConnected; bool fDisconnect; protected: int nRefCount; @@ -459,6 +478,7 @@ class CNode // flood vector vAddrToSend; set setAddrKnown; + bool fGetAddr; // inventory based relay set setInventoryKnown; @@ -483,15 +503,20 @@ class CNode fClient = false; // set by version message fInbound = fInboundIn; fNetworkNode = false; + fSuccessfullyConnected = false; fDisconnect = false; nRefCount = 0; nReleaseTime = 0; + fGetAddr = false; vfSubscribe.assign(256, false); // Push a version message /// when NTP implemented, change to just nTime = GetAdjustedTime() int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); - PushMessage("version", VERSION, nLocalServices, nTime, addr); + CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr); + CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost); + RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); + PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce); } ~CNode() @@ -531,6 +556,21 @@ class CNode + void AddAddressKnown(const CAddress& addr) + { + setAddrKnown.insert(addr); + } + + void PushAddress(const CAddress& addr) + { + // Known checking here is only to save space from duplicates. + // SendMessages will filter it again for knowns that were added + // after addresses were pushed. + if (!setAddrKnown.count(addr)) + vAddrToSend.push_back(addr); + } + + void AddInventoryKnown(const CInv& inv) { CRITICAL_BLOCK(cs_inventory) @@ -562,7 +602,6 @@ class CNode } - void BeginMessage(const char* pszCommand) { EnterCriticalSection(&cs_vSend); @@ -570,7 +609,7 @@ class CNode AbortMessage(); nPushPos = vSend.size(); vSend << CMessageHeader(pszCommand, 0); - printf("sending: %-12s ", pszCommand); + printf("sending: %s ", pszCommand); } void AbortMessage() @@ -706,6 +745,86 @@ class CNode } } + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5 << a6; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + + template + void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9) + { + try + { + BeginMessage(pszCommand); + vSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9; + EndMessage(); + } + catch (...) + { + AbortMessage(); + throw; + } + } + void PushRequest(const char* pszCommand, void (*fn)(void*, CDataStream&), void* param1) @@ -750,7 +869,7 @@ class CNode bool IsSubscribed(unsigned int nChannel); void Subscribe(unsigned int nChannel, unsigned int nHops=0); void CancelSubscribe(unsigned int nChannel); - void Disconnect(); + void DoDisconnect(); }; diff --git a/serialize.h b/serialize.h index b7ab86d22ab1f..9b20e2a0f6311 100644 --- a/serialize.h +++ b/serialize.h @@ -19,7 +19,7 @@ class CScript; class CDataStream; class CAutoFile; -static const int VERSION = 105; +static const int VERSION = 106; diff --git a/strlcpy.h b/strlcpy.h new file mode 100644 index 0000000000000..a79ee1756c792 --- /dev/null +++ b/strlcpy.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +inline size_t strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0) + { + while (--n != 0) + { + if ((*d++ = *s++) == '\0') + break; + } + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) + { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +inline size_t strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') + { + if (n != 1) + { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/ui.cpp b/ui.cpp index 428304796e421..917c64b4456a0 100644 --- a/ui.cpp +++ b/ui.cpp @@ -497,7 +497,7 @@ string SingleLine(const string& strIn) return strOut; } -void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) +bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) { int64 nTime = wtx.nTimeDisplayed = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(); @@ -506,14 +506,11 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) uint256 hash = wtx.GetHash(); string strStatus = FormatTxStatus(wtx); map mapValue = wtx.mapValue; + wtx.nLinesDisplayed = 1; // Filter if (wtx.IsCoinBase()) { - // View->Show Generated - if (!fShowGenerated) - return; - // Don't show generated coin until confirmed by at least one block after it // so we don't get the user's hopes up until it looks like it's probably accepted. // @@ -527,10 +524,13 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) // if (wtx.GetDepthInMainChain() < 2) { - // In case it was previously displayed - DeleteLine(hash); - return; + wtx.nLinesDisplayed = 0; + return false; } + + // View->Show Generated + if (!fShowGenerated) + return false; } // Find the block the tx is in @@ -644,6 +644,7 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) // Debit // int64 nTxFee = nDebit - wtx.GetValueOut(); + wtx.nLinesDisplayed = 0; for (int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; @@ -685,6 +686,7 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) SingleLine(strDescription), FormatMoney(-nValue, true), ""); + wtx.nLinesDisplayed++; } } else @@ -706,12 +708,14 @@ void CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex) ""); } } + + return true; } void CMainFrame::RefreshStatus() { static int nLastTop; - int nTop = m_listCtrl->GetTopItem(); + int nTop = max((int)m_listCtrl->GetTopItem(), 0); if (nTop == nLastTop && pindexBestLast == pindexBest) return; @@ -729,7 +733,7 @@ void CMainFrame::RefreshStatus() nLastTop = nTop; pindexBestLast = pindexBest; - for (int nIndex = nStart; nIndex < nEnd; nIndex++) + for (int nIndex = nStart; nIndex < min(nEnd, m_listCtrl->GetItemCount()); nIndex++) { uint256 hash((string)GetItemText(m_listCtrl, nIndex, 1)); map::iterator mi = mapWallet.find(hash); @@ -738,9 +742,12 @@ void CMainFrame::RefreshStatus() printf("CMainFrame::RefreshStatus() : tx not found in mapWallet\n"); continue; } - const CWalletTx& wtx = (*mi).second; + CWalletTx& wtx = (*mi).second; if (wtx.IsCoinBase() || wtx.GetTxTime() != wtx.nTimeDisplayed) - InsertTransaction(wtx, false, nIndex); + { + if (!InsertTransaction(wtx, false, nIndex)) + m_listCtrl->DeleteItem(nIndex--); + } else m_listCtrl->SetItem(nIndex, 2, FormatTxStatus(wtx)); } @@ -801,6 +808,9 @@ void CMainFrame::OnIdle(wxIdleEvent& event) } printf("RefreshListCtrl done\n"); + + // Update transaction total display + MainFrameRepaint(); } else { @@ -834,31 +844,54 @@ void DelayedRepaint(void* parg) return; fOneThread = true; Sleep(1000); + printf("DelayedRepaint()\n"); MainFrameRepaint(); fOneThread = false; } void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) { + if (ptaskbaricon) + ptaskbaricon->UpdateTooltip(); + // Update listctrl contents if (!vWalletUpdated.empty()) { TRY_CRITICAL_BLOCK(cs_mapWallet) { + bool fInserted = false; foreach(uint256 hash, vWalletUpdated) { map::iterator mi = mapWallet.find(hash); if (mi != mapWallet.end()) - InsertTransaction((*mi).second, false); + fInserted |= InsertTransaction((*mi).second, false); } - 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::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + CWalletTx& wtx = (*it).second; + nTransactionCount += wtx.nLinesDisplayed; + } + } + // Update status bar string strGen = ""; if (fGenerateBitcoins) @@ -867,17 +900,9 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event) strGen = "(not connected)"; m_statusBar->SetStatusText(strGen, 1); - string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, m_listCtrl->GetItemCount()); + string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount); m_statusBar->SetStatusText(strStatus, 2); - // Balance total - bool fRefreshed = false; - TRY_CRITICAL_BLOCK(cs_mapWallet) - { - m_staticTextBalance->SetLabel(FormatMoney(GetBalance()) + " "); - fRefreshed = true; - } - // mapWallet was locked, try again later if (!vWalletUpdated.empty() || !fRefreshed) _beginthread(DelayedRepaint, 0, NULL); @@ -1350,6 +1375,14 @@ COptionsDialog::COptionsDialog(wxWindow* parent) : COptionsDialogBase(parent) m_checkBoxMinimizeOnClose->Enable(fMinimizeToTray); m_checkBoxMinimizeOnClose->SetValue(fMinimizeToTray && fMinimizeOnClose); fTmpMinimizeOnClose = fMinimizeOnClose; + m_checkBoxUseProxy->SetValue(fUseProxy); + m_textCtrlProxyIP->Enable(fUseProxy); + m_textCtrlProxyPort->Enable(fUseProxy); + m_staticTextProxyIP->Enable(fUseProxy); + m_staticTextProxyPort->Enable(fUseProxy); + m_textCtrlProxyIP->SetValue(addrProxy.ToStringIP()); + m_textCtrlProxyPort->SetValue(addrProxy.ToStringPort()); + m_buttonOK->SetFocus(); } @@ -1395,6 +1428,34 @@ void COptionsDialog::OnCheckBoxMinimizeToTray(wxCommandEvent& event) } +void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event) +{ + m_textCtrlProxyIP->Enable(event.IsChecked()); + m_textCtrlProxyPort->Enable(event.IsChecked()); + m_staticTextProxyIP->Enable(event.IsChecked()); + m_staticTextProxyPort->Enable(event.IsChecked()); +} + +CAddress COptionsDialog::GetProxyAddr() +{ + // Be careful about byte order, addr.ip and addr.port are big endian + CAddress addr(m_textCtrlProxyIP->GetValue() + ":" + m_textCtrlProxyPort->GetValue()); + if (addr.ip == INADDR_NONE) + addr.ip = addrProxy.ip; + int nPort = atoi(m_textCtrlProxyPort->GetValue()); + addr.port = htons(nPort); + if (nPort <= 0 || nPort > USHRT_MAX) + addr.port = addrProxy.port; + return addr; +} + +void COptionsDialog::OnKillFocusProxy(wxFocusEvent& event) +{ + m_textCtrlProxyIP->SetValue(GetProxyAddr().ToStringIP()); + m_textCtrlProxyPort->SetValue(GetProxyAddr().ToStringPort()); +} + + void COptionsDialog::OnButtonOK(wxCommandEvent& event) { OnButtonApply(event); @@ -1446,6 +1507,18 @@ void COptionsDialog::OnButtonApply(wxCommandEvent& event) fMinimizeOnClose = (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose); walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose); } + + if (fUseProxy != m_checkBoxUseProxy->GetValue()) + { + fUseProxy = m_checkBoxUseProxy->GetValue(); + walletdb.WriteSetting("fUseProxy", fUseProxy); + } + + if (addrProxy != GetProxyAddr()) + { + addrProxy = GetProxyAddr(); + walletdb.WriteSetting("addrProxy", addrProxy); + } } @@ -1657,7 +1730,7 @@ CSendingDialog::CSendingDialog(wxWindow* parent, const CAddress& addrIn, int64 n nPrice = nPriceIn; wtx = wtxIn; start = wxDateTime::UNow(); - strStatus = ""; + memset(pszStatus, 0, sizeof(pszStatus)); fCanCancel = true; fAbort = false; fSuccess = false; @@ -1721,10 +1794,10 @@ void CSendingDialog::OnButtonCancel(wxCommandEvent& event) void CSendingDialog::OnPaint(wxPaintEvent& event) { - if (strStatus.size() > 130) - m_textCtrlStatus->SetValue(string("\n") + strStatus); + if (strlen(pszStatus) > 130) + m_textCtrlStatus->SetValue(string("\n") + pszStatus); else - m_textCtrlStatus->SetValue(string("\n\n") + strStatus); + m_textCtrlStatus->SetValue(string("\n\n") + pszStatus); m_staticTextSending->SetFocus(); if (!fCanCancel) m_buttonCancel->Enable(false); @@ -1736,7 +1809,7 @@ void CSendingDialog::OnPaint(wxPaintEvent& event) } if (fAbort && fCanCancel && IsShown()) { - strStatus = "CANCELLED"; + strcpy(pszStatus, "CANCELLED"); m_buttonOK->Enable(true); m_buttonOK->SetFocus(); m_buttonCancel->Enable(false); @@ -1777,7 +1850,8 @@ bool CSendingDialog::Status() } if (fAbort && fCanCancel) { - strStatus = "CANCELLED"; + memset(pszStatus, 0, 10); + strcpy(pszStatus, "CANCELLED"); Repaint(); fWorkDone = true; return false; @@ -1789,7 +1863,12 @@ bool CSendingDialog::Status(const string& str) { if (!Status()) return false; - strStatus = str; + + // This can be read by the UI thread at any time, + // so copy in a way that can be read cleanly at all times. + memset(pszStatus, 0, min(str.size()+1, sizeof(pszStatus))); + strlcpy(pszStatus, str.c_str(), sizeof(pszStatus)); + Repaint(); return true; } @@ -1950,8 +2029,8 @@ void CSendingDialog::OnReply3(CDataStream& vRecv) if (nRet > 0) { Error("The payment was sent, but the recipient was unable to verify it.\n" - "The transaction is recorded and will credit to the recipient if it is valid,\n" - "but without comment information."); + "The transaction is recorded and will credit to the recipient,\n" + "but the comment information will be blank."); return; } } @@ -3092,6 +3171,7 @@ END_EVENT_TABLE() void CMyTaskBarIcon::Show(bool fShow) { + static char pszPrevTip[200]; if (fShow) { string strTooltip = "Bitcoin"; @@ -3099,10 +3179,17 @@ void CMyTaskBarIcon::Show(bool fShow) strTooltip = "Bitcoin - Generating"; if (fGenerateBitcoins && vNodes.empty()) strTooltip = "Bitcoin - (not connected)"; - SetIcon(wxICON(bitcoin), strTooltip); + + // Optimization, only update when changed, using char array to be reentrant + if (strncmp(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)-1) != 0) + { + strlcpy(pszPrevTip, strTooltip.c_str(), sizeof(pszPrevTip)); + SetIcon(wxICON(bitcoin), strTooltip); + } } else { + strlcpy(pszPrevTip, "", sizeof(pszPrevTip)); RemoveIcon(); } } @@ -3301,12 +3388,12 @@ bool CMyApp::OnInit2() if (mapArgs.count("/datadir")) strSetDataDir = mapArgs["/datadir"]; - if (mapArgs.count("/proxy")) - addrProxy = CAddress(mapArgs["/proxy"].c_str()); - if (mapArgs.count("/debug")) fDebug = true; + if (mapArgs.count("/printtodebugger")) + fPrintToDebugger = true; + if (mapArgs.count("/dropmessages")) { nDropMessagesTest = atoi(mapArgs["/dropmessages"]); @@ -3380,6 +3467,20 @@ bool CMyApp::OnInit2() return false; } + if (mapArgs.count("/proxy")) + { + fUseProxy = true; + addrProxy = CAddress(mapArgs["/proxy"].c_str()); + if (addrProxy.ip == INADDR_NONE) + { + wxMessageBox("Invalid /proxy address", "Bitcoin"); + OnExit(); + } + CWalletDB walletdb; + walletdb.WriteSetting("fUseProxy", fUseProxy); + walletdb.WriteSetting("addrProxy", addrProxy); + } + if (mapArgs.count("/gen")) { if (mapArgs["/gen"].empty()) @@ -3404,7 +3505,7 @@ bool CMyApp::OnInit2() return false; } - //RandAddSeedPerfmon(); + RandAddSeedPerfmon(); if (!StartNode(strErrors)) wxMessageBox(strErrors, "Bitcoin"); @@ -3514,7 +3615,7 @@ void CMyApp::OnFatalException() void MainFrameRepaint() { - // This is called by network code that shouldn't access pframeMain and ptaskbaricon + // 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) { @@ -3523,20 +3624,47 @@ void MainFrameRepaint() pframeMain->Refresh(); pframeMain->AddPendingEvent(event); } - if (ptaskbaricon) - ptaskbaricon->UpdateTooltip(); } +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 is not usually available on NT 4.0 + HMODULE hShell32 = LoadLibrary("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; +} + string StartupShortcutPath() { - // Get the startup folder shortcut path - char pszLinkPath[MAX_PATH+100]; - pszLinkPath[0] = '\0'; - SHGetSpecialFolderPath(0, pszLinkPath, CSIDL_STARTUP, 0); - strcat(pszLinkPath, "\\Bitcoin.lnk"); - return pszLinkPath; + return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk"; } bool GetStartOnSystemStartup() @@ -3630,7 +3758,8 @@ void ThreadRandSendTest(void* parg) if (GetBalance() < nValue) { wxMessageBox("Out of money "); - return; + while (GetBalance() < 1000) + Sleep(1000); } nValue += (nRep % 100) * CENT; diff --git a/ui.h b/ui.h index f451d9356589c..9fc7e0ebe72ad 100644 --- a/ui.h +++ b/ui.h @@ -89,7 +89,7 @@ class CMainFrame : public CMainFrameBase 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); - void InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex=-1); + bool InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex=-1); void RefreshListCtrl(); void RefreshStatus(); }; @@ -121,6 +121,9 @@ class COptionsDialog : public COptionsDialogBase void OnKillFocusTransactionFee(wxFocusEvent& event); void OnCheckBoxLimitProcessors(wxCommandEvent& event); void OnCheckBoxMinimizeToTray(wxCommandEvent& event); + void OnCheckBoxUseProxy(wxCommandEvent& event); + void OnKillFocusProxy(wxFocusEvent& event); + void OnButtonOK(wxCommandEvent& event); void OnButtonCancel(wxCommandEvent& event); void OnButtonApply(wxCommandEvent& event); @@ -133,6 +136,7 @@ class COptionsDialog : public COptionsDialogBase bool fTmpStartOnSystemStartup; bool fTmpMinimizeOnClose; void SelectPage(int nPage); + CAddress GetProxyAddr(); }; @@ -193,7 +197,7 @@ class CSendingDialog : public CSendingDialogBase int64 nPrice; CWalletTx wtx; wxDateTime start; - string strStatus; + char pszStatus[10000]; bool fCanCancel; bool fAbort; bool fSuccess; diff --git a/uibase.cpp b/uibase.cpp index 0f9e22c52848c..b03e578bd8a01 100644 --- a/uibase.cpp +++ b/uibase.cpp @@ -380,7 +380,7 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w bSizer69 = new wxBoxSizer( wxVERTICAL ); - bSizer69->Add( 0, 14, 0, wxEXPAND, 5 ); + bSizer69->Add( 0, 16, 0, wxEXPAND, 5 ); m_staticText32 = new wxStaticText( m_panelMain, wxID_ANY, wxT("Optional transaction fee you give to the nodes that process your transactions."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText32->Wrap( -1 ); @@ -412,7 +412,7 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w bSizer71->Add( m_checkBoxLimitProcessors, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); m_spinCtrlLimitProcessors = new wxSpinCtrl( m_panelMain, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 48,-1 ), wxSP_ARROW_KEYS, 1, 999, 1 ); - bSizer71->Add( m_spinCtrlLimitProcessors, 0, wxTOP|wxBOTTOM, 5 ); + bSizer71->Add( m_spinCtrlLimitProcessors, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_staticText35 = new wxStaticText( m_panelMain, wxID_ANY, wxT("processors"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText35->Wrap( -1 ); @@ -434,12 +434,45 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w bSizer101->Add( 16, 0, 0, 0, 5 ); - m_checkBoxMinimizeOnClose = new wxCheckBox( m_panelMain, wxID_ANY, wxT("M&inimize to system tray on close"), wxDefaultPosition, wxDefaultSize, 0 ); + m_checkBoxMinimizeOnClose = new wxCheckBox( m_panelMain, wxID_ANY, wxT("Mi&nimize to system tray on close"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizer101->Add( m_checkBoxMinimizeOnClose, 0, wxALL, 5 ); + bSizer101->Add( m_checkBoxMinimizeOnClose, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); bSizer69->Add( bSizer101, 1, wxEXPAND, 5 ); + wxBoxSizer* bSizer102; + bSizer102 = new wxBoxSizer( wxHORIZONTAL ); + + m_checkBoxUseProxy = new wxCheckBox( m_panelMain, wxID_ANY, wxT("&Connect through socks4 proxy: "), wxDefaultPosition, wxDefaultSize, 0 ); + + bSizer102->Add( m_checkBoxUseProxy, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer69->Add( bSizer102, 1, wxEXPAND, 5 ); + + wxBoxSizer* bSizer103; + bSizer103 = new wxBoxSizer( wxHORIZONTAL ); + + + bSizer103->Add( 18, 0, 0, 0, 5 ); + + m_staticTextProxyIP = new wxStaticText( m_panelMain, wxID_ANY, wxT("Proxy &IP:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextProxyIP->Wrap( -1 ); + bSizer103->Add( m_staticTextProxyIP, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_textCtrlProxyIP = new wxTextCtrl( m_panelMain, wxID_PROXYIP, wxEmptyString, wxDefaultPosition, wxSize( 140,-1 ), 0 ); + m_textCtrlProxyIP->SetMaxLength( 15 ); + bSizer103->Add( m_textCtrlProxyIP, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_staticTextProxyPort = new wxStaticText( m_panelMain, wxID_ANY, wxT(" &Port:"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticTextProxyPort->Wrap( -1 ); + bSizer103->Add( m_staticTextProxyPort, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_textCtrlProxyPort = new wxTextCtrl( m_panelMain, wxID_PROXYPORT, wxEmptyString, wxDefaultPosition, wxSize( 55,-1 ), 0 ); + m_textCtrlProxyPort->SetMaxLength( 5 ); + bSizer103->Add( m_textCtrlProxyPort, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer69->Add( bSizer103, 1, wxEXPAND, 5 ); + m_panelMain->SetSizer( bSizer69 ); m_panelMain->Layout(); bSizer69->Fit( m_panelMain ); @@ -450,13 +483,13 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w bSizer64 = new wxBoxSizer( wxVERTICAL ); - bSizer64->Add( 0, 14, 0, wxEXPAND, 5 ); + bSizer64->Add( 0, 16, 0, wxEXPAND, 5 ); m_staticText321 = new wxStaticText( m_panelTest2, wxID_ANY, wxT("Test panel 2 for future expansion"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText321->Wrap( -1 ); bSizer64->Add( m_staticText321, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - m_staticText69 = new wxStaticText( m_panelTest2, wxID_ANY, wxT("MyLabel"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText69 = new wxStaticText( m_panelTest2, wxID_ANY, wxT("Let's not start multiple pages until the first page is filled up"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText69->Wrap( -1 ); bSizer64->Add( m_staticText69, 0, wxALL, 5 ); @@ -506,6 +539,9 @@ COptionsDialogBase::COptionsDialogBase( wxWindow* parent, wxWindowID id, const w m_textCtrlTransactionFee->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusTransactionFee ), NULL, this ); m_checkBoxLimitProcessors->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxLimitProcessors ), NULL, this ); m_checkBoxMinimizeToTray->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxMinimizeToTray ), NULL, this ); + m_checkBoxUseProxy->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxUseProxy ), NULL, this ); + m_textCtrlProxyIP->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this ); + m_textCtrlProxyPort->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this ); m_buttonOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonOK ), NULL, this ); m_buttonCancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonCancel ), NULL, this ); m_buttonApply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonApply ), NULL, this ); @@ -518,6 +554,9 @@ COptionsDialogBase::~COptionsDialogBase() m_textCtrlTransactionFee->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusTransactionFee ), NULL, this ); m_checkBoxLimitProcessors->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxLimitProcessors ), NULL, this ); m_checkBoxMinimizeToTray->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxMinimizeToTray ), NULL, this ); + m_checkBoxUseProxy->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnCheckBoxUseProxy ), NULL, this ); + m_textCtrlProxyIP->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this ); + m_textCtrlProxyPort->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( COptionsDialogBase::OnKillFocusProxy ), NULL, this ); m_buttonOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonOK ), NULL, this ); m_buttonCancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonCancel ), NULL, this ); m_buttonApply->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( COptionsDialogBase::OnButtonApply ), NULL, this ); diff --git a/uibase.h b/uibase.h index e262a3dcb68b2..d52158f127827 100644 --- a/uibase.h +++ b/uibase.h @@ -50,50 +50,52 @@ #define wxID_BUTTONCOPY 1006 #define wxID_BUTTONCHANGE 1007 #define wxID_TRANSACTIONFEE 1008 -#define wxID_TEXTCTRLPAYTO 1009 -#define wxID_BUTTONPASTE 1010 -#define wxID_BUTTONADDRESSBOOK 1011 -#define wxID_TEXTCTRLAMOUNT 1012 -#define wxID_CHOICETRANSFERTYPE 1013 -#define wxID_LISTCTRL 1014 -#define wxID_BUTTONRENAME 1015 -#define wxID_BUTTONNEW 1016 -#define wxID_BUTTONEDIT 1017 -#define wxID_BUTTONDELETE 1018 -#define wxID_DEL0 1019 -#define wxID_DEL1 1020 -#define wxID_DEL2 1021 -#define wxID_DEL3 1022 -#define wxID_DEL4 1023 -#define wxID_DEL5 1024 -#define wxID_DEL6 1025 -#define wxID_DEL7 1026 -#define wxID_DEL8 1027 -#define wxID_DEL9 1028 -#define wxID_DEL10 1029 -#define wxID_DEL11 1030 -#define wxID_DEL12 1031 -#define wxID_DEL13 1032 -#define wxID_DEL14 1033 -#define wxID_DEL15 1034 -#define wxID_DEL16 1035 -#define wxID_DEL17 1036 -#define wxID_DEL18 1037 -#define wxID_DEL19 1038 -#define wxID_BUTTONPREVIEW 1039 -#define wxID_BUTTONSAMPLE 1040 -#define wxID_CANCEL2 1041 -#define wxID_BUTTONBACK 1042 -#define wxID_BUTTONNEXT 1043 -#define wxID_SUBMIT 1044 -#define wxID_OPENNEWTABLE 1045 -#define wxID_DEALHAND 1046 -#define wxID_FOLD 1047 -#define wxID_CALL 1048 -#define wxID_RAISE 1049 -#define wxID_LEAVETABLE 1050 -#define wxID_DITCHPLAYER 1051 -#define wxID_TEXTCTRL 1052 +#define wxID_PROXYIP 1009 +#define wxID_PROXYPORT 1010 +#define wxID_TEXTCTRLPAYTO 1011 +#define wxID_BUTTONPASTE 1012 +#define wxID_BUTTONADDRESSBOOK 1013 +#define wxID_TEXTCTRLAMOUNT 1014 +#define wxID_CHOICETRANSFERTYPE 1015 +#define wxID_LISTCTRL 1016 +#define wxID_BUTTONRENAME 1017 +#define wxID_BUTTONNEW 1018 +#define wxID_BUTTONEDIT 1019 +#define wxID_BUTTONDELETE 1020 +#define wxID_DEL0 1021 +#define wxID_DEL1 1022 +#define wxID_DEL2 1023 +#define wxID_DEL3 1024 +#define wxID_DEL4 1025 +#define wxID_DEL5 1026 +#define wxID_DEL6 1027 +#define wxID_DEL7 1028 +#define wxID_DEL8 1029 +#define wxID_DEL9 1030 +#define wxID_DEL10 1031 +#define wxID_DEL11 1032 +#define wxID_DEL12 1033 +#define wxID_DEL13 1034 +#define wxID_DEL14 1035 +#define wxID_DEL15 1036 +#define wxID_DEL16 1037 +#define wxID_DEL17 1038 +#define wxID_DEL18 1039 +#define wxID_DEL19 1040 +#define wxID_BUTTONPREVIEW 1041 +#define wxID_BUTTONSAMPLE 1042 +#define wxID_CANCEL2 1043 +#define wxID_BUTTONBACK 1044 +#define wxID_BUTTONNEXT 1045 +#define wxID_SUBMIT 1046 +#define wxID_OPENNEWTABLE 1047 +#define wxID_DEALHAND 1048 +#define wxID_FOLD 1049 +#define wxID_CALL 1050 +#define wxID_RAISE 1051 +#define wxID_LEAVETABLE 1052 +#define wxID_DITCHPLAYER 1053 +#define wxID_TEXTCTRL 1054 /////////////////////////////////////////////////////////////////////////////// /// Class CMainFrameBase @@ -211,6 +213,12 @@ class COptionsDialogBase : public wxDialog wxCheckBox* m_checkBoxMinimizeToTray; wxCheckBox* m_checkBoxMinimizeOnClose; + wxCheckBox* m_checkBoxUseProxy; + + wxStaticText* m_staticTextProxyIP; + wxTextCtrl* m_textCtrlProxyIP; + wxStaticText* m_staticTextProxyPort; + wxTextCtrl* m_textCtrlProxyPort; wxPanel* m_panelTest2; wxStaticText* m_staticText321; @@ -226,6 +234,8 @@ class COptionsDialogBase : public wxDialog virtual void OnKillFocusTransactionFee( wxFocusEvent& event ){ event.Skip(); } virtual void OnCheckBoxLimitProcessors( wxCommandEvent& event ){ event.Skip(); } virtual void OnCheckBoxMinimizeToTray( wxCommandEvent& event ){ event.Skip(); } + virtual void OnCheckBoxUseProxy( wxCommandEvent& event ){ event.Skip(); } + virtual void OnKillFocusProxy( wxFocusEvent& event ){ event.Skip(); } virtual void OnButtonOK( wxCommandEvent& event ){ event.Skip(); } virtual void OnButtonCancel( wxCommandEvent& event ){ event.Skip(); } virtual void OnButtonApply( wxCommandEvent& event ){ event.Skip(); } diff --git a/uiproject.fbp b/uiproject.fbp index af5876b4aba0f..313e5aa6cccec 100644 --- a/uiproject.fbp +++ b/uiproject.fbp @@ -1912,7 +1912,7 @@ wxEXPAND 0 - 14 + 16 protected 0 @@ -2148,7 +2148,7 @@ 5 - wxTOP|wxBOTTOM + wxALIGN_CENTER_VERTICAL 0 @@ -2379,7 +2379,7 @@ 5 - wxALL + wxALL|wxALIGN_CENTER_VERTICAL 0 @@ -2390,7 +2390,7 @@ 0 wxID_ANY - M&inimize to system tray on close + Mi&nimize to system tray on close m_checkBoxMinimizeOnClose @@ -2431,6 +2431,302 @@ + + 5 + wxEXPAND + 1 + + + bSizer102 + wxHORIZONTAL + none + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + 0 + + 1 + + + 0 + wxID_ANY + &Connect through socks4 proxy: + + + m_checkBoxUseProxy + protected + + + + + + + + + + OnCheckBoxUseProxy + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxEXPAND + 1 + + + bSizer103 + wxHORIZONTAL + none + + 5 + + 0 + + 0 + protected + 18 + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + Proxy &IP: + + + m_staticTextProxyIP + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_PROXYIP + + 15 + + m_textCtrlProxyIP + protected + + 140,-1 + + + + + + + + + + + + + OnKillFocusProxy + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALL|wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_ANY + &Port: + + + m_staticTextProxyPort + protected + + + + + + + + + -1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_CENTER_VERTICAL + 0 + + + + 1 + + + 0 + wxID_PROXYPORT + + 5 + + m_textCtrlProxyPort + protected + + 55,-1 + + + + + + + + + + + + + OnKillFocusProxy + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2490,7 +2786,7 @@ wxEXPAND 0 - 14 + 16 protected 0 @@ -2558,7 +2854,7 @@ 0 wxID_ANY - MyLabel + Let's not start multiple pages until the first page is filled up m_staticText69 diff --git a/util.cpp b/util.cpp index 8271474eeeb5b..6ba84a516d500 100644 --- a/util.cpp +++ b/util.cpp @@ -5,8 +5,9 @@ #include "headers.h" - bool fDebug = false; +bool fPrintToDebugger = false; +bool fPrintToConsole = false; @@ -37,8 +38,8 @@ class CInit // Seed random number generator with screen scrape and other hardware sources RAND_screen(); - // Seed random number generator with perfmon data - RandAddSeed(true); + // Seed random number generator with performance counter + RandAddSeed(); } ~CInit() { @@ -54,40 +55,43 @@ instance_of_cinit; -void RandAddSeed(bool fPerfmon) +void RandAddSeed() { // Seed with CPU performance counter LARGE_INTEGER PerformanceCount; QueryPerformanceCounter(&PerformanceCount); RAND_add(&PerformanceCount, sizeof(PerformanceCount), 1.5); memset(&PerformanceCount, 0, sizeof(PerformanceCount)); +} +void RandAddSeedPerfmon() +{ + // This can take up to 2 seconds, so only do it every 10 minutes static int64 nLastPerfmon; - if (fPerfmon || GetTime() > nLastPerfmon + 5 * 60) + if (GetTime() < nLastPerfmon + 10 * 60) + return; + nLastPerfmon = GetTime(); + + // Seed with the entire set of perfmon data + unsigned char pdata[250000]; + memset(pdata, 0, sizeof(pdata)); + unsigned long nSize = sizeof(pdata); + long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize); + RegCloseKey(HKEY_PERFORMANCE_DATA); + if (ret == ERROR_SUCCESS) { - nLastPerfmon = GetTime(); - - // Seed with the entire set of perfmon data - unsigned char pdata[250000]; - memset(pdata, 0, sizeof(pdata)); - unsigned long nSize = sizeof(pdata); - long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize); - RegCloseKey(HKEY_PERFORMANCE_DATA); - if (ret == ERROR_SUCCESS) - { - uint256 hash; - SHA256(pdata, nSize, (unsigned char*)&hash); - RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash))); - hash = 0; - memset(pdata, 0, nSize); - - time_t nTime; - time(&nTime); - struct tm* ptmTime = gmtime(&nTime); - char pszTime[200]; - strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime); - printf("%s RandAddSeed() %d bytes\n", pszTime, nSize); - } + uint256 hash; + SHA256(pdata, nSize, (unsigned char*)&hash); + RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash))); + hash = 0; + memset(pdata, 0, nSize); + + time_t nTime; + time(&nTime); + struct tm* ptmTime = gmtime(&nTime); + char pszTime[200]; + strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime); + printf("%s RandAddSeed() %d bytes\n", pszTime, nSize); } } @@ -99,7 +103,6 @@ void RandAddSeed(bool fPerfmon) - // Safer snprintf // - prints up to limit-1 characters // - output string is always null terminated even if limit reached @@ -172,27 +175,6 @@ bool error(const char* format, ...) } -void PrintException(std::exception* pex, const char* pszThread) -{ - char pszModule[MAX_PATH]; - pszModule[0] = '\0'; - GetModuleFileName(NULL, pszModule, sizeof(pszModule)); - _strlwr(pszModule); - char pszMessage[1000]; - if (pex) - snprintf(pszMessage, sizeof(pszMessage), - "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); - else - snprintf(pszMessage, sizeof(pszMessage), - "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); - printf("\n\n************************\n%s", pszMessage); - if (wxTheApp) - wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR); - throw; - //DebugBreak(); -} - - void ParseString(const string& str, char c, vector& v) { unsigned int i1 = 0; @@ -268,6 +250,92 @@ bool ParseMoney(const char* pszIn, int64& nRet) } +vector ParseHex(const char* psz) +{ + vector vch; + while (isspace(*psz)) + psz++; + vch.reserve((strlen(psz)+1)/3); + + 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, }; + + while (*psz) + { + char c = phexdigit[(unsigned char)*psz++]; + if (c == -1) + break; + unsigned char n = (c << 4); + if (*psz) + { + char c = phexdigit[(unsigned char)*psz++]; + if (c == -1) + break; + n |= c; + vch.push_back(n); + } + while (isspace(*psz)) + psz++; + } + + return vch; +} + +vector ParseHex(const std::string& str) +{ + return ParseHex(str.c_str()); +} + + + + + + +void FormatException(char* pszMessage, std::exception* pex, const char* pszThread) +{ + char pszModule[MAX_PATH]; + pszModule[0] = '\0'; + GetModuleFileName(NULL, pszModule, sizeof(pszModule)); + 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[1000]; + FormatException(pszMessage, pex, pszThread); + printf("\n%s", pszMessage); +} + +void PrintException(std::exception* pex, const char* pszThread) +{ + char pszMessage[1000]; + FormatException(pszMessage, pex, pszThread); + printf("\n\n************************\n%s\n", pszMessage); + if (wxTheApp) + wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR); + throw; + //DebugBreak(); +} @@ -363,7 +431,7 @@ void AddTimeData(unsigned int ip, int64 nTime) if (vTimeOffsets.empty()) vTimeOffsets.push_back(0); vTimeOffsets.push_back(nOffsetSample); - printf("Added time data, samples %d, ip %08x, offset %+I64d (%+I64d minutes)\n", vTimeOffsets.size(), ip, vTimeOffsets.back(), vTimeOffsets.back()/60); + printf("Added time data, samples %d, offset %+I64d (%+I64d minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60); if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) { sort(vTimeOffsets.begin(), vTimeOffsets.end()); diff --git a/util.h b/util.h index 97617ab4909ac..61f774a8d9d27 100644 --- a/util.h +++ b/util.h @@ -67,15 +67,22 @@ inline T& REF(const T& val) extern bool fDebug; +extern bool fPrintToDebugger; +extern bool fPrintToConsole; +extern map mapArgs; -void RandAddSeed(bool fPerfmon=false); +void RandAddSeed(); +void RandAddSeedPerfmon(); int my_snprintf(char* buffer, size_t limit, const char* format, ...); string strprintf(const char* format, ...); bool error(const char* format, ...); void PrintException(std::exception* pex, const char* pszThread); +void LogException(std::exception* pex, const char* pszThread); void ParseString(const string& str, char c, vector& v); string FormatMoney(int64 n, bool fPlus=false); bool ParseMoney(const char* pszIn, int64& nRet); +vector ParseHex(const char* psz); +vector ParseHex(const std::string& str); bool FileExists(const char* psz); int GetFilesize(FILE* file); uint64 GetRand(uint64 nMax); @@ -94,6 +101,7 @@ void AddTimeData(unsigned int ip, int64 nTime); + // Wrapper to automatically initialize critical section // Could use wxCriticalSection for portability, but it doesn't support TryEnterCriticalSection class CCriticalSection @@ -156,6 +164,85 @@ class CTryCriticalBlock +inline int OutputDebugStringF(const char* pszFormat, ...) +{ + int ret = 0; +#ifdef __WXDEBUG__ + if (!fPrintToConsole) + { + // print to debug.log + FILE* fileout = fopen("debug.log", "a"); + if (fileout) + { + va_list arg_ptr; + va_start(arg_ptr, pszFormat); + ret = vfprintf(fileout, pszFormat, arg_ptr); + va_end(arg_ptr); + fclose(fileout); + } + } + + if (fPrintToDebugger) + { + // accumulate a line at a time + static CCriticalSection cs_OutputDebugStringF; + 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'; + OutputDebugString(p1); + *p2 = c; + p1 = p2; + } + if (p1 != pszBuffer) + memmove(pszBuffer, p1, pend - p1 + 1); + pend -= (p1 - pszBuffer); + } + } +#endif + + if (fPrintToConsole) + { + // print to console + va_list arg_ptr; + va_start(arg_ptr, pszFormat); + ret = vprintf(pszFormat, arg_ptr); + va_end(arg_ptr); + } + return ret; +} + + + + + + + + + + inline string i64tostr(int64 n) { return strprintf("%"PRId64, n); @@ -205,6 +292,11 @@ string HexStr(const T itbegin, const T itend, bool fSpaces=true) return str; } +inline string HexStr(vector vch, bool fSpaces=true) +{ + return HexStr(vch.begin(), vch.end(), fSpaces); +} + template string HexNumStr(const T itbegin, const T itend, bool f0x=true) { @@ -222,75 +314,9 @@ void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSp printf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str()); } - - - - - - - -inline int OutputDebugStringF(const char* pszFormat, ...) +inline void PrintHex(vector vch, const char* pszFormat="%s", bool fSpaces=true) { -#ifdef __WXDEBUG__ - // log file - FILE* fileout = fopen("debug.log", "a"); - if (fileout) - { - va_list arg_ptr; - va_start(arg_ptr, pszFormat); - vfprintf(fileout, pszFormat, arg_ptr); - va_end(arg_ptr); - fclose(fileout); - } - - // accumulate a line at a time - static CCriticalSection cs_OutputDebugStringF; - 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'; - OutputDebugString(p1); - *p2 = c; - p1 = p2; - } - if (p1 != pszBuffer) - memmove(pszBuffer, p1, pend - p1 + 1); - pend -= (p1 - pszBuffer); - return ret; - } -#endif - - if (!wxTheApp) - { - // print to console - va_list arg_ptr; - va_start(arg_ptr, pszFormat); - vprintf(pszFormat, arg_ptr); - va_end(arg_ptr); - } - return 0; + printf(pszFormat, HexStr(vch, fSpaces).c_str()); }