Merge branch '0.4.x' into 0.5.0.x
authorLuke Dashjr <luke-jr+git@utopios.org>
Tue, 3 Jan 2012 17:19:48 +0000 (12:19 -0500)
committerLuke Dashjr <luke-jr+git@utopios.org>
Tue, 3 Jan 2012 17:19:48 +0000 (12:19 -0500)
Conflicts:
src/util.cpp

1  2 
src/init.cpp
src/net.cpp
src/util.cpp
src/util.h

diff --combined src/init.cpp
@@@ -4,7 -4,7 +4,7 @@@
  // file license.txt or http://www.opensource.org/licenses/mit-license.php.
  #include "headers.h"
  #include "db.h"
 -#include "rpc.h"
 +#include "bitcoinrpc.h"
  #include "net.h"
  #include "init.h"
  #include "strlcpy.h"
  #include <boost/filesystem/fstream.hpp>
  #include <boost/interprocess/sync/file_lock.hpp>
  
 +#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
 +#define _BITCOIN_QT_PLUGINS_INCLUDED
 +#define __INSURE__
 +#include <QtPlugin>
 +Q_IMPORT_PLUGIN(qcncodecs)
 +Q_IMPORT_PLUGIN(qjpcodecs)
 +Q_IMPORT_PLUGIN(qtwcodecs)
 +Q_IMPORT_PLUGIN(qkrcodecs)
 +#endif
 +
  using namespace std;
  using namespace boost;
  
@@@ -34,7 -24,7 +34,7 @@@ CWallet* pwalletMain
  
  void ExitTimeout(void* parg)
  {
 -#ifdef __WXMSW__
 +#ifdef WIN32
      Sleep(5000);
      ExitProcess(0);
  #endif
@@@ -90,7 -80,7 +90,7 @@@ void HandleSIGTERM(int
  //
  // Start
  //
 -#ifndef GUI
 +#if !defined(QT_GUI)
  int main(int argc, char* argv[])
  {
      bool fRet = false;
@@@ -131,10 -121,10 +131,10 @@@ bool AppInit2(int argc, char* argv[]
      // Disable confusing "helpful" text message on abort, ctrl-c
      _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
  #endif
 -#ifndef __WXMSW__
 +#ifndef WIN32
      umask(077);
  #endif
 -#ifndef __WXMSW__
 +#ifndef WIN32
      // Clean shutdown on SIGTERM
      struct sigaction sa;
      sa.sa_handler = HandleSIGTERM;
              "  -maxconnections=<n>\t  " + _("Maintain at most <n> connections to peers (default: 125)\n") +
              "  -addnode=<ip>    \t  "   + _("Add a node to connect to\n") +
              "  -connect=<ip>    \t\t  " + _("Connect only to the specified node\n") +
+             "  -noirc           \t  "   + _("Don't find peers using internet relay chat\n") +
              "  -nolisten        \t  "   + _("Don't accept connections from outside\n") +
              "  -nodnsseed       \t  "   + _("Don't bootstrap list of peers using DNS\n") +
 +            "  -banscore=<n>    \t  "   + _("Threshold for disconnecting misbehaving peers (default: 100)\n") +
 +            "  -bantime=<n>     \t  "   + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)\n") +
              "  -maxreceivebuffer=<n>\t  " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)\n") +
              "  -maxsendbuffer=<n>\t  "   + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)\n") +
  #ifdef USE_UPNP
  #ifdef GUI
              "  -server          \t\t  " + _("Accept command line and JSON-RPC commands\n") +
  #endif
 -#ifndef __WXMSW__
 +#ifndef WIN32
              "  -daemon          \t\t  " + _("Run in the background as a daemon and accept commands\n") +
  #endif
              "  -testnet         \t\t  " + _("Use the test network\n") +
          strUsage += string() +
              "  -?               \t\t  " + _("This help message\n");
  
          // Remove tabs
          strUsage.erase(std::remove(strUsage.begin(), strUsage.end(), '\t'), strUsage.end());
          fprintf(stderr, "%s", strUsage.c_str());
          return false;
      }
  
+     fTestNet = GetBoolArg("-testnet");
      fDebug = GetBoolArg("-debug");
-     fAllowDNS = GetBoolArg("-dns");
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
      fDaemon = GetBoolArg("-daemon");
  #else
      fDaemon = false;
          fServer = GetBoolArg("-server");
  
      /* force fServer when running without GUI */
 -#ifndef GUI
 +#if !defined(QT_GUI)
      fServer = true;
  #endif
 -
      fPrintToConsole = GetBoolArg("-printtoconsole");
      fPrintToDebugger = GetBoolArg("-printtodebugger");
-     fTestNet = GetBoolArg("-testnet");
-     bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
-     fNoListen = GetBoolArg("-nolisten") || fTOR;
      fLogTimestamps = GetBoolArg("-logtimestamps");
  
 +#ifndef QT_GUI
      for (int i = 1; i < argc; i++)
          if (!IsSwitchChar(argv[i][0]))
              fCommandLine = true;
          int ret = CommandLineRPC(argc, argv);
          exit(ret);
      }
 +#endif
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
      if (fDaemon)
      {
          // Daemonize
          ShrinkDebugFile();
      printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
      printf("Bitcoin version %s\n", FormatFullVersion().c_str());
 -#ifdef GUI
 -    printf("OS version %s\n", ((string)wxGetOsDescription()).c_str());
 -    printf("System default language is %d %s\n", g_locale.GetSystemLanguage(), ((string)g_locale.GetSysName()).c_str());
 -    printf("Language file %s (%s)\n", (string("locale/") + (string)g_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)g_locale.GetLocale()).c_str());
 -#endif
      printf("Default data directory %s\n", GetDefaultDataDir().c_str());
  
      if (GetBoolArg("-loadblockindextest"))
          return false;
      }
  
 -    //
 -    // Limit to single instance per user
 -    // Required to protect the database files if we're going to keep deleting log.*
 -    //
 -#if defined(__WXMSW__) && defined(GUI)
 -    // wxSingleInstanceChecker doesn't work on Linux
 -    wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");
 -    for (int i = 0; i < strMutexName.size(); i++)
 -        if (!isalnum(strMutexName[i]))
 -            strMutexName[i] = '.';
 -    wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
 -    if (psingleinstancechecker->IsAnotherRunning())
 -    {
 -        printf("Existing instance found\n");
 -        unsigned int nStart = GetTime();
 -        loop
 -        {
 -            // Show the previous instance and exit
 -            HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");
 -            if (hwndPrev)
 -            {
 -                if (IsIconic(hwndPrev))
 -                    ShowWindow(hwndPrev, SW_RESTORE);
 -                SetForegroundWindow(hwndPrev);
 -                return false;
 -            }
 -
 -            if (GetTime() > nStart + 60)
 -                return false;
 -
 -            // Resume this instance if the other exits
 -            delete psingleinstancechecker;
 -            Sleep(1000);
 -            psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
 -            if (!psingleinstancechecker->IsAnotherRunning())
 -                break;
 -        }
 -    }
 -#endif
 -
      // Make sure only a single bitcoin process is using the data directory.
      string strLockFile = GetDataDir() + "/.lock";
      FILE* file = fopen(strLockFile.c_str(), "a"); // empty lock file; created if it doesn't exist.
          return false;
      }
  
-     // Bind to the port early so we can tell if another instance is already running.
      string strErrors;
-     if (!fNoListen)
-     {
-         if (!BindListenPort(strErrors))
-         {
-             wxMessageBox(strErrors, "Bitcoin");
-             return false;
-         }
-     }
  
      //
      // Load data files
      strErrors = "";
      int64 nStart;
  
 +    InitMessage(_("Loading addresses..."));
      printf("Loading addresses...\n");
      nStart = GetTimeMillis();
      if (!LoadAddresses())
          strErrors += _("Error loading addr.dat      \n");
      printf(" addresses   %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
 +    InitMessage(_("Loading block index..."));
      printf("Loading block index...\n");
      nStart = GetTimeMillis();
      if (!LoadBlockIndex())
          strErrors += _("Error loading blkindex.dat      \n");
      printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
 +    InitMessage(_("Loading wallet..."));
      printf("Loading wallet...\n");
      nStart = GetTimeMillis();
      bool fFirstRun;
      }
      if (pindexBest != pindexRescan)
      {
 +        InitMessage(_("Rescanning..."));
          printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
          nStart = GetTimeMillis();
          pwalletMain->ScanForWalletTransactions(pindexRescan, true);
          printf(" rescan      %15"PRI64d"ms\n", GetTimeMillis() - nStart);
      }
  
 +    InitMessage(_("Done loading"));
      printf("Done loading\n");
  
          //// debug print
      // Add wallet transactions that aren't already in a block to mapTransactions
      pwalletMain->ReacceptWalletTransactions();
  
+     // Note: Bitcoin-QT stores several settings in the wallet, so we want
+     // to load the wallet BEFORE parsing command-line arguments, so
+     // the command-line/bitcoin.conf settings override GUI setting.
      //
      // Parameters
      //
          }
      }
  
+     bool fTor = (fUseProxy && addrProxy.port == htons(9050));
+     if (fTor)
+     {
+         // Use SoftSetArg here so user can override any of these if they wish.
+         // Note: the GetBoolArg() calls for all of these must happen later.
+         SoftSetArg("-nolisten", true);
+         SoftSetArg("-noirc", true);
+         SoftSetArg("-nodnsseed", true);
+         SoftSetArg("-noupnp", true);
+         SoftSetArg("-upnp", false);
+         SoftSetArg("-dns", false);
+     }
+     fAllowDNS = GetBoolArg("-dns");
+     fNoListen = GetBoolArg("-nolisten");
+     if (fHaveUPnP)
+     {
+ #if USE_UPNP
+     if (GetBoolArg("-noupnp"))
+         fUseUPnP = false;
+ #else
+     if (GetBoolArg("-upnp"))
+         fUseUPnP = true;
+ #endif
+     }
+     if (!fNoListen)
+     {
+         if (!BindListenPort(strErrors))
+         {
+             wxMessageBox(strErrors, "Bitcoin");
+             return false;
+         }
+     }
      if (mapArgs.count("-addnode"))
      {
          BOOST_FOREACH(string strAddr, mapMultiArgs["-addnode"])
              wxMessageBox(_("Warning: -paytxfee is set very high.  This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
      }
  
-     if (fHaveUPnP)
-     {
- #if USE_UPNP
-     if (GetBoolArg("-noupnp"))
-         fUseUPnP = false;
- #else
-     if (GetBoolArg("-upnp"))
-         fUseUPnP = true;
- #endif
-     }
      //
 -    // Create the main window and start the node
 +    // Start the node
      //
 -#ifdef GUI
 -    if (!fDaemon)
 -        CreateMainWindow();
 -#endif
 -
      if (!CheckDiskSpace())
          return false;
  
      RandAddSeedPerfmon();
  
      if (!CreateThread(StartNode, NULL))
 -        wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
 +        wxMessageBox(_("Error: CreateThread(StartNode) failed"), "Bitcoin");
  
      if (fServer)
          CreateThread(ThreadRPCServer, NULL);
  
 -#if defined(__WXMSW__) && defined(GUI)
 -    if (fFirstRun)
 -        SetStartOnSystemStartup(true);
 -#endif
 -
 -#ifndef GUI
 +#if !defined(QT_GUI)
      while (1)
          Sleep(5000);
  #endif
diff --combined src/net.cpp
@@@ -10,7 -10,7 +10,7 @@@
  #include "init.h"
  #include "strlcpy.h"
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
  #include <string.h>
  #endif
  
@@@ -103,7 -103,7 +103,7 @@@ bool ConnectSocket(const CAddress& addr
      bool fProxy = (fUseProxy && addrConnect.IsRoutable());
      struct sockaddr_in sockaddr = (fProxy ? addrProxy.GetSockAddr() : addrConnect.GetSockAddr());
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      u_long fNonblock = 1;
      if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
  #else
                  return false;
              }
              socklen_t nRetSize = sizeof(nRet);
 -#ifdef __WXMSW__
 +#ifdef WIN32
              if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, (char*)(&nRet), &nRetSize) == SOCKET_ERROR)
  #else
              if (getsockopt(hSocket, SOL_SOCKET, SO_ERROR, &nRet, &nRetSize) == SOCKET_ERROR)
                  return false;
              }
          }
 -#ifdef __WXMSW__
 +#ifdef WIN32
          else if (WSAGetLastError() != WSAEISCONN)
  #else
          else
      CNode::ConnectNode immediately turns the socket back to non-blocking
      but we'll turn it back to blocking just in case
      */
 -#ifdef __WXMSW__
 +#ifdef WIN32
      fNonblock = 0;
      if (ioctlsocket(hSocket, FIONBIO, &fNonblock) == SOCKET_ERROR)
  #else
@@@ -496,21 -496,25 +496,25 @@@ bool AddAddress(CAddress addr, int64 nT
  
  void AddressCurrentlyConnected(const CAddress& addr)
  {
+     CAddress *paddrFound = NULL;
      CRITICAL_BLOCK(cs_mapAddresses)
      {
          // Only if it's been published already
          map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
          if (it != mapAddresses.end())
+             paddrFound = &(*it).second;
+     }
+     if (paddrFound)
+     {
+         int64 nUpdateInterval = 20 * 60;
+         if (paddrFound->nTime < GetAdjustedTime() - nUpdateInterval)
          {
-             CAddress& addrFound = (*it).second;
-             int64 nUpdateInterval = 20 * 60;
-             if (addrFound.nTime < GetAdjustedTime() - nUpdateInterval)
-             {
-                 // Periodically update most recently seen time
-                 addrFound.nTime = GetAdjustedTime();
-                 CAddrDB addrdb;
-                 addrdb.WriteAddress(addrFound);
-             }
+             // Periodically update most recently seen time
+             paddrFound->nTime = GetAdjustedTime();
+             CAddrDB addrdb;
+             addrdb.WriteAddress(*paddrFound);
          }
      }
  }
@@@ -675,7 -679,7 +679,7 @@@ CNode* ConnectNode(CAddress addrConnect
          printf("connected %s\n", addrConnect.ToString().c_str());
  
          // Set to nonblocking
 -#ifdef __WXMSW__
 +#ifdef WIN32
          u_long nOne = 1;
          if (ioctlsocket(hSocket, FIONBIO, &nOne) == SOCKET_ERROR)
              printf("ConnectSocket() : ioctlsocket nonblocking setting failed, error %d\n", WSAGetLastError());
@@@ -727,52 -731,6 +731,52 @@@ void CNode::Cleanup(
  }
  
  
 +std::map<unsigned int, int64> CNode::setBanned;
 +CCriticalSection CNode::cs_setBanned;
 +
 +void CNode::ClearBanned()
 +{
 +    setBanned.clear();
 +}
 +
 +bool CNode::IsBanned(unsigned int ip)
 +{
 +    bool fResult = false;
 +    CRITICAL_BLOCK(cs_setBanned)
 +    {
 +        std::map<unsigned int, int64>::iterator i = setBanned.find(ip);
 +        if (i != setBanned.end())
 +        {
 +            int64 t = (*i).second;
 +            if (GetTime() < t)
 +                fResult = true;
 +        }
 +    }
 +    return fResult;
 +}
 +
 +bool CNode::Misbehaving(int howmuch)
 +{
 +    if (addr.IsLocal())
 +    {
 +        printf("Warning: local node %s misbehaving\n", addr.ToString().c_str());
 +        return false;
 +    }
 +
 +    nMisbehavior += howmuch;
 +    if (nMisbehavior >= GetArg("-banscore", 100))
 +    {
 +        int64 banTime = GetTime()+GetArg("-bantime", 60*60*24);  // Default 24-hour ban
 +        CRITICAL_BLOCK(cs_setBanned)
 +            if (setBanned[addr.ip] < banTime)
 +                setBanned[addr.ip] = banTime;
 +        CloseSocketDisconnect();
 +        printf("Disconnected %s for misbehavior (score=%d)\n", addr.ToString().c_str(), nMisbehavior);
 +        return true;
 +    }
 +    return false;
 +}
 +
  
  
  
@@@ -943,11 -901,6 +947,11 @@@ void ThreadSocketHandler2(void* parg
              {
                  closesocket(hSocket);
              }
 +            else if (CNode::IsBanned(addr.ip))
 +            {
 +                printf("connetion from %s dropped (banned)\n", addr.ToString().c_str());
 +                closesocket(hSocket);
 +            }
              else
              {
                  printf("accepted connection %s\n", addr.ToString().c_str());
@@@ -1256,13 -1209,13 +1260,13 @@@ void ThreadDNSAddressSeed2(void* parg
      if (!fTestNet)
      {
          printf("Loading addresses from DNS seeds (could take a while)\n");
-         CAddrDB addrDB;
-         addrDB.TxnBegin();
  
          for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
              vector<CAddress> vaddr;
              if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, -1, true))
              {
+                 CAddrDB addrDB;
+                 addrDB.TxnBegin();
                  BOOST_FOREACH (CAddress& addr, vaddr)
                  {
                      if (addr.GetByte(3) != 127)
                          found++;
                      }
                  }
+                 addrDB.TxnCommit();  // Save addresses (it's ok if this fails)
              }
          }
-         addrDB.TxnCommit();  // Save addresses (it's ok if this fails)
      }
  
      printf("%d addresses found from DNS seeds\n", found);
@@@ -1447,28 -1399,32 +1450,32 @@@ void ThreadOpenConnections2(void* parg
          if (fShutdown)
              return;
  
+         bool fAddSeeds = false;
          CRITICAL_BLOCK(cs_mapAddresses)
          {
              // Add seed nodes if IRC isn't working
              bool fTOR = (fUseProxy && addrProxy.port == htons(9050));
-             if (mapAddresses.empty() && (GetTime() - nStart > 60 || fTOR) && !fTestNet)
+             if (mapAddresses.empty() && (GetTime() - nStart > 60 || fUseProxy) && !fTestNet)
+                 fAddSeeds = true;
+         }
+         if (fAddSeeds)
+         {
+             for (int i = 0; i < ARRAYLEN(pnSeed); i++)
              {
-                 for (int i = 0; i < ARRAYLEN(pnSeed); i++)
-                 {
-                     // It'll only connect to one or two seed nodes because once it connects,
-                     // it'll get a pile of addresses with newer timestamps.
-                     // Seed nodes are given a random 'last seen time' of between one and two
-                     // weeks ago.
-                     const int64 nOneWeek = 7*24*60*60;
-                     CAddress addr;
-                     addr.ip = pnSeed[i];
-                     addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
-                     AddAddress(addr);
-                 }
+                 // It'll only connect to one or two seed nodes because once it connects,
+                 // it'll get a pile of addresses with newer timestamps.
+                 // Seed nodes are given a random 'last seen time' of between one and two
+                 // weeks ago.
+                 const int64 nOneWeek = 7*24*60*60;
+                 CAddress addr;
+                 addr.ip = pnSeed[i];
+                 addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
+                 AddAddress(addr);
              }
          }
  
          //
          // Choose an address to connect to based on most recently seen
          //
              BOOST_FOREACH(CNode* pnode, vNodes)
                  setConnected.insert(pnode->addr.ip & 0x0000ffff);
  
 +        int64 nANow = GetAdjustedTime();
 +
          CRITICAL_BLOCK(cs_mapAddresses)
          {
              BOOST_FOREACH(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
                  const CAddress& addr = item.second;
                  if (!addr.IsIPv4() || !addr.IsValid() || setConnected.count(addr.ip & 0x0000ffff))
                      continue;
 -                int64 nSinceLastSeen = GetAdjustedTime() - addr.nTime;
 -                int64 nSinceLastTry = GetAdjustedTime() - addr.nLastTry;
 +                int64 nSinceLastSeen = nANow - addr.nTime;
 +                int64 nSinceLastTry = nANow - addr.nLastTry;
  
                  // Randomize the order in a deterministic way, putting the standard port first
                  int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60);
@@@ -1551,8 -1505,7 +1558,8 @@@ bool OpenNetworkConnection(const CAddre
      //
      if (fShutdown)
          return false;
 -    if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() || FindNode(addrConnect.ip))
 +    if (addrConnect.ip == addrLocalHost.ip || !addrConnect.IsIPv4() ||
 +        FindNode(addrConnect.ip) || CNode::IsBanned(addrConnect.ip))
          return false;
  
      vnThreadsRunning[1]--;
@@@ -1656,7 -1609,7 +1663,7 @@@ bool BindListenPort(string& strError
      int nOne = 1;
      addrLocalHost.port = htons(GetListenPort());
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Initialize Windows Sockets
      WSADATA wsadata;
      int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
      setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
  #endif
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
      // Allow binding if the port is still in TIME_WAIT state after
      // the program was closed and restarted.  Not an issue on windows.
      setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
  #endif
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Set to nonblocking, incoming connections will also inherit this
      if (ioctlsocket(hListenSocket, FIONBIO, (u_long*)&nOne) == SOCKET_ERROR)
  #else
@@@ -1735,7 -1688,7 +1742,7 @@@ void StartNode(void* parg
      if (pnodeLocalHost == NULL)
          pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices));
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Get local host ip
      char pszHostName[1000] = "";
      if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR)
@@@ -1878,7 -1831,7 +1885,7 @@@ public
              if (closesocket(hListenSocket) == SOCKET_ERROR)
                  printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
          // Shutdown Windows Sockets
          WSACleanup();
  #endif
diff --combined src/util.cpp
@@@ -64,7 -64,7 +64,7 @@@ public
              ppmutexOpenSSL[i] = new boost::interprocess::interprocess_mutex();
          CRYPTO_set_locking_callback(locking_callback);
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
          // Seed random number generator with screen scrape and other hardware sources
          RAND_screen();
  #endif
@@@ -108,7 -108,7 +108,7 @@@ void RandAddSeedPerfmon(
          return;
      nLastPerfmon = GetTime();
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
      // Seed with the entire set of perfmon data
      unsigned char pdata[250000];
@@@ -198,7 -198,7 +198,7 @@@ inline int OutputDebugStringF(const cha
          }
      }
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
      if (fPrintToDebugger)
      {
          static CCriticalSection cs_OutputDebugStringF;
@@@ -264,7 -264,8 +264,7 @@@ int my_snprintf(char* buffer, size_t li
      return ret;
  }
  
 -
 -string strprintf(const char* format, ...)
 +string strprintf(const std::string &format, ...)
  {
      char buffer[50000];
      char* p = buffer;
      {
          va_list arg_ptr;
          va_start(arg_ptr, format);
 -        ret = _vsnprintf(p, limit, format, arg_ptr);
 +        ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
          va_end(arg_ptr);
          if (ret >= 0 && ret < limit)
              break;
      return str;
  }
  
 -
 -bool error(const char* format, ...)
 +bool error(const std::string &format, ...)
  {
      char buffer[50000];
      int limit = sizeof(buffer);
      va_list arg_ptr;
      va_start(arg_ptr, format);
 -    int ret = _vsnprintf(buffer, limit, format, arg_ptr);
 +    int ret = _vsnprintf(buffer, limit, format.c_str(), arg_ptr);
      va_end(arg_ptr);
      if (ret < 0 || ret >= limit)
      {
@@@ -443,6 -445,7 +443,6 @@@ vector<unsigned char> ParseHex(const st
      return ParseHex(str.c_str());
  }
  
 -
  void ParseParameters(int argc, char* argv[])
  {
      mapArgs.clear();
              pszValue = strchr(psz, '=');
              *pszValue++ = '\0';
          }
 -        #ifdef __WXMSW__
 +        #ifdef WIN32
          _strlwr(psz);
          if (psz[0] == '/')
              psz[0] = '-';
      }
  }
  
+ bool SoftSetArg(const std::string& strArg, const std::string& strValue)
+ {
+     if (mapArgs.count(strArg))
+         return false;
+     mapArgs[strArg] = strValue;
+     return true;
+ }
+ bool SoftSetArg(const std::string& strArg, bool fValue)
+ {
+     if (fValue)
+         return SoftSetArg(strArg, std::string("1"));
+     else
+         return SoftSetArg(strArg, std::string("0"));
+ }
 +string EncodeBase64(const unsigned char* pch, size_t len)
 +{
 +    static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 +
 +    string strRet="";
 +    strRet.reserve((len+2)/3*4);
 +
 +    int mode=0, left=0;
 +    const unsigned char *pchEnd = pch+len;
  
 -const char* wxGetTranslation(const char* pszEnglish)
 +    while (pch<pchEnd)
 +    {
 +        int enc = *(pch++);
 +        switch (mode)
 +        {
 +            case 0: // we have no bits
 +                strRet += pbase64[enc >> 2];
 +                left = (enc & 3) << 4;
 +                mode = 1;
 +                break;
 +
 +            case 1: // we have two bits
 +                strRet += pbase64[left | (enc >> 4)];
 +                left = (enc & 15) << 2;
 +                mode = 2;
 +                break;
 +
 +            case 2: // we have four bits
 +                strRet += pbase64[left | (enc >> 6)];
 +                strRet += pbase64[enc & 63];
 +                mode = 0;
 +                break;
 +        }
 +    }
 +
 +    if (mode)
 +    {
 +        strRet += pbase64[left];
 +        strRet += '=';
 +        if (mode == 1)
 +            strRet += '=';
 +    }
 +
 +    return strRet;
 +}
 +
 +string EncodeBase64(const string& str)
  {
 -#ifdef GUI
 -    // Wrapper of wxGetTranslation returning the same const char* type as was passed in
 -    static CCriticalSection cs;
 -    CRITICAL_BLOCK(cs)
 +    return EncodeBase64((const unsigned char*)str.c_str(), str.size());
 +}
 +
 +vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
 +{
 +    static const int decode64_table[256] =
 +    {
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
 +        -1, -1, -1, -1, -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
 +        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
 +        29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
 +        49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 +        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
 +    };
 +
 +    if (pfInvalid)
 +        *pfInvalid = false;
 +
 +    vector<unsigned char> vchRet;
 +    vchRet.reserve(strlen(p)*3/4);
 +
 +    int mode = 0;
 +    int left = 0;
 +
 +    while (1)
      {
 -        // Look in cache
 -        static map<string, char*> mapCache;
 -        map<string, char*>::iterator mi = mapCache.find(pszEnglish);
 -        if (mi != mapCache.end())
 -            return (*mi).second;
 -
 -        // wxWidgets translation
 -        wxString strTranslated = wxGetTranslation(wxString(pszEnglish, wxConvUTF8));
 -
 -        // We don't cache unknown strings because caller might be passing in a
 -        // dynamic string and we would keep allocating memory for each variation.
 -        if (strcmp(pszEnglish, strTranslated.utf8_str()) == 0)
 -            return pszEnglish;
 -
 -        // Add to cache, memory doesn't need to be freed.  We only cache because
 -        // we must pass back a pointer to permanently allocated memory.
 -        char* pszCached = new char[strlen(strTranslated.utf8_str())+1];
 -        strcpy(pszCached, strTranslated.utf8_str());
 -        mapCache[pszEnglish] = pszCached;
 -        return pszCached;
 +         int dec = decode64_table[*p];
 +         if (dec == -1) break;
 +         p++;
 +         switch (mode)
 +         {
 +             case 0: // we have no bits and get 6
 +                 left = dec;
 +                 mode = 1;
 +                 break;
 +
 +              case 1: // we have 6 bits and keep 4
 +                  vchRet.push_back((left<<2) | (dec>>4));
 +                  left = dec & 15;
 +                  mode = 2;
 +                  break;
 +
 +             case 2: // we have 4 bits and get 6, we keep 2
 +                 vchRet.push_back((left<<4) | (dec>>2));
 +                 left = dec & 3;
 +                 mode = 3;
 +                 break;
 +
 +             case 3: // we have 2 bits and get 6
 +                 vchRet.push_back((left<<6) | dec);
 +                 mode = 0;
 +                 break;
 +         }
      }
 -    return NULL;
 -#else
 -    return pszEnglish;
 -#endif
 +
 +    if (pfInvalid)
 +        switch (mode)
 +        {
 +            case 0: // 4n base64 characters processed: ok
 +                break;
 +
 +            case 1: // 4n+1 base64 character processed: impossible
 +                *pfInvalid = true;
 +                break;
 +
 +            case 2: // 4n+2 base64 characters processed: require '=='
 +                if (left || p[0] != '=' || p[1] != '=' || decode64_table[p[2]] != -1)
 +                    *pfInvalid = true;
 +                break;
 +
 +            case 3: // 4n+3 base64 characters processed: require '='
 +                if (left || p[0] != '=' || decode64_table[p[1]] != -1)
 +                    *pfInvalid = true;
 +                break;
 +        }
 +
 +    return vchRet;
 +}
 +
 +string DecodeBase64(const string& str)
 +{
 +    vector<unsigned char> vchRet = DecodeBase64(str.c_str());
 +    return string((const char*)&vchRet[0], vchRet.size());
  }
  
  
@@@ -648,7 -563,7 +665,7 @@@ bool WildcardMatch(const string& str, c
  
  void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
  {
 -#ifdef __WXMSW__
 +#ifdef WIN32
      char pszModule[MAX_PATH];
      pszModule[0] = '\0';
      GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
@@@ -677,6 -592,10 +694,6 @@@ void PrintException(std::exception* pex
      printf("\n\n************************\n%s\n", pszMessage);
      fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
      strMiscWarning = pszMessage;
 -#ifdef GUI
 -    if (wxTheApp && !fDaemon)
 -        MyMessageBox(pszMessage, "Bitcoin", wxOK | wxICON_ERROR);
 -#endif
      throw;
  }
  
@@@ -698,6 -617,10 +715,6 @@@ void PrintExceptionContinue(std::except
      printf("\n\n************************\n%s\n", pszMessage);
      fprintf(stderr, "\n\n************************\n%s\n", pszMessage);
      strMiscWarning = pszMessage;
 -#ifdef GUI
 -    if (wxTheApp && !fDaemon)
 -        boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage)));
 -#endif
  }
  
  
  
  
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
  typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
  
  string MyGetSpecialFolderPath(int nFolder, bool fCreate)
@@@ -748,7 -671,7 +765,7 @@@ string GetDefaultDataDir(
      // Windows: C:\Documents and Settings\username\Application Data\Bitcoin
      // Mac: ~/Library/Application Support/Bitcoin
      // Unix: ~/.bitcoin
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Windows
      return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin";
  #else
      string strHome = pszHome;
      if (strHome[strHome.size()-1] != '/')
          strHome += '/';
 -#ifdef __WXMAC_OSX__
 +#ifdef MAC_OSX
      // Mac
      strHome += "Library/Application Support/";
      filesystem::create_directory(strHome.c_str());
@@@ -909,20 -832,11 +926,20 @@@ void ShrinkDebugFile(
  //  - Median of other nodes's clocks
  //  - The user (asking the user to fix the system clock if the first two disagree)
  //
 +static int64 nMockTime = 0;  // For unit testing
 +
  int64 GetTime()
  {
 +    if (nMockTime) return nMockTime;
 +
      return time(NULL);
  }
  
 +void SetMockTime(int64 nMockTimeIn)
 +{
 +    nMockTime = nMockTimeIn;
 +}
 +
  static int64 nTimeOffset = 0;
  
  int64 GetAdjustedTime()
diff --combined src/util.h
@@@ -7,7 -7,7 +7,7 @@@
  
  #include "uint256.h"
  
 -#ifndef __WXMSW__
 +#ifndef WIN32
  #include <sys/types.h>
  #include <sys/time.h>
  #include <sys/resource.h>
@@@ -65,7 -65,7 +65,7 @@@ typedef unsigned long long  uint64
  #endif
  
  // This is needed because the foreach macro can't get over the comma in pair<t1, t2>
 -#define PAIRTYPE(t1, t2)    pair<t1, t2>
 +#define PAIRTYPE(t1, t2)    std::pair<t1, t2>
  
  // Align by increasing pointer, must have extra space at end of buffer
  template <size_t nBytes, typename T>
@@@ -81,7 -81,7 +81,7 @@@ T* alignup(T* p
      return u.ptr;
  }
  
 -#ifdef __WXMSW__
 +#ifdef WIN32
  #define MSG_NOSIGNAL        0
  #define MSG_DONTWAIT        0
  #ifndef UINT64_MAX
@@@ -123,7 -123,7 +123,7 @@@ inline int myclosesocket(SOCKET& hSocke
  {
      if (hSocket == INVALID_SOCKET)
          return WSAENOTSOCK;
 -#ifdef __WXMSW__
 +#ifdef WIN32
      int ret = closesocket(hSocket);
  #else
      int ret = close(hSocket);
      return ret;
  }
  #define closesocket(s)      myclosesocket(s)
 -
 -#ifndef GUI
 +#if !defined(QT_GUI)
  inline const char* _(const char* psz)
  {
      return psz;
  
  
  
 -
  extern std::map<std::string, std::string> mapArgs;
  extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
  extern bool fDebug;
@@@ -167,8 -169,8 +167,8 @@@ void RandAddSeed()
  void RandAddSeedPerfmon();
  int OutputDebugStringF(const char* pszFormat, ...);
  int my_snprintf(char* buffer, size_t limit, const char* format, ...);
 -std::string strprintf(const char* format, ...);
 -bool error(const char* format, ...);
 +std::string strprintf(const std::string &format, ...);
 +bool error(const std::string &format, ...);
  void LogException(std::exception* pex, const char* pszThread);
  void PrintException(std::exception* pex, const char* pszThread);
  void PrintExceptionContinue(std::exception* pex, const char* pszThread);
@@@ -178,10 -180,6 +178,10 @@@ bool ParseMoney(const std::string& str
  bool ParseMoney(const char* pszIn, int64& nRet);
  std::vector<unsigned char> ParseHex(const char* psz);
  std::vector<unsigned char> ParseHex(const std::string& str);
 +std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
 +std::string DecodeBase64(const std::string& str);
 +std::string EncodeBase64(const unsigned char* pch, size_t len);
 +std::string EncodeBase64(const std::string& str);
  void ParseParameters(int argc, char* argv[]);
  const char* wxGetTranslation(const char* psz);
  bool WildcardMatch(const char* psz, const char* mask);
@@@ -192,7 -190,7 +192,7 @@@ std::string GetConfigFile()
  std::string GetPidFile();
  void CreatePidFile(std::string pidFile, pid_t pid);
  void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
 -#ifdef __WXMSW__
 +#ifdef WIN32
  std::string MyGetSpecialFolderPath(int nFolder, bool fCreate);
  #endif
  std::string GetDefaultDataDir();
@@@ -201,7 -199,6 +201,7 @@@ void ShrinkDebugFile()
  int GetRandInt(int nMax);
  uint64 GetRand(uint64 nMax);
  int64 GetTime();
 +void SetMockTime(int64 nMockTimeIn);
  int64 GetAdjustedTime();
  void AddTimeData(unsigned int ip, int64 nTime);
  std::string FormatFullVersion();
@@@ -286,10 -283,6 +286,10 @@@ public
  
  
  
 +// This is exactly like std::string, but with a custom allocator.
 +// (secure_allocator<> is defined in serialize.h)
 +typedef std::basic_string<char, std::char_traits<char>, secure_allocator<char> > SecureString;
 +
  
  
  
@@@ -394,7 -387,7 +394,7 @@@ inline void PrintHex(const std::vector<
  inline int64 GetPerformanceCounter()
  {
      int64 nCounter = 0;
 -#ifdef __WXMSW__
 +#ifdef WIN32
      QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
  #else
      timeval t;
@@@ -428,7 -421,7 +428,7 @@@ void skipspaces(T& it
  
  inline bool IsSwitchChar(char c)
  {
 -#ifdef __WXMSW__
 +#ifdef WIN32
      return c == '-' || c == '/';
  #else
      return c == '-';
@@@ -449,7 -442,7 +449,7 @@@ inline int64 GetArg(const std::string& 
      return nDefault;
  }
  
- inline bool GetBoolArg(const std::string& strArg)
+ inline bool GetBoolArg(const std::string& strArg, bool fDefault=false)
  {
      if (mapArgs.count(strArg))
      {
              return true;
          return (atoi(mapArgs[strArg]) != 0);
      }
-     return false;
+     return fDefault;
  }
  
+ /**
+  * Set an argument if it doesn't already have a value
+  *
+  * @param strArg Argument to set (e.g. "-foo")
+  * @param strValue Value (e.g. "1")
+  * @return true if argument gets set, false if it already had a value
+  */
+ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
+ /**
+  * Set a boolean argument if it doesn't already have a value
+  *
+  * @param strArg Argument to set (e.g. "-foo")
+  * @param fValue Value (e.g. false)
+  * @return true if argument gets set, false if it already had a value
+  */
+ bool SoftSetArg(const std::string& strArg, bool fValue);
  
  
  
  
  inline void heapchk()
  {
 -#ifdef __WXMSW__
 +#ifdef WIN32
      /// for debugging
      //if (_heapchk() != _HEAPOK)
      //    DebugBreak();
@@@ -574,51 -584,6 +591,51 @@@ inline uint160 Hash160(const std::vecto
  }
  
  
 +// Median filter over a stream of values
 +// Returns the median of the last N numbers
 +template <typename T> class CMedianFilter
 +{
 +private:
 +    std::vector<T> vValues;
 +    std::vector<T> vSorted;
 +    int nSize;
 +public:
 +    CMedianFilter(int size, T initial_value):
 +        nSize(size)
 +    {
 +        vValues.reserve(size);
 +        vValues.push_back(initial_value);
 +        vSorted = vValues;
 +    }
 +    
 +    void input(T value)
 +    {
 +        if(vValues.size() == nSize)
 +        {
 +            vValues.erase(vValues.begin());
 +        }
 +        vValues.push_back(value);
 +
 +        vSorted.resize(vValues.size());
 +        std::copy(vValues.begin(), vValues.end(), vSorted.begin());
 +        std::sort(vSorted.begin(), vSorted.end());
 +    }
 +
 +    T median() const
 +    {
 +        int size = vSorted.size();
 +        assert(size>0);
 +        if(size & 1) // Odd number of elements
 +        {
 +            return vSorted[size/2];
 +        }
 +        else // Even number of elements
 +        {
 +            return (vSorted[size/2-1] + vSorted[size/2]) / 2;
 +        }
 +    }
 +};
 +
  
  
  
  
  // Note: It turns out we might have been able to use boost::thread
  // by using TerminateThread(boost::thread.native_handle(), 0);
 -#ifdef __WXMSW__
 +#ifdef WIN32
  typedef HANDLE pthread_t;
  
  inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false)
@@@ -712,7 -677,7 +729,7 @@@ inline void ExitThread(size_t nExitCode
  
  inline bool AffinityBugWorkaround(void(*pfn)(void*))
  {
 -#ifdef __WXMSW__
 +#ifdef WIN32
      // Sometimes after a few hours affinity gets stuck on one processor
      DWORD_PTR dwProcessAffinityMask = -1;
      DWORD_PTR dwSystemAffinityMask = -1;
      return false;
  }
  
 +inline uint32_t ByteReverse(uint32_t value)
 +{
 +      value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
 +      return (value<<16) | (value>>16);
 +}
 +
  #endif