#ifndef STRATUM_CLIENT_H_ #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 #include #include #include #define MAX_PACKET 2048 using namespace boost; using namespace boost::asio::ip; namespace Stratum { class Server; class Client : public boost::enable_shared_from_this { public: 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("StratumMinDifficulty"); _minDiff = _diff; } tcp::socket& GetSocket() { return _socket; } 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(); } void StartRead() { // Read until newline boost::asio::async_read_until( _socket, _recvBuffer, '\n', boost::bind(&Client::_OnReceive, this, asio::placeholders::error, asio::placeholders::bytes_transferred)); } void SendJob(bool clean); void SendMessage(JSON msg) { std::string data = msg.ToString(); data += '\n'; sLog.Debug(LOG_SERVER, "Sending: %s", data.c_str()); boost::asio::async_write( _socket, boost::asio::buffer(data.c_str(), data.length()), boost::bind(&Client::_OnSend, this, boost::asio::placeholders::error)); } void OnMiningSubmit(JSON msg); void OnMiningSubscribe(JSON msg); void OnMiningAuthorize(JSON msg); void OnMessage(JSON msg) { std::string method = msg["method"].GetString(); sLog.Debug(LOG_SERVER, "Decoded: %s", msg.ToString().c_str()); if (method.compare("mining.submit") == 0) OnMiningSubmit(msg); else if (method.compare("mining.subscribe") == 0) OnMiningSubscribe(msg); else if (method.compare("mining.authorize") == 0) OnMiningAuthorize(msg); else sLog.Error(LOG_SERVER, "Method '%s' not found.", method.c_str()); } // 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(); } public: void _OnReceive(const boost::system::error_code& error, size_t bytes_transferred); void _OnSend(const boost::system::error_code& error); private: // Networking asio::streambuf _recvBuffer; tcp::socket _socket; uint32 _ip; uint64 _id; // Pointer to server Stratum::Server* _server; // Authorization std::vector _workers; // Jobs bool _subscribed; uint32 _extranonce; std::map _jobs; uint32 _jobid; // Share limiting uint64 _diff; uint64 _minDiff; ShareLimiter _shareLimiter; }; typedef boost::shared_ptr ClientPtr; } #endif