Browse Source

multipool: Squashed commit (v2)

commit a9d3c1ffdb71d2a4985749acba3d424161154ab4
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Thu May 21 05:39:24 2015 +0200

    multipool: last changes before squashed merge

    and fix net diff on wallets.. was longpoll specific

commit a63f0024f3f1fb52d2c4369518bf87c33a9e16ae
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Thu May 21 05:02:27 2015 +0200

    update api sample for the protocol 1.5

commit adda14b22edde6485932be56550166478f6f00dd
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Thu May 21 04:43:25 2015 +0200

    stats: store pool number in scanlog

commit e1a0274b01c29409ce16f9096b9985a35cf78ba7
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Thu May 21 03:36:15 2015 +0200

    api: switchpool and new pool stats variables (API v1.5)

    add accepted/rej by pool, wait time on conditional, net diff and rate

    also add scantime per pool config option and do some pool cleanup..

commit 1a30450ad2a5e068983531b9d2a96629b970c1e8
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Wed May 20 06:39:09 2015 +0200

    prevent concurrent pool switching

    and limit condtionnal wait messages to the first thread/device

commit e3922c7a331a3ad2730bc83082fcd6b2547542f5
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Wed May 20 05:39:45 2015 +0200

    add some pool rotate options, like pool time-limit

    update sample pools.conf for time rotation

commit 312bd905412d49fd5a9f9e7ff2bc72b23edf38ed
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Wed May 20 04:31:19 2015 +0200

    do not try to restart threads from threads

    Start inconditionally the stratum and longpoll threads,
    these threads are just waiting a tq_push() if unused...

    so add some checks to know if vars are set for the right pool

commit d4a9428fefdd9e9d70c3c8231f10961e7cd41760
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Wed May 20 01:06:31 2015 +0200

    pools: add name and removed attributes

    also increase max defined pools to 8

    to be tested on windows..

commit d840d683ecb2cc4767f0a0612b8359c52d4bad29
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Tue May 19 22:33:11 2015 +0200

    parse json config file pools array

commit d6c29b1f7f6b786c56e1f0cb8a90305f06cc7aec
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Tue May 19 03:29:30 2015 +0200

    multi-pools: prepare storage/switch of credentials

    for the moment:
    - allow the storage of multiple -o params (and user/pass)
    - allow a failover pool on connection failed
    - switch to the next pool with the "seturl" api remote command
    - longpoll to stratum switch (reverse to check...)

    todo: mix stratum/getwork, new api commands, json config...

commit 2d6b3fddf6631d7df1ac6ca74eee91c33a3c09ee
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Fri May 22 08:26:40 2015 +0200

    multipool: increase stability, but not 100% perfect

    several problems fixed:
    - submit to the pool set in work (source pool)
    - longpoll curl timeout could be too high and could lock the switch
    - mutexes cant be copied on windows (stratum global var to fully remove later)

    I linked the -T timeout option to curl and tried to remove all fixed timeout values

commit 6fd935c369cf33949dab98c8b09b2ca8cab3e7ea
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Fri May 22 11:23:07 2015 +0200

    stratum: remove last rpc_ vars in stratum thread

commit ee9c821525be303282e5dab512ffd2ae81ad524f
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Sat May 23 03:53:50 2015 +0200

    stratum: do not alloc empty merkle tree

commit 69852a2874bd18c4ed1daa9180a10d12976424dc
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Sat May 23 04:25:12 2015 +0200

    stratum: properly free jobs on disconnect

Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com>
master
Tanguy Pruvot 10 years ago
parent
commit
bbd2c704f9
  1. 103
      api.cpp
  2. 12
      api/index.php
  3. 824
      ccminer.cpp
  4. 8
      hashlog.cpp
  5. 76
      miner.h
  6. 27
      pools.conf
  7. 2
      stats.cpp
  8. 124
      util.cpp

103
api.cpp

@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
* Software Foundation; either version 2 of the License, or (at your option)
* any later version. See COPYING for more details.
*/
#define APIVERSION "1.4"
#define APIVERSION "1.5"
#ifdef WIN32
# define _WINSOCK_DEPRECATED_NO_WARNINGS
@ -92,13 +92,12 @@ static int bye = 0; @@ -92,13 +92,12 @@ static int bye = 0;
extern char *opt_api_allow;
extern int opt_api_listen; /* port */
extern int opt_api_remote;
extern uint32_t accepted_count;
extern uint32_t rejected_count;
extern int num_cpus;
// current stratum...
extern struct stratum_ctx stratum;
extern char* rpc_user;
// sysinfos.cpp
extern int num_cpus;
extern float cpu_temp(int);
extern uint32_t cpu_clock(int);
// cuda.cpp
@ -111,6 +110,8 @@ char driver_version[32] = { 0 }; @@ -111,6 +110,8 @@ char driver_version[32] = { 0 };
static void gpustatus(int thr_id)
{
struct pool_infos *p = &pools[cur_pooln];
if (thr_id >= 0 && thr_id < opt_n_threads) {
struct cgpu_info *cgpu = &thr_info[thr_id].gpu;
int gpuid = cgpu->gpu_id;
@ -127,8 +128,8 @@ static void gpustatus(int thr_id) @@ -127,8 +128,8 @@ static void gpustatus(int thr_id)
cuda_gpu_clocks(cgpu);
// todo: per gpu
cgpu->accepted = accepted_count;
cgpu->rejected = rejected_count;
cgpu->accepted = p->accepted_count;
cgpu->rejected = p->rejected_count;
cgpu->khashes = stats_get_speed(thr_id, 0.0) / 1000.0;
@ -165,19 +166,27 @@ static char *getsummary(char *params) @@ -165,19 +166,27 @@ static char *getsummary(char *params)
{
char algo[64]; *algo = '\0';
time_t ts = time(NULL);
double uptime = difftime(ts, startup);
double accps = (60.0 * accepted_count) / (uptime ? uptime : 1.0);
double accps, uptime = difftime(ts, startup);
uint32_t wait_time = 0, accepted_count = 0, rejected_count = 0;
for (int p = 0; p < num_pools; p++) {
wait_time += pools[cur_pooln].wait_time;
accepted_count += pools[cur_pooln].accepted_count;
rejected_count += pools[cur_pooln].rejected_count;
}
accps = (60.0 * accepted_count) / (uptime ? uptime : 1.0);
get_currentalgo(algo, sizeof(algo));
*buffer = '\0';
sprintf(buffer, "NAME=%s;VER=%s;API=%s;"
"ALGO=%s;GPUS=%d;KHS=%.2f;ACC=%d;REJ=%d;"
"ACCMN=%.3f;DIFF=%.6f;UPTIME=%.0f;TS=%u|",
"ACCMN=%.3f;DIFF=%.6f;NETKHS=%.2f;"
"POOLS=%u;WAIT=%u;UPTIME=%.0f;TS=%u|",
PACKAGE_NAME, PACKAGE_VERSION, APIVERSION,
algo, active_gpus, (double)global_hashrate / 1000.0,
algo, active_gpus, (double)global_hashrate / 1000.,
accepted_count, rejected_count,
accps, net_diff > 0. ? net_diff : stratum_diff, uptime, (uint32_t) ts);
accps, net_diff > 0. ? net_diff : stratum_diff, (double)net_hashrate / 1000.,
num_pools, wait_time, uptime, (uint32_t) ts);
return buffer;
}
@ -186,31 +195,30 @@ static char *getsummary(char *params) @@ -186,31 +195,30 @@ static char *getsummary(char *params)
*/
static char *getpoolnfo(char *params)
{
char *p = buffer;
char *s = buffer;
char jobid[128] = { 0 };
char nonce[128] = { 0 };
*p = '\0';
struct pool_infos *p = &pools[cur_pooln];
if (!stratum.url) {
sprintf(p, "|");
return p;
}
*s = '\0';
if (stratum.job.job_id)
strncpy(jobid, stratum.job.job_id, sizeof(stratum.job.job_id));
if (stratum.job.xnonce2) {
/* used temporary to be sure all is ok */
cbin2hex(nonce, (const char*) stratum.job.xnonce2, stratum.xnonce2_size);
sprintf(nonce, "0x");
cbin2hex(&nonce[2], (const char*) stratum.job.xnonce2, stratum.xnonce2_size);
}
snprintf(p, MYBUFSIZ, "URL=%s;USER=%s;H=%u;JOB=%s;DIFF=%.6f;N2SZ=%d;N2=0x%s;PING=%u;DISCO=%u;UPTIME=%u|",
stratum.url, rpc_user ? rpc_user : "",
stratum.job.height, jobid, stratum.job.diff,
snprintf(s, MYBUFSIZ, "URL=%s;USER=%s;ACC=%d;REJ=%d;H=%u;JOB=%s;DIFF=%.6f;"
"N2SZ=%d;N2=%s;PING=%u;DISCO=%u;WAIT=%u;UPTIME=%u|",
p->url, p->type & POOL_STRATUM ? p->user : "",
p->accepted_count, p->rejected_count,
stratum.job.height, jobid, stratum_diff,
(int) stratum.xnonce2_size, nonce, stratum.answer_msec,
stratum.disconnects, (uint32_t) (time(NULL) - stratum.tm_connected));
p->disconnects, p->wait_time, p->work_time);
return p;
return s;
}
/*****************************************************************************/
@ -342,9 +350,9 @@ static char *getscanlog(char *params) @@ -342,9 +350,9 @@ static char *getscanlog(char *params)
*buffer = '\0';
for (int i = 0; i < records; i++) {
time_t ts = data[i].tm_upd;
p += sprintf(p, "H=%u;JOB=%u;N=%u;FROM=0x%x;SCANTO=0x%x;"
p += sprintf(p, "H=%u;P=%u;JOB=%u;N=%u;FROM=0x%x;SCANTO=0x%x;"
"COUNT=0x%x;FOUND=%u;TS=%u|",
data[i].height, data[i].njobid, data[i].nonce, data[i].scanned_from, data[i].scanned_to,
data[i].height, data[i].npool, data[i].njobid, data[i].nonce, data[i].scanned_from, data[i].scanned_to,
(data[i].scanned_to - data[i].scanned_from), data[i].tm_sent ? 1 : 0, (uint32_t)ts);
}
return buffer;
@ -380,19 +388,47 @@ static bool check_remote_access(void) @@ -380,19 +388,47 @@ static bool check_remote_access(void)
return (opt_api_remote > 0);
}
/**
* Set pool by index (pools array in json config)
* switchpool|1|
*/
static char *remote_switchpool(char *params)
{
bool ret = false;
*buffer = '\0';
if (!check_remote_access())
return buffer;
if (!params || strlen(params) == 0) {
// rotate pool test
ret = pool_switch_next();
} else {
int n = atoi(params);
if (n == cur_pooln)
ret = true;
else if (n < num_pools)
ret = pool_switch(n);
}
sprintf(buffer, "%s|", ret ? "ok" : "fail");
return buffer;
}
/**
* Change pool url (see --url parameter)
* seturl|stratum+tcp://Danila.1:X@pool.ipominer.com:3335|
* seturl|stratum+tcp://<user>:<pass>@mine.xpool.ca:1131|
*/
extern bool stratum_need_reset;
static char *remote_seturl(char *params)
{
bool ret;
*buffer = '\0';
if (!check_remote_access())
return buffer;
parse_arg('o', params);
stratum_need_reset = true;
sprintf(buffer, "%s", "ok|");
if (!params || strlen(params) == 0) {
// rotate pool test
ret = pool_switch_next();
} else {
ret = pool_switch_url(params);
}
sprintf(buffer, "%s|", ret ? "ok" : "fail");
return buffer;
}
@ -425,7 +461,8 @@ struct CMDS { @@ -425,7 +461,8 @@ struct CMDS {
{ "scanlog", getscanlog },
/* remote functions */
{ "seturl", remote_seturl },
{ "seturl", remote_seturl }, /* prefer switchpool, deprecated */
{ "switchpool", remote_switchpool },
{ "quit", remote_quit },
/* keep it the last */

12
api/index.php

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
<?php
/* ccminer API sample UI */
/* ccminer API sample UI (API 1.5) */
$host = 'http://localhost/api/'; // 'http://'.$_SERVER['SERVER_NAME'].'/api/';
$configs = array(
@ -27,7 +27,7 @@ function getdataFromPeers() @@ -27,7 +27,7 @@ function getdataFromPeers()
function ignoreField($key)
{
$ignored = array(
'API','VER','GPU','BUS',
'API','VER','GPU','BUS','POOLS',
'CARD','GPUS','CPU','TS',
);
return in_array($key, $ignored);
@ -47,13 +47,17 @@ function translateField($key) @@ -47,13 +47,17 @@ function translateField($key)
$intl['ACCMN'] = 'Accepted / mn';
$intl['REJ'] = 'Rejected';
$intl['DIFF'] = 'Difficulty';
$intl['NETKHS'] = 'Net Rate';
$intl['UPTIME'] = 'Miner up time';
$intl['TS'] = 'Last update';
$intl['THR'] = 'Throughput';
$intl['WAIT'] = 'Wait time';
$intl['H'] = 'Bloc height';
$intl['I'] = 'Intensity';
$intl['HWF'] = 'Failures';
$intl['POOLS'] = 'Pools';
$intl['TEMP'] = 'T°c';
$intl['FAN'] = 'Fan %';
@ -76,6 +80,7 @@ function translateValue($key,$val,$data=array()) @@ -76,6 +80,7 @@ function translateValue($key,$val,$data=array())
{
switch ($key) {
case 'UPTIME':
case 'WAIT':
$min = floor(intval($val) / 60);
$sec = intval($val) % 60;
$val = "${min}mn${sec}s";
@ -95,6 +100,7 @@ function translateValue($key,$val,$data=array()) @@ -95,6 +100,7 @@ function translateValue($key,$val,$data=array())
$val = strftime("%H:%M:%S", (int) $val);
break;
case 'KHS':
case 'NETKHS':
$val = '<span class="bold">'.$val.'</span> kH/s';
break;
case 'NAME':
@ -246,7 +252,7 @@ span.elipsis { display: inline-block; max-width: 130px; overflow: hidden; } @@ -246,7 +252,7 @@ span.elipsis { display: inline-block; max-width: 130px; overflow: hidden; }
</div>
<div id="footer">
<p>&copy; 2014 <a href="http://github.com/tpruvot/ccminer">tpruvot@github</a></p>
<p>&copy; 2014-2015 <a href="http://github.com/tpruvot/ccminer">tpruvot@github</a></p>
</div>
</body>

824
ccminer.cpp

File diff suppressed because it is too large Load Diff

8
hashlog.cpp

@ -18,13 +18,17 @@ @@ -18,13 +18,17 @@
/* from miner.h
struct hashlog_data {
uint32_t tm_sent;
uint8_t npool;
uint8_t pool_type;
uint32_t height;
uint32_t njobid;
uint32_t nonce;
uint32_t scanned_from;
uint32_t scanned_to;
uint32_t last_from;
uint32_t tm_add;
uint32_t tm_upd;
uint32_t tm_sent;
};
*/
@ -75,6 +79,8 @@ void hashlog_remember_submit(struct work* work, uint32_t nonce) @@ -75,6 +79,8 @@ void hashlog_remember_submit(struct work* work, uint32_t nonce)
data.height = work->height;
data.njobid = (uint32_t) njobid;
data.tm_add = data.tm_upd = data.tm_sent = (uint32_t) time(NULL);
data.npool = (uint8_t) cur_pooln;
data.pool_type = pools[cur_pooln].type;
tlastshares[key] = data;
}

76
miner.h

@ -423,16 +423,25 @@ struct stats_data { @@ -423,16 +423,25 @@ struct stats_data {
uint32_t tm_stat;
uint32_t hashcount;
uint32_t height;
double difficulty;
double hashrate;
uint8_t thr_id;
uint8_t gpu_id;
uint8_t hashfound;
uint8_t ignored;
uint8_t npool;
uint8_t pool_type;
uint16_t align;
};
struct hashlog_data {
uint32_t tm_sent;
uint8_t npool;
uint8_t pool_type;
uint16_t align;
uint32_t height;
uint32_t njobid;
uint32_t nonce;
@ -441,6 +450,7 @@ struct hashlog_data { @@ -441,6 +450,7 @@ struct hashlog_data {
uint32_t last_from;
uint32_t tm_add;
uint32_t tm_upd;
uint32_t tm_sent;
};
/* end of api */
@ -529,8 +539,6 @@ extern uint32_t gpus_intensity[MAX_GPUS]; @@ -529,8 +539,6 @@ extern uint32_t gpus_intensity[MAX_GPUS];
extern void format_hashrate(double hashrate, char *output);
extern void applog(int prio, const char *fmt, ...);
void get_defconfig_path(char *out, size_t bufsize, char *argv0);
extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
const char *rpc_req, bool, bool, int *);
extern void cbin2hex(char *out, const char *in, size_t len);
extern char *bin2hex(const unsigned char *in, size_t len);
extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
@ -567,7 +575,6 @@ struct stratum_ctx { @@ -567,7 +575,6 @@ struct stratum_ctx {
curl_socket_t sock;
size_t sockbuf_size;
char *sockbuf;
pthread_mutex_t sock_lock;
double next_diff;
@ -576,11 +583,10 @@ struct stratum_ctx { @@ -576,11 +583,10 @@ struct stratum_ctx {
unsigned char *xnonce1;
size_t xnonce2_size;
struct stratum_job job;
pthread_mutex_t work_lock;
struct timeval tv_submit;
uint32_t answer_msec;
uint32_t disconnects;
int pooln;
time_t tm_connected;
int srvtime_diff;
@ -602,11 +608,68 @@ struct work { @@ -602,11 +608,68 @@ struct work {
double difficulty;
uint32_t height;
uint8_t pooln;
uint32_t scanned_from;
uint32_t scanned_to;
};
#define MAX_POOLS 8
struct pool_infos {
uint8_t id;
#define POOL_UNUSED 0
#define POOL_GETWORK 1
#define POOL_STRATUM 2
#define POOL_LONGPOLL 4
uint8_t type;
#define POOL_ST_DEFINED 1
#define POOL_ST_VALID 2
#define POOL_ST_DISABLED 4
#define POOL_ST_REMOVED 8
uint16_t status;
char name[64];
// credentials
char url[256];
char short_url[64];
char user[64];
char pass[64];
// config options
double max_diff;
double max_rate;
int time_limit;
int scantime;
// connection
struct stratum_ctx stratum;
uint8_t allow_gbt;
uint8_t allow_mininginfo;
uint16_t check_dups; // 16_t for align
int retries;
int fail_pause;
int timeout;
// stats
uint32_t work_time;
uint32_t wait_time;
uint32_t accepted_count;
uint32_t rejected_count;
uint32_t disconnects;
};
extern struct pool_infos pools[MAX_POOLS];
extern int num_pools;
extern volatile int cur_pooln;
int pool_get_first_valid(int startfrom);
void pool_set_creds(int pooln);
void pool_set_attr(int pooln, const char* key, char* arg);
bool pool_switch_url(char *params);
bool pool_switch(int pooln);
bool pool_switch_next(void);
json_t * json_rpc_call_pool(CURL *curl, struct pool_infos*,
const char *req, bool lp_scan, bool lp, int *err);
json_t * json_rpc_longpoll(CURL *curl, char *lp_url, struct pool_infos*,
const char *req, int *err);
bool stratum_socket_full(struct stratum_ctx *sctx, int timeout);
bool stratum_send_line(struct stratum_ctx *sctx, char *s);
char *stratum_recv_line(struct stratum_ctx *sctx);
@ -615,6 +678,7 @@ void stratum_disconnect(struct stratum_ctx *sctx); @@ -615,6 +678,7 @@ void stratum_disconnect(struct stratum_ctx *sctx);
bool stratum_subscribe(struct stratum_ctx *sctx);
bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass);
bool stratum_handle_method(struct stratum_ctx *sctx, const char *s);
void stratum_free_job(struct stratum_ctx *sctx);
void hashlog_remember_submit(struct work* work, uint32_t nonce);
void hashlog_remember_scan_range(struct work* work);

27
pools.conf

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
{
"_note": "Sample rotation of 2 pools",
"pools":[{
"name": "Longpoll sample",
"url": "http://ziftr.suprnova.cc:9991",
"user": "tpruvot.win",
"pass": "x",
"max-diff": 0.0,
"time-limit": 180,
"disabled": false
},
{
"name": "Stratum sample",
"url": "stratum+tcp://zrc-stratum.suprnova.cc:2257",
"user": "tpruvot.elite",
"pass": "x",
"time-limit": 300
}],
"algo" : "zr5",
"api-bind" : "0.0.0.0",
"api-remote" : true,
"no-gbt": true
}

2
stats.cpp

@ -41,6 +41,8 @@ void stats_remember_speed(int thr_id, uint32_t hashcount, double hashrate, uint8 @@ -41,6 +41,8 @@ void stats_remember_speed(int thr_id, uint32_t hashcount, double hashrate, uint8
data.thr_id = (uint8_t) thr_id;
data.tm_stat = (uint32_t) time(NULL);
data.height = height;
data.npool = (uint8_t) cur_pooln;
data.pool_type = pools[cur_pooln].type;
data.hashcount = hashcount;
data.hashfound = found;
data.hashrate = hashrate;

124
util.cpp

@ -36,6 +36,9 @@ @@ -36,6 +36,9 @@
#include "miner.h"
#include "elist.h"
extern pthread_mutex_t stratum_sock_lock;
extern pthread_mutex_t stratum_work_lock;
bool opt_tracegpu = false;
struct data_buffer {
@ -385,9 +388,12 @@ static int sockopt_keepalive_cb(void *userdata, curl_socket_t fd, @@ -385,9 +388,12 @@ static int sockopt_keepalive_cb(void *userdata, curl_socket_t fd,
}
#endif
json_t *json_rpc_call(CURL *curl, const char *url,
/* For getwork (longpoll or wallet) - not stratum pools!
* DO NOT USE DIRECTLY
*/
static json_t *json_rpc_call(CURL *curl, const char *url,
const char *userpass, const char *rpc_req,
bool longpoll_scan, bool longpoll, int *curl_err)
bool longpoll_scan, bool longpoll, bool keepalive, int *curl_err)
{
json_t *val, *err_val, *res_val;
int rc;
@ -395,10 +401,10 @@ json_t *json_rpc_call(CURL *curl, const char *url, @@ -395,10 +401,10 @@ json_t *json_rpc_call(CURL *curl, const char *url,
struct upload_buffer upload_data;
json_error_t err;
struct curl_slist *headers = NULL;
char* httpdata;
char *httpdata;
char len_hdr[64], hashrate_hdr[64];
char curl_err_str[CURL_ERROR_SIZE] = { 0 };
long timeout = longpoll ? opt_timeout : 30;
long timeout = longpoll ? opt_timeout*2 : opt_timeout;
struct header_info hi = { 0 };
bool lp_scanning = longpoll_scan && !have_longpoll;
@ -435,7 +441,7 @@ json_t *json_rpc_call(CURL *curl, const char *url, @@ -435,7 +441,7 @@ json_t *json_rpc_call(CURL *curl, const char *url,
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
}
#if LIBCURL_VERSION_NUM >= 0x070f06
if (longpoll)
if (keepalive)
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_keepalive_cb);
#endif
curl_easy_setopt(curl, CURLOPT_POST, 1);
@ -486,7 +492,8 @@ json_t *json_rpc_call(CURL *curl, const char *url, @@ -486,7 +492,8 @@ json_t *json_rpc_call(CURL *curl, const char *url,
}
if (!all_data.buf || !all_data.len) {
applog(LOG_ERR, "Empty data received in json_rpc_call.");
if (!have_longpoll) // seems normal on longpoll timeout
applog(LOG_ERR, "Empty data received in json_rpc_call.");
goto err_out;
}
@ -571,6 +578,31 @@ err_out: @@ -571,6 +578,31 @@ err_out:
return NULL;
}
/* getwork calls with pool pointer (wallet/longpoll pools) */
json_t *json_rpc_call_pool(CURL *curl, struct pool_infos *pool, const char *req,
bool longpoll_scan, bool longpoll, int *curl_err)
{
char userpass[256];
// todo, malloc and store that in pool array
snprintf(userpass, sizeof(userpass), "%s%c%s", pool->user,
strlen(pool->pass)?':':'\0', pool->pass);
return json_rpc_call(curl, pool->url, userpass, req, longpoll_scan, false, false, curl_err);
}
/* called only from longpoll thread */
json_t *json_rpc_longpoll(CURL *curl, char *lp_url, struct pool_infos *pool, const char *req, int *curl_err)
{
char userpass[256];
snprintf(userpass, sizeof(userpass), "%s%c%s", pool->user,
strlen(pool->pass)?':':'\0', pool->pass);
// on pool rotate by time-limit, this keepalive can be a problem
bool keepalive = pool->time_limit == 0 || pool->time_limit > opt_timeout*4;
return json_rpc_call(curl, lp_url, userpass, req, want_longpoll, have_longpoll, keepalive, curl_err);
}
/**
* Unlike malloc, calloc set the memory to zero
*/
@ -774,9 +806,9 @@ bool stratum_send_line(struct stratum_ctx *sctx, char *s) @@ -774,9 +806,9 @@ bool stratum_send_line(struct stratum_ctx *sctx, char *s)
if (opt_protocol)
applog(LOG_DEBUG, "> %s", s);
pthread_mutex_lock(&sctx->sock_lock);
pthread_mutex_lock(&stratum_sock_lock);
ret = send_line(sctx->sock, s);
pthread_mutex_unlock(&sctx->sock_lock);
pthread_mutex_unlock(&stratum_sock_lock);
return ret;
}
@ -797,6 +829,7 @@ static bool socket_full(curl_socket_t sock, int timeout) @@ -797,6 +829,7 @@ static bool socket_full(curl_socket_t sock, int timeout)
bool stratum_socket_full(struct stratum_ctx *sctx, int timeout)
{
if (!sctx->sockbuf) return false;
return strlen(sctx->sockbuf) || socket_full(sctx->sock, timeout);
}
@ -821,10 +854,13 @@ char *stratum_recv_line(struct stratum_ctx *sctx) @@ -821,10 +854,13 @@ char *stratum_recv_line(struct stratum_ctx *sctx)
ssize_t len, buflen;
char *tok, *sret = NULL;
if (!sctx->sockbuf)
return NULL;
if (!strstr(sctx->sockbuf, "\n")) {
bool ret = true;
time_t rstart = time(NULL);
if (!socket_full(sctx->sock, 60)) {
if (!socket_full(sctx->sock, opt_timeout)) {
applog(LOG_ERR, "stratum_recv_line timed out");
goto out;
}
@ -845,7 +881,7 @@ char *stratum_recv_line(struct stratum_ctx *sctx) @@ -845,7 +881,7 @@ char *stratum_recv_line(struct stratum_ctx *sctx)
}
} else
stratum_buffer_append(sctx, s);
} while (time(NULL) - rstart < 60 && !strstr(sctx->sockbuf, "\n"));
} while (time(NULL) - rstart < opt_timeout && !strstr(sctx->sockbuf, "\n"));
if (!ret) {
applog(LOG_ERR, "stratum_recv_line failed");
@ -888,13 +924,13 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url) @@ -888,13 +924,13 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url)
CURL *curl;
int rc;
pthread_mutex_lock(&sctx->sock_lock);
pthread_mutex_lock(&stratum_sock_lock);
if (sctx->curl)
curl_easy_cleanup(sctx->curl);
sctx->curl = curl_easy_init();
if (!sctx->curl) {
applog(LOG_ERR, "CURL initialization failed");
pthread_mutex_unlock(&sctx->sock_lock);
pthread_mutex_unlock(&stratum_sock_lock);
return false;
}
curl = sctx->curl;
@ -903,21 +939,21 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url) @@ -903,21 +939,21 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url)
sctx->sockbuf_size = RBUFSIZE;
}
sctx->sockbuf[0] = '\0';
pthread_mutex_unlock(&sctx->sock_lock);
pthread_mutex_unlock(&stratum_sock_lock);
if (url != sctx->url) {
free(sctx->url);
sctx->url = strdup(url);
}
free(sctx->curl_url);
sctx->curl_url = (char*)malloc(strlen(url));
sctx->curl_url = (char*)malloc(strlen(url)+1);
sprintf(sctx->curl_url, "http%s", strstr(url, "://"));
if (opt_protocol)
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, sctx->curl_url);
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, opt_timeout);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, sctx->curl_err_str);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
@ -957,16 +993,41 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url) @@ -957,16 +993,41 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url)
return true;
}
void stratum_free_job(struct stratum_ctx *sctx)
{
pthread_mutex_lock(&stratum_work_lock);
if (sctx->job.job_id) {
free(sctx->job.job_id);
}
if (sctx->job.merkle_count) {
for (int i = 0; i < sctx->job.merkle_count; i++) {
free(sctx->job.merkle[i]);
sctx->job.merkle[i] = NULL;
}
free(sctx->job.merkle);
}
free(sctx->job.coinbase);
// note: xnonce2 is not allocated
memset(&(sctx->job.job_id), 0, sizeof(struct stratum_job));
pthread_mutex_unlock(&stratum_work_lock);
}
void stratum_disconnect(struct stratum_ctx *sctx)
{
pthread_mutex_lock(&sctx->sock_lock);
pthread_mutex_lock(&stratum_sock_lock);
if (sctx->curl) {
sctx->disconnects++;
pools[sctx->pooln].disconnects++;
curl_easy_cleanup(sctx->curl);
sctx->curl = NULL;
sctx->sockbuf[0] = '\0';
if (sctx->sockbuf)
sctx->sockbuf[0] = '\0';
// free(sctx->sockbuf);
// sctx->sockbuf = NULL;
}
if (sctx->job.job_id) {
stratum_free_job(sctx);
}
pthread_mutex_unlock(&sctx->sock_lock);
pthread_mutex_unlock(&stratum_sock_lock);
}
static const char *get_stratum_session_id(json_t *val)
@ -1012,19 +1073,19 @@ static bool stratum_parse_extranonce(struct stratum_ctx *sctx, json_t *params, i @@ -1012,19 +1073,19 @@ static bool stratum_parse_extranonce(struct stratum_ctx *sctx, json_t *params, i
goto out;
}
pthread_mutex_lock(&sctx->work_lock);
pthread_mutex_lock(&stratum_work_lock);
if (sctx->xnonce1)
free(sctx->xnonce1);
sctx->xnonce1_size = strlen(xnonce1) / 2;
sctx->xnonce1 = (uchar*) calloc(1, sctx->xnonce1_size);
if (unlikely(!sctx->xnonce1)) {
applog(LOG_ERR, "Failed to alloc xnonce1");
pthread_mutex_unlock(&sctx->work_lock);
pthread_mutex_unlock(&stratum_work_lock);
goto out;
}
hex2bin(sctx->xnonce1, xnonce1, sctx->xnonce1_size);
sctx->xnonce2_size = xn2_size;
pthread_mutex_unlock(&sctx->work_lock);
pthread_mutex_unlock(&stratum_work_lock);
if (pndx == 0 && opt_debug) /* pool dynamic change */
applog(LOG_DEBUG, "Stratum set nonce %s with extranonce2 size=%d",
@ -1103,12 +1164,12 @@ start: @@ -1103,12 +1164,12 @@ start:
if (opt_debug && sid)
applog(LOG_DEBUG, "Stratum session id: %s", sid);
pthread_mutex_lock(&sctx->work_lock);
pthread_mutex_lock(&stratum_work_lock);
if (sctx->session_id)
free(sctx->session_id);
sctx->session_id = sid ? strdup(sid) : NULL;
sctx->next_diff = 1.0;
pthread_mutex_unlock(&sctx->work_lock);
pthread_mutex_unlock(&stratum_work_lock);
out:
free(s);
@ -1253,8 +1314,8 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params) @@ -1253,8 +1314,8 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params)
bool clean, ret = false;
int merkle_count, i;
json_t *merkle_arr;
uchar **merkle;
uchar(*merkle_tree)[32] = NULL;
uchar **merkle = NULL;
// uchar(*merkle_tree)[32] = { 0 };
int ntime;
job_id = json_string_value(json_array_get(params, 0));
@ -1287,7 +1348,8 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params) @@ -1287,7 +1348,8 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params)
applog(LOG_DEBUG, "stratum time is at least %ds in the future", ntime);
}
merkle = (uchar**) malloc(merkle_count * sizeof(char *));
if (merkle_count)
merkle = (uchar**) malloc(merkle_count * sizeof(char *));
for (i = 0; i < merkle_count; i++) {
const char *s = json_string_value(json_array_get(merkle_arr, i));
if (!s || strlen(s) != 64) {
@ -1301,7 +1363,7 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params) @@ -1301,7 +1363,7 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params)
hex2bin(merkle[i], s, 32);
}
pthread_mutex_lock(&sctx->work_lock);
pthread_mutex_lock(&stratum_work_lock);
coinb1_size = strlen(coinb1) / 2;
coinb2_size = strlen(coinb2) / 2;
@ -1341,7 +1403,7 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params) @@ -1341,7 +1403,7 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params)
sctx->job.diff = sctx->next_diff;
pthread_mutex_unlock(&sctx->work_lock);
pthread_mutex_unlock(&stratum_work_lock);
ret = true;
@ -1358,9 +1420,9 @@ static bool stratum_set_difficulty(struct stratum_ctx *sctx, json_t *params) @@ -1358,9 +1420,9 @@ static bool stratum_set_difficulty(struct stratum_ctx *sctx, json_t *params)
if (diff <= 0.0)
return false;
pthread_mutex_lock(&sctx->work_lock);
pthread_mutex_lock(&stratum_work_lock);
sctx->next_diff = diff;
pthread_mutex_unlock(&sctx->work_lock);
pthread_mutex_unlock(&stratum_work_lock);
/* store for api stats */
if (diff != stratum_diff) {

Loading…
Cancel
Save