changeset 349:0ed96e0a2383 draft

Merge remote branch 'refs/remotes/svn/trunk' into svn
author Gavin Andresen <gavinandresen@gmail.com>
date Mon, 11 Oct 2010 15:15:09 -0400
parents 4aadb84ec62c (current diff) 6682367e6f12 (diff)
children 393232c22e1e
files init.cpp main.cpp makefile.osx makefile.unix rpc.cpp serialize.h util.cpp
diffstat 7 files changed, 162 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/init.cpp
+++ b/init.cpp
@@ -165,17 +165,31 @@
             "  bitcoin [options] help              \t\t  " + _("List commands\n") +
             "  bitcoin [options] help <command>    \t\t  " + _("Get help for a command\n") +
           _("Options:\n") +
-            "  -conf=<file>    \t  " + _("Specify configuration file (default: bitcoin.conf)\n") +
-            "  -gen            \t  " + _("Generate coins\n") +
-            "  -gen=0          \t  " + _("Don't generate coins\n") +
-            "  -min            \t  " + _("Start minimized\n") +
-            "  -datadir=<dir>  \t  " + _("Specify data directory\n") +
-            "  -proxy=<ip:port>\t  " + _("Connect through socks4 proxy\n") +
-            "  -addnode=<ip>   \t  " + _("Add a node to connect to\n") +
-            "  -connect=<ip>   \t  " + _("Connect only to the specified node\n") +
-            "  -server         \t  " + _("Accept command line and JSON-RPC commands\n") +
-            "  -daemon         \t  " + _("Run in the background as a daemon and accept commands\n") +
-            "  -?              \t  " + _("This help message\n");
+            "  -conf=<file>     \t  " + _("Specify configuration file (default: bitcoin.conf)\n") +
+            "  -gen             \t  " + _("Generate coins\n") +
+            "  -gen=0           \t  " + _("Don't generate coins\n") +
+            "  -min             \t  " + _("Start minimized\n") +
+            "  -datadir=<dir>   \t  " + _("Specify data directory\n") +
+            "  -proxy=<ip:port> \t  " + _("Connect through socks4 proxy\n") +
+            "  -addnode=<ip>    \t  " + _("Add a node to connect to\n") +
+            "  -connect=<ip>    \t  " + _("Connect only to the specified node\n") +
+            "  -server          \t  " + _("Accept command line and JSON-RPC commands\n") +
+            "  -daemon          \t  " + _("Run in the background as a daemon and accept commands\n") +
+            "  -rpcuser=<user>  \t  " + _("Username for JSON-RPC connections\n") +
+            "  -rpcpassword=<pw>\t  " + _("Password for JSON-RPC connections\n") +
+            "  -rpcport=<port>  \t  " + _("Listen for JSON-RPC connections on <port>\n") +
+            "  -rpcallowip=<ip> \t  " + _("Allow JSON-RPC connections from specified IP address\n") +
+            "  -rpcconnect=<ip> \t  " + _("Send commands to node running on <ip>\n") +
+            "  -?               \t  " + _("This help message\n");
+
+#ifdef USE_SSL
+        strUsage += string() +
+            _("\nSSL options: (see the Bitcoin Wiki for SSL setup instructions)\n") +
+            "  -rpcssl=1                             \t  " + _("Use OpenSSL (https) for JSON-RPC connections\n") +
+            "  -rpcsslcertificatchainfile=<file.cert>\t  " + _("Server certificate file (default: server.cert)\n") +
+            "  -rpcsslprivatekeyfile=<file.pem>      \t  " + _("Server private key (default: server.pem)\n") +
+            "  -rpcsslciphers=<ciphers>              \t  " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)\n");
+#endif
 
 #if defined(__WXMSW__) && defined(GUI)
         // Tabs make the columns line up in the message box
--- a/main.cpp
+++ b/main.cpp
@@ -2433,15 +2433,20 @@
     {
         // Nodes rebroadcast an addr every 24 hours
         pfrom->vAddrToSend.clear();
-        int64 nSince = GetAdjustedTime() - 6 * 60 * 60; // in the last 6 hours
+        int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours
         CRITICAL_BLOCK(cs_mapAddresses)
         {
+            unsigned int nCount = 0;
             foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
             {
-                if (fShutdown)
-                    return true;
                 const CAddress& addr = item.second;
                 if (addr.nTime > nSince)
+                    nCount++;
+            }
+            foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
+            {
+                const CAddress& addr = item.second;
+                if (addr.nTime > nSince && GetRand(nCount) < 2000)
                     pfrom->PushAddress(addr);
             }
         }
@@ -2780,7 +2785,7 @@
         vnThreadsRunning[3]--;
         PrintException(NULL, "ThreadBitcoinMiner()");
     }
-    UIThreadCall(bind(CalledSetStatusBar, "", 0));
+    UIThreadCall(boost::bind(CalledSetStatusBar, "", 0));
     nHPSTimerStart = 0;
     if (vnThreadsRunning[3] == 0)
         dHashesPerSec = 0;
@@ -3143,7 +3148,7 @@
                         nHPSTimerStart = GetTimeMillis();
                         nHashCounter = 0;
                         string strStatus = strprintf("    %.0f khash/s", dHashesPerSec/1000.0);
-                        UIThreadCall(bind(CalledSetStatusBar, strStatus, 0));
+                        UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0));
                         static int64 nLogTime;
                         if (GetTime() - nLogTime > 30 * 60)
                         {
--- a/makefile.osx
+++ b/makefile.osx
@@ -22,9 +22,10 @@
  $(DEPSDIR)/lib/libboost_filesystem.a \
  $(DEPSDIR)/lib/libboost_program_options.a \
  $(DEPSDIR)/lib/libboost_thread.a \
+ $(DEPSDIR)/lib/libssl.a \
  $(DEPSDIR)/lib/libcrypto.a 
 
-DEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -D__WXMAC_OSX__ -DNOPCH -DMSG_NOSIGNAL=0
+DEFS=$(shell $(DEPSDIR)/bin/wx-config --cxxflags) -D__WXMAC_OSX__ -DNOPCH -DMSG_NOSIGNAL=0 -DUSE_SSL
 
 DEBUGFLAGS=-g -DwxDEBUG_LEVEL=0
 # ppc doesn't work because we don't support big-endian
--- a/makefile.unix
+++ b/makefile.unix
@@ -23,11 +23,12 @@
    -l boost_program_options \
    -l boost_thread \
    -l db_cxx \
+   -l ssl \
    -l crypto \
  -Wl,-Bdynamic \
    -l gthread-2.0
 
-DEFS=-D__WXGTK__ -DNOPCH -DFOURWAYSSE2
+DEFS=-D__WXGTK__ -DNOPCH -DFOURWAYSSE2 -DUSE_SSL
 DEBUGFLAGS=-g -D__WXDEBUG__
 CFLAGS=-O2 -Wno-invalid-offsetof -Wformat $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
 HEADERS=headers.h strlcpy.h serialize.h uint256.h util.h key.h bignum.h base58.h \
--- a/rpc.cpp
+++ b/rpc.cpp
@@ -5,6 +5,12 @@
 #include "headers.h"
 #undef printf
 #include <boost/asio.hpp>
+#include <boost/iostreams/concepts.hpp>
+#include <boost/iostreams/stream.hpp>
+#ifdef USE_SSL
+#include <boost/asio/ssl.hpp> 
+typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLStream;
+#endif
 #include "json/json_spirit_reader_template.h"
 #include "json/json_spirit_writer_template.h"
 #include "json/json_spirit_utils.h"
@@ -14,7 +20,7 @@
 // a certain size around 145MB.  If we need access to json_spirit outside this
 // file, we could use the compiled json_spirit option.
 
-using boost::asio::ip::tcp;
+using namespace boost::asio;
 using namespace json_spirit;
 
 void ThreadRPCServer2(void* parg);
@@ -777,7 +783,7 @@
         strMsg.c_str());
 }
 
-int ReadHTTPStatus(tcp::iostream& stream)
+int ReadHTTPStatus(std::basic_istream<char>& stream)
 {
     string str;
     getline(stream, str);
@@ -788,7 +794,7 @@
     return atoi(vWords[1].c_str());
 }
 
-int ReadHTTPHeader(tcp::iostream& stream, map<string, string>& mapHeadersRet)
+int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
 {
     int nLen = 0;
     loop
@@ -812,7 +818,7 @@
     return nLen;
 }
 
-int ReadHTTP(tcp::iostream& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
+int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
 {
     mapHeadersRet.clear();
     strMessageRet = "";
@@ -930,8 +936,59 @@
     return false;
 }
 
+#ifdef USE_SSL
+//
+// IOStream device that speaks SSL but can also speak non-SSL
+//
+class SSLIOStreamDevice : public iostreams::device<iostreams::bidirectional> {
+public:
+    SSLIOStreamDevice(SSLStream &streamIn, bool fUseSSLIn) : stream(streamIn)
+    {
+        fUseSSL = fUseSSLIn;
+        fNeedHandshake = fUseSSLIn;
+    }
 
+    void handshake(ssl::stream_base::handshake_type role)
+    {
+        if (!fNeedHandshake) return;
+        fNeedHandshake = false;
+        stream.handshake(role);
+    }
+    std::streamsize read(char* s, std::streamsize n)
+    {
+        handshake(ssl::stream_base::server); // HTTPS servers read first
+        if (fUseSSL) return stream.read_some(asio::buffer(s, n));
+        return stream.next_layer().read_some(asio::buffer(s, n));
+    }
+    std::streamsize write(const char* s, std::streamsize n)
+    {
+        handshake(ssl::stream_base::client); // HTTPS clients write first
+        if (fUseSSL) return asio::write(stream, asio::buffer(s, n));
+        return asio::write(stream.next_layer(), asio::buffer(s, n));
+    }
+    bool connect(const std::string& server, const std::string& port)
+    {
+        ip::tcp::resolver resolver(stream.get_io_service());
+        ip::tcp::resolver::query query(server.c_str(), port.c_str());
+        ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
+        ip::tcp::resolver::iterator end;
+        boost::system::error_code error = asio::error::host_not_found;
+        while (error && endpoint_iterator != end)
+        {
+            stream.lowest_layer().close();
+            stream.lowest_layer().connect(*endpoint_iterator++, error);
+        }
+        if (error)
+            return false;
+        return true;
+    }
 
+private:
+    bool fNeedHandshake;
+    bool fUseSSL;
+    SSLStream& stream;
+};
+#endif
 
 void ThreadRPCServer(void* parg)
 {
@@ -972,18 +1029,54 @@
         return;
     }
 
-    // Bind to loopback 127.0.0.1 so the socket can only be accessed locally
-    boost::asio::io_service io_service;
-    tcp::endpoint endpoint(mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback(), 8332);
-    tcp::acceptor acceptor(io_service, endpoint);
+    bool fUseSSL = (mapArgs.count("-rpcssl") > 0);
+    asio::ip::address bindAddress = mapArgs.count("-rpcallowip") ? asio::ip::address_v4::any() : asio::ip::address_v4::loopback();
+
+    asio::io_service io_service;
+    ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", 8332));
+    ip::tcp::acceptor acceptor(io_service, endpoint);
+
+#ifdef USE_SSL
+    ssl::context context(io_service, ssl::context::sslv23);
+    if (fUseSSL)
+    {
+        context.set_options(ssl::context::no_sslv2);
+        filesystem::path certfile = GetArg("-rpcsslcertificatechainfile", "server.cert");
+        if (!certfile.is_complete()) certfile = filesystem::path(GetDataDir()) / certfile;
+        if (filesystem::exists(certfile)) context.use_certificate_chain_file(certfile.string().c_str());
+        else printf("ThreadRPCServer ERROR: missing server certificate file %s\n", certfile.string().c_str());
+        filesystem::path pkfile = GetArg("-rpcsslprivatekeyfile", "server.pem");
+        if (!pkfile.is_complete()) pkfile = filesystem::path(GetDataDir()) / pkfile;
+        if (filesystem::exists(pkfile)) context.use_private_key_file(pkfile.string().c_str(), ssl::context::pem);
+        else printf("ThreadRPCServer ERROR: missing server private key file %s\n", pkfile.string().c_str());
+
+        string ciphers = GetArg("-rpcsslciphers",
+                                         "TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH");
+        SSL_CTX_set_cipher_list(context.impl(), ciphers.c_str());
+    }
+#else
+    if (fUseSSL)
+        throw runtime_error("-rpcssl=true, but bitcoin compiled without full openssl libraries.");
+#endif
 
     loop
     {
         // Accept connection
-        tcp::iostream stream;
-        tcp::endpoint peer;
+#ifdef USE_SSL
+        SSLStream sslStream(io_service, context);
+        SSLIOStreamDevice d(sslStream, fUseSSL);
+        iostreams::stream<SSLIOStreamDevice> stream(d);
+#else
+        ip::tcp::iostream stream;
+#endif
+
+        ip::tcp::endpoint peer;
         vnThreadsRunning[4]--;
+#ifdef USE_SSL
+        acceptor.accept(sslStream.lowest_layer(), peer);
+#else
         acceptor.accept(*stream.rdbuf(), peer);
+#endif
         vnThreadsRunning[4]++;
         if (fShutdown)
             return;
@@ -1102,9 +1195,25 @@
                 GetConfigFile().c_str()));
 
     // Connect to localhost
-    tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), "8332");
+    bool fUseSSL = (mapArgs.count("-rpcssl") > 0);
+#ifdef USE_SSL
+    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);
+    if (!d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332")))
+        throw runtime_error("couldn't connect to server");
+#else
+    if (fUseSSL)
+        throw runtime_error("-rpcssl=true, but bitcoin compiled without full openssl libraries.");
+
+    ip::tcp::iostream stream(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", "8332"));
     if (stream.fail())
         throw runtime_error("couldn't connect to server");
+#endif
+
 
     // HTTP basic authentication
     string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
--- a/serialize.h
+++ b/serialize.h
@@ -22,7 +22,7 @@
 class CAutoFile;
 static const unsigned int MAX_SIZE = 0x02000000;
 
-static const int VERSION = 31303;
+static const int VERSION = 31304;
 static const char* pszSubVer = "";
 
 
--- a/util.cpp
+++ b/util.cpp
@@ -572,7 +572,7 @@
     strMiscWarning = pszMessage;
 #ifdef GUI
     if (wxTheApp && !fDaemon)
-        boost::thread(bind(ThreadOneMessageBox, string(pszMessage)));
+        boost::thread(boost::bind(ThreadOneMessageBox, string(pszMessage)));
 #endif
 }
 
@@ -807,7 +807,7 @@
                 string strMessage = _("Warning: Please check that your computer's date and time are correct.  If your clock is wrong Bitcoin will not work properly.");
                 strMiscWarning = strMessage;
                 printf("*** %s\n", strMessage.c_str());
-                boost::thread(bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
+                boost::thread(boost::bind(ThreadSafeMessageBox, strMessage+" ", string("Bitcoin"), wxOK | wxICON_EXCLAMATION, (wxWindow*)NULL, -1, -1));
             }
         }
         foreach(int64 n, vTimeOffsets)