Skip to content

Commit 52265e5

Browse files
committed
Use Curl for Stratum as well.
Replacing very old stuff ported from rieMiner's ancestors, simplifying a lot the Code and helping for the next Feature. Signed-off-by: Pttn <28868425+Pttn@users.noreply.github.com>
1 parent 9b4b048 commit 52265e5

File tree

2 files changed

+56
-83
lines changed

2 files changed

+56
-83
lines changed

Client.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class StratumClient : public NetworkedClient {
124124
const std::string _username, _password, _host;
125125
const uint16_t _port;
126126
// Client State Variables
127+
CURL *_curl;
127128
std::mutex _submitMutex;
128129
uint64_t _currentJobId{0}, _shares{0}, _rejectedShares{0};
129130
struct Job { // Stratum Job Data/Context
@@ -151,7 +152,7 @@ class StratumClient : public NetworkedClient {
151152

152153
void _processMessage(const std::string&); // Processes a message received from the pool
153154
public:
154-
StratumClient(const Options &options) : _username(options.username), _password(options.password), _host(options.host), _port(options.port) {}
155+
StratumClient(const Options &options) : _username(options.username), _password(options.password), _host(options.host), _port(options.port), _curl(curl_easy_init()) {}
155156
void connect(); // Also sends mining.subscribe
156157
void process(); // Get messages from the server and calls _processMessage to handle them
157158
std::optional<ClientInfo> info() const;

StratumClient.cpp

Lines changed: 54 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
// (c) 2018-present Pttn (https://riecoin.xyz/rieMiner)
22

3-
#include <fcntl.h>
4-
#ifdef _WIN32
5-
#include <winsock2.h>
6-
#else
7-
#include <arpa/inet.h>
8-
#include <netdb.h>
9-
#endif
103
#include <nlohmann/json.hpp>
114

125
#include "Client.hpp"
@@ -194,8 +187,11 @@ void StratumClient::_processMessage(const std::string &message) {
194187
logger.log("ExtraNonce1 = "s + v8ToHexStr(_extraNonce1) + "\n"s);
195188
logger.log("extraNonce2Len = "s + std::to_string(_extraNonce2Len) + "\n"s);
196189
const std::string miningAuthorizeMessage("{\"jsonrpc\": \"2.0\", \"id\": "s + std::to_string(_jsonId++) + ", \"method\": \"mining.authorize\", \"params\": [\""s + _username + "\", \""s + _password + "\"]}\n"s);
197-
send(_socket, miningAuthorizeMessage.c_str(), miningAuthorizeMessage.size(), 0);
198-
// logger.logDebug("Sent to pool: "s + miningAuthorizeMessage);
190+
// logger.logDebug("Sending: "s + miningAuthorizeMessage);
191+
size_t bytesSent(0);
192+
CURLcode cc(curl_easy_send(_curl, miningAuthorizeMessage.c_str(), miningAuthorizeMessage.size(), &bytesSent));
193+
if (cc != CURLE_OK)
194+
logger.log("Could not send Authorize Message: Curl Error "s + std::to_string(cc) + " - "s + curl_easy_strerror(cc) + "\n"s, MessageType::ERROR);
199195
}
200196
else if (_state == SUBSCRIBED) {
201197
nlohmann::json jsonResult;
@@ -247,75 +243,50 @@ void StratumClient::connect() {
247243
_lastPoolMessageTp = std::chrono::steady_clock::now();
248244
_state = UNSUBSCRIBED;
249245
_jsonId = 0U;
250-
#ifdef _WIN32
251-
WORD wVersionRequested(MAKEWORD(2, 2));
252-
WSADATA wsaData;
253-
const int err(WSAStartup(wVersionRequested, &wsaData));
254-
if (err != 0) {
255-
logger.log("WSAStartup failed with error "s + std::to_string(err) + "\n"s, MessageType::ERROR);
246+
if (!_curl) {
247+
logger.log("Unknown Curl Error\n"s, MessageType::ERROR);
256248
return;
257249
}
258-
#endif
259-
hostent* hostInfo = gethostbyname(_host.c_str());
260-
if (hostInfo == nullptr) {
261-
logger.log("Unable to resolve '"s + _host + "', check the URL.\n"s, MessageType::ERROR);
250+
curl_easy_setopt(_curl, CURLOPT_URL, (_host + ":" + std::to_string(_port) + "/").c_str());
251+
curl_easy_setopt(_curl, CURLOPT_CONNECT_ONLY, 1L);
252+
CURLcode cc(curl_easy_perform(_curl));
253+
if (cc != CURLE_OK) {
254+
logger.log("Could not connect to Server: Curl Error "s + std::to_string(cc) + " - "s + curl_easy_strerror(cc) + "\n"s, MessageType::ERROR);
262255
return;
263256
}
264-
void** ipListPtr((void**) hostInfo->h_addr_list);
265-
uint32_t ip(0xFFFFFFFF);
266-
if (ipListPtr[0]) ip = *(uint32_t*) ipListPtr[0];
267-
std::ostringstream oss;
268-
oss << ((ip >> 0) & 0xFF) << "." << ((ip >> 8) & 0xFF) << "." << ((ip >> 16) & 0xFF) << "." << ((ip >> 24) & 0xFF);
269-
logger.log("Host: '"s + _host + " -> " + oss.str() + "\n"s);
270-
_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
271-
if (_socket == -1) {
272-
#ifdef _WIN32
273-
logger.log("Could not create endpoint, error "s + std::to_string(WSAGetLastError()) + "\n"s, MessageType::ERROR);
274-
#else
275-
logger.log("Could not create endpoint: "s + std::strerror(errno) + "\n"s, MessageType::ERROR);
276-
#endif
257+
cc = curl_easy_getinfo(_curl, CURLINFO_ACTIVESOCKET, &_socket);
258+
if (cc != CURLE_OK) {
259+
logger.log("Could not get Socket File Descriptor: Curl Error "s + std::to_string(cc) + " - "s + curl_easy_strerror(cc) + "\n"s, MessageType::ERROR);
277260
return;
278261
}
279-
struct sockaddr_in addr;
280-
memset(&addr, 0, sizeof(sockaddr_in));
281-
addr.sin_family = AF_INET;
282-
addr.sin_port = htons(_port);
283-
addr.sin_addr.s_addr = inet_addr(oss.str().c_str());
284-
int result = ::connect(_socket, (sockaddr*) &addr, sizeof(sockaddr_in));
285-
if (result != 0) {
286-
#ifdef _WIN32
287-
logger.log("Could not connect to the pool, error "s + std::to_string(WSAGetLastError()) + "\n"s +
288-
#else
289-
logger.log("Could not connect to the pool: "s + std::strerror(errno) + "\n"s +
290-
#endif
291-
"Check the port."s, MessageType::ERROR);
262+
char *ip;
263+
curl_easy_getinfo(_curl, CURLINFO_PRIMARY_IP, &ip);
264+
if (cc != CURLE_OK) {
265+
logger.log("Could not get Server IP: Curl Error "s + std::to_string(cc) + " - "s + curl_easy_strerror(cc) + "\n"s, MessageType::ERROR);
292266
return;
293267
}
294-
#ifdef _WIN32
295-
uint32_t nonBlocking(true), cbRet;
296-
if (WSAIoctl(_socket, FIONBIO, &nonBlocking, sizeof(nonBlocking), nullptr, 0, (LPDWORD) &cbRet, nullptr, nullptr) != 0) {
297-
#else
298-
if (fcntl(_socket, F_SETFL, fcntl(_socket, F_GETFL, 0) | O_NONBLOCK) == -1) {
299-
#endif
300-
logger.log("Unable to make the socket non-blocking\n"s, MessageType::ERROR);
301-
return;
268+
logger.log("Host: "s + _host + " -> " + ip + "\n"s);
269+
if (_state == UNSUBSCRIBED) {
270+
const std::string miningSubscribeMessage("{\"jsonrpc\": \"2.0\", \"id\": "s + std::to_string(_jsonId++) + ", \"method\": \"mining.subscribe\", \"params\": [\""s + userAgent + "\"]}\n"s);
271+
size_t bytesSent(0);
272+
cc = curl_easy_send(_curl, miningSubscribeMessage.c_str(), miningSubscribeMessage.size(), &bytesSent);
273+
logger.logDebug("Sending: "s + miningSubscribeMessage);
274+
if (cc != CURLE_OK) {
275+
logger.log("Could not send Subscribe Message: Curl Error "s + std::to_string(cc) + " - "s + curl_easy_strerror(cc) + "\n"s, MessageType::ERROR);
276+
return;
277+
}
302278
}
303-
}
304-
if (_state == UNSUBSCRIBED) {
305-
const std::string miningSubscribeMessage("{\"jsonrpc\": \"2.0\", \"id\": "s + std::to_string(_jsonId++) + ", \"method\": \"mining.subscribe\", \"params\": [\""s + userAgent + "\"]}\n"s);
306-
send(_socket, miningSubscribeMessage.c_str(), miningSubscribeMessage.size(), 0);
307-
logger.logDebug("Sent to pool: "s + miningSubscribeMessage);
308-
}
309-
const std::chrono::time_point<std::chrono::steady_clock> timeOutTimer(std::chrono::steady_clock::now());
310-
while (!getJob().has_value() || _state != AUTHORIZED) {
311-
process();
312-
if (Stella::timeSince(timeOutTimer) > 1.) {
313-
logger.log("Could not get a first job from the pool!\n"s, MessageType::ERROR);
314-
std::lock_guard<std::mutex> lock(_jobMutex);
315-
_currentJobTemplate.clientInfo = {};
316-
return;
279+
const std::chrono::time_point<std::chrono::steady_clock> timeOutTimer(std::chrono::steady_clock::now());
280+
while (!getJob().has_value() || _state != AUTHORIZED) {
281+
process();
282+
if (Stella::timeSince(timeOutTimer) > 1.) {
283+
logger.log("Could not get a first job from the pool!\n"s, MessageType::ERROR);
284+
std::lock_guard<std::mutex> lock(_jobMutex);
285+
_currentJobTemplate.clientInfo = {};
286+
return;
287+
}
288+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
317289
}
318-
std::this_thread::sleep_for(std::chrono::milliseconds(100));
319290
}
320291
_connected = true;
321292
}
@@ -331,6 +302,7 @@ void StratumClient::process() {
331302
std::lock_guard<std::mutex> lock(_jobMutex);
332303
for (const auto &job : _currentJobs) {
333304
if (job.id == share.jobId) {
305+
_shares++;
334306
logger.logDebug(Stella::formattedClockTimeNow() + " "s + std::to_string(share.primeCount) + "-share found by worker thread "s + std::to_string(share.threadId) + "\n"s);
335307
std::ostringstream oss;
336308
oss << "{\"jsonrpc\": \"2.0\", \"id\": " << std::to_string(_jsonId++) << ", \"method\": \"mining.submit\", \"params\": [\""
@@ -339,9 +311,13 @@ void StratumClient::process() {
339311
<< v8ToHexStr(job.extraNonce2) << "\", \""
340312
<< std::setfill('0') << std::setw(16) << std::hex << job.bh.curtime << "\", \""
341313
<< v8ToHexStr(reverse(a8ToV8(encodedOffset(share)))) << "\"]}\n";
342-
send(_socket, oss.str().c_str(), oss.str().size(), 0);
343-
logger.logDebug("Sent to pool: "s + oss.str());
344-
_shares++;
314+
logger.logDebug("Sending: "s + oss.str());
315+
size_t bytesSent(0);
316+
CURLcode cc(curl_easy_send(_curl, oss.str().c_str(), oss.str().size(), &bytesSent));
317+
if (cc != CURLE_OK) {
318+
logger.log("Could not send Share: Curl Error "s + std::to_string(cc) + " - "s + curl_easy_strerror(cc) + "\n"s, MessageType::ERROR);
319+
_rejectedShares++;
320+
}
345321
break;
346322
} // If not found then Job was obsoleted due to a new Block, do not submit.
347323
}
@@ -353,19 +329,15 @@ void StratumClient::process() {
353329
constexpr std::size_t bufferSize(4096);
354330
char buffer[bufferSize];
355331
memset(&buffer, 0, bufferSize);
356-
const ssize_t messageLength(recv(_socket, buffer, bufferSize - 1U, 0));
357-
if (messageLength <= 0) { // No data received.
358-
if (messageLength == 0)
359-
logger.log("Connection closed by the pool.\n"s, MessageType::WARNING);
360-
else if (Stella::timeSince(_lastPoolMessageTp) > stratumTimeOut)
332+
size_t bytesReceived(0);
333+
CURLcode cc(curl_easy_recv(_curl, buffer, bufferSize - 1U, &bytesReceived));
334+
if (bytesReceived == 0) { // No data received.
335+
if (Stella::timeSince(_lastPoolMessageTp) > stratumTimeOut)
361336
logger.log("Received nothing from the pool since a long time, disconnection assumed.\n"s, MessageType::WARNING);
362-
#ifdef _WIN32
363-
else if (WSAGetLastError() != WSAEWOULDBLOCK)
364-
logger.log("Error receiving work data from pool, error "s + std::to_string(WSAGetLastError()) + "\n"s, MessageType::ERROR);
365-
#else
366-
else if (errno != EWOULDBLOCK)
337+
else if (cc == CURLE_OK)
338+
logger.log("Connection closed by the pool.\n"s, MessageType::WARNING);
339+
else if (cc != CURLE_AGAIN)
367340
logger.log("Error receiving work data from pool: "s + std::strerror(errno) + "\n"s, MessageType::ERROR);
368-
#endif
369341
else // Nothing went wrong, it is expected to get nothing most of the times due to the non blocking socket.
370342
return;
371343
_socket = -1;

0 commit comments

Comments
 (0)