diff --git a/newcoin.vcxproj b/newcoin.vcxproj
index 5b3889f069..83c3483efb 100644
--- a/newcoin.vcxproj
+++ b/newcoin.vcxproj
@@ -143,6 +143,7 @@
+
@@ -184,6 +185,7 @@
+
@@ -295,6 +297,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters
index f8070562c7..f7dfc590ef 100644
--- a/newcoin.vcxproj.filters
+++ b/newcoin.vcxproj.filters
@@ -31,6 +31,9 @@
{92775c5f-dc9f-4a97-a9a6-6d4bd4e424b4}
+
+ {cd4c41c0-3ee6-49f8-8322-d11422b892f9}
+
@@ -351,6 +354,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
@@ -656,6 +665,39 @@
Header Files
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
+
+ Header Files\websocket
+
diff --git a/src/cpp/ripple/Application.cpp b/src/cpp/ripple/Application.cpp
index 91dacfb385..d8b7b8fa31 100644
--- a/src/cpp/ripple/Application.cpp
+++ b/src/cpp/ripple/Application.cpp
@@ -45,8 +45,8 @@ Application::Application() :
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mWSPublicDoor(NULL), mWSPrivateDoor(NULL),
mSweepTimer(mAuxService)
{
- RAND_bytes(mNonce256.begin(), mNonce256.size());
- RAND_bytes(reinterpret_cast(&mNonceST), sizeof(mNonceST));
+ getRand(mNonce256.begin(), mNonce256.size());
+ getRand(reinterpret_cast(&mNonceST), sizeof(mNonceST));
mJobQueue.setThreadCount();
mSweepTimer.expires_from_now(boost::posix_time::seconds(60));
mSweepTimer.async_wait(boost::bind(&Application::sweep, this));
diff --git a/src/cpp/ripple/Config.cpp b/src/cpp/ripple/Config.cpp
index 03c5453321..cede9d2486 100644
--- a/src/cpp/ripple/Config.cpp
+++ b/src/cpp/ripple/Config.cpp
@@ -39,6 +39,10 @@
#define SECTION_WEBSOCKET_PUBLIC_PORT "websocket_public_port"
#define SECTION_WEBSOCKET_IP "websocket_ip"
#define SECTION_WEBSOCKET_PORT "websocket_port"
+#define SECTION_WEBSOCKET_SECURE "websocket_secure"
+#define SECTION_WEBSOCKET_SSL_CERT "websocket_ssl_cert"
+#define SECTION_WEBSOCKET_SSL_CHAIN "websocket_ssl_chain"
+#define SECTION_WEBSOCKET_SSL_KEY "websocket_ssl_key"
#define SECTION_VALIDATORS "validators"
#define SECTION_VALIDATORS_SITE "validators_site"
@@ -134,6 +138,7 @@ void Config::setup(const std::string& strConf, bool bQuiet)
RPC_PORT = 5001;
WEBSOCKET_PORT = SYSTEM_WEBSOCKET_PORT;
WEBSOCKET_PUBLIC_PORT = SYSTEM_WEBSOCKET_PUBLIC_PORT;
+ WEBSOCKET_SECURE = false;
NUMBER_CONNECTIONS = 30;
// a new ledger every minute
@@ -256,6 +261,14 @@ void Config::load()
if (sectionSingleB(secConfig, SECTION_WEBSOCKET_PUBLIC_PORT, strTemp))
WEBSOCKET_PUBLIC_PORT = boost::lexical_cast(strTemp);
+ if (sectionSingleB(secConfig, SECTION_WEBSOCKET_SECURE, strTemp))
+ WEBSOCKET_SECURE = boost::lexical_cast(strTemp);
+
+ sectionSingleB(secConfig, SECTION_WEBSOCKET_SSL_CERT, WEBSOCKET_SSL_CERT);
+ sectionSingleB(secConfig, SECTION_WEBSOCKET_SSL_CHAIN, WEBSOCKET_SSL_CHAIN);
+ sectionSingleB(secConfig, SECTION_WEBSOCKET_SSL_KEY, WEBSOCKET_SSL_KEY);
+
+
if (sectionSingleB(secConfig, SECTION_VALIDATION_SEED, strTemp))
{
VALIDATION_SEED.setSeedGeneric(strTemp);
diff --git a/src/cpp/ripple/Config.h b/src/cpp/ripple/Config.h
index b7e4898c03..bd3c9c56e5 100644
--- a/src/cpp/ripple/Config.h
+++ b/src/cpp/ripple/Config.h
@@ -91,6 +91,10 @@ public:
std::string WEBSOCKET_IP;
int WEBSOCKET_PORT;
+ bool WEBSOCKET_SECURE;
+ std::string WEBSOCKET_SSL_CERT;
+ std::string WEBSOCKET_SSL_CHAIN;
+ std::string WEBSOCKET_SSL_KEY;
// RPC parameters
std::string RPC_IP;
diff --git a/src/cpp/ripple/ECIES.cpp b/src/cpp/ripple/ECIES.cpp
index 447794f93a..ac9c371550 100644
--- a/src/cpp/ripple/ECIES.cpp
+++ b/src/cpp/ripple/ECIES.cpp
@@ -116,8 +116,7 @@ std::vector CKey::encryptECIES(CKey& otherKey, const std::vector<
{
ECIES_ENC_IV_TYPE iv;
- if (RAND_bytes(static_cast(iv.begin()), ECIES_ENC_BLK_SIZE) != 1)
- throw std::runtime_error("insufficient entropy");
+ getRand(static_cast(iv.begin()), ECIES_ENC_BLK_SIZE);
ECIES_ENC_KEY_TYPE secret;
ECIES_HMAC_KEY_TYPE hmacKey;
@@ -280,8 +279,7 @@ bool checkECIES(void)
std::vector message(4096);
int msglen = i%3000;
- if (RAND_bytes(static_cast(&message.front()), msglen) != 1)
- throw std::runtime_error("insufficient entropy");
+ getRand(static_cast(&message.front()), msglen);
message.resize(msglen);
// encrypt message with sender's private key and recipient's public key
diff --git a/src/cpp/ripple/NetworkOPs.cpp b/src/cpp/ripple/NetworkOPs.cpp
index 9ec450ddfc..54566429fc 100644
--- a/src/cpp/ripple/NetworkOPs.cpp
+++ b/src/cpp/ripple/NetworkOPs.cpp
@@ -867,8 +867,10 @@ void NetworkOPs::consensusViewChange()
void NetworkOPs::setMode(OperatingMode om)
{
if (mMode == om) return;
+
if ((om >= omCONNECTED) && (mMode == omDISCONNECTED))
mConnectTime = boost::posix_time::second_clock::universal_time();
+
Log lg((om < mMode) ? lsWARNING : lsINFO);
if (om == omDISCONNECTED)
lg << "STATE->Disconnected";
@@ -878,6 +880,25 @@ void NetworkOPs::setMode(OperatingMode om)
lg << "STATE->Tracking";
else
lg << "STATE->Full";
+
+ if ((om == omDISCONNECTED) || (mMode == omDISCONNECTED))
+ {
+ boost::recursive_mutex::scoped_lock sl(mMonitorLock);
+
+ if (!mSubServer.empty())
+ {
+ Json::Value jvObj(Json::objectValue);
+
+ jvObj["type"] = "serverStatus";
+ jvObj["server_status"] = om >= omCONNECTED ? "ok" : "noNetwork";
+
+ BOOST_FOREACH(InfoSub* ispListener, mSubServer)
+ {
+ ispListener->send(jvObj);
+ }
+ }
+ }
+
mMode = om;
}
@@ -1311,19 +1332,8 @@ bool NetworkOPs::subServer(InfoSub* ispListener, Json::Value& jvResult)
jvResult["stand_alone"] = theConfig.RUN_STANDALONE;
- switch (RAND_bytes(uRandom.begin(), uRandom.size()))
- {
- case 0:
- case 1:
- jvResult["random"] = uRandom.ToString();
- break;
-
- case -1:
- default:
- // XXX Should probably stop running.
- cLog(lsFATAL) << "Internal error: unable to generate secure random.";
- break;
- }
+ getRand(uRandom.begin(), uRandom.size());
+ jvResult["random"] = uRandom.ToString();
return mSubServer.insert(ispListener).second;
}
diff --git a/src/cpp/ripple/ProofOfWork.cpp b/src/cpp/ripple/ProofOfWork.cpp
index 1e4ab5d9b1..9f68929649 100644
--- a/src/cpp/ripple/ProofOfWork.cpp
+++ b/src/cpp/ripple/ProofOfWork.cpp
@@ -61,7 +61,7 @@ uint256 ProofOfWork::solve(int maxIterations) const
throw std::runtime_error("invalid proof of work target/iteration");
uint256 nonce;
- RAND_bytes(nonce.begin(), nonce.size());
+ getRand(nonce.begin(), nonce.size());
std::vector buf2;
buf2.resize(mIterations);
@@ -112,7 +112,7 @@ bool ProofOfWork::checkSolution(const uint256& solution) const
ProofOfWorkGenerator::ProofOfWorkGenerator() : mValidTime(180)
{
setDifficulty(1);
- RAND_bytes(mSecret.begin(), mSecret.size());
+ getRand(mSecret.begin(), mSecret.size());
}
ProofOfWork ProofOfWorkGenerator::getProof()
@@ -123,7 +123,7 @@ ProofOfWork ProofOfWorkGenerator::getProof()
int now = static_cast(time(NULL) / 4);
uint256 challenge;
- RAND_bytes(challenge.begin(), challenge.size());
+ getRand(challenge.begin(), challenge.size());
boost::mutex::scoped_lock sl(mLock);
diff --git a/src/cpp/ripple/RPCErr.cpp b/src/cpp/ripple/RPCErr.cpp
index 4e1eecc127..cbc699a4a3 100644
--- a/src/cpp/ripple/RPCErr.cpp
+++ b/src/cpp/ripple/RPCErr.cpp
@@ -58,7 +58,6 @@ Json::Value rpcError(int iError, Json::Value jvResult)
{ rpcSRC_ACT_MISSING, "srcActMissing", "Source account does not exist." },
{ rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." },
{ rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." },
- { rpcSUCCESS, "success", "Success." },
{ rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." },
{ rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown command." },
{ rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." },
diff --git a/src/cpp/ripple/RPCErr.h b/src/cpp/ripple/RPCErr.h
index d77cc24355..0059b35a45 100644
--- a/src/cpp/ripple/RPCErr.h
+++ b/src/cpp/ripple/RPCErr.h
@@ -4,8 +4,7 @@
#include "../json/value.h"
enum {
- rpcSUCCESS,
-
+ rpcSUCCESS = 0,
rpcBAD_SYNTAX, // Must be 1 to print usage to command line.
rpcJSON_RPC,
diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp
index 0fdc086086..c633ede404 100644
--- a/src/cpp/ripple/RPCHandler.cpp
+++ b/src/cpp/ripple/RPCHandler.cpp
@@ -664,24 +664,16 @@ Json::Value RPCHandler::doRandom(Json::Value jvRequest)
{
uint256 uRandom;
- switch (RAND_bytes(uRandom.begin(), uRandom.size()))
+ try
{
- case 0:
- case 1:
- {
- Json::Value jvResult;
-
- jvResult["random"] = uRandom.ToString();
-
- return jvResult;
- }
- break;
-
- case -1:
- return rpcError(rpcNOT_SUPPORTED);
-
- default:
- return rpcError(rpcINTERNAL);
+ getRand(uRandom.begin(), uRandom.size());
+ Json::Value jvResult;
+ jvResult["random"] = uRandom.ToString();
+ return jvResult;
+ }
+ catch (...)
+ {
+ return rpcError(rpcINTERNAL);
}
}
@@ -1572,7 +1564,7 @@ Json::Value RPCHandler::doLogLevel(Json::Value jvRequest)
if (!jvRequest.isMember("partition"))
{ // set base log severity
Log::setMinSeverity(sv, true);
- return rpcError(rpcSUCCESS);
+ return Json::objectValue;
}
// log_level partition severity base?
@@ -1584,7 +1576,7 @@ Json::Value RPCHandler::doLogLevel(Json::Value jvRequest)
else if (!LogPartition::setSeverity(partition, sv))
return rpcError(rpcINVALID_PARAMS);
- return rpcError(rpcSUCCESS);
+ return Json::objectValue;
}
return rpcError(rpcINVALID_PARAMS);
@@ -2092,6 +2084,7 @@ Json::Value RPCHandler::doSubscribe(Json::Value jvRequest)
if(streamName=="server")
{
mNetOps->subServer(mInfoSub, jvResult);
+ jvResult["server_status"] = mNetOps->available() ? "ok" : "noNetwork";
}else if(streamName=="ledger")
{
mNetOps->subLedger(mInfoSub, jvResult);
diff --git a/src/cpp/ripple/RippleAddress.cpp b/src/cpp/ripple/RippleAddress.cpp
index ecb152857e..7841f322e5 100644
--- a/src/cpp/ripple/RippleAddress.cpp
+++ b/src/cpp/ripple/RippleAddress.cpp
@@ -792,7 +792,7 @@ void RippleAddress::setSeedRandom()
// XXX Maybe we should call MakeNewKey
uint128 key;
- RAND_bytes(key.begin(), key.size());
+ getRand(key.begin(), key.size());
RippleAddress::setSeed(key);
}
diff --git a/src/cpp/ripple/SNTPClient.cpp b/src/cpp/ripple/SNTPClient.cpp
index d9663d134b..d99cee4e1f 100644
--- a/src/cpp/ripple/SNTPClient.cpp
+++ b/src/cpp/ripple/SNTPClient.cpp
@@ -78,7 +78,7 @@ void SNTPClient::resolveComplete(const boost::system::error_code& error, boost::
}
query.mReceivedReply = false;
query.mLocalTimeSent = now;
- RAND_bytes(reinterpret_cast(&query.mQueryNonce), sizeof(query.mQueryNonce));
+ getRand(reinterpret_cast(&query.mQueryNonce), sizeof(query.mQueryNonce));
reinterpret_cast(SNTPQueryData)[NTP_OFF_XMITTS_INT] = time(NULL) + NTP_UNIX_OFFSET;
reinterpret_cast(SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.mQueryNonce;
mSocket.async_send_to(boost::asio::buffer(SNTPQueryData, 48), *sel,
diff --git a/src/cpp/ripple/WSConnection.cpp b/src/cpp/ripple/WSConnection.cpp
deleted file mode 100644
index f217f07dae..0000000000
--- a/src/cpp/ripple/WSConnection.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// WSConnection
-//
-
-#include "Log.h"
-
-SETUP_LOG();
-
-#include "CallRPC.h" // XXX Remove this, don't provide support for RPC syntax.
-#include "WSConnection.h"
-#include "WSHandler.h"
-
-#include "../json/reader.h"
-#include "../json/writer.h"
-
-WSConnection::~WSConnection()
-{
- mNetwork.unsubTransactions(this);
- mNetwork.unsubRTTransactions(this);
- mNetwork.unsubLedger(this);
- mNetwork.unsubServer(this);
- mNetwork.unsubAccount(this, mSubAccountInfo, true);
- mNetwork.unsubAccount(this, mSubAccountInfo, false);
-}
-
-void WSConnection::send(const Json::Value& jvObj)
-{
- mHandler->send(mConnection, jvObj);
-}
-
-//
-// Utilities
-//
-
-Json::Value WSConnection::invokeCommand(Json::Value& jvRequest)
-{
- if (!jvRequest.isMember("command"))
- {
- Json::Value jvResult(Json::objectValue);
-
- jvResult["type"] = "response";
- jvResult["result"] = "error";
- jvResult["error"] = "missingCommand";
- jvResult["command"] = jvRequest;
-
- return jvResult;
- }
-
- RPCHandler mRPCHandler(&mNetwork, this);
- Json::Value jvResult(Json::objectValue);
-
- // XXX Temporarily support RPC style commands over websocket. Remove this.
- if (jvRequest.isMember("params"))
- {
- RPCParser rpParser;
-
- Json::Value jvRpcRequest = rpParser.parseCommand(jvRequest["command"].asString(), jvRequest["params"]);
-
- if (jvRpcRequest.isMember("error"))
- {
- jvResult = jvRpcRequest;
- }
- else
- {
- jvResult["result"] = mRPCHandler.doCommand(
- jvRpcRequest,
- mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN);
- }
- }
- else
- {
- jvResult["result"] = mRPCHandler.doCommand(
- jvRequest,
- mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN);
- }
-
- // Currently we will simply unwrap errors returned by the RPC
- // API, in the future maybe we can make the responses
- // consistent.
- //
- // Regularize result. This is duplicate code.
- if (jvResult["result"].isMember("error"))
- {
- jvResult = jvResult["result"];
- jvResult["status"] = "error";
- jvResult["request"] = jvRequest;
-
- } else {
- jvResult["status"] = "success";
- }
-
- if (jvRequest.isMember("id"))
- {
- jvResult["id"] = jvRequest["id"];
- }
-
- jvResult["type"] = "response";
-
- return jvResult;
-}
-
-// vim:ts=4
diff --git a/src/cpp/ripple/WSConnection.h b/src/cpp/ripple/WSConnection.h
index 2bc4914d4c..cd5b17a631 100644
--- a/src/cpp/ripple/WSConnection.h
+++ b/src/cpp/ripple/WSConnection.h
@@ -1,10 +1,14 @@
+
#include "../websocketpp/src/sockets/tls.hpp"
#include "../websocketpp/src/websocketpp.hpp"
+
+#include "../json/value.h"
+
#include "WSDoor.h"
#include "Application.h"
-
#include "Log.h"
#include "NetworkOPs.h"
+#include "CallRPC.h"
template
class WSServerHandler;
@@ -12,16 +16,17 @@ class WSServerHandler;
// Storage for connection specific info
// - Subscriptions
//
+template
class WSConnection : public InfoSub
{
public:
- typedef websocketpp::WSDOOR_SERVER::handler::connection_ptr connection_ptr;
- typedef websocketpp::WSDOOR_SERVER::handler::message_ptr message_ptr;
+ typedef typename endpoint_type::handler::connection_ptr connection_ptr;
+ typedef typename endpoint_type::handler::message_ptr message_ptr;
protected:
typedef void (WSConnection::*doFuncPtr)(Json::Value& jvResult, Json::Value &jvRequest);
- WSServerHandler* mHandler;
+ WSServerHandler* mHandler;
connection_ptr mConnection;
NetworkOPs& mNetwork;
@@ -30,17 +35,95 @@ public:
// : mHandler((WSServerHandler*)(NULL)),
// mConnection(connection_ptr()) { ; }
- WSConnection(WSServerHandler* wshpHandler, connection_ptr cpConnection)
+ WSConnection(WSServerHandler* wshpHandler, connection_ptr cpConnection)
: mHandler(wshpHandler), mConnection(cpConnection), mNetwork(theApp->getOPs()) { ; }
- virtual ~WSConnection();
+
+ virtual ~WSConnection()
+ {
+ mNetwork.unsubTransactions(this);
+ mNetwork.unsubRTTransactions(this);
+ mNetwork.unsubLedger(this);
+ mNetwork.unsubServer(this);
+ mNetwork.unsubAccount(this, mSubAccountInfo, true);
+ mNetwork.unsubAccount(this, mSubAccountInfo, false);
+ }
// Implement overridden functions from base class:
- void send(const Json::Value& jvObj);
+ void send(const Json::Value& jvObj)
+ {
+ mHandler->send(mConnection, jvObj);
+ }
// Utilities
- Json::Value invokeCommand(Json::Value& jvRequest);
+ Json::Value invokeCommand(Json::Value& jvRequest)
+ {
+ if (!jvRequest.isMember("command"))
+ {
+ Json::Value jvResult(Json::objectValue);
+
+ jvResult["type"] = "response";
+ jvResult["result"] = "error";
+ jvResult["error"] = "missingCommand";
+ jvResult["command"] = jvRequest;
+
+ return jvResult;
+ }
+
+ RPCHandler mRPCHandler(&mNetwork, this);
+ Json::Value jvResult(Json::objectValue);
+
+ // XXX Temporarily support RPC style commands over websocket. Remove this.
+ if (jvRequest.isMember("params"))
+ {
+ RPCParser rpParser;
+
+ Json::Value jvRpcRequest = rpParser.parseCommand(jvRequest["command"].asString(), jvRequest["params"]);
+
+ if (jvRpcRequest.isMember("error"))
+ {
+ jvResult = jvRpcRequest;
+ }
+ else
+ {
+ jvResult["result"] = mRPCHandler.doCommand(
+ jvRpcRequest,
+ mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN);
+ }
+ }
+ else
+ {
+ jvResult["result"] = mRPCHandler.doCommand(
+ jvRequest,
+ mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN);
+ }
+
+ // Currently we will simply unwrap errors returned by the RPC
+ // API, in the future maybe we can make the responses
+ // consistent.
+ //
+ // Regularize result. This is duplicate code.
+ if (jvResult["result"].isMember("error"))
+ {
+ jvResult = jvResult["result"];
+ jvResult["status"] = "error";
+ jvResult["request"] = jvRequest;
+
+ } else {
+ jvResult["status"] = "success";
+ }
+
+ if (jvRequest.isMember("id"))
+ {
+ jvResult["id"] = jvRequest["id"];
+ }
+
+ jvResult["type"] = "response";
+
+ return jvResult;
+ }
};
+
// vim:ts=4
diff --git a/src/cpp/ripple/WSDoor.cpp b/src/cpp/ripple/WSDoor.cpp
index 55e46b58a1..f5327a486d 100644
--- a/src/cpp/ripple/WSDoor.cpp
+++ b/src/cpp/ripple/WSDoor.cpp
@@ -9,6 +9,7 @@ SETUP_LOG();
#include "utils.h"
#include "WSConnection.h"
#include "WSHandler.h"
+#include "Config.h"
#include "WSDoor.h"
@@ -53,21 +54,42 @@ void WSDoor::startListening()
SSL_CTX_set_tmp_dh_callback(mCtx->native_handle(), handleTmpDh);
- // Construct a single handler for all requests.
- websocketpp::WSDOOR_SERVER::handler::ptr handler(new WSServerHandler(mCtx, mPublic));
+ if(theConfig.WEBSOCKET_SECURE)
+ {
+ // Construct a single handler for all requests.
+ websocketpp::server_tls::handler::ptr handler(new WSServerHandler(mCtx, mPublic));
- // Construct a websocket server.
- mEndpoint = new websocketpp::WSDOOR_SERVER(handler);
+ // Construct a websocket server.
+ mSEndpoint = new websocketpp::server_tls(handler);
- // mEndpoint->alog().unset_level(websocketpp::log::alevel::ALL);
- // mEndpoint->elog().unset_level(websocketpp::log::elevel::ALL);
+ // mEndpoint->alog().unset_level(websocketpp::log::alevel::ALL);
+ // mEndpoint->elog().unset_level(websocketpp::log::elevel::ALL);
- // Call the main-event-loop of the websocket server.
- mEndpoint->listen(
- boost::asio::ip::tcp::endpoint(
- boost::asio::ip::address().from_string(mIp), mPort));
+ // Call the main-event-loop of the websocket server.
+ mSEndpoint->listen(
+ boost::asio::ip::tcp::endpoint(
+ boost::asio::ip::address().from_string(mIp), mPort));
- delete mEndpoint;
+ delete mSEndpoint;
+ }else
+ {
+ // Construct a single handler for all requests.
+ websocketpp::server::handler::ptr handler(new WSServerHandler(mCtx, mPublic));
+
+ // Construct a websocket server.
+ mEndpoint = new websocketpp::server(handler);
+
+ // mEndpoint->alog().unset_level(websocketpp::log::alevel::ALL);
+ // mEndpoint->elog().unset_level(websocketpp::log::elevel::ALL);
+
+ // Call the main-event-loop of the websocket server.
+ mEndpoint->listen(
+ boost::asio::ip::tcp::endpoint(
+ boost::asio::ip::address().from_string(mIp), mPort));
+
+ delete mEndpoint;
+ }
+
}
WSDoor* WSDoor::createWSDoor(const std::string& strIp, const int iPort, bool bPublic)
@@ -89,7 +111,11 @@ void WSDoor::stop()
{
if (mThread)
{
- mEndpoint->stop();
+ if (mEndpoint)
+ mEndpoint->stop();
+ if (mSEndpoint)
+ mSEndpoint->stop();
+
mThread->join();
}
diff --git a/src/cpp/ripple/WSDoor.h b/src/cpp/ripple/WSDoor.h
index fe41d1bc5a..40c37815d1 100644
--- a/src/cpp/ripple/WSDoor.h
+++ b/src/cpp/ripple/WSDoor.h
@@ -10,16 +10,12 @@
#include
#include
-#if 1
-#define WSDOOR_SERVER server
-#else
-#define WSDOOR_SERVER server_tls
-#endif
-
class WSDoor
{
private:
- websocketpp::WSDOOR_SERVER* mEndpoint;
+ websocketpp::server* mEndpoint;
+ websocketpp::server_tls* mSEndpoint;
+
boost::thread* mThread;
bool mPublic;
std::string mIp;
@@ -29,7 +25,7 @@ private:
public:
- WSDoor(const std::string& strIp, int iPort, bool bPublic) : mEndpoint(0), mThread(0), mPublic(bPublic), mIp(strIp), mPort(iPort) { ; }
+ WSDoor(const std::string& strIp, int iPort, bool bPublic) : mEndpoint(0), mSEndpoint(0), mThread(0), mPublic(bPublic), mIp(strIp), mPort(iPort) { ; }
void stop();
diff --git a/src/cpp/ripple/WSHandler.h b/src/cpp/ripple/WSHandler.h
index 9f4b23d5e6..9c13fc4f0e 100644
--- a/src/cpp/ripple/WSHandler.h
+++ b/src/cpp/ripple/WSHandler.h
@@ -2,7 +2,9 @@
#define __WSHANDLER__
#include "Application.h"
+#include "Config.h"
+template
class WSConnection;
// A single instance of this object is made.
@@ -25,7 +27,7 @@ private:
protected:
boost::mutex mMapLock;
// For each connection maintain an associated object to track subscriptions.
- boost::unordered_map > mMap;
+ boost::unordered_map > > mMap;
bool mPublic;
public:
@@ -33,10 +35,7 @@ public:
bool getPublic() { return mPublic; };
- boost::shared_ptr on_tls_init()
- {
- return mCtx;
- }
+
void send(connection_ptr cpClient, message_ptr mpMessage)
{
@@ -77,7 +76,7 @@ public:
{
boost::mutex::scoped_lock sl(mMapLock);
- mMap[cpClient] = boost::make_shared(this, cpClient);
+ mMap[cpClient] = boost::make_shared< WSConnection >(this, cpClient);
}
void on_close(connection_ptr cpClient)
@@ -116,7 +115,7 @@ public:
}
else
{
- boost::shared_ptr conn;
+ boost::shared_ptr< WSConnection > conn;
{
boost::mutex::scoped_lock sl(mMapLock);
conn = mMap[cpClient];
@@ -127,6 +126,35 @@ public:
}
}
+ boost::shared_ptr on_tls_init()
+ {
+ if(theConfig.WEBSOCKET_SECURE)
+ {
+ // create a tls context, init, and return.
+ boost::shared_ptr context(new boost::asio::ssl::context(boost::asio::ssl::context::tlsv1));
+ try {
+ context->set_options(boost::asio::ssl::context::default_workarounds |
+ boost::asio::ssl::context::no_sslv2 |
+ boost::asio::ssl::context::single_dh_use);
+// context->set_password_callback(boost::bind(&type::get_password, this));
+ if (!theConfig.WEBSOCKET_SSL_CERT.empty())
+ context->use_certificate_file(theConfig.WEBSOCKET_SSL_CERT, boost::asio::ssl::context::pem);
+ if (!theConfig.WEBSOCKET_SSL_KEY.empty())
+ context->use_private_key_file(theConfig.WEBSOCKET_SSL_KEY, boost::asio::ssl::context::pem);
+ if (!theConfig.WEBSOCKET_SSL_CHAIN.empty())
+ context->use_certificate_chain_file(theConfig.WEBSOCKET_SSL_CHAIN);
+ //context->use_tmp_dh_file("../../src/ssl/dh512.pem");
+ } catch (std::exception& e) {
+ std::cout << e.what() << std::endl;
+ }
+ return context;
+ }else
+ {
+ return mCtx;
+ }
+
+ }
+
// Respond to http requests.
void http(connection_ptr cpClient)
{
diff --git a/src/cpp/ripple/utils.cpp b/src/cpp/ripple/utils.cpp
index 9734e59743..8e94f5a10f 100644
--- a/src/cpp/ripple/utils.cpp
+++ b/src/cpp/ripple/utils.cpp
@@ -5,6 +5,17 @@
#include
#include
+#include
+
+void getRand(unsigned char *buf, int num)
+{
+ if (RAND_bytes(buf, num) != 1)
+ {
+ assert(false);
+ throw std::runtime_error("Entropy pool not seeded");
+ }
+}
+
//
// Time support
// We have our own epoch.
diff --git a/src/cpp/ripple/utils.h b/src/cpp/ripple/utils.h
index 10eae9673b..92161ffae3 100644
--- a/src/cpp/ripple/utils.h
+++ b/src/cpp/ripple/utils.h
@@ -189,6 +189,10 @@ bool parseQuality(const std::string& strSource, uint32& uQuality);
DH* DH_der_load(const std::string& strDer);
std::string DH_der_gen(int iKeyLength);
+void getRand(unsigned char *buf, int num);
+inline static void getRand(char *buf, int num) { return getRand(reinterpret_cast(buf), num); }
+inline static void getRand(void *buf, int num) { return getRand(reinterpret_cast(buf), num); }
+
inline std::string strGetEnv(const std::string& strKey)
{
return getenv(strKey.c_str()) ? getenv(strKey.c_str()) : "";
diff --git a/src/js/amount.js b/src/js/amount.js
index dd96653c44..62b6a51e56 100644
--- a/src/js/amount.js
+++ b/src/js/amount.js
@@ -499,12 +499,16 @@ Amount.prototype.to_human = function (opts)
if ("undefined" === typeof opts.group_sep) opts.group_sep = true;
opts.group_width = opts.group_width || 3;
- var denominator = this._is_native ?
- consts.bi_xns_unit :
- consts.bi_10.clone().pow(-this._offset);
+ var order = this._is_native ? consts.xns_precision : -this._offset;
+ var denominator = consts.bi_10.clone().pow(order);
var int_part = this._value.divide(denominator).toString(10);
var fraction_part = this._value.mod(denominator).toString(10);
+ // Add leading zeros to fraction
+ while (fraction_part.length < order) {
+ fraction_part = "0" + fraction_part;
+ }
+
int_part = int_part.replace(/^0*/, '');
fraction_part = fraction_part.replace(/0*$/, '');
diff --git a/src/js/remote.js b/src/js/remote.js
index f7e02742cd..3f5be45110 100644
--- a/src/js/remote.js
+++ b/src/js/remote.js
@@ -191,6 +191,7 @@ var Remote = function (opts, trace) {
this.trusted = opts.trusted;
this.websocket_ip = opts.websocket_ip;
this.websocket_port = opts.websocket_port;
+ this.websocket_ssl = opts.websocket_ssl;
this.local_sequence = opts.local_sequence; // Locally track sequence numbers
this.local_fee = opts.local_fee; // Locally set fees
this.id = 0;
@@ -384,7 +385,8 @@ Remote.prototype._connect_start = function () {
// with self-signed certs as the user must have pre-approved the self-signed certs.
var self = this;
- var url = "ws://" + this.websocket_ip + ":" + this.websocket_port;
+ var url = (this.websocket_ssl ? "wss://" : "ws://") +
+ this.websocket_ip + ":" + this.websocket_port;
if (this.trace) console.log("remote: connect: %s", url);
@@ -412,8 +414,6 @@ Remote.prototype._connect_start = function () {
};
if (self.online_target) {
- self._set_state('online');
-
// Note, we could get disconnected before this goes through.
self._server_subscribe(); // Automatically subscribe.
}
@@ -493,6 +493,10 @@ Remote.prototype._connect_message = function (ws, json) {
this.emit('ledger_closed', message);
break;
+ case 'serverStatus':
+ this._set_state(message.server_status === 'ok' ? 'online' : 'offline');
+ break;
+
// All other messages
default:
if (this.trace) utils.logObject("remote: "+message.type+": %s", message);
@@ -852,6 +856,10 @@ Remote.prototype._server_subscribe = function () {
self.emit('ledger_closed', message);
}
+ if (message.server_status === "ok") {
+ self._set_state('online');
+ }
+
self.emit('subscribed');
})
.request();
diff --git a/test/config-example.js b/test/config-example.js
index af94850fe1..c43f4d5d87 100644
--- a/test/config-example.js
+++ b/test/config-example.js
@@ -23,6 +23,7 @@ exports.servers = {
'rpc_port' : 5005,
'websocket_ip' : "127.0.0.1",
'websocket_port' : 5006,
+ 'websocket_ssl' : false,
'local_sequence' : true,
'local_fee' : true,
// 'validation_seed' : "shhDFVsmS2GSu5vUyZSPXYfj1r79h",