add LOCK() for proxy related data-structures

- fix #1560 by properly locking proxy related data-structures
- update GetProxy() and introduce GetNameProxy() to be able to use a
  thread-safe local copy from proxyInfo and nameproxyInfo
- update usage of GetProxy() all over the source to match the new
  behaviour, as it now fills a full proxyType object
- rename GetNameProxy() into HaveNameProxy() to be more clear
This commit is contained in:
Philip Kaufmann 2012-09-23 12:55:05 +02:00
parent 0547b02af7
commit 81bbef2609
5 changed files with 77 additions and 49 deletions

View File

@ -1185,7 +1185,7 @@ void ThreadDNSAddressSeed2(void* parg)
printf("Loading addresses from DNS seeds (could take a while)\n"); printf("Loading addresses from DNS seeds (could take a while)\n");
for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) {
if (GetNameProxy()) { if (HaveNameProxy()) {
AddOneShot(strDNSSeed[seed_idx][1]); AddOneShot(strDNSSeed[seed_idx][1]);
} else { } else {
vector<CNetAddr> vaddr; vector<CNetAddr> vaddr;
@ -1529,7 +1529,7 @@ void ThreadOpenAddedConnections2(void* parg)
if (mapArgs.count("-addnode") == 0) if (mapArgs.count("-addnode") == 0)
return; return;
if (GetNameProxy()) { if (HaveNameProxy()) {
while(!fShutdown) { while(!fShutdown) {
BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) { BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) {
CAddress addr; CAddress addr;

View File

@ -5,6 +5,7 @@
#include "netbase.h" #include "netbase.h"
#include "util.h" #include "util.h"
#include "sync.h"
#ifndef WIN32 #ifndef WIN32
#include <sys/fcntl.h> #include <sys/fcntl.h>
@ -16,9 +17,9 @@
using namespace std; using namespace std;
// Settings // Settings
typedef std::pair<CService, int> proxyType;
static proxyType proxyInfo[NET_MAX]; static proxyType proxyInfo[NET_MAX];
static proxyType nameproxyInfo; static proxyType nameproxyInfo;
static CCriticalSection cs_proxyInfos;
int nConnectTimeout = 5000; int nConnectTimeout = 5000;
bool fNameLookup = false; bool fNameLookup = false;
@ -432,15 +433,17 @@ bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion) {
return false; return false;
if (nSocksVersion != 0 && !addrProxy.IsValid()) if (nSocksVersion != 0 && !addrProxy.IsValid())
return false; return false;
LOCK(cs_proxyInfos);
proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion); proxyInfo[net] = std::make_pair(addrProxy, nSocksVersion);
return true; return true;
} }
bool GetProxy(enum Network net, CService &addrProxy) { bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
assert(net >= 0 && net < NET_MAX); assert(net >= 0 && net < NET_MAX);
LOCK(cs_proxyInfos);
if (!proxyInfo[net].second) if (!proxyInfo[net].second)
return false; return false;
addrProxy = proxyInfo[net].first; proxyInfoOut = proxyInfo[net];
return true; return true;
} }
@ -449,15 +452,26 @@ bool SetNameProxy(CService addrProxy, int nSocksVersion) {
return false; return false;
if (nSocksVersion != 0 && !addrProxy.IsValid()) if (nSocksVersion != 0 && !addrProxy.IsValid())
return false; return false;
LOCK(cs_proxyInfos);
nameproxyInfo = std::make_pair(addrProxy, nSocksVersion); nameproxyInfo = std::make_pair(addrProxy, nSocksVersion);
return true; return true;
} }
bool GetNameProxy() { bool GetNameProxy(proxyType &nameproxyInfoOut) {
LOCK(cs_proxyInfos);
if (!nameproxyInfo.second)
return false;
nameproxyInfoOut = nameproxyInfo;
return true;
}
bool HaveNameProxy() {
LOCK(cs_proxyInfos);
return nameproxyInfo.second != 0; return nameproxyInfo.second != 0;
} }
bool IsProxy(const CNetAddr &addr) { bool IsProxy(const CNetAddr &addr) {
LOCK(cs_proxyInfos);
for (int i = 0; i < NET_MAX; i++) { for (int i = 0; i < NET_MAX; i++) {
if (proxyInfo[i].second && (addr == (CNetAddr)proxyInfo[i].first)) if (proxyInfo[i].second && (addr == (CNetAddr)proxyInfo[i].first))
return true; return true;
@ -467,10 +481,10 @@ bool IsProxy(const CNetAddr &addr) {
bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout) bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
{ {
const proxyType &proxy = proxyInfo[addrDest.GetNetwork()]; proxyType proxy;
// no proxy needed // no proxy needed
if (!proxy.second) if (!GetProxy(addrDest.GetNetwork(), proxy))
return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout); return ConnectSocketDirectly(addrDest, hSocketRet, nTimeout);
SOCKET hSocket = INVALID_SOCKET; SOCKET hSocket = INVALID_SOCKET;
@ -504,19 +518,22 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
SplitHostPort(string(pszDest), port, strDest); SplitHostPort(string(pszDest), port, strDest);
SOCKET hSocket = INVALID_SOCKET; SOCKET hSocket = INVALID_SOCKET;
CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port);
proxyType nameproxy;
GetNameProxy(nameproxy);
CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxy.second), port);
if (addrResolved.IsValid()) { if (addrResolved.IsValid()) {
addr = addrResolved; addr = addrResolved;
return ConnectSocket(addr, hSocketRet, nTimeout); return ConnectSocket(addr, hSocketRet, nTimeout);
} }
addr = CService("0.0.0.0:0"); addr = CService("0.0.0.0:0");
if (!nameproxyInfo.second) if (!nameproxy.second)
return false; return false;
if (!ConnectSocketDirectly(nameproxyInfo.first, hSocket, nTimeout)) if (!ConnectSocketDirectly(nameproxy.first, hSocket, nTimeout))
return false; return false;
switch(nameproxyInfo.second) switch(nameproxy.second) {
{
default: default:
case 4: return false; case 4: return false;
case 5: case 5:

View File

@ -133,13 +133,15 @@ class CService : public CNetAddr
) )
}; };
typedef std::pair<CService, int> proxyType;
enum Network ParseNetwork(std::string net); enum Network ParseNetwork(std::string net);
void SplitHostPort(std::string in, int &portOut, std::string &hostOut); void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5); bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5);
bool GetProxy(enum Network net, CService &addrProxy); bool GetProxy(enum Network net, proxyType &proxyInfoOut);
bool IsProxy(const CNetAddr &addr); bool IsProxy(const CNetAddr &addr);
bool SetNameProxy(CService addrProxy, int nSocksVersion = 5); bool SetNameProxy(CService addrProxy, int nSocksVersion = 5);
bool GetNameProxy(); bool HaveNameProxy();
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true);
bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0); bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0);
bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true);

View File

@ -145,18 +145,18 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
case ProxyUse: case ProxyUse:
return settings.value("fUseProxy", false); return settings.value("fUseProxy", false);
case ProxyIP: { case ProxyIP: {
CService addrProxy; proxyType proxy;
if (GetProxy(NET_IPV4, addrProxy)) if (GetProxy(NET_IPV4, proxy))
return QVariant(QString::fromStdString(addrProxy.ToStringIP())); return QVariant(QString::fromStdString(proxy.first.ToStringIP()));
else else
return QVariant(QString::fromStdString("127.0.0.1")); return QVariant(QString::fromStdString("127.0.0.1"));
} }
case ProxyPort: { case ProxyPort: {
CService addrProxy; proxyType proxy;
if (GetProxy(NET_IPV4, addrProxy)) if (GetProxy(NET_IPV4, proxy))
return QVariant(addrProxy.GetPort()); return QVariant(proxy.first.GetPort());
else else
return 9050; return QVariant(9050);
} }
case ProxySocksVersion: case ProxySocksVersion:
return settings.value("nSocksVersion", 5); return settings.value("nSocksVersion", 5);
@ -176,6 +176,7 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
} }
return QVariant(); return QVariant();
} }
bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role) bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
{ {
bool successful = true; /* set to false on parse error */ bool successful = true; /* set to false on parse error */
@ -204,28 +205,36 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
settings.setValue("fUseProxy", value.toBool()); settings.setValue("fUseProxy", value.toBool());
ApplyProxySettings(); ApplyProxySettings();
break; break;
case ProxyIP: case ProxyIP: {
{ proxyType proxy;
CService addrProxy("127.0.0.1", 9050); proxy.first = CService("127.0.0.1", 9050);
GetProxy(NET_IPV4, addrProxy); GetProxy(NET_IPV4, proxy);
CNetAddr addr(value.toString().toStdString()); CNetAddr addr(value.toString().toStdString());
addrProxy.SetIP(addr); proxy.first.SetIP(addr);
settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str()); settings.setValue("addrProxy", proxy.first.ToStringIPPort().c_str());
successful = ApplyProxySettings(); successful = ApplyProxySettings();
} }
break; break;
case ProxyPort: case ProxyPort: {
{ proxyType proxy;
CService addrProxy("127.0.0.1", 9050); proxy.first = CService("127.0.0.1", 9050);
GetProxy(NET_IPV4, addrProxy); GetProxy(NET_IPV4, proxy);
addrProxy.SetPort(value.toInt());
settings.setValue("addrProxy", addrProxy.ToStringIPPort().c_str()); proxy.first.SetPort(value.toInt());
settings.setValue("addrProxy", proxy.first.ToStringIPPort().c_str());
successful = ApplyProxySettings(); successful = ApplyProxySettings();
} }
break; break;
case ProxySocksVersion: case ProxySocksVersion: {
settings.setValue("nSocksVersion", value.toInt()); proxyType proxy;
ApplyProxySettings(); proxy.second = 5;
GetProxy(NET_IPV4, proxy);
proxy.second = value.toInt();
settings.setValue("nSocksVersion", proxy.second);
successful = ApplyProxySettings();
}
break; break;
case Fee: case Fee:
nTransactionFee = value.toLongLong(); nTransactionFee = value.toLongLong();

View File

@ -62,8 +62,8 @@ Value getinfo(const Array& params, bool fHelp)
"getinfo\n" "getinfo\n"
"Returns an object containing various state info."); "Returns an object containing various state info.");
CService addrProxy; proxyType proxy;
GetProxy(NET_IPV4, addrProxy); GetProxy(NET_IPV4, proxy);
Object obj; Object obj;
obj.push_back(Pair("version", (int)CLIENT_VERSION)); obj.push_back(Pair("version", (int)CLIENT_VERSION));
@ -72,7 +72,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("blocks", (int)nBestHeight)); obj.push_back(Pair("blocks", (int)nBestHeight));
obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (addrProxy.IsValid() ? addrProxy.ToStringIPPort() : string()))); obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", fTestNet)); obj.push_back(Pair("testnet", fTestNet));
obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime()));