Merge branch 'master' into async-ipv6-rpc

This commit is contained in:
Giel van Schijndel 2012-06-24 12:34:15 +02:00
commit 415a87ef36
37 changed files with 898 additions and 205 deletions

96
doc/Tor.txt Normal file
View File

@ -0,0 +1,96 @@
TOR SUPPORT IN BITCOIN
======================
It is possible to run Bitcoin as a Tor hidden service, and connect to such services.
The following assumes you have a Tor proxy running on port 9050. Many distributions
default to having a SOCKS proxy listening on port 9050, but others may not.
In particular, the Tor Browser Bundle defaults to listening on a random port. See
https://www.torproject.org/docs/faq.html.en#TBBSocksPort for how to properly
configure Tor.
1. Run bitcoin behind a Tor proxy
---------------------------------
The first step is running Bitcoin behind a Tor proxy. This will already make all
outgoing connections be anonimized, but more is possible.
-socks=5 SOCKS5 supports connecting-to-hostname, which can be used instead
of doing a (leaking) local DNS lookup. SOCKS5 is the default,
but SOCKS4 does not support this. (SOCKS4a does, but isn't
implemented).
-proxy=ip:port Set the proxy server. If SOCKS5 is selected (default), this proxy
server will be used to try to reach .onion addresses as well.
-tor=ip:port Set the proxy server to use for tor hidden services. You do not
need to set this if it's the same as -proxy. You can use -notor
to explicitly disable access to hidden service.
-dnsseed DNS seeds are not resolved directly when a SOCKS5 proxy server is
set. Rather, a short-lived proxy connection to the dns seed
hostname is attempted, and peer addresses are requested.
-listen When using -proxy, listening is disabled by default. If you want
to run a hidden service (see next section), you'll need to enable
it explicitly.
-connect=X When behing a Tor proxy, you can specify .onion addresses instead
-addnode=X of IP addresses or hostnames in these parameters. It requires
-seednode=X SOCKS5. In Tor mode, such addresses can also be exchanged with
other P2P nodes.
In a typical situation, this suffices to run behind a Tor proxy:
./bitcoin -proxy=127.0.0.1:9050
2. Run a bitcoin hidden server
------------------------------
If you configure your Tor system accordingly, it is possible to make your node also
reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equivalent
config file):
HiddenServiceDir /var/lib/tor/bitcoin-service/
HiddenServicePort 8333 127.0.0.1:8333
The directory can be different of course, but (both) 8333's should be equal to your
bitcoind's P2P listen port (8333 by default).
-externalip=X You can tell bitcoin about its publically reachable address using
this option, and this can be a .onion address. Given the above
configuration, you can find your onion address in
/var/lib/tor/bitcoin-service/hostname. Onion addresses are given
preference for your node to advertize itself with, for connections
coming from unroutable addresses (such as 127.0.0.1, where the
Tor proxy typically runs).
-listen You'll need to enable listening for incoming connections, as this
is off by default behind a proxy.
-discover When -externalip is specified, no attempt is made to discover local
IPv4 or IPv6 addresses. If you want to run a dual stack, reachable
from both Tor and IPv4 (or IPv6), you'll need to either pass your
other addresses using -externalip, or explicitly enable -discover.
Note that both addresses of a dual-stack system may be easily
linkable using traffic analysis.
In a typical situation, where you're only reachable via Tor, this should suffice:
./bitcoind -proxy=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -listen
(obviously replace the Onion address with your own). If you don't care too much
about hiding your node, and want to be reachable on IPv4 as well, additionally
specify:
./bitcoind ... -discover
and open port 8333 on your firewall (or use -upnp).
If you only want to use Tor to reach onion addresses, but not use it as a proxy
for normal IPv4/IPv6 communication, use:
./bitcoin -tor=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -discover

View File

@ -7,7 +7,7 @@ cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP
software written by Thomas Bernard. software written by Thomas Bernard.
See readme-qt.rst for instructions on building Bitcoin QT, the See readme-qt.rst for instructions on building Bitcoin-Qt, the
graphical user interface. graphical user interface.
WINDOWS BUILD NOTES WINDOWS BUILD NOTES

View File

@ -1,10 +1,10 @@
Copyright (c) 2009-2012 Bitcoin Developers Copyright (c) 2009-2012 Bitcoin Developers
Distributed under the MIT/X11 software license, see the accompanying file Distributed under the MIT/X11 software license, see the accompanying
license.txt or http://www.opensource.org/licenses/mit-license.php. This file license.txt or http://www.opensource.org/licenses/mit-license.php.
product includes software developed by the OpenSSL Project for use in the This product includes software developed by the OpenSSL Project for use in
OpenSSL Toolkit (http://www.openssl.org/). This product includes cryptographic the OpenSSL Toolkit (http://www.openssl.org/). This product includes
software written by Eric Young (eay@cryptsoft.com) and UPnP software written by cryptographic software written by Eric Young (eay@cryptsoft.com) and UPnP
Thomas Bernard. software written by Thomas Bernard.
Mac OS X bitcoind build instructions Mac OS X bitcoind build instructions
@ -12,17 +12,17 @@ Laszlo Hanyecz <solar@heliacal.net>
Douglas Huff <dhuff@jrbobdobbs.org> Douglas Huff <dhuff@jrbobdobbs.org>
See readme-qt.rst for instructions on building Bitcoin QT, the See readme-qt.rst for instructions on building Bitcoin-Qt, the
graphical user interface. graphical user interface.
Tested on 10.5 and 10.6 intel. PPC is not supported because it's big-endian. Tested on 10.5, 10.6 and 10.7 intel. PPC is not supported because it's big-endian.
All of the commands should be executed in Terminal.app.. it's in All of the commands should be executed in Terminal.app.. it's in
/Applications/Utilities /Applications/Utilities
You need to install XCode with all the options checked so that the compiler and You need to install XCode with all the options checked so that the compiler and
everything is available in /usr not just /Developer I think it comes on the DVD everything is available in /usr not just /Developer. XCode should be available on your OS X
but you can get the current version from http://developer.apple.com install DVD, but if not, you can get the current version from https://developer.apple.com/xcode/
1. Clone the github tree to get the source code: 1. Clone the github tree to get the source code:

View File

@ -16,8 +16,8 @@ To Build
cd src/ cd src/
make -f makefile.unix # Headless bitcoin make -f makefile.unix # Headless bitcoin
See readme-qt.rst for instructions on building Bitcoin QT, See readme-qt.rst for instructions on building Bitcoin-Qt,
the graphical bitcoin. the graphical user interface.
Dependencies Dependencies
------------ ------------

View File

@ -122,16 +122,30 @@ public:
return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n); return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
} }
void setint64(int64 n) void setint64(int64 sn)
{ {
unsigned char pch[sizeof(n) + 6]; unsigned char pch[sizeof(sn) + 6];
unsigned char* p = pch + 4; unsigned char* p = pch + 4;
bool fNegative = false; bool fNegative;
if (n < (int64)0) uint64 n;
if (sn < (int64)0)
{ {
// We negate in 2 steps to avoid signed subtraction overflow,
// i.e. -(-2^63), which is an undefined operation and causes SIGILL
// when compiled with -ftrapv.
//
// Note that uint64_t n = sn, when sn is an int64_t, is a
// well-defined operation and n will be equal to sn + 2^64 when sn
// is negative.
n = sn;
n = -n; n = -n;
fNegative = true; fNegative = true;
} else {
n = sn;
fNegative = false;
} }
bool fLeadingZeroes = true; bool fLeadingZeroes = true;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {

View File

@ -2198,6 +2198,23 @@ Value getmemorypool(const Array& params, bool fHelp)
} }
} }
Value getrawmempool(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getrawmempool\n"
"Returns all transaction ids in memory pool.");
vector<uint256> vtxid;
mempool.queryHashes(vtxid);
Array a;
BOOST_FOREACH(const uint256& hash, vtxid)
a.push_back(hash.ToString());
return a;
}
Value getblockhash(const Array& params, bool fHelp) Value getblockhash(const Array& params, bool fHelp)
{ {
if (fHelp || params.size() != 1) if (fHelp || params.size() != 1)
@ -2321,6 +2338,7 @@ static const CRPCCommand vRPCCommands[] =
{ "sendfrom", &sendfrom, false }, { "sendfrom", &sendfrom, false },
{ "sendmany", &sendmany, false }, { "sendmany", &sendmany, false },
{ "addmultisigaddress", &addmultisigaddress, false }, { "addmultisigaddress", &addmultisigaddress, false },
{ "getrawmempool", &getrawmempool, true },
{ "getblock", &getblock, false }, { "getblock", &getblock, false },
{ "getblockhash", &getblockhash, false }, { "getblockhash", &getblockhash, false },
{ "gettransaction", &gettransaction, false }, { "gettransaction", &gettransaction, false },

View File

@ -404,66 +404,6 @@ bool CTxDB::ContainsTx(uint256 hash)
return Exists(make_pair(string("tx"), hash)); return Exists(make_pair(string("tx"), hash));
} }
bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx)
{
assert(!fClient);
vtx.clear();
// Get cursor
Dbc* pcursor = GetCursor();
if (!pcursor)
return false;
unsigned int fFlags = DB_SET_RANGE;
loop
{
// Read next record
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
if (fFlags == DB_SET_RANGE)
ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
fFlags = DB_NEXT;
if (ret == DB_NOTFOUND)
break;
else if (ret != 0)
{
pcursor->close();
return false;
}
// Unserialize
string strType;
uint160 hashItem;
CDiskTxPos pos;
int nItemHeight;
try {
ssKey >> strType >> hashItem >> pos;
ssValue >> nItemHeight;
}
catch (std::exception &e) {
return error("%s() : deserialize error", __PRETTY_FUNCTION__);
}
// Read transaction
if (strType != "owner" || hashItem != hash160)
break;
if (nItemHeight >= nMinHeight)
{
vtx.resize(vtx.size()+1);
if (!vtx.back().ReadFromDisk(pos))
{
pcursor->close();
return false;
}
}
}
pcursor->close();
return true;
}
bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex) bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
{ {
assert(!fClient); assert(!fClient);

View File

@ -307,7 +307,6 @@ public:
bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight); bool AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight);
bool EraseTxIndex(const CTransaction& tx); bool EraseTxIndex(const CTransaction& tx);
bool ContainsTx(uint256 hash); bool ContainsTx(uint256 hash);
bool ReadOwnerTxes(uint160 hash160, int nHeight, std::vector<CTransaction>& vtx);
bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex); bool ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex);
bool ReadDiskTx(uint256 hash, CTransaction& tx); bool ReadDiskTx(uint256 hash, CTransaction& tx);
bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex); bool ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex);

View File

@ -223,6 +223,7 @@ std::string HelpMessage()
" -timeout=<n> " + _("Specify connection timeout (in milliseconds)") + "\n" + " -timeout=<n> " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" + " -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" +
" -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" + " -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" +
" -tor=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n"
" -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" + " -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" +
" -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" + " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n" +
" -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" + " -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" +
@ -230,12 +231,12 @@ std::string HelpMessage()
" -connect=<ip> " + _("Connect only to the specified node(s)") + "\n" + " -connect=<ip> " + _("Connect only to the specified node(s)") + "\n" +
" -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" + " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n" +
" -externalip=<ip> " + _("Specify your own public address") + "\n" + " -externalip=<ip> " + _("Specify your own public address") + "\n" +
" -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4 or IPv6)") + "\n" + " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n" +
" -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" + " -discover " + _("Discover own IP address (default: 1 when listening and no -externalip)") + "\n" +
" -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" + " -irc " + _("Find peers using internet relay chat (default: 0)") + "\n" +
" -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" + " -listen " + _("Accept connections from outside (default: 1 if no -proxy or -connect)") + "\n" +
" -bind=<addr> " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" + " -bind=<addr> " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
" -dnsseed " + _("Find peers using DNS lookup (default: 1)") + "\n" + " -dnsseed " + _("Find peers using DNS lookup (default: 1 unless -connect)") + "\n" +
" -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" + " -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
" -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" + " -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
" -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)") + "\n" + " -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 10000)") + "\n" +
@ -345,7 +346,7 @@ bool AppInit2()
SoftSetBoolArg("-listen", false); SoftSetBoolArg("-listen", false);
} }
if (GetBoolArg("-listen", true)) { if (!GetBoolArg("-listen", true)) {
// do not map ports or try to retrieve public IP when not listening (pointless) // do not map ports or try to retrieve public IP when not listening (pointless)
SoftSetBoolArg("-upnp", false); SoftSetBoolArg("-upnp", false);
SoftSetBoolArg("-discover", false); SoftSetBoolArg("-discover", false);
@ -359,6 +360,13 @@ bool AppInit2()
// ********************************************************* Step 3: parameter-to-internal-flags // ********************************************************* Step 3: parameter-to-internal-flags
fDebug = GetBoolArg("-debug"); fDebug = GetBoolArg("-debug");
// -debug implies fDebug*
if (fDebug)
fDebugNet = true;
else
fDebugNet = GetBoolArg("-debugnet");
bitdb.SetDetach(GetBoolArg("-detachdb", false)); bitdb.SetDetach(GetBoolArg("-detachdb", false));
#if !defined(WIN32) && !defined(QT_GUI) #if !defined(WIN32) && !defined(QT_GUI)
@ -470,8 +478,10 @@ bool AppInit2()
} }
} }
CService addrProxy;
bool fProxy = false;
if (mapArgs.count("-proxy")) { if (mapArgs.count("-proxy")) {
CService addrProxy = CService(mapArgs["-proxy"], 9050); addrProxy = CService(mapArgs["-proxy"], 9050);
if (!addrProxy.IsValid()) if (!addrProxy.IsValid())
return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"].c_str())); return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"].c_str()));
@ -484,6 +494,20 @@ bool AppInit2()
#endif #endif
SetNameProxy(addrProxy, nSocksVersion); SetNameProxy(addrProxy, nSocksVersion);
} }
fProxy = true;
}
// -tor can override normal proxy, -notor disables tor entirely
if (!(mapArgs.count("-tor") && mapArgs["-tor"] == "0") && (fProxy || mapArgs.count("-tor"))) {
CService addrOnion;
if (!mapArgs.count("-tor"))
addrOnion = addrProxy;
else
addrOnion = CService(mapArgs["-tor"], 9050);
if (!addrOnion.IsValid())
return InitError(strprintf(_("Invalid -tor address: '%s'"), mapArgs["-tor"].c_str()));
SetProxy(NET_TOR, addrOnion, 5);
SetReachable(NET_TOR);
} }
// see Step 2: parameter interactions for more information about these // see Step 2: parameter interactions for more information about these

View File

@ -129,6 +129,8 @@ void CKey::SetCompressedPubKey()
void CKey::Reset() void CKey::Reset()
{ {
fCompressedPubKey = false; fCompressedPubKey = false;
if (pkey != NULL)
EC_KEY_free(pkey);
pkey = EC_KEY_new_by_curve_name(NID_secp256k1); pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if (pkey == NULL) if (pkey == NULL)
throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
@ -137,6 +139,7 @@ void CKey::Reset()
CKey::CKey() CKey::CKey()
{ {
pkey = NULL;
Reset(); Reset();
} }

View File

@ -180,8 +180,8 @@ bool AddOrphanTx(const CDataStream& vMsg)
// at most 500 megabytes of orphans: // at most 500 megabytes of orphans:
if (pvMsg->size() > 5000) if (pvMsg->size() > 5000)
{ {
delete pvMsg;
printf("ignoring large orphan tx (size: %u, hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str()); printf("ignoring large orphan tx (size: %u, hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str());
delete pvMsg;
return false; return false;
} }
@ -652,7 +652,15 @@ bool CTxMemPool::remove(CTransaction &tx)
return true; return true;
} }
void CTxMemPool::queryHashes(std::vector<uint256>& vtxid)
{
vtxid.clear();
LOCK(cs);
vtxid.reserve(mapTx.size());
for (map<uint256, CTransaction>::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
vtxid.push_back((*mi).first);
}
@ -1317,8 +1325,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
// This logic is not necessary for memory pool transactions, as AcceptToMemoryPool // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool
// already refuses previously-known transaction id's entirely. // already refuses previously-known transaction id's entirely.
// This rule applies to all blocks whose timestamp is after March 15, 2012, 0:00 UTC. // This rule applies to all blocks whose timestamp is after March 15, 2012, 0:00 UTC.
// On testnet it is enabled as of februari 20, 2012, 0:00 UTC. if (pindex->nTime > 1331769600)
if (pindex->nTime > 1331769600 || (fTestNet && pindex->nTime > 1329696000))
{ {
BOOST_FOREACH(CTransaction& tx, vtx) BOOST_FOREACH(CTransaction& tx, vtx)
{ {
@ -1332,8 +1339,8 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
} }
} }
// BIP16 didn't become active until Apr 1 2012 (Feb 15 on testnet) // BIP16 didn't become active until Apr 1 2012
int64 nBIP16SwitchTime = fTestNet ? 1329264000 : 1333238400; int64 nBIP16SwitchTime = 1333238400;
bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime); bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
//// issue here: it doesn't know the version //// issue here: it doesn't know the version
@ -2419,7 +2426,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fSuccessfullyConnected = true; pfrom->fSuccessfullyConnected = true;
printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight); printf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str());
cPeerBlockCounts.input(pfrom->nStartingHeight); cPeerBlockCounts.input(pfrom->nStartingHeight);
} }
@ -2475,7 +2482,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
static uint256 hashSalt; static uint256 hashSalt;
if (hashSalt == 0) if (hashSalt == 0)
hashSalt = GetRandHash(); hashSalt = GetRandHash();
int64 hashAddr = addr.GetHash(); uint64 hashAddr = addr.GetHash();
uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60)); uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
hashRand = Hash(BEGIN(hashRand), END(hashRand)); hashRand = Hash(BEGIN(hashRand), END(hashRand));
multimap<uint256, CNode*> mapMix; multimap<uint256, CNode*> mapMix;
@ -3143,7 +3150,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
const CInv& inv = (*pto->mapAskFor.begin()).second; const CInv& inv = (*pto->mapAskFor.begin()).second;
if (!AlreadyHave(txdb, inv)) if (!AlreadyHave(txdb, inv))
{ {
printf("sending getdata: %s\n", inv.ToString().c_str()); if (fDebugNet)
printf("sending getdata: %s\n", inv.ToString().c_str());
vGetData.push_back(inv); vGetData.push_back(inv);
if (vGetData.size() >= 1000) if (vGetData.size() >= 1000)
{ {

View File

@ -1604,6 +1604,7 @@ public:
bool fCheckInputs, bool* pfMissingInputs); bool fCheckInputs, bool* pfMissingInputs);
bool addUnchecked(CTransaction &tx); bool addUnchecked(CTransaction &tx);
bool remove(CTransaction &tx); bool remove(CTransaction &tx);
void queryHashes(std::vector<uint256>& vtxid);
unsigned long size() unsigned long size()
{ {

View File

@ -51,7 +51,7 @@ public:
size_type max_size(size_type s) size_type max_size(size_type s)
{ {
if (s) if (s)
while (queue.size() >= s) while (queue.size() > s)
{ {
set.erase(queue.front()); set.erase(queue.front());
queue.pop_front(); queue.pop_front();

View File

@ -206,6 +206,14 @@ void static AdvertizeLocal()
} }
} }
void SetReachable(enum Network net, bool fFlag)
{
LOCK(cs_mapLocalHost);
vfReachable[net] = fFlag;
if (net == NET_IPV6 && fFlag)
vfReachable[NET_IPV4] = true;
}
// learn a new local address // learn a new local address
bool AddLocal(const CService& addr, int nScore) bool AddLocal(const CService& addr, int nScore)
{ {
@ -228,9 +236,7 @@ bool AddLocal(const CService& addr, int nScore)
info.nScore = nScore; info.nScore = nScore;
info.nPort = addr.GetPort() + (fAlready ? 1 : 0); info.nPort = addr.GetPort() + (fAlready ? 1 : 0);
} }
enum Network net = addr.GetNetwork(); SetReachable(addr.GetNetwork());
vfReachable[net] = true;
if (net == NET_IPV6) vfReachable[NET_IPV4] = true;
} }
AdvertizeLocal(); AdvertizeLocal();
@ -543,6 +549,7 @@ void CNode::PushVersion()
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0))); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
CAddress addrMe = GetLocalAddress(&addr); CAddress addrMe = GetLocalAddress(&addr);
RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); RAND_bytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
printf("send version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString().c_str(), addrYou.ToString().c_str(), addr.ToString().c_str());
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe, PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight); nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
} }

View File

@ -64,6 +64,7 @@ bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr); bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL); bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
bool IsReachable(const CNetAddr &addr); bool IsReachable(const CNetAddr &addr);
void SetReachable(enum Network net, bool fFlag = true);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL); CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
@ -296,7 +297,8 @@ public:
// We're using mapAskFor as a priority queue, // We're using mapAskFor as a priority queue,
// the key is the earliest time the request can be sent // the key is the earliest time the request can be sent
int64& nRequestTime = mapAlreadyAskedFor[inv]; int64& nRequestTime = mapAlreadyAskedFor[inv];
printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime); if (fDebugNet)
printf("askfor %s %"PRI64d"\n", inv.ToString().c_str(), nRequestTime);
// Make sure not to reuse time indexes to keep things in the same order // Make sure not to reuse time indexes to keep things in the same order
int64 nNow = (GetTime() - 1) * 1000000; int64 nNow = (GetTime() - 1) * 1000000;

View File

@ -33,9 +33,39 @@ enum Network ParseNetwork(std::string net) {
return NET_UNROUTABLE; return NET_UNROUTABLE;
} }
void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
size_t colon = in.find_last_of(':');
// if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
bool fHaveColon = colon != in.npos;
bool fBracketed = fHaveColon && (in[0]=='[' && in[colon-1]==']'); // if there is a colon, and in[0]=='[', colon is not 0, so in[colon-1] is safe
bool fMultiColon = fHaveColon && (in.find_last_of(':',colon-1) != in.npos);
if (fHaveColon && (colon==0 || fBracketed || !fMultiColon)) {
char *endp = NULL;
int n = strtol(in.c_str() + colon + 1, &endp, 10);
if (endp && *endp == 0 && n >= 0) {
in = in.substr(0, colon);
if (n > 0 && n < 0x10000)
portOut = n;
}
}
if (in.size()>0 && in[0] == '[' && in[in.size()-1] == ']')
hostOut = in.substr(1, in.size()-2);
else
hostOut = in;
}
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup) bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{ {
vIP.clear(); vIP.clear();
{
CNetAddr addr;
if (addr.SetSpecial(std::string(pszName))) {
vIP.push_back(addr);
return true;
}
}
struct addrinfo aiHint; struct addrinfo aiHint;
memset(&aiHint, 0, sizeof(struct addrinfo)); memset(&aiHint, 0, sizeof(struct addrinfo));
@ -44,19 +74,17 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
#ifdef WIN32 #ifdef WIN32
# ifdef USE_IPV6 # ifdef USE_IPV6
aiHint.ai_family = AF_UNSPEC; aiHint.ai_family = AF_UNSPEC;
aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
# else # else
aiHint.ai_family = AF_INET; aiHint.ai_family = AF_INET;
aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
# endif # endif
aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
#else #else
# ifdef USE_IPV6 # ifdef USE_IPV6
aiHint.ai_family = AF_UNSPEC; aiHint.ai_family = AF_UNSPEC;
aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST);
# else # else
aiHint.ai_family = AF_INET; aiHint.ai_family = AF_INET;
aiHint.ai_flags = AI_ADDRCONFIG | (fAllowLookup ? 0 : AI_NUMERICHOST);
# endif # endif
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
#endif #endif
struct addrinfo *aiRes = NULL; struct addrinfo *aiRes = NULL;
int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes); int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes);
@ -114,36 +142,11 @@ bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault,
if (pszName[0] == 0) if (pszName[0] == 0)
return false; return false;
int port = portDefault; int port = portDefault;
char psz[256]; std::string hostname = "";
char *pszHost = psz; SplitHostPort(std::string(pszName), port, hostname);
strlcpy(psz, pszName, sizeof(psz));
char* pszColon = strrchr(psz+1,':');
char *pszPortEnd = NULL;
int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0;
if (pszColon && pszPortEnd && pszPortEnd[0] == 0)
{
if (psz[0] == '[' && pszColon[-1] == ']')
{
pszHost = psz+1;
pszColon[-1] = 0;
}
else
pszColon[0] = 0;
if (port >= 0 && port <= USHRT_MAX)
port = portParsed;
}
else
{
if (psz[0] == '[' && psz[strlen(psz)-1] == ']')
{
pszHost = psz+1;
psz[strlen(psz)-1] = 0;
}
}
std::vector<CNetAddr> vIP; std::vector<CNetAddr> vIP;
bool fRet = LookupIntern(pszHost, vIP, nMaxSolutions, fAllowLookup); bool fRet = LookupIntern(hostname.c_str(), vIP, nMaxSolutions, fAllowLookup);
if (!fRet) if (!fRet)
return false; return false;
vAddr.resize(vIP.size()); vAddr.resize(vIP.size());
@ -496,22 +499,9 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout)
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout) bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout)
{ {
string strDest(pszDest); string strDest;
int port = portDefault; int port = portDefault;
SplitHostPort(string(pszDest), port, strDest);
// split hostname and port
size_t colon = strDest.find_last_of(':');
if (colon != strDest.npos) {
char *endp = NULL;
int n = strtol(pszDest + colon + 1, &endp, 10);
if (endp && *endp == 0 && n >= 0) {
strDest = strDest.substr(0, colon);
if (n > 0 && n < 0x10000)
port = n;
}
}
if (strDest[0] == '[' && strDest[strDest.size()-1] == ']')
strDest = strDest.substr(1, strDest.size()-2);
SOCKET hSocket = INVALID_SOCKET; SOCKET hSocket = INVALID_SOCKET;
CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port); CService addrResolved(CNetAddr(strDest, fNameLookup && !nameproxyInfo.second), port);
@ -549,6 +539,32 @@ void CNetAddr::SetIP(const CNetAddr& ipIn)
memcpy(ip, ipIn.ip, sizeof(ip)); memcpy(ip, ipIn.ip, sizeof(ip));
} }
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5};
bool CNetAddr::SetSpecial(const std::string &strName)
{
if (strName.size()>6 && strName.substr(strName.size() - 6, 6) == ".onion") {
std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 6).c_str());
if (vchAddr.size() != 16-sizeof(pchOnionCat))
return false;
memcpy(ip, pchOnionCat, sizeof(pchOnionCat));
for (unsigned int i=0; i<16-sizeof(pchOnionCat); i++)
ip[i + sizeof(pchOnionCat)] = vchAddr[i];
return true;
}
if (strName.size()>11 && strName.substr(strName.size() - 11, 11) == ".oc.b32.i2p") {
std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 11).c_str());
if (vchAddr.size() != 16-sizeof(pchGarliCat))
return false;
memcpy(ip, pchOnionCat, sizeof(pchGarliCat));
for (unsigned int i=0; i<16-sizeof(pchGarliCat); i++)
ip[i + sizeof(pchGarliCat)] = vchAddr[i];
return true;
}
return false;
}
CNetAddr::CNetAddr() CNetAddr::CNetAddr()
{ {
Init(); Init();
@ -595,7 +611,7 @@ bool CNetAddr::IsIPv4() const
bool CNetAddr::IsIPv6() const bool CNetAddr::IsIPv6() const
{ {
return (!IsIPv4()); return (!IsIPv4() && !IsTor() && !IsI2P());
} }
bool CNetAddr::IsRFC1918() const bool CNetAddr::IsRFC1918() const
@ -654,15 +670,13 @@ bool CNetAddr::IsRFC4843() const
return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10); return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10);
} }
bool CNetAddr::IsOnionCat() const bool CNetAddr::IsTor() const
{ {
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0); return (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
} }
bool CNetAddr::IsGarliCat() const bool CNetAddr::IsI2P() const
{ {
static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5};
return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0); return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0);
} }
@ -724,7 +738,7 @@ bool CNetAddr::IsValid() const
bool CNetAddr::IsRoutable() const bool CNetAddr::IsRoutable() const
{ {
return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsOnionCat() && !IsGarliCat()) || IsRFC4843() || IsLocal()); return IsValid() && !(IsRFC1918() || IsRFC3927() || IsRFC4862() || (IsRFC4193() && !IsTor() && !IsI2P()) || IsRFC4843() || IsLocal());
} }
enum Network CNetAddr::GetNetwork() const enum Network CNetAddr::GetNetwork() const
@ -735,10 +749,10 @@ enum Network CNetAddr::GetNetwork() const
if (IsIPv4()) if (IsIPv4())
return NET_IPV4; return NET_IPV4;
if (IsOnionCat()) if (IsTor())
return NET_TOR; return NET_TOR;
if (IsGarliCat()) if (IsI2P())
return NET_I2P; return NET_I2P;
return NET_IPV6; return NET_IPV6;
@ -746,6 +760,10 @@ enum Network CNetAddr::GetNetwork() const
std::string CNetAddr::ToStringIP() const std::string CNetAddr::ToStringIP() const
{ {
if (IsTor())
return EncodeBase32(&ip[6], 10) + ".onion";
if (IsI2P())
return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p";
CService serv(*this, 0); CService serv(*this, 0);
#ifdef USE_IPV6 #ifdef USE_IPV6
struct sockaddr_storage sockaddr; struct sockaddr_storage sockaddr;
@ -758,7 +776,7 @@ std::string CNetAddr::ToStringIP() const
if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST)) if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST))
return std::string(name); return std::string(name);
} }
if (IsIPv4()) if (IsIPv4())
return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0)); return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
else else
return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
@ -847,6 +865,18 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
vchRet.push_back(GetByte(2) ^ 0xFF); vchRet.push_back(GetByte(2) ^ 0xFF);
return vchRet; return vchRet;
} }
else if (IsTor())
{
nClass = NET_TOR;
nStartByte = 6;
nBits = 4;
}
else if (IsI2P())
{
nClass = NET_I2P;
nStartByte = 6;
nBits = 4;
}
// for he.net, use /36 groups // for he.net, use /36 groups
else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70) else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
nBits = 36; nBits = 36;
@ -867,10 +897,10 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
return vchRet; return vchRet;
} }
int64 CNetAddr::GetHash() const uint64 CNetAddr::GetHash() const
{ {
uint256 hash = Hash(&ip[0], &ip[16]); uint256 hash = Hash(&ip[0], &ip[16]);
int64 nRet; uint64 nRet;
memcpy(&nRet, &hash, sizeof(nRet)); memcpy(&nRet, &hash, sizeof(nRet));
return nRet; return nRet;
} }
@ -880,27 +910,82 @@ void CNetAddr::print() const
printf("CNetAddr(%s)\n", ToString().c_str()); printf("CNetAddr(%s)\n", ToString().c_str());
} }
// for IPv6 partners: for unknown/Teredo partners: for IPv4 partners: // private extensions to enum Network, only returned by GetExtNetwork,
// 0 - unroutable // 0 - unroutable // 0 - unroutable // and only used in GetReachabilityFrom
// 1 - teredo // 1 - teredo // 1 - ipv4 static const int NET_UNKNOWN = NET_MAX + 0;
// 2 - tunneled ipv6 // 2 - tunneled ipv6 static const int NET_TEREDO = NET_MAX + 1;
// 3 - ipv4 // 3 - ipv6 int static GetExtNetwork(const CNetAddr *addr)
// 4 - ipv6 // 4 - ipv4 {
if (addr == NULL)
return NET_UNKNOWN;
if (addr->IsRFC4380())
return NET_TEREDO;
return addr->GetNetwork();
}
/** Calculates a metric for how reachable (*this) is from a given partner */
int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
{ {
if (!IsValid() || !IsRoutable()) enum Reachability {
return 0; REACH_UNREACHABLE,
if (paddrPartner && paddrPartner->IsIPv4()) REACH_DEFAULT,
return IsIPv4() ? 1 : 0; REACH_TEREDO,
if (IsRFC4380()) REACH_IPV6_WEAK,
return 1; REACH_IPV4,
if (IsRFC3964() || IsRFC6052()) REACH_IPV6_STRONG,
return 2; REACH_PRIVATE
bool fRealIPv6 = paddrPartner && !paddrPartner->IsRFC4380() && paddrPartner->IsValid() && paddrPartner->IsRoutable(); };
if (fRealIPv6)
return IsIPv4() ? 3 : 4; if (!IsRoutable())
else return REACH_UNREACHABLE;
return IsIPv4() ? 4 : 3;
int ourNet = GetExtNetwork(this);
int theirNet = GetExtNetwork(paddrPartner);
bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();
switch(theirNet) {
case NET_IPV4:
switch(ourNet) {
default: return REACH_DEFAULT;
case NET_IPV4: return REACH_IPV4;
}
case NET_IPV6:
switch(ourNet) {
default: return REACH_DEFAULT;
case NET_TEREDO: return REACH_TEREDO;
case NET_IPV4: return REACH_IPV4;
case NET_IPV6: return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG; // only prefer giving our IPv6 address if it's not tunneled
}
case NET_TOR:
switch(ourNet) {
default: return REACH_DEFAULT;
case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well
case NET_TOR: return REACH_PRIVATE;
}
case NET_I2P:
switch(ourNet) {
default: return REACH_DEFAULT;
case NET_I2P: return REACH_PRIVATE;
}
case NET_TEREDO:
switch(ourNet) {
default: return REACH_DEFAULT;
case NET_TEREDO: return REACH_TEREDO;
case NET_IPV6: return REACH_IPV6_WEAK;
case NET_IPV4: return REACH_IPV4;
}
case NET_UNKNOWN:
case NET_UNROUTABLE:
default:
switch(ourNet) {
default: return REACH_DEFAULT;
case NET_TEREDO: return REACH_TEREDO;
case NET_IPV6: return REACH_IPV6_WEAK;
case NET_IPV4: return REACH_IPV4;
case NET_I2P: return REACH_PRIVATE; // assume connections from unroutable addresses are
case NET_TOR: return REACH_PRIVATE; // either from Tor/I2P, or don't care about our address
}
}
} }
void CService::Init() void CService::Init()
@ -1055,7 +1140,7 @@ std::string CService::ToStringPort() const
std::string CService::ToStringIPPort() const std::string CService::ToStringIPPort() const
{ {
if (IsIPv4()) { if (IsIPv4() || IsTor() || IsI2P()) {
return ToStringIP() + ":" + ToStringPort(); return ToStringIP() + ":" + ToStringPort();
} else { } else {
return "[" + ToStringIP() + "]:" + ToStringPort(); return "[" + ToStringIP() + "]:" + ToStringPort();

View File

@ -25,7 +25,7 @@ enum Network
NET_TOR, NET_TOR,
NET_I2P, NET_I2P,
NET_MAX NET_MAX,
}; };
extern int nConnectTimeout; extern int nConnectTimeout;
@ -44,8 +44,9 @@ class CNetAddr
explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false);
void Init(); void Init();
void SetIP(const CNetAddr& ip); void SetIP(const CNetAddr& ip);
bool SetSpecial(const std::string &strName); // for Tor and I2P addresses
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not IPv4) bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/I2P)
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32) bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16) bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
@ -56,8 +57,8 @@ class CNetAddr
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64) bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96) bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96) bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
bool IsOnionCat() const; bool IsTor() const;
bool IsGarliCat() const; bool IsI2P() const;
bool IsLocal() const; bool IsLocal() const;
bool IsRoutable() const; bool IsRoutable() const;
bool IsValid() const; bool IsValid() const;
@ -66,7 +67,7 @@ class CNetAddr
std::string ToString() const; std::string ToString() const;
std::string ToStringIP() const; std::string ToStringIP() const;
int GetByte(int n) const; int GetByte(int n) const;
int64 GetHash() const; uint64 GetHash() const;
bool GetInAddr(struct in_addr* pipv4Addr) const; bool GetInAddr(struct in_addr* pipv4Addr) const;
std::vector<unsigned char> GetGroup() const; std::vector<unsigned char> GetGroup() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
@ -133,6 +134,7 @@ class CService : public CNetAddr
}; };
enum Network ParseNetwork(std::string net); enum Network ParseNetwork(std::string net);
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, CService &addrProxy);
bool IsProxy(const CNetAddr &addr); bool IsProxy(const CNetAddr &addr);

View File

@ -212,7 +212,7 @@ int main(int argc, char *argv[])
if (mapArgs.count("-?") || mapArgs.count("--help")) if (mapArgs.count("-?") || mapArgs.count("--help"))
{ {
GUIUtil::HelpMessageBox help; GUIUtil::HelpMessageBox help;
help.exec(); help.showOrPrint();
return 1; return 1;
} }

View File

@ -70,6 +70,9 @@
<iconset resource="../bitcoin.qrc"> <iconset resource="../bitcoin.qrc">
<normaloff>:/icons/add</normaloff>:/icons/add</iconset> <normaloff>:/icons/add</normaloff>:/icons/add</iconset>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@ -93,6 +96,9 @@
<property name="autoRepeatDelay"> <property name="autoRepeatDelay">
<number>300</number> <number>300</number>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@ -109,6 +115,9 @@
</item> </item>
<item> <item>
<widget class="QLabel" name="labelBalance"> <widget class="QLabel" name="labelBalance">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text"> <property name="text">
<string>123.456 BTC</string> <string>123.456 BTC</string>
</property> </property>

View File

@ -441,15 +441,21 @@ HelpMessageBox::HelpMessageBox(QWidget *parent) :
setDetailedText(coreOptions + "\n" + uiOptions); setDetailedText(coreOptions + "\n" + uiOptions);
} }
void HelpMessageBox::exec() void HelpMessageBox::printToConsole()
{ {
#if defined(WIN32)
// On windows, show a message box, as there is no stderr in windowed applications
QMessageBox::exec();
#else
// On other operating systems, the expected action is to print the message to the console. // On other operating systems, the expected action is to print the message to the console.
QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions; QString strUsage = header + "\n" + coreOptions + "\n" + uiOptions;
fprintf(stderr, "%s", strUsage.toStdString().c_str()); fprintf(stderr, "%s", strUsage.toStdString().c_str());
}
void HelpMessageBox::showOrPrint()
{
#if defined(WIN32)
// On windows, show a message box, as there is no stderr/stdout in windowed applications
exec();
#else
// On other operating systems, print help text to console
printToConsole();
#endif #endif
} }

View File

@ -103,7 +103,11 @@ namespace GUIUtil
public: public:
HelpMessageBox(QWidget *parent = 0); HelpMessageBox(QWidget *parent = 0);
void exec(); /** Show message box or print help message to standard output, based on operating system. */
void showOrPrint();
/** Print help message to console */
void printToConsole();
private: private:
QString header; QString header;

View File

@ -152,7 +152,7 @@ void OverviewPage::setNumTransactions(int count)
void OverviewPage::setModel(WalletModel *model) void OverviewPage::setModel(WalletModel *model)
{ {
this->model = model; this->model = model;
if(model) if(model && model->getOptionsModel())
{ {
// Set up transaction list // Set up transaction list
filter = new TransactionFilterProxy(); filter = new TransactionFilterProxy();
@ -172,19 +172,25 @@ void OverviewPage::setModel(WalletModel *model)
setNumTransactions(model->getNumTransactions()); setNumTransactions(model->getNumTransactions());
connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int))); connect(model, SIGNAL(numTransactionsChanged(int)), this, SLOT(setNumTransactions(int)));
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(displayUnitChanged())); connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
} }
// update the display unit, to not use the default ("BTC")
updateDisplayUnit();
} }
void OverviewPage::displayUnitChanged() void OverviewPage::updateDisplayUnit()
{ {
if(!model || !model->getOptionsModel()) if(model && model->getOptionsModel())
return; {
if(currentBalance != -1) if(currentBalance != -1)
setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance); setBalance(currentBalance, currentUnconfirmedBalance, currentImmatureBalance);
txdelegate->unit = model->getOptionsModel()->getDisplayUnit(); // Update txdelegate->unit with the current unit
ui->listTransactions->update(); txdelegate->unit = model->getOptionsModel()->getDisplayUnit();
ui->listTransactions->update();
}
} }
void OverviewPage::showOutOfSyncWarning(bool fShow) void OverviewPage::showOutOfSyncWarning(bool fShow)

View File

@ -44,7 +44,7 @@ private:
TransactionFilterProxy *filter; TransactionFilterProxy *filter;
private slots: private slots:
void displayUnitChanged(); void updateDisplayUnit();
void handleTransactionClicked(const QModelIndex &index); void handleTransactionClicked(const QModelIndex &index);
}; };

View File

@ -46,10 +46,11 @@ void SendCoinsDialog::setModel(WalletModel *model)
entry->setModel(model); entry->setModel(model);
} }
} }
if(model) if(model && model->getOptionsModel())
{ {
setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance()); setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance());
connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64))); connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64)));
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
} }
} }
@ -202,7 +203,7 @@ SendCoinsEntry *SendCoinsDialog::addEntry()
ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint()); ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());
QCoreApplication::instance()->processEvents(); QCoreApplication::instance()->processEvents();
QScrollBar* bar = ui->scrollArea->verticalScrollBar(); QScrollBar* bar = ui->scrollArea->verticalScrollBar();
if (bar) if(bar)
bar->setSliderPosition(bar->maximum()); bar->setSliderPosition(bar->maximum());
return entry; return entry;
} }
@ -245,7 +246,7 @@ QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv) void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
{ {
if (!fNewRecipientAllowed) if(!fNewRecipientAllowed)
return; return;
SendCoinsEntry *entry = 0; SendCoinsEntry *entry = 0;
@ -289,3 +290,12 @@ void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint
int unit = model->getOptionsModel()->getDisplayUnit(); int unit = model->getOptionsModel()->getDisplayUnit();
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance)); ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
} }
void SendCoinsDialog::updateDisplayUnit()
{
if(model && model->getOptionsModel())
{
// Update labelBalance with the current balance and the current unit
ui->labelBalance->setText(BitcoinUnits::formatWithUnit(model->getOptionsModel()->getDisplayUnit(), model->getBalance()));
}
}

View File

@ -47,8 +47,8 @@ private:
private slots: private slots:
void on_sendButton_clicked(); void on_sendButton_clicked();
void removeEntry(SendCoinsEntry* entry); void removeEntry(SendCoinsEntry* entry);
void updateDisplayUnit();
}; };
#endif // SENDCOINSDIALOG_H #endif // SENDCOINSDIALOG_H

View File

@ -68,6 +68,10 @@ void SendCoinsEntry::on_payTo_textChanged(const QString &address)
void SendCoinsEntry::setModel(WalletModel *model) void SendCoinsEntry::setModel(WalletModel *model)
{ {
this->model = model; this->model = model;
if(model && model->getOptionsModel())
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
clear(); clear();
} }
@ -82,10 +86,8 @@ void SendCoinsEntry::clear()
ui->addAsLabel->clear(); ui->addAsLabel->clear();
ui->payAmount->clear(); ui->payAmount->clear();
ui->payTo->setFocus(); ui->payTo->setFocus();
if(model && model->getOptionsModel()) // update the display unit, to not use the default ("BTC")
{ updateDisplayUnit();
ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
}
} }
void SendCoinsEntry::on_deleteButton_clicked() void SendCoinsEntry::on_deleteButton_clicked()
@ -160,3 +162,11 @@ void SendCoinsEntry::setFocus()
ui->payTo->setFocus(); ui->payTo->setFocus();
} }
void SendCoinsEntry::updateDisplayUnit()
{
if(model && model->getOptionsModel())
{
// Update payAmount with the current unit
ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
}
}

View File

@ -45,6 +45,7 @@ private slots:
void on_payTo_textChanged(const QString &address); void on_payTo_textChanged(const QString &address);
void on_addressBookButton_clicked(); void on_addressBookButton_clicked();
void on_pasteButton_clicked(); void on_pasteButton_clicked();
void updateDisplayUnit();
private: private:
Ui::SendCoinsEntry *ui; Ui::SendCoinsEntry *ui;

View File

@ -230,6 +230,8 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
QTimer *timer = new QTimer(this); QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateConfirmations())); connect(timer, SIGNAL(timeout()), this, SLOT(updateConfirmations()));
timer->start(MODEL_UPDATE_DELAY); timer->start(MODEL_UPDATE_DELAY);
connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
} }
TransactionTableModel::~TransactionTableModel() TransactionTableModel::~TransactionTableModel()
@ -624,3 +626,8 @@ QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex
} }
} }
void TransactionTableModel::updateDisplayUnit()
{
// emit dataChanged to update Amount column with the current unit
emit dataChanged(index(0, Amount), index(priv->size()-1, Amount));
}

View File

@ -76,6 +76,7 @@ private:
public slots: public slots:
void updateTransaction(const QString &hash, int status); void updateTransaction(const QString &hash, int status);
void updateConfirmations(); void updateConfirmations();
void updateDisplayUnit();
friend class TransactionTablePriv; friend class TransactionTablePriv;
}; };

20
src/test/base32_tests.cpp Normal file
View File

@ -0,0 +1,20 @@
#include <boost/test/unit_test.hpp>
#include "util.h"
BOOST_AUTO_TEST_SUITE(base32_tests)
BOOST_AUTO_TEST_CASE(base32_testvectors)
{
static const std::string vstrIn[] = {"","f","fo","foo","foob","fooba","foobar"};
static const std::string vstrOut[] = {"","my======","mzxq====","mzxw6===","mzxw6yq=","mzxw6ytb","mzxw6ytboi======"};
for (unsigned int i=0; i<sizeof(vstrIn)/sizeof(vstrIn[0]); i++)
{
std::string strEnc = EncodeBase32(vstrIn[i]);
BOOST_CHECK(strEnc == vstrOut[i]);
std::string strDec = DecodeBase32(vstrOut[i]);
BOOST_CHECK(strDec == vstrIn[i]);
}
}
BOOST_AUTO_TEST_SUITE_END()

125
src/test/bignum_tests.cpp Normal file
View File

@ -0,0 +1,125 @@
#include <boost/test/unit_test.hpp>
#include <limits>
#include "bignum.h"
#include "util.h"
BOOST_AUTO_TEST_SUITE(bignum_tests)
// Unfortunately there's no standard way of preventing a function from being
// inlined, so we define a macro for it.
//
// You should use it like this:
// NOINLINE void function() {...}
#if defined(__GNUC__)
// This also works and will be defined for any compiler implementing gcc
// extensions, such as clang and icc.
#define NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define NOINLINE __declspec(noinline)
#else
// We give out a warning because it impacts the correctness of one bignum test.
#warning You should define NOINLINE for your compiler.
#define NOINLINE
#endif
// For the following test case, it is useful to use additional tools.
//
// The simplest one to use is the compiler flag -ftrapv, which detects integer
// overflows and similar errors. However, due to optimizations and compilers
// taking advantage of undefined behavior sometimes it may not actually detect
// anything.
//
// You can also use compiler-based stack protection to possibly detect possible
// stack buffer overruns.
//
// For more accurate diagnostics, you can use an undefined arithmetic operation
// detector such as the clang-based tool:
//
// "IOC: An Integer Overflow Checker for C/C++"
//
// Available at: http://embed.cs.utah.edu/ioc/
//
// It might also be useful to use Google's AddressSanitizer to detect
// stack buffer overruns, which valgrind can't currently detect.
// Let's force this code not to be inlined, in order to actually
// test a generic version of the function. This increases the chance
// that -ftrapv will detect overflows.
NOINLINE void mysetint64(CBigNum& num, int64 n)
{
num.setint64(n);
}
// For each number, we do 2 tests: one with inline code, then we reset the
// value to 0, then the second one with a non-inlined function.
BOOST_AUTO_TEST_CASE(bignum_setint64)
{
int64 n;
{
n = 0;
CBigNum num(n);
BOOST_CHECK(num.ToString() == "0");
num.setulong(0);
BOOST_CHECK(num.ToString() == "0");
mysetint64(num, n);
BOOST_CHECK(num.ToString() == "0");
}
{
n = 1;
CBigNum num(n);
BOOST_CHECK(num.ToString() == "1");
num.setulong(0);
BOOST_CHECK(num.ToString() == "0");
mysetint64(num, n);
BOOST_CHECK(num.ToString() == "1");
}
{
n = -1;
CBigNum num(n);
BOOST_CHECK(num.ToString() == "-1");
num.setulong(0);
BOOST_CHECK(num.ToString() == "0");
mysetint64(num, n);
BOOST_CHECK(num.ToString() == "-1");
}
{
n = 5;
CBigNum num(n);
BOOST_CHECK(num.ToString() == "5");
num.setulong(0);
BOOST_CHECK(num.ToString() == "0");
mysetint64(num, n);
BOOST_CHECK(num.ToString() == "5");
}
{
n = -5;
CBigNum num(n);
BOOST_CHECK(num.ToString() == "-5");
num.setulong(0);
BOOST_CHECK(num.ToString() == "0");
mysetint64(num, n);
BOOST_CHECK(num.ToString() == "-5");
}
{
n = std::numeric_limits<int64>::min();
CBigNum num(n);
BOOST_CHECK(num.ToString() == "-9223372036854775808");
num.setulong(0);
BOOST_CHECK(num.ToString() == "0");
mysetint64(num, n);
BOOST_CHECK(num.ToString() == "-9223372036854775808");
}
{
n = std::numeric_limits<int64>::max();
CBigNum num(n);
BOOST_CHECK(num.ToString() == "9223372036854775807");
num.setulong(0);
BOOST_CHECK(num.ToString() == "0");
mysetint64(num, n);
BOOST_CHECK(num.ToString() == "9223372036854775807");
}
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -235,7 +235,7 @@ BOOST_AUTO_TEST_CASE(multisig_Solver1)
BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired));
BOOST_CHECK(addrs[0] == keyaddr[0]); BOOST_CHECK(addrs[0] == keyaddr[0]);
BOOST_CHECK(addrs[1] == keyaddr[1]); BOOST_CHECK(addrs[1] == keyaddr[1]);
BOOST_CHECK(nRequired = 1); BOOST_CHECK(nRequired == 1);
BOOST_CHECK(IsMine(keystore, s)); BOOST_CHECK(IsMine(keystore, s));
BOOST_CHECK(!IsMine(emptykeystore, s)); BOOST_CHECK(!IsMine(emptykeystore, s));
BOOST_CHECK(!IsMine(partialkeystore, s)); BOOST_CHECK(!IsMine(partialkeystore, s));

102
src/test/netbase_tests.cpp Normal file
View File

@ -0,0 +1,102 @@
#include <boost/test/unit_test.hpp>
#include <string>
#include <vector>
#include "netbase.h"
using namespace std;
BOOST_AUTO_TEST_SUITE(netbase_tests)
BOOST_AUTO_TEST_CASE(netbase_networks)
{
BOOST_CHECK(CNetAddr("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
BOOST_CHECK(CNetAddr("::1").GetNetwork() == NET_UNROUTABLE);
BOOST_CHECK(CNetAddr("8.8.8.8").GetNetwork() == NET_IPV4);
BOOST_CHECK(CNetAddr("2001::8888").GetNetwork() == NET_IPV6);
BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() == NET_TOR);
}
BOOST_AUTO_TEST_CASE(netbase_properties)
{
BOOST_CHECK(CNetAddr("127.0.0.1").IsIPv4());
BOOST_CHECK(CNetAddr("::FFFF:192.168.1.1").IsIPv4());
BOOST_CHECK(CNetAddr("::1").IsIPv6());
BOOST_CHECK(CNetAddr("10.0.0.1").IsRFC1918());
BOOST_CHECK(CNetAddr("192.168.1.1").IsRFC1918());
BOOST_CHECK(CNetAddr("172.31.255.255").IsRFC1918());
BOOST_CHECK(CNetAddr("2001:0DB8::").IsRFC3849());
BOOST_CHECK(CNetAddr("169.254.1.1").IsRFC3927());
BOOST_CHECK(CNetAddr("2002::1").IsRFC3964());
BOOST_CHECK(CNetAddr("FC00::").IsRFC4193());
BOOST_CHECK(CNetAddr("2001::2").IsRFC4380());
BOOST_CHECK(CNetAddr("2001:10::").IsRFC4843());
BOOST_CHECK(CNetAddr("FE80::").IsRFC4862());
BOOST_CHECK(CNetAddr("64:FF9B::").IsRFC6052());
BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor());
BOOST_CHECK(CNetAddr("127.0.0.1").IsLocal());
BOOST_CHECK(CNetAddr("::1").IsLocal());
BOOST_CHECK(CNetAddr("8.8.8.8").IsRoutable());
BOOST_CHECK(CNetAddr("2001::1").IsRoutable());
BOOST_CHECK(CNetAddr("127.0.0.1").IsValid());
}
bool static TestSplitHost(string test, string host, int port)
{
string hostOut;
int portOut = -1;
SplitHostPort(test, portOut, hostOut);
return hostOut == host && port == portOut;
}
BOOST_AUTO_TEST_CASE(netbase_splithost)
{
BOOST_CHECK(TestSplitHost("www.bitcoin.org", "www.bitcoin.org", -1));
BOOST_CHECK(TestSplitHost("[www.bitcoin.org]", "www.bitcoin.org", -1));
BOOST_CHECK(TestSplitHost("www.bitcoin.org:80", "www.bitcoin.org", 80));
BOOST_CHECK(TestSplitHost("[www.bitcoin.org]:80", "www.bitcoin.org", 80));
BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1));
BOOST_CHECK(TestSplitHost("127.0.0.1:8333", "127.0.0.1", 8333));
BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1));
BOOST_CHECK(TestSplitHost("[127.0.0.1]:8333", "127.0.0.1", 8333));
BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1));
BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:8333", "::ffff:127.0.0.1", 8333));
BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333));
BOOST_CHECK(TestSplitHost("::8333", "::8333", -1));
BOOST_CHECK(TestSplitHost(":8333", "", 8333));
BOOST_CHECK(TestSplitHost("[]:8333", "", 8333));
BOOST_CHECK(TestSplitHost("", "", -1));
}
bool static TestParse(string src, string canon)
{
CService addr;
if (!LookupNumeric(src.c_str(), addr, 65535))
return canon == "";
return canon == addr.ToString();
}
BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
{
BOOST_CHECK(TestParse("127.0.0.1", "127.0.0.1:65535"));
BOOST_CHECK(TestParse("127.0.0.1:8333", "127.0.0.1:8333"));
BOOST_CHECK(TestParse("::ffff:127.0.0.1", "127.0.0.1:65535"));
BOOST_CHECK(TestParse("::", "[::]:65535"));
BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
BOOST_CHECK(TestParse(":::", ""));
}
BOOST_AUTO_TEST_CASE(onioncat_test)
{
// values from http://www.cypherpunk.at/onioncat/wiki/OnionCat
CNetAddr addr1("5wyqrzbvrdsumnok.onion");
CNetAddr addr2("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca");
BOOST_CHECK(addr1 == addr2);
BOOST_CHECK(addr1.IsTor());
BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion");
BOOST_CHECK(addr1.IsRoutable());
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -58,6 +58,7 @@ using namespace std;
map<string, string> mapArgs; map<string, string> mapArgs;
map<string, vector<string> > mapMultiArgs; map<string, vector<string> > mapMultiArgs;
bool fDebug = false; bool fDebug = false;
bool fDebugNet = false;
bool fPrintToConsole = false; bool fPrintToConsole = false;
bool fPrintToDebugger = false; bool fPrintToDebugger = false;
bool fRequestShutdown = false; bool fRequestShutdown = false;
@ -702,6 +703,193 @@ string DecodeBase64(const string& str)
return string((const char*)&vchRet[0], vchRet.size()); return string((const char*)&vchRet[0], vchRet.size());
} }
string EncodeBase32(const unsigned char* pch, size_t len)
{
static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
string strRet="";
strRet.reserve((len+4)/5*8);
int mode=0, left=0;
const unsigned char *pchEnd = pch+len;
while (pch<pchEnd)
{
int enc = *(pch++);
switch (mode)
{
case 0: // we have no bits
strRet += pbase32[enc >> 3];
left = (enc & 7) << 2;
mode = 1;
break;
case 1: // we have three bits
strRet += pbase32[left | (enc >> 6)];
strRet += pbase32[(enc >> 1) & 31];
left = (enc & 1) << 4;
mode = 2;
break;
case 2: // we have one bit
strRet += pbase32[left | (enc >> 4)];
left = (enc & 15) << 1;
mode = 3;
break;
case 3: // we have four bits
strRet += pbase32[left | (enc >> 7)];
strRet += pbase32[(enc >> 2) & 31];
left = (enc & 3) << 3;
mode = 4;
break;
case 4: // we have two bits
strRet += pbase32[left | (enc >> 5)];
strRet += pbase32[enc & 31];
mode = 0;
}
}
static const int nPadding[5] = {0, 6, 4, 3, 1};
if (mode)
{
strRet += pbase32[left];
for (int n=0; n<nPadding[mode]; n++)
strRet += '=';
}
return strRet;
}
string EncodeBase32(const string& str)
{
return EncodeBase32((const unsigned char*)str.c_str(), str.size());
}
vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
{
static const int decode32_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, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -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, 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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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))*5/8);
int mode = 0;
int left = 0;
while (1)
{
int dec = decode32_table[(unsigned char)*p];
if (dec == -1) break;
p++;
switch (mode)
{
case 0: // we have no bits and get 5
left = dec;
mode = 1;
break;
case 1: // we have 5 bits and keep 2
vchRet.push_back((left<<3) | (dec>>2));
left = dec & 3;
mode = 2;
break;
case 2: // we have 2 bits and keep 7
left = left << 5 | dec;
mode = 3;
break;
case 3: // we have 7 bits and keep 4
vchRet.push_back((left<<1) | (dec>>4));
left = dec & 15;
mode = 4;
break;
case 4: // we have 4 bits, and keep 1
vchRet.push_back((left<<4) | (dec>>1));
left = dec & 1;
mode = 5;
break;
case 5: // we have 1 bit, and keep 6
left = left << 5 | dec;
mode = 6;
break;
case 6: // we have 6 bits, and keep 3
vchRet.push_back((left<<2) | (dec>>3));
left = dec & 7;
mode = 7;
break;
case 7: // we have 3 bits, and keep 0
vchRet.push_back((left<<5) | dec);
mode = 0;
break;
}
}
if (pfInvalid)
switch (mode)
{
case 0: // 8n base32 characters processed: ok
break;
case 1: // 8n+1 base32 characters processed: impossible
case 3: // +3
case 6: // +6
*pfInvalid = true;
break;
case 2: // 8n+2 base32 characters processed: require '======'
if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1)
*pfInvalid = true;
break;
case 4: // 8n+4 base32 characters processed: require '===='
if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1)
*pfInvalid = true;
break;
case 5: // 8n+5 base32 characters processed: require '==='
if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1)
*pfInvalid = true;
break;
case 7: // 8n+7 base32 characters processed: require '='
if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1)
*pfInvalid = true;
break;
}
return vchRet;
}
string DecodeBase32(const string& str)
{
vector<unsigned char> vchRet = DecodeBase32(str.c_str());
return string((const char*)&vchRet[0], vchRet.size());
}
bool WildcardMatch(const char* psz, const char* mask) bool WildcardMatch(const char* psz, const char* mask)
{ {

View File

@ -105,6 +105,7 @@ inline void Sleep(int64 n)
extern std::map<std::string, std::string> mapArgs; extern std::map<std::string, std::string> mapArgs;
extern std::map<std::string, std::vector<std::string> > mapMultiArgs; extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
extern bool fDebug; extern bool fDebug;
extern bool fDebugNet;
extern bool fPrintToConsole; extern bool fPrintToConsole;
extern bool fPrintToDebugger; extern bool fPrintToDebugger;
extern bool fRequestShutdown; extern bool fRequestShutdown;
@ -146,6 +147,10 @@ std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
std::string DecodeBase64(const std::string& str); std::string DecodeBase64(const std::string& str);
std::string EncodeBase64(const unsigned char* pch, size_t len); std::string EncodeBase64(const unsigned char* pch, size_t len);
std::string EncodeBase64(const std::string& str); std::string EncodeBase64(const std::string& str);
std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL);
std::string DecodeBase32(const std::string& str);
std::string EncodeBase32(const unsigned char* pch, size_t len);
std::string EncodeBase32(const std::string& str);
void ParseParameters(int argc, const char*const argv[]); void ParseParameters(int argc, const char*const argv[]);
bool WildcardMatch(const char* psz, const char* mask); bool WildcardMatch(const char* psz, const char* mask);
bool WildcardMatch(const std::string& str, const std::string& mask); bool WildcardMatch(const std::string& str, const std::string& mask);
@ -272,7 +277,7 @@ inline int64 GetPerformanceCounter()
#else #else
timeval t; timeval t;
gettimeofday(&t, NULL); gettimeofday(&t, NULL);
nCounter = t.tv_sec * 1000000 + t.tv_usec; nCounter = (int64) t.tv_sec * 1000000 + t.tv_usec;
#endif #endif
return nCounter; return nCounter;
} }