Browse Source

We are back

peercoin
Intel 11 years ago
parent
commit
6432acff9d
  1. 2
      .gitignore
  2. 4
      CMakeLists.txt
  3. 8
      src/server/poolserver/CMakeLists.txt
  4. 36
      src/server/poolserver/DataMgr/DataMgr.cpp
  5. 47
      src/server/poolserver/DataMgr/DataMgr.h
  6. 22
      src/server/poolserver/DataMgr/Share.h
  7. 15
      src/server/poolserver/Main.cpp
  8. 188
      src/server/poolserver/NetworkMgr/NetworkMgr.cpp
  9. 84
      src/server/poolserver/NetworkMgr/NetworkMgr.h
  10. 76
      src/server/poolserver/Server/Server.cpp
  11. 6
      src/server/poolserver/Server/Server.h
  12. 74
      src/server/poolserver/Stratum/Client.cpp
  13. 48
      src/server/poolserver/Stratum/Client.h
  14. 1
      src/server/poolserver/Stratum/Job.h
  15. 27
      src/server/poolserver/Stratum/Server.cpp
  16. 144
      src/server/poolserver/Stratum/Server.h
  17. 39
      src/server/poolserver/Stratum/ShareLimiter.cpp
  18. 44
      src/server/poolserver/Stratum/ShareLimiter.h
  19. 6
      src/server/poolserver/poolserver.cfg.dist
  20. 29
      src/server/shared/Bitcoin/Bitcoin.h
  21. 2
      src/server/shared/ByteBuffer.h
  22. 5
      src/server/shared/Common.h
  23. 27
      src/server/shared/Exception.h
  24. 34
      src/server/shared/JSON/JSON.h
  25. 3
      src/server/shared/JSON/JSONReader.h
  26. 35
      src/server/shared/JSONRPC/JSONRPC.cpp
  27. 9
      src/server/shared/JSONRPC/JSONRPC.h
  28. 10
      src/server/shared/MySQL/DatabaseConnection.cpp
  29. 15
      src/server/shared/MySQL/DatabaseConnection.h
  30. 20
      src/server/shared/Util.cpp
  31. 3
      src/server/shared/Util.h

2
.gitignore vendored

@ -15,3 +15,5 @@ CMakeLists.txt.user @@ -15,3 +15,5 @@ CMakeLists.txt.user
*.BACKUP.*
*.BASE.*
*.LOCAL.*
bin/
etc/

4
CMakeLists.txt

@ -25,10 +25,10 @@ set(Boost_USE_MULTITHREADED ON) @@ -25,10 +25,10 @@ set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
set(Boost_ALL_DYN_LINK ON)
SET(Boost_ADDITIONAL_VERSIONS "1.54" "1.54.0")
SET(Boost_ADDITIONAL_VERSIONS "1.49" "1.49.0")
# Boost
find_package(Boost 1.54 COMPONENTS thread chrono program_options date_time REQUIRED)
find_package(Boost 1.49 COMPONENTS thread chrono program_options date_time system REQUIRED)
message(status "** Boost Include: ${Boost_INCLUDE_DIR}")
message(status "** Boost Libraries: ${Boost_LIBRARY_DIRS}")
message(status "** Boost Libraries: ${Boost_LIBRARIES}")

8
src/server/poolserver/CMakeLists.txt

@ -3,12 +3,16 @@ @@ -3,12 +3,16 @@
file(GLOB_RECURSE sources_Server Server/*.cpp Server/*.h)
file(GLOB_RECURSE sources_Database Database/*.cpp Database/*.h)
file(GLOB_RECURSE sources_Stratum Stratum/*.cpp Stratum/*.h)
file(GLOB_RECURSE sources_DataMgr DataMgr/*.cpp DataMgr/*.h)
file(GLOB_RECURSE sources_NetworkMgr NetworkMgr/*.cpp NetworkMgr/*.h)
file(GLOB sources_localdir *.cpp *.h)
set(sources_Poolserver
${sources_Server}
${sources_Database}
${sources_Stratum}
${sources_DataMgr}
${sources_NetworkMgr}
${sources_localdir}
)
@ -16,6 +20,8 @@ include_directories( @@ -16,6 +20,8 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/Server
${CMAKE_CURRENT_SOURCE_DIR}/Database
${CMAKE_CURRENT_SOURCE_DIR}/DataMgr
${CMAKE_CURRENT_SOURCE_DIR}/NetworkMgr
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/MySQL
@ -46,7 +52,7 @@ target_link_libraries(poolserver @@ -46,7 +52,7 @@ target_link_libraries(poolserver
# Install
if(UNIX)
install(TARGETS poolserver DESTINATION bin)
install(FILES poolserver.cfg.dist DESTINATION bin)
install(FILES poolserver.cfg.dist DESTINATION etc)
elseif(WIN32)
install(TARGETS poolserver DESTINATION "${CMAKE_INSTALL_PREFIX}")
install(FILES poolserver.cfg.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")

36
src/server/poolserver/DataMgr/DataMgr.cpp

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
#include "DataMgr.h"
#include "ServerDatabaseEnv.h"
#include "Util.h"
#include "Log.h"
template<>
void DataMgr<Share>::Upload()
{
sLog.Info(LOG_SERVER, "We have %u shares", Size());
while (Size() > BULK_MIN)
{
sLog.Info(LOG_SERVER, "Uploading %u shares to database", Size());
std::string query("INSERT INTO `shares` (`rem_host`, `username`, `our_result`, `upstream_result`, `reason`, `time`, `difficulty`) VALUES ");
for (int i = 0; i < BULK_COUNT; ++i)
{
sLog.Info(LOG_SERVER, "Query: %s", query.c_str());
Share share = Pop();
query += Util::FS("(INET_NTOA(%u), '%s', %u, 0, '%s', FROM_UNIXTIME(%u), %u)", share.host, share.username.c_str(), share.result, share.reason.c_str(), share.time, share.diff);
if (!Size())
break;
if (i != BULK_COUNT-1)
query += ',';
}
sDatabase.ExecuteAsync(query.c_str());
}
}
DataMgr<Share> sDataMgr;

47
src/server/poolserver/DataMgr/DataMgr.h

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
#ifndef DATAMGR_H_
#define DATAMGR_H_
#include <deque>
#include <boost/thread.hpp>
#include "Util.h"
#include "Share.h"
#define BULK_MIN 1
#define BULK_COUNT 50
template<class T>
class DataMgr
{
public:
DataMgr() {}
void Push(T data)
{
boost::unique_lock<boost::mutex> lock(_datamutex);
_datastore.push_back(data);
}
T Pop()
{
boost::unique_lock<boost::mutex> lock(_datamutex);
Share share = _datastore.front();
_datastore.pop_front();
return share;
}
size_t Size()
{
boost::unique_lock<boost::mutex> lock(_datamutex);
return _datastore.size();
}
void Upload();
private:
boost::mutex _datamutex;
std::deque<T> _datastore;
};
extern DataMgr<Share> sDataMgr;
#endif

22
src/server/poolserver/DataMgr/Share.h

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
#ifndef SHARE_H_
#define SHARE_H_
#include <string>
#include "Common.h"
class Share
{
public:
Share(uint32 ahost, std::string ausername, bool aresult, std::string areason, uint64 atime, uint64 adiff):
host(ahost), username(ausername), result(aresult), reason(areason), time(atime), diff(adiff) {}
uint64 host;
std::string username;
bool result;
std::string reason;
uint64 time;
uint64 diff;
};
#endif

15
src/server/poolserver/Main.cpp

@ -26,15 +26,16 @@ bool InitConfig(int argc, char *argv[]) @@ -26,15 +26,16 @@ bool InitConfig(int argc, char *argv[])
// Generic
descGeneric.add_options()
("version,v", "print version string")
("help,h", "produce help message")
("config,c", boost::program_options::value<std::string>()->default_value("poolserver.cfg"),"name of a file of a configuration.")
("version,v", "Print version string")
("help,h", "Produce help message")
("config,c", boost::program_options::value<std::string>()->default_value("../etc/poolserver.cfg"),"Path to configuration file")
;
// Server
descServer.add_options()
("MinDiffTime", boost::program_options::value<uint32_t>()->default_value(100), "Minimum server diff time")
("MiningAddress", boost::program_options::value<std::string>()->default_value("n1w8gkPXdNGb6edm4vujBn71A72eQFCNCw"), "Address to send coins to")
("BitcoinRPC", boost::program_options::value<std::vector<std::string> >()->multitoken(), "Bitcoin RPC login credentials")
;
// Stratum
@ -42,13 +43,14 @@ bool InitConfig(int argc, char *argv[]) @@ -42,13 +43,14 @@ bool InitConfig(int argc, char *argv[])
("StratumHost,sh", boost::program_options::value<std::string>()->default_value("0.0.0.0"), "Stratum server host")
("StratumPort,sp", boost::program_options::value<uint16_t>()->default_value(3333), "Stratum server port")
("StratumBlockCheckTime", boost::program_options::value<uint32>()->default_value(2000), "Time between block checks in ms")
("StratumMinDifficulty", boost::program_options::value<uint32>()->default_value(1), "The difficulty on which a new miner starts")
;
// Logging
descLogging.add_options()
("LogConsoleLevel", boost::program_options::value<uint32_t>()->default_value(LOG_LEVEL_INFO), "Console log level (0-None, 1-Error, 2-Warn, 3-Info, 4-Debug)")
("LogConsoleDebugMask", boost::program_options::value<uint32_t>()->default_value(0), "Console log debug mask")
("LogFilePath", boost::program_options::value<std::string>()->default_value("."), "File log path")
("LogFilePath", boost::program_options::value<std::string>()->default_value("../etc"), "File log path")
("LogFileLevel", boost::program_options::value<uint32_t>()->default_value(LOG_LEVEL_WARN), "File log level (0-None, 1-Error, 2-Warn, 3-Info, 4-Debug)")
("LogFileDebugMask", boost::program_options::value<uint32_t>()->default_value(0), "File log debug mask")
;
@ -88,6 +90,8 @@ bool InitConfig(int argc, char *argv[]) @@ -88,6 +90,8 @@ bool InitConfig(int argc, char *argv[])
return true;
}
sLog.Info(LOG_GENERAL, "Using config file: %s", sConfig.Get<std::string>("config").c_str());
store(parse_config_file(ifs, fileOptions), sConfig.vm);
notify(sConfig.vm);
@ -102,7 +106,8 @@ int main(int argc, char *argv[]) @@ -102,7 +106,8 @@ int main(int argc, char *argv[])
sLog.OpenLogFile(sConfig.Get<std::string>("LogFilePath"));
sLog.Info(LOG_GENERAL, "LogFile Started: %s", sLog.logFileLoc.c_str());
Server* server = new Server();
boost::asio::io_service io;
Server* server = new Server(io);
int exitcode = server->Run();
delete server;

188
src/server/poolserver/NetworkMgr/NetworkMgr.cpp

@ -0,0 +1,188 @@ @@ -0,0 +1,188 @@
#include "NetworkMgr.h"
#include "Config.h"
NetworkMgr* NetworkMgr::singleton = 0;
NetworkMgr::NetworkMgr(asio::io_service& io_service) : _io_service(io_service), _blockNotifyTimer(io_service), _blockCheckTimer(io_service), _blockHeight(0)
{
BlockCheckTimerStart();
BlockNotifyTimerStart();
}
NetworkMgr::~NetworkMgr()
{
for (int i = 0; i < _cons.size(); ++i)
delete _cons[i];
}
// Bitcoin daemon connection
void NetworkMgr::Connect(JSONRPCConnectionInfo coninfo)
{
JSONRPC* bitcoinrpc = new JSONRPC();
bitcoinrpc->Connect(coninfo);
JSON response = bitcoinrpc->Query("getinfo");
if (response["error"].GetType() != JSON_NULL)
throw Exception(Util::FS("Failed to get response from bitcoin rpc: %s", response["error"].GetString().c_str()));
sLog.Info(LOG_SERVER, "Connected to Bitcoin RPC at %s:%s", coninfo.Host.c_str(), coninfo.Port.c_str());
_cons.push_back(bitcoinrpc);
// Fetch block height on first connection
if (_cons.size() == 1)
BlockCheck();
}
// Get new block template
void NetworkMgr::UpdateBlockTemplate()
{
// Might be called by block notify timer and block check timer so we need a lock
boost::lock_guard<boost::mutex> guard(_mtxBlockTmpl);
for (int i = 0; i < _cons.size(); ++i)
{
try {
JSON response = _cons[i]->Query("getblocktemplate");
// New blocks may not appear on all daemons the same time
if (response["height"].GetInt() < _blockHeight)
continue;
Bitcoin::BlockPtr block = Bitcoin::BlockPtr(new Bitcoin::Block());
block->version = response["version"].GetInt();
block->prevBlockHash = Util::Reverse(Util::ASCIIToBin(response["previousblockhash"].GetString()));
block->time = response["curtime"].GetInt();
// Set bits
ByteBuffer bitbuf(Util::Reverse(Util::ASCIIToBin(response["bits"].GetString())));
bitbuf >> block->bits;
// Add coinbase tx
BinaryData pubkey = Util::ASCIIToBin(sConfig.Get<std::string>("MiningAddress"));
block->tx.push_back(Bitcoin::CreateCoinbaseTX(_blockHeight, pubkey, response["coinbasevalue"].GetInt()));
// Add other transactions
JSON trans = response["transactions"];
for (uint64 tidx = 0; tidx < trans.Size(); ++tidx) {
ByteBuffer txbuf(Util::ASCIIToBin(trans[tidx]["data"].GetString()));
Bitcoin::Transaction tx;
txbuf >> tx;
block->tx.push_back(tx);
}
// Genrate merkle tree
block->BuildMerkleTree();
// Set
_curBlockTmpl = block;
sLog.Debug(LOG_SERVER, "Fetched block template from rpc #%u", i);
// Break from loop
break;
} catch (std::exception& e) {
sLog.Error(LOG_SERVER, "Failed to fetch block template from daemon #%u: %s", i, e.what());
}
}
}
// Submit new block
bool NetworkMgr::SubmitBlock(Bitcoin::Block block)
{
// Serialize block
ByteBuffer blockbuf;
blockbuf << block;
for (int i = 0; i < _cons.size(); ++i)
{
try {
JSON params;
params.Add(Util::BinToASCII(blockbuf.Binary()));
JSON response = _cons[i]->Query("submitblock", params);
if (response["result"].GetType() == JSON_NULL) {
sLog.Info(LOG_SERVER, "Block accepted! YAY!");
BlockCheck();
return true;
} else {
sLog.Error(LOG_SERVER, "Block rejected: %s", response["error"].GetString().c_str());
}
} catch (std::exception& e) {
sLog.Error(LOG_SERVER, "Exception caught while submiting block: %s", e.what());
}
}
return false;
}
// Check for new blocks
void NetworkMgr::BlockCheck()
{
// Might be called twice from timer and when block is found
boost::lock_guard<boost::mutex> guard(_mtxBlockCheck);
for (int i = 0; i < _cons.size(); ++i)
{
try {
JSON response = _cons[i]->Query("getinfo");
uint32 curBlock = response["blocks"].GetInt();
if (curBlock > _blockHeight) {
sLog.Debug(LOG_SERVER, "New block on network! Height: %u", curBlock);
_blockHeight = curBlock;
// Update block template
UpdateBlockTemplate();
// Send notifications (and reset work)
BlockNotifySend(true);
}
} catch (std::exception& e) {
sLog.Error(LOG_SERVER, "Failed to fetch block height from daemon #%u: %s", i, e.what());
}
}
}
void NetworkMgr::BlockCheckTimerStart()
{
_blockCheckTimer.expires_from_now(boost::posix_time::seconds(3));
_blockCheckTimer.async_wait(boost::bind(&NetworkMgr::BlockCheckTimerExpired, this, boost::asio::placeholders::error));
}
void NetworkMgr::BlockCheckTimerExpired(const boost::system::error_code& /*e*/)
{
BlockCheck();
BlockCheckTimerStart();
}
// Bind for receiving block notifications
void NetworkMgr::BlockNotifyBind(FBlockNotify f)
{
_blockNotifyBinds.push_back(f);
}
// Block notify timer
void NetworkMgr::BlockNotifyTimerStart()
{
_blockNotifyTimer.expires_from_now(boost::posix_time::seconds(3));
_blockNotifyTimer.async_wait(boost::bind(&NetworkMgr::BlockNotifyTimerExpired, this, boost::asio::placeholders::error));
}
void NetworkMgr::BlockNotifyTimerExpired(const boost::system::error_code& /*e*/)
{
sLog.Debug(LOG_SERVER, "Sending block template update");
UpdateBlockTemplate();
BlockNotifySend();
BlockNotifyTimerStart();
}
// Send block notification to all subscribers
void NetworkMgr::BlockNotifySend(bool newBlock)
{
for (int i = 0; i < _blockNotifyBinds.size(); ++i)
_io_service.post(boost::bind(_blockNotifyBinds[i], _curBlockTmpl, newBlock));
}

84
src/server/poolserver/NetworkMgr/NetworkMgr.h

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
#ifndef NETWORKMGR_H_
#define NETWORKMGR_H_
// Provides high level interaction with bitcoin daemon
#include "JSONRPC.h"
#include "Bitcoin.h"
#include "Log.h"
#include <vector>
#include <boost/asio.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
using namespace boost;
typedef boost::function<void (Bitcoin::BlockPtr /*blockTmpl*/, bool /*newBlock*/)> FBlockNotify;
class NetworkMgr
{
// Singleton
private:
static NetworkMgr* singleton;
public:
static NetworkMgr* Instance()
{
return singleton;
}
static void Initialize(asio::io_service& io_service)
{
singleton = new NetworkMgr(io_service);
}
public:
NetworkMgr(asio::io_service& io_service);
~NetworkMgr();
// Bitcoin daemon connection
void Connect(JSONRPCConnectionInfo coninfo);
// Get new block template
void UpdateBlockTemplate();
// Submit new block
bool SubmitBlock(Bitcoin::Block block);
// Checking for blocks
void BlockCheck();
void BlockCheckTimerStart();
void BlockCheckTimerExpired(const boost::system::error_code& /*e*/);
// Bind for receiving block notifications
void BlockNotifyBind(FBlockNotify f);
// Block notify timer
void BlockNotifyTimerStart();
void BlockNotifyTimerExpired(const boost::system::error_code& /*e*/);
// Send block notification to all subscribers
void BlockNotifySend(bool newBlock = false);
private:
// Holds subscriptions for block notifications
std::vector<FBlockNotify> _blockNotifyBinds;
boost::asio::deadline_timer _blockNotifyTimer;
// Checking for new blocks
boost::asio::deadline_timer _blockCheckTimer;
boost::mutex _mtxBlockCheck;
uint32 _blockHeight;
// Connections to bitcoin rpc
std::vector<JSONRPC*> _cons;
// Current block template
Bitcoin::BlockPtr _curBlockTmpl;
boost::mutex _mtxBlockTmpl;
// ASIO
asio::io_service& _io_service;
};
#endif

76
src/server/poolserver/Server/Server.cpp

@ -6,22 +6,16 @@ @@ -6,22 +6,16 @@
#include "ServerDatabaseEnv.h"
#include "Crypto.h"
#include "Bitcoin.h"
#include "DataMgr.h"
#include "NetworkMgr.h"
#include "Exception.h"
#include <boost/thread.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <algorithm>
struct Share
{
Share(uint64 _id, uint32 _diff, uint32 _workerid, uint32 _timestamp) :
id(_id), diff(_diff), workerid(_workerid), timestamp(_timestamp) {}
uint64 id;
uint32 diff;
uint32 workerid;
uint32 timestamp;
};
Server::Server() : serverLoops(0)
Server::Server(asio::io_service& io) : serverLoops(0), io_service(io), uploadtimer(io)
{
}
@ -34,13 +28,22 @@ void AsyncQueryCallback(MySQL::QueryResult result) @@ -34,13 +28,22 @@ void AsyncQueryCallback(MySQL::QueryResult result)
{
}
void Server::UploadShares(const boost::system::error_code& /*e*/)
{
sDataMgr.Upload();
uploadtimer.expires_from_now(boost::posix_time::seconds(3)); //repeat rate here
uploadtimer.async_wait(boost::bind(&Server::UploadShares, this, boost::asio::placeholders::error));
}
int Server::Run()
{
sLog.Info(LOG_SERVER, "Server is starting...");
InitDatabase();
std::vector<Share> shares;
/*std::vector<Share> shares;
sLog.Info(LOG_SERVER, "Loading shares...");
@ -51,7 +54,7 @@ int Server::Run() @@ -51,7 +54,7 @@ int Server::Run()
sLog.Info(LOG_SERVER, "Min: %u Max: %u", min, max);
MySQL::PreparedStatement* stmt = sDatabase.GetPreparedStatement(STMT_QUERY_SHARES);
for (uint32 i = min; i < max; i += 500000)
for (uint32 i = min; i <= max; i += 500000)
{
stmt->SetUInt32(0, i);
MySQL::QueryResult result2 = sDatabase.Query(stmt);
@ -61,11 +64,7 @@ int Server::Run() @@ -61,11 +64,7 @@ int Server::Run()
sLog.Info(LOG_SERVER, "Shares: %u", shares.size());
}
sLog.Info(LOG_SERVER, "Loaded %u shares", shares.size());
JSON node = JSON::FromString("{\"test\":{\"omg\":\"smth\"},\"other\":[\"smth2\", \"smth3\"] }");
sLog.Info(LOG_SERVER, "Something2: %s", node["other"][0].GetString().c_str());
sLog.Info(LOG_SERVER, "Something: %s", node.ToString().c_str());
sLog.Info(LOG_SERVER, "Loaded %u shares", shares.size());*/
/*std::vector<byte> test = Util::ASCIIToBin("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
sLog.Info(LOG_SERVER, "Hash: %s", Util::BinToASCII(Crypto::SHA256D(test)).c_str());
@ -103,31 +102,34 @@ int Server::Run() @@ -103,31 +102,34 @@ int Server::Run()
// Main io service
asio::io_service io_service;
NetworkMgr::Initialize(io_service);
Stratum::Server srv(io_service);
std::vector<std::string> btcrpc = sConfig.Get<std::vector<std::string> >("BitcoinRPC");
for (int i = 0; i < btcrpc.size(); ++i) {
std::vector<std::string> params = Util::Explode(btcrpc[i], ";");
if (params.size() != 4)
throw Exception("Invalid Bitcoin RPC parameters");
// Init Bitcoin RPC
/*JSONRPCConnectionInfo coninfo;
coninfo.Host = "84.240.15.208";
coninfo.Port = "8332";
coninfo.User = "user";
coninfo.Pass = "DYAL6bC4RUHksL6ikdx7";*/
JSONRPCConnectionInfo coninfo;
coninfo.Host = "127.0.0.1";
coninfo.Port = "19001";
coninfo.User = "test";
coninfo.Pass = "123";
JSONRPC* bitcoinrpc = new JSONRPC();
bitcoinrpc->Connect(coninfo);
srv.SetBitcoinRPC(bitcoinrpc);
JSONRPCConnectionInfo coninfo;
coninfo.Host = params[0];
coninfo.Port = params[1];
coninfo.User = params[2];
coninfo.Pass = params[3];
NetworkMgr::Instance()->Connect(coninfo);
}
Stratum::Server srv(io_service);
// Start stratum server
tcp::endpoint endpoint(tcp::v4(), sConfig.Get<uint16>("StratumPort"));
srv.Start(endpoint);
// Start timer
uploadtimer.expires_from_now(boost::posix_time::seconds(3)); //repeat rate here
uploadtimer.async_wait(boost::bind(&Server::UploadShares, this, boost::asio::placeholders::error));
io_service.run();
@ -182,7 +184,7 @@ int Server::Run() @@ -182,7 +184,7 @@ int Server::Run()
// Mercy for CPU
if (diff < minDiffTime+sleepDuration) {
sleepDuration = minDiffTime - diff + sleepDuration;
boost::this_thread::sleep_for(boost::chrono::milliseconds(sleepDuration));
boost::this_thread::sleep(boost::posix_time::milliseconds(sleepDuration));
} else
sleepDuration = 0;

6
src/server/poolserver/Server/Server.h

@ -12,11 +12,12 @@ @@ -12,11 +12,12 @@
class Server
{
public:
Server();
Server(asio::io_service& io);
~Server();
Stratum::Server* stratumServer;
void UploadShares(const boost::system::error_code& e);
boost::chrono::steady_clock::time_point diffStart;
bool running;
uint64_t serverLoops;
@ -25,6 +26,9 @@ public: @@ -25,6 +26,9 @@ public:
void Update(uint32_t);
bool InitDatabase();
boost::asio::deadline_timer uploadtimer;
asio::io_service& io_service;
};
#endif

74
src/server/poolserver/Stratum/Client.cpp

@ -1,6 +1,9 @@ @@ -1,6 +1,9 @@
#include "Server.h"
#include "Client.h"
#include "BigNum.h"
#include "DataMgr.h"
#include "ShareLimiter.h"
#include "Exception.h"
#include <iostream>
namespace Stratum
@ -55,11 +58,23 @@ namespace Stratum @@ -55,11 +58,23 @@ namespace Stratum
{
JSON params = msg["params"];
std::string username = params[0].GetString();
// Share limiter
if (!_shareLimiter.Submit()) {
JSON response;
response["id"] = msg["id"];
response["result"];
response["error"].Add(int64(20));
response["error"].Add("Blocked by share limiter");
response["error"].Add(JSON());
SendMessage(response);
return;
}
uint32 jobid;
ByteBuffer jobbuf(Util::ASCIIToBin(params[1].GetString()));
jobbuf >> jobid;
// Check if such job exists
if (!_jobs.count(jobid)) {
JSON response;
response["id"] = msg["id"];
@ -72,22 +87,44 @@ namespace Stratum @@ -72,22 +87,44 @@ namespace Stratum
}
// check username
std::string username = params[0].GetString();
BinaryData extranonce2 = Util::ASCIIToBin(params[2].GetString());
if (extranonce2.size() != 4) {
sLog.Error(LOG_SERVER, "Wrong extranonce size");
JSON response;
response["id"] = msg["id"];
response["result"];
response["error"].Add(int64(20));
response["error"].Add("Wrong extranonce size");
response["error"].Add(JSON());
SendMessage(response);
return;
}
ByteBuffer timebuf(Util::Reverse(Util::ASCIIToBin(params[3].GetString())));
if (timebuf.Size() != 4) {
sLog.Error(LOG_SERVER, "Wrong ntime size");
JSON response;
response["id"] = msg["id"];
response["result"];
response["error"].Add(int64(20));
response["error"].Add("Wrong ntime size");
response["error"].Add(JSON());
SendMessage(response);
return;
}
ByteBuffer noncebuf(Util::Reverse(Util::ASCIIToBin(params[4].GetString())));
if (noncebuf.Size() != 4) {
sLog.Error(LOG_SERVER, "Wrong nonce size");
JSON response;
response["id"] = msg["id"];
response["result"];
response["error"].Add(int64(20));
response["error"].Add("Wrong nonce size");
response["error"].Add(JSON());
SendMessage(response);
return;
}
@ -98,6 +135,13 @@ namespace Stratum @@ -98,6 +135,13 @@ namespace Stratum
share << extranonce2 << timebuf << noncebuf;
if (!job.SubmitShare(share.Binary())) {
sLog.Error(LOG_SERVER, "Duplicate share");
JSON response;
response["id"] = msg["id"];
response["result"];
response["error"].Add(int64(22));
response["error"].Add("Duplicate share");
response["error"].Add(JSON());
SendMessage(response);
return;
}
@ -140,11 +184,33 @@ namespace Stratum @@ -140,11 +184,33 @@ namespace Stratum
std::cout << "Criteria: " << criteria << std::endl;
std::cout << "Diff: " << diff << std::endl;
// Check if difficulty meets job diff
if (target > Bitcoin::DiffToTarget(job.diff)) {
sLog.Error(LOG_SERVER, "Share above target");
JSON response;
response["id"] = msg["id"];
response["result"];
response["error"].Add(int64(23));
response["error"].Add("Share above target");
response["error"].Add(JSON());
SendMessage(response);
return;
}
// Check if block meets criteria
if (target <= criteria) {
sLog.Info(LOG_SERVER, "We have found a block candidate!");
_server->SubmitBlock(block);
} else {
sDataMgr.Push(Share(_ip, username, true, "", Util::Date(), job.diff));
JSON response;
response["id"] = msg["id"];
response["result"] = true;
response["error"];
SendMessage(response);
return;
}
}
@ -192,6 +258,7 @@ namespace Stratum @@ -192,6 +258,7 @@ namespace Stratum
{
Job job;
job.block = _server->GetWork();
job.diff = 1;
// Serialize transaction
ByteBuffer coinbasebuf;
@ -219,6 +286,11 @@ namespace Stratum @@ -219,6 +286,11 @@ namespace Stratum
iss << is.rdbuf();
sLog.Debug(LOG_SERVER, "Received: %s", iss.str().c_str());
OnMessage(JSON::FromString(iss.str()));
/*try {
OnMessage(JSON::FromString(iss.str()));
} catch (uint64 e) {
sLog.Error(LOG_SERVER, "Exception caught while parsing json: %s", e.what());
}*/
StartRead();
} else {

48
src/server/poolserver/Stratum/Client.h

@ -2,10 +2,12 @@ @@ -2,10 +2,12 @@
#define STRATUM_CLIENT_H_
#include "Common.h"
#include "Config.h"
#include "Log.h"
#include "JSON.h"
#include "Server.h"
#include "Job.h"
#include "ShareLimiter.h"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
@ -24,8 +26,10 @@ namespace Stratum @@ -24,8 +26,10 @@ namespace Stratum
class Client : public boost::enable_shared_from_this<Client>
{
public:
Client(Server* server, asio::io_service& io_service) : _server(server), _socket(io_service), _subscribed(false), _jobid(0)
Client(Server* server, asio::io_service& io_service, uint64 id) : _server(server), _socket(io_service), _id(id), _subscribed(false), _jobid(0), _shareLimiter(this)
{
_diff = sConfig.Get<uint32>("StratumMinDifficulty");
_minDiff = _diff;
}
tcp::socket& GetSocket()
@ -35,6 +39,11 @@ namespace Stratum @@ -35,6 +39,11 @@ namespace Stratum
void Start()
{
// Get IP
tcp::endpoint remote_ep = _socket.remote_endpoint();
address remote_ad = remote_ep.address();
_ip = remote_ad.to_v4().to_ulong();
// Start reading socket
StartRead();
}
@ -84,6 +93,36 @@ namespace Stratum @@ -84,6 +93,36 @@ namespace Stratum
// Gets new job from the server
Job GetJob();
// Worker difficulty
uint64 GetDifficulty()
{
return _diff;
}
void SetDifficulty(uint64 diff, bool resendJob = false)
{
_diff = diff;
// Send difficulty update
JSON params;
params.Add(int64(_diff));
JSON msg;
msg["id"];
msg["params"] = params;
msg["method"] = "mining.set_difficulty";
SendMessage(msg);
if (resendJob)
SendJob(false);
}
// Client ID
uint64 GetID()
{
return _id;
}
void Disconnect()
{
_socket.close();
@ -96,6 +135,8 @@ namespace Stratum @@ -96,6 +135,8 @@ namespace Stratum
// Networking
asio::streambuf _recvBuffer;
tcp::socket _socket;
uint32 _ip;
uint64 _id;
// Pointer to server
Stratum::Server* _server;
@ -108,6 +149,11 @@ namespace Stratum @@ -108,6 +149,11 @@ namespace Stratum
uint32 _extranonce;
std::map<uint64, Job> _jobs;
uint32 _jobid;
// Share limiting
uint64 _diff;
uint64 _minDiff;
ShareLimiter _shareLimiter;
};
typedef boost::shared_ptr<Client> ClientPtr;

1
src/server/poolserver/Stratum/Job.h

@ -11,6 +11,7 @@ namespace Stratum @@ -11,6 +11,7 @@ namespace Stratum
class Job
{
public:
uint64 diff;
Bitcoin::BlockPtr block;
BinaryData coinbase1;
BinaryData coinbase2;

27
src/server/poolserver/Stratum/Server.cpp

@ -4,9 +4,6 @@ namespace Stratum @@ -4,9 +4,6 @@ namespace Stratum
{
void Server::Start(tcp::endpoint endpoint)
{
// Start block checking timer
_CheckBlocksTimer();
_acceptor.open(endpoint.protocol());
_acceptor.set_option(tcp::acceptor::reuse_address(true));
_acceptor.bind(endpoint);
@ -24,33 +21,15 @@ namespace Stratum @@ -24,33 +21,15 @@ namespace Stratum
_io_service.post(boost::bind(&Client::SendMessage, (*it), msg));
}
void Server::ResetWork()
void Server::SendBlockTmpl(bool resetWork)
{
std::set<ClientPtr>::iterator it;
for (it = _clients.begin(); it != _clients.end(); ++it)
_io_service.post(boost::bind(&Client::SendJob, (*it), true));
_io_service.post(boost::bind(&Client::SendJob, (*it), resetWork));
}
bool Server::SubmitBlock(Bitcoin::Block block)
{
// Serialize block
ByteBuffer blockbuf;
blockbuf << block;
try {
JSON params;
params.Add(Util::BinToASCII(blockbuf.Binary()));
JSON response = _bitcoinrpc->Query("submitblock", params);
if (response["result"].GetType() == JSON_NULL) {
sLog.Info(LOG_STRATUM, "Block accepted! YAY!");
_io_service.post(boost::bind(&Server::_CheckBlocks, this));
return true;
} else {
sLog.Info(LOG_STRATUM, "Block rejected! Booooo");
}
} catch (...) {
return false;
}
return NetworkMgr::Instance()->SubmitBlock(block);
}
}

144
src/server/poolserver/Stratum/Server.h

@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
#include "Bitcoin.h"
#include "Util.h"
#include "ByteBuffer.h"
#include "NetworkMgr.h"
#include <boost/asio.hpp>
#include <boost/bind.hpp>
@ -27,12 +28,22 @@ namespace Stratum @@ -27,12 +28,22 @@ namespace Stratum
uint16 Port;
};
// Used for sorting std::set
struct ClientPtrCMP
{
bool operator() (const ClientPtr& a, const ClientPtr& b)
{
return a->GetID() < b->GetID();
}
};
class Server
{
public:
Server(asio::io_service& io_service) : _io_service(io_service), _acceptor(io_service), _blockCheckTimer(io_service), _blockHeight(0), _extranonce(0)
Server(asio::io_service& io_service) : _io_service(io_service), _acceptor(io_service), _extranonce(0), _clientId(0)
{
_pubkey = Util::ASCIIToBin(sConfig.Get<std::string>("MiningAddress"));
// Subscribe for block updates
NetworkMgr::Instance()->BlockNotifyBind(boost::bind(&Server::BlockNotify, this, _1, _2));
}
~Server()
@ -45,11 +56,6 @@ namespace Stratum @@ -45,11 +56,6 @@ namespace Stratum
// Starts accepting connections
void Start(tcp::endpoint endpoint);
void SetBitcoinRPC(JSONRPC* bitcoinrpc)
{
_bitcoinrpc = bitcoinrpc;
}
// Sends message to all clients
void SendToAll(JSON msg);
@ -62,12 +68,22 @@ namespace Stratum @@ -62,12 +68,22 @@ namespace Stratum
// Returns current work
Bitcoin::BlockPtr GetWork()
{
boost::lock_guard<boost::mutex> guard(_mtx_workupdate);
boost::lock_guard<boost::mutex> guard(_mtxCurrentWork);
return _currentWork;
}
// Block template update event
void BlockNotify(Bitcoin::BlockPtr block, bool newBlock)
{
sLog.Debug(LOG_SERVER, "Received block template update");
_mtxCurrentWork.lock();
_currentWork = block;
_mtxCurrentWork.unlock();
SendBlockTmpl(newBlock);
}
// Resets work for all clients
void ResetWork();
void SendBlockTmpl(bool resetWork);
// Submits block to bitcoind
bool SubmitBlock(Bitcoin::Block block);
@ -82,7 +98,7 @@ namespace Stratum @@ -82,7 +98,7 @@ namespace Stratum
private:
void _StartAccept()
{
ClientPtr client = ClientPtr(new Client(this, _io_service));
ClientPtr client = ClientPtr(new Client(this, _io_service, _clientId++));
_acceptor.async_accept(client->GetSocket(), boost::bind(&Server::_OnAccept, this, client, asio::placeholders::error));
}
@ -90,7 +106,7 @@ namespace Stratum @@ -90,7 +106,7 @@ namespace Stratum
void _OnAccept(ClientPtr client, const boost::system::error_code& error)
{
if (!error) {
sLog.Debug(LOG_STRATUM, "New stratum client accepted");
sLog.Debug(LOG_STRATUM, "New stratum client accepted. Total clients: %u", _clients.size());
client->Start();
_clients.insert(client);
} else {
@ -100,116 +116,18 @@ namespace Stratum @@ -100,116 +116,18 @@ namespace Stratum
_StartAccept();
}
void _UpdateWork(bool reset)
{
JSON response = _bitcoinrpc->Query("getblocktemplate");
Bitcoin::BlockPtr block = Bitcoin::BlockPtr(new Bitcoin::Block());
block->version = response["version"].GetInt();
block->prevBlockHash = Util::Reverse(Util::ASCIIToBin(response["previousblockhash"].GetString()));
block->time = response["curtime"].GetInt();
// Set bits
ByteBuffer bitbuf(Util::Reverse(Util::ASCIIToBin(response["bits"].GetString())));
bitbuf >> block->bits;
// Add coinbase tx
block->tx.push_back(CreateCoinbaseTX(_blockHeight, _pubkey, response["coinbasevalue"].GetInt()));
// Add other transactions
JSON trans = response["transactions"];
for (uint64 i = 0; i < trans.Size(); ++i) {
ByteBuffer txbuf(Util::ASCIIToBin(trans[i]["data"].GetString()));
Bitcoin::Transaction tx;
txbuf >> tx;
block->tx.push_back(tx);
}
// Genrate merkle tree
block->BuildMerkleTree();
// Set current work
_mtx_workupdate.lock();
_currentWork = block;
_mtx_workupdate.unlock();
// Requests all clients to reset work
if (reset)
ResetWork();
}
void _CheckBlocksTimer()
{
_CheckBlocks();
_blockCheckTimer.expires_from_now(boost::posix_time::milliseconds(sConfig.Get<uint32>("StratumBlockCheckTime")));
_blockCheckTimer.async_wait(boost::bind(&Server::_CheckBlocksTimer, this));
}
void _CheckBlocks()
{
// Might be called twice from timer and when block is found
boost::lock_guard<boost::mutex> guard(_mtx_checkblock);
sLog.Debug(LOG_STRATUM, "Clients: %u", _clients.size());
JSON response = _bitcoinrpc->Query("getinfo");
uint32 curBlock = response["blocks"].GetInt();
if (curBlock > _blockHeight) {
sLog.Debug(LOG_STRATUM, "New block on network! Height: %u", curBlock);
_blockHeight = curBlock;
_UpdateWork(true);
}
}
Bitcoin::Transaction CreateCoinbaseTX(uint32 blockHeight, BinaryData pubkey, int64 value)
{
// Extranonce placeholder
BinaryData extranonce_ph(8, 0);
ByteBuffer scriptsig;
scriptsig << _blockHeight << extranonce_ph;
Bitcoin::OutPoint outpoint;
outpoint.hash.resize(32, 0);
outpoint.n = 0xFFFFFFFF;
Bitcoin::TxIn txin;
txin.prevout = outpoint;
txin.script = scriptsig.Binary();
txin.n = 0;
Bitcoin::TxOut txout;
txout.value = value;
txout.scriptPubKey = Bitcoin::Script(pubkey) + Bitcoin::OP_CHECKSIG;
Bitcoin::Transaction tx;
tx.version = 1;
tx.in.push_back(txin);
tx.out.push_back(txout);
tx.lockTime = 0;
return tx;
}
private:
// Network
std::set<ClientPtr> _clients;
asio::io_service& _io_service;
tcp::acceptor _acceptor;
// Mutexes
boost::mutex _mtx_checkblock;
boost::mutex _mtx_workupdate;
// RPC
JSONRPC* _bitcoinrpc;
// Bitcoin info
BinaryData _pubkey;
asio::deadline_timer _blockCheckTimer;
uint32 _blockHeight;
// Clients
std::set<ClientPtr, ClientPtrCMP> _clients;
uint64 _clientId;
// Work
Bitcoin::BlockPtr _currentWork;
boost::mutex _mtxCurrentWork;
uint32 _extranonce;
};
}

39
src/server/poolserver/Stratum/ShareLimiter.cpp

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
#include "ShareLimiter.h"
#include "Server.h"
#include "Client.h"
namespace Stratum
{
// Returning false will stop any further share verifications (DoS prevention, etc)
bool ShareLimiter::Submit()
{
uint64 curTime = Util::Date();
uint64 sinceLast = curTime - _lastRetarget;
_shares.push_back(curTime);
if (sinceLast < RETARGET_INTERVAL)
return true;
while (_shares.size() && (_shares.front() < curTime - RETARGET_TIME_BUFFER))
_shares.pop_front();
uint32 interval = std::min(curTime - _startTime, uint64(RETARGET_TIME_BUFFER));
// Calculate shares/min
double speed = (_shares.size()*60) / interval;
// Calculate difference from pool target in %
double variance = (speed - RETARGET_SHARES_PER_MIN) / RETARGET_SHARES_PER_MIN;
// Check if we need to retarget
if (std::abs(variance)*100 < RETARGET_VARIANCE)
return true;
uint64 newDiff = double(_client->GetDifficulty()) * variance;
_client->SetDifficulty(newDiff, true);
return true;
}
}

44
src/server/poolserver/Stratum/ShareLimiter.h

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
#ifndef SHARELIMITER_H_
#define SHARELIMITER_H_
#include "Common.h"
#include "Util.h"
#include <deque>
#define RETARGET_INTERVAL 60
#define RETARGET_TIME_BUFFER 60*5
#define RETARGET_SHARES_PER_MIN 15
#define RETARGET_VARIANCE 40
namespace Stratum
{
class Client;
class ShareLimiterRecord
{
public:
ShareLimiterRecord(uint64 atime, uint64 adiff) : time(atime), diff(adiff) {}
uint64 time;
uint64 diff;
};
class ShareLimiter
{
public:
ShareLimiter(Client* client) : _client(client), _lastRetarget(0)
{
_startTime = Util::Date();
}
bool Submit();
private:
std::deque<uint64> _shares;
Client* _client;
uint64 _lastRetarget;
uint64 _startTime;
};
}
#endif

6
src/server/poolserver/poolserver.cfg.dist

@ -72,9 +72,9 @@ StratumPort=3333 @@ -72,9 +72,9 @@ StratumPort=3333
# Description: Location to save logfile to
# Important: Do not add trailing slash
# Example: "/var/log"
# Default: "." - (Save log file next to executable)
# Default: "../etc" - (Save log file next to executable)
LogFilePath="."
LogFilePath="../etc"
#
# LogConsoleLevel
@ -144,7 +144,7 @@ MySQLPort=3306 @@ -144,7 +144,7 @@ MySQLPort=3306
# Description: MySQL Server Username
# Default: "" - (No Username)
MySQLUser=""
MySQLUser="root"
#
# MySQLPass

29
src/server/shared/Bitcoin/Bitcoin.h

@ -30,6 +30,35 @@ namespace Bitcoin @@ -30,6 +30,35 @@ namespace Bitcoin
mpz_ui_pow_ui(power, 2, 8 * (nbytes - 3));
return BigInt(bits & 0xFFFFFF) * BigInt(power);
}
inline Transaction CreateCoinbaseTX(uint32 blockHeight, BinaryData pubkey, int64 value)
{
// Extranonce placeholder
BinaryData extranonce_ph(8, 0);
ByteBuffer scriptsig;
scriptsig << blockHeight << extranonce_ph;
Bitcoin::OutPoint outpoint;
outpoint.hash.resize(32, 0);
outpoint.n = 0xFFFFFFFF;
TxIn txin;
txin.prevout = outpoint;
txin.script = scriptsig.Binary();
txin.n = 0;
TxOut txout;
txout.value = value;
txout.scriptPubKey = Bitcoin::Script(pubkey) + Bitcoin::OP_CHECKSIG;
Transaction tx;
tx.version = 1;
tx.in.push_back(txin);
tx.out.push_back(txout);
tx.lockTime = 0;
return tx;
}
}
#endif

2
src/server/shared/ByteBuffer.h

@ -69,7 +69,7 @@ public: @@ -69,7 +69,7 @@ public:
size_t size = sizeof(T);
if (vec.size() < pointer+size)
return NULL;
return 0;
T data = 0;
for (uint64 i = 0; i < size; ++i)

5
src/server/shared/Common.h

@ -3,6 +3,11 @@ @@ -3,6 +3,11 @@
#include <boost/cstdint.hpp>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdarg>
#define MAX_FORMAT_LEN 32*1024
typedef uint8_t uint8;
typedef uint16_t uint16;

27
src/server/shared/Exception.h

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
#ifndef EXCEPTION_H_
#define EXCEPTION_H_
class Exception: public std::exception
{
public:
Exception(const char *text)
{
_msg.assign(text);
}
Exception(std::string text)
{
_msg.assign(text);
}
virtual ~Exception() throw () {}
virtual const char* what() const throw () {
return _msg.c_str();
}
protected:
std::string _msg;
};
#endif

34
src/server/shared/JSON/JSON.h

@ -2,6 +2,9 @@ @@ -2,6 +2,9 @@
#define JSON_H_
#include "Common.h"
#include "Log.h"
#include "Util.h"
#include "Exception.h"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/variant.hpp>
@ -10,7 +13,6 @@ @@ -10,7 +13,6 @@
#include <sstream>
#include <vector>
#include <map>
#include <Log.h>
enum JSONValueType
{
@ -25,6 +27,13 @@ enum JSONValueType @@ -25,6 +27,13 @@ enum JSONValueType
typedef boost::variant<bool, int64, double, std::string> JSONValue;
class JSONException: public Exception
{
public:
JSONException(const char *text): Exception(text) {}
JSONException(std::string text): Exception(text) {}
};
class JSON
{
public:
@ -41,6 +50,9 @@ public: @@ -41,6 +50,9 @@ public:
// Arrays
JSON& operator[] (uint32 index)
{
if (index >= _vec.size())
throw JSONException(Util::FS("Index %u out of range. Vector size: %u", index, _vec.size()));
return _vec[index];
}
@ -49,7 +61,7 @@ public: @@ -49,7 +61,7 @@ public:
{
if (_type != JSON_ARRAY) {
if (_type != JSON_NULL)
throw "Bad type";
throw JSONException("Node is not an array type");
else
_type = JSON_ARRAY;
}
@ -63,7 +75,7 @@ public: @@ -63,7 +75,7 @@ public:
{
if (_type != JSON_ARRAY) {
if (_type != JSON_NULL)
throw "Bad type";
throw JSONException("Node is not an array type");
else
_type = JSON_ARRAY;
}
@ -77,7 +89,7 @@ public: @@ -77,7 +89,7 @@ public:
{
if (_type != JSON_OBJECT) {
if (_type != JSON_NULL)
throw "Bad type";
throw JSONException("Node is not an object type");
else
_type = JSON_OBJECT;
}
@ -95,7 +107,7 @@ public: @@ -95,7 +107,7 @@ public:
{
if (_type != JSON_OBJECT) {
if (_type != JSON_NULL)
throw "Bad type";
throw JSONException("Node is not an object type");
else
_type = JSON_OBJECT;
}
@ -112,7 +124,7 @@ public: @@ -112,7 +124,7 @@ public:
bool GetBool()
{
if (_type != JSON_BOOL)
throw "Bad type";
throw JSONException("Node is not a bool type");
return boost::get<bool>(_val);
}
@ -126,7 +138,7 @@ public: @@ -126,7 +138,7 @@ public:
int64 GetInt()
{
if (_type != JSON_INTEGER)
throw "Bad type";
throw JSONException("Node is not an int type");
return boost::get<int64>(_val);
}
@ -140,7 +152,7 @@ public: @@ -140,7 +152,7 @@ public:
double GetDouble()
{
if (_type != JSON_DOUBLE)
throw "Bad type";
throw JSONException("Node is not a double type");
return boost::get<double>(_val);
}
@ -154,7 +166,7 @@ public: @@ -154,7 +166,7 @@ public:
std::string GetString()
{
if (_type != JSON_STRING)
throw "Bad type";
throw JSONException("Node is not a string type");
return boost::get<std::string>(_val);
}
@ -188,7 +200,7 @@ public: @@ -188,7 +200,7 @@ public:
else if (_type == JSON_OBJECT)
return _map.size();
else
throw "Type has no size";
return 0;
}
JSONValueType GetType()
@ -227,7 +239,7 @@ inline void JSON::Add(JSON& node) @@ -227,7 +239,7 @@ inline void JSON::Add(JSON& node)
{
if (_type != JSON_ARRAY) {
if (_type != JSON_NULL)
throw "Bad type";
throw JSONException("Node is not an array type");
else
_type = JSON_ARRAY;
}

3
src/server/shared/JSON/JSONReader.h

@ -176,7 +176,8 @@ namespace JSONReader @@ -176,7 +176,8 @@ namespace JSONReader
std::string::const_iterator begin = str.begin();
std::string::const_iterator end = str.end();
qi::phrase_parse(begin, end, g, ascii::space);
if (!qi::phrase_parse(begin, end, g, ascii::space))
throw JSONException("Failed to parse JSON");
}
}

35
src/server/shared/JSONRPC/JSONRPC.cpp

@ -30,10 +30,9 @@ bool JSONRPC::Connect(JSONRPCConnectionInfo connInfo) @@ -30,10 +30,9 @@ bool JSONRPC::Connect(JSONRPCConnectionInfo connInfo)
_sock.connect(_ep, error);
}
if (error)
{
sLog.Error(LOG_JSONRPC, "JSONRPC::Connect(): Error connecting to '%s': %s", _connInfo.Host.c_str(), boost::system::system_error(error).what());
return false;
if (error) {
_sock.close();
throw JSONRPCException(Util::FS("JSONRPC::Connect(): Error connecting to '%s': %s", _connInfo.Host.c_str(), boost::system::system_error(error).what()));
}
_sock.close();
@ -58,10 +57,9 @@ JSON JSONRPC::Query(std::string method, JSON params) @@ -58,10 +57,9 @@ JSON JSONRPC::Query(std::string method, JSON params)
_sock.close();
_sock.connect(_ep, error);
if (error)
{
sLog.Error(LOG_JSONRPC, "JSONRPC::Query(): Error connecting to '%s': %s", _connInfo.Host.c_str(), boost::system::system_error(error).what());
throw "fail";
if (error) {
_sock.close();
throw JSONRPCException(Util::FS("JSONRPC::Connect(): Error connecting to '%s': %s", _connInfo.Host.c_str(), boost::system::system_error(error).what()));
}
boost::asio::streambuf request_buf;
@ -88,16 +86,14 @@ JSON JSONRPC::Query(std::string method, JSON params) @@ -88,16 +86,14 @@ JSON JSONRPC::Query(std::string method, JSON params)
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
sLog.Error(LOG_JSONRPC, "JSONRPC::Query(): Malformed HTTP Response");
throw "fail";
if (!response_stream || http_version.substr(0, 5) != "HTTP/") {
_sock.close();
throw JSONRPCException("JSONRPC::Query(): Malformed HTTP Response");
}
if (status_code != 200)
{
sLog.Error(LOG_JSONRPC, "JSONRPC::Query(): Returned status code: %u", status_code);
throw "fail";
if (status_code != 200) {
_sock.close();
throw JSONRPCException(Util::FS("JSONRPC::Query(): Returned status code: %u", status_code));
}
std::vector<std::string> headers;
@ -116,13 +112,6 @@ JSON JSONRPC::Query(std::string method, JSON params) @@ -116,13 +112,6 @@ JSON JSONRPC::Query(std::string method, JSON params)
jsonresponse += oss.str();
}
// Read until EOF, writing data to output as we go.
/*while (_sock.available() && boost::asio::read(_sock, response, error)){
std::ostringstream oss;
oss << &response;
jsonresponse += oss.str();
}*/
_sock.close();
sLog.Debug(LOG_JSONRPC, "JSONRPC::Query(): JSON Response: %s", jsonresponse.c_str());

9
src/server/shared/JSONRPC/JSONRPC.h

@ -6,7 +6,9 @@ @@ -6,7 +6,9 @@
#include <boost/cstdint.hpp>
#include <boost/asio.hpp>
#include <string>
#include "JSON.h"
#include "Exception.h"
struct JSONRPCConnectionInfo
{
@ -17,6 +19,13 @@ struct JSONRPCConnectionInfo @@ -17,6 +19,13 @@ struct JSONRPCConnectionInfo
std::string B64Auth;
};
class JSONRPCException: public Exception
{
public:
JSONRPCException(const char *text): Exception(text) {}
JSONRPCException(std::string text): Exception(text) {}
};
class JSONRPC
{
public:

10
src/server/shared/MySQL/DatabaseConnection.cpp

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
#include "DatabaseConnection.h"
#include "Log.h"
#include "Util.h"
namespace MySQL
{
@ -28,10 +29,7 @@ namespace MySQL @@ -28,10 +29,7 @@ namespace MySQL
MYSQL* mysqlInit;
mysqlInit = mysql_init(NULL);
if (!mysqlInit)
{
sLog.Error(LOG_DATABASE, "Could not initialize Mysql connection to database `%s`", _connectionInfo.DB.c_str());
return false;
}
throw ConnectionException(Util::FS("Could not initialize Mysql connection to database `%s`", _connectionInfo.DB.c_str()));
mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME, "utf8");
@ -51,9 +49,9 @@ namespace MySQL @@ -51,9 +49,9 @@ namespace MySQL
}
else
{
sLog.Error(LOG_DATABASE, "Could not connect to MySQL database at %s: %s\n", _connectionInfo.Host.c_str(), mysql_error(mysqlInit));
const char* error = mysql_error(mysqlInit);
mysql_close(mysqlInit);
return false;
throw ConnectionException(Util::FS("Could not connect to MySQL database at %s: %s", _connectionInfo.Host.c_str(), mysql_error(mysqlInit)));
}
}

15
src/server/shared/MySQL/DatabaseConnection.h

@ -1,14 +1,16 @@ @@ -1,14 +1,16 @@
#ifndef DATABASE_CONNECTION_MYSQL_H_
#define DATABASE_CONNECTION_MYSQL_H_
#include <boost/thread.hpp>
#include <mysql.h>
#include <string>
#include "DatabaseOperation.h"
#include "DatabaseWorker.h"
#include "QueryResult.h"
#include "PreparedStatement.h"
#include "Log.h"
#include <boost/thread.hpp>
#include <mysql.h>
#include "Exception.h"
namespace MySQL
{
@ -28,6 +30,13 @@ namespace MySQL @@ -28,6 +30,13 @@ namespace MySQL
std::string DB;
};
class ConnectionException: public Exception
{
public:
ConnectionException(const char *text): Exception(text) {}
ConnectionException(std::string text): Exception(text) {}
};
class DatabaseConnection
{
public:

20
src/server/shared/Util.cpp

@ -31,6 +31,26 @@ uint32 Util::Date(bool utc) @@ -31,6 +31,26 @@ uint32 Util::Date(bool utc)
return diff.total_seconds();
}
std::string Util::FS(const char *str, ...)
{
va_list ap;
va_start(ap, str);
char text[MAX_FORMAT_LEN];
vsnprintf(text, MAX_FORMAT_LEN, str, ap);
va_end(ap);
return std::string(text);
}
std::vector<std::string> Util::Explode(std::string input, std::string delim)
{
std::vector<std::string> strs;
boost::split(strs, input, boost::is_any_of(delim));
return strs;
}
std::string Util::ToBase64(std::string input, bool linebreaks)
{
uint32_t writePaddChars = (3 - input.length() % 3) % 3;

3
src/server/shared/Util.h

@ -14,11 +14,14 @@ @@ -14,11 +14,14 @@
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/remove_whitespace.hpp>
#include <boost/algorithm/string.hpp>
namespace Util
{
std::string Date(const char* format, bool utc = false);
uint32 Date(bool utc = true);
std::string FS(const char *str, ...);
std::vector<std::string> Explode(std::string input, std::string delim);
template <typename T>
class SynchronisedQueue

Loading…
Cancel
Save