aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bitcoinrpc.cpp287
-rw-r--r--src/checkpoints.cpp5
-rw-r--r--src/init.cpp32
-rw-r--r--src/main.cpp33
-rw-r--r--src/makefile.linux-mingw2
-rw-r--r--src/makefile.mingw2
-rw-r--r--src/net.cpp20
-rw-r--r--src/net.h5
-rw-r--r--src/netbase.cpp162
-rw-r--r--src/netbase.h9
-rw-r--r--src/qt/optionsdialog.cpp15
-rw-r--r--src/test/Checkpoints_tests.cpp14
-rw-r--r--src/test/base32_tests.cpp20
-rw-r--r--src/test/netbase_tests.cpp13
-rw-r--r--src/test/rpc_tests.cpp6
-rw-r--r--src/ui_interface.h5
-rw-r--r--src/util.cpp187
-rw-r--r--src/util.h4
18 files changed, 665 insertions, 156 deletions
diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp
index 9dd6774984..de6db53982 100644
--- a/src/bitcoinrpc.cpp
+++ b/src/bitcoinrpc.cpp
@@ -15,14 +15,18 @@
#undef printf
#include <boost/asio.hpp>
+#include <boost/asio/ip/v6_only.hpp>
+#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/filesystem/fstream.hpp>
-typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
+#include <boost/shared_ptr.hpp>
+#include <list>
#define printf OutputDebugStringF
// MinGW 3.4.5 gets "fatal error: had to relocate PCH" if the json headers are
@@ -2579,10 +2583,22 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
stream << HTTPReply(nStatus, strReply, false) << std::flush;
}
-bool ClientAllowed(const string& strAddress)
+bool ClientAllowed(const boost::asio::ip::address& address)
{
- if (strAddress == asio::ip::address_v4::loopback().to_string())
+ // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses
+ if (address.is_v6()
+ && (address.to_v6().is_v4_compatible()
+ || address.to_v6().is_v4_mapped()))
+ return ClientAllowed(address.to_v6().to_v4());
+
+ if (address == asio::ip::address_v4::loopback()
+ || address == asio::ip::address_v6::loopback()
+ || (address.is_v4()
+ // Chech whether IPv4 addresses match 127.0.0.0/8 (loopback subnet)
+ && (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000))
return true;
+
+ const string strAddress = address.to_string();
const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
BOOST_FOREACH(string strAllow, vAllow)
if (WildcardMatch(strAddress, strAllow))
@@ -2593,9 +2609,10 @@ bool ClientAllowed(const string& strAddress)
//
// IOStream device that speaks SSL but can also speak non-SSL
//
+template <typename Protocol>
class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
public:
- SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
+ SSLIOStreamDevice(asio::ssl::stream<typename Protocol::socket> &streamIn, bool fUseSSLIn) : stream(streamIn)
{
fUseSSL = fUseSSLIn;
fNeedHandshake = fUseSSLIn;
@@ -2639,21 +2656,54 @@ public:
private:
bool fNeedHandshake;
bool fUseSSL;
- SSLStream& stream;
+ asio::ssl::stream<typename Protocol::socket>& stream;
};
class AcceptedConnection
{
- public:
- SSLStream sslStream;
- SSLIOStreamDevice d;
- iostreams::stream<SSLIOStreamDevice> stream;
+public:
+ virtual ~AcceptedConnection() {}
- ip::tcp::endpoint peer;
+ virtual std::iostream& stream() = 0;
+ virtual std::string peer_address_to_string() const = 0;
+ virtual void close() = 0;
+};
- AcceptedConnection(asio::io_service &io_service, ssl::context &context,
- bool fUseSSL) : sslStream(io_service, context), d(sslStream, fUseSSL),
- stream(d) { ; }
+template <typename Protocol>
+class AcceptedConnectionImpl : public AcceptedConnection
+{
+public:
+ AcceptedConnectionImpl(
+ asio::io_service& io_service,
+ ssl::context &context,
+ bool fUseSSL) :
+ sslStream(io_service, context),
+ _d(sslStream, fUseSSL),
+ _stream(_d)
+ {
+ }
+
+ virtual std::iostream& stream()
+ {
+ return _stream;
+ }
+
+ virtual std::string peer_address_to_string() const
+ {
+ return peer.address().to_string();
+ }
+
+ virtual void close()
+ {
+ _stream.close();
+ }
+
+ typename Protocol::endpoint peer;
+ asio::ssl::stream<typename Protocol::socket> sslStream;
+
+private:
+ SSLIOStreamDevice<Protocol> _d;
+ iostreams::stream< SSLIOStreamDevice<Protocol> > _stream;
};
void ThreadRPCServer(void* parg)
@@ -2675,6 +2725,82 @@ void ThreadRPCServer(void* parg)
printf("ThreadRPCServer exited\n");
}
+// Forward declaration required for RPCListen
+template <typename Protocol, typename SocketAcceptorService>
+static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
+ ssl::context& context,
+ bool fUseSSL,
+ AcceptedConnection* conn,
+ const boost::system::error_code& error);
+
+/**
+ * Sets up I/O resources to accept and handle a new connection.
+ */
+template <typename Protocol, typename SocketAcceptorService>
+static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
+ ssl::context& context,
+ const bool fUseSSL)
+{
+ // Accept connection
+ AcceptedConnectionImpl<Protocol>* conn = new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL);
+
+ acceptor->async_accept(
+ conn->sslStream.lowest_layer(),
+ conn->peer,
+ boost::bind(&RPCAcceptHandler<Protocol, SocketAcceptorService>,
+ acceptor,
+ boost::ref(context),
+ fUseSSL,
+ conn,
+ boost::asio::placeholders::error));
+}
+
+/**
+ * Accept and handle incoming connection.
+ */
+template <typename Protocol, typename SocketAcceptorService>
+static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
+ ssl::context& context,
+ const bool fUseSSL,
+ AcceptedConnection* conn,
+ const boost::system::error_code& error)
+{
+ vnThreadsRunning[THREAD_RPCLISTENER]++;
+
+ // Immediately start accepting new connections, except when we're canceled or our socket is closed.
+ if (error != asio::error::operation_aborted
+ && acceptor->is_open())
+ RPCListen(acceptor, context, fUseSSL);
+
+ AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn);
+
+ // TODO: Actually handle errors
+ if (error)
+ {
+ delete conn;
+ }
+
+ // Restrict callers by IP. It is important to
+ // do this before starting client thread, to filter out
+ // certain DoS and misbehaving clients.
+ else if (tcp_conn
+ && !ClientAllowed(tcp_conn->peer.address()))
+ {
+ // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
+ if (!fUseSSL)
+ conn->stream() << HTTPReply(403, "", false) << std::flush;
+ delete conn;
+ }
+
+ // start HTTP client thread
+ else if (!CreateThread(ThreadRPCServer3, conn)) {
+ printf("Failed to create RPC server client thread\n");
+ delete conn;
+ }
+
+ vnThreadsRunning[THREAD_RPCLISTENER]--;
+}
+
void ThreadRPCServer2(void* parg)
{
printf("ThreadRPCServer started\n");
@@ -2704,26 +2830,9 @@ void ThreadRPCServer2(void* parg)
return;
}
- bool fUseSSL = GetBoolArg("-rpcssl");
- asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
+ const bool fUseSSL = GetBoolArg("-rpcssl");
asio::io_service io_service;
- ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
- ip::tcp::acceptor acceptor(io_service);
- try
- {
- acceptor.open(endpoint.protocol());
- acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
- acceptor.bind(endpoint);
- acceptor.listen(socket_base::max_connections);
- }
- catch(boost::system::system_error &e)
- {
- uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
- _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
- StartShutdown();
- return;
- }
ssl::context context(io_service, ssl::context::sslv23);
if (fUseSSL)
@@ -2744,77 +2853,110 @@ void ThreadRPCServer2(void* parg)
SSL_CTX_set_cipher_list(context.impl(), strCiphers.c_str());
}
- loop
+ // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets
+ const bool loopback = !mapArgs.count("-rpcallowip");
+ asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any();
+ ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
+
+ boost::signals2::signal<void ()> StopRequests;
+
+ try
{
- // Accept connection
- AcceptedConnection *conn =
- new AcceptedConnection(io_service, context, fUseSSL);
+ boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(io_service));
+ acceptor->open(endpoint.protocol());
+ acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
- vnThreadsRunning[THREAD_RPCLISTENER]--;
- acceptor.accept(conn->sslStream.lowest_layer(), conn->peer);
- vnThreadsRunning[THREAD_RPCLISTENER]++;
+ // Try making the socket dual IPv6/IPv4 (if listening on the "any" address)
+ boost::system::error_code v6_only_error;
+ acceptor->set_option(boost::asio::ip::v6_only(loopback), v6_only_error);
- if (fShutdown)
- {
- delete conn;
- return;
- }
+ acceptor->bind(endpoint);
+ acceptor->listen(socket_base::max_connections);
- // Restrict callers by IP. It is important to
- // do this before starting client thread, to filter out
- // certain DoS and misbehaving clients.
- if (!ClientAllowed(conn->peer.address().to_string()))
- {
- // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
- if (!fUseSSL)
- conn->stream << HTTPReply(403, "", false) << std::flush;
- delete conn;
- }
+ RPCListen(acceptor, context, fUseSSL);
+ // Cancel outstanding listen-requests for this acceptor when shutting down
+ StopRequests.connect(signals2::slot<void ()>(
+ static_cast<void (ip::tcp::acceptor::*)()>(&ip::tcp::acceptor::close), acceptor.get())
+ .track(acceptor));
- // start HTTP client thread
- else if (!CreateThread(ThreadRPCServer3, conn)) {
- printf("Failed to create RPC server client thread\n");
- delete conn;
+ // If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately
+ if (loopback || v6_only_error)
+ {
+ bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any();
+ endpoint.address(bindAddress);
+
+ acceptor.reset(new ip::tcp::acceptor(io_service));
+ acceptor->open(endpoint.protocol());
+ acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ acceptor->bind(endpoint);
+ acceptor->listen(socket_base::max_connections);
+
+ RPCListen(acceptor, context, fUseSSL);
+ // Cancel outstanding listen-requests for this acceptor when shutting down
+ StopRequests.connect(signals2::slot<void ()>(
+ static_cast<void (ip::tcp::acceptor::*)()>(&ip::tcp::acceptor::close), acceptor.get())
+ .track(acceptor));
}
}
+ catch(boost::system::system_error &e)
+ {
+ uiInterface.ThreadSafeMessageBox(strprintf(_("An error occured while setting up the RPC port %i for listening: %s"), endpoint.port(), e.what()),
+ _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
+ StartShutdown();
+ return;
+ }
+
+ vnThreadsRunning[THREAD_RPCLISTENER]--;
+ while (!fShutdown)
+ io_service.run_one();
+ vnThreadsRunning[THREAD_RPCLISTENER]++;
+ StopRequests();
}
+static CCriticalSection cs_THREAD_RPCHANDLER;
+
void ThreadRPCServer3(void* parg)
{
IMPLEMENT_RANDOMIZE_STACK(ThreadRPCServer3(parg));
- vnThreadsRunning[THREAD_RPCHANDLER]++;
+ {
+ LOCK(cs_THREAD_RPCHANDLER);
+ vnThreadsRunning[THREAD_RPCHANDLER]++;
+ }
AcceptedConnection *conn = (AcceptedConnection *) parg;
bool fRun = true;
loop {
if (fShutdown || !fRun)
{
- conn->stream.close();
+ conn->close();
delete conn;
- --vnThreadsRunning[THREAD_RPCHANDLER];
+ {
+ LOCK(cs_THREAD_RPCHANDLER);
+ --vnThreadsRunning[THREAD_RPCHANDLER];
+ }
return;
}
map<string, string> mapHeaders;
string strRequest;
- ReadHTTP(conn->stream, mapHeaders, strRequest);
+ ReadHTTP(conn->stream(), mapHeaders, strRequest);
// Check authorization
if (mapHeaders.count("authorization") == 0)
{
- conn->stream << HTTPReply(401, "", false) << std::flush;
+ conn->stream() << HTTPReply(401, "", false) << std::flush;
break;
}
if (!HTTPAuthorized(mapHeaders))
{
- printf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer.address().to_string().c_str());
+ printf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string().c_str());
/* Deter brute-forcing short passwords.
If this results in a DOS the user really
shouldn't have their RPC port exposed.*/
if (mapArgs["-rpcpassword"].size() < 20)
Sleep(250);
- conn->stream << HTTPReply(401, "", false) << std::flush;
+ conn->stream() << HTTPReply(401, "", false) << std::flush;
break;
}
if (mapHeaders["connection"] == "close")
@@ -2856,22 +2998,25 @@ void ThreadRPCServer3(void* parg)
// Send reply
string strReply = JSONRPCReply(result, Value::null, id);
- conn->stream << HTTPReply(200, strReply, fRun) << std::flush;
+ conn->stream() << HTTPReply(200, strReply, fRun) << std::flush;
}
catch (Object& objError)
{
- ErrorReply(conn->stream, objError, id);
+ ErrorReply(conn->stream(), objError, id);
break;
}
catch (std::exception& e)
{
- ErrorReply(conn->stream, JSONRPCError(-32700, e.what()), id);
+ ErrorReply(conn->stream(), JSONRPCError(-32700, e.what()), id);
break;
}
}
delete conn;
- vnThreadsRunning[THREAD_RPCHANDLER]--;
+ {
+ LOCK(cs_THREAD_RPCHANDLER);
+ vnThreadsRunning[THREAD_RPCHANDLER]--;
+ }
}
json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
@@ -2917,9 +3062,9 @@ Object CallRPC(const string& strMethod, const Array& params)
asio::io_service io_service;
ssl::context context(io_service, ssl::context::sslv23);
context.set_options(ssl::context::no_sslv2);
- SSLStream sslStream(io_service, context);
- SSLIOStreamDevice d(sslStream, fUseSSL);
- iostreams::stream<SSLIOStreamDevice> stream(d);
+ asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
+ SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
+ iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);
if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
throw runtime_error("couldn't connect to server");
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 6f7a92bb25..2df647e83d 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -25,14 +25,11 @@ namespace Checkpoints
boost::assign::map_list_of
( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
- ( 68555, uint256("0x00000000001e1b4903550a0b96e9a9405c8a95f387162e4944e8d9fbe501cd6a"))
- ( 70567, uint256("0x00000000006a49b14bcf27462068f1264c961f11fa2e0eddd2be0791e1d4124a"))
( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
(105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
- (118000, uint256("0x000000000000774a7f8a7a12dc906ddb9e17e75d684f15e00f8767f9e8f36553"))
(134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
- (140700, uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd"))
(168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
+ (185333, uint256("0x00000000000002334c71b8706940c20348af897a9cfc0f1a6dab0d14d4ceb815"))
;
static MapCheckpoints mapCheckpointsTestnet =
diff --git a/src/init.cpp b/src/init.cpp
index 21c32a6d67..b25d52200f 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -222,6 +222,7 @@ std::string HelpMessage()
" -timeout=<n> " + _("Specify connection timeout (in milliseconds)") + "\n" +
" -proxy=<ip:port> " + _("Connect through socks proxy") + "\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" +
" -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" +
@@ -229,16 +230,16 @@ std::string HelpMessage()
" -connect=<ip> " + _("Connect only to the specified node(s)") + "\n" +
" -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\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" +
" -irc " + _("Find peers using internet relay chat (default: 0)") + "\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" +
- " -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" +
" -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" +
- " -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 10000)") + "\n" +
+ " -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)") + "\n" +
+ " -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 5000)") + "\n" +
#ifdef USE_UPNP
#if USE_UPNP
" -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n" +
@@ -255,7 +256,8 @@ std::string HelpMessage()
" -daemon " + _("Run in the background as a daemon and accept commands") + "\n" +
#endif
" -testnet " + _("Use the test network") + "\n" +
- " -debug " + _("Output extra debugging information") + "\n" +
+ " -debug " + _("Output extra debugging information. Implies all other -debug* options") + "\n" +
+ " -debugnet " + _("Output extra network debugging information") + "\n" +
" -logtimestamps " + _("Prepend debug output with timestamp") + "\n" +
" -printtoconsole " + _("Send trace/debug info to console instead of debug.log file") + "\n" +
#ifdef WIN32
@@ -476,8 +478,10 @@ bool AppInit2()
}
}
+ CService addrProxy;
+ bool fProxy = false;
if (mapArgs.count("-proxy")) {
- CService addrProxy = CService(mapArgs["-proxy"], 9050);
+ addrProxy = CService(mapArgs["-proxy"], 9050);
if (!addrProxy.IsValid())
return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"].c_str()));
@@ -490,6 +494,20 @@ bool AppInit2()
#endif
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
@@ -620,7 +638,7 @@ bool AppInit2()
if (GetBoolArg("-upgradewallet", fFirstRun))
{
int nMaxVersion = GetArg("-upgradewallet", 0);
- if (nMaxVersion == 0) // the -walletupgrade without argument case
+ if (nMaxVersion == 0) // the -upgradewallet without argument case
{
printf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = CLIENT_VERSION;
diff --git a/src/main.cpp b/src/main.cpp
index a49d2a06b4..d2cb154c1f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1325,8 +1325,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
// This logic is not necessary for memory pool transactions, as AcceptToMemoryPool
// already refuses previously-known transaction id's entirely.
// 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 || (fTestNet && pindex->nTime > 1329696000))
+ if (pindex->nTime > 1331769600)
{
BOOST_FOREACH(CTransaction& tx, vtx)
{
@@ -1340,8 +1339,8 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
}
}
- // BIP16 didn't become active until Apr 1 2012 (Feb 15 on testnet)
- int64 nBIP16SwitchTime = fTestNet ? 1329264000 : 1333238400;
+ // BIP16 didn't become active until Apr 1 2012
+ int64 nBIP16SwitchTime = 1333238400;
bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime);
//// issue here: it doesn't know the version
@@ -2427,7 +2426,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
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);
}
@@ -2575,11 +2574,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return error("message getdata size() = %d", vInv.size());
}
+ if (fDebugNet || (vInv.size() != 1))
+ printf("received getdata (%d invsz)\n", vInv.size());
+
BOOST_FOREACH(const CInv& inv, vInv)
{
if (fShutdown)
return true;
- printf("received getdata for: %s\n", inv.ToString().c_str());
+ if (fDebugNet || (vInv.size() == 1))
+ printf("received getdata for: %s\n", inv.ToString().c_str());
if (inv.type == MSG_BLOCK)
{
@@ -2633,25 +2636,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Send the rest of the chain
if (pindex)
pindex = pindex->pnext;
- int nLimit = 500 + locator.GetDistanceBack();
- unsigned int nBytes = 0;
+ int nLimit = 500;
printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
for (; pindex; pindex = pindex->pnext)
{
if (pindex->GetBlockHash() == hashStop)
{
- printf(" getblocks stopping at %d %s (%u bytes)\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str(), nBytes);
+ printf(" getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
break;
}
pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
- CBlock block;
- block.ReadFromDisk(pindex, true);
- nBytes += block.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION);
- if (--nLimit <= 0 || nBytes >= SendBufferSize()/2)
+ if (--nLimit <= 0)
{
// When this block is requested, we'll send an inv that'll make them
// getblocks the next batch of inventory.
- printf(" getblocks stopping at limit %d %s (%u bytes)\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str(), nBytes);
+ printf(" getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
pfrom->hashContinue = pindex->GetBlockHash();
break;
}
@@ -2911,6 +2910,10 @@ bool ProcessMessages(CNode* pfrom)
loop
{
+ // Don't bother if send buffer is too full to respond anyway
+ if (pfrom->vSend.size() >= SendBufferSize())
+ break;
+
// Scan for message start
CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
@@ -3159,8 +3162,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pto->PushMessage("getdata", vGetData);
vGetData.clear();
}
+ mapAlreadyAskedFor[inv] = nNow;
}
- mapAlreadyAskedFor[inv] = nNow;
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
if (!vGetData.empty())
diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw
index 51f49bb3cf..cd8e97080c 100644
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -39,7 +39,7 @@ ifdef USE_UPNP
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif
-LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi
+LIBS += -l mingwthrd -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi
# TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are
HEADERS = $(wildcard *.h)
diff --git a/src/makefile.mingw b/src/makefile.mingw
index 577c77b7d4..919be007b6 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -36,7 +36,7 @@ ifdef USE_UPNP
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif
-LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l shlwapi
+LIBS += -l kernel32 -l user32 -l gdi32 -l comdlg32 -l winspool -l winmm -l shell32 -l comctl32 -l ole32 -l oleaut32 -l uuid -l rpcrt4 -l advapi32 -l ws2_32 -l mswsock -l shlwapi
# TODO: make the mingw builds smarter about dependencies, like the linux/osx builds are
HEADERS = $(wildcard *.h)
diff --git a/src/net.cpp b/src/net.cpp
index 804cb0f543..f1073e0a3e 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -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
bool AddLocal(const CService& addr, int nScore)
{
@@ -228,9 +236,7 @@ bool AddLocal(const CService& addr, int nScore)
info.nScore = nScore;
info.nPort = addr.GetPort() + (fAlready ? 1 : 0);
}
- enum Network net = addr.GetNetwork();
- vfReachable[net] = true;
- if (net == NET_IPV6) vfReachable[NET_IPV4] = true;
+ SetReachable(addr.GetNetwork());
}
AdvertizeLocal();
@@ -543,6 +549,7 @@ void CNode::PushVersion()
CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0)));
CAddress addrMe = GetLocalAddress(&addr);
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,
nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight);
}
@@ -915,11 +922,8 @@ void ThreadSocketHandler2(void* parg)
pnode->CloseSocketDisconnect();
}
}
- if (vSend.size() > SendBufferSize()) {
- if (!pnode->fDisconnect)
- printf("socket send flood control disconnect (%d bytes)\n", vSend.size());
- pnode->CloseSocketDisconnect();
- }
+ if (vSend.size() > SendBufferSize())
+ printf("socket send buffer full warning (%d bytes)\n", vSend.size());
}
}
}
diff --git a/src/net.h b/src/net.h
index f059c7a448..fa6f700867 100644
--- a/src/net.h
+++ b/src/net.h
@@ -26,8 +26,8 @@ extern int nBestHeight;
-inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 10*1000); }
-inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
+inline unsigned int ReceiveBufferSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
+inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 5*1000); }
void AddOneShot(std::string strDest);
bool RecvLine(SOCKET hSocket, std::string& strLine);
@@ -64,6 +64,7 @@ bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
bool IsReachable(const CNetAddr &addr);
+void SetReachable(enum Network net, bool fFlag = true);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
diff --git a/src/netbase.cpp b/src/netbase.cpp
index ffd3ea68a5..aa767cd3eb 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -57,6 +57,15 @@ void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions, bool fAllowLookup)
{
vIP.clear();
+
+ {
+ CNetAddr addr;
+ if (addr.SetSpecial(std::string(pszName))) {
+ vIP.push_back(addr);
+ return true;
+ }
+ }
+
struct addrinfo aiHint;
memset(&aiHint, 0, sizeof(struct addrinfo));
@@ -530,6 +539,32 @@ void CNetAddr::SetIP(const CNetAddr& ipIn)
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()
{
Init();
@@ -576,7 +611,7 @@ bool CNetAddr::IsIPv4() const
bool CNetAddr::IsIPv6() const
{
- return (!IsIPv4());
+ return (!IsIPv4() && !IsTor() && !IsI2P());
}
bool CNetAddr::IsRFC1918() const
@@ -635,15 +670,13 @@ bool CNetAddr::IsRFC4843() const
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);
}
-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);
}
@@ -705,7 +738,7 @@ bool CNetAddr::IsValid() 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
@@ -716,10 +749,10 @@ enum Network CNetAddr::GetNetwork() const
if (IsIPv4())
return NET_IPV4;
- if (IsOnionCat())
+ if (IsTor())
return NET_TOR;
- if (IsGarliCat())
+ if (IsI2P())
return NET_I2P;
return NET_IPV6;
@@ -727,6 +760,10 @@ enum Network CNetAddr::GetNetwork() 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);
#ifdef USE_IPV6
struct sockaddr_storage sockaddr;
@@ -739,7 +776,7 @@ std::string CNetAddr::ToStringIP() const
if (!getnameinfo((const struct sockaddr*)&sockaddr, socklen, name, sizeof(name), NULL, 0, NI_NUMERICHOST))
return std::string(name);
}
- if (IsIPv4())
+ if (IsIPv4())
return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
else
return strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
@@ -828,6 +865,18 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
vchRet.push_back(GetByte(2) ^ 0xFF);
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
else if (GetByte(15) == 0x20 && GetByte(14) == 0x11 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
nBits = 36;
@@ -861,27 +910,82 @@ void CNetAddr::print() const
printf("CNetAddr(%s)\n", ToString().c_str());
}
-// for IPv6 partners: for unknown/Teredo partners: for IPv4 partners:
-// 0 - unroutable // 0 - unroutable // 0 - unroutable
-// 1 - teredo // 1 - teredo // 1 - ipv4
-// 2 - tunneled ipv6 // 2 - tunneled ipv6
-// 3 - ipv4 // 3 - ipv6
-// 4 - ipv6 // 4 - ipv4
+// private extensions to enum Network, only returned by GetExtNetwork,
+// and only used in GetReachabilityFrom
+static const int NET_UNKNOWN = NET_MAX + 0;
+static const int NET_TEREDO = NET_MAX + 1;
+int static GetExtNetwork(const CNetAddr *addr)
+{
+ 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
{
- if (!IsValid() || !IsRoutable())
- return 0;
- if (paddrPartner && paddrPartner->IsIPv4())
- return IsIPv4() ? 1 : 0;
- if (IsRFC4380())
- return 1;
- if (IsRFC3964() || IsRFC6052())
- return 2;
- bool fRealIPv6 = paddrPartner && !paddrPartner->IsRFC4380() && paddrPartner->IsValid() && paddrPartner->IsRoutable();
- if (fRealIPv6)
- return IsIPv4() ? 3 : 4;
- else
- return IsIPv4() ? 4 : 3;
+ enum Reachability {
+ REACH_UNREACHABLE,
+ REACH_DEFAULT,
+ REACH_TEREDO,
+ REACH_IPV6_WEAK,
+ REACH_IPV4,
+ REACH_IPV6_STRONG,
+ REACH_PRIVATE
+ };
+
+ if (!IsRoutable())
+ return REACH_UNREACHABLE;
+
+ 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()
@@ -1036,7 +1140,7 @@ std::string CService::ToStringPort() const
std::string CService::ToStringIPPort() const
{
- if (IsIPv4()) {
+ if (IsIPv4() || IsTor() || IsI2P()) {
return ToStringIP() + ":" + ToStringPort();
} else {
return "[" + ToStringIP() + "]:" + ToStringPort();
diff --git a/src/netbase.h b/src/netbase.h
index 7a797e2fd6..f097d7f5ae 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -25,7 +25,7 @@ enum Network
NET_TOR,
NET_I2P,
- NET_MAX
+ NET_MAX,
};
extern int nConnectTimeout;
@@ -44,8 +44,9 @@ class CNetAddr
explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false);
void Init();
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 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 IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
@@ -56,8 +57,8 @@ class CNetAddr
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
- bool IsOnionCat() const;
- bool IsGarliCat() const;
+ bool IsTor() const;
+ bool IsI2P() const;
bool IsLocal() const;
bool IsRoutable() const;
bool IsValid() const;
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 9c7b85451c..e28b96b090 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -14,6 +14,7 @@
#include <QIntValidator>
#include <QLabel>
#include <QLineEdit>
+#include <QLocale>
#include <QMessageBox>
#include <QPushButton>
#include <QRegExp>
@@ -62,7 +63,19 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
foreach(const QString &langStr, translations.entryList())
{
- ui->lang->addItem(langStr, QVariant(langStr));
+ QLocale locale(langStr);
+
+ /** check if the locale name consists of 2 parts (language_country) */
+ if(langStr.contains("_"))
+ {
+ /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */
+ ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
+ }
+ else
+ {
+ /** display language strings as "language (locale name)", e.g. "German (de)" */
+ ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
+ }
}
ui->unit->setModel(new BitcoinUnits(this));
diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp
index 0d8a366d7a..b14e9f7057 100644
--- a/src/test/Checkpoints_tests.cpp
+++ b/src/test/Checkpoints_tests.cpp
@@ -15,20 +15,20 @@ BOOST_AUTO_TEST_SUITE(Checkpoints_tests)
BOOST_AUTO_TEST_CASE(sanity)
{
uint256 p11111 = uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d");
- uint256 p140700 = uint256("0x000000000000033b512028abb90e1626d8b346fd0ed598ac0a3c371138dce2bd");
+ uint256 p134444 = uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe");
BOOST_CHECK(Checkpoints::CheckBlock(11111, p11111));
- BOOST_CHECK(Checkpoints::CheckBlock(140700, p140700));
+ BOOST_CHECK(Checkpoints::CheckBlock(134444, p134444));
// Wrong hashes at checkpoints should fail:
- BOOST_CHECK(!Checkpoints::CheckBlock(11111, p140700));
- BOOST_CHECK(!Checkpoints::CheckBlock(140700, p11111));
+ BOOST_CHECK(!Checkpoints::CheckBlock(11111, p134444));
+ BOOST_CHECK(!Checkpoints::CheckBlock(134444, p11111));
// ... but any hash not at a checkpoint should succeed:
- BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p140700));
- BOOST_CHECK(Checkpoints::CheckBlock(140700+1, p11111));
+ BOOST_CHECK(Checkpoints::CheckBlock(11111+1, p134444));
+ BOOST_CHECK(Checkpoints::CheckBlock(134444+1, p11111));
- BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 140700);
+ BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate() >= 134444);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
new file mode 100644
index 0000000000..fdf3285913
--- /dev/null
+++ b/src/test/base32_tests.cpp
@@ -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()
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index f0828f39fc..e5a7562d97 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -34,7 +34,7 @@ BOOST_AUTO_TEST_CASE(netbase_properties)
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").IsOnionCat());
+ 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());
@@ -88,4 +88,15 @@ BOOST_AUTO_TEST_CASE(netbase_lookupnumeric)
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()
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 7a438e5d51..e6c00e39d8 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -34,9 +34,9 @@ BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture)
rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
// old, 65-byte-long:
- const char* address1Hex = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
+ const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
// new, compressed:
- const char* address2Hex = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
+ const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
Value v;
CBitcoinAddress address;
@@ -62,7 +62,7 @@ BOOST_FIXTURE_TEST_CASE(rpc_addmultisig, TestNetFixture)
string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing
BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error);
- string short2(address1Hex+2, address1Hex+sizeof(address1Hex)); // first byte missing
+ string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing
BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
}
diff --git a/src/ui_interface.h b/src/ui_interface.h
index b94446cc20..0f7fdef264 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -1,4 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
+// Copyright (c) 2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UI_INTERFACE_H
@@ -61,10 +62,10 @@ public:
/** Show message box. */
boost::signals2::signal<void (const std::string& message, const std::string& caption, int style)> ThreadSafeMessageBox;
- /** Ask the user whether he want to pay a fee or not. */
+ /** Ask the user whether they want to pay a fee or not. */
boost::signals2::signal<bool (int64 nFeeRequired, const std::string& strCaption), boost::signals2::last_value<bool> > ThreadSafeAskFee;
- /** Handle an URL passed on the command line. */
+ /** Handle a URL passed at the command line. */
boost::signals2::signal<void (const std::string& strURI)> ThreadSafeHandleURI;
/** Progress message during initialization. */
diff --git a/src/util.cpp b/src/util.cpp
index 4b1c1ae116..9d0f9ab347 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -703,6 +703,193 @@ string DecodeBase64(const string& str)
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)
{
diff --git a/src/util.h b/src/util.h
index 21bec68ae0..7b2c678916 100644
--- a/src/util.h
+++ b/src/util.h
@@ -147,6 +147,10 @@ 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);
+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[]);
bool WildcardMatch(const char* psz, const char* mask);
bool WildcardMatch(const std::string& str, const std::string& mask);