changeset 26:c94801659fe4 draft

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