diff --git a/src/Application.cpp b/src/Application.cpp index 05ea8e446d..ebca2d4524 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -1,11 +1,4 @@ -#include - -#include -#include - -#include "../database/SqliteDatabase.h" - #include "Application.h" #include "Config.h" #include "PeerDoor.h" @@ -14,9 +7,16 @@ #include "key.h" #include "utils.h" #include "TaggedCache.h" -#include "boost/filesystem.hpp" #include "Log.h" +#include "../database/SqliteDatabase.h" + +#include + +#include +#include +#include + Application* theApp = NULL; DatabaseCon::DatabaseCon(const std::string& strName, const char *initStrings[], int initCount) @@ -52,7 +52,7 @@ void Application::stop() { mIOService.stop(); - std::cerr << "Stopped: " << mIOService.stopped() << std::endl; + Log(lsINFO) << "Stopped: " << mIOService.stopped(); } static void InitDB(DatabaseCon** dbCon, const char *fileName, const char *dbInit[], int dbCount) @@ -111,6 +111,8 @@ void Application::run() std::cerr << "RPC interface: disabled" << std::endl; } + mWSDoor = WSDoor::createWSDoor(); + // // Begin connecting to network. // @@ -122,8 +124,8 @@ void Application::run() NewcoinAddress rootAddress = NewcoinAddress::createAccountPublic(rootGeneratorMaster, 0); // Print enough information to be able to claim root account. - std::cerr << "Root master seed: " << rootSeedMaster.humanSeed() << std::endl; - std::cerr << "Root account: " << rootAddress.humanAccountID() << std::endl; + Log(lsINFO) << "Root master seed: " << rootSeedMaster.humanSeed(); + Log(lsINFO) << "Root account: " << rootAddress.humanAccountID(); Ledger::pointer firstLedger = boost::make_shared(rootAddress, SYSTEM_CURRENCY_START); assert(!!firstLedger->getAccountState(rootAddress)); @@ -141,6 +143,8 @@ void Application::run() mIOService.run(); // This blocks + mWSDoor->stop(); + std::cout << "Done." << std::endl; } diff --git a/src/Application.h b/src/Application.h index ec00b94e89..629976dadb 100644 --- a/src/Application.h +++ b/src/Application.h @@ -12,6 +12,7 @@ #include "Wallet.h" #include "Peer.h" #include "NetworkOPs.h" +#include "WSDoor.h" #include "TaggedCache.h" #include "ValidationCollection.h" #include "Suppression.h" @@ -54,6 +55,7 @@ class Application ConnectionPool mConnectionPool; PeerDoor* mPeerDoor; RPCDoor* mRPCDoor; + WSDoor* mWSDoor; uint256 mNonce256; std::size_t mNonceST; diff --git a/src/Config.cpp b/src/Config.cpp index c49b5a13d2..41030c187b 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -118,6 +118,7 @@ void Config::setup(const std::string& strConf) PEER_PORT = SYSTEM_PEER_PORT; RPC_PORT = 5001; + WEBSOCKET_PORT = SYSTEM_WEBSOCKET_PORT; NUMBER_CONNECTIONS = 30; // a new ledger every minute diff --git a/src/Config.h b/src/Config.h index 3a0948ddf8..44eb864e57 100644 --- a/src/Config.h +++ b/src/Config.h @@ -22,7 +22,9 @@ #define DEFAULT_VALIDATORS_SITE "redstem.com" #define VALIDATORS_FILE_NAME "validators.txt" -const int SYSTEM_PEER_PORT = 6561; + +const int SYSTEM_PEER_PORT = 6561; +const int SYSTEM_WEBSOCKET_PORT = 6562; // Allow anonymous DH. #define DEFAULT_PEER_SSL_CIPHER_LIST "ALL:!LOW:!EXP:!MD5:@STRENGTH" @@ -76,7 +78,7 @@ public: int PEER_START_MAX; int PEER_CONNECT_LOW_WATER; - // Client networking parameters + // Websocket networking parameters std::string WEBSOCKET_IP; int WEBSOCKET_PORT; @@ -96,7 +98,7 @@ public: uint64 FEE_NICKNAME_CREATE; // Fee to create a nickname. // Client behavior - int ACCOUNT_PROBE_MAX; // How far to scan for accounts. + int ACCOUNT_PROBE_MAX; // How far to scan for accounts. void setup(const std::string& strConf); void load(); diff --git a/src/HttpsClient.cpp b/src/HttpsClient.cpp index 5b9215cab6..26f027870a 100644 --- a/src/HttpsClient.cpp +++ b/src/HttpsClient.cpp @@ -169,7 +169,6 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult) { // std::cerr << "Connected." << std::endl; - mSocketSsl.lowest_layer().set_option(boost::asio::ip::tcp::no_delay(true)); mSocketSsl.set_verify_mode(boost::asio::ssl::verify_peer); // XXX Verify semantics of RFC 2818 are what we want. diff --git a/src/PeerDoor.cpp b/src/PeerDoor.cpp index 3ed7a6bd02..3544816729 100644 --- a/src/PeerDoor.cpp +++ b/src/PeerDoor.cpp @@ -49,7 +49,7 @@ void PeerDoor::startListening() void PeerDoor::handleConnect(Peer::pointer new_connection, const boost::system::error_code& error) { - if(!error) + if (!error) { new_connection->connected(error); } @@ -57,4 +57,5 @@ void PeerDoor::handleConnect(Peer::pointer new_connection, startListening(); } + // vim:ts=4 diff --git a/src/PeerDoor.h b/src/PeerDoor.h index 52b8fae1ee..ac472ee0e9 100644 --- a/src/PeerDoor.h +++ b/src/PeerDoor.h @@ -1,3 +1,6 @@ +#ifndef __PEERDOOR__ +#define __PEERDOOR__ + #include #include @@ -22,4 +25,7 @@ private: public: PeerDoor(boost::asio::io_service& io_service); }; + +#endif + // vim:ts=4 diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp new file mode 100644 index 0000000000..3b1dc53681 --- /dev/null +++ b/src/WSDoor.cpp @@ -0,0 +1,102 @@ + +#include "WSDoor.h" + +#include + +#include +#include + +#include "Application.h" +#include "Config.h" +#include "Log.h" +#include "utils.h" + +using namespace std; +using namespace boost::asio::ip; + +// Generate DH for SSL connection. +static DH* handleTmpDh(SSL* ssl, int is_export, int iKeyLength) +{ + return 512 == iKeyLength ? theApp->getWallet().getDh512() : theApp->getWallet().getDh1024(); +} + +// A single instance of this object is made. +// This instance dispatches all events. There is no per connection persistency. +template +class WSServerHandler : public endpoint_type::handler { +private: + boost::shared_ptr mCtx; + +public: + typedef typename endpoint_type::handler::connection_ptr connection_ptr; + typedef typename endpoint_type::handler::message_ptr message_ptr; + + WSServerHandler(boost::shared_ptr spCtx) : mCtx(spCtx) {} + + boost::shared_ptr on_tls_init() + { + return mCtx; + } + + void on_message(connection_ptr con, message_ptr msg) { + con->send(msg->get_payload(), msg->get_opcode()); + } + + void http(connection_ptr con) { + con->set_body("WebSocket++ TLS certificate test

WebSocket++ TLS certificate test

This is an HTTP(S) page served by a WebSocket++ server for the purposes of confirming that certificates are working since browsers normally silently ignore certificate issues.

"); + } +}; + +void WSDoor::startListening() +{ + boost::shared_ptr mCtx; + mCtx = boost::make_shared(boost::asio::ssl::context::sslv23); + + mCtx->set_options( + boost::asio::ssl::context::default_workarounds + | boost::asio::ssl::context::no_sslv2 + | boost::asio::ssl::context::single_dh_use); + + SSL_CTX_set_tmp_dh_callback(mCtx->native_handle(), handleTmpDh); + + websocketpp::server_tls::handler::ptr handler(new WSServerHandler(mCtx)); + mEndpoint = new websocketpp::server_tls(handler); + + Log(lsINFO) << "listening>"; + + mEndpoint->listen(boost::asio::ip::tcp::endpoint(address().from_string(theConfig.WEBSOCKET_IP), theConfig.WEBSOCKET_PORT)); + + free(mEndpoint); + + Log(lsINFO) << "listening<"; +} + +WSDoor* WSDoor::createWSDoor() +{ + WSDoor* wdpResult = new WSDoor(); + + if (!theConfig.WEBSOCKET_IP.empty() && theConfig.WEBSOCKET_PORT) + { + Log(lsINFO) << "Websocket: Listening: " << theConfig.WEBSOCKET_IP << " " << theConfig.WEBSOCKET_PORT; + + wdpResult->mThread = new boost::thread(boost::bind(&WSDoor::startListening, wdpResult)); + } + else + { + Log(lsINFO) << "Websocket: Disabled"; + } + + return wdpResult; +} + +void WSDoor::stop() +{ + if (mThread) + { + mEndpoint->stop(); // XXX Make this thread safe + + mThread->join(); + } +} + +// vim:ts=4 diff --git a/src/WSDoor.h b/src/WSDoor.h new file mode 100644 index 0000000000..86260ca851 --- /dev/null +++ b/src/WSDoor.h @@ -0,0 +1,32 @@ +#ifndef __WSDOOR__ +#define __WSDOOR__ + +#include "../websocketpp/src/sockets/tls.hpp" +#include "../websocketpp/src/websocketpp.hpp" + +#include +#include +#include +#include +#include + +class WSDoor +{ +private: + websocketpp::server_tls* mEndpoint; + boost::thread* mThread; + + void startListening(); + +public: + + WSDoor() : mEndpoint(0), mThread(0) { ; } + + void stop(); + + static WSDoor* createWSDoor(); +}; + +#endif + +// vim:ts=4