cryptographic software written by Eric Young (eay@cryptsoft.com).\r
\r
\r
- WINDOWS BUILD NOTES\r
+WINDOWS BUILD NOTES\r
\r
\r
Compilers Supported\r
\r
Dependencies\r
------------\r
+Install the dev files for the shared libraries:\r
apt-get install build-essential\r
apt-get install libgtk2.0-dev\r
apt-get install libssl-dev\r
{\r
vchDefaultKeyRet.clear();\r
\r
+ // Modify defaults\r
+#ifndef __WXMSW__\r
+ // Reports that tray icon can disappear on gnome, leaving no way to access the program\r
+ fMinimizeToTray = false;\r
+ fMinimizeOnClose = false;\r
+#endif\r
+\r
//// todo: shouldn't we catch exceptions and try to recover and continue?\r
CRITICAL_BLOCK(cs_mapKeys)\r
CRITICAL_BLOCK(cs_mapWallet)\r
CWalletDB().WriteDefaultKey(keyUser.GetPubKey());\r
}\r
\r
- _beginthread(ThreadFlushWalletDB, 0, NULL);\r
+ CreateThread(ThreadFlushWalletDB, NULL);\r
return true;\r
}\r
\r
#include <net/if.h>\r
#include <ifaddrs.h>\r
#include <boost/filesystem.hpp>\r
-#include <boost/thread/thread.hpp>\r
#include <boost/algorithm/string.hpp>\r
#endif\r
\r
const char* pszEnd = psz + strlen(psz);\r
while (psz < pszEnd)\r
{\r
- int ret = send(hSocket, psz, pszEnd - psz, 0);\r
+ int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);\r
if (ret < 0)\r
return false;\r
psz += ret;\r
\r
void ThreadIRCSeed(void* parg)\r
{\r
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);\r
+ SetThreadPriority(THREAD_PRIORITY_NORMAL);\r
int nErrorWait = 10;\r
int nRetryWait = 10;\r
\r
CAddress addr;\r
if (DecodeAddress(pszName, addr))\r
{\r
+ addr.nTime = GetAdjustedTime() - 51 * 60;\r
CAddrDB addrdb;\r
if (AddAddress(addrdb, addr))\r
printf("IRC got new address\n");\r
CCriticalSection cs_mapKeys;\r
CKey keyUser;\r
\r
+map<uint256, int> mapRequestCount;\r
+CCriticalSection cs_mapRequestCount;\r
+\r
// Settings\r
int fGenerateBitcoins = false;\r
int64 nTransactionFee = 0;\r
return nTimeReceived;\r
}\r
\r
+int CWalletTx::GetRequestCount() const\r
+{\r
+ // Returns -1 if it wasn't being tracked\r
+ int nRequests = -1;\r
+ CRITICAL_BLOCK(cs_mapRequestCount)\r
+ {\r
+ if (IsCoinBase())\r
+ {\r
+ // Generated block\r
+ if (hashBlock != 0)\r
+ {\r
+ map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);\r
+ if (mi != mapRequestCount.end())\r
+ nRequests = (*mi).second;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ // Did anyone request this transaction?\r
+ map<uint256, int>::iterator mi = mapRequestCount.find(GetHash());\r
+ if (mi != mapRequestCount.end())\r
+ {\r
+ nRequests = (*mi).second;\r
\r
+ // How about the block it's in?\r
+ if (nRequests == 0 && hashBlock != 0)\r
+ {\r
+ map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);\r
+ if (mi != mapRequestCount.end())\r
+ nRequests = (*mi).second;\r
+ else\r
+ nRequests = 1; // If it's in someone else's block it must have got out\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return nRequests;\r
+}\r
\r
\r
\r
CTxIndex txindex;\r
if (!CTxDB("r").ReadTxIndex(GetHash(), txindex))\r
return 0;\r
- if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, true))\r
+ if (!blockTmp.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos))\r
return 0;\r
pblock = &blockTmp;\r
}\r
foreach(CBlockIndex* pindex, vDisconnect)\r
{\r
CBlock block;\r
- if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos, true))\r
+ if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))\r
return error("Reorganize() : ReadFromDisk for disconnect failed");\r
if (!block.DisconnectBlock(txdb, pindex))\r
return error("Reorganize() : DisconnectBlock failed");\r
{\r
CBlockIndex* pindex = vConnect[i];\r
CBlock block;\r
- if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos, true))\r
+ if (!block.ReadFromDisk(pindex->nFile, pindex->nBlockPos))\r
return error("Reorganize() : ReadFromDisk for connect failed");\r
if (!block.ConnectBlock(txdb, pindex))\r
{\r
{\r
fShutdown = true;\r
ThreadSafeMessageBox("Warning: Your disk space is low ", "Bitcoin", wxOK | wxICON_EXCLAMATION);\r
- _beginthread(Shutdown, 0, NULL);\r
+ CreateThread(Shutdown, NULL);\r
return false;\r
}\r
return true;\r
\r
// print item\r
CBlock block;\r
- block.ReadFromDisk(pindex, true);\r
+ block.ReadFromDisk(pindex);\r
printf("%d (%u,%u) %s %s tx %d",\r
pindex->nHeight,\r
pindex->nFile,\r
CDataStream& vRecv = pfrom->vRecv;\r
if (vRecv.empty())\r
return true;\r
- //printf("ProcessMessages(%d bytes)\n", vRecv.size());\r
+ //if (fDebug)\r
+ // printf("ProcessMessages(%d bytes)\n", vRecv.size());\r
\r
//\r
// Message format\r
{\r
// Rewind and wait for rest of message\r
///// need a mechanism to give up waiting for overlong message size error\r
- //printf("message-break\n");\r
+ //if (fDebug)\r
+ // printf("message-break\n");\r
vRecv.insert(vRecv.begin(), BEGIN(hdr), END(hdr));\r
Sleep(100);\r
break;\r
{\r
static map<unsigned int, vector<unsigned char> > mapReuseKey;\r
RandAddSeedPerfmon();\r
+ if (fDebug)\r
+ printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
printf("received: %s (%d bytes)\n", strCommand.c_str(), vRecv.size());\r
if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)\r
{\r
CAddress addrMe;\r
CAddress addrFrom;\r
uint64 nNonce = 1;\r
+ string strSubVer;\r
vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;\r
if (pfrom->nVersion >= 106 && !vRecv.empty())\r
vRecv >> addrFrom >> nNonce;\r
+ if (pfrom->nVersion >= 106 && !vRecv.empty())\r
+ vRecv >> strSubVer;\r
if (pfrom->nVersion == 0)\r
return false;\r
\r
// Disconnect if we connected to ourself\r
- if (nNonce == nLocalHostNonce)\r
+ if (nNonce == nLocalHostNonce && nNonce > 1)\r
{\r
pfrom->fDisconnect = true;\r
- pfrom->vRecv.clear();\r
- pfrom->vSend.clear();\r
return true;\r
}\r
\r
\r
pfrom->fSuccessfullyConnected = true;\r
\r
- // Update the last seen time\r
- if (pfrom->fNetworkNode)\r
- AddressCurrentlyConnected(pfrom->addr);\r
-\r
printf("version message: version %d\n", pfrom->nVersion);\r
}\r
\r
vector<CInv> vInv;\r
vRecv >> vInv;\r
\r
- // Update the last seen time for this node's address\r
- if (pfrom->fNetworkNode)\r
- AddressCurrentlyConnected(pfrom->addr);\r
-\r
CTxDB txdb("r");\r
foreach(const CInv& inv, vInv)\r
{\r
pfrom->AskFor(inv);\r
else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash))\r
pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), GetOrphanRoot(mapOrphanBlocks[inv.hash]));\r
+\r
+ // Track requests for our stuff\r
+ CRITICAL_BLOCK(cs_mapRequestCount)\r
+ {\r
+ map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);\r
+ if (mi != mapRequestCount.end())\r
+ (*mi).second++;\r
+ }\r
}\r
}\r
\r
pfrom->PushMessage(inv.GetCommand(), (*mi).second);\r
}\r
}\r
+\r
+ // Track requests for our stuff\r
+ CRITICAL_BLOCK(cs_mapRequestCount)\r
+ {\r
+ map<uint256, int>::iterator mi = mapRequestCount.find(inv.hash);\r
+ if (mi != mapRequestCount.end())\r
+ (*mi).second++;\r
+ }\r
}\r
}\r
\r
}\r
\r
\r
+ else if (strCommand == "ping")\r
+ {\r
+ }\r
+\r
+\r
else\r
{\r
// Ignore unknown commands for extensibility\r
}\r
\r
+\r
+ // Update the last seen time for this node's address\r
+ if (pfrom->fNetworkNode)\r
+ if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")\r
+ AddressCurrentlyConnected(pfrom->addr);\r
+\r
+\r
return true;\r
}\r
\r
}\r
}\r
\r
+ // Keep-alive ping\r
+ if (pto->nLastSend && GetTime() - pto->nLastSend > 12 * 60 && pto->vSend.empty())\r
+ pto->PushMessage("ping");\r
+\r
\r
//\r
// Message: addr\r
{\r
// returns true if wasn't already contained in the set\r
if (pto->setAddrKnown.insert(addr).second)\r
+ {\r
vAddrToSend.push_back(addr);\r
+ if (vAddrToSend.size() >= 1000)\r
+ {\r
+ pto->PushMessage("addr", vAddrToSend);\r
+ vAddrToSend.clear();\r
+ }\r
+ }\r
}\r
pto->vAddrToSend.clear();\r
if (!vAddrToSend.empty())\r
{\r
// returns true if wasn't already contained in the set\r
if (pto->setInventoryKnown.insert(inv).second)\r
+ {\r
vInventoryToSend.push_back(inv);\r
+ if (vInventoryToSend.size() >= 1000)\r
+ {\r
+ pto->PushMessage("inv", vInventoryToSend);\r
+ vInventoryToSend.clear();\r
+ }\r
+ }\r
}\r
pto->vInventoryToSend.clear();\r
pto->setInventoryKnown2.clear();\r
{\r
printf("sending getdata: %s\n", inv.ToString().c_str());\r
vAskFor.push_back(inv);\r
+ if (vAskFor.size() >= 1000)\r
+ {\r
+ pto->PushMessage("getdata", vAskFor);\r
+ vAskFor.clear();\r
+ }\r
}\r
pto->mapAskFor.erase(pto->mapAskFor.begin());\r
}\r
int nAddThreads = nProcessors - vnThreadsRunning[3];\r
printf("Starting %d BitcoinMiner threads\n", nAddThreads);\r
for (int i = 0; i < nAddThreads; i++)\r
- if (_beginthread(ThreadBitcoinMiner, 0, NULL) == -1)\r
- printf("Error: _beginthread(ThreadBitcoinMiner) failed\n");\r
+ if (!CreateThread(ThreadBitcoinMiner, NULL))\r
+ printf("Error: CreateThread(ThreadBitcoinMiner) failed\n");\r
}\r
}\r
\r
CBigNum bnExtraNonce = 0;\r
while (fGenerateBitcoins)\r
{\r
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);\r
+ SetThreadPriority(THREAD_PRIORITY_LOWEST);\r
Sleep(50);\r
if (fShutdown)\r
return;\r
printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());\r
pblock->print();\r
\r
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);\r
+ SetThreadPriority(THREAD_PRIORITY_NORMAL);\r
CRITICAL_BLOCK(cs_main)\r
{\r
if (pindexPrev == pindexBest)\r
return;\r
key.MakeNewKey();\r
\r
+ // Track how many getdata requests this block gets\r
+ CRITICAL_BLOCK(cs_mapRequestCount)\r
+ mapRequestCount[pblock->GetHash()] = 0;\r
+\r
// Process this block the same as if we had received it from another node\r
if (!ProcessBlock(NULL, pblock.release()))\r
printf("ERROR in BitcoinMiner, ProcessBlock, block not accepted\n");\r
}\r
}\r
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);\r
+ SetThreadPriority(THREAD_PRIORITY_LOWEST);\r
\r
Sleep(500);\r
break;\r
setCoinsRet.clear();\r
\r
// List of values less than target\r
- int64 nLowestLarger = _I64_MAX;\r
+ int64 nLowestLarger = INT64_MAX;\r
CWalletTx* pcoinLowestLarger = NULL;\r
vector<pair<int64, CWalletTx*> > vValue;\r
int64 nTotalLower = 0;\r
return error("SendMoney() : Error finalizing transaction");\r
}\r
\r
+ // Track how many getdata requests our transaction gets\r
+ CRITICAL_BLOCK(cs_mapRequestCount)\r
+ mapRequestCount[wtxNew.GetHash()] = 0;\r
+\r
printf("SendMoney: %s\n", wtxNew.GetHash().ToString().substr(0,6).c_str());\r
\r
// Broadcast\r
extern uint256 hashBestChain;\r
extern CBlockIndex* pindexBest;\r
extern unsigned int nTransactionsUpdated;\r
+extern map<uint256, int> mapRequestCount;\r
+extern CCriticalSection cs_mapRequestCount;\r
\r
// Settings\r
extern int fGenerateBitcoins;\r
nGetCreditCached = 0;\r
}\r
\r
+ IMPLEMENT_SERIALIZE\r
+ (\r
+ nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);\r
+ nVersion = this->nVersion;\r
+ READWRITE(hashBlock);\r
+ READWRITE(vMerkleBranch);\r
+ READWRITE(nIndex);\r
+ )\r
+\r
int64 GetCredit(bool fUseCache=false) const\r
{\r
// Must wait until coinbase is safely deep enough in the chain before valuing it\r
return nGetCreditCached;\r
}\r
\r
- IMPLEMENT_SERIALIZE\r
- (\r
- nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);\r
- nVersion = this->nVersion;\r
- READWRITE(hashBlock);\r
- READWRITE(vMerkleBranch);\r
- READWRITE(nIndex);\r
- )\r
-\r
\r
int SetMerkleBranch(const CBlock* pblock=NULL);\r
int GetDepthInMainChain() const;\r
\r
\r
int64 GetTxTime() const;\r
+ int GetRequestCount() const;\r
\r
void AddSupportingTransactions(CTxDB& txdb);\r
\r
return true;\r
}\r
\r
- bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions)\r
+ bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true)\r
{\r
SetNull();\r
\r
int64 GetBlockValue(int64 nFees) const;\r
bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);\r
bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);\r
- bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions);\r
+ bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions=true);\r
bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);\r
bool CheckBlock() const;\r
bool AcceptBlock();\r
\r
\r
\r
-\r
//\r
// Global state variables\r
//\r
bool fShutdown = false;\r
array<int, 10> vnThreadsRunning;\r
SOCKET hListenSocket = INVALID_SOCKET;\r
+int64 nThreadSocketHandlerHeartbeat = INT64_MAX;\r
\r
vector<CNode*> vNodes;\r
CCriticalSection cs_vNodes;\r
\r
if (fProxy)\r
{\r
- printf("Proxy connecting %s\n", addrConnect.ToStringLog().c_str());\r
+ printf("proxy connecting %s\n", addrConnect.ToStringLog().c_str());\r
char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user";\r
memcpy(pszSocks4IP + 2, &addrConnect.port, 2);\r
memcpy(pszSocks4IP + 4, &addrConnect.ip, 4);\r
if (pchRet[1] != 0x5a)\r
{\r
closesocket(hSocket);\r
- return error("Proxy returned error %d", pchRet[1]);\r
+ if (pchRet[1] != 0x5b)\r
+ printf("ERROR: Proxy returned error %d\n", pchRet[1]);\r
+ return false;\r
}\r
- printf("Proxy connection established %s\n", addrConnect.ToStringLog().c_str());\r
+ printf("proxy connected %s\n", addrConnect.ToStringLog().c_str());\r
}\r
\r
hSocketRet = hSocket;\r
if (it == mapAddresses.end())\r
{\r
// New address\r
+ printf("AddAddress(%s)\n", addr.ToStringLog().c_str());\r
mapAddresses.insert(make_pair(addr.GetKey(), addr));\r
addrdb.WriteAddress(addr);\r
return true;\r
if (it != mapAddresses.end())\r
{\r
CAddress& addrFound = (*it).second;\r
- int64 nUpdateInterval = 60 * 60;\r
+ int64 nUpdateInterval = 20 * 60;\r
if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)\r
{\r
// Periodically update most recently seen time\r
}\r
\r
/// debug print\r
- printf("trying connection %s\n", addrConnect.ToStringLog().c_str());\r
+ printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n",\r
+ addrConnect.ToStringLog().c_str(),\r
+ (double)(addrConnect.nTime - GetAdjustedTime())/3600.0,\r
+ (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0);\r
+\r
+ CRITICAL_BLOCK(cs_mapAddresses)\r
+ mapAddresses[addrConnect.GetKey()].nLastTry = GetAdjustedTime();\r
\r
// Connect\r
SOCKET hSocket;\r
\r
// Set to nonblocking\r
#ifdef __WXMSW__\r
- u_long nOne = 1;\r
+ u_long nOne = 1;\r
if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)\r
printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());\r
#else\r
CRITICAL_BLOCK(cs_vNodes)\r
vNodes.push_back(pnode);\r
\r
- CRITICAL_BLOCK(cs_mapAddresses)\r
- mapAddresses[addrConnect.GetKey()].nLastFailed = 0;\r
+ pnode->nTimeConnected = GetTime();\r
return pnode;\r
}\r
else\r
{\r
- CRITICAL_BLOCK(cs_mapAddresses)\r
- mapAddresses[addrConnect.GetKey()].nLastFailed = GetAdjustedTime();\r
return NULL;\r
}\r
}\r
\r
void CNode::DoDisconnect()\r
{\r
+ if (fDebug)\r
+ printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
printf("disconnecting node %s\n", addr.ToStringLog().c_str());\r
\r
closesocket(hSocket);\r
\r
- // If outbound and never got version message, mark address as failed\r
- if (!fInbound && !fSuccessfullyConnected)\r
- CRITICAL_BLOCK(cs_mapAddresses)\r
- mapAddresses[addr.GetKey()].nLastFailed = GetAdjustedTime();\r
-\r
// All of a nodes broadcasts and subscriptions are automatically torn down\r
// when it goes down, so a node has to stay up to keep its broadcast going.\r
\r
PrintException(&e, "ThreadSocketHandler()");\r
} catch (...) {\r
vnThreadsRunning[0]--;\r
- PrintException(NULL, "ThreadSocketHandler()");\r
+ throw; // support pthread_cancel()\r
}\r
\r
printf("ThreadSocketHandler exiting\n");\r
vector<CNode*> vNodesCopy = vNodes;\r
foreach(CNode* pnode, vNodesCopy)\r
{\r
- if (pnode->ReadyToDisconnect() && pnode->vRecv.empty() && pnode->vSend.empty())\r
+ if (pnode->fDisconnect ||\r
+ (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))\r
{\r
// remove from vNodes\r
vNodes.erase(remove(vNodes.begin(), vNodes.end(), pnode), vNodes.end());\r
+\r
+ // close socket\r
pnode->DoDisconnect();\r
\r
// hold in disconnected pool until all refs are released\r
pnode->nReleaseTime = max(pnode->nReleaseTime, GetTime() + 5 * 60);\r
- if (pnode->fNetworkNode)\r
+ if (pnode->fNetworkNode || pnode->fInbound)\r
pnode->Release();\r
vNodesDisconnected.push_back(pnode);\r
}\r
\r
fd_set fdsetRecv;\r
fd_set fdsetSend;\r
+ fd_set fdsetError;\r
FD_ZERO(&fdsetRecv);\r
FD_ZERO(&fdsetSend);\r
+ FD_ZERO(&fdsetError);\r
SOCKET hSocketMax = 0;\r
FD_SET(hListenSocket, &fdsetRecv);\r
hSocketMax = max(hSocketMax, hListenSocket);\r
foreach(CNode* pnode, vNodes)\r
{\r
FD_SET(pnode->hSocket, &fdsetRecv);\r
+ FD_SET(pnode->hSocket, &fdsetError);\r
hSocketMax = max(hSocketMax, pnode->hSocket);\r
TRY_CRITICAL_BLOCK(pnode->cs_vSend)\r
if (!pnode->vSend.empty())\r
}\r
\r
vnThreadsRunning[0]--;\r
- int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, NULL, &timeout);\r
+ int nSelect = select(hSocketMax + 1, &fdsetRecv, &fdsetSend, &fdsetError, &timeout);\r
vnThreadsRunning[0]++;\r
if (fShutdown)\r
return;\r
if (nSelect == SOCKET_ERROR)\r
{\r
int nErr = WSAGetLastError();\r
- printf("select failed: %d\n", nErr);\r
+ printf("socket select error %d\n", nErr);\r
for (int i = 0; i <= hSocketMax; i++)\r
- {\r
FD_SET(i, &fdsetRecv);\r
- FD_SET(i, &fdsetSend);\r
- }\r
+ FD_ZERO(&fdsetSend);\r
+ FD_ZERO(&fdsetError);\r
Sleep(timeout.tv_usec/1000);\r
}\r
\r
- //// debug print\r
- //foreach(CNode* pnode, vNodes)\r
- //{\r
- // printf("vRecv = %-5d ", pnode->vRecv.size());\r
- // printf("vSend = %-5d ", pnode->vSend.size());\r
- //}\r
- //printf("\n");\r
-\r
\r
//\r
// Accept new connections\r
if (hSocket == INVALID_SOCKET)\r
{\r
if (WSAGetLastError() != WSAEWOULDBLOCK)\r
- printf("ERROR ThreadSocketHandler accept failed: %d\n", WSAGetLastError());\r
+ printf("socket error accept failed: %d\n", WSAGetLastError());\r
}\r
else\r
{\r
//\r
// Receive\r
//\r
- if (FD_ISSET(hSocket, &fdsetRecv))\r
+ if (FD_ISSET(hSocket, &fdsetRecv) || FD_ISSET(hSocket, &fdsetError))\r
{\r
TRY_CRITICAL_BLOCK(pnode->cs_vRecv)\r
{\r
unsigned int nPos = vRecv.size();\r
\r
// typical socket buffer is 8K-64K\r
- const unsigned int nBufSize = 0x10000;\r
- vRecv.resize(nPos + nBufSize);\r
- int nBytes = recv(hSocket, &vRecv[nPos], nBufSize, 0);\r
- vRecv.resize(nPos + max(nBytes, 0));\r
- if (nBytes == 0)\r
+ char pchBuf[0x10000];\r
+ int nBytes = recv(hSocket, pchBuf, sizeof(pchBuf), MSG_DONTWAIT);\r
+ if (nBytes > 0)\r
+ {\r
+ vRecv.resize(nPos + nBytes);\r
+ memcpy(&vRecv[nPos], pchBuf, nBytes);\r
+ pnode->nLastRecv = GetTime();\r
+ }\r
+ else if (nBytes == 0)\r
{\r
// socket closed gracefully\r
if (!pnode->fDisconnect)\r
- printf("recv: socket closed\n");\r
+ printf("socket closed\n");\r
pnode->fDisconnect = true;\r
}\r
else if (nBytes < 0)\r
{\r
- // socket error\r
+ // error\r
int nErr = WSAGetLastError();\r
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)\r
{\r
if (!pnode->fDisconnect)\r
- printf("recv failed: %d\n", nErr);\r
+ printf("socket recv error %d\n", nErr);\r
pnode->fDisconnect = true;\r
}\r
}\r
CDataStream& vSend = pnode->vSend;\r
if (!vSend.empty())\r
{\r
- int nBytes = send(hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL);\r
+ int nBytes = send(hSocket, &vSend[0], vSend.size(), MSG_NOSIGNAL | MSG_DONTWAIT);\r
if (nBytes > 0)\r
{\r
vSend.erase(vSend.begin(), vSend.begin() + nBytes);\r
+ pnode->nLastSend = GetTime();\r
}\r
- else if (nBytes == 0)\r
- {\r
- if (pnode->ReadyToDisconnect())\r
- pnode->vSend.clear();\r
- }\r
- else\r
+ else if (nBytes < 0)\r
{\r
- printf("send error %d\n", nBytes);\r
- if (pnode->ReadyToDisconnect())\r
- pnode->vSend.clear();\r
+ // error\r
+ int nErr = WSAGetLastError();\r
+ if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)\r
+ {\r
+ printf("socket send error %d\n", nErr);\r
+ pnode->fDisconnect = true;\r
+ }\r
}\r
}\r
}\r
}\r
+\r
+ //\r
+ // Inactivity checking\r
+ //\r
+ if (pnode->vSend.empty())\r
+ pnode->nLastSendEmpty = GetTime();\r
+ if (GetTime() - pnode->nTimeConnected > 60)\r
+ {\r
+ if (pnode->nLastRecv == 0 || pnode->nLastSend == 0)\r
+ {\r
+ printf("socket no message in first 60 seconds, %d %d\n", pnode->nLastRecv != 0, pnode->nLastSend != 0);\r
+ pnode->fDisconnect = true;\r
+ }\r
+ else if (GetTime() - pnode->nLastSend > 10 * 60 && GetTime() - pnode->nLastSendEmpty > 10 * 60)\r
+ {\r
+ printf("socket not sending\n");\r
+ pnode->fDisconnect = true;\r
+ }\r
+ else if (GetTime() - pnode->nLastRecv > (pnode->nVersion >= 107 ? 15*60 : 90*60))\r
+ {\r
+ printf("socket inactivity timeout\n");\r
+ pnode->fDisconnect = true;\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ //// debug heartbeat\r
+ static int64 nHeartbeat1;\r
+ if (GetTime() - nHeartbeat1 >= 5 * 60)\r
+ {\r
+ printf("%s sendrecv\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
+ nHeartbeat1 = GetTime();\r
+ fDebug = true;\r
}\r
\r
\r
+ nThreadSocketHandlerHeartbeat = GetTime();\r
Sleep(10);\r
}\r
}\r
{\r
printf("ThreadOpenConnections started\n");\r
\r
- // Connect to one specified address\r
+ // Connect to specific addresses\r
while (mapArgs.count("-connect"))\r
{\r
- OpenNetworkConnection(CAddress(mapArgs["-connect"]));\r
- for (int i = 0; i < 10; i++)\r
+ foreach(string strAddr, mapMultiArgs["-connect"])\r
{\r
- Sleep(1000);\r
- if (fShutdown)\r
- return;\r
+ CAddress addr(strAddr, NODE_NETWORK);\r
+ if (addr.IsValid())\r
+ OpenNetworkConnection(addr);\r
+ for (int i = 0; i < 10; i++)\r
+ {\r
+ Sleep(1000);\r
+ if (fShutdown)\r
+ return;\r
+ }\r
}\r
}\r
\r
// Choose an address to connect to based on most recently seen\r
//\r
CAddress addrConnect;\r
- int64 nBestTime = 0;\r
- int64 nDelay = ((60 * 60) << vNodes.size());\r
- if (vNodes.size() >= 3)\r
- nDelay *= 4;\r
- if (nGotIRCAddresses > 0)\r
- nDelay *= 100;\r
+ int64 nBest = INT64_MIN;\r
\r
// Do this here so we don't have to critsect vNodes inside mapAddresses critsect\r
set<unsigned int> setConnected;\r
const CAddress& addr = item.second;\r
if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip))\r
continue;\r
+ int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;\r
+ int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;\r
\r
// Randomize the order in a deterministic way, putting the standard port first\r
- int64 nRandomizer = (uint64)(addr.nLastFailed * 9567851 + addr.ip * 7789) % (1 * 60 * 60);\r
+ int64 nRandomizer = (uint64)(addr.nLastTry * 9567851 + addr.ip * 7789) % (30 * 60);\r
if (addr.port != DEFAULT_PORT)\r
- nRandomizer += 1 * 60 * 60;\r
+ nRandomizer += 30 * 60;\r
+\r
+ // Last seen Base retry frequency\r
+ // <1 hour 10 min\r
+ // 1 hour 1 hour\r
+ // 4 hours 2 hours\r
+ // 24 hours 5 hours\r
+ // 48 hours 7 hours\r
+ // 7 days 13 hours\r
+ // 30 days 27 hours\r
+ // 90 days 46 hours\r
+ // 365 days 93 hours\r
+ int64 nDelay = 3600.0 * sqrt(fabs(nSinceLastSeen) / 3600.0) + nRandomizer;\r
+\r
+ // Fast reconnect for one hour after last seen\r
+ if (nSinceLastSeen < 60 * 60)\r
+ nDelay = 10 * 60;\r
\r
// Limit retry frequency\r
- if (GetAdjustedTime() < addr.nLastFailed + nDelay + nRandomizer)\r
+ if (nSinceLastTry < nDelay)\r
continue;\r
\r
- // Try again only after all addresses had a first attempt\r
- int64 nTime = addr.nTime - nRandomizer;\r
- if (addr.nLastFailed > addr.nTime)\r
- nTime -= 365 * 24 * 60 * 60;\r
+ // If we have IRC, we'll be notified when they first come online,\r
+ // and again every 24 hours by the refresh broadcast.\r
+ if (nGotIRCAddresses > 0 && vNodes.size() >= 2 && nSinceLastSeen > 24 * 60 * 60)\r
+ continue;\r
\r
- if (nTime > nBestTime)\r
+ // Only try the old stuff if we don't have enough connections\r
+ if (vNodes.size() >= 2 && nSinceLastSeen > 7 * 24 * 60 * 60)\r
+ continue;\r
+ if (vNodes.size() >= 4 && nSinceLastSeen > 24 * 60 * 60)\r
+ continue;\r
+\r
+ // If multiple addresses are ready, prioritize by time since\r
+ // last seen and time since last tried.\r
+ int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;\r
+ if (nScore > nBest)\r
{\r
- nBestTime = nTime;\r
+ nBest = nScore;\r
addrConnect = addr;\r
}\r
}\r
void ThreadMessageHandler2(void* parg)\r
{\r
printf("ThreadMessageHandler started\n");\r
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);\r
+ SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);\r
loop\r
{\r
// Poll the connected nodes for messages\r
return true;\r
}\r
\r
-bool StartNode(string& strError)\r
+void StartNode(void* parg)\r
{\r
- strError = "";\r
if (pnodeLocalHost == NULL)\r
pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices));\r
\r
#ifdef __WXMSW__\r
// Get local host ip\r
- char pszHostName[255];\r
- if (gethostname(pszHostName, sizeof(pszHostName)) == SOCKET_ERROR)\r
+ char pszHostName[1000] = "";\r
+ if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)\r
{\r
- strError = strprintf("Error: Unable to get IP address of this computer (gethostname returned error %d)", WSAGetLastError());\r
- printf("%s\n", strError.c_str());\r
- return false;\r
- }\r
- struct hostent* phostent = gethostbyname(pszHostName);\r
- if (!phostent)\r
- {\r
- strError = strprintf("Error: Unable to get IP address of this computer (gethostbyname returned error %d)", WSAGetLastError());\r
- printf("%s\n", strError.c_str());\r
- return false;\r
- }\r
-\r
- // Take the first IP that isn't loopback 127.x.x.x\r
- for (int i = 0; phostent->h_addr_list[i] != NULL; i++)\r
- printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str());\r
- for (int i = 0; phostent->h_addr_list[i] != NULL; i++)\r
- {\r
- CAddress addr(*(unsigned int*)phostent->h_addr_list[i], DEFAULT_PORT, nLocalServices);\r
- if (addr.IsValid() && addr.GetByte(3) != 127)\r
+ struct hostent* phostent = gethostbyname(pszHostName);\r
+ if (phostent)\r
{\r
- addrLocalHost = addr;\r
- break;\r
+ // Take the first IP that isn't loopback 127.x.x.x\r
+ for (int i = 0; phostent->h_addr_list[i] != NULL; i++)\r
+ printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str());\r
+ for (int i = 0; phostent->h_addr_list[i] != NULL; i++)\r
+ {\r
+ CAddress addr(*(unsigned int*)phostent->h_addr_list[i], DEFAULT_PORT, nLocalServices);\r
+ if (addr.IsValid() && addr.GetByte(3) != 127)\r
+ {\r
+ addrLocalHost = addr;\r
+ break;\r
+ }\r
+ }\r
}\r
}\r
#else\r
}\r
else\r
{\r
- if (addrIncoming.ip)\r
+ if (addrIncoming.IsValid())\r
addrLocalHost.ip = addrIncoming.ip;\r
\r
if (GetMyExternalIP(addrLocalHost.ip))\r
{\r
addrIncoming = addrLocalHost;\r
CWalletDB().WriteSetting("addrIncoming", addrIncoming);\r
+ printf("addrLocalHost = %s\n", addrLocalHost.ToString().c_str());\r
}\r
}\r
\r
- // Get addresses from IRC and advertise ours\r
- if (_beginthread(ThreadIRCSeed, 0, NULL) == -1)\r
- printf("Error: _beginthread(ThreadIRCSeed) failed\n");\r
-\r
//\r
// Start threads\r
//\r
- if (_beginthread(ThreadSocketHandler, 0, NULL) == -1)\r
- {\r
- strError = "Error: _beginthread(ThreadSocketHandler) failed";\r
- printf("%s\n", strError.c_str());\r
- return false;\r
- }\r
\r
- if (_beginthread(ThreadOpenConnections, 0, NULL) == -1)\r
- {\r
- strError = "Error: _beginthread(ThreadOpenConnections) failed";\r
- printf("%s\n", strError.c_str());\r
- return false;\r
- }\r
+ // Get addresses from IRC and advertise ours\r
+ if (!CreateThread(ThreadIRCSeed, NULL))\r
+ printf("Error: CreateThread(ThreadIRCSeed) failed\n");\r
+\r
+ // Send and receive from sockets, accept connections\r
+ pthread_t hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);\r
+\r
+ // Initiate outbound connections\r
+ if (!CreateThread(ThreadOpenConnections, NULL))\r
+ printf("Error: CreateThread(ThreadOpenConnections) failed\n");\r
+\r
+ // Process messages\r
+ if (!CreateThread(ThreadMessageHandler, NULL))\r
+ printf("Error: CreateThread(ThreadMessageHandler) failed\n");\r
\r
- if (_beginthread(ThreadMessageHandler, 0, NULL) == -1)\r
+ // Generate coins in the background\r
+ GenerateBitcoins(fGenerateBitcoins);\r
+\r
+ //\r
+ // Thread monitoring\r
+ //\r
+ loop\r
{\r
- strError = "Error: _beginthread(ThreadMessageHandler) failed";\r
- printf("%s\n", strError.c_str());\r
- return false;\r
+ Sleep(15000);\r
+ if (GetTime() - nThreadSocketHandlerHeartbeat > 4 * 60)\r
+ {\r
+ // First see if closing sockets will free it\r
+ printf("*** ThreadSocketHandler is stopped ***\n");\r
+ CRITICAL_BLOCK(cs_vNodes)\r
+ {\r
+ foreach(CNode* pnode, vNodes)\r
+ {\r
+ bool fGot = false;\r
+ TRY_CRITICAL_BLOCK(pnode->cs_vRecv)\r
+ TRY_CRITICAL_BLOCK(pnode->cs_vSend)\r
+ fGot = true;\r
+ if (!fGot)\r
+ {\r
+ printf("*** closing socket\n");\r
+ closesocket(pnode->hSocket);\r
+ pnode->fDisconnect = true;\r
+ }\r
+ }\r
+ }\r
+ Sleep(10000);\r
+ if (GetTime() - nThreadSocketHandlerHeartbeat < 60)\r
+ continue;\r
+\r
+ // Hopefully it never comes to this.\r
+ // We know it'll always be hung in the recv or send call.\r
+ // cs_vRecv or cs_vSend may be left permanently unreleased,\r
+ // but we always only use TRY_CRITICAL_SECTION on them.\r
+ printf("*** Restarting ThreadSocketHandler ***\n");\r
+ TerminateThread(hThreadSocketHandler, 0);\r
+ #ifdef __WXMSW__\r
+ CloseHandle(hThreadSocketHandler);\r
+ #endif\r
+ vnThreadsRunning[0] = 0;\r
+\r
+ // Restart\r
+ hThreadSocketHandler = CreateThread(ThreadSocketHandler, NULL, true);\r
+ nThreadSocketHandlerHeartbeat = GetTime();\r
+ }\r
}\r
-\r
- return true;\r
}\r
\r
bool StopNode()\r
void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);\r
bool AnySubscribed(unsigned int nChannel);\r
bool BindListenPort(string& strError=REF(string()));\r
-bool StartNode(string& strError=REF(string()));\r
+void StartNode(void* parg);\r
bool StopNode();\r
\r
\r
\r
\r
\r
-\r
//\r
// Message header\r
// (4) message start\r
unsigned int nTime;\r
\r
// memory only\r
- unsigned int nLastFailed;\r
+ unsigned int nLastTry;\r
\r
CAddress()\r
{\r
ip = INADDR_NONE;\r
port = DEFAULT_PORT;\r
nTime = GetAdjustedTime();\r
- nLastFailed = 0;\r
+ nLastTry = 0;\r
}\r
\r
bool SetAddress(const char* pszIn)\r
extern bool fShutdown;\r
extern array<int, 10> vnThreadsRunning;\r
extern SOCKET hListenSocket;\r
+extern int64 nThreadSocketHandlerHeartbeat;\r
\r
extern vector<CNode*> vNodes;\r
extern CCriticalSection cs_vNodes;\r
CDataStream vRecv;\r
CCriticalSection cs_vSend;\r
CCriticalSection cs_vRecv;\r
+ int64 nLastSend;\r
+ int64 nLastRecv;\r
+ int64 nLastSendEmpty;\r
+ int64 nTimeConnected;\r
unsigned int nPushPos;\r
CAddress addr;\r
int nVersion;\r
hSocket = hSocketIn;\r
vSend.SetType(SER_NETWORK);\r
vRecv.SetType(SER_NETWORK);\r
+ nLastSend = 0;\r
+ nLastRecv = 0;\r
+ nLastSendEmpty = GetTime();\r
+ nTimeConnected = GetTime();\r
nPushPos = -1;\r
addr = addrIn;\r
nVersion = 0;\r
CAddress addrYou = (fUseProxy ? CAddress("0.0.0.0") : addr);\r
CAddress addrMe = (fUseProxy ? CAddress("0.0.0.0") : addrLocalHost);\r
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));\r
- PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce);\r
+ PushMessage("version", VERSION, nLocalServices, nTime, addrYou, addrMe, nLocalHostNonce, "linux-test5");\r
}\r
\r
~CNode()\r
public:\r
\r
\r
- bool ReadyToDisconnect()\r
- {\r
- return fDisconnect || GetRefCount() <= 0;\r
- }\r
-\r
int GetRefCount()\r
{\r
return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);\r
AbortMessage();\r
nPushPos = vSend.size();\r
vSend << CMessageHeader(pszCommand, 0);\r
+ if (fDebug)\r
+ printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
printf("sending: %s ", pszCommand);\r
}\r
\r
bool fRandSendTest = false;\r
void RandSend();\r
extern int g_isPainting;\r
+bool fClosedToTray = false;\r
\r
// Settings\r
int fShowGenerated = true;\r
\r
void CMainFrame::OnClose(wxCloseEvent& event)\r
{\r
- if (fMinimizeToTray && fMinimizeOnClose && event.CanVeto() && !IsIconized())\r
+ if (fMinimizeOnClose && event.CanVeto() && !IsIconized())\r
{\r
// Divert close to minimize\r
event.Veto();\r
+ fClosedToTray = true;\r
Iconize(true);\r
}\r
else\r
{\r
Destroy();\r
- _beginthread(Shutdown, 0, NULL);\r
+ CreateThread(Shutdown, NULL);\r
}\r
}\r
\r
{\r
// Hide the task bar button when minimized.\r
// Event is sent when the frame is minimized or restored.\r
- Show(!fMinimizeToTray || !event.Iconized());\r
+ if (!event.Iconized())\r
+ fClosedToTray = false;\r
+#ifndef __WXMSW__\r
+ // Tray is not reliable on Linux gnome\r
+ fClosedToTray = false;\r
+#endif\r
+ if (fMinimizeToTray && event.Iconized())\r
+ fClosedToTray = true;\r
+ Show(!fClosedToTray);\r
+ ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);\r
}\r
\r
void CMainFrame::OnMouseEvents(wxMouseEvent& event)\r
string FormatTxStatus(const CWalletTx& wtx)\r
{\r
// Status\r
- int nDepth = wtx.GetDepthInMainChain();\r
if (!wtx.IsFinal())\r
{\r
if (wtx.nLockTime < 500000000)\r
else\r
return strprintf("Open until %s", DateTimeStr(wtx.nLockTime).c_str());\r
}\r
- else if (nDepth < 6)\r
- return strprintf("%d/unconfirmed", nDepth);\r
else\r
- return strprintf("%d blocks", nDepth);\r
+ {\r
+ int nDepth = wtx.GetDepthInMainChain();\r
+ if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)\r
+ return strprintf("%d/offline?", nDepth);\r
+ else if (nDepth < 6)\r
+ return strprintf("%d/unconfirmed", nDepth);\r
+ else\r
+ return strprintf("%d blocks", nDepth);\r
+ }\r
}\r
\r
string SingleLine(const string& strIn)\r
foreach(const CTxOut& txout, wtx.vout)\r
nUnmatured += txout.GetCredit();\r
if (wtx.IsInMainChain())\r
- strDescription += strprintf(" (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());\r
+ {\r
+ strDescription = strprintf("Generated (%s matures in %d more blocks)", FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());\r
+\r
+ // Check if the block was requested by anyone\r
+ if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)\r
+ strDescription = "Generated - Warning: This block was not received by any other nodes and will probably not be accepted!";\r
+ }\r
else\r
- strDescription += " (not accepted)";\r
+ {\r
+ strDescription = "Generated (not accepted)";\r
+ }\r
}\r
}\r
else if (!mapValue["from"].empty() || !mapValue["message"].empty())\r
strStatus,\r
nTime ? DateTimeStr(nTime) : "",\r
"Payment to yourself",\r
- FormatMoney(nNet - nValue, true),\r
- FormatMoney(nValue, true));\r
+ "",\r
+ "");\r
+ /// issue: can't tell which is the payment and which is the change anymore\r
+ // FormatMoney(nNet - nValue, true),\r
+ // FormatMoney(nValue, true));\r
}\r
else if (fAllFromMe)\r
{\r
string strStatus = strprintf(" %d connections %d blocks %d transactions", vNodes.size(), nBestHeight + 1, nTransactionCount);\r
m_statusBar->SetStatusText(strStatus, 2);\r
\r
+ if (fDebug && GetTime() - nThreadSocketHandlerHeartbeat > 60)\r
+ m_statusBar->SetStatusText(" ERROR: ThreadSocketHandler has stopped", 0);\r
+\r
// Pass through to listctrl to actually do the paint, we're just hooking the message\r
m_listCtrl->Disconnect(wxEVT_PAINT, (wxObjectEventFunction)NULL, NULL, this);\r
m_listCtrl->GetEventHandler()->ProcessEvent(event);\r
\r
\r
\r
- strHTML += "<b>Status:</b> " + FormatTxStatus(wtx) + "<br>";\r
+ strHTML += "<b>Status:</b> " + FormatTxStatus(wtx);\r
+ int nRequests = wtx.GetRequestCount();\r
+ if (nRequests != -1)\r
+ {\r
+ if (nRequests == 0)\r
+ strHTML += ", has not been successfully broadcast yet";\r
+ else if (nRequests == 1)\r
+ strHTML += strprintf(", broadcast through %d node", nRequests);\r
+ else\r
+ strHTML += strprintf(", broadcast through %d nodes", nRequests);\r
+ }\r
+ strHTML += "<br>";\r
+\r
strHTML += "<b>Date:</b> " + (nTime ? DateTimeStr(nTime) : "") + "<br>";\r
\r
\r
if (fAllToMe)\r
{\r
// Payment to self\r
- int64 nValue = wtx.vout[0].nValue;\r
- strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";\r
- strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";\r
+ /// issue: can't tell which is the payment and which is the change anymore\r
+ //int64 nValue = wtx.vout[0].nValue;\r
+ //strHTML += "<b>Debit:</b> " + FormatMoney(-nValue) + "<br>";\r
+ //strHTML += "<b>Credit:</b> " + FormatMoney(nValue) + "<br>";\r
}\r
\r
int64 nTxFee = nDebit - wtx.GetValueOut();\r
//m_listBox->Append("Test 2");\r
m_listBox->SetSelection(0);\r
SelectPage(0);\r
+#ifndef __WXMSW__\r
+ m_checkBoxMinimizeOnClose->SetLabel("&Minimize on close");\r
+#endif\r
\r
// Init values\r
m_textCtrlTransactionFee->SetValue(FormatMoney(nTransactionFee));\r
m_spinCtrlLimitProcessors->SetRange(1, nProcessors);\r
m_checkBoxStartOnSystemStartup->SetValue(fTmpStartOnSystemStartup = GetStartOnSystemStartup());\r
m_checkBoxMinimizeToTray->SetValue(fMinimizeToTray);\r
- m_checkBoxMinimizeOnClose->Enable(fMinimizeToTray);\r
- m_checkBoxMinimizeOnClose->SetValue(fMinimizeToTray && fMinimizeOnClose);\r
- fTmpMinimizeOnClose = fMinimizeOnClose;\r
+ m_checkBoxMinimizeOnClose->SetValue(fMinimizeOnClose);\r
m_checkBoxUseProxy->SetValue(fUseProxy);\r
m_textCtrlProxyIP->Enable(fUseProxy);\r
m_textCtrlProxyPort->Enable(fUseProxy);\r
m_spinCtrlLimitProcessors->Enable(event.IsChecked());\r
}\r
\r
-void COptionsDialog::OnCheckBoxMinimizeToTray(wxCommandEvent& event)\r
-{\r
- m_checkBoxMinimizeOnClose->Enable(event.IsChecked());\r
-\r
- // Save the value in fTmpMinimizeOnClose so we can\r
- // show the checkbox unchecked when its parent is unchecked\r
- if (event.IsChecked())\r
- m_checkBoxMinimizeOnClose->SetValue(fTmpMinimizeOnClose);\r
- else\r
- {\r
- fTmpMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();\r
- m_checkBoxMinimizeOnClose->SetValue(false);\r
- }\r
-\r
-}\r
-\r
void COptionsDialog::OnCheckBoxUseProxy(wxCommandEvent& event)\r
{\r
m_textCtrlProxyIP->Enable(event.IsChecked());\r
{\r
fMinimizeToTray = m_checkBoxMinimizeToTray->GetValue();\r
walletdb.WriteSetting("fMinimizeToTray", fMinimizeToTray);\r
- ptaskbaricon->Show(fMinimizeToTray);\r
+ ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);\r
}\r
\r
- if (fMinimizeOnClose != (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose))\r
+ if (fMinimizeOnClose != m_checkBoxMinimizeOnClose->GetValue())\r
{\r
- fMinimizeOnClose = (fMinimizeToTray ? m_checkBoxMinimizeOnClose->GetValue() : fTmpMinimizeOnClose);\r
+ fMinimizeOnClose = m_checkBoxMinimizeOnClose->GetValue();\r
walletdb.WriteSetting("fMinimizeOnClose", fMinimizeOnClose);\r
}\r
\r
if (str.Find('Â') != wxNOT_FOUND)\r
str.Remove(str.Find('Â'), 1);\r
m_staticTextMain->SetLabel(str);\r
+#ifndef __WXMSW__\r
+ SetSize(510, 380);\r
+#endif\r
}\r
\r
void CAboutDialog::OnButtonOK(wxCommandEvent& event)\r
SetTitle(strprintf("Sending %s to %s", FormatMoney(nPrice).c_str(), wtx.mapValue["to"].c_str()));\r
m_textCtrlStatus->SetValue("");\r
\r
- _beginthread(SendingDialogStartTransfer, 0, this);\r
+ CreateThread(SendingDialogStartTransfer, this);\r
}\r
\r
CSendingDialog::~CSendingDialog()\r
this->Layout();\r
\r
// Request details from seller\r
- _beginthread(ThreadRequestProductDetails, 0, new pair<CProduct, wxEvtHandler*>(product, GetEventHandler()));\r
+ CreateThread(ThreadRequestProductDetails, new pair<CProduct, wxEvtHandler*>(product, GetEventHandler()));\r
}\r
\r
CViewProductDialog::~CViewProductDialog()\r
enum\r
{\r
ID_TASKBAR_RESTORE = 10001,\r
+ ID_TASKBAR_OPTIONS,\r
ID_TASKBAR_GENERATE,\r
ID_TASKBAR_EXIT,\r
};\r
BEGIN_EVENT_TABLE(CMyTaskBarIcon, wxTaskBarIcon)\r
EVT_TASKBAR_LEFT_DCLICK(CMyTaskBarIcon::OnLeftButtonDClick)\r
EVT_MENU(ID_TASKBAR_RESTORE, CMyTaskBarIcon::OnMenuRestore)\r
+ EVT_MENU(ID_TASKBAR_OPTIONS, CMyTaskBarIcon::OnMenuOptions)\r
EVT_MENU(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnMenuGenerate)\r
EVT_UPDATE_UI(ID_TASKBAR_GENERATE, CMyTaskBarIcon::OnUpdateUIGenerate)\r
EVT_MENU(ID_TASKBAR_EXIT, CMyTaskBarIcon::OnMenuExit)\r
Restore();\r
}\r
\r
+void CMyTaskBarIcon::OnMenuOptions(wxCommandEvent& event)\r
+{\r
+ // Since it's modal, get the main window to do it\r
+ wxCommandEvent event2(wxEVT_COMMAND_MENU_SELECTED, wxID_MENUOPTIONSOPTIONS);\r
+ pframeMain->AddPendingEvent(event2);\r
+}\r
+\r
void CMyTaskBarIcon::Restore()\r
{\r
pframeMain->Show();\r
+ wxIconizeEvent event(0, false);\r
+ pframeMain->AddPendingEvent(event);\r
pframeMain->Iconize(false);\r
pframeMain->Raise();\r
}\r
{\r
wxMenu* pmenu = new wxMenu;\r
pmenu->Append(ID_TASKBAR_RESTORE, "&Open Bitcoin");\r
+ pmenu->Append(ID_TASKBAR_OPTIONS, "O&ptions...");\r
pmenu->AppendCheckItem(ID_TASKBAR_GENERATE, "&Generate Coins")->Check(fGenerateBitcoins);\r
#ifndef __WXMAC_OSX__ // Mac has built-in quit menu\r
pmenu->AppendSeparator();\r
{\r
CBlockIndex* pindex = (*mi).second;\r
CBlock block;\r
- block.ReadFromDisk(pindex, true);\r
+ block.ReadFromDisk(pindex);\r
block.BuildMerkleTree();\r
block.print();\r
printf("\n");\r
if (mapArgs.count("-min"))\r
pframeMain->Iconize(true);\r
pframeMain->Show(true); // have to show first to get taskbar button to hide\r
- pframeMain->Show(!fMinimizeToTray || !pframeMain->IsIconized());\r
- ptaskbaricon->Show(fMinimizeToTray);\r
+ if (fMinimizeToTray && pframeMain->IsIconized())\r
+ fClosedToTray = true;\r
+ pframeMain->Show(!fClosedToTray);\r
+ ptaskbaricon->Show(fMinimizeToTray || fClosedToTray);\r
\r
- _beginthread(ThreadDelayedRepaint, 0, NULL);\r
+ CreateThread(ThreadDelayedRepaint, NULL);\r
\r
if (!CheckDiskSpace())\r
return false;\r
\r
RandAddSeedPerfmon();\r
\r
- if (!StartNode(strErrors))\r
- wxMessageBox(strErrors, "Bitcoin");\r
-\r
- GenerateBitcoins(fGenerateBitcoins);\r
+ if (!CreateThread(StartNode, NULL))\r
+ wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");\r
\r
if (fFirstRun)\r
SetStartOnSystemStartup(true);\r
void OnListBox(wxCommandEvent& event);\r
void OnKillFocusTransactionFee(wxFocusEvent& event);\r
void OnCheckBoxLimitProcessors(wxCommandEvent& event);\r
- void OnCheckBoxMinimizeToTray(wxCommandEvent& event);\r
void OnCheckBoxUseProxy(wxCommandEvent& event);\r
void OnKillFocusProxy(wxFocusEvent& event);\r
\r
// Event handlers\r
void OnLeftButtonDClick(wxTaskBarIconEvent& event);\r
void OnMenuRestore(wxCommandEvent& event);\r
+ void OnMenuOptions(wxCommandEvent& event);\r
void OnUpdateUIGenerate(wxUpdateUIEvent& event);\r
void OnMenuGenerate(wxCommandEvent& event);\r
void OnMenuExit(wxCommandEvent& event);\r
m_menuOptions->Append( m_menuOptionsChangeYourAddress );\r
\r
wxMenuItem* m_menuOptionsOptions;\r
- m_menuOptionsOptions = new wxMenuItem( m_menuOptions, wxID_ANY, wxString( wxT("&Options...") ) , wxEmptyString, wxITEM_NORMAL );\r
+ m_menuOptionsOptions = new wxMenuItem( m_menuOptions, wxID_MENUOPTIONSOPTIONS, wxString( wxT("&Options...") ) , wxEmptyString, wxITEM_NORMAL );\r
m_menuOptions->Append( m_menuOptionsOptions );\r
\r
m_menubar->Append( m_menuOptions, wxT("&Options") );\r
\r
bSizer69->Add( m_checkBoxStartOnSystemStartup, 0, wxALL, 5 );\r
\r
- m_checkBoxMinimizeToTray = new wxCheckBox( m_panelMain, wxID_ANY, wxT("&Minimize to the system tray instead of the taskbar"), wxDefaultPosition, wxDefaultSize, 0 );\r
+ m_checkBoxMinimizeToTray = new wxCheckBox( m_panelMain, wxID_ANY, wxT("&Minimize to the tray instead of the taskbar"), wxDefaultPosition, wxDefaultSize, 0 );\r
\r
bSizer69->Add( m_checkBoxMinimizeToTray, 0, wxALL, 5 );\r
\r
- wxBoxSizer* bSizer101;\r
- bSizer101 = new wxBoxSizer( wxHORIZONTAL );\r
+ m_checkBoxMinimizeOnClose = new wxCheckBox( m_panelMain, wxID_ANY, wxT("M&inimize to the tray on close"), wxDefaultPosition, wxDefaultSize, 0 );\r
\r
- \r
- bSizer101->Add( 16, 0, 0, 0, 5 );\r
- \r
- m_checkBoxMinimizeOnClose = new wxCheckBox( m_panelMain, wxID_ANY, wxT("Mi&nimize to system tray on close"), wxDefaultPosition, wxDefaultSize, 0 );\r
- \r
- bSizer101->Add( m_checkBoxMinimizeOnClose, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );\r
- \r
- bSizer69->Add( bSizer101, 1, wxEXPAND, 5 );\r
+ bSizer69->Add( m_checkBoxMinimizeOnClose, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );\r
\r
wxBoxSizer* bSizer102;\r
bSizer102 = new wxBoxSizer( wxHORIZONTAL );\r
#define wxID_MAINFRAME 1000\r
#define wxID_VIEWSHOWGENERATED 1001\r
#define wxID_OPTIONSGENERATEBITCOINS 1002\r
-#define wxID_BUTTONSEND 1003\r
-#define wxID_BUTTONRECEIVE 1004\r
-#define wxID_TEXTCTRLADDRESS 1005\r
-#define wxID_BUTTONCOPY 1006\r
-#define wxID_BUTTONCHANGE 1007\r
-#define wxID_TRANSACTIONFEE 1008\r
-#define wxID_PROXYIP 1009\r
-#define wxID_PROXYPORT 1010\r
-#define wxID_TEXTCTRLPAYTO 1011\r
-#define wxID_BUTTONPASTE 1012\r
-#define wxID_BUTTONADDRESSBOOK 1013\r
-#define wxID_TEXTCTRLAMOUNT 1014\r
-#define wxID_CHOICETRANSFERTYPE 1015\r
-#define wxID_LISTCTRL 1016\r
-#define wxID_BUTTONRENAME 1017\r
-#define wxID_BUTTONNEW 1018\r
-#define wxID_BUTTONEDIT 1019\r
-#define wxID_BUTTONDELETE 1020\r
-#define wxID_DEL0 1021\r
-#define wxID_DEL1 1022\r
-#define wxID_DEL2 1023\r
-#define wxID_DEL3 1024\r
-#define wxID_DEL4 1025\r
-#define wxID_DEL5 1026\r
-#define wxID_DEL6 1027\r
-#define wxID_DEL7 1028\r
-#define wxID_DEL8 1029\r
-#define wxID_DEL9 1030\r
-#define wxID_DEL10 1031\r
-#define wxID_DEL11 1032\r
-#define wxID_DEL12 1033\r
-#define wxID_DEL13 1034\r
-#define wxID_DEL14 1035\r
-#define wxID_DEL15 1036\r
-#define wxID_DEL16 1037\r
-#define wxID_DEL17 1038\r
-#define wxID_DEL18 1039\r
-#define wxID_DEL19 1040\r
-#define wxID_BUTTONPREVIEW 1041\r
-#define wxID_BUTTONSAMPLE 1042\r
-#define wxID_CANCEL2 1043\r
-#define wxID_BUTTONBACK 1044\r
-#define wxID_BUTTONNEXT 1045\r
-#define wxID_SUBMIT 1046\r
-#define wxID_TEXTCTRL 1047\r
+#define wxID_MENUOPTIONSOPTIONS 1003\r
+#define wxID_BUTTONSEND 1004\r
+#define wxID_BUTTONRECEIVE 1005\r
+#define wxID_TEXTCTRLADDRESS 1006\r
+#define wxID_BUTTONCOPY 1007\r
+#define wxID_BUTTONCHANGE 1008\r
+#define wxID_TRANSACTIONFEE 1009\r
+#define wxID_PROXYIP 1010\r
+#define wxID_PROXYPORT 1011\r
+#define wxID_TEXTCTRLPAYTO 1012\r
+#define wxID_BUTTONPASTE 1013\r
+#define wxID_BUTTONADDRESSBOOK 1014\r
+#define wxID_TEXTCTRLAMOUNT 1015\r
+#define wxID_CHOICETRANSFERTYPE 1016\r
+#define wxID_LISTCTRL 1017\r
+#define wxID_BUTTONRENAME 1018\r
+#define wxID_BUTTONNEW 1019\r
+#define wxID_BUTTONEDIT 1020\r
+#define wxID_BUTTONDELETE 1021\r
+#define wxID_DEL0 1022\r
+#define wxID_DEL1 1023\r
+#define wxID_DEL2 1024\r
+#define wxID_DEL3 1025\r
+#define wxID_DEL4 1026\r
+#define wxID_DEL5 1027\r
+#define wxID_DEL6 1028\r
+#define wxID_DEL7 1029\r
+#define wxID_DEL8 1030\r
+#define wxID_DEL9 1031\r
+#define wxID_DEL10 1032\r
+#define wxID_DEL11 1033\r
+#define wxID_DEL12 1034\r
+#define wxID_DEL13 1035\r
+#define wxID_DEL14 1036\r
+#define wxID_DEL15 1037\r
+#define wxID_DEL16 1038\r
+#define wxID_DEL17 1039\r
+#define wxID_DEL18 1040\r
+#define wxID_DEL19 1041\r
+#define wxID_BUTTONPREVIEW 1042\r
+#define wxID_BUTTONSAMPLE 1043\r
+#define wxID_CANCEL2 1044\r
+#define wxID_BUTTONBACK 1045\r
+#define wxID_BUTTONNEXT 1046\r
+#define wxID_SUBMIT 1047\r
+#define wxID_TEXTCTRL 1048\r
\r
///////////////////////////////////////////////////////////////////////////////\r
/// Class CMainFrameBase\r
wxStaticText* m_staticText35;\r
wxCheckBox* m_checkBoxStartOnSystemStartup;\r
wxCheckBox* m_checkBoxMinimizeToTray;\r
- \r
wxCheckBox* m_checkBoxMinimizeOnClose;\r
wxCheckBox* m_checkBoxUseProxy;\r
\r
<event name="OnSetFocus"></event>\r
<event name="OnSize"></event>\r
<event name="OnUpdateUI"></event>\r
- <object class="wxMenuBar" expanded="0">\r
+ <object class="wxMenuBar" expanded="1">\r
<property name="bg">240,240,240</property>\r
<property name="context_help"></property>\r
<property name="enabled">1</property>\r
<property name="checked">0</property>\r
<property name="enabled">1</property>\r
<property name="help"></property>\r
- <property name="id">wxID_ANY</property>\r
+ <property name="id">wxID_MENUOPTIONSOPTIONS</property>\r
<property name="kind">wxITEM_NORMAL</property>\r
<property name="label">&Options...</property>\r
<property name="name">m_menuOptionsOptions</property>\r
<property name="font"></property>\r
<property name="hidden">0</property>\r
<property name="id">wxID_ANY</property>\r
- <property name="label">&Minimize to the system tray instead of the taskbar</property>\r
+ <property name="label">&Minimize to the tray instead of the taskbar</property>\r
<property name="maximum_size"></property>\r
<property name="minimum_size"></property>\r
<property name="name">m_checkBoxMinimizeToTray</property>\r
</object>\r
<object class="sizeritem" expanded="1">\r
<property name="border">5</property>\r
- <property name="flag">wxEXPAND</property>\r
- <property name="proportion">1</property>\r
- <object class="wxBoxSizer" expanded="1">\r
+ <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>\r
+ <property name="proportion">0</property>\r
+ <object class="wxCheckBox" expanded="1">\r
+ <property name="bg"></property>\r
+ <property name="checked">0</property>\r
+ <property name="context_help"></property>\r
+ <property name="enabled">1</property>\r
+ <property name="fg"></property>\r
+ <property name="font"></property>\r
+ <property name="hidden">0</property>\r
+ <property name="id">wxID_ANY</property>\r
+ <property name="label">M&inimize to the tray on close</property>\r
+ <property name="maximum_size"></property>\r
<property name="minimum_size"></property>\r
- <property name="name">bSizer101</property>\r
- <property name="orient">wxHORIZONTAL</property>\r
- <property name="permission">none</property>\r
- <object class="sizeritem" expanded="1">\r
- <property name="border">5</property>\r
- <property name="flag"></property>\r
- <property name="proportion">0</property>\r
- <object class="spacer" expanded="1">\r
- <property name="height">0</property>\r
- <property name="permission">protected</property>\r
- <property name="width">16</property>\r
- </object>\r
- </object>\r
- <object class="sizeritem" expanded="1">\r
- <property name="border">5</property>\r
- <property name="flag">wxALL|wxALIGN_CENTER_VERTICAL</property>\r
- <property name="proportion">0</property>\r
- <object class="wxCheckBox" expanded="1">\r
- <property name="bg"></property>\r
- <property name="checked">0</property>\r
- <property name="context_help"></property>\r
- <property name="enabled">1</property>\r
- <property name="fg"></property>\r
- <property name="font"></property>\r
- <property name="hidden">0</property>\r
- <property name="id">wxID_ANY</property>\r
- <property name="label">Mi&nimize to system tray on close</property>\r
- <property name="maximum_size"></property>\r
- <property name="minimum_size"></property>\r
- <property name="name">m_checkBoxMinimizeOnClose</property>\r
- <property name="permission">protected</property>\r
- <property name="pos"></property>\r
- <property name="size"></property>\r
- <property name="style"></property>\r
- <property name="subclass"></property>\r
- <property name="tooltip"></property>\r
- <property name="window_extra_style"></property>\r
- <property name="window_name"></property>\r
- <property name="window_style"></property>\r
- <event name="OnChar"></event>\r
- <event name="OnCheckBox"></event>\r
- <event name="OnEnterWindow"></event>\r
- <event name="OnEraseBackground"></event>\r
- <event name="OnKeyDown"></event>\r
- <event name="OnKeyUp"></event>\r
- <event name="OnKillFocus"></event>\r
- <event name="OnLeaveWindow"></event>\r
- <event name="OnLeftDClick"></event>\r
- <event name="OnLeftDown"></event>\r
- <event name="OnLeftUp"></event>\r
- <event name="OnMiddleDClick"></event>\r
- <event name="OnMiddleDown"></event>\r
- <event name="OnMiddleUp"></event>\r
- <event name="OnMotion"></event>\r
- <event name="OnMouseEvents"></event>\r
- <event name="OnMouseWheel"></event>\r
- <event name="OnPaint"></event>\r
- <event name="OnRightDClick"></event>\r
- <event name="OnRightDown"></event>\r
- <event name="OnRightUp"></event>\r
- <event name="OnSetFocus"></event>\r
- <event name="OnSize"></event>\r
- <event name="OnUpdateUI"></event>\r
- </object>\r
- </object>\r
+ <property name="name">m_checkBoxMinimizeOnClose</property>\r
+ <property name="permission">protected</property>\r
+ <property name="pos"></property>\r
+ <property name="size"></property>\r
+ <property name="style"></property>\r
+ <property name="subclass"></property>\r
+ <property name="tooltip"></property>\r
+ <property name="window_extra_style"></property>\r
+ <property name="window_name"></property>\r
+ <property name="window_style"></property>\r
+ <event name="OnChar"></event>\r
+ <event name="OnCheckBox"></event>\r
+ <event name="OnEnterWindow"></event>\r
+ <event name="OnEraseBackground"></event>\r
+ <event name="OnKeyDown"></event>\r
+ <event name="OnKeyUp"></event>\r
+ <event name="OnKillFocus"></event>\r
+ <event name="OnLeaveWindow"></event>\r
+ <event name="OnLeftDClick"></event>\r
+ <event name="OnLeftDown"></event>\r
+ <event name="OnLeftUp"></event>\r
+ <event name="OnMiddleDClick"></event>\r
+ <event name="OnMiddleDown"></event>\r
+ <event name="OnMiddleUp"></event>\r
+ <event name="OnMotion"></event>\r
+ <event name="OnMouseEvents"></event>\r
+ <event name="OnMouseWheel"></event>\r
+ <event name="OnPaint"></event>\r
+ <event name="OnRightDClick"></event>\r
+ <event name="OnRightDown"></event>\r
+ <event name="OnRightUp"></event>\r
+ <event name="OnSetFocus"></event>\r
+ <event name="OnSize"></event>\r
+ <event name="OnUpdateUI"></event>\r
</object>\r
</object>\r
<object class="sizeritem" expanded="1">\r
\r
void RandAddSeedPerfmon()\r
{\r
-#ifdef __WXMSW__\r
- // Don't need this on Linux, OpenSSL automatically uses /dev/urandom\r
// This can take up to 2 seconds, so only do it every 10 minutes\r
static int64 nLastPerfmon;\r
if (GetTime() < nLastPerfmon + 10 * 60)\r
return;\r
nLastPerfmon = GetTime();\r
\r
+#ifdef __WXMSW__\r
+ // Don't need this on Linux, OpenSSL automatically uses /dev/urandom\r
// Seed with the entire set of perfmon data\r
unsigned char pdata[250000];\r
memset(pdata, 0, sizeof(pdata));\r
\r
printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str(), nSize);\r
}\r
+#else\r
+ printf("%s RandAddSeed()\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
#endif\r
}\r
\r
+uint64 GetRand(uint64 nMax)\r
+{\r
+ if (nMax == 0)\r
+ return 0;\r
+\r
+ // The range of the random source must be a multiple of the modulus\r
+ // to give every possible output value an equal possibility\r
+ uint64 nRange = (UINT64_MAX / nMax) * nMax;\r
+ uint64 nRand = 0;\r
+ do\r
+ RAND_bytes((unsigned char*)&nRand, sizeof(nRand));\r
+ while (nRand >= nRange);\r
+ return (nRand % nMax);\r
+}\r
+\r
+\r
+\r
+\r
+\r
\r
\r
\r
\r
\r
\r
-uint64 GetRand(uint64 nMax)\r
-{\r
- if (nMax == 0)\r
- return 0;\r
-\r
- // The range of the random source must be a multiple of the modulus\r
- // to give every possible output value an equal possibility\r
- uint64 nRange = (_UI64_MAX / nMax) * nMax;\r
- uint64 nRand = 0;\r
- do\r
- RAND_bytes((unsigned char*)&nRand, sizeof(nRand));\r
- while (nRand >= nRange);\r
- return (nRand % nMax);\r
-}\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
\r
\r
//\r
// note: NTP isn't implemented yet, so until then we just use the median\r
// of other nodes clocks to correct ours.\r
//\r
-\r
int64 GetTime()\r
{\r
return time(NULL);\r
return (T&)val;\r
}\r
\r
-#ifndef __WXMSW__\r
-#define _UI64_MAX UINT64_MAX\r
-#define _I64_MAX INT64_MAX\r
+#ifdef __WXMSW__\r
+#define MSG_NOSIGNAL 0\r
+#define MSG_DONTWAIT 0\r
+#define UINT64_MAX _UI64_MAX\r
+#define INT64_MAX _I64_MAX\r
+#define INT64_MIN _I64_MIN\r
+#else\r
#define WSAGetLastError() errno\r
#define WSAEWOULDBLOCK EWOULDBLOCK\r
#define WSAEMSGSIZE EMSGSIZE\r
#define MAX_PATH 1024\r
#define Sleep(n) wxMilliSleep(n)\r
#define Beep(n1,n2) (0)\r
-inline int _beginthread(void(*pfn)(void*), unsigned nStack, void* parg) { thread(bind(pfn, parg)); return 0; }\r
-inline void _endthread() { pthread_exit(NULL); }\r
-inline int GetCurrentThread() { return 0; }\r
-// threads are processes on linux, so setpriority affects just the one thread\r
-inline void SetThreadPriority(int nThread, int nPriority) { setpriority(PRIO_PROCESS, getpid(), nPriority); }\r
-#define THREAD_PRIORITY_LOWEST PRIO_MIN\r
-#define THREAD_PRIORITY_BELOW_NORMAL 2\r
-#define THREAD_PRIORITY_NORMAL 0\r
-#define THREAD_PRIORITY_ABOVE_NORMAL 0\r
-#endif\r
-#ifndef MSG_NOSIGNAL\r
-#define MSG_NOSIGNAL 0\r
#endif\r
\r
\r
\r
\r
\r
+\r
// Wrapper to automatically initialize critical sections\r
class CCriticalSection\r
{\r
\r
\r
\r
-\r
-\r
inline int OutputDebugStringF(const char* pszFormat, ...)\r
{\r
int ret = 0;\r
RIPEMD160((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);\r
return hash2;\r
}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+// Note: It turns out we might have been able to use boost::thread\r
+// by using TerminateThread(boost::thread.native_handle(), 0);\r
+#ifdef __WXMSW__\r
+typedef HANDLE pthread_t;\r
+\r
+inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)\r
+{\r
+ DWORD nUnused = 0;\r
+ HANDLE hthread =\r
+ CreateThread(\r
+ NULL, // default security\r
+ 0, // inherit stack size from parent\r
+ (LPTHREAD_START_ROUTINE)pfn, // function pointer\r
+ parg, // argument\r
+ 0, // creation option, start immediately\r
+ &nUnused); // thread identifier\r
+ if (hthread == NULL)\r
+ {\r
+ printf("Error: CreateThread() returned %d\n", GetLastError());\r
+ return (pthread_t)0;\r
+ }\r
+ if (!fWantHandle)\r
+ {\r
+ CloseHandle(hthread);\r
+ return (pthread_t)-1;\r
+ }\r
+ return hthread;\r
+}\r
+\r
+inline void SetThreadPriority(int nPriority)\r
+{\r
+ SetThreadPriority(GetCurrentThread(), nPriority);\r
+}\r
+#else\r
+inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)\r
+{\r
+ pthread_t hthread = 0;\r
+ int ret = pthread_create(&hthread, NULL, (void*(*)(void*))pfn, parg);\r
+ if (ret != 0)\r
+ {\r
+ printf("Error: pthread_create() returned %d\n", ret);\r
+ return (pthread_t)0;\r
+ }\r
+ if (!fWantHandle)\r
+ return (pthread_t)-1;\r
+ return hthread;\r
+}\r
+\r
+#define THREAD_PRIORITY_LOWEST PRIO_MIN\r
+#define THREAD_PRIORITY_BELOW_NORMAL 2\r
+#define THREAD_PRIORITY_NORMAL 0\r
+#define THREAD_PRIORITY_ABOVE_NORMAL 0\r
+\r
+inline void SetThreadPriority(int nPriority)\r
+{\r
+ // threads are processes on linux, so PRIO_PROCESS affects just the one thread\r
+ setpriority(PRIO_PROCESS, getpid(), nPriority);\r
+}\r
+\r
+inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode)\r
+{\r
+ return (pthread_cancel(hthread) == 0);\r
+}\r
+\r
+inline void ExitThread(unsigned int nExitCode)\r
+{\r
+ pthread_exit((void*)nExitCode);\r
+}\r
+#endif\r